PageSourceSearch

https://www.hamienet.com/assets/HelpCenterManager-DPjaYina.js

js hamienet.com collected 2026-10-02 05:01:46 UTC 38,885 bytes, 633 lines download raw bytes

1import { r as reactExports, j as jsxRuntimeExports } from "./vendor-react-Bay9Y7Lb.js";
2import { a as api } from "./index-w5lXls15.js";
3import { b as Drawer } from "./AdminShared-BP_vxG_A.js";
4import { a as ai } from "./ai-B0Mlroaa.js";
5import { bG as CircleQuestionMark, ck as Layers, ct as BookOpen, cf as Plus, bz as EyeOff, bA as Eye, f9 as Pen, b5 as Trash2, a_ as CircleCheck, bi as Sparkles, cd as Save } from "./vendor-D0P4XgNj.js";
6import "./vendor-i18n-BC7ZMXWQ.js";
7import "./vendor-ai-gQv1oOjO.js";
8const ICONS = ["user", "play", "upload", "shield", "settings", "message-circle", "credit-card", "globe"];
9const DeleteConfirmationModal = ({
10  isOpen,
11  onClose,
12  onConfirm,
13  title,
14  message
15}) => {
16  if (!isOpen) return null;
17  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "fixed inset-0 z-[100] flex items-center justify-center p-4", children: [
18    /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute inset-0 bg-black/50 backdrop-blur-sm", onClick: onClose }),
19    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative w-full max-w-sm bg-white dark:bg-zinc-900 rounded-xl shadow-2xl p-6 border border-zinc-200 dark:border-zinc-800 animate-in zoom-in-95", children: [
20      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 mb-4 text-red-600 dark:text-red-500", children: [
21        /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-2 bg-red-100 dark:bg-red-900/20 rounded-lg", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { size: 20 }) }),
22        /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "font-bold text-lg text-zinc-900 dark:text-white", children: "Confirm Deletion" })
23      ] }),
24      /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm font-bold text-zinc-900 dark:text-white mb-2", children: title }),
25      /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-600 dark:text-zinc-400 mb-6 leading-relaxed", children: message }),
26      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-end gap-3", children: [
27        /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: onClose, className: "px-4 py-2 rounded-lg text-xs font-bold text-zinc-600 dark:text-zinc-400 hover:bg-zinc-100 dark:hover:bg-zinc-800 transition-colors", children: "Cancel" }),
28        /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: onConfirm, className: "px-4 py-2 rounded-lg text-xs font-bold bg-red-600 hover:bg-red-700 text-white shadow-lg shadow-red-500/20 transition-colors", children: "Delete Permanently" })
29      ] })
30    ] })
31  ] });
32};
33const LanguageTabs = ({ activeLang, setActiveLang, locales, hasTranslation }) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2 overflow-x-auto pb-2 mb-4 border-b border-zinc-200 dark:border-zinc-800 custom-scrollbar", children: [
34  /* @__PURE__ */ jsxRuntimeExports.jsx(
35    "button",
36    {
37      onClick: () => setActiveLang("default"),
38      className: `px-3 py-1.5 rounded-full text-xs font-bold whitespace-nowrap transition-colors ${activeLang === "default" ? "bg-zinc-900 text-white dark:bg-white dark:text-black" : "bg-zinc-100 text-zinc-600 dark:bg-zinc-800 dark:text-zinc-400"}`,
39      children: "English (Default)"
40    }
41  ),
42  locales.filter((l) => l.code !== "en").map((l) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
43    "button",
44    {
45      onClick: () => setActiveLang(l.code),
46      className: `px-3 py-1.5 rounded-full text-xs font-bold whitespace-nowrap transition-colors flex items-center gap-1 ${activeLang === l.code ? "bg-indigo-600 text-white" : "bg-zinc-100 text-zinc-600 dark:bg-zinc-800 dark:text-zinc-400"}`,
47      children: [
48        l.name,
49        hasTranslation(l.code) && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-1.5 h-1.5 rounded-full bg-emerald-400" })
50      ]
51    },
52    l.code
53  ))
54] });
55const CategoryForm = ({ category, onClose, onRefresh }) => {
56  const [form, setForm] = reactExports.useState({
57    id: "",
58    title: "",
59    description: "",
60    iconKey: "help-circle",
61    colorClass: "text-indigo-500 bg-indigo-50",
62    order: 0,
63    type: "info",
64    isHidden: false,
65    translations: {}
66  });
67  const [locales, setLocales] = reactExports.useState([]);
68  const [activeLang, setActiveLang] = reactExports.useState("default");
69  const [isTranslating, setIsTranslating] = reactExports.useState(false);
70  const isEdit = !!(category == null ? void 0 : category.id);
71  reactExports.useEffect(() => {
72    api.getLocales().then((l) => setLocales(l.filter((loc) => loc.isActive)));
73    if (category) setForm({ type: "info", ...category, translations: category.translations || {} });
74    else setForm({ id: "", title: "", description: "", iconKey: "help-circle", colorClass: "text-indigo-500 bg-indigo-50", order: 0, type: "info", isHidden: false, translations: {} });
75  }, [category]);
76  const handleSave = async () => {
77    if (!form.title || !form.id) return alert("Title and ID are required");
78    await api.saveHelpCategory(form);
79    onRefresh();
80    onClose();
81  };
82  const updateTranslation = (field, value) => {
83    if (activeLang === "default") {
84      setForm({ ...form, [field]: value });
85    } else {
86      setForm((prev) => {
87        const currentTrans = prev.translations || {};
88        const langTrans = currentTrans[activeLang] || { title: "", description: "" };
89        return {
90          ...prev,
91          translations: {
92            ...currentTrans,
93            [activeLang]: { ...langTrans, [field]: value }
94          }
95        };
96      });
97    }
98  };
99  const getValue = (field) => {
100    var _a, _b;
101    if (activeLang === "default") return form[field];
102    return ((_b = (_a = form.translations) == null ? void 0 : _a[activeLang]) == null ? void 0 : _b[field]) || "";
103  };
104  const handleAutoTranslate = async () => {
105    if (!form.title || !form.description) return alert("Please enter title and description first.");
106    setIsTranslating(true);
107    try {
108      const targetLangs = locales.filter((l) => l.code !== "en").map((l) => l.code);
109      if (targetLangs.length === 0) {
110        alert("No other active languages found to translate to.");
111        return;
112      }
113      const prompt = `Translate the following category title and description into these languages: ${targetLangs.join(", ")}.
114            
115            Title: ${form.title}
116            Description: ${form.description}
117            
118            Return a JSON object where keys are language codes and values are objects with "title" and "description".
119            Example: { "es": { "title": "...", "description": "..." }, "ja": { ... } }`;
120      const response = await ai.models.generateContent({
121        model: "gemini-3-flash-preview",
122        contents: prompt
123      });
124      const jsonStr = (response.text || "").replace(/^```json/, "").replace(/^```/, "").replace(/```$/, "").trim();
125      const translations = JSON.parse(jsonStr);
126      setForm((prev) => ({
127        ...prev,
128        translations: { ...prev.translations, ...translations }
129      }));
130      alert(`Translated into ${Object.keys(translations).length} languages.`);
131    } catch (e) {
132      console.error(e);
133      alert("Translation failed. Check API Key or try again.");
134    } finally {
135      setIsTranslating(false);
136    }
137  };
138  if (!category && category !== null) return null;
139  return /* @__PURE__ */ jsxRuntimeExports.jsx(Drawer, { isOpen: !!category || category === null, onClose, title: isEdit ? "Edit Category" : "New Category", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [
140    /* @__PURE__ */ jsxRuntimeExports.jsx(
141      LanguageTabs,
142      {
143        activeLang,
144        setActiveLang,
145        locales,
146        hasTranslation: (code) => {
147          var _a;
148          return !!((_a = form.translations) == null ? void 0 : _a[code]);
149        }
150      }
151    ),
152    activeLang === "default" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-4", children: [
153      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
154        /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-xs font-bold text-zinc-500 uppercase mb-1", children: "ID (Slug)" }),
155        /* @__PURE__ */ jsxRuntimeExports.jsx(
156          "input",
157          {
158            value: form.id,
159            onChange: (e) => setForm({ ...form, id: e.target.value.toLowerCase().replace(/\s+/g, "-") }),
160            disabled: isEdit,
161            className: `w-full bg-zinc-50 dark:bg-zinc-950 border border-zinc-300 dark:border-zinc-800 rounded p-2 text-sm outline-none focus:border-indigo-500 text-zinc-900 dark:text-white font-mono ${isEdit ? "opacity-50" : ""}`,
162            placeholder: "account-billing"
163          }
164        )
165      ] }),
166      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
167        /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-xs font-bold text-zinc-500 uppercase mb-1", children: "Category Type" }),
168        /* @__PURE__ */ jsxRuntimeExports.jsxs(
169          "select",
170          {
171            value: form.type,
172            onChange: (e) => setForm({ ...form, type: e.target.value }),
173            className: "w-full bg-zinc-50 dark:bg-zinc-950 border border-zinc-300 dark:border-zinc-800 rounded p-2 text-sm outline-none focus:border-indigo-500 text-zinc-900 dark:text-white",
174            children: [
175              /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "info", children: "Knowledge Base (Info)" }),
176              /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "support", children: "Support Center" })
177            ]
178          }
179        )
180      ] })
181    ] }),
182    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
183      /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "block text-xs font-bold text-zinc-500 uppercase mb-1", children: [
184        "Title (",
185        activeLang === "default" ? "English" : activeLang,
186        ")"
187      ] }),
188      /* @__PURE__ */ jsxRuntimeExports.jsx(
189        "input",
190        {
191          value: getValue("title"),
192          onChange: (e) => updateTranslation("title", e.target.value),
193          className: "w-full bg-zinc-50 dark:bg-zinc-950 border border-zinc-300 dark:border-zinc-800 rounded p-2 text-sm outline-none focus:border-indigo-500 text-zinc-900 dark:text-white",
194          placeholder: "Account & Billing"
195        }
196      )
197    ] }),
198    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
199      /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "block text-xs font-bold text-zinc-500 uppercase mb-1", children: [
200        "Description (",
201        activeLang === "default" ? "English" : activeLang,
202        ")"
203      ] }),
204      /* @__PURE__ */ jsxRuntimeExports.jsx(
205        "textarea",
206        {
207          value: getValue("description"),
208          onChange: (e) => updateTranslation("description", e.target.value),
209          className: "w-full bg-zinc-50 dark:bg-zinc-950 border border-zinc-300 dark:border-zinc-800 rounded p-2 text-sm outline-none focus:border-indigo-500 text-zinc-900 dark:text-white h-20 resize-none"
210        }
211      )
212    ] }),
213    activeLang === "default" && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
214      /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
215        "button",
216        {
217          onClick: handleAutoTranslate,
218          disabled: isTranslating,
219          className: "flex items-center gap-2 px-3 py-1.5 bg-indigo-50 dark:bg-indigo-900/20 text-indigo-600 dark:text-indigo-400 rounded-lg text-xs font-bold hover:bg-indigo-100 dark:hover:bg-indigo-900/40 transition-colors disabled:opacity-50",
220          children: [
221            /* @__PURE__ */ jsxRuntimeExports.jsx(Sparkles, { size: 14, className: isTranslating ? "animate-spin" : "" }),
222            isTranslating ? "Translating..." : "Auto-Translate All"
223          ]
224        }
225      ) }),
226      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
227        /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-xs font-bold text-zinc-500 uppercase mb-2", children: "Icon" }),
228        /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "grid grid-cols-4 gap-2", children: ICONS.map((icon) => /* @__PURE__ */ jsxRuntimeExports.jsx(
229          "button",
230          {
231            onClick: () => setForm({ ...form, iconKey: icon }),
232            className: `p-2 rounded border text-center text-xs font-bold uppercase ${form.iconKey === icon ? "bg-indigo-100 dark:bg-indigo-900/30 border-indigo-500 text-indigo-700 dark:text-indigo-300" : "bg-white dark:bg-zinc-900 border-zinc-200 dark:border-zinc-800 text-zinc-500"}`,
233            children: icon
234          },
235          icon
236        )) })
237      ] }),
238      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between gap-4", children: [
239        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1", children: [
240          /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-xs font-bold text-zinc-500 uppercase mb-1", children: "Sort Order" }),
241          /* @__PURE__ */ jsxRuntimeExports.jsx(
242            "input",
243            {
244              type: "number",
245              value: form.order,
246              onChange: (e) => setForm({ ...form, order: parseInt(e.target.value) }),
247              className: "w-full bg-zinc-50 dark:bg-zinc-950 border border-zinc-300 dark:border-zinc-800 rounded p-2 text-sm outline-none focus:border-indigo-500 text-zinc-900 dark:text-white"
248            }
249          )
250        ] }),
251        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 bg-zinc-100 dark:bg-zinc-800 p-3 rounded-lg mt-5", children: [
252          /* @__PURE__ */ jsxRuntimeExports.jsx(
253            "input",
254            {
255              type: "checkbox",
256              checked: form.isHidden,
257              onChange: (e) => setForm({ ...form, isHidden: e.target.checked }),
258              className: "rounded text-indigo-600 focus:ring-indigo-500"
259            }
260          ),
261          /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-sm font-medium text-zinc-900 dark:text-white", children: "Hide Category" })
262        ] })
263      ] })
264    ] }),
265    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2 pt-4", children: [
266      /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: onClose, className: "flex-1 px-4 py-2 rounded-lg border border-zinc-300 dark:border-zinc-700 font-bold text-zinc-600 dark:text-zinc-400 hover:bg-zinc-50 dark:hover:bg-zinc-800", children: "Cancel" }),
267      /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { onClick: handleSave, className: "flex-1 px-4 py-2 rounded-lg bg-indigo-600 hover:bg-indigo-700 text-white font-bold flex items-center justify-center gap-2", children: [
268        /* @__PURE__ */ jsxRuntimeExports.jsx(Save, { size: 16 }),
269        " Save"
270      ] })
271    ] })
272  ] }) });
273};
274const ArticleForm = ({ article, categories, onClose, onRefresh }) => {
275  var _a;
276  const [form, setForm] = reactExports.useState({
277    id: "",
278    categoryId: ((_a = categories[0]) == null ? void 0 : _a.id) || "",
279    title: "",
280    content: "",
281    isPublished: true,
282    isHidden: false,
283    views: 0,
284    translations: {}
285  });
286  const [locales, setLocales] = reactExports.useState([]);
287  const [activeLang, setActiveLang] = reactExports.useState("default");
288  const [isTranslating, setIsTranslating] = reactExports.useState(false);
289  const isEdit = !!(article == null ? void 0 : article.id);
290  reactExports.useEffect(() => {
291    var _a2;
292    api.getLocales().then((l) => setLocales(l.filter((loc) => loc.isActive)));
293    if (article) setForm({ ...article, translations: article.translations || {} });
294    else setForm({ id: `art-${Date.now()}`, categoryId: ((_a2 = categories[0]) == null ? void 0 : _a2.id) || "", title: "", content: "", isPublished: true, isHidden: false, views: 0, translations: {} });
295  }, [article, categories]);
296  const handleSave = async () => {
297    if (!form.title || !form.content) return alert("Title and Content are required");
298    await api.saveHelpArticle(form);
299    onRefresh();
300    onClose();
301  };
302  const updateTranslation = (field, value) => {
303    if (activeLang === "default") {
304      setForm({ ...form, [field]: value });
305    } else {
306      setForm((prev) => {
307        const currentTrans = prev.translations || {};
308        const langTrans = currentTrans[activeLang] || { title: "", content: "" };
309        return {
310          ...prev,
311          translations: {
312            ...currentTrans,
313            [activeLang]: { ...langTrans, [field]: value }
314          }
315        };
316      });
317    }
318  };
319  const getValue = (field) => {
320    var _a2, _b;
321    if (activeLang === "default") return form[field];
322    return ((_b = (_a2 = form.translations) == null ? void 0 : _a2[activeLang]) == null ? void 0 : _b[field]) || "";
323  };
324  const handleAutoTranslate = async () => {
325    if (!form.title || !form.content) return alert("Please enter title and content first.");
326    setIsTranslating(true);
327    try {
328      const targetLangs = locales.filter((l) => l.code !== "en").map((l) => l.code);
329      if (targetLangs.length === 0) {
330        alert("No other active languages found to translate to.");
331        return;
332      }
333      const prompt = `Translate the following article title and content into these languages: ${targetLangs.join(", ")}.
334            
335            Title: ${form.title}
336            Content: ${form.content}
337            
338            Return a JSON object where keys are language codes and values are objects with "title" and "content".
339            Example: { "es": { "title": "...", "content": "..." }, "ja": { ... } }
340            Maintain Markdown formatting in content.`;
341      const response = await ai.models.generateContent({
342        model: "gemini-3-flash-preview",
343        contents: prompt
344      });
345      const jsonStr = (response.text || "").replace(/^```json/, "").replace(/^```/, "").replace(/```$/, "").trim();
346      const translations = JSON.parse(jsonStr);
347      setForm((prev) => ({
348        ...prev,
349        translations: { ...prev.translations, ...translations }
350      }));
351      alert(`Translated into ${Object.keys(translations).length} languages.`);
352    } catch (e) {
353      console.error(e);
354      alert("Translation failed. Check API Key or try again.");
355    } finally {
356      setIsTranslating(false);
357    }
358  };
359  if (!article && article !== null) return null;
360  return /* @__PURE__ */ jsxRuntimeExports.jsx(Drawer, { isOpen: !!article || article === null, onClose, title: isEdit ? "Edit Article" : "New Article", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [
361    /* @__PURE__ */ jsxRuntimeExports.jsx(
362      LanguageTabs,
363      {
364        activeLang,
365        setActiveLang,
366        locales,
367        hasTranslation: (code) => {
368          var _a2;
369          return !!((_a2 = form.translations) == null ? void 0 : _a2[code]);
370        }
371      }
372    ),
373    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
374      /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "block text-xs font-bold text-zinc-500 uppercase mb-1", children: [
375        "Title (",
376        activeLang === "default" ? "English" : activeLang,
377        ")"
378      ] }),
379      /* @__PURE__ */ jsxRuntimeExports.jsx(
380        "input",
381        {
382          value: getValue("title"),
383          onChange: (e) => updateTranslation("title", e.target.value),
384          className: "w-full bg-zinc-50 dark:bg-zinc-950 border border-zinc-300 dark:border-zinc-800 rounded p-2 text-sm outline-none focus:border-indigo-500 text-zinc-900 dark:text-white",
385          placeholder: "How to..."
386        }
387      )
388    ] }),
389    activeLang === "default" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
390      /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-xs font-bold text-zinc-500 uppercase mb-1", children: "Category" }),
391      /* @__PURE__ */ jsxRuntimeExports.jsx(
392        "select",
393        {
394          value: form.categoryId,
395          onChange: (e) => setForm({ ...form, categoryId: e.target.value }),
396          className: "w-full bg-zinc-50 dark:bg-zinc-950 border border-zinc-300 dark:border-zinc-800 rounded p-2 text-sm outline-none focus:border-indigo-500 text-zinc-900 dark:text-white",
397          children: categories.map((c) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: c.id, children: c.title }, c.id))
398        }
399      )
400    ] }),
401    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
402      /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-xs font-bold text-zinc-500 uppercase mb-1", children: "Content (Markdown)" }),
403      /* @__PURE__ */ jsxRuntimeExports.jsx(
404        "textarea",
405        {
406          value: getValue("content"),
407          onChange: (e) => updateTranslation("content", e.target.value),
408          className: "w-full bg-zinc-50 dark:bg-zinc-950 border border-zinc-300 dark:border-zinc-800 rounded p-3 text-sm outline-none focus:border-indigo-500 text-zinc-900 dark:text-white h-60 resize-none font-mono",
409          placeholder: "Write your article content here..."
410        }
411      )
412    ] }),
413    activeLang === "default" && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
414      /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
415        "button",
416        {
417          onClick: handleAutoTranslate,
418          disabled: isTranslating,
419          className: "flex items-center gap-2 px-3 py-1.5 bg-indigo-50 dark:bg-indigo-900/20 text-indigo-600 dark:text-indigo-400 rounded-lg text-xs font-bold hover:bg-indigo-100 dark:hover:bg-indigo-900/40 transition-colors disabled:opacity-50",
420          children: [
421            /* @__PURE__ */ jsxRuntimeExports.jsx(Sparkles, { size: 14, className: isTranslating ? "animate-spin" : "" }),
422            isTranslating ? "Translating..." : "Auto-Translate All"
423          ]
424        }
425      ) }),
426      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-4 p-3 bg-zinc-100 dark:bg-zinc-800 rounded-lg", children: [
427        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
428          /* @__PURE__ */ jsxRuntimeExports.jsx(
429            "input",
430            {
431              type: "checkbox",
432              checked: form.isPublished,
433              onChange: (e) => setForm({ ...form, isPublished: e.target.checked }),
434              className: "rounded text-indigo-600 focus:ring-indigo-500"
435            }
436          ),
437          /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-sm font-medium text-zinc-900 dark:text-white", children: "Published" })
438        ] }),
439        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
440          /* @__PURE__ */ jsxRuntimeExports.jsx(
441            "input",
442            {
443              type: "checkbox",
444              checked: form.isHidden,
445              onChange: (e) => setForm({ ...form, isHidden: e.target.checked }),
446              className: "rounded text-indigo-600 focus:ring-indigo-500"
447            }
448          ),
449          /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-sm font-medium text-zinc-900 dark:text-white", children: "Hidden" })
450        ] })
451      ] })
452    ] }),
453    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2 pt-4", children: [
454      /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: onClose, className: "flex-1 px-4 py-2 rounded-lg border border-zinc-300 dark:border-zinc-700 font-bold text-zinc-600 dark:text-zinc-400 hover:bg-zinc-50 dark:hover:bg-zinc-800", children: "Cancel" }),
455      /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { onClick: handleSave, className: "flex-1 px-4 py-2 rounded-lg bg-indigo-600 hover:bg-indigo-700 text-white font-bold flex items-center justify-center gap-2", children: [
456        /* @__PURE__ */ jsxRuntimeExports.jsx(Save, { size: 16 }),
457        " Save"
458      ] })
459    ] })
460  ] }) });
461};
462const HelpCenterManager = () => {
463  const [categories, setCategories] = reactExports.useState([]);
464  const [articles, setArticles] = reactExports.useState([]);
465  const [activeTab, setActiveTab] = reactExports.useState("categories");
466  const [editingCategory, setEditingCategory] = reactExports.useState(void 0);
467  const [editingArticle, setEditingArticle] = reactExports.useState(void 0);
468  const [deleteTarget, setDeleteTarget] = reactExports.useState(null);
469  reactExports.useEffect(() => {
470    loadData();
471  }, []);
472  const loadData = async () => {
473    const cats = await api.getHelpCategories();
474    const arts = await api.getHelpArticles();
475    setCategories([...cats]);
476    setArticles([...arts]);
477  };
478  const handleDeleteCategory = (cat) => {
479    setDeleteTarget({ type: "category", id: cat.id, name: cat.title });
480  };
481  const handleDeleteArticle = (art) => {
482    setDeleteTarget({ type: "article", id: art.id, name: art.title });
483  };
484  const handleConfirmDelete = async () => {
485    if (!deleteTarget) return;
486    if (deleteTarget.type === "category") {
487      await api.deleteHelpCategory(deleteTarget.id);
488    } else {
489      await api.deleteHelpArticle(deleteTarget.id);
490    }
491    loadData();
492    setDeleteTarget(null);
493  };
494  const handleToggleCategoryHidden = async (cat) => {
495    await api.saveHelpCategory({ ...cat, isHidden: !cat.isHidden });
496    loadData();
497  };
498  const handleToggleArticleHidden = async (art) => {
499    await api.saveHelpArticle({ ...art, isHidden: !art.isHidden });
500    loadData();
501  };
502  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "h-full flex flex-col space-y-6", children: [
503    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center bg-white dark:bg-zinc-900 p-4 rounded-xl border border-zinc-200 dark:border-zinc-800 shadow-sm", children: [
504      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
505        /* @__PURE__ */ jsxRuntimeExports.jsxs("h2", { className: "text-xl font-bold text-zinc-900 dark:text-white flex items-center gap-2", children: [
506          /* @__PURE__ */ jsxRuntimeExports.jsx(CircleQuestionMark, { className: "text-indigo-500" }),
507          " Resource Center"
508        ] }),
509        /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-zinc-500 dark:text-zinc-400", children: "Manage categories and knowledge base articles." })
510      ] }),
511      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex bg-zinc-100 dark:bg-zinc-800 p-1 rounded-lg", children: [
512        /* @__PURE__ */ jsxRuntimeExports.jsxs(
513          "button",
514          {
515            onClick: () => setActiveTab("categories"),
516            className: `flex items-center gap-2 px-4 py-2 rounded-md text-sm font-bold transition-all ${activeTab === "categories" ? "bg-white dark:bg-zinc-700 shadow text-indigo-600 dark:text-indigo-400" : "text-zinc-500 hover:text-zinc-900 dark:hover:text-white"}`,
517            children: [
518              /* @__PURE__ */ jsxRuntimeExports.jsx(Layers, { size: 16 }),
519              " Categories"
520            ]
521          }
522        ),
523        /* @__PURE__ */ jsxRuntimeExports.jsxs(
524          "button",
525          {
526            onClick: () => setActiveTab("articles"),
527            className: `flex items-center gap-2 px-4 py-2 rounded-md text-sm font-bold transition-all ${activeTab === "articles" ? "bg-white dark:bg-zinc-700 shadow text-indigo-600 dark:text-indigo-400" : "text-zinc-500 hover:text-zinc-900 dark:hover:text-white"}`,
528            children: [
529              /* @__PURE__ */ jsxRuntimeExports.jsx(BookOpen, { size: 16 }),
530              " Articles"
531            ]
532          }
533        )
534      ] })
535    ] }),
536    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 bg-white dark:bg-zinc-900 rounded-xl border border-zinc-200 dark:border-zinc-800 overflow-hidden flex flex-col", children: [
537      activeTab === "categories" && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
538        /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-4 border-b border-zinc-200 dark:border-zinc-800 flex justify-end", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { onClick: () => setEditingCategory(null), className: "flex items-center gap-2 px-4 py-2 bg-indigo-600 hover:bg-indigo-700 text-white rounded-lg text-sm font-bold", children: [
539          /* @__PURE__ */ jsxRuntimeExports.jsx(Plus, { size: 16 }),
540          " Add Category"
541        ] }) }),
542        /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 overflow-auto p-4 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4", children: categories.map((cat) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `border border-zinc-200 dark:border-zinc-800 rounded-xl p-4 flex flex-col justify-between hover:border-indigo-300 dark:hover:border-indigo-700 transition-colors ${cat.isHidden ? "opacity-60 bg-zinc-50 dark:bg-zinc-950 border-dashed" : ""}`, children: [
543          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
544            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 mb-2", children: [
545              /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `p-2 rounded-lg ${cat.colorClass}`, children: /* @__PURE__ */ jsxRuntimeExports.jsx(CircleQuestionMark, { size: 20 }) }),
546              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
547                /* @__PURE__ */ jsxRuntimeExports.jsxs("h3", { className: "font-bold text-zinc-900 dark:text-white flex items-center gap-2", children: [
548                  cat.title,
549                  cat.isHidden && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { title: "Hidden from public view", children: /* @__PURE__ */ jsxRuntimeExports.jsx(EyeOff, { size: 14, className: "text-zinc-400" }) })
550                ] }),
551                /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-500", children: cat.id })
552              ] })
553            ] }),
554            /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-zinc-600 dark:text-zinc-400 line-clamp-2 mb-4", children: cat.description })
555          ] }),
556          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center border-t border-zinc-100 dark:border-zinc-800 pt-3", children: [
557            /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs text-zinc-400 font-mono", children: [
558              "Order: ",
559              cat.order
560            ] }),
561            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
562              /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => handleToggleCategoryHidden(cat), className: "p-1.5 text-zinc-500 hover:bg-zinc-100 dark:hover:bg-zinc-800 rounded", title: cat.isHidden ? "Unhide" : "Hide", children: cat.isHidden ? /* @__PURE__ */ jsxRuntimeExports.jsx(EyeOff, { size: 14 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Eye, { size: 14 }) }),
563              /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => setEditingCategory(cat), className: "p-1.5 text-zinc-500 hover:bg-zinc-100 dark:hover:bg-zinc-800 rounded", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Pen, { size: 14 }) }),
564              /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => handleDeleteCategory(cat), className: "p-1.5 text-zinc-500 hover:text-red-500 hover:bg-red-50 dark:hover:bg-red-900/20 rounded", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { size: 14 }) })
565            ] })
566          ] })
567        ] }, cat.id)) })
568      ] }),
569      activeTab === "articles" && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
570        /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-4 border-b border-zinc-200 dark:border-zinc-800 flex justify-end", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { onClick: () => setEditingArticle(null), className: "flex items-center gap-2 px-4 py-2 bg-indigo-600 hover:bg-indigo-700 text-white rounded-lg text-sm font-bold", children: [
571          /* @__PURE__ */ jsxRuntimeExports.jsx(Plus, { size: 16 }),
572          " New Article"
573        ] }) }),
574        /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 overflow-auto", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("table", { className: "w-full text-left text-sm", children: [
575          /* @__PURE__ */ jsxRuntimeExports.jsx("thead", { className: "bg-zinc-50 dark:bg-zinc-950 text-xs font-bold text-zinc-500 uppercase border-b border-zinc-200 dark:border-zinc-800", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("tr", { children: [
576            /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "px-6 py-3", children: "Title" }),
577            /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "px-6 py-3", children: "Category" }),
578            /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "px-6 py-3", children: "Status" }),
579            /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "px-6 py-3", children: "Locales" }),
580            /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "px-6 py-3 text-right", children: "Actions" })
581          ] }) }),
582          /* @__PURE__ */ jsxRuntimeExports.jsxs("tbody", { className: "divide-y divide-zinc-100 dark:divide-zinc-800", children: [
583            articles.map((art) => {
584              var _a;
585              return /* @__PURE__ */ jsxRuntimeExports.jsxs("tr", { className: `hover:bg-zinc-50 dark:hover:bg-zinc-800/50 transition-colors ${art.isHidden ? "opacity-60 bg-zinc-50/50 dark:bg-zinc-900/50" : ""}`, children: [
586                /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "px-6 py-4 font-medium text-zinc-900 dark:text-white", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
587                  art.title,
588                  art.isHidden && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { title: "Hidden", children: /* @__PURE__ */ jsxRuntimeExports.jsx(EyeOff, { size: 14, className: "text-zinc-400" }) })
589                ] }) }),
590                /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "px-6 py-4 text-zinc-500", children: ((_a = categories.find((c) => c.id === art.categoryId)) == null ? void 0 : _a.title) || art.categoryId }),
591                /* @__PURE__ */ jsxRuntimeExports.jsxs("td", { className: "px-6 py-4", children: [
592                  art.isPublished ? /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 rounded-full bg-emerald-100 text-emerald-700 text-xs font-bold", children: [
593                    /* @__P
593URE__ */ jsxRuntimeExports.jsx(CircleCheck, { size: 12 }),
594                    " Published"
595                  ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 rounded-full bg-zinc-200 text-zinc-600 text-xs font-bold", children: "Draft" }),
596                  art.isHidden && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ml-2 inline-flex items-center gap-1 px-2 py-0.5 rounded-full bg-amber-100 text-amber-700 text-xs font-bold", children: [
597                    /* @__PURE__ */ jsxRuntimeExports.jsx(EyeOff, { size: 12 }),
598                    " Hidden"
599                  ] })
600                ] }),
601                /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-1", children: [
602                  art.translations && Object.keys(art.translations).map((lang) => /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] uppercase font-mono bg-zinc-100 dark:bg-zinc-800 px-1 rounded text-zinc-500", children: lang }, lang)),
603                  (!art.translations || Object.keys(art.translations).length === 0) && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-400 text-xs", children: "-" })
604                ] }) }),
605                /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "px-6 py-4 text-right", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-end gap-2", children: [
606                  /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => handleToggleArticleHidden(art), className: "p-1.5 text-zinc-500 hover:bg-zinc-200 dark:hover:bg-zinc-700 rounded", title: art.isHidden ? "Unhide" : "Hide", children: art.isHidden ? /* @__PURE__ */ jsxRuntimeExports.jsx(EyeOff, { size: 14 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Eye, { size: 14 }) }),
607                  /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => setEditingArticle(art), className: "p-1.5 text-zinc-500 hover:bg-zinc-200 dark:hover:bg-zinc-700 rounded", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Pen, { size: 14 }) }),
608                  /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => handleDeleteArticle(art), className: "p-1.5 text-zinc-500 hover:text-red-500 hover:bg-red-50 dark:hover:bg-red-900/20 rounded", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { size: 14 }) })
609                ] }) })
610              ] }, art.id);
611            }),
612            articles.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("tr", { children: /* @__PURE__ */ jsxRuntimeExports.jsx("td", { colSpan: 5, className: "p-8 text-center text-zinc-500", children: "No articles found." }) })
613          ] })
614        ] }) })
615      ] })
616    ] }),
617    editingCategory !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(CategoryForm, { category: editingCategory, onClose: () =>
617 setEditingCategory(void 0), onRefresh: loadData }),
618    editingArticle !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(ArticleForm, { article: editingArticle, categories, onClose: () => setEditingArticle(void 0), onRefresh: loadData }),
619    /* @__PURE__ */ jsxRuntimeExports.jsx(
620      DeleteConfirmationModal,
621      {
622        isOpen: !!deleteTarget,
623        onClose: () => setDeleteTarget(null),
624        onConfirm: handleConfirmDelete,
625        title: (deleteTarget == null ? void 0 : deleteTarget.type) === "category" ? "Delete Category?" : "Delete Article?",
626        message: (deleteTarget == null ? void 0 : deleteTarget.type) === "category" ? `Are you sure you want to delete "${deleteTarget == null ? void 0 : deleteTarget.name}"? Articles in this category will not be deleted but may become orphaned.` : `Are you sure you want to delete "${deleteTarget == null ? void 0 : deleteTarget.name}"? This action cannot be undone.`
627      }
628    )
629  ] });
630};
631export {
632  HelpCenterManager as default
633};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.