"use client"; import { Download, Globe, Save } from "lucide-react"; import { useMemo, useState } from "react"; import { saveTranslations } from "@/actions/translations"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { useServerAction } from "@/hooks/use-server-action"; import { flattenObject, unflattenObject } from "@/lib/translations-utils"; interface Props { enJson: string; itJson: string; } export function TranslationsClient({ enJson, itJson }: Props) { const [en, setEn] = useState(() => flattenObject(JSON.parse(enJson))); const [it, setIt] = useState(() => flattenObject(JSON.parse(itJson))); const [search, setSearch] = useState(""); const [group, setGroup] = useState(""); const [activeLang, setActiveLang] = useState<"en" | "it">("en"); const { run, isPending } = useServerAction(); const PER_PAGE = 30; const [page, setPage] = useState(1); const activeData = activeLang === "en" ? en : it; const setActiveData = activeLang === "en" ? setEn : setIt; const groups = useMemo(() => { const g = new Set(); Object.keys(en).forEach((k) => { const parts = k.split("."); if (parts.length > 1) g.add(parts[0]); }); return Array.from(g).sort(); }, [en]); const filteredKeys = useMemo(() => { return Object.keys(activeData).filter((key) => { const matchSearch = !search || key.toLowerCase().includes(search.toLowerCase()) || activeData[key].toLowerCase().includes(search.toLowerCase()); const matchGroup = !group || key.startsWith(`${group}.`); return matchSearch && matchGroup; }); }, [activeData, search, group]); const totalPages = Math.ceil(filteredKeys.length / PER_PAGE); const pageKeys = filteredKeys.slice((page - 1) * PER_PAGE, page * PER_PAGE); function updateValue(key: string, value: string) { setActiveData({ ...activeData, [key]: value }); } function handleSave() { run(() => saveTranslations({ locale: activeLang, data: unflattenObject(activeData) }), { successMessage: "Translations saved!", }); } function handleExport() { const blob = new Blob([JSON.stringify(unflattenObject(activeData), null, 2)], { type: "application/json", }); const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = `${activeLang}.json`; a.click(); URL.revokeObjectURL(url); } return (

CMS

{ setSearch(e.target.value); setPage(1); }} className="max-w-xs" /> {filteredKeys.length} keys
{pageKeys.map((key) => (
{key} updateValue(key, e.target.value)} className="flex-1 h-8 text-sm" />
))}
{totalPages > 1 && (
Page {page} of {totalPages}
)}
); }