import { Button } from '@/common/components/atoms/Button/Button'; import { MotionButton } from '@/common/components/molecules/MotionButton/MotionButton'; import { ctw } from '@/common/utils/ctw/ctw'; import { useAuthenticatedUserQuery } from '@/domains/auth/hooks/queries/useAuthenticatedUserQuery/useAuthenticatedUserQuery'; import { useRevisionTaskByIdMutation } from '@/domains/entities/hooks/mutations/useRevisionTaskByIdMutation/useRevisionTaskByIdMutation'; import { useEventMutation } from '@/domains/workflows/hooks/mutations/useEventMutation/useEventMutation'; import { useWorkflowByIdQuery } from '@/domains/workflows/hooks/queries/useWorkflowByIdQuery/useWorkflowByIdQuery'; import { useAssociatedCompaniesInformationBlock } from '@/lib/blocks/hooks/useAssociatedCompaniesInformationBlock/useAssociatedCompaniesInformationBlock'; import { associatedCompanyAdapter } from '@/lib/blocks/hooks/useAssosciatedCompaniesBlock/associated-company-adapter'; import { motionButtonProps, useAssociatedCompaniesBlock, } from '@/lib/blocks/hooks/useAssosciatedCompaniesBlock/useAssociatedCompaniesBlock'; import { useEntityInfoBlock } from '@/lib/blocks/hooks/useEntityInfoBlock/useEntityInfoBlock'; import { createDirectorsBlocks } from '@/lib/blocks/components/DirectorBlock/hooks/useDirectorBlock/create-directors-blocks'; import { useDocumentBlocks } from '@/lib/blocks/hooks/useDocumentBlocks/useDocumentBlocks'; import { useMainRepresentativeBlock } from '@/lib/blocks/hooks/useMainRepresentativeBlock/useMainRepresentativeBlock'; import { useCaseDecision } from '@/pages/Entity/components/Case/hooks/useCaseDecision/useCaseDecision'; import { useCaseState } from '@/pages/Entity/components/Case/hooks/useCaseState/useCaseState'; import { buildCollectionFlowUrl, StateTag } from '@ballerine/common'; import { ExternalLink, Send } from 'lucide-react'; import { useCallback, useMemo } from 'react'; import { useParams } from 'react-router-dom'; import { toast } from 'sonner'; import { associatedCompanyToWorkflowAdapter } from '@/lib/blocks/hooks/useAssosciatedCompaniesBlock/associated-company-to-workflow-adapter'; import { directorAdapter } from '@/lib/blocks/components/DirectorBlock/hooks/useDirectorBlock/helpers'; import { useRemoveTaskDecisionByIdMutation } from '@/domains/entities/hooks/mutations/useRemoveTaskDecisionByIdMutation/useRemoveTaskDecisionByIdMutation'; import { useApproveTaskByIdMutation } from '@/domains/entities/hooks/mutations/useApproveTaskByIdMutation/useApproveTaskByIdMutation'; import { useReviseDocumentByIdMutation } from '@/domains/documents/hooks/mutations/useReviseDocumentByIdMutation/useReviseDocumentByIdMutation'; import { useRemoveDocumentDecisionByIdMutation } from '@/domains/documents/hooks/mutations/useRemoveDocumentDecisionByIdMutation/useRemoveDocumentDecisionByIdMutation'; import { useApproveDocumentByIdMutation } from '@/domains/documents/hooks/mutations/useApproveDocumentByIdMutation/useApproveDocumentByIdMutation'; import { useEditCollectionFlow } from '@/pages/Entity/components/Case/components/CaseOptions/hooks/useEditCollectionFlow/useEditCollectionFlow'; import { EDIT_TEMPLATES } from '@/pages/Entity/components/Case/components/CaseOptions/hooks/useEditCollectionFlow'; export const useKybExampleBlocksLogic = () => { const { entityId: workflowId } = useParams(); const { data: workflow, isLoading } = useWorkflowByIdQuery({ workflowId: workflowId ?? '', }); const { noAction } = useCaseDecision(); const { data: session } = useAuthenticatedUserQuery(); const caseState = useCaseState(session?.user ?? null, workflow); const { store: _store, bank: _bank, directors: directorsUserProvided = [], mainRepresentative, mainContact: _mainContact, openCorporate: _openCorporate, ...entityDataAdditionalInfo } = workflow?.context?.entity?.data?.additionalInfo ?? {}; const { mutate: mutateEvent, isLoading: isLoadingEvent } = useEventMutation(); const onClose = useCallback( (associatedCompany: ReturnType) => () => { mutateEvent({ workflowId: associatedCompany?.workflowId, event: 'START_ASSOCIATED_COMPANY_KYB', }); window.open(associatedCompany?.collectionFlowUrl, '_blank'); }, [mutateEvent], ); const { mutate: mutateRevisionTaskById, isLoading: isLoadingReuploadNeeded } = useRevisionTaskByIdMutation(); const { mutate: mutateReviseDocumentById, isLoading: isLoadingReviseDocumentById } = useReviseDocumentByIdMutation(); const onReuploadNeeded = useCallback( ({ workflowId, documentId, reason, }: Pick< Parameters[0], 'workflowId' | 'documentId' | 'reason' >) => () => { if (!documentId) { toast.error('Invalid task id'); return; } if (workflow?.workflowDefinition?.config?.isDocumentsV2) { mutateReviseDocumentById({ documentId, decisionReason: reason, }); } if (!workflow?.workflowDefinition?.config?.isDocumentsV2) { mutateRevisionTaskById({ workflowId, documentId, reason, contextUpdateMethod: 'base', }); } }, [ workflow?.workflowDefinition?.config?.isDocumentsV2, mutateReviseDocumentById, mutateRevisionTaskById, ], ); // Blocks const { onEditCollectionFlow: onEditCompanyDetails } = useEditCollectionFlow( EDIT_TEMPLATES.COMPANY_DETAILS, ); const businessInformation = useEntityInfoBlock({ entity: workflow?.context?.entity, workflow, isEditDisabled: [ !caseState.actionButtonsEnabled, !workflow?.tags?.includes(StateTag.MANUAL_REVIEW), !workflow?.workflowDefinition?.config?.editableContext?.entityInfo, ].some(Boolean), onEdit: onEditCompanyDetails, }); const isWorkflowLevelResolution = workflow?.workflowDefinition?.config?.workflowLevelResolution ?? workflow?.context?.entity?.type === 'business'; const { businessDocumentBlocks: documentsBlocks } = useDocumentBlocks({ workflow, parentMachine: workflow?.context?.parentMachine, noAction, withEntityNameInHeader: false, caseState, onReuploadNeeded, isLoadingReuploadNeeded: isLoadingReuploadNeeded || isLoadingReviseDocumentById, // TODO - Remove `CallToActionLegacy` and revisit this object. dialog: { reupload: { Description: () => (

{isWorkflowLevelResolution && ( <> After selecting one or more documents for re-upload, click ‘Ask for all re-uploads’ at the top of the case. This action will open a new tab to simulate the document re-upload request process. Note: In the live environment, requests for document re-uploads are initiated via email to the company’s representative. )} {!isWorkflowLevelResolution && ( <> Click the button below to simulate a document re-upload request process in a new tab. Note: In the live environment, requests for document re-uploads are initiated via email to the company’s representative. )}

), }, }, }); const mainRepresentativeBlock = useMainRepresentativeBlock({ workflow, mainRepresentative, }); const { mutate: mutateRemoveTaskDecisionById } = useRemoveTaskDecisionByIdMutation(workflow?.id); const { mutate: mutateRemoveDocumentDecisionById, isLoading: isLoadingRemoveDocumentDecisionById, } = useRemoveDocumentDecisionByIdMutation(workflow?.id); const { mutate: mutateApproveTaskById, isLoading: isLoadingApproveTaskById } = useApproveTaskByIdMutation(workflow?.id); const { mutate: mutateApproveDocumentById, isLoading: isLoadingApproveDocumentById } = useApproveDocumentByIdMutation(workflow?.id); const onMutateRevisionTaskByIdDirectors = useCallback( ({ directorId, workflowId, documentId, reason, }: Pick< Parameters[0], 'directorId' | 'workflowId' | 'documentId' | 'reason' >) => () => { if (!documentId) { toast.error('Invalid task id'); return; } if (workflow?.workflowDefinition?.config?.isDocumentsV2) { mutateReviseDocumentById({ documentId, decisionReason: reason, }); } if (!workflow?.workflowDefinition?.config?.isDocumentsV2) { mutateRevisionTaskById({ directorId, workflowId, documentId, reason, contextUpdateMethod: 'director', }); } const url = buildCollectionFlowUrl(workflow?.context?.metadata?.collectionFlowUrl, { workflowId: workflow?.id, token: workflow?.context?.metadata?.token, }); window.open(url, '_blank'); }, [ mutateReviseDocumentById, mutateRevisionTaskById, workflow?.id, workflow?.context?.metadata?.token, workflow?.context?.metadata?.collectionFlowUrl, workflow?.workflowDefinition?.config?.isDocumentsV2, ], ); const onMutateApproveTaskByIdDirectors = useCallback( ({ directorId, documentId }: { directorId: string; documentId: string }) => { if (workflow?.workflowDefinition?.config?.isDocumentsV2) { mutateApproveDocumentById({ documentId }); return; } mutateApproveTaskById({ directorId, documentId, contextUpdateMethod: 'director' }); }, [ mutateApproveDocumentById, mutateApproveTaskById, workflow?.workflowDefinition?.config?.isDocumentsV2, ], ); const onMutateRemoveTaskDecisionByIdDirectors = useCallback( ({ directorId, documentId }: { directorId: string; documentId: string }) => { if (workflow?.workflowDefinition?.config?.isDocumentsV2) { mutateRemoveDocumentDecisionById({ documentId }); return; } mutateRemoveTaskDecisionById({ directorId, documentId, contextUpdateMethod: 'director' }); }, [ mutateRemoveTaskDecisionById, mutateRemoveDocumentDecisionById, workflow?.workflowDefinition?.config?.isDocumentsV2, ], ); const directors = workflow?.context?.entity?.data?.additionalInfo?.directors?.map(directorAdapter); const revisionReasons = workflow?.workflowDefinition?.contextSchema?.schema?.properties?.documents?.items?.properties?.decision?.properties?.revisionReason?.anyOf?.find( ({ enum: enum_ }) => !!enum_, )?.enum ?? []; const directorsBlock = createDirectorsBlocks({ workflowId: workflow?.id ?? '', onReuploadNeeded: onMutateRevisionTaskByIdDirectors, onRemoveDecision: onMutateRemoveTaskDecisionByIdDirectors, onApprove: onMutateApproveTaskByIdDirectors, directors, tags: workflow?.tags ?? [], revisionReasons, isEditable: caseState.writeEnabled, isApproveDisabled: isLoadingApproveTaskById, // Remove once callToActionLegacy is removed workflow, }); const kybChildWorkflows = workflow?.childWorkflows?.filter( childWorkflow => childWorkflow?.context?.entity?.type === 'business', ); const associatedCompanies = !kybChildWorkflows?.length && !workflow?.workflowDefinition?.config?.isAssociatedCompanyKybEnabled ? workflow?.context?.entity?.data?.additionalInfo?.associatedCompanies?.map( associatedCompanyToWorkflowAdapter, ) : kybChildWorkflows; const associatedCompaniesBlock = useAssociatedCompaniesBlock({ workflows: associatedCompanies ?? [], dialog: { Trigger: props => ( Initiate KYB ), Title: ({ associatedCompany }) => <>Initiate KYB for {associatedCompany.companyName}, Description: ({ associatedCompany }) => (

Explore our parent KYB Demo. Click the "Open KYB" to launch a simulated KYB process for {associatedCompany?.companyName} in a new tab. Note: In the live environment, the KYB process begins with an email to {associatedCompany?.companyName}'s representative.

), Close: ({ associatedCompany }) => ( <> ), }, isAssociatedCompanyKybEnabled: !!workflow?.workflowDefinition?.config?.isAssociatedCompanyKybEnabled, }); const associatedCompaniesInformationBlock = useAssociatedCompaniesInformationBlock( kybChildWorkflows ?? [], ); // /Blocks const blocks = useMemo(() => { return [ ...businessInformation, ...mainRepresentativeBlock, ...documentsBlocks, ...directorsBlock, ...associatedCompaniesBlock, ...associatedCompaniesInformationBlock, ]; }, [ businessInformation, mainRepresentativeBlock, documentsBlocks, directorsBlock, associatedCompaniesBlock, associatedCompaniesInformationBlock, ]); return { blocks, kybChildWorkflows, workflowId: workflow?.id, parentMachine: workflow?.context?.parentMachine, onReuploadNeeded, isLoadingReuploadNeeded: isLoadingReuploadNeeded || isLoadingReviseDocumentById, isLoading, }; };