@doujins/payments-ui 0.1.16 → 0.1.17-alpha
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.cjs +823 -129
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +306 -68
- package/dist/index.d.ts +306 -68
- package/dist/index.js +821 -131
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -281,6 +281,7 @@ var createClient = (config) => {
|
|
|
281
281
|
return normalizeList(result);
|
|
282
282
|
},
|
|
283
283
|
createPaymentMethod(payload) {
|
|
284
|
+
console.log("Creating payment method with payload:", payload);
|
|
284
285
|
return request("POST", "/me/payment-methods", {
|
|
285
286
|
body: payload
|
|
286
287
|
});
|
|
@@ -298,10 +299,10 @@ var createClient = (config) => {
|
|
|
298
299
|
},
|
|
299
300
|
checkout(payload, idempotencyKey) {
|
|
300
301
|
const key = idempotencyKey ?? crypto.randomUUID();
|
|
301
|
-
return request("POST", "/
|
|
302
|
+
return request("POST", "/checkout", {
|
|
302
303
|
body: payload,
|
|
303
304
|
headers: {
|
|
304
|
-
"Idempotency-Key": key
|
|
305
|
+
"X-Idempotency-Key": key
|
|
305
306
|
}
|
|
306
307
|
});
|
|
307
308
|
},
|
|
@@ -310,6 +311,36 @@ var createClient = (config) => {
|
|
|
310
311
|
body: feedback ? { feedback } : void 0
|
|
311
312
|
});
|
|
312
313
|
},
|
|
314
|
+
async listSubscriptions(params) {
|
|
315
|
+
const result = await request(
|
|
316
|
+
"GET",
|
|
317
|
+
"/me/subscriptions",
|
|
318
|
+
{
|
|
319
|
+
query: {
|
|
320
|
+
status: params?.status,
|
|
321
|
+
limit: params?.limit,
|
|
322
|
+
offset: params?.offset
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
);
|
|
326
|
+
return normalizeList(result);
|
|
327
|
+
},
|
|
328
|
+
updateSubscriptionPaymentMethod(payload) {
|
|
329
|
+
return request("PUT", "/me/subscriptions/payment-method", {
|
|
330
|
+
body: {
|
|
331
|
+
subscription_id: payload.subscription_id,
|
|
332
|
+
payment_method_id: payload.payment_method_id
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
},
|
|
336
|
+
resumeSubscription() {
|
|
337
|
+
return request("POST", "/me/subscriptions/resume");
|
|
338
|
+
},
|
|
339
|
+
changeSubscription(payload) {
|
|
340
|
+
return request("POST", "/me/subscriptions/change", {
|
|
341
|
+
body: payload
|
|
342
|
+
});
|
|
343
|
+
},
|
|
313
344
|
async getPaymentHistory(params) {
|
|
314
345
|
const result = await request("GET", "/me/payments", {
|
|
315
346
|
query: {
|
|
@@ -455,6 +486,19 @@ function DialogHeader({ className, ...props }) {
|
|
|
455
486
|
}
|
|
456
487
|
);
|
|
457
488
|
}
|
|
489
|
+
function DialogFooter({ className, ...props }) {
|
|
490
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
491
|
+
"div",
|
|
492
|
+
{
|
|
493
|
+
"data-slot": "dialog-footer",
|
|
494
|
+
className: cn(
|
|
495
|
+
"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
|
|
496
|
+
className
|
|
497
|
+
),
|
|
498
|
+
...props
|
|
499
|
+
}
|
|
500
|
+
);
|
|
501
|
+
}
|
|
458
502
|
function DialogTitle({
|
|
459
503
|
className,
|
|
460
504
|
...props
|
|
@@ -709,6 +753,28 @@ var defaultBillingDetails = {
|
|
|
709
753
|
email: "",
|
|
710
754
|
provider: "mobius"
|
|
711
755
|
};
|
|
756
|
+
var defaultCardDetailsFormTranslations = {
|
|
757
|
+
firstName: "First name",
|
|
758
|
+
lastName: "Last name",
|
|
759
|
+
email: "Email",
|
|
760
|
+
address: "Address",
|
|
761
|
+
city: "City",
|
|
762
|
+
state: "State / Region",
|
|
763
|
+
postalCode: "Postal code",
|
|
764
|
+
country: "Country",
|
|
765
|
+
cardNumber: "Card number",
|
|
766
|
+
expiry: "Expiry",
|
|
767
|
+
cvv: "CVV",
|
|
768
|
+
submit: "Submit",
|
|
769
|
+
processing: "Processing\u2026",
|
|
770
|
+
errorRequiredFields: "Please complete all required billing fields.",
|
|
771
|
+
errorTokenization: "Payment tokenization failed. Please try again.",
|
|
772
|
+
errorFormNotReady: "Payment form is not ready. Please try again later.",
|
|
773
|
+
infoSecure: "Your payment information is encrypted and processed securely.",
|
|
774
|
+
cancel: "Cancel",
|
|
775
|
+
editEmail: "Edit email",
|
|
776
|
+
selectCountry: "Select a country"
|
|
777
|
+
};
|
|
712
778
|
var buildSelector = (prefix, field) => `#${prefix}-${field}`;
|
|
713
779
|
var CardDetailsForm = ({
|
|
714
780
|
visible,
|
|
@@ -720,8 +786,10 @@ var CardDetailsForm = ({
|
|
|
720
786
|
collectPrefix = "card-form",
|
|
721
787
|
className,
|
|
722
788
|
onBillingChange,
|
|
723
|
-
submitDisabled = false
|
|
789
|
+
submitDisabled = false,
|
|
790
|
+
translations
|
|
724
791
|
}) => {
|
|
792
|
+
const t = { ...defaultCardDetailsFormTranslations, ...translations };
|
|
725
793
|
const { config } = usePaymentContext();
|
|
726
794
|
const defaultValuesKey = React4.useMemo(() => JSON.stringify(defaultValues ?? {}), [defaultValues]);
|
|
727
795
|
const mergedDefaults = React4.useMemo(
|
|
@@ -762,8 +830,11 @@ var CardDetailsForm = ({
|
|
|
762
830
|
if (!visible) {
|
|
763
831
|
setLocalError(null);
|
|
764
832
|
setIsTokenizing(false);
|
|
833
|
+
if (typeof window !== "undefined" && window.__doujinsCollectConfigured && collectPrefix) {
|
|
834
|
+
window.__doujinsCollectConfigured[collectPrefix] = false;
|
|
835
|
+
}
|
|
765
836
|
}
|
|
766
|
-
}, [visible]);
|
|
837
|
+
}, [visible, collectPrefix]);
|
|
767
838
|
React4.useEffect(() => {
|
|
768
839
|
if (!visible) return;
|
|
769
840
|
setFirstName(mergedDefaults.firstName);
|
|
@@ -825,6 +896,8 @@ var CardDetailsForm = ({
|
|
|
825
896
|
setLocalError("Payment tokenization failed. Please try again.");
|
|
826
897
|
return;
|
|
827
898
|
}
|
|
899
|
+
let rawExp = response.card?.exp;
|
|
900
|
+
let formattedExp = rawExp && rawExp.length === 4 ? `${rawExp.slice(0, 2)}/${rawExp.slice(2)}` : rawExp;
|
|
828
901
|
const billing = {
|
|
829
902
|
firstName,
|
|
830
903
|
lastName,
|
|
@@ -834,7 +907,10 @@ var CardDetailsForm = ({
|
|
|
834
907
|
postalCode,
|
|
835
908
|
country,
|
|
836
909
|
email,
|
|
837
|
-
provider: mergedDefaults.provider ?? "mobius"
|
|
910
|
+
provider: mergedDefaults.provider ?? "mobius",
|
|
911
|
+
last_four: response.card?.number,
|
|
912
|
+
card_type: response.card?.type,
|
|
913
|
+
expiry_date: formattedExp
|
|
838
914
|
};
|
|
839
915
|
onTokenize(response.token, billing);
|
|
840
916
|
};
|
|
@@ -875,7 +951,7 @@ var CardDetailsForm = ({
|
|
|
875
951
|
]);
|
|
876
952
|
const validate = () => {
|
|
877
953
|
if (!firstName.trim() || !lastName.trim() || !address1.trim() || !city.trim() || !postalCode.trim() || !country.trim() || !email.trim()) {
|
|
878
|
-
setLocalError(
|
|
954
|
+
setLocalError(t.errorRequiredFields);
|
|
879
955
|
return false;
|
|
880
956
|
}
|
|
881
957
|
setLocalError(null);
|
|
@@ -885,7 +961,7 @@ var CardDetailsForm = ({
|
|
|
885
961
|
event.preventDefault();
|
|
886
962
|
if (!validate()) return;
|
|
887
963
|
if (!window.CollectJS) {
|
|
888
|
-
setLocalError(
|
|
964
|
+
setLocalError(t.errorFormNotReady);
|
|
889
965
|
return;
|
|
890
966
|
}
|
|
891
967
|
setIsTokenizing(true);
|
|
@@ -905,7 +981,7 @@ var CardDetailsForm = ({
|
|
|
905
981
|
errorMessage && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-md border border-red-500/40 bg-red-500/10 px-4 py-2 text-sm text-red-400", children: errorMessage }),
|
|
906
982
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2 md:flex-row", children: [
|
|
907
983
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 space-y-2", children: [
|
|
908
|
-
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "firstName", children:
|
|
984
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "firstName", children: t.firstName }),
|
|
909
985
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
910
986
|
Input,
|
|
911
987
|
{
|
|
@@ -917,7 +993,7 @@ var CardDetailsForm = ({
|
|
|
917
993
|
)
|
|
918
994
|
] }),
|
|
919
995
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 space-y-2", children: [
|
|
920
|
-
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "lastName", children:
|
|
996
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "lastName", children: t.lastName }),
|
|
921
997
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
922
998
|
Input,
|
|
923
999
|
{
|
|
@@ -930,7 +1006,7 @@ var CardDetailsForm = ({
|
|
|
930
1006
|
] })
|
|
931
1007
|
] }),
|
|
932
1008
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
933
|
-
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "email", children:
|
|
1009
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "email", children: t.email }),
|
|
934
1010
|
showEmailInput ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2 items-center", children: [
|
|
935
1011
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
936
1012
|
Input,
|
|
@@ -954,7 +1030,7 @@ var CardDetailsForm = ({
|
|
|
954
1030
|
setEmail(mergedDefaults.email ?? "");
|
|
955
1031
|
},
|
|
956
1032
|
className: "px-3 text-xs text-muted-foreground hover:text-foreground",
|
|
957
|
-
children:
|
|
1033
|
+
children: t.cancel
|
|
958
1034
|
}
|
|
959
1035
|
)
|
|
960
1036
|
] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between h-9 w-full rounded-md border border-white/30 bg-transparent px-3 text-sm text-foreground", children: [
|
|
@@ -965,14 +1041,14 @@ var CardDetailsForm = ({
|
|
|
965
1041
|
type: "button",
|
|
966
1042
|
onClick: () => setIsEditingEmail(true),
|
|
967
1043
|
className: "text-muted-foreground hover:text-foreground transition-colors",
|
|
968
|
-
"aria-label":
|
|
1044
|
+
"aria-label": t.editEmail,
|
|
969
1045
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pencil, { className: "h-4 w-4" })
|
|
970
1046
|
}
|
|
971
1047
|
)
|
|
972
1048
|
] })
|
|
973
1049
|
] }),
|
|
974
1050
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
975
|
-
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "address1", children:
|
|
1051
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "address1", children: t.address }),
|
|
976
1052
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
977
1053
|
Input,
|
|
978
1054
|
{
|
|
@@ -985,7 +1061,7 @@ var CardDetailsForm = ({
|
|
|
985
1061
|
] }),
|
|
986
1062
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-2 md:grid-cols-2", children: [
|
|
987
1063
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
988
|
-
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "city", children:
|
|
1064
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "city", children: t.city }),
|
|
989
1065
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
990
1066
|
Input,
|
|
991
1067
|
{
|
|
@@ -997,7 +1073,7 @@ var CardDetailsForm = ({
|
|
|
997
1073
|
)
|
|
998
1074
|
] }),
|
|
999
1075
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
1000
|
-
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "state", children:
|
|
1076
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "state", children: t.state }),
|
|
1001
1077
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1002
1078
|
Input,
|
|
1003
1079
|
{
|
|
@@ -1010,7 +1086,7 @@ var CardDetailsForm = ({
|
|
|
1010
1086
|
] }),
|
|
1011
1087
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-2 md:grid-cols-2", children: [
|
|
1012
1088
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
1013
|
-
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "postal", children:
|
|
1089
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "postal", children: t.postalCode }),
|
|
1014
1090
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1015
1091
|
Input,
|
|
1016
1092
|
{
|
|
@@ -1022,24 +1098,24 @@ var CardDetailsForm = ({
|
|
|
1022
1098
|
)
|
|
1023
1099
|
] }),
|
|
1024
1100
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
1025
|
-
/* @__PURE__ */ jsxRuntime.jsx(Label, { children:
|
|
1101
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { children: t.country }),
|
|
1026
1102
|
/* @__PURE__ */ jsxRuntime.jsxs(Select, { value: country, onValueChange: setCountry, children: [
|
|
1027
|
-
/* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, { placeholder:
|
|
1103
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, { placeholder: t.selectCountry }) }),
|
|
1028
1104
|
/* @__PURE__ */ jsxRuntime.jsx(SelectContent, { children: countries.map((option) => /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: option.code, children: option.name }, option.code)) })
|
|
1029
1105
|
] })
|
|
1030
1106
|
] })
|
|
1031
1107
|
] }),
|
|
1032
1108
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
1033
|
-
/* @__PURE__ */ jsxRuntime.jsx(Label, { children:
|
|
1109
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { children: t.cardNumber }),
|
|
1034
1110
|
/* @__PURE__ */ jsxRuntime.jsx("div", { id: buildSelector(collectPrefix, "ccnumber").slice(1), className: collectFieldClass })
|
|
1035
1111
|
] }),
|
|
1036
1112
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-2 md:grid-cols-2", children: [
|
|
1037
1113
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
1038
|
-
/* @__PURE__ */ jsxRuntime.jsx(Label, { children:
|
|
1114
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { children: t.expiry }),
|
|
1039
1115
|
/* @__PURE__ */ jsxRuntime.jsx("div", { id: buildSelector(collectPrefix, "ccexp").slice(1), className: collectFieldClass })
|
|
1040
1116
|
] }),
|
|
1041
1117
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
1042
|
-
/* @__PURE__ */ jsxRuntime.jsx(Label, { children:
|
|
1118
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { children: t.cvv }),
|
|
1043
1119
|
/* @__PURE__ */ jsxRuntime.jsx("div", { id: buildSelector(collectPrefix, "cvv").slice(1), className: collectFieldClass })
|
|
1044
1120
|
] })
|
|
1045
1121
|
] }),
|
|
@@ -1051,11 +1127,12 @@ var CardDetailsForm = ({
|
|
|
1051
1127
|
disabled: submitting || submitDisabled || isTokenizing,
|
|
1052
1128
|
children: submitting || isTokenizing ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1053
1129
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }),
|
|
1054
|
-
"
|
|
1055
|
-
|
|
1130
|
+
" ",
|
|
1131
|
+
t.processing
|
|
1132
|
+
] }) : submitLabel || t.submit
|
|
1056
1133
|
}
|
|
1057
1134
|
),
|
|
1058
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-white/60", children:
|
|
1135
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-white/60", children: t.infoSecure })
|
|
1059
1136
|
]
|
|
1060
1137
|
}
|
|
1061
1138
|
);
|
|
@@ -1092,7 +1169,9 @@ var usePaymentMethods = () => {
|
|
|
1092
1169
|
zip: billing.postalCode,
|
|
1093
1170
|
country: billing.country,
|
|
1094
1171
|
email: billing.email,
|
|
1095
|
-
provider: billing.provider
|
|
1172
|
+
provider: billing.provider,
|
|
1173
|
+
last_four: billing.last_four,
|
|
1174
|
+
card_type: billing.card_type
|
|
1096
1175
|
};
|
|
1097
1176
|
return client.createPaymentMethod(payload);
|
|
1098
1177
|
},
|
|
@@ -1161,21 +1240,34 @@ var ScrollBar = React4__namespace.forwardRef(({ className, orientation = "vertic
|
|
|
1161
1240
|
}
|
|
1162
1241
|
));
|
|
1163
1242
|
ScrollBar.displayName = ScrollAreaPrimitive__namespace.ScrollAreaScrollbar.displayName;
|
|
1243
|
+
var defaultTranslations = {
|
|
1244
|
+
loadingCards: "Loading cards...",
|
|
1245
|
+
noSavedMethods: "No saved payment methods yet.",
|
|
1246
|
+
selectedLabel: "Selected",
|
|
1247
|
+
useCardLabel: "Use card"
|
|
1248
|
+
};
|
|
1164
1249
|
var formatCardLabel = (method) => {
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1250
|
+
if (method.card) {
|
|
1251
|
+
const brand = method.card.brand ? method.card.brand.toUpperCase() : "CARD";
|
|
1252
|
+
const lastFour = method.card.last4 ? `\u2022\u2022\u2022\u2022 ${method.card.last4}` : "";
|
|
1253
|
+
const exp = method.card.exp_month && method.card.exp_year ? ` \u2022 ${String(method.card.exp_month).padStart(2, "0")}/${String(method.card.exp_year).slice(-2)}` : "";
|
|
1254
|
+
return `${brand} ${lastFour}${exp}`.trim();
|
|
1255
|
+
}
|
|
1256
|
+
return "CARD";
|
|
1168
1257
|
};
|
|
1169
1258
|
var StoredPaymentMethods = ({
|
|
1170
1259
|
selectedMethodId,
|
|
1171
|
-
onMethodSelect
|
|
1260
|
+
onMethodSelect,
|
|
1261
|
+
translations
|
|
1172
1262
|
}) => {
|
|
1173
1263
|
const { listQuery } = usePaymentMethods();
|
|
1174
1264
|
const payments = React4.useMemo(() => listQuery.data?.data ?? [], [listQuery.data]);
|
|
1265
|
+
const t = { ...defaultTranslations, ...translations };
|
|
1175
1266
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-4", children: listQuery.isLoading ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center py-4 text-sm text-muted-foreground", children: [
|
|
1176
1267
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }),
|
|
1177
|
-
"
|
|
1178
|
-
|
|
1268
|
+
" ",
|
|
1269
|
+
t.loadingCards
|
|
1270
|
+
] }) : payments.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 text-center text-sm text-muted-foreground", children: t.noSavedMethods }) : /* @__PURE__ */ jsxRuntime.jsx(ScrollArea, { className: "max-h-[320px] pr-2", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-3", children: payments.map((method) => {
|
|
1179
1271
|
const isSelected = selectedMethodId === method.id;
|
|
1180
1272
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1181
1273
|
"div",
|
|
@@ -1198,7 +1290,7 @@ var StoredPaymentMethods = ({
|
|
|
1198
1290
|
disabled: isSelected,
|
|
1199
1291
|
onClick: () => onMethodSelect(method),
|
|
1200
1292
|
className: clsx2__default.default("px-3", { "bg-muted/90": !isSelected, "bg-inherit": isSelected }),
|
|
1201
|
-
children: isSelected ?
|
|
1293
|
+
children: isSelected ? t.selectedLabel : t.useCardLabel
|
|
1202
1294
|
}
|
|
1203
1295
|
)
|
|
1204
1296
|
] })
|
|
@@ -1208,6 +1300,26 @@ var StoredPaymentMethods = ({
|
|
|
1208
1300
|
);
|
|
1209
1301
|
}) }) }) });
|
|
1210
1302
|
};
|
|
1303
|
+
|
|
1304
|
+
// src/utils/errorMessages.ts
|
|
1305
|
+
var resolveErrorMessageByCode = (error, translationErrors, fallbackMessage) => {
|
|
1306
|
+
const errors = translationErrors ?? {};
|
|
1307
|
+
const defaultMessage = fallbackMessage ?? (error instanceof Error ? error.message : typeof error === "string" ? error : "An unexpected error occurred");
|
|
1308
|
+
if (error instanceof ClientApiError) {
|
|
1309
|
+
const payload = error.body;
|
|
1310
|
+
const code = payload?.code ?? payload?.error?.code;
|
|
1311
|
+
if (code && errors[code]) return errors[code];
|
|
1312
|
+
if (typeof payload?.error?.message === "string") return payload.error.message;
|
|
1313
|
+
return error.message;
|
|
1314
|
+
}
|
|
1315
|
+
if (typeof error === "object" && error !== null && "code" in error) {
|
|
1316
|
+
const code = error.code;
|
|
1317
|
+
if (typeof code === "string" && errors[code]) return errors[code];
|
|
1318
|
+
}
|
|
1319
|
+
if (error instanceof Error) return error.message;
|
|
1320
|
+
if (typeof error === "string") return error;
|
|
1321
|
+
return defaultMessage;
|
|
1322
|
+
};
|
|
1211
1323
|
function Tabs({
|
|
1212
1324
|
className,
|
|
1213
1325
|
...props
|
|
@@ -2003,20 +2115,45 @@ var SolanaPaymentView = ({
|
|
|
2003
2115
|
renderBody()
|
|
2004
2116
|
] });
|
|
2005
2117
|
};
|
|
2118
|
+
var defaultPaymentExperienceTranslations = {
|
|
2119
|
+
...defaultCardDetailsFormTranslations,
|
|
2120
|
+
useSavedCardTab: "Use saved card",
|
|
2121
|
+
addNewCardTab: "Add new card",
|
|
2122
|
+
savedUnavailable: "Saved payment methods are unavailable right now. Add a new card to get started.",
|
|
2123
|
+
payWithSavedCard: "Pay with selected card",
|
|
2124
|
+
processingSavedCard: "Processing...",
|
|
2125
|
+
savedErrorFallback: "Unable to complete payment with saved card",
|
|
2126
|
+
newCardUnavailable: "Select a subscription plan to add a new card.",
|
|
2127
|
+
payNow: "Pay now",
|
|
2128
|
+
storedLoadingCards: "Loading cards...",
|
|
2129
|
+
storedNoSavedMethods: "No saved payment methods yet.",
|
|
2130
|
+
storedSelectedLabel: "Selected",
|
|
2131
|
+
storedUseCardLabel: "Use card",
|
|
2132
|
+
payWithCcbill: "Pay with CCBill",
|
|
2133
|
+
processingCcbill: "Redirecting...",
|
|
2134
|
+
errors: {}
|
|
2135
|
+
};
|
|
2006
2136
|
var PaymentExperience = ({
|
|
2007
2137
|
priceId,
|
|
2008
2138
|
usdAmount,
|
|
2009
2139
|
onNewCardPayment,
|
|
2010
2140
|
onSavedMethodPayment,
|
|
2141
|
+
onCcbillPayment,
|
|
2011
2142
|
enableNewCard = true,
|
|
2012
2143
|
enableStoredMethods = true,
|
|
2013
2144
|
enableSolanaPay = true,
|
|
2014
2145
|
onSolanaSuccess,
|
|
2015
2146
|
onSolanaError,
|
|
2016
|
-
initialMode = "cards"
|
|
2147
|
+
initialMode = "cards",
|
|
2148
|
+
translations
|
|
2017
2149
|
}) => {
|
|
2150
|
+
const t = {
|
|
2151
|
+
...defaultPaymentExperienceTranslations,
|
|
2152
|
+
...translations
|
|
2153
|
+
};
|
|
2018
2154
|
const showNewCard = enableNewCard && Boolean(onNewCardPayment);
|
|
2019
2155
|
const showStored = enableStoredMethods && Boolean(onSavedMethodPayment);
|
|
2156
|
+
const showCcbill = showNewCard && Boolean(onCcbillPayment);
|
|
2020
2157
|
const defaultTab = showStored ? "saved" : "new";
|
|
2021
2158
|
const [activeTab, setActiveTab] = React4.useState(defaultTab);
|
|
2022
2159
|
const [mode, setMode] = React4.useState(
|
|
@@ -2027,6 +2164,9 @@ var PaymentExperience = ({
|
|
|
2027
2164
|
const [savedError, setSavedError] = React4.useState(null);
|
|
2028
2165
|
const [newCardStatus, setNewCardStatus] = React4.useState("idle");
|
|
2029
2166
|
const [newCardError, setNewCardError] = React4.useState(null);
|
|
2167
|
+
const [billingDetails, setBillingDetails] = React4.useState(null);
|
|
2168
|
+
const [ccbillStatus, setCcbillStatus] = React4.useState("idle");
|
|
2169
|
+
const [ccbillError, setCcbillError] = React4.useState(null);
|
|
2030
2170
|
const { notifyStatus, notifyError } = usePaymentNotifications();
|
|
2031
2171
|
React4.useEffect(() => {
|
|
2032
2172
|
setActiveTab(showStored ? "saved" : "new");
|
|
@@ -2042,6 +2182,24 @@ var PaymentExperience = ({
|
|
|
2042
2182
|
setMode("cards");
|
|
2043
2183
|
}
|
|
2044
2184
|
}, [enableSolanaPay, initialMode]);
|
|
2185
|
+
React4.useEffect(() => {
|
|
2186
|
+
if (!showNewCard) {
|
|
2187
|
+
setBillingDetails(null);
|
|
2188
|
+
setCcbillStatus("idle");
|
|
2189
|
+
setCcbillError(null);
|
|
2190
|
+
}
|
|
2191
|
+
}, [showNewCard]);
|
|
2192
|
+
const handleBillingChange = React4.useCallback((billing) => {
|
|
2193
|
+
setBillingDetails(billing);
|
|
2194
|
+
setCcbillError(null);
|
|
2195
|
+
setCcbillStatus("idle");
|
|
2196
|
+
}, []);
|
|
2197
|
+
const isBillingComplete = React4.useCallback((billing) => {
|
|
2198
|
+
if (!billing) return false;
|
|
2199
|
+
return Boolean(
|
|
2200
|
+
billing.firstName.trim() && billing.lastName.trim() && billing.address1.trim() && billing.city.trim() && billing.postalCode.trim() && billing.country.trim() && billing.email.trim()
|
|
2201
|
+
);
|
|
2202
|
+
}, []);
|
|
2045
2203
|
const handleMethodSelect = React4.useCallback((method) => {
|
|
2046
2204
|
setSelectedMethodId(method.id);
|
|
2047
2205
|
setSavedStatus("idle");
|
|
@@ -2060,13 +2218,17 @@ var PaymentExperience = ({
|
|
|
2060
2218
|
setSavedStatus("success");
|
|
2061
2219
|
notifyStatus("success", { source: "saved-payment" });
|
|
2062
2220
|
} catch (error) {
|
|
2063
|
-
const message =
|
|
2221
|
+
const message = resolveErrorMessageByCode(
|
|
2222
|
+
error,
|
|
2223
|
+
t.errors,
|
|
2224
|
+
t.savedErrorFallback
|
|
2225
|
+
);
|
|
2064
2226
|
setSavedStatus("error");
|
|
2065
2227
|
setSavedError(message);
|
|
2066
2228
|
notifyStatus("error", { source: "saved-payment" });
|
|
2067
2229
|
notifyError(message);
|
|
2068
2230
|
}
|
|
2069
|
-
}, [notifyError, notifyStatus, onSavedMethodPayment, selectedMethodId, usdAmount]);
|
|
2231
|
+
}, [notifyError, notifyStatus, onSavedMethodPayment, selectedMethodId, t, usdAmount]);
|
|
2070
2232
|
const handleNewCardTokenize = React4.useCallback(
|
|
2071
2233
|
async (token, billing) => {
|
|
2072
2234
|
if (!onNewCardPayment) return;
|
|
@@ -2078,15 +2240,56 @@ var PaymentExperience = ({
|
|
|
2078
2240
|
setNewCardStatus("success");
|
|
2079
2241
|
notifyStatus("success", { source: "new-card" });
|
|
2080
2242
|
} catch (error) {
|
|
2081
|
-
const message =
|
|
2243
|
+
const message = resolveErrorMessageByCode(
|
|
2244
|
+
error,
|
|
2245
|
+
t.errors,
|
|
2246
|
+
"Unable to complete payment"
|
|
2247
|
+
);
|
|
2082
2248
|
setNewCardStatus("error");
|
|
2083
2249
|
setNewCardError(message);
|
|
2084
2250
|
notifyStatus("error", { source: "new-card" });
|
|
2085
2251
|
notifyError(message);
|
|
2086
2252
|
}
|
|
2087
2253
|
},
|
|
2088
|
-
[notifyError, notifyStatus, onNewCardPayment]
|
|
2254
|
+
[notifyError, notifyStatus, onNewCardPayment, t]
|
|
2089
2255
|
);
|
|
2256
|
+
const handleCcbillPayment = React4.useCallback(async () => {
|
|
2257
|
+
if (!onCcbillPayment) return;
|
|
2258
|
+
if (!billingDetails || !isBillingComplete(billingDetails)) {
|
|
2259
|
+
const message = t.errorRequiredFields;
|
|
2260
|
+
setActiveTab("new");
|
|
2261
|
+
setCcbillStatus("error");
|
|
2262
|
+
setCcbillError(message);
|
|
2263
|
+
notifyStatus("error", { source: "ccbill" });
|
|
2264
|
+
notifyError(message);
|
|
2265
|
+
return;
|
|
2266
|
+
}
|
|
2267
|
+
try {
|
|
2268
|
+
setCcbillStatus("processing");
|
|
2269
|
+
setCcbillError(null);
|
|
2270
|
+
notifyStatus("processing", { source: "ccbill" });
|
|
2271
|
+
await onCcbillPayment({ billing: billingDetails });
|
|
2272
|
+
setCcbillStatus("success");
|
|
2273
|
+
notifyStatus("success", { source: "ccbill" });
|
|
2274
|
+
} catch (error) {
|
|
2275
|
+
const message = resolveErrorMessageByCode(
|
|
2276
|
+
error,
|
|
2277
|
+
t.errors,
|
|
2278
|
+
"Unable to start CCBill checkout"
|
|
2279
|
+
);
|
|
2280
|
+
setCcbillStatus("error");
|
|
2281
|
+
setCcbillError(message);
|
|
2282
|
+
notifyStatus("error", { source: "ccbill" });
|
|
2283
|
+
notifyError(message);
|
|
2284
|
+
}
|
|
2285
|
+
}, [
|
|
2286
|
+
billingDetails,
|
|
2287
|
+
isBillingComplete,
|
|
2288
|
+
notifyError,
|
|
2289
|
+
notifyStatus,
|
|
2290
|
+
onCcbillPayment,
|
|
2291
|
+
t
|
|
2292
|
+
]);
|
|
2090
2293
|
React4.useCallback(() => {
|
|
2091
2294
|
if (!enableSolanaPay) return;
|
|
2092
2295
|
setMode("solana");
|
|
@@ -2109,14 +2312,20 @@ var PaymentExperience = ({
|
|
|
2109
2312
|
);
|
|
2110
2313
|
const renderSavedTab = () => {
|
|
2111
2314
|
if (!showStored) {
|
|
2112
|
-
return /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children:
|
|
2315
|
+
return /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: t.savedUnavailable });
|
|
2113
2316
|
}
|
|
2114
2317
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
|
|
2115
2318
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2116
2319
|
StoredPaymentMethods,
|
|
2117
2320
|
{
|
|
2118
2321
|
selectedMethodId,
|
|
2119
|
-
onMethodSelect: handleMethodSelect
|
|
2322
|
+
onMethodSelect: handleMethodSelect,
|
|
2323
|
+
translations: {
|
|
2324
|
+
loadingCards: t.storedLoadingCards,
|
|
2325
|
+
noSavedMethods: t.storedNoSavedMethods,
|
|
2326
|
+
selectedLabel: t.storedSelectedLabel,
|
|
2327
|
+
useCardLabel: t.storedUseCardLabel
|
|
2328
|
+
}
|
|
2120
2329
|
}
|
|
2121
2330
|
),
|
|
2122
2331
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -2125,7 +2334,7 @@ var PaymentExperience = ({
|
|
|
2125
2334
|
className: "w-full",
|
|
2126
2335
|
disabled: !selectedMethodId || savedStatus === "processing",
|
|
2127
2336
|
onClick: handleSavedPayment,
|
|
2128
|
-
children: savedStatus === "processing" ?
|
|
2337
|
+
children: savedStatus === "processing" ? t.processingSavedCard : t.payWithSavedCard
|
|
2129
2338
|
}
|
|
2130
2339
|
),
|
|
2131
2340
|
savedError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive", children: savedError })
|
|
@@ -2133,29 +2342,50 @@ var PaymentExperience = ({
|
|
|
2133
2342
|
};
|
|
2134
2343
|
const renderNewTab = () => {
|
|
2135
2344
|
if (!showNewCard) {
|
|
2136
|
-
return /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children:
|
|
2345
|
+
return /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: t.newCardUnavailable });
|
|
2137
2346
|
}
|
|
2138
2347
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2139
2348
|
CardDetailsForm,
|
|
2140
2349
|
{
|
|
2141
2350
|
visible: true,
|
|
2142
|
-
submitLabel:
|
|
2351
|
+
submitLabel: t.payNow,
|
|
2143
2352
|
externalError: newCardError,
|
|
2144
2353
|
onTokenize: handleNewCardTokenize,
|
|
2145
|
-
submitting: newCardStatus === "processing"
|
|
2354
|
+
submitting: newCardStatus === "processing",
|
|
2355
|
+
onBillingChange: handleBillingChange,
|
|
2356
|
+
translations: t
|
|
2146
2357
|
}
|
|
2147
2358
|
);
|
|
2148
2359
|
};
|
|
2149
2360
|
const renderCardExperience = () => /* @__PURE__ */ jsxRuntime.jsxs(Tabs, { value: activeTab, onValueChange: setActiveTab, children: [
|
|
2150
2361
|
/* @__PURE__ */ jsxRuntime.jsxs(TabsList, { className: "w-full rounded-md mb-4", children: [
|
|
2151
|
-
/* @__PURE__ */ jsxRuntime.jsx(TabsTrigger, { className: "cursor-pointer", value: "saved", children:
|
|
2152
|
-
/* @__PURE__ */ jsxRuntime.jsx(TabsTrigger, { className: "cursor-pointer", value: "new", children:
|
|
2362
|
+
/* @__PURE__ */ jsxRuntime.jsx(TabsTrigger, { className: "cursor-pointer", value: "saved", children: t.useSavedCardTab }),
|
|
2363
|
+
/* @__PURE__ */ jsxRuntime.jsx(TabsTrigger, { className: "cursor-pointer", value: "new", children: t.addNewCardTab })
|
|
2153
2364
|
] }),
|
|
2154
2365
|
/* @__PURE__ */ jsxRuntime.jsx(TabsContent, { value: "saved", children: renderSavedTab() }),
|
|
2155
2366
|
/* @__PURE__ */ jsxRuntime.jsx(TabsContent, { value: "new", children: renderNewTab() })
|
|
2156
2367
|
] });
|
|
2368
|
+
const renderCcbillAction = () => {
|
|
2369
|
+
if (!showCcbill) return null;
|
|
2370
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2 border-t border-white/10 pt-4", children: [
|
|
2371
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2372
|
+
Button,
|
|
2373
|
+
{
|
|
2374
|
+
className: "w-full",
|
|
2375
|
+
variant: "outline",
|
|
2376
|
+
disabled: ccbillStatus === "processing",
|
|
2377
|
+
onClick: handleCcbillPayment,
|
|
2378
|
+
children: ccbillStatus === "processing" ? t.processingCcbill : t.payWithCcbill
|
|
2379
|
+
}
|
|
2380
|
+
),
|
|
2381
|
+
ccbillError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive", children: ccbillError })
|
|
2382
|
+
] });
|
|
2383
|
+
};
|
|
2157
2384
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6 pt-4", children: [
|
|
2158
|
-
mode === "cards" &&
|
|
2385
|
+
mode === "cards" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2386
|
+
renderCardExperience(),
|
|
2387
|
+
renderCcbillAction()
|
|
2388
|
+
] }),
|
|
2159
2389
|
mode === "solana" && enableSolanaPay && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2160
2390
|
SolanaPaymentView,
|
|
2161
2391
|
{
|
|
@@ -2207,17 +2437,17 @@ var useSubscriptionActions = () => {
|
|
|
2207
2437
|
const subscribeWithCard = React4.useCallback(
|
|
2208
2438
|
async ({
|
|
2209
2439
|
priceId,
|
|
2210
|
-
processor = "
|
|
2440
|
+
processor = "mobius",
|
|
2211
2441
|
provider,
|
|
2212
2442
|
paymentToken,
|
|
2213
2443
|
billing,
|
|
2214
2444
|
idempotencyKey
|
|
2215
2445
|
}) => {
|
|
2216
|
-
|
|
2217
|
-
|
|
2446
|
+
if (processor !== "ccbill" && !paymentToken) {
|
|
2447
|
+
throw new Error("payments-ui: payment token is required for card checkout");
|
|
2448
|
+
}
|
|
2449
|
+
const payment = {
|
|
2218
2450
|
processor,
|
|
2219
|
-
provider,
|
|
2220
|
-
payment_token: paymentToken,
|
|
2221
2451
|
email: billing.email,
|
|
2222
2452
|
first_name: billing.firstName,
|
|
2223
2453
|
last_name: billing.lastName,
|
|
@@ -2227,6 +2457,17 @@ var useSubscriptionActions = () => {
|
|
|
2227
2457
|
zip: billing.postalCode,
|
|
2228
2458
|
country: billing.country
|
|
2229
2459
|
};
|
|
2460
|
+
if (paymentToken) {
|
|
2461
|
+
payment.payment_token = paymentToken;
|
|
2462
|
+
payment.last_four = billing.last_four;
|
|
2463
|
+
payment.card_type = billing.card_type;
|
|
2464
|
+
payment.expiry_date = billing.expiry_date;
|
|
2465
|
+
}
|
|
2466
|
+
const payload = {
|
|
2467
|
+
price_id: ensurePrice(priceId),
|
|
2468
|
+
provider,
|
|
2469
|
+
payment
|
|
2470
|
+
};
|
|
2230
2471
|
return client.checkout(payload, idempotencyKey);
|
|
2231
2472
|
},
|
|
2232
2473
|
[client]
|
|
@@ -2234,7 +2475,7 @@ var useSubscriptionActions = () => {
|
|
|
2234
2475
|
const subscribeWithSavedMethod = React4.useCallback(
|
|
2235
2476
|
async ({
|
|
2236
2477
|
priceId,
|
|
2237
|
-
processor = "
|
|
2478
|
+
processor = "mobius",
|
|
2238
2479
|
provider,
|
|
2239
2480
|
paymentMethodId,
|
|
2240
2481
|
email,
|
|
@@ -2242,10 +2483,12 @@ var useSubscriptionActions = () => {
|
|
|
2242
2483
|
}) => {
|
|
2243
2484
|
const payload = {
|
|
2244
2485
|
price_id: ensurePrice(priceId),
|
|
2245
|
-
processor,
|
|
2246
2486
|
provider,
|
|
2247
|
-
|
|
2248
|
-
|
|
2487
|
+
payment: {
|
|
2488
|
+
processor,
|
|
2489
|
+
payment_method_id: paymentMethodId,
|
|
2490
|
+
email
|
|
2491
|
+
}
|
|
2249
2492
|
};
|
|
2250
2493
|
return client.checkout(payload, idempotencyKey);
|
|
2251
2494
|
},
|
|
@@ -2264,12 +2507,14 @@ var useSubscriptionActions = () => {
|
|
|
2264
2507
|
}) => {
|
|
2265
2508
|
const payload = {
|
|
2266
2509
|
price_id: ensurePrice(priceId),
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2510
|
+
payment: {
|
|
2511
|
+
processor,
|
|
2512
|
+
email,
|
|
2513
|
+
first_name: firstName,
|
|
2514
|
+
last_name: lastName,
|
|
2515
|
+
zip: zipCode,
|
|
2516
|
+
country
|
|
2517
|
+
}
|
|
2273
2518
|
};
|
|
2274
2519
|
return client.checkout(payload, idempotencyKey);
|
|
2275
2520
|
},
|
|
@@ -2281,6 +2526,11 @@ var useSubscriptionActions = () => {
|
|
|
2281
2526
|
subscribeWithCCBill
|
|
2282
2527
|
};
|
|
2283
2528
|
};
|
|
2529
|
+
var defaultTranslations2 = {
|
|
2530
|
+
...defaultPaymentExperienceTranslations,
|
|
2531
|
+
title: "Checkout",
|
|
2532
|
+
selectPlanMessage: "Select a subscription plan to continue."
|
|
2533
|
+
};
|
|
2284
2534
|
var SubscriptionCheckoutModal = ({
|
|
2285
2535
|
open,
|
|
2286
2536
|
onOpenChange,
|
|
@@ -2295,11 +2545,16 @@ var SubscriptionCheckoutModal = ({
|
|
|
2295
2545
|
enableSolanaPay = true,
|
|
2296
2546
|
onSolanaSuccess,
|
|
2297
2547
|
onSolanaError,
|
|
2298
|
-
initialMode = "cards"
|
|
2548
|
+
initialMode = "cards",
|
|
2549
|
+
translations
|
|
2299
2550
|
}) => {
|
|
2300
2551
|
const [showSuccess, setShowSuccess] = React4.useState(false);
|
|
2301
2552
|
const [idempotencyKey, setIdempotencyKey] = React4.useState(() => crypto.randomUUID());
|
|
2302
2553
|
const { subscribeWithCard, subscribeWithSavedMethod } = useSubscriptionActions();
|
|
2554
|
+
const t = {
|
|
2555
|
+
...defaultTranslations2,
|
|
2556
|
+
...translations
|
|
2557
|
+
};
|
|
2303
2558
|
React4.useEffect(() => {
|
|
2304
2559
|
if (open) {
|
|
2305
2560
|
setIdempotencyKey(crypto.randomUUID());
|
|
@@ -2323,13 +2578,31 @@ var SubscriptionCheckoutModal = ({
|
|
|
2323
2578
|
console.debug("[payments-ui] subscription success", result);
|
|
2324
2579
|
}
|
|
2325
2580
|
};
|
|
2326
|
-
const
|
|
2327
|
-
if (status === "blocked") {
|
|
2328
|
-
throw new Error(message || "This subscription cannot be completed right now.");
|
|
2581
|
+
const handleCheckoutResponse = (response) => {
|
|
2582
|
+
if (response.status === "blocked") {
|
|
2583
|
+
throw new Error(response.message || "This subscription cannot be completed right now.");
|
|
2584
|
+
}
|
|
2585
|
+
const nextAction = response.next_action;
|
|
2586
|
+
if (nextAction?.type === "redirect_to_url") {
|
|
2587
|
+
const redirectUrl = nextAction.redirect_to_url?.url || response.payment?.redirect_url;
|
|
2588
|
+
if (!redirectUrl) {
|
|
2589
|
+
throw new Error(response.message || "Checkout requires a redirect URL.");
|
|
2590
|
+
}
|
|
2591
|
+
if (typeof window !== "undefined") {
|
|
2592
|
+
window.location.assign(redirectUrl);
|
|
2593
|
+
}
|
|
2594
|
+
return;
|
|
2595
|
+
}
|
|
2596
|
+
if (response.payment?.redirect_url) {
|
|
2597
|
+
if (typeof window !== "undefined") {
|
|
2598
|
+
window.location.assign(response.payment.redirect_url);
|
|
2599
|
+
}
|
|
2600
|
+
return;
|
|
2329
2601
|
}
|
|
2330
|
-
if (
|
|
2331
|
-
throw new Error(message || "
|
|
2602
|
+
if (nextAction && nextAction.type !== "none") {
|
|
2603
|
+
throw new Error(response.message || "Unsupported checkout action.");
|
|
2332
2604
|
}
|
|
2605
|
+
notifySuccess();
|
|
2333
2606
|
};
|
|
2334
2607
|
const handleNewCardPayment = async ({ token, billing }) => {
|
|
2335
2608
|
const response = await subscribeWithCard({
|
|
@@ -2339,8 +2612,7 @@ var SubscriptionCheckoutModal = ({
|
|
|
2339
2612
|
paymentToken: token,
|
|
2340
2613
|
priceId: ensurePrice()
|
|
2341
2614
|
});
|
|
2342
|
-
|
|
2343
|
-
notifySuccess();
|
|
2615
|
+
handleCheckoutResponse(response);
|
|
2344
2616
|
};
|
|
2345
2617
|
const handleSavedMethodPayment = async ({ paymentMethodId }) => {
|
|
2346
2618
|
const response = await subscribeWithSavedMethod({
|
|
@@ -2350,8 +2622,16 @@ var SubscriptionCheckoutModal = ({
|
|
|
2350
2622
|
email: userEmail ?? "",
|
|
2351
2623
|
idempotencyKey
|
|
2352
2624
|
});
|
|
2353
|
-
|
|
2354
|
-
|
|
2625
|
+
handleCheckoutResponse(response);
|
|
2626
|
+
};
|
|
2627
|
+
const handleCcbillPayment = async ({ billing }) => {
|
|
2628
|
+
const response = await subscribeWithCard({
|
|
2629
|
+
billing,
|
|
2630
|
+
idempotencyKey,
|
|
2631
|
+
processor: "ccbill",
|
|
2632
|
+
priceId: ensurePrice()
|
|
2633
|
+
});
|
|
2634
|
+
handleCheckoutResponse(response);
|
|
2355
2635
|
};
|
|
2356
2636
|
const solanaSuccess = (result) => {
|
|
2357
2637
|
notifySuccess(result);
|
|
@@ -2367,11 +2647,11 @@ var SubscriptionCheckoutModal = ({
|
|
|
2367
2647
|
{
|
|
2368
2648
|
className: "z-[100] max-w-xl max-h-[90vh] overflow-y-auto border border-white/20 p-6 backdrop-blur-xl bg-background-regular rounded-md [&::-webkit-scrollbar]:hidden",
|
|
2369
2649
|
children: [
|
|
2370
|
-
/* @__PURE__ */ jsxRuntime.jsx(DialogHeader, { children: /* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { className: "flex items-center gap-2 text-foreground", children:
|
|
2650
|
+
/* @__PURE__ */ jsxRuntime.jsx(DialogHeader, { children: /* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { className: "flex items-center gap-2 text-foreground", children: t.title }) }),
|
|
2371
2651
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-4", children: !priceId ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-center px-3 py-2 text-sm text-destructive", children: [
|
|
2372
2652
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertCircle, { className: "h-4 w-4" }),
|
|
2373
2653
|
" ",
|
|
2374
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children:
|
|
2654
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: t.selectPlanMessage })
|
|
2375
2655
|
] }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
2376
2656
|
PaymentExperience,
|
|
2377
2657
|
{
|
|
@@ -2384,7 +2664,9 @@ var SubscriptionCheckoutModal = ({
|
|
|
2384
2664
|
enableStoredMethods: Boolean(priceId),
|
|
2385
2665
|
enableSolanaPay: enableSolanaPay && Boolean(priceId),
|
|
2386
2666
|
onNewCardPayment: priceId ? handleNewCardPayment : void 0,
|
|
2387
|
-
onSavedMethodPayment: priceId ? handleSavedMethodPayment : void 0
|
|
2667
|
+
onSavedMethodPayment: priceId ? handleSavedMethodPayment : void 0,
|
|
2668
|
+
onCcbillPayment: priceId ? handleCcbillPayment : void 0,
|
|
2669
|
+
translations: t
|
|
2388
2670
|
}
|
|
2389
2671
|
) })
|
|
2390
2672
|
]
|
|
@@ -2394,7 +2676,9 @@ var SubscriptionCheckoutModal = ({
|
|
|
2394
2676
|
SubscriptionSuccessDialog,
|
|
2395
2677
|
{
|
|
2396
2678
|
open: showSuccess,
|
|
2397
|
-
onClose: () =>
|
|
2679
|
+
onClose: () => {
|
|
2680
|
+
setShowSuccess(false);
|
|
2681
|
+
},
|
|
2398
2682
|
planName,
|
|
2399
2683
|
amountLabel: amountLabel ?? `$${usdAmount.toFixed(2)}`,
|
|
2400
2684
|
billingPeriodLabel
|
|
@@ -2819,7 +3103,7 @@ var notifyDefault = (payload) => {
|
|
|
2819
3103
|
const level = payload.status === "destructive" ? "error" : "info";
|
|
2820
3104
|
console[level === "error" ? "error" : "log"]("[payments-ui] cancellation", payload);
|
|
2821
3105
|
};
|
|
2822
|
-
var
|
|
3106
|
+
var defaultTranslations3 = {
|
|
2823
3107
|
buttonLabel: "Cancel Membership",
|
|
2824
3108
|
title: "Confirm Membership Cancellation",
|
|
2825
3109
|
description: "You are about to cancel your membership. Please review the consequences:",
|
|
@@ -2841,23 +3125,33 @@ var CancelMembershipDialog = ({
|
|
|
2841
3125
|
minReasonLength = 15,
|
|
2842
3126
|
onCancelled,
|
|
2843
3127
|
onNotify,
|
|
2844
|
-
translations: customTranslations
|
|
3128
|
+
translations: customTranslations,
|
|
3129
|
+
open,
|
|
3130
|
+
onOpenChange
|
|
2845
3131
|
}) => {
|
|
2846
3132
|
const { client } = usePaymentContext();
|
|
2847
3133
|
const notify = onNotify ?? notifyDefault;
|
|
2848
|
-
const t = { ...
|
|
3134
|
+
const t = { ...defaultTranslations3, ...customTranslations };
|
|
2849
3135
|
const [cancelReason, setCancelReason] = React4.useState("");
|
|
2850
|
-
const [
|
|
3136
|
+
const [internalOpen, setInternalOpen] = React4.useState(false);
|
|
2851
3137
|
const [isReasonValid, setIsReasonValid] = React4.useState(false);
|
|
2852
3138
|
const [hasInteracted, setHasInteracted] = React4.useState(false);
|
|
2853
3139
|
const [isSubmitting, setIsSubmitting] = React4.useState(false);
|
|
3140
|
+
const isControlled = typeof open === "boolean";
|
|
3141
|
+
const isOpen = isControlled ? open : internalOpen;
|
|
3142
|
+
const setOpen = (next) => {
|
|
3143
|
+
if (!isControlled) {
|
|
3144
|
+
setInternalOpen(next);
|
|
3145
|
+
}
|
|
3146
|
+
onOpenChange?.(next);
|
|
3147
|
+
};
|
|
2854
3148
|
React4.useEffect(() => {
|
|
2855
3149
|
const trimmed = cancelReason.trim();
|
|
2856
3150
|
setIsReasonValid(trimmed.length >= minReasonLength);
|
|
2857
3151
|
}, [cancelReason, minReasonLength]);
|
|
2858
|
-
const handleOpenChange = (
|
|
2859
|
-
|
|
2860
|
-
if (!
|
|
3152
|
+
const handleOpenChange = (open2) => {
|
|
3153
|
+
setOpen(open2);
|
|
3154
|
+
if (!open2) {
|
|
2861
3155
|
setCancelReason("");
|
|
2862
3156
|
setIsReasonValid(false);
|
|
2863
3157
|
setHasInteracted(false);
|
|
@@ -2894,7 +3188,7 @@ var CancelMembershipDialog = ({
|
|
|
2894
3188
|
};
|
|
2895
3189
|
const showError = hasInteracted && !isReasonValid;
|
|
2896
3190
|
return /* @__PURE__ */ jsxRuntime.jsxs(AlertDialog, { open: isOpen, onOpenChange: handleOpenChange, children: [
|
|
2897
|
-
/* @__PURE__ */ jsxRuntime.jsx(AlertDialogTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(Button, {
|
|
3191
|
+
/* @__PURE__ */ jsxRuntime.jsx(AlertDialogTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(Button, { className: "bg-destructive text-destructive-foreground border-destructive/50 hover:bg-destructive/90", children: [
|
|
2898
3192
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Ban, { className: "mr-2 h-4 w-4" }),
|
|
2899
3193
|
" ",
|
|
2900
3194
|
t.buttonLabel
|
|
@@ -2961,7 +3255,7 @@ var notifyDefault2 = (payload) => {
|
|
|
2961
3255
|
const level = payload.status === "destructive" ? "error" : "info";
|
|
2962
3256
|
console[level === "error" ? "error" : "log"]("[payments-ui] billing", payload);
|
|
2963
3257
|
};
|
|
2964
|
-
var
|
|
3258
|
+
var defaultTranslations4 = {
|
|
2965
3259
|
title: "Transaction History",
|
|
2966
3260
|
description: "Record of billing history",
|
|
2967
3261
|
reviewActivity: "Review your account activity below",
|
|
@@ -2983,7 +3277,7 @@ var BillingHistory = ({
|
|
|
2983
3277
|
}) => {
|
|
2984
3278
|
const { client } = usePaymentContext();
|
|
2985
3279
|
const notify = onNotify ?? notifyDefault2;
|
|
2986
|
-
const t = { ...
|
|
3280
|
+
const t = { ...defaultTranslations4, ...customTranslations };
|
|
2987
3281
|
const [isExpanded, setIsExpanded] = React4.useState(false);
|
|
2988
3282
|
const observerRef = React4.useRef(null);
|
|
2989
3283
|
const loadMoreRef = React4.useRef(null);
|
|
@@ -3092,15 +3386,21 @@ var BillingHistory = ({
|
|
|
3092
3386
|
] }) });
|
|
3093
3387
|
};
|
|
3094
3388
|
var formatCardLabel2 = (method) => {
|
|
3095
|
-
|
|
3096
|
-
|
|
3389
|
+
if (method.card) {
|
|
3390
|
+
const brand2 = method.card.brand ? method.card.brand.toUpperCase() : "CARD";
|
|
3391
|
+
const lastFour2 = method.card.last4 ? `\u2022\u2022\u2022\u2022 ${method.card.last4}` : "";
|
|
3392
|
+
const exp = method.card.exp_month && method.card.exp_year ? ` \u2022 ${String(method.card.exp_month).padStart(2, "0")}/${String(method.card.exp_year).slice(-2)}` : "";
|
|
3393
|
+
return `${brand2} ${lastFour2}${exp}`.trim();
|
|
3394
|
+
}
|
|
3395
|
+
const brand = "CARD";
|
|
3396
|
+
const lastFour = "";
|
|
3097
3397
|
return `${brand} ${lastFour}`.trim();
|
|
3098
3398
|
};
|
|
3099
3399
|
var notifyDefault3 = (payload) => {
|
|
3100
3400
|
const level = payload.status === "destructive" ? "error" : "info";
|
|
3101
3401
|
console[level === "error" ? "error" : "log"]("[payments-ui] notification", payload);
|
|
3102
3402
|
};
|
|
3103
|
-
var
|
|
3403
|
+
var defaultTranslations5 = {
|
|
3104
3404
|
title: "Payment Methods",
|
|
3105
3405
|
description: "Manage your saved billing cards",
|
|
3106
3406
|
addCard: "Add card",
|
|
@@ -3121,7 +3421,11 @@ var defaultTranslations3 = {
|
|
|
3121
3421
|
cardUpdated: "Card updated",
|
|
3122
3422
|
unableToRemoveCard: "Unable to remove card",
|
|
3123
3423
|
defaultPaymentMethodUpdated: "Default payment method updated",
|
|
3124
|
-
unableToSetDefault: "Unable to set default payment method"
|
|
3424
|
+
unableToSetDefault: "Unable to set default payment method",
|
|
3425
|
+
errors: {},
|
|
3426
|
+
activeSubscriptions: "Active subscriptions",
|
|
3427
|
+
showSubscriptions: "Show",
|
|
3428
|
+
hideSubscriptions: "Hide"
|
|
3125
3429
|
};
|
|
3126
3430
|
var PaymentMethodsSection = ({
|
|
3127
3431
|
isAuthenticated = true,
|
|
@@ -3132,8 +3436,7 @@ var PaymentMethodsSection = ({
|
|
|
3132
3436
|
onNotify,
|
|
3133
3437
|
translations: customTranslations
|
|
3134
3438
|
}) => {
|
|
3135
|
-
const { client } = usePaymentContext();
|
|
3136
|
-
const queryClient = reactQuery.useQueryClient();
|
|
3439
|
+
const { client, queryClient } = usePaymentContext();
|
|
3137
3440
|
const paymentMethods = {
|
|
3138
3441
|
list: (params) => client.listPaymentMethods({ limit: params.pageSize }),
|
|
3139
3442
|
create: (payload) => client.createPaymentMethod(payload),
|
|
@@ -3143,13 +3446,15 @@ var PaymentMethodsSection = ({
|
|
|
3143
3446
|
};
|
|
3144
3447
|
const [isModalOpen, setIsModalOpen] = React4.useState(false);
|
|
3145
3448
|
const [deletingId, setDeletingId] = React4.useState(null);
|
|
3449
|
+
const [createErrorMessage, setCreateErrorMessage] = React4.useState(null);
|
|
3450
|
+
const [expandedSubscriptions, setExpandedSubscriptions] = React4.useState({});
|
|
3146
3451
|
const notify = onNotify ?? notifyDefault3;
|
|
3147
|
-
const t = { ...
|
|
3452
|
+
const t = { ...defaultTranslations5, ...customTranslations };
|
|
3148
3453
|
const queryKey = ["payments-ui", "payment-methods"];
|
|
3149
3454
|
const paymentQuery = reactQuery.useQuery({
|
|
3150
3455
|
queryKey,
|
|
3151
3456
|
queryFn: () => paymentMethods.list({ pageSize: 50 }),
|
|
3152
|
-
enabled: isAuthenticated,
|
|
3457
|
+
enabled: isAuthenticated && !!client,
|
|
3153
3458
|
staleTime: 3e4
|
|
3154
3459
|
});
|
|
3155
3460
|
const createMutation = reactQuery.useMutation({
|
|
@@ -3158,11 +3463,14 @@ var PaymentMethodsSection = ({
|
|
|
3158
3463
|
notify({ title: t.cardAddedSuccess, status: "success" });
|
|
3159
3464
|
setIsModalOpen(false);
|
|
3160
3465
|
void queryClient.invalidateQueries({ queryKey });
|
|
3466
|
+
setCreateErrorMessage(null);
|
|
3161
3467
|
},
|
|
3162
3468
|
onError: (error) => {
|
|
3469
|
+
const message = resolveErrorMessageByCode(error, t.errors, error.message);
|
|
3470
|
+
setCreateErrorMessage(message);
|
|
3163
3471
|
notify({
|
|
3164
3472
|
title: t.unableToAddCard,
|
|
3165
|
-
description:
|
|
3473
|
+
description: message,
|
|
3166
3474
|
status: "destructive"
|
|
3167
3475
|
});
|
|
3168
3476
|
}
|
|
@@ -3173,6 +3481,9 @@ var PaymentMethodsSection = ({
|
|
|
3173
3481
|
onSuccess: () => {
|
|
3174
3482
|
notify({ title: t.cardRemoved, status: "success" });
|
|
3175
3483
|
void queryClient.invalidateQueries({ queryKey });
|
|
3484
|
+
if (paymentQuery.refetch) {
|
|
3485
|
+
paymentQuery.refetch();
|
|
3486
|
+
}
|
|
3176
3487
|
},
|
|
3177
3488
|
onError: (error) => {
|
|
3178
3489
|
notify({
|
|
@@ -3183,7 +3494,7 @@ var PaymentMethodsSection = ({
|
|
|
3183
3494
|
},
|
|
3184
3495
|
onSettled: () => setDeletingId(null)
|
|
3185
3496
|
});
|
|
3186
|
-
|
|
3497
|
+
reactQuery.useMutation({
|
|
3187
3498
|
mutationFn: (id) => paymentMethods.activate(id),
|
|
3188
3499
|
onSuccess: () => {
|
|
3189
3500
|
notify({ title: t.defaultPaymentMethodUpdated, status: "success" });
|
|
@@ -3200,8 +3511,14 @@ var PaymentMethodsSection = ({
|
|
|
3200
3511
|
React4.useEffect(() => {
|
|
3201
3512
|
if (!isModalOpen) {
|
|
3202
3513
|
createMutation.reset();
|
|
3514
|
+
setCreateErrorMessage(null);
|
|
3515
|
+
}
|
|
3516
|
+
}, [isModalOpen]);
|
|
3517
|
+
React4.useEffect(() => {
|
|
3518
|
+
if (!isModalOpen && paymentQuery.refetch) {
|
|
3519
|
+
paymentQuery.refetch();
|
|
3203
3520
|
}
|
|
3204
|
-
}, [
|
|
3521
|
+
}, [isModalOpen]);
|
|
3205
3522
|
const payments = React4.useMemo(() => paymentQuery.data?.data ?? [], [paymentQuery.data]);
|
|
3206
3523
|
const loading = paymentQuery.isLoading || paymentQuery.isFetching;
|
|
3207
3524
|
const buildPayload = (token, billing) => ({
|
|
@@ -3215,9 +3532,13 @@ var PaymentMethodsSection = ({
|
|
|
3215
3532
|
zip: billing.postalCode,
|
|
3216
3533
|
country: billing.country,
|
|
3217
3534
|
email: billing.email,
|
|
3218
|
-
provider: billing.provider
|
|
3535
|
+
provider: billing.provider,
|
|
3536
|
+
last_four: billing.last_four,
|
|
3537
|
+
card_type: billing.card_type,
|
|
3538
|
+
expiry_date: billing.expiry_date
|
|
3219
3539
|
});
|
|
3220
3540
|
const handleCardTokenize = (token, billing) => {
|
|
3541
|
+
setCreateErrorMessage(null);
|
|
3221
3542
|
createMutation.mutate(buildPayload(token, billing));
|
|
3222
3543
|
};
|
|
3223
3544
|
return /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: "border-0 bg-black/30 shadow-2xl backdrop-blur-xl", children: [
|
|
@@ -3236,32 +3557,19 @@ var PaymentMethodsSection = ({
|
|
|
3236
3557
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "mr-2 h-5 w-5 animate-spin" }),
|
|
3237
3558
|
" ",
|
|
3238
3559
|
t.loadingCards
|
|
3239
|
-
] }) : payments.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6 text-sm text-center", children: t.noPaymentMethods }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-3", children: payments.map((method) =>
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3560
|
+
] }) : payments.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6 text-sm text-center", children: t.noPaymentMethods }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-3", children: payments.map((method) => {
|
|
3561
|
+
(method.subscriptions?.length ?? 0) > 0;
|
|
3562
|
+
expandedSubscriptions[method.id] ?? false;
|
|
3563
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3564
|
+
"div",
|
|
3565
|
+
{
|
|
3566
|
+
className: "rounded-lg border bg-white/5 p-4 shadow-sm",
|
|
3567
|
+
children: [
|
|
3568
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
|
|
3569
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-between", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-base font-medium text-white", children: formatCardLabel2(method) }) }),
|
|
3570
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { children: method.failure_reason && /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "destructive", children: method.failure_reason }) })
|
|
3248
3571
|
] }),
|
|
3249
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", {
|
|
3250
|
-
] }),
|
|
3251
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 flex flex-wrap gap-2", children: [
|
|
3252
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3253
|
-
Button,
|
|
3254
|
-
{
|
|
3255
|
-
variant: "outline",
|
|
3256
|
-
disabled: method.is_active || activateMutation.isPending,
|
|
3257
|
-
onClick: () => activateMutation.mutate(method.id),
|
|
3258
|
-
children: [
|
|
3259
|
-
activateMutation.isPending ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : null,
|
|
3260
|
-
method.is_active ? t.defaultMethod : t.makeDefault
|
|
3261
|
-
]
|
|
3262
|
-
}
|
|
3263
|
-
),
|
|
3264
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3572
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3 flex flex-wrap gap-2", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3265
3573
|
Button,
|
|
3266
3574
|
{
|
|
3267
3575
|
variant: "ghost",
|
|
@@ -3273,12 +3581,12 @@ var PaymentMethodsSection = ({
|
|
|
3273
3581
|
t.remove
|
|
3274
3582
|
]
|
|
3275
3583
|
}
|
|
3276
|
-
)
|
|
3277
|
-
]
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
)
|
|
3584
|
+
) })
|
|
3585
|
+
]
|
|
3586
|
+
},
|
|
3587
|
+
method.id
|
|
3588
|
+
);
|
|
3589
|
+
}) }) }),
|
|
3282
3590
|
/* @__PURE__ */ jsxRuntime.jsx(Dialog, { open: isModalOpen, onOpenChange: setIsModalOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3283
3591
|
DialogContent,
|
|
3284
3592
|
{
|
|
@@ -3296,12 +3604,13 @@ var PaymentMethodsSection = ({
|
|
|
3296
3604
|
collectPrefix,
|
|
3297
3605
|
onTokenize: handleCardTokenize,
|
|
3298
3606
|
submitting: createMutation.isPending,
|
|
3607
|
+
translations: t,
|
|
3299
3608
|
defaultValues: {
|
|
3300
3609
|
provider,
|
|
3301
3610
|
email: userEmail ?? "",
|
|
3302
3611
|
country: defaultCountry
|
|
3303
3612
|
},
|
|
3304
|
-
externalError:
|
|
3613
|
+
externalError: createErrorMessage
|
|
3305
3614
|
}
|
|
3306
3615
|
)
|
|
3307
3616
|
]
|
|
@@ -3309,6 +3618,387 @@ var PaymentMethodsSection = ({
|
|
|
3309
3618
|
) })
|
|
3310
3619
|
] });
|
|
3311
3620
|
};
|
|
3621
|
+
var notifyDefault4 = (payload) => {
|
|
3622
|
+
const level = payload.status === "destructive" ? "error" : "info";
|
|
3623
|
+
console[level === "error" ? "error" : "log"]("[payments-ui] notification", payload);
|
|
3624
|
+
};
|
|
3625
|
+
var defaultTranslations6 = {
|
|
3626
|
+
title: "Subscriptions",
|
|
3627
|
+
description: "Manage your active and recent subscriptions.",
|
|
3628
|
+
loading: "Loading subscriptions...",
|
|
3629
|
+
noSubscriptions: "No subscriptions found.",
|
|
3630
|
+
status: "Status",
|
|
3631
|
+
active: "Active",
|
|
3632
|
+
cancelled: "Cancelled",
|
|
3633
|
+
pastDue: "Past due",
|
|
3634
|
+
pending: "Pending",
|
|
3635
|
+
paymentMethodLabel: "Payment method",
|
|
3636
|
+
changePaymentMethod: "Change payment method",
|
|
3637
|
+
paymentMethodUpdated: "Payment method updated",
|
|
3638
|
+
paymentMethodUpdateFailed: "Unable to update payment method",
|
|
3639
|
+
resume: "Resume subscription",
|
|
3640
|
+
changePlan: "Change plan",
|
|
3641
|
+
changePlanPlaceholder: "Enter a new price ID",
|
|
3642
|
+
planChanged: "Subscription updated",
|
|
3643
|
+
planChangeFailed: "Unable to update subscription",
|
|
3644
|
+
planChangeUnavailable: "Plan changes are unavailable for this subscription.",
|
|
3645
|
+
resumeSuccess: "Resume requested",
|
|
3646
|
+
resumeFailed: "Unable to resume subscription",
|
|
3647
|
+
update: "Update",
|
|
3648
|
+
product: "Product",
|
|
3649
|
+
price: "Price",
|
|
3650
|
+
currentPeriod: "Current period",
|
|
3651
|
+
refresh: "Refresh",
|
|
3652
|
+
manage: "Manage",
|
|
3653
|
+
close: "Close",
|
|
3654
|
+
paymentMethodTab: "Payment method",
|
|
3655
|
+
changePlanTab: "Change plan",
|
|
3656
|
+
statusTab: "Details",
|
|
3657
|
+
cancelTab: "Cancel/Resume"
|
|
3658
|
+
};
|
|
3659
|
+
var formatCardLabel3 = (method) => {
|
|
3660
|
+
if (method.card) {
|
|
3661
|
+
const brand2 = method.card.brand ? method.card.brand.toUpperCase() : "CARD";
|
|
3662
|
+
const lastFour2 = method.card.last4 ? `\u2022\u2022\u2022\u2022 ${method.card.last4}` : "";
|
|
3663
|
+
const exp = method.card.exp_month && method.card.exp_year ? ` \u2022 ${String(method.card.exp_month).padStart(2, "0")}/${String(method.card.exp_year).slice(-2)}` : "";
|
|
3664
|
+
return `${brand2} ${lastFour2}${exp}`.trim();
|
|
3665
|
+
}
|
|
3666
|
+
const brand = "CARD";
|
|
3667
|
+
const lastFour = "";
|
|
3668
|
+
return `${brand} ${lastFour}`.trim();
|
|
3669
|
+
};
|
|
3670
|
+
var SubscriptionsSection = ({
|
|
3671
|
+
isAuthenticated = true,
|
|
3672
|
+
translations: customTranslations,
|
|
3673
|
+
onNotify,
|
|
3674
|
+
statusFilter,
|
|
3675
|
+
cancelDialogTranslations,
|
|
3676
|
+
onCancelled
|
|
3677
|
+
}) => {
|
|
3678
|
+
const { client, queryClient } = usePaymentContext();
|
|
3679
|
+
const notify = onNotify ?? notifyDefault4;
|
|
3680
|
+
const t = { ...defaultTranslations6, ...customTranslations };
|
|
3681
|
+
const cancelTranslations = cancelDialogTranslations ?? defaultTranslations3;
|
|
3682
|
+
const [paymentSelections, setPaymentSelections] = React4.useState({});
|
|
3683
|
+
const [priceInputs, setPriceInputs] = React4.useState({});
|
|
3684
|
+
const [activeSubId, setActiveSubId] = React4.useState(null);
|
|
3685
|
+
const [cancelDialogOpen, setCancelDialogOpen] = React4.useState(false);
|
|
3686
|
+
const [sectionsOpen, setSectionsOpen] = React4.useState({
|
|
3687
|
+
status: true,
|
|
3688
|
+
payment: false,
|
|
3689
|
+
plan: false,
|
|
3690
|
+
cancel: false
|
|
3691
|
+
});
|
|
3692
|
+
const normalizedStatusFilter = statusFilter ?? "all";
|
|
3693
|
+
const subscriptionsQueryKey = ["payments-ui", "subscriptions", normalizedStatusFilter];
|
|
3694
|
+
const paymentMethodsQueryKey = ["payments-ui", "payment-methods"];
|
|
3695
|
+
const subscriptionsQuery = reactQuery.useQuery({
|
|
3696
|
+
queryKey: subscriptionsQueryKey,
|
|
3697
|
+
queryFn: () => client.listSubscriptions({
|
|
3698
|
+
status: normalizedStatusFilter,
|
|
3699
|
+
limit: 50
|
|
3700
|
+
}),
|
|
3701
|
+
enabled: isAuthenticated && !!client,
|
|
3702
|
+
staleTime: 3e4
|
|
3703
|
+
});
|
|
3704
|
+
const paymentMethodsQuery = reactQuery.useQuery({
|
|
3705
|
+
queryKey: paymentMethodsQueryKey,
|
|
3706
|
+
queryFn: () => client.listPaymentMethods({ limit: 50 }),
|
|
3707
|
+
enabled: isAuthenticated && !!client,
|
|
3708
|
+
staleTime: 3e4
|
|
3709
|
+
});
|
|
3710
|
+
const subscriptions = React4.useMemo(() => subscriptionsQuery.data?.data ?? [], [subscriptionsQuery.data]);
|
|
3711
|
+
const paymentMethods = React4.useMemo(() => paymentMethodsQuery.data?.data ?? [], [paymentMethodsQuery.data]);
|
|
3712
|
+
const activeSubscription = React4.useMemo(
|
|
3713
|
+
() => subscriptions.find((sub) => sub.id === activeSubId),
|
|
3714
|
+
[subscriptions, activeSubId]
|
|
3715
|
+
);
|
|
3716
|
+
React4.useEffect(() => {
|
|
3717
|
+
setPaymentSelections((prev) => {
|
|
3718
|
+
const next = {};
|
|
3719
|
+
subscriptions.forEach((sub) => {
|
|
3720
|
+
next[sub.id] = prev[sub.id] ?? "";
|
|
3721
|
+
});
|
|
3722
|
+
return next;
|
|
3723
|
+
});
|
|
3724
|
+
}, [subscriptions]);
|
|
3725
|
+
React4.useEffect(() => {
|
|
3726
|
+
setCancelDialogOpen(false);
|
|
3727
|
+
}, [activeSubId]);
|
|
3728
|
+
const updatePaymentMethodMutation = reactQuery.useMutation({
|
|
3729
|
+
mutationFn: (payload) => client.updateSubscriptionPaymentMethod({
|
|
3730
|
+
subscription_id: payload.subscriptionId,
|
|
3731
|
+
payment_method_id: payload.paymentMethodId
|
|
3732
|
+
}),
|
|
3733
|
+
onSuccess: () => {
|
|
3734
|
+
notify({ title: t.paymentMethodUpdated, status: "success" });
|
|
3735
|
+
void queryClient.invalidateQueries({ queryKey: subscriptionsQueryKey });
|
|
3736
|
+
},
|
|
3737
|
+
onError: (error) => {
|
|
3738
|
+
notify({
|
|
3739
|
+
title: t.paymentMethodUpdateFailed,
|
|
3740
|
+
description: resolveErrorMessageByCode(error, {}, error.message),
|
|
3741
|
+
status: "destructive"
|
|
3742
|
+
});
|
|
3743
|
+
}
|
|
3744
|
+
});
|
|
3745
|
+
const resumeSubscriptionMutation = reactQuery.useMutation({
|
|
3746
|
+
mutationFn: () => client.resumeSubscription(),
|
|
3747
|
+
onSuccess: () => {
|
|
3748
|
+
notify({ title: t.resumeSuccess, status: "success" });
|
|
3749
|
+
void queryClient.invalidateQueries({ queryKey: subscriptionsQueryKey });
|
|
3750
|
+
},
|
|
3751
|
+
onError: (error) => {
|
|
3752
|
+
notify({
|
|
3753
|
+
title: t.resumeFailed,
|
|
3754
|
+
description: resolveErrorMessageByCode(error, {}, error.message),
|
|
3755
|
+
status: "destructive"
|
|
3756
|
+
});
|
|
3757
|
+
}
|
|
3758
|
+
});
|
|
3759
|
+
reactQuery.useMutation({
|
|
3760
|
+
mutationFn: (payload) => client.changeSubscription({ price_id: payload.priceId }),
|
|
3761
|
+
onSuccess: () => {
|
|
3762
|
+
notify({ title: t.planChanged, status: "success" });
|
|
3763
|
+
void queryClient.invalidateQueries({ queryKey: subscriptionsQueryKey });
|
|
3764
|
+
},
|
|
3765
|
+
onError: (error) => {
|
|
3766
|
+
notify({
|
|
3767
|
+
title: t.planChangeFailed,
|
|
3768
|
+
description: resolveErrorMessageByCode(error, {}, error.message),
|
|
3769
|
+
status: "destructive"
|
|
3770
|
+
});
|
|
3771
|
+
}
|
|
3772
|
+
});
|
|
3773
|
+
const isLoading = subscriptionsQuery.isLoading || subscriptionsQuery.isFetching;
|
|
3774
|
+
const isError = subscriptionsQuery.isError;
|
|
3775
|
+
const errorMessage = subscriptionsQuery.error instanceof Error ? subscriptionsQuery.error.message : void 0;
|
|
3776
|
+
React4.useEffect(() => {
|
|
3777
|
+
if (subscriptionsQuery.refetch) {
|
|
3778
|
+
void subscriptionsQuery.refetch();
|
|
3779
|
+
}
|
|
3780
|
+
}, []);
|
|
3781
|
+
const formatPrice = (sub) => {
|
|
3782
|
+
const price = sub.price;
|
|
3783
|
+
if (!price) return t.price;
|
|
3784
|
+
const amount = (price.amount / 100).toFixed(2);
|
|
3785
|
+
const currency = price.currency ? price.currency?.toUpperCase() : "";
|
|
3786
|
+
return `${price.display_name ?? t.price} \u2014 ${currency} ${amount}`;
|
|
3787
|
+
};
|
|
3788
|
+
const renderStatusBadge = (status) => {
|
|
3789
|
+
const normalized = status.toLowerCase();
|
|
3790
|
+
const label = normalized === "active" ? t.active : normalized === "past_due" ? t.pastDue : normalized === "pending" ? t.pending : t.cancelled;
|
|
3791
|
+
const variant = normalized === "active" ? "default" : normalized === "past_due" ? "destructive" : normalized === "pending" ? "outline" : "secondary";
|
|
3792
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant, children: label });
|
|
3793
|
+
};
|
|
3794
|
+
const handleUpdatePaymentMethod = (subscriptionId) => {
|
|
3795
|
+
const paymentMethodId = paymentSelections[subscriptionId];
|
|
3796
|
+
const currentPaymentMethodId = "pm_" + subscriptions.find((s) => s.id === subscriptionId)?.payment_method_id;
|
|
3797
|
+
if (!paymentMethodId) return;
|
|
3798
|
+
if (currentPaymentMethodId && paymentMethodId === currentPaymentMethodId) {
|
|
3799
|
+
notify({
|
|
3800
|
+
title: t.paymentMethodUpdateFailed,
|
|
3801
|
+
description: t.paymentMethodUpdateFailed,
|
|
3802
|
+
status: "destructive"
|
|
3803
|
+
});
|
|
3804
|
+
return;
|
|
3805
|
+
}
|
|
3806
|
+
updatePaymentMethodMutation.mutate({ subscriptionId, paymentMethodId });
|
|
3807
|
+
};
|
|
3808
|
+
const toggleSection = (key) => {
|
|
3809
|
+
setSectionsOpen((prev) => ({
|
|
3810
|
+
...prev,
|
|
3811
|
+
[key]: !prev[key]
|
|
3812
|
+
}));
|
|
3813
|
+
};
|
|
3814
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3815
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Card, { className: "border-0 bg-black/30 shadow-2xl backdrop-blur-xl", children: [
|
|
3816
|
+
/* @__PURE__ */ jsxRuntime.jsxs(CardHeader, { className: "flex flex-col gap-4 md:flex-row md:items-center md:justify-between", children: [
|
|
3817
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
3818
|
+
/* @__PURE__ */ jsxRuntime.jsxs(CardTitle, { className: "flex items-center gap-2", children: [
|
|
3819
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.WalletCards, { className: "h-5 w-5" }),
|
|
3820
|
+
t.title
|
|
3821
|
+
] }),
|
|
3822
|
+
/* @__PURE__ */ jsxRuntime.jsx(CardDescription, { children: t.description })
|
|
3823
|
+
] }),
|
|
3824
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3825
|
+
Button,
|
|
3826
|
+
{
|
|
3827
|
+
variant: "ghost",
|
|
3828
|
+
size: "sm",
|
|
3829
|
+
onClick: () => subscriptionsQuery.refetch?.(),
|
|
3830
|
+
disabled: subscriptionsQuery.isFetching,
|
|
3831
|
+
children: [
|
|
3832
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, { className: "mr-2 h-4 w-4" }),
|
|
3833
|
+
" ",
|
|
3834
|
+
subscriptionsQuery.isFetching ? t.loading : t.refresh
|
|
3835
|
+
]
|
|
3836
|
+
}
|
|
3837
|
+
)
|
|
3838
|
+
] }),
|
|
3839
|
+
/* @__PURE__ */ jsxRuntime.jsx(CardContent, { className: "space-y-4", children: isLoading ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center py-10 text-white/60", children: [
|
|
3840
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "mr-2 h-5 w-5 animate-spin" }),
|
|
3841
|
+
" ",
|
|
3842
|
+
t.loading
|
|
3843
|
+
] }) : isError ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-md border border-red-500/30 bg-red-500/10 p-4 text-sm text-red-100", children: errorMessage ?? "Unable to load subscriptions." }) : subscriptions.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6 text-sm text-center", children: t.noSubscriptions }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-3", children: subscriptions.map((subscription) => {
|
|
3844
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3845
|
+
"div",
|
|
3846
|
+
{
|
|
3847
|
+
className: "rounded-lg border bg-white/5 p-4 shadow-sm",
|
|
3848
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-4", children: [
|
|
3849
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
3850
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-base font-semibold text-white", children: subscription.product?.display_name ?? t.product }),
|
|
3851
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm text-white/80", children: formatPrice(subscription) })
|
|
3852
|
+
] }),
|
|
3853
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
3854
|
+
renderStatusBadge(subscription.status),
|
|
3855
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3856
|
+
Button,
|
|
3857
|
+
{
|
|
3858
|
+
variant: "default",
|
|
3859
|
+
size: "sm",
|
|
3860
|
+
className: "rounded-full bg-foreground/10 text-muted-foreground hover:bg-foreground/20 hover:text-foreground",
|
|
3861
|
+
onClick: () => setActiveSubId(subscription.id),
|
|
3862
|
+
children: t.update
|
|
3863
|
+
}
|
|
3864
|
+
)
|
|
3865
|
+
] })
|
|
3866
|
+
] })
|
|
3867
|
+
},
|
|
3868
|
+
subscription.id
|
|
3869
|
+
);
|
|
3870
|
+
}) }) })
|
|
3871
|
+
] }),
|
|
3872
|
+
/* @__PURE__ */ jsxRuntime.jsx(Dialog, { open: !!activeSubscription, onOpenChange: (open) => setActiveSubId(open ? activeSubId : null), children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: "max-w-2xl min-h-[300px] border border-white/20 bg-background-regular p-6 text-foreground", children: [
|
|
3873
|
+
/* @__PURE__ */ jsxRuntime.jsxs(DialogHeader, { children: [
|
|
3874
|
+
/* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { className: "flex items-center gap-2", children: activeSubscription?.product?.display_name ?? t.product }),
|
|
3875
|
+
/* @__PURE__ */ jsxRuntime.jsx(DialogDescription, { className: "text-white/70", children: activeSubscription ? formatPrice(activeSubscription) : null })
|
|
3876
|
+
] }),
|
|
3877
|
+
activeSubscription && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4 space-y-3", children: [
|
|
3878
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "overflow-hidden rounded-lg border border-white/15 bg-white/5", children: [
|
|
3879
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3880
|
+
"button",
|
|
3881
|
+
{
|
|
3882
|
+
type: "button",
|
|
3883
|
+
className: "flex w-full items-center justify-between px-4 py-3 text-left text-white hover:bg-white/10",
|
|
3884
|
+
onClick: () => toggleSection("status"),
|
|
3885
|
+
children: [
|
|
3886
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold", children: t.statusTab }),
|
|
3887
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3888
|
+
lucideReact.ChevronDown,
|
|
3889
|
+
{
|
|
3890
|
+
className: `h-4 w-4 transition-transform ${sectionsOpen.status ? "rotate-180" : ""}`
|
|
3891
|
+
}
|
|
3892
|
+
)
|
|
3893
|
+
]
|
|
3894
|
+
}
|
|
3895
|
+
),
|
|
3896
|
+
sectionsOpen.status ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3 border-t border-white/10 px-4 py-3", children: [
|
|
3897
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between rounded-lg border border-white/10 bg-white/5 p-3", children: [
|
|
3898
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium text-white/80", children: t.status }),
|
|
3899
|
+
renderStatusBadge(activeSubscription.status)
|
|
3900
|
+
] }),
|
|
3901
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-white/60", children: [
|
|
3902
|
+
t.currentPeriod,
|
|
3903
|
+
": ",
|
|
3904
|
+
activeSubscription.started_at ? new Date(activeSubscription.started_at).toLocaleDateString() : "\u2014",
|
|
3905
|
+
" \u2192",
|
|
3906
|
+
" ",
|
|
3907
|
+
activeSubscription.current_period_ends_at ?? "\u2014"
|
|
3908
|
+
] }),
|
|
3909
|
+
activeSubscription.status.toLowerCase() === "cancelled" ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3910
|
+
Button,
|
|
3911
|
+
{
|
|
3912
|
+
variant: "secondary",
|
|
3913
|
+
onClick: () => resumeSubscriptionMutation.mutate(),
|
|
3914
|
+
disabled: resumeSubscriptionMutation.isPending,
|
|
3915
|
+
className: "rounded-full px-4",
|
|
3916
|
+
children: [
|
|
3917
|
+
resumeSubscriptionMutation.isPending ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : null,
|
|
3918
|
+
t.resume
|
|
3919
|
+
]
|
|
3920
|
+
}
|
|
3921
|
+
) : null
|
|
3922
|
+
] }) : null
|
|
3923
|
+
] }),
|
|
3924
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "overflow-hidden rounded-lg border border-white/15 bg-white/5", children: [
|
|
3925
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3926
|
+
"button",
|
|
3927
|
+
{
|
|
3928
|
+
type: "button",
|
|
3929
|
+
className: "flex w-full items-center justify-between px-4 py-3 text-left text-white hover:bg-white/10",
|
|
3930
|
+
onClick: () => toggleSection("payment"),
|
|
3931
|
+
children: [
|
|
3932
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold", children: t.paymentMethodTab }),
|
|
3933
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3934
|
+
lucideReact.ChevronDown,
|
|
3935
|
+
{
|
|
3936
|
+
className: `h-4 w-4 transition-transform ${sectionsOpen.payment ? "rotate-180" : ""}`
|
|
3937
|
+
}
|
|
3938
|
+
)
|
|
3939
|
+
]
|
|
3940
|
+
}
|
|
3941
|
+
),
|
|
3942
|
+
sectionsOpen.payment ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2 border-t border-white/10 px-4 py-3", children: [
|
|
3943
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs uppercase tracking-wide text-white/60", children: t.paymentMethodLabel }),
|
|
3944
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3 md:flex-row md:items-center md:gap-2", children: [
|
|
3945
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3946
|
+
Select,
|
|
3947
|
+
{
|
|
3948
|
+
value: paymentSelections[activeSubscription.id] || "pm_" + activeSubscription.payment_method_id || "",
|
|
3949
|
+
onValueChange: (value) => setPaymentSelections((prev) => ({ ...prev, [activeSubscription.id]: value })),
|
|
3950
|
+
disabled: paymentMethodsQuery.isLoading || paymentMethods.length === 0,
|
|
3951
|
+
children: [
|
|
3952
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { className: "w-full md:w-64 text-white", children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, { placeholder: paymentMethodsQuery.isLoading ? t.loading : "" }) }),
|
|
3953
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectContent, { children: paymentMethods.filter((method) => method.id !== activeSubscription.payment_method_id).map((method) => /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: method.id, children: formatCardLabel3(method) }, method.id)) })
|
|
3954
|
+
]
|
|
3955
|
+
}
|
|
3956
|
+
),
|
|
3957
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3958
|
+
Button,
|
|
3959
|
+
{
|
|
3960
|
+
size: "sm",
|
|
3961
|
+
onClick: () => handleUpdatePaymentMethod(activeSubscription.id),
|
|
3962
|
+
disabled: updatePaymentMethodMutation.isPending || !paymentSelections[activeSubscription.id] || paymentSelections[activeSubscription.id] === activeSubscription.payment_method_id,
|
|
3963
|
+
className: "border-0 bg-green-bg text-white hover:bg-green-bg/80 disabled:opacity-50",
|
|
3964
|
+
children: [
|
|
3965
|
+
updatePaymentMethodMutation.isPending ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : null,
|
|
3966
|
+
t.update
|
|
3967
|
+
]
|
|
3968
|
+
}
|
|
3969
|
+
)
|
|
3970
|
+
] })
|
|
3971
|
+
] }) : null
|
|
3972
|
+
] })
|
|
3973
|
+
] }),
|
|
3974
|
+
/* @__PURE__ */ jsxRuntime.jsxs(DialogFooter, { className: "flex flex-wrap gap-2", children: [
|
|
3975
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3976
|
+
CancelMembershipDialog,
|
|
3977
|
+
{
|
|
3978
|
+
translations: cancelTranslations,
|
|
3979
|
+
onNotify,
|
|
3980
|
+
open: cancelDialogOpen,
|
|
3981
|
+
onOpenChange: (openState) => setCancelDialogOpen(openState),
|
|
3982
|
+
onCancelled: () => {
|
|
3983
|
+
void queryClient.invalidateQueries({ queryKey: subscriptionsQueryKey });
|
|
3984
|
+
onCancelled?.();
|
|
3985
|
+
setActiveSubId(null);
|
|
3986
|
+
}
|
|
3987
|
+
}
|
|
3988
|
+
),
|
|
3989
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3990
|
+
Button,
|
|
3991
|
+
{
|
|
3992
|
+
variant: "secondary",
|
|
3993
|
+
onClick: () => setActiveSubId(null),
|
|
3994
|
+
className: "border-white/20 bg-transparent text-foreground hover:bg-foreground/10 hover:text-foreground",
|
|
3995
|
+
children: t.close
|
|
3996
|
+
}
|
|
3997
|
+
)
|
|
3998
|
+
] })
|
|
3999
|
+
] }) })
|
|
4000
|
+
] });
|
|
4001
|
+
};
|
|
3312
4002
|
var Checkbox = React4__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
3313
4003
|
CheckboxPrimitive__namespace.Root,
|
|
3314
4004
|
{
|
|
@@ -3838,9 +4528,13 @@ exports.SolanaPaymentView = SolanaPaymentView;
|
|
|
3838
4528
|
exports.StoredPaymentMethods = StoredPaymentMethods;
|
|
3839
4529
|
exports.SubscriptionCheckoutModal = SubscriptionCheckoutModal;
|
|
3840
4530
|
exports.SubscriptionSuccessDialog = SubscriptionSuccessDialog;
|
|
4531
|
+
exports.SubscriptionsSection = SubscriptionsSection;
|
|
3841
4532
|
exports.WalletDialog = WalletDialog;
|
|
3842
4533
|
exports.WalletModal = WalletModal;
|
|
3843
4534
|
exports.createClient = createClient;
|
|
4535
|
+
exports.defaultCardDetailsFormTranslations = defaultCardDetailsFormTranslations;
|
|
4536
|
+
exports.defaultPaymentExperienceTranslations = defaultPaymentExperienceTranslations;
|
|
4537
|
+
exports.defaultTranslations = defaultTranslations3;
|
|
3844
4538
|
exports.usePaymentContext = usePaymentContext;
|
|
3845
4539
|
exports.usePaymentDialogs = usePaymentDialogs;
|
|
3846
4540
|
exports.usePaymentMethods = usePaymentMethods;
|