Skip to content

Commit

Permalink
Only require one id document during registration
Browse files Browse the repository at this point in the history
  • Loading branch information
IanPhilips committed Sep 21, 2024
1 parent be5a3c3 commit 6560ca2
Show file tree
Hide file tree
Showing 9 changed files with 84 additions and 41 deletions.
6 changes: 5 additions & 1 deletion backend/api/src/gidx/get-checkout-session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,11 @@ export const getCheckoutSession: APIHandler<
throw new APIError(400, 'GIDX customer profile failed')
}
const CustomerProfile = (await idRes.json()) as CustomerProfileResponse
log('Customer profile response:', CustomerProfile)
log(
'Customer profile response:',
CustomerProfile.MerchantCustomerID,
CustomerProfile.ReasonCodes
)
if (props.PayActionCode === 'PAYOUT') {
const { status, message } = getVerificationStatus(user)
if (status !== 'success') {
Expand Down
15 changes: 11 additions & 4 deletions backend/api/src/gidx/get-verification-documents.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { APIError, APIHandler } from 'api/helpers/endpoint'
import { log } from 'shared/utils'
import { getUser, log } from 'shared/utils'
import {
getGIDXStandardParams,
GIDX_BASE_URL,
Expand All @@ -8,17 +8,24 @@ import {
import { GIDXDocument } from 'common/gidx/gidx'
import { TWOMBA_ENABLED } from 'common/envs/constants'
import { getDocumentsStatus } from 'common/gidx/document'
import { createSupabaseDirectClient } from 'shared/supabase/init'
import { assessDocumentStatus } from './get-verification-status'

export const getVerificationDocuments: APIHandler<
'get-verification-documents-gidx'
> = async (_, auth) => {
if (!TWOMBA_ENABLED) throw new APIError(400, 'GIDX registration is disabled')
const pg = createSupabaseDirectClient()
const user = await getUser(auth.uid, pg)
if (!user) {
throw new APIError(400, 'User not found')
}
const {
documents,
unrejectedUtilityDocuments,
unrejectedIdDocuments,
rejectedDocuments,
} = await getIdentityVerificationDocuments(auth.uid)
} = await assessDocumentStatus(user, pg)

return {
status: 'success',
Expand Down Expand Up @@ -54,13 +61,13 @@ export const getIdentityVerificationDocuments = async (userId: string) => {
data.MerchantCustomerID
)
const { Documents: documents } = data
return getDocumentsStatus(documents)
return getDocumentsStatus(documents ?? [])
}

type DocumentCheck = {
ResponseCode: number
ResponseMessage: string
MerchantCustomerID: string
DocumentCount: number
Documents: GIDXDocument[]
Documents: GIDXDocument[] | null
}
22 changes: 19 additions & 3 deletions backend/api/src/gidx/get-verification-status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,19 @@ export const getVerificationStatusInternal = async (
}
}

const assessDocumentStatus = async (user: User, pg: SupabaseDirectClient) => {
const { isPending, isVerified, isRejected, documents } =
await getIdentityVerificationDocuments(user.id)
export const assessDocumentStatus = async (
user: User,
pg: SupabaseDirectClient
) => {
const {
documents,
rejectedDocuments,
unrejectedUtilityDocuments,
unrejectedIdDocuments,
isPending,
isVerified,
isRejected,
} = await getIdentityVerificationDocuments(user.id)

if (isVerified && user.kycDocumentStatus !== 'verified') {
// They passed the reason codes and have the required documents
Expand Down Expand Up @@ -129,5 +139,11 @@ const assessDocumentStatus = async (user: User, pg: SupabaseDirectClient) => {
return {
status: 'success',
documents,
rejectedDocuments,
unrejectedUtilityDocuments,
unrejectedIdDocuments,
isPending,
isVerified,
isRejected,
}
}
24 changes: 16 additions & 8 deletions common/src/gidx/document.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { GIDX_DOCUMENTS_REQUIRED, GIDXDocument } from 'common/gidx/gidx'
import {
GIDX_REGISTATION_DOCUMENTS_REQUIRED,
GIDXDocument,
} from 'common/gidx/gidx'
const acceptDocText = 'Review Complete - Customer Identity Verified'

export const getDocumentsStatus = (documents: GIDXDocument[]) => {
Expand Down Expand Up @@ -32,23 +35,28 @@ export const getDocumentsStatus = (documents: GIDXDocument[]) => {
)
const pendingDocuments = documents.filter((doc) => doc.DocumentStatus !== 3)

const requiresMultipleDocuments = GIDX_REGISTATION_DOCUMENTS_REQUIRED > 1

const isVerified =
acceptedDocuments.length >= GIDX_DOCUMENTS_REQUIRED &&
acceptedUtilityDocuments.length > 0 &&
acceptedIdDocuments.length > 0
acceptedDocuments.length >= GIDX_REGISTATION_DOCUMENTS_REQUIRED &&
requiresMultipleDocuments
? acceptedUtilityDocuments.length > 0 && acceptedIdDocuments.length > 0
: acceptedIdDocuments.length > 0

const isPending =
!isVerified &&
acceptedDocuments.length + pendingDocuments.length >=
GIDX_DOCUMENTS_REQUIRED &&
unrejectedUtilityDocuments.length > 0 &&
unrejectedIdDocuments.length > 0
GIDX_REGISTATION_DOCUMENTS_REQUIRED &&
requiresMultipleDocuments
? unrejectedUtilityDocuments.length > 0 &&
unrejectedIdDocuments.length > 0
: unrejectedIdDocuments.length > 0

const isRejected =
!isVerified &&
!isPending &&
(rejectedDocuments.length > 0 ||
acceptedDocuments.length < GIDX_DOCUMENTS_REQUIRED)
acceptedDocuments.length < GIDX_REGISTATION_DOCUMENTS_REQUIRED)

return {
documents,
Expand Down
2 changes: 1 addition & 1 deletion common/src/gidx/gidx.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { z } from 'zod'
import { MIN_CASHOUT_AMOUNT, SWEEPIES_CASHOUT_FEE } from 'common/economy'

export const GIDX_DOCUMENTS_REQUIRED = 2
export const GIDX_REGISTATION_DOCUMENTS_REQUIRED = 1

export const GPSProps = z.object({
Latitude: z.number(),
Expand Down
10 changes: 6 additions & 4 deletions web/components/cashout/select-cashout-options.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
} from 'web/components/buttons/button'
import { Col } from 'web/components/layout/col'
import { Row } from 'web/components/layout/row'
import { getNativePlatform } from 'web/lib/native/is-native'
import { CashoutPagesType } from 'web/pages/redeem'
import { ManaCoin } from 'web/public/custom-components/manaCoin'
import { CoinNumber } from '../widgets/coin-number'
Expand All @@ -28,6 +27,7 @@ import { PaginationNextPrev } from '../widgets/pagination'
import { DateTimeTooltip } from '../widgets/datetime-tooltip'
import { shortenedFromNow } from 'web/lib/util/shortenedFromNow'
import { Spacer } from '../layout/spacer'
import { useNativeInfo } from '../native-message-provider'

export const CASHOUTS_PER_PAGE = 10

Expand All @@ -47,6 +47,7 @@ export function getStatusColor(status: string) {
export function SelectCashoutOptions(props: {
user: User
redeemableCash: number
redeemForUSDPageName: CashoutPagesType
setPage: (page: CashoutPagesType) => void
allDisabled?: boolean
}) {
Expand Down Expand Up @@ -158,11 +159,12 @@ export function SelectCashoutOptions(props: {
function CashoutOptionsContent(props: {
user: User
redeemableCash: number
redeemForUSDPageName: CashoutPagesType
setPage: (page: CashoutPagesType) => void
allDisabled?: boolean
}) {
const { setPage, allDisabled, redeemableCash } = props
const { isNative, platform } = getNativePlatform()
const { setPage, allDisabled, redeemableCash, redeemForUSDPageName } = props
const { isNative, platform } = useNativeInfo()
const isNativeIOS = isNative && platform === 'ios'

const noHasMinRedeemableCash = redeemableCash < MIN_CASHOUT_AMOUNT
Expand Down Expand Up @@ -299,7 +301,7 @@ function CashoutOptionsContent(props: {
<Button
className={clsx('text-xs sm:text-sm')}
onClick={() => {
setPage('documents')
setPage(redeemForUSDPageName)
}}
disabled={!!allDisabled || noHasMinRedeemableCash}
>
Expand Down
3 changes: 2 additions & 1 deletion web/components/gidx/register-user-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,7 @@ export const RegisterUserForm = (props: {
<UploadDocuments
back={() => router.back()}
next={() => setPage('final')}
requireUtilityDoc={false}
/>
</>
)
Expand Down Expand Up @@ -461,7 +462,7 @@ export const RegisterUserForm = (props: {
<span className="text-ink-700 mx-auto">
{user.kycDocumentStatus === 'fail' &&
'There were errors with your documents. '}
Please upload identity documents to continue.
Please upload a photo of your id to continue.
</span>
<Row className="mx-auto">
<Button onClick={() => setPage('documents')}>Continue</Button>
Expand Down
9 changes: 5 additions & 4 deletions web/components/gidx/upload-document.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ import { BottomRow } from './register-component-helpers'
export const UploadDocuments = (props: {
back: () => void
next: () => void
requireUtilityDoc: boolean
}) => {
const { back, next } = props
const { back, next, requireUtilityDoc } = props
const user = useUser()
const [docs, setDocs] = useState<{
documents: GIDXDocument[]
Expand Down Expand Up @@ -103,11 +104,11 @@ export const UploadDocuments = (props: {
})
setFile(null)
if (currentStep === 'id' && idDocuments.length > 0) {
if (utilityDocuments.length > 0) {
next()
} else {
if (requireUtilityDoc && utilityDocuments.length === 0) {
setCategoryType(7)
setCurrentStep('utility')
} else {
next()
}
} else if (currentStep === 'utility' && utilityDocuments.length > 0) {
next()
Expand Down
34 changes: 19 additions & 15 deletions web/pages/redeem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import {
InputTitle,
} from 'web/components/gidx/register-component-helpers'
import { UsOnlyDisclaimer } from 'web/components/twomba/us-only-disclaimer'
import { useEvent } from 'web/hooks/use-event'

export type CashoutPagesType =
| 'select-cashout-method'
Expand Down Expand Up @@ -123,6 +124,16 @@ const CashoutPage = () => {
const [completedCashout, setCompletedCashout] = useState(0)
const kycAmount = useKYCGiftAmount(user)

const { data: documentData } = useAPIGetter(
'get-verification-documents-gidx',
{}
)
const { utilityDocuments, idDocuments } = documentData ?? {}
const mustUploadDocs =
user?.kycDocumentStatus === 'await-documents' ||
(utilityDocuments?.length ?? 0) <= 0 ||
(idDocuments?.length ?? 0) <= 0

useApiSubscription({
topics: [
`gidx-checkout-session/${checkoutSession?.MerchantSessionID ?? '_'}`,
Expand Down Expand Up @@ -164,13 +175,11 @@ const CashoutPage = () => {
setPage('ach-details')
} else if (message && status === 'error') {
setError(message)
setloading(false)
}
} catch (e) {
console.error('Error getting redemption session', e)
setError('Error getting redemption session')
setloading(false)
}
setloading(false)
}

const handleSubmit = async () => {
Expand Down Expand Up @@ -217,14 +226,10 @@ const CashoutPage = () => {
setloading(false)
}

const handleLocationReceived = (data: GPSData) => {
if (user?.kycDocumentStatus === 'await-documents') {
setPage('documents')
return
}
const handleLocationReceived = useEvent((data: GPSData) => {
setPage('get-session')
getCashoutSession(data)
}
})

const privateUser = usePrivateUser()

Expand Down Expand Up @@ -335,6 +340,7 @@ const CashoutPage = () => {
/>
)}
<SelectCashoutOptions
redeemForUSDPageName={mustUploadDocs ? 'documents' : 'location'}
user={user}
redeemableCash={redeemableCash}
setPage={setPage}
Expand All @@ -350,7 +356,7 @@ const CashoutPage = () => {

return (
<Page trackPageView={'redemptions page'}>
<Col className="bg-canvas-0 mx-auto max-w-lg items-center gap-2 px-6 py-4">
<Col className="bg-canvas-0 w-full max-w-lg items-center gap-2 self-center px-6 py-4">
<Row className="w-full justify-end">
<UsOnlyDisclaimer />
</Row>
Expand All @@ -367,6 +373,7 @@ const CashoutPage = () => {
) : page == 'select-cashout-method' ? (
<>
<SelectCashoutOptions
redeemForUSDPageName={mustUploadDocs ? 'documents' : 'location'}
user={user}
redeemableCash={redeemableCash}
setPage={setPage}
Expand All @@ -381,14 +388,11 @@ const CashoutPage = () => {
<UploadDocuments
back={router.back}
next={() => setPage('location')}
requireUtilityDoc={true}
/>
) : page === 'location' ? (
<LocationPanel
back={() =>
user?.kycDocumentStatus != 'verified'
? setPage('documents')
: router.back()
}
back={() => (mustUploadDocs ? setPage('documents') : router.back())}
setLocation={handleLocationReceived}
setLocationError={setLocationError}
setLoading={setloading}
Expand Down

0 comments on commit 6560ca2

Please sign in to comment.