Last active
February 16, 2023 09:33
-
-
Save IvanMMM/40aa50998778ad7e1601750aab7f0979 to your computer and use it in GitHub Desktop.
Generated by XState Viz: https://xstate.js.org/viz
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const REVIEW_STATUS = { | |
PENDING: "pending", | |
PRECHECKED: "prechecked", | |
QUEUED: "queued", | |
HOLD: "onHold", | |
COMPLETED: "completed", | |
}; | |
const REVIEW_RESULT = { | |
GOOD: "GREEN", | |
BAD: "RED", | |
}; | |
const REJECT_TYPE = { | |
TRY_AGAIN: "RETRY", | |
FINAL: "FINAL", | |
}; | |
const WEBHOOK_TYPE = { | |
// When an applicant is created. | |
CREATED: "applicantCreated", | |
// When a user uploaded all the required documents and the applicant's status changed to pending. | |
PENDING: "applicantPending", | |
// Processing of the applicant is paused for an agreed reason. | |
HOLD: "applicantOnHold", | |
// When verification is completed. Contains the verification result | |
REVIEWED: "applicantReviewed", | |
// Applicant has been reset: applicant status changed to init and all documents were set as inactive. | |
RESET: "applicantReset", | |
}; | |
const KYC_RESULT = { | |
NONE: "NONE", | |
SEND: "SEND", | |
DENY: "DENY", | |
ACCEPT: "ACCEPT", | |
RE_VERIFY: "RE_VERIFY", | |
ADDITIONAL_DOCS_REQUIRED: "ADDITIONAL_DOCS_REQUIRED", | |
MANUAL_REVIEW: "MANUAL_REVIEW", | |
KYC_RESTRICTION: "KYC_RESTRICTION", | |
}; | |
const SERVICE_TYPES = { | |
IDENTITY: "identity", | |
ADDRESS: "address", | |
}; | |
actions = { | |
initApplicant: async (content) => { | |
await Promise.all([ | |
sumSubApi.updateApplicant(content.applicantId, content.user), | |
sumSubApi.updateApplicantData(content.applicantId, content.user), | |
]); | |
}, | |
updateEventData: assign({ | |
applicantId: (context, event) => event.applicantId, | |
levelName: (context, event) => event.levelName, | |
}), | |
updateUserData: assign({ | |
data: (context, event) => { | |
const info = event.data && event.data.info; | |
const questionnaires = event && event.data && event.data.questionnaires; | |
return {info, questionnaires}; | |
}, | |
}), | |
resetUserData: assign({ | |
data: () => ({info: {}, questionnaires: []}), | |
}), | |
notifySend: (content) => { | |
if (content.id === SERVICE_TYPES.ADDRESS) { | |
dataLayer.kycAddressSent(content.user); | |
} | |
}, | |
notifyAdditionalDocsRequired: (content) => { | |
if (content.id === SERVICE_TYPES.IDENTITY) { | |
dataLayer.kycIdentityDocsRequired(content.user); | |
} | |
}, | |
notifyManualReview: (content) => { | |
if (content.id === SERVICE_TYPES.IDENTITY) { | |
notifications.kycManualReview(content.user, { | |
name: content.user.fullName, | |
}); | |
} | |
}, | |
notifyDeny: (content) => { | |
if (content.id === SERVICE_TYPES.IDENTITY) { | |
notifications.kycDeny(content.user, { | |
name: content.user.fullName, | |
}); | |
} | |
if (content.id === SERVICE_TYPES.ADDRESS) { | |
notifications.kycAddressDeny(content.user, { | |
name: content.user.fullName, | |
}); | |
} | |
}, | |
notifyAccept: (content) => { | |
if (content.id === SERVICE_TYPES.IDENTITY) { | |
dataLayer.kycIdentityAccept(content.user); | |
// TODO Add check for phone number exists | |
dataLayer.kycPhoneAccept(content.user); | |
dataLayer.verification(content.user); | |
notifications.kycAccepted(content.user, { | |
name: content.user.fullName, | |
}); | |
} | |
if (content.id === SERVICE_TYPES.ADDRESS) { | |
dataLayer.kycAddressAccept(content.user); | |
} | |
}, | |
} | |
const guards = { | |
isTransitioned: (context) => context.isTransitioned, | |
isAccept: (context, event) => true, | |
isRetry: (context, event) => true, | |
isDeny: (context, event) => true, | |
}; | |
const actions2 = { | |
initApplicant: async (content) => { | |
await Promise.all([ | |
sumSubApi.updateApplicant(content.applicantId, content.user), | |
sumSubApi.updateApplicantData(content.applicantId, content.user), | |
]); | |
}, | |
updateEventData: assign({ | |
applicantId: (context, event) => event.applicantId, | |
levelName: (context, event) => event.levelName, | |
}), | |
updateUserData: assign({ | |
data: (context, event) => { | |
const info = event.data && event.data.info; | |
const questionnaires = event && event.data && event.data.questionnaires; | |
return {info, questionnaires}; | |
}, | |
}), | |
notifySend: (content) => { | |
if (content.id === SERVICE_TYPES.ADDRESS) { | |
dataLayer.kycAddressSent(content.user); | |
} | |
}, | |
notifyAdditionalDocsRequired: (content) => { | |
if (content.id === SERVICE_TYPES.IDENTITY) { | |
dataLayer.kycIdentityDocsRequired(content.user); | |
} | |
}, | |
notifyManualReview: (content) => { | |
if (content.id === SERVICE_TYPES.IDENTITY) { | |
notifications.kycManualReview(content.user, { | |
name: content.user.fullName, | |
}); | |
} | |
}, | |
notifyDeny: (content) => { | |
if (content.id === SERVICE_TYPES.IDENTITY) { | |
notifications.kycDeny(content.user, { | |
name: content.user.fullName, | |
}); | |
} | |
if (content.id === SERVICE_TYPES.ADDRESS) { | |
notifications.kycAddressDeny(content.user, { | |
name: content.user.fullName, | |
}); | |
} | |
}, | |
notifyAccept: (content) => { | |
if (content.id === SERVICE_TYPES.IDENTITY) { | |
dataLayer.kycIdentityAccept(content.user); | |
// TODO Add check for phone number exists | |
dataLayer.kycPhoneAccept(content.user); | |
dataLayer.verification(content.user); | |
notifications.kycAccepted(content.user, { | |
name: content.user.fullName, | |
}); | |
} | |
if (content.id === SERVICE_TYPES.ADDRESS) { | |
dataLayer.kycAddressAccept(content.user); | |
} | |
}, | |
}; | |
function createMachineWithContext(id, user, data = {}) { | |
return Machine( | |
{ | |
predictableActionArguments: true, | |
id, | |
initial: "NONE", | |
context: { | |
id, | |
user, | |
data, | |
applicantId: undefined, | |
levelName: undefined, | |
}, | |
states: { | |
[KYC_RESULT.NONE]: { | |
entry: [actions.updateEventData, actions.resetUserData], | |
on: { | |
// User initially created | |
[WEBHOOK_TYPE.CREATED]: { | |
target: KYC_RESULT.NONE, | |
actions: [actions.updateEventData, actions.initApplicant], | |
}, | |
// User uploaded documents first time | |
[WEBHOOK_TYPE.PENDING]: { | |
target: KYC_RESULT.SEND, | |
actions: [actions.notifySend], | |
}, | |
// User was reset again | |
[WEBHOOK_TYPE.RESET]: { | |
target: KYC_RESULT.NONE, | |
}, | |
}, | |
}, | |
[KYC_RESULT.SEND]: { | |
entry: [actions.updateEventData, actions.updateUserData], | |
on: { | |
// User was reviewed by sumsub | |
[WEBHOOK_TYPE.REVIEWED]: [ | |
// User was accepted after providing documents | |
{ | |
target: KYC_RESULT.ACCEPT, | |
cond: "isAccept", | |
actions: [actions.notifyAccept], | |
}, | |
// User was rejected after providing documents | |
{ | |
target: KYC_RESULT.DENY, | |
cond: "isDeny", | |
actions: [actions.notifyDeny], | |
}, | |
// User was asked for additional documents | |
{ | |
target: KYC_RESULT.ADDITIONAL_DOCS_REQUIRED, | |
cond: "isRetry", | |
actions: [actions.notifyAdditionalDocsRequired], | |
}, | |
], | |
// User was switched to manual review after providing docs | |
[WEBHOOK_TYPE.HOLD]: { | |
target: KYC_RESULT.MANUAL_REVIEW, | |
actions: [actions.notifyManualReview], | |
}, | |
// User verification levels reset | |
[WEBHOOK_TYPE.RESET]: { | |
target: KYC_RESULT.NONE, | |
}, | |
}, | |
}, | |
[KYC_RESULT.MANUAL_REVIEW]: { | |
entry: [actions.updateEventData, actions.updateUserData], | |
on: { | |
// User was reviewed by compliance | |
[WEBHOOK_TYPE.REVIEWED]: [ | |
{ | |
target: KYC_RESULT.ACCEPT, | |
cond: "isAccept", | |
actions: [actions.notifyAccept], | |
}, | |
{ | |
target: KYC_RESULT.DENY, | |
cond: "isDeny", | |
actions: [actions.notifyDeny], | |
}, | |
{ | |
target: KYC_RESULT.ADDITIONAL_DOCS_REQUIRED, | |
cond: "isRetry", | |
actions: [actions.notifyAdditionalDocsRequired], | |
}, | |
], | |
// User verification levels reset | |
[WEBHOOK_TYPE.RESET]: { | |
target: KYC_RESULT.NONE, | |
}, | |
}, | |
}, | |
[KYC_RESULT.ACCEPT]: { | |
entry: [actions.updateEventData, actions.updateUserData], | |
on: { | |
// User was re-reviewed | |
[WEBHOOK_TYPE.REVIEWED]: [ | |
// User blocked because of PEP or some other rejection | |
{ | |
target: KYC_RESULT.DENY, | |
cond: "isDeny", | |
actions: [actions.notifyDeny], | |
}, | |
// Additional docs was requested | |
{ | |
target: KYC_RESULT.ADDITIONAL_DOCS_REQUIRED, | |
cond: "isRetry", | |
actions: [actions.notifyAdditionalDocsRequired], | |
}, | |
], | |
// User was switched to manual review after successful verification | |
[WEBHOOK_TYPE.HOLD]: { | |
target: KYC_RESULT.MANUAL_REVIEW, | |
actions: [actions.notifyManualReview], | |
}, | |
// User verification levels reset | |
[WEBHOOK_TYPE.RESET]: { | |
target: KYC_RESULT.NONE, | |
}, | |
}, | |
}, | |
[KYC_RESULT.DENY]: { | |
entry: [actions.updateEventData, actions.updateUserData], | |
// User was switched to manual review after final deny | |
on: { | |
[WEBHOOK_TYPE.HOLD]: { | |
target: KYC_RESULT.MANUAL_REVIEW, | |
actions: [actions.notifyManualReview], | |
}, | |
// User verification levels reset | |
[WEBHOOK_TYPE.RESET]: { | |
target: KYC_RESULT.NONE, | |
}, | |
}, | |
}, | |
[KYC_RESULT.ADDITIONAL_DOCS_REQUIRED]: { | |
entry: [actions.updateEventData, actions.updateUserData], | |
on: { | |
// User re-uploaded documents | |
[WEBHOOK_TYPE.PENDING]: { | |
target: KYC_RESULT.SEND, | |
actions: [actions.notifySend], | |
}, | |
// User was switched to manual review after requesting additional docs | |
[WEBHOOK_TYPE.HOLD]: { | |
target: KYC_RESULT.MANUAL_REVIEW, | |
actions: [actions.notifyManualReview], | |
}, | |
// User verification levels reset | |
[WEBHOOK_TYPE.RESET]: { | |
target: KYC_RESULT.NONE, | |
}, | |
}, | |
}, | |
}, | |
}, | |
{ | |
actions, | |
guards, | |
}, | |
); | |
} | |
const m = createMachineWithContext("identify", {}); | |
interpret(m); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment