import { useEffect, useState, type HTMLAttributes, type ReactNode } from "react"; import { ChevronDown } from "lucide-react"; import { usePlatformLanguage } from "../i18n/LanguageContext"; import type { PlatformInterfaceIdentityProps } from "../types"; export type CardProps = PlatformInterfaceIdentityProps & Omit, "children" | "title"> & { title?: ReactNode; children: ReactNode; actions?: ReactNode; afterBody?: ReactNode; collapsible?: boolean; collapseKey?: string; persistCollapse?: boolean; as?: "section" | "article"; headerClassName?: string; bodyClassName?: string; actionsClassName?: string; }; function resolveCollapseStorageKey(collapsible: boolean, persistCollapse: boolean, collapseKey: string | undefined, title: ReactNode): string | null { if (!collapsible || !persistCollapse) return null; if (collapseKey) return `govoplan.card.collapsed:${collapseKey}`; if (typeof window === "undefined" || typeof title !== "string") return null; const normalizedTitle = title.trim(); if (!normalizedTitle) return null; return `govoplan.card.collapsed:${window.location.pathname}:${normalizedTitle}`; } function readCollapseState(storageKey: string | null): boolean { if (!storageKey || typeof window === "undefined") return false; try { return window.localStorage.getItem(storageKey) === "1"; } catch { return false; } } function writeCollapseState(storageKey: string | null, collapsed: boolean): void { if (!storageKey || typeof window === "undefined") return; try { window.localStorage.setItem(storageKey, collapsed ? "1" : "0"); } catch { // localStorage may be unavailable in private or restricted contexts. }} export default function Card({ title, children, actions, afterBody, collapsible = false, collapseKey, persistCollapse = true, as = "section", className = "", headerClassName = "", bodyClassName = "", actionsClassName = "", interfaceId, helpContextId, helpModuleId, helpTopicId, ...props }: CardProps) { const { translateText } = usePlatformLanguage(); const Element = as; const storageKey = resolveCollapseStorageKey(collapsible, persistCollapse, collapseKey, title); const [collapseState, setCollapseState] = useState(() => ({ storageKey, collapsed: readCollapseState(storageKey) })); const collapsed = collapseState.storageKey === storageKey ? collapseState.collapsed : readCollapseState(storageKey); const hasHeader = Boolean(title || actions || collapsible); const body = {children}; const shouldRenderBody = !collapsible || !collapsed; const collapseLabel = translateText(collapsed ? "i18n:govoplan-core.show_content.0528d8d2" : "i18n:govoplan-core.show_header_only.24afefca"); useEffect(() => { setCollapseState({ storageKey, collapsed: readCollapseState(storageKey) }); }, [storageKey]); function toggleCollapsed() { const nextCollapsed = !collapsed; writeCollapseState(storageKey, nextCollapsed); setCollapseState({ storageKey, collapsed: nextCollapsed }); } return ( {hasHeader && {title && (typeof title === "string" ? {translateText(title)} : {title})} {(actions || collapsible) && {actions} {collapsible && } } } {shouldRenderBody && (collapsible ? {body}{afterBody} : <>{body}{afterBody}>)} ); }