@thinkingcat/subscription-ui 1.0.0 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,3 +1,5 @@
1
+ "use client";
2
+
1
3
  // src/components/SubscribePage.tsx
2
4
  import { useState, useEffect } from "react";
3
5
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -9,7 +11,8 @@ function SubscribePage({
9
11
  callbackUrl = "/",
10
12
  serviceName = "\uC11C\uBE44\uC2A4",
11
13
  primaryColor = DEFAULT_PRIMARY,
12
- showExpiredBanner = true
14
+ showExpiredBanner = true,
15
+ theme = "system"
13
16
  }) {
14
17
  const [step, setStep] = useState("plan");
15
18
  const [plans, setPlans] = useState([]);
@@ -99,8 +102,10 @@ function SubscribePage({
99
102
  return;
100
103
  }
101
104
  setSuccess(true);
105
+ const separator = callbackUrl.includes("?") ? "&" : "?";
106
+ const redirectUrl = `${callbackUrl}${separator}subscribed=true`;
102
107
  setTimeout(() => {
103
- window.location.href = callbackUrl;
108
+ window.location.href = redirectUrl;
104
109
  }, 2e3);
105
110
  } catch {
106
111
  setError("\uAD6C\uB3C5 \uCC98\uB9AC \uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.");
@@ -111,12 +116,15 @@ function SubscribePage({
111
116
  function fmt(price) {
112
117
  return price.toLocaleString("ko-KR") + "\uC6D0";
113
118
  }
114
- if (loading) return /* @__PURE__ */ jsx(PageLayout, { children: /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center h-64 text-gray-400", children: "\uBD88\uB7EC\uC624\uB294 \uC911..." }) });
119
+ const themeClass = theme === "dark" ? "dark" : theme === "light" ? "light-mode-override" : "";
120
+ if (loading) {
121
+ return /* @__PURE__ */ jsx(PageLayout, { themeClass, children: /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center h-64 text-gray-400 dark:text-gray-500", children: "\uBD88\uB7EC\uC624\uB294 \uC911..." }) });
122
+ }
115
123
  if (success) {
116
- return /* @__PURE__ */ jsx(PageLayout, { children: /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center h-64", children: /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
117
- /* @__PURE__ */ jsx("div", { className: "w-16 h-16 rounded-full bg-green-500/20 flex items-center justify-center mx-auto mb-4", children: /* @__PURE__ */ jsx(CheckIcon, { className: "w-8 h-8 text-green-400" }) }),
118
- /* @__PURE__ */ jsx("h2", { className: "text-xl font-bold text-white mb-2", children: "\uAD6C\uB3C5\uC774 \uC2DC\uC791\uB418\uC5C8\uC2B5\uB2C8\uB2E4!" }),
119
- /* @__PURE__ */ jsx("p", { className: "text-gray-400 text-sm", children: "\uC7A0\uC2DC \uD6C4 \uC774\uB3D9\uD569\uB2C8\uB2E4..." })
124
+ return /* @__PURE__ */ jsx(PageLayout, { themeClass, children: /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center min-h-[60vh]", children: /* @__PURE__ */ jsxs("div", { className: "text-center px-4", children: [
125
+ /* @__PURE__ */ jsx("div", { className: "w-16 h-16 rounded-full bg-green-500/20 flex items-center justify-center mx-auto mb-4", children: /* @__PURE__ */ jsx(CheckIcon, { className: "w-8 h-8 text-green-500 dark:text-green-400" }) }),
126
+ /* @__PURE__ */ jsx("h2", { className: "text-xl font-bold text-gray-900 dark:text-white mb-2", children: "\uAD6C\uB3C5\uC774 \uC2DC\uC791\uB418\uC5C8\uC2B5\uB2C8\uB2E4!" }),
127
+ /* @__PURE__ */ jsx("p", { className: "text-gray-500 dark:text-gray-400 text-sm", children: "\uC7A0\uC2DC \uD6C4 \uC774\uB3D9\uD569\uB2C8\uB2E4..." })
120
128
  ] }) }) });
121
129
  }
122
130
  const steps = [
@@ -124,56 +132,71 @@ function SubscribePage({
124
132
  { key: "card", label: "\uACB0\uC81C\uC218\uB2E8" },
125
133
  { key: "confirm", label: "\uD655\uC778" }
126
134
  ];
127
- return /* @__PURE__ */ jsxs(PageLayout, { children: [
128
- /* @__PURE__ */ jsx("div", { className: "border-b border-white/10 px-4 py-4 mb-8", children: /* @__PURE__ */ jsxs("div", { className: "max-w-3xl mx-auto flex items-center justify-between", children: [
135
+ const currentStepIndex = steps.findIndex((s) => s.key === step);
136
+ return /* @__PURE__ */ jsxs(PageLayout, { themeClass, children: [
137
+ /* @__PURE__ */ jsx("div", { className: "border-b border-gray-200 dark:border-white/10 px-4 sm:px-6 py-4", children: /* @__PURE__ */ jsxs("div", { className: "max-w-3xl mx-auto flex flex-col sm:flex-row sm:items-center gap-3 sm:gap-0 sm:justify-between", children: [
129
138
  /* @__PURE__ */ jsxs("div", { children: [
130
- /* @__PURE__ */ jsxs("h1", { className: "text-lg font-bold text-white", children: [
139
+ /* @__PURE__ */ jsxs("h1", { className: "text-base sm:text-lg font-bold text-gray-900 dark:text-white", children: [
131
140
  serviceName,
132
141
  " \uAD6C\uB3C5"
133
142
  ] }),
134
- showExpiredBanner && /* @__PURE__ */ jsx("p", { className: "text-xs text-amber-400 mt-0.5", children: "\uAD6C\uB3C5\uC774 \uB9CC\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uC11C\uBE44\uC2A4\uB97C \uACC4\uC18D \uC774\uC6A9\uD558\uB824\uBA74 \uAD6C\uB3C5\uC774 \uD544\uC694\uD569\uB2C8\uB2E4." })
143
+ showExpiredBanner && /* @__PURE__ */ jsx("p", { className: "text-xs text-amber-600 dark:text-amber-400 mt-0.5", children: "\uAD6C\uB3C5\uC774 \uB9CC\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uC11C\uBE44\uC2A4\uB97C \uACC4\uC18D \uC774\uC6A9\uD558\uB824\uBA74 \uAD6C\uB3C5\uC774 \uD544\uC694\uD569\uB2C8\uB2E4." })
135
144
  ] }),
136
- /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: steps.map((s, i) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
137
- i > 0 && /* @__PURE__ */ jsx("div", { className: "w-4 h-px bg-white/20" }),
138
- /* @__PURE__ */ jsx(
145
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1 sm:gap-2", children: steps.map((s, i) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 sm:gap-2", children: [
146
+ i > 0 && /* @__PURE__ */ jsx(
139
147
  "div",
140
148
  {
141
- className: `w-6 h-6 rounded-full flex items-center justify-center text-xs font-medium ${step === s.key ? "text-white" : "bg-white/10 text-gray-400"}`,
142
- style: step === s.key ? { backgroundColor: primaryColor } : void 0,
143
- children: i + 1
149
+ className: `w-6 sm:w-10 h-px transition-colors ${i <= currentStepIndex ? "bg-blue-500" : "bg-gray-200 dark:bg-white/20"}`
144
150
  }
145
- )
151
+ ),
152
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
153
+ /* @__PURE__ */ jsx(
154
+ "div",
155
+ {
156
+ className: `w-6 h-6 rounded-full flex items-center justify-center text-xs font-medium transition-all ${step === s.key ? "text-white shadow-sm" : i < currentStepIndex ? "text-white" : "bg-gray-100 dark:bg-white/10 text-gray-400 dark:text-gray-500"}`,
157
+ style: step === s.key ? { backgroundColor: primaryColor } : i < currentStepIndex ? { backgroundColor: primaryColor, opacity: 0.5 } : void 0,
158
+ children: i < currentStepIndex ? /* @__PURE__ */ jsx(CheckIcon, { className: "w-3 h-3" }) : i + 1
159
+ }
160
+ ),
161
+ /* @__PURE__ */ jsx(
162
+ "span",
163
+ {
164
+ className: `hidden sm:inline text-xs font-medium ${step === s.key ? "text-gray-900 dark:text-white" : "text-gray-400 dark:text-gray-500"}`,
165
+ children: s.label
166
+ }
167
+ )
168
+ ] })
146
169
  ] }, s.key)) })
147
170
  ] }) }),
148
- /* @__PURE__ */ jsxs("div", { className: "max-w-3xl mx-auto px-4 pb-12", children: [
149
- error && /* @__PURE__ */ jsx("div", { className: "mb-6 p-3 bg-red-500/10 border border-red-500/30 rounded-lg text-red-400 text-sm", children: error }),
171
+ /* @__PURE__ */ jsxs("div", { className: "max-w-3xl mx-auto px-4 sm:px-6 py-6 sm:py-8 pb-16", children: [
172
+ error && /* @__PURE__ */ jsx("div", { className: "mb-5 p-3 bg-red-50 dark:bg-red-500/10 border border-red-200 dark:border-red-500/30 rounded-xl text-red-600 dark:text-red-400 text-sm", children: error }),
150
173
  step === "plan" && /* @__PURE__ */ jsxs("div", { children: [
151
- /* @__PURE__ */ jsx("h2", { className: "text-white font-semibold mb-4", children: "\uD50C\uB79C\uC744 \uC120\uD0DD\uD574\uC8FC\uC138\uC694" }),
174
+ /* @__PURE__ */ jsx("h2", { className: "text-gray-900 dark:text-white font-semibold mb-4 text-sm sm:text-base", children: "\uD50C\uB79C\uC744 \uC120\uD0DD\uD574\uC8FC\uC138\uC694" }),
152
175
  /* @__PURE__ */ jsx("div", { className: "grid gap-3", children: plans.map((plan) => /* @__PURE__ */ jsxs(
153
176
  "button",
154
177
  {
155
178
  onClick: () => setSelectedPlan(plan),
156
- className: `w-full text-left p-4 rounded-xl border transition-all ${selectedPlan?.id === plan.id ? "border-blue-500 bg-blue-500/10" : "border-white/10 bg-white/5 hover:border-white/20"}`,
179
+ className: `w-full text-left p-4 rounded-xl border transition-all ${selectedPlan?.id === plan.id ? "border-blue-500 bg-blue-50 dark:bg-blue-500/10" : "border-gray-200 dark:border-white/10 bg-white dark:bg-white/5 hover:border-gray-300 dark:hover:border-white/20 hover:bg-gray-50 dark:hover:bg-white/8"}`,
157
180
  children: [
158
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-2", children: [
159
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
160
- /* @__PURE__ */ jsx("span", { className: "text-white font-medium", children: plan.name }),
161
- plan.isPopular && /* @__PURE__ */ jsx("span", { className: "px-2 py-0.5 bg-blue-500/20 text-blue-400 text-xs rounded-full border border-blue-500/30", children: "\uC778\uAE30" })
181
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-3 mb-2", children: [
182
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [
183
+ /* @__PURE__ */ jsx("span", { className: "text-gray-900 dark:text-white font-medium text-sm sm:text-base", children: plan.name }),
184
+ plan.isPopular && /* @__PURE__ */ jsx("span", { className: "px-2 py-0.5 bg-blue-100 dark:bg-blue-500/20 text-blue-600 dark:text-blue-400 text-xs rounded-full border border-blue-200 dark:border-blue-500/30", children: "\uC778\uAE30" })
162
185
  ] }),
163
- /* @__PURE__ */ jsxs("div", { className: "text-right", children: [
164
- /* @__PURE__ */ jsx("span", { className: "text-white font-bold", children: fmt(plan.price) }),
165
- /* @__PURE__ */ jsxs("span", { className: "text-gray-400 text-xs ml-1", children: [
186
+ /* @__PURE__ */ jsxs("div", { className: "text-right flex-shrink-0", children: [
187
+ /* @__PURE__ */ jsx("span", { className: "text-gray-900 dark:text-white font-bold text-sm sm:text-base", children: fmt(plan.price) }),
188
+ /* @__PURE__ */ jsxs("span", { className: "text-gray-400 dark:text-gray-500 text-xs ml-1", children: [
166
189
  "/ ",
167
190
  plan.interval,
168
191
  "\uAC1C\uC6D4"
169
192
  ] })
170
193
  ] })
171
194
  ] }),
172
- plan.description && /* @__PURE__ */ jsx("p", { className: "text-gray-400 text-sm mb-2", children: plan.description }),
173
- plan.features.length > 0 && /* @__PURE__ */ jsx("ul", { className: "space-y-1", children: plan.features.slice(0, 3).map((f, i) => /* @__PURE__ */ jsxs("li", { className: "flex items-center gap-1.5 text-xs text-gray-300", children: [
174
- /* @__PURE__ */ jsx(CheckIcon, { className: "w-3 h-3 text-green-400 flex-shrink-0" }),
195
+ plan.description && /* @__PURE__ */ jsx("p", { className: "text-gray-500 dark:text-gray-400 text-sm mb-2", children: plan.description }),
196
+ plan.features.length > 0 && /* @__PURE__ */ jsx("ul", { className: "space-y-1", children: plan.features.slice(0, 3).map((f, idx) => /* @__PURE__ */ jsxs("li", { className: "flex items-center gap-1.5 text-xs text-gray-600 dark:text-gray-300", children: [
197
+ /* @__PURE__ */ jsx(CheckIcon, { className: "w-3 h-3 text-green-500 dark:text-green-400 flex-shrink-0" }),
175
198
  f
176
- ] }, i)) })
199
+ ] }, idx)) })
177
200
  ]
178
201
  },
179
202
  plan.id
@@ -184,26 +207,26 @@ function SubscribePage({
184
207
  disabled: !selectedPlan,
185
208
  onClick: () => setStep("card"),
186
209
  style: selectedPlan ? { backgroundColor: primaryColor } : void 0,
187
- className: `mt-6 w-full py-3 rounded-xl font-medium transition-all ${selectedPlan ? "text-white hover:opacity-90" : "bg-white/10 text-gray-500 cursor-not-allowed"}`,
210
+ className: `mt-6 w-full py-3 rounded-xl font-medium transition-all text-sm sm:text-base ${selectedPlan ? "text-white hover:opacity-90 shadow-sm" : "bg-gray-100 dark:bg-white/10 text-gray-400 dark:text-gray-500 cursor-not-allowed"}`,
188
211
  children: "\uB2E4\uC74C \u2014 \uACB0\uC81C\uC218\uB2E8 \uC120\uD0DD"
189
212
  }
190
213
  )
191
214
  ] }),
192
215
  step === "card" && /* @__PURE__ */ jsxs("div", { children: [
193
- /* @__PURE__ */ jsx("h2", { className: "text-white font-semibold mb-4", children: "\uACB0\uC81C\uC218\uB2E8\uC744 \uC120\uD0DD\uD574\uC8FC\uC138\uC694" }),
216
+ /* @__PURE__ */ jsx("h2", { className: "text-gray-900 dark:text-white font-semibold mb-4 text-sm sm:text-base", children: "\uACB0\uC81C\uC218\uB2E8\uC744 \uC120\uD0DD\uD574\uC8FC\uC138\uC694" }),
194
217
  cards.length > 0 && /* @__PURE__ */ jsx("div", { className: "grid gap-3 mb-4", children: cards.map((card) => /* @__PURE__ */ jsx(
195
218
  "button",
196
219
  {
197
220
  onClick: () => setSelectedCard(card),
198
- className: `w-full text-left p-4 rounded-xl border transition-all ${selectedCard?.id === card.id ? "border-blue-500 bg-blue-500/10" : "border-white/10 bg-white/5 hover:border-white/20"}`,
199
- children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
200
- /* @__PURE__ */ jsxs("div", { children: [
201
- /* @__PURE__ */ jsx("span", { className: "text-white font-medium", children: card.cardBrand }),
202
- /* @__PURE__ */ jsx("span", { className: "text-gray-400 text-sm ml-2", children: card.maskedCardNumber })
221
+ className: `w-full text-left p-4 rounded-xl border transition-all ${selectedCard?.id === card.id ? "border-blue-500 bg-blue-50 dark:bg-blue-500/10" : "border-gray-200 dark:border-white/10 bg-white dark:bg-white/5 hover:border-gray-300 dark:hover:border-white/20"}`,
222
+ children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
223
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
224
+ /* @__PURE__ */ jsx("span", { className: "text-gray-900 dark:text-white font-medium text-sm", children: card.cardBrand }),
225
+ /* @__PURE__ */ jsx("span", { className: "text-gray-500 dark:text-gray-400 text-sm ml-2", children: card.maskedCardNumber })
203
226
  ] }),
204
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
205
- card.isDefault && /* @__PURE__ */ jsx("span", { className: "px-2 py-0.5 bg-blue-500/20 text-blue-400 text-xs rounded-full border border-blue-500/30", children: "\uAE30\uBCF8" }),
206
- /* @__PURE__ */ jsxs("span", { className: "text-gray-400 text-xs", children: [
227
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 flex-shrink-0", children: [
228
+ card.isDefault && /* @__PURE__ */ jsx("span", { className: "px-2 py-0.5 bg-blue-100 dark:bg-blue-500/20 text-blue-600 dark:text-blue-400 text-xs rounded-full border border-blue-200 dark:border-blue-500/30", children: "\uAE30\uBCF8" }),
229
+ /* @__PURE__ */ jsxs("span", { className: "text-gray-400 dark:text-gray-500 text-xs", children: [
207
230
  card.expiryMonth,
208
231
  "/",
209
232
  card.expiryYear
@@ -217,21 +240,21 @@ function SubscribePage({
217
240
  "button",
218
241
  {
219
242
  onClick: () => setShowCardForm(true),
220
- className: "w-full p-4 rounded-xl border border-dashed border-white/20 text-gray-400 hover:border-white/40 hover:text-gray-300 transition-all text-sm",
243
+ className: "w-full p-4 rounded-xl border border-dashed border-gray-300 dark:border-white/20 text-gray-400 dark:text-gray-500 hover:border-gray-400 dark:hover:border-white/40 hover:text-gray-500 dark:hover:text-gray-300 transition-all text-sm",
221
244
  children: "+ \uC0C8 \uCE74\uB4DC \uCD94\uAC00"
222
245
  }
223
- ) : /* @__PURE__ */ jsxs("div", { className: "p-4 rounded-xl border border-white/10 bg-white/5 space-y-3", children: [
224
- /* @__PURE__ */ jsx("h3", { className: "text-white text-sm font-medium mb-1", children: "\uCE74\uB4DC \uC815\uBCF4 \uC785\uB825" }),
225
- cardError && /* @__PURE__ */ jsx("div", { className: "p-3 bg-red-500/10 border border-red-500/30 rounded-lg text-red-400 text-xs", children: cardError }),
226
- [
227
- { label: "\uCE74\uB4DC \uBC88\uD638", key: "cardNumber", placeholder: "0000-0000-0000-0000", type: "text" },
228
- { label: "\uB9CC\uB8CC\uC77C", key: "expiryDate", placeholder: "MM/YY", type: "text" },
229
- { label: "CVC", key: "cvc", placeholder: "3\uC790\uB9AC", type: "password" },
230
- { label: "\uCE74\uB4DC \uBE44\uBC00\uBC88\uD638 \uC55E 2\uC790\uB9AC", key: "cardPassword", placeholder: "\u2022\u2022", type: "password" },
231
- { label: "\uCE74\uB4DC \uC18C\uC720\uC790\uBA85", key: "cardHolderName", placeholder: "\uD64D\uAE38\uB3D9", type: "text" },
232
- { label: "\uC0DD\uB144\uC6D4\uC77C 6\uC790\uB9AC / \uC0AC\uC5C5\uC790\uBC88\uD638 10\uC790\uB9AC", key: "birthNumber", placeholder: "990101", type: "text" }
233
- ].map(({ label, key, placeholder, type }) => /* @__PURE__ */ jsxs("div", { children: [
234
- /* @__PURE__ */ jsx("label", { className: "text-xs text-gray-400 block mb-1", children: label }),
246
+ ) : /* @__PURE__ */ jsxs("div", { className: "p-4 rounded-xl border border-gray-200 dark:border-white/10 bg-gray-50 dark:bg-white/5 space-y-3", children: [
247
+ /* @__PURE__ */ jsx("h3", { className: "text-gray-900 dark:text-white text-sm font-medium", children: "\uCE74\uB4DC \uC815\uBCF4 \uC785\uB825" }),
248
+ cardError && /* @__PURE__ */ jsx("div", { className: "p-3 bg-red-50 dark:bg-red-500/10 border border-red-200 dark:border-red-500/30 rounded-lg text-red-600 dark:text-red-400 text-xs", children: cardError }),
249
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-3", children: [
250
+ { label: "\uCE74\uB4DC \uBC88\uD638", key: "cardNumber", placeholder: "0000-0000-0000-0000", type: "text", colSpan: true },
251
+ { label: "\uB9CC\uB8CC\uC77C", key: "expiryDate", placeholder: "MM/YY", type: "text", colSpan: false },
252
+ { label: "CVC", key: "cvc", placeholder: "3\uC790\uB9AC", type: "password", colSpan: false },
253
+ { label: "\uCE74\uB4DC \uBE44\uBC00\uBC88\uD638 \uC55E 2\uC790\uB9AC", key: "cardPassword", placeholder: "\u2022\u2022", type: "password", colSpan: false },
254
+ { label: "\uCE74\uB4DC \uC18C\uC720\uC790\uBA85", key: "cardHolderName", placeholder: "\uD64D\uAE38\uB3D9", type: "text", colSpan: false },
255
+ { label: "\uC0DD\uB144\uC6D4\uC77C 6\uC790\uB9AC / \uC0AC\uC5C5\uC790\uBC88\uD638 10\uC790\uB9AC", key: "birthNumber", placeholder: "990101", type: "text", colSpan: true }
256
+ ].map(({ label, key, placeholder, type, colSpan }) => /* @__PURE__ */ jsxs("div", { className: colSpan ? "sm:col-span-2" : "", children: [
257
+ /* @__PURE__ */ jsx("label", { className: "text-xs text-gray-500 dark:text-gray-400 block mb-1", children: label }),
235
258
  /* @__PURE__ */ jsx(
236
259
  "input",
237
260
  {
@@ -239,10 +262,10 @@ function SubscribePage({
239
262
  placeholder,
240
263
  value: cardForm[key],
241
264
  onChange: (e) => setCardForm((f) => ({ ...f, [key]: e.target.value })),
242
- className: "w-full bg-white/5 border border-white/10 rounded-lg px-3 py-2 text-white text-sm placeholder-gray-600 focus:outline-none focus:border-blue-500"
265
+ className: "w-full bg-white dark:bg-white/5 border border-gray-200 dark:border-white/10 rounded-lg px-3 py-2 text-gray-900 dark:text-white text-sm placeholder-gray-300 dark:placeholder-gray-600 focus:outline-none focus:border-blue-500 dark:focus:border-blue-500 transition-colors"
243
266
  }
244
267
  )
245
- ] }, key)),
268
+ ] }, key)) }),
246
269
  /* @__PURE__ */ jsxs("div", { className: "flex gap-2 pt-1", children: [
247
270
  /* @__PURE__ */ jsx(
248
271
  "button",
@@ -251,7 +274,7 @@ function SubscribePage({
251
274
  setShowCardForm(false);
252
275
  setCardError("");
253
276
  },
254
- className: "flex-1 py-2 rounded-lg border border-white/10 text-gray-400 text-sm hover:border-white/20 transition-all",
277
+ className: "flex-1 py-2.5 rounded-lg border border-gray-200 dark:border-white/10 text-gray-500 dark:text-gray-400 text-sm hover:border-gray-300 dark:hover:border-white/20 transition-all",
255
278
  children: "\uCDE8\uC18C"
256
279
  }
257
280
  ),
@@ -261,36 +284,46 @@ function SubscribePage({
261
284
  onClick: handleRegisterCard,
262
285
  disabled: cardSubmitting,
263
286
  style: { backgroundColor: primaryColor },
264
- className: "flex-1 py-2 rounded-lg text-white text-sm font-medium hover:opacity-90 disabled:opacity-50 transition-all",
287
+ className: "flex-1 py-2.5 rounded-lg text-white text-sm font-medium hover:opacity-90 disabled:opacity-50 transition-all",
265
288
  children: cardSubmitting ? "\uB4F1\uB85D \uC911..." : "\uCE74\uB4DC \uB4F1\uB85D"
266
289
  }
267
290
  )
268
291
  ] })
269
292
  ] }),
270
293
  /* @__PURE__ */ jsxs("div", { className: "flex gap-3 mt-6", children: [
271
- /* @__PURE__ */ jsx("button", { onClick: () => setStep("plan"), className: "flex-1 py-3 rounded-xl border border-white/10 text-gray-400 font-medium hover:border-white/20 transition-all", children: "\uC774\uC804" }),
272
294
  /* @__PURE__ */ jsx(
295
+ "button",
296
+ {
297
+ onClick: () => setStep("plan"),
298
+ className: "flex-1 py-3 rounded-xl border border-gray-200 dark:border-white/10 text-gray-500 dark:text-gray-400 font-medium text-sm hover:border-gray-300 dark:hover:border-white/20 transition-all",
299
+ children: "\uC774\uC804"
300
+ }
301
+ ),
302
+ /* @__PURE__ */ jsxs(
273
303
  "button",
274
304
  {
275
305
  disabled: !selectedCard,
276
306
  onClick: () => setStep("confirm"),
277
307
  style: selectedCard ? { backgroundColor: primaryColor } : void 0,
278
- className: `flex-1 py-3 rounded-xl font-medium transition-all ${selectedCard ? "text-white hover:opacity-90" : "bg-white/10 text-gray-500 cursor-not-allowed"}`,
279
- children: "\uB2E4\uC74C \u2014 \uCD5C\uC885 \uD655\uC778"
308
+ className: `flex-1 py-3 rounded-xl font-medium text-sm transition-all ${selectedCard ? "text-white hover:opacity-90 shadow-sm" : "bg-gray-100 dark:bg-white/10 text-gray-400 dark:text-gray-500 cursor-not-allowed"}`,
309
+ children: [
310
+ /* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: "\uB2E4\uC74C \u2014 \uCD5C\uC885 \uD655\uC778" }),
311
+ /* @__PURE__ */ jsx("span", { className: "sm:hidden", children: "\uB2E4\uC74C" })
312
+ ]
280
313
  }
281
314
  )
282
315
  ] })
283
316
  ] }),
284
317
  step === "confirm" && selectedPlan && selectedCard && /* @__PURE__ */ jsxs("div", { children: [
285
- /* @__PURE__ */ jsx("h2", { className: "text-white font-semibold mb-6", children: "\uAD6C\uB3C5 \uB0B4\uC6A9\uC744 \uD655\uC778\uD574\uC8FC\uC138\uC694" }),
318
+ /* @__PURE__ */ jsx("h2", { className: "text-gray-900 dark:text-white font-semibold mb-5 text-sm sm:text-base", children: "\uAD6C\uB3C5 \uB0B4\uC6A9\uC744 \uD655\uC778\uD574\uC8FC\uC138\uC694" }),
286
319
  /* @__PURE__ */ jsxs("div", { className: "space-y-3 mb-6", children: [
287
- /* @__PURE__ */ jsxs("div", { className: "p-4 rounded-xl border border-white/10 bg-white/5", children: [
288
- /* @__PURE__ */ jsx("p", { className: "text-xs text-gray-400 mb-1", children: "\uC120\uD0DD \uD50C\uB79C" }),
289
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
290
- /* @__PURE__ */ jsx("span", { className: "text-white font-medium", children: selectedPlan.name }),
291
- /* @__PURE__ */ jsxs("span", { className: "text-white font-bold", children: [
320
+ /* @__PURE__ */ jsxs("div", { className: "p-4 rounded-xl border border-gray-200 dark:border-white/10 bg-white dark:bg-white/5", children: [
321
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-gray-400 dark:text-gray-500 mb-1.5", children: "\uC120\uD0DD \uD50C\uB79C" }),
322
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3", children: [
323
+ /* @__PURE__ */ jsx("span", { className: "text-gray-900 dark:text-white font-medium text-sm", children: selectedPlan.name }),
324
+ /* @__PURE__ */ jsxs("span", { className: "text-gray-900 dark:text-white font-bold text-sm flex-shrink-0", children: [
292
325
  fmt(selectedPlan.price),
293
- /* @__PURE__ */ jsxs("span", { className: "text-gray-400 text-xs font-normal ml-1", children: [
326
+ /* @__PURE__ */ jsxs("span", { className: "text-gray-400 dark:text-gray-500 text-xs font-normal ml-1", children: [
294
327
  "/ ",
295
328
  selectedPlan.interval,
296
329
  "\uAC1C\uC6D4"
@@ -298,34 +331,48 @@ function SubscribePage({
298
331
  ] })
299
332
  ] })
300
333
  ] }),
301
- /* @__PURE__ */ jsxs("div", { className: "p-4 rounded-xl border border-white/10 bg-white/5", children: [
302
- /* @__PURE__ */ jsx("p", { className: "text-xs text-gray-400 mb-1", children: "\uACB0\uC81C\uC218\uB2E8" }),
334
+ /* @__PURE__ */ jsxs("div", { className: "p-4 rounded-xl border border-gray-200 dark:border-white/10 bg-white dark:bg-white/5", children: [
335
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-gray-400 dark:text-gray-500 mb-1.5", children: "\uACB0\uC81C\uC218\uB2E8" }),
303
336
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
304
- /* @__PURE__ */ jsx("span", { className: "text-white font-medium", children: selectedCard.cardBrand }),
305
- /* @__PURE__ */ jsx("span", { className: "text-gray-400 text-sm", children: selectedCard.maskedCardNumber })
337
+ /* @__PURE__ */ jsx("span", { className: "text-gray-900 dark:text-white font-medium text-sm", children: selectedCard.cardBrand }),
338
+ /* @__PURE__ */ jsx("span", { className: "text-gray-500 dark:text-gray-400 text-sm", children: selectedCard.maskedCardNumber })
306
339
  ] })
307
340
  ] }),
308
- /* @__PURE__ */ jsxs("div", { className: "p-4 rounded-xl border border-white/10 bg-white/5", style: { borderColor: `${primaryColor}4D` }, children: [
309
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
310
- /* @__PURE__ */ jsx("span", { className: "text-gray-300 text-sm", children: "\uACB0\uC81C \uAE08\uC561" }),
311
- /* @__PURE__ */ jsx("span", { className: "font-bold text-lg", style: { color: primaryColor }, children: fmt(selectedPlan.price) })
312
- ] }),
313
- /* @__PURE__ */ jsxs("p", { className: "text-gray-500 text-xs mt-1", children: [
314
- "\uC624\uB298 \uACB0\uC81C \uD6C4 ",
315
- selectedPlan.interval,
316
- "\uAC1C\uC6D4 \uAC04 \uC774\uC6A9 \uAC00\uB2A5\uD569\uB2C8\uB2E4"
317
- ] })
318
- ] })
341
+ /* @__PURE__ */ jsxs(
342
+ "div",
343
+ {
344
+ className: "p-4 rounded-xl border bg-blue-50/50 dark:bg-blue-500/5",
345
+ style: { borderColor: `${primaryColor}40` },
346
+ children: [
347
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3", children: [
348
+ /* @__PURE__ */ jsx("span", { className: "text-gray-600 dark:text-gray-300 text-sm", children: "\uACB0\uC81C \uAE08\uC561" }),
349
+ /* @__PURE__ */ jsx("span", { className: "font-bold text-xl", style: { color: primaryColor }, children: fmt(selectedPlan.price) })
350
+ ] }),
351
+ /* @__PURE__ */ jsxs("p", { className: "text-gray-400 dark:text-gray-500 text-xs mt-1.5", children: [
352
+ "\uC624\uB298 \uACB0\uC81C \uD6C4 ",
353
+ selectedPlan.interval,
354
+ "\uAC1C\uC6D4 \uAC04 \uC774\uC6A9 \uAC00\uB2A5\uD569\uB2C8\uB2E4"
355
+ ] })
356
+ ]
357
+ }
358
+ )
319
359
  ] }),
320
360
  /* @__PURE__ */ jsxs("div", { className: "flex gap-3", children: [
321
- /* @__PURE__ */ jsx("button", { onClick: () => setStep("card"), className: "flex-1 py-3 rounded-xl border border-white/10 text-gray-400 font-medium hover:border-white/20 transition-all", children: "\uC774\uC804" }),
361
+ /* @__PURE__ */ jsx(
362
+ "button",
363
+ {
364
+ onClick: () => setStep("card"),
365
+ className: "flex-1 py-3 rounded-xl border border-gray-200 dark:border-white/10 text-gray-500 dark:text-gray-400 font-medium text-sm hover:border-gray-300 dark:hover:border-white/20 transition-all",
366
+ children: "\uC774\uC804"
367
+ }
368
+ ),
322
369
  /* @__PURE__ */ jsx(
323
370
  "button",
324
371
  {
325
372
  onClick: handleSubscribe,
326
373
  disabled: submitting,
327
374
  style: { backgroundColor: primaryColor },
328
- className: "flex-1 py-3 rounded-xl text-white font-medium hover:opacity-90 disabled:opacity-50 transition-all",
375
+ className: "flex-1 py-3 rounded-xl text-white font-medium text-sm hover:opacity-90 disabled:opacity-50 transition-all shadow-sm",
329
376
  children: submitting ? "\uCC98\uB9AC \uC911..." : `${fmt(selectedPlan.price)} \uACB0\uC81C\uD558\uAE30`
330
377
  }
331
378
  )
@@ -334,12 +381,243 @@ function SubscribePage({
334
381
  ] })
335
382
  ] });
336
383
  }
337
- function PageLayout({ children }) {
338
- return /* @__PURE__ */ jsx("div", { className: "min-h-screen bg-gray-950", children });
384
+ function PageLayout({ children, themeClass }) {
385
+ return /* @__PURE__ */ jsx("div", { className: themeClass, children: /* @__PURE__ */ jsx("div", { className: "min-h-screen bg-white dark:bg-gray-950 transition-colors", children }) });
339
386
  }
340
387
  function CheckIcon({ className }) {
341
388
  return /* @__PURE__ */ jsx("svg", { className, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 13l4 4L19 7" }) });
342
389
  }
390
+
391
+ // src/components/SubscriptionManagement.tsx
392
+ import { useState as useState2, useEffect as useEffect2 } from "react";
393
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
394
+ var DEFAULT_PRIMARY2 = "#60A5FA";
395
+ function SubscriptionManagement({
396
+ subscriptionsApiPath = "/api/subscribe/subscriptions",
397
+ paymentsApiPath = "/api/subscribe/payments",
398
+ primaryColor = DEFAULT_PRIMARY2,
399
+ theme = "system"
400
+ }) {
401
+ const [tab, setTab] = useState2("subscription");
402
+ const [subscriptions, setSubscriptions] = useState2([]);
403
+ const [payments, setPayments] = useState2([]);
404
+ const [loading, setLoading] = useState2(true);
405
+ const [error, setError] = useState2("");
406
+ const [actionLoading, setActionLoading] = useState2(null);
407
+ const [confirmModal, setConfirmModal] = useState2(null);
408
+ const themeClass = theme === "dark" ? "dark" : theme === "light" ? "light-mode-override" : "";
409
+ useEffect2(() => {
410
+ fetchSubscriptions();
411
+ fetchPayments();
412
+ }, []);
413
+ async function fetchSubscriptions() {
414
+ try {
415
+ const res = await fetch(subscriptionsApiPath);
416
+ const data = await res.json();
417
+ if (data.success) setSubscriptions(data.subscriptions);
418
+ } catch {
419
+ } finally {
420
+ setLoading(false);
421
+ }
422
+ }
423
+ async function fetchPayments() {
424
+ try {
425
+ const res = await fetch(paymentsApiPath);
426
+ const data = await res.json();
427
+ if (data.success) setPayments(data.payments);
428
+ } catch {
429
+ }
430
+ }
431
+ async function handleCancelSubscription(subscriptionId) {
432
+ setActionLoading(subscriptionId);
433
+ setError("");
434
+ try {
435
+ const res = await fetch(subscriptionsApiPath, {
436
+ method: "DELETE",
437
+ headers: { "Content-Type": "application/json" },
438
+ body: JSON.stringify({ subscriptionId })
439
+ });
440
+ const data = await res.json();
441
+ if (!data.success) {
442
+ setError(data.error || "\uAD6C\uB3C5 \uCDE8\uC18C\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4.");
443
+ return;
444
+ }
445
+ await fetchSubscriptions();
446
+ } catch {
447
+ setError("\uAD6C\uB3C5 \uCDE8\uC18C \uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.");
448
+ } finally {
449
+ setActionLoading(null);
450
+ setConfirmModal(null);
451
+ }
452
+ }
453
+ async function handleCancelPayment(paymentId) {
454
+ setActionLoading(paymentId);
455
+ setError("");
456
+ try {
457
+ const res = await fetch(paymentsApiPath, {
458
+ method: "POST",
459
+ headers: { "Content-Type": "application/json" },
460
+ body: JSON.stringify({ paymentId })
461
+ });
462
+ const data = await res.json();
463
+ if (!data.success) {
464
+ setError(data.error || "\uACB0\uC81C \uCDE8\uC18C\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4.");
465
+ return;
466
+ }
467
+ await fetchPayments();
468
+ await fetchSubscriptions();
469
+ } catch {
470
+ setError("\uACB0\uC81C \uCDE8\uC18C \uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.");
471
+ } finally {
472
+ setActionLoading(null);
473
+ setConfirmModal(null);
474
+ }
475
+ }
476
+ function fmt(price) {
477
+ return price.toLocaleString("ko-KR") + "\uC6D0";
478
+ }
479
+ function fmtDate(dateStr) {
480
+ return new Date(dateStr).toLocaleDateString("ko-KR", { year: "numeric", month: "long", day: "numeric" });
481
+ }
482
+ function statusBadge(status) {
483
+ if (status === "ACTIVE") return { bg: "bg-green-100 dark:bg-green-500/20", text: "text-green-700 dark:text-green-400", label: "\uD65C\uC131" };
484
+ if (status === "CANCELLED") return { bg: "bg-red-100 dark:bg-red-500/20", text: "text-red-700 dark:text-red-400", label: "\uCDE8\uC18C\uB428" };
485
+ return { bg: "bg-gray-100 dark:bg-gray-700", text: "text-gray-600 dark:text-gray-400", label: status };
486
+ }
487
+ function paymentStatusBadge(status) {
488
+ if (status === "COMPLETED") return { bg: "bg-green-100 dark:bg-green-500/20", text: "text-green-700 dark:text-green-400", label: "\uC644\uB8CC" };
489
+ if (status === "CANCELLED") return { bg: "bg-red-100 dark:bg-red-500/20", text: "text-red-700 dark:text-red-400", label: "\uCDE8\uC18C\uB428" };
490
+ if (status === "FAILED") return { bg: "bg-orange-100 dark:bg-orange-500/20", text: "text-orange-700 dark:text-orange-400", label: "\uC2E4\uD328" };
491
+ return { bg: "bg-gray-100 dark:bg-gray-700", text: "text-gray-600 dark:text-gray-400", label: status };
492
+ }
493
+ function canCancelPayment(p) {
494
+ if (p.status !== "COMPLETED") return false;
495
+ const paidDate = new Date(p.paidAt || p.createdAt);
496
+ const daysDiff = Math.ceil((Date.now() - paidDate.getTime()) / (1e3 * 3600 * 24));
497
+ return daysDiff <= 7;
498
+ }
499
+ if (loading) return /* @__PURE__ */ jsx2("div", { className: themeClass, children: /* @__PURE__ */ jsx2("div", { className: "text-gray-400 py-8 text-center", children: "\uBD88\uB7EC\uC624\uB294 \uC911..." }) });
500
+ return /* @__PURE__ */ jsx2("div", { className: themeClass, children: /* @__PURE__ */ jsxs2("div", { className: "space-y-4", children: [
501
+ error && /* @__PURE__ */ jsx2("div", { className: "p-3 bg-red-50 dark:bg-red-500/10 border border-red-200 dark:border-red-500/30 rounded-lg text-red-600 dark:text-red-400 text-sm", children: error }),
502
+ /* @__PURE__ */ jsx2("div", { className: "flex border-b border-gray-200 dark:border-white/10", children: [
503
+ { key: "subscription", label: "\uAD6C\uB3C5 \uC815\uBCF4" },
504
+ { key: "payments", label: "\uACB0\uC81C \uC774\uB825" }
505
+ ].map(({ key, label }) => /* @__PURE__ */ jsx2(
506
+ "button",
507
+ {
508
+ onClick: () => setTab(key),
509
+ className: `px-4 py-2.5 text-sm font-medium border-b-2 transition-colors -mb-px ${tab === key ? "border-current text-blue-600 dark:text-blue-400" : "border-transparent text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300"}`,
510
+ style: tab === key ? { color: primaryColor, borderColor: primaryColor } : void 0,
511
+ children: label
512
+ },
513
+ key
514
+ )) }),
515
+ tab === "subscription" && /* @__PURE__ */ jsx2("div", { className: "space-y-3", children: subscriptions.length === 0 ? /* @__PURE__ */ jsx2("div", { className: "text-center py-12 text-gray-400 dark:text-gray-500 text-sm", children: "\uD65C\uC131 \uAD6C\uB3C5\uC774 \uC5C6\uC2B5\uB2C8\uB2E4." }) : subscriptions.map((sub) => {
516
+ const badge = statusBadge(sub.status);
517
+ return /* @__PURE__ */ jsx2("div", { className: "p-4 sm:p-5 rounded-xl border border-gray-200 dark:border-white/10 bg-white dark:bg-white/5", children: /* @__PURE__ */ jsxs2("div", { className: "flex flex-col sm:flex-row sm:items-start sm:justify-between gap-3", children: [
518
+ /* @__PURE__ */ jsxs2("div", { className: "space-y-2 flex-1 min-w-0", children: [
519
+ /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 flex-wrap", children: [
520
+ /* @__PURE__ */ jsx2("span", { className: "text-gray-900 dark:text-white font-semibold text-base", children: sub.plan.name }),
521
+ /* @__PURE__ */ jsx2("span", { className: `px-2 py-0.5 rounded-full text-xs font-medium ${badge.bg} ${badge.text}`, children: badge.label }),
522
+ sub.isTrial && /* @__PURE__ */ jsx2("span", { className: "px-2 py-0.5 rounded-full text-xs font-medium bg-purple-100 dark:bg-purple-500/20 text-purple-700 dark:text-purple-400", children: "\uCCB4\uD5D8" })
523
+ ] }),
524
+ /* @__PURE__ */ jsxs2("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-x-8 gap-y-1 text-sm", children: [
525
+ /* @__PURE__ */ jsxs2("div", { children: [
526
+ /* @__PURE__ */ jsx2("span", { className: "text-gray-400 dark:text-gray-500", children: "\uAE08\uC561" }),
527
+ /* @__PURE__ */ jsxs2("span", { className: "ml-2 text-gray-700 dark:text-gray-300 font-medium", children: [
528
+ fmt(sub.plan.price),
529
+ " / ",
530
+ sub.plan.interval,
531
+ "\uAC1C\uC6D4"
532
+ ] })
533
+ ] }),
534
+ /* @__PURE__ */ jsxs2("div", { children: [
535
+ /* @__PURE__ */ jsx2("span", { className: "text-gray-400 dark:text-gray-500", children: "\uC0C1\uD0DC" }),
536
+ /* @__PURE__ */ jsx2("span", { className: "ml-2 text-gray-700 dark:text-gray-300", children: sub.statusMessage })
537
+ ] }),
538
+ /* @__PURE__ */ jsxs2("div", { children: [
539
+ /* @__PURE__ */ jsx2("span", { className: "text-gray-400 dark:text-gray-500", children: "\uC2DC\uC791\uC77C" }),
540
+ /* @__PURE__ */ jsx2("span", { className: "ml-2 text-gray-700 dark:text-gray-300", children: fmtDate(sub.startDate) })
541
+ ] }),
542
+ /* @__PURE__ */ jsxs2("div", { children: [
543
+ /* @__PURE__ */ jsx2("span", { className: "text-gray-400 dark:text-gray-500", children: "\uB9CC\uB8CC\uC77C" }),
544
+ /* @__PURE__ */ jsx2("span", { className: "ml-2 text-gray-700 dark:text-gray-300", children: fmtDate(sub.endDate) })
545
+ ] }),
546
+ /* @__PURE__ */ jsxs2("div", { children: [
547
+ /* @__PURE__ */ jsx2("span", { className: "text-gray-400 dark:text-gray-500", children: "\uB0A8\uC740 \uAE30\uAC04" }),
548
+ /* @__PURE__ */ jsxs2("span", { className: "ml-2 text-gray-700 dark:text-gray-300 font-medium", children: [
549
+ sub.remainingDays,
550
+ "\uC77C"
551
+ ] })
552
+ ] }),
553
+ /* @__PURE__ */ jsxs2("div", { children: [
554
+ /* @__PURE__ */ jsx2("span", { className: "text-gray-400 dark:text-gray-500", children: "\uC790\uB3D9\uACB0\uC81C" }),
555
+ /* @__PURE__ */ jsx2("span", { className: "ml-2 text-gray-700 dark:text-gray-300", children: sub.autoRenew ? "\uC0AC\uC6A9" : "\uD574\uC81C" })
556
+ ] })
557
+ ] })
558
+ ] }),
559
+ sub.status === "ACTIVE" && /* @__PURE__ */ jsx2(
560
+ "button",
561
+ {
562
+ onClick: () => setConfirmModal({ type: "cancel_subscription", id: sub.id, label: sub.plan.name }),
563
+ disabled: actionLoading === sub.id,
564
+ className: "flex-shrink-0 px-4 py-2 rounded-lg border border-red-200 dark:border-red-500/30 text-red-600 dark:text-red-400 text-sm font-medium hover:bg-red-50 dark:hover:bg-red-500/10 disabled:opacity-50 transition-all",
565
+ children: "\uAD6C\uB3C5 \uCDE8\uC18C"
566
+ }
567
+ )
568
+ ] }) }, sub.id);
569
+ }) }),
570
+ tab === "payments" && /* @__PURE__ */ jsx2("div", { className: "space-y-2", children: payments.length === 0 ? /* @__PURE__ */ jsx2("div", { className: "text-center py-12 text-gray-400 dark:text-gray-500 text-sm", children: "\uACB0\uC81C \uC774\uB825\uC774 \uC5C6\uC2B5\uB2C8\uB2E4." }) : /* @__PURE__ */ jsx2("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs2("table", { className: "w-full text-sm", children: [
571
+ /* @__PURE__ */ jsx2("thead", { children: /* @__PURE__ */ jsx2("tr", { className: "border-b border-gray-200 dark:border-white/10", children: ["\uC77C\uC2DC", "\uB0B4\uC6A9", "\uAE08\uC561", "\uACB0\uC81C\uC218\uB2E8", "\uC0C1\uD0DC", ""].map((h) => /* @__PURE__ */ jsx2("th", { className: "text-left py-2.5 px-3 text-xs font-medium text-gray-400 dark:text-gray-500 whitespace-nowrap", children: h }, h)) }) }),
572
+ /* @__PURE__ */ jsx2("tbody", { children: payments.map((p) => {
573
+ const badge = paymentStatusBadge(p.status);
574
+ return /* @__PURE__ */ jsxs2("tr", { className: "border-b border-gray-100 dark:border-white/5 last:border-0", children: [
575
+ /* @__PURE__ */ jsx2("td", { className: "py-3 px-3 text-gray-600 dark:text-gray-300 whitespace-nowrap", children: fmtDate(p.paidAt || p.createdAt) }),
576
+ /* @__PURE__ */ jsx2("td", { className: "py-3 px-3 text-gray-900 dark:text-white font-medium", children: p.orderName }),
577
+ /* @__PURE__ */ jsx2("td", { className: "py-3 px-3 text-gray-900 dark:text-white font-semibold whitespace-nowrap", children: fmt(p.amount) }),
578
+ /* @__PURE__ */ jsx2("td", { className: "py-3 px-3 text-gray-500 dark:text-gray-400 whitespace-nowrap", children: p.cardBrand && p.maskedCardNumber ? `${p.cardBrand} ${p.maskedCardNumber}` : "-" }),
579
+ /* @__PURE__ */ jsx2("td", { className: "py-3 px-3", children: /* @__PURE__ */ jsx2("span", { className: `px-2 py-0.5 rounded-full text-xs font-medium ${badge.bg} ${badge.text}`, children: badge.label }) }),
580
+ /* @__PURE__ */ jsx2("td", { className: "py-3 px-3", children: canCancelPayment(p) && /* @__PURE__ */ jsx2(
581
+ "button",
582
+ {
583
+ onClick: () => setConfirmModal({ type: "cancel_payment", id: p.id, label: p.orderName }),
584
+ disabled: actionLoading === p.id,
585
+ className: "text-xs text-red-500 dark:text-red-400 hover:underline disabled:opacity-50",
586
+ children: "\uCDE8\uC18C"
587
+ }
588
+ ) })
589
+ ] }, p.id);
590
+ }) })
591
+ ] }) }) }),
592
+ confirmModal && /* @__PURE__ */ jsx2("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4", children: /* @__PURE__ */ jsxs2("div", { className: "bg-white dark:bg-gray-900 rounded-2xl p-6 max-w-sm w-full shadow-xl", children: [
593
+ /* @__PURE__ */ jsx2("h3", { className: "text-gray-900 dark:text-white font-semibold text-base mb-2", children: confirmModal.type === "cancel_subscription" ? "\uAD6C\uB3C5 \uCDE8\uC18C" : "\uACB0\uC81C \uCDE8\uC18C" }),
594
+ /* @__PURE__ */ jsxs2("p", { className: "text-gray-500 dark:text-gray-400 text-sm mb-5", children: [
595
+ /* @__PURE__ */ jsx2("span", { className: "text-gray-900 dark:text-white font-medium", children: confirmModal.label }),
596
+ confirmModal.type === "cancel_subscription" ? "\uC744(\uB97C) \uCDE8\uC18C\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C? \uD604\uC7AC \uAD6C\uB3C5 \uAE30\uAC04\uC774 \uB05D\uB098\uBA74 \uC11C\uBE44\uC2A4\uB97C \uC774\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4." : "\uC758 \uACB0\uC81C\uB97C \uCDE8\uC18C\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C? \uC774 \uC791\uC5C5\uC740 \uB418\uB3CC\uB9B4 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4."
597
+ ] }),
598
+ /* @__PURE__ */ jsxs2("div", { className: "flex gap-2", children: [
599
+ /* @__PURE__ */ jsx2(
600
+ "button",
601
+ {
602
+ onClick: () => setConfirmModal(null),
603
+ className: "flex-1 py-2.5 rounded-lg border border-gray-200 dark:border-white/10 text-gray-500 dark:text-gray-400 text-sm hover:border-gray-300 dark:hover:border-white/20 transition-all",
604
+ children: "\uC544\uB2C8\uC624"
605
+ }
606
+ ),
607
+ /* @__PURE__ */ jsx2(
608
+ "button",
609
+ {
610
+ onClick: () => confirmModal.type === "cancel_subscription" ? handleCancelSubscription(confirmModal.id) : handleCancelPayment(confirmModal.id),
611
+ disabled: !!actionLoading,
612
+ className: "flex-1 py-2.5 rounded-lg bg-red-500 text-white text-sm font-medium hover:bg-red-600 disabled:opacity-50 transition-all",
613
+ children: actionLoading ? "\uCC98\uB9AC \uC911..." : "\uC608, \uCDE8\uC18C\uD569\uB2C8\uB2E4"
614
+ }
615
+ )
616
+ ] })
617
+ ] }) })
618
+ ] }) });
619
+ }
343
620
  export {
344
- SubscribePage
621
+ SubscribePage,
622
+ SubscriptionManagement
345
623
  };