@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.d.mts +57 -2
- package/dist/index.d.ts +57 -2
- package/dist/index.js +369 -91
- package/dist/index.mjs +368 -90
- package/package.json +1 -1
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 =
|
|
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
|
-
|
|
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-
|
|
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
|
-
|
|
128
|
-
|
|
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(
|
|
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
|
|
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-
|
|
149
|
-
error && /* @__PURE__ */ jsx("div", { className: "mb-
|
|
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-
|
|
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,
|
|
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
|
-
] },
|
|
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
|
|
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:
|
|
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-
|
|
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(
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
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(
|
|
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
|
};
|