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.