PageSourceSearch

https://www.hamienet.com/assets/AdManager-Ct0IrFQq.js

js hamienet.com collected 2026-09-24 19:00:15 UTC 31,948 bytes, 439 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 { bq as Coins, b9 as Settings, f3 as ToggleRight, f4 as ToggleLeft, bA as Eye, cL as RefreshCw, cc as Save, bv as CircleCheckBig, cJ as ShieldAlert, cs as BookOpen, b1 as CircleAlert, ch as Database } from "./vendor-dVNaLJx_.js";
4import "./vendor-i18n-R-bMoYp_.js";
5const DEFAULT_AD_SETTINGS = {
6  isEnabled: false,
7  publisherId: "",
8  enableAutoAds: false,
9  enableVignettes: false,
10  enableAnchors: false,
11  enableNonIntrusiveOnly: false,
12  adUnits: {
13    homeTop: { enabled: false, slotId: "" },
14    homeBottom: { enabled: false, slotId: "" },
15    watchSidebar: { enabled: false, slotId: "" },
16    watchBottom: { enabled: false, slotId: "" },
17    exploreSidebar: { enabled: false, slotId: "" },
18    exploreList: { enabled: false, slotId: "" },
19    converterBottom: { enabled: false, slotId: "" }
20  },
21  excludeRoles: ["ADMIN"]
22};
23const AdManager = ({ activeRole }) => {
24  const [config, setConfig] = reactExports.useState(DEFAULT_AD_SETTINGS);
25  const [isSaving, setIsSaving] = reactExports.useState(false);
26  const [saveStatus, setSaveStatus] = reactExports.useState("idle");
27  const [activeTab, setActiveTab] = reactExports.useState("config");
28  reactExports.useEffect(() => {
29    const fetchConfig = async () => {
30      try {
31        const res = await api.getSystemSetting("ad_settings");
32        if (res && res.value) {
33          const dbConfig = res.value;
34          setConfig({
35            ...DEFAULT_AD_SETTINGS,
36            ...dbConfig,
37            adUnits: {
38              ...DEFAULT_AD_SETTINGS.adUnits,
39              ...dbConfig.adUnits || {}
40            },
41            excludeRoles: dbConfig.excludeRoles || ["ADMIN"]
42          });
43        }
44      } catch (err) {
45        console.error("Failed to load ad_settings", err);
46      }
47    };
48    fetchConfig();
49  }, []);
50  const handleSave = async () => {
51    setIsSaving(true);
52    setSaveStatus("idle");
53    try {
54      await api.saveSystemSetting("ad_settings", config);
55      setSaveStatus("success");
56      setTimeout(() => setSaveStatus("idle"), 3e3);
57    } catch (err) {
58      console.error("Failed to save ad_settings", err);
59      setSaveStatus("error");
60    } finally {
61      setIsSaving(false);
62    }
63  };
64  const updateField = (key, value) => {
65    setConfig((prev) => ({
66      ...prev,
67      [key]: value
68    }));
69  };
70  const updateAdUnit = (slotKey, field, value) => {
71    setConfig((prev) => ({
72      ...prev,
73      adUnits: {
74        ...prev.adUnits,
75        [slotKey]: {
76          ...prev.adUnits[slotKey],
77          [field]: value
78        }
79      }
80    }));
81  };
82  const toggleRoleExclusion = (role) => {
83    setConfig((prev) => {
84      const current = prev.excludeRoles || [];
85      const updated = current.includes(role) ? current.filter((r) => r !== role) : [...current, role];
86      return {
87        ...prev,
88        excludeRoles: updated
89      };
90    });
91  };
92  const DevDebugInfo = ({ table, keyName, value }) => {
93    if (!(activeRole == null ? void 0 : activeRole.isSuperAdmin)) return null;
94    return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-3 p-2 bg-zinc-100 dark:bg-zinc-950 border border-dashed border-zinc-300 dark:border-zinc-800 rounded-lg text-[10px] font-mono text-zinc-500 overflow-hidden", children: [
95      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2 items-center mb-0.5", children: [
96        /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-indigo-600 dark:text-indigo-400 font-bold flex items-center gap-1", children: [
97          /* @__PURE__ */ jsxRuntimeExports.jsx(Database, { size: 8 }),
98          " ",
99          table
100        ] }),
101        /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-400", children: "|" }),
102        /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-600 dark:text-zinc-400", children: keyName })
103      ] }),
104      value !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-emerald-600 dark:text-emerald-500 truncate font-medium", children: [
105        "VAL: ",
106        JSON.stringify(value)
107      ] })
108    ] });
109  };
110  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-6 max-w-5xl", children: [
111    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-indigo-50 dark:bg-indigo-900/20 p-5 rounded-2xl border border-indigo-200 dark:border-indigo-900/50 flex flex-col md:flex-row md:items-center justify-between gap-4", children: [
112      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
113        /* @__PURE__ */ jsxRuntimeExports.jsxs("h3", { className: "font-extrabold text-indigo-950 dark:text-indigo-200 text-base mb-1 flex items-center gap-2", children: [
114          /* @__PURE__ */ jsxRuntimeExports.jsx(Coins, { className: "text-indigo-650 dark:text-indigo-400", size: 20 }),
115          " Ad Monetization & Revenue Manager"
116        ] }),
117        /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-indigo-900 dark:text-indigo-300 max-w-xl", children: "Configure Google AdSense integration, manage responsive ad placements across public pages, and toggle script rendering parameters dynamically." })
118      ] }),
119      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2 self-start md:self-center", children: [
120        /* @__PURE__ */ jsxRuntimeExports.jsx(
121          "button",
122          {
123            onClick: () => setActiveTab("config"),
124            className: `px-4 py-2 text-xs font-bold rounded-lg transition-all ${activeTab === "config" ? "bg-indigo-600 text-white shadow-md shadow-indigo-600/20" : "bg-zinc-105 dark:bg-zinc-800 text-zinc-700 dark:text-zinc-300 hover:bg-zinc-200 dark:hover:bg-zinc-700"}`,
125            children: "Ad Settings"
126          }
127        ),
128        /* @__PURE__ */ jsxRuntimeExports.jsx(
129          "button",
130          {
131            onClick: () => setActiveTab("guide"),
132            className: `px-4 py-2 text-xs font-bold rounded-lg transition-all ${activeTab === "guide" ? "bg-indigo-600 text-white shadow-md shadow-indigo-600/20" : "bg-zinc-105 dark:bg-zinc-800 text-zinc-700 dark:text-zinc-300 hover:bg-zinc-200 dark:hover:bg-zinc-700"}`,
133            children: "Setup Guide"
134          }
135        )
136      ] })
137    ] }),
138    activeTab === "config" ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-3 gap-6", children: [
139      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "lg:col-span-2 space-y-6", children: [
140        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-900 border border-zinc-250 dark:border-zinc-800 rounded-2xl p-6 shadow-sm space-y-6", children: [
141          /* @__PURE__ */ jsxRuntimeExports.jsxs("h4", { className: "text-sm font-extrabold text-zinc-900 dark:text-white border-b border-zinc-200 dark:border-zinc-800 pb-3 flex items-center gap-2", children: [
142            /* @__PURE__ */ jsxRuntimeExports.jsx(Settings, { size: 16, className: "text-zinc-600 dark:text-zinc-450" }),
143            " Global AdSense Settings"
144          ] }),
145          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-5", children: [
146            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-4 bg-zinc-50 dark:bg-zinc-800/40 rounded-xl border border-zinc-200 dark:border-zinc-800 flex items-center justify-between", children: [
147              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
148                /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-sm font-bold text-zinc-800 dark:text-zinc-200", children: "Global Monetization" }),
149                /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs text-zinc-650 dark:text-zinc-400", children: "Inject AdSense elements on pages" })
150              ] }),
151              /* @__PURE__ */ jsxRuntimeExports.jsx(
152                "button",
153                {
154                  onClick: () => updateField("isEnabled", !config.isEnabled),
155                  className: `p-1.5 rounded transition-colors ${config.isEnabled ? "text-emerald-600 dark:text-emerald-500" : "text-zinc-400"}`,
156                  children: config.isEnabled ? /* @__PURE__ */ jsxRuntimeExports.jsx(ToggleRight, { size: 32 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ToggleLeft, { size: 32 })
157                }
158              )
159            ] }),
160            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-4 bg-zinc-50 dark:bg-zinc-800/40 rounded-xl border border-zinc-200 dark:border-zinc-800 flex items-center justify-between", children: [
161              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
162                /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-sm font-bold text-zinc-800 dark:text-zinc-200", children: "AdSense Auto Ads" }),
163                /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs text-zinc-650 dark:text-zinc-400", children: "Let Google place ads automatically" })
164              ] }),
165              /* @__PURE__ */ jsxRuntimeExports.jsx(
166                "button",
167                {
168                  onClick: () => updateField("enableAutoAds", !config.enableAutoAds),
169                  className: `p-1.5 rounded transition-colors ${config.enableAutoAds ? "text-emerald-600 dark:text-emerald-500" : "text-zinc-400"}`,
170                  children: config.enableAutoAds ? /* @__PURE__ */ jsxRuntimeExports.jsx(ToggleRight, { size: 32 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ToggleLeft, { size: 32 })
171                }
172              )
173            ] })
174          ] }),
175          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5", children: [
176            /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-xs font-bold text-zinc-700 dark:text-zinc-400 uppercase tracking-wider block", children: "AdSense Publisher Account ID (Client ID)" }),
177            /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "relative", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
178              "input",
179              {
180                type: "text",
181                placeholder: "e.g. ca-pub-xxxxxxxxxxxxxxxx",
182                value: config.publisherId,
183                onChange: (e) => updateField("publisherId", e.target.value.trim()),
184                className: "w-full px-4 py-2.5 bg-zinc-50 dark:bg-zinc-800 border border-zinc-200 dark:border-zinc-800 rounded-xl text-sm text-zinc-800 dark:text-zinc-100 focus:outline-none focus:ring-2 focus:ring-indigo-500 font-mono"
185              }
186            ) }),
187            /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-xs text-zinc-600 dark:text-zinc-400", children: [
188              "Must start with ",
189              /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "bg-zinc-200 dark:bg-zinc-800 px-1 py-0.5 rounded font-mono text-zinc-800 dark:text-zinc-300", children: "ca-pub-" }),
190              ". This is required for both Auto Ads and individual ad units."
191            ] })
192          ] }),
193          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-t border-zinc-200 dark:border-zinc-800 pt-5", children: [
194            /* @__PURE__ */ jsxRuntimeExports.jsx("h5", { className: "text-xs font-bold text-indigo-750 dark:text-indigo-400 uppercase tracking-widest mb-3", children: "Google Page Format Features" }),
195            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [
196              /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex items-center gap-3 p-3 bg-indigo-50/40 dark:bg-indigo-950/20 hover:bg-indigo-50/80 dark:hover:bg-indigo-950/30 rounded-lg cursor-pointer border border-indigo-150 dark:border-indigo-900/40", children: [
197                /* @__PURE__ */ jsxRuntimeExports.jsx(
198                  "input",
199                  {
200                    type: "checkbox",
201                    checked: config.enableNonIntrusiveOnly || false,
202                    onChange: (e) => {
203                      const val = e.target.checked;
204                      setConfig((prev) => ({
205                        ...prev,
206                        enableNonIntrusiveOnly: val,
207                        ...val ? { enableVignettes: false, enableAnchors: false } : {}
208                      }));
209                    },
210                    className: "rounded border-zinc-300 text-indigo-600 focus:ring-indigo-500 w-4 h-4"
211                  }
212                ),
213                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
214                  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs font-bold text-zinc-850 dark:text-zinc-200", children: "Enforce Non-Intrusive Placements" }),
215                  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] text-zinc-650 dark:text-zinc-400", children: "Limit heights of manual ad containers and disable vignettes & overlay formats" })
216                ] })
217              ] }),
218              /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: `flex items-center gap-3 p-3 bg-zinc-50 dark:bg-zinc-800/20 hover:bg-zinc-100/50 dark:hover:bg-zinc-800/40 rounded-lg cursor-pointer border border-zinc-200 dark:border-zinc-800 transition-all ${config.enableNonIntrusiveOnly ? "opacity-40 cursor-not-allowed" : ""}`, children: [
219                /* @__PURE__ */ jsxRuntimeExports.jsx(
220                  "input",
221                  {
222                    type: "checkbox",
223                    disabled: config.enableNonIntrusiveOnly,
224                    checked: config.enableNonIntrusiveOnly ? false : config.enableVignettes || false,
225                    onChange: (e) => updateField("enableVignettes", e.target.checked),
226                    className: "rounded border-zinc-300 text-indigo-600 focus:ring-indigo-500 w-4 h-4 disabled:opacity-50"
227                  }
228                ),
229                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
230                  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs font-bold text-zinc-850 dark:text-zinc-200", children: "Enable Vignettes" }),
231                  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] text-zinc-650 dark:text-zinc-400", children: "Full-screen ads between page visits" })
232                ] })
233              ] }),
234              /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: `flex items-center gap-3 p-3 bg-zinc-50 dark:bg-zinc-800/20 hover:bg-zinc-100/50 dark:hover:bg-zinc-800/40 rounded-lg cursor-pointer border border-zinc-200 dark:border-zinc-800 transition-all ${config.enableNonIntrusiveOnly ? "opacity-40 cursor-not-allowed" : ""}`, children: [
235                /* @__PURE__ */ jsxRuntimeExports.jsx(
236                  "input",
237                  {
238                    type: "checkbox",
239                    disabled: config.enableNonIntrusiveOnly,
240                    checked: config.enableNonIntrusiveOnly ? false : config.enableAnchors || false,
241                    onChange: (e) => updateField("enableAnchors", e.target.checked),
242                    className: "rounded border-zinc-300 text-indigo-650 focus:ring-indigo-500 w-4 h-4 disabled:opacity-50"
243                  }
244                ),
245                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
246                  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs font-bold text-zinc-850 dark:text-zinc-200", children: "Enable Anchor Ads" }),
247                  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] text-zinc-650 dark:text-zinc-400", children: "Sticky ads at the bottom or top margin" })
248                ] })
249              ] })
250            ] })
251          ] })
252        ] }),
253        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-900 border border-zinc-250 dark:border-zinc-800 rounded-2xl p-6 shadow-sm space-y-6", children: [
254          /* @__PURE__ */ jsxRuntimeExports.jsxs("h4", { className: "text-sm font-extrabold text-zinc-900 dark:text-white border-b border-zinc-200 dark:border-zinc-800 pb-3 flex items-center gap-2", children: [
255            /* @__PURE__ */ jsxRuntimeExports.jsx(Eye, { size: 16, className: "text-zinc-600 dark:text-zinc-400" }),
256            " Manual Ad Placements"
257          ] }),
258          /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-600 dark:text-zinc-400 -mt-2", children: "If Auto Ads are off or if you wish to run dedicated units in specific visual slots, configure them here." }),
259          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-4", children: Object.keys(config.adUnits).map((slotKey) => {
260            const unit = config.adUnits[slotKey];
261            let label = slotKey;
262            let desc = "";
263            if (slotKey === "homeTop") {
264              label = "Home Page (Top Banner)";
265              desc = "Displayed below navigation header on Home";
266            } else if (slotKey === "homeBottom") {
267              label = "Home Page (Bottom)";
268              desc = "Displayed at bottom of homepage, perfect for Multiplex";
269            } else if (slotKey === "watchSidebar") {
270              label = "Watch Page (Sidebar)";
271              desc = "Placed in sidebar column beside related tracks/comments";
272            } else if (slotKey === "watchBottom") {
273              label = "Watch Page (Bottom)";
274              desc = "Underneath player & comments, matches Multiplex format";
275            } else if (slotKey === "exploreSidebar") {
276              label = "Explore Page (Sidebar)";
277              desc = "Beside search/category filters";
278            } else if (slotKey === "exploreList") {
279              label = "Explore Page (In-List)";
280              desc = "Interspersed in results list";
281            } else if (slotKey === "converterBottom") {
282              label = "Converter Page (Bottom)";
283              desc = "Placed clean below download dashboard";
284            }
285            return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-4 bg-zinc-50 dark:bg-zinc-800/30 border border-zinc-200 dark:border-zinc-800/80 rounded-xl space-y-3", children: [
286              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [
287                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
288                  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-extrabold text-zinc-850 dark:text-zinc-200", children: label }),
289                  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-zinc-600 dark:text-zinc-400 block", children: desc })
290                ] }),
291                /* @__PURE__ */ jsxRuntimeExports.jsx(
292                  "button",
293                  {
294                    onClick: () => updateAdUnit(slotKey, "enabled", !unit.enabled),
295                    className: `p-1 rounded transition-colors ${unit.enabled ? "text-emerald-600 dark:text-emerald-500" : "text-zinc-400"}`,
296                    children: unit.enabled ? /* @__PURE__ */ jsxRuntimeExports.jsx(ToggleRight, { size: 26 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ToggleLeft, { size: 26 })
297                  }
298                )
299              ] }),
300              unit.enabled && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "relative", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
301                "input",
302                {
303                  type: "text",
304                  placeholder: "Enter Ad Unit Slot ID (e.g. 1234567890)",
305                  value: unit.slotId,
306                  onChange: (e) => updateAdUnit(slotKey, "slotId", e.target.value.trim()),
307                  className: "w-full px-3 py-1.5 bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-lg text-xs text-zinc-700 dark:text-zinc-300 font-mono focus:outline-none focus:ring-1 focus:ring-indigo-500"
308                }
309              ) })
310            ] }, slotKey);
311          }) })
312        ] })
313      ] }),
314      /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-6", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-2xl p-5 shadow-sm space-y-4 sticky top-6", children: [
315        /* @__PURE__ */ jsxRuntimeExports.jsx("h4", { className: "text-xs font-bold text-zinc-700 dark:text-zinc-450 uppercase tracking-widest", children: "Save & Synchronize" }),
316        /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-xs text-zinc-655 dark:text-zinc-400 leading-relaxed", children: [
317          "Saving updates the centralized ",
318          /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "font-mono text-zinc-800 dark:text-zinc-300", children: "SystemSetting" }),
319          ", which triggers real-time pushes to the entire web cluster."
320        ] }),
321        /* @__PURE__ */ jsxRuntimeExports.jsxs(
322          "button",
323          {
324            onClick: handleSave,
325            disabled: isSaving,
326            className: "w-full py-3 bg-indigo-600 hover:bg-indigo-700 text-white rounded-xl text-sm font-extrabold flex items-center justify-center gap-2 shadow-lg shadow-indigo-500/25 active:scale-95 transition-all cursor-pointer disabled:opacity-50",
327            children: [
328              isSaving ? /* @__P
328URE__ */ jsxRuntimeExports.jsx(RefreshCw, { className: "animate-spin", size: 16 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Save, { size: 16 }),
329              isSaving ? "Saving Configurations..." : "Commit Settings"
330            ]
331          }
332        ),
333        saveStatus === "success" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-3 bg-emerald-50 dark:bg-emerald-950/20 text-emerald-800 dark:text-emerald-350 border border-emerald-150 dark:border-emerald-900/40 rounded-xl text-xs flex items-center gap-2", children: [
334          /* @__PURE__ */ jsxRuntimeExports.jsx(CircleCheckBig, { size: 16 }),
335          " settings committed and cluster notified."
336        ] }),
337        saveStatus === "error" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-3 bg-red-50 dark:bg-red-950/20 text-red-805 dark:text-red-350 border border-red-150 dark:border-red-900/40 rounded-xl text-xs flex items-center gap-2", children: [
338          /* @__PURE__ */ jsxRuntimeExports.jsx(ShieldAlert, { size: 16 }),
339          " Error saving configuration to database."
340        ] }),
341        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-t border-zinc-200 dark:border-zinc-800 pt-4 space-y-3", children: [
342          /* @__PURE__ */ jsxRuntimeExports.jsx("h5", { className: "text-[10px] font-bold text-zinc-700 dark:text-zinc-450 uppercase tracking-wider", children: "Exclude User Roles" }),
343          /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] text-zinc-600 dark:text-zinc-400 leading-relaxed", children: "Roles selected below will completely bypass script loading (e.g. ad-free system testing)." }),
344          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-2 pt-1", children: ["ADMIN", "USER", "GUEST"].map((role) => {
345            var _a;
346            const isChecked = ((_a = config.excludeRoles) == null ? void 0 : _a.includes(role)) || false;
347            return /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex items-center gap-2.5 text-xs text-zinc-800 dark:text-zinc-300 cursor-pointer", children: [
348              /* @__PURE__ */ jsxRuntimeExports.jsx(
349                "input",
350                {
351                  type: "checkbox",
352                  checked: isChecked,
353                  onChange: () => toggleRoleExclusion(role),
354                  className: "rounded border-zinc-300 text-indigo-600 focus:ring-indigo-500"
355                }
356              ),
357              /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-semibold", children: role })
358            ] }, role);
359          }) })
360        ] }),
361        /* @__PURE__ */ jsxRuntimeExports.jsx(DevDebugInfo, { table: "SystemSetting", keyName: "ad_settings", value: config })
362      ] }) })
363    ] }) : (
364      /* Setup Guide Tab */
365      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-2xl p-6 shadow-sm space-y-6", children: [
366        /* @__PURE__ */ jsxRuntimeExports.jsxs("h4", { className: "text-sm font-extrabold text-zinc-900 dark:text-white border-b border-zinc-200 dark:border-zinc-800 pb-3 flex items-center gap-2", children: [
367          /* @__PURE__ */ jsxRuntimeExports.jsx(BookOpen, { size: 16, className: "text-zinc-600" }),
368          " Connecting Google AdSense to HamieNET"
369        ] }),
370        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4 text-xs text-zinc-700 dark:text-zinc-300 leading-relaxed", children: [
371          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-3", children: [
372            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-shrink-0 w-5 h-5 rounded-full bg-indigo-100 dark:bg-indigo-900/40 text-indigo-900 dark:text-indigo-300 flex items-center justify-center font-bold font-mono", children: "1" }),
373            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
374              /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "font-bold text-zinc-900 dark:text-zinc-100 text-sm mb-0.5", children: "Locate your AdSense Publisher ID" }),
375              /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
376                "Log in to your ",
377                /* @__PURE__ */ jsxRuntimeExports.jsx("a", { href: "https://adsense.google.com", target: "_blank", rel: "noreferrer", className: "text-indigo-600 dark:text-indigo-400 hover:underline", children: "Google AdSense Dashboard" }),
378                ". Go to Account > Settings > Account information. Copy your Publisher ID (starts with ",
379                /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "bg-zinc-200 dark:bg-zinc-800 px-1 py-0.5 rounded font-mono text-zinc-800 dark:text-zinc-300", children: "ca-pub-xxxxxxxxxxxxxxxx" }),
380                ")."
381              ] })
382            ] })
383          ] }),
384          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-3", children: [
385            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-shrink-0 w-5 h-5 rounded-full bg-indigo-100 dark:bg-indigo-900/40 text-indigo-900 dark:text-indigo-300 flex items-center justify-center font-bold font-mono", children: "2" }),
386            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
387              /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "font-bold text-zinc-900 dark:text-zinc-100 text-sm mb-0.5", children: "Enable AdSense Globally in this panel" }),
388              /* @__PURE__ */ jsxRuntimeExports.jsx("p", { children: 'Toggle "Global Monetization" on the settings tab, paste your publisher ID, and click "Commit Settings". This injects the official Google JS library in the head element of the page for users.' })
389            ] })
390          ] }),
391          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-3", children: [
392            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-shrink-0 w-5 h-5 rounded-full bg-indigo-100 dark:bg-indigo-900/40 text-indigo-900 dark:text-indigo-300 flex items-center justify-center font-bold font-mono", children: "3" }),
393            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
394              /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "font-bold text-zinc-900 dark:text-zinc-100 text-sm mb-0.5", children: "Choose between Auto Ads and Manual Ads" }),
395              /* @__PURE__ */ jsxRuntimeExports.jsxs("ul", { className: "list-disc pl-5 space-y-1.5 mt-1 text-zinc-700 dark:text-zinc-350", children: [
396                /* @__PURE__ */ jsxRuntimeExports.jsxs("li", { children: [
397                  /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Auto Ads:" }),
398                  " Enable this to let Google automatically scan the pages of HamieNET and inject ads dynamically in headers, margin sidebars, and native text streams. Perfect for effortless setup."
399                ] }),
400                /* @__PURE__ */ jsxRuntimeExports.jsxs("li", { children: [
401                  /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Manual Placements:" }),
402                  " Turn Auto Ads off and toggle specific slots in the settings panel (like Watch Page Sidebar). Add the exact Slot ID generated inside AdSense > Ads > By Ad Unit. We support responsive display formats and multiplex (related post grid) recommendations."
403                ] }),
404                /* @__PURE__ */ jsxRuntimeExports.jsxs("li", { children: [
405                  /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Non-Intrusive Mode:" }),
406                  " Enforce Non-Intrusive Placements to disable vignettes and anchors globally, set manual ad components to a compact 90px height limit, and request horizontal banner formats only."
407                ] })
408              ] })
409            ] })
410          ] }),
411          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-3", children: [
412            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-shrink-0 w-5 h-5 rounded-full bg-indigo-100 dark:bg-indigo-900/40 text-indigo-900 dark:text-indigo-300 flex items-center justify-center font-bold font-mono", children: "4" }),
413            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
414              /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "font-bold text-zinc-900 dark:text-zinc-100 text-sm mb-0.5", children: "Verify ads.txt Placement" }),
415              /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
416                "AdSense requires an ",
417                /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "font-mono text-zinc-800 dark:text-zinc-200 bg-zinc-100 dark:bg-zinc-800/40 px-1 border border-zinc-200 dark:border-zinc-800 rounded", children: "ads.txt" }),
418                " file in the public root. Make sure it is placed in the static assets path ",
419                /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "font-mono", children: "/web/public/ads.txt" }),
420                " of the deployer containing your publisher key:"
421              ] }),
422              /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "p-3 bg-zinc-100 dark:bg-zinc-800 rounded-lg font-mono text-[10px] mt-2 border border-zinc-250 dark:border-zinc-800 text-zinc-900 dark:text-zinc-250 select-all", children: "google.com, pub-XXXXXXXXXXXXXXXX, DIRECT, f08c47fec0942fa0" })
423            ] })
424          ] }),
425          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-6 p-4 bg-yellow-50 dark:bg-yellow-950/20 border border-yellow-200 dark:border-yellow-900/30 rounded-xl text-yellow-950 dark:text-yellow-350 flex gap-2.5", children: [
426            /* @__PURE__ */ jsxRuntimeExports.jsx(CircleAlert, { className: "flex-shrink-0 text-yellow-600 dark:text-yellow-400", size: 18 }),
427            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
428              /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-extrabold text-sm block mb-0.5 text-yellow-905 dark:text-yellow-200", children: "Ad Blocking Extensions Notice" }),
429              /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-yellow-900 dark:text-yellow-300", children: "If you have an active ad blocker installed on your browser, mock slots and Google script injection will fail to report status correctly. Disable ad blockers for this domain while verifying configurations." })
430            ] })
431          ] })
432        ] })
433      ] })
434    )
435  ] });
436};
437export {
438  AdManager as default
439};

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.