1import { r as reactExports, j as jsxRuntimeExports } from "./vendor-react-Bay9Y7Lb.js"; 2import { a as api } from "./index-D0Bmh-UX.js"; 3import { a as getAllActionCosts, c as creditRules } from "./credit-rules-8PgauDOD.js"; 4import { D as DevDebugInfo } from "./AdminShared-P_hor2hS.js"; 5import { a$ as Shield, bQ as ExternalLink, b5 as Trash2, bn as Globe, ce as Plus, cL as RefreshCw, cc as Save } from "./vendor-dVNaLJx_.js"; 6import "./vendor-i18n-R-bMoYp_.js"; 7const CATEGORY_SHORTCUTS = { 8 "Downloads": "/", 9 "MIDI Conversion": "/converter", 10 "Studio & Processing": "/audio-digitizer" 11}; 12const CreditManager = ({ activeRole }) => { 13 var _a, _b; 14 const [config, setConfig] = reactExports.useState(null); 15 const [filterConfig, setFilterConfig] = reactExports.useState(null); 16 const [activeTab, setActiveTab] = reactExports.useState("credits"); 17 const [activeCategory, setActiveCategory] = reactExports.useState(""); 18 const [loading, setLoading] = reactExports.useState(true); 19 const [saving, setSaving] = reactExports.useState(false); 20 reactExports.useEffect(() => { 21 Promise.all([loadConfig(), loadFilterConfig()]); 22 }, []); 23 const loadFilterConfig = async () => { 24 const saved = await api.getSystemSetting("content_filter_config"); 25 if (saved) setFilterConfig(saved.value); 26 }; 27 const loadConfig = async () => { 28 setLoading(true); 29 const saved = await api.getSystemSetting("credit_config"); 30 if (saved && saved.value) { 31 let currentConfig = { ...saved.value }; 32 if (!Array.isArray(currentConfig.allotments)) { 33 currentConfig.allotments = []; 34 } 35 if (!currentConfig.allotments.some((a) => a.id === "guest")) { 36 const guestTier = { 37 id: "guest", 38 name: "Guest (Unregistered)", 39 base: 15, 40 trustTiers: [] 41 }; 42 currentConfig.allotments = [guestTier, ...currentConfig.allotments]; 43 console.log("[CreditManager] Auto-repaired missing Guest tier."); 44 } 45 setConfig(currentConfig); 46 } 47 setLoading(false); 48 }; 49 const handleSave = async () => { 50 setSaving(true); 51 try { 52 await Promise.all([ 53 api.saveSystemSetting("credit_config", config), 54 api.saveSystemSetting("content_filter_config", filterConfig) 55 ]); 56 alert("Configuration saved successfully."); 57 } catch (e) { 58 alert("Failed to save configuration."); 59 } finally { 60 setSaving(false); 61 } 62 }; 63 const updateTierField = (tierIndex, field, value) => { 64 setConfig((prev) => { 65 const newAllotments = [...prev.allotments]; 66 newAllotments[tierIndex] = { ...newAllotments[tierIndex], [field]: value }; 67 return { ...prev, allotments: newAllotments }; 68 }); 69 }; 70 const updateBonusTierField = (tierIndex, bonusIndex, field, value) => { 71 setConfig((prev) => { 72 const newAllotments = [...prev.allotments]; 73 const newTrustTiers = [...newAllotments[tierIndex].trustTiers]; 74 newTrustTiers[bonusIndex] = { ...newTrustTiers[bonusIndex], [field]: value }; 75 newAllotments[tierIndex] = { ...newAllotments[tierIndex], trustTiers: newTrustTiers }; 76 return { ...prev, allotments: newAllotments }; 77 }); 78 }; 79 const handleAddLevel = () => { 80 const newLevel = { 81 id: `new-level-${Date.now()}`, 82 name: "New Level", 83 base: 0, 84 trustTiers: [] 85 }; 86 setConfig((prev) => ({ ...prev, allotments: [...prev.allotments, newLevel] })); 87 }; 88 const handleRemoveLevel = (index) => { 89 if (!confirm("Are you sure you want to remove this entire user level?")) return; 90 setConfig((prev) => ({ ...prev, allotments: prev.allotments.filter((_, i) => i !== index) })); 91 }; 92 const handleAddBonusTier = (tierIndex) => { 93 const newTrustTiers = [...config.allotments[tierIndex].trustTiers, { score: 0, credits: 0 }]; 94 updateTierField(tierIndex, "trustTiers", newTrustTiers); 95 }; 96 const handleRemoveBonusTier = (tierIndex, bonusIndex) => { 97 if (!confirm("Remove this bonus tier?")) return; 98 const newTrustTiers = config.allotments[tierIndex].trustTiers.filter((_, i) => i !== bonusIndex); 99 updateTierField(tierIndex, "trustTiers", newTrustTiers); 100 }; 101 const handleInitialize = async () => { 102 const defaultCosts = {};
103 Object.entries(creditRules.actions).forEach(([key, action]) => { 104 defaultCosts[key] = action.defaultCost; 105 }); 106 const defaultConfig = { 107 costs: defaultCosts, 108 allotments: [ 109 { 110 id: "guest", 111 name: "Guest (Unregistered)", 112 base: 15, 113 trustTiers: [] 114 }, 115 { 116 id: "free", 117 name: "Free Membership", 118 base: 25, 119 trustTiers: [ 120 { score: 50, credits: 25 }, 121 { score: 90, credits: 50 } 122 ] 123 }, 124 { 125 id: "gold", 126 name: "Gold Supporter", 127 base: 250, 128 trustTiers: [] 129 }, 130 { 131 id: "premium", 132 name: "Premium Supporter", 133 base: 1e3, 134 trustTiers: [] 135 }, 136 { 137 id: "admin", 138 name: "Administrator", 139 base: 9999, 140 trustTiers: [] 141 } 142 ] 143 }; 144 setConfig(defaultConfig); 145 }; 146 if (loading) return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-10 text-center text-zinc-500", children: "Loading Configuration..." }); 147 if (!config) return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-10 text-center space-y-4", children: [ 148 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-red-500 font-bold", children: "Error: Credit Configuration not found in database." }), 149 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-zinc-500 text-sm", children: "The credit system has not been initialized yet." }), 150 /* @__PURE__ */ jsxRuntimeExports.jsx( 151 "button", 152 { 153 onClick: handleInitialize, 154 className: "px-6 py-2 bg-indigo-600 hover:bg-indigo-700 text-white rounded-lg font-bold text-sm shadow-lg shadow-indigo-500/20 transition-all", 155 children: "Initialize Default Settings" 156 } 157 ) 158 ] }); 159 const allCosts = getAllActionCosts(config); 160 const categories = Array.from(new Set(allCosts.map((a) => a.category))); 161 if (categories.length > 0 && !activeCategory) { 162 setActiveCategory(categories[0]); 163 } 164 const currentShortcut = CATEGORY_SHORTCUTS[activeCategory]; 165 const activeCategoryCosts = allCosts.filter((action) => action.category === activeCategory); 166 return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-6 max-w-5xl mx-auto animate-in fade-in", children: [ 167 /* @__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: [
168 /* @__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: [ 169 /* @__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(Shield, { size: 24 }) }), 170 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 171 /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "text-xl font-bold text-zinc-900 dark:text-white", children: "Usage & Quotas" }), 172 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-zinc-500", children: "Control download limits, credit allotments, and content usage policies." }) 173 ] }) 174 ] }) }), 175 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-b border-zinc-200 dark:border-zinc-800 flex items-center gap-6 mb-6", children: [
176 /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => setActiveTab("credits"), className: `pb-2 text-sm font-bold border-b-2 transition-all ${activeTab === "credits" ? "border-indigo-500 text-indigo-600 dark:text-indigo-400" : "border-transparent text-zinc-500"}`, children: "Allotments & Costs" }), 177 /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => setActiveTab("policy"), className: `pb-2 text-sm font-bold border-b-2 transition-all ${activeTab === "policy" ? "border-indigo-500 text-indigo-600 dark:text-indigo-400" : "border-transparent text-zinc-500"}`, children: "Content Usage Policy" }) 178 ] }), 179 activeTab === "credits" ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [ 180 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mb-6", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-4 bg-zinc-50 dark:bg-zinc-800/50 rounded-xl border border-zinc-200 dark:border-zinc-800", children: [ 181 /* @__PURE__ */ jsxRuntimeExports.jsxs("h3", { className: "text-sm font-bold text-zinc-700 dark:text-zinc-300 mb-3 flex items-center justify-between", children: [
182 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Action Costs" }), 183 currentShortcut && /* @__PURE__ */ jsxRuntimeExports.jsxs( 184 "a", 185 { 186 href: currentShortcut, 187 target: "_blank", 188 rel: "noopener noreferrer", 189 className: "text-xs text-indigo-600 dark:text-indigo-400 hover:underline flex items-center gap-1 font-semibold", 190 children: [ 191 "Launch App ", 192 /* @__PURE__ */ jsxRuntimeExports.jsx(ExternalLink, { size: 12 }) 193 ] 194 } 195 ) 196 ] }), 197 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-4", children: [ 198 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-1/3 flex flex-col gap-1 border-r border-zinc-200 dark:border-zinc-800 pr-3", children: categories.map((cat) => /* @__PURE__ */ jsxRuntimeExports.jsx( 199 "button", 200 { 201 type: "button", 202 onClick: () => setActiveCategory(cat), 203 className: `w-full text-left px-3 py-1.5 rounded-lg text-xs font-semibold transition-all ${activeCategory === cat ? "bg-indigo-500 text-white shadow-sm" : "text-zinc-650 hover:bg-zinc-100 dark:text-zinc-400 dark:hover:bg-zinc-800/60"}`, 204 children: cat 205 }, 206 cat 207 )) }),
208 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 space-y-2 max-h-[250px] overflow-y-auto pr-1", children: activeCategoryCosts.map((action) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between gap-4 py-1 border-b border-zinc-150 dark:border-zinc-850/60 last:border-0", children: [ 209 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0", children: [ 210 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs font-semibold text-zinc-755 dark:text-zinc-250 truncate", children: action.label }), 211 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px] font-mono text-zinc-450", children: action.key }) 212 ] }), 213 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5 flex-shrink-0", children: [ 214 /* @__PURE__ */ jsxRuntimeExports.jsx( 215 "input", 216 { 217 type: "number", 218 value: action.currentCost, 219 onChange: (e) => setConfig((prev) => ({ 220 ...prev, 221 costs: { ...(prev == null ? void 0 : prev.costs) || {}, [action.key]: Number(e.target.value) } 222 })), 223 className: "w-16 bg-white dark:bg-zinc-900 border border-zinc-300 dark:border-zinc-700 rounded-md py-1 px-1.5 text-xs outline-none focus:ring-1 focus:ring-indigo-500 text-zinc-900 dark:text-white text-right font-medium" 224 } 225 ),
226 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-zinc-400 dark:text-zinc-500", children: "cr" }) 227 ] }) 228 ] }, action.key)) }) 229 ] }) 230 ] }) }), 231 /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-lg font-bold text-zinc-900 dark:text-white border-t border-zinc-200 dark:border-zinc-800 pt-6 mb-4", children: "User Level Allotments" }), 232 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-6", children: config.allotments.map((tier, tierIndex) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-4 bg-white dark:bg-zinc-950 rounded-lg border border-zinc-200 dark:border-zinc-800 space-y-4 relative", children: [ 233 tier.id !== "guest" && /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => handleRemoveLevel(tierIndex), className: "absolute top-3 right-3 p-1.5 text-red-500 hover:bg-red-100 dark:hover:bg-red-900/30 rounded-full", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { size: 14 }) }),
234 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-4", children: [ 235 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 236 /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-xs font-bold text-zinc-500", children: "Level ID (Key)" }), 237 /* @__PURE__ */ jsxRuntimeExports.jsx( 238 "input", 239 { 240 type: "text", 241 value: tier.id, 242 onChange: (e) => updateTierField(tierIndex, "id", e.target.value.toLowerCase().replace(/\s+/g, "-")), 243 readOnly: !tier.id.startsWith("new-level"), 244 className: "w-full mt-1 bg-zinc-100 dark:bg-zinc-800 border border-zinc-300 dark:border-zinc-700 rounded-md p-2 text-sm font-mono text-zinc-900 dark:text-white outline-none focus:ring-2 focus:ring-indigo-500 read-only:opacity-60" 245 } 246 ) 247 ] }), 248 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
249 /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-xs font-bold text-zinc-500", children: "Level Name (Default)" }), 250 /* @__PURE__ */ jsxRuntimeExports.jsx( 251 "input", 252 { 253 type: "text", 254 value: tier.name, 255 onChange: (e) => updateTierField(tierIndex, "name", e.target.value), 256 className: "w-full mt-1 bg-zinc-100 dark:bg-zinc-800 border border-zinc-300 dark:border-zinc-700 rounded-md p-2 text-sm text-zinc-900 dark:text-white outline-none focus:ring-2 focus:ring-indigo-500" 257 } 258 ) 259 ] }), 260 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 261 /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-xs font-bold text-zinc-500", children: tier.id === "guest" ? "Max Daily Downloads (IP-based)" : "Base Credits" }), 262 /* @__PURE__ */ jsxRuntimeExports.jsx( 263 "input", 264 { 265 type: "number", 266 value: tier.base, 267 onChange: (e) => updateTierField(tierIndex, "base", Number(e.target.value)), 268 className: "w-full mt-1 bg-zinc-100 dark:bg-zinc-800 border border-zinc-300 dark:border-zinc-700 rounded-md p-2 text-sm text-zinc-900 dark:text-white outline-none focus:ring-2 focus:ring-indigo-500" 269 } 270 ) 271 ] }) 272 ] }),
273 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-2 bg-blue-50 dark:bg-blue-900/10 rounded-lg text-xs text-blue-700 dark:text-blue-300 flex items-center gap-2 mt-2", children: [ 274 /* @__PURE__ */ jsxRuntimeExports.jsx(Globe, { size: 14 }), 275 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [ 276 "Translations for Level Names are managed in the ", 277 /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Translation Manager" }), 278 " using the key: ", 279 /* @__PURE__ */ jsxRuntimeExports.jsxs("code", { className: "font-mono bg-blue-100 dark:bg-blue-900/20 px-1 rounded", children: [ 280 "creditTiers.", 281 tier.id 282 ] }) 283 ] }) 284 ] }), 285 tier.id !== "guest" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 286 /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "text-xs font-bold text-zinc-500 flex items-center gap-1 mb-2", children: [
287 /* @__PURE__ */ jsxRuntimeExports.jsx(Shield, { size: 12 }), 288 " Trust Score Bonuses" 289 ] }), 290 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-2", children: tier.trustTiers.map((bonus, bonusIndex) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 text-sm bg-zinc-50 dark:bg-zinc-900 p-2 rounded", children: [ 291 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-700 dark:text-zinc-300", children: "If score â¥" }), 292 /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "number", value: bonus.score, onChange: (e) => updateBonusTierField(tierIndex, bonusIndex, "score", Number(e.target.value)), className: "w-16 p-1 rounded border border-zinc-300 dark:border-zinc-700 bg-white dark:bg-zinc-800 text-center text-zinc-900 dark:text-white outline-none focus:ring-1 focus:ring-indigo-500" }), 293 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-700 dark:text-zinc-300", children: ", grant" }),
294 /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "number", value: bonus.credits, onChange: (e) => updateBonusTierField(tierIndex, bonusIndex, "credits", Number(e.target.value)), className: "w-20 p-1 rounded border border-zinc-300 dark:border-zinc-700 bg-white dark:bg-zinc-800 text-center text-zinc-900 dark:text-white outline-none focus:ring-1 focus:ring-indigo-500" }), 295 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-700 dark:text-zinc-300", children: "credits." }), 296 /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => handleRemoveBonusTier(tierIndex, bonusIndex), className: "p-1 text-red-500 hover:bg-red-100 dark:hover:bg-red-900/20 rounded-full transition-colors ml-auto", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { size: 14 }) }) 297 ] }, bonusIndex)) }), 298 /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { onClick: () => handleAddBonusTier(tierIndex), className: "mt-3 flex items-center gap-1 text-xs font-bold text-indigo-600 hover:text-indigo-500 transition-colors", children: [
299 /* @__PURE__ */ jsxRuntimeExports.jsx(Plus, { size: 12 }), 300 " Add Bonus Tier" 301 ] }) 302 ] }) 303 ] }, tier.id)) }), 304 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-6 border-t border-zinc-200 dark:border-zinc-800 pt-6", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { onClick: handleAddLevel, className: "w-full flex items-center justify-center gap-2 py-3 border-2 border-dashed border-zinc-300 dark:border-zinc-700 rounded-lg text-sm font-bold text-zinc-500 hover:border-indigo-500 hover:text-indigo-500 transition-colors", children: [ 305 /* @__PURE__ */ jsxRuntimeExports.jsx(Plus, { size: 16 }), 306 " Add New User Level" 307 ] }) }) 308 ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-6", children: [ 309 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [ 310 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between p-4 bg-zinc-50 dark:bg-zinc-800/50 rounded-lg border border-zinc-200 dark:border-zinc-800", children: [
311 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 312 /* @__PURE__ */ jsxRuntimeExports.jsx("h4", { className: "text-sm font-bold text-zinc-900 dark:text-white", children: "Strict Enforcement" }), 313 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-500", children: "Block uploads containing prohibited content." }) 314 ] }), 315 /* @__PURE__ */ jsxRuntimeExports.jsx( 316 "button", 317 { 318 onClick: () => setFilterConfig({ ...filterConfig, strictMode: !filterConfig.strictMode }), 319 className: `w-10 h-5 rounded-full transition-colors relative ${filterConfig.strictMode ? "bg-indigo-600" : "bg-zinc-300 dark:bg-zinc-700"}`, 320 children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `absolute top-0.5 w-4 h-4 bg-white rounded-full transition-all ${filterConfig.strictMode ? "left-5.5" : "left-0.5"}` }) 321 } 322 ) 323 ] }), 324 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between p-4 bg-zinc-50 dark:bg-zinc-800/50 rounded-lg border border-zinc-200 dark:border-zinc-800", children: [
325 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 326 /* @__PURE__ */ jsxRuntimeExports.jsx("h4", { className: "text-sm font-bold text-zinc-900 dark:text-white", children: "Auto-Strip HTML" }), 327 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-500", children: "Remove HTML tags from all text fields." }) 328 ] }), 329 /* @__PURE__ */ jsxRuntimeExports.jsx( 330 "button", 331 { 332 onClick: () => setFilterConfig({ ...filterConfig, stripHtml: !filterConfig.stripHtml }), 333 className: `w-10 h-5 rounded-full transition-colors relative ${filterConfig.stripHtml ? "bg-indigo-600" : "bg-zinc-300 dark:bg-zinc-700"}`, 334 children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `absolute top-0.5 w-4 h-4 bg-white rounded-full transition-all ${filterConfig.stripHtml ? "left-5.5" : "left-0.5"}` }) 335 } 336 ) 337 ] }) 338 ] }), 339 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-6", children: [
340 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 341 /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block font-bold text-sm text-zinc-900 dark:text-white mb-2", children: "Prohibited Words" }), 342 /* @__PURE__ */ jsxRuntimeExports.jsx( 343 "textarea", 344 { 345 className: "w-full h-48 bg-zinc-50 dark:bg-zinc-900 border border-zinc-300 dark:border-zinc-700 rounded-lg p-3 text-sm text-zinc-800 dark:text-zinc-200 font-mono", 346 value: Array.isArray(filterConfig.badWords) ? filterConfig.badWords.join(", ") : "", 347 onChange: (e) => setFilterConfig({ ...filterConfig, badWords: e.target.value.split(",").map((s) => s.trim()).filter(Boolean) }) 348 } 349 ) 350 ] }), 351 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 352 /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block font-bold text-sm text-zinc-900 dark:text-white mb-2", children: "Forbidden Domains" }),
353 /* @__PURE__ */ jsxRuntimeExports.jsx( 354 "textarea", 355 { 356 className: "w-full h-48 bg-zinc-50 dark:bg-zinc-900 border border-zinc-300 dark:border-zinc-700 rounded-lg p-3 text-sm text-zinc-800 dark:text-zinc-200 font-mono", 357 value: Array.isArray(filterConfig.forbiddenDomains) ? filterConfig.forbiddenDomains.join("\n") : "", 358 onChange: (e) => setFilterConfig({ ...filterConfig, forbiddenDomains: e.target.value.split("\n").map((s) => s.trim()).filter(Boolean) }) 359 } 360 ) 361 ] }) 362 ] }), 363 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-4 bg-zinc-50 dark:bg-zinc-800/50 rounded-lg border border-zinc-200 dark:border-zinc-800 space-y-4", children: [ 364 /* @__PURE__ */ jsxRuntimeExports.jsx("h4", { className: "text-sm font-bold text-zinc-900 dark:text-white", children: "Guest Upload Restrictions" }), 365 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-4", children: [
366 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 367 /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-[10px] font-bold text-zinc-500 uppercase", children: "Max Uploads / 24h" }), 368 /* @__PURE__ */ jsxRuntimeExports.jsx( 369 "input", 370 { 371 type: "number", 372 className: "w-full mt-1 bg-white dark:bg-zinc-900 border border-zinc-300 dark:border-zinc-700 rounded-md p-2 text-sm", 373 value: ((_a = filterConfig == null ? void 0 : filterConfig.guestLimits) == null ? void 0 : _a.maxUploadsPerDay) || 3, 374 onChange: (e) => setFilterConfig({ ...filterConfig, guestLimits: { ...filterConfig.guestLimits, maxUploadsPerDay: parseInt(e.target.value) } }) 375 } 376 ) 377 ] }), 378 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 379 /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-[10px] font-bold text-zinc-500 uppercase", children: "Max File Size (KB)" }),
380 /* @__PURE__ */ jsxRuntimeExports.jsx( 381 "input", 382 { 383 type: "number", 384 className: "w-full mt-1 bg-white dark:bg-zinc-900 border border-zinc-300 dark:border-zinc-700 rounded-md p-2 text-sm", 385 value: ((_b = filterConfig == null ? void 0 : filterConfig.guestLimits) == null ? void 0 : _b.maxFileSizeKB) || 500, 386 onChange: (e) => setFilterConfig({ ...filterConfig, guestLimits: { ...filterConfig.guestLimits, maxFileSizeKB: parseInt(e.target.value) } }) 387 } 388 ) 389 ] }) 390 ] }) 391 ] }) 392 ] }), 393 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-8 flex justify-end", children: /* @__PURE__ */ jsxRuntimeExports.jsxs( 394 "button", 395 { 396 onClick: handleSave, 397 disabled: saving, 398 className: "px-8 py-3 bg-indigo-600 hover:bg-indigo-700 text-white rounded-lg font-bold shadow-lg shadow-indigo-500/20 disabled:opacity-50 transition-all flex items-center gap-2", 399 children: [
400 saving ? /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { className: "animate-spin", size: 18 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Save, { size: 18 }), 401 "Save All Changes" 402 ] 403 } 404 ) }) 405 ] }), 406 /* @__PURE__ */ jsxRuntimeExports.jsx(DevDebugInfo, { table: "SystemSetting", keyName: "credit_config", value: config, isSuperAdmin: activeRole == null ? void 0 : activeRole.isSuperAdmin }), 407 /* @__PURE__ */ jsxRuntimeExports.jsx(DevDebugInfo, { table: "SystemSetting", keyName: "content_filter_config", value: filterConfig, isSuperAdmin: activeRole == null ? void 0 : activeRole.isSuperAdmin }) 408 ] }); 409}; 410export { 411 CreditManager as default 412};
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.