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.