@daimo/sdk 1.8.0-beta.0 → 1.8.2

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.
Files changed (249) hide show
  1. package/README.md +17 -0
  2. package/dist/client/createDaimoClient.d.ts +9 -1
  3. package/dist/client/createDaimoClient.d.ts.map +1 -1
  4. package/dist/client/createDaimoClient.js +23 -0
  5. package/dist/client/createDaimoClient.js.map +1 -1
  6. package/dist/common/account.d.ts +419 -13
  7. package/dist/common/account.d.ts.map +1 -1
  8. package/dist/common/account.js +278 -0
  9. package/dist/common/account.js.map +1 -1
  10. package/dist/common/frameReadiness.d.ts +22 -0
  11. package/dist/common/frameReadiness.d.ts.map +1 -0
  12. package/dist/common/frameReadiness.js +33 -0
  13. package/dist/common/frameReadiness.js.map +1 -0
  14. package/dist/common/frameReadiness.test.d.ts +2 -0
  15. package/dist/common/frameReadiness.test.d.ts.map +1 -0
  16. package/dist/common/frameReadiness.test.js +76 -0
  17. package/dist/common/frameReadiness.test.js.map +1 -0
  18. package/dist/native/DaimoFrameRN.d.ts +3 -2
  19. package/dist/native/DaimoFrameRN.d.ts.map +1 -1
  20. package/dist/native/DaimoFrameRN.js +22 -14
  21. package/dist/native/DaimoFrameRN.js.map +1 -1
  22. package/dist/version.d.ts +1 -1
  23. package/dist/version.d.ts.map +1 -1
  24. package/dist/version.js +1 -1
  25. package/dist/version.js.map +1 -1
  26. package/dist/web/api/navTree.d.ts +3 -1
  27. package/dist/web/api/navTree.d.ts.map +1 -1
  28. package/dist/web/components/ChooseOptionPage.d.ts +2 -1
  29. package/dist/web/components/ChooseOptionPage.d.ts.map +1 -1
  30. package/dist/web/components/ChooseOptionPage.js +3 -4
  31. package/dist/web/components/ChooseOptionPage.js.map +1 -1
  32. package/dist/web/components/ChooseOptionPage.test.d.ts +2 -0
  33. package/dist/web/components/ChooseOptionPage.test.d.ts.map +1 -0
  34. package/dist/web/components/ChooseOptionPage.test.js +29 -0
  35. package/dist/web/components/ChooseOptionPage.test.js.map +1 -0
  36. package/dist/web/components/Countdown.d.ts +4 -1
  37. package/dist/web/components/Countdown.d.ts.map +1 -1
  38. package/dist/web/components/Countdown.js +24 -10
  39. package/dist/web/components/Countdown.js.map +1 -1
  40. package/dist/web/components/Countdown.test.d.ts +2 -0
  41. package/dist/web/components/Countdown.test.d.ts.map +1 -0
  42. package/dist/web/components/Countdown.test.js +16 -0
  43. package/dist/web/components/Countdown.test.js.map +1 -0
  44. package/dist/web/components/DaimoFrame.d.ts +3 -2
  45. package/dist/web/components/DaimoFrame.d.ts.map +1 -1
  46. package/dist/web/components/DaimoFrame.js +42 -19
  47. package/dist/web/components/DaimoFrame.js.map +1 -1
  48. package/dist/web/components/DaimoModal.d.ts.map +1 -1
  49. package/dist/web/components/DaimoModal.js +45 -32
  50. package/dist/web/components/DaimoModal.js.map +1 -1
  51. package/dist/web/components/ProgressPulse.d.ts +14 -0
  52. package/dist/web/components/ProgressPulse.d.ts.map +1 -0
  53. package/dist/web/components/ProgressPulse.js +15 -0
  54. package/dist/web/components/ProgressPulse.js.map +1 -0
  55. package/dist/web/components/account/AccountApplePayPage.d.ts +4 -3
  56. package/dist/web/components/account/AccountApplePayPage.d.ts.map +1 -1
  57. package/dist/web/components/account/AccountApplePayPage.js +75 -40
  58. package/dist/web/components/account/AccountApplePayPage.js.map +1 -1
  59. package/dist/web/components/account/AccountApprovalPage.d.ts +34 -0
  60. package/dist/web/components/account/AccountApprovalPage.d.ts.map +1 -0
  61. package/dist/web/components/account/AccountApprovalPage.js +145 -0
  62. package/dist/web/components/account/AccountApprovalPage.js.map +1 -0
  63. package/dist/web/components/account/AccountBankDetailsPage.d.ts +4 -3
  64. package/dist/web/components/account/AccountBankDetailsPage.d.ts.map +1 -1
  65. package/dist/web/components/account/AccountBankDetailsPage.js +12 -10
  66. package/dist/web/components/account/AccountBankDetailsPage.js.map +1 -1
  67. package/dist/web/components/account/AccountBankPickerPage.d.ts +6 -9
  68. package/dist/web/components/account/AccountBankPickerPage.d.ts.map +1 -1
  69. package/dist/web/components/account/AccountBankPickerPage.js +52 -23
  70. package/dist/web/components/account/AccountBankPickerPage.js.map +1 -1
  71. package/dist/web/components/account/AccountBankTransferSubmittedPage.d.ts +15 -0
  72. package/dist/web/components/account/AccountBankTransferSubmittedPage.d.ts.map +1 -0
  73. package/dist/web/components/account/AccountBankTransferSubmittedPage.js +33 -0
  74. package/dist/web/components/account/AccountBankTransferSubmittedPage.js.map +1 -0
  75. package/dist/web/components/account/AccountDeeplinkPage.d.ts +3 -1
  76. package/dist/web/components/account/AccountDeeplinkPage.d.ts.map +1 -1
  77. package/dist/web/components/account/AccountDeeplinkPage.js +17 -9
  78. package/dist/web/components/account/AccountDeeplinkPage.js.map +1 -1
  79. package/dist/web/components/account/AccountEnrollmentPage.d.ts +1 -4
  80. package/dist/web/components/account/AccountEnrollmentPage.d.ts.map +1 -1
  81. package/dist/web/components/account/AccountEnrollmentPage.js +270 -236
  82. package/dist/web/components/account/AccountEnrollmentPage.js.map +1 -1
  83. package/dist/web/components/account/AccountInteracConfirmPage.d.ts +4 -3
  84. package/dist/web/components/account/AccountInteracConfirmPage.d.ts.map +1 -1
  85. package/dist/web/components/account/AccountInteracConfirmPage.js +15 -23
  86. package/dist/web/components/account/AccountInteracConfirmPage.js.map +1 -1
  87. package/dist/web/components/account/AccountOtpCodeEntry.d.ts +2 -1
  88. package/dist/web/components/account/AccountOtpCodeEntry.d.ts.map +1 -1
  89. package/dist/web/components/account/AccountOtpCodeEntry.js +25 -6
  90. package/dist/web/components/account/AccountOtpCodeEntry.js.map +1 -1
  91. package/dist/web/components/account/AccountPaymentPage.d.ts +3 -2
  92. package/dist/web/components/account/AccountPaymentPage.d.ts.map +1 -1
  93. package/dist/web/components/account/AccountPaymentPage.js +10 -5
  94. package/dist/web/components/account/AccountPaymentPage.js.map +1 -1
  95. package/dist/web/components/account/AccountPaymentResumePage.d.ts +8 -0
  96. package/dist/web/components/account/AccountPaymentResumePage.d.ts.map +1 -0
  97. package/dist/web/components/account/AccountPaymentResumePage.js +42 -0
  98. package/dist/web/components/account/AccountPaymentResumePage.js.map +1 -0
  99. package/dist/web/components/account/AccountPhoneOtpPage.d.ts +1 -3
  100. package/dist/web/components/account/AccountPhoneOtpPage.d.ts.map +1 -1
  101. package/dist/web/components/account/AccountPhoneOtpPage.js +3 -40
  102. package/dist/web/components/account/AccountPhoneOtpPage.js.map +1 -1
  103. package/dist/web/components/account/AccountPhonePage.d.ts +1 -2
  104. package/dist/web/components/account/AccountPhonePage.d.ts.map +1 -1
  105. package/dist/web/components/account/AccountPhonePage.js +1 -2
  106. package/dist/web/components/account/AccountPhonePage.js.map +1 -1
  107. package/dist/web/components/account/AccountReadyPage.d.ts +2 -0
  108. package/dist/web/components/account/AccountReadyPage.d.ts.map +1 -0
  109. package/dist/web/components/account/AccountReadyPage.js +7 -0
  110. package/dist/web/components/account/AccountReadyPage.js.map +1 -0
  111. package/dist/web/components/account/AccountRequestToPayPage.d.ts +28 -0
  112. package/dist/web/components/account/AccountRequestToPayPage.d.ts.map +1 -0
  113. package/dist/web/components/account/AccountRequestToPayPage.js +79 -0
  114. package/dist/web/components/account/AccountRequestToPayPage.js.map +1 -0
  115. package/dist/web/components/account/AccountRipioOtpPage.d.ts +7 -0
  116. package/dist/web/components/account/AccountRipioOtpPage.d.ts.map +1 -0
  117. package/dist/web/components/account/AccountRipioOtpPage.js +53 -0
  118. package/dist/web/components/account/AccountRipioOtpPage.js.map +1 -0
  119. package/dist/web/components/account/PaginatedEnrollmentForm.d.ts +4 -1
  120. package/dist/web/components/account/PaginatedEnrollmentForm.d.ts.map +1 -1
  121. package/dist/web/components/account/PaginatedEnrollmentForm.js +74 -8
  122. package/dist/web/components/account/PaginatedEnrollmentForm.js.map +1 -1
  123. package/dist/web/components/account/PaginatedEnrollmentForm.test.d.ts +2 -0
  124. package/dist/web/components/account/PaginatedEnrollmentForm.test.d.ts.map +1 -0
  125. package/dist/web/components/account/PaginatedEnrollmentForm.test.js +67 -0
  126. package/dist/web/components/account/PaginatedEnrollmentForm.test.js.map +1 -0
  127. package/dist/web/components/account/accountNav.d.ts +14 -10
  128. package/dist/web/components/account/accountNav.d.ts.map +1 -1
  129. package/dist/web/components/account/accountNav.js +60 -34
  130. package/dist/web/components/account/accountNav.js.map +1 -1
  131. package/dist/web/components/account/accountNav.test.js +148 -17
  132. package/dist/web/components/account/accountNav.test.js.map +1 -1
  133. package/dist/web/components/account/accountPaymentCompatibility.d.ts +40 -0
  134. package/dist/web/components/account/accountPaymentCompatibility.d.ts.map +1 -0
  135. package/dist/web/components/account/accountPaymentCompatibility.js +319 -0
  136. package/dist/web/components/account/accountPaymentCompatibility.js.map +1 -0
  137. package/dist/web/components/account/accountSessionRecreate.d.ts +15 -0
  138. package/dist/web/components/account/accountSessionRecreate.d.ts.map +1 -0
  139. package/dist/web/components/account/accountSessionRecreate.js +24 -0
  140. package/dist/web/components/account/accountSessionRecreate.js.map +1 -0
  141. package/dist/web/components/account/accountSessionRecreate.test.d.ts +2 -0
  142. package/dist/web/components/account/accountSessionRecreate.test.d.ts.map +1 -0
  143. package/dist/web/components/account/accountSessionRecreate.test.js +75 -0
  144. package/dist/web/components/account/accountSessionRecreate.test.js.map +1 -0
  145. package/dist/web/components/account/approvalInteractions.test.d.ts +2 -0
  146. package/dist/web/components/account/approvalInteractions.test.d.ts.map +1 -0
  147. package/dist/web/components/account/approvalInteractions.test.js +209 -0
  148. package/dist/web/components/account/approvalInteractions.test.js.map +1 -0
  149. package/dist/web/components/account/enrollmentProtocol.d.ts +76 -0
  150. package/dist/web/components/account/enrollmentProtocol.d.ts.map +1 -0
  151. package/dist/web/components/account/enrollmentProtocol.js +323 -0
  152. package/dist/web/components/account/enrollmentProtocol.js.map +1 -0
  153. package/dist/web/components/account/enrollmentProtocol.test.d.ts +2 -0
  154. package/dist/web/components/account/enrollmentProtocol.test.d.ts.map +1 -0
  155. package/dist/web/components/account/enrollmentProtocol.test.js +544 -0
  156. package/dist/web/components/account/enrollmentProtocol.test.js.map +1 -0
  157. package/dist/web/components/account/fiatPopup.d.ts +7 -2
  158. package/dist/web/components/account/fiatPopup.d.ts.map +1 -1
  159. package/dist/web/components/account/fiatPopup.js +16 -6
  160. package/dist/web/components/account/fiatPopup.js.map +1 -1
  161. package/dist/web/components/account/fiatPopup.test.js +8 -6
  162. package/dist/web/components/account/fiatPopup.test.js.map +1 -1
  163. package/dist/web/components/account/formSchemas.d.ts +6 -6
  164. package/dist/web/components/account/requestToPay.test.d.ts +2 -0
  165. package/dist/web/components/account/requestToPay.test.d.ts.map +1 -0
  166. package/dist/web/components/account/requestToPay.test.js +117 -0
  167. package/dist/web/components/account/requestToPay.test.js.map +1 -0
  168. package/dist/web/components/account/walletPayDetails.d.ts +8 -0
  169. package/dist/web/components/account/walletPayDetails.d.ts.map +1 -0
  170. package/dist/web/components/account/walletPayDetails.js +46 -0
  171. package/dist/web/components/account/walletPayDetails.js.map +1 -0
  172. package/dist/web/components/account/walletPayDetails.test.d.ts +2 -0
  173. package/dist/web/components/account/walletPayDetails.test.d.ts.map +1 -0
  174. package/dist/web/components/account/walletPayDetails.test.js +87 -0
  175. package/dist/web/components/account/walletPayDetails.test.js.map +1 -0
  176. package/dist/web/components/account/walletPayName.d.ts +8 -0
  177. package/dist/web/components/account/walletPayName.d.ts.map +1 -0
  178. package/dist/web/components/account/walletPayName.js +12 -0
  179. package/dist/web/components/account/walletPayName.js.map +1 -0
  180. package/dist/web/components/account/walletPayName.test.d.ts +2 -0
  181. package/dist/web/components/account/walletPayName.test.d.ts.map +1 -0
  182. package/dist/web/components/account/walletPayName.test.js +15 -0
  183. package/dist/web/components/account/walletPayName.test.js.map +1 -0
  184. package/dist/web/components/shared.d.ts.map +1 -1
  185. package/dist/web/components/shared.js +1 -1
  186. package/dist/web/components/shared.js.map +1 -1
  187. package/dist/web/hooks/accountAuthNav.d.ts.map +1 -1
  188. package/dist/web/hooks/accountAuthNav.js +1 -6
  189. package/dist/web/hooks/accountAuthNav.js.map +1 -1
  190. package/dist/web/hooks/accountAuthNav.test.js +9 -15
  191. package/dist/web/hooks/accountAuthNav.test.js.map +1 -1
  192. package/dist/web/hooks/locales/en.d.ts +3 -2
  193. package/dist/web/hooks/locales/en.d.ts.map +1 -1
  194. package/dist/web/hooks/locales/en.js +4 -3
  195. package/dist/web/hooks/locales/en.js.map +1 -1
  196. package/dist/web/hooks/locales/es.d.ts.map +1 -1
  197. package/dist/web/hooks/locales/es.js +4 -3
  198. package/dist/web/hooks/locales/es.js.map +1 -1
  199. package/dist/web/hooks/locales/ja.d.ts.map +1 -1
  200. package/dist/web/hooks/locales/ja.js +4 -3
  201. package/dist/web/hooks/locales/ja.js.map +1 -1
  202. package/dist/web/hooks/locales/ko.d.ts.map +1 -1
  203. package/dist/web/hooks/locales/ko.js +4 -3
  204. package/dist/web/hooks/locales/ko.js.map +1 -1
  205. package/dist/web/hooks/locales/pt.d.ts.map +1 -1
  206. package/dist/web/hooks/locales/pt.js +4 -3
  207. package/dist/web/hooks/locales/pt.js.map +1 -1
  208. package/dist/web/hooks/locales/zh.d.ts.map +1 -1
  209. package/dist/web/hooks/locales/zh.js +4 -3
  210. package/dist/web/hooks/locales/zh.js.map +1 -1
  211. package/dist/web/hooks/types.d.ts +15 -8
  212. package/dist/web/hooks/types.d.ts.map +1 -1
  213. package/dist/web/hooks/types.js.map +1 -1
  214. package/dist/web/hooks/useAccountFlow.d.ts +3 -9
  215. package/dist/web/hooks/useAccountFlow.d.ts.map +1 -1
  216. package/dist/web/hooks/useAccountFlow.js +0 -12
  217. package/dist/web/hooks/useAccountFlow.js.map +1 -1
  218. package/dist/web/hooks/useCreateDeposit.d.ts +20 -0
  219. package/dist/web/hooks/useCreateDeposit.d.ts.map +1 -0
  220. package/dist/web/hooks/useCreateDeposit.js +54 -0
  221. package/dist/web/hooks/useCreateDeposit.js.map +1 -0
  222. package/dist/web/hooks/useDepositPoller.js +1 -1
  223. package/dist/web/hooks/useDepositPoller.js.map +1 -1
  224. package/dist/web/hooks/useDraftDeposit.d.ts +3 -2
  225. package/dist/web/hooks/useDraftDeposit.d.ts.map +1 -1
  226. package/dist/web/hooks/useDraftDeposit.js +12 -5
  227. package/dist/web/hooks/useDraftDeposit.js.map +1 -1
  228. package/dist/web/hooks/useMediaQuery.d.ts +3 -0
  229. package/dist/web/hooks/useMediaQuery.d.ts.map +1 -0
  230. package/dist/web/hooks/useMediaQuery.js +11 -0
  231. package/dist/web/hooks/useMediaQuery.js.map +1 -0
  232. package/dist/web/hooks/useRequestToPayDeposit.d.ts +26 -0
  233. package/dist/web/hooks/useRequestToPayDeposit.d.ts.map +1 -0
  234. package/dist/web/hooks/useRequestToPayDeposit.js +81 -0
  235. package/dist/web/hooks/useRequestToPayDeposit.js.map +1 -0
  236. package/dist/web/hooks/useSessionNav.d.ts +5 -1
  237. package/dist/web/hooks/useSessionNav.d.ts.map +1 -1
  238. package/dist/web/hooks/useSessionNav.js +150 -21
  239. package/dist/web/hooks/useSessionNav.js.map +1 -1
  240. package/dist/web/isDesktopBrowser.d.ts +2 -0
  241. package/dist/web/isDesktopBrowser.d.ts.map +1 -0
  242. package/dist/web/isDesktopBrowser.js +6 -0
  243. package/dist/web/isDesktopBrowser.js.map +1 -0
  244. package/dist/web/styles.css +1 -1
  245. package/dist/web/theme.css +1 -1
  246. package/dist/web/theme.d.ts.map +1 -1
  247. package/dist/web/theme.js +3 -1
  248. package/dist/web/theme.js.map +1 -1
  249. package/package.json +1 -1
@@ -1,7 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useCallback, useEffect, useRef, useState, } from "react";
3
- import { zodResolver } from "@hookform/resolvers/zod";
4
- import { useForm } from "react-hook-form";
2
+ import { useCallback, useEffect, useMemo, useRef, useState, } from "react";
5
3
  import { useDaimoClient } from "../../hooks/DaimoClientContext.js";
6
4
  import { getLocale, t } from "../../hooks/locale.js";
7
5
  import { useAccountFlow } from "../../hooks/useAccountFlow.js";
@@ -11,218 +9,296 @@ import { ErrorPage } from "../ErrorPage.js";
11
9
  import { CheckIcon, ErrorIcon } from "../icons.js";
12
10
  import { Skeleton, SkeletonText } from "../Skeleton.js";
13
11
  import { CenteredContent, ContactSupportButton, PageHeader, } from "../shared.js";
14
- import { DaimoFormField, DaimoTextField } from "../formFields.js";
15
- import { AccountKycInfoPage, AccountKycInfoSkeleton, } from "./AccountKycInfoPage.js";
16
- import { zLegalNameForm } from "./formSchemas.js";
12
+ import { AccountOtpCodeEntry, } from "./AccountOtpCodeEntry.js";
13
+ import { enrollmentInteractionIdentity, enrollmentFormActionInput, enrollmentHostedReturnTiming, enrollmentNavigationEffect, enrollmentPollingDelay, isEnrollmentResponseCurrent, loadEnrollmentStep, shouldLoadEnrollmentTarget, submitEnrollmentStep, } from "./enrollmentProtocol.js";
17
14
  import { getKycRequirement, KycIndicator } from "./kycRequirement.js";
18
15
  import { PaginatedEnrollmentForm, } from "./PaginatedEnrollmentForm.js";
19
- /** Actions that should trigger polling the state is still advancing. */
20
- const POLLING_ACTIONS = new Set([
21
- "kyc_required",
22
- "kyc_retry",
23
- "kyc_pending_review",
24
- "hosted_agreement_required",
25
- "hosted_kyc_required",
26
- "provider_pending",
27
- ]);
28
- export function AccountEnrollmentPage({ node, sessionId, platform, onBack, onReady, onPhoneRequired, onProviderOtpRequired, }) {
16
+ export function AccountEnrollmentPage({ node, sessionId, platform, onBack, onReady, onPhoneRequired, }) {
29
17
  const rail = node.fiatMethod;
30
- const requiresLegalNameBeforeEnrollment = rail === "ach" || rail === "sepa";
18
+ const target = `${sessionId}:${rail}`;
31
19
  const account = useAccountFlow();
32
- const setProviderOtp = account?.setProviderOtp;
20
+ const getAccessToken = account?.getAccessToken;
33
21
  const client = useDaimoClient();
34
- const [response, setResponse] = useState(null);
22
+ const legacyCopy = useMemo(() => getLegacyCopy(platform), [platform]);
23
+ const [step, setStep] = useState(null);
35
24
  const [isLoading, setIsLoading] = useState(true);
36
- const [kycAccepted, setKycAccepted] = useState(false);
37
- const [legalName, setLegalName] = useState(null);
38
- const started = useRef(false);
39
- const responseRef = useRef(null);
40
- const readyTimeoutRef = useRef(null);
41
- const applyEnrollmentResult = useCallback((result, previousAction) => {
42
- if (previousAction === "hosted_agreement_required" &&
43
- result.action === "active") {
44
- const pending = { action: "provider_pending" };
45
- responseRef.current = pending;
46
- setResponse(pending);
47
- if (readyTimeoutRef.current != null) {
48
- window.clearTimeout(readyTimeoutRef.current);
49
- }
50
- readyTimeoutRef.current = window.setTimeout(() => {
51
- responseRef.current = result;
52
- setResponse(result);
53
- onReady();
54
- }, 900);
55
- return;
56
- }
57
- if (result.action === "active") {
58
- responseRef.current = result;
59
- setResponse(result);
60
- onReady();
25
+ const [errorMessage, setErrorMessage] = useState(null);
26
+ const latestRequestRef = useRef(0);
27
+ const targetRef = useRef(target);
28
+ const stepRef = useRef(null);
29
+ const mountedRef = useRef(true);
30
+ const loadedTargetRef = useRef(null);
31
+ const onReadyRef = useRef(onReady);
32
+ const onPhoneRequiredRef = useRef(onPhoneRequired);
33
+ targetRef.current = target;
34
+ onReadyRef.current = onReady;
35
+ onPhoneRequiredRef.current = onPhoneRequired;
36
+ useEffect(() => {
37
+ mountedRef.current = true;
38
+ return () => {
39
+ mountedRef.current = false;
40
+ latestRequestRef.current += 1;
41
+ };
42
+ }, []);
43
+ const applyStep = useCallback((result) => {
44
+ stepRef.current = result;
45
+ setStep(result);
46
+ setIsLoading(false);
47
+ setErrorMessage(null);
48
+ switch (enrollmentNavigationEffect(result.interaction)) {
49
+ case "ready":
50
+ onReadyRef.current();
51
+ return;
52
+ case "phone":
53
+ onPhoneRequiredRef.current();
54
+ return;
55
+ case "render":
56
+ return;
61
57
  }
62
- else if (result.action === "phone_required") {
63
- // Coinbase Headless has no KYC phone OTP is the only step.
64
- // Navigate to the phone entry screen; the server will flip to "active"
65
- // once we return from phone verification.
66
- responseRef.current = result;
67
- setResponse(result);
68
- onPhoneRequired();
58
+ }, []);
59
+ const runRequest = useCallback(async (request, expectedInteraction) => {
60
+ const requestId = ++latestRequestRef.current;
61
+ const requestTarget = targetRef.current;
62
+ let result;
63
+ try {
64
+ result = await request();
69
65
  }
70
- else if (result.action === "provider_otp_required") {
71
- responseRef.current = result;
72
- setResponse(result);
73
- setProviderOtp?.(result);
74
- onProviderOtpRequired();
66
+ catch {
67
+ if (mountedRef.current &&
68
+ isEnrollmentResponseCurrent({
69
+ requestId,
70
+ latestRequestId: latestRequestRef.current,
71
+ requestTarget,
72
+ currentTarget: targetRef.current,
73
+ expectedInteraction,
74
+ currentInteraction: enrollmentInteractionIdentity(stepRef.current),
75
+ })) {
76
+ setIsLoading(false);
77
+ setErrorMessage(t.errorGeneric);
78
+ }
79
+ return null;
75
80
  }
76
- else {
77
- responseRef.current = result;
78
- setResponse(result);
81
+ if (!mountedRef.current ||
82
+ !isEnrollmentResponseCurrent({
83
+ requestId,
84
+ latestRequestId: latestRequestRef.current,
85
+ requestTarget,
86
+ currentTarget: targetRef.current,
87
+ expectedInteraction,
88
+ currentInteraction: enrollmentInteractionIdentity(stepRef.current),
89
+ })) {
90
+ return null;
79
91
  }
80
- }, [onReady, onPhoneRequired, onProviderOtpRequired, setProviderOtp]);
81
- const fetchEnrollment = useCallback(async () => {
82
- if (!account)
83
- return;
84
- const isInitial = responseRef.current == null;
85
- const previousAction = responseRef.current?.action;
86
- if (isInitial)
87
- setIsLoading(true);
88
- let result;
89
- try {
90
- result = await account.startEnrollment(client, {
92
+ applyStep(result);
93
+ return result;
94
+ }, [applyStep]);
95
+ const refreshEnrollment = useCallback(async (expectedInteraction = null) => {
96
+ if (!getAccessToken)
97
+ return null;
98
+ return runRequest(async () => {
99
+ const token = await getAccessToken();
100
+ if (!token)
101
+ throw new Error("not authenticated");
102
+ return loadEnrollmentStep({
103
+ client,
91
104
  rail,
92
- ...(legalName ? { legalName } : {}),
105
+ locale: getLocale(),
106
+ auth: { bearerToken: token },
107
+ legacyCopy,
93
108
  });
94
- }
95
- catch (err) {
96
- console.error("[enrollment] fetch failed:", err);
97
- result = { action: "error", message: t.errorGeneric, retryable: true };
98
- }
99
- if (isInitial)
100
- setIsLoading(false);
101
- if (!result)
102
- return;
103
- applyEnrollmentResult(result, previousAction);
104
- }, [account, applyEnrollmentResult, client, legalName, rail]);
105
- // Initial fetch
109
+ }, expectedInteraction);
110
+ }, [client, getAccessToken, legacyCopy, rail, runRequest]);
111
+ const submitAction = useCallback(async (source, actionId, input) => {
112
+ if (!getAccessToken)
113
+ return null;
114
+ const expectedInteraction = enrollmentInteractionIdentity(source);
115
+ return runRequest(async () => {
116
+ const token = await getAccessToken();
117
+ if (!token)
118
+ throw new Error("not authenticated");
119
+ return submitEnrollmentStep({
120
+ client,
121
+ rail,
122
+ locale: getLocale(),
123
+ auth: { bearerToken: token },
124
+ step: source,
125
+ actionId,
126
+ input,
127
+ legacyCopy,
128
+ });
129
+ }, expectedInteraction);
130
+ }, [client, getAccessToken, legacyCopy, rail, runRequest]);
131
+ const refreshEnrollmentRef = useRef(refreshEnrollment);
132
+ refreshEnrollmentRef.current = refreshEnrollment;
106
133
  useEffect(() => {
107
- if (started.current)
108
- return;
109
- if (requiresLegalNameBeforeEnrollment && legalName == null)
134
+ if (!shouldLoadEnrollmentTarget({
135
+ loadedTarget: loadedTargetRef.current,
136
+ target,
137
+ canLoad: getAccessToken != null,
138
+ })) {
110
139
  return;
111
- started.current = true;
112
- fetchEnrollment();
113
- }, [requiresLegalNameBeforeEnrollment, fetchEnrollment, legalName]);
114
- // Poll while the state is still advancing
140
+ }
141
+ loadedTargetRef.current = target;
142
+ latestRequestRef.current += 1;
143
+ stepRef.current = null;
144
+ setStep(null);
145
+ setErrorMessage(null);
146
+ setIsLoading(true);
147
+ void refreshEnrollmentRef.current();
148
+ }, [getAccessToken, target]);
115
149
  useEffect(() => {
116
- if (!response || !POLLING_ACTIONS.has(response.action))
150
+ if (!step)
117
151
  return;
118
- const interval = setInterval(fetchEnrollment, 2000);
119
- return () => clearInterval(interval);
120
- }, [response?.action, fetchEnrollment]);
121
- useEffect(() => {
122
- return () => {
123
- if (readyTimeoutRef.current != null) {
124
- window.clearTimeout(readyTimeoutRef.current);
125
- }
126
- };
127
- }, []);
128
- // --- Render ---
129
- if (requiresLegalNameBeforeEnrollment && legalName == null) {
130
- if (!kycAccepted) {
131
- return (_jsx(AccountKycInfoPage, { node: node, onContinue: () => setKycAccepted(true), onBack: onBack }));
132
- }
133
- return (_jsx(AccountLegalNamePage, { onBack: () => setKycAccepted(false), onSubmit: (name) => {
134
- setLegalName(name);
135
- } }));
136
- }
152
+ const delayMs = enrollmentPollingDelay(step.interaction);
153
+ if (delayMs == null)
154
+ return;
155
+ const expectedInteraction = enrollmentInteractionIdentity(step);
156
+ const timeout = window.setTimeout(() => {
157
+ void refreshEnrollmentRef.current(expectedInteraction);
158
+ }, delayMs);
159
+ return () => window.clearTimeout(timeout);
160
+ }, [step]);
137
161
  if (isLoading) {
138
- return rail === "apple_pay" ? (_jsx(PhoneEntrySkeleton, { onBack: onBack })) : (_jsx(AccountKycInfoSkeleton, { node: node, onBack: onBack }));
162
+ return (_jsx(EnrollmentWaiting, { title: t.loading, label: t.loading, onBack: onBack }));
163
+ }
164
+ if (errorMessage) {
165
+ return (_jsx(ErrorPage, { message: errorMessage, sessionId: sessionId, retryText: t.tryAgain, onRetry: () => void refreshEnrollment() }));
139
166
  }
140
- if (!response)
167
+ if (!step)
141
168
  return null;
142
- switch (response.action) {
143
- case "kyc_required":
144
- if (!kycAccepted) {
145
- return (_jsx(AccountKycInfoPage, { node: node, onContinue: () => setKycAccepted(true), onBack: onBack }));
146
- }
147
- return (_jsx(HostedEnrollmentPage, { node: node, step: response, platform: platform, onBack: () => setKycAccepted(false) }));
148
- case "kyc_retry":
149
- return (_jsx(HostedEnrollmentPage, { node: node, step: response, platform: platform, onBack: onBack }));
150
- case "kyc_pending_review":
151
- return (_jsx(EnrollmentReviewSubmitted, { title: t.accountEnrollmentPending, message: t.accountEnrollmentPendingDesc, onBack: onBack }));
152
- case "enrollment_form_required":
153
- return (_jsx(AccountEnrollmentFormPage, { form: response.form, onBack: onBack, onSubmitted: (result) => applyEnrollmentResult(result, response.action) }));
154
- case "hosted_kyc_required":
155
- return (_jsx(HostedEnrollmentPage, { node: node, step: response, platform: platform, onBack: onBack }));
156
- case "hosted_agreement_required":
157
- return (_jsx(HostedEnrollmentPage, { node: node, step: response, platform: platform, onBack: onBack }));
158
- case "provider_pending":
159
- return (_jsx(EnrollmentWaiting, { title: t.accountProviderPending, label: t.accountProviderPendingDesc }));
160
- case "kyc_rejected_final":
161
- return (_jsx(EnrollmentTerminal, { title: t.accountEnrollmentRejected, message: response.reason, sessionId: sessionId }));
162
- case "not_eligible":
163
- return (_jsx(EnrollmentIneligible, { message: response.reason, sessionId: sessionId, onBack: onBack }));
169
+ const interaction = step.interaction;
170
+ switch (interaction.kind) {
171
+ case "form":
172
+ return (_jsx(AccountEnrollmentFormPage, { interaction: interaction, onBack: onBack, onSubmit: (actionId, input) => submitAction(step, actionId, input) }, enrollmentInteractionIdentity(step)));
173
+ case "otp":
174
+ return (_jsx(EnrollmentOtpPage, { interaction: interaction, onBack: onBack, onSubmit: (actionId, input) => submitAction(step, actionId, input) }, enrollmentInteractionIdentity(step)));
175
+ case "account-phone-verification":
176
+ return _jsx(EnrollmentWaiting, { title: t.accountPhone, onBack: onBack });
177
+ case "hosted":
178
+ return (_jsx(EnrollmentHostedActionPage, { node: node, platform: platform, url: interaction.url, title: interaction.copy.title, description: interaction.copy.description, actionLabel: interaction.copy.openExternalLabel, purpose: interaction.purpose, autoSubmitDelayMs: interaction.returnBehavior.autoSubmitDelayMs, onBack: onBack, onReturn: () => submitAction(step, interaction.returnBehavior.action.id, {
179
+ kind: "continue",
180
+ }) }, enrollmentInteractionIdentity(step)));
181
+ case "wait":
182
+ return interaction.reason === "review" ? (_jsx(EnrollmentReviewSubmitted, { title: t.accountEnrollmentPending, message: t.accountEnrollmentPendingDesc, onBack: onBack })) : (_jsx(EnrollmentWaiting, { title: t.accountProviderPending, label: t.accountProviderPendingDesc, onBack: onBack }));
183
+ case "retry":
184
+ return interaction.link ? (_jsx(EnrollmentHostedActionPage, { node: node, platform: platform, url: interaction.link.url, title: interaction.link.copy.title, description: `${interaction.reason}\n\n${interaction.link.copy.description}`, actionLabel: interaction.link.copy.openExternalLabel, purpose: "identity-verification", onBack: onBack, onReturn: () => submitAction(step, interaction.action.id, { kind: "retry" }) }, enrollmentInteractionIdentity(step))) : (_jsx(ErrorPage, { message: interaction.reason, sessionId: sessionId, retryText: t.tryAgain, onRetry: () => void submitAction(step, interaction.action.id, { kind: "retry" }) }));
185
+ case "rejection":
186
+ return (_jsx(EnrollmentTerminal, { title: t.accountEnrollmentRejected, message: interaction.reason, sessionId: sessionId }));
187
+ case "ineligible":
188
+ return (_jsx(EnrollmentIneligible, { message: interaction.reason, sessionId: sessionId, onBack: onBack }));
164
189
  case "suspended":
165
- return (_jsx(EnrollmentTerminal, { title: t.accountSuspended, message: response.reason, sessionId: sessionId }));
166
- case "error":
167
- return (_jsx(ErrorPage, { message: response.message, sessionId: sessionId, retryText: t.tryAgain, onRetry: response.retryable ? fetchEnrollment : undefined, hideRetry: !response.retryable }));
168
- case "phone_required":
169
- // Navigation is triggered in fetchEnrollment; render a waiting state
170
- // here to avoid flicker until the modal pushes the phone screen.
171
- return _jsx(PhoneEntrySkeleton, { onBack: onBack });
172
- case "provider_otp_required":
173
- return _jsx(PhoneEntrySkeleton, { onBack: onBack });
190
+ return (_jsx(EnrollmentTerminal, { title: t.accountSuspended, message: interaction.reason, sessionId: sessionId }));
191
+ case "error": {
192
+ const retryAction = interaction.retryAction;
193
+ return (_jsx(ErrorPage, { message: interaction.message, sessionId: sessionId, retryText: t.tryAgain, onRetry: interaction.retryable && retryAction
194
+ ? () => void submitAction(step, retryAction.id, {
195
+ kind: "retry",
196
+ })
197
+ : undefined, hideRetry: !interaction.retryable || !retryAction }));
198
+ }
174
199
  case "active":
175
200
  return null;
176
- default:
177
- return assertUnreachable(response);
178
201
  }
179
202
  }
180
- // --- Sub-components ---
181
- function AccountEnrollmentFormPage({ form, onBack, onSubmitted, }) {
182
- const account = useAccountFlow();
183
- const client = useDaimoClient();
203
+ function AccountEnrollmentFormPage({ interaction, onBack, onSubmit, }) {
184
204
  const submitForm = async (values) => {
185
- if (!account) {
186
- return { ok: false, fieldErrors: { _form: t.errorConnectionLost } };
187
- }
188
- const token = await account.getAccessToken();
189
- if (!token) {
190
- return { ok: false, fieldErrors: { _form: t.errorConnectionLost } };
191
- }
205
+ let input;
192
206
  try {
193
- const result = await client.account.submitEnrollmentForm({
194
- formId: form.id,
195
- revision: form.revision,
196
- values,
197
- locale: getLocale(),
198
- }, { bearerToken: token });
199
- onSubmitted(result);
200
- return { ok: true };
207
+ input = enrollmentFormActionInput(interaction, values);
201
208
  }
202
- catch (err) {
203
- console.error("[enrollment] form submit failed:", err);
209
+ catch {
204
210
  return { ok: false, fieldErrors: { _form: t.errorGeneric } };
205
211
  }
212
+ const result = await onSubmit(interaction.action.id, input);
213
+ if (!result) {
214
+ return { ok: false, fieldErrors: { _form: t.errorGeneric } };
215
+ }
216
+ if (result.interaction.kind === "form") {
217
+ return {
218
+ ok: false,
219
+ fieldErrors: result.interaction.form.fieldErrors ?? {
220
+ _form: t.errorGeneric,
221
+ },
222
+ };
223
+ }
224
+ return { ok: true };
206
225
  };
207
- return (_jsx(PaginatedEnrollmentForm, { form: form, onBack: onBack, onSubmit: submitForm }));
226
+ return (_jsx(PaginatedEnrollmentForm, { form: interaction.form, onBack: onBack, onSubmit: submitForm }));
208
227
  }
209
- function AccountLegalNamePage({ onBack, onSubmit, }) {
210
- const { formState: { errors, isValid }, handleSubmit, register, } = useForm({
211
- resolver: zodResolver(zLegalNameForm),
212
- mode: "onChange",
213
- defaultValues: { firstName: "", lastName: "" },
214
- });
215
- return (_jsxs("div", { className: "daimo-flex daimo-flex-col daimo-flex-1 daimo-min-h-0", children: [_jsx(PageHeader, { title: t.accountLegalNameTitle, onBack: onBack }), _jsxs("form", { className: "daimo-flex daimo-flex-col daimo-flex-1 daimo-min-h-0", onSubmit: handleSubmit(onSubmit), children: [_jsx(CenteredContent, { children: _jsxs("div", { className: "daimo-flex daimo-w-full daimo-max-w-xs daimo-flex-col daimo-gap-4", children: [_jsx("p", { className: "daimo-text-center daimo-text-sm daimo-leading-relaxed daimo-text-[var(--daimo-text-secondary)]", children: t.accountLegalNameDesc }), _jsxs("div", { className: "daimo-flex daimo-flex-col daimo-gap-3", children: [_jsx(DaimoFormField, { label: t.accountLegalNameFirst, error: errors.firstName?.message, children: ({ id, describedBy, invalid }) => (_jsx(DaimoTextField, { ...register("firstName"), id: id, type: "text", "aria-describedby": describedBy, invalid: invalid, autoComplete: "given-name", autoFocus: true, className: "daimo-px-4 daimo-py-3" })) }), _jsx(DaimoFormField, { label: t.accountLegalNameLast, error: errors.lastName?.message, children: ({ id, describedBy, invalid }) => (_jsx(DaimoTextField, { ...register("lastName"), id: id, type: "text", "aria-describedby": describedBy, invalid: invalid, autoComplete: "family-name", className: "daimo-px-4 daimo-py-3" })) })] })] }) }), _jsx("div", { className: "daimo-px-6 daimo-pb-6 daimo-flex daimo-flex-col daimo-items-center", children: _jsx(PrimaryButton, { type: "submit", disabled: !isValid, children: t.continue }) })] })] }));
228
+ function EnrollmentOtpPage({ interaction, onBack, onSubmit, }) {
229
+ const handleVerify = async (code) => {
230
+ const result = await onSubmit(interaction.submitAction.id, {
231
+ kind: "otp",
232
+ code,
233
+ });
234
+ if (!result)
235
+ return { ok: false, msg: t.errorGeneric };
236
+ if (result.interaction.kind === "otp") {
237
+ return {
238
+ ok: false,
239
+ msg: result.interaction.copy.invalidMessage,
240
+ };
241
+ }
242
+ return { ok: true };
243
+ };
244
+ const handleResend = async () => {
245
+ await onSubmit(interaction.resend.action.id, { kind: "resend-otp" });
246
+ };
247
+ return (_jsx(AccountOtpCodeEntry, { destination: interaction.destination, title: interaction.copy.title, message: interaction.copy.message, invalidMessage: interaction.copy.invalidMessage, resendDelayMs: interaction.resend.delayMs, onBack: onBack, onVerified: () => undefined, onVerify: handleVerify, onResend: handleResend }));
216
248
  }
217
- function PhoneEntrySkeleton({ onBack }) {
218
- return (_jsxs("div", { className: "daimo-flex daimo-flex-col daimo-flex-1 daimo-min-h-0", "aria-busy": "true", "aria-label": t.loading, children: [_jsx(PageHeader, { title: t.accountPhone, onBack: onBack }), _jsxs(CenteredContent, { children: [_jsx(Skeleton, { className: "daimo-h-4 daimo-w-full daimo-max-w-[300px]", rounded: "sm" }), _jsx(Skeleton, { className: "daimo-h-[56px] daimo-w-full daimo-max-w-xs" })] }), _jsx("div", { className: "daimo-px-6 daimo-pb-6 daimo-flex daimo-flex-col daimo-items-center", children: _jsx(Skeleton, { className: "daimo-h-[54px] daimo-w-full daimo-max-w-xs" }) })] }));
249
+ function EnrollmentHostedActionPage({ node, platform, url, title, description, actionLabel, purpose, autoSubmitDelayMs, onBack, onReturn, }) {
250
+ const cleanupRef = useRef(() => undefined);
251
+ const returnSubmittedRef = useRef(false);
252
+ const [isSubmitting, setIsSubmitting] = useState(false);
253
+ useEffect(() => () => cleanupRef.current(), []);
254
+ const submitReturn = useCallback(() => {
255
+ if (returnSubmittedRef.current)
256
+ return;
257
+ returnSubmittedRef.current = true;
258
+ cleanupRef.current();
259
+ setIsSubmitting(true);
260
+ void onReturn().finally(() => setIsSubmitting(false));
261
+ }, [onReturn]);
262
+ const openHostedStep = useCallback(() => {
263
+ cleanupRef.current();
264
+ returnSubmittedRef.current = false;
265
+ openExternalUrl(url, platform, purpose === "agreement" ? "daimo-agreement" : "daimo-verification", "width=500,height=760");
266
+ const timing = enrollmentHostedReturnTiming(autoSubmitDelayMs);
267
+ if (timing.kind === "auto") {
268
+ setIsSubmitting(true);
269
+ const timeout = window.setTimeout(submitReturn, timing.delayMs);
270
+ cleanupRef.current = () => window.clearTimeout(timeout);
271
+ return;
272
+ }
273
+ let armed = false;
274
+ const armTimeout = window.setTimeout(() => {
275
+ armed = true;
276
+ }, 0);
277
+ const handleReturn = () => {
278
+ if (!armed || document.visibilityState === "hidden")
279
+ return;
280
+ submitReturn();
281
+ };
282
+ window.addEventListener("focus", handleReturn);
283
+ window.addEventListener("pageshow", handleReturn);
284
+ document.addEventListener("visibilitychange", handleReturn);
285
+ cleanupRef.current = () => {
286
+ window.clearTimeout(armTimeout);
287
+ window.removeEventListener("focus", handleReturn);
288
+ window.removeEventListener("pageshow", handleReturn);
289
+ document.removeEventListener("visibilitychange", handleReturn);
290
+ };
291
+ }, [autoSubmitDelayMs, platform, purpose, submitReturn, url]);
292
+ return (_jsx(EnrollmentExternalActionPage, { title: title, description: description, actionLabel: isSubmitting ? t.loading : actionLabel, icon: purpose === "identity-verification" ? (_jsx(KycIndicator, { requirement: getKycRequirement(node.kycRequirement), size: "xl", variant: "badge" })) : null, onBack: onBack, onOpen: openHostedStep, disabled: isSubmitting }));
293
+ }
294
+ function EnrollmentExternalActionPage({ title, description, actionLabel, icon, onBack, onOpen, disabled, }) {
295
+ return (_jsxs("div", { className: "daimo-flex daimo-flex-col daimo-flex-1 daimo-min-h-0", children: [_jsx(PageHeader, { title: title, onBack: onBack }), _jsxs(CenteredContent, { children: [icon, _jsx("p", { className: "daimo-text-[var(--daimo-text-secondary)] daimo-text-center daimo-max-w-xs daimo-text-sm daimo-whitespace-pre-line", children: description }), _jsx(PrimaryButton, { onClick: onOpen, disabled: disabled, icon: _jsx(ExternalLinkIcon, { size: 16 }), children: actionLabel })] })] }));
219
296
  }
220
297
  function EnrollmentIneligible({ message, sessionId, onBack, }) {
221
298
  return (_jsxs("div", { className: "daimo-flex daimo-flex-col daimo-flex-1 daimo-min-h-0", children: [_jsx(PageHeader, { title: t.accountRegionUnavailableTitle, onBack: onBack }), _jsx(CenteredContent, { children: _jsxs("div", { className: "daimo-flex daimo-flex-col daimo-items-center daimo-gap-4 daimo-px-6 daimo-text-center", children: [_jsx("div", { className: "daimo-flex daimo-h-16 daimo-w-16 daimo-items-center daimo-justify-center daimo-rounded-full", style: {
222
299
  backgroundColor: "var(--daimo-warning-light, var(--daimo-surface-secondary))",
223
300
  }, children: _jsxs("svg", { width: "30", height: "30", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.9", strokeLinecap: "round", strokeLinejoin: "round", style: { color: "var(--daimo-warning, #f59e0b)" }, "aria-hidden": "true", children: [_jsx("path", { d: "M12 3 2.8 19a1 1 0 0 0 .87 1.5h16.66A1 1 0 0 0 21.2 19z" }), _jsx("path", { d: "M12 9v4.5" }), _jsx("path", { d: "M12 17h.01" })] }) }), _jsxs("div", { className: "daimo-flex daimo-flex-col daimo-gap-2", children: [_jsx("h2", { className: "daimo-text-xl daimo-font-semibold daimo-text-[var(--daimo-text)]", children: t.accountRegionUnavailableHeading }), _jsx("p", { className: "daimo-text-sm daimo-leading-relaxed daimo-text-[var(--daimo-text-secondary)]", children: message || t.accountRegionUnavailableDescription })] })] }) }), _jsxs("div", { className: "daimo-flex daimo-flex-col daimo-items-center daimo-gap-3 daimo-px-6 daimo-pb-6", children: [_jsx(SecondaryButton, { onClick: onBack, children: t.accountRegionUnavailableCta }), _jsx(ContactSupportButton, { subject: t.accountRegionUnavailableTitle, info: { sessionId, error: message } })] })] }));
224
301
  }
225
- /** Terminal error — specific title, error icon, message, and support link. */
226
302
  function EnrollmentTerminal({ title, message, sessionId, }) {
227
303
  return (_jsxs("div", { className: "daimo-flex daimo-flex-col daimo-flex-1 daimo-min-h-0", children: [_jsx(PageHeader, { title: title }), _jsxs("div", { className: "daimo-flex-1 daimo-flex daimo-flex-col daimo-items-center daimo-justify-center daimo-p-6 daimo-gap-6", children: [_jsx("div", { className: "daimo-w-16 daimo-h-16 daimo-rounded-full daimo-flex daimo-items-center daimo-justify-center", style: {
228
304
  backgroundColor: "var(--daimo-error-badge-bg)",
@@ -232,70 +308,28 @@ function EnrollmentTerminal({ title, message, sessionId, }) {
232
308
  function EnrollmentReviewSubmitted({ title, message, onBack, }) {
233
309
  return (_jsxs("div", { className: "daimo-flex daimo-flex-col daimo-flex-1 daimo-min-h-0", children: [_jsx(PageHeader, { title: t.accountHostedKycTitle, onBack: onBack }), _jsx(CenteredContent, { children: _jsxs("div", { className: "daimo-flex daimo-w-full daimo-max-w-[320px] daimo-flex-col daimo-items-center daimo-gap-5 daimo-px-6 daimo-text-center", children: [_jsx("div", { className: "daimo-flex daimo-h-16 daimo-w-16 daimo-items-center daimo-justify-center daimo-rounded-full", style: { backgroundColor: "var(--daimo-success-light)" }, "aria-hidden": "true", children: _jsx(CheckIcon, { size: 34 }) }), _jsxs("div", { className: "daimo-flex daimo-flex-col daimo-gap-2", children: [_jsx("h2", { className: "daimo-text-xl daimo-font-semibold daimo-text-[var(--daimo-text)]", children: title }), _jsx("p", { className: "daimo-text-sm daimo-leading-relaxed daimo-text-[var(--daimo-text-secondary)]", children: message })] })] }) })] }));
234
310
  }
235
- /** Waiting view — stable skeleton placeholders for advancing account states. */
236
311
  function EnrollmentWaiting({ title, label, onBack, }) {
237
- return (_jsxs("div", { className: "daimo-flex daimo-flex-col daimo-flex-1 daimo-min-h-0", children: [_jsx(PageHeader, { title: title, onBack: onBack }), _jsx(CenteredContent, { children: _jsxs("div", { className: "daimo-flex daimo-w-full daimo-max-w-[260px] daimo-flex-col daimo-items-center daimo-gap-4", "aria-busy": "true", "aria-label": label ?? t.loading, children: [_jsx(Skeleton, { className: "daimo-h-14 daimo-w-14", rounded: "full" }), _jsx(SkeletonText, { lines: label ? 2 : 1, widths: label ? ["88%", "64%"] : ["56%"] })] }) })] }));
238
- }
239
- /** Hosted enrollment step. Polling drives completion. */
240
- function HostedEnrollmentPage({ node, step, platform, onBack, }) {
241
- const isKyc = step.action !== "hosted_agreement_required";
242
- const openHostedStep = useCallback(() => {
243
- openExternalUrl(step.url, platform, externalWindowName(step), "width=500,height=760");
244
- }, [platform, step]);
245
- return (_jsx(EnrollmentExternalActionPage, { title: externalActionTitle(step), description: externalActionDescription(step, platform), actionLabel: externalActionLabel(step), icon: isKyc ? (_jsx(KycIndicator, { requirement: getKycRequirement(node.kycRequirement), size: "xl", variant: "badge" })) : null, onBack: onBack, onOpen: openHostedStep }));
246
- }
247
- function EnrollmentExternalActionPage({ title, description, actionLabel, icon, onBack, onOpen, }) {
248
- return (_jsxs("div", { className: "daimo-flex daimo-flex-col daimo-flex-1 daimo-min-h-0", children: [_jsx(PageHeader, { title: title, onBack: onBack }), _jsxs(CenteredContent, { children: [icon, _jsx("p", { className: "daimo-text-[var(--daimo-text-secondary)] daimo-text-center daimo-max-w-xs daimo-text-sm daimo-whitespace-pre-line", children: description }), _jsx(PrimaryButton, { onClick: onOpen, icon: _jsx(ExternalLinkIcon, { size: 16 }), children: actionLabel })] })] }));
249
- }
250
- /** Whether this hosted step is the partner liveness check (vs general KYC). */
251
- function isLivenessStep(step) {
252
- return step.action === "hosted_kyc_required";
312
+ return (_jsxs("div", { className: "daimo-flex daimo-flex-col daimo-flex-1 daimo-min-h-0", children: [_jsx(PageHeader, { title: title, onBack: onBack }), _jsx(CenteredContent, { children: _jsxs("div", { className: "daimo-flex daimo-w-full daimo-max-w-[260px] daimo-flex-col daimo-items-center daimo-gap-4", "aria-busy": "true", "aria-live": "polite", "aria-label": label ?? t.loading, children: [_jsx(Skeleton, { className: "daimo-h-14 daimo-w-14", rounded: "full" }), _jsx(SkeletonText, { lines: label ? 2 : 1, widths: label ? ["88%", "64%"] : ["56%"] })] }) })] }));
253
313
  }
254
- function externalActionTitle(step) {
255
- if (step.title)
256
- return step.title;
257
- return isLivenessStep(step)
258
- ? t.accountHostedLivenessTitle
259
- : t.accountHostedKycTitle;
260
- }
261
- function externalActionDescription(step, platform) {
262
- if (step.action === "hosted_agreement_required") {
263
- const handoff = isDesktop(platform)
264
- ? t.accountHostedActionDesktopSuffix
265
- : t.accountHostedActionMobileSuffix;
266
- return `${step.description} ${handoff}`;
267
- }
268
- if (step.description)
269
- return step.description;
270
- const base = isLivenessStep(step)
271
- ? t.accountHostedLivenessDesc
272
- : isDesktop(platform)
273
- ? t.accountHostedKycDesktopDesc
274
- : t.accountHostedKycMobileDesc;
275
- if (step.action === "kyc_retry") {
276
- return `${step.reason}\n\n${base}`;
277
- }
278
- return base;
279
- }
280
- function externalActionLabel(step) {
281
- if (step.openExternalLabel)
282
- return step.openExternalLabel;
283
- return isLivenessStep(step)
284
- ? t.accountHostedLivenessCta
285
- : t.accountHostedKycCta;
286
- }
287
- function externalWindowName(step) {
288
- return step.action === "hosted_agreement_required"
289
- ? "daimo-terms"
290
- : "daimo-verification";
314
+ function getLegacyCopy(platform) {
315
+ return {
316
+ verification: {
317
+ title: t.accountHostedKycTitle,
318
+ description: isDesktop(platform)
319
+ ? t.accountHostedKycDesktopDesc
320
+ : t.accountHostedKycMobileDesc,
321
+ openExternalLabel: t.accountHostedKycCta,
322
+ },
323
+ liveness: {
324
+ title: t.accountHostedLivenessTitle,
325
+ description: t.accountHostedLivenessDesc,
326
+ openExternalLabel: t.accountHostedLivenessCta,
327
+ },
328
+ };
291
329
  }
292
330
  function openExternalUrl(url, platform, target, features) {
293
- if (isDesktop(platform)) {
331
+ if (isDesktop(platform))
294
332
  return window.open(url, target, features);
295
- }
296
333
  return window.open(url, "_blank");
297
334
  }
298
- function assertUnreachable(value) {
299
- throw new Error(`unhandled enrollment response: ${JSON.stringify(value)}`);
300
- }
301
335
  //# sourceMappingURL=AccountEnrollmentPage.js.map