PageSourceSearch

https://www.hamienet.com/assets/SubscriptionSettings-COU6ImTj.js

js hamienet.com collected 2026-10-02 05:02:16 UTC 21,128 bytes, 331 lines download raw bytes

1import { r as reactExports, j as jsxRuntimeExports } from "./vendor-react-Bay9Y7Lb.js";
2import { a as api } from "./index-w5lXls15.js";
3import { D as DevDebugInfo } from "./AdminShared-BP_vxG_A.js";
4import { bj as CreditCard, cM as RefreshCw, cd as Save, fg as ToggleRight, fh as ToggleLeft, cF as Key, bz as EyeOff, bA as Eye, bq as Coins, bi as Sparkles } from "./vendor-D0P4XgNj.js";
5import "./vendor-i18n-BC7ZMXWQ.js";
6const SubscriptionSettings = ({ activeRole }) => {
7  const [config, setConfig] = reactExports.useState({
8    enabled: false,
9    stripeSecretKey: "",
10    stripeWebhookSecret: "",
11    goldPriceIdMonthly: "",
12    goldPriceIdAnnual: "",
13    goldCreditsFixed: 250,
14    premiumPriceIdMonthly: "",
15    premiumPriceIdAnnual: "",
16    premiumCreditsFixed: 1e3,
17    priceIdCreditPack: "",
18    creditPackPrice: 4.99,
19    creditPackSize: 500
20  });
21  const [loading, setLoading] = reactExports.useState(true);
22  const [saving, setSaving] = reactExports.useState(false);
23  const [showSecretKey, setShowSecretKey] = reactExports.useState(false);
24  const [showWebhookSecret, setShowWebhookSecret] = reactExports.useState(false);
25  reactExports.useEffect(() => {
26    loadConfig();
27  }, []);
28  const loadConfig = async () => {
29    setLoading(true);
30    try {
31      const saved = await api.getSystemSetting("subscription_config");
32      if (saved && saved.value) {
33        const parsed = typeof saved.value === "string" ? JSON.parse(saved.value) : saved.value;
34        setConfig((prev) => ({
35          ...prev,
36          ...parsed
37        }));
38      }
39    } catch (e) {
40      console.error("[SubSettings] Failed to load config:", e);
41    } finally {
42      setLoading(false);
43    }
44  };
45  const handleSave = async () => {
46    setSaving(true);
47    try {
48      await api.saveSystemSetting("subscription_config", config);
49      alert("Supporter Membership Configuration saved successfully.");
50    } catch (e) {
51      alert("Failed to save configuration: " + (e instanceof Error ? e.message : String(e)));
52    } finally {
53      setSaving(false);
54    }
55  };
56  const handleChange = (field, value) => {
57    setConfig((prev) => ({
58      ...prev,
59      ...field.endsWith("Fixed") || field === "creditPackSize" ? { [field]: parseInt(value) || 0 } : field === "creditPackPrice" ? { [field]: parseFloat(value) || 0 } : { [field]: value }
60    }));
61  };
62  if (loading) {
63    return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-8 text-center text-zinc-500 font-mono animate-pulse", children: "Loading Membership Engine Config..." });
64  }
65  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-6 max-w-4xl animate-in fade-in duration-300 pb-16", children: [
66    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center bg-zinc-900 border border-zinc-800 p-6 rounded-2xl shadow-sm shrink-0", children: [
67      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1", children: [
68        /* @__PURE__ */ jsxRuntimeExports.jsxs("h2", { className: "text-xl font-bold text-white flex items-center gap-2", children: [
69          /* @__PURE__ */ jsxRuntimeExports.jsx(CreditCard, { className: "text-indigo-500" }),
70          " Supporter Membership Settings"
71        ] }),
72        /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-400", children: "Configure Stripe integrations, supporter tiers (Gold & Premium), daily credits, and global pre-launch switches." })
73      ] }),
74      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
75        /* @__PURE__ */ jsxRuntimeExports.jsx(
76          "button",
77          {
78            onClick: loadConfig,
79            className: "p-2 bg-zinc-800 hover:bg-zinc-700 text-zinc-400 hover:text-white rounded-lg transition-colors border-0",
80            title: "Reload configuration",
81            children: /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { size: 16 })
82          }
83        ),
84        /* @__PURE__ */ jsxRuntimeExports.jsxs(
85          "button",
86          {
87            onClick: handleSave,
88            disabled: saving,
89            className: "flex items-center gap-2 px-4 py-2 bg-indigo-600 hover:bg-indigo-700 text-white rounded-lg text-sm font-bold shadow-md hover:shadow-indigo-500/20 active:scale-95 transition-all border-0 cursor-pointer",
90            children: [
91              saving ? /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { size: 16, className: "animate-spin" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Save, { size: 16 }),
92              "Save Settings"
93            ]
94          }
95        )
96      ] })
97    ] }),
98    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 p-6 rounded-2xl shadow-sm flex items-center justify-between", children: [
99      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1 flex-1 pr-6", children: [
100        /* @__PURE__ */ jsxRuntimeExports.jsxs("h3", { className: "text-md font-bold text-zinc-900 dark:text-white flex items-center gap-1.5", children: [
101          "Membership System Launch State",
102          !config.enabled && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px] font-bold bg-amber-500/10 text-amber-500 px-1.5 py-0.5 rounded uppercase", children: "Pre-Launch (OFF)" }),
103          config.enabled && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px] font-bold bg-emerald-500/10 text-emerald-500 px-1.5 py-0.5 rounded uppercase", children: "Live (ON)" })
104        ] }),
105        /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-500 dark:text-zinc-400 leading-relaxed", children: "When disabled, checkout routes will return 403 and the public Billing page will show a pre-launch overlay. Turn this ON once you configure the Stripe keys and Price IDs below." })
106      ] }),
107      /* @__PURE__ */ jsxRuntimeExports.jsx(
108        "button",
109        {
110          onClick: () => handleChange("enabled", !config.enabled),
111          className: "border-0 bg-transparent cursor-pointer text-indigo-600 dark:text-indigo-400 p-1 hover:scale-105 transition-transform",
112          children: config.enabled ? /* @__PURE__ */ jsxRuntimeExports.jsx(ToggleRight, { className: "w-14 h-10 text-indigo-500" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ToggleLeft, { className: "w-14 h-10 text-zinc-400 dark:text-zinc-600" })
113        }
114      )
115    ] }),
116    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-6", children: [
117      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 p-6 rounded-2xl shadow-sm space-y-4", children: [
118        /* @__PURE__ */ jsxRuntimeExports.jsxs("h3", { className: "font-bold text-zinc-900 dark:text-white text-sm flex items-center gap-2 border-b border-zinc-100 dark:border-zinc-800 pb-3", children: [
119          /* @__PURE__ */ jsxRuntimeExports.jsx(Key, { size: 16, className: "text-indigo-500" }),
120          " Stripe API Keys"
121        ] }),
122        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5", children: [
123          /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-xs font-bold text-zinc-500 dark:text-zinc-400", children: "Stripe Secret Key (sk_test_...)" }),
124          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative", children: [
125            /* @__PURE__ */ jsxRuntimeExports.jsx(
126              "input",
127              {
128                type: showSecretKey ? "text" : "password",
129                value: config.stripeSecretKey,
130                onChange: (e) => handleChange("stripeSecretKey", e.target.value),
131                className: "w-full text-sm rounded-lg border border-zinc-200 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-950 p-2.5 pr-10 text-zinc-800 dark:text-zinc-100 focus:outline-none focus:border-indigo-500",
132                placeholder: "sk_live_..."
133              }
134            ),
135            /* @__PURE__ */ jsxRuntimeExports.jsx(
136              "button",
137              {
138                type: "button",
139                onClick: () => setShowSecretKey(!showSecretKey),
140                className: "absolute right-3 top-1/2 -translate-y-1/2 text-zinc-400 hover:text-zinc-600 dark:hover:text-zinc-200 bg-transparent border-0 cursor-pointer",
141                children: showSecretKey ? /* @__PURE__ */ jsxRuntimeExports.jsx(EyeOff, { size: 16 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Eye, { size: 16 })
142              }
143            )
144          ] })
145        ] }),
146        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5", children: [
147          /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-xs font-bold text-zinc-500 dark:text-zinc-400", children: "Stripe Webhook Secret (whsec_...)" }),
148          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative", children: [
149            /* @__PURE__ */ jsxRuntimeExports.jsx(
150              "input",
151              {
152                type: showWebhookSecret ? "text" : "password",
153                value: config.stripeWebhookSecret,
154                onChange: (e) => handleChange("stripeWebhookSecret", e.target.value),
155                className: "w-full text-sm rounded-lg border border-zinc-200 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-950 p-2.5 pr-10 text-zinc-800 dark:text-zinc-100 focus:outline-none focus:border-indigo-500",
156                placeholder: "whsec_..."
157              }
158            ),
159            /* @__PURE__ */ jsxRuntimeExports.jsx(
160              "button",
161              {
162                type: "button",
163                onClick: () => setShowWebhookSecret(!showWebhookSecret),
164                className: "absolute right-3 top-1/2 -translate-y-1/2 text-zinc-400 hover:text-zinc-600 dark:hover:text-zinc-200 bg-transparent border-0 cursor-pointer",
165                children: showWebhookSecret ? /* @__PURE__ */ jsxRuntimeExports.jsx(EyeOff, { size: 16 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Eye, { size: 16 })
166              }
167            )
168          ] })
169        ] }),
170        /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-[10px] text-zinc-400 leading-relaxed", children: [
171          "To receive live payment callbacks, configure Stripe Webhooks pointing to ",
172          /* @__PURE__ */ jsxRuntimeExports.jsx("code", { children: "https://yourdomain.com/api/payments/webhook" }),
173          " and subscribe to ",
174          /* @__PURE__ */ jsxRuntimeExports.jsx("code", { children: "checkout.session.completed" }),
175          ", ",
176          /* @__PURE__ */ jsxRuntimeExports.jsx("code", { children: "customer.subscription.updated" }),
177          ", and ",
178          /* @__PURE__ */ jsxRuntimeExports.jsx("code", { children: "customer.subscription.deleted" }),
179          " events."
180        ] })
181      ] }),
182      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 p-6 rounded-2xl shadow-sm space-y-4", children: [
183        /* @__PURE__ */ jsxRuntimeExports.jsxs("h3", { className: "font-bold text-zinc-900 dark:text-white text-sm flex items-center gap-2 border-b border-zinc-100 dark:border-zinc-800 pb-3", children: [
184          /* @__PURE__ */ jsxRuntimeExports.jsx(Coins, { size: 16, className: "text-amber-500" }),
185          " Credit Allowances & Packs"
186        ] }),
187        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-4", children: [
188          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5", children: [
189            /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-xs font-bold text-zinc-500 dark:text-zinc-400", children: "Gold Daily Credits" }),
190            /* @__PURE__ */ jsxRuntimeExports.jsx(
191              "input",
192              {
193                type: "number",
194                value: config.goldCreditsFixed,
195                onChange: (e) => handleChange("goldCreditsFixed", e.target.value),
196                className: "w-full text-sm rounded-lg border border-zinc-200 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-950 p-2.5 text-zinc-800 dark:text-zinc-100 focus:outline-none focus:border-indigo-500"
197              }
198            )
199          ] }),
200          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5", children: [
201            /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-xs font-bold text-zinc-500 dark:text-zinc-400", children: "Premium Daily Credits" }),
202            /* @__PURE__ */ jsxRuntimeExports.jsx(
203              "input",
204              {
205                type: "number",
206                value: config.premiumCreditsFixed,
207                onChange: (e) => handleChange("premiumCreditsFixed", e.target.value),
208                className: "w-full text-sm rounded-lg border border-zinc-200 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-950 p-2.5 text-zinc-800 dark:text-zinc-100 focus:outline-none focus:border-indigo-500"
209              }
210            )
211          ] })
212        ] }),
213        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-t border-zinc-100 dark:border-zinc-800/80 pt-4 grid grid-cols-2 gap-4", children: [
214          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5", children: [
215            /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-xs font-bold text-zinc-500 dark:text-zinc-400", children: "Credit Pack Size" }),
216            /* @__PURE__ */ jsxRuntimeExports.jsx(
217              "input",
218              {
219                type: "number",
220                value: config.creditPackSize,
221                onChange: (e) => handleChange("creditPackSize", e.target.value),
222                className: "w-full text-sm rounded-lg border border-zinc-200 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-950 p-2.5 text-zinc-800 dark:text-zinc-100 focus:outline-none focus:border-indigo-500"
223              }
224            )
225          ] }),
226          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5", children: [
227            /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-xs font-bold text-zinc-500 dark:text-zinc-400", children: "Credit Pack Price ($)" }),
228            /* @__PURE__ */ jsxRuntimeExports.jsx(
229              "input",
230              {
231                type: "number",
232                step: "0.01",
233                value: config.creditPackPrice,
234                onChange: (e) => handleChange("creditPackPrice", e.target.value),
235                className: "w-full text-sm rounded-lg border border-zinc-200 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-950 p-2.5 text-zinc-800 dark:text-zinc-100 focus:outline-none focus:border-indigo-500"
236              }
237            )
238          ] })
239        ] })
240      ] })
241    ] }),
242    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 p-6 rounded-2xl shadow-sm space-y-6", children: [
243      /* @__PURE__ */ jsxRuntimeExports.jsxs("h3", { className: "font-bold text-zinc-900 dark:text-white text-sm flex items-center gap-2 border-b border-zinc-100 dark:border-zinc-800 pb-3", children: [
244        /* @__PURE__ */ jsxRuntimeExports.jsx(Sparkles, { size: 16, className: "text-indigo-500" }),
245        " Stripe Price IDs Mapping"
246      ] }),
247      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [
248        /* @__PURE__ */ jsxRuntimeExports.jsx("h4", { className: "text-xs font-black text-amber-600 dark:text-amber-400 uppercase tracking-wider", children: "Gold Supporter Pricing" }),
249        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [
250          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5", children: [
251            /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-xs font-bold text-zinc-500 dark:text-zinc-400", children: "Gold Monthly Price ID (price_...)" }),
252            /* @__PURE__ */ jsxRuntimeExports.jsx(
253              "input",
254              {
255                type: "text",
256                value: config.goldPriceIdMonthly,
257                onChange: (e) => handleChange("goldPriceIdMonthly", e.target.value),
258                className: "w-full text-sm rounded-lg border border-zinc-200 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-950 p-2.5 text-zinc-800 dark:text-zinc-100 focus:outline-none focus:border-indigo-500 font-mono",
259                placeholder: "price_1O..."
260              }
261            )
262          ] }),
263          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5", children: [
264            /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-xs font-bold text-zinc-500 dark:text-zinc-400", children: "Gold Annual Price ID (price_...)" }),
265            /* @__PURE__ */ jsxRuntimeExports.jsx(
266              "input",
267              {
268                type: "text",
269                value: config.goldPriceIdAnnual,
270                onChange: (e) => handleChange("goldPriceIdAnnual", e.target.value),
271                className: "w-full text-sm rounded-lg border border-zinc-200 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-950 p-2.5 text-zinc-800 dark:text-zinc-100 focus:outline-none focus:border-indigo-500 font-mono",
272                placeholder: "price_1O..."
273              }
274            )
275          ] })
276        ] })
277      ] }),
278      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4 border-t border-zinc-100 dark:border-zinc-800/80 pt-4", children: [
279        /* @__PURE__ */ jsxRuntimeExports.jsx("h4", { className: "text-xs font-black text-indigo-600 dark:text-indigo-400 uppercase tracking-wider", children: "Premium Supporter Pricing" }),
280        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [
281          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5", children: [
282            /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-xs font-bold text-zinc-500 dark:text-zinc-400", children: "Premium Monthly Price ID (price_...)" }),
283            /* @__PURE__ */ jsxRuntimeExports.jsx(
284              "input",
285              {
286                type: "text",
287                value: config.premiumPriceIdMonthly,
288                onChange: (e) => handleChange("premiumPriceIdMonthly", e.target.value),
289                className: "w-full text-sm rounded-lg border border-zinc-200 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-950 p-2.5 text-zinc-800 dark:text-zinc-100 focus:outline-none focus:border-indigo-500 font-mono",
290                placeholder: "price_1O..."
291              }
292            )
293          ] }),
294          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5", children: [
295            /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-xs font-bold text-zinc-500 dark:text-zinc-400", children: "Premium Annual Price ID (price_...)" }),
296            /* @__PURE__ */ jsxRuntimeExports.jsx(
297              "input",
298              {
299                type: "text",
300                value: config.premiumPriceIdAnnual,
301                onChange: (e) => handleChange("premiumPriceIdAnnual", e.target.value),
302                className: "w-full text-sm rounded-lg border border-zinc-200 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-950 p-2.5 text-zinc-800 dark:text-zinc-100 focus:outline-none focus:border-indigo-500 font-mono",
303                placeholder: "price_1O..."
304              }
305            )
306          ] })
307        ] })
308      ] }),
309      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4 border-t border-zinc-100 dark:border-zinc-800/80 pt-4", children: [
310        /* @__PURE__ */ jsxRuntimeExports.jsx("h4", { className: "text-xs font-black text-emerald-600 dark:text-emerald-400 uppercase tracking-wider", children: "Credit Pack Pricing" }),
311        /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5", children: [
312          /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-xs font-bold text-zinc-500 dark:text-zinc-400", children: "Credit Pack Price ID (price_...)" }),
313          /* @__PURE__ */ jsxRuntimeExports.jsx(
314            "input",
315            {
316              type: "text",
317              value: config.priceIdCreditPack,
318              onChange: (e) => handleChange("priceIdCreditPack", e.target.value),
319              className: "w-full text-sm rounded-lg border border-zinc-200 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-950 p-2.5 text-zinc-800 dark:text-zinc-100 focus:outline-none focus:border-indigo-500 font-mono",
320              placeholder: "price_1O..."
321            }
322          )
323        ] }) })
324      ] })
325    ] }),
326    /* @__PURE__ */ jsxRuntimeExports.jsx(DevDebugInfo, { table: "SystemSetting", keyName: "subscription_config", value: config, isSuperAdmin: activeRole == null ? void 0 : activeRole.isSuperAdmin })
327  ] });
328};
329export {
330  SubscriptionSettings as default
331};

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.