Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions constants/countries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export const COUNTRIES: Country[] = [
{ code: 'CM', name: 'Cameroon' },
{ code: 'CA', name: 'Canada' },
{ code: 'CV', name: 'Cape Verde' },
{ code: 'KY', name: 'Cayman Islands' },
{ code: 'CF', name: 'Central African Republic' },
{ code: 'TD', name: 'Chad' },
{ code: 'CL', name: 'Chile' },
Expand Down Expand Up @@ -68,25 +69,31 @@ export const COUNTRIES: Country[] = [
{ code: 'GE', name: 'Georgia' },
{ code: 'DE', name: 'Germany' },
{ code: 'GH', name: 'Ghana' },
{ code: 'GI', name: 'Gibraltar' },
{ code: 'GR', name: 'Greece' },
{ code: 'GD', name: 'Grenada' },
{ code: 'GT', name: 'Guatemala' },
{ code: 'GG', name: 'Guernsey' },
{ code: 'GN', name: 'Guinea' },
{ code: 'GW', name: 'Guinea-Bissau' },
{ code: 'GY', name: 'Guyana' },
{ code: 'HT', name: 'Haiti' },
{ code: 'HN', name: 'Honduras' },
{ code: 'HK', name: 'Hong Kong' },
{ code: 'HU', name: 'Hungary' },
{ code: 'IS', name: 'Iceland' },
{ code: 'IN', name: 'India' },
{ code: 'ID', name: 'Indonesia' },
{ code: 'IR', name: 'Iran' },
{ code: 'IQ', name: 'Iraq' },
{ code: 'IE', name: 'Ireland' },
{ code: 'IM', name: 'Isle of Man' },
{ code: 'IL', name: 'Israel' },
{ code: 'IT', name: 'Italy' },
{ code: 'CI', name: 'Ivory Coast' },
{ code: 'JM', name: 'Jamaica' },
{ code: 'JP', name: 'Japan' },
{ code: 'JE', name: 'Jersey' },
{ code: 'JO', name: 'Jordan' },
{ code: 'KZ', name: 'Kazakhstan' },
{ code: 'KE', name: 'Kenya' },
Expand All @@ -105,6 +112,7 @@ export const COUNTRIES: Country[] = [
{ code: 'LT', name: 'Lithuania' },
{ code: 'LU', name: 'Luxembourg' },
{ code: 'MK', name: 'North Macedonia' },
{ code: 'MO', name: 'Macao' },
{ code: 'MG', name: 'Madagascar' },
{ code: 'MW', name: 'Malawi' },
{ code: 'MY', name: 'Malaysia' },
Expand Down Expand Up @@ -183,6 +191,7 @@ export const COUNTRIES: Country[] = [
{ code: 'TN', name: 'Tunisia' },
{ code: 'TR', name: 'Turkey' },
{ code: 'TM', name: 'Turkmenistan' },
{ code: 'TC', name: 'Turks and Caicos Islands' },
{ code: 'TV', name: 'Tuvalu' },
{ code: 'UG', name: 'Uganda' },
{ code: 'UA', name: 'Ukraine' },
Expand Down
53 changes: 28 additions & 25 deletions hooks/useCardSteps/useCardSteps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,9 +255,8 @@ export function useCardSteps(
* ended up on Rain permanently: the Didit session creates a card customer
* that defaults to Rain, and nothing ever rewrites it.
*
* Ask instead of guessing. This is the same screen the Sumsub branch
* below uses, and it is only reached when the IP lookup failed too — a
* country that resolved keeps going without an extra step.
* Ask instead of guessing. This is the same screen the declared-country
* check below sends to; it is split out only so the event says why.
*/
if (!countryCode) {
track(TRACKING_EVENTS.CARD_KYC_FLOW_TRIGGERED, {
Expand Down Expand Up @@ -292,29 +291,33 @@ export function useCardSteps(
router.push(path.CARD_PENDING as any);
return;
}
}

/**
* Sumsub card sessions REQUIRE a country the user declared themselves —
* an IP guess is refused server-side, because `user.country` pins which
* issuer serves them and nothing writes it back. Ask here rather than
* letting the session fail: this is the entry point the home setup step
* uses (`useHomeSetupSteps` calls this action directly rather than
* `startCardOnboarding`), so it is reached with no gate having run at
* all, and `resolveKycProvider` deliberately does not persist the
* country it routes on.
*
* The selection screen writes `source: 'manual'` and re-enters the flow
* via `/card/activate?countryConfirmed=true`, so this asks once.
*/
if (useCountryStore.getState().countryInfo?.source !== 'manual') {
track(TRACKING_EVENTS.CARD_KYC_FLOW_TRIGGERED, {
action: 'country_selection_required',
kycProvider,
countryCode,
});
router.push(path.CARD_COUNTRY_SELECTION as any);
return;
}
/**
* Every card verification, Didit included, starts from a country the user
* declared themselves. This is the entry point the home setup step uses
* (`useHomeSetupSteps` calls this action directly rather than
* `startCardOnboarding`), so it is reached with no gate having run at all.
*
* Sumsub refuses an IP guess server-side, so that branch always needed
* this. Didit used to skip it, and the IP answer then picked the issuer:
* a Hong Kong resident whose IP resolved to Singapore was routed to Didit,
* which created a Rain card customer that nothing rewrites, in a Didit
* questionnaire that does not offer Hong Kong. The backend only refuses a
* Didit card session for a country Wirex serves, and an IP in a Rain-only
* market gives it nothing to refuse on.
*
* The selection screen writes `source: 'manual'` and re-enters the flow
* via `/card/activate?countryConfirmed=true`, so this asks once.
*/
if (useCountryStore.getState().countryInfo?.source !== 'manual') {
track(TRACKING_EVENTS.CARD_KYC_FLOW_TRIGGERED, {
action: 'country_selection_required',
kycProvider,
countryCode,
});
router.push(path.CARD_COUNTRY_SELECTION as any);
return;
}

router.push((kycProvider === KycProvider.SUMSUB ? path.SUMSUB_KYC : path.KYC) as any);
Expand Down
Loading