@fluid-app/portal-sdk 0.1.28 → 0.1.30
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/{AppNavigationContext-DrayF_RG.cjs → AppNavigationContext-DAcrNgXZ.cjs} +1 -1
- package/dist/{AppNavigationContext-DrayF_RG.cjs.map → AppNavigationContext-DAcrNgXZ.cjs.map} +1 -1
- package/dist/{AppNavigationContext-2nkMoO8F.mjs → AppNavigationContext-v_y8OYHo.mjs} +1 -1
- package/dist/{AppNavigationContext-2nkMoO8F.mjs.map → AppNavigationContext-v_y8OYHo.mjs.map} +1 -1
- package/dist/{ContactsScreen-GPOgZ-Wi.cjs → ContactsScreen-BL5Jlaz5.cjs} +2 -2
- package/dist/{ContactsScreen-GPOgZ-Wi.cjs.map → ContactsScreen-BL5Jlaz5.cjs.map} +1 -1
- package/dist/{ContactsScreen-BicHZ37M.mjs → ContactsScreen-CcNUC8xu.mjs} +2 -2
- package/dist/{ContactsScreen-BicHZ37M.mjs.map → ContactsScreen-CcNUC8xu.mjs.map} +1 -1
- package/dist/{CoreScreenPlaceholder-Cl_zuOBC.cjs → CoreScreenPlaceholder-B64M78iR.cjs} +1 -1
- package/dist/{CoreScreenPlaceholder-Cl_zuOBC.cjs.map → CoreScreenPlaceholder-B64M78iR.cjs.map} +1 -1
- package/dist/{CoreScreenPlaceholder-Cdyl97Wo.mjs → CoreScreenPlaceholder-DVVLc-OM.mjs} +1 -1
- package/dist/{CoreScreenPlaceholder-Cdyl97Wo.mjs.map → CoreScreenPlaceholder-DVVLc-OM.mjs.map} +1 -1
- package/dist/{CustomersScreen-Brz5zLkq.mjs → CustomersScreen-SuHGSUdb.mjs} +2 -2
- package/dist/{CustomersScreen-Brz5zLkq.mjs.map → CustomersScreen-SuHGSUdb.mjs.map} +1 -1
- package/dist/{CustomersScreen-CK1jJhvM.cjs → CustomersScreen-zl_vRzcJ.cjs} +2 -2
- package/dist/{CustomersScreen-CK1jJhvM.cjs.map → CustomersScreen-zl_vRzcJ.cjs.map} +1 -1
- package/dist/{MessagingScreen-DVU3c8fX.mjs → MessagingScreen-BGzfLD8k.mjs} +2 -2
- package/dist/{MessagingScreen-sAWF7pjl.cjs → MessagingScreen-CRLd91tP.cjs} +2 -2
- package/dist/{MessagingScreen-sAWF7pjl.cjs.map → MessagingScreen-CRLd91tP.cjs.map} +1 -1
- package/dist/{MessagingScreen-C33eDdna.cjs → MessagingScreen-DIZ72Tg0.cjs} +2 -2
- package/dist/{MessagingScreen-II_iNqLk.mjs → MessagingScreen-We1B2pka.mjs} +2 -2
- package/dist/{MessagingScreen-II_iNqLk.mjs.map → MessagingScreen-We1B2pka.mjs.map} +1 -1
- package/dist/OrdersScreen-Bu-ENmH6.cjs +133 -0
- package/dist/OrdersScreen-Bu-ENmH6.cjs.map +1 -0
- package/dist/OrdersScreen-TSXDDHZe.cjs +33 -0
- package/dist/OrdersScreen-afRAHf07.mjs +126 -0
- package/dist/OrdersScreen-afRAHf07.mjs.map +1 -0
- package/dist/{ProductsScreen-DrrBYFl0.mjs → ProductsScreen-B-oWUzvD.mjs} +3 -3
- package/dist/{ProductsScreen-BOngRxSO.mjs → ProductsScreen-ChvK61hX.mjs} +3 -3
- package/dist/{ProductsScreen-BOngRxSO.mjs.map → ProductsScreen-ChvK61hX.mjs.map} +1 -1
- package/dist/{ProductsScreen-DzD-TPh5.cjs → ProductsScreen-CkE2nyuw.cjs} +3 -3
- package/dist/{ProductsScreen-DzD-TPh5.cjs.map → ProductsScreen-CkE2nyuw.cjs.map} +1 -1
- package/dist/{ProductsScreen-CdP_m_Ok.cjs → ProductsScreen-PCg91SbX.cjs} +3 -3
- package/dist/ProfileScreen-B6Dp7RLa.cjs +2856 -0
- package/dist/ProfileScreen-B6Dp7RLa.cjs.map +1 -0
- package/dist/ProfileScreen-B83tzedh.mjs +2849 -0
- package/dist/ProfileScreen-B83tzedh.mjs.map +1 -0
- package/dist/{AccountScreen-Vzz8W4Iq.cjs → ProfileScreen-CH3B-IQz.cjs} +3 -3
- package/dist/{ShareablesScreen-DYPJgZ3z.cjs → ShareablesScreen-Bqj6dtOM.cjs} +3 -3
- package/dist/{ShareablesScreen-DYPJgZ3z.cjs.map → ShareablesScreen-Bqj6dtOM.cjs.map} +1 -1
- package/dist/{ShareablesScreen-jHqLmOC6.cjs → ShareablesScreen-BvJIBZvI.cjs} +3 -3
- package/dist/{ShareablesScreen-CQy39TAK.mjs → ShareablesScreen-ChS517hq.mjs} +3 -3
- package/dist/{ShareablesScreen-CQy39TAK.mjs.map → ShareablesScreen-ChS517hq.mjs.map} +1 -1
- package/dist/{ShareablesScreen-BsqZvRSK.mjs → ShareablesScreen-CqVj81Ol.mjs} +3 -3
- package/dist/{ShopScreen-BPCwix1m.cjs → ShopScreen-CjoTGnCJ.cjs} +2 -2
- package/dist/{ShopScreen-BPCwix1m.cjs.map → ShopScreen-CjoTGnCJ.cjs.map} +1 -1
- package/dist/{ShopScreen--pUsiUNt.cjs → ShopScreen-DS4p47Ry.cjs} +1 -1
- package/dist/{ShopScreen-BKBzgkr7.mjs → ShopScreen-KeU6x3PT.mjs} +2 -2
- package/dist/{ShopScreen-BKBzgkr7.mjs.map → ShopScreen-KeU6x3PT.mjs.map} +1 -1
- package/dist/SubscriptionsScreen-CHn_Q0zf.cjs +1288 -0
- package/dist/SubscriptionsScreen-CHn_Q0zf.cjs.map +1 -0
- package/dist/SubscriptionsScreen-D5_eJwBP.mjs +1281 -0
- package/dist/SubscriptionsScreen-D5_eJwBP.mjs.map +1 -0
- package/dist/SubscriptionsScreen-DGJ_YeX3.cjs +33 -0
- package/dist/{es-kNOrmozy.cjs → es-BtechuHV.cjs} +1 -1
- package/dist/{es-kNOrmozy.cjs.map → es-BtechuHV.cjs.map} +1 -1
- package/dist/{es-BL8VBBDa.mjs → es-DxWiENwN.mjs} +1 -1
- package/dist/{es-BL8VBBDa.mjs.map → es-DxWiENwN.mjs.map} +1 -1
- package/dist/index.cjs +166 -94
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +38 -8
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +38 -8
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +162 -92
- package/dist/index.mjs.map +1 -1
- package/dist/src-BZEkCfd4.mjs +973 -0
- package/dist/src-BZEkCfd4.mjs.map +1 -0
- package/dist/src-DXC-Jw6i.cjs +1009 -0
- package/dist/src-DXC-Jw6i.cjs.map +1 -0
- package/dist/{src-DMjlIMO9.cjs → src-vxm9rMYT.cjs} +2 -2
- package/dist/{src-DMjlIMO9.cjs.map → src-vxm9rMYT.cjs.map} +1 -1
- package/dist/{src-9pW9wS5O.mjs → src-wpQFW94i.mjs} +2 -2
- package/dist/{src-9pW9wS5O.mjs.map → src-wpQFW94i.mjs.map} +1 -1
- package/dist/use-account-clients-DYTyFvdN.mjs +134 -0
- package/dist/use-account-clients-DYTyFvdN.mjs.map +1 -0
- package/dist/use-account-clients-n2a8bdSP.cjs +182 -0
- package/dist/use-account-clients-n2a8bdSP.cjs.map +1 -0
- package/package.json +10 -10
- package/dist/AccountScreen-Dp6QFyEr.cjs +0 -5322
- package/dist/AccountScreen-Dp6QFyEr.cjs.map +0 -1
- package/dist/AccountScreen-E4ZBgOUS.mjs +0 -5309
- package/dist/AccountScreen-E4ZBgOUS.mjs.map +0 -1
- package/dist/OrdersScreen-DGt-CTBS.mjs +0 -24
- package/dist/OrdersScreen-DGt-CTBS.mjs.map +0 -1
- package/dist/OrdersScreen-Dy-JChVQ.cjs +0 -41
- package/dist/OrdersScreen-Dy-JChVQ.cjs.map +0 -1
|
@@ -0,0 +1,2849 @@
|
|
|
1
|
+
import { n as __exportAll } from "./chunk-ByhMGyNw.mjs";
|
|
2
|
+
import { n as useFluidContext } from "./FluidProvider-x96kqsgN.mjs";
|
|
3
|
+
import { A as DropdownMenuContent, At as AvatarFallback, B as DialogContent, Gt as AccordionTrigger, H as DialogFooter, Ht as Accordion, K as DialogTitle, L as DropdownMenuTrigger, N as DropdownMenuSeparator, O as Label, R as Dialog, U as DialogHeader, Ut as AccordionContent, Wt as AccordionItem, c as fluidToast, f as Select, g as SelectValue, h as SelectTrigger, j as DropdownMenuItem, k as DropdownMenu, kt as Avatar, m as SelectItem, p as SelectContent, qt as cn, u as Skeleton, y as Input, z as DialogClose, zt as Button } from "./src-PSNQSAUF.mjs";
|
|
4
|
+
import { c as useFluidAuth, i as useSdkClient, n as useFluidPayClient, o as fetchCustomerAccount, s as updateCustomer, t as API_VERSION } from "./use-account-clients-DYTyFvdN.mjs";
|
|
5
|
+
import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
|
6
|
+
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
7
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
import { Pencil } from "lucide-react";
|
|
9
|
+
import { zodResolver } from "@hookform/resolvers/zod";
|
|
10
|
+
import { Controller, useController, useForm, useWatch } from "react-hook-form";
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
//#region ../../platform/api-client-core/src/parse-api-errors.ts
|
|
13
|
+
/**
|
|
14
|
+
* Framework-agnostic API error parsing utilities.
|
|
15
|
+
*
|
|
16
|
+
* Extracts structured field-level errors from API responses and formats
|
|
17
|
+
* them into human-readable messages. Works with ApiError from this package
|
|
18
|
+
* as well as any error object that has `status`, `data`, and optional `message`.
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* Converts snake_case or camelCase field names to Title Case
|
|
22
|
+
*/
|
|
23
|
+
function formatFieldName(field) {
|
|
24
|
+
return field.replace(/_/g, " ").replace(/([A-Z])/g, " $1").split(" ").map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" ").trim();
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Type guard to check if an error looks like an API error
|
|
28
|
+
*/
|
|
29
|
+
function isApiLikeError(error) {
|
|
30
|
+
if (!error || typeof error !== "object") return false;
|
|
31
|
+
const err = error;
|
|
32
|
+
return typeof err.status === "number" && "data" in err && (typeof err.message === "string" || err.message === void 0);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Extracts field-level errors from API error data
|
|
36
|
+
*/
|
|
37
|
+
function extractFieldErrors(data) {
|
|
38
|
+
const errors = [];
|
|
39
|
+
if (!data || typeof data !== "object") return errors;
|
|
40
|
+
const errorObj = data;
|
|
41
|
+
for (const [key, value] of Object.entries(errorObj)) if (Array.isArray(value) && value.length > 0) errors.push({
|
|
42
|
+
field: formatFieldName(key),
|
|
43
|
+
messages: value.map((item) => typeof item === "string" ? item : JSON.stringify(item))
|
|
44
|
+
});
|
|
45
|
+
else if (typeof value === "string" && value.length > 0) errors.push({
|
|
46
|
+
field: formatFieldName(key),
|
|
47
|
+
messages: [value]
|
|
48
|
+
});
|
|
49
|
+
else if (value && typeof value === "object" && !Array.isArray(value)) extractFieldErrors(value).forEach((nestedError) => {
|
|
50
|
+
errors.push({
|
|
51
|
+
field: `${formatFieldName(key)} → ${nestedError.field}`,
|
|
52
|
+
messages: nestedError.messages
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
return errors;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Formats field errors into a readable description string
|
|
59
|
+
*/
|
|
60
|
+
function formatErrorDescription(errors) {
|
|
61
|
+
if (errors.length === 0) return "";
|
|
62
|
+
if (errors.length === 1) {
|
|
63
|
+
const err = errors[0];
|
|
64
|
+
if (!err) return "";
|
|
65
|
+
const message = err.messages[0] || "is invalid";
|
|
66
|
+
return `${err.field} ${message}`;
|
|
67
|
+
}
|
|
68
|
+
if (errors.length <= 3) return errors.map((e) => `${e.field} ${e.messages[0] || "is invalid"}`).join("\n");
|
|
69
|
+
const shown = errors.slice(0, 3).map((e) => `${e.field} ${e.messages[0] || "is invalid"}`).join("\n");
|
|
70
|
+
const remaining = errors.length - 3;
|
|
71
|
+
return `${shown}\n...and ${remaining} more ${remaining === 1 ? "error" : "errors"}`;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Parses an error and returns a human-readable description string.
|
|
75
|
+
*
|
|
76
|
+
* Handles:
|
|
77
|
+
* - API-like errors with structured field-level data
|
|
78
|
+
* - API-like errors with a top-level message
|
|
79
|
+
* - Standard Error instances
|
|
80
|
+
* - Falls back to the provided fallback string
|
|
81
|
+
*
|
|
82
|
+
* @param error - The error to parse (ApiError, Error, or unknown)
|
|
83
|
+
* @param fallback - Optional fallback description if error cannot be parsed
|
|
84
|
+
* @returns A human-readable error description, or undefined if nothing could be extracted
|
|
85
|
+
*/
|
|
86
|
+
function parseApiErrors(error, fallback) {
|
|
87
|
+
if (isApiLikeError(error)) {
|
|
88
|
+
if (error.data) {
|
|
89
|
+
const fieldErrors = extractFieldErrors(error.data);
|
|
90
|
+
if (fieldErrors.length > 0) return formatErrorDescription(fieldErrors);
|
|
91
|
+
}
|
|
92
|
+
if (error.message) return error.message;
|
|
93
|
+
} else if (error instanceof Error) return error.message;
|
|
94
|
+
return fallback;
|
|
95
|
+
}
|
|
96
|
+
//#endregion
|
|
97
|
+
//#region ../../profile/core/src/context.ts
|
|
98
|
+
const ProfileUIContext = createContext(null);
|
|
99
|
+
function useProfileUI() {
|
|
100
|
+
const context = useContext(ProfileUIContext);
|
|
101
|
+
if (!context) throw new Error("useProfileUI must be used within a ProfileUIProvider");
|
|
102
|
+
return context;
|
|
103
|
+
}
|
|
104
|
+
//#endregion
|
|
105
|
+
//#region ../../profile/core/src/provider.tsx
|
|
106
|
+
function ProfileUIProvider({ t, children }) {
|
|
107
|
+
const value = useMemo(() => ({ t }), [t]);
|
|
108
|
+
return /* @__PURE__ */ jsx(ProfileUIContext.Provider, {
|
|
109
|
+
value,
|
|
110
|
+
children
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
//#endregion
|
|
114
|
+
//#region ../../fluid-pay/api-client/src/namespaces/addresses.ts
|
|
115
|
+
/**
|
|
116
|
+
* Fetch all customer addresses.
|
|
117
|
+
* Endpoint: GET /fluid_pay/addresses?jwt={jwt}
|
|
118
|
+
*/
|
|
119
|
+
async function fetchCustomerAddresses(client, jwt) {
|
|
120
|
+
return client.get("/fluid_pay/addresses", {
|
|
121
|
+
jwt,
|
|
122
|
+
page: "1",
|
|
123
|
+
per_page: "100"
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Create a new customer address.
|
|
128
|
+
* Endpoint: POST /fluid_pay/create_address?jwt={jwt}
|
|
129
|
+
*/
|
|
130
|
+
async function createCustomerAddress(client, jwt, body) {
|
|
131
|
+
return client.post(`/fluid_pay/create_address?jwt=${jwt}`, body);
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Update an existing customer address.
|
|
135
|
+
* Endpoint: PATCH /fluid_pay/update_address/{addressId}?jwt={jwt}
|
|
136
|
+
*/
|
|
137
|
+
async function updateCustomerAddress(client, jwt, addressId, body) {
|
|
138
|
+
return client.patch(`/fluid_pay/update_address/${addressId}?jwt=${jwt}`, body);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Delete a customer address.
|
|
142
|
+
* Endpoint: DELETE /fluid_pay/delete_address/{addressId}?jwt={jwt}
|
|
143
|
+
*/
|
|
144
|
+
async function deleteCustomerAddress(client, jwt, addressId) {
|
|
145
|
+
return client.delete(`/fluid_pay/delete_address/${addressId}?jwt=${jwt}`);
|
|
146
|
+
}
|
|
147
|
+
//#endregion
|
|
148
|
+
//#region ../../fluid-pay/api-client/src/namespaces/payment-methods.ts
|
|
149
|
+
/**
|
|
150
|
+
* Fetch all customer payment methods.
|
|
151
|
+
* Endpoint: GET /fluid_pay/payment_methods?jwt={jwt}
|
|
152
|
+
*/
|
|
153
|
+
async function fetchCustomerPaymentMethods(client, jwt, countryCode) {
|
|
154
|
+
const params = {
|
|
155
|
+
jwt,
|
|
156
|
+
page: "1",
|
|
157
|
+
per_page: "100"
|
|
158
|
+
};
|
|
159
|
+
if (countryCode) params.country_code = countryCode;
|
|
160
|
+
return client.get("/fluid_pay/payment_methods", params);
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Add a credit card to the customer's account.
|
|
164
|
+
* Endpoint: POST /fluid_pay/create_payment_method?jwt={jwt}
|
|
165
|
+
*/
|
|
166
|
+
async function addCreditCardToCustomer(client, jwt, data) {
|
|
167
|
+
return client.post(`/fluid_pay/create_payment_method?jwt=${jwt}`, data);
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Delete a customer payment method.
|
|
171
|
+
* Endpoint: DELETE /fluid_pay/delete_payment_method/{id}?jwt={jwt}
|
|
172
|
+
*/
|
|
173
|
+
async function deleteCustomerPaymentMethod(client, jwt, paymentMethodId) {
|
|
174
|
+
return client.delete(`/fluid_pay/delete_payment_method/${paymentMethodId}?jwt=${jwt}`);
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Update a payment method (default status, billing address).
|
|
178
|
+
* Endpoint: PATCH /fluid_pay/update_payment_method/{id}?jwt={jwt}
|
|
179
|
+
*/
|
|
180
|
+
async function updatePaymentMethod(client, jwt, paymentMethodId, body) {
|
|
181
|
+
return client.patch(`/fluid_pay/update_payment_method/${paymentMethodId}?jwt=${jwt}`, body);
|
|
182
|
+
}
|
|
183
|
+
//#endregion
|
|
184
|
+
//#region ../../fluid-pay/api-client/src/namespaces/vault.ts
|
|
185
|
+
/**
|
|
186
|
+
* Fetch VGS vault credentials for the customer's payment account.
|
|
187
|
+
* Endpoint: GET /fluid_pay/vault?jwt={jwt}
|
|
188
|
+
*/
|
|
189
|
+
async function fetchVaultCredentialsForPaymentAccount(client, jwt) {
|
|
190
|
+
return client.get("/fluid_pay/vault", { jwt });
|
|
191
|
+
}
|
|
192
|
+
//#endregion
|
|
193
|
+
//#region ../../fluid-pay/core/src/utils/country-config.ts
|
|
194
|
+
const US_STATES = [
|
|
195
|
+
{
|
|
196
|
+
name: "Alabama",
|
|
197
|
+
isoCode: "AL"
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
name: "Alaska",
|
|
201
|
+
isoCode: "AK"
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
name: "Arizona",
|
|
205
|
+
isoCode: "AZ"
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
name: "Arkansas",
|
|
209
|
+
isoCode: "AR"
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
name: "California",
|
|
213
|
+
isoCode: "CA"
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
name: "Colorado",
|
|
217
|
+
isoCode: "CO"
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
name: "Connecticut",
|
|
221
|
+
isoCode: "CT"
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
name: "Delaware",
|
|
225
|
+
isoCode: "DE"
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
name: "Florida",
|
|
229
|
+
isoCode: "FL"
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
name: "Georgia",
|
|
233
|
+
isoCode: "GA"
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
name: "Hawaii",
|
|
237
|
+
isoCode: "HI"
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
name: "Idaho",
|
|
241
|
+
isoCode: "ID"
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
name: "Illinois",
|
|
245
|
+
isoCode: "IL"
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
name: "Indiana",
|
|
249
|
+
isoCode: "IN"
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
name: "Iowa",
|
|
253
|
+
isoCode: "IA"
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
name: "Kansas",
|
|
257
|
+
isoCode: "KS"
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
name: "Kentucky",
|
|
261
|
+
isoCode: "KY"
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
name: "Louisiana",
|
|
265
|
+
isoCode: "LA"
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
name: "Maine",
|
|
269
|
+
isoCode: "ME"
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
name: "Maryland",
|
|
273
|
+
isoCode: "MD"
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
name: "Massachusetts",
|
|
277
|
+
isoCode: "MA"
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
name: "Michigan",
|
|
281
|
+
isoCode: "MI"
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
name: "Minnesota",
|
|
285
|
+
isoCode: "MN"
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
name: "Mississippi",
|
|
289
|
+
isoCode: "MS"
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
name: "Missouri",
|
|
293
|
+
isoCode: "MO"
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
name: "Montana",
|
|
297
|
+
isoCode: "MT"
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
name: "Nebraska",
|
|
301
|
+
isoCode: "NE"
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
name: "Nevada",
|
|
305
|
+
isoCode: "NV"
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
name: "New Hampshire",
|
|
309
|
+
isoCode: "NH"
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
name: "New Jersey",
|
|
313
|
+
isoCode: "NJ"
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
name: "New Mexico",
|
|
317
|
+
isoCode: "NM"
|
|
318
|
+
},
|
|
319
|
+
{
|
|
320
|
+
name: "New York",
|
|
321
|
+
isoCode: "NY"
|
|
322
|
+
},
|
|
323
|
+
{
|
|
324
|
+
name: "North Carolina",
|
|
325
|
+
isoCode: "NC"
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
name: "North Dakota",
|
|
329
|
+
isoCode: "ND"
|
|
330
|
+
},
|
|
331
|
+
{
|
|
332
|
+
name: "Ohio",
|
|
333
|
+
isoCode: "OH"
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
name: "Oklahoma",
|
|
337
|
+
isoCode: "OK"
|
|
338
|
+
},
|
|
339
|
+
{
|
|
340
|
+
name: "Oregon",
|
|
341
|
+
isoCode: "OR"
|
|
342
|
+
},
|
|
343
|
+
{
|
|
344
|
+
name: "Pennsylvania",
|
|
345
|
+
isoCode: "PA"
|
|
346
|
+
},
|
|
347
|
+
{
|
|
348
|
+
name: "Rhode Island",
|
|
349
|
+
isoCode: "RI"
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
name: "South Carolina",
|
|
353
|
+
isoCode: "SC"
|
|
354
|
+
},
|
|
355
|
+
{
|
|
356
|
+
name: "South Dakota",
|
|
357
|
+
isoCode: "SD"
|
|
358
|
+
},
|
|
359
|
+
{
|
|
360
|
+
name: "Tennessee",
|
|
361
|
+
isoCode: "TN"
|
|
362
|
+
},
|
|
363
|
+
{
|
|
364
|
+
name: "Texas",
|
|
365
|
+
isoCode: "TX"
|
|
366
|
+
},
|
|
367
|
+
{
|
|
368
|
+
name: "Utah",
|
|
369
|
+
isoCode: "UT"
|
|
370
|
+
},
|
|
371
|
+
{
|
|
372
|
+
name: "Vermont",
|
|
373
|
+
isoCode: "VT"
|
|
374
|
+
},
|
|
375
|
+
{
|
|
376
|
+
name: "Virginia",
|
|
377
|
+
isoCode: "VA"
|
|
378
|
+
},
|
|
379
|
+
{
|
|
380
|
+
name: "Washington",
|
|
381
|
+
isoCode: "WA"
|
|
382
|
+
},
|
|
383
|
+
{
|
|
384
|
+
name: "West Virginia",
|
|
385
|
+
isoCode: "WV"
|
|
386
|
+
},
|
|
387
|
+
{
|
|
388
|
+
name: "Wisconsin",
|
|
389
|
+
isoCode: "WI"
|
|
390
|
+
},
|
|
391
|
+
{
|
|
392
|
+
name: "Wyoming",
|
|
393
|
+
isoCode: "WY"
|
|
394
|
+
},
|
|
395
|
+
{
|
|
396
|
+
name: "District of Columbia",
|
|
397
|
+
isoCode: "DC"
|
|
398
|
+
}
|
|
399
|
+
];
|
|
400
|
+
const COUNTRY_CONFIGS = {
|
|
401
|
+
US: {
|
|
402
|
+
regionLabel: "State",
|
|
403
|
+
postalLabel: "ZIP Code"
|
|
404
|
+
},
|
|
405
|
+
JP: {
|
|
406
|
+
regionLabel: "Prefecture",
|
|
407
|
+
postalLabel: "Postal Code"
|
|
408
|
+
}
|
|
409
|
+
};
|
|
410
|
+
const DEFAULT_REGION_CONFIG = {
|
|
411
|
+
regionLabel: "Province",
|
|
412
|
+
postalLabel: "Postal Code"
|
|
413
|
+
};
|
|
414
|
+
function getRegionConfig(countryCode) {
|
|
415
|
+
return COUNTRY_CONFIGS[countryCode] ?? DEFAULT_REGION_CONFIG;
|
|
416
|
+
}
|
|
417
|
+
//#endregion
|
|
418
|
+
//#region ../../fluid-pay/core/src/hooks/use-country-states.ts
|
|
419
|
+
function useCountryStates() {
|
|
420
|
+
const [selectedCountry, setSelectedCountry] = useState("US");
|
|
421
|
+
const [stateOptions, setStateOptions] = useState(US_STATES);
|
|
422
|
+
return {
|
|
423
|
+
handleCountryChange: useCallback((selectedCountryCode, fetchStates) => {
|
|
424
|
+
setSelectedCountry(selectedCountryCode);
|
|
425
|
+
if (selectedCountryCode === "US") setStateOptions(US_STATES);
|
|
426
|
+
else if (fetchStates) fetchStates(selectedCountryCode).then((states) => setStateOptions(states)).catch((error) => {
|
|
427
|
+
console.error("Failed to fetch states:", error);
|
|
428
|
+
setStateOptions([]);
|
|
429
|
+
});
|
|
430
|
+
else setStateOptions([]);
|
|
431
|
+
}, []),
|
|
432
|
+
stateOptions,
|
|
433
|
+
config: getRegionConfig(selectedCountry),
|
|
434
|
+
selectedCountry
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
//#endregion
|
|
438
|
+
//#region ../../profile/ui/src/components/ellipses-dropdown.tsx
|
|
439
|
+
function EllipsesDropdown({ onDelete, onEdit, editLabel = "Edit", deleteLabel = "Delete", disabled = false }) {
|
|
440
|
+
if (disabled) return /* @__PURE__ */ jsx(Button, {
|
|
441
|
+
variant: "ghost",
|
|
442
|
+
disabled: true,
|
|
443
|
+
className: "cursor-not-allowed opacity-50",
|
|
444
|
+
children: /* @__PURE__ */ jsx("svg", {
|
|
445
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
446
|
+
viewBox: "0 0 128 512",
|
|
447
|
+
className: "h-4 w-1 fill-gray-400",
|
|
448
|
+
children: /* @__PURE__ */ jsx("path", { d: "M64 360a56 56 0 1 0 0 112 56 56 0 1 0 0-112zm0-160a56 56 0 1 0 0 112 56 56 0 1 0 0-112zM120 96A56 56 0 1 0 8 96a56 56 0 1 0 112 0z" })
|
|
449
|
+
})
|
|
450
|
+
});
|
|
451
|
+
return /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, {
|
|
452
|
+
asChild: true,
|
|
453
|
+
children: /* @__PURE__ */ jsx(Button, {
|
|
454
|
+
variant: "ghost",
|
|
455
|
+
children: /* @__PURE__ */ jsx("svg", {
|
|
456
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
457
|
+
viewBox: "0 0 128 512",
|
|
458
|
+
className: "h-4 w-1 fill-gray-400",
|
|
459
|
+
children: /* @__PURE__ */ jsx("path", { d: "M64 360a56 56 0 1 0 0 112 56 56 0 1 0 0-112zm0-160a56 56 0 1 0 0 112 56 56 0 1 0 0-112zM120 96A56 56 0 1 0 8 96a56 56 0 1 0 112 0z" })
|
|
460
|
+
})
|
|
461
|
+
})
|
|
462
|
+
}), /* @__PURE__ */ jsxs(DropdownMenuContent, {
|
|
463
|
+
className: "min-w-20 space-y-1 text-sm text-gray-900",
|
|
464
|
+
children: [onEdit && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs(DropdownMenuItem, {
|
|
465
|
+
className: "flex cursor-pointer flex-row items-center justify-between space-x-2 rounded px-2 hover:bg-gray-50",
|
|
466
|
+
onClick: (e) => {
|
|
467
|
+
e.stopPropagation();
|
|
468
|
+
onEdit();
|
|
469
|
+
},
|
|
470
|
+
children: [/* @__PURE__ */ jsx("span", { children: editLabel }), /* @__PURE__ */ jsx("svg", {
|
|
471
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
472
|
+
viewBox: "0 0 512 512",
|
|
473
|
+
className: "h-2.5 w-2.5 fill-current",
|
|
474
|
+
children: /* @__PURE__ */ jsx("path", { d: "M362.7 19.3L314.3 67.7 444.3 197.7l48.4-48.4c25-25 25-65.5 0-90.5L453.3 19.3c-25-25-65.5-25-90.5 0zm-71 71L58.6 323.5c-10.4 10.4-18 23.3-22.2 37.4L1 481.2C-1.5 489.7 .8 498.8 7 505s15.3 8.5 23.7 6.1l120.3-35.4c14.1-4.2 27-11.8 37.4-22.2L421.7 220.3 291.7 90.3z" })
|
|
475
|
+
})]
|
|
476
|
+
}), /* @__PURE__ */ jsx(DropdownMenuSeparator, {})] }), /* @__PURE__ */ jsxs(DropdownMenuItem, {
|
|
477
|
+
className: "flex cursor-pointer flex-row items-center justify-between space-x-2 rounded px-2 text-red-500 hover:bg-red-50",
|
|
478
|
+
onClick: (e) => {
|
|
479
|
+
e.stopPropagation();
|
|
480
|
+
onDelete?.();
|
|
481
|
+
},
|
|
482
|
+
children: [/* @__PURE__ */ jsx("span", { children: deleteLabel }), /* @__PURE__ */ jsx("svg", {
|
|
483
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
484
|
+
viewBox: "0 0 448 512",
|
|
485
|
+
className: "h-2.5 w-2.5 fill-red-500",
|
|
486
|
+
children: /* @__PURE__ */ jsx("path", { d: "M135.2 17.7C140.6 6.8 151.7 0 163.8 0L284.2 0c12.1 0 23.2 6.8 28.6 17.7L320 32l80 0c17.7 0 32 14.3 32 32s-14.3 32-32 32L48 96C30.3 96 16 81.7 16 64S30.3 32 48 32l80 0 7.2-14.3zM32 128l384 0 0 320c0 35.3-28.7 64-64 64L96 512c-35.3 0-64-28.7-64-64l0-320z" })
|
|
487
|
+
})]
|
|
488
|
+
})]
|
|
489
|
+
})] });
|
|
490
|
+
}
|
|
491
|
+
//#endregion
|
|
492
|
+
//#region ../../profile/ui/src/components/confirm-action-dialog.tsx
|
|
493
|
+
function ConfirmActionDialog({ title, description, onAction, openDialog, setOpenDialog, errorMsg, isLoading, actionText = "Delete" }) {
|
|
494
|
+
const { t } = useProfileUI();
|
|
495
|
+
return /* @__PURE__ */ jsx(Dialog, {
|
|
496
|
+
open: openDialog,
|
|
497
|
+
onOpenChange: setOpenDialog,
|
|
498
|
+
children: /* @__PURE__ */ jsxs(DialogContent, {
|
|
499
|
+
className: "max-w-sm rounded md:w-90",
|
|
500
|
+
children: [
|
|
501
|
+
/* @__PURE__ */ jsx(DialogHeader, {
|
|
502
|
+
className: "flex flex-row justify-between",
|
|
503
|
+
children: /* @__PURE__ */ jsx(DialogTitle, {
|
|
504
|
+
className: "text-md w-full text-left font-medium",
|
|
505
|
+
children: title
|
|
506
|
+
})
|
|
507
|
+
}),
|
|
508
|
+
/* @__PURE__ */ jsx("div", {
|
|
509
|
+
className: "space-y-4",
|
|
510
|
+
children: /* @__PURE__ */ jsx("p", {
|
|
511
|
+
className: "text-left text-sm text-gray-500",
|
|
512
|
+
children: description
|
|
513
|
+
})
|
|
514
|
+
}),
|
|
515
|
+
errorMsg && /* @__PURE__ */ jsx("p", {
|
|
516
|
+
className: "text-sm text-red-500",
|
|
517
|
+
children: errorMsg
|
|
518
|
+
}),
|
|
519
|
+
/* @__PURE__ */ jsx(DialogFooter, { children: /* @__PURE__ */ jsxs("div", {
|
|
520
|
+
className: "flex w-full flex-row justify-between space-x-2",
|
|
521
|
+
children: [/* @__PURE__ */ jsx(DialogClose, {
|
|
522
|
+
asChild: true,
|
|
523
|
+
children: /* @__PURE__ */ jsx(Button, {
|
|
524
|
+
className: "min-w-[70px] rounded bg-gray-50 p-3 text-gray-900 ring-1 ring-gray-300 hover:bg-gray-100",
|
|
525
|
+
onClick: () => setOpenDialog(false),
|
|
526
|
+
children: t("cancel")
|
|
527
|
+
})
|
|
528
|
+
}), /* @__PURE__ */ jsx(Button, {
|
|
529
|
+
type: "button",
|
|
530
|
+
className: "min-w-[70px] rounded bg-red-600 p-3 text-white hover:bg-red-700",
|
|
531
|
+
onClick: onAction,
|
|
532
|
+
disabled: isLoading,
|
|
533
|
+
children: isLoading ? /* @__PURE__ */ jsx("div", { className: "h-5 w-5 animate-spin rounded-full border-4 border-t-4 border-white border-t-transparent" }) : actionText
|
|
534
|
+
})]
|
|
535
|
+
}) })
|
|
536
|
+
]
|
|
537
|
+
})
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
//#endregion
|
|
541
|
+
//#region ../../profile/ui/src/components/customer-points-ledger.tsx
|
|
542
|
+
function formatTransactionType(ledger, t) {
|
|
543
|
+
const transactionType = ledger.metadata.transaction_type;
|
|
544
|
+
if (!transactionType) {
|
|
545
|
+
if (ledger.metadata.source) return ledger.amount > 0 ? t("points_awarded") : t("points_redeemed");
|
|
546
|
+
return t("transaction");
|
|
547
|
+
}
|
|
548
|
+
const translationKey = transactionType.toLowerCase().replace(/ /g, "_");
|
|
549
|
+
const translated = t(translationKey);
|
|
550
|
+
if (translated !== translationKey) return translated;
|
|
551
|
+
return transactionType.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
552
|
+
}
|
|
553
|
+
function formatPoints(amount) {
|
|
554
|
+
return `${amount >= 0 ? "+" : ""}${amount}`;
|
|
555
|
+
}
|
|
556
|
+
function formatDateTime(dateString) {
|
|
557
|
+
return new Date(dateString).toLocaleDateString(void 0, {
|
|
558
|
+
year: "numeric",
|
|
559
|
+
month: "short",
|
|
560
|
+
day: "numeric",
|
|
561
|
+
hour: "2-digit",
|
|
562
|
+
minute: "2-digit"
|
|
563
|
+
});
|
|
564
|
+
}
|
|
565
|
+
function CustomerPointsLedger({ pointsLedger, isLoading = false }) {
|
|
566
|
+
const [accordionValue, setAccordionValue] = useState("");
|
|
567
|
+
const { t } = useProfileUI();
|
|
568
|
+
const availablePoints = pointsLedger[0]?.total_balance ?? 0;
|
|
569
|
+
return /* @__PURE__ */ jsx("div", {
|
|
570
|
+
className: "mb-6 border-b border-gray-300 pb-4",
|
|
571
|
+
children: /* @__PURE__ */ jsx(Accordion, {
|
|
572
|
+
type: "single",
|
|
573
|
+
collapsible: true,
|
|
574
|
+
value: accordionValue,
|
|
575
|
+
onValueChange: setAccordionValue,
|
|
576
|
+
className: "w-full",
|
|
577
|
+
children: /* @__PURE__ */ jsxs(AccordionItem, {
|
|
578
|
+
value: "points-history",
|
|
579
|
+
className: "border-b-0",
|
|
580
|
+
children: [
|
|
581
|
+
/* @__PURE__ */ jsxs("div", {
|
|
582
|
+
className: "flex flex-row items-center justify-between",
|
|
583
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
584
|
+
className: "mt-4 mb-1 text-sm text-gray-400",
|
|
585
|
+
children: t("points_history")
|
|
586
|
+
}), /* @__PURE__ */ jsx(AccordionTrigger, { className: "m-0 ml-2 flex h-auto min-h-0 w-auto py-0 hover:no-underline" })]
|
|
587
|
+
}),
|
|
588
|
+
isLoading && /* @__PURE__ */ jsx(Skeleton, { className: "h-6 w-full" }),
|
|
589
|
+
!isLoading && !accordionValue && /* @__PURE__ */ jsx("div", {
|
|
590
|
+
className: "mb-2 flex w-full cursor-pointer flex-col",
|
|
591
|
+
onClick: () => setAccordionValue("points-history"),
|
|
592
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
593
|
+
className: "text-sm font-semibold text-gray-900",
|
|
594
|
+
children: [
|
|
595
|
+
availablePoints.toLocaleString(),
|
|
596
|
+
" ",
|
|
597
|
+
/* @__PURE__ */ jsx("span", {
|
|
598
|
+
className: "font-normal text-gray-500",
|
|
599
|
+
children: t("points_available").toLowerCase()
|
|
600
|
+
})
|
|
601
|
+
]
|
|
602
|
+
})
|
|
603
|
+
}),
|
|
604
|
+
/* @__PURE__ */ jsxs(AccordionContent, {
|
|
605
|
+
className: "max-h-[400px] overflow-y-auto pt-2",
|
|
606
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
607
|
+
className: "mb-3 flex w-full flex-col",
|
|
608
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
609
|
+
className: "text-sm font-semibold text-gray-900",
|
|
610
|
+
children: [
|
|
611
|
+
availablePoints.toLocaleString(),
|
|
612
|
+
" ",
|
|
613
|
+
/* @__PURE__ */ jsx("span", {
|
|
614
|
+
className: "font-normal text-gray-500",
|
|
615
|
+
children: t("points_available").toLowerCase()
|
|
616
|
+
})
|
|
617
|
+
]
|
|
618
|
+
})
|
|
619
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
620
|
+
className: "flex flex-col space-y-0",
|
|
621
|
+
children: pointsLedger.length > 0 ? pointsLedger.map((ledger) => /* @__PURE__ */ jsxs("div", {
|
|
622
|
+
className: "relative flex flex-row items-start justify-between py-3",
|
|
623
|
+
children: [
|
|
624
|
+
/* @__PURE__ */ jsxs("div", {
|
|
625
|
+
className: "absolute top-3 left-0",
|
|
626
|
+
children: [/* @__PURE__ */ jsx("div", { className: "mt-1.5 h-2 w-2 flex-shrink-0 rounded-full border border-gray-300" }), /* @__PURE__ */ jsx("div", { className: "mr-1 h-10 border-r border-gray-200" })]
|
|
627
|
+
}),
|
|
628
|
+
/* @__PURE__ */ jsx("div", {
|
|
629
|
+
className: "ml-6 flex flex-row items-start space-x-3",
|
|
630
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
631
|
+
className: "flex flex-col",
|
|
632
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
633
|
+
className: "text-sm font-medium text-gray-900",
|
|
634
|
+
children: formatTransactionType(ledger, t)
|
|
635
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
636
|
+
className: "text-sm text-gray-500",
|
|
637
|
+
children: formatDateTime(ledger.created_at)
|
|
638
|
+
})]
|
|
639
|
+
})
|
|
640
|
+
}),
|
|
641
|
+
/* @__PURE__ */ jsx("div", {
|
|
642
|
+
className: cn("text-sm font-medium", ledger.amount >= 0 ? "text-green-500" : "text-red-500"),
|
|
643
|
+
children: formatPoints(ledger.amount)
|
|
644
|
+
})
|
|
645
|
+
]
|
|
646
|
+
}, ledger.id)) : /* @__PURE__ */ jsx("div", {
|
|
647
|
+
className: "text-sm text-gray-500",
|
|
648
|
+
children: t("no_points_history_found")
|
|
649
|
+
})
|
|
650
|
+
})]
|
|
651
|
+
})
|
|
652
|
+
]
|
|
653
|
+
})
|
|
654
|
+
})
|
|
655
|
+
});
|
|
656
|
+
}
|
|
657
|
+
//#endregion
|
|
658
|
+
//#region ../../profile/ui/src/components/form-fields.tsx
|
|
659
|
+
function FormTextField$1({ control, name, label, containerClassName, ...props }) {
|
|
660
|
+
const { field, fieldState: { error } } = useController({
|
|
661
|
+
name,
|
|
662
|
+
control
|
|
663
|
+
});
|
|
664
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
665
|
+
className: cn("space-y-1", containerClassName),
|
|
666
|
+
children: [
|
|
667
|
+
label && /* @__PURE__ */ jsx(Label, {
|
|
668
|
+
htmlFor: name,
|
|
669
|
+
className: "mb-1.5 block text-sm font-medium text-gray-700",
|
|
670
|
+
children: label
|
|
671
|
+
}),
|
|
672
|
+
/* @__PURE__ */ jsx(Input, {
|
|
673
|
+
...field,
|
|
674
|
+
...props,
|
|
675
|
+
id: name,
|
|
676
|
+
value: field.value ?? "",
|
|
677
|
+
className: cn(error && "ring-1 ring-red-500", props.className)
|
|
678
|
+
}),
|
|
679
|
+
error && /* @__PURE__ */ jsx("p", {
|
|
680
|
+
className: "text-sm text-red-500",
|
|
681
|
+
children: error.message
|
|
682
|
+
})
|
|
683
|
+
]
|
|
684
|
+
});
|
|
685
|
+
}
|
|
686
|
+
function FormSelectField$1({ control, name, label, options, placeholder, containerClassName, onChange }) {
|
|
687
|
+
const { field, fieldState: { error } } = useController({
|
|
688
|
+
name,
|
|
689
|
+
control
|
|
690
|
+
});
|
|
691
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
692
|
+
className: cn("space-y-1", containerClassName),
|
|
693
|
+
children: [
|
|
694
|
+
label && /* @__PURE__ */ jsx(Label, {
|
|
695
|
+
htmlFor: name,
|
|
696
|
+
className: "block text-sm font-medium text-gray-700",
|
|
697
|
+
children: label
|
|
698
|
+
}),
|
|
699
|
+
/* @__PURE__ */ jsxs(Select, {
|
|
700
|
+
value: field.value?.toString() ?? "",
|
|
701
|
+
onValueChange: (val) => {
|
|
702
|
+
field.onChange(val);
|
|
703
|
+
onChange?.(val);
|
|
704
|
+
},
|
|
705
|
+
children: [/* @__PURE__ */ jsx(SelectTrigger, {
|
|
706
|
+
className: cn(error && "ring-1 ring-red-500"),
|
|
707
|
+
children: /* @__PURE__ */ jsx(SelectValue, { placeholder })
|
|
708
|
+
}), /* @__PURE__ */ jsx(SelectContent, { children: options?.map((opt) => /* @__PURE__ */ jsx(SelectItem, {
|
|
709
|
+
value: opt.value.toString(),
|
|
710
|
+
children: opt.name
|
|
711
|
+
}, `${opt.name}-${opt.value}`)) })]
|
|
712
|
+
}),
|
|
713
|
+
error && /* @__PURE__ */ jsx("p", {
|
|
714
|
+
className: "text-sm text-red-500",
|
|
715
|
+
children: error.message
|
|
716
|
+
})
|
|
717
|
+
]
|
|
718
|
+
});
|
|
719
|
+
}
|
|
720
|
+
//#endregion
|
|
721
|
+
//#region ../../profile/ui/src/components/user-info-dialog.tsx
|
|
722
|
+
function UserInfoDialog({ control, isOpen, onSubmit, handleClose, languageOptions, errorMsg, isSubmitting }) {
|
|
723
|
+
const { t } = useProfileUI();
|
|
724
|
+
return /* @__PURE__ */ jsx(Dialog, {
|
|
725
|
+
open: isOpen,
|
|
726
|
+
onOpenChange: (open) => !open && handleClose(),
|
|
727
|
+
children: /* @__PURE__ */ jsxs(DialogContent, {
|
|
728
|
+
className: "max-w-sm rounded md:max-w-lg",
|
|
729
|
+
children: [
|
|
730
|
+
/* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, {
|
|
731
|
+
className: "text-md font-medium text-gray-900",
|
|
732
|
+
children: t("edit_profile")
|
|
733
|
+
}) }),
|
|
734
|
+
/* @__PURE__ */ jsxs("div", {
|
|
735
|
+
className: "space-y-0",
|
|
736
|
+
children: [
|
|
737
|
+
/* @__PURE__ */ jsx(FormTextField$1, {
|
|
738
|
+
control,
|
|
739
|
+
name: "first_name",
|
|
740
|
+
label: t("first_name")
|
|
741
|
+
}),
|
|
742
|
+
/* @__PURE__ */ jsx(FormTextField$1, {
|
|
743
|
+
control,
|
|
744
|
+
name: "last_name",
|
|
745
|
+
label: t("last_name")
|
|
746
|
+
}),
|
|
747
|
+
/* @__PURE__ */ jsx(FormTextField$1, {
|
|
748
|
+
control,
|
|
749
|
+
name: "phone_number",
|
|
750
|
+
label: t("phone_number"),
|
|
751
|
+
type: "tel"
|
|
752
|
+
}),
|
|
753
|
+
/* @__PURE__ */ jsx(FormSelectField$1, {
|
|
754
|
+
control,
|
|
755
|
+
name: "language",
|
|
756
|
+
label: t("language"),
|
|
757
|
+
options: languageOptions,
|
|
758
|
+
placeholder: t("select_an_option")
|
|
759
|
+
})
|
|
760
|
+
]
|
|
761
|
+
}),
|
|
762
|
+
errorMsg && /* @__PURE__ */ jsx("p", {
|
|
763
|
+
className: "text-sm text-red-500",
|
|
764
|
+
children: errorMsg
|
|
765
|
+
}),
|
|
766
|
+
/* @__PURE__ */ jsx(DialogFooter, {
|
|
767
|
+
className: "flex flex-row items-center justify-end",
|
|
768
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
769
|
+
className: "flex-1 text-right",
|
|
770
|
+
children: /* @__PURE__ */ jsx(DialogClose, {
|
|
771
|
+
asChild: true,
|
|
772
|
+
children: /* @__PURE__ */ jsxs(Button, {
|
|
773
|
+
type: "button",
|
|
774
|
+
onClick: onSubmit,
|
|
775
|
+
children: [isSubmitting && /* @__PURE__ */ jsx("div", { className: "mr-3 h-5 w-5 animate-spin rounded-full border-4 border-t-4 border-white border-t-transparent" }), isSubmitting ? t("saving") : t("save_changes")]
|
|
776
|
+
})
|
|
777
|
+
})
|
|
778
|
+
})
|
|
779
|
+
})
|
|
780
|
+
]
|
|
781
|
+
})
|
|
782
|
+
});
|
|
783
|
+
}
|
|
784
|
+
//#endregion
|
|
785
|
+
//#region ../../profile/ui/src/components/customer-info.tsx
|
|
786
|
+
function createUserInfoSchema(messages) {
|
|
787
|
+
return z.object({
|
|
788
|
+
first_name: z.string().min(1, { message: messages.firstNameRequired }),
|
|
789
|
+
last_name: z.string().min(1, { message: messages.lastNameRequired }),
|
|
790
|
+
phone_number: z.string().optional(),
|
|
791
|
+
language: z.string().min(1, { message: messages.languageRequired })
|
|
792
|
+
});
|
|
793
|
+
}
|
|
794
|
+
function CustomerInfo({ customerAccount, languages, onUpdateCustomer, isUpdating = false }) {
|
|
795
|
+
const [isEditDialogOpen, setIsEditDialogOpen] = useState(false);
|
|
796
|
+
const [updateError, setUpdateError] = useState(void 0);
|
|
797
|
+
const { t } = useProfileUI();
|
|
798
|
+
const { first_name, full_name } = customerAccount.customer;
|
|
799
|
+
const derivedLastName = full_name.startsWith(first_name) ? full_name.slice(first_name.length).trim() : "";
|
|
800
|
+
const userInitial = first_name ? first_name.charAt(0).toUpperCase() : "";
|
|
801
|
+
const customerLanguage = languages?.find((language) => language.iso === customerAccount.fluid_pay_account.language_iso)?.name;
|
|
802
|
+
const languageOptions = languages?.map((language) => ({
|
|
803
|
+
name: language.name,
|
|
804
|
+
value: language.name
|
|
805
|
+
}));
|
|
806
|
+
const { control, handleSubmit, reset } = useForm({
|
|
807
|
+
resolver: zodResolver(useMemo(() => createUserInfoSchema({
|
|
808
|
+
firstNameRequired: t("first_name_is_required"),
|
|
809
|
+
lastNameRequired: t("last_name_is_required"),
|
|
810
|
+
languageRequired: t("language_is_required")
|
|
811
|
+
}), [t])),
|
|
812
|
+
defaultValues: {
|
|
813
|
+
first_name: customerAccount.customer.first_name || "",
|
|
814
|
+
last_name: derivedLastName,
|
|
815
|
+
phone_number: customerAccount.customer.phone || "",
|
|
816
|
+
language: customerLanguage || "English"
|
|
817
|
+
}
|
|
818
|
+
});
|
|
819
|
+
const handleOpenEditDialog = () => {
|
|
820
|
+
reset({
|
|
821
|
+
first_name: customerAccount.customer.first_name || "",
|
|
822
|
+
last_name: derivedLastName,
|
|
823
|
+
phone_number: customerAccount.customer.phone || "",
|
|
824
|
+
language: customerLanguage || "English"
|
|
825
|
+
});
|
|
826
|
+
setIsEditDialogOpen(true);
|
|
827
|
+
};
|
|
828
|
+
const handleCloseEditDialog = () => {
|
|
829
|
+
setIsEditDialogOpen(false);
|
|
830
|
+
setUpdateError(void 0);
|
|
831
|
+
};
|
|
832
|
+
const onSubmitUserInfo = handleSubmit(async (data) => {
|
|
833
|
+
try {
|
|
834
|
+
await onUpdateCustomer(data);
|
|
835
|
+
setIsEditDialogOpen(false);
|
|
836
|
+
} catch (error) {
|
|
837
|
+
console.error("Error updating profile:", error);
|
|
838
|
+
setUpdateError("Error updating profile. Please verify your information and try again.");
|
|
839
|
+
}
|
|
840
|
+
});
|
|
841
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("div", {
|
|
842
|
+
className: "mb-6 flex flex-row items-center justify-between space-x-2 border-b border-gray-300 pb-4",
|
|
843
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
844
|
+
className: "flex flex-row items-center space-x-2",
|
|
845
|
+
children: [/* @__PURE__ */ jsx(Avatar, { children: /* @__PURE__ */ jsx(AvatarFallback, { children: userInitial }) }), /* @__PURE__ */ jsxs("div", {
|
|
846
|
+
className: "flex flex-col",
|
|
847
|
+
children: [/* @__PURE__ */ jsx("p", {
|
|
848
|
+
className: "text-sm font-medium",
|
|
849
|
+
children: customerAccount.customer.full_name
|
|
850
|
+
}), /* @__PURE__ */ jsx("p", {
|
|
851
|
+
className: "text-sm text-gray-500",
|
|
852
|
+
children: customerAccount.customer.email
|
|
853
|
+
})]
|
|
854
|
+
})]
|
|
855
|
+
}), /* @__PURE__ */ jsx("button", {
|
|
856
|
+
className: "cursor-pointer rounded-md border border-gray-300 p-1 hover:bg-gray-50 disabled:opacity-50",
|
|
857
|
+
onClick: handleOpenEditDialog,
|
|
858
|
+
children: /* @__PURE__ */ jsx(Pencil, { className: "h-2.5 w-2.5 text-gray-400" })
|
|
859
|
+
})]
|
|
860
|
+
}), /* @__PURE__ */ jsx(UserInfoDialog, {
|
|
861
|
+
control,
|
|
862
|
+
isOpen: isEditDialogOpen,
|
|
863
|
+
onSubmit: onSubmitUserInfo,
|
|
864
|
+
handleClose: handleCloseEditDialog,
|
|
865
|
+
languageOptions,
|
|
866
|
+
errorMsg: updateError,
|
|
867
|
+
isSubmitting: isUpdating
|
|
868
|
+
})] });
|
|
869
|
+
}
|
|
870
|
+
//#endregion
|
|
871
|
+
//#region ../../profile/ui/src/components/address-dropdown.tsx
|
|
872
|
+
function formatAddressName(address) {
|
|
873
|
+
return address.name ?? "";
|
|
874
|
+
}
|
|
875
|
+
function AddressDropdown({ title, displayAddress, addressList, onAddAddressClick, onEditAddress, onDeleteAddress, accordionItemValue, addAddressLabel, showAddButton = true, borderStyle = "border-b border-gray-300 pb-4 mb-6", className = "", showActions = true, isLoading = false }) {
|
|
876
|
+
const [addressesValue, setAddressesValue] = useState("");
|
|
877
|
+
const { t } = useProfileUI();
|
|
878
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
879
|
+
className: `${borderStyle} ${className}`,
|
|
880
|
+
children: [/* @__PURE__ */ jsx(Accordion, {
|
|
881
|
+
type: "single",
|
|
882
|
+
collapsible: true,
|
|
883
|
+
value: addressesValue,
|
|
884
|
+
onValueChange: setAddressesValue,
|
|
885
|
+
className: "w-full",
|
|
886
|
+
children: /* @__PURE__ */ jsxs(AccordionItem, {
|
|
887
|
+
value: accordionItemValue,
|
|
888
|
+
className: "border-b-0",
|
|
889
|
+
children: [
|
|
890
|
+
/* @__PURE__ */ jsxs("div", {
|
|
891
|
+
className: "flex flex-row items-center justify-between",
|
|
892
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
893
|
+
className: "mt-4 mb-1 text-sm text-gray-400",
|
|
894
|
+
children: title
|
|
895
|
+
}), /* @__PURE__ */ jsx(AccordionTrigger, { className: "m-0 ml-2 flex h-auto min-h-0 w-auto py-0 hover:no-underline" })]
|
|
896
|
+
}),
|
|
897
|
+
isLoading && /* @__PURE__ */ jsxs("div", {
|
|
898
|
+
className: "space-y-2",
|
|
899
|
+
children: [/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-2/3" }), /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-1/2" })]
|
|
900
|
+
}),
|
|
901
|
+
!isLoading && !addressesValue && displayAddress && /* @__PURE__ */ jsxs("div", {
|
|
902
|
+
className: "mb-2 flex w-full cursor-pointer flex-col",
|
|
903
|
+
onClick: () => setAddressesValue(accordionItemValue),
|
|
904
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
905
|
+
className: "flex items-center text-sm font-medium text-gray-900",
|
|
906
|
+
children: [
|
|
907
|
+
formatAddressName(displayAddress),
|
|
908
|
+
", ",
|
|
909
|
+
displayAddress.address1
|
|
910
|
+
]
|
|
911
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
912
|
+
className: "text-sm text-gray-500",
|
|
913
|
+
children: [
|
|
914
|
+
displayAddress.city,
|
|
915
|
+
", ",
|
|
916
|
+
displayAddress.state,
|
|
917
|
+
" ",
|
|
918
|
+
displayAddress.postal_code
|
|
919
|
+
]
|
|
920
|
+
})]
|
|
921
|
+
}),
|
|
922
|
+
/* @__PURE__ */ jsx(AccordionContent, {
|
|
923
|
+
className: "max-h-[400px] overflow-y-auto pt-2",
|
|
924
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
925
|
+
className: "mt-2 flex flex-col justify-between space-y-4 px-0.5",
|
|
926
|
+
children: addressList.length > 0 ? addressList.map((address, index) => /* @__PURE__ */ jsxs("div", {
|
|
927
|
+
className: cn("flex min-h-[48px] w-full flex-row items-center justify-between space-x-2 px-2", { "items-center border-b border-gray-300 p-3": addressList.length - 1 !== index }),
|
|
928
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
929
|
+
className: "flex flex-col",
|
|
930
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
931
|
+
className: "text-sm text-gray-900",
|
|
932
|
+
children: [
|
|
933
|
+
formatAddressName(address),
|
|
934
|
+
" ",
|
|
935
|
+
/* @__PURE__ */ jsx("br", {}),
|
|
936
|
+
address.address1,
|
|
937
|
+
" ",
|
|
938
|
+
/* @__PURE__ */ jsx("br", {}),
|
|
939
|
+
address.city,
|
|
940
|
+
", ",
|
|
941
|
+
address.state,
|
|
942
|
+
" ",
|
|
943
|
+
address.postal_code
|
|
944
|
+
]
|
|
945
|
+
})
|
|
946
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
947
|
+
className: "flex flex-row items-center space-x-2",
|
|
948
|
+
children: [address.default && /* @__PURE__ */ jsx("p", {
|
|
949
|
+
className: "mt-1 w-fit rounded bg-gray-500 px-2 py-0.5 text-xs font-medium text-white",
|
|
950
|
+
children: t("default")
|
|
951
|
+
}), showActions && /* @__PURE__ */ jsx(EllipsesDropdown, {
|
|
952
|
+
onDelete: () => onDeleteAddress?.(address),
|
|
953
|
+
onEdit: () => onEditAddress?.(address),
|
|
954
|
+
editLabel: t("edit"),
|
|
955
|
+
deleteLabel: t("delete")
|
|
956
|
+
})]
|
|
957
|
+
})]
|
|
958
|
+
}, address.id)) : /* @__PURE__ */ jsx("div", {
|
|
959
|
+
className: "text-sm text-gray-500",
|
|
960
|
+
children: t("no_saved_addresses_found")
|
|
961
|
+
})
|
|
962
|
+
})
|
|
963
|
+
})
|
|
964
|
+
]
|
|
965
|
+
})
|
|
966
|
+
}), showAddButton && /* @__PURE__ */ jsx("button", {
|
|
967
|
+
className: "mt-3 text-left text-sm text-gray-900",
|
|
968
|
+
onClick: onAddAddressClick,
|
|
969
|
+
children: addAddressLabel
|
|
970
|
+
})]
|
|
971
|
+
});
|
|
972
|
+
}
|
|
973
|
+
//#endregion
|
|
974
|
+
//#region ../../profile/ui/src/components/addresses.tsx
|
|
975
|
+
function Addresses({ addresses, isLoading = false, onCreateAddress, onDeleteAddress, isDeletingAddress = false, renderAddressDialog }) {
|
|
976
|
+
const [openAddressDialog, setOpenAddressDialog] = useState(false);
|
|
977
|
+
const [openDeleteDialog, setOpenDeleteDialog] = useState(false);
|
|
978
|
+
const [selectedAddress, setSelectedAddress] = useState(null);
|
|
979
|
+
const [deleteAddressError, setDeleteAddressError] = useState(void 0);
|
|
980
|
+
const { t } = useProfileUI();
|
|
981
|
+
const defaultAddress = addresses.find((addr) => addr.default) ?? null;
|
|
982
|
+
const handleDeleteClick = (address) => {
|
|
983
|
+
setSelectedAddress(address);
|
|
984
|
+
setDeleteAddressError(void 0);
|
|
985
|
+
requestAnimationFrame(() => {
|
|
986
|
+
setOpenDeleteDialog(true);
|
|
987
|
+
});
|
|
988
|
+
};
|
|
989
|
+
const handleEditClick = (address) => {
|
|
990
|
+
setSelectedAddress(address);
|
|
991
|
+
requestAnimationFrame(() => {
|
|
992
|
+
setOpenAddressDialog(true);
|
|
993
|
+
});
|
|
994
|
+
};
|
|
995
|
+
const handleDeleteAddress = async () => {
|
|
996
|
+
if (!selectedAddress) return;
|
|
997
|
+
try {
|
|
998
|
+
await onDeleteAddress(selectedAddress.id);
|
|
999
|
+
setDeleteAddressError(void 0);
|
|
1000
|
+
setOpenDeleteDialog(false);
|
|
1001
|
+
setSelectedAddress(null);
|
|
1002
|
+
} catch {
|
|
1003
|
+
setDeleteAddressError("We were unable to delete this address. Please try again.");
|
|
1004
|
+
}
|
|
1005
|
+
};
|
|
1006
|
+
const handleAddClick = () => {
|
|
1007
|
+
setSelectedAddress(null);
|
|
1008
|
+
if (onCreateAddress) onCreateAddress();
|
|
1009
|
+
setOpenAddressDialog(true);
|
|
1010
|
+
};
|
|
1011
|
+
const handleCloseAddressDialog = () => {
|
|
1012
|
+
setOpenAddressDialog(false);
|
|
1013
|
+
setSelectedAddress(null);
|
|
1014
|
+
};
|
|
1015
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
1016
|
+
/* @__PURE__ */ jsx(AddressDropdown, {
|
|
1017
|
+
title: t("shipping_addresses"),
|
|
1018
|
+
displayAddress: defaultAddress,
|
|
1019
|
+
addressList: addresses,
|
|
1020
|
+
onAddAddressClick: handleAddClick,
|
|
1021
|
+
onEditAddress: handleEditClick,
|
|
1022
|
+
onDeleteAddress: handleDeleteClick,
|
|
1023
|
+
accordionItemValue: "addresses",
|
|
1024
|
+
addAddressLabel: `+ ${t("add_an_address")}`,
|
|
1025
|
+
showAddButton: true,
|
|
1026
|
+
borderStyle: "border-b border-gray-300 pb-4 mb-6",
|
|
1027
|
+
showActions: true,
|
|
1028
|
+
isLoading
|
|
1029
|
+
}),
|
|
1030
|
+
/* @__PURE__ */ jsx(ConfirmActionDialog, {
|
|
1031
|
+
title: t("delete_address"),
|
|
1032
|
+
description: t("delete_address_message"),
|
|
1033
|
+
onAction: handleDeleteAddress,
|
|
1034
|
+
actionText: t("delete"),
|
|
1035
|
+
openDialog: openDeleteDialog,
|
|
1036
|
+
setOpenDialog: setOpenDeleteDialog,
|
|
1037
|
+
errorMsg: deleteAddressError,
|
|
1038
|
+
isLoading: isDeletingAddress
|
|
1039
|
+
}),
|
|
1040
|
+
renderAddressDialog?.({
|
|
1041
|
+
isOpen: openAddressDialog,
|
|
1042
|
+
onClose: handleCloseAddressDialog,
|
|
1043
|
+
selectedAddress
|
|
1044
|
+
})
|
|
1045
|
+
] });
|
|
1046
|
+
}
|
|
1047
|
+
//#endregion
|
|
1048
|
+
//#region ../../profile/ui/src/components/payment-method-dropdown.tsx
|
|
1049
|
+
function getCardDisplayName(paymentMethod) {
|
|
1050
|
+
if (paymentMethod.payment_type === "Credit Card") {
|
|
1051
|
+
const brand = paymentMethod.details.card_type;
|
|
1052
|
+
const lastFour = paymentMethod.details.last_four;
|
|
1053
|
+
return `${brand ?? "Card"} •••• ${lastFour ?? "****"}`;
|
|
1054
|
+
}
|
|
1055
|
+
return paymentMethod.payment_type;
|
|
1056
|
+
}
|
|
1057
|
+
function getCardExpiry(paymentMethod) {
|
|
1058
|
+
const { exp_month, exp_year } = paymentMethod.details;
|
|
1059
|
+
if (exp_month != null && exp_year != null) return `Expires ${exp_month}/${exp_year}`;
|
|
1060
|
+
return "";
|
|
1061
|
+
}
|
|
1062
|
+
function PaymentMethodDropdown({ title, displayPaymentMethod, paymentMethodList, onAddPaymentMethodClick, onEditPaymentMethod, onDeletePaymentMethod, accordionItemValue = "paymentMethods", addPaymentMethodLabel = "+ Add a payment method", showAddButton = true, borderStyle = "border-b border-gray-300 pb-4 mb-6", className = "", showActions = true, isLoading = false }) {
|
|
1063
|
+
const [paymentsValue, setPaymentsValue] = useState("");
|
|
1064
|
+
const { t } = useProfileUI();
|
|
1065
|
+
const renderPaymentMethod = (paymentMethod) => /* @__PURE__ */ jsxs("div", {
|
|
1066
|
+
className: "flex flex-row items-center space-x-2",
|
|
1067
|
+
children: [paymentMethod.details.logo_url && /* @__PURE__ */ jsx("div", {
|
|
1068
|
+
className: "h-6 w-10 flex-shrink-0",
|
|
1069
|
+
children: /* @__PURE__ */ jsx("img", {
|
|
1070
|
+
src: paymentMethod.details.logo_url,
|
|
1071
|
+
alt: paymentMethod.details.card_type ?? t("payment_method"),
|
|
1072
|
+
width: 40,
|
|
1073
|
+
height: 24,
|
|
1074
|
+
className: "object-contain"
|
|
1075
|
+
})
|
|
1076
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
1077
|
+
className: "flex flex-col",
|
|
1078
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
1079
|
+
className: "flex items-center text-sm font-medium text-gray-900",
|
|
1080
|
+
children: getCardDisplayName(paymentMethod)
|
|
1081
|
+
}), getCardExpiry(paymentMethod) && /* @__PURE__ */ jsx("div", {
|
|
1082
|
+
className: "text-sm text-gray-500",
|
|
1083
|
+
children: getCardExpiry(paymentMethod)
|
|
1084
|
+
})]
|
|
1085
|
+
})]
|
|
1086
|
+
});
|
|
1087
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
1088
|
+
className: `${borderStyle} ${className}`,
|
|
1089
|
+
children: [/* @__PURE__ */ jsx(Accordion, {
|
|
1090
|
+
type: "single",
|
|
1091
|
+
collapsible: true,
|
|
1092
|
+
value: paymentsValue,
|
|
1093
|
+
onValueChange: setPaymentsValue,
|
|
1094
|
+
className: "w-full",
|
|
1095
|
+
children: /* @__PURE__ */ jsxs(AccordionItem, {
|
|
1096
|
+
value: accordionItemValue,
|
|
1097
|
+
className: "border-b-0",
|
|
1098
|
+
children: [
|
|
1099
|
+
/* @__PURE__ */ jsxs("div", {
|
|
1100
|
+
className: "flex flex-row items-center justify-between",
|
|
1101
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
1102
|
+
className: "mt-4 mb-1 text-sm text-gray-400",
|
|
1103
|
+
children: title
|
|
1104
|
+
}), /* @__PURE__ */ jsx(AccordionTrigger, { className: "m-0 ml-2 flex h-auto min-h-0 w-auto py-0 hover:no-underline" })]
|
|
1105
|
+
}),
|
|
1106
|
+
!paymentsValue && isLoading ? /* @__PURE__ */ jsxs("div", {
|
|
1107
|
+
className: "mb-2 flex w-full flex-row items-center space-x-2",
|
|
1108
|
+
children: [/* @__PURE__ */ jsx(Skeleton, { className: "h-6 w-10" }), /* @__PURE__ */ jsxs("div", {
|
|
1109
|
+
className: "flex flex-col space-y-1",
|
|
1110
|
+
children: [/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-32" }), /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-24" })]
|
|
1111
|
+
})]
|
|
1112
|
+
}) : !paymentsValue && displayPaymentMethod && /* @__PURE__ */ jsx("div", {
|
|
1113
|
+
className: "mb-2 flex w-full cursor-pointer flex-col",
|
|
1114
|
+
onClick: () => setPaymentsValue(accordionItemValue),
|
|
1115
|
+
children: renderPaymentMethod(displayPaymentMethod)
|
|
1116
|
+
}),
|
|
1117
|
+
/* @__PURE__ */ jsx(AccordionContent, {
|
|
1118
|
+
className: "max-h-[400px] overflow-y-auto pt-2",
|
|
1119
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
1120
|
+
className: "mt-2 flex flex-col justify-between space-y-4 px-0.5",
|
|
1121
|
+
children: isLoading ? /* @__PURE__ */ jsx(Fragment$1, { children: [1, 2].map((i) => /* @__PURE__ */ jsx("div", {
|
|
1122
|
+
className: "items-center rounded bg-gray-100 p-3",
|
|
1123
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
1124
|
+
className: "flex flex-row items-center justify-between",
|
|
1125
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
1126
|
+
className: "flex flex-row items-center space-x-2",
|
|
1127
|
+
children: [/* @__PURE__ */ jsx(Skeleton, { className: "h-6 w-10" }), /* @__PURE__ */ jsxs("div", {
|
|
1128
|
+
className: "flex flex-col space-y-1",
|
|
1129
|
+
children: [/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-32" }), /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-24" })]
|
|
1130
|
+
})]
|
|
1131
|
+
}), /* @__PURE__ */ jsx(Skeleton, { className: "h-6 w-6" })]
|
|
1132
|
+
})
|
|
1133
|
+
}, `skeleton-${i}`)) }) : paymentMethodList.map((paymentMethod, index) => /* @__PURE__ */ jsxs("div", {
|
|
1134
|
+
className: cn("flex min-h-[48px] w-full flex-row items-center justify-between space-x-2 px-2", { "items-center border-b border-gray-300 p-3": paymentMethodList.length - 1 !== index }),
|
|
1135
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
1136
|
+
className: "flex flex-row items-center space-x-2",
|
|
1137
|
+
children: [paymentMethod.details.logo_url && /* @__PURE__ */ jsx("div", {
|
|
1138
|
+
className: "h-6 w-10 flex-shrink-0",
|
|
1139
|
+
children: /* @__PURE__ */ jsx("img", {
|
|
1140
|
+
src: paymentMethod.details.logo_url,
|
|
1141
|
+
alt: paymentMethod.details.card_type ?? t("payment_method"),
|
|
1142
|
+
width: 40,
|
|
1143
|
+
height: 24,
|
|
1144
|
+
className: "object-contain"
|
|
1145
|
+
})
|
|
1146
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
1147
|
+
className: "flex flex-col",
|
|
1148
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
1149
|
+
className: "flex items-center text-sm font-medium text-gray-900",
|
|
1150
|
+
children: `${paymentMethod.details.card_type ?? "Card"} •••• ${paymentMethod.details.last_four ?? "****"}`
|
|
1151
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
1152
|
+
className: "text-sm text-gray-500",
|
|
1153
|
+
children: `${t("card_expires")} ${paymentMethod.details.exp_month}/${paymentMethod.details.exp_year}`
|
|
1154
|
+
})]
|
|
1155
|
+
})]
|
|
1156
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
1157
|
+
className: "flex flex-row items-center space-x-2",
|
|
1158
|
+
children: [paymentMethod.default && /* @__PURE__ */ jsx("p", {
|
|
1159
|
+
className: "mt-1 w-fit rounded bg-gray-500 px-2 py-0.5 text-xs font-medium text-white",
|
|
1160
|
+
children: t("default")
|
|
1161
|
+
}), showActions && /* @__PURE__ */ jsx(EllipsesDropdown, {
|
|
1162
|
+
onDelete: () => onDeletePaymentMethod?.(paymentMethod),
|
|
1163
|
+
deleteLabel: t("delete"),
|
|
1164
|
+
onEdit: () => onEditPaymentMethod?.(paymentMethod),
|
|
1165
|
+
editLabel: t("edit")
|
|
1166
|
+
})]
|
|
1167
|
+
})]
|
|
1168
|
+
}, paymentMethod.id))
|
|
1169
|
+
})
|
|
1170
|
+
})
|
|
1171
|
+
]
|
|
1172
|
+
})
|
|
1173
|
+
}), showAddButton && /* @__PURE__ */ jsx("button", {
|
|
1174
|
+
className: "mt-3 text-left text-sm text-gray-900",
|
|
1175
|
+
onClick: onAddPaymentMethodClick,
|
|
1176
|
+
children: addPaymentMethodLabel
|
|
1177
|
+
})]
|
|
1178
|
+
});
|
|
1179
|
+
}
|
|
1180
|
+
//#endregion
|
|
1181
|
+
//#region ../../profile/ui/src/components/view-payment-method-dialog.tsx
|
|
1182
|
+
function ViewPaymentMethodDialog({ isOpen, paymentMethod, billingAddress, onClose, onEdit }) {
|
|
1183
|
+
const { t } = useProfileUI();
|
|
1184
|
+
if (!paymentMethod) return null;
|
|
1185
|
+
const { details } = paymentMethod;
|
|
1186
|
+
const cardBrand = details.card_type ?? "Card";
|
|
1187
|
+
const lastFour = details.last_four ?? "****";
|
|
1188
|
+
const expMonth = details.exp_month;
|
|
1189
|
+
const expYear = details.exp_year;
|
|
1190
|
+
return /* @__PURE__ */ jsx(Dialog, {
|
|
1191
|
+
open: isOpen,
|
|
1192
|
+
onOpenChange: (open) => !open && onClose(),
|
|
1193
|
+
children: /* @__PURE__ */ jsxs(DialogContent, {
|
|
1194
|
+
className: "max-w-sm rounded md:max-w-lg",
|
|
1195
|
+
children: [
|
|
1196
|
+
/* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, {
|
|
1197
|
+
className: "text-md font-medium",
|
|
1198
|
+
children: t("edit_card")
|
|
1199
|
+
}) }),
|
|
1200
|
+
/* @__PURE__ */ jsxs("div", {
|
|
1201
|
+
className: "space-y-4",
|
|
1202
|
+
children: [/* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs("div", {
|
|
1203
|
+
className: "rounded-lg bg-gray-50 p-4",
|
|
1204
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
1205
|
+
className: "flex items-center space-x-3",
|
|
1206
|
+
children: [details.logo_url && /* @__PURE__ */ jsx("div", {
|
|
1207
|
+
className: "h-6 w-10 flex-shrink-0",
|
|
1208
|
+
children: /* @__PURE__ */ jsx("img", {
|
|
1209
|
+
src: details.logo_url,
|
|
1210
|
+
alt: cardBrand,
|
|
1211
|
+
width: 40,
|
|
1212
|
+
height: 24,
|
|
1213
|
+
className: "object-contain"
|
|
1214
|
+
})
|
|
1215
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
1216
|
+
className: "flex flex-col",
|
|
1217
|
+
children: [/* @__PURE__ */ jsxs("span", {
|
|
1218
|
+
className: "text-sm font-medium text-gray-900",
|
|
1219
|
+
children: [
|
|
1220
|
+
cardBrand,
|
|
1221
|
+
" •••• ",
|
|
1222
|
+
lastFour
|
|
1223
|
+
]
|
|
1224
|
+
}), expMonth != null && expYear != null && /* @__PURE__ */ jsxs("span", {
|
|
1225
|
+
className: "text-sm text-gray-500",
|
|
1226
|
+
children: [
|
|
1227
|
+
t("card_expires"),
|
|
1228
|
+
" ",
|
|
1229
|
+
expMonth,
|
|
1230
|
+
"/",
|
|
1231
|
+
expYear
|
|
1232
|
+
]
|
|
1233
|
+
})]
|
|
1234
|
+
})]
|
|
1235
|
+
}), paymentMethod.default && /* @__PURE__ */ jsx("span", {
|
|
1236
|
+
className: "mt-2 inline-block rounded bg-gray-500 px-2 py-0.5 text-xs font-medium text-white",
|
|
1237
|
+
children: t("default")
|
|
1238
|
+
})]
|
|
1239
|
+
}) }), /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs("div", {
|
|
1240
|
+
className: "mb-2 flex items-center justify-between",
|
|
1241
|
+
children: [/* @__PURE__ */ jsx("h3", {
|
|
1242
|
+
className: "text-sm font-medium text-gray-900",
|
|
1243
|
+
children: t("billing_address")
|
|
1244
|
+
}), onEdit && /* @__PURE__ */ jsx(Button, {
|
|
1245
|
+
variant: "ghost",
|
|
1246
|
+
size: "sm",
|
|
1247
|
+
className: "h-auto p-0 text-sm text-gray-600 underline hover:bg-transparent",
|
|
1248
|
+
onClick: onEdit,
|
|
1249
|
+
children: t("edit")
|
|
1250
|
+
})]
|
|
1251
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
1252
|
+
className: "rounded-lg bg-gray-50 p-4",
|
|
1253
|
+
children: billingAddress ? /* @__PURE__ */ jsxs("div", {
|
|
1254
|
+
className: "space-y-1 text-sm text-gray-900",
|
|
1255
|
+
children: [
|
|
1256
|
+
billingAddress.name && /* @__PURE__ */ jsx("p", { children: billingAddress.name }),
|
|
1257
|
+
/* @__PURE__ */ jsx("p", { children: billingAddress.address1 }),
|
|
1258
|
+
billingAddress.address2 && /* @__PURE__ */ jsx("p", { children: billingAddress.address2 }),
|
|
1259
|
+
/* @__PURE__ */ jsxs("p", { children: [
|
|
1260
|
+
billingAddress.city,
|
|
1261
|
+
", ",
|
|
1262
|
+
billingAddress.state,
|
|
1263
|
+
" ",
|
|
1264
|
+
billingAddress.zip
|
|
1265
|
+
] }),
|
|
1266
|
+
/* @__PURE__ */ jsx("p", { children: billingAddress.country_code })
|
|
1267
|
+
]
|
|
1268
|
+
}) : /* @__PURE__ */ jsx("p", {
|
|
1269
|
+
className: "text-sm text-gray-500 italic",
|
|
1270
|
+
children: t("no_billing_address")
|
|
1271
|
+
})
|
|
1272
|
+
})] })]
|
|
1273
|
+
}),
|
|
1274
|
+
/* @__PURE__ */ jsx(DialogFooter, { children: /* @__PURE__ */ jsx(DialogClose, {
|
|
1275
|
+
asChild: true,
|
|
1276
|
+
children: /* @__PURE__ */ jsx(Button, {
|
|
1277
|
+
className: "rounded bg-gray-50 p-3 text-gray-900 ring-1 ring-gray-300 hover:bg-gray-100",
|
|
1278
|
+
onClick: onClose,
|
|
1279
|
+
children: t("close")
|
|
1280
|
+
})
|
|
1281
|
+
}) })
|
|
1282
|
+
]
|
|
1283
|
+
})
|
|
1284
|
+
});
|
|
1285
|
+
}
|
|
1286
|
+
//#endregion
|
|
1287
|
+
//#region ../../profile/ui/src/components/edit-payment-method-dialog.tsx
|
|
1288
|
+
const editPaymentMethodFormSchema = z.object({
|
|
1289
|
+
billing_address: z.object({
|
|
1290
|
+
name: z.string().min(1, "Name is required"),
|
|
1291
|
+
address1: z.string().min(1, "Address line 1 is required"),
|
|
1292
|
+
address2: z.string().optional().nullable(),
|
|
1293
|
+
city: z.string().min(1, "City is required"),
|
|
1294
|
+
state: z.string().min(1, "State is required"),
|
|
1295
|
+
zip: z.string().min(1, "Zip code is required"),
|
|
1296
|
+
country_code: z.string().min(1, "Country is required")
|
|
1297
|
+
}),
|
|
1298
|
+
set_as_default: z.boolean()
|
|
1299
|
+
});
|
|
1300
|
+
function EditPaymentMethodDialog({ isOpen, paymentMethod, billingAddress, onClose, onSubmit, isSubmitting, error, countries = [] }) {
|
|
1301
|
+
const { t } = useProfileUI();
|
|
1302
|
+
const { control, handleSubmit, reset, setValue } = useForm({
|
|
1303
|
+
resolver: zodResolver(editPaymentMethodFormSchema),
|
|
1304
|
+
defaultValues: {
|
|
1305
|
+
billing_address: {
|
|
1306
|
+
name: "",
|
|
1307
|
+
address1: "",
|
|
1308
|
+
address2: "",
|
|
1309
|
+
city: "",
|
|
1310
|
+
state: "",
|
|
1311
|
+
zip: "",
|
|
1312
|
+
country_code: "US"
|
|
1313
|
+
},
|
|
1314
|
+
set_as_default: false
|
|
1315
|
+
}
|
|
1316
|
+
});
|
|
1317
|
+
const billingCountry = useWatch({
|
|
1318
|
+
control,
|
|
1319
|
+
name: "billing_address.country_code"
|
|
1320
|
+
});
|
|
1321
|
+
const setAsDefault = useWatch({
|
|
1322
|
+
control,
|
|
1323
|
+
name: "set_as_default"
|
|
1324
|
+
});
|
|
1325
|
+
const { stateOptions, config, handleCountryChange } = useCountryStates();
|
|
1326
|
+
const countryOptions = [...countries].map((country) => ({
|
|
1327
|
+
name: country.name,
|
|
1328
|
+
value: country.iso
|
|
1329
|
+
})).sort((a, b) => {
|
|
1330
|
+
if (a.value === billingCountry) return -1;
|
|
1331
|
+
if (b.value === billingCountry) return 1;
|
|
1332
|
+
return a.name.localeCompare(b.name);
|
|
1333
|
+
});
|
|
1334
|
+
const stateSelectOptions = stateOptions.map((state) => ({
|
|
1335
|
+
name: state.name,
|
|
1336
|
+
value: state.isoCode
|
|
1337
|
+
}));
|
|
1338
|
+
useEffect(() => {
|
|
1339
|
+
if (paymentMethod && isOpen) reset({
|
|
1340
|
+
billing_address: {
|
|
1341
|
+
name: billingAddress?.name ?? "",
|
|
1342
|
+
address1: billingAddress?.address1 ?? "",
|
|
1343
|
+
address2: billingAddress?.address2 ?? "",
|
|
1344
|
+
city: billingAddress?.city ?? "",
|
|
1345
|
+
state: billingAddress?.state ?? "",
|
|
1346
|
+
zip: billingAddress?.zip ?? "",
|
|
1347
|
+
country_code: billingAddress?.country_code ?? "US"
|
|
1348
|
+
},
|
|
1349
|
+
set_as_default: paymentMethod.default
|
|
1350
|
+
});
|
|
1351
|
+
}, [
|
|
1352
|
+
paymentMethod,
|
|
1353
|
+
billingAddress,
|
|
1354
|
+
isOpen,
|
|
1355
|
+
reset
|
|
1356
|
+
]);
|
|
1357
|
+
const handleCountrySelect = (countryCode) => {
|
|
1358
|
+
handleCountryChange(countryCode);
|
|
1359
|
+
setValue("billing_address.country_code", countryCode, { shouldValidate: true });
|
|
1360
|
+
};
|
|
1361
|
+
const handleFormSubmit = handleSubmit((data) => {
|
|
1362
|
+
onSubmit(data);
|
|
1363
|
+
});
|
|
1364
|
+
if (!paymentMethod) return null;
|
|
1365
|
+
const { details } = paymentMethod;
|
|
1366
|
+
const cardBrand = details.card_type ?? "Card";
|
|
1367
|
+
const lastFour = details.last_four ?? "****";
|
|
1368
|
+
const expMonth = details.exp_month;
|
|
1369
|
+
const expYear = details.exp_year;
|
|
1370
|
+
return /* @__PURE__ */ jsx(Dialog, {
|
|
1371
|
+
open: isOpen,
|
|
1372
|
+
onOpenChange: (open) => !open && onClose(),
|
|
1373
|
+
children: /* @__PURE__ */ jsxs(DialogContent, {
|
|
1374
|
+
className: "max-h-[90vh] max-w-sm overflow-y-auto rounded md:max-w-lg",
|
|
1375
|
+
children: [
|
|
1376
|
+
/* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, {
|
|
1377
|
+
className: "text-md font-medium",
|
|
1378
|
+
children: t("edit_card")
|
|
1379
|
+
}) }),
|
|
1380
|
+
/* @__PURE__ */ jsxs("div", {
|
|
1381
|
+
className: "space-y-4",
|
|
1382
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
1383
|
+
className: "rounded-lg bg-gray-50 p-4",
|
|
1384
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
1385
|
+
className: "flex items-center space-x-3",
|
|
1386
|
+
children: [details.logo_url && /* @__PURE__ */ jsx("div", {
|
|
1387
|
+
className: "h-6 w-10 flex-shrink-0",
|
|
1388
|
+
children: /* @__PURE__ */ jsx("img", {
|
|
1389
|
+
src: details.logo_url,
|
|
1390
|
+
alt: cardBrand,
|
|
1391
|
+
width: 40,
|
|
1392
|
+
height: 24,
|
|
1393
|
+
className: "object-contain"
|
|
1394
|
+
})
|
|
1395
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
1396
|
+
className: "flex flex-col",
|
|
1397
|
+
children: [/* @__PURE__ */ jsxs("span", {
|
|
1398
|
+
className: "text-sm font-medium text-gray-900",
|
|
1399
|
+
children: [
|
|
1400
|
+
cardBrand,
|
|
1401
|
+
" •••• ",
|
|
1402
|
+
lastFour
|
|
1403
|
+
]
|
|
1404
|
+
}), expMonth != null && expYear != null && /* @__PURE__ */ jsxs("span", {
|
|
1405
|
+
className: "text-sm text-gray-500",
|
|
1406
|
+
children: [
|
|
1407
|
+
t("card_expires"),
|
|
1408
|
+
" ",
|
|
1409
|
+
expMonth,
|
|
1410
|
+
"/",
|
|
1411
|
+
expYear
|
|
1412
|
+
]
|
|
1413
|
+
})]
|
|
1414
|
+
})]
|
|
1415
|
+
})
|
|
1416
|
+
}), /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h3", {
|
|
1417
|
+
className: "mb-1 text-sm font-medium text-gray-900",
|
|
1418
|
+
children: t("billing_address")
|
|
1419
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
1420
|
+
className: "space-y-0",
|
|
1421
|
+
children: [
|
|
1422
|
+
/* @__PURE__ */ jsx(FormSelectField$1, {
|
|
1423
|
+
control,
|
|
1424
|
+
name: "billing_address.country_code",
|
|
1425
|
+
label: t("country"),
|
|
1426
|
+
options: countryOptions,
|
|
1427
|
+
placeholder: t("select_an_option"),
|
|
1428
|
+
onChange: (val) => {
|
|
1429
|
+
handleCountrySelect(val);
|
|
1430
|
+
}
|
|
1431
|
+
}),
|
|
1432
|
+
/* @__PURE__ */ jsx(FormTextField$1, {
|
|
1433
|
+
control,
|
|
1434
|
+
name: "billing_address.name",
|
|
1435
|
+
label: t("name")
|
|
1436
|
+
}),
|
|
1437
|
+
/* @__PURE__ */ jsx(FormTextField$1, {
|
|
1438
|
+
control,
|
|
1439
|
+
name: "billing_address.address1",
|
|
1440
|
+
label: t("address_line_1")
|
|
1441
|
+
}),
|
|
1442
|
+
/* @__PURE__ */ jsx(FormTextField$1, {
|
|
1443
|
+
control,
|
|
1444
|
+
name: "billing_address.address2",
|
|
1445
|
+
label: t("address_line_2")
|
|
1446
|
+
}),
|
|
1447
|
+
/* @__PURE__ */ jsxs("div", {
|
|
1448
|
+
className: "sm:flex sm:gap-2",
|
|
1449
|
+
children: [
|
|
1450
|
+
/* @__PURE__ */ jsx(FormTextField$1, {
|
|
1451
|
+
control,
|
|
1452
|
+
name: "billing_address.city",
|
|
1453
|
+
label: t("city"),
|
|
1454
|
+
containerClassName: "flex-1"
|
|
1455
|
+
}),
|
|
1456
|
+
/* @__PURE__ */ jsx(FormSelectField$1, {
|
|
1457
|
+
control,
|
|
1458
|
+
name: "billing_address.state",
|
|
1459
|
+
label: config?.regionLabel ? t(config.regionLabel) : t("state"),
|
|
1460
|
+
options: stateSelectOptions,
|
|
1461
|
+
placeholder: t("select_state"),
|
|
1462
|
+
containerClassName: "flex-1"
|
|
1463
|
+
}),
|
|
1464
|
+
/* @__PURE__ */ jsx(FormTextField$1, {
|
|
1465
|
+
control,
|
|
1466
|
+
name: "billing_address.zip",
|
|
1467
|
+
label: config?.postalLabel ? t(config.postalLabel) : t("zip_code"),
|
|
1468
|
+
containerClassName: "flex-1"
|
|
1469
|
+
})
|
|
1470
|
+
]
|
|
1471
|
+
})
|
|
1472
|
+
]
|
|
1473
|
+
})] })]
|
|
1474
|
+
}),
|
|
1475
|
+
/* @__PURE__ */ jsxs("div", {
|
|
1476
|
+
className: "mt-2 flex items-center space-x-2",
|
|
1477
|
+
children: [/* @__PURE__ */ jsx("input", {
|
|
1478
|
+
type: "checkbox",
|
|
1479
|
+
id: "set_as_default",
|
|
1480
|
+
checked: setAsDefault,
|
|
1481
|
+
onChange: () => setValue("set_as_default", !setAsDefault),
|
|
1482
|
+
className: "h-4 w-4"
|
|
1483
|
+
}), /* @__PURE__ */ jsx("label", {
|
|
1484
|
+
htmlFor: "set_as_default",
|
|
1485
|
+
className: "text-sm",
|
|
1486
|
+
children: t("set_as_default_payment_method")
|
|
1487
|
+
})]
|
|
1488
|
+
}),
|
|
1489
|
+
error && /* @__PURE__ */ jsx("div", {
|
|
1490
|
+
className: "text-sm text-red-500",
|
|
1491
|
+
children: error
|
|
1492
|
+
}),
|
|
1493
|
+
/* @__PURE__ */ jsxs(DialogFooter, {
|
|
1494
|
+
className: "flex flex-row items-center justify-between",
|
|
1495
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
1496
|
+
className: "flex-2",
|
|
1497
|
+
children: /* @__PURE__ */ jsx(Button, {
|
|
1498
|
+
type: "button",
|
|
1499
|
+
className: "rounded bg-gray-50 p-3 text-gray-900 ring-1 ring-gray-300 hover:bg-gray-100",
|
|
1500
|
+
onClick: onClose,
|
|
1501
|
+
disabled: isSubmitting,
|
|
1502
|
+
children: t("cancel")
|
|
1503
|
+
})
|
|
1504
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
1505
|
+
className: "flex-1 text-right",
|
|
1506
|
+
children: /* @__PURE__ */ jsx(Button, {
|
|
1507
|
+
type: "submit",
|
|
1508
|
+
onClick: handleFormSubmit,
|
|
1509
|
+
disabled: isSubmitting,
|
|
1510
|
+
className: "rounded bg-gray-900 p-3 text-white hover:bg-gray-800",
|
|
1511
|
+
children: isSubmitting ? /* @__PURE__ */ jsx("div", { className: "h-5 w-5 animate-spin rounded-full border-4 border-t-4 border-white border-t-transparent" }) : t("save")
|
|
1512
|
+
})
|
|
1513
|
+
})]
|
|
1514
|
+
})
|
|
1515
|
+
]
|
|
1516
|
+
})
|
|
1517
|
+
});
|
|
1518
|
+
}
|
|
1519
|
+
//#endregion
|
|
1520
|
+
//#region ../../profile/ui/src/components/payment-methods.tsx
|
|
1521
|
+
function PaymentMethods({ paymentMethods, isLoading = false, onDeletePaymentMethod, isDeletingPaymentMethod = false, onUpdatePaymentMethod, isUpdatingPaymentMethod = false, getBillingAddress, countries, renderCreditCardDialog }) {
|
|
1522
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
1523
|
+
const [openDeleteDialog, setOpenDeleteDialog] = useState(false);
|
|
1524
|
+
const [deleteCardError, setDeleteCardError] = useState(void 0);
|
|
1525
|
+
const [selectedCreditCard, setSelectedCreditCard] = useState(void 0);
|
|
1526
|
+
const [isViewOpen, setIsViewOpen] = useState(false);
|
|
1527
|
+
const [isEditOpen, setIsEditOpen] = useState(false);
|
|
1528
|
+
const [selectedPaymentMethod, setSelectedPaymentMethod] = useState(null);
|
|
1529
|
+
const [editError, setEditError] = useState(void 0);
|
|
1530
|
+
const { t } = useProfileUI();
|
|
1531
|
+
const defaultPaymentMethod = paymentMethods.find((method) => method.default) ?? null;
|
|
1532
|
+
const handleDeleteCard = async (cardId) => {
|
|
1533
|
+
if (!cardId) return;
|
|
1534
|
+
try {
|
|
1535
|
+
await onDeletePaymentMethod(cardId);
|
|
1536
|
+
setSelectedCreditCard(void 0);
|
|
1537
|
+
setDeleteCardError(void 0);
|
|
1538
|
+
setOpenDeleteDialog(false);
|
|
1539
|
+
} catch {
|
|
1540
|
+
setDeleteCardError("Unable to delete payment method. Please try again.");
|
|
1541
|
+
}
|
|
1542
|
+
};
|
|
1543
|
+
const handleDeletePaymentMethod = (paymentMethod) => {
|
|
1544
|
+
setSelectedCreditCard(paymentMethod);
|
|
1545
|
+
requestAnimationFrame(() => {
|
|
1546
|
+
setOpenDeleteDialog(true);
|
|
1547
|
+
});
|
|
1548
|
+
};
|
|
1549
|
+
const handleViewPaymentMethod = (paymentMethod) => {
|
|
1550
|
+
setSelectedPaymentMethod(paymentMethod);
|
|
1551
|
+
requestAnimationFrame(() => {
|
|
1552
|
+
setIsViewOpen(true);
|
|
1553
|
+
});
|
|
1554
|
+
};
|
|
1555
|
+
const handleCloseViewDialog = () => {
|
|
1556
|
+
setIsViewOpen(false);
|
|
1557
|
+
setSelectedPaymentMethod(null);
|
|
1558
|
+
};
|
|
1559
|
+
const handleOpenEditFromView = () => {
|
|
1560
|
+
setIsViewOpen(false);
|
|
1561
|
+
setEditError(void 0);
|
|
1562
|
+
requestAnimationFrame(() => {
|
|
1563
|
+
setIsEditOpen(true);
|
|
1564
|
+
});
|
|
1565
|
+
};
|
|
1566
|
+
const handleCloseEditDialog = () => {
|
|
1567
|
+
setIsEditOpen(false);
|
|
1568
|
+
setSelectedPaymentMethod(null);
|
|
1569
|
+
setEditError(void 0);
|
|
1570
|
+
};
|
|
1571
|
+
const handleEditSubmit = async (data) => {
|
|
1572
|
+
if (!selectedPaymentMethod) return;
|
|
1573
|
+
try {
|
|
1574
|
+
await onUpdatePaymentMethod(selectedPaymentMethod.id, data);
|
|
1575
|
+
handleCloseEditDialog();
|
|
1576
|
+
fluidToast({
|
|
1577
|
+
title: t("default_payment_method_updated"),
|
|
1578
|
+
type: "success"
|
|
1579
|
+
});
|
|
1580
|
+
} catch (error) {
|
|
1581
|
+
console.error("Error updating payment method:", error);
|
|
1582
|
+
fluidToast({
|
|
1583
|
+
title: t("failed_to_set_default_payment_method"),
|
|
1584
|
+
type: "error",
|
|
1585
|
+
description: parseApiErrors(error)
|
|
1586
|
+
});
|
|
1587
|
+
if (error instanceof Error) setEditError(error.message);
|
|
1588
|
+
else setEditError("An unexpected error occurred. Please try again.");
|
|
1589
|
+
}
|
|
1590
|
+
};
|
|
1591
|
+
const handleOpenDialog = () => {
|
|
1592
|
+
setIsOpen(true);
|
|
1593
|
+
};
|
|
1594
|
+
const handleCloseDialog = () => {
|
|
1595
|
+
setIsOpen(false);
|
|
1596
|
+
};
|
|
1597
|
+
const selectedBillingAddress = selectedPaymentMethod ? getBillingAddress?.(selectedPaymentMethod) ?? null : null;
|
|
1598
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
1599
|
+
/* @__PURE__ */ jsx(PaymentMethodDropdown, {
|
|
1600
|
+
title: t("payment_methods"),
|
|
1601
|
+
displayPaymentMethod: defaultPaymentMethod,
|
|
1602
|
+
paymentMethodList: paymentMethods,
|
|
1603
|
+
onAddPaymentMethodClick: handleOpenDialog,
|
|
1604
|
+
onEditPaymentMethod: handleViewPaymentMethod,
|
|
1605
|
+
onDeletePaymentMethod: handleDeletePaymentMethod,
|
|
1606
|
+
addPaymentMethodLabel: `+ ${t("add_payment_method")}`,
|
|
1607
|
+
isLoading
|
|
1608
|
+
}),
|
|
1609
|
+
renderCreditCardDialog?.({
|
|
1610
|
+
isOpen,
|
|
1611
|
+
onClose: handleCloseDialog
|
|
1612
|
+
}),
|
|
1613
|
+
/* @__PURE__ */ jsx(ConfirmActionDialog, {
|
|
1614
|
+
title: t("delete_credit_card"),
|
|
1615
|
+
description: t("delete_credit_card_message"),
|
|
1616
|
+
actionText: t("delete"),
|
|
1617
|
+
onAction: () => handleDeleteCard(selectedCreditCard?.id ?? null),
|
|
1618
|
+
openDialog: openDeleteDialog,
|
|
1619
|
+
setOpenDialog: setOpenDeleteDialog,
|
|
1620
|
+
errorMsg: deleteCardError,
|
|
1621
|
+
isLoading: isDeletingPaymentMethod
|
|
1622
|
+
}),
|
|
1623
|
+
/* @__PURE__ */ jsx(ViewPaymentMethodDialog, {
|
|
1624
|
+
isOpen: isViewOpen,
|
|
1625
|
+
paymentMethod: selectedPaymentMethod,
|
|
1626
|
+
billingAddress: selectedBillingAddress,
|
|
1627
|
+
onClose: handleCloseViewDialog,
|
|
1628
|
+
onEdit: handleOpenEditFromView
|
|
1629
|
+
}),
|
|
1630
|
+
/* @__PURE__ */ jsx(EditPaymentMethodDialog, {
|
|
1631
|
+
isOpen: isEditOpen,
|
|
1632
|
+
paymentMethod: selectedPaymentMethod,
|
|
1633
|
+
billingAddress: selectedBillingAddress,
|
|
1634
|
+
onClose: handleCloseEditDialog,
|
|
1635
|
+
onSubmit: handleEditSubmit,
|
|
1636
|
+
isSubmitting: isUpdatingPaymentMethod,
|
|
1637
|
+
error: editError,
|
|
1638
|
+
countries
|
|
1639
|
+
})
|
|
1640
|
+
] });
|
|
1641
|
+
}
|
|
1642
|
+
//#endregion
|
|
1643
|
+
//#region ../../profile/ui/src/components/profile.tsx
|
|
1644
|
+
function Profile({ customerAccount, languages, onUpdateCustomer, isUpdatingCustomer, rewardsPointsEnabled = false, pointsLedger, isLoadingPointsLedger, addresses, isLoadingAddresses, onDeleteAddress, isDeletingAddress, renderAddressDialog, paymentMethods, isLoadingPaymentMethods, onDeletePaymentMethod, isDeletingPaymentMethod, onUpdatePaymentMethod, isUpdatingPaymentMethod, getBillingAddress, countries, renderCreditCardDialog }) {
|
|
1645
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
1646
|
+
/* @__PURE__ */ jsx(CustomerInfo, {
|
|
1647
|
+
customerAccount,
|
|
1648
|
+
languages,
|
|
1649
|
+
onUpdateCustomer,
|
|
1650
|
+
isUpdating: isUpdatingCustomer
|
|
1651
|
+
}),
|
|
1652
|
+
rewardsPointsEnabled && /* @__PURE__ */ jsx(CustomerPointsLedger, {
|
|
1653
|
+
pointsLedger: pointsLedger ?? [],
|
|
1654
|
+
isLoading: isLoadingPointsLedger
|
|
1655
|
+
}),
|
|
1656
|
+
/* @__PURE__ */ jsx(Addresses, {
|
|
1657
|
+
addresses,
|
|
1658
|
+
isLoading: isLoadingAddresses,
|
|
1659
|
+
onDeleteAddress,
|
|
1660
|
+
isDeletingAddress,
|
|
1661
|
+
renderAddressDialog
|
|
1662
|
+
}),
|
|
1663
|
+
/* @__PURE__ */ jsx(PaymentMethods, {
|
|
1664
|
+
paymentMethods,
|
|
1665
|
+
isLoading: isLoadingPaymentMethods,
|
|
1666
|
+
onDeletePaymentMethod,
|
|
1667
|
+
isDeletingPaymentMethod,
|
|
1668
|
+
onUpdatePaymentMethod,
|
|
1669
|
+
isUpdatingPaymentMethod,
|
|
1670
|
+
getBillingAddress,
|
|
1671
|
+
countries,
|
|
1672
|
+
renderCreditCardDialog
|
|
1673
|
+
})
|
|
1674
|
+
] });
|
|
1675
|
+
}
|
|
1676
|
+
//#endregion
|
|
1677
|
+
//#region ../../fluid-pay/ui/src/components/form-fields/FormTextField.tsx
|
|
1678
|
+
function FormTextField({ control, name, placeholder, containerClassName, type, disabled, inputMode }) {
|
|
1679
|
+
const { field, fieldState: { error } } = useController({
|
|
1680
|
+
name,
|
|
1681
|
+
control
|
|
1682
|
+
});
|
|
1683
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
1684
|
+
className: cn("space-y-1", containerClassName),
|
|
1685
|
+
children: [/* @__PURE__ */ jsx(Input, {
|
|
1686
|
+
...field,
|
|
1687
|
+
value: field.value ?? "",
|
|
1688
|
+
id: name,
|
|
1689
|
+
type,
|
|
1690
|
+
disabled,
|
|
1691
|
+
inputMode,
|
|
1692
|
+
placeholder,
|
|
1693
|
+
"aria-invalid": !!error
|
|
1694
|
+
}), error?.message && /* @__PURE__ */ jsx("p", {
|
|
1695
|
+
className: "text-sm text-red-500",
|
|
1696
|
+
children: error.message
|
|
1697
|
+
})]
|
|
1698
|
+
});
|
|
1699
|
+
}
|
|
1700
|
+
//#endregion
|
|
1701
|
+
//#region ../../fluid-pay/ui/src/components/form-fields/FormSelectField.tsx
|
|
1702
|
+
function FormSelectField({ control, name, placeholder = "Select", options, containerClassName, disabled }) {
|
|
1703
|
+
return /* @__PURE__ */ jsx("div", {
|
|
1704
|
+
className: cn("space-y-1", containerClassName),
|
|
1705
|
+
children: /* @__PURE__ */ jsx(Controller, {
|
|
1706
|
+
control,
|
|
1707
|
+
name,
|
|
1708
|
+
render: ({ field: { onChange, value }, fieldState: { error } }) => /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs(Select, {
|
|
1709
|
+
value: value?.toString() ?? "",
|
|
1710
|
+
onValueChange: onChange,
|
|
1711
|
+
disabled,
|
|
1712
|
+
children: [/* @__PURE__ */ jsx(SelectTrigger, {
|
|
1713
|
+
"aria-invalid": !!error,
|
|
1714
|
+
className: cn("w-full", error && "border-red-500 ring-1 ring-red-500"),
|
|
1715
|
+
children: /* @__PURE__ */ jsx(SelectValue, { placeholder })
|
|
1716
|
+
}), /* @__PURE__ */ jsx(SelectContent, { children: options && options.length > 0 ? options.map((opt) => /* @__PURE__ */ jsx(SelectItem, {
|
|
1717
|
+
value: opt.value.toString(),
|
|
1718
|
+
children: opt.name
|
|
1719
|
+
}, opt.value.toString())) : /* @__PURE__ */ jsx(SelectItem, {
|
|
1720
|
+
value: "__empty",
|
|
1721
|
+
disabled: true,
|
|
1722
|
+
children: "No available options"
|
|
1723
|
+
}) })]
|
|
1724
|
+
}), error?.message && /* @__PURE__ */ jsx("p", {
|
|
1725
|
+
className: "text-sm text-red-500",
|
|
1726
|
+
children: error.message
|
|
1727
|
+
})] })
|
|
1728
|
+
})
|
|
1729
|
+
});
|
|
1730
|
+
}
|
|
1731
|
+
//#endregion
|
|
1732
|
+
//#region ../../fluid-pay/ui/src/components/AddressFormDialog.tsx
|
|
1733
|
+
const addressFormSchema = z.object({
|
|
1734
|
+
first_name: z.string().min(1, "First name is required"),
|
|
1735
|
+
last_name: z.string().min(1, "Last name is required"),
|
|
1736
|
+
address1: z.string().min(1, "Address line 1 is required"),
|
|
1737
|
+
address2: z.string().optional().nullable(),
|
|
1738
|
+
city: z.string().min(1, "City is required"),
|
|
1739
|
+
state: z.string().min(1, "State is required"),
|
|
1740
|
+
postal_code: z.string().min(1, "Postal code is required"),
|
|
1741
|
+
country_code: z.string().min(1, "Country is required"),
|
|
1742
|
+
default: z.boolean()
|
|
1743
|
+
});
|
|
1744
|
+
function AddressFormDialog({ isOpen, onClose, selectedAddress, onSubmit, isSubmitting, countries = [], error, renderAddressAutocomplete, t }) {
|
|
1745
|
+
const { control, handleSubmit, reset, setValue } = useForm({
|
|
1746
|
+
resolver: zodResolver(addressFormSchema),
|
|
1747
|
+
defaultValues: {
|
|
1748
|
+
first_name: "",
|
|
1749
|
+
last_name: "",
|
|
1750
|
+
address1: "",
|
|
1751
|
+
address2: "",
|
|
1752
|
+
city: "",
|
|
1753
|
+
state: "",
|
|
1754
|
+
postal_code: "",
|
|
1755
|
+
country_code: "US",
|
|
1756
|
+
default: false
|
|
1757
|
+
}
|
|
1758
|
+
});
|
|
1759
|
+
const selectedCountryCode = useWatch({
|
|
1760
|
+
control,
|
|
1761
|
+
name: "country_code"
|
|
1762
|
+
});
|
|
1763
|
+
const isDefault = useWatch({
|
|
1764
|
+
control,
|
|
1765
|
+
name: "default"
|
|
1766
|
+
});
|
|
1767
|
+
const { stateOptions, config, handleCountryChange } = useCountryStates();
|
|
1768
|
+
const countrySelectOptions = [...countries].map((country) => ({
|
|
1769
|
+
name: country.name,
|
|
1770
|
+
value: country.iso
|
|
1771
|
+
})).sort((a, b) => {
|
|
1772
|
+
if (a.value === selectedCountryCode) return -1;
|
|
1773
|
+
if (b.value === selectedCountryCode) return 1;
|
|
1774
|
+
return a.name.localeCompare(b.name);
|
|
1775
|
+
});
|
|
1776
|
+
const stateSelectOptions = stateOptions.map((state) => ({
|
|
1777
|
+
name: state.name,
|
|
1778
|
+
value: state.isoCode
|
|
1779
|
+
}));
|
|
1780
|
+
useEffect(() => {
|
|
1781
|
+
if (isOpen) if (selectedAddress) {
|
|
1782
|
+
const nameParts = (selectedAddress.name ?? "").split(" ");
|
|
1783
|
+
reset({
|
|
1784
|
+
first_name: nameParts[0] ?? "",
|
|
1785
|
+
last_name: nameParts.slice(1).join(" "),
|
|
1786
|
+
address1: selectedAddress.address1,
|
|
1787
|
+
address2: selectedAddress.address2 ?? "",
|
|
1788
|
+
city: selectedAddress.city,
|
|
1789
|
+
state: selectedAddress.state,
|
|
1790
|
+
postal_code: selectedAddress.postal_code,
|
|
1791
|
+
country_code: selectedAddress.country_code ?? "US",
|
|
1792
|
+
default: selectedAddress.default
|
|
1793
|
+
});
|
|
1794
|
+
handleCountryChange(selectedAddress.country_code ?? "US");
|
|
1795
|
+
} else {
|
|
1796
|
+
reset({
|
|
1797
|
+
first_name: "",
|
|
1798
|
+
last_name: "",
|
|
1799
|
+
address1: "",
|
|
1800
|
+
address2: "",
|
|
1801
|
+
city: "",
|
|
1802
|
+
state: "",
|
|
1803
|
+
postal_code: "",
|
|
1804
|
+
country_code: "US",
|
|
1805
|
+
default: false
|
|
1806
|
+
});
|
|
1807
|
+
handleCountryChange("US");
|
|
1808
|
+
}
|
|
1809
|
+
}, [
|
|
1810
|
+
selectedAddress,
|
|
1811
|
+
isOpen,
|
|
1812
|
+
reset,
|
|
1813
|
+
handleCountryChange
|
|
1814
|
+
]);
|
|
1815
|
+
useEffect(() => {
|
|
1816
|
+
handleCountryChange(selectedCountryCode);
|
|
1817
|
+
}, [selectedCountryCode, handleCountryChange]);
|
|
1818
|
+
const handleFormSubmit = handleSubmit((data) => {
|
|
1819
|
+
onSubmit({ address: {
|
|
1820
|
+
first_name: data.first_name,
|
|
1821
|
+
last_name: data.last_name,
|
|
1822
|
+
address1: data.address1,
|
|
1823
|
+
address2: data.address2 ?? null,
|
|
1824
|
+
city: data.city,
|
|
1825
|
+
state: data.state,
|
|
1826
|
+
postal_code: data.postal_code,
|
|
1827
|
+
country_code: data.country_code,
|
|
1828
|
+
default: data.default
|
|
1829
|
+
} });
|
|
1830
|
+
});
|
|
1831
|
+
return /* @__PURE__ */ jsx(Dialog, {
|
|
1832
|
+
open: isOpen,
|
|
1833
|
+
onOpenChange: (open) => !open && onClose(),
|
|
1834
|
+
children: /* @__PURE__ */ jsxs(DialogContent, {
|
|
1835
|
+
className: "max-h-[90vh] max-w-md overflow-y-auto rounded md:max-w-xl",
|
|
1836
|
+
children: [
|
|
1837
|
+
/* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, {
|
|
1838
|
+
className: "text-lg font-medium",
|
|
1839
|
+
children: selectedAddress !== null ? t("edit_address") : t("add_an_address")
|
|
1840
|
+
}) }),
|
|
1841
|
+
/* @__PURE__ */ jsxs("div", {
|
|
1842
|
+
className: "space-y-3 pt-2",
|
|
1843
|
+
children: [
|
|
1844
|
+
/* @__PURE__ */ jsx(FormSelectField, {
|
|
1845
|
+
control,
|
|
1846
|
+
name: "country_code",
|
|
1847
|
+
placeholder: t("country"),
|
|
1848
|
+
options: countrySelectOptions,
|
|
1849
|
+
disabled: isSubmitting
|
|
1850
|
+
}),
|
|
1851
|
+
/* @__PURE__ */ jsxs("div", {
|
|
1852
|
+
className: "flex gap-3",
|
|
1853
|
+
children: [/* @__PURE__ */ jsx(FormTextField, {
|
|
1854
|
+
control,
|
|
1855
|
+
name: "first_name",
|
|
1856
|
+
placeholder: t("first_name"),
|
|
1857
|
+
containerClassName: "flex-1",
|
|
1858
|
+
disabled: isSubmitting
|
|
1859
|
+
}), /* @__PURE__ */ jsx(FormTextField, {
|
|
1860
|
+
control,
|
|
1861
|
+
name: "last_name",
|
|
1862
|
+
placeholder: t("last_name"),
|
|
1863
|
+
containerClassName: "flex-1",
|
|
1864
|
+
disabled: isSubmitting
|
|
1865
|
+
})]
|
|
1866
|
+
}),
|
|
1867
|
+
renderAddressAutocomplete ? renderAddressAutocomplete({
|
|
1868
|
+
control,
|
|
1869
|
+
setValue,
|
|
1870
|
+
countryCode: selectedCountryCode
|
|
1871
|
+
}) : /* @__PURE__ */ jsx(FormTextField, {
|
|
1872
|
+
control,
|
|
1873
|
+
name: "address1",
|
|
1874
|
+
placeholder: t("address_line_1"),
|
|
1875
|
+
disabled: isSubmitting
|
|
1876
|
+
}),
|
|
1877
|
+
/* @__PURE__ */ jsx(FormTextField, {
|
|
1878
|
+
control,
|
|
1879
|
+
name: "address2",
|
|
1880
|
+
placeholder: t("address_line_2"),
|
|
1881
|
+
disabled: isSubmitting
|
|
1882
|
+
}),
|
|
1883
|
+
/* @__PURE__ */ jsxs("div", {
|
|
1884
|
+
className: "flex gap-3",
|
|
1885
|
+
children: [
|
|
1886
|
+
/* @__PURE__ */ jsx(FormTextField, {
|
|
1887
|
+
control,
|
|
1888
|
+
name: "city",
|
|
1889
|
+
placeholder: t("city"),
|
|
1890
|
+
containerClassName: "flex-1",
|
|
1891
|
+
disabled: isSubmitting
|
|
1892
|
+
}),
|
|
1893
|
+
/* @__PURE__ */ jsx(FormSelectField, {
|
|
1894
|
+
control,
|
|
1895
|
+
name: "state",
|
|
1896
|
+
placeholder: config?.regionLabel ? t(config.regionLabel) : t("select_state"),
|
|
1897
|
+
options: stateSelectOptions,
|
|
1898
|
+
containerClassName: "flex-1",
|
|
1899
|
+
disabled: isSubmitting
|
|
1900
|
+
}),
|
|
1901
|
+
/* @__PURE__ */ jsx(FormTextField, {
|
|
1902
|
+
control,
|
|
1903
|
+
name: "postal_code",
|
|
1904
|
+
placeholder: config?.postalLabel ? t(config.postalLabel) : t("zip_code"),
|
|
1905
|
+
containerClassName: "flex-1",
|
|
1906
|
+
disabled: isSubmitting
|
|
1907
|
+
})
|
|
1908
|
+
]
|
|
1909
|
+
})
|
|
1910
|
+
]
|
|
1911
|
+
}),
|
|
1912
|
+
/* @__PURE__ */ jsxs("div", {
|
|
1913
|
+
className: "mt-4 flex items-center justify-between",
|
|
1914
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
1915
|
+
className: "flex items-center space-x-2",
|
|
1916
|
+
children: [/* @__PURE__ */ jsx("input", {
|
|
1917
|
+
type: "checkbox",
|
|
1918
|
+
id: "set_as_default_address",
|
|
1919
|
+
checked: isDefault,
|
|
1920
|
+
onChange: () => setValue("default", !isDefault),
|
|
1921
|
+
disabled: isSubmitting,
|
|
1922
|
+
className: "h-4 w-4"
|
|
1923
|
+
}), /* @__PURE__ */ jsx("label", {
|
|
1924
|
+
htmlFor: "set_as_default_address",
|
|
1925
|
+
className: "text-sm",
|
|
1926
|
+
children: t("set_as_default_address")
|
|
1927
|
+
})]
|
|
1928
|
+
}), /* @__PURE__ */ jsx(Button, {
|
|
1929
|
+
type: "submit",
|
|
1930
|
+
onClick: handleFormSubmit,
|
|
1931
|
+
disabled: isSubmitting,
|
|
1932
|
+
className: "rounded bg-gray-900 px-5 py-2.5 text-white hover:bg-gray-800",
|
|
1933
|
+
children: isSubmitting ? /* @__PURE__ */ jsx("div", { className: "h-5 w-5 animate-spin rounded-full border-4 border-t-4 border-white border-t-transparent" }) : t("save_address")
|
|
1934
|
+
})]
|
|
1935
|
+
}),
|
|
1936
|
+
error && /* @__PURE__ */ jsx("div", {
|
|
1937
|
+
className: "mt-2 text-sm text-red-500",
|
|
1938
|
+
children: error
|
|
1939
|
+
})
|
|
1940
|
+
]
|
|
1941
|
+
})
|
|
1942
|
+
});
|
|
1943
|
+
}
|
|
1944
|
+
//#endregion
|
|
1945
|
+
//#region ../../fluid-pay/ui/src/hooks/use-vgs-collect.ts
|
|
1946
|
+
const getVGSCollect = () => {
|
|
1947
|
+
if (typeof window !== "undefined") return window.VGSCollect || null;
|
|
1948
|
+
return null;
|
|
1949
|
+
};
|
|
1950
|
+
const DEFAULT_FIELD_STATE = {
|
|
1951
|
+
card_number: {
|
|
1952
|
+
isFocused: false,
|
|
1953
|
+
isValid: false,
|
|
1954
|
+
isEmpty: true
|
|
1955
|
+
},
|
|
1956
|
+
card_exp: {
|
|
1957
|
+
isFocused: false,
|
|
1958
|
+
isValid: false,
|
|
1959
|
+
isEmpty: true
|
|
1960
|
+
},
|
|
1961
|
+
card_cvc: {
|
|
1962
|
+
isFocused: false,
|
|
1963
|
+
isValid: false,
|
|
1964
|
+
isEmpty: true
|
|
1965
|
+
},
|
|
1966
|
+
card_holder: {
|
|
1967
|
+
isFocused: false,
|
|
1968
|
+
isValid: false,
|
|
1969
|
+
isEmpty: true
|
|
1970
|
+
}
|
|
1971
|
+
};
|
|
1972
|
+
function useVgsCollect() {
|
|
1973
|
+
const [isFormReady, setIsFormReady] = useState(false);
|
|
1974
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
1975
|
+
const [isScriptLoaded, setIsScriptLoaded] = useState(false);
|
|
1976
|
+
const [vgsFieldState, setVgsFieldState] = useState(DEFAULT_FIELD_STATE);
|
|
1977
|
+
const formRef = useRef(null);
|
|
1978
|
+
const onSuccessRef = useRef(null);
|
|
1979
|
+
const onErrorRef = useRef(null);
|
|
1980
|
+
useEffect(() => {
|
|
1981
|
+
if (typeof window === "undefined") return;
|
|
1982
|
+
if (getVGSCollect()) {
|
|
1983
|
+
const timeoutId = window.setTimeout(() => {
|
|
1984
|
+
setIsScriptLoaded(true);
|
|
1985
|
+
}, 0);
|
|
1986
|
+
return () => window.clearTimeout(timeoutId);
|
|
1987
|
+
}
|
|
1988
|
+
if (isScriptLoaded) return;
|
|
1989
|
+
const script = document.createElement("script");
|
|
1990
|
+
script.src = "https://js.verygoodvault.com/vgs-collect/3.3.0/vgs-collect.js";
|
|
1991
|
+
script.async = true;
|
|
1992
|
+
script.onload = () => setIsScriptLoaded(true);
|
|
1993
|
+
script.onerror = () => onErrorRef.current?.("Failed to load payment form");
|
|
1994
|
+
document.head.appendChild(script);
|
|
1995
|
+
}, [isScriptLoaded]);
|
|
1996
|
+
const updateFieldState = useCallback((state) => {
|
|
1997
|
+
if (!state) return;
|
|
1998
|
+
setVgsFieldState((prev) => {
|
|
1999
|
+
const newState = { ...prev };
|
|
2000
|
+
let hasChanges = false;
|
|
2001
|
+
Object.keys(state).forEach((key) => {
|
|
2002
|
+
const field = state[key];
|
|
2003
|
+
if (!field) return;
|
|
2004
|
+
const next = {
|
|
2005
|
+
isFocused: !!field.isFocused,
|
|
2006
|
+
isValid: !!field.isValid,
|
|
2007
|
+
isEmpty: !!field.isEmpty
|
|
2008
|
+
};
|
|
2009
|
+
if (!newState[key] || JSON.stringify(newState[key]) !== JSON.stringify(next)) {
|
|
2010
|
+
newState[key] = next;
|
|
2011
|
+
hasChanges = true;
|
|
2012
|
+
}
|
|
2013
|
+
});
|
|
2014
|
+
return hasChanges ? newState : prev;
|
|
2015
|
+
});
|
|
2016
|
+
}, []);
|
|
2017
|
+
const resetVgs = useCallback(() => {
|
|
2018
|
+
if (formRef.current) {
|
|
2019
|
+
try {
|
|
2020
|
+
formRef.current.unmount();
|
|
2021
|
+
} catch (e) {
|
|
2022
|
+
console.warn("VGS unmount error", e);
|
|
2023
|
+
}
|
|
2024
|
+
formRef.current = null;
|
|
2025
|
+
}
|
|
2026
|
+
setIsFormReady(false);
|
|
2027
|
+
setVgsFieldState({ ...DEFAULT_FIELD_STATE });
|
|
2028
|
+
}, []);
|
|
2029
|
+
const initializeForm = useCallback(async (credentials) => {
|
|
2030
|
+
if (!isScriptLoaded) return;
|
|
2031
|
+
const VGSCollect = getVGSCollect();
|
|
2032
|
+
if (!VGSCollect) {
|
|
2033
|
+
onErrorRef.current?.("Payment script not loaded");
|
|
2034
|
+
return;
|
|
2035
|
+
}
|
|
2036
|
+
try {
|
|
2037
|
+
setIsLoading(true);
|
|
2038
|
+
const vgsEnvironment = credentials.vault.environment === "sandbox" ? "sandbox" : "live-eu-1";
|
|
2039
|
+
const form = VGSCollect.create(credentials.vault.vault_id, vgsEnvironment, (state) => updateFieldState(state));
|
|
2040
|
+
if (credentials.vault.route_id) form.setRouteId(credentials.vault.route_id);
|
|
2041
|
+
formRef.current = form;
|
|
2042
|
+
let retries = 0;
|
|
2043
|
+
const maxRetries = 20;
|
|
2044
|
+
const retryDelay = 200;
|
|
2045
|
+
const waitForDom = async () => {
|
|
2046
|
+
if ([
|
|
2047
|
+
"vgs-card-number",
|
|
2048
|
+
"vgs-expiration-date",
|
|
2049
|
+
"vgs-cvc",
|
|
2050
|
+
"vgs-card-holder"
|
|
2051
|
+
].every((id) => {
|
|
2052
|
+
const el = document.getElementById(id);
|
|
2053
|
+
return el && el.isConnected;
|
|
2054
|
+
})) return true;
|
|
2055
|
+
if (retries >= maxRetries) return false;
|
|
2056
|
+
retries++;
|
|
2057
|
+
await new Promise((resolve) => setTimeout(resolve, retryDelay));
|
|
2058
|
+
return waitForDom();
|
|
2059
|
+
};
|
|
2060
|
+
if (!await waitForDom()) throw new Error("Payment form elements not ready");
|
|
2061
|
+
const css = {
|
|
2062
|
+
fontSize: "14px",
|
|
2063
|
+
fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif",
|
|
2064
|
+
color: "#1f2937",
|
|
2065
|
+
paddingTop: "0px",
|
|
2066
|
+
paddingBottom: "0px",
|
|
2067
|
+
paddingLeft: "0px",
|
|
2068
|
+
paddingRight: "0px",
|
|
2069
|
+
boxSizing: "border-box",
|
|
2070
|
+
lineHeight: "38px",
|
|
2071
|
+
height: "100%",
|
|
2072
|
+
width: "100%",
|
|
2073
|
+
"&::placeholder": {
|
|
2074
|
+
color: "#9ca3af",
|
|
2075
|
+
opacity: 1
|
|
2076
|
+
},
|
|
2077
|
+
"&:focus": { outline: "none" }
|
|
2078
|
+
};
|
|
2079
|
+
form.field("#vgs-card-number", {
|
|
2080
|
+
type: "card-number",
|
|
2081
|
+
name: "card_number",
|
|
2082
|
+
placeholder: "0000 0000 0000 0000",
|
|
2083
|
+
showCardIcon: true,
|
|
2084
|
+
css: {
|
|
2085
|
+
...css,
|
|
2086
|
+
paddingRight: "40px"
|
|
2087
|
+
},
|
|
2088
|
+
autoComplete: "cc-number",
|
|
2089
|
+
validations: ["required", "validCardNumber"]
|
|
2090
|
+
});
|
|
2091
|
+
form.field("#vgs-expiration-date", {
|
|
2092
|
+
type: "card-expiration-date",
|
|
2093
|
+
name: "card_exp",
|
|
2094
|
+
yearLength: 2,
|
|
2095
|
+
placeholder: "MM / YY",
|
|
2096
|
+
css,
|
|
2097
|
+
autoComplete: "cc-exp",
|
|
2098
|
+
validations: ["required", "validCardExpirationDate"]
|
|
2099
|
+
});
|
|
2100
|
+
form.field("#vgs-cvc", {
|
|
2101
|
+
type: "card-security-code",
|
|
2102
|
+
name: "card_cvc",
|
|
2103
|
+
placeholder: "123",
|
|
2104
|
+
css,
|
|
2105
|
+
autoComplete: "cc-csc",
|
|
2106
|
+
validations: ["required", "validCardSecurityCode"]
|
|
2107
|
+
});
|
|
2108
|
+
form.field("#vgs-card-holder", {
|
|
2109
|
+
type: "text",
|
|
2110
|
+
name: "card_holder",
|
|
2111
|
+
placeholder: "Full Name",
|
|
2112
|
+
css,
|
|
2113
|
+
autoComplete: "cc-name",
|
|
2114
|
+
validations: ["required"]
|
|
2115
|
+
});
|
|
2116
|
+
setIsFormReady(true);
|
|
2117
|
+
} catch (error) {
|
|
2118
|
+
console.error("Failed to initialize VGS:", error);
|
|
2119
|
+
onErrorRef.current?.("Failed to initialize payment form");
|
|
2120
|
+
} finally {
|
|
2121
|
+
setIsLoading(false);
|
|
2122
|
+
}
|
|
2123
|
+
}, [isScriptLoaded, updateFieldState]);
|
|
2124
|
+
const submitCard = useCallback(() => {
|
|
2125
|
+
if (!formRef.current) {
|
|
2126
|
+
onErrorRef.current?.("Form not initialized");
|
|
2127
|
+
return;
|
|
2128
|
+
}
|
|
2129
|
+
formRef.current.submit(`/post`, {}, (status, response) => {
|
|
2130
|
+
if (status >= 200 && status < 400) onSuccessRef.current?.(response);
|
|
2131
|
+
else onErrorRef.current?.("Payment failed");
|
|
2132
|
+
}, (errors) => {
|
|
2133
|
+
const allErrors = Object.values(errors).flat().filter((msg) => typeof msg === "string" && msg.trim().length > 0 && msg !== "Required");
|
|
2134
|
+
const uniqueErrors = Array.from(new Set(allErrors));
|
|
2135
|
+
let errorMsg = "Please verify your payment details.";
|
|
2136
|
+
if (uniqueErrors.length > 0) errorMsg = uniqueErrors.join(", ");
|
|
2137
|
+
else if (Object.values(errors).flat().length > 0) errorMsg = "Please fill in all required fields.";
|
|
2138
|
+
onErrorRef.current?.(errorMsg);
|
|
2139
|
+
});
|
|
2140
|
+
}, []);
|
|
2141
|
+
useEffect(() => {
|
|
2142
|
+
return () => {
|
|
2143
|
+
if (formRef.current) {
|
|
2144
|
+
try {
|
|
2145
|
+
formRef.current.unmount();
|
|
2146
|
+
} catch (e) {
|
|
2147
|
+
console.warn("VGS unmount error", e);
|
|
2148
|
+
}
|
|
2149
|
+
formRef.current = null;
|
|
2150
|
+
}
|
|
2151
|
+
};
|
|
2152
|
+
}, []);
|
|
2153
|
+
return {
|
|
2154
|
+
isFormReady,
|
|
2155
|
+
isLoading,
|
|
2156
|
+
isScriptLoaded,
|
|
2157
|
+
initializeForm,
|
|
2158
|
+
submitCard,
|
|
2159
|
+
vgsFieldState,
|
|
2160
|
+
resetVgs,
|
|
2161
|
+
onSuccessRef,
|
|
2162
|
+
onErrorRef
|
|
2163
|
+
};
|
|
2164
|
+
}
|
|
2165
|
+
//#endregion
|
|
2166
|
+
//#region ../../fluid-pay/ui/src/components/CreditCardFormDialog.tsx
|
|
2167
|
+
const billingAddressSchema = z.object({
|
|
2168
|
+
name: z.string().min(1, "Name is required"),
|
|
2169
|
+
address1: z.string().min(1, "Address line 1 is required"),
|
|
2170
|
+
address2: z.string().optional().nullable(),
|
|
2171
|
+
city: z.string().min(1, "City is required"),
|
|
2172
|
+
state: z.string().min(1, "State is required"),
|
|
2173
|
+
zip: z.string().min(1, "Zip code is required"),
|
|
2174
|
+
country_code: z.string().min(1, "Country is required"),
|
|
2175
|
+
set_as_default: z.boolean()
|
|
2176
|
+
});
|
|
2177
|
+
function VgsInputWrapper({ id, fieldState, className }) {
|
|
2178
|
+
const isInvalid = fieldState?.isValid === false && !fieldState?.isFocused && !fieldState?.isEmpty;
|
|
2179
|
+
const isFocused = fieldState?.isFocused;
|
|
2180
|
+
return /* @__PURE__ */ jsx("div", {
|
|
2181
|
+
className: "w-full",
|
|
2182
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
2183
|
+
id,
|
|
2184
|
+
className: cn("relative flex h-10 w-full items-center rounded-md border border-gray-300 bg-white px-3 shadow-sm transition-all duration-200 ease-in-out", "[&_iframe]:block! [&_iframe]:h-full! [&_iframe]:w-full!", isFocused && "border-blue-600 ring-1 ring-blue-600", isInvalid && "border-red-500 ring-1 ring-red-500", className)
|
|
2185
|
+
})
|
|
2186
|
+
});
|
|
2187
|
+
}
|
|
2188
|
+
function VgsCardForm({ isLoading, isFormReady, vgsFieldState, networkError, t }) {
|
|
2189
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
2190
|
+
className: "space-y-4",
|
|
2191
|
+
"aria-label": "Credit card form",
|
|
2192
|
+
children: [
|
|
2193
|
+
/* @__PURE__ */ jsx(VgsInputWrapper, {
|
|
2194
|
+
id: "vgs-card-number",
|
|
2195
|
+
fieldState: vgsFieldState["card_number"]
|
|
2196
|
+
}),
|
|
2197
|
+
/* @__PURE__ */ jsxs("div", {
|
|
2198
|
+
className: "flex gap-3",
|
|
2199
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
2200
|
+
className: "flex-1",
|
|
2201
|
+
children: /* @__PURE__ */ jsx(VgsInputWrapper, {
|
|
2202
|
+
id: "vgs-expiration-date",
|
|
2203
|
+
fieldState: vgsFieldState["card_exp"]
|
|
2204
|
+
})
|
|
2205
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
2206
|
+
className: "flex-1",
|
|
2207
|
+
children: /* @__PURE__ */ jsx(VgsInputWrapper, {
|
|
2208
|
+
id: "vgs-cvc",
|
|
2209
|
+
fieldState: vgsFieldState["card_cvc"]
|
|
2210
|
+
})
|
|
2211
|
+
})]
|
|
2212
|
+
}),
|
|
2213
|
+
/* @__PURE__ */ jsx(VgsInputWrapper, {
|
|
2214
|
+
id: "vgs-card-holder",
|
|
2215
|
+
fieldState: vgsFieldState["card_holder"]
|
|
2216
|
+
}),
|
|
2217
|
+
networkError && networkError.trim().length > 0 && /* @__PURE__ */ jsx("div", {
|
|
2218
|
+
className: "rounded-md bg-red-50 p-3 text-sm text-red-600",
|
|
2219
|
+
children: networkError
|
|
2220
|
+
})
|
|
2221
|
+
]
|
|
2222
|
+
});
|
|
2223
|
+
}
|
|
2224
|
+
function CreditCardFormDialog({ isOpen, onClose, onSubmit, isSubmitting, countries = [], error, jwt, client, renderAddressAutocomplete, t }) {
|
|
2225
|
+
const [cardError, setCardError] = useState(void 0);
|
|
2226
|
+
const [isVgsSubmitting, setIsVgsSubmitting] = useState(false);
|
|
2227
|
+
const { isFormReady, isLoading: isVgsLoading, isScriptLoaded, initializeForm, submitCard, vgsFieldState, resetVgs, onSuccessRef, onErrorRef } = useVgsCollect();
|
|
2228
|
+
const { control, handleSubmit, reset, setValue } = useForm({
|
|
2229
|
+
resolver: zodResolver(billingAddressSchema),
|
|
2230
|
+
defaultValues: {
|
|
2231
|
+
name: "",
|
|
2232
|
+
address1: "",
|
|
2233
|
+
address2: "",
|
|
2234
|
+
city: "",
|
|
2235
|
+
state: "",
|
|
2236
|
+
zip: "",
|
|
2237
|
+
country_code: "US",
|
|
2238
|
+
set_as_default: false
|
|
2239
|
+
}
|
|
2240
|
+
});
|
|
2241
|
+
const billingCountry = useWatch({
|
|
2242
|
+
control,
|
|
2243
|
+
name: "country_code"
|
|
2244
|
+
});
|
|
2245
|
+
const setAsDefault = useWatch({
|
|
2246
|
+
control,
|
|
2247
|
+
name: "set_as_default"
|
|
2248
|
+
});
|
|
2249
|
+
const { stateOptions, config, handleCountryChange } = useCountryStates();
|
|
2250
|
+
const countrySelectOptions = [...countries].map((country) => ({
|
|
2251
|
+
name: country.name,
|
|
2252
|
+
value: country.iso
|
|
2253
|
+
})).sort((a, b) => {
|
|
2254
|
+
if (a.value === billingCountry) return -1;
|
|
2255
|
+
if (b.value === billingCountry) return 1;
|
|
2256
|
+
return a.name.localeCompare(b.name);
|
|
2257
|
+
});
|
|
2258
|
+
const stateSelectOptions = stateOptions.map((state) => ({
|
|
2259
|
+
name: state.name,
|
|
2260
|
+
value: state.isoCode
|
|
2261
|
+
}));
|
|
2262
|
+
useEffect(() => {
|
|
2263
|
+
handleCountryChange(billingCountry);
|
|
2264
|
+
}, [billingCountry, handleCountryChange]);
|
|
2265
|
+
useEffect(() => {
|
|
2266
|
+
if (!isOpen || !isScriptLoaded || !jwt) return;
|
|
2267
|
+
let cancelled = false;
|
|
2268
|
+
const init = async () => {
|
|
2269
|
+
try {
|
|
2270
|
+
const credentials = await fetchVaultCredentialsForPaymentAccount(client, jwt);
|
|
2271
|
+
if (!cancelled) await initializeForm(credentials);
|
|
2272
|
+
} catch (err) {
|
|
2273
|
+
console.error("Failed to fetch vault credentials:", err);
|
|
2274
|
+
if (!cancelled) setCardError("Failed to initialize payment form");
|
|
2275
|
+
}
|
|
2276
|
+
};
|
|
2277
|
+
init();
|
|
2278
|
+
return () => {
|
|
2279
|
+
cancelled = true;
|
|
2280
|
+
};
|
|
2281
|
+
}, [
|
|
2282
|
+
isOpen,
|
|
2283
|
+
isScriptLoaded,
|
|
2284
|
+
jwt,
|
|
2285
|
+
client,
|
|
2286
|
+
initializeForm
|
|
2287
|
+
]);
|
|
2288
|
+
const handleVgsSuccess = useCallback((response) => {
|
|
2289
|
+
const expValue = response?.card_exp;
|
|
2290
|
+
if (!expValue) {
|
|
2291
|
+
setCardError("Missing expiration date from payment form");
|
|
2292
|
+
setIsVgsSubmitting(false);
|
|
2293
|
+
return;
|
|
2294
|
+
}
|
|
2295
|
+
const [expMonth, expYearShort] = expValue.replace(/\s+/g, "").split("/");
|
|
2296
|
+
if (!expMonth || !expYearShort) {
|
|
2297
|
+
setCardError("Invalid expiration date format");
|
|
2298
|
+
setIsVgsSubmitting(false);
|
|
2299
|
+
return;
|
|
2300
|
+
}
|
|
2301
|
+
const expYear = expYearShort.length === 2 ? `20${expYearShort}` : expYearShort;
|
|
2302
|
+
const cardholderName = response?.card_holder?.trim();
|
|
2303
|
+
if (!cardholderName) {
|
|
2304
|
+
setCardError("Cardholder name is required");
|
|
2305
|
+
setIsVgsSubmitting(false);
|
|
2306
|
+
return;
|
|
2307
|
+
}
|
|
2308
|
+
handleSubmit((formData) => {
|
|
2309
|
+
onSubmit({
|
|
2310
|
+
type: "credit_card",
|
|
2311
|
+
country_code: formData.country_code,
|
|
2312
|
+
default_payment_method: formData.set_as_default,
|
|
2313
|
+
payment_method: {
|
|
2314
|
+
token: response.card_number,
|
|
2315
|
+
cvv_token: response.card_cvc,
|
|
2316
|
+
exp_month: expMonth,
|
|
2317
|
+
exp_year: expYear,
|
|
2318
|
+
card_holder: cardholderName,
|
|
2319
|
+
billing_zip: formData.zip
|
|
2320
|
+
},
|
|
2321
|
+
billing_address: {
|
|
2322
|
+
name: formData.name,
|
|
2323
|
+
address1: formData.address1,
|
|
2324
|
+
address2: formData.address2 ?? void 0,
|
|
2325
|
+
city: formData.city,
|
|
2326
|
+
state: formData.state,
|
|
2327
|
+
zip: formData.zip,
|
|
2328
|
+
country_code: formData.country_code
|
|
2329
|
+
}
|
|
2330
|
+
});
|
|
2331
|
+
setIsVgsSubmitting(false);
|
|
2332
|
+
})();
|
|
2333
|
+
}, [handleSubmit, onSubmit]);
|
|
2334
|
+
const handleVgsError = useCallback((err) => {
|
|
2335
|
+
setCardError(err);
|
|
2336
|
+
setIsVgsSubmitting(false);
|
|
2337
|
+
}, []);
|
|
2338
|
+
useEffect(() => {
|
|
2339
|
+
onSuccessRef.current = handleVgsSuccess;
|
|
2340
|
+
onErrorRef.current = handleVgsError;
|
|
2341
|
+
}, [
|
|
2342
|
+
handleVgsSuccess,
|
|
2343
|
+
handleVgsError,
|
|
2344
|
+
onSuccessRef,
|
|
2345
|
+
onErrorRef
|
|
2346
|
+
]);
|
|
2347
|
+
const handleClose = () => {
|
|
2348
|
+
resetVgs();
|
|
2349
|
+
reset();
|
|
2350
|
+
setCardError(void 0);
|
|
2351
|
+
setIsVgsSubmitting(false);
|
|
2352
|
+
onClose();
|
|
2353
|
+
};
|
|
2354
|
+
const handleFormSubmit = handleSubmit(() => {
|
|
2355
|
+
setIsVgsSubmitting(true);
|
|
2356
|
+
setCardError(void 0);
|
|
2357
|
+
submitCard();
|
|
2358
|
+
});
|
|
2359
|
+
const isBusy = isSubmitting || isVgsSubmitting;
|
|
2360
|
+
return /* @__PURE__ */ jsx(Dialog, {
|
|
2361
|
+
open: isOpen,
|
|
2362
|
+
onOpenChange: (open) => !open && handleClose(),
|
|
2363
|
+
children: /* @__PURE__ */ jsx(DialogContent, {
|
|
2364
|
+
className: "max-h-[90vh] max-w-md overflow-y-auto rounded p-0 md:max-w-xl",
|
|
2365
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
2366
|
+
className: "relative p-6",
|
|
2367
|
+
children: [
|
|
2368
|
+
(isVgsLoading || !isFormReady) && /* @__PURE__ */ jsx("div", {
|
|
2369
|
+
className: "absolute inset-0 z-10 flex items-center justify-center rounded bg-white/80 backdrop-blur-[1px]",
|
|
2370
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
2371
|
+
className: "flex items-center justify-center",
|
|
2372
|
+
children: [/* @__PURE__ */ jsx("div", { className: "mr-3 h-5 w-5 animate-spin rounded-full border-2 border-t-2 border-blue-600 border-t-transparent" }), /* @__PURE__ */ jsx("p", {
|
|
2373
|
+
className: "text-sm font-medium text-gray-600",
|
|
2374
|
+
children: t("securing")
|
|
2375
|
+
})]
|
|
2376
|
+
})
|
|
2377
|
+
}),
|
|
2378
|
+
/* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, {
|
|
2379
|
+
className: "text-lg font-medium",
|
|
2380
|
+
children: t("add_credit_card")
|
|
2381
|
+
}) }),
|
|
2382
|
+
/* @__PURE__ */ jsxs("div", {
|
|
2383
|
+
className: "space-y-4 pt-6",
|
|
2384
|
+
children: [/* @__PURE__ */ jsx(VgsCardForm, {
|
|
2385
|
+
isLoading: isVgsLoading,
|
|
2386
|
+
isFormReady,
|
|
2387
|
+
vgsFieldState,
|
|
2388
|
+
networkError: cardError ?? error,
|
|
2389
|
+
t
|
|
2390
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
2391
|
+
className: "space-y-3 pt-2",
|
|
2392
|
+
children: [
|
|
2393
|
+
/* @__PURE__ */ jsx("h3", {
|
|
2394
|
+
className: "text-sm font-medium text-gray-500",
|
|
2395
|
+
children: t("billing_address")
|
|
2396
|
+
}),
|
|
2397
|
+
/* @__PURE__ */ jsx(FormSelectField, {
|
|
2398
|
+
control,
|
|
2399
|
+
name: "country_code",
|
|
2400
|
+
placeholder: t("country"),
|
|
2401
|
+
options: countrySelectOptions,
|
|
2402
|
+
disabled: isBusy
|
|
2403
|
+
}),
|
|
2404
|
+
/* @__PURE__ */ jsx(FormTextField, {
|
|
2405
|
+
control,
|
|
2406
|
+
name: "name",
|
|
2407
|
+
placeholder: t("name"),
|
|
2408
|
+
disabled: isBusy
|
|
2409
|
+
}),
|
|
2410
|
+
renderAddressAutocomplete ? renderAddressAutocomplete({
|
|
2411
|
+
control,
|
|
2412
|
+
setValue,
|
|
2413
|
+
countryCode: billingCountry
|
|
2414
|
+
}) : /* @__PURE__ */ jsx(FormTextField, {
|
|
2415
|
+
control,
|
|
2416
|
+
name: "address1",
|
|
2417
|
+
placeholder: t("address_line_1"),
|
|
2418
|
+
disabled: isBusy
|
|
2419
|
+
}),
|
|
2420
|
+
/* @__PURE__ */ jsx(FormTextField, {
|
|
2421
|
+
control,
|
|
2422
|
+
name: "address2",
|
|
2423
|
+
placeholder: t("address_line_2"),
|
|
2424
|
+
disabled: isBusy
|
|
2425
|
+
}),
|
|
2426
|
+
/* @__PURE__ */ jsxs("div", {
|
|
2427
|
+
className: "flex gap-3",
|
|
2428
|
+
children: [
|
|
2429
|
+
/* @__PURE__ */ jsx(FormTextField, {
|
|
2430
|
+
control,
|
|
2431
|
+
name: "city",
|
|
2432
|
+
placeholder: t("city"),
|
|
2433
|
+
containerClassName: "flex-1",
|
|
2434
|
+
disabled: isBusy
|
|
2435
|
+
}),
|
|
2436
|
+
/* @__PURE__ */ jsx(FormSelectField, {
|
|
2437
|
+
control,
|
|
2438
|
+
name: "state",
|
|
2439
|
+
placeholder: config?.regionLabel ? t(config.regionLabel) : t("select_state"),
|
|
2440
|
+
options: stateSelectOptions,
|
|
2441
|
+
containerClassName: "flex-1",
|
|
2442
|
+
disabled: isBusy
|
|
2443
|
+
}),
|
|
2444
|
+
/* @__PURE__ */ jsx(FormTextField, {
|
|
2445
|
+
control,
|
|
2446
|
+
name: "zip",
|
|
2447
|
+
placeholder: config?.postalLabel ? t(config.postalLabel) : t("zip_code"),
|
|
2448
|
+
containerClassName: "flex-1",
|
|
2449
|
+
disabled: isBusy
|
|
2450
|
+
})
|
|
2451
|
+
]
|
|
2452
|
+
})
|
|
2453
|
+
]
|
|
2454
|
+
})]
|
|
2455
|
+
}),
|
|
2456
|
+
/* @__PURE__ */ jsxs("div", {
|
|
2457
|
+
className: "mt-4 flex items-center justify-between",
|
|
2458
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
2459
|
+
className: "flex items-center space-x-2",
|
|
2460
|
+
children: [/* @__PURE__ */ jsx("input", {
|
|
2461
|
+
type: "checkbox",
|
|
2462
|
+
id: "set_as_default_cc",
|
|
2463
|
+
checked: setAsDefault,
|
|
2464
|
+
onChange: () => setValue("set_as_default", !setAsDefault),
|
|
2465
|
+
disabled: isBusy,
|
|
2466
|
+
className: "h-4 w-4"
|
|
2467
|
+
}), /* @__PURE__ */ jsx("label", {
|
|
2468
|
+
htmlFor: "set_as_default_cc",
|
|
2469
|
+
className: "text-sm",
|
|
2470
|
+
children: t("set_as_default_payment_method")
|
|
2471
|
+
})]
|
|
2472
|
+
}), /* @__PURE__ */ jsx(Button, {
|
|
2473
|
+
type: "submit",
|
|
2474
|
+
onClick: handleFormSubmit,
|
|
2475
|
+
disabled: isBusy,
|
|
2476
|
+
className: "rounded bg-gray-900 px-5 py-2.5 text-white hover:bg-gray-800",
|
|
2477
|
+
children: isBusy ? /* @__PURE__ */ jsx("div", { className: "h-5 w-5 animate-spin rounded-full border-4 border-t-4 border-white border-t-transparent" }) : t("save_card")
|
|
2478
|
+
})]
|
|
2479
|
+
})
|
|
2480
|
+
]
|
|
2481
|
+
})
|
|
2482
|
+
})
|
|
2483
|
+
});
|
|
2484
|
+
}
|
|
2485
|
+
//#endregion
|
|
2486
|
+
//#region src/screens/ProfileContentScreen.tsx
|
|
2487
|
+
const translations = {
|
|
2488
|
+
edit_profile: "Edit Profile",
|
|
2489
|
+
first_name: "First Name",
|
|
2490
|
+
last_name: "Last Name",
|
|
2491
|
+
phone_number: "Phone Number",
|
|
2492
|
+
language: "Language",
|
|
2493
|
+
first_name_is_required: "First name is required",
|
|
2494
|
+
last_name_is_required: "Last name is required",
|
|
2495
|
+
language_is_required: "Language is required",
|
|
2496
|
+
saving: "Saving...",
|
|
2497
|
+
save_changes: "Save Changes",
|
|
2498
|
+
select_an_option: "Select an option",
|
|
2499
|
+
points_history: "Points History",
|
|
2500
|
+
points_available: "Points Available",
|
|
2501
|
+
points_awarded: "Points Awarded",
|
|
2502
|
+
points_redeemed: "Points Redeemed",
|
|
2503
|
+
transaction: "Transaction",
|
|
2504
|
+
no_points_history_found: "No points history found",
|
|
2505
|
+
shipping_addresses: "Shipping Addresses",
|
|
2506
|
+
add_an_address: "Add an Address",
|
|
2507
|
+
delete_address: "Delete Address",
|
|
2508
|
+
delete_address_message: "Are you sure you want to delete this address? This action cannot be undone.",
|
|
2509
|
+
delete: "Delete",
|
|
2510
|
+
add_address: "Add Address",
|
|
2511
|
+
edit_address: "Edit Address",
|
|
2512
|
+
set_as_default_address: "Set as default address",
|
|
2513
|
+
save_address: "Save Address",
|
|
2514
|
+
card_number: "Card Number",
|
|
2515
|
+
expiration_date: "Expiration (MM / YY)",
|
|
2516
|
+
cvc: "CVC",
|
|
2517
|
+
cardholder_name: "Cardholder Name",
|
|
2518
|
+
add_credit_card: "Add Credit Card",
|
|
2519
|
+
save_card: "Save Card",
|
|
2520
|
+
securing: "Loading secure form...",
|
|
2521
|
+
payment_methods: "Payment Methods",
|
|
2522
|
+
add_payment_method: "Add Payment Method",
|
|
2523
|
+
delete_credit_card: "Delete Credit Card",
|
|
2524
|
+
delete_credit_card_message: "Are you sure you want to delete this payment method? This action cannot be undone.",
|
|
2525
|
+
edit_card: "Card Details",
|
|
2526
|
+
billing_address: "Billing Address",
|
|
2527
|
+
country: "Country",
|
|
2528
|
+
name: "Name",
|
|
2529
|
+
address_line_1: "Address Line 1",
|
|
2530
|
+
address_line_2: "Address Line 2",
|
|
2531
|
+
city: "City",
|
|
2532
|
+
state: "State",
|
|
2533
|
+
province: "Province",
|
|
2534
|
+
zip_code: "Zip Code",
|
|
2535
|
+
postal_code: "Postal Code",
|
|
2536
|
+
select_state: "Select state",
|
|
2537
|
+
set_as_default_payment_method: "Set as default payment method",
|
|
2538
|
+
cancel: "Cancel",
|
|
2539
|
+
save: "Save",
|
|
2540
|
+
close: "Close",
|
|
2541
|
+
edit: "Edit",
|
|
2542
|
+
default: "Default",
|
|
2543
|
+
card_expires: "Expires",
|
|
2544
|
+
no_billing_address: "No billing address on file",
|
|
2545
|
+
default_payment_method_updated: "Payment method updated",
|
|
2546
|
+
failed_to_set_default_payment_method: "Failed to update payment method"
|
|
2547
|
+
};
|
|
2548
|
+
function t(key) {
|
|
2549
|
+
if (translations[key]) return translations[key];
|
|
2550
|
+
return key.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
2551
|
+
}
|
|
2552
|
+
function adaptPointsLedger(entry) {
|
|
2553
|
+
return {
|
|
2554
|
+
id: entry.id,
|
|
2555
|
+
amount: entry.amount,
|
|
2556
|
+
company_id: 0,
|
|
2557
|
+
created_at: entry.created_at,
|
|
2558
|
+
customer_id: entry.customer_id,
|
|
2559
|
+
metadata: {
|
|
2560
|
+
transaction_type: entry.metadata?.transaction_type ?? void 0,
|
|
2561
|
+
source: entry.metadata?.source ?? void 0
|
|
2562
|
+
},
|
|
2563
|
+
total_balance: entry.total_balance ?? 0,
|
|
2564
|
+
updated_at: entry.created_at
|
|
2565
|
+
};
|
|
2566
|
+
}
|
|
2567
|
+
function ProfileContentScreen({ onToast, countryIso }) {
|
|
2568
|
+
const { token, user } = useFluidAuth();
|
|
2569
|
+
const client = useFluidPayClient();
|
|
2570
|
+
const sdkClient = useSdkClient();
|
|
2571
|
+
const queryClient = useQueryClient();
|
|
2572
|
+
const jwt = token ?? "";
|
|
2573
|
+
const userId = user?.id;
|
|
2574
|
+
const { data: accountData, isLoading: isLoadingAccount, isError: isAccountError } = useQuery({
|
|
2575
|
+
queryKey: ["fluidPayAccount", userId],
|
|
2576
|
+
queryFn: () => fetchCustomerAccount(client, jwt),
|
|
2577
|
+
enabled: !!jwt
|
|
2578
|
+
});
|
|
2579
|
+
const { data: addressesData, isLoading: isLoadingAddresses } = useQuery({
|
|
2580
|
+
queryKey: ["fluidPayAddresses", userId],
|
|
2581
|
+
queryFn: () => fetchCustomerAddresses(client, jwt),
|
|
2582
|
+
enabled: !!jwt
|
|
2583
|
+
});
|
|
2584
|
+
const { data: paymentMethodsData, isLoading: isLoadingPaymentMethods } = useQuery({
|
|
2585
|
+
queryKey: [
|
|
2586
|
+
"fluidPayPaymentMethods",
|
|
2587
|
+
userId,
|
|
2588
|
+
countryIso
|
|
2589
|
+
],
|
|
2590
|
+
queryFn: () => fetchCustomerPaymentMethods(client, jwt, countryIso),
|
|
2591
|
+
enabled: !!jwt
|
|
2592
|
+
});
|
|
2593
|
+
const { data: countriesData } = useQuery({
|
|
2594
|
+
queryKey: ["sdk-countries"],
|
|
2595
|
+
queryFn: () => sdkClient.get("/countries"),
|
|
2596
|
+
initialData: []
|
|
2597
|
+
});
|
|
2598
|
+
const customerId = accountData?.customer?.id;
|
|
2599
|
+
const { data: pointsLedgerData, isLoading: isLoadingPointsLedger } = useQuery({
|
|
2600
|
+
queryKey: ["customer-points-ledger", customerId],
|
|
2601
|
+
queryFn: () => sdkClient.get(`${API_VERSION}/customers/${customerId}/points_ledgers`),
|
|
2602
|
+
enabled: !!customerId
|
|
2603
|
+
});
|
|
2604
|
+
const updateCustomerMutation = useMutation({
|
|
2605
|
+
mutationFn: (data) => {
|
|
2606
|
+
const languageIso = adaptedLanguages?.find((l) => l.name === data.language)?.iso ?? "en";
|
|
2607
|
+
return updateCustomer(client, jwt, {
|
|
2608
|
+
first_name: data.first_name,
|
|
2609
|
+
last_name: data.last_name,
|
|
2610
|
+
phone: data.phone_number,
|
|
2611
|
+
language_iso: languageIso
|
|
2612
|
+
});
|
|
2613
|
+
},
|
|
2614
|
+
onSuccess: () => {
|
|
2615
|
+
queryClient.invalidateQueries({ queryKey: ["fluidPayAccount", userId] });
|
|
2616
|
+
onToast("Profile updated", "success");
|
|
2617
|
+
},
|
|
2618
|
+
onError: () => {
|
|
2619
|
+
onToast("Failed to update profile", "error");
|
|
2620
|
+
}
|
|
2621
|
+
});
|
|
2622
|
+
const deleteAddressMutation = useMutation({
|
|
2623
|
+
mutationFn: (addressId) => deleteCustomerAddress(client, jwt, addressId),
|
|
2624
|
+
onSuccess: () => {
|
|
2625
|
+
queryClient.invalidateQueries({ queryKey: ["fluidPayAddresses", userId] });
|
|
2626
|
+
}
|
|
2627
|
+
});
|
|
2628
|
+
const deletePaymentMethodMutation = useMutation({
|
|
2629
|
+
mutationFn: (paymentMethodId) => deleteCustomerPaymentMethod(client, jwt, paymentMethodId),
|
|
2630
|
+
onSuccess: () => {
|
|
2631
|
+
queryClient.invalidateQueries({ queryKey: [
|
|
2632
|
+
"fluidPayPaymentMethods",
|
|
2633
|
+
userId,
|
|
2634
|
+
countryIso
|
|
2635
|
+
] });
|
|
2636
|
+
}
|
|
2637
|
+
});
|
|
2638
|
+
const updatePaymentMethodMutation = useMutation({
|
|
2639
|
+
mutationFn: ({ paymentMethodId, data }) => updatePaymentMethod(client, jwt, paymentMethodId, {
|
|
2640
|
+
set_as_default: data.set_as_default,
|
|
2641
|
+
billing_address: data.billing_address
|
|
2642
|
+
}),
|
|
2643
|
+
onSuccess: () => {
|
|
2644
|
+
queryClient.invalidateQueries({ queryKey: [
|
|
2645
|
+
"fluidPayPaymentMethods",
|
|
2646
|
+
userId,
|
|
2647
|
+
countryIso
|
|
2648
|
+
] });
|
|
2649
|
+
}
|
|
2650
|
+
});
|
|
2651
|
+
const createAddressMutation = useMutation({
|
|
2652
|
+
mutationFn: (body) => createCustomerAddress(client, jwt, body),
|
|
2653
|
+
onSuccess: () => {
|
|
2654
|
+
queryClient.invalidateQueries({ queryKey: ["fluidPayAddresses", userId] });
|
|
2655
|
+
onToast("Address created", "success");
|
|
2656
|
+
},
|
|
2657
|
+
onError: () => {
|
|
2658
|
+
onToast("Failed to create address", "error");
|
|
2659
|
+
}
|
|
2660
|
+
});
|
|
2661
|
+
const updateAddressMutation = useMutation({
|
|
2662
|
+
mutationFn: ({ addressId, body }) => updateCustomerAddress(client, jwt, addressId, body),
|
|
2663
|
+
onSuccess: () => {
|
|
2664
|
+
queryClient.invalidateQueries({ queryKey: ["fluidPayAddresses", userId] });
|
|
2665
|
+
onToast("Address updated", "success");
|
|
2666
|
+
},
|
|
2667
|
+
onError: () => {
|
|
2668
|
+
onToast("Failed to update address", "error");
|
|
2669
|
+
}
|
|
2670
|
+
});
|
|
2671
|
+
const addCreditCardMutation = useMutation({
|
|
2672
|
+
mutationFn: (data) => addCreditCardToCustomer(client, jwt, data),
|
|
2673
|
+
onSuccess: () => {
|
|
2674
|
+
queryClient.invalidateQueries({ queryKey: [
|
|
2675
|
+
"fluidPayPaymentMethods",
|
|
2676
|
+
userId,
|
|
2677
|
+
countryIso
|
|
2678
|
+
] });
|
|
2679
|
+
onToast("Payment method added", "success");
|
|
2680
|
+
},
|
|
2681
|
+
onError: () => {
|
|
2682
|
+
onToast("Failed to add payment method", "error");
|
|
2683
|
+
}
|
|
2684
|
+
});
|
|
2685
|
+
const addresses = addressesData?.addresses ?? [];
|
|
2686
|
+
const paymentMethods = paymentMethodsData?.payment_methods ?? [];
|
|
2687
|
+
const adaptedPointsLedger = pointsLedgerData?.points_ledgers?.map(adaptPointsLedger) ?? [];
|
|
2688
|
+
const adaptedLanguages = [{
|
|
2689
|
+
id: 0,
|
|
2690
|
+
name: "English",
|
|
2691
|
+
iso: "en"
|
|
2692
|
+
}];
|
|
2693
|
+
const countryOptions = useMemo(() => [...countriesData].map((c) => ({
|
|
2694
|
+
iso: c.iso,
|
|
2695
|
+
name: c.name
|
|
2696
|
+
})).sort((a, b) => a.name.localeCompare(b.name)), [countriesData]);
|
|
2697
|
+
if (!token) return /* @__PURE__ */ jsx("div", {
|
|
2698
|
+
className: "px-4 py-8 sm:px-9",
|
|
2699
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
2700
|
+
className: "rounded-lg border p-4 text-center",
|
|
2701
|
+
children: "Login Required"
|
|
2702
|
+
})
|
|
2703
|
+
});
|
|
2704
|
+
if (isAccountError && !isLoadingAccount) return /* @__PURE__ */ jsx("div", {
|
|
2705
|
+
className: "px-4 py-8 sm:px-9",
|
|
2706
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
2707
|
+
className: "text-muted-foreground text-center text-sm",
|
|
2708
|
+
children: "Unable to load account data. Please try again later."
|
|
2709
|
+
})
|
|
2710
|
+
});
|
|
2711
|
+
if (isLoadingAccount || !accountData) return /* @__PURE__ */ jsx("div", {
|
|
2712
|
+
className: "px-4 pt-4 sm:px-9 md:pt-8",
|
|
2713
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
2714
|
+
className: "space-y-4",
|
|
2715
|
+
children: [
|
|
2716
|
+
/* @__PURE__ */ jsx("div", { className: "bg-muted h-16 animate-pulse rounded" }),
|
|
2717
|
+
/* @__PURE__ */ jsx("div", { className: "bg-muted h-32 animate-pulse rounded" }),
|
|
2718
|
+
/* @__PURE__ */ jsx("div", { className: "bg-muted h-32 animate-pulse rounded" })
|
|
2719
|
+
]
|
|
2720
|
+
})
|
|
2721
|
+
});
|
|
2722
|
+
return /* @__PURE__ */ jsx("div", {
|
|
2723
|
+
className: "px-4 pt-4 sm:px-9 md:pt-8",
|
|
2724
|
+
children: /* @__PURE__ */ jsx(ProfileUIProvider, {
|
|
2725
|
+
t,
|
|
2726
|
+
children: /* @__PURE__ */ jsx(Profile, {
|
|
2727
|
+
customerAccount: accountData,
|
|
2728
|
+
languages: adaptedLanguages,
|
|
2729
|
+
onUpdateCustomer: async (data) => {
|
|
2730
|
+
await updateCustomerMutation.mutateAsync(data);
|
|
2731
|
+
},
|
|
2732
|
+
isUpdatingCustomer: updateCustomerMutation.isPending,
|
|
2733
|
+
rewardsPointsEnabled: adaptedPointsLedger.length > 0,
|
|
2734
|
+
pointsLedger: adaptedPointsLedger,
|
|
2735
|
+
isLoadingPointsLedger,
|
|
2736
|
+
addresses,
|
|
2737
|
+
isLoadingAddresses,
|
|
2738
|
+
onDeleteAddress: async (addressId) => {
|
|
2739
|
+
await deleteAddressMutation.mutateAsync(addressId);
|
|
2740
|
+
},
|
|
2741
|
+
isDeletingAddress: deleteAddressMutation.isPending,
|
|
2742
|
+
paymentMethods,
|
|
2743
|
+
isLoadingPaymentMethods,
|
|
2744
|
+
onDeletePaymentMethod: async (paymentMethodId) => {
|
|
2745
|
+
await deletePaymentMethodMutation.mutateAsync(paymentMethodId);
|
|
2746
|
+
},
|
|
2747
|
+
isDeletingPaymentMethod: deletePaymentMethodMutation.isPending,
|
|
2748
|
+
onUpdatePaymentMethod: async (paymentMethodId, data) => {
|
|
2749
|
+
await updatePaymentMethodMutation.mutateAsync({
|
|
2750
|
+
paymentMethodId,
|
|
2751
|
+
data
|
|
2752
|
+
});
|
|
2753
|
+
},
|
|
2754
|
+
isUpdatingPaymentMethod: updatePaymentMethodMutation.isPending,
|
|
2755
|
+
getBillingAddress: (pm) => pm.billing_address ?? null,
|
|
2756
|
+
countries: countryOptions,
|
|
2757
|
+
renderAddressDialog: ({ isOpen, onClose, selectedAddress }) => /* @__PURE__ */ jsx(AddressFormDialog, {
|
|
2758
|
+
isOpen,
|
|
2759
|
+
onClose,
|
|
2760
|
+
selectedAddress,
|
|
2761
|
+
t,
|
|
2762
|
+
onSubmit: async (formData) => {
|
|
2763
|
+
if (selectedAddress) await updateAddressMutation.mutateAsync({
|
|
2764
|
+
addressId: selectedAddress.id,
|
|
2765
|
+
body: formData
|
|
2766
|
+
});
|
|
2767
|
+
else await createAddressMutation.mutateAsync(formData);
|
|
2768
|
+
onClose();
|
|
2769
|
+
},
|
|
2770
|
+
isSubmitting: createAddressMutation.isPending || updateAddressMutation.isPending,
|
|
2771
|
+
countries: countryOptions,
|
|
2772
|
+
renderAddressAutocomplete: ({ control, setValue: _setValue }) => /* @__PURE__ */ jsx(PlainAddressInput, {
|
|
2773
|
+
control,
|
|
2774
|
+
name: "address1"
|
|
2775
|
+
})
|
|
2776
|
+
}),
|
|
2777
|
+
renderCreditCardDialog: ({ isOpen, onClose }) => /* @__PURE__ */ jsx(CreditCardFormDialog, {
|
|
2778
|
+
isOpen,
|
|
2779
|
+
onClose,
|
|
2780
|
+
t,
|
|
2781
|
+
onSubmit: async (data) => {
|
|
2782
|
+
await addCreditCardMutation.mutateAsync(data);
|
|
2783
|
+
onClose();
|
|
2784
|
+
},
|
|
2785
|
+
isSubmitting: addCreditCardMutation.isPending,
|
|
2786
|
+
countries: countryOptions,
|
|
2787
|
+
jwt,
|
|
2788
|
+
client,
|
|
2789
|
+
renderAddressAutocomplete: ({ control, setValue: _setValue }) => /* @__PURE__ */ jsx(PlainAddressInput, {
|
|
2790
|
+
control,
|
|
2791
|
+
name: "address1"
|
|
2792
|
+
})
|
|
2793
|
+
})
|
|
2794
|
+
})
|
|
2795
|
+
})
|
|
2796
|
+
});
|
|
2797
|
+
}
|
|
2798
|
+
/**
|
|
2799
|
+
* Plain text input fallback for address autocomplete.
|
|
2800
|
+
* The SDK doesn't have Google Places integration.
|
|
2801
|
+
*/
|
|
2802
|
+
function PlainAddressInput({ control, name }) {
|
|
2803
|
+
const { field } = useController({
|
|
2804
|
+
control,
|
|
2805
|
+
name
|
|
2806
|
+
});
|
|
2807
|
+
return /* @__PURE__ */ jsx("input", {
|
|
2808
|
+
type: "text",
|
|
2809
|
+
value: field.value ?? "",
|
|
2810
|
+
placeholder: "Address Line 1",
|
|
2811
|
+
className: "border-input bg-background ring-offset-background placeholder:text-muted-foreground focus-visible:ring-ring flex h-10 w-full rounded-md border px-3 py-2 text-sm file:border-0 file:bg-transparent file:text-sm file:font-medium focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50",
|
|
2812
|
+
onChange: field.onChange
|
|
2813
|
+
});
|
|
2814
|
+
}
|
|
2815
|
+
//#endregion
|
|
2816
|
+
//#region src/screens/ProfileScreen.tsx
|
|
2817
|
+
var ProfileScreen_exports = /* @__PURE__ */ __exportAll({
|
|
2818
|
+
ProfileScreen: () => ProfileScreen,
|
|
2819
|
+
profileScreenPropertySchema: () => profileScreenPropertySchema
|
|
2820
|
+
});
|
|
2821
|
+
function defaultToast(message, type) {
|
|
2822
|
+
if (type === "error" || type === "warning") console.warn("[Profile]", message);
|
|
2823
|
+
else console.info("[Profile]", message);
|
|
2824
|
+
}
|
|
2825
|
+
function ProfileScreen({ onToast, background, textColor, accentColor, padding, borderRadius, ...divProps }) {
|
|
2826
|
+
const { config } = useFluidContext();
|
|
2827
|
+
const effectiveToast = onToast ?? defaultToast;
|
|
2828
|
+
const countryIso = config.countryIso ?? "US";
|
|
2829
|
+
return /* @__PURE__ */ jsx("div", {
|
|
2830
|
+
...divProps,
|
|
2831
|
+
children: /* @__PURE__ */ jsx(ProfileContentScreen, {
|
|
2832
|
+
onToast: effectiveToast,
|
|
2833
|
+
countryIso
|
|
2834
|
+
})
|
|
2835
|
+
});
|
|
2836
|
+
}
|
|
2837
|
+
const profileScreenPropertySchema = {
|
|
2838
|
+
widgetType: "ProfileScreen",
|
|
2839
|
+
displayName: "Profile Screen",
|
|
2840
|
+
tabsConfig: [{
|
|
2841
|
+
id: "styling",
|
|
2842
|
+
label: "Styling"
|
|
2843
|
+
}],
|
|
2844
|
+
fields: []
|
|
2845
|
+
};
|
|
2846
|
+
//#endregion
|
|
2847
|
+
export { ProfileScreen_exports as n, profileScreenPropertySchema as r, ProfileScreen as t };
|
|
2848
|
+
|
|
2849
|
+
//# sourceMappingURL=ProfileScreen-B83tzedh.mjs.map
|