@pollar/react 0.11.4-rc.1 → 0.11.4-rc.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.css +193 -0
- package/dist/index.css.map +1 -1
- package/dist/index.d.mts +20 -4
- package/dist/index.d.ts +20 -4
- package/dist/index.js +954 -24
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +954 -25
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1038,7 +1038,7 @@ var PollarModalFooter = ({ shield = false }) => {
|
|
|
1038
1038
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-footer-name", children: "Pollar" }),
|
|
1039
1039
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-footer-version", children: [
|
|
1040
1040
|
"v",
|
|
1041
|
-
"0.11.4-rc.
|
|
1041
|
+
"0.11.4-rc.4"
|
|
1042
1042
|
] })
|
|
1043
1043
|
] })
|
|
1044
1044
|
] });
|
|
@@ -2079,7 +2079,8 @@ function KycModalTemplate({
|
|
|
2079
2079
|
kycStatus !== "approved" && kycStatus !== "rejected" && kycStatus !== "expired" && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-secondary", onClick: onDoneVerifying, children: "Check again" }),
|
|
2080
2080
|
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-primary", onClick: onClose, children: "Close" })
|
|
2081
2081
|
] })
|
|
2082
|
-
] })
|
|
2082
|
+
] }),
|
|
2083
|
+
/* @__PURE__ */ jsxRuntime.jsx(PollarModalFooter, {})
|
|
2083
2084
|
]
|
|
2084
2085
|
}
|
|
2085
2086
|
);
|
|
@@ -2089,7 +2090,15 @@ function newIdempotencyKey() {
|
|
|
2089
2090
|
if (c && typeof c.randomUUID === "function") return c.randomUUID();
|
|
2090
2091
|
return `kyc-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 12)}`;
|
|
2091
2092
|
}
|
|
2092
|
-
function KycModal({
|
|
2093
|
+
function KycModal({
|
|
2094
|
+
onClose,
|
|
2095
|
+
country = "MX",
|
|
2096
|
+
level = "basic",
|
|
2097
|
+
onApproved,
|
|
2098
|
+
corridorId,
|
|
2099
|
+
cardProviderId,
|
|
2100
|
+
providerId
|
|
2101
|
+
}) {
|
|
2093
2102
|
const { getClient, styles } = usePollar();
|
|
2094
2103
|
const [step, setStep] = react.useState("select_provider");
|
|
2095
2104
|
const [providers, setProviders] = react.useState([]);
|
|
@@ -2117,7 +2126,7 @@ function KycModal({ onClose, country = "MX", level = "basic", onApproved, corrid
|
|
|
2117
2126
|
else finish(read.decisionStatus === "expired" ? "expired" : read.status);
|
|
2118
2127
|
}
|
|
2119
2128
|
function readStatus(providerId2) {
|
|
2120
|
-
return corridorId ? client.getKycStatus(void 0, corridorId) : client.getKycStatus(providerId2);
|
|
2129
|
+
return corridorId || cardProviderId ? client.getKycStatus(void 0, corridorId, cardProviderId) : client.getKycStatus(providerId2);
|
|
2121
2130
|
}
|
|
2122
2131
|
const starting = react.useRef(false);
|
|
2123
2132
|
async function handleSelectProvider(provider, listed = true) {
|
|
@@ -2134,7 +2143,8 @@ function KycModal({ onClose, country = "MX", level = "basic", onApproved, corrid
|
|
|
2134
2143
|
provider.levels?.[0] ?? level,
|
|
2135
2144
|
listed ? country : void 0,
|
|
2136
2145
|
corridorId,
|
|
2137
|
-
key
|
|
2146
|
+
key,
|
|
2147
|
+
cardProviderId
|
|
2138
2148
|
);
|
|
2139
2149
|
if (result.alreadyApproved) {
|
|
2140
2150
|
finish("approved");
|
|
@@ -2163,7 +2173,7 @@ function KycModal({ onClose, country = "MX", level = "basic", onApproved, corrid
|
|
|
2163
2173
|
const loadProviders = react.useCallback(() => {
|
|
2164
2174
|
setIsLoading(true);
|
|
2165
2175
|
setError(null);
|
|
2166
|
-
return getClient().getKycProviders(country, corridorId).then((result) => {
|
|
2176
|
+
return getClient().getKycProviders(country, corridorId, cardProviderId).then((result) => {
|
|
2167
2177
|
setProviders(result.providers);
|
|
2168
2178
|
return result.providers;
|
|
2169
2179
|
}).catch((e) => {
|
|
@@ -2171,7 +2181,7 @@ function KycModal({ onClose, country = "MX", level = "basic", onApproved, corrid
|
|
|
2171
2181
|
setError(kycErrorMessage(e, "load"));
|
|
2172
2182
|
return [];
|
|
2173
2183
|
}).finally(() => setIsLoading(false));
|
|
2174
|
-
}, [getClient, country, corridorId]);
|
|
2184
|
+
}, [getClient, country, corridorId, cardProviderId]);
|
|
2175
2185
|
react.useEffect(() => {
|
|
2176
2186
|
void loadProviders().then((list) => {
|
|
2177
2187
|
if (!providerId || autoOpened.current) return;
|
|
@@ -2193,7 +2203,8 @@ function KycModal({ onClose, country = "MX", level = "basic", onApproved, corrid
|
|
|
2193
2203
|
const read = await client.pollKycDecision(selectedProvider.id, {
|
|
2194
2204
|
intervalMs: 3e3,
|
|
2195
2205
|
timeoutMs: 12e4,
|
|
2196
|
-
...corridorId ? { corridorId } : {}
|
|
2206
|
+
...corridorId ? { corridorId } : {},
|
|
2207
|
+
...cardProviderId ? { cardProviderId } : {}
|
|
2197
2208
|
});
|
|
2198
2209
|
finishWith(read);
|
|
2199
2210
|
} catch {
|
|
@@ -2515,7 +2526,8 @@ function RequirementFormModal({ formId, progress, onClose, onSubmitted }) {
|
|
|
2515
2526
|
] })
|
|
2516
2527
|
]
|
|
2517
2528
|
}
|
|
2518
|
-
)
|
|
2529
|
+
),
|
|
2530
|
+
/* @__PURE__ */ jsxRuntime.jsx(PollarModalFooter, {})
|
|
2519
2531
|
]
|
|
2520
2532
|
}
|
|
2521
2533
|
) });
|
|
@@ -3892,7 +3904,8 @@ function RampWidgetTemplate({
|
|
|
3892
3904
|
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-secondary", onClick: onClose, children: "Close" }),
|
|
3893
3905
|
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-primary", onClick: onRetry, children: "Try again" })
|
|
3894
3906
|
] })
|
|
3895
|
-
] })
|
|
3907
|
+
] }),
|
|
3908
|
+
/* @__PURE__ */ jsxRuntime.jsx(PollarModalFooter, {})
|
|
3896
3909
|
] });
|
|
3897
3910
|
}
|
|
3898
3911
|
|
|
@@ -3915,6 +3928,7 @@ var REGISTRY_COPY = {
|
|
|
3915
3928
|
notApplicable: "This check is only for Bolivian ID cards (CI). Your verified document is not one, so this route is not available.",
|
|
3916
3929
|
identityRequired: "Verify your identity first.",
|
|
3917
3930
|
nameMismatch: "Both surnames together must read as on your document: {full}.",
|
|
3931
|
+
rejected: "The registry did not confirm: {fields}. Check how they are written and try again.",
|
|
3918
3932
|
loadError: "Could not load your details. Please try again.",
|
|
3919
3933
|
submitError: "Could not check your details. Please try again.",
|
|
3920
3934
|
step: "Step {n} of {total}"
|
|
@@ -3936,6 +3950,7 @@ var REGISTRY_COPY = {
|
|
|
3936
3950
|
notApplicable: "Esta validaci\xF3n es solo para c\xE9dulas bolivianas (CI). Tu documento verificado no lo es, as\xED que esta ruta no est\xE1 disponible.",
|
|
3937
3951
|
identityRequired: "Primero verifica tu identidad.",
|
|
3938
3952
|
nameMismatch: "Los dos apellidos juntos deben leerse como en tu documento: {full}.",
|
|
3953
|
+
rejected: "El registro no confirm\xF3: {fields}. Revisa c\xF3mo est\xE1n escritos e intenta de nuevo.",
|
|
3939
3954
|
loadError: "No se pudieron cargar tus datos. Intenta de nuevo.",
|
|
3940
3955
|
submitError: "No se pudieron validar tus datos. Intenta de nuevo.",
|
|
3941
3956
|
step: "Paso {n} de {total}"
|
|
@@ -3951,9 +3966,15 @@ var REGISTRATION_COPY = {
|
|
|
3951
3966
|
close: "Close",
|
|
3952
3967
|
notReady: "Complete the previous steps first.",
|
|
3953
3968
|
missing: "Some details are missing: {fields}.",
|
|
3969
|
+
invalid: "Some details need to be corrected: {fields}.",
|
|
3970
|
+
fix: "Review my details",
|
|
3971
|
+
incomplete: "Your registration with the provider did not finish. Register again to complete it.",
|
|
3972
|
+
providerDown: "The provider is not responding right now. Please try again in a few minutes.",
|
|
3973
|
+
ipNotSupported: "The provider cannot accept your current connection (IPv6). Please try again from another network, for example Wi-Fi.",
|
|
3954
3974
|
loadError: "Could not load the registration. Please try again.",
|
|
3955
3975
|
submitError: "Could not register you. Please try again.",
|
|
3956
|
-
step: "Step {n} of {total}"
|
|
3976
|
+
step: "Step {n} of {total}",
|
|
3977
|
+
terms: "Read the provider's terms of service"
|
|
3957
3978
|
},
|
|
3958
3979
|
es: {
|
|
3959
3980
|
title: "Registro con el proveedor de pagos",
|
|
@@ -3964,9 +3985,15 @@ var REGISTRATION_COPY = {
|
|
|
3964
3985
|
close: "Cerrar",
|
|
3965
3986
|
notReady: "Primero completa los pasos anteriores.",
|
|
3966
3987
|
missing: "Faltan algunos datos: {fields}.",
|
|
3988
|
+
invalid: "Hay datos que corregir: {fields}.",
|
|
3989
|
+
fix: "Revisar mis datos",
|
|
3990
|
+
incomplete: "Tu registro con el proveedor no se complet\xF3. Reg\xEDstrate de nuevo para terminarlo.",
|
|
3991
|
+
providerDown: "El proveedor no responde en este momento. Intenta de nuevo en unos minutos.",
|
|
3992
|
+
ipNotSupported: "El proveedor no acepta tu conexi\xF3n actual (IPv6). Intenta desde otra red, por ejemplo Wi-Fi.",
|
|
3967
3993
|
loadError: "No se pudo cargar el registro. Intenta de nuevo.",
|
|
3968
3994
|
submitError: "No se pudo completar el registro. Intenta de nuevo.",
|
|
3969
|
-
step: "Paso {n} de {total}"
|
|
3995
|
+
step: "Paso {n} de {total}",
|
|
3996
|
+
terms: "Leer los t\xE9rminos de servicio del proveedor"
|
|
3970
3997
|
}
|
|
3971
3998
|
};
|
|
3972
3999
|
var SHARED_FIELD_LABELS = {
|
|
@@ -3981,7 +4008,24 @@ var SHARED_FIELD_LABELS = {
|
|
|
3981
4008
|
source_of_funds: "Source of funds",
|
|
3982
4009
|
destination_of_funds: "Use of funds",
|
|
3983
4010
|
income_level: "Income level",
|
|
3984
|
-
doc_provider_id: "SEGIP validation"
|
|
4011
|
+
doc_provider_id: "SEGIP validation",
|
|
4012
|
+
first_name: "First name",
|
|
4013
|
+
last_name: "Last name",
|
|
4014
|
+
email: "Email",
|
|
4015
|
+
birth_date: "Date of birth",
|
|
4016
|
+
document_country: "Document country",
|
|
4017
|
+
phone_country_code: "Phone country code",
|
|
4018
|
+
phone_number: "Phone number",
|
|
4019
|
+
occupation: "Occupation",
|
|
4020
|
+
annual_salary: "Annual income",
|
|
4021
|
+
account_purpose: "Purpose of the card",
|
|
4022
|
+
expected_monthly_volume: "Expected monthly spend",
|
|
4023
|
+
address_line1: "Street address",
|
|
4024
|
+
address_line2: "Address line 2",
|
|
4025
|
+
city: "City",
|
|
4026
|
+
region: "State or province",
|
|
4027
|
+
postal_code: "Postal code",
|
|
4028
|
+
country_code: "Country of residence"
|
|
3985
4029
|
},
|
|
3986
4030
|
es: {
|
|
3987
4031
|
name: "Nombres",
|
|
@@ -3994,7 +4038,24 @@ var SHARED_FIELD_LABELS = {
|
|
|
3994
4038
|
source_of_funds: "Origen de los fondos",
|
|
3995
4039
|
destination_of_funds: "Destino de los fondos",
|
|
3996
4040
|
income_level: "Nivel de ingresos",
|
|
3997
|
-
doc_provider_id: "Validaci\xF3n SEGIP"
|
|
4041
|
+
doc_provider_id: "Validaci\xF3n SEGIP",
|
|
4042
|
+
first_name: "Nombres",
|
|
4043
|
+
last_name: "Apellidos",
|
|
4044
|
+
email: "Correo electr\xF3nico",
|
|
4045
|
+
birth_date: "Fecha de nacimiento",
|
|
4046
|
+
document_country: "Pa\xEDs del documento",
|
|
4047
|
+
phone_country_code: "C\xF3digo de pa\xEDs del tel\xE9fono",
|
|
4048
|
+
phone_number: "Tel\xE9fono",
|
|
4049
|
+
occupation: "Ocupaci\xF3n",
|
|
4050
|
+
annual_salary: "Ingreso anual",
|
|
4051
|
+
account_purpose: "Uso de la tarjeta",
|
|
4052
|
+
expected_monthly_volume: "Gasto mensual esperado",
|
|
4053
|
+
address_line1: "Direcci\xF3n",
|
|
4054
|
+
address_line2: "Direcci\xF3n (l\xEDnea 2)",
|
|
4055
|
+
city: "Ciudad",
|
|
4056
|
+
region: "Estado o provincia",
|
|
4057
|
+
postal_code: "C\xF3digo postal",
|
|
4058
|
+
country_code: "Pa\xEDs de residencia"
|
|
3998
4059
|
}
|
|
3999
4060
|
};
|
|
4000
4061
|
var errorCode = (error) => error && typeof error === "object" && typeof error.code === "string" ? error.code : null;
|
|
@@ -4002,6 +4063,15 @@ function missingFieldsOf(error) {
|
|
|
4002
4063
|
const body = error && typeof error === "object" ? error.body : void 0;
|
|
4003
4064
|
return Array.isArray(body?.missing) ? body.missing.filter((item) => typeof item === "string") : [];
|
|
4004
4065
|
}
|
|
4066
|
+
function registrationFixOf(error) {
|
|
4067
|
+
const body = error && typeof error === "object" ? error.body : void 0;
|
|
4068
|
+
const strings = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
4069
|
+
const forms = Array.isArray(body?.forms) ? body.forms.flatMap((item) => {
|
|
4070
|
+
const form = item && typeof item === "object" ? item : {};
|
|
4071
|
+
return typeof form.formId === "string" ? [{ formId: form.formId, keys: strings(form.keys) }] : [];
|
|
4072
|
+
}) : [];
|
|
4073
|
+
return { invalid: strings(body?.invalid), forms };
|
|
4074
|
+
}
|
|
4005
4075
|
function RegistryCheckModal({ optionId, progress, onClose, onApproved }) {
|
|
4006
4076
|
const { getClient, styles } = usePollar();
|
|
4007
4077
|
const client = getClient();
|
|
@@ -4014,6 +4084,7 @@ function RegistryCheckModal({ optionId, progress, onClose, onApproved }) {
|
|
|
4014
4084
|
const [surname2, setSurname2] = react.useState("");
|
|
4015
4085
|
const [complement, setComplement] = react.useState("");
|
|
4016
4086
|
const [error, setError] = react.useState(null);
|
|
4087
|
+
const [rejected, setRejected] = react.useState([]);
|
|
4017
4088
|
const [review, setReview] = react.useState(false);
|
|
4018
4089
|
const [submitting, setSubmitting] = react.useState(false);
|
|
4019
4090
|
const mounted = react.useRef(true);
|
|
@@ -4029,6 +4100,7 @@ function RegistryCheckModal({ optionId, progress, onClose, onApproved }) {
|
|
|
4029
4100
|
if (loaded.status === "approved") return onApproved();
|
|
4030
4101
|
setCheck(loaded);
|
|
4031
4102
|
if (loaded.status === "pending") setReview(true);
|
|
4103
|
+
if (loaded.status === "rejected") showRejected(loaded.rejectedFields);
|
|
4032
4104
|
if (loaded.prefill.applies) {
|
|
4033
4105
|
setSurname1(loaded.prefill.surname1);
|
|
4034
4106
|
setSurname2(loaded.prefill.surname2 ?? "");
|
|
@@ -4040,10 +4112,21 @@ function RegistryCheckModal({ optionId, progress, onClose, onApproved }) {
|
|
|
4040
4112
|
});
|
|
4041
4113
|
}, [optionId]);
|
|
4042
4114
|
const prefill = check?.prefill.applies ? check.prefill : null;
|
|
4115
|
+
function showRejected(fields) {
|
|
4116
|
+
const labels = {
|
|
4117
|
+
surname1: copy.surname1,
|
|
4118
|
+
surname2: copy.surname2,
|
|
4119
|
+
complementNumber: copy.complement
|
|
4120
|
+
};
|
|
4121
|
+
const named = fields?.length ? fields : ["surname2"];
|
|
4122
|
+
setRejected(named);
|
|
4123
|
+
setError(copy.rejected.replace("{fields}", named.map((field) => labels[field] ?? field).join(", ")));
|
|
4124
|
+
}
|
|
4043
4125
|
async function submit() {
|
|
4044
4126
|
if (!prefill) return;
|
|
4045
4127
|
setSubmitting(true);
|
|
4046
4128
|
setError(null);
|
|
4129
|
+
setRejected([]);
|
|
4047
4130
|
try {
|
|
4048
4131
|
const result = await client.submitRegistryCheck(optionId, {
|
|
4049
4132
|
surname1: surname1.trim(),
|
|
@@ -4052,6 +4135,7 @@ function RegistryCheckModal({ optionId, progress, onClose, onApproved }) {
|
|
|
4052
4135
|
});
|
|
4053
4136
|
if (!mounted.current) return;
|
|
4054
4137
|
if (result.status === "approved") onApproved();
|
|
4138
|
+
else if (result.status === "rejected") showRejected(result.rejectedFields);
|
|
4055
4139
|
else setReview(true);
|
|
4056
4140
|
} catch (e) {
|
|
4057
4141
|
if (!mounted.current) return;
|
|
@@ -4116,6 +4200,7 @@ function RegistryCheckModal({ optionId, progress, onClose, onApproved }) {
|
|
|
4116
4200
|
value: surname1,
|
|
4117
4201
|
required: true,
|
|
4118
4202
|
disabled: submitting,
|
|
4203
|
+
"aria-invalid": rejected.includes("surname1") || void 0,
|
|
4119
4204
|
onChange: (e) => setSurname1(e.target.value)
|
|
4120
4205
|
}
|
|
4121
4206
|
)
|
|
@@ -4129,6 +4214,7 @@ function RegistryCheckModal({ optionId, progress, onClose, onApproved }) {
|
|
|
4129
4214
|
className: "pollar-input",
|
|
4130
4215
|
value: surname2,
|
|
4131
4216
|
disabled: submitting,
|
|
4217
|
+
"aria-invalid": rejected.includes("surname2") || void 0,
|
|
4132
4218
|
onChange: (e) => setSurname2(e.target.value)
|
|
4133
4219
|
}
|
|
4134
4220
|
)
|
|
@@ -4145,6 +4231,7 @@ function RegistryCheckModal({ optionId, progress, onClose, onApproved }) {
|
|
|
4145
4231
|
value: complement,
|
|
4146
4232
|
maxLength: 3,
|
|
4147
4233
|
disabled: submitting,
|
|
4234
|
+
"aria-invalid": rejected.includes("complementNumber") || void 0,
|
|
4148
4235
|
onChange: (e) => setComplement(e.target.value.toUpperCase().replace(/[^0-9A-Z]/g, ""))
|
|
4149
4236
|
}
|
|
4150
4237
|
)
|
|
@@ -4155,12 +4242,19 @@ function RegistryCheckModal({ optionId, progress, onClose, onApproved }) {
|
|
|
4155
4242
|
] })
|
|
4156
4243
|
]
|
|
4157
4244
|
}
|
|
4158
|
-
)
|
|
4245
|
+
),
|
|
4246
|
+
/* @__PURE__ */ jsxRuntime.jsx(PollarModalFooter, {})
|
|
4159
4247
|
]
|
|
4160
4248
|
}
|
|
4161
4249
|
) });
|
|
4162
4250
|
}
|
|
4163
|
-
function ProviderRegistrationModal({
|
|
4251
|
+
function ProviderRegistrationModal({
|
|
4252
|
+
corridorId,
|
|
4253
|
+
cardProviderId,
|
|
4254
|
+
progress,
|
|
4255
|
+
onClose,
|
|
4256
|
+
onRegistered
|
|
4257
|
+
}) {
|
|
4164
4258
|
const { getClient, styles } = usePollar();
|
|
4165
4259
|
const client = getClient();
|
|
4166
4260
|
const { theme, accentColor, styleOverrides, overlayStyle } = modalChrome(styles);
|
|
@@ -4169,9 +4263,12 @@ function ProviderRegistrationModal({ corridorId, progress, onClose, onRegistered
|
|
|
4169
4263
|
const copy = REGISTRATION_COPY[language];
|
|
4170
4264
|
const labels = SHARED_FIELD_LABELS[language];
|
|
4171
4265
|
const [registration, setRegistration] = react.useState(null);
|
|
4266
|
+
const [termsUrl, setTermsUrl] = react.useState(null);
|
|
4172
4267
|
const [consent, setConsent] = react.useState(false);
|
|
4173
4268
|
const [error, setError] = react.useState(null);
|
|
4174
4269
|
const [submitting, setSubmitting] = react.useState(false);
|
|
4270
|
+
const [fixForm, setFixForm] = react.useState(null);
|
|
4271
|
+
const [fixing, setFixing] = react.useState(null);
|
|
4175
4272
|
const mounted = react.useRef(true);
|
|
4176
4273
|
react.useEffect(() => {
|
|
4177
4274
|
mounted.current = true;
|
|
@@ -4180,34 +4277,59 @@ function ProviderRegistrationModal({ corridorId, progress, onClose, onRegistered
|
|
|
4180
4277
|
};
|
|
4181
4278
|
}, []);
|
|
4182
4279
|
react.useEffect(() => {
|
|
4183
|
-
client.
|
|
4280
|
+
const load = cardProviderId ? client.getCardProviderRegistration(cardProviderId).then((loaded) => {
|
|
4281
|
+
setTermsUrl(loaded.termsUrl);
|
|
4282
|
+
return loaded;
|
|
4283
|
+
}) : client.getProviderRegistration(corridorId ?? "");
|
|
4284
|
+
load.then((loaded) => {
|
|
4184
4285
|
if (!mounted.current) return;
|
|
4185
4286
|
if (loaded.status === "registered") onRegistered();
|
|
4186
4287
|
else setRegistration(loaded);
|
|
4187
4288
|
}).catch(() => mounted.current && setError(copy.loadError));
|
|
4188
|
-
}, [corridorId]);
|
|
4289
|
+
}, [corridorId, cardProviderId]);
|
|
4189
4290
|
async function submit() {
|
|
4190
4291
|
setSubmitting(true);
|
|
4191
4292
|
setError(null);
|
|
4293
|
+
setFixForm(null);
|
|
4192
4294
|
try {
|
|
4193
|
-
await client.
|
|
4295
|
+
if (cardProviderId) await client.submitCardProviderRegistration(cardProviderId);
|
|
4296
|
+
else await client.submitProviderRegistration(corridorId ?? "");
|
|
4194
4297
|
if (mounted.current) onRegistered();
|
|
4195
4298
|
} catch (e) {
|
|
4196
4299
|
if (!mounted.current) return;
|
|
4197
4300
|
const code = errorCode(e);
|
|
4198
4301
|
if (code === "KYC_REGISTRATION_MISSING_DATA") {
|
|
4302
|
+
const fix = registrationFixOf(e);
|
|
4303
|
+
const named = (keys) => keys.map((key) => labels[key] ?? key).join(", ");
|
|
4304
|
+
const missing = missingFieldsOf(e).filter((key) => !fix.invalid.includes(key));
|
|
4199
4305
|
setError(
|
|
4200
|
-
|
|
4201
|
-
"{fields}",
|
|
4202
|
-
|
|
4203
|
-
)
|
|
4306
|
+
[
|
|
4307
|
+
fix.invalid.length ? copy.invalid.replace("{fields}", named(fix.invalid)) : null,
|
|
4308
|
+
missing.length ? copy.missing.replace("{fields}", named(missing)) : null
|
|
4309
|
+
].filter(Boolean).join(" ")
|
|
4204
4310
|
);
|
|
4311
|
+
setFixForm(fix.forms[0]?.formId ?? null);
|
|
4205
4312
|
} else if (code === "KYC_REGISTRATION_STEPS_PENDING") setError(copy.notReady);
|
|
4313
|
+
else if (code === "SDK_CARDS_PROVIDER_ERROR") setError(copy.providerDown);
|
|
4314
|
+
else if (code === "SDK_CARDS_IP_NOT_SUPPORTED") setError(copy.ipNotSupported);
|
|
4206
4315
|
else setError(copy.submitError);
|
|
4207
4316
|
} finally {
|
|
4208
4317
|
if (mounted.current) setSubmitting(false);
|
|
4209
4318
|
}
|
|
4210
4319
|
}
|
|
4320
|
+
if (fixing) {
|
|
4321
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4322
|
+
RequirementFormModal,
|
|
4323
|
+
{
|
|
4324
|
+
formId: fixing,
|
|
4325
|
+
onClose: () => setFixing(null),
|
|
4326
|
+
onSubmitted: () => {
|
|
4327
|
+
setFixing(null);
|
|
4328
|
+
void submit();
|
|
4329
|
+
}
|
|
4330
|
+
}
|
|
4331
|
+
);
|
|
4332
|
+
}
|
|
4211
4333
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-overlay", style: overlayStyle, onClick: onClose, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4212
4334
|
"div",
|
|
4213
4335
|
{
|
|
@@ -4226,6 +4348,7 @@ function ProviderRegistrationModal({ corridorId, progress, onClose, onRegistered
|
|
|
4226
4348
|
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-modal-close", onClick: onClose, "aria-label": copy.close, children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M2 2l12 12M14 2L2 14", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }) })
|
|
4227
4349
|
] }),
|
|
4228
4350
|
error && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-form-error", role: "alert", children: error }),
|
|
4351
|
+
fixForm && !submitting && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-actions", children: /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-primary", onClick: () => setFixing(fixForm), children: copy.fix }) }),
|
|
4229
4352
|
!registration && !error && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-loading-block", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-spinner" }) }),
|
|
4230
4353
|
registration && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4231
4354
|
"form",
|
|
@@ -4237,8 +4360,10 @@ function ProviderRegistrationModal({ corridorId, progress, onClose, onRegistered
|
|
|
4237
4360
|
},
|
|
4238
4361
|
children: [
|
|
4239
4362
|
registration.ready ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
4363
|
+
registration.status === "incomplete" && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-form-error", role: "status", children: copy.incomplete }),
|
|
4240
4364
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-form-description", children: copy.intro }),
|
|
4241
4365
|
/* @__PURE__ */ jsxRuntime.jsx("ul", { className: "pollar-form-description", children: registration.fields.map((key) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: labels[key] ?? key }, key)) }),
|
|
4366
|
+
termsUrl && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-form-description", children: /* @__PURE__ */ jsxRuntime.jsx("a", { href: termsUrl, target: "_blank", rel: "noreferrer", children: copy.terms }) }),
|
|
4242
4367
|
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "pollar-form-choice", children: [
|
|
4243
4368
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4244
4369
|
"input",
|
|
@@ -4258,7 +4383,8 @@ function ProviderRegistrationModal({ corridorId, progress, onClose, onRegistered
|
|
|
4258
4383
|
] })
|
|
4259
4384
|
]
|
|
4260
4385
|
}
|
|
4261
|
-
)
|
|
4386
|
+
),
|
|
4387
|
+
/* @__PURE__ */ jsxRuntime.jsx(PollarModalFooter, {})
|
|
4262
4388
|
]
|
|
4263
4389
|
}
|
|
4264
4390
|
) });
|
|
@@ -6769,6 +6895,781 @@ function EarnModal({ onClose }) {
|
|
|
6769
6895
|
}
|
|
6770
6896
|
) });
|
|
6771
6897
|
}
|
|
6898
|
+
|
|
6899
|
+
// src/components/card-modal/card-kyc.ts
|
|
6900
|
+
var nonEmpty2 = (value) => typeof value === "string" && !!value.trim();
|
|
6901
|
+
function requiredCardStep(error) {
|
|
6902
|
+
if (!error || typeof error !== "object") return null;
|
|
6903
|
+
const { code, body } = error;
|
|
6904
|
+
if (code !== "SDK_CARDS_REQUIREMENT_REQUIRED" || !body || typeof body !== "object") return null;
|
|
6905
|
+
const { cardProviderId, requirementType, optionId } = body;
|
|
6906
|
+
if (!nonEmpty2(cardProviderId) || !nonEmpty2(optionId)) return null;
|
|
6907
|
+
if (requirementType === "KYC" || requirementType === "FORM" || requirementType === "REGISTRY_CHECK" || requirementType === "PROVIDER_REGISTRATION") {
|
|
6908
|
+
return { cardProviderId, type: requirementType, optionId };
|
|
6909
|
+
}
|
|
6910
|
+
return null;
|
|
6911
|
+
}
|
|
6912
|
+
function pendingFromRequirement(cardProviderId, next) {
|
|
6913
|
+
return {
|
|
6914
|
+
cardProviderId,
|
|
6915
|
+
type: next.type,
|
|
6916
|
+
optionId: next.optionId,
|
|
6917
|
+
progress: { position: next.completed + 1, total: next.total }
|
|
6918
|
+
};
|
|
6919
|
+
}
|
|
6920
|
+
function blockedStepMessage(next) {
|
|
6921
|
+
if (next.type === "REGISTRY_CHECK" && next.status === "pending") return "Your details are under review.";
|
|
6922
|
+
if (next.type !== "KYC") return null;
|
|
6923
|
+
if (next.status === "pending" && next.reviewReason) return "Your verification is under review.";
|
|
6924
|
+
if (next.status === "rejected") return "Your verification was not approved.";
|
|
6925
|
+
return null;
|
|
6926
|
+
}
|
|
6927
|
+
function cardStage(holder, requirements) {
|
|
6928
|
+
if (holder === void 0 || requirements === void 0) return null;
|
|
6929
|
+
if (holder === null || holder.kycStatus === "NOT_STARTED" && requirements?.next) return "steps";
|
|
6930
|
+
if (holder.kycStatus !== "NOT_STARTED") return null;
|
|
6931
|
+
return requirements?.steps.some((step) => step.type === "PROVIDER_REGISTRATION") ? "steps" : "provider-form";
|
|
6932
|
+
}
|
|
6933
|
+
var KYC_POLL_MS = 5e3;
|
|
6934
|
+
var REVEAL_MS = 3e4;
|
|
6935
|
+
var TX_LIMIT = 10;
|
|
6936
|
+
var FUNDING_POLL_MS = 5e3;
|
|
6937
|
+
var FUNDING_INFLIGHT = /* @__PURE__ */ new Set(["CREATED", "BURNED", "ATTESTED", "MINTED"]);
|
|
6938
|
+
var FUNDING_COPY = {
|
|
6939
|
+
CREATED: {
|
|
6940
|
+
title: "Confirming your payment",
|
|
6941
|
+
step: 1,
|
|
6942
|
+
hint: "Your USDC payment is being confirmed on Stellar. This takes a few seconds."
|
|
6943
|
+
},
|
|
6944
|
+
BURNED: {
|
|
6945
|
+
title: "Sending it to the card network",
|
|
6946
|
+
step: 2,
|
|
6947
|
+
hint: "Your USDC left Stellar. Circle is confirming the transfer, usually in about a minute."
|
|
6948
|
+
},
|
|
6949
|
+
ATTESTED: {
|
|
6950
|
+
title: "Crossing to the card network",
|
|
6951
|
+
step: 3,
|
|
6952
|
+
hint: "Transfer confirmed. Delivering the USDC to the card network."
|
|
6953
|
+
},
|
|
6954
|
+
MINTED: {
|
|
6955
|
+
title: "Arrived, crediting your card",
|
|
6956
|
+
step: 4,
|
|
6957
|
+
hint: "The USDC reached the card provider, which is adding it to your card. This can take a few minutes."
|
|
6958
|
+
},
|
|
6959
|
+
CREDITED: { title: "Credited to your card" },
|
|
6960
|
+
FAILED: { title: "Failed" }
|
|
6961
|
+
};
|
|
6962
|
+
var FUNDING_STEPS = 4;
|
|
6963
|
+
var INCOME_RANGES = [
|
|
6964
|
+
{ value: "0-1000", label: "Up to 1,000 USD" },
|
|
6965
|
+
{ value: "1000-5000", label: "1,000 to 5,000 USD" },
|
|
6966
|
+
{ value: "5000-10000", label: "5,000 to 10,000 USD" },
|
|
6967
|
+
{ value: "10000+", label: "More than 10,000 USD" }
|
|
6968
|
+
];
|
|
6969
|
+
var TX_LABELS = {
|
|
6970
|
+
deposit: "Deposit",
|
|
6971
|
+
transactionTransfer: "Bank deposit",
|
|
6972
|
+
spend: "Purchase",
|
|
6973
|
+
spend_adjustment: "Adjustment",
|
|
6974
|
+
fee: "Fee",
|
|
6975
|
+
fee_refund: "Fee refund",
|
|
6976
|
+
withdrawal: "Withdrawal",
|
|
6977
|
+
card_insurance: "Card issuance"
|
|
6978
|
+
};
|
|
6979
|
+
var KYC_PENDING_COPY = {
|
|
6980
|
+
PENDING: "Your information is being reviewed.",
|
|
6981
|
+
NEEDS_ACTION: "Finish verifying your identity with the card provider: you will be asked for a photo of your document and a selfie.",
|
|
6982
|
+
IN_REVIEW: "Your verification is under manual review. This can take a while."
|
|
6983
|
+
};
|
|
6984
|
+
var KYC_FINAL_COPY = {
|
|
6985
|
+
DENIED: "Your verification was denied.",
|
|
6986
|
+
LOCKED: "Your account is locked.",
|
|
6987
|
+
CANCELED: "Your verification was canceled."
|
|
6988
|
+
};
|
|
6989
|
+
var emptyKyc = {
|
|
6990
|
+
firstName: "",
|
|
6991
|
+
lastName: "",
|
|
6992
|
+
birthDate: "",
|
|
6993
|
+
nationalId: "",
|
|
6994
|
+
countryOfIssue: "",
|
|
6995
|
+
phoneCountryCode: "",
|
|
6996
|
+
phoneNumber: "",
|
|
6997
|
+
occupation: "",
|
|
6998
|
+
annualSalary: "1000-5000",
|
|
6999
|
+
accountPurpose: "Personal expenses",
|
|
7000
|
+
expectedMonthlyVolume: "1000-5000",
|
|
7001
|
+
address: { line1: "", line2: "", city: "", region: "", postalCode: "", countryCode: "" }
|
|
7002
|
+
};
|
|
7003
|
+
function usd(cents) {
|
|
7004
|
+
if (cents === null || cents === void 0) return "-";
|
|
7005
|
+
return (cents / 100).toLocaleString("en-US", { style: "currency", currency: "USD" });
|
|
7006
|
+
}
|
|
7007
|
+
function money(amount, currency) {
|
|
7008
|
+
const n = Number(amount);
|
|
7009
|
+
try {
|
|
7010
|
+
return n.toLocaleString("en-US", { style: "currency", currency });
|
|
7011
|
+
} catch {
|
|
7012
|
+
return `${n.toFixed(2)} ${currency}`;
|
|
7013
|
+
}
|
|
7014
|
+
}
|
|
7015
|
+
function groupPan(pan) {
|
|
7016
|
+
return pan.replace(/\s+/g, "").replace(/(.{4})/g, "$1 ").trim();
|
|
7017
|
+
}
|
|
7018
|
+
var CARD_ERROR_COPY = {
|
|
7019
|
+
SDK_CARDS_PROVIDER_ERROR: "The card provider is not responding right now. Please try again in a few minutes.",
|
|
7020
|
+
SDK_CARDS_IP_NOT_SUPPORTED: "The card provider cannot accept your current connection (IPv6). Please try again from another network, for example Wi-Fi."
|
|
7021
|
+
};
|
|
7022
|
+
function errorText(e, fallback) {
|
|
7023
|
+
if (core.isPollarApiError(e)) {
|
|
7024
|
+
const known = CARD_ERROR_COPY[e.code];
|
|
7025
|
+
if (known) return known;
|
|
7026
|
+
const providerMessage = e.body.providerMessage;
|
|
7027
|
+
if (typeof providerMessage === "string" && providerMessage) return providerMessage;
|
|
7028
|
+
const message = e.body.message;
|
|
7029
|
+
if (typeof message === "string" && message) return message;
|
|
7030
|
+
return e.code;
|
|
7031
|
+
}
|
|
7032
|
+
return e instanceof Error && e.message ? e.message : fallback;
|
|
7033
|
+
}
|
|
7034
|
+
function CardModal({ onClose }) {
|
|
7035
|
+
const { getClient, styles, wallet } = usePollar();
|
|
7036
|
+
const { theme, accentColor, styleOverrides, overlayStyle } = modalChrome(styles);
|
|
7037
|
+
const cssVars = buildModalCssVars(theme, accentColor, styleOverrides);
|
|
7038
|
+
const [providers, setProviders] = react.useState(null);
|
|
7039
|
+
const [holder, setHolder] = react.useState(void 0);
|
|
7040
|
+
const [requirements, setRequirements] = react.useState(void 0);
|
|
7041
|
+
const [pendingStep, setPendingStep] = react.useState(null);
|
|
7042
|
+
const stepAttempt = react.useRef(null);
|
|
7043
|
+
const [cards, setCards] = react.useState(null);
|
|
7044
|
+
const [balance, setBalance] = react.useState(null);
|
|
7045
|
+
const [transactions, setTransactions] = react.useState(null);
|
|
7046
|
+
const [deposit, setDeposit] = react.useState(null);
|
|
7047
|
+
const [fundings, setFundings] = react.useState(null);
|
|
7048
|
+
const [fundAmount, setFundAmount] = react.useState("");
|
|
7049
|
+
const [showManual, setShowManual] = react.useState(false);
|
|
7050
|
+
const [occupations, setOccupations] = react.useState([]);
|
|
7051
|
+
const [kyc, setKyc] = react.useState(emptyKyc);
|
|
7052
|
+
const [terms, setTerms] = react.useState(false);
|
|
7053
|
+
const [nickname, setNickname] = react.useState("");
|
|
7054
|
+
const [secrets, setSecrets] = react.useState(null);
|
|
7055
|
+
const [panel, setPanel] = react.useState("card");
|
|
7056
|
+
const [busy, setBusy] = react.useState(null);
|
|
7057
|
+
const [error, setError] = react.useState("");
|
|
7058
|
+
const revealTimer = react.useRef(null);
|
|
7059
|
+
const provider = providers?.[0] ?? null;
|
|
7060
|
+
const card = cards?.[0] ?? null;
|
|
7061
|
+
const loadHolder = react.useCallback(async () => {
|
|
7062
|
+
const h = await getClient().getCardHolder();
|
|
7063
|
+
setHolder(h);
|
|
7064
|
+
return h;
|
|
7065
|
+
}, [getClient]);
|
|
7066
|
+
const loadRequirements = react.useCallback(
|
|
7067
|
+
async (cardProviderId) => {
|
|
7068
|
+
try {
|
|
7069
|
+
const r = await getClient().getCardRequirements({ cardProviderId });
|
|
7070
|
+
setRequirements(r);
|
|
7071
|
+
return r;
|
|
7072
|
+
} catch {
|
|
7073
|
+
setRequirements(null);
|
|
7074
|
+
return null;
|
|
7075
|
+
}
|
|
7076
|
+
},
|
|
7077
|
+
[getClient]
|
|
7078
|
+
);
|
|
7079
|
+
const loadCardData = react.useCallback(async () => {
|
|
7080
|
+
const client = getClient();
|
|
7081
|
+
const list = await client.getCards();
|
|
7082
|
+
if (list.length === 0) {
|
|
7083
|
+
setCards(list);
|
|
7084
|
+
return;
|
|
7085
|
+
}
|
|
7086
|
+
const [b, tx] = await Promise.all([client.getCardBalance(), client.getCardTransactions({ limit: TX_LIMIT })]);
|
|
7087
|
+
setBalance(b);
|
|
7088
|
+
setTransactions(tx.transactions);
|
|
7089
|
+
setCards(list);
|
|
7090
|
+
}, [getClient]);
|
|
7091
|
+
react.useEffect(() => {
|
|
7092
|
+
let cancelled = false;
|
|
7093
|
+
(async () => {
|
|
7094
|
+
try {
|
|
7095
|
+
const ps = await getClient().getCardProviders();
|
|
7096
|
+
if (cancelled) return;
|
|
7097
|
+
setProviders(ps);
|
|
7098
|
+
if (ps.length === 0) return;
|
|
7099
|
+
const [h] = await Promise.all([loadHolder(), loadRequirements(ps[0].id)]);
|
|
7100
|
+
if (cancelled) return;
|
|
7101
|
+
if (h?.kycStatus === "APPROVED") await loadCardData();
|
|
7102
|
+
} catch (e) {
|
|
7103
|
+
if (!cancelled) {
|
|
7104
|
+
setProviders((cur) => cur ?? []);
|
|
7105
|
+
setError(errorText(e, "Could not load your card"));
|
|
7106
|
+
}
|
|
7107
|
+
}
|
|
7108
|
+
})();
|
|
7109
|
+
return () => {
|
|
7110
|
+
cancelled = true;
|
|
7111
|
+
};
|
|
7112
|
+
}, [getClient, loadHolder, loadRequirements, loadCardData]);
|
|
7113
|
+
const stage = cardStage(holder, requirements);
|
|
7114
|
+
react.useEffect(() => {
|
|
7115
|
+
if (stage !== "provider-form") return;
|
|
7116
|
+
const profile = getClient().getUserProfile();
|
|
7117
|
+
setKyc((k) => ({
|
|
7118
|
+
...k,
|
|
7119
|
+
firstName: k.firstName || profile?.first_name || "",
|
|
7120
|
+
lastName: k.lastName || profile?.last_name || ""
|
|
7121
|
+
}));
|
|
7122
|
+
getClient().getCardOccupations().then(setOccupations).catch(() => setOccupations([]));
|
|
7123
|
+
}, [stage, getClient]);
|
|
7124
|
+
const kycPending = holder ? holder.kycStatus in KYC_PENDING_COPY : false;
|
|
7125
|
+
react.useEffect(() => {
|
|
7126
|
+
if (!kycPending) return;
|
|
7127
|
+
const id = setInterval(() => {
|
|
7128
|
+
loadHolder().then((h) => {
|
|
7129
|
+
if (h?.kycStatus === "APPROVED") void loadCardData();
|
|
7130
|
+
}).catch(() => {
|
|
7131
|
+
});
|
|
7132
|
+
}, KYC_POLL_MS);
|
|
7133
|
+
return () => clearInterval(id);
|
|
7134
|
+
}, [kycPending, loadHolder, loadCardData]);
|
|
7135
|
+
react.useEffect(
|
|
7136
|
+
() => () => {
|
|
7137
|
+
if (revealTimer.current) clearTimeout(revealTimer.current);
|
|
7138
|
+
},
|
|
7139
|
+
[]
|
|
7140
|
+
);
|
|
7141
|
+
function openStep(step) {
|
|
7142
|
+
stepAttempt.current = step;
|
|
7143
|
+
setPendingStep(step);
|
|
7144
|
+
}
|
|
7145
|
+
async function run(key, work, fallback) {
|
|
7146
|
+
if (busy) return;
|
|
7147
|
+
setBusy(key);
|
|
7148
|
+
setError("");
|
|
7149
|
+
try {
|
|
7150
|
+
await work();
|
|
7151
|
+
} catch (e) {
|
|
7152
|
+
const step = requiredCardStep(e);
|
|
7153
|
+
if (step) openStep(step);
|
|
7154
|
+
else setError(errorText(e, fallback));
|
|
7155
|
+
} finally {
|
|
7156
|
+
setBusy(null);
|
|
7157
|
+
}
|
|
7158
|
+
}
|
|
7159
|
+
async function afterStep() {
|
|
7160
|
+
if (!provider) return;
|
|
7161
|
+
const [h, r] = await Promise.all([loadHolder(), loadRequirements(provider.id)]);
|
|
7162
|
+
if (h?.kycStatus === "APPROVED") await loadCardData();
|
|
7163
|
+
if (r?.next && !blockedStepMessage(r.next)) openStep(pendingFromRequirement(provider.id, r.next));
|
|
7164
|
+
}
|
|
7165
|
+
const start = () => run(
|
|
7166
|
+
"start",
|
|
7167
|
+
async () => {
|
|
7168
|
+
if (!provider) return;
|
|
7169
|
+
if (requirements?.next) {
|
|
7170
|
+
openStep(pendingFromRequirement(provider.id, requirements.next));
|
|
7171
|
+
return;
|
|
7172
|
+
}
|
|
7173
|
+
if (holder) return afterStep();
|
|
7174
|
+
setHolder(await getClient().createCardHolder());
|
|
7175
|
+
},
|
|
7176
|
+
"Could not start your card application"
|
|
7177
|
+
);
|
|
7178
|
+
const sendKyc = () => run(
|
|
7179
|
+
"kyc",
|
|
7180
|
+
async () => {
|
|
7181
|
+
const address = { ...kyc.address };
|
|
7182
|
+
if (!address.line2) delete address.line2;
|
|
7183
|
+
setHolder(await getClient().submitCardKyc({ termsAccepted: terms, kyc: { ...kyc, address } }));
|
|
7184
|
+
},
|
|
7185
|
+
"Could not submit your information"
|
|
7186
|
+
);
|
|
7187
|
+
const issue = () => run(
|
|
7188
|
+
"issue",
|
|
7189
|
+
async () => {
|
|
7190
|
+
await getClient().issueCard(nickname.trim() ? { nickname: nickname.trim() } : {});
|
|
7191
|
+
await loadCardData();
|
|
7192
|
+
},
|
|
7193
|
+
"Could not issue your card"
|
|
7194
|
+
);
|
|
7195
|
+
const refresh = () => run(
|
|
7196
|
+
"refresh",
|
|
7197
|
+
async () => {
|
|
7198
|
+
await loadCardData();
|
|
7199
|
+
},
|
|
7200
|
+
"Could not refresh your card"
|
|
7201
|
+
);
|
|
7202
|
+
const reveal = () => run(
|
|
7203
|
+
"reveal",
|
|
7204
|
+
async () => {
|
|
7205
|
+
if (!card) return;
|
|
7206
|
+
const s = await getClient().revealCardSecrets(card.id);
|
|
7207
|
+
setSecrets(s);
|
|
7208
|
+
if (revealTimer.current) clearTimeout(revealTimer.current);
|
|
7209
|
+
revealTimer.current = setTimeout(() => setSecrets(null), REVEAL_MS);
|
|
7210
|
+
},
|
|
7211
|
+
"Could not show the card details"
|
|
7212
|
+
);
|
|
7213
|
+
const openFund = () => run(
|
|
7214
|
+
"fund",
|
|
7215
|
+
async () => {
|
|
7216
|
+
setFundings(await getClient().listCardFundings());
|
|
7217
|
+
setPanel("fund");
|
|
7218
|
+
},
|
|
7219
|
+
"Could not load your fundings"
|
|
7220
|
+
);
|
|
7221
|
+
const fund = () => run(
|
|
7222
|
+
"fund-send",
|
|
7223
|
+
async () => {
|
|
7224
|
+
const outcome = await getClient().fundCard({ amount: fundAmount.trim() });
|
|
7225
|
+
if (outcome.status === "cancelled") {
|
|
7226
|
+
setError("The payment was not signed.");
|
|
7227
|
+
return;
|
|
7228
|
+
}
|
|
7229
|
+
setFundings((cur) => [outcome.funding, ...(cur ?? []).filter((f) => f.id !== outcome.funding.id)]);
|
|
7230
|
+
setFundAmount("");
|
|
7231
|
+
},
|
|
7232
|
+
"Could not fund the card"
|
|
7233
|
+
);
|
|
7234
|
+
const showManualAddress = () => run(
|
|
7235
|
+
"fund-manual",
|
|
7236
|
+
async () => {
|
|
7237
|
+
if (!deposit) setDeposit(await getClient().getCardDepositAddresses());
|
|
7238
|
+
setShowManual(true);
|
|
7239
|
+
},
|
|
7240
|
+
"Could not load the deposit address"
|
|
7241
|
+
);
|
|
7242
|
+
const fundingsInflight = (fundings ?? []).some((f) => FUNDING_INFLIGHT.has(f.status));
|
|
7243
|
+
react.useEffect(() => {
|
|
7244
|
+
if (panel !== "fund" || !fundingsInflight) return;
|
|
7245
|
+
const id = setInterval(() => {
|
|
7246
|
+
getClient().listCardFundings().then((next) => {
|
|
7247
|
+
setFundings((previous) => {
|
|
7248
|
+
const credited = next.some(
|
|
7249
|
+
(f) => f.status === "CREDITED" && previous?.find((p) => p.id === f.id)?.status !== "CREDITED"
|
|
7250
|
+
);
|
|
7251
|
+
if (credited) void loadCardData().catch(() => {
|
|
7252
|
+
});
|
|
7253
|
+
return next;
|
|
7254
|
+
});
|
|
7255
|
+
}).catch(() => {
|
|
7256
|
+
});
|
|
7257
|
+
}, FUNDING_POLL_MS);
|
|
7258
|
+
return () => clearInterval(id);
|
|
7259
|
+
}, [panel, fundingsInflight, getClient, loadCardData]);
|
|
7260
|
+
const field = (key, label, extra = {}) => /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "pollar-send-field", children: [
|
|
7261
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-send-label", children: label }),
|
|
7262
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7263
|
+
"input",
|
|
7264
|
+
{
|
|
7265
|
+
className: "pollar-input",
|
|
7266
|
+
value: kyc[key],
|
|
7267
|
+
onChange: (e) => setKyc((k) => ({ ...k, [key]: e.target.value })),
|
|
7268
|
+
...extra
|
|
7269
|
+
}
|
|
7270
|
+
)
|
|
7271
|
+
] });
|
|
7272
|
+
const addressField = (key, label, extra = {}) => /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "pollar-send-field", children: [
|
|
7273
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-send-label", children: label }),
|
|
7274
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7275
|
+
"input",
|
|
7276
|
+
{
|
|
7277
|
+
className: "pollar-input",
|
|
7278
|
+
value: kyc.address[key] ?? "",
|
|
7279
|
+
onChange: (e) => setKyc((k) => ({ ...k, address: { ...k.address, [key]: e.target.value } })),
|
|
7280
|
+
...extra
|
|
7281
|
+
}
|
|
7282
|
+
)
|
|
7283
|
+
] });
|
|
7284
|
+
const rangeField = (key, label) => /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "pollar-send-field", children: [
|
|
7285
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-send-label", children: label }),
|
|
7286
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7287
|
+
"select",
|
|
7288
|
+
{
|
|
7289
|
+
className: "pollar-input pollar-send-select",
|
|
7290
|
+
value: kyc[key],
|
|
7291
|
+
onChange: (e) => setKyc((k) => ({ ...k, [key]: e.target.value })),
|
|
7292
|
+
children: INCOME_RANGES.map((r) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: r.value, children: r.label }, r.value))
|
|
7293
|
+
}
|
|
7294
|
+
)
|
|
7295
|
+
] });
|
|
7296
|
+
const kycComplete = kyc.firstName && kyc.lastName && /^\d{4}-\d{2}-\d{2}$/.test(kyc.birthDate) && kyc.nationalId && kyc.countryOfIssue.length === 2 && kyc.phoneCountryCode && kyc.phoneNumber && kyc.occupation && kyc.accountPurpose && kyc.address.line1 && kyc.address.city && kyc.address.region && kyc.address.postalCode && kyc.address.countryCode.length === 2;
|
|
7297
|
+
if (pendingStep) {
|
|
7298
|
+
const close = () => {
|
|
7299
|
+
stepAttempt.current = null;
|
|
7300
|
+
setPendingStep(null);
|
|
7301
|
+
};
|
|
7302
|
+
const done = () => {
|
|
7303
|
+
if (stepAttempt.current !== pendingStep) return;
|
|
7304
|
+
close();
|
|
7305
|
+
void afterStep();
|
|
7306
|
+
};
|
|
7307
|
+
const progress = pendingStep.progress ? { progress: pendingStep.progress } : {};
|
|
7308
|
+
if (pendingStep.type === "FORM") {
|
|
7309
|
+
return /* @__PURE__ */ jsxRuntime.jsx(RequirementFormModal, { formId: pendingStep.optionId, ...progress, onClose: close, onSubmitted: done });
|
|
7310
|
+
}
|
|
7311
|
+
if (pendingStep.type === "REGISTRY_CHECK") {
|
|
7312
|
+
return /* @__PURE__ */ jsxRuntime.jsx(RegistryCheckModal, { optionId: pendingStep.optionId, ...progress, onClose: close, onApproved: done });
|
|
7313
|
+
}
|
|
7314
|
+
if (pendingStep.type === "PROVIDER_REGISTRATION") {
|
|
7315
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
7316
|
+
ProviderRegistrationModal,
|
|
7317
|
+
{
|
|
7318
|
+
cardProviderId: pendingStep.cardProviderId,
|
|
7319
|
+
...progress,
|
|
7320
|
+
onClose: close,
|
|
7321
|
+
onRegistered: done
|
|
7322
|
+
}
|
|
7323
|
+
);
|
|
7324
|
+
}
|
|
7325
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
7326
|
+
KycModal,
|
|
7327
|
+
{
|
|
7328
|
+
cardProviderId: pendingStep.cardProviderId,
|
|
7329
|
+
providerId: pendingStep.optionId,
|
|
7330
|
+
onClose: close,
|
|
7331
|
+
onApproved: done
|
|
7332
|
+
}
|
|
7333
|
+
);
|
|
7334
|
+
}
|
|
7335
|
+
const loading = providers === null || providers.length > 0 && (holder === void 0 || requirements === void 0) || holder?.kycStatus === "APPROVED" && cards === null && !error;
|
|
7336
|
+
const blocked = requirements?.next ? blockedStepMessage(requirements.next) : null;
|
|
7337
|
+
const stepsPending = !!requirements?.next;
|
|
7338
|
+
const title = panel === "fund" ? "Add funds" : card ? card.nickname ?? "Your card" : "Get a card";
|
|
7339
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-overlay", style: overlayStyle, onClick: onClose, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
7340
|
+
"div",
|
|
7341
|
+
{
|
|
7342
|
+
className: "pollar-modal-card pollar-card-modal",
|
|
7343
|
+
"data-theme": theme,
|
|
7344
|
+
style: cssVars,
|
|
7345
|
+
onClick: (e) => e.stopPropagation(),
|
|
7346
|
+
children: [
|
|
7347
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-header", children: [
|
|
7348
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-send-header-left", children: [
|
|
7349
|
+
panel === "fund" && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-modal-close", onClick: () => setPanel("card"), "aria-label": "Back", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M10 3L5 8l5 5", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) }),
|
|
7350
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "pollar-modal-title", children: title })
|
|
7351
|
+
] }),
|
|
7352
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-header-actions", children: [
|
|
7353
|
+
card && panel === "card" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
7354
|
+
"button",
|
|
7355
|
+
{
|
|
7356
|
+
type: "button",
|
|
7357
|
+
className: "pollar-modal-close",
|
|
7358
|
+
onClick: () => void refresh(),
|
|
7359
|
+
disabled: busy !== null,
|
|
7360
|
+
"aria-label": "Refresh",
|
|
7361
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
7362
|
+
"svg",
|
|
7363
|
+
{
|
|
7364
|
+
className: busy === "refresh" ? "pollar-modal-refresh-icon pollar-spinning" : "pollar-modal-refresh-icon",
|
|
7365
|
+
width: "16",
|
|
7366
|
+
height: "16",
|
|
7367
|
+
viewBox: "0 0 16 16",
|
|
7368
|
+
fill: "none",
|
|
7369
|
+
"aria-hidden": true,
|
|
7370
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
7371
|
+
"path",
|
|
7372
|
+
{
|
|
7373
|
+
d: "M13.5 8a5.5 5.5 0 1 1-1.6-3.9M13.5 2v3h-3",
|
|
7374
|
+
stroke: "currentColor",
|
|
7375
|
+
strokeWidth: "1.6",
|
|
7376
|
+
strokeLinecap: "round",
|
|
7377
|
+
strokeLinejoin: "round"
|
|
7378
|
+
}
|
|
7379
|
+
)
|
|
7380
|
+
}
|
|
7381
|
+
)
|
|
7382
|
+
}
|
|
7383
|
+
),
|
|
7384
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-modal-close", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M2 2l12 12M14 2L2 14", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }) })
|
|
7385
|
+
] })
|
|
7386
|
+
] }),
|
|
7387
|
+
loading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-loading-block", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-spinner" }) }),
|
|
7388
|
+
!loading && providers?.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-error", children: "Cards are not available for this app." }),
|
|
7389
|
+
!loading && provider && !provider.available && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-error", children: "Cards are not available right now." }),
|
|
7390
|
+
!loading && provider && provider.available && stage === "steps" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
7391
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
|
|
7392
|
+
"Get ",
|
|
7393
|
+
provider.cardLabel ?? `a ${provider.name} card`,
|
|
7394
|
+
" funded from your wallet",
|
|
7395
|
+
wallet ? "" : " once you sign in",
|
|
7396
|
+
". You will verify your identity first; it takes a few minutes."
|
|
7397
|
+
] }),
|
|
7398
|
+
requirements && requirements.total > 0 && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "pollar-card-note", children: [
|
|
7399
|
+
requirements.completed,
|
|
7400
|
+
" of ",
|
|
7401
|
+
requirements.total,
|
|
7402
|
+
" steps done"
|
|
7403
|
+
] }),
|
|
7404
|
+
blocked && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-error", children: blocked }),
|
|
7405
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-actions", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
7406
|
+
"button",
|
|
7407
|
+
{
|
|
7408
|
+
type: "button",
|
|
7409
|
+
className: "pollar-btn-primary",
|
|
7410
|
+
onClick: () => void start(),
|
|
7411
|
+
disabled: busy !== null || !wallet || !!blocked,
|
|
7412
|
+
children: busy === "start" ? "Starting..." : stepsPending ? "Continue" : "Start"
|
|
7413
|
+
}
|
|
7414
|
+
) })
|
|
7415
|
+
] }),
|
|
7416
|
+
!loading && provider && stage === "provider-form" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
7417
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-card-section-title", children: "About you" }),
|
|
7418
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-card-grid", children: [
|
|
7419
|
+
field("firstName", "First name", { autoComplete: "given-name" }),
|
|
7420
|
+
field("lastName", "Last name", { autoComplete: "family-name" }),
|
|
7421
|
+
field("birthDate", "Birth date", { placeholder: "YYYY-MM-DD", autoComplete: "bday" }),
|
|
7422
|
+
field("nationalId", "ID number"),
|
|
7423
|
+
field("countryOfIssue", "ID country (2 letters)", { maxLength: 2, placeholder: "AR" }),
|
|
7424
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "pollar-send-field", children: [
|
|
7425
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-send-label", children: "Occupation" }),
|
|
7426
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
7427
|
+
"select",
|
|
7428
|
+
{
|
|
7429
|
+
className: "pollar-input pollar-send-select",
|
|
7430
|
+
value: kyc.occupation,
|
|
7431
|
+
onChange: (e) => setKyc((k) => ({ ...k, occupation: e.target.value })),
|
|
7432
|
+
children: [
|
|
7433
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "Select..." }),
|
|
7434
|
+
occupations.map((o) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: o.code, children: o.label }, o.code))
|
|
7435
|
+
]
|
|
7436
|
+
}
|
|
7437
|
+
)
|
|
7438
|
+
] }),
|
|
7439
|
+
field("phoneCountryCode", "Phone country code", { placeholder: "54", inputMode: "numeric" }),
|
|
7440
|
+
field("phoneNumber", "Phone number", { placeholder: "91155551234", inputMode: "numeric" }),
|
|
7441
|
+
rangeField("annualSalary", "Annual income"),
|
|
7442
|
+
rangeField("expectedMonthlyVolume", "Expected monthly spend"),
|
|
7443
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-card-grid-full", children: field("accountPurpose", "What will you use the card for?") })
|
|
7444
|
+
] }),
|
|
7445
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-card-section-title", children: "Address" }),
|
|
7446
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-card-grid", children: [
|
|
7447
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-card-grid-full", children: addressField("line1", "Street and number", { autoComplete: "address-line1" }) }),
|
|
7448
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-card-grid-full", children: addressField("line2", "Apartment, floor (optional)", { autoComplete: "address-line2" }) }),
|
|
7449
|
+
addressField("city", "City", { autoComplete: "address-level2" }),
|
|
7450
|
+
addressField("region", "State or province", { autoComplete: "address-level1" }),
|
|
7451
|
+
addressField("postalCode", "Postal code", { autoComplete: "postal-code" }),
|
|
7452
|
+
addressField("countryCode", "Country (2 letters)", { maxLength: 2, placeholder: "AR" })
|
|
7453
|
+
] }),
|
|
7454
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "pollar-card-terms", children: [
|
|
7455
|
+
/* @__PURE__ */ jsxRuntime.jsx("input", { type: "checkbox", checked: terms, onChange: (e) => setTerms(e.target.checked) }),
|
|
7456
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
7457
|
+
"I have read and accept the",
|
|
7458
|
+
" ",
|
|
7459
|
+
/* @__PURE__ */ jsxRuntime.jsxs("a", { className: "pollar-card-link", href: provider.termsUrl ?? "#", target: "_blank", rel: "noreferrer", children: [
|
|
7460
|
+
provider.name,
|
|
7461
|
+
" terms of service"
|
|
7462
|
+
] }),
|
|
7463
|
+
provider.termsUrl ? "" : " (demo: the final terms link is pending)",
|
|
7464
|
+
"."
|
|
7465
|
+
] })
|
|
7466
|
+
] }),
|
|
7467
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-actions", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
7468
|
+
"button",
|
|
7469
|
+
{
|
|
7470
|
+
type: "button",
|
|
7471
|
+
className: "pollar-btn-primary",
|
|
7472
|
+
onClick: () => void sendKyc(),
|
|
7473
|
+
disabled: busy !== null || !terms || !kycComplete,
|
|
7474
|
+
children: busy === "kyc" ? "Sending..." : "Continue"
|
|
7475
|
+
}
|
|
7476
|
+
) })
|
|
7477
|
+
] }),
|
|
7478
|
+
!loading && holder && holder.kycStatus in KYC_PENDING_COPY && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
7479
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { children: KYC_PENDING_COPY[holder.kycStatus] }),
|
|
7480
|
+
holder.kycReason && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-card-note", children: holder.kycReason }),
|
|
7481
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-actions", children: [
|
|
7482
|
+
holder.verificationLink && /* @__PURE__ */ jsxRuntime.jsx("a", { className: "pollar-btn-primary", href: holder.verificationLink, target: "_blank", rel: "noreferrer", children: "Verify my identity" }),
|
|
7483
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-secondary", onClick: () => void loadHolder().catch(() => {
|
|
7484
|
+
}), children: "I am done" })
|
|
7485
|
+
] }),
|
|
7486
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-card-note", children: "This screen updates on its own once the verification comes back." })
|
|
7487
|
+
] }),
|
|
7488
|
+
!loading && holder && holder.kycStatus in KYC_FINAL_COPY && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-error", children: [
|
|
7489
|
+
KYC_FINAL_COPY[holder.kycStatus],
|
|
7490
|
+
holder.kycReason ? ` ${holder.kycReason}` : ""
|
|
7491
|
+
] }),
|
|
7492
|
+
!loading && provider && holder?.kycStatus === "APPROVED" && cards !== null && !card && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
7493
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { children: "Your identity is verified. Issue your virtual card to start." }),
|
|
7494
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "pollar-send-field", children: [
|
|
7495
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-send-label", children: "Card name (optional)" }),
|
|
7496
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7497
|
+
"input",
|
|
7498
|
+
{
|
|
7499
|
+
className: "pollar-input",
|
|
7500
|
+
value: nickname,
|
|
7501
|
+
maxLength: 40,
|
|
7502
|
+
onChange: (e) => setNickname(e.target.value),
|
|
7503
|
+
placeholder: "Everyday card"
|
|
7504
|
+
}
|
|
7505
|
+
)
|
|
7506
|
+
] }),
|
|
7507
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-actions", children: /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-primary", onClick: () => void issue(), disabled: busy !== null, children: busy === "issue" ? "Issuing..." : "Issue my card" }) })
|
|
7508
|
+
] }),
|
|
7509
|
+
!loading && provider && card && panel === "card" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
7510
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-card-visual", children: [
|
|
7511
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-card-visual-top", children: [
|
|
7512
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-card-brand", children: [
|
|
7513
|
+
styles.logoUrl && /* @__PURE__ */ jsxRuntime.jsx("img", { src: styles.logoUrl, alt: "", className: "pollar-card-brand-logo" }),
|
|
7514
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: provider.cardLabel ?? provider.name })
|
|
7515
|
+
] }),
|
|
7516
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-card-status", children: card.status.toLowerCase() })
|
|
7517
|
+
] }),
|
|
7518
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-card-visual-chip" }),
|
|
7519
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-card-visual-number", children: secrets ? groupPan(secrets.pan) : `\u2022\u2022\u2022\u2022 \u2022\u2022\u2022\u2022 \u2022\u2022\u2022\u2022 ${card.last4 ?? "\u2022\u2022\u2022\u2022"}` }),
|
|
7520
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-card-visual-bottom", children: [
|
|
7521
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
7522
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Expires" }),
|
|
7523
|
+
/* @__PURE__ */ jsxRuntime.jsx("strong", { children: card.expMonth && card.expYear ? `${card.expMonth}/${card.expYear.slice(-2)}` : "--/--" })
|
|
7524
|
+
] }),
|
|
7525
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
7526
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "CVC" }),
|
|
7527
|
+
/* @__PURE__ */ jsxRuntime.jsx("strong", { children: secrets ? secrets.cvc : "\u2022\u2022\u2022" })
|
|
7528
|
+
] }),
|
|
7529
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
7530
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: card.type.toLowerCase() }),
|
|
7531
|
+
/* @__PURE__ */ jsxRuntime.jsx("strong", { children: card.currency })
|
|
7532
|
+
] })
|
|
7533
|
+
] })
|
|
7534
|
+
] }),
|
|
7535
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-card-balance", children: [
|
|
7536
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
7537
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Available" }),
|
|
7538
|
+
/* @__PURE__ */ jsxRuntime.jsx("strong", { children: usd(balance?.spendingPowerCents) })
|
|
7539
|
+
] }),
|
|
7540
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
7541
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Limit" }),
|
|
7542
|
+
/* @__PURE__ */ jsxRuntime.jsx("strong", { children: usd(balance?.creditLimitCents) })
|
|
7543
|
+
] }),
|
|
7544
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
7545
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "To pay" }),
|
|
7546
|
+
/* @__PURE__ */ jsxRuntime.jsx("strong", { children: usd(balance?.balanceDueCents) })
|
|
7547
|
+
] })
|
|
7548
|
+
] }),
|
|
7549
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-actions", children: [
|
|
7550
|
+
provider.supports.revealSecrets && (secrets ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-secondary", onClick: () => setSecrets(null), children: "Hide details" }) : /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-secondary", onClick: () => void reveal(), disabled: busy !== null, children: busy === "reveal" ? "Loading..." : "Show details" })),
|
|
7551
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-primary", onClick: () => void openFund(), disabled: busy !== null, children: "Add funds" })
|
|
7552
|
+
] }),
|
|
7553
|
+
secrets && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-card-note", children: "The details hide on their own in 30 seconds. Do not share them." }),
|
|
7554
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-card-section-title", children: "Recent activity" }),
|
|
7555
|
+
transactions === null && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-card-note", children: "Loading..." }),
|
|
7556
|
+
transactions?.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-card-note", children: "No movements yet." }),
|
|
7557
|
+
transactions?.map((tx) => {
|
|
7558
|
+
const purchase = tx.purchase;
|
|
7559
|
+
const local = purchase?.localAmount && purchase.localCurrency && purchase.localCurrency !== "USD" ? money(String(purchase.localAmount), purchase.localCurrency) : null;
|
|
7560
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-card-tx", children: [
|
|
7561
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
7562
|
+
tx.merchantName ?? TX_LABELS[tx.type] ?? tx.type,
|
|
7563
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-card-tx-meta", children: [
|
|
7564
|
+
new Date(tx.occurredAt).toLocaleDateString(),
|
|
7565
|
+
tx.merchantName ? ` \xB7 ${TX_LABELS[tx.type] ?? tx.type}` : "",
|
|
7566
|
+
purchase?.status && purchase.status !== "completed" ? ` \xB7 ${purchase.status}` : ""
|
|
7567
|
+
] })
|
|
7568
|
+
] }),
|
|
7569
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-card-tx-amount", "data-direction": tx.direction ?? void 0, children: [
|
|
7570
|
+
tx.direction === "credit" ? "+" : tx.direction === "debit" ? "-" : "",
|
|
7571
|
+
money(tx.amount, tx.currency),
|
|
7572
|
+
local && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-card-tx-meta", children: local })
|
|
7573
|
+
] })
|
|
7574
|
+
] }, tx.id);
|
|
7575
|
+
})
|
|
7576
|
+
] }),
|
|
7577
|
+
!loading && provider && card && panel === "fund" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
7578
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
|
|
7579
|
+
"Move ",
|
|
7580
|
+
provider.fundingAssets.join(" or ") || "USDC",
|
|
7581
|
+
" from your wallet to your card. It takes a few minutes to cross to the card network."
|
|
7582
|
+
] }),
|
|
7583
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "pollar-send-field", children: [
|
|
7584
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-send-label", children: "Amount (USDC)" }),
|
|
7585
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7586
|
+
"input",
|
|
7587
|
+
{
|
|
7588
|
+
className: "pollar-input",
|
|
7589
|
+
inputMode: "decimal",
|
|
7590
|
+
placeholder: "10",
|
|
7591
|
+
value: fundAmount,
|
|
7592
|
+
onChange: (e) => setFundAmount(e.target.value.replace(/[^0-9.]/g, ""))
|
|
7593
|
+
}
|
|
7594
|
+
)
|
|
7595
|
+
] }),
|
|
7596
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-actions", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
7597
|
+
"button",
|
|
7598
|
+
{
|
|
7599
|
+
type: "button",
|
|
7600
|
+
className: "pollar-btn-primary",
|
|
7601
|
+
onClick: () => void fund(),
|
|
7602
|
+
disabled: busy !== null || !(Number(fundAmount) >= 1),
|
|
7603
|
+
children: busy === "fund-send" ? "Sending..." : "Fund from my wallet"
|
|
7604
|
+
}
|
|
7605
|
+
) }),
|
|
7606
|
+
fundings && fundings.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
7607
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-card-section-title", children: "Your fundings" }),
|
|
7608
|
+
fundings.map((f) => {
|
|
7609
|
+
const copy = FUNDING_COPY[f.status];
|
|
7610
|
+
const inflight = FUNDING_INFLIGHT.has(f.status);
|
|
7611
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-card-tx", "aria-busy": inflight, children: [
|
|
7612
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
7613
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-card-funding-title", children: [
|
|
7614
|
+
inflight && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-spinner pollar-spinner-sm", "aria-hidden": true }),
|
|
7615
|
+
copy?.title ?? f.status
|
|
7616
|
+
] }),
|
|
7617
|
+
inflight && copy?.step && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-card-tx-meta", role: "status", children: [
|
|
7618
|
+
"Step ",
|
|
7619
|
+
copy.step,
|
|
7620
|
+
" of ",
|
|
7621
|
+
FUNDING_STEPS,
|
|
7622
|
+
" \xB7 ",
|
|
7623
|
+
copy.hint
|
|
7624
|
+
] }),
|
|
7625
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-card-tx-meta", children: [
|
|
7626
|
+
new Date(f.createdAt).toLocaleString(),
|
|
7627
|
+
f.status === "FAILED" && f.error ? ` \xB7 ${f.error}` : ""
|
|
7628
|
+
] })
|
|
7629
|
+
] }),
|
|
7630
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-card-tx-amount", "data-direction": f.status === "CREDITED" ? "credit" : void 0, children: money(f.amount, "USD") })
|
|
7631
|
+
] }, f.id);
|
|
7632
|
+
}),
|
|
7633
|
+
fundingsInflight && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-card-note", children: "You can close this window: the funding keeps going and your card is credited when it finishes." })
|
|
7634
|
+
] }),
|
|
7635
|
+
!showManual && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "pollar-card-note", children: [
|
|
7636
|
+
"Prefer to send from another wallet?",
|
|
7637
|
+
" ",
|
|
7638
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7639
|
+
"button",
|
|
7640
|
+
{
|
|
7641
|
+
type: "button",
|
|
7642
|
+
className: "pollar-card-link",
|
|
7643
|
+
onClick: () => void showManualAddress(),
|
|
7644
|
+
disabled: busy !== null,
|
|
7645
|
+
children: "Show the deposit address"
|
|
7646
|
+
}
|
|
7647
|
+
)
|
|
7648
|
+
] }),
|
|
7649
|
+
showManual && deposit?.map((d) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-card-deposit", children: [
|
|
7650
|
+
/* @__PURE__ */ jsxRuntime.jsx("strong", { children: d.network }),
|
|
7651
|
+
" (chain ",
|
|
7652
|
+
d.chainId,
|
|
7653
|
+
")",
|
|
7654
|
+
/* @__PURE__ */ jsxRuntime.jsx("code", { children: d.address }),
|
|
7655
|
+
/* @__PURE__ */ jsxRuntime.jsx(CopyButton, { value: d.address, label: "Copy address" }),
|
|
7656
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "pollar-card-note", children: [
|
|
7657
|
+
"Send only ",
|
|
7658
|
+
d.tokens.map((t) => (t.currency ?? "token").toUpperCase()).join(" or "),
|
|
7659
|
+
" on ",
|
|
7660
|
+
d.network,
|
|
7661
|
+
"; anything else can be lost."
|
|
7662
|
+
] })
|
|
7663
|
+
] }, d.network)),
|
|
7664
|
+
showManual && deposit?.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-error", children: "The provider returned no deposit address." }),
|
|
7665
|
+
showManual && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-card-note", children: /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-card-link", onClick: () => setShowManual(false), children: "Hide the deposit address" }) })
|
|
7666
|
+
] }),
|
|
7667
|
+
error && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-error", children: error }),
|
|
7668
|
+
/* @__PURE__ */ jsxRuntime.jsx(PollarModalFooter, {})
|
|
7669
|
+
]
|
|
7670
|
+
}
|
|
7671
|
+
) });
|
|
7672
|
+
}
|
|
6772
7673
|
function describeDevice(s) {
|
|
6773
7674
|
if (s.deviceLabel) return normalizeDeviceLabel(s.deviceLabel);
|
|
6774
7675
|
if (!s.userAgent) return "Unknown device";
|
|
@@ -7785,9 +8686,30 @@ function PollarProvider({
|
|
|
7785
8686
|
const [sendModalKey, setSendModalKey] = react.useState(0);
|
|
7786
8687
|
const [swapModalKey, setSwapModalKey] = react.useState(0);
|
|
7787
8688
|
const [earnModalKey, setEarnModalKey] = react.useState(0);
|
|
8689
|
+
const [cardModalOpen, setCardModalOpen] = react.useState(false);
|
|
8690
|
+
const [cardModalKey, setCardModalKey] = react.useState(0);
|
|
7788
8691
|
const [receiveModalOpen, setReceiveModalOpen] = react.useState(false);
|
|
7789
8692
|
const [sessionsModalOpen, setSessionsModalOpen] = react.useState(false);
|
|
7790
8693
|
const [distributionRulesModalOpen, setDistributionRulesModalOpen] = react.useState(false);
|
|
8694
|
+
react.useEffect(
|
|
8695
|
+
() => pollarClient.onAuthStateChange((authState) => {
|
|
8696
|
+
if (authState.step !== "idle") return;
|
|
8697
|
+
setTransactionModalOpen(false);
|
|
8698
|
+
setKycModalOpen(false);
|
|
8699
|
+
setRampModalOpen(false);
|
|
8700
|
+
setTxHistoryModalOpen(false);
|
|
8701
|
+
setWalletBalanceModalOpen(false);
|
|
8702
|
+
setEnabledAssetsModalOpen(false);
|
|
8703
|
+
setSendModalOpen(false);
|
|
8704
|
+
setSwapModalOpen(false);
|
|
8705
|
+
setEarnModalOpen(false);
|
|
8706
|
+
setCardModalOpen(false);
|
|
8707
|
+
setReceiveModalOpen(false);
|
|
8708
|
+
setSessionsModalOpen(false);
|
|
8709
|
+
setDistributionRulesModalOpen(false);
|
|
8710
|
+
}),
|
|
8711
|
+
[pollarClient]
|
|
8712
|
+
);
|
|
7791
8713
|
const walletAddress = sessionState?.wallet?.address || "";
|
|
7792
8714
|
const walletProvisioning = sessionState?.wallet?.provisioning;
|
|
7793
8715
|
const getClient = react.useCallback(() => pollarClient, [pollarClient]);
|
|
@@ -7857,6 +8779,11 @@ function PollarProvider({
|
|
|
7857
8779
|
setEarnModalKey((k) => k + 1);
|
|
7858
8780
|
setEarnModalOpen(true);
|
|
7859
8781
|
},
|
|
8782
|
+
// cards
|
|
8783
|
+
openCardModal: () => {
|
|
8784
|
+
setCardModalKey((k) => k + 1);
|
|
8785
|
+
setCardModalOpen(true);
|
|
8786
|
+
},
|
|
7860
8787
|
// sessions
|
|
7861
8788
|
sessions,
|
|
7862
8789
|
openSessionsModal: () => setSessionsModalOpen(true),
|
|
@@ -7931,6 +8858,8 @@ function PollarProvider({
|
|
|
7931
8858
|
sendModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setSendModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(SendModal, { onClose: () => setSendModalOpen(false) }) }, sendModalKey),
|
|
7932
8859
|
swapModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setSwapModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(SwapModal, { onClose: () => setSwapModalOpen(false) }) }, swapModalKey),
|
|
7933
8860
|
earnModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setEarnModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(EarnModal, { onClose: () => setEarnModalOpen(false) }) }, earnModalKey),
|
|
8861
|
+
cardModalOpen && // Keyed by the wallet too: a different user, or signing in with it open, starts it from scratch.
|
|
8862
|
+
/* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setCardModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(CardModal, { onClose: () => setCardModalOpen(false) }) }, `${cardModalKey}:${walletAddress}`),
|
|
7934
8863
|
receiveModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setReceiveModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(ReceiveModal, { onClose: () => setReceiveModalOpen(false) }) }),
|
|
7935
8864
|
sessionsModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setSessionsModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(SessionsModal, { onClose: () => setSessionsModalOpen(false) }) }),
|
|
7936
8865
|
distributionRulesModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setDistributionRulesModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(DistributionRulesModal, { onClose: () => setDistributionRulesModalOpen(false) }) })
|
|
@@ -8442,6 +9371,7 @@ function WalletButton() {
|
|
|
8442
9371
|
);
|
|
8443
9372
|
}
|
|
8444
9373
|
|
|
9374
|
+
exports.CardModal = CardModal;
|
|
8445
9375
|
exports.ChainSelect = ChainSelect;
|
|
8446
9376
|
exports.DistributionRulesModal = DistributionRulesModal;
|
|
8447
9377
|
exports.DistributionRulesModalTemplate = DistributionRulesModalTemplate;
|