PageSourceSearch

https://www.hamienet.com/assets/EmailSettings-CBkm3rKS.js

js hamienet.com collected 2026-09-24 19:00:33 UTC 34,076 bytes, 564 lines download raw bytes

1import { r as reactExports, j as jsxRuntimeExports } from "./vendor-react-Bay9Y7Lb.js";
2import { a as api } from "./index-D0Bmh-UX.js";
3import { D as DevDebugInfo } from "./AdminShared-P_hor2hS.js";
4import { dX as Server, dz as LayoutTemplate, cT as Type, aZ as Mail, aY as TriangleAlert, bz as EyeOff, bA as Eye, cL as RefreshCw, cc as Save, bv as CircleCheckBig, dB as Paintbrush, cp as Settings2, bn as Globe, fL as Code, c3 as RotateCcw, fM as ReactQuill } from "./vendor-dVNaLJx_.js";
5import "./vendor-i18n-R-bMoYp_.js";
6const SUPPORTED_LANGUAGES = [
7  { code: "en", name: "English" },
8  { code: "zh-CN", name: "Simplified Chinese" },
9  { code: "zh-TW", name: "Traditional Chinese" },
10  { code: "ja", name: "Japanese" },
11  { code: "ko", name: "Korean" },
12  { code: "es", name: "Spanish" },
13  { code: "pt", name: "Portuguese" },
14  { code: "fr", name: "French" },
15  { code: "de", name: "German" },
16  { code: "it", name: "Italian" },
17  { code: "ru", name: "Russian" },
18  { code: "ar", name: "Arabic" },
19  { code: "id", name: "Indonesian" }
20];
21const EmailSettings = ({ activeRole }) => {
22  var _a;
23  const [activeTab, setActiveTab] = reactExports.useState("smtp");
24  const [config, setConfig] = reactExports.useState({
25    host: "",
26    port: 587,
27    secure: false,
28    auth: { user: "", pass: "" },
29    fromEmail: "[email protected]",
30    fromName: "HamieNET"
31  });
32  const [wrapperConfig, setWrapperConfig] = reactExports.useState({
33    primaryColor: "#4f46e5",
34    siteName: "HamieNET",
35    footerText: "HamieNET.com",
36    logoUrl: ""
37  });
38  const [templatesData, setTemplatesData] = reactExports.useState({ defaultTemplates: {}, overrides: {} });
39  const [selectedTemplate, setSelectedTemplate] = reactExports.useState("");
40  const [selectedLang, setSelectedLang] = reactExports.useState("en");
41  const [editorSubject, setEditorSubject] = reactExports.useState("");
42  const [editorBodyHtml, setEditorBodyHtml] = reactExports.useState("");
43  const [rawMode, setRawMode] = reactExports.useState(false);
44  const [loading, setLoading] = reactExports.useState(true);
45  const [saving, setSaving] = reactExports.useState(false);
46  const [testing, setTesting] = reactExports.useState(false);
47  const [testRecipient, setTestRecipient] = reactExports.useState("");
48  const [testResult, setTestResult] = reactExports.useState(null);
49  const [showPass, setShowPass] = reactExports.useState(false);
50  reactExports.useEffect(() => {
51    loadAllData();
52  }, []);
53  const loadAllData = async () => {
54    setLoading(true);
55    try {
56      const [smtp, wrapper, templates] = await Promise.all([
57        api.getSystemSetting("email_config"),
58        api.getEmailTemplateConfig(),
59        api.getEmailTemplates()
60      ]);
61      if (smtp && smtp.value) setConfig(smtp.value);
62      if (wrapper) setWrapperConfig(wrapper);
63      if (templates) {
64        setTemplatesData(templates);
65        const keys = Object.keys(templates.defaultTemplates);
66        if (keys.length > 0) setSelectedTemplate(keys[0]);
67      }
68    } catch (e) {
69      console.error("Failed to load email configs", e);
70    } finally {
71      setLoading(false);
72    }
73  };
74  reactExports.useEffect(() => {
75    if (!selectedTemplate || !templatesData.defaultTemplates[selectedTemplate]) return;
76    const defaults = templatesData.defaultTemplates[selectedTemplate];
77    const overrides = templatesData.overrides[selectedTemplate] || {};
78    const langData = overrides[selectedLang] || defaults[selectedLang] || defaults["en"];
79    setEditorSubject(langData.subject || "");
80    setEditorBodyHtml(langData.bodyHtml || "");
81  }, [selectedTemplate, selectedLang, templatesData]);
82  const handleSaveSMTP = async () => {
83    setSaving(true);
84    try {
85      await api.saveEmailConfig(config);
86      alert("SMTP Configuration saved successfully.");
87    } catch (e) {
88      alert("Failed to save SMTP configuration.");
89    } finally {
90      setSaving(false);
91    }
92  };
93  const handleSaveWrapper = async () => {
94    setSaving(true);
95    try {
96      await api.saveEmailTemplateConfig(wrapperConfig);
97      alert("Wrapper Configuration saved successfully.");
98    } catch (e) {
99      alert("Failed to save Wrapper configuration.");
100    } finally {
101      setSaving(false);
102    }
103  };
104  const handleSaveTemplate = async () => {
105    setSaving(true);
106    try {
107      await api.saveEmailTemplateOverride(selectedTemplate, selectedLang, editorSubject, editorBodyHtml);
108      const templates = await api.getEmailTemplates();
109      setTemplatesData(templates);
110      alert("Template saved successfully.");
111    } catch (e) {
112      alert("Failed to save Template.");
113    } finally {
114      setSaving(false);
115    }
116  };
117  const handleResetTemplate = async () => {
118    if (!confirm(`Are you sure you want to reset the ${selectedLang} translation for ${selectedTemplate} to default?`)) return;
119    setSaving(true);
120    try {
121      await api.resetEmailTemplateOverride(selectedTemplate, selectedLang);
122      const templates = await api.getEmailTemplates();
123      setTemplatesData(templates);
124    } catch (e) {
125      alert("Failed to reset Template.");
126    } finally {
127      setSaving(false);
128    }
129  };
130  const handleTest = async () => {
131    if (!testRecipient) return;
132    setTesting(true);
133    setTestResult(null);
134    try {
135      const result = await api.testEmailConfig(config, testRecipient);
136      setTestResult(result);
137    } catch (e) {
138      setTestResult({ success: false, message: e.message || "Unknown error" });
139    } finally {
140      setTesting(false);
141    }
142  };
143  if (loading) return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-10 text-center text-zinc-500", children: "Loading Configuration..." });
144  const hasOverride = ((_a = templatesData.overrides[selectedTemplate]) == null ? void 0 : _a[selectedLang]) !== void 0;
145  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-6 max-w-5xl mx-auto animate-in fade-in", children: [
146    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-xl p-1 shadow-sm", children: [
147      /* @__PURE__ */ jsxRuntimeExports.jsxs(
148        "button",
149        {
150          onClick: () => setActiveTab("smtp"),
151          className: `flex-1 flex justify-center items-center gap-2 py-3 px-4 rounded-lg text-sm font-bold transition-all ${activeTab === "smtp" ? "bg-zinc-100 dark:bg-zinc-800 text-zinc-900 dark:text-white shadow-sm" : "text-zinc-500 hover:text-zinc-700 dark:hover:text-zinc-300 hover:bg-zinc-50 dark:hover:bg-zinc-800/50"}`,
152          children: [
153            /* @__PURE__ */ jsxRuntimeExports.jsx(Server, { size: 18 }),
154            "SMTP Config"
155          ]
156        }
157      ),
158      /* @__PURE__ */ jsxRuntimeExports.jsxs(
159        "button",
160        {
161          onClick: () => setActiveTab("wrapper"),
162          className: `flex-1 flex justify-center items-center gap-2 py-3 px-4 rounded-lg text-sm font-bold transition-all ${activeTab === "wrapper" ? "bg-zinc-100 dark:bg-zinc-800 text-zinc-900 dark:text-white shadow-sm" : "text-zinc-500 hover:text-zinc-700 dark:hover:text-zinc-300 hover:bg-zinc-50 dark:hover:bg-zinc-800/50"}`,
163          children: [
164            /* @__PURE__ */ jsxRuntimeExports.jsx(LayoutTemplate, { size: 18 }),
165            "Wrapper Design"
166          ]
167        }
168      ),
169      /* @__PURE__ */ jsxRuntimeExports.jsxs(
170        "button",
171        {
172          onClick: () => setActiveTab("templates"),
173          className: `flex-1 flex justify-center items-center gap-2 py-3 px-4 rounded-lg text-sm font-bold transition-all ${activeTab === "templates" ? "bg-zinc-100 dark:bg-zinc-800 text-zinc-900 dark:text-white shadow-sm" : "text-zinc-500 hover:text-zinc-700 dark:hover:text-zinc-300 hover:bg-zinc-50 dark:hover:bg-zinc-800/50"}`,
174          children: [
175            /* @__PURE__ */ jsxRuntimeExports.jsx(Type, { size: 18 }),
176            "Email Templates"
177          ]
178        }
179      )
180    ] }),
181    activeTab === "smtp" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-xl p-6 shadow-sm", children: [
182      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 mb-6 pb-6 border-b border-zinc-100 dark:border-zinc-800", children: [
183        /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-12 h-12 bg-indigo-50 dark:bg-indigo-900/20 rounded-xl flex items-center justify-center text-indigo-600 dark:text-indigo-400", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Mail, { size: 24 }) }),
184        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
185          /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "text-xl font-bold text-zinc-900 dark:text-white", children: "SMTP Configuration" }),
186          /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-zinc-500", children: "Configure outbound email server credentials." })
187        ] })
188      ] }),
189      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mb-8 p-4 bg-blue-50 dark:bg-blue-900/10 border border-blue-200 dark:border-blue-800 rounded-xl flex gap-3", children: [
190        /* @__PURE__ */ jsxRuntimeExports.jsx(TriangleAlert, { className: "text-blue-600 dark:text-blue-400 shrink-0", size: 20 }),
191        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-sm text-blue-800 dark:text-blue-200", children: [
192          /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "font-bold mb-1", children: "Gmail / Google Workspace Tip:" }),
193          /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
194            "For Google accounts with 2FA enabled, you must use an ",
195            /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "App Password" }),
196            "."
197          ] })
198        ] })
199      ] }),
200      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-6 mb-6", children: [
201        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [
202          /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-sm font-bold uppercase text-zinc-500 tracking-wider", children: "Server Settings" }),
203          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
204            /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-xs font-bold text-zinc-700 dark:text-zinc-300 mb-1", children: "SMTP Host" }),
205            /* @__P
205URE__ */ jsxRuntimeExports.jsxs("div", { className: "relative", children: [
206              /* @__PURE__ */ jsxRuntimeExports.jsx(Server, { size: 14, className: "absolute left-3 top-1/2 -translate-y-1/2 text-zinc-400" }),
207              /* @__PURE__ */ jsxRuntimeExports.jsx(
208                "input",
209                {
210                  value: config.host,
211                  onChange: (e) => setConfig({ ...config, host: e.target.value }),
212                  placeholder: "smtp.gmail.com",
213                  className: "w-full pl-9 pr-3 py-2 bg-zinc-50 dark:bg-zinc-950 border border-zinc-300 dark:border-zinc-700 rounded-lg text-sm text-zinc-900 dark:text-white focus:ring-2 focus:ring-indigo-500 outline-none"
214                }
215              )
216            ] })
217          ] }),
218          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-4", children: [
219            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
220              /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-xs font-bold text-zinc-700 dark:text-zinc-300 mb-1", children: "Port" }),
221              /* @__PURE__ */ jsxRuntimeExports.jsx(
222                "input",
223                {
224                  type: "number",
225                  value: config.port,
226                  onChange: (e) => setConfig({ ...config, port: parseInt(e.target.value) }),
227                  className: "w-full px-3 py-2 bg-zinc-50 dark:bg-zinc-950 border border-zinc-300 dark:border-zinc-700 rounded-lg text-sm text-zinc-900 dark:text-white focus:ring-2 focus:ring-indigo-500 outline-none"
228                }
229              )
230            ] }),
231            /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-end pb-2", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex items-center gap-2 cursor-pointer select-none", children: [
232              /* @__PURE__ */ jsxRuntimeExports.jsx(
233                "input",
234                {
235                  type: "checkbox",
236                  checked: config.secure,
237                  onChange: (e) => setConfig({ ...config, secure: e.target.checked }),
238                  className: "rounded border-zinc-300 text-indigo-600 focus:ring-indigo-500"
239                }
240              ),
241              /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm text-zinc-700 dark:text-zinc-300 font-medium", children: "Use SSL/TLS" })
242            ] }) })
243          ] })
244        ] }),
245        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [
246          /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-sm font-bold uppercase text-zinc-500 tracking-wider", children: "Authentication" }),
247          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
248            /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-xs font-bold text-zinc-700 dark:text-zinc-300 mb-1", children: "Username / Email" }),
249            /* @__PURE__ */ jsxRuntimeExports.jsx(
250              "input",
251              {
252                value: config.auth.user,
253                onChange: (e) => setConfig({ ...config, auth: { ...config.auth, user: e.target.value } }),
254                className: "w-full px-3 py-2 bg-zinc-50 dark:bg-zinc-950 border border-zinc-300 dark:border-zinc-700 rounded-lg text-sm text-zinc-900 dark:text-white focus:ring-2 focus:ring-indigo-500 outline-none"
255              }
256            )
257          ] }),
258          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
259            /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-xs font-bold text-zinc-700 dark:text-zinc-300 mb-1", children: "Password / App Key" }),
260            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative", children: [
261              /* @__PURE__ */ jsxRuntimeExports.jsx(
262                "input",
263                {
264                  type: showPass ? "text" : "password",
265                  value: config.auth.pass,
266                  onChange: (e) => setConfig({ ...config, auth: { ...config.auth, pass: e.target.value } }),
267                  className: "w-full px-3 py-2 bg-zinc-50 dark:bg-zinc-950 border border-zinc-300 dark:border-zinc-700 rounded-lg text-sm text-zinc-900 dark:text-white focus:ring-2 focus:ring-indigo-500 outline-none pr-10"
268                }
269              ),
270              /* @__PURE__ */ jsxRuntimeExports.jsx(
271                "button",
272                {
273                  onClick: () => setShowPass(!showPass),
274                  className: "absolute right-3 top-1/2 -translate-y-1/2 text-zinc-400 hover:text-zinc-600 dark:hover:text-zinc-200",
275                  children: showPass ? /* @__PURE__ */ jsxRuntimeExports.jsx(EyeOff, { size: 16 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Eye, { size: 16 })
276                }
277              )
278            ] })
279          ] })
280        ] })
281      ] }),
282      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-t border-zinc-100 dark:border-zinc-800 pt-6", children: [
283        /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-sm font-bold uppercase text-zinc-500 tracking-wider mb-4", children: "Sender Details" }),
284        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-6", children: [
285          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
286            /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-xs font-bold text-zinc-700 dark:text-zinc-300 mb-1", children: "From Name" }),
287            /* @__PURE__ */ jsxRuntimeExports.jsx(
288              "input",
289              {
290                value: config.fromName,
291                onChange: (e) => setConfig({ ...config, fromName: e.target.value }),
292                className: "w-full px-3 py-2 bg-zinc-50 dark:bg-zinc-950 border border-zinc-300 dark:border-zinc-700 rounded-lg text-sm text-zinc-900 dark:text-white focus:ring-2 focus:ring-indigo-500 outline-none"
293              }
294            )
295          ] }),
296          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
297            /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-xs font-bold text-zinc-700 dark:text-zinc-300 mb-1", children: "From Email" }),
298            /* @__PURE__ */ jsxRuntimeExports.jsx(
299              "input",
300              {
301                value: config.fromEmail,
302                onChange: (e) => setConfig({ ...config, fromEmail: e.target.value }),
303                className: "w-full px-3 py-2 bg-zinc-50 dark:bg-zinc-950 border border-zinc-300 dark:border-zinc-700 rounded-lg text-sm text-zinc-900 dark:text-white focus:ring-2 focus:ring-indigo-500 outline-none"
304              }
305            )
306          ] })
307        ] })
308      ] }),
309      /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-8 flex justify-end", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
310        "button",
311        {
312          onClick: handleSaveSMTP,
313          disabled: saving,
314          className: "px-6 py-2 bg-indigo-600 hover:bg-indigo-700 text-white rounded-lg font-bold text-sm flex items-center gap-2 shadow-lg shadow-indigo-500/20 disabled:opacity-50",
315          children: [
316            saving ? /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { className: "animate-spin", size: 16 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Save, { size: 16 }),
317            "Save SMTP Config"
318          ]
319        }
320      ) }),
321      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-8 pt-8 border-t border-zinc-100 dark:border-zinc-800", children: [
322        /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "font-bold text-zinc-900 dark:text-white mb-4", children: "Test Configuration" }),
323        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-3", children: [
324          /* @__PURE__ */ jsxRuntimeExports.jsx(
325            "input",
326            {
327              type: "email",
328              placeholder: "[email protected]",
329              value: testRecipient,
330              onChange: (e) => setTestRecipient(e.target.value),
331              className: "flex-1 px-4 py-2 bg-zinc-50 dark:bg-zinc-950 border border-zinc-300 dark:border-zinc-700 rounded-lg text-sm outline-none focus:border-indigo-500 text-zinc-900 dark:text-white"
332            }
333          ),
334          /* @__PURE__ */ jsxRuntimeExports.jsx(
335            "button",
336            {
337              onClick: handleTest,
338              disabled: testing || !testRecipient,
339              className: "px-6 py-2 bg-zinc-200 dark:bg-zinc-800 hover:bg-zinc-300 dark:hover:bg-zinc-700 text-zinc-700 dark:text-zinc-300 rounded-lg font-bold text-sm flex items-center gap-2 disabled:opacity-50",
340              children: testing ? /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { className: "animate-spin", size: 16 }) : "Send Test Email"
341            }
342          )
343        ] }),
344        testResult && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `mt-4 p-4 rounded-lg flex items-start gap-3 ${testResult.success ? "bg-emerald-50 dark:bg-emerald-900/20 text-emerald-800 dark:text-emerald-200" : "bg-red-50 dark:bg-red-900/20 text-red-800 dark:text-red-200"}`, children: [
345          testResult.success ? /* @__PURE__ */ jsxRuntimeExports.jsx(CircleCheckBig, { className: "shrink-0 mt-0.5", size: 18 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(TriangleAlert, { className: "shrink-0 mt-0.5", size: 18 }),
346          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-sm font-medium", children: testResult.message })
347        ] })
348      ] })
349    ] }),
350    activeTab === "wrapper" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-xl p-6 shadow-sm", children: [
351      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 mb-6 pb-6 border-b border-zinc-100 dark:border-zinc-800", children: [
352        /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-12 h-12 bg-pink-50 dark:bg-pink-900/20 rounded-xl flex items-center justify-center text-pink-600 dark:text-pink-400", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Paintbrush, { size: 24 }) }),
353        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
354          /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "text-xl font-bold text-zinc-900 dark:text-white", children: "Email Design Wrapper" }),
355          /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-zinc-500", children: "Configure how the outer frame of all emails appears." })
356        ] })
357      ] }),
358      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 gap-6", children: [
359        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
360          /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-sm font-bold text-zinc-700 dark:text-zinc-300 mb-1", children: "Site Name" }),
361          /* @__PURE__ */ jsxRuntimeExports.jsx(
362            "input",
363            {
364              value: wrapperConfig.siteName,
365              onChange: (e) => setWrapperConfig({ ...wrapperConfig, siteName: e.target.value }),
366              className: "w-full px-3 py-2 bg-zinc-50 dark:bg-zinc-950 border border-zinc-300 dark:border-zinc-700 rounded-lg text-sm text-zinc-900 dark:text-white outline-none"
367            }
368          )
369        ] }),
370        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
371          /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-sm font-bold text-zinc-700 dark:text-zinc-300 mb-1", children: "Logo Image URL" }),
372          /* @__PURE__ */ jsxRuntimeExports.jsx(
373            "input",
374            {
375              value: wrapperConfig.logoUrl,
376              onChange: (e) => setWrapperConfig({ ...wrapperConfig, logoUrl: e.target.value }),
377              placeholder: "https://example.com/logo.png",
378              className: "w-full px-3 py-2 bg-zinc-50 dark:bg-zinc-950 border border-zinc-300 dark:border-zinc-700 rounded-lg text-sm text-zinc-900 dark:text-white outline-none"
379            }
380          )
381        ] }),
382        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
383          /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-sm font-bold text-zinc-700 dark:text-zinc-300 mb-1", children: "Primary Color (Hex)" }),
384          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-3 items-center", children: [
385            /* @__PURE__ */ jsxRuntimeExports.jsx(
386              "input",
387              {
388                type: "color",
389                value: wrapperConfig.primaryColor,
390                onChange: (e) => setWrapperConfig({ ...wrapperConfig, primaryColor: e.target.value }),
391                className: "w-12 h-12 rounded cursor-pointer border-0 bg-transparent p-0"
392              }
393            ),
394            /* @__PURE__ */ jsxRuntimeExports.jsx(
395              "input",
396              {
397                value: wrapperConfig.primaryColor,
398                onChange: (e) => setWrapperConfig({ ...wrapperConfig, primaryColor: e.target.value }),
399                className: "flex-1 px-3 py-2 bg-zinc-50 dark:bg-zinc-950 border border-zinc-300 dark:border-zinc-700 rounded-lg text-sm text-zinc-900 dark:text-white outline-none"
400              }
401            )
402          ] })
403        ] }),
404        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
405          /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-sm font-bold text-zinc-700 dark:text-zinc-300 mb-1", children: "Footer Text" }),
406          /* @__PURE__ */ jsxRuntimeExports.jsx(
407            "input",
408            {
409              value: wrapperConfig.footerText,
410              onChange: (e) => setWrapperConfig({ ...wrapperConfig, footerText: e.target.value }),
411              className: "w-full px-3 py-2 bg-zinc-50 dark:bg-zinc-950 border border-zinc-300 dark:border-zinc-700 rounded-lg text-sm text-zinc-900 dark:text-white outline-none"
412            }
413          )
414        ] })
415      ] }),
416      /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-8 flex justify-end", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
417        "button",
418        {
419          onClick: handleSaveWrapper,
420          disabled: saving,
421          className: "px-6 py-2 bg-pink-600 hover:bg-pink-700 text-white rounded-lg font-bold text-sm flex items-center gap-2 shadow-lg shadow-pink-500/20 disabled:opacity-50",
422          children: [
423            saving ? /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { className: "animate-spin", size: 16 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Save, { size: 16 }),
424            "Save Design Config"
425          ]
426        }
427      ) })
428    ] }),
429    activeTab === "templates" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-xl p-6 shadow-sm", children: [
430      /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-between mb-6 pb-6 border-b border-zinc-100 dark:border-zinc-800", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3", children: [
431        /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-12 h-12 bg-emerald-50 dark:bg-emerald-900/20 rounded-xl flex items-center justify-center text-emerald-600 dark:text-emerald-400", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Settings2, { size: 24 }) }),
432        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
433          /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "text-xl font-bold text-zinc-900 dark:text-white", children: "Manage Templates" }),
434          /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-zinc-500", children: "Edit email subjects and contents for all languages." })
435        ] })
436      ] }) }),
437      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 md:grid-cols-4 gap-6", children: [
438        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-6", children: [
439          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
440            /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-xs font-bold text-zinc-700 dark:text-zinc-300 mb-2 uppercase tracking-wide", children: "Template" }),
441            /* @__PURE__ */ jsxRuntimeExports.jsx(
442              "select",
443              {
444                value: selectedTemplate,
445                onChange: (e) => setSelectedTemplate(e.target.value),
446                className: "w-full text-zinc-800 dark:text-zinc-200 bg-zinc-50 dark:bg-zinc-950 border border-zinc-300 dark:border-zinc-700 rounded-lg px-3 py-2 text-sm outline-none focus:border-emerald-500",
447                children: Object.keys(templatesData.defaultTemplates).map((t) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: t, children: t }, t))
448              }
449            )
450          ] }),
451          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
452            /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-xs font-bold text-zinc-700 dark:text-zinc-300 mb-2 uppercase tracking-wide", children: "Language" }),
453            /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-1", children: SUPPORTED_LANGUAGES.map((lang) => {
454              var _a2;
455              const isOverride = ((_a2 = templatesData.overrides[selectedTemplate]) == null ? void 0 : _a2[lang.code]) !== void 0;
456              return /* @__PURE__ */ jsxRuntimeExports.jsxs(
457                "button",
458                {
459                  onClick: () => setSelectedLang(lang.code),
460                  className: `w-full text-left px-3 py-2 rounded-lg text-sm font-medium transition-colors flex items-center justify-between ${selectedLang === lang.code ? "bg-emerald-100 dark:bg-emerald-900/30 text-emerald-800 dark:text-emerald-300" : "hover:bg-zinc-100 dark:hover:bg-zinc-800 text-zinc-700 dark:text-zinc-400"}`,
461                  children: [
462                    /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-2", children: [
463                      /* @__PURE__ */ jsxRuntimeExports.jsx(Globe, { size: 14 }),
464                      lang.name
465                    ] }),
466                    isOverride && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-2 h-2 rounded-full bg-emerald-500", title: "Custom override exists" })
467                  ]
468                },
469                lang.code
470              );
471            }) })
472          ] })
473        ] }),
474        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "md:col-span-3 space-y-4 border-l border-zinc-100 dark:border-zinc-800 pl-0 md:pl-6", children: [
475          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center bg-zinc-50 dark:bg-zinc-800/50 p-3 rounded-lg", children: [
476            /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-sm font-bold text-zinc-700 dark:text-zinc-300", children: [
477              "Editing: ",
478              selectedTemplate,
479              " (",
480              selectedLang,
481              ")"
482            ] }),
483            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3", children: [
484              /* @__PURE__ */ jsxRuntimeExports.jsxs(
485                "button",
486                {
487                  onClick: () => setRawMode(!rawMode),
488                  className: "text-xs flex items-center gap-1 font-bold text-zinc-500 hover:text-zinc-800 dark:hover:text-zinc-200",
489                  children: [
490                    /* @__PURE__ */ jsxRuntimeExports.jsx(Code, { size: 14 }),
491                    rawMode ? "Visual Editor" : "Raw HTML"
492                  ]
493                }
494              ),
495              hasOverride && /* @__PURE__ */ jsxRuntimeExports.jsxs(
496                "button",
497                {
498                  onClick: handleResetTemplate,
499                  className: "text-xs flex items-center gap-1 font-bold text-red-500 hover:text-red-700",
500                  children: [
501                    /* @__PURE__ */ jsxRuntimeExports.jsx(RotateCcw, { size: 14 }),
502                    "Reset to Default"
503                  ]
504                }
505              )
506            ] })
507          ] }),
508          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
509            /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-sm font-bold text-zinc-700 dark:text-zinc-300 mb-1", children: "Subject" }),
510            /* @__PURE__ */ jsxRuntimeExports.jsx(
511              "input",
512              {
513                value: editorSubject,
514                onChange: (e) => setEditorSubject(e.target.value),
515                className: "w-full px-3 py-2 bg-white dark:bg-zinc-950 border border-zinc-300 dark:border-zinc-700 rounded-lg text-sm text-zinc-900 dark:text-white outline-none focus:border-emerald-500"
516              }
517            )
518          ] }),
519          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1", children: [
520            /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-sm font-bold text-zinc-700 dark:text-zinc-300 mb-1", children: "Body Content" }),
521            rawMode ? /* @__PURE__ */ jsxRuntimeExports.jsx(
522              "textarea",
523              {
524                value: editorBodyHtml,
525                onChange: (e) => setEditorBodyHtml(e.target.value),
526                className: "w-full h-80 px-4 py-3 bg-zinc-900 text-emerald-400 font-mono border border-zinc-700 rounded-lg text-sm outline-none"
527              }
528            ) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "bg-white dark:bg-zinc-950 border border-zinc-300 dark:border-zinc-700 rounded-lg overflow-hidden [&_.ql-toolbar]:border-0 [&_.ql-toolbar]:border-b [&_.ql-toolbar]:border-zinc-200 dark:[&_.ql-toolbar]:border-zinc-700 [&_.ql-container]:border-0 [&_.ql-editor]:min-h-[300px]", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
529              ReactQuill,
530              {
531                theme: "snow",
532                value: editorBodyHtml,
533                onChange: setEditorBodyHtml
534              }
535            ) })
536          ] }),
537          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center mt-6", children: [
538            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs text-zinc-500 max-w-sm", children: [
539              "Variables like ",
540              /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "bg-zinc-100 dark:bg-zinc-800 px-1 rounded", children: `{{username}}` }),
541              " will be replaced automatically during sending."
542            ] }),
543            /* @__PURE__ */ jsxRuntimeExports.jsxs(
544              "button",
545              {
546                onClick: handleSaveTemplate,
547                disabled: saving,
548                className: "px-6 py-2 bg-emerald-600 hover:bg-emerald-700 text-white rounded-lg font-bold text-sm flex items-center gap-2 shadow-lg shadow-emerald-500/20 disabled:opacity-50",
549                children: [
550                  saving ? /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { className: "animate-spin", size: 16 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Save, { size: 16 }),
551                  "Save Override"
552                ]
553              }
554            )
555          ] })
556        ] })
557      ] })
558    ] }),
559    /* @__PURE__ */ jsxRuntimeExports.jsx(DevDebugInfo, { table: "SystemSetting", keyName: "email_template_config", value: templatesData, isSuperAdmin: activeRole == null ? void 0 : activeRole.isSuperAdmin })
560  ] });
561};
562export {
563  EmailSettings as default
564};

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.