@fluid-app/portal-sdk 0.1.511 → 0.1.512
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/{ContactsScreen-9uwS06kQ.mjs → ContactsScreen-DVGoPMxo.mjs} +2 -0
- package/dist/{FluidProvider-BiCeYuLV.mjs → FluidProvider-BwYSWXvD.mjs} +35 -35
- package/dist/{FluidProvider-BiCeYuLV.mjs.map → FluidProvider-BwYSWXvD.mjs.map} +1 -1
- package/dist/{FluidProvider--nibp8IV.cjs → FluidProvider-jiBsFzwX.cjs} +35 -35
- package/dist/{FluidProvider--nibp8IV.cjs.map → FluidProvider-jiBsFzwX.cjs.map} +1 -1
- package/dist/{MessagingScreen-BORvUGna.cjs → MessagingScreen-BoPOajsJ.cjs} +2 -2
- package/dist/{MessagingScreen-SUZcjJhr.cjs → MessagingScreen-CbS-I_AD.cjs} +2 -2
- package/dist/{MessagingScreen-SUZcjJhr.cjs.map → MessagingScreen-CbS-I_AD.cjs.map} +1 -1
- package/dist/{MessagingScreen-BqkBe42a.mjs → MessagingScreen-DXEazJ1u.mjs} +5 -2
- package/dist/{MessagingScreen-DQRVATl3.mjs → MessagingScreen-DmFW-md3.mjs} +2 -2
- package/dist/{MessagingScreen-DQRVATl3.mjs.map → MessagingScreen-DmFW-md3.mjs.map} +1 -1
- package/dist/{MySiteScreen-CmuWTTHD.mjs → MySiteScreen-BxF5RFtm.mjs} +1 -0
- package/dist/{OrdersScreen-CyGANI31.cjs → OrdersScreen-CC66apSh.cjs} +2 -2
- package/dist/{OrdersScreen-KuFZ1yvM.mjs → OrdersScreen-DPmWvnMk.mjs} +5 -2
- package/dist/{OrdersScreen-z5tc-nBP.mjs → OrdersScreen-DtMYxhYh.mjs} +2 -2
- package/dist/{OrdersScreen-z5tc-nBP.mjs.map → OrdersScreen-DtMYxhYh.mjs.map} +1 -1
- package/dist/{OrdersScreen-CaZvXkul.cjs → OrdersScreen-sy6AG47r.cjs} +2 -2
- package/dist/{OrdersScreen-CaZvXkul.cjs.map → OrdersScreen-sy6AG47r.cjs.map} +1 -1
- package/dist/{ProfileScreen-CQAMGoLW.mjs → ProfileScreen-CTYwLHGQ.mjs} +6 -3
- package/dist/{ProfileScreen-wqtz71Jn.mjs → ProfileScreen-GdwPz5rK.mjs} +2 -2
- package/dist/{ProfileScreen-wqtz71Jn.mjs.map → ProfileScreen-GdwPz5rK.mjs.map} +1 -1
- package/dist/{ProfileScreen-BOjKptWG.cjs → ProfileScreen-ZVIawSmq.cjs} +2 -2
- package/dist/{ProfileScreen-BOjKptWG.cjs.map → ProfileScreen-ZVIawSmq.cjs.map} +1 -1
- package/dist/{ProfileScreen-BT3Mt1y1.cjs → ProfileScreen-yIYYpQ2N.cjs} +3 -3
- package/dist/{ShareablesScreen-0cse1_-D.mjs → ShareablesScreen-JMjElYlz.mjs} +3 -0
- package/dist/{ShopScreen-DSSoDy5O.mjs → ShopScreen-80D3hiO0.mjs} +2 -0
- package/dist/{SubscriptionsScreen-DfoCjsPl.mjs → SubscriptionsScreen-BgMCPJx0.mjs} +3 -3
- package/dist/{SubscriptionsScreen-DfoCjsPl.mjs.map → SubscriptionsScreen-BgMCPJx0.mjs.map} +1 -1
- package/dist/{SubscriptionsScreen-DiF_pJWA.cjs → SubscriptionsScreen-CZz0wQ9G.cjs} +3 -3
- package/dist/{SubscriptionsScreen-DiF_pJWA.cjs.map → SubscriptionsScreen-CZz0wQ9G.cjs.map} +1 -1
- package/dist/{SubscriptionsScreen-DNPANUMS.cjs → SubscriptionsScreen-j0BROH4n.cjs} +3 -3
- package/dist/{SubscriptionsScreen-Bq6eMkoN.mjs → SubscriptionsScreen-uWXwxZHg.mjs} +6 -3
- package/dist/{ar-a5XheqF4.cjs → ar-BRTqPIQm.cjs} +2 -1
- package/dist/ar-BRTqPIQm.cjs.map +1 -0
- package/dist/{ar-DzFfeuH6.mjs → ar-Bdmxegli.mjs} +2 -1
- package/dist/ar-Bdmxegli.mjs.map +1 -0
- package/dist/{bg-E4rjQ5VN.cjs → bg-QPLVQePh.cjs} +2 -1
- package/dist/bg-QPLVQePh.cjs.map +1 -0
- package/dist/{bg-CcHDDtuc.mjs → bg-Qa4MSxXf.mjs} +2 -1
- package/dist/bg-Qa4MSxXf.mjs.map +1 -0
- package/dist/{bn-BzPHQVQQ.cjs → bn-DHoCNlnT.cjs} +2 -1
- package/dist/bn-DHoCNlnT.cjs.map +1 -0
- package/dist/{bn-BaTYefLg.mjs → bn-u0Y6Pv02.mjs} +2 -1
- package/dist/bn-u0Y6Pv02.mjs.map +1 -0
- package/dist/{cs-BDNOATcV.cjs → cs-DPyeI1gt.cjs} +2 -1
- package/dist/cs-DPyeI1gt.cjs.map +1 -0
- package/dist/{cs-CKzroIj9.mjs → cs-Dp9PPgM6.mjs} +2 -1
- package/dist/cs-Dp9PPgM6.mjs.map +1 -0
- package/dist/{da-Cg-epQHP.cjs → da-BKrHgpc1.cjs} +2 -1
- package/dist/da-BKrHgpc1.cjs.map +1 -0
- package/dist/{da-D6jqtE6K.mjs → da-VuA-GrRb.mjs} +2 -1
- package/dist/da-VuA-GrRb.mjs.map +1 -0
- package/dist/{de-LTtnZcP6.mjs → de-9vk6k0nJ.mjs} +2 -1
- package/dist/de-9vk6k0nJ.mjs.map +1 -0
- package/dist/{de-DExsPlF0.cjs → de-BOG93PI8.cjs} +2 -1
- package/dist/de-BOG93PI8.cjs.map +1 -0
- package/dist/{el-PhsTmMc4.cjs → el-CYZv1P0r.cjs} +2 -1
- package/dist/el-CYZv1P0r.cjs.map +1 -0
- package/dist/{el-CLOA4Iht.mjs → el-DXPx1g2c.mjs} +2 -1
- package/dist/el-DXPx1g2c.mjs.map +1 -0
- package/dist/{es-CuD_WTjc.mjs → es-BB85bwJ_.mjs} +2 -1
- package/dist/es-BB85bwJ_.mjs.map +1 -0
- package/dist/{es-BO79JXnd.cjs → es-G6bSRkdk.cjs} +2 -1
- package/dist/es-G6bSRkdk.cjs.map +1 -0
- package/dist/{fi-B4gfHXKw.cjs → fi-BUV6jW3T.cjs} +2 -1
- package/dist/fi-BUV6jW3T.cjs.map +1 -0
- package/dist/{fi-D10qDpB_.mjs → fi-D-TtktPt.mjs} +2 -1
- package/dist/fi-D-TtktPt.mjs.map +1 -0
- package/dist/{fr-BLII0ePc.mjs → fr--BgxXkpf.mjs} +2 -1
- package/dist/fr--BgxXkpf.mjs.map +1 -0
- package/dist/{fr-CMBprdKc.cjs → fr-dhVoJgWK.cjs} +2 -1
- package/dist/fr-dhVoJgWK.cjs.map +1 -0
- package/dist/{he-CMDK884V.mjs → he-CDTvXkZd.mjs} +2 -1
- package/dist/he-CDTvXkZd.mjs.map +1 -0
- package/dist/{he-Cm3TmloM.cjs → he-Do9yqDxB.cjs} +2 -1
- package/dist/he-Do9yqDxB.cjs.map +1 -0
- package/dist/{hi-Cm_DH4G0.cjs → hi-AiRJhk6a.cjs} +2 -1
- package/dist/hi-AiRJhk6a.cjs.map +1 -0
- package/dist/{hi-CUx-Aq1K.mjs → hi-CjRrL1Q7.mjs} +2 -1
- package/dist/hi-CjRrL1Q7.mjs.map +1 -0
- package/dist/{hr-DBY2Lt8Y.mjs → hr-B0nd9e9C.mjs} +2 -1
- package/dist/hr-B0nd9e9C.mjs.map +1 -0
- package/dist/{hr-Bfcyy_rR.cjs → hr-DqJVAx7M.cjs} +2 -1
- package/dist/hr-DqJVAx7M.cjs.map +1 -0
- package/dist/{hu-BTYlpv8x.cjs → hu-DVgZpQ2J.cjs} +2 -1
- package/dist/hu-DVgZpQ2J.cjs.map +1 -0
- package/dist/{hu-CFdlLxix.mjs → hu-yj7Fc4o9.mjs} +2 -1
- package/dist/hu-yj7Fc4o9.mjs.map +1 -0
- package/dist/{id-DpB12DnB.cjs → id-DM2xUNOq.cjs} +2 -1
- package/dist/id-DM2xUNOq.cjs.map +1 -0
- package/dist/{id-CLnXnsUI.mjs → id-DOqWgn6h.mjs} +2 -1
- package/dist/id-DOqWgn6h.mjs.map +1 -0
- package/dist/index.cjs +14 -14
- package/dist/index.mjs +22 -22
- package/dist/{it-Nmq4disb.cjs → it-BAS4gSTn.cjs} +2 -1
- package/dist/it-BAS4gSTn.cjs.map +1 -0
- package/dist/{it-Dnm3Ubcb.mjs → it-C98SovBr.mjs} +2 -1
- package/dist/it-C98SovBr.mjs.map +1 -0
- package/dist/{ja-D__pQNSM.cjs → ja-BWYAe0zp.cjs} +2 -1
- package/dist/ja-BWYAe0zp.cjs.map +1 -0
- package/dist/{ja-ZDGpYIT9.mjs → ja-C716ev_g.mjs} +2 -1
- package/dist/ja-C716ev_g.mjs.map +1 -0
- package/dist/{ko-BAKmWypV.mjs → ko-C4vWj-M9.mjs} +2 -1
- package/dist/ko-C4vWj-M9.mjs.map +1 -0
- package/dist/{ko-BGQ9Vnh-.cjs → ko-CgTaued5.cjs} +2 -1
- package/dist/ko-CgTaued5.cjs.map +1 -0
- package/dist/{ms-6IGsCaks.mjs → ms-BY0Pxptn.mjs} +2 -1
- package/dist/ms-BY0Pxptn.mjs.map +1 -0
- package/dist/{ms-Bq2pHRM-.cjs → ms-JIbuoytI.cjs} +2 -1
- package/dist/ms-JIbuoytI.cjs.map +1 -0
- package/dist/{nl-l-MVSomn.mjs → nl-C9HE9V_v.mjs} +2 -1
- package/dist/nl-C9HE9V_v.mjs.map +1 -0
- package/dist/{nl-DHrQ875w.cjs → nl-haNh87L1.cjs} +2 -1
- package/dist/nl-haNh87L1.cjs.map +1 -0
- package/dist/{no-KpFMm1AJ.mjs → no-Blcb2-Cz.mjs} +2 -1
- package/dist/no-Blcb2-Cz.mjs.map +1 -0
- package/dist/{no-R3-EB5Co.cjs → no-CzSXTPnT.cjs} +2 -1
- package/dist/no-CzSXTPnT.cjs.map +1 -0
- package/dist/{pl-Bca2Pq5-.mjs → pl-CCpUmitV.mjs} +2 -1
- package/dist/pl-CCpUmitV.mjs.map +1 -0
- package/dist/{pl-Cd_YrfPg.cjs → pl-CUPFZTSC.cjs} +2 -1
- package/dist/pl-CUPFZTSC.cjs.map +1 -0
- package/dist/{pt-CIkRdYeG.mjs → pt-CIxZRWyv.mjs} +2 -1
- package/dist/pt-CIxZRWyv.mjs.map +1 -0
- package/dist/{pt-DIiHu6Mp.cjs → pt-D3RNC97N.cjs} +2 -1
- package/dist/pt-D3RNC97N.cjs.map +1 -0
- package/dist/{ro-CiE-AxDf.mjs → ro-8P4MgS9f.mjs} +2 -1
- package/dist/ro-8P4MgS9f.mjs.map +1 -0
- package/dist/{ro-odHdLgL4.cjs → ro-D8z0fvE2.cjs} +2 -1
- package/dist/ro-D8z0fvE2.cjs.map +1 -0
- package/dist/{ru-D2OwVHj5.cjs → ru-CtmifJv4.cjs} +2 -1
- package/dist/ru-CtmifJv4.cjs.map +1 -0
- package/dist/{ru-BYdpmEiK.mjs → ru-lM0vNqkN.mjs} +2 -1
- package/dist/ru-lM0vNqkN.mjs.map +1 -0
- package/dist/{sk-DQiXACwE.mjs → sk-CgEjIW_S.mjs} +2 -1
- package/dist/sk-CgEjIW_S.mjs.map +1 -0
- package/dist/{sk-BaDSrJ8u.cjs → sk-DZxahVB3.cjs} +2 -1
- package/dist/sk-DZxahVB3.cjs.map +1 -0
- package/dist/{sv-Btkf1rNQ.mjs → sv-BWt6_WTg.mjs} +2 -1
- package/dist/sv-BWt6_WTg.mjs.map +1 -0
- package/dist/{sv-B6EUMOBb.cjs → sv-GC8OT1vt.cjs} +2 -1
- package/dist/sv-GC8OT1vt.cjs.map +1 -0
- package/dist/{th-Dhyq5YKF.mjs → th-CmUZlvpQ.mjs} +2 -1
- package/dist/th-CmUZlvpQ.mjs.map +1 -0
- package/dist/{th-D8g2gDha.cjs → th-DblYfjWT.cjs} +2 -1
- package/dist/th-DblYfjWT.cjs.map +1 -0
- package/dist/{tl-sxgiHAif.mjs → tl-C_hEnuMY.mjs} +2 -1
- package/dist/tl-C_hEnuMY.mjs.map +1 -0
- package/dist/{tl-tEocbrz2.cjs → tl-DLw-m_KB.cjs} +2 -1
- package/dist/tl-DLw-m_KB.cjs.map +1 -0
- package/dist/{tr-BtM6b91I.mjs → tr-Dfc8ydzD.mjs} +2 -1
- package/dist/tr-Dfc8ydzD.mjs.map +1 -0
- package/dist/{tr-BAyeQkex.cjs → tr-gaXTEiH1.cjs} +2 -1
- package/dist/tr-gaXTEiH1.cjs.map +1 -0
- package/dist/{uk-kvcTBcGh.cjs → uk-BA-lGtnm.cjs} +2 -1
- package/dist/uk-BA-lGtnm.cjs.map +1 -0
- package/dist/{uk-Cv_fKgTe.mjs → uk-wvHSaNjV.mjs} +2 -1
- package/dist/uk-wvHSaNjV.mjs.map +1 -0
- package/dist/{use-portal-card-add-3ds-flow-7umBe1LL.mjs → use-portal-card-add-3ds-flow-BqZulT6m.mjs} +2 -2
- package/dist/{use-portal-card-add-3ds-flow-7umBe1LL.mjs.map → use-portal-card-add-3ds-flow-BqZulT6m.mjs.map} +1 -1
- package/dist/{use-portal-card-add-3ds-flow-DXDPr80N.cjs → use-portal-card-add-3ds-flow-DCVXl0ky.cjs} +2 -2
- package/dist/{use-portal-card-add-3ds-flow-DXDPr80N.cjs.map → use-portal-card-add-3ds-flow-DCVXl0ky.cjs.map} +1 -1
- package/dist/utils/build-remote-widget-plugin-manifests.mjs +3 -0
- package/dist/utils/build-remote-widget-plugin-manifests.mjs.map +1 -1
- package/dist/utils/build-widget-registry.mjs +3 -0
- package/dist/{vi-D1M0pUmI.cjs → vi-5pYkRRAI.cjs} +2 -1
- package/dist/vi-5pYkRRAI.cjs.map +1 -0
- package/dist/{vi-B877Wvfs.mjs → vi-CI1vgr9K.mjs} +2 -1
- package/dist/vi-CI1vgr9K.mjs.map +1 -0
- package/dist/{zh_CN-BbzxVpys.cjs → zh_CN-CRA7Eajb.cjs} +2 -1
- package/dist/zh_CN-CRA7Eajb.cjs.map +1 -0
- package/dist/{zh_CN-DSesb0bt.mjs → zh_CN-DHfCPhjH.mjs} +2 -1
- package/dist/zh_CN-DHfCPhjH.mjs.map +1 -0
- package/dist/{zh_TW-BDxZdNH7.cjs → zh_TW-CAJScAfB.cjs} +2 -1
- package/dist/zh_TW-CAJScAfB.cjs.map +1 -0
- package/dist/{zh_TW-Bxz64eoL.mjs → zh_TW-eo1sgYEl.mjs} +2 -1
- package/dist/zh_TW-eo1sgYEl.mjs.map +1 -0
- package/package.json +16 -16
- package/dist/ar-DzFfeuH6.mjs.map +0 -1
- package/dist/ar-a5XheqF4.cjs.map +0 -1
- package/dist/bg-CcHDDtuc.mjs.map +0 -1
- package/dist/bg-E4rjQ5VN.cjs.map +0 -1
- package/dist/bn-BaTYefLg.mjs.map +0 -1
- package/dist/bn-BzPHQVQQ.cjs.map +0 -1
- package/dist/cs-BDNOATcV.cjs.map +0 -1
- package/dist/cs-CKzroIj9.mjs.map +0 -1
- package/dist/da-Cg-epQHP.cjs.map +0 -1
- package/dist/da-D6jqtE6K.mjs.map +0 -1
- package/dist/de-DExsPlF0.cjs.map +0 -1
- package/dist/de-LTtnZcP6.mjs.map +0 -1
- package/dist/el-CLOA4Iht.mjs.map +0 -1
- package/dist/el-PhsTmMc4.cjs.map +0 -1
- package/dist/es-BO79JXnd.cjs.map +0 -1
- package/dist/es-CuD_WTjc.mjs.map +0 -1
- package/dist/fi-B4gfHXKw.cjs.map +0 -1
- package/dist/fi-D10qDpB_.mjs.map +0 -1
- package/dist/fr-BLII0ePc.mjs.map +0 -1
- package/dist/fr-CMBprdKc.cjs.map +0 -1
- package/dist/he-CMDK884V.mjs.map +0 -1
- package/dist/he-Cm3TmloM.cjs.map +0 -1
- package/dist/hi-CUx-Aq1K.mjs.map +0 -1
- package/dist/hi-Cm_DH4G0.cjs.map +0 -1
- package/dist/hr-Bfcyy_rR.cjs.map +0 -1
- package/dist/hr-DBY2Lt8Y.mjs.map +0 -1
- package/dist/hu-BTYlpv8x.cjs.map +0 -1
- package/dist/hu-CFdlLxix.mjs.map +0 -1
- package/dist/id-CLnXnsUI.mjs.map +0 -1
- package/dist/id-DpB12DnB.cjs.map +0 -1
- package/dist/it-Dnm3Ubcb.mjs.map +0 -1
- package/dist/it-Nmq4disb.cjs.map +0 -1
- package/dist/ja-D__pQNSM.cjs.map +0 -1
- package/dist/ja-ZDGpYIT9.mjs.map +0 -1
- package/dist/ko-BAKmWypV.mjs.map +0 -1
- package/dist/ko-BGQ9Vnh-.cjs.map +0 -1
- package/dist/ms-6IGsCaks.mjs.map +0 -1
- package/dist/ms-Bq2pHRM-.cjs.map +0 -1
- package/dist/nl-DHrQ875w.cjs.map +0 -1
- package/dist/nl-l-MVSomn.mjs.map +0 -1
- package/dist/no-KpFMm1AJ.mjs.map +0 -1
- package/dist/no-R3-EB5Co.cjs.map +0 -1
- package/dist/pl-Bca2Pq5-.mjs.map +0 -1
- package/dist/pl-Cd_YrfPg.cjs.map +0 -1
- package/dist/pt-CIkRdYeG.mjs.map +0 -1
- package/dist/pt-DIiHu6Mp.cjs.map +0 -1
- package/dist/ro-CiE-AxDf.mjs.map +0 -1
- package/dist/ro-odHdLgL4.cjs.map +0 -1
- package/dist/ru-BYdpmEiK.mjs.map +0 -1
- package/dist/ru-D2OwVHj5.cjs.map +0 -1
- package/dist/sk-BaDSrJ8u.cjs.map +0 -1
- package/dist/sk-DQiXACwE.mjs.map +0 -1
- package/dist/sv-B6EUMOBb.cjs.map +0 -1
- package/dist/sv-Btkf1rNQ.mjs.map +0 -1
- package/dist/th-D8g2gDha.cjs.map +0 -1
- package/dist/th-Dhyq5YKF.mjs.map +0 -1
- package/dist/tl-sxgiHAif.mjs.map +0 -1
- package/dist/tl-tEocbrz2.cjs.map +0 -1
- package/dist/tr-BAyeQkex.cjs.map +0 -1
- package/dist/tr-BtM6b91I.mjs.map +0 -1
- package/dist/uk-Cv_fKgTe.mjs.map +0 -1
- package/dist/uk-kvcTBcGh.cjs.map +0 -1
- package/dist/vi-B877Wvfs.mjs.map +0 -1
- package/dist/vi-D1M0pUmI.cjs.map +0 -1
- package/dist/zh_CN-BbzxVpys.cjs.map +0 -1
- package/dist/zh_CN-DSesb0bt.mjs.map +0 -1
- package/dist/zh_TW-BDxZdNH7.cjs.map +0 -1
- package/dist/zh_TW-Bxz64eoL.mjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-portal-card-add-3ds-flow-7umBe1LL.mjs","names":["FormTextField","FormTextField","FormTextField"],"sources":["../../../profile/core/src/translation-api-context.ts","../src/providers/ProfileTranslationBridge.tsx","../../../profile/ui/src/components/ellipses-dropdown.tsx","../../../profile/ui/src/components/confirm-action-dialog.tsx","../../../profile/ui/src/components/form-fields.tsx","../../../profile/ui/src/components/user-info-dialog.tsx","../../../profile/ui/src/components/payment-method-card-internals.tsx","../../../platform/address-autocomplete/src/administrative-area.ts","../../../platform/address-autocomplete/src/components/AddressAutocompleteInput.tsx","../../../platform/address-fields/src/field-layout.ts","../../../profile/core/src/context.ts","../../../fluid-pay/core/src/context.ts","../../../fluid-pay/core/src/provider.tsx","../../../platform/address-fields/src/country-config.ts","../../../fluid-pay/core/src/utils/country-config.ts","../../../fluid-pay/core/src/hooks/use-country-states.ts","../../../profile/ui/src/components/edit-payment-method-dialog.tsx","../../../profile/ui/src/components/my-site-profile-section.tsx","../../../fluid-pay/ui/src/components/form-fields/FormTextField.tsx","../../../fluid-pay/ui/src/components/form-fields/FormComboboxField.tsx","../../../fluid-pay/ui/src/components/AddressFormDialog.tsx","../../../fluid-pay/ui/src/hooks/use-vgs-collect.ts","../../../fluid-pay/ui/src/components/CreditCardFormDialog.tsx","../../../fluid-pay/ui/src/components/VgsThreeDSModal.tsx","../../../fluid-pay/ui/src/hooks/three-ds-attempt.ts","../../../fluid-pay/ui/src/hooks/use-vgs-3ds-completion.ts","../../../fluid-pay/core/src/utils/browser-info.ts","../../core/src/pay-types.ts","../src/adapters/fluid-pay-api-adapter.ts","../../../fluid-pay/core/src/utils/fingerprinting.ts","../src/hooks/three-ds-card-add-helpers.ts","../src/hooks/use-portal-card-add-3ds-flow.tsx"],"sourcesContent":["import type { Provider } from \"react\";\nimport { createTranslationContext } from \"@fluid-app/i18n/translation-api-context-factory\";\nimport type { TranslationApi } from \"@fluid-app/i18n/translation-api\";\nimport type { ProfileDict } from \"./translation-dictionary\";\n\nconst { Provider: ProfileProvider, useTranslation } =\n createTranslationContext<ProfileDict>(\"Profile\");\n\nexport const ProfileTranslationProvider: Provider<TranslationApi<ProfileDict> | null> =\n ProfileProvider;\nexport const useProfileTranslation = useTranslation;\n","import { useMemo, type ReactNode } from \"react\";\nimport { useActiveLocale } from \"@fluid-app/i18n/locale-context\";\nimport { useDomainDict } from \"@fluid-app/i18n/use-domain-dict\";\nimport {\n profileDomain,\n createProfileTranslationAdapter,\n} from \"@fluid-app/profile-core/translation-adapter\";\nimport { ProfileTranslationProvider } from \"@fluid-app/profile-core/translation-api-context\";\n\nexport function ProfileTranslationBridge({\n children,\n}: {\n children: ReactNode;\n}): React.JSX.Element {\n const { locale } = useActiveLocale();\n const dict = useDomainDict(profileDomain, locale);\n const api = useMemo(\n () => createProfileTranslationAdapter(locale, dict),\n [locale, dict],\n );\n return (\n <ProfileTranslationProvider value={api}>\n {children}\n </ProfileTranslationProvider>\n );\n}\n","import { useState, type JSX } from \"react\";\nimport { Check, EllipsisVertical, Pencil, Trash2 } from \"lucide-react\";\nimport { MobileBottomSheet } from \"@fluid-app/ui-components/components/MobileBottomSheet\";\nimport type { ResponsiveDialogPresentation } from \"@fluid-app/ui-components/components/ResponsiveDialog\";\nimport {\n Button,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from \"@fluid-app/ui-primitives\";\nimport { useProfileTranslation } from \"@fluid-app/profile-core/translation-api-context\";\n\ntype EllipsesDropdownProps = {\n onDelete?: () => void;\n onEdit?: () => void;\n onMakeDefault?: () => void;\n editLabel?: string;\n deleteLabel?: string;\n makeDefaultLabel?: string;\n menuLabel?: string;\n disabled?: boolean;\n presentation?: ResponsiveDialogPresentation;\n};\n\nexport default function EllipsesDropdown({\n onDelete,\n onEdit,\n onMakeDefault,\n editLabel,\n deleteLabel,\n makeDefaultLabel,\n menuLabel,\n disabled = false,\n presentation = \"dialog\",\n}: EllipsesDropdownProps): JSX.Element {\n const { t } = useProfileTranslation();\n const [isOpen, setIsOpen] = useState(false);\n const resolvedEditLabel = editLabel ?? t(\"edit\");\n const resolvedDeleteLabel = deleteLabel ?? t(\"delete\");\n const resolvedMakeDefaultLabel = makeDefaultLabel ?? t(\"make_default\");\n const resolvedMenuLabel = menuLabel ?? resolvedEditLabel;\n\n if (presentation === \"bottom-sheet\") {\n const handleAction = (action: () => void): void => {\n setIsOpen(false);\n action();\n };\n\n return (\n <>\n <Button\n variant=\"ghost\"\n disabled={disabled}\n aria-label={resolvedMenuLabel}\n onClick={() => setIsOpen(true)}\n >\n <EllipsisVertical className=\"text-muted-foreground size-4\" />\n </Button>\n <MobileBottomSheet\n open={isOpen}\n onOpenChange={setIsOpen}\n title={resolvedMenuLabel}\n >\n <div className=\"space-y-1 px-2\">\n {onEdit && (\n <Button\n type=\"button\"\n variant=\"ghost\"\n className=\"h-12 w-full justify-start\"\n onClick={() => handleAction(onEdit)}\n >\n <Pencil className=\"size-4\" />\n {resolvedEditLabel}\n </Button>\n )}\n {onMakeDefault && (\n <Button\n type=\"button\"\n variant=\"ghost\"\n className=\"h-12 w-full justify-start\"\n onClick={() => handleAction(onMakeDefault)}\n >\n <Check className=\"size-4\" />\n {resolvedMakeDefaultLabel}\n </Button>\n )}\n {onDelete && (\n <Button\n type=\"button\"\n variant=\"ghost\"\n className=\"text-destructive hover:bg-destructive/10 hover:text-destructive h-12 w-full justify-start\"\n onClick={() => handleAction(onDelete)}\n >\n <Trash2 className=\"size-4\" />\n {resolvedDeleteLabel}\n </Button>\n )}\n </div>\n </MobileBottomSheet>\n </>\n );\n }\n\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"ghost\"\n disabled={disabled}\n aria-label={resolvedMenuLabel}\n >\n <EllipsisVertical className=\"text-muted-foreground size-4\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent className=\"text-foreground min-w-28 space-y-1 text-sm\">\n {onEdit && (\n <>\n <DropdownMenuItem\n className=\"hover:bg-muted flex cursor-pointer flex-row items-center gap-x-2 rounded px-2\"\n onClick={(event) => {\n event.stopPropagation();\n onEdit();\n }}\n >\n <Pencil className=\"size-3.5 shrink-0\" />\n <span>{resolvedEditLabel}</span>\n </DropdownMenuItem>\n {(onMakeDefault || onDelete) && <DropdownMenuSeparator />}\n </>\n )}\n {onMakeDefault && (\n <>\n <DropdownMenuItem\n className=\"hover:bg-muted flex cursor-pointer flex-row items-center gap-x-2 rounded px-2\"\n onClick={(event) => {\n event.stopPropagation();\n onMakeDefault();\n }}\n >\n <Check className=\"size-3.5 shrink-0\" />\n <span>{resolvedMakeDefaultLabel}</span>\n </DropdownMenuItem>\n {onDelete && <DropdownMenuSeparator />}\n </>\n )}\n {onDelete && (\n <DropdownMenuItem\n className=\"text-destructive hover:bg-destructive/10 flex cursor-pointer flex-row items-center gap-x-2 rounded px-2\"\n onClick={(event) => {\n event.stopPropagation();\n onDelete();\n }}\n >\n <Trash2 className=\"size-3.5 shrink-0\" />\n <span>{resolvedDeleteLabel}</span>\n </DropdownMenuItem>\n )}\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n","import type { JSX } from \"react\";\nimport { DialogFooter, Button } from \"@fluid-app/ui-primitives\";\nimport {\n ResponsiveDialog,\n type ResponsiveDialogPresentation,\n} from \"@fluid-app/ui-components/components/ResponsiveDialog\";\nimport { useProfileTranslation } from \"@fluid-app/profile-core/translation-api-context\";\n\ntype ConfirmActionDialogProps = {\n title: string;\n description: string;\n onAction: () => void;\n openDialog: boolean;\n setOpenDialog: (open: boolean) => void;\n errorMsg?: string;\n isLoading?: boolean;\n actionText?: string;\n presentation?: ResponsiveDialogPresentation;\n};\n\nexport default function ConfirmActionDialog({\n title,\n description,\n onAction,\n openDialog,\n setOpenDialog,\n errorMsg,\n isLoading,\n actionText,\n presentation = \"dialog\",\n}: ConfirmActionDialogProps): JSX.Element {\n const { t } = useProfileTranslation();\n const resolvedActionText = actionText ?? t(\"delete\");\n\n return (\n <ResponsiveDialog\n open={openDialog}\n onOpenChange={setOpenDialog}\n title={title}\n presentation={presentation}\n size=\"compact\"\n >\n <div className=\"space-y-4\">\n <p className=\"text-muted-foreground text-left text-sm\">{description}</p>\n </div>\n\n {errorMsg && <p className=\"text-destructive text-sm\">{errorMsg}</p>}\n\n <DialogFooter>\n <div className=\"flex w-full flex-row justify-between gap-x-2\">\n <Button\n variant=\"secondary\"\n className=\"min-w-[70px]\"\n onClick={() => setOpenDialog(false)}\n >\n {t(\"cancel\")}\n </Button>\n <Button\n type=\"button\"\n variant=\"destructive\"\n className=\"min-w-[70px]\"\n onClick={onAction}\n disabled={isLoading}\n >\n {isLoading ? (\n <div className=\"border-primary-foreground size-5 animate-spin rounded-full border-4 border-t-4 border-t-transparent\" />\n ) : (\n resolvedActionText\n )}\n </Button>\n </div>\n </DialogFooter>\n </ResponsiveDialog>\n );\n}\n","import type React from \"react\";\nimport {\n useController,\n type Control,\n type FieldPath,\n type FieldValues,\n} from \"react-hook-form\";\nimport {\n Input,\n Label,\n Select,\n SelectTrigger,\n SelectContent,\n SelectItem,\n SelectValue,\n Textarea,\n cn,\n} from \"@fluid-app/ui-primitives\";\n\nexport type NameValue = { name: string; value: string | number };\n\nexport function FormTextField<T extends FieldValues>({\n control,\n name,\n label,\n containerClassName,\n ...props\n}: {\n control: Control<T>;\n name: FieldPath<T>;\n label?: string;\n containerClassName?: string;\n} & Omit<React.ComponentProps<\"input\">, \"name\">): React.JSX.Element {\n const {\n field,\n fieldState: { error },\n } = useController({ name, control });\n return (\n <div className={cn(\"min-w-0 space-y-1\", containerClassName)}>\n {label && (\n <Label htmlFor={name} className=\"mb-1.5 block text-sm font-medium\">\n {label}\n </Label>\n )}\n <Input\n {...field}\n {...props}\n id={name}\n value={field.value ?? \"\"}\n className={cn(error && \"ring-destructive ring-1\", props.className)}\n />\n {error && <p className=\"text-destructive text-sm\">{error.message}</p>}\n </div>\n );\n}\n\nexport function FormTextareaField<T extends FieldValues>({\n control,\n name,\n label,\n containerClassName,\n ...props\n}: {\n control: Control<T>;\n name: FieldPath<T>;\n label?: string;\n containerClassName?: string;\n} & Omit<React.ComponentProps<\"textarea\">, \"name\">): React.JSX.Element {\n const {\n field,\n fieldState: { error },\n } = useController({ name, control });\n return (\n <div className={cn(\"min-w-0 space-y-1\", containerClassName)}>\n {label && (\n <Label htmlFor={name} className=\"mb-1.5 block text-sm font-medium\">\n {label}\n </Label>\n )}\n <Textarea\n {...field}\n {...props}\n id={name}\n value={field.value ?? \"\"}\n className={cn(error && \"ring-destructive ring-1\", props.className)}\n />\n {error && <p className=\"text-destructive text-sm\">{error.message}</p>}\n </div>\n );\n}\n\nexport function FormSelectField<T extends FieldValues>({\n control,\n name,\n label,\n options,\n placeholder,\n containerClassName,\n onChange,\n}: {\n control: Control<T>;\n name: FieldPath<T>;\n label?: string;\n options?: NameValue[];\n placeholder?: string;\n containerClassName?: string;\n onChange?: (value: string) => void;\n}): React.JSX.Element {\n const {\n field,\n fieldState: { error },\n } = useController({ name, control });\n return (\n <div className={cn(\"min-w-0 space-y-1\", containerClassName)}>\n {label && (\n <Label htmlFor={name} className=\"block text-sm font-medium\">\n {label}\n </Label>\n )}\n <Select\n value={field.value?.toString() ?? \"\"}\n onValueChange={(val) => {\n field.onChange(val);\n onChange?.(val);\n }}\n >\n <SelectTrigger\n id={name}\n className={cn(\"w-full\", error && \"ring-destructive ring-1\")}\n >\n <SelectValue placeholder={placeholder} />\n </SelectTrigger>\n <SelectContent>\n {options?.map((opt) => (\n <SelectItem\n key={`${opt.name}-${opt.value}`}\n value={opt.value.toString()}\n >\n {opt.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n {error && <p className=\"text-destructive text-sm\">{error.message}</p>}\n </div>\n );\n}\n","import { useState, type JSX } from \"react\";\nimport type { Control } from \"react-hook-form\";\nimport { DialogFooter, Button, Input } from \"@fluid-app/ui-primitives\";\nimport {\n ResponsiveDialog,\n type ResponsiveDialogPresentation,\n} from \"@fluid-app/ui-components/components/ResponsiveDialog\";\nimport { Info } from \"lucide-react\";\nimport {\n FormTextField,\n FormTextareaField,\n FormSelectField,\n type NameValue,\n} from \"./form-fields\";\nimport { useProfileTranslation } from \"@fluid-app/profile-core/translation-api-context\";\n\nexport type UserFormData = {\n first_name: string;\n last_name: string;\n phone_number?: string;\n language: string;\n bio?: string;\n};\n\nexport default function UserInfoDialog({\n control,\n isOpen,\n onSubmit,\n handleClose,\n languageOptions,\n errorMsg,\n isSubmitting,\n email,\n onChangeEmail,\n isChangingEmail,\n pendingEmail,\n disableNameEdit = false,\n presentation = \"dialog\",\n}: {\n control: Control<UserFormData>;\n isOpen: boolean;\n onSubmit: () => void;\n handleClose: () => void;\n languageOptions?: NameValue[];\n errorMsg: string | undefined;\n isSubmitting: boolean;\n email?: string;\n onChangeEmail?: (newEmail: string) => Promise<void> | void;\n isChangingEmail?: boolean;\n pendingEmail?: string;\n // When true, the first_name / last_name inputs are read-only with a short\n // policy hint. Phone, bio, and language remain editable. Matches the\n // per-company `allow_name_edit` flag surfaced through the portal-tenant\n // Store payload. Server-side enforcement lives in Company::IdentityEditPolicy.\n disableNameEdit?: boolean;\n presentation?: ResponsiveDialogPresentation;\n}): JSX.Element {\n const { t } = useProfileTranslation();\n const [isEditingEmail, setIsEditingEmail] = useState(false);\n const [newEmail, setNewEmail] = useState(\"\");\n const [emailError, setEmailError] = useState<string | undefined>(undefined);\n\n const handleEmailSubmit = async () => {\n setEmailError(undefined);\n const trimmed = newEmail.trim();\n if (!trimmed) {\n setEmailError(t(\"please_enter_new_email\"));\n return;\n }\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n if (!emailRegex.test(trimmed)) {\n setEmailError(t(\"please_enter_valid_email\"));\n return;\n }\n if (email && trimmed.toLowerCase() === email.toLowerCase()) {\n setEmailError(t(\"new_email_must_be_different\"));\n return;\n }\n try {\n await onChangeEmail?.(trimmed);\n setIsEditingEmail(false);\n setNewEmail(\"\");\n } catch (err) {\n setEmailError(\n err instanceof Error\n ? err.message\n : t(\"failed_to_initiate_email_change\"),\n );\n }\n };\n\n const handleCancelEmailEdit = () => {\n setIsEditingEmail(false);\n setNewEmail(\"\");\n setEmailError(undefined);\n };\n\n const handleDialogClose = () => {\n handleCancelEmailEdit();\n handleClose();\n };\n\n return (\n <ResponsiveDialog\n open={isOpen}\n onOpenChange={(open) => !open && handleDialogClose()}\n title={t(\"edit_profile\")}\n presentation={presentation}\n >\n <div className=\"space-y-4\">\n <FormTextField\n control={control}\n name=\"first_name\"\n label={t(\"first_name\")}\n disabled={disableNameEdit}\n readOnly={disableNameEdit}\n aria-readonly={disableNameEdit || undefined}\n aria-describedby={\n disableNameEdit ? \"name-edit-disabled-hint\" : undefined\n }\n />\n <FormTextField\n control={control}\n name=\"last_name\"\n label={t(\"last_name\")}\n disabled={disableNameEdit}\n readOnly={disableNameEdit}\n aria-readonly={disableNameEdit || undefined}\n aria-describedby={\n disableNameEdit ? \"name-edit-disabled-hint\" : undefined\n }\n />\n {disableNameEdit && (\n <p\n id=\"name-edit-disabled-hint\"\n className=\"text-muted-foreground text-xs\"\n >\n {t(\"name_change_disabled_hint\")}\n </p>\n )}\n <FormTextField\n control={control}\n name=\"phone_number\"\n label={t(\"phone_number\")}\n type=\"tel\"\n />\n <FormTextareaField\n control={control}\n name=\"bio\"\n label={t(\"bio\")}\n rows={3}\n placeholder={t(\"add_a_short_bio\")}\n />\n <FormSelectField\n control={control}\n name=\"language\"\n label={t(\"language\")}\n options={languageOptions}\n placeholder={t(\"select_an_option\")}\n />\n </div>\n {email && (\n <div className=\"space-y-2\">\n <label className=\"text-foreground text-sm font-medium\">\n {t(\"email\")}\n </label>\n {isEditingEmail ? (\n <div className=\"space-y-2\">\n <Input\n type=\"email\"\n placeholder={t(\"enter_new_email_placeholder\")}\n value={newEmail}\n onChange={(e) => {\n setNewEmail(e.target.value);\n setEmailError(undefined);\n }}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") {\n e.preventDefault();\n handleEmailSubmit();\n }\n if (e.key === \"Escape\") {\n handleCancelEmailEdit();\n }\n }}\n aria-invalid={!!emailError || undefined}\n autoFocus\n />\n {emailError && (\n <p className=\"text-destructive text-xs\">{emailError}</p>\n )}\n <div className=\"bg-muted flex items-start gap-2.5 rounded-md px-3 py-2.5\">\n <Info className=\"text-primary mt-0.5 size-4 shrink-0\" />\n <p className=\"text-muted-foreground text-xs\">\n {t(\"email_verification_hint\")}\n </p>\n </div>\n <div className=\"flex gap-2\">\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={handleCancelEmailEdit}\n >\n {t(\"cancel\")}\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n onClick={handleEmailSubmit}\n disabled={!newEmail.trim() || isChangingEmail}\n >\n {isChangingEmail && (\n <div className=\"mr-2 size-3.5 animate-spin rounded-full border-2 border-current/30 border-t-current\" />\n )}\n {isChangingEmail ? t(\"sending\") : t(\"send_verification\")}\n </Button>\n </div>\n </div>\n ) : pendingEmail ? (\n <div className=\"space-y-2\">\n <div className=\"bg-muted text-muted-foreground min-w-0 rounded-md px-3 py-2 text-sm\">\n {email}\n </div>\n <div className=\"bg-muted flex items-start gap-2.5 rounded-md px-3 py-2.5\">\n <Info className=\"text-primary mt-0.5 size-4 shrink-0\" />\n <p className=\"text-muted-foreground text-xs\">\n {t(\"changing_email_to\")}{\" \"}\n <span className=\"text-foreground font-medium\">\n {pendingEmail}\n </span>\n . {t(\"check_new_email_verification\")}\n </p>\n </div>\n </div>\n ) : (\n <div className=\"flex items-center gap-2\">\n <div className=\"bg-muted text-muted-foreground min-w-0 flex-1 rounded-md px-3 py-2 text-sm\">\n {email}\n </div>\n {onChangeEmail && (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => setIsEditingEmail(true)}\n className=\"shrink-0\"\n >\n {t(\"change\")}\n </Button>\n )}\n </div>\n )}\n </div>\n )}\n {errorMsg && <p className=\"text-destructive text-sm\">{errorMsg}</p>}\n <DialogFooter className=\"flex flex-row items-center justify-end\">\n <div className=\"flex-1 text-right\">\n <Button type=\"button\" onClick={onSubmit}>\n {isSubmitting && (\n <div className=\"mr-2 size-4 animate-spin rounded-full border-2 border-current/30 border-t-current\" />\n )}\n {isSubmitting ? t(\"saving\") : t(\"save_changes\")}\n </Button>\n </div>\n </DialogFooter>\n </ResponsiveDialog>\n );\n}\n","import { useState, type JSX } from \"react\";\nimport type { fluidPay } from \"@fluid-app/fluid-pay-core\";\nimport {\n brandIconUrl as resolveBrandIconUrl,\n normalizeCardBrand,\n} from \"@fluid-app/payments-display/brands\";\nimport {\n isCardPaymentDescriptor,\n normalizePaymentDescriptor,\n paymentDescriptorLabel,\n resolvePaymentLogo,\n resolvePaymentMethodDisplay,\n} from \"@fluid-app/payments-display/display\";\n\nexport function brandIconUrl(brand: string | null | undefined): string {\n return resolveBrandIconUrl(brand);\n}\n\nexport function PaymentIcon({\n logoUrl,\n brand,\n alt,\n}: {\n logoUrl?: string;\n brand: string | null | undefined;\n alt: string;\n}): JSX.Element {\n const logo = resolvePaymentLogo({ brand, logoUrl, alt });\n const [hasError, setHasError] = useState(false);\n const src = hasError ? logo.fallbackUrl : logo.primaryUrl;\n return (\n <img\n src={src}\n alt={logo.alt}\n width={40}\n height={24}\n className=\"object-contain\"\n onError={() => setHasError(true)}\n />\n );\n}\n\nexport function getPaymentMethodLogoBrand(\n paymentMethod: fluidPay.CustomerPaymentMethod,\n): string | null {\n if (isCardPaymentMethod(paymentMethod)) {\n return (\n normalizeCardBrand(paymentMethod.details.card_brand) ??\n normalizeCardBrand(paymentMethod.details.card_network)\n );\n }\n\n return paymentDescriptorLabel(\n paymentMethod.payment_type,\n paymentMethod.source,\n );\n}\n\nexport function getCardDisplayName(\n paymentMethod: fluidPay.CustomerPaymentMethod,\n cardFallback = \"Card\",\n): string {\n if (isCardPaymentMethod(paymentMethod)) {\n return resolvePaymentMethodDisplay({\n kind: \"card\",\n brand: getPaymentMethodLogoBrand(paymentMethod) ?? cardFallback,\n last4: paymentMethod.details.last_four,\n logoUrl: paymentMethod.details.logo_url,\n }).label;\n }\n\n const fallbackLabel = paymentDescriptorLabel(\n paymentMethod.payment_type,\n paymentMethod.source,\n );\n return resolvePaymentMethodDisplay({\n kind: \"non_card\",\n brand: fallbackLabel,\n fallbackLabel,\n logoUrl: paymentMethod.details.logo_url,\n }).label;\n}\n\nexport function getCardExpiry(\n paymentMethod: fluidPay.CustomerPaymentMethod,\n expiresLabel = \"Expires\",\n): string {\n const { exp_month, exp_year } = paymentMethod.details;\n if (exp_month != null && exp_year != null) {\n return `${expiresLabel} ${exp_month}/${exp_year}`;\n }\n return \"\";\n}\n\nfunction isCardPaymentMethod(\n paymentMethod: fluidPay.CustomerPaymentMethod,\n): boolean {\n return (\n paymentMethod.source === \"card\" ||\n isCardPaymentDescriptor(paymentMethod.payment_type) ||\n isCardPaymentDescriptor(paymentMethod.source) ||\n normalizePaymentDescriptor(paymentMethod.details.card_brand) != null ||\n normalizePaymentDescriptor(paymentMethod.details.card_network) != null ||\n paymentMethod.details.last_four != null\n );\n}\n","export interface StateOption {\n readonly isoCode: string;\n readonly name: string;\n}\n\ninterface AdministrativeAreaDetails {\n readonly state?: string;\n readonly administrativeAreaShort?: string;\n readonly administrativeAreaLong?: string;\n}\n\nfunction normalize(value: string): string {\n return value.trim().toLowerCase();\n}\n\nfunction firstPresent(...values: Array<string | undefined>): string {\n return values.find((value) => value && value.trim() !== \"\") ?? \"\";\n}\n\nfunction findStateByIsoCode(\n stateOptions: readonly StateOption[],\n value: string,\n): StateOption | undefined {\n const normalizedValue = normalize(value);\n if (!normalizedValue) return undefined;\n return stateOptions.find(\n (state) => normalize(state.isoCode) === normalizedValue,\n );\n}\n\nfunction findStateByName(\n stateOptions: readonly StateOption[],\n value: string,\n): StateOption | undefined {\n const normalizedValue = normalize(value);\n if (!normalizedValue) return undefined;\n return stateOptions.find(\n (state) => normalize(state.name) === normalizedValue,\n );\n}\n\nexport function resolveAdministrativeAreaState(\n details: AdministrativeAreaDetails,\n stateOptions: readonly StateOption[] = [],\n): string {\n const displayValue = firstPresent(\n details.state,\n details.administrativeAreaLong,\n details.administrativeAreaShort,\n );\n\n if (stateOptions.length === 0) return displayValue;\n\n const candidates = [\n details.administrativeAreaShort,\n details.state,\n details.administrativeAreaLong,\n ].filter((value): value is string => Boolean(value));\n\n for (const candidate of candidates) {\n const state =\n findStateByIsoCode(stateOptions, candidate) ??\n findStateByName(stateOptions, candidate);\n if (state) return state.isoCode;\n }\n\n return displayValue;\n}\n","import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ChangeEvent,\n type JSX,\n} from \"react\";\nimport {\n useController,\n type Control,\n type FieldValues,\n type Path,\n type PathValue,\n type UseFormSetValue,\n} from \"react-hook-form\";\nimport { Input, Label } from \"@fluid-app/ui-primitives\";\nimport { useAddressAutocompleteApiOptional } from \"../api-context\";\nimport type { AddressDetails, AddressSuggestion } from \"../api\";\nimport {\n resolveAdministrativeAreaState,\n type StateOption,\n} from \"../administrative-area\";\n\nexport interface AddressAutocompleteInputProps<T extends FieldValues> {\n readonly control: Control<T>;\n readonly setValue: UseFormSetValue<T>;\n readonly countryIso: string;\n readonly addressLineField: Path<T>;\n readonly cityField: Path<T>;\n /** Omit when the country's address format has no administrative area. */\n readonly stateField?: Path<T>;\n readonly postalCodeField: Path<T>;\n readonly stateOptions?: readonly StateOption[];\n readonly id?: string;\n readonly label?: string;\n readonly placeholder?: string;\n readonly disabled?: boolean;\n /** Applied to the text input, so callers can match sibling fields. */\n readonly inputClassName?: string;\n}\n\nconst SET_OPTS = {\n shouldValidate: true,\n shouldDirty: true,\n shouldTouch: true,\n} as const;\n\nconst DEBOUNCE_MS = 250;\nconst EMPTY_STATE_OPTIONS: readonly StateOption[] = [];\n\nexport function AddressAutocompleteInput<T extends FieldValues>({\n control,\n setValue,\n countryIso,\n addressLineField,\n cityField,\n stateField,\n postalCodeField,\n stateOptions = EMPTY_STATE_OPTIONS,\n id,\n label,\n placeholder,\n disabled,\n inputClassName,\n}: AddressAutocompleteInputProps<T>): JSX.Element {\n const api = useAddressAutocompleteApiOptional();\n const {\n field,\n fieldState: { error },\n } = useController({ name: addressLineField, control });\n const [suggestions, setSuggestions] = useState<readonly AddressSuggestion[]>(\n [],\n );\n const [isOpen, setIsOpen] = useState(false);\n const [needsCountry, setNeedsCountry] = useState(false);\n const containerRef = useRef<HTMLDivElement | null>(null);\n // Monotonically increasing request ID. We only apply a fetch result when its\n // ID still matches the latest issued one — guards against stale responses\n // arriving out of order under network jitter.\n const requestIdRef = useRef(0);\n const debounceTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const isCountrySelected = useMemo(\n () => Boolean(countryIso && countryIso.trim() !== \"\"),\n [countryIso],\n );\n const inputId = id ?? addressLineField;\n\n useEffect(() => {\n function onClickOutside(e: MouseEvent) {\n if (\n containerRef.current &&\n !containerRef.current.contains(e.target as Node)\n ) {\n setIsOpen(false);\n setNeedsCountry(false);\n }\n }\n document.addEventListener(\"mousedown\", onClickOutside);\n return () => document.removeEventListener(\"mousedown\", onClickOutside);\n }, []);\n\n useEffect(\n () => () => {\n if (debounceTimerRef.current !== null) {\n clearTimeout(debounceTimerRef.current);\n }\n },\n [],\n );\n\n // Every suggestion belongs to the country it was looked up for, so switching\n // country invalidates all of it: what is on screen, a debounce still waiting\n // to fire with the old country captured, and any lookup already in flight.\n // Advancing the request ID is what discards those late responses.\n useEffect(() => {\n if (debounceTimerRef.current !== null) {\n clearTimeout(debounceTimerRef.current);\n debounceTimerRef.current = null;\n }\n requestIdRef.current += 1;\n setSuggestions([]);\n setIsOpen(false);\n setNeedsCountry(false);\n }, [countryIso]);\n\n useEffect(() => {\n if (api) return;\n // Suggestions failing quietly is the exact bug this input exists to prevent,\n // so a host that forgot the provider should hear about it.\n console.warn(\n \"AddressAutocompleteInput: no AddressAutocompleteApiProvider found — address suggestions are disabled.\",\n );\n }, [api]);\n\n const populate = useCallback(\n (s: AddressDetails) => {\n setValue(\n addressLineField,\n s.streetLine as PathValue<T, Path<T>>,\n SET_OPTS,\n );\n setValue(cityField, s.city as PathValue<T, Path<T>>, SET_OPTS);\n // The lookup returns an administrative area even for countries that do\n // not collect one, and writing it would save a value the form never\n // showed.\n if (stateField) {\n setValue(\n stateField,\n resolveAdministrativeAreaState(s, stateOptions) as PathValue<\n T,\n Path<T>\n >,\n SET_OPTS,\n );\n }\n setValue(\n postalCodeField,\n s.postalCode as PathValue<T, Path<T>>,\n SET_OPTS,\n );\n },\n [\n addressLineField,\n cityField,\n postalCodeField,\n setValue,\n stateField,\n stateOptions,\n ],\n );\n\n const handleChange = useCallback(\n (e: ChangeEvent<HTMLInputElement>) => {\n const value = e.target.value;\n field.onChange(value);\n if (!api) return;\n\n // Cancel any pending fetch from a prior keystroke.\n if (debounceTimerRef.current !== null) {\n clearTimeout(debounceTimerRef.current);\n debounceTimerRef.current = null;\n }\n\n if (value.length < 1) {\n setIsOpen(false);\n setNeedsCountry(false);\n setSuggestions([]);\n return;\n }\n if (!isCountrySelected) {\n setNeedsCountry(true);\n setIsOpen(true);\n return;\n }\n setNeedsCountry(false);\n\n const requestId = ++requestIdRef.current;\n debounceTimerRef.current = setTimeout(() => {\n debounceTimerRef.current = null;\n void api.fetchSuggestions({ query: value, countryIso }).then((next) => {\n // Drop stale responses — a newer keystroke has already issued a\n // request, and applying this would clobber its result.\n if (requestId !== requestIdRef.current) return;\n setSuggestions(next);\n setIsOpen(true);\n });\n }, DEBOUNCE_MS);\n },\n [api, countryIso, field, isCountrySelected],\n );\n\n const handleClick = useCallback(\n async (suggestion: AddressSuggestion) => {\n // Cancel any debounced fetch still pending from a recent keystroke and\n // advance the request ID so any in-flight response is dropped — without\n // this, the timer could fire after a selection and re-open the dropdown.\n if (debounceTimerRef.current !== null) {\n clearTimeout(debounceTimerRef.current);\n debounceTimerRef.current = null;\n }\n const clickId = ++requestIdRef.current;\n\n if (!suggestion.needsDetailLookup) {\n populate({\n streetLine: suggestion.streetLine ?? suggestion.text,\n city: suggestion.city ?? \"\",\n state: suggestion.state ?? \"\",\n postalCode: suggestion.postalCode ?? \"\",\n });\n setIsOpen(false);\n return;\n }\n if (!api) return;\n const { details, drilldownSuggestions } = await api.fetchDetails({\n suggestion,\n countryIso,\n });\n // Drop the result if the user typed during the network round-trip — a\n // newer keystroke has superseded this click and applying its result\n // would clobber what the user has since entered.\n if (clickId !== requestIdRef.current) return;\n if (details) {\n populate(details);\n setIsOpen(false);\n return;\n }\n setSuggestions(drilldownSuggestions);\n setIsOpen(true);\n },\n [api, countryIso, populate],\n );\n\n return (\n <div className=\"space-y-1\">\n {label && (\n <Label htmlFor={inputId} className=\"mb-1.5 block text-sm font-medium\">\n {label}\n </Label>\n )}\n <div ref={containerRef} className=\"relative\">\n <Input\n id={inputId}\n className={inputClassName}\n type=\"text\"\n ref={field.ref}\n value={(field.value as string) ?? \"\"}\n onChange={handleChange}\n onBlur={field.onBlur}\n placeholder={placeholder}\n disabled={disabled}\n aria-invalid={!!error}\n />\n {isOpen && needsCountry && (\n <div className=\"bg-muted text-foreground absolute z-50 mt-1 w-full rounded-md px-3 py-2 text-sm shadow-lg\">\n Please select a country first to enable address suggestions\n </div>\n )}\n {isOpen && !needsCountry && suggestions.length > 0 && (\n <div className=\"bg-background text-foreground border-border absolute z-50 mt-1 max-h-60 w-full overflow-y-auto rounded-md border shadow-lg\">\n {suggestions.map((s) => (\n <button\n key={s.id}\n type=\"button\"\n onClick={() => {\n void handleClick(s).catch((err) => {\n // handleClick is async because of fetchDetails — the current\n // Smarty adapter and NULL_API swallow errors, so this is\n // belt-and-suspenders for future adapters that might throw.\n console.error(\"Address autocomplete click failed:\", err);\n });\n }}\n className=\"hover:bg-muted block w-full cursor-pointer px-3 py-2 text-left text-sm\"\n >\n {s.text}\n {s.needsDetailLookup ? \" →\" : \"\"}\n </button>\n ))}\n </div>\n )}\n </div>\n {error?.message && (\n <p className=\"text-destructive text-sm\">{error.message}</p>\n )}\n </div>\n );\n}\n","import type { AddressField } from \"./types\";\n\n/**\n * Which address fields a country collects, in what order, and how they group\n * into rows. The address-fields service is the authority: when it answers, its\n * list decides presence and order, and its labels arrive already translated.\n * The static values below cover only the window before it answers, or a host\n * with no provider wired.\n */\nexport const ADDRESS_FIELD_NAMES = [\n \"name\",\n \"address1\",\n \"address2\",\n \"city\",\n \"state\",\n \"postal_code\",\n \"phone\",\n] as const;\n\nexport type AddressFieldName = (typeof ADDRESS_FIELD_NAMES)[number];\n\nconst STATIC_LABEL_KEYS: Record<AddressFieldName, string> = {\n name: \"name\",\n address1: \"address_line_1\",\n address2: \"address_line_2\",\n city: \"city\",\n state: \"state\",\n postal_code: \"zip_code\",\n phone: \"phone_number\",\n};\n\nconst DEFAULT_HIDDEN_FIELDS = new Set<AddressFieldName>([\"phone\"]);\n\nconst STATIC_REQUIRED_FIELDS = new Set<AddressFieldName>([\n \"name\",\n \"address1\",\n \"city\",\n \"state\",\n \"postal_code\",\n]);\n\n// Autocomplete fills city, state and postal from the street line, so those\n// three come first regardless of where the service puts them.\nconst AUTOCOMPLETE_FIELD_PREFIX: readonly AddressFieldName[] = [\n \"name\",\n \"address1\",\n \"address2\",\n];\n\nconst ROW_GROUPED_FIELDS = new Set<AddressFieldName>([\n \"city\",\n \"state\",\n \"postal_code\",\n]);\n\nexport function isAddressFieldName(value: string): value is AddressFieldName {\n return (ADDRESS_FIELD_NAMES as readonly string[]).includes(value);\n}\n\nexport function addressFieldOrder(\n fields: readonly AddressField[] | null,\n): AddressFieldName[] {\n if (!fields) {\n return ADDRESS_FIELD_NAMES.filter(\n (field) => !DEFAULT_HIDDEN_FIELDS.has(field),\n );\n }\n const fromService = fields\n .map((field) => field.field)\n .filter(isAddressFieldName);\n const prefix = AUTOCOMPLETE_FIELD_PREFIX.filter((field) =>\n fromService.includes(field),\n );\n const rest = fromService.filter(\n (field) => !AUTOCOMPLETE_FIELD_PREFIX.includes(field),\n );\n return [...prefix, ...rest];\n}\n\n/** Consecutive city, state and postal fields share one row. */\nexport function groupAddressFields(\n fields: readonly AddressFieldName[],\n): AddressFieldName[][] {\n const groups: AddressFieldName[][] = [];\n let i = 0;\n while (i < fields.length) {\n const current = fields[i]!;\n if (ROW_GROUPED_FIELDS.has(current)) {\n const group: AddressFieldName[] = [current];\n while (\n i + group.length < fields.length &&\n ROW_GROUPED_FIELDS.has(fields[i + group.length]!)\n ) {\n group.push(fields[i + group.length]!);\n }\n if (group.length > 1) {\n groups.push(group);\n i += group.length;\n continue;\n }\n }\n groups.push([current]);\n i++;\n }\n return groups;\n}\n\nexport function isAddressFieldRequired(\n fields: readonly AddressField[] | null,\n fieldName: AddressFieldName,\n): boolean {\n if (!fields) return STATIC_REQUIRED_FIELDS.has(fieldName);\n return fields.find((field) => field.field === fieldName)?.required ?? false;\n}\n\n/**\n * The service's label when it has one, otherwise a translation key for the\n * caller to resolve. `regionKey` and `postalKey` let a caller pass the\n * country-specific key it already has, such as province or postal_code.\n */\nexport function addressFieldLabel(\n fields: readonly AddressField[] | null,\n fieldName: AddressFieldName,\n fallbackKeys?: { regionKey?: string; postalKey?: string },\n): { label?: string; translationKey?: string } {\n const serviceLabel = fields?.find(\n (field) => field.field === fieldName,\n )?.label;\n if (serviceLabel) return { label: serviceLabel };\n if (fieldName === \"state\" && fallbackKeys?.regionKey) {\n return { translationKey: fallbackKeys.regionKey };\n }\n if (fieldName === \"postal_code\" && fallbackKeys?.postalKey) {\n return { translationKey: fallbackKeys.postalKey };\n }\n return { translationKey: STATIC_LABEL_KEYS[fieldName] };\n}\n","import { createContext, useContext } from \"react\";\n\nexport type TranslationFn = (key: string) => string;\n\nexport interface ProfileUIContextValue {\n t: TranslationFn;\n}\n\nexport const ProfileUIContext = createContext<ProfileUIContextValue | null>(\n null,\n);\n\nexport function useProfileUI(): ProfileUIContextValue {\n const context = useContext(ProfileUIContext);\n if (!context) {\n throw new Error(\"useProfileUI must be used within a ProfileUIProvider\");\n }\n return context;\n}\n","import { createContext, useContext } from \"react\";\nimport type { FluidPayApi } from \"./api-interface\";\n\nconst FluidPayApiContext = createContext<FluidPayApi | null>(null);\n\nexport const FluidPayApiProvider = FluidPayApiContext.Provider;\n\nexport function useFluidPayApi(): FluidPayApi {\n const api = useContext(FluidPayApiContext);\n if (!api) {\n throw new Error(\n \"useFluidPayApi must be used within a FluidPayCoreProvider\",\n );\n }\n return api;\n}\n","import type { JSX } from \"react\";\nimport type { FluidPayApi } from \"./api-interface\";\nimport { FluidPayApiProvider } from \"./context\";\n\nexport interface FluidPayCoreProviderProps {\n api: FluidPayApi;\n children: React.ReactNode;\n}\n\nexport function FluidPayCoreProvider({\n api,\n children,\n}: FluidPayCoreProviderProps): JSX.Element {\n return <FluidPayApiProvider value={api}>{children}</FluidPayApiProvider>;\n}\n","import type { AddressField, RegionConfig, State } from \"./types\";\n\nexport const COUNTRY_CONFIGS: Record<string, RegionConfig> & {\n default: RegionConfig;\n} = {\n US: { regionLabel: \"state\", postalLabel: \"zip_code\" },\n JP: { regionLabel: \"prefecture\", postalLabel: \"postal_code\" },\n default: { regionLabel: \"province\", postalLabel: \"postal_code\" },\n} as const;\n\nexport function getRegionConfig(countryCode: string): RegionConfig {\n return COUNTRY_CONFIGS[countryCode] ?? COUNTRY_CONFIGS.default;\n}\n\nexport const US_STATES: State[] = [\n { name: \"Alabama\", isoCode: \"AL\" },\n { name: \"Alaska\", isoCode: \"AK\" },\n { name: \"American Samoa\", isoCode: \"AS\" },\n { name: \"Arizona\", isoCode: \"AZ\" },\n { name: \"Arkansas\", isoCode: \"AR\" },\n { name: \"California\", isoCode: \"CA\" },\n { name: \"Colorado\", isoCode: \"CO\" },\n { name: \"Connecticut\", isoCode: \"CT\" },\n { name: \"Delaware\", isoCode: \"DE\" },\n { name: \"District of Columbia\", isoCode: \"DC\" },\n { name: \"Florida\", isoCode: \"FL\" },\n { name: \"Georgia\", isoCode: \"GA\" },\n { name: \"Guam\", isoCode: \"GU\" },\n { name: \"Hawaii\", isoCode: \"HI\" },\n { name: \"Idaho\", isoCode: \"ID\" },\n { name: \"Illinois\", isoCode: \"IL\" },\n { name: \"Indiana\", isoCode: \"IN\" },\n { name: \"Iowa\", isoCode: \"IA\" },\n { name: \"Kansas\", isoCode: \"KS\" },\n { name: \"Kentucky\", isoCode: \"KY\" },\n { name: \"Louisiana\", isoCode: \"LA\" },\n { name: \"Maine\", isoCode: \"ME\" },\n { name: \"Maryland\", isoCode: \"MD\" },\n { name: \"Massachusetts\", isoCode: \"MA\" },\n { name: \"Michigan\", isoCode: \"MI\" },\n { name: \"Minnesota\", isoCode: \"MN\" },\n { name: \"Mississippi\", isoCode: \"MS\" },\n { name: \"Missouri\", isoCode: \"MO\" },\n { name: \"Montana\", isoCode: \"MT\" },\n { name: \"Nebraska\", isoCode: \"NE\" },\n { name: \"Nevada\", isoCode: \"NV\" },\n { name: \"New Hampshire\", isoCode: \"NH\" },\n { name: \"New Jersey\", isoCode: \"NJ\" },\n { name: \"New Mexico\", isoCode: \"NM\" },\n { name: \"New York\", isoCode: \"NY\" },\n { name: \"North Carolina\", isoCode: \"NC\" },\n { name: \"North Dakota\", isoCode: \"ND\" },\n { name: \"Northern Mariana Islands\", isoCode: \"MP\" },\n { name: \"Ohio\", isoCode: \"OH\" },\n { name: \"Oklahoma\", isoCode: \"OK\" },\n { name: \"Oregon\", isoCode: \"OR\" },\n { name: \"Pennsylvania\", isoCode: \"PA\" },\n { name: \"Puerto Rico\", isoCode: \"PR\" },\n { name: \"Rhode Island\", isoCode: \"RI\" },\n { name: \"South Carolina\", isoCode: \"SC\" },\n { name: \"South Dakota\", isoCode: \"SD\" },\n { name: \"Tennessee\", isoCode: \"TN\" },\n { name: \"Texas\", isoCode: \"TX\" },\n { name: \"Utah\", isoCode: \"UT\" },\n { name: \"U.S. Virgin Islands\", isoCode: \"VI\" },\n { name: \"Vermont\", isoCode: \"VT\" },\n { name: \"Virginia\", isoCode: \"VA\" },\n { name: \"Washington\", isoCode: \"WA\" },\n { name: \"West Virginia\", isoCode: \"WV\" },\n { name: \"Wisconsin\", isoCode: \"WI\" },\n { name: \"Wyoming\", isoCode: \"WY\" },\n];\n\nexport const DEFAULT_ADDRESS_FIELDS: AddressField[] = [\n { field: \"name\", label: \"Full name\", required: true },\n { field: \"address1\", label: \"Address\", required: true },\n { field: \"address2\", label: \"Apartment, suite, etc.\", required: false },\n { field: \"city\", label: \"City\", required: true },\n { field: \"state\", label: \"State\", required: true },\n { field: \"postal_code\", label: \"Zip code\", required: true },\n];\n\nexport function isFieldRequired(\n addressFields: readonly AddressField[],\n fieldName: string,\n): boolean {\n return addressFields.find((f) => f.field === fieldName)?.required ?? false;\n}\n","export interface State {\n name: string;\n isoCode: string;\n}\n\nexport interface RegionConfig {\n regionLabel: string;\n postalLabel: string;\n}\n\n/** Re-exported from the platform source of truth rather than duplicated.\n *\n * The local copy had drifted: it listed 51 entries and was missing the\n * five US territories `@fluid-app/address-fields` carries — American\n * Samoa (AS), Guam (GU), Northern Mariana Islands (MP), Puerto Rico\n * (PR) and the U.S. Virgin Islands (VI). Every consumer of\n * `useCountryStates` (the payment-method billing dialog, the address\n * form) therefore could not offer them, while checkout — which\n * re-exports the canonical list — could. */\nexport { US_STATES } from \"@fluid-app/address-fields/country-config\";\n\n// Translation keys, not display text. A capitalized value here would miss the\n// lowercase dictionary keys.\nexport const COUNTRY_CONFIGS: Record<string, RegionConfig> = {\n US: { regionLabel: \"state\", postalLabel: \"zip_code\" },\n JP: { regionLabel: \"prefecture\", postalLabel: \"postal_code\" },\n};\n\nconst DEFAULT_REGION_CONFIG: RegionConfig = {\n regionLabel: \"province\",\n postalLabel: \"postal_code\",\n};\n\nexport function getRegionConfig(countryCode: string): RegionConfig {\n return COUNTRY_CONFIGS[countryCode] ?? DEFAULT_REGION_CONFIG;\n}\n\nexport const DEFAULT_ADDRESS_FIELDS = [\n { field: \"name\", label: \"Name\", required: true },\n { field: \"address1\", label: \"Address\", required: true },\n { field: \"address2\", label: \"Apartment, suite, etc.\", required: false },\n { field: \"city\", label: \"City\", required: true },\n { field: \"state\", label: \"State\", required: true },\n { field: \"postal_code\", label: \"Postal Code\", required: true },\n { field: \"country_code\", label: \"Country\", required: true },\n];\n","import { useCallback, useRef, useState } from \"react\";\nimport {\n US_STATES,\n getRegionConfig,\n type State,\n} from \"../utils/country-config\";\n\nexport default function useCountryStates() {\n const [selectedCountry, setSelectedCountry] = useState<string>(\"US\");\n const [stateOptions, setStateOptions] = useState<State[]>(US_STATES);\n // Which country `stateOptions` describes, or null while a lookup is pending.\n // Callers that decide whether a subdivision is required cannot tell an empty\n // list apart from one that has not loaded yet without this.\n const [optionsCountry, setOptionsCountry] = useState<string | null>(\"US\");\n // Monotonically increasing lookup ID. Only the newest lookup may write the\n // options — switching country twice in quick succession leaves two fetches in\n // flight, and a slow response for the abandoned country would otherwise\n // replace the list for the one now selected.\n const lookupIdRef = useRef(0);\n\n const handleCountryChange = useCallback(\n (\n selectedCountryCode: string,\n fetchStates?: (countryCode: string) => Promise<State[]>,\n ) => {\n setSelectedCountry(selectedCountryCode);\n const lookupId = ++lookupIdRef.current;\n const fallbackStates = selectedCountryCode === \"US\" ? US_STATES : [];\n if (fetchStates) {\n // Drop the previous country's options up front. Callers derive things\n // from this list, so leaving the old country's subdivisions in place\n // while a lookup is pending would have them acting on the wrong data.\n setStateOptions(fallbackStates);\n setOptionsCountry(null);\n fetchStates(selectedCountryCode)\n .then((states) => {\n if (lookupId !== lookupIdRef.current) return;\n setStateOptions(states.length > 0 ? states : fallbackStates);\n setOptionsCountry(selectedCountryCode);\n })\n .catch((error) => {\n if (lookupId !== lookupIdRef.current) return;\n console.error(\"Failed to fetch states:\", error);\n setStateOptions(fallbackStates);\n setOptionsCountry(selectedCountryCode);\n });\n } else {\n setStateOptions(selectedCountryCode === \"US\" ? US_STATES : []);\n setOptionsCountry(selectedCountryCode);\n }\n },\n [],\n );\n\n const config = getRegionConfig(selectedCountry);\n\n return {\n handleCountryChange,\n stateOptions,\n optionsCountry,\n config,\n selectedCountry,\n };\n}\n","import { useEffect, useMemo, useRef, useState, type JSX } from \"react\";\nimport { Controller, useWatch } from \"react-hook-form\";\nimport { z } from \"zod\";\nimport { Trash2 } from \"lucide-react\";\nimport {\n Button,\n Checkbox,\n DialogFooter,\n Label,\n cn,\n useZodForm,\n} from \"@fluid-app/ui-primitives\";\nimport {\n ResponsiveDialog,\n type ResponsiveDialogPresentation,\n} from \"@fluid-app/ui-components/components/ResponsiveDialog\";\nimport { AddressAutocompleteInput } from \"@fluid-app/address-autocomplete/components/AddressAutocompleteInput\";\nimport { useAddressFieldsApiOptional } from \"@fluid-app/address-fields/address-fields-api-context\";\nimport type { AddressField } from \"@fluid-app/address-fields/types\";\nimport {\n addressFieldLabel,\n addressFieldOrder,\n groupAddressFields,\n isAddressFieldRequired,\n type AddressFieldName,\n} from \"@fluid-app/address-fields/field-layout\";\nimport { FormTextField, FormSelectField } from \"./form-fields\";\nimport type { fluidPay } from \"@fluid-app/fluid-pay-core\";\nimport { useCountryStates, type State } from \"@fluid-app/profile-core\";\nimport { useProfileTranslation } from \"@fluid-app/profile-core/translation-api-context\";\nimport type { BillingAddress } from \"./view-payment-method-dialog\";\nimport {\n PaymentIcon,\n getCardDisplayName,\n getPaymentMethodLogoBrand,\n} from \"./payment-method-card-internals\";\n\nfunction createEditPaymentMethodFormSchema(t: (key: string) => string) {\n return z.object({\n billing_address: z.object({\n // Required-ness is decided at submit time from the address fields\n // service.\n name: z.string(),\n address1: z.string(),\n address2: z.string().optional().nullable(),\n city: z.string(),\n state: z.string(),\n zip: z.string(),\n country_code: z.string().min(1, t(\"country_is_required\")),\n }),\n set_as_default: z.boolean(),\n });\n}\n\n// The shared field names are the service's; this form nests them and calls the\n// postal field zip.\nconst FORM_PATHS_BY_FIELD = [\n { field: \"name\", key: \"name\", path: \"billing_address.name\" },\n { field: \"address1\", key: \"address1\", path: \"billing_address.address1\" },\n { field: \"address2\", key: \"address2\", path: \"billing_address.address2\" },\n { field: \"city\", key: \"city\", path: \"billing_address.city\" },\n { field: \"state\", key: \"state\", path: \"billing_address.state\" },\n { field: \"postal_code\", key: \"zip\", path: \"billing_address.zip\" },\n] as const satisfies readonly {\n field: AddressFieldName;\n key: keyof EditPaymentMethodFormData[\"billing_address\"];\n path: string;\n}[];\n\nfunction pathForField(\n fieldName: AddressFieldName,\n):\n | \"billing_address.name\"\n | \"billing_address.address1\"\n | \"billing_address.address2\"\n | \"billing_address.city\"\n | \"billing_address.state\"\n | \"billing_address.zip\" {\n const entry = FORM_PATHS_BY_FIELD.find((e) => e.field === fieldName);\n return entry?.path ?? \"billing_address.address1\";\n}\n\nfunction valueForField(\n data: EditPaymentMethodFormData,\n fieldName: AddressFieldName,\n): string | undefined {\n const entry = FORM_PATHS_BY_FIELD.find((e) => e.field === fieldName);\n if (!entry) return undefined;\n const value = data.billing_address[entry.key];\n return typeof value === \"string\" ? value : undefined;\n}\n\nexport type EditPaymentMethodFormData = z.infer<\n ReturnType<typeof createEditPaymentMethodFormSchema>\n>;\n\ninterface CountryOption {\n iso: string;\n name: string;\n}\n\ninterface EditPaymentMethodDialogProps {\n isOpen: boolean;\n paymentMethod: fluidPay.CustomerPaymentMethod | null;\n billingAddress?: BillingAddress | null;\n onClose: () => void;\n onSubmit: (data: EditPaymentMethodFormData) => void;\n isSubmitting: boolean;\n error?: string;\n countries?: CountryOption[];\n fetchStates?: (countryCode: string) => Promise<State[]>;\n /** Locale for the address fields lookup, so its labels come back translated. */\n languageIso?: string;\n onDelete?: () => void;\n isDeleting?: boolean;\n presentation?: ResponsiveDialogPresentation;\n}\n\nexport default function EditPaymentMethodDialog({\n isOpen,\n paymentMethod,\n billingAddress,\n onClose,\n onSubmit,\n isSubmitting,\n error,\n countries = [],\n fetchStates,\n languageIso,\n onDelete,\n isDeleting = false,\n presentation = \"dialog\",\n}: EditPaymentMethodDialogProps): JSX.Element | null {\n const { t } = useProfileTranslation();\n const [confirmDelete, setConfirmDelete] = useState(false);\n\n useEffect(() => {\n if (!isOpen) setConfirmDelete(false);\n }, [isOpen]);\n\n useEffect(() => {\n if (!confirmDelete) return;\n const timeoutId = setTimeout(() => setConfirmDelete(false), 3000);\n return () => clearTimeout(timeoutId);\n }, [confirmDelete]);\n\n const editPaymentMethodFormSchema = useMemo(\n () => createEditPaymentMethodFormSchema((key) => t(key as never)),\n [t],\n );\n\n const { control, handleSubmit, reset, setValue, setError, clearErrors } =\n useZodForm<EditPaymentMethodFormData>(editPaymentMethodFormSchema, {\n defaultValues: {\n billing_address: {\n name: \"\",\n address1: \"\",\n address2: \"\",\n city: \"\",\n state: \"\",\n zip: \"\",\n country_code: \"US\",\n },\n set_as_default: false,\n },\n });\n\n const billingCountry = useWatch({\n control,\n name: \"billing_address.country_code\",\n });\n\n const { stateOptions, optionsCountry, config, handleCountryChange } =\n useCountryStates();\n\n const countryOptions = [...countries]\n .map((country) => ({\n name: country.name,\n value: country.iso,\n }))\n .sort((a, b) => {\n if (a.value === billingCountry) return -1;\n if (b.value === billingCountry) return 1;\n return a.name.localeCompare(b.name);\n });\n\n const stateSelectOptions = stateOptions.map((state) => ({\n name: state.name,\n value: state.isoCode,\n }));\n\n useEffect(() => {\n if (paymentMethod && isOpen) {\n reset({\n billing_address: {\n name: billingAddress?.name ?? \"\",\n address1: billingAddress?.address1 ?? \"\",\n address2: billingAddress?.address2 ?? \"\",\n city: billingAddress?.city ?? \"\",\n state: billingAddress?.state ?? \"\",\n zip: billingAddress?.zip ?? \"\",\n country_code: billingAddress?.country_code ?? \"US\",\n },\n set_as_default: paymentMethod.default,\n });\n }\n }, [paymentMethod, billingAddress, isOpen, reset]);\n\n // The form opens on its static default and only takes the card's country once\n // the reset lands, so following the watched value immediately would look up a\n // country this card is not in and throw the answer away. Stay on the card's\n // country until the user picks a different one. Null while no card is on\n // screen, since hooks run before this dialog's early return.\n const cardCountry = billingAddress?.country_code ?? \"US\";\n const countryTouchedRef = useRef(false);\n useEffect(() => {\n if (!isOpen) countryTouchedRef.current = false;\n }, [isOpen]);\n const lookupCountry =\n !isOpen || !paymentMethod\n ? null\n : countryTouchedRef.current || billingCountry === cardCountry\n ? billingCountry\n : null;\n\n // Keeps the state options in step with the selected country, including on\n // open, so a non-US card doesn't come up listing US states.\n useEffect(() => {\n if (!lookupCountry) return;\n handleCountryChange(lookupCountry, fetchStates);\n }, [lookupCountry, handleCountryChange, fetchStates]);\n\n // Whether the subdivision list on screen describes the selected country. An\n // empty list means \"this country has none\" only once it does.\n const stateOptionsReady = optionsCountry === billingCountry;\n\n const addressFieldsApi = useAddressFieldsApiOptional();\n // The country's field metadata, or null when the lookup failed. `country`\n // records what the answer is about, so a pending lookup is distinguishable.\n const [countryFields, setCountryFields] = useState<{\n country: string;\n fields: readonly AddressField[] | null;\n } | null>(null);\n\n useEffect(() => {\n if (!addressFieldsApi || !lookupCountry) return;\n let cancelled = false;\n setCountryFields(null);\n addressFieldsApi\n .fetchAddressFields(lookupCountry, languageIso)\n .then((response) => {\n if (cancelled) return;\n setCountryFields({\n country: lookupCountry,\n fields: response.address_fields.fields,\n });\n })\n .catch(() => {\n if (!cancelled)\n setCountryFields({ country: lookupCountry, fields: null });\n });\n return () => {\n cancelled = true;\n };\n }, [addressFieldsApi, lookupCountry, languageIso]);\n\n const answeredFields =\n countryFields?.country === billingCountry ? countryFields?.fields : null;\n\n // Which fields this country collects, in the service's own order. The billing\n // form has no phone field, so drop it if the service sends one.\n const fieldOrder = useMemo(\n () =>\n addressFieldOrder(answeredFields ?? null).filter((f) => f !== \"phone\"),\n [answeredFields],\n );\n const fieldGroups = useMemo(\n () => groupAddressFields(fieldOrder),\n [fieldOrder],\n );\n\n // Deciding anything from the list before it arrives would act on the static\n // fallback and then rearrange under the user, so hold Save until the lookup\n // settles. A failed lookup counts as settled: otherwise a service outage\n // would leave the form unsaveable.\n const layoutReady = addressFieldsApi\n ? lookupCountry === null || countryFields?.country === billingCountry\n : // Without the service, the option list is the only signal, so wait for it.\n stateOptionsReady;\n\n const isRequired = (fieldName: AddressFieldName): boolean => {\n if (answeredFields)\n return isAddressFieldRequired(answeredFields, fieldName);\n // The static fallback assumes a US-shaped address, so require a\n // subdivision only when there is a list to pick one from.\n if (fieldName === \"state\") return stateSelectOptions.length > 0;\n return isAddressFieldRequired(null, fieldName);\n };\n\n const fieldLabel = (fieldName: AddressFieldName): string => {\n const resolved = addressFieldLabel(answeredFields ?? null, fieldName, {\n regionKey: config?.regionLabel,\n postalKey: config?.postalLabel,\n });\n return resolved.label ?? t((resolved.translationKey ?? fieldName) as never);\n };\n\n const REQUIRED_MESSAGE_KEYS: Record<string, string> = {\n name: \"name_is_required\",\n address1: \"address_line_1_is_required\",\n city: \"city_is_required\",\n state: \"state_is_required\",\n postal_code: \"zip_code_is_required\",\n };\n\n const handleFormSubmit = handleSubmit((data) => {\n clearErrors(FORM_PATHS_BY_FIELD.map((entry) => entry.path));\n if (!layoutReady) return;\n\n const missing = fieldOrder.filter(\n (fieldName) =>\n isRequired(fieldName) && !valueForField(data, fieldName)?.trim(),\n );\n if (missing.length > 0) {\n for (const fieldName of missing) {\n const key = REQUIRED_MESSAGE_KEYS[fieldName];\n if (!key) continue;\n setError(pathForField(fieldName), {\n type: \"manual\",\n message: t(key as never),\n });\n }\n return;\n }\n\n // Deliberately submits what is in the form even when the field is hidden:\n // blanking it would erase a stored subdivision the user never saw. Changing\n // country clears it through the country select instead.\n onSubmit(data);\n });\n\n const deleteButtonLabel = useMemo(() => {\n if (isDeleting) return t(\"deleting\");\n if (confirmDelete) return t(\"tap_to_confirm\");\n return t(\"delete_card\");\n }, [isDeleting, confirmDelete, t]);\n\n if (!paymentMethod) return null;\n\n const { details } = paymentMethod;\n const displayName = getCardDisplayName(paymentMethod, t(\"card_fallback\"));\n const expMonth = details.exp_month;\n const expYear = details.exp_year;\n\n const renderField = (fieldName: AddressFieldName): JSX.Element => {\n const label = fieldLabel(fieldName);\n if (fieldName === \"address1\") {\n return (\n <AddressAutocompleteInput\n key={fieldName}\n control={control}\n setValue={setValue}\n countryIso={billingCountry}\n addressLineField=\"billing_address.address1\"\n cityField=\"billing_address.city\"\n stateField={\n fieldOrder.includes(\"state\") ? \"billing_address.state\" : undefined\n }\n postalCodeField=\"billing_address.zip\"\n stateOptions={stateOptions}\n label={label}\n disabled={isSubmitting}\n />\n );\n }\n if (fieldName === \"state\" && stateSelectOptions.length > 0) {\n return (\n <FormSelectField\n key={fieldName}\n control={control}\n name=\"billing_address.state\"\n label={label}\n options={stateSelectOptions}\n placeholder={t(\"select_state\")}\n />\n );\n }\n // Anything else, including a subdivision with no list to pick from, is\n // typed. A required field must stay answerable.\n return (\n <FormTextField\n key={fieldName}\n control={control}\n name={pathForField(fieldName)}\n label={label}\n />\n );\n };\n\n return (\n <ResponsiveDialog\n open={isOpen}\n onOpenChange={(open) => !open && onClose()}\n title={t(\"edit_card\")}\n presentation={presentation}\n >\n <div className=\"space-y-4\">\n <div className=\"bg-muted rounded-lg p-4\">\n <div className=\"flex items-center gap-x-3\">\n <div className=\"h-6 w-10 flex-shrink-0\">\n <PaymentIcon\n logoUrl={details.logo_url}\n brand={getPaymentMethodLogoBrand(paymentMethod)}\n alt={displayName}\n />\n </div>\n <div className=\"flex flex-col\">\n <span className=\"text-foreground text-sm font-medium\">\n {displayName}\n </span>\n {expMonth != null && expYear != null && (\n <span className=\"text-muted-foreground text-sm\">\n {t(\"card_expires\")} {expMonth}/{expYear}\n </span>\n )}\n </div>\n </div>\n </div>\n\n <div>\n <h3 className=\"text-foreground mb-3 text-sm font-medium\">\n {t(\"billing_address\")}\n </h3>\n <div className=\"space-y-3\">\n <FormSelectField\n control={control}\n name=\"billing_address.country_code\"\n label={t(\"country\")}\n options={countryOptions}\n placeholder={t(\"select_an_option\")}\n onChange={() => {\n // From here on the select, not the card, decides which country\n // to look up.\n countryTouchedRef.current = true;\n // The old subdivision does not belong to the newly picked\n // country, and neither does a \"state is required\" error raised\n // against it by an earlier submit.\n setValue(\"billing_address.state\", \"\");\n clearErrors(\"billing_address.state\");\n }}\n />\n {fieldGroups.map((group) => (\n <div\n key={group.join(\"-\")}\n className={cn(\n \"grid grid-cols-1 gap-3\",\n group.length === 3\n ? \"sm:grid-cols-3\"\n : group.length === 2\n ? \"sm:grid-cols-2\"\n : undefined,\n )}\n >\n {group.map((fieldName) => renderField(fieldName))}\n </div>\n ))}\n </div>\n </div>\n </div>\n\n <Controller\n control={control}\n name=\"set_as_default\"\n render={({ field }) => (\n <div className=\"mt-2 flex items-center gap-x-2\">\n <Checkbox\n id=\"set_as_default\"\n checked={field.value}\n onCheckedChange={(checked) => field.onChange(checked === true)}\n />\n <Label htmlFor=\"set_as_default\" className=\"text-sm font-normal\">\n {t(\"set_as_default_payment_method\")}\n </Label>\n </div>\n )}\n />\n\n {error && <div className=\"text-destructive text-sm\">{error}</div>}\n\n <DialogFooter className=\"flex flex-row items-center justify-between gap-2\">\n {onDelete ? (\n <Button\n type=\"button\"\n variant=\"ghost\"\n onClick={() => {\n if (confirmDelete) {\n onDelete();\n } else {\n setConfirmDelete(true);\n }\n }}\n disabled={isSubmitting || isDeleting}\n className=\"text-destructive hover:bg-destructive/10 hover:text-destructive\"\n >\n <Trash2 className=\"size-4\" />\n {deleteButtonLabel}\n </Button>\n ) : (\n <span />\n )}\n <div className=\"flex items-center gap-2\">\n <Button\n type=\"button\"\n variant=\"secondary\"\n onClick={onClose}\n disabled={isSubmitting || isDeleting}\n >\n {t(\"cancel\")}\n </Button>\n <Button\n type=\"button\"\n onClick={handleFormSubmit}\n disabled={isSubmitting || isDeleting || !layoutReady}\n >\n {isSubmitting && (\n <div className=\"mr-2 size-4 animate-spin rounded-full border-2 border-current/30 border-t-current\" />\n )}\n {isSubmitting ? t(\"saving\") : t(\"save_changes\")}\n </Button>\n </div>\n </DialogFooter>\n </ResponsiveDialog>\n );\n}\n","import type React from \"react\";\nimport { useController, type Control } from \"react-hook-form\";\nimport {\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Label,\n Textarea,\n cn,\n} from \"@fluid-app/ui-primitives\";\nimport { z } from \"zod\";\nimport { FormTextField } from \"./form-fields\";\nimport { useProfileTranslation } from \"@fluid-app/profile-core/translation-api-context\";\n\nfunction normalizeUrl(value: string): string {\n const trimmed = value.trim();\n if (!trimmed) return \"\";\n if (/^https?:\\/\\//i.test(trimmed)) return trimmed;\n return `https://${trimmed}`;\n}\n\nconst urlField = z\n .string()\n .transform(normalizeUrl)\n .pipe(z.string().url().or(z.literal(\"\")));\n\nexport const mySiteProfileSchema = z.object({\n bio: z.string().optional(),\n linkedin: urlField,\n facebook: urlField,\n twitter: urlField,\n instagram: urlField,\n youtube: urlField,\n pinterest: urlField,\n tiktok: urlField,\n whatsapp: z.string().optional(),\n wechat: z.string().optional(),\n});\n\nexport type MySiteProfileFormData = z.infer<typeof mySiteProfileSchema>;\n\nexport const socialFields = [\n {\n name: \"linkedin\",\n label: \"LinkedIn\",\n placeholder: \"linkedin.com/in/username\",\n },\n { name: \"facebook\", label: \"Facebook\", placeholder: \"facebook.com/username\" },\n { name: \"twitter\", label: \"X (Twitter)\", placeholder: \"x.com/username\" },\n {\n name: \"instagram\",\n label: \"Instagram\",\n placeholder: \"instagram.com/username\",\n },\n { name: \"youtube\", label: \"YouTube\", placeholder: \"youtube.com/@channel\" },\n {\n name: \"pinterest\",\n label: \"Pinterest\",\n placeholder: \"pinterest.com/username\",\n },\n { name: \"tiktok\", label: \"TikTok\", placeholder: \"tiktok.com/@username\" },\n { name: \"whatsapp\", label: \"WhatsApp\", placeholder: \"Phone number or link\" },\n { name: \"wechat\", label: \"WeChat\", placeholder: \"WeChat ID\" },\n] as const satisfies readonly {\n name: keyof Omit<MySiteProfileFormData, \"bio\">;\n label: string;\n placeholder: string;\n}[];\n\nexport interface MySiteProfileSectionProps {\n avatarUrl?: string | null;\n initial?: string;\n control: Control<MySiteProfileFormData>;\n}\n\nfunction BioField({ control }: { control: Control<MySiteProfileFormData> }) {\n const { t } = useProfileTranslation();\n const {\n field,\n fieldState: { error },\n } = useController({ name: \"bio\", control });\n return (\n <div className=\"space-y-1\">\n <Label htmlFor=\"mysite-bio\" className=\"block text-sm font-medium\">\n {t(\"bio\")}\n </Label>\n <Textarea\n id=\"mysite-bio\"\n rows={4}\n placeholder={t(\"bio_placeholder\")}\n className={cn(error && \"ring-destructive ring-1\")}\n {...field}\n value={field.value ?? \"\"}\n />\n {error && <p className=\"text-destructive text-sm\">{error.message}</p>}\n </div>\n );\n}\n\nexport function MySiteProfileSection({\n avatarUrl,\n initial,\n control,\n}: MySiteProfileSectionProps): React.JSX.Element {\n const { t } = useProfileTranslation();\n return (\n <Card>\n <CardHeader>\n <CardTitle>{t(\"about_me\")}</CardTitle>\n </CardHeader>\n <CardContent className=\"flex flex-col gap-6 lg:flex-row lg:gap-10\">\n <div className=\"bg-muted relative h-[120px] w-[120px] shrink-0 self-center overflow-hidden rounded-full lg:self-auto\">\n {avatarUrl ? (\n <img\n src={avatarUrl}\n alt={t(\"profile_image_alt\")}\n className=\"h-full w-full object-cover\"\n />\n ) : (\n <div className=\"bg-background text-foreground flex h-full w-full items-center justify-center text-xl font-semibold\">\n {initial ?? \"U\"}\n </div>\n )}\n </div>\n\n <div className=\"min-w-0 flex-1\">\n <BioField control={control} />\n </div>\n </CardContent>\n </Card>\n );\n}\n\nexport interface MySiteProfileSocialSectionProps {\n control: Control<MySiteProfileFormData>;\n}\n\nexport function MySiteProfileSocialSection({\n control,\n}: MySiteProfileSocialSectionProps): React.JSX.Element {\n const { t } = useProfileTranslation();\n return (\n <Card>\n <CardHeader>\n <CardTitle>{t(\"social_media_links\")}</CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-4\">\n {socialFields.map((field) => {\n let placeholder: string = field.placeholder;\n if (field.name === \"whatsapp\")\n placeholder = t(\"whatsapp_placeholder\");\n if (field.name === \"wechat\") placeholder = t(\"wechat_placeholder\");\n return (\n <FormTextField\n key={field.name}\n control={control}\n name={field.name}\n label={field.label}\n placeholder={placeholder}\n />\n );\n })}\n </div>\n </CardContent>\n </Card>\n );\n}\n\nexport interface MySiteProfileSaveButtonProps {\n isDirty: boolean;\n isPending: boolean;\n onSubmit: () => void;\n}\n\nexport function MySiteProfileSaveButton({\n isDirty,\n isPending,\n onSubmit,\n}: MySiteProfileSaveButtonProps): React.JSX.Element {\n const { t } = useProfileTranslation();\n return (\n <div className=\"flex justify-end pb-6\">\n <Button\n type=\"button\"\n onClick={onSubmit}\n disabled={!isDirty || isPending}\n className=\"w-full sm:w-auto\"\n >\n {isPending && (\n <div className=\"mr-2 size-4 animate-spin rounded-full border-2 border-current/30 border-t-current\" />\n )}\n {isPending ? t(\"saving\") : t(\"save\")}\n </Button>\n </div>\n );\n}\n","\"use client\";\n\nimport type { Control, FieldPath, FieldValues } from \"react-hook-form\";\nimport { useController } from \"react-hook-form\";\nimport { Input, Label, cn } from \"@fluid-app/ui-primitives\";\n\ninterface FormTextFieldProps<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n> {\n control: Control<TFieldValues>;\n name: TName;\n label?: string;\n placeholder?: string;\n containerClassName?: string;\n type?: React.HTMLInputTypeAttribute;\n disabled?: boolean;\n inputMode?: React.HTMLAttributes<HTMLInputElement>[\"inputMode\"];\n autoComplete?: string;\n}\n\nexport function FormTextField<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n>({\n control,\n name,\n label,\n placeholder,\n containerClassName,\n type,\n disabled,\n inputMode,\n autoComplete,\n}: FormTextFieldProps<TFieldValues, TName>) {\n const {\n field,\n fieldState: { error },\n } = useController({ name, control });\n\n return (\n <div className={cn(\"space-y-1\", containerClassName)}>\n {label && (\n <Label htmlFor={name} className=\"mb-1.5 block text-sm font-medium\">\n {label}\n </Label>\n )}\n <Input\n {...field}\n value={field.value ?? \"\"}\n id={name}\n type={type}\n disabled={disabled}\n inputMode={inputMode}\n placeholder={placeholder}\n autoComplete={autoComplete}\n aria-invalid={!!error}\n />\n {error?.message && (\n <p className=\"text-destructive text-sm\">{error.message}</p>\n )}\n </div>\n );\n}\n","\"use client\";\n\nimport { useMemo } from \"react\";\nimport type { Control, FieldPath, FieldValues } from \"react-hook-form\";\nimport { Controller } from \"react-hook-form\";\nimport { Label, cn } from \"@fluid-app/ui-primitives\";\nimport { Combobox } from \"@fluid-app/ui-components/components/Combobox\";\n\ntype NameValue = { name: string; value: string | number };\n\ninterface FormComboboxFieldProps<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n> {\n control: Control<TFieldValues>;\n name: TName;\n label?: string;\n placeholder?: string;\n emptyText?: string;\n options?: NameValue[];\n containerClassName?: string;\n disabled?: boolean;\n onChange?: (value: string) => void;\n}\n\nexport function FormComboboxField<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n>({\n control,\n name,\n label,\n placeholder = \"Select\",\n emptyText = \"No results found.\",\n options,\n containerClassName,\n disabled,\n onChange,\n}: FormComboboxFieldProps<TFieldValues, TName>) {\n const comboboxOptions = useMemo(\n () =>\n options?.map((opt) => ({\n label: opt.name,\n value: opt.value.toString(),\n })) ?? [],\n [options],\n );\n\n return (\n <div className={cn(\"space-y-1\", containerClassName)}>\n {label && (\n <Label htmlFor={name} className=\"mb-1.5 block text-sm font-medium\">\n {label}\n </Label>\n )}\n <Controller\n control={control}\n name={name}\n render={({\n field: { onChange: fieldOnChange, value },\n fieldState: { error },\n }) => (\n <>\n <Combobox\n options={comboboxOptions}\n value={value?.toString() ?? \"\"}\n onValueChange={(next) => {\n fieldOnChange(next);\n onChange?.(next);\n }}\n placeholder={placeholder}\n emptyText={emptyText}\n disabled={disabled}\n />\n {error?.message && (\n <p className=\"text-destructive text-sm\">{error.message}</p>\n )}\n </>\n )}\n />\n </div>\n );\n}\n","import { type JSX, useEffect, useId, useMemo, useState } from \"react\";\nimport { Controller, useWatch } from \"react-hook-form\";\nimport { Trash2 } from \"lucide-react\";\nimport { z } from \"zod\";\nimport {\n Button,\n Checkbox,\n Label,\n cn,\n useZodForm,\n} from \"@fluid-app/ui-primitives\";\nimport {\n ResponsiveDialog,\n type ResponsiveDialogPresentation,\n} from \"@fluid-app/ui-components/components/ResponsiveDialog\";\nimport { FormTextField } from \"./form-fields/FormTextField\";\nimport { FormComboboxField } from \"./form-fields/FormComboboxField\";\nimport { PhoneInput } from \"@fluid-app/ui-components/components/PhoneInput\";\nimport type { fluidPay } from \"@fluid-app/fluid-pay-core\";\nimport { useCountryStates, type State } from \"@fluid-app/fluid-pay-core\";\nimport { useAddressFieldsApiOptional } from \"@fluid-app/address-fields/address-fields-api-context\";\nimport type { AddressField } from \"@fluid-app/address-fields/types\";\nimport {\n addressFieldLabel,\n addressFieldOrder,\n groupAddressFields,\n isAddressFieldRequired,\n type AddressFieldName,\n} from \"@fluid-app/address-fields/field-layout\";\nimport { AddressAutocompleteInput } from \"@fluid-app/address-autocomplete/components/AddressAutocompleteInput\";\n\nconst addressFormSchema = z.object({\n name: z.string(),\n address1: z.string(),\n address2: z.string().optional().nullable(),\n city: z.string(),\n state: z.string(),\n postal_code: z.string(),\n phone: z.string().optional().nullable(),\n country_code: z.string().min(1, \"Country is required\"),\n default: z.boolean(),\n});\n\nexport type AddressFormData = z.infer<typeof addressFormSchema>;\n\ninterface CountryOption {\n iso: string;\n name: string;\n}\n\ninterface AddressFormDialogProps {\n isOpen: boolean;\n onClose: () => void;\n selectedAddress: fluidPay.CustomerAddress | null;\n onSubmit: (data: fluidPay.CreateAddressBody) => void;\n isSubmitting: boolean;\n countries?: CountryOption[];\n error?: string;\n fetchStates?: (countryCode: string) => Promise<State[]>;\n t: (key: string) => string;\n onDelete?: () => void;\n isDeleting?: boolean;\n defaultCountry?: string;\n languageIso?: string;\n presentation?: ResponsiveDialogPresentation;\n}\n\nconst REQUIRED_FIELD_MESSAGES: Record<AddressFieldName, string> = {\n name: \"Name is required\",\n address1: \"Address line 1 is required\",\n address2: \"Address line 2 is required\",\n city: \"City is required\",\n state: \"State is required\",\n postal_code: \"Postal code is required\",\n phone: \"Phone is required\",\n};\n\nfunction isBlank(value: string | null | undefined): boolean {\n return value == null || value.trim().length === 0;\n}\n\nexport default function AddressFormDialog({\n isOpen,\n onClose,\n selectedAddress,\n onSubmit,\n isSubmitting,\n countries = [],\n error,\n fetchStates,\n t,\n onDelete,\n isDeleting = false,\n defaultCountry = \"US\",\n languageIso,\n presentation = \"dialog\",\n}: AddressFormDialogProps): JSX.Element {\n const [confirmDelete, setConfirmDelete] = useState(false);\n const phoneInputId = useId();\n const addressFieldsApi = useAddressFieldsApiOptional();\n const [bffFields, setBffFields] = useState<AddressField[] | null>(null);\n\n useEffect(() => {\n if (!isOpen) setConfirmDelete(false);\n }, [isOpen]);\n\n useEffect(() => {\n if (!confirmDelete) return;\n const timeoutId = setTimeout(() => setConfirmDelete(false), 3000);\n return () => clearTimeout(timeoutId);\n }, [confirmDelete]);\n\n const deleteButtonLabel = useMemo(() => {\n if (isDeleting) return t(\"deleting\");\n if (confirmDelete) return t(\"tap_to_confirm\");\n return t(\"delete_address\");\n }, [isDeleting, confirmDelete, t]);\n\n const { control, handleSubmit, reset, setValue, setError, clearErrors } =\n useZodForm<AddressFormData>(addressFormSchema, {\n defaultValues: {\n name: \"\",\n address1: \"\",\n address2: \"\",\n city: \"\",\n state: \"\",\n postal_code: \"\",\n phone: \"\",\n country_code: defaultCountry,\n default: false,\n },\n });\n\n const selectedCountryCode = useWatch({ control, name: \"country_code\" });\n\n const { stateOptions, config, handleCountryChange } = useCountryStates();\n\n useEffect(() => {\n if (!addressFieldsApi || !selectedCountryCode) return;\n let cancelled = false;\n setBffFields(null);\n addressFieldsApi\n .fetchAddressFields(selectedCountryCode, languageIso)\n .then((response) => {\n if (!cancelled) {\n setBffFields([...response.address_fields.fields]);\n }\n })\n .catch(() => {\n if (!cancelled) setBffFields(null);\n });\n return () => {\n cancelled = true;\n };\n }, [addressFieldsApi, selectedCountryCode, languageIso]);\n\n const fieldOrder = useMemo(() => addressFieldOrder(bffFields), [bffFields]);\n\n const fieldGroups = useMemo(\n () => groupAddressFields(fieldOrder),\n [fieldOrder],\n );\n\n const getFieldLabel = (fieldName: AddressFieldName): string => {\n const resolved = addressFieldLabel(bffFields, fieldName, {\n regionKey: config?.regionLabel,\n postalKey: config?.postalLabel,\n });\n return resolved.label ?? t(resolved.translationKey ?? fieldName);\n };\n\n const countrySelectOptions = [...countries]\n .map((country) => ({\n name: country.name,\n value: country.iso,\n }))\n .sort((a, b) => {\n if (a.value === selectedCountryCode) return -1;\n if (b.value === selectedCountryCode) return 1;\n return a.name.localeCompare(b.name);\n });\n\n const stateSelectOptions = stateOptions.map((state) => ({\n name: state.name,\n value: state.isoCode,\n }));\n\n useEffect(() => {\n if (isOpen) {\n if (selectedAddress) {\n reset({\n name: selectedAddress.name ?? \"\",\n address1: selectedAddress.address1,\n address2: selectedAddress.address2 ?? \"\",\n city: selectedAddress.city,\n state: selectedAddress.state,\n postal_code: selectedAddress.postal_code,\n phone: selectedAddress.phone ?? \"\",\n country_code: selectedAddress.country_code ?? defaultCountry,\n default: selectedAddress.default,\n });\n handleCountryChange(\n selectedAddress.country_code ?? defaultCountry,\n fetchStates,\n );\n } else {\n reset({\n name: \"\",\n address1: \"\",\n address2: \"\",\n city: \"\",\n state: \"\",\n postal_code: \"\",\n phone: \"\",\n country_code: defaultCountry,\n default: false,\n });\n handleCountryChange(defaultCountry, fetchStates);\n }\n }\n // defaultCountry intentionally omitted: a background addresses refetch can\n // change the parent-computed value while the dialog is open, which would\n // wipe the user's in-progress edits.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selectedAddress, isOpen, reset, handleCountryChange, fetchStates]);\n\n useEffect(() => {\n handleCountryChange(selectedCountryCode, fetchStates);\n }, [selectedCountryCode, handleCountryChange, fetchStates]);\n\n const handleFormSubmit = handleSubmit((data) => {\n clearErrors(fieldOrder);\n const missingRequiredFields = fieldOrder.filter(\n (fieldName) =>\n isAddressFieldRequired(bffFields, fieldName) &&\n isBlank(data[fieldName]),\n );\n\n if (missingRequiredFields.length > 0) {\n for (const fieldName of missingRequiredFields) {\n setError(fieldName, {\n type: \"manual\",\n message: REQUIRED_FIELD_MESSAGES[fieldName],\n });\n }\n return;\n }\n\n // Submits what is in the form even for a field this country does not\n // collect. The value is rendered in full_address and on order PDFs, so\n // erasing it would drop it from documents the customer reads. Switching\n // country is what clears a subdivision left over from the previous one.\n onSubmit({\n address: {\n name: data.name,\n address1: data.address1,\n address2: data.address2 ?? null,\n city: data.city,\n state: data.state,\n postal_code: data.postal_code,\n phone: data.phone || null,\n country_code: data.country_code,\n default: data.default,\n },\n });\n });\n\n const renderField = (\n fieldName: AddressFieldName,\n containerClassName?: string,\n ): JSX.Element => {\n const label = getFieldLabel(fieldName);\n\n if (fieldName === \"state\" && stateSelectOptions.length > 0) {\n return (\n <FormComboboxField\n key={fieldName}\n control={control}\n name=\"state\"\n label={label}\n placeholder={t(\"select_state\")}\n options={stateSelectOptions}\n containerClassName={containerClassName}\n disabled={isSubmitting}\n />\n );\n }\n\n if (fieldName === \"address1\") {\n return (\n <div key={fieldName} className={cn(\"space-y-1\", containerClassName)}>\n <Label\n htmlFor={fieldName}\n className=\"mb-1.5 block text-sm font-medium\"\n >\n {label}\n </Label>\n <AddressAutocompleteInput\n control={control}\n setValue={setValue}\n countryIso={selectedCountryCode}\n addressLineField=\"address1\"\n cityField=\"city\"\n stateField={fieldOrder.includes(\"state\") ? \"state\" : undefined}\n postalCodeField=\"postal_code\"\n stateOptions={stateOptions}\n disabled={isSubmitting}\n />\n </div>\n );\n }\n\n if (fieldName === \"phone\") {\n return (\n <div key={fieldName} className={containerClassName}>\n <Controller\n control={control}\n name=\"phone\"\n render={({ field: { value, onChange }, fieldState: { error } }) => (\n <div className=\"space-y-1\">\n <Label\n htmlFor={phoneInputId}\n className=\"mb-1.5 block text-sm font-medium\"\n >\n {label}\n </Label>\n <PhoneInput\n id={phoneInputId}\n value={value ?? \"\"}\n onChange={onChange}\n defaultCountry={selectedCountryCode}\n error={!!error}\n disabled={isSubmitting}\n searchPlaceholder={t(\"search_country\")}\n emptyText={t(\"no_results_found\")}\n />\n {error?.message && (\n <p className=\"text-destructive text-sm\">{error.message}</p>\n )}\n </div>\n )}\n />\n </div>\n );\n }\n\n return (\n <FormTextField\n key={fieldName}\n control={control}\n name={fieldName}\n label={label}\n containerClassName={containerClassName}\n disabled={isSubmitting}\n autoComplete={fieldName === \"name\" ? \"name\" : undefined}\n />\n );\n };\n\n const isEditMode = selectedAddress !== null;\n\n return (\n <ResponsiveDialog\n open={isOpen}\n onOpenChange={(open) => !open && onClose()}\n title={isEditMode ? t(\"edit_address\") : t(\"add_an_address\")}\n presentation={presentation}\n size=\"wide\"\n >\n <div className=\"space-y-3 pt-2\">\n <FormComboboxField\n control={control}\n name=\"country_code\"\n label={t(\"country\")}\n placeholder={t(\"select_an_option\")}\n options={countrySelectOptions}\n disabled={isSubmitting}\n onChange={() => {\n // The old subdivision does not belong to the newly picked country,\n // and neither does a required-field error raised against it by an\n // earlier submit.\n setValue(\"state\", \"\");\n clearErrors(\"state\");\n }}\n />\n {fieldGroups.map((group) => {\n if (group.length === 1) {\n return renderField(group[0]!);\n }\n return (\n <div\n key={group.join(\"-\")}\n className=\"flex flex-col gap-3 sm:flex-row\"\n >\n {group.map((fieldName) =>\n renderField(fieldName, \"min-w-0 flex-1\"),\n )}\n </div>\n );\n })}\n </div>\n\n <div className=\"mt-4 flex flex-wrap items-center justify-between gap-3\">\n {onDelete ? (\n <Button\n type=\"button\"\n variant=\"ghost\"\n onClick={() => {\n if (confirmDelete) {\n onDelete();\n } else {\n setConfirmDelete(true);\n }\n }}\n disabled={isSubmitting || isDeleting}\n className=\"text-destructive hover:bg-destructive/10 hover:text-destructive\"\n >\n <Trash2 className=\"size-4\" />\n {deleteButtonLabel}\n </Button>\n ) : (\n <span />\n )}\n <div className=\"flex items-center gap-3\">\n <Controller\n control={control}\n name=\"default\"\n render={({ field }) => (\n <div className=\"flex items-center gap-x-2\">\n <Checkbox\n id=\"set_as_default_address\"\n checked={field.value}\n onCheckedChange={(checked) =>\n field.onChange(checked === true)\n }\n disabled={isSubmitting || isDeleting}\n />\n <Label\n htmlFor=\"set_as_default_address\"\n className=\"text-sm font-normal\"\n >\n {t(\"set_as_default_address\")}\n </Label>\n </div>\n )}\n />\n\n <Button\n type=\"submit\"\n onClick={handleFormSubmit}\n disabled={isSubmitting || isDeleting}\n >\n {isSubmitting && (\n <div className=\"mr-2 size-4 animate-spin rounded-full border-2 border-current/30 border-t-current\" />\n )}\n {isSubmitting ? t(\"saving\") : t(\"save_address\")}\n </Button>\n </div>\n </div>\n\n {error && <div className=\"text-destructive mt-2 text-sm\">{error}</div>}\n </ResponsiveDialog>\n );\n}\n","import { useEffect, useRef, useState, useCallback } from \"react\";\nimport type { fluidPay } from \"@fluid-app/fluid-pay-core\";\n\nexport type VgsFieldState = {\n isFocused: boolean;\n isValid: boolean;\n isEmpty: boolean;\n cardType?: string;\n bin?: string;\n last4?: string;\n};\n\nexport type VgsFormState = {\n [key: string]: VgsFieldState;\n};\n\ninterface VGSCollectForm {\n setRouteId: (routeId: string) => void;\n field: (selector: string, config: Record<string, unknown>) => void;\n submit: (\n path: string,\n options: { headers?: Record<string, string> },\n successCallback: (\n status: number,\n response: fluidPay.VgsCollectSubmitResponse,\n ) => void,\n errorCallback: (errors: Record<string, string[]>) => void,\n ) => void;\n unmount: () => void;\n}\n\ninterface VGSCollectLibrary {\n create: (\n vaultId: string,\n environment: string,\n stateCallback: (state: Record<string, Partial<VgsFieldState>>) => void,\n ) => VGSCollectForm;\n}\n\nconst getVGSCollect = (): VGSCollectLibrary | null => {\n if (typeof window !== \"undefined\") {\n return (\n (window as unknown as { VGSCollect?: VGSCollectLibrary }).VGSCollect ||\n null\n );\n }\n return null;\n};\n\nconst DEFAULT_FIELD_STATE: VgsFormState = {\n card_number: { isFocused: false, isValid: false, isEmpty: true },\n card_exp: { isFocused: false, isValid: false, isEmpty: true },\n card_cvc: { isFocused: false, isValid: false, isEmpty: true },\n card_holder: { isFocused: false, isValid: false, isEmpty: true },\n};\n\nexport function useVgsCollect() {\n const [isFormReady, setIsFormReady] = useState(false);\n const [isLoading, setIsLoading] = useState(false);\n const [isScriptLoaded, setIsScriptLoaded] = useState(false);\n const [scriptLoadError, setScriptLoadError] = useState<string | undefined>(\n undefined,\n );\n\n const [vgsFieldState, setVgsFieldState] =\n useState<VgsFormState>(DEFAULT_FIELD_STATE);\n\n const formRef = useRef<VGSCollectForm | null>(null);\n const onSuccessRef = useRef<\n ((response: fluidPay.VgsCollectSubmitResponse) => void) | null\n >(null);\n const onErrorRef = useRef<((error: string) => void) | null>(null);\n\n // Load VGS Collect script\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n\n const vgsCollect = getVGSCollect();\n if (vgsCollect) {\n const timeoutId = window.setTimeout(() => {\n setIsScriptLoaded(true);\n }, 0);\n return () => window.clearTimeout(timeoutId);\n }\n\n if (isScriptLoaded) return;\n\n const script = document.createElement(\"script\");\n script.src =\n \"https://js.verygoodvault.com/vgs-collect/3.3.0/vgs-collect.js\";\n script.async = true;\n script.onload = () => setIsScriptLoaded(true);\n // Surface load failures both to a registered consumer (if any) and to\n // state, so a consumer mounting after the failure still sees it.\n script.onerror = () => {\n const message = \"Failed to load payment form\";\n setScriptLoadError(message);\n onErrorRef.current?.(message);\n };\n document.head.appendChild(script);\n }, [isScriptLoaded]);\n\n const updateFieldState = useCallback(\n (state: Record<string, Partial<VgsFieldState>>) => {\n if (!state) return;\n\n setVgsFieldState((prev) => {\n const newState: VgsFormState = { ...prev };\n let hasChanges = false;\n\n Object.keys(state).forEach((key) => {\n const field = state[key];\n if (!field) return;\n\n const next: VgsFieldState = {\n isFocused: !!field.isFocused,\n isValid: !!field.isValid,\n isEmpty: !!field.isEmpty,\n cardType: field.cardType,\n bin: field.bin,\n last4: field.last4,\n };\n\n if (\n !newState[key] ||\n JSON.stringify(newState[key]) !== JSON.stringify(next)\n ) {\n newState[key] = next;\n hasChanges = true;\n }\n });\n\n return hasChanges ? newState : prev;\n });\n },\n [],\n );\n\n const resetVgs = useCallback(() => {\n if (formRef.current) {\n try {\n formRef.current.unmount();\n } catch (e) {\n console.warn(\"VGS unmount error\", e);\n }\n formRef.current = null;\n }\n\n setIsFormReady(false);\n setVgsFieldState({ ...DEFAULT_FIELD_STATE });\n }, []);\n\n const initializeForm = useCallback(\n async (credentials: fluidPay.VaultResponse) => {\n if (!isScriptLoaded) return;\n\n const VGSCollect = getVGSCollect();\n if (!VGSCollect) {\n onErrorRef.current?.(\"Payment script not loaded\");\n return;\n }\n\n try {\n setIsLoading(true);\n\n const vgsEnvironment =\n credentials.vault.environment === \"sandbox\" ? \"sandbox\" : \"live-eu-1\";\n\n const form = VGSCollect.create(\n credentials.vault.vault_id,\n vgsEnvironment,\n (state) => updateFieldState(state),\n );\n\n if (credentials.vault.route_id) {\n form.setRouteId(credentials.vault.route_id);\n }\n\n formRef.current = form;\n\n // Wait for DOM elements\n let retries = 0;\n const maxRetries = 20;\n const retryDelay = 200;\n\n const waitForDom = async (): Promise<boolean> => {\n const allExist = [\n \"vgs-card-number\",\n \"vgs-expiration-date\",\n \"vgs-cvc\",\n \"vgs-card-holder\",\n ].every((id) => {\n const el = document.getElementById(id);\n return el && el.isConnected;\n });\n\n if (allExist) return true;\n if (retries >= maxRetries) return false;\n\n retries++;\n await new Promise((resolve) => setTimeout(resolve, retryDelay));\n return waitForDom();\n };\n\n const domReady = await waitForDom();\n if (!domReady) {\n throw new Error(\"Payment form elements not ready\");\n }\n\n // Resolve theme tokens from the wrapper element. The theme engine\n // applies `data-theme` on a subtree element (not <html>), so CSS\n // variables aren't visible on document.documentElement — only on a\n // node inside the themed subtree. Cross-origin iframe contents\n // can't see parent CSS variables, so we resolve concrete values\n // here and pass them to VGS.\n //\n // The `vgs-card-number` element is guaranteed to exist at this\n // point: the `waitForDom` check above blocks until all four VGS\n // wrapper elements are mounted. The hardcoded fallback colors only\n // activate if the CSS variables themselves are unset.\n const themedNode = document.getElementById(\"vgs-card-number\");\n const probeStyle = themedNode ? getComputedStyle(themedNode) : null;\n const foregroundColor =\n probeStyle?.getPropertyValue(\"--color-foreground\").trim() ||\n \"#0a0a0a\";\n const mutedForegroundColor =\n probeStyle?.getPropertyValue(\"--color-muted-foreground\").trim() ||\n \"#737373\";\n\n const css = {\n fontSize: \"16px\",\n fontFamily:\n \"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif\",\n color: foregroundColor,\n background: \"transparent\",\n paddingTop: \"0px\",\n paddingBottom: \"0px\",\n paddingLeft: \"0px\",\n paddingRight: \"0px\",\n boxSizing: \"border-box\",\n lineHeight: \"26px\",\n height: \"100%\",\n width: \"100%\",\n \"&::placeholder\": { color: mutedForegroundColor, opacity: 1 },\n \"&:focus\": { outline: \"none\" },\n };\n\n form.field(\"#vgs-card-number\", {\n type: \"card-number\",\n name: \"card_number\",\n placeholder: \"0000 0000 0000 0000\",\n showCardIcon: true,\n css: { ...css, paddingRight: \"40px\" },\n autoComplete: \"cc-number\",\n validations: [\"required\", \"validCardNumber\"],\n });\n\n form.field(\"#vgs-expiration-date\", {\n type: \"card-expiration-date\",\n name: \"card_exp\",\n yearLength: 2,\n placeholder: \"MM / YY\",\n css,\n autoComplete: \"cc-exp\",\n validations: [\"required\", \"validCardExpirationDate\"],\n });\n\n form.field(\"#vgs-cvc\", {\n type: \"card-security-code\",\n name: \"card_cvc\",\n placeholder: \"123\",\n css,\n autoComplete: \"cc-csc\",\n validations: [\"required\", \"validCardSecurityCode\"],\n });\n\n form.field(\"#vgs-card-holder\", {\n type: \"text\",\n name: \"card_holder\",\n placeholder: \"Full Name\",\n css,\n autoComplete: \"cc-name\",\n validations: [\"required\"],\n });\n\n setIsFormReady(true);\n } catch (error) {\n console.error(\"Failed to initialize VGS:\", error);\n onErrorRef.current?.(\"Failed to initialize payment form\");\n } finally {\n setIsLoading(false);\n }\n },\n [isScriptLoaded, updateFieldState],\n );\n\n const submitCard = useCallback(() => {\n if (!formRef.current) {\n onErrorRef.current?.(\"Form not initialized\");\n return;\n }\n\n formRef.current.submit(\n `/post`,\n {},\n (status: number, response: fluidPay.VgsCollectSubmitResponse) => {\n if (status >= 200 && status < 400) {\n onSuccessRef.current?.(response);\n } else {\n onErrorRef.current?.(\"Payment failed\");\n }\n },\n (errors: Record<string, string[]>) => {\n const allErrors = Object.values(errors)\n .flat()\n .filter(\n (msg) =>\n typeof msg === \"string\" &&\n msg.trim().length > 0 &&\n msg !== \"Required\",\n );\n\n const uniqueErrors = Array.from(new Set(allErrors));\n\n let errorMsg = \"Please verify your payment details.\";\n if (uniqueErrors.length > 0) {\n errorMsg = uniqueErrors.join(\", \");\n } else {\n const rawErrors = Object.values(errors).flat();\n if (rawErrors.length > 0) {\n errorMsg = \"Please fill in all required fields.\";\n }\n }\n\n onErrorRef.current?.(errorMsg);\n },\n );\n }, []);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n if (formRef.current) {\n try {\n formRef.current.unmount();\n } catch (e) {\n console.warn(\"VGS unmount error\", e);\n }\n formRef.current = null;\n }\n };\n }, []);\n\n return {\n isFormReady,\n isLoading,\n isScriptLoaded,\n scriptLoadError,\n initializeForm,\n submitCard,\n vgsFieldState,\n resetVgs,\n onSuccessRef,\n onErrorRef,\n };\n}\n","import {\n type JSX,\n type ReactNode,\n useCallback,\n useEffect,\n useMemo,\n useState,\n} from \"react\";\nimport { Controller } from \"react-hook-form\";\nimport { z } from \"zod\";\nimport {\n Button,\n Checkbox,\n Label,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n cn,\n useZodForm,\n} from \"@fluid-app/ui-primitives\";\nimport {\n ResponsiveDialog,\n type ResponsiveDialogPresentation,\n} from \"@fluid-app/ui-components/components/ResponsiveDialog\";\nimport type { fluidPay } from \"@fluid-app/fluid-pay-core\";\nimport { useFluidPayApi } from \"@fluid-app/fluid-pay-core\";\nimport {\n useVgsCollect,\n type VgsFieldState,\n type VgsFormState,\n} from \"../hooks/use-vgs-collect\";\n\nconst SENTINEL_CREATE_NEW = \"__create_new__\";\n\nconst formSchema = z.object({\n billing_address_selection: z\n .string()\n .refine((value) => value !== \"\" && value !== SENTINEL_CREATE_NEW, {\n message: \"Please select a billing address\",\n }),\n set_as_default: z.boolean(),\n});\n\ntype FormData = z.infer<typeof formSchema>;\n\nexport interface CreditCardFormSubmitData {\n set_as_default: boolean;\n payment_method: {\n token: string;\n cvv_token: string;\n exp_month: string;\n exp_year: string;\n card_holder: string;\n bin?: string;\n last_four?: string;\n card_network?: string;\n };\n billing_address_id: number;\n}\n\nexport interface RenderAddressFormDialogProps {\n isOpen: boolean;\n onClose: () => void;\n onAddressCreated: (address: fluidPay.CustomerAddress) => void;\n}\n\ninterface CreditCardFormDialogProps {\n isOpen: boolean;\n onClose: () => void;\n onSubmit: (data: CreditCardFormSubmitData) => void;\n isSubmitting: boolean;\n error?: string;\n jwt: string;\n /** When provided, adds a top \"Same as shipping\" option referencing this address. */\n shippingAddress?: fluidPay.CustomerAddress | null;\n /** Saved customer addresses populating the dropdown. */\n savedAddresses?: fluidPay.CustomerAddress[];\n /** ID of the customer's preferred billing address; used to pre-select. */\n defaultBillingAddressId?: number;\n /**\n * Render-prop slot for AddressFormDialog. The host wires the dialog so this\n * component doesn't import it directly, keeping the address-create flow's\n * data plumbing (mutations, error toasts) under host control.\n */\n renderAddressFormDialog?: (props: RenderAddressFormDialogProps) => ReactNode;\n t: (key: string) => string;\n presentation?: ResponsiveDialogPresentation;\n}\n\nfunction VgsInputWrapper({\n id,\n label,\n fieldState,\n className,\n}: {\n id: string;\n label: string;\n fieldState?: VgsFieldState;\n className?: string;\n}) {\n const isInvalid =\n fieldState?.isValid === false &&\n !fieldState?.isFocused &&\n !fieldState?.isEmpty;\n const isFocused = !!fieldState?.isFocused;\n\n return (\n <div\n id={id}\n role=\"group\"\n aria-label={label}\n data-invalid={isInvalid ? \"\" : undefined}\n className={cn(\n \"border-input selection:bg-primary selection:text-primary-foreground file:text-foreground placeholder:text-muted-foreground h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm\",\n \"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]\",\n \"data-[invalid]:border-destructive data-[invalid]:ring-destructive/20\",\n \"[&_iframe]:block! [&_iframe]:h-full! [&_iframe]:w-full! [&_iframe]:border-0!\",\n isFocused && \"border-ring ring-ring/50 ring-[3px]\",\n isFocused && isInvalid && \"border-destructive ring-destructive/20\",\n className,\n )}\n />\n );\n}\n\nfunction VgsCardForm({\n vgsFieldState,\n networkError,\n}: {\n vgsFieldState: VgsFormState;\n networkError?: string;\n}) {\n return (\n <div className=\"space-y-4\" aria-label=\"Credit card form\">\n <VgsInputWrapper\n id=\"vgs-card-number\"\n label=\"Card number\"\n fieldState={vgsFieldState[\"card_number\"]}\n />\n\n <div className=\"flex gap-3\">\n <div className=\"min-w-0 flex-1\">\n <VgsInputWrapper\n id=\"vgs-expiration-date\"\n label=\"Expiration date\"\n fieldState={vgsFieldState[\"card_exp\"]}\n />\n </div>\n <div className=\"min-w-0 flex-1\">\n <VgsInputWrapper\n id=\"vgs-cvc\"\n label=\"CVC\"\n fieldState={vgsFieldState[\"card_cvc\"]}\n />\n </div>\n </div>\n\n <VgsInputWrapper\n id=\"vgs-card-holder\"\n label=\"Cardholder name\"\n fieldState={vgsFieldState[\"card_holder\"]}\n />\n\n {networkError && networkError.trim().length > 0 && (\n <div className=\"bg-destructive/10 text-destructive rounded-md p-3 text-sm\">\n {networkError}\n </div>\n )}\n </div>\n );\n}\n\nfunction formatAddressOneLine(addr: fluidPay.CustomerAddress): string {\n const cityStateZip = [addr.city, addr.state, addr.postal_code]\n .filter((p): p is string => Boolean(p && p.trim().length > 0))\n .join(\", \");\n const parts = [\n addr.address1,\n addr.address2,\n cityStateZip,\n addr.country_code,\n ].filter((p): p is string => Boolean(p && p.trim().length > 0));\n return parts.join(\" • \");\n}\n\nfunction AddressSummaryCard({\n address,\n}: {\n address: fluidPay.CustomerAddress;\n}) {\n return (\n <div className=\"border-input bg-muted/30 rounded-md border p-3 text-sm break-words\">\n {address.name && <div className=\"font-medium\">{address.name}</div>}\n <div className=\"text-muted-foreground\">{address.address1}</div>\n {address.address2 && (\n <div className=\"text-muted-foreground\">{address.address2}</div>\n )}\n <div className=\"text-muted-foreground\">\n {[address.city, address.state].filter(Boolean).join(\", \")}\n {address.postal_code ? ` ${address.postal_code}` : \"\"}\n </div>\n {address.country_code && (\n <div className=\"text-muted-foreground\">{address.country_code}</div>\n )}\n </div>\n );\n}\n\nexport default function CreditCardFormDialog({\n isOpen,\n onClose,\n onSubmit,\n isSubmitting,\n error,\n jwt,\n shippingAddress,\n savedAddresses = [],\n defaultBillingAddressId,\n renderAddressFormDialog,\n t,\n presentation = \"dialog\",\n}: CreditCardFormDialogProps): JSX.Element {\n const api = useFluidPayApi();\n const [cardError, setCardError] = useState<string | undefined>(undefined);\n const [isVgsSubmitting, setIsVgsSubmitting] = useState(false);\n const [createdAddresses, setCreatedAddresses] = useState<\n fluidPay.CustomerAddress[]\n >([]);\n const [isAddressDialogOpen, setIsAddressDialogOpen] = useState(false);\n\n const {\n isFormReady,\n isLoading: isVgsLoading,\n isScriptLoaded,\n scriptLoadError,\n initializeForm,\n submitCard,\n vgsFieldState,\n resetVgs,\n onSuccessRef,\n onErrorRef,\n } = useVgsCollect();\n\n const shippingId = shippingAddress?.id ?? null;\n const dedupedSavedAddresses = useMemo(\n () =>\n shippingId === null\n ? savedAddresses\n : savedAddresses.filter((a) => a.id !== shippingId),\n [savedAddresses, shippingId],\n );\n\n const allAddresses = useMemo<fluidPay.CustomerAddress[]>(() => {\n const list: fluidPay.CustomerAddress[] = [];\n if (shippingAddress) list.push(shippingAddress);\n list.push(...dedupedSavedAddresses);\n list.push(...createdAddresses);\n return list;\n }, [shippingAddress, dedupedSavedAddresses, createdAddresses]);\n\n const hasRealAddresses = allAddresses.length > 0;\n\n // Default selection per ticket: shipping → default billing → first saved → \"use different\".\n const initialSelection = useMemo<string>(() => {\n if (shippingAddress) return shippingAddress.id.toString();\n if (\n defaultBillingAddressId &&\n dedupedSavedAddresses.some((a) => a.id === defaultBillingAddressId)\n ) {\n return defaultBillingAddressId.toString();\n }\n const first = dedupedSavedAddresses[0];\n if (first) return first.id.toString();\n return SENTINEL_CREATE_NEW;\n }, [shippingAddress, defaultBillingAddressId, dedupedSavedAddresses]);\n\n const { control, handleSubmit, reset, setValue, watch } =\n useZodForm<FormData>(formSchema, {\n defaultValues: {\n billing_address_selection: initialSelection,\n set_as_default: false,\n },\n });\n\n // Reset the form whenever the dialog (re)opens or the upstream address list\n // changes — the initial selection depends on shipping/saved/default props.\n useEffect(() => {\n if (isOpen) {\n reset({\n billing_address_selection: initialSelection,\n set_as_default: false,\n });\n setCreatedAddresses([]);\n }\n }, [isOpen, initialSelection, reset]);\n\n const currentSelection = watch(\"billing_address_selection\");\n\n const selectedAddress = useMemo(() => {\n if (!currentSelection || currentSelection === SENTINEL_CREATE_NEW) {\n return null;\n }\n const id = Number(currentSelection);\n if (!Number.isFinite(id)) return null;\n return allAddresses.find((a) => a.id === id) ?? null;\n }, [currentSelection, allAddresses]);\n\n const selectOptions = useMemo(() => {\n const options: { name: string; value: string }[] = [];\n if (shippingAddress) {\n options.push({\n name: t(\"same_as_shipping\"),\n value: shippingAddress.id.toString(),\n });\n }\n for (const addr of dedupedSavedAddresses) {\n options.push({\n name: formatAddressOneLine(addr),\n value: addr.id.toString(),\n });\n }\n for (const addr of createdAddresses) {\n options.push({\n name: formatAddressOneLine(addr),\n value: addr.id.toString(),\n });\n }\n options.push({\n name: t(\"use_a_different_address\"),\n value: SENTINEL_CREATE_NEW,\n });\n return options;\n }, [shippingAddress, dedupedSavedAddresses, createdAddresses, t]);\n\n const handleSelectionChange = useCallback(\n (value: string) => {\n if (value === SENTINEL_CREATE_NEW) {\n // Don't commit the sentinel to form state — opening the sub-modal is\n // the action. The form's previous selection remains intact so closing\n // the sub-modal without saving leaves the dropdown unchanged.\n setIsAddressDialogOpen(true);\n return;\n }\n setValue(\"billing_address_selection\", value, { shouldValidate: true });\n },\n [setValue],\n );\n\n const handleAddressCreated = useCallback(\n (address: fluidPay.CustomerAddress) => {\n setCreatedAddresses((list) => [...list, address]);\n setValue(\"billing_address_selection\", address.id.toString(), {\n shouldValidate: true,\n });\n setIsAddressDialogOpen(false);\n },\n [setValue],\n );\n\n const handleVgsSuccess = useCallback(\n (response: fluidPay.VgsCollectSubmitResponse) => {\n const expValue = response?.card_exp;\n if (!expValue) {\n setCardError(\"Missing expiration date from payment form\");\n setIsVgsSubmitting(false);\n return;\n }\n\n const cleanExp = expValue.replace(/\\s+/g, \"\");\n const [expMonth, expYearShort] = cleanExp.split(\"/\");\n\n if (!expMonth || !expYearShort) {\n setCardError(\"Invalid expiration date format\");\n setIsVgsSubmitting(false);\n return;\n }\n\n const expYear =\n expYearShort.length === 2 ? `20${expYearShort}` : expYearShort;\n\n const cardholderName = response?.card_holder?.trim();\n if (!cardholderName) {\n setCardError(\"Cardholder name is required\");\n setIsVgsSubmitting(false);\n return;\n }\n\n handleSubmit(\n (formData) => {\n const billingAddressId = Number(formData.billing_address_selection);\n if (!Number.isFinite(billingAddressId)) {\n setCardError(\"Please select a billing address.\");\n setIsVgsSubmitting(false);\n return;\n }\n\n const cardMeta = vgsFieldState[\"card_number\"];\n onSubmit({\n set_as_default: formData.set_as_default,\n payment_method: {\n token: response.card_number,\n cvv_token: response.card_cvc,\n exp_month: expMonth,\n exp_year: expYear,\n card_holder: cardholderName,\n ...(cardMeta?.bin ? { bin: cardMeta.bin } : {}),\n ...(cardMeta?.last4 ? { last_four: cardMeta.last4 } : {}),\n ...(cardMeta?.cardType\n ? { card_network: cardMeta.cardType }\n : {}),\n },\n billing_address_id: billingAddressId,\n });\n setIsVgsSubmitting(false);\n },\n () => {\n setCardError(\"Please select a billing address.\");\n setIsVgsSubmitting(false);\n },\n )();\n },\n [handleSubmit, onSubmit, vgsFieldState],\n );\n\n const handleVgsError = useCallback((err: string) => {\n setCardError(err);\n setIsVgsSubmitting(false);\n }, []);\n\n useEffect(() => {\n onSuccessRef.current = handleVgsSuccess;\n onErrorRef.current = handleVgsError;\n }, [handleVgsSuccess, handleVgsError, onSuccessRef, onErrorRef]);\n\n useEffect(() => {\n if (!isOpen || !isScriptLoaded) return;\n\n let cancelled = false;\n\n const init = async () => {\n try {\n const credentials = await api.vault.fetchCredentials(jwt);\n if (!cancelled) {\n await initializeForm(credentials);\n }\n } catch (err) {\n console.error(\"Failed to fetch vault credentials:\", err);\n if (!cancelled) {\n setCardError(\"Failed to initialize payment form\");\n }\n }\n };\n\n init();\n\n return () => {\n cancelled = true;\n };\n }, [isOpen, isScriptLoaded, jwt, api, initializeForm]);\n\n const handleClose = () => {\n resetVgs();\n reset();\n setCardError(undefined);\n setIsVgsSubmitting(false);\n setIsAddressDialogOpen(false);\n onClose();\n };\n\n const handleFormSubmit = handleSubmit(() => {\n setIsVgsSubmitting(true);\n setCardError(undefined);\n submitCard();\n });\n\n const isBusy = isSubmitting || isVgsSubmitting;\n\n return (\n <>\n <ResponsiveDialog\n open={isOpen}\n onOpenChange={(open) => !open && handleClose()}\n title={t(\"add_credit_card\")}\n presentation={presentation}\n size=\"wide\"\n >\n <div className=\"relative min-w-0 pt-1\">\n {(isVgsLoading || !isFormReady) && !scriptLoadError && (\n <div className=\"bg-background/80 absolute inset-0 z-10 flex items-center justify-center rounded backdrop-blur-[1px]\">\n <div className=\"flex items-center justify-center\">\n <div className=\"border-primary mr-3 size-5 animate-spin rounded-full border-2 border-t-2 border-t-transparent\" />\n <p className=\"text-muted-foreground text-sm font-medium\">\n {t(\"securing\")}\n </p>\n </div>\n </div>\n )}\n <div className=\"space-y-4\">\n <VgsCardForm\n vgsFieldState={vgsFieldState}\n networkError={cardError ?? scriptLoadError ?? error}\n />\n\n <div className=\"space-y-3 pt-2\">\n <h3 className=\"text-muted-foreground text-sm font-medium\">\n {t(\"billing_address\")}\n </h3>\n {hasRealAddresses ? (\n <Controller\n control={control}\n name=\"billing_address_selection\"\n render={({\n field: { value },\n fieldState: { error: fieldError },\n }) => (\n <div className=\"space-y-1\">\n <Label\n htmlFor=\"billing-address-selection\"\n className=\"mb-1.5 block text-sm font-medium\"\n >\n {t(\"billing_address\")}\n </Label>\n <Select\n value={value}\n onValueChange={handleSelectionChange}\n disabled={isBusy}\n >\n <SelectTrigger\n id=\"billing-address-selection\"\n aria-invalid={!!fieldError}\n className=\"w-full min-w-0 [&>span]:block! [&>span]:min-w-0 [&>span]:truncate\"\n >\n <SelectValue placeholder={t(\"select_an_option\")} />\n </SelectTrigger>\n <SelectContent>\n {selectOptions.map((opt) => (\n <SelectItem\n key={opt.value}\n value={opt.value}\n // Radix Select fires onValueChange only when the value\n // *changes*. Picking the already-selected sentinel\n // would otherwise be a no-op, leaving the user with\n // no way to reopen the address form.\n onClick={\n opt.value === SENTINEL_CREATE_NEW\n ? () => setIsAddressDialogOpen(true)\n : undefined\n }\n >\n {opt.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n {fieldError?.message && (\n <p className=\"text-destructive text-sm\">\n {fieldError.message}\n </p>\n )}\n </div>\n )}\n />\n ) : (\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => setIsAddressDialogOpen(true)}\n disabled={isBusy}\n className=\"w-full\"\n >\n {t(\"add_billing_address\")}\n </Button>\n )}\n\n {selectedAddress && (\n <AddressSummaryCard address={selectedAddress} />\n )}\n </div>\n </div>\n\n <div className=\"mt-4 flex items-center justify-between\">\n <Controller\n control={control}\n name=\"set_as_default\"\n render={({ field }) => (\n <div className=\"flex items-center gap-x-2\">\n <Checkbox\n id=\"set_as_default_cc\"\n checked={field.value}\n onCheckedChange={(checked) =>\n field.onChange(checked === true)\n }\n disabled={isBusy}\n />\n <Label\n htmlFor=\"set_as_default_cc\"\n className=\"text-sm font-normal\"\n >\n {t(\"set_as_default_payment_method\")}\n </Label>\n </div>\n )}\n />\n\n <Button type=\"button\" onClick={handleFormSubmit} disabled={isBusy}>\n {isBusy && (\n <div className=\"mr-2 size-4 animate-spin rounded-full border-2 border-current/30 border-t-current\" />\n )}\n {isBusy ? t(\"saving\") : t(\"save_card\")}\n </Button>\n </div>\n </div>\n </ResponsiveDialog>\n\n {renderAddressFormDialog?.({\n isOpen: isAddressDialogOpen,\n onClose: () => setIsAddressDialogOpen(false),\n onAddressCreated: handleAddressCreated,\n })}\n </>\n );\n}\n","import { useEffect, useMemo, useRef } from \"react\";\n\nimport { Lock } from \"lucide-react\";\n\nimport { Dialog, DialogContent, DialogTitle } from \"@fluid-app/ui-primitives\";\n\n/** Display strings for the modal chrome — injected by the host app so the\n * package stays translation-system agnostic. */\nexport interface VgsThreeDSModalLabels {\n title: string;\n cancel: string;\n timedOut: string;\n stillWorking: string;\n dontRefresh: string;\n}\n\nexport interface VgsThreeDSModalProps {\n isOpen: boolean;\n challengeHtml: string;\n challengeUrl?: string;\n onClose: (error?: string) => void;\n labels: VgsThreeDSModalLabels;\n}\n\nfunction escapeAttr(s: string | null): string {\n return (s ?? \"\")\n .replace(/&/g, \"&\")\n .replace(/\"/g, \""\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\");\n}\n\n/**\n * Parse the challenge HTML to extract the form action URL and hidden fields.\n * This lets us POST directly to the bank ACS, bypassing intermediary pages\n * (e.g. Entersekt's red.js auto-submit) that cause extra iframe loads.\n */\nfunction parseDirectPostHtml(\n challengeHtml: string,\n challengeUrl?: string,\n): string | null {\n try {\n const parser = new DOMParser();\n const doc = parser.parseFromString(challengeHtml, \"text/html\");\n const form = doc.querySelector(\"form\");\n if (!form) return null;\n\n const action = challengeUrl || form.getAttribute(\"action\");\n if (!action) return null;\n\n const hiddenInputs = form.querySelectorAll('input[type=\"hidden\"]');\n if (hiddenInputs.length === 0) return null;\n\n const fieldsHtml = Array.from(hiddenInputs)\n .map(\n (input) =>\n `<input type=\"hidden\" name=\"${escapeAttr(input.getAttribute(\"name\"))}\" value=\"${escapeAttr(input.getAttribute(\"value\"))}\">`,\n )\n .join(\"\\n\");\n\n return `<!DOCTYPE html>\n<html>\n<body>\n<form id=\"acsForm\" method=\"POST\" action=\"${escapeAttr(action)}\">\n${fieldsHtml}\n</form>\n<script>document.getElementById(\"acsForm\").submit();</script>\n</body>\n</html>`;\n } catch {\n return null;\n }\n}\n\n/**\n * Pure iframe container for the 3DS challenge.\n *\n * The modal does NOT try to detect challenge completion via load-counting or\n * postMessage — that was fragile across different bank ACS implementations.\n * Instead, `useVgs3DSCompletion` subscribes to the realtime transport as soon\n * as the modal opens and receives the authoritative result from the backend.\n *\n * This modal only handles:\n * - Rendering the ACS challenge iframe\n * - User cancellation (Cancel button in header band)\n * - Hard timeout (6.5 min) as a safety net\n */\nexport function VgsThreeDSModal({\n isOpen,\n challengeHtml,\n challengeUrl,\n onClose,\n labels,\n}: VgsThreeDSModalProps) {\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const onCloseRef = useRef(onClose);\n // Capture labels in a ref so the timeout effect can read the current\n // translation without depending on labels in its deps array (host apps\n // typically build the labels object inline per render and would otherwise\n // reset the timer on every re-render).\n const labelsRef = useRef(labels);\n\n useEffect(() => {\n onCloseRef.current = onClose;\n });\n\n useEffect(() => {\n labelsRef.current = labels;\n });\n\n // Build a direct-POST page that skips intermediary auto-redirect pages.\n // Falls back to the original challengeHtml if parsing fails.\n const iframeSrcDoc = useMemo(\n () => parseDirectPostHtml(challengeHtml, challengeUrl) ?? challengeHtml,\n [challengeHtml, challengeUrl],\n );\n\n // Hard timeout — aligned just past the backend safety-net boundary (~6:00)\n // so the cart poll surfaces the backend's verdict (accurate decline,\n // rescued approval, or TIMEOUT) before the modal gives up at 6.5 min.\n // (The old comment attributed the 5-minute value to the EMVCo spec;\n // EMVCo leaves challenge-timeout handling to the ACS/issuer — the real\n // constraint is our own safety-net boundary.) Depends only on isOpen so\n // the timer resets on open, not on content change.\n useEffect(() => {\n if (!isOpen) return;\n\n const timeoutId = setTimeout(() => {\n onCloseRef.current(labelsRef.current.timedOut);\n }, 390_000);\n\n return () => {\n clearTimeout(timeoutId);\n };\n }, [isOpen]);\n\n const handleCancel = () => {\n onClose();\n };\n\n return (\n <Dialog open={isOpen} onOpenChange={handleCancel}>\n {/* z-[110]: a bank challenge must never be occluded by host chrome.\n Card-add surfaces launch this modal from a dialog that pins its\n content at z-[100] (fluid-checkout's credit-card dialog), where the\n default z-50 + DOM-order stacking would paint the host dialog on\n top of the challenge — and Radix would inert it underneath. */}\n <DialogContent\n className=\"z-[110] h-[600px] max-w-2xl p-0 sm:max-w-2xl\"\n overlayClassName=\"z-[110]\"\n showCloseButton={false}\n >\n <div className=\"flex h-full w-full flex-col\">\n {/* Header band — replaces VisuallyHidden DialogTitle */}\n <div className=\"flex items-center justify-between border-b border-gray-200 px-4 py-3\">\n <div className=\"flex items-center gap-2\">\n <Lock className=\"h-4 w-4 text-gray-600\" aria-hidden=\"true\" />\n <DialogTitle className=\"text-sm font-semibold text-gray-900\">\n {labels.title}\n </DialogTitle>\n </div>\n <button\n type=\"button\"\n onClick={handleCancel}\n className=\"rounded text-xs text-indigo-600 hover:text-indigo-700 focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2 focus-visible:outline-none\"\n >\n {labels.cancel}\n </button>\n </div>\n\n {/* Iframe (unchanged behavior). */}\n <div className=\"relative flex-1\">\n {challengeHtml && (\n <iframe\n ref={iframeRef}\n srcDoc={iframeSrcDoc}\n className=\"h-full w-full border-0\"\n title=\"VGS 3DS Challenge\"\n sandbox=\"allow-same-origin allow-scripts allow-forms allow-top-navigation allow-popups\"\n />\n )}\n </div>\n\n {/* Footer band — indeterminate progress + status caption + tab-refresh hint */}\n <div className=\"border-t border-gray-200 px-4 py-3\">\n <div\n data-testid=\"threeds-progress-bar\"\n role=\"progressbar\"\n aria-label={labels.stillWorking}\n className=\"relative h-1 overflow-hidden rounded-full bg-indigo-100\"\n >\n <div className=\"threeds-progress-pill absolute top-0 h-full w-[30%] rounded-full bg-indigo-500\" />\n </div>\n <div className=\"mt-2 flex items-center justify-between text-xs\">\n <span className=\"text-gray-600\">{labels.stillWorking}</span>\n <span className=\"text-gray-400\">{labels.dontRefresh}</span>\n </div>\n </div>\n </div>\n </DialogContent>\n </Dialog>\n );\n}\n\nexport default VgsThreeDSModal;\n","// Pure attempt-scoping predicate shared by the poll and Pusher paths of\n// useVgs3DSCompletion. Presence-guarded on BOTH sides: when either the\n// active attempt key or the result's key is missing (backend not yet\n// deployed, old event shape), the result is honored — exactly today's\n// unscoped behavior.\nexport function belongsToActiveAttempt(\n activeMerchantTxId: string | undefined,\n resultMerchantTxId: string | undefined,\n): boolean {\n if (!activeMerchantTxId || !resultMerchantTxId) return true;\n return resultMerchantTxId === activeMerchantTxId;\n}\n","import { useEffect, useEffectEvent, useRef } from \"react\";\nimport type { ThreeDSStatus } from \"@fluid-app/fluid-pay-core/types\";\nimport { belongsToActiveAttempt } from \"./three-ds-attempt\";\n\nexport interface Vgs3DSCompletionResult {\n success: boolean;\n transactionId: string;\n status?: string;\n}\n\nexport interface Vgs3DSChallengeEvent {\n xid: string;\n /** Optional for backward compatibility: older events may omit it, and the\n * attempt-scoping guard deliberately honors key-less events. */\n merchant_transaction_id?: string;\n status: \"success\" | \"failed\";\n challenge_status?: string;\n error_message?: string;\n}\n\n/** Minimal structural slice of a realtime channel — pusher-js's `Channel`\n * satisfies this as-is (its `bind`/`unbind` return `Channel`, which is\n * assignable to a `void`-returning method). */\nexport interface ThreeDsRealtimeChannel {\n bind(eventName: string, handler: (data: Vgs3DSChallengeEvent) => void): void;\n unbind(\n eventName: string,\n handler: (data: Vgs3DSChallengeEvent) => void,\n ): void;\n}\n\n/** Transport abstraction for the fast path — the app's `pusherClient`\n * satisfies this structurally with no adapter. */\nexport interface ThreeDsRealtimeTransport {\n subscribe(channelName: string): ThreeDsRealtimeChannel | null;\n unsubscribe(channelName: string): void;\n}\n\ninterface UseVgs3DSCompletionOptions {\n /** Realtime channel carrying the `vgs_3ds_challenge` event\n * (e.g. `private-cart-{cartToken}`). */\n channelName: string;\n transport: ThreeDsRealtimeTransport;\n /** Status poll — the reliable fallback alongside the realtime fast path. */\n checkStatus: () => Promise<ThreeDSStatus | null>;\n onComplete: (result: Vgs3DSCompletionResult) => void;\n onError: (error: string) => void;\n /** Subscribe to the realtime channel and start polling when true (i.e. when the 3DS modal is open). */\n enabled?: boolean;\n /** The active attempt's merchant_tx_id — when present, completion signals\n * for any OTHER attempt are ignored (stale metadata, late webhooks). */\n merchantTxId?: string;\n /** Called when the attempt was canceled (e.g. from another tab) — a quiet,\n * no-error terminal. */\n onCanceled?: () => void;\n}\n\n// Poll interval and timeout for the status-poll fallback.\n// Polling at 3-second intervals is the reliable secondary check alongside\n// the Pusher fast path (the backend broadcasts the result immediately).\n// The 6.5-minute timeout sits past the backend safety-net boundary (~6:00),\n// so the poll surfaces the backend's verdict — accurate decline, rescued\n// approval, or TIMEOUT — instead of the frontend self-declaring first.\nconst POLL_INTERVAL_MS = 3_000;\nconst TIMEOUT_MS = 390_000;\n\n/**\n * Subscribes to the realtime transport and polls the injected status check\n * for the 3DS challenge result.\n *\n * Activated by `enabled` — pass `vgsThreeDSModal.isOpen` so the subscription\n * starts as soon as the challenge modal opens. No URL-param dance needed.\n */\nexport function useVgs3DSCompletion({\n channelName,\n transport,\n checkStatus,\n onComplete,\n onError,\n enabled = false,\n merchantTxId,\n onCanceled,\n}: UseVgs3DSCompletionOptions) {\n const hasHandledRef = useRef(false);\n const isSubscribedRef = useRef(false);\n\n // Kept current via a per-render effect so an inline `transport` value at\n // the call site never retriggers the main effect.\n const transportRef = useRef(transport);\n useEffect(() => {\n transportRef.current = transport;\n });\n\n const handleComplete = useEffectEvent((result: Vgs3DSCompletionResult) => {\n onComplete(result);\n });\n\n const handleError = useEffectEvent((error: string) => {\n onError(error);\n });\n\n const handleCanceled = useEffectEvent(() => {\n onCanceled?.();\n });\n\n // Non-reactive wrapper so an inline `checkStatus` closure at the call site\n // never retriggers the main effect. Called from the poll during the active\n // phase only — never from cleanup.\n const performStatusCheck = useEffectEvent(() => checkStatus());\n\n // Shared handler for Pusher events, polling results, and timeout.\n // hasHandledRef ensures only the first source to resolve wins.\n const handleResult = useEffectEvent(\n (result: {\n status: \"success\" | \"failed\";\n errorMessage?: string;\n transactionId?: string;\n }) => {\n if (hasHandledRef.current) return;\n hasHandledRef.current = true;\n\n if (result.status === \"success\") {\n handleComplete({\n success: true,\n transactionId: result.transactionId ?? \"\",\n status: result.status,\n });\n } else {\n handleError(result.errorMessage || \"3DS verification failed\");\n }\n },\n );\n\n // Reset handled flag when enabled toggles off (modal closed / new attempt).\n useEffect(() => {\n if (!enabled && hasHandledRef.current) {\n hasHandledRef.current = false;\n }\n }, [enabled]);\n\n useEffect(() => {\n if (!enabled || !channelName || hasHandledRef.current) {\n return;\n }\n\n if (isSubscribedRef.current) {\n return;\n }\n\n let cancelled = false;\n // Captured ONCE so subscribe and the cleanup's unsubscribe use the same\n // transport object even if a different one is passed mid-flight.\n const activeTransport = transportRef.current;\n\n isSubscribedRef.current = true;\n const channel = activeTransport.subscribe(channelName);\n const hasPusher = !!channel;\n\n if (!hasPusher) {\n console.error(\n \"[VGS 3DS] Pusher subscribe returned null — using status polling only\",\n );\n isSubscribedRef.current = false;\n // intentionally NOT returning — polling + timeout below are the fallback\n }\n\n // --- Fast path: Pusher event ---\n const handleVgs3DSChallenge = (data: Vgs3DSChallengeEvent) => {\n if (cancelled) return;\n\n // Attempt-scoping: ignore events for a different (older) attempt.\n if (!belongsToActiveAttempt(merchantTxId, data.merchant_transaction_id)) {\n return;\n }\n\n handleResult({\n status: data.status,\n errorMessage: data.error_message,\n transactionId: data.merchant_transaction_id,\n });\n };\n\n if (hasPusher) {\n channel.bind(\"vgs_3ds_challenge\", handleVgs3DSChallenge);\n }\n\n // --- Reliable fallback: poll the injected status check ---\n const pollInterval = setInterval(async () => {\n if (hasHandledRef.current || cancelled) return;\n\n const status = await performStatusCheck();\n if (cancelled || !status) return;\n\n // Attempt-scoping: stale metadata from a previous attempt must not\n // resolve this modal (the backend wipes per-attempt keys on re-init,\n // but a late webhook can still land mid-retry).\n if (!belongsToActiveAttempt(merchantTxId, status.merchantTxId)) {\n return;\n }\n\n if (status.completed) {\n handleResult({ status: \"success\" });\n } else if (status.failed) {\n handleResult({\n status: \"failed\",\n errorMessage:\n status.errorMessage ||\n `3DS verification ${status.status || \"failed\"}`,\n });\n } else if (status.canceled) {\n // Canceled (possibly from another tab): quiet no-error terminal.\n if (!hasHandledRef.current) {\n hasHandledRef.current = true;\n handleCanceled();\n }\n }\n }, POLL_INTERVAL_MS);\n\n // --- Safety net: hard timeout ---\n const timeout = setTimeout(() => {\n if (hasHandledRef.current || cancelled) return;\n\n console.error(\"[VGS 3DS] Timed out waiting for 3DS result\");\n handleResult({\n status: \"failed\",\n errorMessage: \"Payment verification timed out. Please try again.\",\n });\n }, TIMEOUT_MS);\n\n // Cleanup — cancelled flag prevents in-flight polls from calling handleResult\n return () => {\n cancelled = true;\n clearTimeout(timeout);\n clearInterval(pollInterval);\n if (hasPusher) {\n channel.unbind(\"vgs_3ds_challenge\", handleVgs3DSChallenge);\n activeTransport.unsubscribe(channelName);\n }\n isSubscribedRef.current = false;\n };\n }, [enabled, channelName, merchantTxId]);\n}\n","import { z } from \"zod\";\n\nexport const browserInfoSchema = z.object({\n color_depth: z.number().optional(),\n screen_height: z.number().optional(),\n screen_width: z.number().optional(),\n time_zone: z.number().optional(),\n java_enabled: z.boolean().optional(),\n java_script_enabled: z.boolean().optional(),\n language: z.string().optional(),\n user_agent: z.string().optional(),\n accept_header: z.string().optional(),\n});\n\nexport type BrowserInfo = z.infer<typeof browserInfoSchema>;\n\nexport function getBrowserInfo(): BrowserInfo | undefined {\n // Check if we're in a browser environment\n if (typeof window === \"undefined\") {\n console.warn(\"getBrowserInfo called in non-browser environment\");\n return undefined;\n }\n\n try {\n const { screen, navigator } = window;\n\n // Validate that we have the required objects\n if (!screen || !navigator) {\n console.warn(\"Missing screen or navigator objects\");\n return undefined;\n }\n\n const browserInfo: BrowserInfo = {\n color_depth: screen.colorDepth || undefined,\n screen_height: screen.height || undefined,\n screen_width: screen.width || undefined,\n time_zone: new Date().getTimezoneOffset(),\n java_enabled:\n typeof navigator.javaEnabled === \"function\"\n ? navigator.javaEnabled()\n : false,\n java_script_enabled: true,\n language: navigator.language || undefined,\n user_agent: navigator.userAgent || undefined,\n accept_header: \"*/*\",\n };\n\n // Validate that we have at least some essential info\n if (\n !browserInfo.screen_height ||\n !browserInfo.screen_width ||\n !browserInfo.user_agent\n ) {\n console.warn(\"Missing essential browser info fields\");\n }\n\n return browserInfo;\n } catch (error) {\n console.error(\"Error getting browser info:\", error);\n return undefined;\n }\n}\n","/**\n * TypeScript interfaces for portal-tenant pay management.\n * These types mirror the portal-tenant BFF `/api/pay/*` endpoints.\n * Packages import from here instead of from any concrete API client.\n */\n\nimport type { ResponseMeta } from \"./fluidos-api\";\n\n// ---------------------------------------------------------------------------\n// Address\n// ---------------------------------------------------------------------------\n\nexport interface PayAddress {\n id: number;\n name: string | null;\n street1: string;\n street2: string | null;\n city: string;\n state: string;\n zip: string;\n country: string;\n phone?: string | null;\n default: boolean;\n created_at: string | null;\n updated_at: string | null;\n}\n\nexport interface CreateAddressBody {\n address: {\n name?: string | null;\n street1: string;\n street2?: string | null;\n city: string;\n state: string;\n zip: string;\n country: string;\n phone?: string | null;\n default?: boolean;\n };\n}\n\n// ---------------------------------------------------------------------------\n// Payment method\n// ---------------------------------------------------------------------------\n\nexport interface PayPaymentMethod {\n id: number;\n type: string;\n brand: string | null;\n last_four: string;\n logo_url: string | null;\n exp_month: number | null;\n exp_year: number | null;\n card_holder: string | null;\n default: boolean;\n billing_address: PayAddress | null;\n created_at: string | null;\n updated_at: string | null;\n}\n\nexport const TOKEN_PROVIDER_VGS = \"vgs\" as const;\n\n// Body for POST /api/pay/payment_methods on the portal-tenant BFF.\n//\n// Note: the BFF always creates the PM with customer scope\n// (PaymentMethodCreator hardcodes set_customer_payment_method: true on its\n// way into the FluidPay action), so PMs created via this body are always\n// immediately referenceable from customer.payment_methods — no need to\n// expose set_customer_payment_method to the client. The checkout app's\n// direct /fluid_pay/create_payment_method route exposes it because that\n// route does not have the same default.\nexport interface CreatePaymentMethodBody {\n payment_method: {\n type: \"card\";\n token: string;\n token_provider?: string;\n exp_month: string;\n exp_year: string;\n cvv_token?: string;\n card_holder?: string;\n default?: boolean;\n bin?: string;\n last_four?: string;\n card_network?: string;\n };\n billing_address_id: number;\n // `| null` mirrors the OpenAPI contract / generated client so callers can send\n // an explicit null instead of being forced to omit the field.\n browser_info?: Record<string, unknown> | null;\n}\n\nexport interface UpdatePaymentMethodBody {\n payment_method: {\n default?: boolean;\n billing_address?: {\n name?: string | null;\n street1: string;\n street2?: string | null;\n city: string;\n state: string;\n zip: string;\n country: string;\n };\n };\n}\n\n// ---------------------------------------------------------------------------\n// Vault\n// ---------------------------------------------------------------------------\n\nexport interface VaultCredentials {\n vault_id: string;\n environment: string;\n route_id: string | null;\n}\n\n// ---------------------------------------------------------------------------\n// Response types\n// ---------------------------------------------------------------------------\n\nexport interface AddressesResponse {\n addresses: PayAddress[];\n meta: ResponseMeta;\n}\n\nexport interface PaymentMethodsResponse {\n payment_methods: PayPaymentMethod[];\n meta: ResponseMeta;\n}\n\nexport interface CreatedPaymentMethodResult {\n payment_method: PayPaymentMethod;\n meta: ResponseMeta;\n}\n\nexport interface ThreeDsRequiredCreateResult {\n three_ds: {\n status: \"three_ds_required\";\n session_token: string;\n tds_method_content: string | null;\n fingerprinting_required: boolean | null;\n merchant_tx_id: string | null;\n };\n meta: ResponseMeta;\n}\n\n// Discriminated union: 201 (created PM) | 200 (3DS required).\nexport type CreatePaymentMethodResponse =\n | CreatedPaymentMethodResult\n | ThreeDsRequiredCreateResult;\n\nexport function isThreeDsRequiredCreate(\n r: CreatePaymentMethodResponse,\n): r is ThreeDsRequiredCreateResult {\n return \"three_ds\" in r && r.three_ds.status === \"three_ds_required\";\n}\n\nexport interface ConfirmApprovedResult {\n status: \"approved\";\n session_token: string;\n payment_method: PayPaymentMethod;\n was_created?: boolean;\n}\n\nexport interface ConfirmChallengeResult {\n status: \"three_ds_challenge\";\n session_token: string;\n challenge_form: string | null;\n challenge_url: string | null;\n}\n\nexport type ConfirmPaymentMethod3DSResponse =\n | ConfirmApprovedResult\n | ConfirmChallengeResult;\n\n// 3DS session lifecycle state from the BFF. The known values are listed for\n// autocomplete + typo-safety, but the type stays open (`string & {}`) because\n// the backend enum may grow: the adapter forwards the wire string without a\n// lying `as` cast, and an unrecognized state stays non-terminal in\n// mapSessionStateToThreeDSStatus — resolved by the EMVCo polling timeout rather\n// than mis-mapped to completed/failed/canceled.\nexport type ThreeDsSessionState =\n | \"initialized\"\n | \"pending\"\n | \"approved\"\n | \"denied\"\n | \"timed_out\"\n | \"cancelled\"\n | \"skipped\"\n | (string & {});\n\nexport interface ThreeDsStatusResponse {\n session_token: string;\n state: ThreeDsSessionState;\n payment_method_id: number | null;\n expired: boolean | null;\n}\n\nexport interface ThreeDsCancelResponse {\n session_token: string;\n state: ThreeDsSessionState;\n cancelled: boolean | null;\n}\n\nexport interface VaultResponse {\n vault: VaultCredentials;\n meta: ResponseMeta;\n}\n\n// ---------------------------------------------------------------------------\n// Points ledger\n// ---------------------------------------------------------------------------\n\nexport interface PointsLedgerEntry {\n id: number;\n amount: number;\n total_balance: number;\n metadata: Record<string, unknown> | null;\n created_at: string;\n}\n\nexport interface PointsLedgersResponse {\n points_ledgers: PointsLedgerEntry[];\n meta: ResponseMeta;\n}\n","import { type FluidPayApi, type fluidPay } from \"@fluid-app/fluid-pay-core\";\nimport type { PayApi } from \"@fluid-app/portal-core/pay-api\";\nimport type { PayPaymentMethod } from \"@fluid-app/portal-core/pay-types\";\n\n/**\n * Maps a portal-tenant PayPaymentMethod to the fluidPay shape consumed by\n * profile-ui components (PaymentMethodDropdown, CreditCardFormDialog, etc.).\n * Co-located with the adapter because both speak the portal-tenant ↔ fluid-pay\n * boundary.\n */\nexport function mapToFluidPayPaymentMethod(\n raw: PayPaymentMethod,\n): fluidPay.CustomerPaymentMethod {\n return {\n id: raw.id,\n created_at: raw.created_at ?? \"\",\n default: raw.default,\n details: {\n card_network: raw.brand,\n card_brand: raw.brand,\n card_holder: raw.card_holder,\n last_four: raw.last_four,\n logo_url: raw.logo_url ?? undefined,\n exp_month: raw.exp_month ?? undefined,\n exp_year: raw.exp_year ?? undefined,\n },\n billing_address: raw.billing_address\n ? {\n name: raw.billing_address.name,\n address1: raw.billing_address.street1,\n address2: raw.billing_address.street2,\n city: raw.billing_address.city,\n state: raw.billing_address.state,\n zip: raw.billing_address.zip,\n country_code: raw.billing_address.country,\n }\n : null,\n payment_type: raw.type,\n source: \"\",\n updated_at: raw.updated_at ?? \"\",\n };\n}\n\nconst notImplemented = () => {\n throw new Error(\"Not available in portal-tenant context\");\n};\n\n/**\n * Adapts the portal-tenant PayApi to the FluidPayApi shape required by\n * FluidPayCoreProvider. Only `vault.fetchCredentials` is implemented —\n * the rest of the FluidPayApi surface is not used by the profile-ui\n * components that consume this provider in the portal context.\n */\nexport function createFluidPayApiAdapter(payApi: PayApi): FluidPayApi {\n return {\n customers: { fetchAccount: notImplemented, update: notImplemented },\n addresses: {\n fetchAll: notImplemented,\n create: notImplemented,\n update: notImplemented,\n delete: notImplemented,\n },\n paymentMethods: {\n fetchAll: notImplemented,\n addCreditCard: notImplemented,\n delete: notImplemented,\n updateDefault: notImplemented,\n update: notImplemented,\n },\n vault: {\n fetchCredentials: async () => {\n const response = await payApi.fetchVaultCredentials();\n return {\n vault: {\n vault_id: response.vault.vault_id,\n environment: response.vault.environment,\n route_id: response.vault.route_id ?? \"\",\n requires_3ds: false,\n },\n meta: {\n request_id: response.meta?.request_id ?? \"\",\n timestamp: response.meta?.timestamp ?? \"\",\n },\n } satisfies fluidPay.VaultResponse;\n },\n },\n };\n}\n","// Helper to render the device fingerprinting iframe.\n//\n// Browser-only: the function body requires `document` — never call during\n// SSR. Importing this module is SSR-safe; only invocation touches the DOM.\nexport const renderFingerprintingIframe = (html: string): Promise<void> => {\n return new Promise((resolve) => {\n const iframe = document.createElement(\"iframe\");\n iframe.srcdoc = html;\n iframe.style.display = \"none\";\n\n document.body.appendChild(iframe);\n\n // Wait for fingerprinting to complete (usually <10 seconds)\n setTimeout(() => {\n document.body.removeChild(iframe);\n resolve();\n }, 10000);\n });\n};\n","import type { ThreeDsRealtimeTransport } from \"@fluid-app/fluid-pay-ui\";\nimport type { ThreeDSStatus } from \"@fluid-app/fluid-pay-core/types\";\nimport type { ThreeDsSessionState } from \"@fluid-app/portal-core/pay-types\";\n\n/**\n * Polling-only realtime transport. A no-op channel keeps useVgs3DSCompletion's\n * `hasPusher` true so it does not log the misleading \"subscribe returned null\"\n * error; the 3s status poll is the sole resolver. The Pusher fast-follow\n * replaces this constant with a real pusher-js client.\n */\nexport const POLLING_ONLY_TRANSPORT: ThreeDsRealtimeTransport = {\n subscribe: () => ({ bind: () => {}, unbind: () => {} }),\n unsubscribe: () => {},\n};\n\n/**\n * Map the BFF 3ds_status session state -> the FE-A hook's ThreeDSStatus. Only\n * the known terminal states resolve the poll (approved/skipped -> completed,\n * denied/timed_out/expired -> failed, cancelled -> canceled); any other value\n * (initialized/pending or a future backend state) stays non-terminal so the\n * poll keeps running until the EMVCo timeout, rather than being mis-classified.\n */\nexport function mapSessionStateToThreeDSStatus(\n state: ThreeDsSessionState,\n expired: boolean | null,\n): ThreeDSStatus {\n return {\n completed: state === \"approved\" || state === \"skipped\",\n failed: state === \"denied\" || state === \"timed_out\" || expired === true,\n canceled: state === \"cancelled\",\n status: state,\n };\n}\n\n/**\n * Dig the portal BFF error code off a thrown ApiError. Structural and\n * self-validating: a non-ApiError simply yields undefined (no instanceof gate).\n */\nexport function cardAdd3DSErrorCode(error: unknown): string | undefined {\n // `meta` is an envelope key, so read `body` — `data` unwraps past it whenever\n // the response carried an `errors` key (docs/api-error-data-contract.md).\n const body = (error as { body?: unknown } | null)?.body;\n const meta = (body as { meta?: unknown } | null)?.meta;\n const code = (meta as { error_code?: unknown } | null)?.error_code;\n return typeof code === \"string\" ? code : undefined;\n}\n\n/**\n * Customer-facing message off a thrown portal ApiError. The client lifts the\n * portal `{ error: { message } }` onto ApiError.message; fall back to the\n * nested envelope field, then the supplied generic.\n */\nexport function cardAdd3DSErrorMessage(\n error: unknown,\n fallback: string,\n): string {\n if (error instanceof Error && error.message) return error.message;\n const body = (error as { body?: unknown } | null)?.body;\n const nested = (body as { error?: { message?: unknown } } | null)?.error\n ?.message;\n return typeof nested === \"string\" ? nested : fallback;\n}\n","import { useEffectEvent, useRef, useState, type ReactNode } from \"react\";\nimport { renderFingerprintingIframe } from \"@fluid-app/fluid-pay-core/utils/fingerprinting\";\nimport type { ThreeDSStatus } from \"@fluid-app/fluid-pay-core/types\";\nimport { useVgs3DSCompletion, VgsThreeDSModal } from \"@fluid-app/fluid-pay-ui\";\nimport type { PayApi } from \"@fluid-app/portal-core/pay-api\";\nimport type {\n ConfirmApprovedResult,\n ThreeDsRequiredCreateResult,\n} from \"@fluid-app/portal-core/pay-types\";\nimport {\n POLLING_ONLY_TRANSPORT,\n cardAdd3DSErrorCode,\n cardAdd3DSErrorMessage,\n mapSessionStateToThreeDSStatus,\n} from \"./three-ds-card-add-helpers\";\n\n// Wait before the single confirm retry when a completion signal races the\n// backend's upstream reconcile (422 three_ds_pending).\nconst PENDING_RETRY_DELAY_MS = 2_000;\nconst waitFor = (ms: number) =>\n new Promise<void>((resolve) => setTimeout(resolve, ms));\n\ninterface ActiveSession {\n sessionToken: string;\n merchantTxId: string | undefined;\n}\ninterface PendingChallenge {\n html: string;\n url?: string;\n}\n\nexport interface UsePortalCardAdd3DSFlowOptions {\n payApi: PayApi;\n onApproved: (approved: ConfirmApprovedResult) => void | Promise<void>;\n onFailed: (message: string) => void;\n onCanceled: () => void;\n t: (key: string) => string;\n}\n\nexport interface PortalCardAdd3DSFlow {\n begin: (created: ThreeDsRequiredCreateResult) => Promise<void>;\n modal: ReactNode;\n isActive: boolean;\n}\n\nexport function usePortalCardAdd3DSFlow({\n payApi,\n onApproved,\n onFailed,\n onCanceled,\n t,\n}: UsePortalCardAdd3DSFlowOptions): PortalCardAdd3DSFlow {\n const [session, setSession] = useState<ActiveSession | null>(null);\n const [challenge, setChallenge] = useState<PendingChallenge | null>(null);\n // Synchronous mirror for the single-flight guard and async continuations.\n const activeSessionRef = useRef<ActiveSession | null>(null);\n\n // Always call the latest surface callbacks.\n const emitApproved = useEffectEvent((approved: ConfirmApprovedResult) =>\n onApproved(approved),\n );\n const emitFailed = useEffectEvent((message: string) => onFailed(message));\n const emitCanceled = useEffectEvent(() => onCanceled());\n\n const resetFlow = () => {\n activeSessionRef.current = null;\n setSession(null);\n setChallenge(null);\n };\n\n // Exactly-one-terminal guard: each finish* no-ops once a terminal has won\n // (resetFlow nulls the ref right before the emit). Covers the modal's\n // Cancel/timeout and begin()'s catch racing a terminal.\n const finishApproved = async (approved: ConfirmApprovedResult) => {\n if (!activeSessionRef.current) return;\n resetFlow();\n await emitApproved(approved);\n };\n const finishFailed = (message: string) => {\n if (!activeSessionRef.current) return;\n resetFlow();\n emitFailed(message);\n };\n const finishCanceled = () => {\n if (!activeSessionRef.current) return;\n resetFlow();\n emitCanceled();\n };\n\n const failureMessageFrom = (error: unknown): string => {\n if (cardAdd3DSErrorCode(error) === \"three_ds_session_not_found\") {\n return t(\"payment_verification_timed_out\");\n }\n return cardAdd3DSErrorMessage(\n error,\n t(\"payment_verification_didnt_complete\"),\n );\n };\n\n const begin = async (created: ThreeDsRequiredCreateResult): Promise<void> => {\n // Single-flight: one bank check at a time.\n if (activeSessionRef.current) return;\n\n const {\n session_token,\n merchant_tx_id,\n fingerprinting_required,\n tds_method_content,\n } = created.three_ds;\n // No attempt activated yet — emit directly (the finish* ref-guard would swallow this).\n if (!session_token) {\n emitFailed(t(\"payment_verification_didnt_complete\"));\n return;\n }\n\n const active: ActiveSession = {\n sessionToken: session_token,\n merchantTxId: merchant_tx_id ?? undefined,\n };\n activeSessionRef.current = active;\n setSession(active);\n\n try {\n // Inside the try so a synchronous throw lands on finishFailed — an\n // escape would leave the ref set and deadlock single-flight.\n if (\n fingerprinting_required !== false &&\n typeof tds_method_content === \"string\" &&\n tds_method_content.length > 0\n ) {\n await renderFingerprintingIframe(tds_method_content);\n }\n\n const confirmation = await payApi.confirmPaymentMethod3DS({\n session_token: active.sessionToken,\n });\n if (confirmation.status === \"approved\") {\n await finishApproved(confirmation);\n return;\n }\n // A challenge with no form renders an empty modal that strands the user\n // — fail fast. (challenge_url alone is only the POST target for the\n // form's hidden fields; the modal renders the iframe from the form HTML.)\n if (!confirmation.challenge_form) {\n finishFailed(t(\"payment_verification_didnt_complete\"));\n return;\n }\n setChallenge({\n html: confirmation.challenge_form,\n url: confirmation.challenge_url ?? undefined,\n });\n } catch (error) {\n finishFailed(failureMessageFrom(error));\n }\n };\n\n // Replays confirm after a completion signal. The modal stays open (its\n // Cancel/timeout terminal can fire mid-await), so check staleness against\n // the attempt captured at entry after every await — land on EXACTLY ONE\n // terminal.\n const reconfirmAfterSignal = async (\n allowPendingRetry: boolean,\n ): Promise<void> => {\n const active = activeSessionRef.current;\n if (!active) return;\n try {\n const confirmation = await payApi.confirmPaymentMethod3DS({\n session_token: active.sessionToken,\n });\n if (activeSessionRef.current !== active) return;\n if (confirmation.status === \"approved\") {\n await finishApproved(confirmation);\n return;\n }\n // A second challenge after a completion signal is out of contract.\n finishFailed(t(\"payment_verification_didnt_complete\"));\n } catch (error) {\n if (activeSessionRef.current !== active) return;\n if (\n allowPendingRetry &&\n cardAdd3DSErrorCode(error) === \"three_ds_pending\"\n ) {\n await waitFor(PENDING_RETRY_DELAY_MS);\n if (activeSessionRef.current !== active) return;\n await reconfirmAfterSignal(false);\n return;\n }\n finishFailed(failureMessageFrom(error));\n }\n };\n\n const sessionStatusSnapshot = async (): Promise<ThreeDSStatus | null> => {\n const active = activeSessionRef.current;\n if (!active) return null;\n try {\n const snapshot = await payApi.fetchPaymentMethod3DSStatus({\n session_token: active.sessionToken,\n });\n return mapSessionStateToThreeDSStatus(snapshot.state, snapshot.expired);\n } catch {\n return null; // transient — keep polling\n }\n };\n\n useVgs3DSCompletion({\n channelName: session ? `private-3ds-session-${session.sessionToken}` : \"\",\n transport: POLLING_ONLY_TRANSPORT,\n checkStatus: sessionStatusSnapshot,\n merchantTxId: session?.merchantTxId,\n enabled: challenge !== null,\n onComplete: () => {\n void reconfirmAfterSignal(true);\n },\n onError: (message) => finishFailed(message),\n onCanceled: finishCanceled,\n });\n\n const closeChallengeModal = (timeoutError?: string) => {\n const active = activeSessionRef.current;\n // Fire-and-forget server-side cancel; the close never waits on it.\n if (active) {\n void payApi\n .cancelPaymentMethod3DS({ session_token: active.sessionToken })\n .catch(() => {});\n }\n if (timeoutError) finishFailed(timeoutError);\n else finishCanceled();\n };\n\n const modal = (\n <VgsThreeDSModal\n isOpen={challenge !== null}\n challengeHtml={challenge?.html ?? \"\"}\n challengeUrl={challenge?.url}\n onClose={closeChallengeModal}\n labels={{\n title: t(\"verify_your_payment\"),\n cancel: t(\"cancel\"),\n timedOut: t(\"payment_verification_timed_out\"),\n stillWorking: t(\"still_working_with_your_bank\"),\n dontRefresh: t(\"dont_refresh_this_tab\"),\n }}\n />\n );\n\n return { begin, modal, isActive: session !== null };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"use-portal-card-add-3ds-flow-BqZulT6m.mjs","names":["FormTextField","FormTextField","FormTextField"],"sources":["../../../profile/core/src/translation-api-context.ts","../src/providers/ProfileTranslationBridge.tsx","../../../profile/ui/src/components/ellipses-dropdown.tsx","../../../profile/ui/src/components/confirm-action-dialog.tsx","../../../profile/ui/src/components/form-fields.tsx","../../../profile/ui/src/components/user-info-dialog.tsx","../../../profile/ui/src/components/payment-method-card-internals.tsx","../../../platform/address-autocomplete/src/administrative-area.ts","../../../platform/address-autocomplete/src/components/AddressAutocompleteInput.tsx","../../../platform/address-fields/src/field-layout.ts","../../../profile/core/src/context.ts","../../../fluid-pay/core/src/context.ts","../../../fluid-pay/core/src/provider.tsx","../../../platform/address-fields/src/country-config.ts","../../../fluid-pay/core/src/utils/country-config.ts","../../../fluid-pay/core/src/hooks/use-country-states.ts","../../../profile/ui/src/components/edit-payment-method-dialog.tsx","../../../profile/ui/src/components/my-site-profile-section.tsx","../../../fluid-pay/ui/src/components/form-fields/FormTextField.tsx","../../../fluid-pay/ui/src/components/form-fields/FormComboboxField.tsx","../../../fluid-pay/ui/src/components/AddressFormDialog.tsx","../../../fluid-pay/ui/src/hooks/use-vgs-collect.ts","../../../fluid-pay/ui/src/components/CreditCardFormDialog.tsx","../../../fluid-pay/ui/src/components/VgsThreeDSModal.tsx","../../../fluid-pay/ui/src/hooks/three-ds-attempt.ts","../../../fluid-pay/ui/src/hooks/use-vgs-3ds-completion.ts","../../../fluid-pay/core/src/utils/browser-info.ts","../../core/src/pay-types.ts","../src/adapters/fluid-pay-api-adapter.ts","../../../fluid-pay/core/src/utils/fingerprinting.ts","../src/hooks/three-ds-card-add-helpers.ts","../src/hooks/use-portal-card-add-3ds-flow.tsx"],"sourcesContent":["import type { Provider } from \"react\";\nimport { createTranslationContext } from \"@fluid-app/i18n/translation-api-context-factory\";\nimport type { TranslationApi } from \"@fluid-app/i18n/translation-api\";\nimport type { ProfileDict } from \"./translation-dictionary\";\n\nconst { Provider: ProfileProvider, useTranslation } =\n createTranslationContext<ProfileDict>(\"Profile\");\n\nexport const ProfileTranslationProvider: Provider<TranslationApi<ProfileDict> | null> =\n ProfileProvider;\nexport const useProfileTranslation = useTranslation;\n","import { useMemo, type ReactNode } from \"react\";\nimport { useActiveLocale } from \"@fluid-app/i18n/locale-context\";\nimport { useDomainDict } from \"@fluid-app/i18n/use-domain-dict\";\nimport {\n profileDomain,\n createProfileTranslationAdapter,\n} from \"@fluid-app/profile-core/translation-adapter\";\nimport { ProfileTranslationProvider } from \"@fluid-app/profile-core/translation-api-context\";\n\nexport function ProfileTranslationBridge({\n children,\n}: {\n children: ReactNode;\n}): React.JSX.Element {\n const { locale } = useActiveLocale();\n const dict = useDomainDict(profileDomain, locale);\n const api = useMemo(\n () => createProfileTranslationAdapter(locale, dict),\n [locale, dict],\n );\n return (\n <ProfileTranslationProvider value={api}>\n {children}\n </ProfileTranslationProvider>\n );\n}\n","import { useState, type JSX } from \"react\";\nimport { Check, EllipsisVertical, Pencil, Trash2 } from \"lucide-react\";\nimport { MobileBottomSheet } from \"@fluid-app/ui-components/components/MobileBottomSheet\";\nimport type { ResponsiveDialogPresentation } from \"@fluid-app/ui-components/components/ResponsiveDialog\";\nimport {\n Button,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from \"@fluid-app/ui-primitives\";\nimport { useProfileTranslation } from \"@fluid-app/profile-core/translation-api-context\";\n\ntype EllipsesDropdownProps = {\n onDelete?: () => void;\n onEdit?: () => void;\n onMakeDefault?: () => void;\n editLabel?: string;\n deleteLabel?: string;\n makeDefaultLabel?: string;\n menuLabel?: string;\n disabled?: boolean;\n presentation?: ResponsiveDialogPresentation;\n};\n\nexport default function EllipsesDropdown({\n onDelete,\n onEdit,\n onMakeDefault,\n editLabel,\n deleteLabel,\n makeDefaultLabel,\n menuLabel,\n disabled = false,\n presentation = \"dialog\",\n}: EllipsesDropdownProps): JSX.Element {\n const { t } = useProfileTranslation();\n const [isOpen, setIsOpen] = useState(false);\n const resolvedEditLabel = editLabel ?? t(\"edit\");\n const resolvedDeleteLabel = deleteLabel ?? t(\"delete\");\n const resolvedMakeDefaultLabel = makeDefaultLabel ?? t(\"make_default\");\n const resolvedMenuLabel = menuLabel ?? resolvedEditLabel;\n\n if (presentation === \"bottom-sheet\") {\n const handleAction = (action: () => void): void => {\n setIsOpen(false);\n action();\n };\n\n return (\n <>\n <Button\n variant=\"ghost\"\n disabled={disabled}\n aria-label={resolvedMenuLabel}\n onClick={() => setIsOpen(true)}\n >\n <EllipsisVertical className=\"text-muted-foreground size-4\" />\n </Button>\n <MobileBottomSheet\n open={isOpen}\n onOpenChange={setIsOpen}\n title={resolvedMenuLabel}\n >\n <div className=\"space-y-1 px-2\">\n {onEdit && (\n <Button\n type=\"button\"\n variant=\"ghost\"\n className=\"h-12 w-full justify-start\"\n onClick={() => handleAction(onEdit)}\n >\n <Pencil className=\"size-4\" />\n {resolvedEditLabel}\n </Button>\n )}\n {onMakeDefault && (\n <Button\n type=\"button\"\n variant=\"ghost\"\n className=\"h-12 w-full justify-start\"\n onClick={() => handleAction(onMakeDefault)}\n >\n <Check className=\"size-4\" />\n {resolvedMakeDefaultLabel}\n </Button>\n )}\n {onDelete && (\n <Button\n type=\"button\"\n variant=\"ghost\"\n className=\"text-destructive hover:bg-destructive/10 hover:text-destructive h-12 w-full justify-start\"\n onClick={() => handleAction(onDelete)}\n >\n <Trash2 className=\"size-4\" />\n {resolvedDeleteLabel}\n </Button>\n )}\n </div>\n </MobileBottomSheet>\n </>\n );\n }\n\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"ghost\"\n disabled={disabled}\n aria-label={resolvedMenuLabel}\n >\n <EllipsisVertical className=\"text-muted-foreground size-4\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent className=\"text-foreground min-w-28 space-y-1 text-sm\">\n {onEdit && (\n <>\n <DropdownMenuItem\n className=\"hover:bg-muted flex cursor-pointer flex-row items-center gap-x-2 rounded px-2\"\n onClick={(event) => {\n event.stopPropagation();\n onEdit();\n }}\n >\n <Pencil className=\"size-3.5 shrink-0\" />\n <span>{resolvedEditLabel}</span>\n </DropdownMenuItem>\n {(onMakeDefault || onDelete) && <DropdownMenuSeparator />}\n </>\n )}\n {onMakeDefault && (\n <>\n <DropdownMenuItem\n className=\"hover:bg-muted flex cursor-pointer flex-row items-center gap-x-2 rounded px-2\"\n onClick={(event) => {\n event.stopPropagation();\n onMakeDefault();\n }}\n >\n <Check className=\"size-3.5 shrink-0\" />\n <span>{resolvedMakeDefaultLabel}</span>\n </DropdownMenuItem>\n {onDelete && <DropdownMenuSeparator />}\n </>\n )}\n {onDelete && (\n <DropdownMenuItem\n className=\"text-destructive hover:bg-destructive/10 flex cursor-pointer flex-row items-center gap-x-2 rounded px-2\"\n onClick={(event) => {\n event.stopPropagation();\n onDelete();\n }}\n >\n <Trash2 className=\"size-3.5 shrink-0\" />\n <span>{resolvedDeleteLabel}</span>\n </DropdownMenuItem>\n )}\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n","import type { JSX } from \"react\";\nimport { DialogFooter, Button } from \"@fluid-app/ui-primitives\";\nimport {\n ResponsiveDialog,\n type ResponsiveDialogPresentation,\n} from \"@fluid-app/ui-components/components/ResponsiveDialog\";\nimport { useProfileTranslation } from \"@fluid-app/profile-core/translation-api-context\";\n\ntype ConfirmActionDialogProps = {\n title: string;\n description: string;\n onAction: () => void;\n openDialog: boolean;\n setOpenDialog: (open: boolean) => void;\n errorMsg?: string;\n isLoading?: boolean;\n actionText?: string;\n presentation?: ResponsiveDialogPresentation;\n};\n\nexport default function ConfirmActionDialog({\n title,\n description,\n onAction,\n openDialog,\n setOpenDialog,\n errorMsg,\n isLoading,\n actionText,\n presentation = \"dialog\",\n}: ConfirmActionDialogProps): JSX.Element {\n const { t } = useProfileTranslation();\n const resolvedActionText = actionText ?? t(\"delete\");\n\n return (\n <ResponsiveDialog\n open={openDialog}\n onOpenChange={setOpenDialog}\n title={title}\n presentation={presentation}\n size=\"compact\"\n >\n <div className=\"space-y-4\">\n <p className=\"text-muted-foreground text-left text-sm\">{description}</p>\n </div>\n\n {errorMsg && <p className=\"text-destructive text-sm\">{errorMsg}</p>}\n\n <DialogFooter>\n <div className=\"flex w-full flex-row justify-between gap-x-2\">\n <Button\n variant=\"secondary\"\n className=\"min-w-[70px]\"\n onClick={() => setOpenDialog(false)}\n >\n {t(\"cancel\")}\n </Button>\n <Button\n type=\"button\"\n variant=\"destructive\"\n className=\"min-w-[70px]\"\n onClick={onAction}\n disabled={isLoading}\n >\n {isLoading ? (\n <div className=\"border-primary-foreground size-5 animate-spin rounded-full border-4 border-t-4 border-t-transparent\" />\n ) : (\n resolvedActionText\n )}\n </Button>\n </div>\n </DialogFooter>\n </ResponsiveDialog>\n );\n}\n","import type React from \"react\";\nimport {\n useController,\n type Control,\n type FieldPath,\n type FieldValues,\n} from \"react-hook-form\";\nimport {\n Input,\n Label,\n Select,\n SelectTrigger,\n SelectContent,\n SelectItem,\n SelectValue,\n Textarea,\n cn,\n} from \"@fluid-app/ui-primitives\";\n\nexport type NameValue = { name: string; value: string | number };\n\nexport function FormTextField<T extends FieldValues>({\n control,\n name,\n label,\n containerClassName,\n ...props\n}: {\n control: Control<T>;\n name: FieldPath<T>;\n label?: string;\n containerClassName?: string;\n} & Omit<React.ComponentProps<\"input\">, \"name\">): React.JSX.Element {\n const {\n field,\n fieldState: { error },\n } = useController({ name, control });\n return (\n <div className={cn(\"min-w-0 space-y-1\", containerClassName)}>\n {label && (\n <Label htmlFor={name} className=\"mb-1.5 block text-sm font-medium\">\n {label}\n </Label>\n )}\n <Input\n {...field}\n {...props}\n id={name}\n value={field.value ?? \"\"}\n className={cn(error && \"ring-destructive ring-1\", props.className)}\n />\n {error && <p className=\"text-destructive text-sm\">{error.message}</p>}\n </div>\n );\n}\n\nexport function FormTextareaField<T extends FieldValues>({\n control,\n name,\n label,\n containerClassName,\n ...props\n}: {\n control: Control<T>;\n name: FieldPath<T>;\n label?: string;\n containerClassName?: string;\n} & Omit<React.ComponentProps<\"textarea\">, \"name\">): React.JSX.Element {\n const {\n field,\n fieldState: { error },\n } = useController({ name, control });\n return (\n <div className={cn(\"min-w-0 space-y-1\", containerClassName)}>\n {label && (\n <Label htmlFor={name} className=\"mb-1.5 block text-sm font-medium\">\n {label}\n </Label>\n )}\n <Textarea\n {...field}\n {...props}\n id={name}\n value={field.value ?? \"\"}\n className={cn(error && \"ring-destructive ring-1\", props.className)}\n />\n {error && <p className=\"text-destructive text-sm\">{error.message}</p>}\n </div>\n );\n}\n\nexport function FormSelectField<T extends FieldValues>({\n control,\n name,\n label,\n options,\n placeholder,\n containerClassName,\n onChange,\n}: {\n control: Control<T>;\n name: FieldPath<T>;\n label?: string;\n options?: NameValue[];\n placeholder?: string;\n containerClassName?: string;\n onChange?: (value: string) => void;\n}): React.JSX.Element {\n const {\n field,\n fieldState: { error },\n } = useController({ name, control });\n return (\n <div className={cn(\"min-w-0 space-y-1\", containerClassName)}>\n {label && (\n <Label htmlFor={name} className=\"block text-sm font-medium\">\n {label}\n </Label>\n )}\n <Select\n value={field.value?.toString() ?? \"\"}\n onValueChange={(val) => {\n field.onChange(val);\n onChange?.(val);\n }}\n >\n <SelectTrigger\n id={name}\n className={cn(\"w-full\", error && \"ring-destructive ring-1\")}\n >\n <SelectValue placeholder={placeholder} />\n </SelectTrigger>\n <SelectContent>\n {options?.map((opt) => (\n <SelectItem\n key={`${opt.name}-${opt.value}`}\n value={opt.value.toString()}\n >\n {opt.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n {error && <p className=\"text-destructive text-sm\">{error.message}</p>}\n </div>\n );\n}\n","import { useState, type JSX } from \"react\";\nimport type { Control } from \"react-hook-form\";\nimport { DialogFooter, Button, Input } from \"@fluid-app/ui-primitives\";\nimport {\n ResponsiveDialog,\n type ResponsiveDialogPresentation,\n} from \"@fluid-app/ui-components/components/ResponsiveDialog\";\nimport { Info } from \"lucide-react\";\nimport {\n FormTextField,\n FormTextareaField,\n FormSelectField,\n type NameValue,\n} from \"./form-fields\";\nimport { useProfileTranslation } from \"@fluid-app/profile-core/translation-api-context\";\n\nexport type UserFormData = {\n first_name: string;\n last_name: string;\n phone_number?: string;\n language: string;\n bio?: string;\n};\n\nexport default function UserInfoDialog({\n control,\n isOpen,\n onSubmit,\n handleClose,\n languageOptions,\n errorMsg,\n isSubmitting,\n email,\n onChangeEmail,\n isChangingEmail,\n pendingEmail,\n disableNameEdit = false,\n presentation = \"dialog\",\n}: {\n control: Control<UserFormData>;\n isOpen: boolean;\n onSubmit: () => void;\n handleClose: () => void;\n languageOptions?: NameValue[];\n errorMsg: string | undefined;\n isSubmitting: boolean;\n email?: string;\n onChangeEmail?: (newEmail: string) => Promise<void> | void;\n isChangingEmail?: boolean;\n pendingEmail?: string;\n // When true, the first_name / last_name inputs are read-only with a short\n // policy hint. Phone, bio, and language remain editable. Matches the\n // per-company `allow_name_edit` flag surfaced through the portal-tenant\n // Store payload. Server-side enforcement lives in Company::IdentityEditPolicy.\n disableNameEdit?: boolean;\n presentation?: ResponsiveDialogPresentation;\n}): JSX.Element {\n const { t } = useProfileTranslation();\n const [isEditingEmail, setIsEditingEmail] = useState(false);\n const [newEmail, setNewEmail] = useState(\"\");\n const [emailError, setEmailError] = useState<string | undefined>(undefined);\n\n const handleEmailSubmit = async () => {\n setEmailError(undefined);\n const trimmed = newEmail.trim();\n if (!trimmed) {\n setEmailError(t(\"please_enter_new_email\"));\n return;\n }\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n if (!emailRegex.test(trimmed)) {\n setEmailError(t(\"please_enter_valid_email\"));\n return;\n }\n if (email && trimmed.toLowerCase() === email.toLowerCase()) {\n setEmailError(t(\"new_email_must_be_different\"));\n return;\n }\n try {\n await onChangeEmail?.(trimmed);\n setIsEditingEmail(false);\n setNewEmail(\"\");\n } catch (err) {\n setEmailError(\n err instanceof Error\n ? err.message\n : t(\"failed_to_initiate_email_change\"),\n );\n }\n };\n\n const handleCancelEmailEdit = () => {\n setIsEditingEmail(false);\n setNewEmail(\"\");\n setEmailError(undefined);\n };\n\n const handleDialogClose = () => {\n handleCancelEmailEdit();\n handleClose();\n };\n\n return (\n <ResponsiveDialog\n open={isOpen}\n onOpenChange={(open) => !open && handleDialogClose()}\n title={t(\"edit_profile\")}\n presentation={presentation}\n >\n <div className=\"space-y-4\">\n <FormTextField\n control={control}\n name=\"first_name\"\n label={t(\"first_name\")}\n disabled={disableNameEdit}\n readOnly={disableNameEdit}\n aria-readonly={disableNameEdit || undefined}\n aria-describedby={\n disableNameEdit ? \"name-edit-disabled-hint\" : undefined\n }\n />\n <FormTextField\n control={control}\n name=\"last_name\"\n label={t(\"last_name\")}\n disabled={disableNameEdit}\n readOnly={disableNameEdit}\n aria-readonly={disableNameEdit || undefined}\n aria-describedby={\n disableNameEdit ? \"name-edit-disabled-hint\" : undefined\n }\n />\n {disableNameEdit && (\n <p\n id=\"name-edit-disabled-hint\"\n className=\"text-muted-foreground text-xs\"\n >\n {t(\"name_change_disabled_hint\")}\n </p>\n )}\n <FormTextField\n control={control}\n name=\"phone_number\"\n label={t(\"phone_number\")}\n type=\"tel\"\n />\n <FormTextareaField\n control={control}\n name=\"bio\"\n label={t(\"bio\")}\n rows={3}\n placeholder={t(\"add_a_short_bio\")}\n />\n <FormSelectField\n control={control}\n name=\"language\"\n label={t(\"language\")}\n options={languageOptions}\n placeholder={t(\"select_an_option\")}\n />\n </div>\n {email && (\n <div className=\"space-y-2\">\n <label className=\"text-foreground text-sm font-medium\">\n {t(\"email\")}\n </label>\n {isEditingEmail ? (\n <div className=\"space-y-2\">\n <Input\n type=\"email\"\n placeholder={t(\"enter_new_email_placeholder\")}\n value={newEmail}\n onChange={(e) => {\n setNewEmail(e.target.value);\n setEmailError(undefined);\n }}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") {\n e.preventDefault();\n handleEmailSubmit();\n }\n if (e.key === \"Escape\") {\n handleCancelEmailEdit();\n }\n }}\n aria-invalid={!!emailError || undefined}\n autoFocus\n />\n {emailError && (\n <p className=\"text-destructive text-xs\">{emailError}</p>\n )}\n <div className=\"bg-muted flex items-start gap-2.5 rounded-md px-3 py-2.5\">\n <Info className=\"text-primary mt-0.5 size-4 shrink-0\" />\n <p className=\"text-muted-foreground text-xs\">\n {t(\"email_verification_hint\")}\n </p>\n </div>\n <div className=\"flex gap-2\">\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={handleCancelEmailEdit}\n >\n {t(\"cancel\")}\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n onClick={handleEmailSubmit}\n disabled={!newEmail.trim() || isChangingEmail}\n >\n {isChangingEmail && (\n <div className=\"mr-2 size-3.5 animate-spin rounded-full border-2 border-current/30 border-t-current\" />\n )}\n {isChangingEmail ? t(\"sending\") : t(\"send_verification\")}\n </Button>\n </div>\n </div>\n ) : pendingEmail ? (\n <div className=\"space-y-2\">\n <div className=\"bg-muted text-muted-foreground min-w-0 rounded-md px-3 py-2 text-sm\">\n {email}\n </div>\n <div className=\"bg-muted flex items-start gap-2.5 rounded-md px-3 py-2.5\">\n <Info className=\"text-primary mt-0.5 size-4 shrink-0\" />\n <p className=\"text-muted-foreground text-xs\">\n {t(\"changing_email_to\")}{\" \"}\n <span className=\"text-foreground font-medium\">\n {pendingEmail}\n </span>\n . {t(\"check_new_email_verification\")}\n </p>\n </div>\n </div>\n ) : (\n <div className=\"flex items-center gap-2\">\n <div className=\"bg-muted text-muted-foreground min-w-0 flex-1 rounded-md px-3 py-2 text-sm\">\n {email}\n </div>\n {onChangeEmail && (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => setIsEditingEmail(true)}\n className=\"shrink-0\"\n >\n {t(\"change\")}\n </Button>\n )}\n </div>\n )}\n </div>\n )}\n {errorMsg && <p className=\"text-destructive text-sm\">{errorMsg}</p>}\n <DialogFooter className=\"flex flex-row items-center justify-end\">\n <div className=\"flex-1 text-right\">\n <Button type=\"button\" onClick={onSubmit}>\n {isSubmitting && (\n <div className=\"mr-2 size-4 animate-spin rounded-full border-2 border-current/30 border-t-current\" />\n )}\n {isSubmitting ? t(\"saving\") : t(\"save_changes\")}\n </Button>\n </div>\n </DialogFooter>\n </ResponsiveDialog>\n );\n}\n","import { useState, type JSX } from \"react\";\nimport type { fluidPay } from \"@fluid-app/fluid-pay-core\";\nimport {\n brandIconUrl as resolveBrandIconUrl,\n normalizeCardBrand,\n} from \"@fluid-app/payments-display/brands\";\nimport {\n isCardPaymentDescriptor,\n normalizePaymentDescriptor,\n paymentDescriptorLabel,\n resolvePaymentLogo,\n resolvePaymentMethodDisplay,\n} from \"@fluid-app/payments-display/display\";\n\nexport function brandIconUrl(brand: string | null | undefined): string {\n return resolveBrandIconUrl(brand);\n}\n\nexport function PaymentIcon({\n logoUrl,\n brand,\n alt,\n}: {\n logoUrl?: string;\n brand: string | null | undefined;\n alt: string;\n}): JSX.Element {\n const logo = resolvePaymentLogo({ brand, logoUrl, alt });\n const [hasError, setHasError] = useState(false);\n const src = hasError ? logo.fallbackUrl : logo.primaryUrl;\n return (\n <img\n src={src}\n alt={logo.alt}\n width={40}\n height={24}\n className=\"object-contain\"\n onError={() => setHasError(true)}\n />\n );\n}\n\nexport function getPaymentMethodLogoBrand(\n paymentMethod: fluidPay.CustomerPaymentMethod,\n): string | null {\n if (isCardPaymentMethod(paymentMethod)) {\n return (\n normalizeCardBrand(paymentMethod.details.card_brand) ??\n normalizeCardBrand(paymentMethod.details.card_network)\n );\n }\n\n return paymentDescriptorLabel(\n paymentMethod.payment_type,\n paymentMethod.source,\n );\n}\n\nexport function getCardDisplayName(\n paymentMethod: fluidPay.CustomerPaymentMethod,\n cardFallback = \"Card\",\n): string {\n if (isCardPaymentMethod(paymentMethod)) {\n return resolvePaymentMethodDisplay({\n kind: \"card\",\n brand: getPaymentMethodLogoBrand(paymentMethod) ?? cardFallback,\n last4: paymentMethod.details.last_four,\n logoUrl: paymentMethod.details.logo_url,\n }).label;\n }\n\n const fallbackLabel = paymentDescriptorLabel(\n paymentMethod.payment_type,\n paymentMethod.source,\n );\n return resolvePaymentMethodDisplay({\n kind: \"non_card\",\n brand: fallbackLabel,\n fallbackLabel,\n logoUrl: paymentMethod.details.logo_url,\n }).label;\n}\n\nexport function getCardExpiry(\n paymentMethod: fluidPay.CustomerPaymentMethod,\n expiresLabel = \"Expires\",\n): string {\n const { exp_month, exp_year } = paymentMethod.details;\n if (exp_month != null && exp_year != null) {\n return `${expiresLabel} ${exp_month}/${exp_year}`;\n }\n return \"\";\n}\n\nfunction isCardPaymentMethod(\n paymentMethod: fluidPay.CustomerPaymentMethod,\n): boolean {\n return (\n paymentMethod.source === \"card\" ||\n isCardPaymentDescriptor(paymentMethod.payment_type) ||\n isCardPaymentDescriptor(paymentMethod.source) ||\n normalizePaymentDescriptor(paymentMethod.details.card_brand) != null ||\n normalizePaymentDescriptor(paymentMethod.details.card_network) != null ||\n paymentMethod.details.last_four != null\n );\n}\n","export interface StateOption {\n readonly isoCode: string;\n readonly name: string;\n}\n\ninterface AdministrativeAreaDetails {\n readonly state?: string;\n readonly administrativeAreaShort?: string;\n readonly administrativeAreaLong?: string;\n}\n\nfunction normalize(value: string): string {\n return value.trim().toLowerCase();\n}\n\nfunction firstPresent(...values: Array<string | undefined>): string {\n return values.find((value) => value && value.trim() !== \"\") ?? \"\";\n}\n\nfunction findStateByIsoCode(\n stateOptions: readonly StateOption[],\n value: string,\n): StateOption | undefined {\n const normalizedValue = normalize(value);\n if (!normalizedValue) return undefined;\n return stateOptions.find(\n (state) => normalize(state.isoCode) === normalizedValue,\n );\n}\n\nfunction findStateByName(\n stateOptions: readonly StateOption[],\n value: string,\n): StateOption | undefined {\n const normalizedValue = normalize(value);\n if (!normalizedValue) return undefined;\n return stateOptions.find(\n (state) => normalize(state.name) === normalizedValue,\n );\n}\n\nexport function resolveAdministrativeAreaState(\n details: AdministrativeAreaDetails,\n stateOptions: readonly StateOption[] = [],\n): string {\n const displayValue = firstPresent(\n details.state,\n details.administrativeAreaLong,\n details.administrativeAreaShort,\n );\n\n if (stateOptions.length === 0) return displayValue;\n\n const candidates = [\n details.administrativeAreaShort,\n details.state,\n details.administrativeAreaLong,\n ].filter((value): value is string => Boolean(value));\n\n for (const candidate of candidates) {\n const state =\n findStateByIsoCode(stateOptions, candidate) ??\n findStateByName(stateOptions, candidate);\n if (state) return state.isoCode;\n }\n\n return displayValue;\n}\n","import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ChangeEvent,\n type JSX,\n} from \"react\";\nimport {\n useController,\n type Control,\n type FieldValues,\n type Path,\n type PathValue,\n type UseFormSetValue,\n} from \"react-hook-form\";\nimport { Input, Label } from \"@fluid-app/ui-primitives\";\nimport { useAddressAutocompleteApiOptional } from \"../api-context\";\nimport type { AddressDetails, AddressSuggestion } from \"../api\";\nimport {\n resolveAdministrativeAreaState,\n type StateOption,\n} from \"../administrative-area\";\n\nexport interface AddressAutocompleteInputProps<T extends FieldValues> {\n readonly control: Control<T>;\n readonly setValue: UseFormSetValue<T>;\n readonly countryIso: string;\n readonly addressLineField: Path<T>;\n readonly cityField: Path<T>;\n /** Omit when the country's address format has no administrative area. */\n readonly stateField?: Path<T>;\n readonly postalCodeField: Path<T>;\n readonly stateOptions?: readonly StateOption[];\n readonly id?: string;\n readonly label?: string;\n readonly placeholder?: string;\n readonly disabled?: boolean;\n /** Applied to the text input, so callers can match sibling fields. */\n readonly inputClassName?: string;\n}\n\nconst SET_OPTS = {\n shouldValidate: true,\n shouldDirty: true,\n shouldTouch: true,\n} as const;\n\nconst DEBOUNCE_MS = 250;\nconst EMPTY_STATE_OPTIONS: readonly StateOption[] = [];\n\nexport function AddressAutocompleteInput<T extends FieldValues>({\n control,\n setValue,\n countryIso,\n addressLineField,\n cityField,\n stateField,\n postalCodeField,\n stateOptions = EMPTY_STATE_OPTIONS,\n id,\n label,\n placeholder,\n disabled,\n inputClassName,\n}: AddressAutocompleteInputProps<T>): JSX.Element {\n const api = useAddressAutocompleteApiOptional();\n const {\n field,\n fieldState: { error },\n } = useController({ name: addressLineField, control });\n const [suggestions, setSuggestions] = useState<readonly AddressSuggestion[]>(\n [],\n );\n const [isOpen, setIsOpen] = useState(false);\n const [needsCountry, setNeedsCountry] = useState(false);\n const containerRef = useRef<HTMLDivElement | null>(null);\n // Monotonically increasing request ID. We only apply a fetch result when its\n // ID still matches the latest issued one — guards against stale responses\n // arriving out of order under network jitter.\n const requestIdRef = useRef(0);\n const debounceTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const isCountrySelected = useMemo(\n () => Boolean(countryIso && countryIso.trim() !== \"\"),\n [countryIso],\n );\n const inputId = id ?? addressLineField;\n\n useEffect(() => {\n function onClickOutside(e: MouseEvent) {\n if (\n containerRef.current &&\n !containerRef.current.contains(e.target as Node)\n ) {\n setIsOpen(false);\n setNeedsCountry(false);\n }\n }\n document.addEventListener(\"mousedown\", onClickOutside);\n return () => document.removeEventListener(\"mousedown\", onClickOutside);\n }, []);\n\n useEffect(\n () => () => {\n if (debounceTimerRef.current !== null) {\n clearTimeout(debounceTimerRef.current);\n }\n },\n [],\n );\n\n // Every suggestion belongs to the country it was looked up for, so switching\n // country invalidates all of it: what is on screen, a debounce still waiting\n // to fire with the old country captured, and any lookup already in flight.\n // Advancing the request ID is what discards those late responses.\n useEffect(() => {\n if (debounceTimerRef.current !== null) {\n clearTimeout(debounceTimerRef.current);\n debounceTimerRef.current = null;\n }\n requestIdRef.current += 1;\n setSuggestions([]);\n setIsOpen(false);\n setNeedsCountry(false);\n }, [countryIso]);\n\n useEffect(() => {\n if (api) return;\n // Suggestions failing quietly is the exact bug this input exists to prevent,\n // so a host that forgot the provider should hear about it.\n console.warn(\n \"AddressAutocompleteInput: no AddressAutocompleteApiProvider found — address suggestions are disabled.\",\n );\n }, [api]);\n\n const populate = useCallback(\n (s: AddressDetails) => {\n setValue(\n addressLineField,\n s.streetLine as PathValue<T, Path<T>>,\n SET_OPTS,\n );\n setValue(cityField, s.city as PathValue<T, Path<T>>, SET_OPTS);\n // The lookup returns an administrative area even for countries that do\n // not collect one, and writing it would save a value the form never\n // showed.\n if (stateField) {\n setValue(\n stateField,\n resolveAdministrativeAreaState(s, stateOptions) as PathValue<\n T,\n Path<T>\n >,\n SET_OPTS,\n );\n }\n setValue(\n postalCodeField,\n s.postalCode as PathValue<T, Path<T>>,\n SET_OPTS,\n );\n },\n [\n addressLineField,\n cityField,\n postalCodeField,\n setValue,\n stateField,\n stateOptions,\n ],\n );\n\n const handleChange = useCallback(\n (e: ChangeEvent<HTMLInputElement>) => {\n const value = e.target.value;\n field.onChange(value);\n if (!api) return;\n\n // Cancel any pending fetch from a prior keystroke.\n if (debounceTimerRef.current !== null) {\n clearTimeout(debounceTimerRef.current);\n debounceTimerRef.current = null;\n }\n\n if (value.length < 1) {\n setIsOpen(false);\n setNeedsCountry(false);\n setSuggestions([]);\n return;\n }\n if (!isCountrySelected) {\n setNeedsCountry(true);\n setIsOpen(true);\n return;\n }\n setNeedsCountry(false);\n\n const requestId = ++requestIdRef.current;\n debounceTimerRef.current = setTimeout(() => {\n debounceTimerRef.current = null;\n void api.fetchSuggestions({ query: value, countryIso }).then((next) => {\n // Drop stale responses — a newer keystroke has already issued a\n // request, and applying this would clobber its result.\n if (requestId !== requestIdRef.current) return;\n setSuggestions(next);\n setIsOpen(true);\n });\n }, DEBOUNCE_MS);\n },\n [api, countryIso, field, isCountrySelected],\n );\n\n const handleClick = useCallback(\n async (suggestion: AddressSuggestion) => {\n // Cancel any debounced fetch still pending from a recent keystroke and\n // advance the request ID so any in-flight response is dropped — without\n // this, the timer could fire after a selection and re-open the dropdown.\n if (debounceTimerRef.current !== null) {\n clearTimeout(debounceTimerRef.current);\n debounceTimerRef.current = null;\n }\n const clickId = ++requestIdRef.current;\n\n if (!suggestion.needsDetailLookup) {\n populate({\n streetLine: suggestion.streetLine ?? suggestion.text,\n city: suggestion.city ?? \"\",\n state: suggestion.state ?? \"\",\n postalCode: suggestion.postalCode ?? \"\",\n });\n setIsOpen(false);\n return;\n }\n if (!api) return;\n const { details, drilldownSuggestions } = await api.fetchDetails({\n suggestion,\n countryIso,\n });\n // Drop the result if the user typed during the network round-trip — a\n // newer keystroke has superseded this click and applying its result\n // would clobber what the user has since entered.\n if (clickId !== requestIdRef.current) return;\n if (details) {\n populate(details);\n setIsOpen(false);\n return;\n }\n setSuggestions(drilldownSuggestions);\n setIsOpen(true);\n },\n [api, countryIso, populate],\n );\n\n return (\n <div className=\"space-y-1\">\n {label && (\n <Label htmlFor={inputId} className=\"mb-1.5 block text-sm font-medium\">\n {label}\n </Label>\n )}\n <div ref={containerRef} className=\"relative\">\n <Input\n id={inputId}\n className={inputClassName}\n type=\"text\"\n ref={field.ref}\n value={(field.value as string) ?? \"\"}\n onChange={handleChange}\n onBlur={field.onBlur}\n placeholder={placeholder}\n disabled={disabled}\n aria-invalid={!!error}\n />\n {isOpen && needsCountry && (\n <div className=\"bg-muted text-foreground absolute z-50 mt-1 w-full rounded-md px-3 py-2 text-sm shadow-lg\">\n Please select a country first to enable address suggestions\n </div>\n )}\n {isOpen && !needsCountry && suggestions.length > 0 && (\n <div className=\"bg-background text-foreground border-border absolute z-50 mt-1 max-h-60 w-full overflow-y-auto rounded-md border shadow-lg\">\n {suggestions.map((s) => (\n <button\n key={s.id}\n type=\"button\"\n onClick={() => {\n void handleClick(s).catch((err) => {\n // handleClick is async because of fetchDetails — the current\n // Smarty adapter and NULL_API swallow errors, so this is\n // belt-and-suspenders for future adapters that might throw.\n console.error(\"Address autocomplete click failed:\", err);\n });\n }}\n className=\"hover:bg-muted block w-full cursor-pointer px-3 py-2 text-left text-sm\"\n >\n {s.text}\n {s.needsDetailLookup ? \" →\" : \"\"}\n </button>\n ))}\n </div>\n )}\n </div>\n {error?.message && (\n <p className=\"text-destructive text-sm\">{error.message}</p>\n )}\n </div>\n );\n}\n","import type { AddressField } from \"./types\";\n\n/**\n * Which address fields a country collects, in what order, and how they group\n * into rows. The address-fields service is the authority: when it answers, its\n * list decides presence and order, and its labels arrive already translated.\n * The static values below cover only the window before it answers, or a host\n * with no provider wired.\n */\nexport const ADDRESS_FIELD_NAMES = [\n \"name\",\n \"address1\",\n \"address2\",\n \"city\",\n \"state\",\n \"postal_code\",\n \"phone\",\n] as const;\n\nexport type AddressFieldName = (typeof ADDRESS_FIELD_NAMES)[number];\n\nconst STATIC_LABEL_KEYS: Record<AddressFieldName, string> = {\n name: \"name\",\n address1: \"address_line_1\",\n address2: \"address_line_2\",\n city: \"city\",\n state: \"state\",\n postal_code: \"zip_code\",\n phone: \"phone_number\",\n};\n\nconst DEFAULT_HIDDEN_FIELDS = new Set<AddressFieldName>([\"phone\"]);\n\nconst STATIC_REQUIRED_FIELDS = new Set<AddressFieldName>([\n \"name\",\n \"address1\",\n \"city\",\n \"state\",\n \"postal_code\",\n]);\n\n// Autocomplete fills city, state and postal from the street line, so those\n// three come first regardless of where the service puts them.\nconst AUTOCOMPLETE_FIELD_PREFIX: readonly AddressFieldName[] = [\n \"name\",\n \"address1\",\n \"address2\",\n];\n\nconst ROW_GROUPED_FIELDS = new Set<AddressFieldName>([\n \"city\",\n \"state\",\n \"postal_code\",\n]);\n\nexport function isAddressFieldName(value: string): value is AddressFieldName {\n return (ADDRESS_FIELD_NAMES as readonly string[]).includes(value);\n}\n\nexport function addressFieldOrder(\n fields: readonly AddressField[] | null,\n): AddressFieldName[] {\n if (!fields) {\n return ADDRESS_FIELD_NAMES.filter(\n (field) => !DEFAULT_HIDDEN_FIELDS.has(field),\n );\n }\n const fromService = fields\n .map((field) => field.field)\n .filter(isAddressFieldName);\n const prefix = AUTOCOMPLETE_FIELD_PREFIX.filter((field) =>\n fromService.includes(field),\n );\n const rest = fromService.filter(\n (field) => !AUTOCOMPLETE_FIELD_PREFIX.includes(field),\n );\n return [...prefix, ...rest];\n}\n\n/** Consecutive city, state and postal fields share one row. */\nexport function groupAddressFields(\n fields: readonly AddressFieldName[],\n): AddressFieldName[][] {\n const groups: AddressFieldName[][] = [];\n let i = 0;\n while (i < fields.length) {\n const current = fields[i]!;\n if (ROW_GROUPED_FIELDS.has(current)) {\n const group: AddressFieldName[] = [current];\n while (\n i + group.length < fields.length &&\n ROW_GROUPED_FIELDS.has(fields[i + group.length]!)\n ) {\n group.push(fields[i + group.length]!);\n }\n if (group.length > 1) {\n groups.push(group);\n i += group.length;\n continue;\n }\n }\n groups.push([current]);\n i++;\n }\n return groups;\n}\n\nexport function isAddressFieldRequired(\n fields: readonly AddressField[] | null,\n fieldName: AddressFieldName,\n): boolean {\n if (!fields) return STATIC_REQUIRED_FIELDS.has(fieldName);\n return fields.find((field) => field.field === fieldName)?.required ?? false;\n}\n\n/**\n * The service's label when it has one, otherwise a translation key for the\n * caller to resolve. `regionKey` and `postalKey` let a caller pass the\n * country-specific key it already has, such as province or postal_code.\n */\nexport function addressFieldLabel(\n fields: readonly AddressField[] | null,\n fieldName: AddressFieldName,\n fallbackKeys?: { regionKey?: string; postalKey?: string },\n): { label?: string; translationKey?: string } {\n const serviceLabel = fields?.find(\n (field) => field.field === fieldName,\n )?.label;\n if (serviceLabel) return { label: serviceLabel };\n if (fieldName === \"state\" && fallbackKeys?.regionKey) {\n return { translationKey: fallbackKeys.regionKey };\n }\n if (fieldName === \"postal_code\" && fallbackKeys?.postalKey) {\n return { translationKey: fallbackKeys.postalKey };\n }\n return { translationKey: STATIC_LABEL_KEYS[fieldName] };\n}\n","import { createContext, useContext } from \"react\";\n\nexport type TranslationFn = (key: string) => string;\n\nexport interface ProfileUIContextValue {\n t: TranslationFn;\n}\n\nexport const ProfileUIContext = createContext<ProfileUIContextValue | null>(\n null,\n);\n\nexport function useProfileUI(): ProfileUIContextValue {\n const context = useContext(ProfileUIContext);\n if (!context) {\n throw new Error(\"useProfileUI must be used within a ProfileUIProvider\");\n }\n return context;\n}\n","import { createContext, useContext } from \"react\";\nimport type { FluidPayApi } from \"./api-interface\";\n\nconst FluidPayApiContext = createContext<FluidPayApi | null>(null);\n\nexport const FluidPayApiProvider = FluidPayApiContext.Provider;\n\nexport function useFluidPayApi(): FluidPayApi {\n const api = useContext(FluidPayApiContext);\n if (!api) {\n throw new Error(\n \"useFluidPayApi must be used within a FluidPayCoreProvider\",\n );\n }\n return api;\n}\n","import type { JSX } from \"react\";\nimport type { FluidPayApi } from \"./api-interface\";\nimport { FluidPayApiProvider } from \"./context\";\n\nexport interface FluidPayCoreProviderProps {\n api: FluidPayApi;\n children: React.ReactNode;\n}\n\nexport function FluidPayCoreProvider({\n api,\n children,\n}: FluidPayCoreProviderProps): JSX.Element {\n return <FluidPayApiProvider value={api}>{children}</FluidPayApiProvider>;\n}\n","import type { AddressField, RegionConfig, State } from \"./types\";\n\nexport const COUNTRY_CONFIGS: Record<string, RegionConfig> & {\n default: RegionConfig;\n} = {\n US: { regionLabel: \"state\", postalLabel: \"zip_code\" },\n JP: { regionLabel: \"prefecture\", postalLabel: \"postal_code\" },\n default: { regionLabel: \"province\", postalLabel: \"postal_code\" },\n} as const;\n\nexport function getRegionConfig(countryCode: string): RegionConfig {\n return COUNTRY_CONFIGS[countryCode] ?? COUNTRY_CONFIGS.default;\n}\n\nexport const US_STATES: State[] = [\n { name: \"Alabama\", isoCode: \"AL\" },\n { name: \"Alaska\", isoCode: \"AK\" },\n { name: \"American Samoa\", isoCode: \"AS\" },\n { name: \"Arizona\", isoCode: \"AZ\" },\n { name: \"Arkansas\", isoCode: \"AR\" },\n { name: \"California\", isoCode: \"CA\" },\n { name: \"Colorado\", isoCode: \"CO\" },\n { name: \"Connecticut\", isoCode: \"CT\" },\n { name: \"Delaware\", isoCode: \"DE\" },\n { name: \"District of Columbia\", isoCode: \"DC\" },\n { name: \"Florida\", isoCode: \"FL\" },\n { name: \"Georgia\", isoCode: \"GA\" },\n { name: \"Guam\", isoCode: \"GU\" },\n { name: \"Hawaii\", isoCode: \"HI\" },\n { name: \"Idaho\", isoCode: \"ID\" },\n { name: \"Illinois\", isoCode: \"IL\" },\n { name: \"Indiana\", isoCode: \"IN\" },\n { name: \"Iowa\", isoCode: \"IA\" },\n { name: \"Kansas\", isoCode: \"KS\" },\n { name: \"Kentucky\", isoCode: \"KY\" },\n { name: \"Louisiana\", isoCode: \"LA\" },\n { name: \"Maine\", isoCode: \"ME\" },\n { name: \"Maryland\", isoCode: \"MD\" },\n { name: \"Massachusetts\", isoCode: \"MA\" },\n { name: \"Michigan\", isoCode: \"MI\" },\n { name: \"Minnesota\", isoCode: \"MN\" },\n { name: \"Mississippi\", isoCode: \"MS\" },\n { name: \"Missouri\", isoCode: \"MO\" },\n { name: \"Montana\", isoCode: \"MT\" },\n { name: \"Nebraska\", isoCode: \"NE\" },\n { name: \"Nevada\", isoCode: \"NV\" },\n { name: \"New Hampshire\", isoCode: \"NH\" },\n { name: \"New Jersey\", isoCode: \"NJ\" },\n { name: \"New Mexico\", isoCode: \"NM\" },\n { name: \"New York\", isoCode: \"NY\" },\n { name: \"North Carolina\", isoCode: \"NC\" },\n { name: \"North Dakota\", isoCode: \"ND\" },\n { name: \"Northern Mariana Islands\", isoCode: \"MP\" },\n { name: \"Ohio\", isoCode: \"OH\" },\n { name: \"Oklahoma\", isoCode: \"OK\" },\n { name: \"Oregon\", isoCode: \"OR\" },\n { name: \"Pennsylvania\", isoCode: \"PA\" },\n { name: \"Puerto Rico\", isoCode: \"PR\" },\n { name: \"Rhode Island\", isoCode: \"RI\" },\n { name: \"South Carolina\", isoCode: \"SC\" },\n { name: \"South Dakota\", isoCode: \"SD\" },\n { name: \"Tennessee\", isoCode: \"TN\" },\n { name: \"Texas\", isoCode: \"TX\" },\n { name: \"Utah\", isoCode: \"UT\" },\n { name: \"U.S. Virgin Islands\", isoCode: \"VI\" },\n { name: \"Vermont\", isoCode: \"VT\" },\n { name: \"Virginia\", isoCode: \"VA\" },\n { name: \"Washington\", isoCode: \"WA\" },\n { name: \"West Virginia\", isoCode: \"WV\" },\n { name: \"Wisconsin\", isoCode: \"WI\" },\n { name: \"Wyoming\", isoCode: \"WY\" },\n];\n\nexport const DEFAULT_ADDRESS_FIELDS: AddressField[] = [\n { field: \"name\", label: \"Full name\", required: true },\n { field: \"address1\", label: \"Address\", required: true },\n { field: \"address2\", label: \"Apartment, suite, etc.\", required: false },\n { field: \"city\", label: \"City\", required: true },\n { field: \"state\", label: \"State\", required: true },\n { field: \"postal_code\", label: \"Zip code\", required: true },\n];\n\nexport function isFieldRequired(\n addressFields: readonly AddressField[],\n fieldName: string,\n): boolean {\n return addressFields.find((f) => f.field === fieldName)?.required ?? false;\n}\n","export interface State {\n name: string;\n isoCode: string;\n}\n\nexport interface RegionConfig {\n regionLabel: string;\n postalLabel: string;\n}\n\n/** Re-exported from the platform source of truth rather than duplicated.\n *\n * The local copy had drifted: it listed 51 entries and was missing the\n * five US territories `@fluid-app/address-fields` carries — American\n * Samoa (AS), Guam (GU), Northern Mariana Islands (MP), Puerto Rico\n * (PR) and the U.S. Virgin Islands (VI). Every consumer of\n * `useCountryStates` (the payment-method billing dialog, the address\n * form) therefore could not offer them, while checkout — which\n * re-exports the canonical list — could. */\nexport { US_STATES } from \"@fluid-app/address-fields/country-config\";\n\n// Translation keys, not display text. A capitalized value here would miss the\n// lowercase dictionary keys.\nexport const COUNTRY_CONFIGS: Record<string, RegionConfig> = {\n US: { regionLabel: \"state\", postalLabel: \"zip_code\" },\n JP: { regionLabel: \"prefecture\", postalLabel: \"postal_code\" },\n};\n\nconst DEFAULT_REGION_CONFIG: RegionConfig = {\n regionLabel: \"province\",\n postalLabel: \"postal_code\",\n};\n\nexport function getRegionConfig(countryCode: string): RegionConfig {\n return COUNTRY_CONFIGS[countryCode] ?? DEFAULT_REGION_CONFIG;\n}\n\nexport const DEFAULT_ADDRESS_FIELDS = [\n { field: \"name\", label: \"Name\", required: true },\n { field: \"address1\", label: \"Address\", required: true },\n { field: \"address2\", label: \"Apartment, suite, etc.\", required: false },\n { field: \"city\", label: \"City\", required: true },\n { field: \"state\", label: \"State\", required: true },\n { field: \"postal_code\", label: \"Postal Code\", required: true },\n { field: \"country_code\", label: \"Country\", required: true },\n];\n","import { useCallback, useRef, useState } from \"react\";\nimport {\n US_STATES,\n getRegionConfig,\n type State,\n} from \"../utils/country-config\";\n\nexport default function useCountryStates() {\n const [selectedCountry, setSelectedCountry] = useState<string>(\"US\");\n const [stateOptions, setStateOptions] = useState<State[]>(US_STATES);\n // Which country `stateOptions` describes, or null while a lookup is pending.\n // Callers that decide whether a subdivision is required cannot tell an empty\n // list apart from one that has not loaded yet without this.\n const [optionsCountry, setOptionsCountry] = useState<string | null>(\"US\");\n // Monotonically increasing lookup ID. Only the newest lookup may write the\n // options — switching country twice in quick succession leaves two fetches in\n // flight, and a slow response for the abandoned country would otherwise\n // replace the list for the one now selected.\n const lookupIdRef = useRef(0);\n\n const handleCountryChange = useCallback(\n (\n selectedCountryCode: string,\n fetchStates?: (countryCode: string) => Promise<State[]>,\n ) => {\n setSelectedCountry(selectedCountryCode);\n const lookupId = ++lookupIdRef.current;\n const fallbackStates = selectedCountryCode === \"US\" ? US_STATES : [];\n if (fetchStates) {\n // Drop the previous country's options up front. Callers derive things\n // from this list, so leaving the old country's subdivisions in place\n // while a lookup is pending would have them acting on the wrong data.\n setStateOptions(fallbackStates);\n setOptionsCountry(null);\n fetchStates(selectedCountryCode)\n .then((states) => {\n if (lookupId !== lookupIdRef.current) return;\n setStateOptions(states.length > 0 ? states : fallbackStates);\n setOptionsCountry(selectedCountryCode);\n })\n .catch((error) => {\n if (lookupId !== lookupIdRef.current) return;\n console.error(\"Failed to fetch states:\", error);\n setStateOptions(fallbackStates);\n setOptionsCountry(selectedCountryCode);\n });\n } else {\n setStateOptions(selectedCountryCode === \"US\" ? US_STATES : []);\n setOptionsCountry(selectedCountryCode);\n }\n },\n [],\n );\n\n const config = getRegionConfig(selectedCountry);\n\n return {\n handleCountryChange,\n stateOptions,\n optionsCountry,\n config,\n selectedCountry,\n };\n}\n","import { useEffect, useMemo, useRef, useState, type JSX } from \"react\";\nimport { Controller, useWatch } from \"react-hook-form\";\nimport { z } from \"zod\";\nimport { Trash2 } from \"lucide-react\";\nimport {\n Button,\n Checkbox,\n DialogFooter,\n Label,\n cn,\n useZodForm,\n} from \"@fluid-app/ui-primitives\";\nimport {\n ResponsiveDialog,\n type ResponsiveDialogPresentation,\n} from \"@fluid-app/ui-components/components/ResponsiveDialog\";\nimport { AddressAutocompleteInput } from \"@fluid-app/address-autocomplete/components/AddressAutocompleteInput\";\nimport { useAddressFieldsApiOptional } from \"@fluid-app/address-fields/address-fields-api-context\";\nimport type { AddressField } from \"@fluid-app/address-fields/types\";\nimport {\n addressFieldLabel,\n addressFieldOrder,\n groupAddressFields,\n isAddressFieldRequired,\n type AddressFieldName,\n} from \"@fluid-app/address-fields/field-layout\";\nimport { FormTextField, FormSelectField } from \"./form-fields\";\nimport type { fluidPay } from \"@fluid-app/fluid-pay-core\";\nimport { useCountryStates, type State } from \"@fluid-app/profile-core\";\nimport { useProfileTranslation } from \"@fluid-app/profile-core/translation-api-context\";\nimport type { BillingAddress } from \"./view-payment-method-dialog\";\nimport {\n PaymentIcon,\n getCardDisplayName,\n getPaymentMethodLogoBrand,\n} from \"./payment-method-card-internals\";\n\nfunction createEditPaymentMethodFormSchema(t: (key: string) => string) {\n return z.object({\n billing_address: z.object({\n // Required-ness is decided at submit time from the address fields\n // service.\n name: z.string(),\n address1: z.string(),\n address2: z.string().optional().nullable(),\n city: z.string(),\n state: z.string(),\n zip: z.string(),\n country_code: z.string().min(1, t(\"country_is_required\")),\n }),\n set_as_default: z.boolean(),\n });\n}\n\n// The shared field names are the service's; this form nests them and calls the\n// postal field zip.\nconst FORM_PATHS_BY_FIELD = [\n { field: \"name\", key: \"name\", path: \"billing_address.name\" },\n { field: \"address1\", key: \"address1\", path: \"billing_address.address1\" },\n { field: \"address2\", key: \"address2\", path: \"billing_address.address2\" },\n { field: \"city\", key: \"city\", path: \"billing_address.city\" },\n { field: \"state\", key: \"state\", path: \"billing_address.state\" },\n { field: \"postal_code\", key: \"zip\", path: \"billing_address.zip\" },\n] as const satisfies readonly {\n field: AddressFieldName;\n key: keyof EditPaymentMethodFormData[\"billing_address\"];\n path: string;\n}[];\n\nfunction pathForField(\n fieldName: AddressFieldName,\n):\n | \"billing_address.name\"\n | \"billing_address.address1\"\n | \"billing_address.address2\"\n | \"billing_address.city\"\n | \"billing_address.state\"\n | \"billing_address.zip\" {\n const entry = FORM_PATHS_BY_FIELD.find((e) => e.field === fieldName);\n return entry?.path ?? \"billing_address.address1\";\n}\n\nfunction valueForField(\n data: EditPaymentMethodFormData,\n fieldName: AddressFieldName,\n): string | undefined {\n const entry = FORM_PATHS_BY_FIELD.find((e) => e.field === fieldName);\n if (!entry) return undefined;\n const value = data.billing_address[entry.key];\n return typeof value === \"string\" ? value : undefined;\n}\n\nexport type EditPaymentMethodFormData = z.infer<\n ReturnType<typeof createEditPaymentMethodFormSchema>\n>;\n\ninterface CountryOption {\n iso: string;\n name: string;\n}\n\ninterface EditPaymentMethodDialogProps {\n isOpen: boolean;\n paymentMethod: fluidPay.CustomerPaymentMethod | null;\n billingAddress?: BillingAddress | null;\n onClose: () => void;\n onSubmit: (data: EditPaymentMethodFormData) => void;\n isSubmitting: boolean;\n error?: string;\n countries?: CountryOption[];\n fetchStates?: (countryCode: string) => Promise<State[]>;\n /** Locale for the address fields lookup, so its labels come back translated. */\n languageIso?: string;\n onDelete?: () => void;\n isDeleting?: boolean;\n presentation?: ResponsiveDialogPresentation;\n}\n\nexport default function EditPaymentMethodDialog({\n isOpen,\n paymentMethod,\n billingAddress,\n onClose,\n onSubmit,\n isSubmitting,\n error,\n countries = [],\n fetchStates,\n languageIso,\n onDelete,\n isDeleting = false,\n presentation = \"dialog\",\n}: EditPaymentMethodDialogProps): JSX.Element | null {\n const { t } = useProfileTranslation();\n const [confirmDelete, setConfirmDelete] = useState(false);\n\n useEffect(() => {\n if (!isOpen) setConfirmDelete(false);\n }, [isOpen]);\n\n useEffect(() => {\n if (!confirmDelete) return;\n const timeoutId = setTimeout(() => setConfirmDelete(false), 3000);\n return () => clearTimeout(timeoutId);\n }, [confirmDelete]);\n\n const editPaymentMethodFormSchema = useMemo(\n () => createEditPaymentMethodFormSchema((key) => t(key as never)),\n [t],\n );\n\n const { control, handleSubmit, reset, setValue, setError, clearErrors } =\n useZodForm<EditPaymentMethodFormData>(editPaymentMethodFormSchema, {\n defaultValues: {\n billing_address: {\n name: \"\",\n address1: \"\",\n address2: \"\",\n city: \"\",\n state: \"\",\n zip: \"\",\n country_code: \"US\",\n },\n set_as_default: false,\n },\n });\n\n const billingCountry = useWatch({\n control,\n name: \"billing_address.country_code\",\n });\n\n const { stateOptions, optionsCountry, config, handleCountryChange } =\n useCountryStates();\n\n const countryOptions = [...countries]\n .map((country) => ({\n name: country.name,\n value: country.iso,\n }))\n .sort((a, b) => {\n if (a.value === billingCountry) return -1;\n if (b.value === billingCountry) return 1;\n return a.name.localeCompare(b.name);\n });\n\n const stateSelectOptions = stateOptions.map((state) => ({\n name: state.name,\n value: state.isoCode,\n }));\n\n useEffect(() => {\n if (paymentMethod && isOpen) {\n reset({\n billing_address: {\n name: billingAddress?.name ?? \"\",\n address1: billingAddress?.address1 ?? \"\",\n address2: billingAddress?.address2 ?? \"\",\n city: billingAddress?.city ?? \"\",\n state: billingAddress?.state ?? \"\",\n zip: billingAddress?.zip ?? \"\",\n country_code: billingAddress?.country_code ?? \"US\",\n },\n set_as_default: paymentMethod.default,\n });\n }\n }, [paymentMethod, billingAddress, isOpen, reset]);\n\n // The form opens on its static default and only takes the card's country once\n // the reset lands, so following the watched value immediately would look up a\n // country this card is not in and throw the answer away. Stay on the card's\n // country until the user picks a different one. Null while no card is on\n // screen, since hooks run before this dialog's early return.\n const cardCountry = billingAddress?.country_code ?? \"US\";\n const countryTouchedRef = useRef(false);\n useEffect(() => {\n if (!isOpen) countryTouchedRef.current = false;\n }, [isOpen]);\n const lookupCountry =\n !isOpen || !paymentMethod\n ? null\n : countryTouchedRef.current || billingCountry === cardCountry\n ? billingCountry\n : null;\n\n // Keeps the state options in step with the selected country, including on\n // open, so a non-US card doesn't come up listing US states.\n useEffect(() => {\n if (!lookupCountry) return;\n handleCountryChange(lookupCountry, fetchStates);\n }, [lookupCountry, handleCountryChange, fetchStates]);\n\n // Whether the subdivision list on screen describes the selected country. An\n // empty list means \"this country has none\" only once it does.\n const stateOptionsReady = optionsCountry === billingCountry;\n\n const addressFieldsApi = useAddressFieldsApiOptional();\n // The country's field metadata, or null when the lookup failed. `country`\n // records what the answer is about, so a pending lookup is distinguishable.\n const [countryFields, setCountryFields] = useState<{\n country: string;\n fields: readonly AddressField[] | null;\n } | null>(null);\n\n useEffect(() => {\n if (!addressFieldsApi || !lookupCountry) return;\n let cancelled = false;\n setCountryFields(null);\n addressFieldsApi\n .fetchAddressFields(lookupCountry, languageIso)\n .then((response) => {\n if (cancelled) return;\n setCountryFields({\n country: lookupCountry,\n fields: response.address_fields.fields,\n });\n })\n .catch(() => {\n if (!cancelled)\n setCountryFields({ country: lookupCountry, fields: null });\n });\n return () => {\n cancelled = true;\n };\n }, [addressFieldsApi, lookupCountry, languageIso]);\n\n const answeredFields =\n countryFields?.country === billingCountry ? countryFields?.fields : null;\n\n // Which fields this country collects, in the service's own order. The billing\n // form has no phone field, so drop it if the service sends one.\n const fieldOrder = useMemo(\n () =>\n addressFieldOrder(answeredFields ?? null).filter((f) => f !== \"phone\"),\n [answeredFields],\n );\n const fieldGroups = useMemo(\n () => groupAddressFields(fieldOrder),\n [fieldOrder],\n );\n\n // Deciding anything from the list before it arrives would act on the static\n // fallback and then rearrange under the user, so hold Save until the lookup\n // settles. A failed lookup counts as settled: otherwise a service outage\n // would leave the form unsaveable.\n const layoutReady = addressFieldsApi\n ? lookupCountry === null || countryFields?.country === billingCountry\n : // Without the service, the option list is the only signal, so wait for it.\n stateOptionsReady;\n\n const isRequired = (fieldName: AddressFieldName): boolean => {\n if (answeredFields)\n return isAddressFieldRequired(answeredFields, fieldName);\n // The static fallback assumes a US-shaped address, so require a\n // subdivision only when there is a list to pick one from.\n if (fieldName === \"state\") return stateSelectOptions.length > 0;\n return isAddressFieldRequired(null, fieldName);\n };\n\n const fieldLabel = (fieldName: AddressFieldName): string => {\n const resolved = addressFieldLabel(answeredFields ?? null, fieldName, {\n regionKey: config?.regionLabel,\n postalKey: config?.postalLabel,\n });\n return resolved.label ?? t((resolved.translationKey ?? fieldName) as never);\n };\n\n const REQUIRED_MESSAGE_KEYS: Record<string, string> = {\n name: \"name_is_required\",\n address1: \"address_line_1_is_required\",\n city: \"city_is_required\",\n state: \"state_is_required\",\n postal_code: \"zip_code_is_required\",\n };\n\n const handleFormSubmit = handleSubmit((data) => {\n clearErrors(FORM_PATHS_BY_FIELD.map((entry) => entry.path));\n if (!layoutReady) return;\n\n const missing = fieldOrder.filter(\n (fieldName) =>\n isRequired(fieldName) && !valueForField(data, fieldName)?.trim(),\n );\n if (missing.length > 0) {\n for (const fieldName of missing) {\n const key = REQUIRED_MESSAGE_KEYS[fieldName];\n if (!key) continue;\n setError(pathForField(fieldName), {\n type: \"manual\",\n message: t(key as never),\n });\n }\n return;\n }\n\n // Deliberately submits what is in the form even when the field is hidden:\n // blanking it would erase a stored subdivision the user never saw. Changing\n // country clears it through the country select instead.\n onSubmit(data);\n });\n\n const deleteButtonLabel = useMemo(() => {\n if (isDeleting) return t(\"deleting\");\n if (confirmDelete) return t(\"tap_to_confirm\");\n return t(\"delete_card\");\n }, [isDeleting, confirmDelete, t]);\n\n if (!paymentMethod) return null;\n\n const { details } = paymentMethod;\n const displayName = getCardDisplayName(paymentMethod, t(\"card_fallback\"));\n const expMonth = details.exp_month;\n const expYear = details.exp_year;\n\n const renderField = (fieldName: AddressFieldName): JSX.Element => {\n const label = fieldLabel(fieldName);\n if (fieldName === \"address1\") {\n return (\n <AddressAutocompleteInput\n key={fieldName}\n control={control}\n setValue={setValue}\n countryIso={billingCountry}\n addressLineField=\"billing_address.address1\"\n cityField=\"billing_address.city\"\n stateField={\n fieldOrder.includes(\"state\") ? \"billing_address.state\" : undefined\n }\n postalCodeField=\"billing_address.zip\"\n stateOptions={stateOptions}\n label={label}\n disabled={isSubmitting}\n />\n );\n }\n if (fieldName === \"state\" && stateSelectOptions.length > 0) {\n return (\n <FormSelectField\n key={fieldName}\n control={control}\n name=\"billing_address.state\"\n label={label}\n options={stateSelectOptions}\n placeholder={t(\"select_state\")}\n />\n );\n }\n // Anything else, including a subdivision with no list to pick from, is\n // typed. A required field must stay answerable.\n return (\n <FormTextField\n key={fieldName}\n control={control}\n name={pathForField(fieldName)}\n label={label}\n />\n );\n };\n\n return (\n <ResponsiveDialog\n open={isOpen}\n onOpenChange={(open) => !open && onClose()}\n title={t(\"edit_card\")}\n presentation={presentation}\n >\n <div className=\"space-y-4\">\n <div className=\"bg-muted rounded-lg p-4\">\n <div className=\"flex items-center gap-x-3\">\n <div className=\"h-6 w-10 flex-shrink-0\">\n <PaymentIcon\n logoUrl={details.logo_url}\n brand={getPaymentMethodLogoBrand(paymentMethod)}\n alt={displayName}\n />\n </div>\n <div className=\"flex flex-col\">\n <span className=\"text-foreground text-sm font-medium\">\n {displayName}\n </span>\n {expMonth != null && expYear != null && (\n <span className=\"text-muted-foreground text-sm\">\n {t(\"card_expires\")} {expMonth}/{expYear}\n </span>\n )}\n </div>\n </div>\n </div>\n\n <div>\n <h3 className=\"text-foreground mb-3 text-sm font-medium\">\n {t(\"billing_address\")}\n </h3>\n <div className=\"space-y-3\">\n <FormSelectField\n control={control}\n name=\"billing_address.country_code\"\n label={t(\"country\")}\n options={countryOptions}\n placeholder={t(\"select_an_option\")}\n onChange={() => {\n // From here on the select, not the card, decides which country\n // to look up.\n countryTouchedRef.current = true;\n // The old subdivision does not belong to the newly picked\n // country, and neither does a \"state is required\" error raised\n // against it by an earlier submit.\n setValue(\"billing_address.state\", \"\");\n clearErrors(\"billing_address.state\");\n }}\n />\n {fieldGroups.map((group) => (\n <div\n key={group.join(\"-\")}\n className={cn(\n \"grid grid-cols-1 gap-3\",\n group.length === 3\n ? \"sm:grid-cols-3\"\n : group.length === 2\n ? \"sm:grid-cols-2\"\n : undefined,\n )}\n >\n {group.map((fieldName) => renderField(fieldName))}\n </div>\n ))}\n </div>\n </div>\n </div>\n\n <Controller\n control={control}\n name=\"set_as_default\"\n render={({ field }) => (\n <div className=\"mt-2 flex items-center gap-x-2\">\n <Checkbox\n id=\"set_as_default\"\n checked={field.value}\n onCheckedChange={(checked) => field.onChange(checked === true)}\n />\n <Label htmlFor=\"set_as_default\" className=\"text-sm font-normal\">\n {t(\"set_as_default_payment_method\")}\n </Label>\n </div>\n )}\n />\n\n {error && <div className=\"text-destructive text-sm\">{error}</div>}\n\n <DialogFooter className=\"flex flex-row items-center justify-between gap-2\">\n {onDelete ? (\n <Button\n type=\"button\"\n variant=\"ghost\"\n onClick={() => {\n if (confirmDelete) {\n onDelete();\n } else {\n setConfirmDelete(true);\n }\n }}\n disabled={isSubmitting || isDeleting}\n className=\"text-destructive hover:bg-destructive/10 hover:text-destructive\"\n >\n <Trash2 className=\"size-4\" />\n {deleteButtonLabel}\n </Button>\n ) : (\n <span />\n )}\n <div className=\"flex items-center gap-2\">\n <Button\n type=\"button\"\n variant=\"secondary\"\n onClick={onClose}\n disabled={isSubmitting || isDeleting}\n >\n {t(\"cancel\")}\n </Button>\n <Button\n type=\"button\"\n onClick={handleFormSubmit}\n disabled={isSubmitting || isDeleting || !layoutReady}\n >\n {isSubmitting && (\n <div className=\"mr-2 size-4 animate-spin rounded-full border-2 border-current/30 border-t-current\" />\n )}\n {isSubmitting ? t(\"saving\") : t(\"save_changes\")}\n </Button>\n </div>\n </DialogFooter>\n </ResponsiveDialog>\n );\n}\n","import type React from \"react\";\nimport { useController, type Control } from \"react-hook-form\";\nimport {\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Label,\n Textarea,\n cn,\n} from \"@fluid-app/ui-primitives\";\nimport { z } from \"zod\";\nimport { FormTextField } from \"./form-fields\";\nimport { useProfileTranslation } from \"@fluid-app/profile-core/translation-api-context\";\n\nfunction normalizeUrl(value: string): string {\n const trimmed = value.trim();\n if (!trimmed) return \"\";\n if (/^https?:\\/\\//i.test(trimmed)) return trimmed;\n return `https://${trimmed}`;\n}\n\nconst urlField = z\n .string()\n .transform(normalizeUrl)\n .pipe(z.string().url().or(z.literal(\"\")));\n\nexport const mySiteProfileSchema = z.object({\n bio: z.string().optional(),\n linkedin: urlField,\n facebook: urlField,\n twitter: urlField,\n instagram: urlField,\n youtube: urlField,\n pinterest: urlField,\n tiktok: urlField,\n whatsapp: z.string().optional(),\n wechat: z.string().optional(),\n});\n\nexport type MySiteProfileFormData = z.infer<typeof mySiteProfileSchema>;\n\nexport const socialFields = [\n {\n name: \"linkedin\",\n label: \"LinkedIn\",\n placeholder: \"linkedin.com/in/username\",\n },\n { name: \"facebook\", label: \"Facebook\", placeholder: \"facebook.com/username\" },\n { name: \"twitter\", label: \"X (Twitter)\", placeholder: \"x.com/username\" },\n {\n name: \"instagram\",\n label: \"Instagram\",\n placeholder: \"instagram.com/username\",\n },\n { name: \"youtube\", label: \"YouTube\", placeholder: \"youtube.com/@channel\" },\n {\n name: \"pinterest\",\n label: \"Pinterest\",\n placeholder: \"pinterest.com/username\",\n },\n { name: \"tiktok\", label: \"TikTok\", placeholder: \"tiktok.com/@username\" },\n { name: \"whatsapp\", label: \"WhatsApp\", placeholder: \"Phone number or link\" },\n { name: \"wechat\", label: \"WeChat\", placeholder: \"WeChat ID\" },\n] as const satisfies readonly {\n name: keyof Omit<MySiteProfileFormData, \"bio\">;\n label: string;\n placeholder: string;\n}[];\n\nexport interface MySiteProfileSectionProps {\n avatarUrl?: string | null;\n initial?: string;\n control: Control<MySiteProfileFormData>;\n}\n\nfunction BioField({ control }: { control: Control<MySiteProfileFormData> }) {\n const { t } = useProfileTranslation();\n const {\n field,\n fieldState: { error },\n } = useController({ name: \"bio\", control });\n return (\n <div className=\"space-y-1\">\n <Label htmlFor=\"mysite-bio\" className=\"block text-sm font-medium\">\n {t(\"bio\")}\n </Label>\n <Textarea\n id=\"mysite-bio\"\n rows={4}\n placeholder={t(\"bio_placeholder\")}\n className={cn(error && \"ring-destructive ring-1\")}\n {...field}\n value={field.value ?? \"\"}\n />\n {error && <p className=\"text-destructive text-sm\">{error.message}</p>}\n </div>\n );\n}\n\nexport function MySiteProfileSection({\n avatarUrl,\n initial,\n control,\n}: MySiteProfileSectionProps): React.JSX.Element {\n const { t } = useProfileTranslation();\n return (\n <Card>\n <CardHeader>\n <CardTitle>{t(\"about_me\")}</CardTitle>\n </CardHeader>\n <CardContent className=\"flex flex-col gap-6 lg:flex-row lg:gap-10\">\n <div className=\"bg-muted relative h-[120px] w-[120px] shrink-0 self-center overflow-hidden rounded-full lg:self-auto\">\n {avatarUrl ? (\n <img\n src={avatarUrl}\n alt={t(\"profile_image_alt\")}\n className=\"h-full w-full object-cover\"\n />\n ) : (\n <div className=\"bg-background text-foreground flex h-full w-full items-center justify-center text-xl font-semibold\">\n {initial ?? \"U\"}\n </div>\n )}\n </div>\n\n <div className=\"min-w-0 flex-1\">\n <BioField control={control} />\n </div>\n </CardContent>\n </Card>\n );\n}\n\nexport interface MySiteProfileSocialSectionProps {\n control: Control<MySiteProfileFormData>;\n}\n\nexport function MySiteProfileSocialSection({\n control,\n}: MySiteProfileSocialSectionProps): React.JSX.Element {\n const { t } = useProfileTranslation();\n return (\n <Card>\n <CardHeader>\n <CardTitle>{t(\"social_media_links\")}</CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-4\">\n {socialFields.map((field) => {\n let placeholder: string = field.placeholder;\n if (field.name === \"whatsapp\")\n placeholder = t(\"whatsapp_placeholder\");\n if (field.name === \"wechat\") placeholder = t(\"wechat_placeholder\");\n return (\n <FormTextField\n key={field.name}\n control={control}\n name={field.name}\n label={field.label}\n placeholder={placeholder}\n />\n );\n })}\n </div>\n </CardContent>\n </Card>\n );\n}\n\nexport interface MySiteProfileSaveButtonProps {\n isDirty: boolean;\n isPending: boolean;\n onSubmit: () => void;\n}\n\nexport function MySiteProfileSaveButton({\n isDirty,\n isPending,\n onSubmit,\n}: MySiteProfileSaveButtonProps): React.JSX.Element {\n const { t } = useProfileTranslation();\n return (\n <div className=\"flex justify-end pb-6\">\n <Button\n type=\"button\"\n onClick={onSubmit}\n disabled={!isDirty || isPending}\n className=\"w-full sm:w-auto\"\n >\n {isPending && (\n <div className=\"mr-2 size-4 animate-spin rounded-full border-2 border-current/30 border-t-current\" />\n )}\n {isPending ? t(\"saving\") : t(\"save\")}\n </Button>\n </div>\n );\n}\n","\"use client\";\n\nimport type { Control, FieldPath, FieldValues } from \"react-hook-form\";\nimport { useController } from \"react-hook-form\";\nimport { Input, Label, cn } from \"@fluid-app/ui-primitives\";\n\ninterface FormTextFieldProps<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n> {\n control: Control<TFieldValues>;\n name: TName;\n label?: string;\n placeholder?: string;\n containerClassName?: string;\n type?: React.HTMLInputTypeAttribute;\n disabled?: boolean;\n inputMode?: React.HTMLAttributes<HTMLInputElement>[\"inputMode\"];\n autoComplete?: string;\n}\n\nexport function FormTextField<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n>({\n control,\n name,\n label,\n placeholder,\n containerClassName,\n type,\n disabled,\n inputMode,\n autoComplete,\n}: FormTextFieldProps<TFieldValues, TName>) {\n const {\n field,\n fieldState: { error },\n } = useController({ name, control });\n\n return (\n <div className={cn(\"space-y-1\", containerClassName)}>\n {label && (\n <Label htmlFor={name} className=\"mb-1.5 block text-sm font-medium\">\n {label}\n </Label>\n )}\n <Input\n {...field}\n value={field.value ?? \"\"}\n id={name}\n type={type}\n disabled={disabled}\n inputMode={inputMode}\n placeholder={placeholder}\n autoComplete={autoComplete}\n aria-invalid={!!error}\n />\n {error?.message && (\n <p className=\"text-destructive text-sm\">{error.message}</p>\n )}\n </div>\n );\n}\n","\"use client\";\n\nimport { useMemo } from \"react\";\nimport type { Control, FieldPath, FieldValues } from \"react-hook-form\";\nimport { Controller } from \"react-hook-form\";\nimport { Label, cn } from \"@fluid-app/ui-primitives\";\nimport { Combobox } from \"@fluid-app/ui-components/components/Combobox\";\n\ntype NameValue = { name: string; value: string | number };\n\ninterface FormComboboxFieldProps<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n> {\n control: Control<TFieldValues>;\n name: TName;\n label?: string;\n placeholder?: string;\n emptyText?: string;\n options?: NameValue[];\n containerClassName?: string;\n disabled?: boolean;\n onChange?: (value: string) => void;\n}\n\nexport function FormComboboxField<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n>({\n control,\n name,\n label,\n placeholder = \"Select\",\n emptyText = \"No results found.\",\n options,\n containerClassName,\n disabled,\n onChange,\n}: FormComboboxFieldProps<TFieldValues, TName>) {\n const comboboxOptions = useMemo(\n () =>\n options?.map((opt) => ({\n label: opt.name,\n value: opt.value.toString(),\n })) ?? [],\n [options],\n );\n\n return (\n <div className={cn(\"space-y-1\", containerClassName)}>\n {label && (\n <Label htmlFor={name} className=\"mb-1.5 block text-sm font-medium\">\n {label}\n </Label>\n )}\n <Controller\n control={control}\n name={name}\n render={({\n field: { onChange: fieldOnChange, value },\n fieldState: { error },\n }) => (\n <>\n <Combobox\n options={comboboxOptions}\n value={value?.toString() ?? \"\"}\n onValueChange={(next) => {\n fieldOnChange(next);\n onChange?.(next);\n }}\n placeholder={placeholder}\n emptyText={emptyText}\n disabled={disabled}\n />\n {error?.message && (\n <p className=\"text-destructive text-sm\">{error.message}</p>\n )}\n </>\n )}\n />\n </div>\n );\n}\n","import { type JSX, useEffect, useId, useMemo, useState } from \"react\";\nimport { Controller, useWatch } from \"react-hook-form\";\nimport { Trash2 } from \"lucide-react\";\nimport { z } from \"zod\";\nimport {\n Button,\n Checkbox,\n Label,\n cn,\n useZodForm,\n} from \"@fluid-app/ui-primitives\";\nimport {\n ResponsiveDialog,\n type ResponsiveDialogPresentation,\n} from \"@fluid-app/ui-components/components/ResponsiveDialog\";\nimport { FormTextField } from \"./form-fields/FormTextField\";\nimport { FormComboboxField } from \"./form-fields/FormComboboxField\";\nimport { PhoneInput } from \"@fluid-app/ui-components/components/PhoneInput\";\nimport type { fluidPay } from \"@fluid-app/fluid-pay-core\";\nimport { useCountryStates, type State } from \"@fluid-app/fluid-pay-core\";\nimport { useAddressFieldsApiOptional } from \"@fluid-app/address-fields/address-fields-api-context\";\nimport type { AddressField } from \"@fluid-app/address-fields/types\";\nimport {\n addressFieldLabel,\n addressFieldOrder,\n groupAddressFields,\n isAddressFieldRequired,\n type AddressFieldName,\n} from \"@fluid-app/address-fields/field-layout\";\nimport { AddressAutocompleteInput } from \"@fluid-app/address-autocomplete/components/AddressAutocompleteInput\";\n\nconst addressFormSchema = z.object({\n name: z.string(),\n address1: z.string(),\n address2: z.string().optional().nullable(),\n city: z.string(),\n state: z.string(),\n postal_code: z.string(),\n phone: z.string().optional().nullable(),\n country_code: z.string().min(1, \"Country is required\"),\n default: z.boolean(),\n});\n\nexport type AddressFormData = z.infer<typeof addressFormSchema>;\n\ninterface CountryOption {\n iso: string;\n name: string;\n}\n\ninterface AddressFormDialogProps {\n isOpen: boolean;\n onClose: () => void;\n selectedAddress: fluidPay.CustomerAddress | null;\n onSubmit: (data: fluidPay.CreateAddressBody) => void;\n isSubmitting: boolean;\n countries?: CountryOption[];\n error?: string;\n fetchStates?: (countryCode: string) => Promise<State[]>;\n t: (key: string) => string;\n onDelete?: () => void;\n isDeleting?: boolean;\n defaultCountry?: string;\n languageIso?: string;\n presentation?: ResponsiveDialogPresentation;\n}\n\nconst REQUIRED_FIELD_MESSAGES: Record<AddressFieldName, string> = {\n name: \"Name is required\",\n address1: \"Address line 1 is required\",\n address2: \"Address line 2 is required\",\n city: \"City is required\",\n state: \"State is required\",\n postal_code: \"Postal code is required\",\n phone: \"Phone is required\",\n};\n\nfunction isBlank(value: string | null | undefined): boolean {\n return value == null || value.trim().length === 0;\n}\n\nexport default function AddressFormDialog({\n isOpen,\n onClose,\n selectedAddress,\n onSubmit,\n isSubmitting,\n countries = [],\n error,\n fetchStates,\n t,\n onDelete,\n isDeleting = false,\n defaultCountry = \"US\",\n languageIso,\n presentation = \"dialog\",\n}: AddressFormDialogProps): JSX.Element {\n const [confirmDelete, setConfirmDelete] = useState(false);\n const phoneInputId = useId();\n const addressFieldsApi = useAddressFieldsApiOptional();\n const [bffFields, setBffFields] = useState<AddressField[] | null>(null);\n\n useEffect(() => {\n if (!isOpen) setConfirmDelete(false);\n }, [isOpen]);\n\n useEffect(() => {\n if (!confirmDelete) return;\n const timeoutId = setTimeout(() => setConfirmDelete(false), 3000);\n return () => clearTimeout(timeoutId);\n }, [confirmDelete]);\n\n const deleteButtonLabel = useMemo(() => {\n if (isDeleting) return t(\"deleting\");\n if (confirmDelete) return t(\"tap_to_confirm\");\n return t(\"delete_address\");\n }, [isDeleting, confirmDelete, t]);\n\n const { control, handleSubmit, reset, setValue, setError, clearErrors } =\n useZodForm<AddressFormData>(addressFormSchema, {\n defaultValues: {\n name: \"\",\n address1: \"\",\n address2: \"\",\n city: \"\",\n state: \"\",\n postal_code: \"\",\n phone: \"\",\n country_code: defaultCountry,\n default: false,\n },\n });\n\n const selectedCountryCode = useWatch({ control, name: \"country_code\" });\n\n const { stateOptions, config, handleCountryChange } = useCountryStates();\n\n useEffect(() => {\n if (!addressFieldsApi || !selectedCountryCode) return;\n let cancelled = false;\n setBffFields(null);\n addressFieldsApi\n .fetchAddressFields(selectedCountryCode, languageIso)\n .then((response) => {\n if (!cancelled) {\n setBffFields([...response.address_fields.fields]);\n }\n })\n .catch(() => {\n if (!cancelled) setBffFields(null);\n });\n return () => {\n cancelled = true;\n };\n }, [addressFieldsApi, selectedCountryCode, languageIso]);\n\n const fieldOrder = useMemo(() => addressFieldOrder(bffFields), [bffFields]);\n\n const fieldGroups = useMemo(\n () => groupAddressFields(fieldOrder),\n [fieldOrder],\n );\n\n const getFieldLabel = (fieldName: AddressFieldName): string => {\n const resolved = addressFieldLabel(bffFields, fieldName, {\n regionKey: config?.regionLabel,\n postalKey: config?.postalLabel,\n });\n return resolved.label ?? t(resolved.translationKey ?? fieldName);\n };\n\n const countrySelectOptions = [...countries]\n .map((country) => ({\n name: country.name,\n value: country.iso,\n }))\n .sort((a, b) => {\n if (a.value === selectedCountryCode) return -1;\n if (b.value === selectedCountryCode) return 1;\n return a.name.localeCompare(b.name);\n });\n\n const stateSelectOptions = stateOptions.map((state) => ({\n name: state.name,\n value: state.isoCode,\n }));\n\n useEffect(() => {\n if (isOpen) {\n if (selectedAddress) {\n reset({\n name: selectedAddress.name ?? \"\",\n address1: selectedAddress.address1,\n address2: selectedAddress.address2 ?? \"\",\n city: selectedAddress.city,\n state: selectedAddress.state,\n postal_code: selectedAddress.postal_code,\n phone: selectedAddress.phone ?? \"\",\n country_code: selectedAddress.country_code ?? defaultCountry,\n default: selectedAddress.default,\n });\n handleCountryChange(\n selectedAddress.country_code ?? defaultCountry,\n fetchStates,\n );\n } else {\n reset({\n name: \"\",\n address1: \"\",\n address2: \"\",\n city: \"\",\n state: \"\",\n postal_code: \"\",\n phone: \"\",\n country_code: defaultCountry,\n default: false,\n });\n handleCountryChange(defaultCountry, fetchStates);\n }\n }\n // defaultCountry intentionally omitted: a background addresses refetch can\n // change the parent-computed value while the dialog is open, which would\n // wipe the user's in-progress edits.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selectedAddress, isOpen, reset, handleCountryChange, fetchStates]);\n\n useEffect(() => {\n handleCountryChange(selectedCountryCode, fetchStates);\n }, [selectedCountryCode, handleCountryChange, fetchStates]);\n\n const handleFormSubmit = handleSubmit((data) => {\n clearErrors(fieldOrder);\n const missingRequiredFields = fieldOrder.filter(\n (fieldName) =>\n isAddressFieldRequired(bffFields, fieldName) &&\n isBlank(data[fieldName]),\n );\n\n if (missingRequiredFields.length > 0) {\n for (const fieldName of missingRequiredFields) {\n setError(fieldName, {\n type: \"manual\",\n message: REQUIRED_FIELD_MESSAGES[fieldName],\n });\n }\n return;\n }\n\n // Submits what is in the form even for a field this country does not\n // collect. The value is rendered in full_address and on order PDFs, so\n // erasing it would drop it from documents the customer reads. Switching\n // country is what clears a subdivision left over from the previous one.\n onSubmit({\n address: {\n name: data.name,\n address1: data.address1,\n address2: data.address2 ?? null,\n city: data.city,\n state: data.state,\n postal_code: data.postal_code,\n phone: data.phone || null,\n country_code: data.country_code,\n default: data.default,\n },\n });\n });\n\n const renderField = (\n fieldName: AddressFieldName,\n containerClassName?: string,\n ): JSX.Element => {\n const label = getFieldLabel(fieldName);\n\n if (fieldName === \"state\" && stateSelectOptions.length > 0) {\n return (\n <FormComboboxField\n key={fieldName}\n control={control}\n name=\"state\"\n label={label}\n placeholder={t(\"select_state\")}\n options={stateSelectOptions}\n containerClassName={containerClassName}\n disabled={isSubmitting}\n />\n );\n }\n\n if (fieldName === \"address1\") {\n return (\n <div key={fieldName} className={cn(\"space-y-1\", containerClassName)}>\n <Label\n htmlFor={fieldName}\n className=\"mb-1.5 block text-sm font-medium\"\n >\n {label}\n </Label>\n <AddressAutocompleteInput\n control={control}\n setValue={setValue}\n countryIso={selectedCountryCode}\n addressLineField=\"address1\"\n cityField=\"city\"\n stateField={fieldOrder.includes(\"state\") ? \"state\" : undefined}\n postalCodeField=\"postal_code\"\n stateOptions={stateOptions}\n disabled={isSubmitting}\n />\n </div>\n );\n }\n\n if (fieldName === \"phone\") {\n return (\n <div key={fieldName} className={containerClassName}>\n <Controller\n control={control}\n name=\"phone\"\n render={({ field: { value, onChange }, fieldState: { error } }) => (\n <div className=\"space-y-1\">\n <Label\n htmlFor={phoneInputId}\n className=\"mb-1.5 block text-sm font-medium\"\n >\n {label}\n </Label>\n <PhoneInput\n id={phoneInputId}\n value={value ?? \"\"}\n onChange={onChange}\n defaultCountry={selectedCountryCode}\n error={!!error}\n disabled={isSubmitting}\n searchPlaceholder={t(\"search_country\")}\n emptyText={t(\"no_results_found\")}\n />\n {error?.message && (\n <p className=\"text-destructive text-sm\">{error.message}</p>\n )}\n </div>\n )}\n />\n </div>\n );\n }\n\n return (\n <FormTextField\n key={fieldName}\n control={control}\n name={fieldName}\n label={label}\n containerClassName={containerClassName}\n disabled={isSubmitting}\n autoComplete={fieldName === \"name\" ? \"name\" : undefined}\n />\n );\n };\n\n const isEditMode = selectedAddress !== null;\n\n return (\n <ResponsiveDialog\n open={isOpen}\n onOpenChange={(open) => !open && onClose()}\n title={isEditMode ? t(\"edit_address\") : t(\"add_an_address\")}\n presentation={presentation}\n size=\"wide\"\n >\n <div className=\"space-y-3 pt-2\">\n <FormComboboxField\n control={control}\n name=\"country_code\"\n label={t(\"country\")}\n placeholder={t(\"select_an_option\")}\n options={countrySelectOptions}\n disabled={isSubmitting}\n onChange={() => {\n // The old subdivision does not belong to the newly picked country,\n // and neither does a required-field error raised against it by an\n // earlier submit.\n setValue(\"state\", \"\");\n clearErrors(\"state\");\n }}\n />\n {fieldGroups.map((group) => {\n if (group.length === 1) {\n return renderField(group[0]!);\n }\n return (\n <div\n key={group.join(\"-\")}\n className=\"flex flex-col gap-3 sm:flex-row\"\n >\n {group.map((fieldName) =>\n renderField(fieldName, \"min-w-0 flex-1\"),\n )}\n </div>\n );\n })}\n </div>\n\n <div className=\"mt-4 flex flex-wrap items-center justify-between gap-3\">\n {onDelete ? (\n <Button\n type=\"button\"\n variant=\"ghost\"\n onClick={() => {\n if (confirmDelete) {\n onDelete();\n } else {\n setConfirmDelete(true);\n }\n }}\n disabled={isSubmitting || isDeleting}\n className=\"text-destructive hover:bg-destructive/10 hover:text-destructive\"\n >\n <Trash2 className=\"size-4\" />\n {deleteButtonLabel}\n </Button>\n ) : (\n <span />\n )}\n <div className=\"flex items-center gap-3\">\n <Controller\n control={control}\n name=\"default\"\n render={({ field }) => (\n <div className=\"flex items-center gap-x-2\">\n <Checkbox\n id=\"set_as_default_address\"\n checked={field.value}\n onCheckedChange={(checked) =>\n field.onChange(checked === true)\n }\n disabled={isSubmitting || isDeleting}\n />\n <Label\n htmlFor=\"set_as_default_address\"\n className=\"text-sm font-normal\"\n >\n {t(\"set_as_default_address\")}\n </Label>\n </div>\n )}\n />\n\n <Button\n type=\"submit\"\n onClick={handleFormSubmit}\n disabled={isSubmitting || isDeleting}\n >\n {isSubmitting && (\n <div className=\"mr-2 size-4 animate-spin rounded-full border-2 border-current/30 border-t-current\" />\n )}\n {isSubmitting ? t(\"saving\") : t(\"save_address\")}\n </Button>\n </div>\n </div>\n\n {error && <div className=\"text-destructive mt-2 text-sm\">{error}</div>}\n </ResponsiveDialog>\n );\n}\n","import { useEffect, useRef, useState, useCallback } from \"react\";\nimport type { fluidPay } from \"@fluid-app/fluid-pay-core\";\n\nexport type VgsFieldState = {\n isFocused: boolean;\n isValid: boolean;\n isEmpty: boolean;\n cardType?: string;\n bin?: string;\n last4?: string;\n};\n\nexport type VgsFormState = {\n [key: string]: VgsFieldState;\n};\n\ninterface VGSCollectForm {\n setRouteId: (routeId: string) => void;\n field: (selector: string, config: Record<string, unknown>) => void;\n submit: (\n path: string,\n options: { headers?: Record<string, string> },\n successCallback: (\n status: number,\n response: fluidPay.VgsCollectSubmitResponse,\n ) => void,\n errorCallback: (errors: Record<string, string[]>) => void,\n ) => void;\n unmount: () => void;\n}\n\ninterface VGSCollectLibrary {\n create: (\n vaultId: string,\n environment: string,\n stateCallback: (state: Record<string, Partial<VgsFieldState>>) => void,\n ) => VGSCollectForm;\n}\n\nconst getVGSCollect = (): VGSCollectLibrary | null => {\n if (typeof window !== \"undefined\") {\n return (\n (window as unknown as { VGSCollect?: VGSCollectLibrary }).VGSCollect ||\n null\n );\n }\n return null;\n};\n\nconst DEFAULT_FIELD_STATE: VgsFormState = {\n card_number: { isFocused: false, isValid: false, isEmpty: true },\n card_exp: { isFocused: false, isValid: false, isEmpty: true },\n card_cvc: { isFocused: false, isValid: false, isEmpty: true },\n card_holder: { isFocused: false, isValid: false, isEmpty: true },\n};\n\nexport function useVgsCollect() {\n const [isFormReady, setIsFormReady] = useState(false);\n const [isLoading, setIsLoading] = useState(false);\n const [isScriptLoaded, setIsScriptLoaded] = useState(false);\n const [scriptLoadError, setScriptLoadError] = useState<string | undefined>(\n undefined,\n );\n\n const [vgsFieldState, setVgsFieldState] =\n useState<VgsFormState>(DEFAULT_FIELD_STATE);\n\n const formRef = useRef<VGSCollectForm | null>(null);\n const onSuccessRef = useRef<\n ((response: fluidPay.VgsCollectSubmitResponse) => void) | null\n >(null);\n const onErrorRef = useRef<((error: string) => void) | null>(null);\n\n // Load VGS Collect script\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n\n const vgsCollect = getVGSCollect();\n if (vgsCollect) {\n const timeoutId = window.setTimeout(() => {\n setIsScriptLoaded(true);\n }, 0);\n return () => window.clearTimeout(timeoutId);\n }\n\n if (isScriptLoaded) return;\n\n const script = document.createElement(\"script\");\n script.src =\n \"https://js.verygoodvault.com/vgs-collect/3.3.0/vgs-collect.js\";\n script.async = true;\n script.onload = () => setIsScriptLoaded(true);\n // Surface load failures both to a registered consumer (if any) and to\n // state, so a consumer mounting after the failure still sees it.\n script.onerror = () => {\n const message = \"Failed to load payment form\";\n setScriptLoadError(message);\n onErrorRef.current?.(message);\n };\n document.head.appendChild(script);\n }, [isScriptLoaded]);\n\n const updateFieldState = useCallback(\n (state: Record<string, Partial<VgsFieldState>>) => {\n if (!state) return;\n\n setVgsFieldState((prev) => {\n const newState: VgsFormState = { ...prev };\n let hasChanges = false;\n\n Object.keys(state).forEach((key) => {\n const field = state[key];\n if (!field) return;\n\n const next: VgsFieldState = {\n isFocused: !!field.isFocused,\n isValid: !!field.isValid,\n isEmpty: !!field.isEmpty,\n cardType: field.cardType,\n bin: field.bin,\n last4: field.last4,\n };\n\n if (\n !newState[key] ||\n JSON.stringify(newState[key]) !== JSON.stringify(next)\n ) {\n newState[key] = next;\n hasChanges = true;\n }\n });\n\n return hasChanges ? newState : prev;\n });\n },\n [],\n );\n\n const resetVgs = useCallback(() => {\n if (formRef.current) {\n try {\n formRef.current.unmount();\n } catch (e) {\n console.warn(\"VGS unmount error\", e);\n }\n formRef.current = null;\n }\n\n setIsFormReady(false);\n setVgsFieldState({ ...DEFAULT_FIELD_STATE });\n }, []);\n\n const initializeForm = useCallback(\n async (credentials: fluidPay.VaultResponse) => {\n if (!isScriptLoaded) return;\n\n const VGSCollect = getVGSCollect();\n if (!VGSCollect) {\n onErrorRef.current?.(\"Payment script not loaded\");\n return;\n }\n\n try {\n setIsLoading(true);\n\n const vgsEnvironment =\n credentials.vault.environment === \"sandbox\" ? \"sandbox\" : \"live-eu-1\";\n\n const form = VGSCollect.create(\n credentials.vault.vault_id,\n vgsEnvironment,\n (state) => updateFieldState(state),\n );\n\n if (credentials.vault.route_id) {\n form.setRouteId(credentials.vault.route_id);\n }\n\n formRef.current = form;\n\n // Wait for DOM elements\n let retries = 0;\n const maxRetries = 20;\n const retryDelay = 200;\n\n const waitForDom = async (): Promise<boolean> => {\n const allExist = [\n \"vgs-card-number\",\n \"vgs-expiration-date\",\n \"vgs-cvc\",\n \"vgs-card-holder\",\n ].every((id) => {\n const el = document.getElementById(id);\n return el && el.isConnected;\n });\n\n if (allExist) return true;\n if (retries >= maxRetries) return false;\n\n retries++;\n await new Promise((resolve) => setTimeout(resolve, retryDelay));\n return waitForDom();\n };\n\n const domReady = await waitForDom();\n if (!domReady) {\n throw new Error(\"Payment form elements not ready\");\n }\n\n // Resolve theme tokens from the wrapper element. The theme engine\n // applies `data-theme` on a subtree element (not <html>), so CSS\n // variables aren't visible on document.documentElement — only on a\n // node inside the themed subtree. Cross-origin iframe contents\n // can't see parent CSS variables, so we resolve concrete values\n // here and pass them to VGS.\n //\n // The `vgs-card-number` element is guaranteed to exist at this\n // point: the `waitForDom` check above blocks until all four VGS\n // wrapper elements are mounted. The hardcoded fallback colors only\n // activate if the CSS variables themselves are unset.\n const themedNode = document.getElementById(\"vgs-card-number\");\n const probeStyle = themedNode ? getComputedStyle(themedNode) : null;\n const foregroundColor =\n probeStyle?.getPropertyValue(\"--color-foreground\").trim() ||\n \"#0a0a0a\";\n const mutedForegroundColor =\n probeStyle?.getPropertyValue(\"--color-muted-foreground\").trim() ||\n \"#737373\";\n\n const css = {\n fontSize: \"16px\",\n fontFamily:\n \"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif\",\n color: foregroundColor,\n background: \"transparent\",\n paddingTop: \"0px\",\n paddingBottom: \"0px\",\n paddingLeft: \"0px\",\n paddingRight: \"0px\",\n boxSizing: \"border-box\",\n lineHeight: \"26px\",\n height: \"100%\",\n width: \"100%\",\n \"&::placeholder\": { color: mutedForegroundColor, opacity: 1 },\n \"&:focus\": { outline: \"none\" },\n };\n\n form.field(\"#vgs-card-number\", {\n type: \"card-number\",\n name: \"card_number\",\n placeholder: \"0000 0000 0000 0000\",\n showCardIcon: true,\n css: { ...css, paddingRight: \"40px\" },\n autoComplete: \"cc-number\",\n validations: [\"required\", \"validCardNumber\"],\n });\n\n form.field(\"#vgs-expiration-date\", {\n type: \"card-expiration-date\",\n name: \"card_exp\",\n yearLength: 2,\n placeholder: \"MM / YY\",\n css,\n autoComplete: \"cc-exp\",\n validations: [\"required\", \"validCardExpirationDate\"],\n });\n\n form.field(\"#vgs-cvc\", {\n type: \"card-security-code\",\n name: \"card_cvc\",\n placeholder: \"123\",\n css,\n autoComplete: \"cc-csc\",\n validations: [\"required\", \"validCardSecurityCode\"],\n });\n\n form.field(\"#vgs-card-holder\", {\n type: \"text\",\n name: \"card_holder\",\n placeholder: \"Full Name\",\n css,\n autoComplete: \"cc-name\",\n validations: [\"required\"],\n });\n\n setIsFormReady(true);\n } catch (error) {\n console.error(\"Failed to initialize VGS:\", error);\n onErrorRef.current?.(\"Failed to initialize payment form\");\n } finally {\n setIsLoading(false);\n }\n },\n [isScriptLoaded, updateFieldState],\n );\n\n const submitCard = useCallback(() => {\n if (!formRef.current) {\n onErrorRef.current?.(\"Form not initialized\");\n return;\n }\n\n formRef.current.submit(\n `/post`,\n {},\n (status: number, response: fluidPay.VgsCollectSubmitResponse) => {\n if (status >= 200 && status < 400) {\n onSuccessRef.current?.(response);\n } else {\n onErrorRef.current?.(\"Payment failed\");\n }\n },\n (errors: Record<string, string[]>) => {\n const allErrors = Object.values(errors)\n .flat()\n .filter(\n (msg) =>\n typeof msg === \"string\" &&\n msg.trim().length > 0 &&\n msg !== \"Required\",\n );\n\n const uniqueErrors = Array.from(new Set(allErrors));\n\n let errorMsg = \"Please verify your payment details.\";\n if (uniqueErrors.length > 0) {\n errorMsg = uniqueErrors.join(\", \");\n } else {\n const rawErrors = Object.values(errors).flat();\n if (rawErrors.length > 0) {\n errorMsg = \"Please fill in all required fields.\";\n }\n }\n\n onErrorRef.current?.(errorMsg);\n },\n );\n }, []);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n if (formRef.current) {\n try {\n formRef.current.unmount();\n } catch (e) {\n console.warn(\"VGS unmount error\", e);\n }\n formRef.current = null;\n }\n };\n }, []);\n\n return {\n isFormReady,\n isLoading,\n isScriptLoaded,\n scriptLoadError,\n initializeForm,\n submitCard,\n vgsFieldState,\n resetVgs,\n onSuccessRef,\n onErrorRef,\n };\n}\n","import {\n type JSX,\n type ReactNode,\n useCallback,\n useEffect,\n useMemo,\n useState,\n} from \"react\";\nimport { Controller } from \"react-hook-form\";\nimport { z } from \"zod\";\nimport {\n Button,\n Checkbox,\n Label,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n cn,\n useZodForm,\n} from \"@fluid-app/ui-primitives\";\nimport {\n ResponsiveDialog,\n type ResponsiveDialogPresentation,\n} from \"@fluid-app/ui-components/components/ResponsiveDialog\";\nimport type { fluidPay } from \"@fluid-app/fluid-pay-core\";\nimport { useFluidPayApi } from \"@fluid-app/fluid-pay-core\";\nimport {\n useVgsCollect,\n type VgsFieldState,\n type VgsFormState,\n} from \"../hooks/use-vgs-collect\";\n\nconst SENTINEL_CREATE_NEW = \"__create_new__\";\n\nconst formSchema = z.object({\n billing_address_selection: z\n .string()\n .refine((value) => value !== \"\" && value !== SENTINEL_CREATE_NEW, {\n message: \"Please select a billing address\",\n }),\n set_as_default: z.boolean(),\n});\n\ntype FormData = z.infer<typeof formSchema>;\n\nexport interface CreditCardFormSubmitData {\n set_as_default: boolean;\n payment_method: {\n token: string;\n cvv_token: string;\n exp_month: string;\n exp_year: string;\n card_holder: string;\n bin?: string;\n last_four?: string;\n card_network?: string;\n };\n billing_address_id: number;\n}\n\nexport interface RenderAddressFormDialogProps {\n isOpen: boolean;\n onClose: () => void;\n onAddressCreated: (address: fluidPay.CustomerAddress) => void;\n}\n\ninterface CreditCardFormDialogProps {\n isOpen: boolean;\n onClose: () => void;\n onSubmit: (data: CreditCardFormSubmitData) => void;\n isSubmitting: boolean;\n error?: string;\n jwt: string;\n /** When provided, adds a top \"Same as shipping\" option referencing this address. */\n shippingAddress?: fluidPay.CustomerAddress | null;\n /** Saved customer addresses populating the dropdown. */\n savedAddresses?: fluidPay.CustomerAddress[];\n /** ID of the customer's preferred billing address; used to pre-select. */\n defaultBillingAddressId?: number;\n /**\n * Render-prop slot for AddressFormDialog. The host wires the dialog so this\n * component doesn't import it directly, keeping the address-create flow's\n * data plumbing (mutations, error toasts) under host control.\n */\n renderAddressFormDialog?: (props: RenderAddressFormDialogProps) => ReactNode;\n t: (key: string) => string;\n presentation?: ResponsiveDialogPresentation;\n}\n\nfunction VgsInputWrapper({\n id,\n label,\n fieldState,\n className,\n}: {\n id: string;\n label: string;\n fieldState?: VgsFieldState;\n className?: string;\n}) {\n const isInvalid =\n fieldState?.isValid === false &&\n !fieldState?.isFocused &&\n !fieldState?.isEmpty;\n const isFocused = !!fieldState?.isFocused;\n\n return (\n <div\n id={id}\n role=\"group\"\n aria-label={label}\n data-invalid={isInvalid ? \"\" : undefined}\n className={cn(\n \"border-input selection:bg-primary selection:text-primary-foreground file:text-foreground placeholder:text-muted-foreground h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm\",\n \"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]\",\n \"data-[invalid]:border-destructive data-[invalid]:ring-destructive/20\",\n \"[&_iframe]:block! [&_iframe]:h-full! [&_iframe]:w-full! [&_iframe]:border-0!\",\n isFocused && \"border-ring ring-ring/50 ring-[3px]\",\n isFocused && isInvalid && \"border-destructive ring-destructive/20\",\n className,\n )}\n />\n );\n}\n\nfunction VgsCardForm({\n vgsFieldState,\n networkError,\n}: {\n vgsFieldState: VgsFormState;\n networkError?: string;\n}) {\n return (\n <div className=\"space-y-4\" aria-label=\"Credit card form\">\n <VgsInputWrapper\n id=\"vgs-card-number\"\n label=\"Card number\"\n fieldState={vgsFieldState[\"card_number\"]}\n />\n\n <div className=\"flex gap-3\">\n <div className=\"min-w-0 flex-1\">\n <VgsInputWrapper\n id=\"vgs-expiration-date\"\n label=\"Expiration date\"\n fieldState={vgsFieldState[\"card_exp\"]}\n />\n </div>\n <div className=\"min-w-0 flex-1\">\n <VgsInputWrapper\n id=\"vgs-cvc\"\n label=\"CVC\"\n fieldState={vgsFieldState[\"card_cvc\"]}\n />\n </div>\n </div>\n\n <VgsInputWrapper\n id=\"vgs-card-holder\"\n label=\"Cardholder name\"\n fieldState={vgsFieldState[\"card_holder\"]}\n />\n\n {networkError && networkError.trim().length > 0 && (\n <div className=\"bg-destructive/10 text-destructive rounded-md p-3 text-sm\">\n {networkError}\n </div>\n )}\n </div>\n );\n}\n\nfunction formatAddressOneLine(addr: fluidPay.CustomerAddress): string {\n const cityStateZip = [addr.city, addr.state, addr.postal_code]\n .filter((p): p is string => Boolean(p && p.trim().length > 0))\n .join(\", \");\n const parts = [\n addr.address1,\n addr.address2,\n cityStateZip,\n addr.country_code,\n ].filter((p): p is string => Boolean(p && p.trim().length > 0));\n return parts.join(\" • \");\n}\n\nfunction AddressSummaryCard({\n address,\n}: {\n address: fluidPay.CustomerAddress;\n}) {\n return (\n <div className=\"border-input bg-muted/30 rounded-md border p-3 text-sm break-words\">\n {address.name && <div className=\"font-medium\">{address.name}</div>}\n <div className=\"text-muted-foreground\">{address.address1}</div>\n {address.address2 && (\n <div className=\"text-muted-foreground\">{address.address2}</div>\n )}\n <div className=\"text-muted-foreground\">\n {[address.city, address.state].filter(Boolean).join(\", \")}\n {address.postal_code ? ` ${address.postal_code}` : \"\"}\n </div>\n {address.country_code && (\n <div className=\"text-muted-foreground\">{address.country_code}</div>\n )}\n </div>\n );\n}\n\nexport default function CreditCardFormDialog({\n isOpen,\n onClose,\n onSubmit,\n isSubmitting,\n error,\n jwt,\n shippingAddress,\n savedAddresses = [],\n defaultBillingAddressId,\n renderAddressFormDialog,\n t,\n presentation = \"dialog\",\n}: CreditCardFormDialogProps): JSX.Element {\n const api = useFluidPayApi();\n const [cardError, setCardError] = useState<string | undefined>(undefined);\n const [isVgsSubmitting, setIsVgsSubmitting] = useState(false);\n const [createdAddresses, setCreatedAddresses] = useState<\n fluidPay.CustomerAddress[]\n >([]);\n const [isAddressDialogOpen, setIsAddressDialogOpen] = useState(false);\n\n const {\n isFormReady,\n isLoading: isVgsLoading,\n isScriptLoaded,\n scriptLoadError,\n initializeForm,\n submitCard,\n vgsFieldState,\n resetVgs,\n onSuccessRef,\n onErrorRef,\n } = useVgsCollect();\n\n const shippingId = shippingAddress?.id ?? null;\n const dedupedSavedAddresses = useMemo(\n () =>\n shippingId === null\n ? savedAddresses\n : savedAddresses.filter((a) => a.id !== shippingId),\n [savedAddresses, shippingId],\n );\n\n const allAddresses = useMemo<fluidPay.CustomerAddress[]>(() => {\n const list: fluidPay.CustomerAddress[] = [];\n if (shippingAddress) list.push(shippingAddress);\n list.push(...dedupedSavedAddresses);\n list.push(...createdAddresses);\n return list;\n }, [shippingAddress, dedupedSavedAddresses, createdAddresses]);\n\n const hasRealAddresses = allAddresses.length > 0;\n\n // Default selection per ticket: shipping → default billing → first saved → \"use different\".\n const initialSelection = useMemo<string>(() => {\n if (shippingAddress) return shippingAddress.id.toString();\n if (\n defaultBillingAddressId &&\n dedupedSavedAddresses.some((a) => a.id === defaultBillingAddressId)\n ) {\n return defaultBillingAddressId.toString();\n }\n const first = dedupedSavedAddresses[0];\n if (first) return first.id.toString();\n return SENTINEL_CREATE_NEW;\n }, [shippingAddress, defaultBillingAddressId, dedupedSavedAddresses]);\n\n const { control, handleSubmit, reset, setValue, watch } =\n useZodForm<FormData>(formSchema, {\n defaultValues: {\n billing_address_selection: initialSelection,\n set_as_default: false,\n },\n });\n\n // Reset the form whenever the dialog (re)opens or the upstream address list\n // changes — the initial selection depends on shipping/saved/default props.\n useEffect(() => {\n if (isOpen) {\n reset({\n billing_address_selection: initialSelection,\n set_as_default: false,\n });\n setCreatedAddresses([]);\n }\n }, [isOpen, initialSelection, reset]);\n\n const currentSelection = watch(\"billing_address_selection\");\n\n const selectedAddress = useMemo(() => {\n if (!currentSelection || currentSelection === SENTINEL_CREATE_NEW) {\n return null;\n }\n const id = Number(currentSelection);\n if (!Number.isFinite(id)) return null;\n return allAddresses.find((a) => a.id === id) ?? null;\n }, [currentSelection, allAddresses]);\n\n const selectOptions = useMemo(() => {\n const options: { name: string; value: string }[] = [];\n if (shippingAddress) {\n options.push({\n name: t(\"same_as_shipping\"),\n value: shippingAddress.id.toString(),\n });\n }\n for (const addr of dedupedSavedAddresses) {\n options.push({\n name: formatAddressOneLine(addr),\n value: addr.id.toString(),\n });\n }\n for (const addr of createdAddresses) {\n options.push({\n name: formatAddressOneLine(addr),\n value: addr.id.toString(),\n });\n }\n options.push({\n name: t(\"use_a_different_address\"),\n value: SENTINEL_CREATE_NEW,\n });\n return options;\n }, [shippingAddress, dedupedSavedAddresses, createdAddresses, t]);\n\n const handleSelectionChange = useCallback(\n (value: string) => {\n if (value === SENTINEL_CREATE_NEW) {\n // Don't commit the sentinel to form state — opening the sub-modal is\n // the action. The form's previous selection remains intact so closing\n // the sub-modal without saving leaves the dropdown unchanged.\n setIsAddressDialogOpen(true);\n return;\n }\n setValue(\"billing_address_selection\", value, { shouldValidate: true });\n },\n [setValue],\n );\n\n const handleAddressCreated = useCallback(\n (address: fluidPay.CustomerAddress) => {\n setCreatedAddresses((list) => [...list, address]);\n setValue(\"billing_address_selection\", address.id.toString(), {\n shouldValidate: true,\n });\n setIsAddressDialogOpen(false);\n },\n [setValue],\n );\n\n const handleVgsSuccess = useCallback(\n (response: fluidPay.VgsCollectSubmitResponse) => {\n const expValue = response?.card_exp;\n if (!expValue) {\n setCardError(\"Missing expiration date from payment form\");\n setIsVgsSubmitting(false);\n return;\n }\n\n const cleanExp = expValue.replace(/\\s+/g, \"\");\n const [expMonth, expYearShort] = cleanExp.split(\"/\");\n\n if (!expMonth || !expYearShort) {\n setCardError(\"Invalid expiration date format\");\n setIsVgsSubmitting(false);\n return;\n }\n\n const expYear =\n expYearShort.length === 2 ? `20${expYearShort}` : expYearShort;\n\n const cardholderName = response?.card_holder?.trim();\n if (!cardholderName) {\n setCardError(\"Cardholder name is required\");\n setIsVgsSubmitting(false);\n return;\n }\n\n handleSubmit(\n (formData) => {\n const billingAddressId = Number(formData.billing_address_selection);\n if (!Number.isFinite(billingAddressId)) {\n setCardError(\"Please select a billing address.\");\n setIsVgsSubmitting(false);\n return;\n }\n\n const cardMeta = vgsFieldState[\"card_number\"];\n onSubmit({\n set_as_default: formData.set_as_default,\n payment_method: {\n token: response.card_number,\n cvv_token: response.card_cvc,\n exp_month: expMonth,\n exp_year: expYear,\n card_holder: cardholderName,\n ...(cardMeta?.bin ? { bin: cardMeta.bin } : {}),\n ...(cardMeta?.last4 ? { last_four: cardMeta.last4 } : {}),\n ...(cardMeta?.cardType\n ? { card_network: cardMeta.cardType }\n : {}),\n },\n billing_address_id: billingAddressId,\n });\n setIsVgsSubmitting(false);\n },\n () => {\n setCardError(\"Please select a billing address.\");\n setIsVgsSubmitting(false);\n },\n )();\n },\n [handleSubmit, onSubmit, vgsFieldState],\n );\n\n const handleVgsError = useCallback((err: string) => {\n setCardError(err);\n setIsVgsSubmitting(false);\n }, []);\n\n useEffect(() => {\n onSuccessRef.current = handleVgsSuccess;\n onErrorRef.current = handleVgsError;\n }, [handleVgsSuccess, handleVgsError, onSuccessRef, onErrorRef]);\n\n useEffect(() => {\n if (!isOpen || !isScriptLoaded) return;\n\n let cancelled = false;\n\n const init = async () => {\n try {\n const credentials = await api.vault.fetchCredentials(jwt);\n if (!cancelled) {\n await initializeForm(credentials);\n }\n } catch (err) {\n console.error(\"Failed to fetch vault credentials:\", err);\n if (!cancelled) {\n setCardError(\"Failed to initialize payment form\");\n }\n }\n };\n\n init();\n\n return () => {\n cancelled = true;\n };\n }, [isOpen, isScriptLoaded, jwt, api, initializeForm]);\n\n const handleClose = () => {\n resetVgs();\n reset();\n setCardError(undefined);\n setIsVgsSubmitting(false);\n setIsAddressDialogOpen(false);\n onClose();\n };\n\n const handleFormSubmit = handleSubmit(() => {\n setIsVgsSubmitting(true);\n setCardError(undefined);\n submitCard();\n });\n\n const isBusy = isSubmitting || isVgsSubmitting;\n\n return (\n <>\n <ResponsiveDialog\n open={isOpen}\n onOpenChange={(open) => !open && handleClose()}\n title={t(\"add_credit_card\")}\n presentation={presentation}\n size=\"wide\"\n >\n <div className=\"relative min-w-0 pt-1\">\n {(isVgsLoading || !isFormReady) && !scriptLoadError && (\n <div className=\"bg-background/80 absolute inset-0 z-10 flex items-center justify-center rounded backdrop-blur-[1px]\">\n <div className=\"flex items-center justify-center\">\n <div className=\"border-primary mr-3 size-5 animate-spin rounded-full border-2 border-t-2 border-t-transparent\" />\n <p className=\"text-muted-foreground text-sm font-medium\">\n {t(\"securing\")}\n </p>\n </div>\n </div>\n )}\n <div className=\"space-y-4\">\n <VgsCardForm\n vgsFieldState={vgsFieldState}\n networkError={cardError ?? scriptLoadError ?? error}\n />\n\n <div className=\"space-y-3 pt-2\">\n <h3 className=\"text-muted-foreground text-sm font-medium\">\n {t(\"billing_address\")}\n </h3>\n {hasRealAddresses ? (\n <Controller\n control={control}\n name=\"billing_address_selection\"\n render={({\n field: { value },\n fieldState: { error: fieldError },\n }) => (\n <div className=\"space-y-1\">\n <Label\n htmlFor=\"billing-address-selection\"\n className=\"mb-1.5 block text-sm font-medium\"\n >\n {t(\"billing_address\")}\n </Label>\n <Select\n value={value}\n onValueChange={handleSelectionChange}\n disabled={isBusy}\n >\n <SelectTrigger\n id=\"billing-address-selection\"\n aria-invalid={!!fieldError}\n className=\"w-full min-w-0 [&>span]:block! [&>span]:min-w-0 [&>span]:truncate\"\n >\n <SelectValue placeholder={t(\"select_an_option\")} />\n </SelectTrigger>\n <SelectContent>\n {selectOptions.map((opt) => (\n <SelectItem\n key={opt.value}\n value={opt.value}\n // Radix Select fires onValueChange only when the value\n // *changes*. Picking the already-selected sentinel\n // would otherwise be a no-op, leaving the user with\n // no way to reopen the address form.\n onClick={\n opt.value === SENTINEL_CREATE_NEW\n ? () => setIsAddressDialogOpen(true)\n : undefined\n }\n >\n {opt.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n {fieldError?.message && (\n <p className=\"text-destructive text-sm\">\n {fieldError.message}\n </p>\n )}\n </div>\n )}\n />\n ) : (\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => setIsAddressDialogOpen(true)}\n disabled={isBusy}\n className=\"w-full\"\n >\n {t(\"add_billing_address\")}\n </Button>\n )}\n\n {selectedAddress && (\n <AddressSummaryCard address={selectedAddress} />\n )}\n </div>\n </div>\n\n <div className=\"mt-4 flex items-center justify-between\">\n <Controller\n control={control}\n name=\"set_as_default\"\n render={({ field }) => (\n <div className=\"flex items-center gap-x-2\">\n <Checkbox\n id=\"set_as_default_cc\"\n checked={field.value}\n onCheckedChange={(checked) =>\n field.onChange(checked === true)\n }\n disabled={isBusy}\n />\n <Label\n htmlFor=\"set_as_default_cc\"\n className=\"text-sm font-normal\"\n >\n {t(\"set_as_default_payment_method\")}\n </Label>\n </div>\n )}\n />\n\n <Button type=\"button\" onClick={handleFormSubmit} disabled={isBusy}>\n {isBusy && (\n <div className=\"mr-2 size-4 animate-spin rounded-full border-2 border-current/30 border-t-current\" />\n )}\n {isBusy ? t(\"saving\") : t(\"save_card\")}\n </Button>\n </div>\n </div>\n </ResponsiveDialog>\n\n {renderAddressFormDialog?.({\n isOpen: isAddressDialogOpen,\n onClose: () => setIsAddressDialogOpen(false),\n onAddressCreated: handleAddressCreated,\n })}\n </>\n );\n}\n","import { useEffect, useMemo, useRef } from \"react\";\n\nimport { Lock } from \"lucide-react\";\n\nimport { Dialog, DialogContent, DialogTitle } from \"@fluid-app/ui-primitives\";\n\n/** Display strings for the modal chrome — injected by the host app so the\n * package stays translation-system agnostic. */\nexport interface VgsThreeDSModalLabels {\n title: string;\n cancel: string;\n timedOut: string;\n stillWorking: string;\n dontRefresh: string;\n}\n\nexport interface VgsThreeDSModalProps {\n isOpen: boolean;\n challengeHtml: string;\n challengeUrl?: string;\n onClose: (error?: string) => void;\n labels: VgsThreeDSModalLabels;\n}\n\nfunction escapeAttr(s: string | null): string {\n return (s ?? \"\")\n .replace(/&/g, \"&\")\n .replace(/\"/g, \""\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\");\n}\n\n/**\n * Parse the challenge HTML to extract the form action URL and hidden fields.\n * This lets us POST directly to the bank ACS, bypassing intermediary pages\n * (e.g. Entersekt's red.js auto-submit) that cause extra iframe loads.\n */\nfunction parseDirectPostHtml(\n challengeHtml: string,\n challengeUrl?: string,\n): string | null {\n try {\n const parser = new DOMParser();\n const doc = parser.parseFromString(challengeHtml, \"text/html\");\n const form = doc.querySelector(\"form\");\n if (!form) return null;\n\n const action = challengeUrl || form.getAttribute(\"action\");\n if (!action) return null;\n\n const hiddenInputs = form.querySelectorAll('input[type=\"hidden\"]');\n if (hiddenInputs.length === 0) return null;\n\n const fieldsHtml = Array.from(hiddenInputs)\n .map(\n (input) =>\n `<input type=\"hidden\" name=\"${escapeAttr(input.getAttribute(\"name\"))}\" value=\"${escapeAttr(input.getAttribute(\"value\"))}\">`,\n )\n .join(\"\\n\");\n\n return `<!DOCTYPE html>\n<html>\n<body>\n<form id=\"acsForm\" method=\"POST\" action=\"${escapeAttr(action)}\">\n${fieldsHtml}\n</form>\n<script>document.getElementById(\"acsForm\").submit();</script>\n</body>\n</html>`;\n } catch {\n return null;\n }\n}\n\n/**\n * Pure iframe container for the 3DS challenge.\n *\n * The modal does NOT try to detect challenge completion via load-counting or\n * postMessage — that was fragile across different bank ACS implementations.\n * Instead, `useVgs3DSCompletion` subscribes to the realtime transport as soon\n * as the modal opens and receives the authoritative result from the backend.\n *\n * This modal only handles:\n * - Rendering the ACS challenge iframe\n * - User cancellation (Cancel button in header band)\n * - Hard timeout (6.5 min) as a safety net\n */\nexport function VgsThreeDSModal({\n isOpen,\n challengeHtml,\n challengeUrl,\n onClose,\n labels,\n}: VgsThreeDSModalProps) {\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const onCloseRef = useRef(onClose);\n // Capture labels in a ref so the timeout effect can read the current\n // translation without depending on labels in its deps array (host apps\n // typically build the labels object inline per render and would otherwise\n // reset the timer on every re-render).\n const labelsRef = useRef(labels);\n\n useEffect(() => {\n onCloseRef.current = onClose;\n });\n\n useEffect(() => {\n labelsRef.current = labels;\n });\n\n // Build a direct-POST page that skips intermediary auto-redirect pages.\n // Falls back to the original challengeHtml if parsing fails.\n const iframeSrcDoc = useMemo(\n () => parseDirectPostHtml(challengeHtml, challengeUrl) ?? challengeHtml,\n [challengeHtml, challengeUrl],\n );\n\n // Hard timeout — aligned just past the backend safety-net boundary (~6:00)\n // so the cart poll surfaces the backend's verdict (accurate decline,\n // rescued approval, or TIMEOUT) before the modal gives up at 6.5 min.\n // (The old comment attributed the 5-minute value to the EMVCo spec;\n // EMVCo leaves challenge-timeout handling to the ACS/issuer — the real\n // constraint is our own safety-net boundary.) Depends only on isOpen so\n // the timer resets on open, not on content change.\n useEffect(() => {\n if (!isOpen) return;\n\n const timeoutId = setTimeout(() => {\n onCloseRef.current(labelsRef.current.timedOut);\n }, 390_000);\n\n return () => {\n clearTimeout(timeoutId);\n };\n }, [isOpen]);\n\n const handleCancel = () => {\n onClose();\n };\n\n return (\n <Dialog open={isOpen} onOpenChange={handleCancel}>\n {/* z-[110]: a bank challenge must never be occluded by host chrome.\n Card-add surfaces launch this modal from a dialog that pins its\n content at z-[100] (fluid-checkout's credit-card dialog), where the\n default z-50 + DOM-order stacking would paint the host dialog on\n top of the challenge — and Radix would inert it underneath. */}\n <DialogContent\n className=\"z-[110] h-[600px] max-w-2xl p-0 sm:max-w-2xl\"\n overlayClassName=\"z-[110]\"\n showCloseButton={false}\n >\n <div className=\"flex h-full w-full flex-col\">\n {/* Header band — replaces VisuallyHidden DialogTitle */}\n <div className=\"flex items-center justify-between border-b border-gray-200 px-4 py-3\">\n <div className=\"flex items-center gap-2\">\n <Lock className=\"h-4 w-4 text-gray-600\" aria-hidden=\"true\" />\n <DialogTitle className=\"text-sm font-semibold text-gray-900\">\n {labels.title}\n </DialogTitle>\n </div>\n <button\n type=\"button\"\n onClick={handleCancel}\n className=\"rounded text-xs text-indigo-600 hover:text-indigo-700 focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2 focus-visible:outline-none\"\n >\n {labels.cancel}\n </button>\n </div>\n\n {/* Iframe (unchanged behavior). */}\n <div className=\"relative flex-1\">\n {challengeHtml && (\n <iframe\n ref={iframeRef}\n srcDoc={iframeSrcDoc}\n className=\"h-full w-full border-0\"\n title=\"VGS 3DS Challenge\"\n sandbox=\"allow-same-origin allow-scripts allow-forms allow-top-navigation allow-popups\"\n />\n )}\n </div>\n\n {/* Footer band — indeterminate progress + status caption + tab-refresh hint */}\n <div className=\"border-t border-gray-200 px-4 py-3\">\n <div\n data-testid=\"threeds-progress-bar\"\n role=\"progressbar\"\n aria-label={labels.stillWorking}\n className=\"relative h-1 overflow-hidden rounded-full bg-indigo-100\"\n >\n <div className=\"threeds-progress-pill absolute top-0 h-full w-[30%] rounded-full bg-indigo-500\" />\n </div>\n <div className=\"mt-2 flex items-center justify-between text-xs\">\n <span className=\"text-gray-600\">{labels.stillWorking}</span>\n <span className=\"text-gray-400\">{labels.dontRefresh}</span>\n </div>\n </div>\n </div>\n </DialogContent>\n </Dialog>\n );\n}\n\nexport default VgsThreeDSModal;\n","// Pure attempt-scoping predicate shared by the poll and Pusher paths of\n// useVgs3DSCompletion. Presence-guarded on BOTH sides: when either the\n// active attempt key or the result's key is missing (backend not yet\n// deployed, old event shape), the result is honored — exactly today's\n// unscoped behavior.\nexport function belongsToActiveAttempt(\n activeMerchantTxId: string | undefined,\n resultMerchantTxId: string | undefined,\n): boolean {\n if (!activeMerchantTxId || !resultMerchantTxId) return true;\n return resultMerchantTxId === activeMerchantTxId;\n}\n","import { useEffect, useEffectEvent, useRef } from \"react\";\nimport type { ThreeDSStatus } from \"@fluid-app/fluid-pay-core/types\";\nimport { belongsToActiveAttempt } from \"./three-ds-attempt\";\n\nexport interface Vgs3DSCompletionResult {\n success: boolean;\n transactionId: string;\n status?: string;\n}\n\nexport interface Vgs3DSChallengeEvent {\n xid: string;\n /** Optional for backward compatibility: older events may omit it, and the\n * attempt-scoping guard deliberately honors key-less events. */\n merchant_transaction_id?: string;\n status: \"success\" | \"failed\";\n challenge_status?: string;\n error_message?: string;\n}\n\n/** Minimal structural slice of a realtime channel — pusher-js's `Channel`\n * satisfies this as-is (its `bind`/`unbind` return `Channel`, which is\n * assignable to a `void`-returning method). */\nexport interface ThreeDsRealtimeChannel {\n bind(eventName: string, handler: (data: Vgs3DSChallengeEvent) => void): void;\n unbind(\n eventName: string,\n handler: (data: Vgs3DSChallengeEvent) => void,\n ): void;\n}\n\n/** Transport abstraction for the fast path — the app's `pusherClient`\n * satisfies this structurally with no adapter. */\nexport interface ThreeDsRealtimeTransport {\n subscribe(channelName: string): ThreeDsRealtimeChannel | null;\n unsubscribe(channelName: string): void;\n}\n\ninterface UseVgs3DSCompletionOptions {\n /** Realtime channel carrying the `vgs_3ds_challenge` event\n * (e.g. `private-cart-{cartToken}`). */\n channelName: string;\n transport: ThreeDsRealtimeTransport;\n /** Status poll — the reliable fallback alongside the realtime fast path. */\n checkStatus: () => Promise<ThreeDSStatus | null>;\n onComplete: (result: Vgs3DSCompletionResult) => void;\n onError: (error: string) => void;\n /** Subscribe to the realtime channel and start polling when true (i.e. when the 3DS modal is open). */\n enabled?: boolean;\n /** The active attempt's merchant_tx_id — when present, completion signals\n * for any OTHER attempt are ignored (stale metadata, late webhooks). */\n merchantTxId?: string;\n /** Called when the attempt was canceled (e.g. from another tab) — a quiet,\n * no-error terminal. */\n onCanceled?: () => void;\n}\n\n// Poll interval and timeout for the status-poll fallback.\n// Polling at 3-second intervals is the reliable secondary check alongside\n// the Pusher fast path (the backend broadcasts the result immediately).\n// The 6.5-minute timeout sits past the backend safety-net boundary (~6:00),\n// so the poll surfaces the backend's verdict — accurate decline, rescued\n// approval, or TIMEOUT — instead of the frontend self-declaring first.\nconst POLL_INTERVAL_MS = 3_000;\nconst TIMEOUT_MS = 390_000;\n\n/**\n * Subscribes to the realtime transport and polls the injected status check\n * for the 3DS challenge result.\n *\n * Activated by `enabled` — pass `vgsThreeDSModal.isOpen` so the subscription\n * starts as soon as the challenge modal opens. No URL-param dance needed.\n */\nexport function useVgs3DSCompletion({\n channelName,\n transport,\n checkStatus,\n onComplete,\n onError,\n enabled = false,\n merchantTxId,\n onCanceled,\n}: UseVgs3DSCompletionOptions) {\n const hasHandledRef = useRef(false);\n const isSubscribedRef = useRef(false);\n\n // Kept current via a per-render effect so an inline `transport` value at\n // the call site never retriggers the main effect.\n const transportRef = useRef(transport);\n useEffect(() => {\n transportRef.current = transport;\n });\n\n const handleComplete = useEffectEvent((result: Vgs3DSCompletionResult) => {\n onComplete(result);\n });\n\n const handleError = useEffectEvent((error: string) => {\n onError(error);\n });\n\n const handleCanceled = useEffectEvent(() => {\n onCanceled?.();\n });\n\n // Non-reactive wrapper so an inline `checkStatus` closure at the call site\n // never retriggers the main effect. Called from the poll during the active\n // phase only — never from cleanup.\n const performStatusCheck = useEffectEvent(() => checkStatus());\n\n // Shared handler for Pusher events, polling results, and timeout.\n // hasHandledRef ensures only the first source to resolve wins.\n const handleResult = useEffectEvent(\n (result: {\n status: \"success\" | \"failed\";\n errorMessage?: string;\n transactionId?: string;\n }) => {\n if (hasHandledRef.current) return;\n hasHandledRef.current = true;\n\n if (result.status === \"success\") {\n handleComplete({\n success: true,\n transactionId: result.transactionId ?? \"\",\n status: result.status,\n });\n } else {\n handleError(result.errorMessage || \"3DS verification failed\");\n }\n },\n );\n\n // Reset handled flag when enabled toggles off (modal closed / new attempt).\n useEffect(() => {\n if (!enabled && hasHandledRef.current) {\n hasHandledRef.current = false;\n }\n }, [enabled]);\n\n useEffect(() => {\n if (!enabled || !channelName || hasHandledRef.current) {\n return;\n }\n\n if (isSubscribedRef.current) {\n return;\n }\n\n let cancelled = false;\n // Captured ONCE so subscribe and the cleanup's unsubscribe use the same\n // transport object even if a different one is passed mid-flight.\n const activeTransport = transportRef.current;\n\n isSubscribedRef.current = true;\n const channel = activeTransport.subscribe(channelName);\n const hasPusher = !!channel;\n\n if (!hasPusher) {\n console.error(\n \"[VGS 3DS] Pusher subscribe returned null — using status polling only\",\n );\n isSubscribedRef.current = false;\n // intentionally NOT returning — polling + timeout below are the fallback\n }\n\n // --- Fast path: Pusher event ---\n const handleVgs3DSChallenge = (data: Vgs3DSChallengeEvent) => {\n if (cancelled) return;\n\n // Attempt-scoping: ignore events for a different (older) attempt.\n if (!belongsToActiveAttempt(merchantTxId, data.merchant_transaction_id)) {\n return;\n }\n\n handleResult({\n status: data.status,\n errorMessage: data.error_message,\n transactionId: data.merchant_transaction_id,\n });\n };\n\n if (hasPusher) {\n channel.bind(\"vgs_3ds_challenge\", handleVgs3DSChallenge);\n }\n\n // --- Reliable fallback: poll the injected status check ---\n const pollInterval = setInterval(async () => {\n if (hasHandledRef.current || cancelled) return;\n\n const status = await performStatusCheck();\n if (cancelled || !status) return;\n\n // Attempt-scoping: stale metadata from a previous attempt must not\n // resolve this modal (the backend wipes per-attempt keys on re-init,\n // but a late webhook can still land mid-retry).\n if (!belongsToActiveAttempt(merchantTxId, status.merchantTxId)) {\n return;\n }\n\n if (status.completed) {\n handleResult({ status: \"success\" });\n } else if (status.failed) {\n handleResult({\n status: \"failed\",\n errorMessage:\n status.errorMessage ||\n `3DS verification ${status.status || \"failed\"}`,\n });\n } else if (status.canceled) {\n // Canceled (possibly from another tab): quiet no-error terminal.\n if (!hasHandledRef.current) {\n hasHandledRef.current = true;\n handleCanceled();\n }\n }\n }, POLL_INTERVAL_MS);\n\n // --- Safety net: hard timeout ---\n const timeout = setTimeout(() => {\n if (hasHandledRef.current || cancelled) return;\n\n console.error(\"[VGS 3DS] Timed out waiting for 3DS result\");\n handleResult({\n status: \"failed\",\n errorMessage: \"Payment verification timed out. Please try again.\",\n });\n }, TIMEOUT_MS);\n\n // Cleanup — cancelled flag prevents in-flight polls from calling handleResult\n return () => {\n cancelled = true;\n clearTimeout(timeout);\n clearInterval(pollInterval);\n if (hasPusher) {\n channel.unbind(\"vgs_3ds_challenge\", handleVgs3DSChallenge);\n activeTransport.unsubscribe(channelName);\n }\n isSubscribedRef.current = false;\n };\n }, [enabled, channelName, merchantTxId]);\n}\n","import { z } from \"zod\";\n\nexport const browserInfoSchema = z.object({\n color_depth: z.number().optional(),\n screen_height: z.number().optional(),\n screen_width: z.number().optional(),\n time_zone: z.number().optional(),\n java_enabled: z.boolean().optional(),\n java_script_enabled: z.boolean().optional(),\n language: z.string().optional(),\n user_agent: z.string().optional(),\n accept_header: z.string().optional(),\n});\n\nexport type BrowserInfo = z.infer<typeof browserInfoSchema>;\n\nexport function getBrowserInfo(): BrowserInfo | undefined {\n // Check if we're in a browser environment\n if (typeof window === \"undefined\") {\n console.warn(\"getBrowserInfo called in non-browser environment\");\n return undefined;\n }\n\n try {\n const { screen, navigator } = window;\n\n // Validate that we have the required objects\n if (!screen || !navigator) {\n console.warn(\"Missing screen or navigator objects\");\n return undefined;\n }\n\n const browserInfo: BrowserInfo = {\n color_depth: screen.colorDepth || undefined,\n screen_height: screen.height || undefined,\n screen_width: screen.width || undefined,\n time_zone: new Date().getTimezoneOffset(),\n java_enabled:\n typeof navigator.javaEnabled === \"function\"\n ? navigator.javaEnabled()\n : false,\n java_script_enabled: true,\n language: navigator.language || undefined,\n user_agent: navigator.userAgent || undefined,\n accept_header: \"*/*\",\n };\n\n // Validate that we have at least some essential info\n if (\n !browserInfo.screen_height ||\n !browserInfo.screen_width ||\n !browserInfo.user_agent\n ) {\n console.warn(\"Missing essential browser info fields\");\n }\n\n return browserInfo;\n } catch (error) {\n console.error(\"Error getting browser info:\", error);\n return undefined;\n }\n}\n","/**\n * TypeScript interfaces for portal-tenant pay management.\n * These types mirror the portal-tenant BFF `/api/pay/*` endpoints.\n * Packages import from here instead of from any concrete API client.\n */\n\nimport type { ResponseMeta } from \"./fluidos-api\";\n\n// ---------------------------------------------------------------------------\n// Address\n// ---------------------------------------------------------------------------\n\nexport interface PayAddress {\n id: number;\n name: string | null;\n street1: string;\n street2: string | null;\n city: string;\n state: string;\n zip: string;\n country: string;\n phone?: string | null;\n default: boolean;\n created_at: string | null;\n updated_at: string | null;\n}\n\nexport interface CreateAddressBody {\n address: {\n name?: string | null;\n street1: string;\n street2?: string | null;\n city: string;\n state: string;\n zip: string;\n country: string;\n phone?: string | null;\n default?: boolean;\n };\n}\n\n// ---------------------------------------------------------------------------\n// Payment method\n// ---------------------------------------------------------------------------\n\nexport interface PayPaymentMethod {\n id: number;\n type: string;\n brand: string | null;\n last_four: string;\n logo_url: string | null;\n exp_month: number | null;\n exp_year: number | null;\n card_holder: string | null;\n default: boolean;\n billing_address: PayAddress | null;\n created_at: string | null;\n updated_at: string | null;\n}\n\nexport const TOKEN_PROVIDER_VGS = \"vgs\" as const;\n\n// Body for POST /api/pay/payment_methods on the portal-tenant BFF.\n//\n// Note: the BFF always creates the PM with customer scope\n// (PaymentMethodCreator hardcodes set_customer_payment_method: true on its\n// way into the FluidPay action), so PMs created via this body are always\n// immediately referenceable from customer.payment_methods — no need to\n// expose set_customer_payment_method to the client. The checkout app's\n// direct /fluid_pay/create_payment_method route exposes it because that\n// route does not have the same default.\nexport interface CreatePaymentMethodBody {\n payment_method: {\n type: \"card\";\n token: string;\n token_provider?: string;\n exp_month: string;\n exp_year: string;\n cvv_token?: string;\n card_holder?: string;\n default?: boolean;\n bin?: string;\n last_four?: string;\n card_network?: string;\n };\n billing_address_id: number;\n // `| null` mirrors the OpenAPI contract / generated client so callers can send\n // an explicit null instead of being forced to omit the field.\n browser_info?: Record<string, unknown> | null;\n}\n\nexport interface UpdatePaymentMethodBody {\n payment_method: {\n default?: boolean;\n billing_address?: {\n name?: string | null;\n street1: string;\n street2?: string | null;\n city: string;\n state: string;\n zip: string;\n country: string;\n };\n };\n}\n\n// ---------------------------------------------------------------------------\n// Vault\n// ---------------------------------------------------------------------------\n\nexport interface VaultCredentials {\n vault_id: string;\n environment: string;\n route_id: string | null;\n}\n\n// ---------------------------------------------------------------------------\n// Response types\n// ---------------------------------------------------------------------------\n\nexport interface AddressesResponse {\n addresses: PayAddress[];\n meta: ResponseMeta;\n}\n\nexport interface PaymentMethodsResponse {\n payment_methods: PayPaymentMethod[];\n meta: ResponseMeta;\n}\n\nexport interface CreatedPaymentMethodResult {\n payment_method: PayPaymentMethod;\n meta: ResponseMeta;\n}\n\nexport interface ThreeDsRequiredCreateResult {\n three_ds: {\n status: \"three_ds_required\";\n session_token: string;\n tds_method_content: string | null;\n fingerprinting_required: boolean | null;\n merchant_tx_id: string | null;\n };\n meta: ResponseMeta;\n}\n\n// Discriminated union: 201 (created PM) | 200 (3DS required).\nexport type CreatePaymentMethodResponse =\n | CreatedPaymentMethodResult\n | ThreeDsRequiredCreateResult;\n\nexport function isThreeDsRequiredCreate(\n r: CreatePaymentMethodResponse,\n): r is ThreeDsRequiredCreateResult {\n return \"three_ds\" in r && r.three_ds.status === \"three_ds_required\";\n}\n\nexport interface ConfirmApprovedResult {\n status: \"approved\";\n session_token: string;\n payment_method: PayPaymentMethod;\n was_created?: boolean;\n}\n\nexport interface ConfirmChallengeResult {\n status: \"three_ds_challenge\";\n session_token: string;\n challenge_form: string | null;\n challenge_url: string | null;\n}\n\nexport type ConfirmPaymentMethod3DSResponse =\n | ConfirmApprovedResult\n | ConfirmChallengeResult;\n\n// 3DS session lifecycle state from the BFF. The known values are listed for\n// autocomplete + typo-safety, but the type stays open (`string & {}`) because\n// the backend enum may grow: the adapter forwards the wire string without a\n// lying `as` cast, and an unrecognized state stays non-terminal in\n// mapSessionStateToThreeDSStatus — resolved by the EMVCo polling timeout rather\n// than mis-mapped to completed/failed/canceled.\nexport type ThreeDsSessionState =\n | \"initialized\"\n | \"pending\"\n | \"approved\"\n | \"denied\"\n | \"timed_out\"\n | \"cancelled\"\n | \"skipped\"\n | (string & {});\n\nexport interface ThreeDsStatusResponse {\n session_token: string;\n state: ThreeDsSessionState;\n payment_method_id: number | null;\n expired: boolean | null;\n}\n\nexport interface ThreeDsCancelResponse {\n session_token: string;\n state: ThreeDsSessionState;\n cancelled: boolean | null;\n}\n\nexport interface VaultResponse {\n vault: VaultCredentials;\n meta: ResponseMeta;\n}\n\n// ---------------------------------------------------------------------------\n// Points ledger\n// ---------------------------------------------------------------------------\n\nexport interface PointsLedgerEntry {\n id: number;\n amount: number;\n total_balance: number;\n metadata: Record<string, unknown> | null;\n created_at: string;\n}\n\nexport interface PointsLedgersResponse {\n points_ledgers: PointsLedgerEntry[];\n meta: ResponseMeta;\n}\n","import { type FluidPayApi, type fluidPay } from \"@fluid-app/fluid-pay-core\";\nimport type { PayApi } from \"@fluid-app/portal-core/pay-api\";\nimport type { PayPaymentMethod } from \"@fluid-app/portal-core/pay-types\";\n\n/**\n * Maps a portal-tenant PayPaymentMethod to the fluidPay shape consumed by\n * profile-ui components (PaymentMethodDropdown, CreditCardFormDialog, etc.).\n * Co-located with the adapter because both speak the portal-tenant ↔ fluid-pay\n * boundary.\n */\nexport function mapToFluidPayPaymentMethod(\n raw: PayPaymentMethod,\n): fluidPay.CustomerPaymentMethod {\n return {\n id: raw.id,\n created_at: raw.created_at ?? \"\",\n default: raw.default,\n details: {\n card_network: raw.brand,\n card_brand: raw.brand,\n card_holder: raw.card_holder,\n last_four: raw.last_four,\n logo_url: raw.logo_url ?? undefined,\n exp_month: raw.exp_month ?? undefined,\n exp_year: raw.exp_year ?? undefined,\n },\n billing_address: raw.billing_address\n ? {\n name: raw.billing_address.name,\n address1: raw.billing_address.street1,\n address2: raw.billing_address.street2,\n city: raw.billing_address.city,\n state: raw.billing_address.state,\n zip: raw.billing_address.zip,\n country_code: raw.billing_address.country,\n }\n : null,\n payment_type: raw.type,\n source: \"\",\n updated_at: raw.updated_at ?? \"\",\n };\n}\n\nconst notImplemented = () => {\n throw new Error(\"Not available in portal-tenant context\");\n};\n\n/**\n * Adapts the portal-tenant PayApi to the FluidPayApi shape required by\n * FluidPayCoreProvider. Only `vault.fetchCredentials` is implemented —\n * the rest of the FluidPayApi surface is not used by the profile-ui\n * components that consume this provider in the portal context.\n */\nexport function createFluidPayApiAdapter(payApi: PayApi): FluidPayApi {\n return {\n customers: { fetchAccount: notImplemented, update: notImplemented },\n addresses: {\n fetchAll: notImplemented,\n create: notImplemented,\n update: notImplemented,\n delete: notImplemented,\n },\n paymentMethods: {\n fetchAll: notImplemented,\n addCreditCard: notImplemented,\n delete: notImplemented,\n updateDefault: notImplemented,\n update: notImplemented,\n },\n vault: {\n fetchCredentials: async () => {\n const response = await payApi.fetchVaultCredentials();\n return {\n vault: {\n vault_id: response.vault.vault_id,\n environment: response.vault.environment,\n route_id: response.vault.route_id ?? \"\",\n requires_3ds: false,\n },\n meta: {\n request_id: response.meta?.request_id ?? \"\",\n timestamp: response.meta?.timestamp ?? \"\",\n },\n } satisfies fluidPay.VaultResponse;\n },\n },\n };\n}\n","// Helper to render the device fingerprinting iframe.\n//\n// Browser-only: the function body requires `document` — never call during\n// SSR. Importing this module is SSR-safe; only invocation touches the DOM.\nexport const renderFingerprintingIframe = (html: string): Promise<void> => {\n return new Promise((resolve) => {\n const iframe = document.createElement(\"iframe\");\n iframe.srcdoc = html;\n iframe.style.display = \"none\";\n\n document.body.appendChild(iframe);\n\n // Wait for fingerprinting to complete (usually <10 seconds)\n setTimeout(() => {\n document.body.removeChild(iframe);\n resolve();\n }, 10000);\n });\n};\n","import type { ThreeDsRealtimeTransport } from \"@fluid-app/fluid-pay-ui\";\nimport type { ThreeDSStatus } from \"@fluid-app/fluid-pay-core/types\";\nimport type { ThreeDsSessionState } from \"@fluid-app/portal-core/pay-types\";\n\n/**\n * Polling-only realtime transport. A no-op channel keeps useVgs3DSCompletion's\n * `hasPusher` true so it does not log the misleading \"subscribe returned null\"\n * error; the 3s status poll is the sole resolver. The Pusher fast-follow\n * replaces this constant with a real pusher-js client.\n */\nexport const POLLING_ONLY_TRANSPORT: ThreeDsRealtimeTransport = {\n subscribe: () => ({ bind: () => {}, unbind: () => {} }),\n unsubscribe: () => {},\n};\n\n/**\n * Map the BFF 3ds_status session state -> the FE-A hook's ThreeDSStatus. Only\n * the known terminal states resolve the poll (approved/skipped -> completed,\n * denied/timed_out/expired -> failed, cancelled -> canceled); any other value\n * (initialized/pending or a future backend state) stays non-terminal so the\n * poll keeps running until the EMVCo timeout, rather than being mis-classified.\n */\nexport function mapSessionStateToThreeDSStatus(\n state: ThreeDsSessionState,\n expired: boolean | null,\n): ThreeDSStatus {\n return {\n completed: state === \"approved\" || state === \"skipped\",\n failed: state === \"denied\" || state === \"timed_out\" || expired === true,\n canceled: state === \"cancelled\",\n status: state,\n };\n}\n\n/**\n * Dig the portal BFF error code off a thrown ApiError. Structural and\n * self-validating: a non-ApiError simply yields undefined (no instanceof gate).\n */\nexport function cardAdd3DSErrorCode(error: unknown): string | undefined {\n // `meta` is an envelope key, so read `body` — `data` unwraps past it whenever\n // the response carried an `errors` key (docs/api-error-data-contract.md).\n const body = (error as { body?: unknown } | null)?.body;\n const meta = (body as { meta?: unknown } | null)?.meta;\n const code = (meta as { error_code?: unknown } | null)?.error_code;\n return typeof code === \"string\" ? code : undefined;\n}\n\n/**\n * Customer-facing message off a thrown portal ApiError. The client lifts the\n * portal `{ error: { message } }` onto ApiError.message; fall back to the\n * nested envelope field, then the supplied generic.\n */\nexport function cardAdd3DSErrorMessage(\n error: unknown,\n fallback: string,\n): string {\n if (error instanceof Error && error.message) return error.message;\n const body = (error as { body?: unknown } | null)?.body;\n const nested = (body as { error?: { message?: unknown } } | null)?.error\n ?.message;\n return typeof nested === \"string\" ? nested : fallback;\n}\n","import { useEffectEvent, useRef, useState, type ReactNode } from \"react\";\nimport { renderFingerprintingIframe } from \"@fluid-app/fluid-pay-core/utils/fingerprinting\";\nimport type { ThreeDSStatus } from \"@fluid-app/fluid-pay-core/types\";\nimport { useVgs3DSCompletion, VgsThreeDSModal } from \"@fluid-app/fluid-pay-ui\";\nimport type { PayApi } from \"@fluid-app/portal-core/pay-api\";\nimport type {\n ConfirmApprovedResult,\n ThreeDsRequiredCreateResult,\n} from \"@fluid-app/portal-core/pay-types\";\nimport {\n POLLING_ONLY_TRANSPORT,\n cardAdd3DSErrorCode,\n cardAdd3DSErrorMessage,\n mapSessionStateToThreeDSStatus,\n} from \"./three-ds-card-add-helpers\";\n\n// Wait before the single confirm retry when a completion signal races the\n// backend's upstream reconcile (422 three_ds_pending).\nconst PENDING_RETRY_DELAY_MS = 2_000;\nconst waitFor = (ms: number) =>\n new Promise<void>((resolve) => setTimeout(resolve, ms));\n\ninterface ActiveSession {\n sessionToken: string;\n merchantTxId: string | undefined;\n}\ninterface PendingChallenge {\n html: string;\n url?: string;\n}\n\nexport interface UsePortalCardAdd3DSFlowOptions {\n payApi: PayApi;\n onApproved: (approved: ConfirmApprovedResult) => void | Promise<void>;\n onFailed: (message: string) => void;\n onCanceled: () => void;\n t: (key: string) => string;\n}\n\nexport interface PortalCardAdd3DSFlow {\n begin: (created: ThreeDsRequiredCreateResult) => Promise<void>;\n modal: ReactNode;\n isActive: boolean;\n}\n\nexport function usePortalCardAdd3DSFlow({\n payApi,\n onApproved,\n onFailed,\n onCanceled,\n t,\n}: UsePortalCardAdd3DSFlowOptions): PortalCardAdd3DSFlow {\n const [session, setSession] = useState<ActiveSession | null>(null);\n const [challenge, setChallenge] = useState<PendingChallenge | null>(null);\n // Synchronous mirror for the single-flight guard and async continuations.\n const activeSessionRef = useRef<ActiveSession | null>(null);\n\n // Always call the latest surface callbacks.\n const emitApproved = useEffectEvent((approved: ConfirmApprovedResult) =>\n onApproved(approved),\n );\n const emitFailed = useEffectEvent((message: string) => onFailed(message));\n const emitCanceled = useEffectEvent(() => onCanceled());\n\n const resetFlow = () => {\n activeSessionRef.current = null;\n setSession(null);\n setChallenge(null);\n };\n\n // Exactly-one-terminal guard: each finish* no-ops once a terminal has won\n // (resetFlow nulls the ref right before the emit). Covers the modal's\n // Cancel/timeout and begin()'s catch racing a terminal.\n const finishApproved = async (approved: ConfirmApprovedResult) => {\n if (!activeSessionRef.current) return;\n resetFlow();\n await emitApproved(approved);\n };\n const finishFailed = (message: string) => {\n if (!activeSessionRef.current) return;\n resetFlow();\n emitFailed(message);\n };\n const finishCanceled = () => {\n if (!activeSessionRef.current) return;\n resetFlow();\n emitCanceled();\n };\n\n const failureMessageFrom = (error: unknown): string => {\n if (cardAdd3DSErrorCode(error) === \"three_ds_session_not_found\") {\n return t(\"payment_verification_timed_out\");\n }\n return cardAdd3DSErrorMessage(\n error,\n t(\"payment_verification_didnt_complete\"),\n );\n };\n\n const begin = async (created: ThreeDsRequiredCreateResult): Promise<void> => {\n // Single-flight: one bank check at a time.\n if (activeSessionRef.current) return;\n\n const {\n session_token,\n merchant_tx_id,\n fingerprinting_required,\n tds_method_content,\n } = created.three_ds;\n // No attempt activated yet — emit directly (the finish* ref-guard would swallow this).\n if (!session_token) {\n emitFailed(t(\"payment_verification_didnt_complete\"));\n return;\n }\n\n const active: ActiveSession = {\n sessionToken: session_token,\n merchantTxId: merchant_tx_id ?? undefined,\n };\n activeSessionRef.current = active;\n setSession(active);\n\n try {\n // Inside the try so a synchronous throw lands on finishFailed — an\n // escape would leave the ref set and deadlock single-flight.\n if (\n fingerprinting_required !== false &&\n typeof tds_method_content === \"string\" &&\n tds_method_content.length > 0\n ) {\n await renderFingerprintingIframe(tds_method_content);\n }\n\n const confirmation = await payApi.confirmPaymentMethod3DS({\n session_token: active.sessionToken,\n });\n if (confirmation.status === \"approved\") {\n await finishApproved(confirmation);\n return;\n }\n // A challenge with no form renders an empty modal that strands the user\n // — fail fast. (challenge_url alone is only the POST target for the\n // form's hidden fields; the modal renders the iframe from the form HTML.)\n if (!confirmation.challenge_form) {\n finishFailed(t(\"payment_verification_didnt_complete\"));\n return;\n }\n setChallenge({\n html: confirmation.challenge_form,\n url: confirmation.challenge_url ?? undefined,\n });\n } catch (error) {\n finishFailed(failureMessageFrom(error));\n }\n };\n\n // Replays confirm after a completion signal. The modal stays open (its\n // Cancel/timeout terminal can fire mid-await), so check staleness against\n // the attempt captured at entry after every await — land on EXACTLY ONE\n // terminal.\n const reconfirmAfterSignal = async (\n allowPendingRetry: boolean,\n ): Promise<void> => {\n const active = activeSessionRef.current;\n if (!active) return;\n try {\n const confirmation = await payApi.confirmPaymentMethod3DS({\n session_token: active.sessionToken,\n });\n if (activeSessionRef.current !== active) return;\n if (confirmation.status === \"approved\") {\n await finishApproved(confirmation);\n return;\n }\n // A second challenge after a completion signal is out of contract.\n finishFailed(t(\"payment_verification_didnt_complete\"));\n } catch (error) {\n if (activeSessionRef.current !== active) return;\n if (\n allowPendingRetry &&\n cardAdd3DSErrorCode(error) === \"three_ds_pending\"\n ) {\n await waitFor(PENDING_RETRY_DELAY_MS);\n if (activeSessionRef.current !== active) return;\n await reconfirmAfterSignal(false);\n return;\n }\n finishFailed(failureMessageFrom(error));\n }\n };\n\n const sessionStatusSnapshot = async (): Promise<ThreeDSStatus | null> => {\n const active = activeSessionRef.current;\n if (!active) return null;\n try {\n const snapshot = await payApi.fetchPaymentMethod3DSStatus({\n session_token: active.sessionToken,\n });\n return mapSessionStateToThreeDSStatus(snapshot.state, snapshot.expired);\n } catch {\n return null; // transient — keep polling\n }\n };\n\n useVgs3DSCompletion({\n channelName: session ? `private-3ds-session-${session.sessionToken}` : \"\",\n transport: POLLING_ONLY_TRANSPORT,\n checkStatus: sessionStatusSnapshot,\n merchantTxId: session?.merchantTxId,\n enabled: challenge !== null,\n onComplete: () => {\n void reconfirmAfterSignal(true);\n },\n onError: (message) => finishFailed(message),\n onCanceled: finishCanceled,\n });\n\n const closeChallengeModal = (timeoutError?: string) => {\n const active = activeSessionRef.current;\n // Fire-and-forget server-side cancel; the close never waits on it.\n if (active) {\n void payApi\n .cancelPaymentMethod3DS({ session_token: active.sessionToken })\n .catch(() => {});\n }\n if (timeoutError) finishFailed(timeoutError);\n else finishCanceled();\n };\n\n const modal = (\n <VgsThreeDSModal\n isOpen={challenge !== null}\n challengeHtml={challenge?.html ?? \"\"}\n challengeUrl={challenge?.url}\n onClose={closeChallengeModal}\n labels={{\n title: t(\"verify_your_payment\"),\n cancel: t(\"cancel\"),\n timedOut: t(\"payment_verification_timed_out\"),\n stillWorking: t(\"still_working_with_your_bank\"),\n dontRefresh: t(\"dont_refresh_this_tab\"),\n }}\n />\n );\n\n return { begin, modal, isActive: session !== null };\n}\n"],"mappings":"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"}
|