From 4684c8ebdb7bdaf65d845451f4f7f120719f2124 Mon Sep 17 00:00:00 2001 From: Omri Levy <61207713+Omri-Levy@users.noreply.github.com> Date: Tue, 22 Aug 2023 14:00:14 +0300 Subject: [PATCH] Blocks api updates (#923) * refactor(backoffice-v2): moved blocks into variables and wrapped blocks in cells prop * fix: fixed registryInfoBlock structure --------- Co-authored-by: Tomer Shvadron --- .../pages/Entity/hooks/useTasks/useTasks.tsx | 577 +++++++++--------- .../plugins/external-plugin/email-plugin.ts | 2 +- 2 files changed, 288 insertions(+), 291 deletions(-) diff --git a/apps/backoffice-v2/src/pages/Entity/hooks/useTasks/useTasks.tsx b/apps/backoffice-v2/src/pages/Entity/hooks/useTasks/useTasks.tsx index 76fddfaa5c..896ec9a412 100644 --- a/apps/backoffice-v2/src/pages/Entity/hooks/useTasks/useTasks.tsx +++ b/apps/backoffice-v2/src/pages/Entity/hooks/useTasks/useTasks.tsx @@ -66,317 +66,314 @@ export const useTasks = ({ const issuerCountryCode = extractCountryCodeFromWorkflow(workflow); const documentsSchemas = !!issuerCountryCode && getDocumentsByCountry(issuerCountryCode); - return useMemo(() => { - return entity - ? [ - ...(Object.keys(pluginsOutput ?? {}).length === 0 - ? [] - : pluginsOutputKeys - ?.filter(key => !!Object.keys(pluginsOutput[key] ?? {})?.length) - ?.map(key => [ - { - id: 'nested-details-heading', - type: 'heading', - value: 'Registry information', - }, - { - type: 'details', - value: { - data: Object.entries(pluginsOutput[key] ?? {})?.map(([title, value]) => ({ - title, - value, - })), - }, - }, - ])), - ...(documents?.map( - ( - { id, type: docType, category, issuer, properties, propertiesSchema, decision }, - docIndex, - ) => { - const additionProperties = - isExistingSchemaForDocument(documentsSchemas) && - composePickableCategoryType(category, docType, documentsSchemas); - - const isDoneWithRevision = - decision?.status === 'revised' && parentMachine?.status === 'completed'; + const registryInfoBlock = + Object.keys(pluginsOutput ?? {}).length === 0 + ? {} + : pluginsOutputKeys + ?.filter(key => !!Object.keys(pluginsOutput[key] ?? {})?.length) + ?.map(key => ({ + cells: [ + { + id: 'nested-details-heading', + type: 'heading', + value: 'Registry information', + }, + { + type: 'details', + value: { + data: Object.entries(pluginsOutput[key] ?? {})?.map(([title, value]) => ({ + title, + value, + })), + }, + }, + ], + })); - const isRevision = - decision?.status === 'revision' && (!isDoneWithRevision || noAction); + const taskBlocks = + documents?.map( + ({ id, type: docType, category, properties, propertiesSchema, decision }, docIndex) => { + const additionProperties = + isExistingSchemaForDocument(documentsSchemas) && + composePickableCategoryType(category, docType, documentsSchemas); - const getDecisionStatusOrAction = ( - isRevision: boolean, - decision: { status: 'revision' | 'rejected' | 'approved'; reason: string }, - ) => { - const badgeClassNames = 'text-sm font-bold'; + const isDoneWithRevision = + decision?.status === 'revised' && parentMachine?.status === 'completed'; - if (isRevision) { - return noAction - ? [ - { - type: 'badge', - value: 'Pending re-upload', - props: { - ...motionProps, - variant: 'warning', - className: badgeClassNames, - }, - }, - ] - : [ - { - type: 'badge', - value: ( - - Re-upload needed - - mutateRevisionTaskById({ documentId: id, decision: null }) - } - /> - - ), - props: { - ...motionProps, - variant: 'warning', - className: `gap-x-1 text-white bg-warning ${badgeClassNames}`, - }, - }, - ]; - } + const isRevision = decision?.status === 'revision' && (!isDoneWithRevision || noAction); - if (decision?.status === 'approved') { - return [ - { - type: 'badge', - value: 'Approved', - props: { - ...motionProps, - variant: 'success', - className: `${badgeClassNames} bg-success/20`, - }, - }, - ]; - } + const getDecisionStatusOrAction = ( + isRevision: boolean, + decision: { status: 'revision' | 'rejected' | 'approved'; reason: string }, + ) => { + const badgeClassNames = 'text-sm font-bold'; - if (decision?.status === 'rejected') { - return [ - { - type: 'badge', - value: 'Rejected', - props: { - ...motionProps, - variant: 'destructive', - className: badgeClassNames, - }, - }, - ]; - } - - return [ + if (isRevision) { + return noAction + ? [ { - type: 'callToAction', - value: 'Reject', - data: { - id, - disabled: (!isDoneWithRevision && Boolean(decision?.status)) || noAction, - decision: 'reject', + type: 'badge', + value: 'Pending re-upload', + props: { + ...motionProps, + variant: 'warning', + className: badgeClassNames, }, }, + ] + : [ { - type: 'callToAction', - value: 'Approve', - data: { - id, - disabled: (!isDoneWithRevision && Boolean(decision?.status)) || noAction, - decision: 'approve', + type: 'badge', + value: ( + + Re-upload needed + mutateRevisionTaskById({ documentId: id, decision: null })} + /> + + ), + props: { + ...motionProps, + variant: 'warning', + className: `gap-x-1 text-white bg-warning ${badgeClassNames}`, }, }, ]; - }; + } - return { - className: isRevision - ? `animate-pending-task shadow-[0_4px_4px_0_rgba(174,174,174,0.0625)] border-[1px] border-warning ${ - noAction ? '' : 'bg-warning/10' - }` - : '', - cells: [ - { - id: 'header', - type: 'container', - value: [ - { - type: 'heading', - value: `${convertSnakeCaseToTitleCase( - category, - )} - ${convertSnakeCaseToTitleCase(docType)}`, - }, - { - id: 'actions', - type: 'container', - value: getDecisionStatusOrAction(isRevision, decision), - }, - ], - }, - { - type: 'container', - value: [ - { - id: 'decision', - type: 'details', - value: { - id, - title: `${category} - ${docType}`, - data: Object.entries( - { - ...additionProperties, - ...propertiesSchema?.properties, - } ?? {}, - )?.map( - ([ - title, - { type, format, pattern, isEditable = true, dropdownOptions, value }, - ]) => { - const fieldValue = value || (properties?.[title] ?? ''); - // if (value === 'bank_statement') { - console.log({ props: propertiesSchema?.properties }); - // } - const isEditableDecision = isDoneWithRevision || !decision?.status; + if (decision?.status === 'approved') { + return [ + { + type: 'badge', + value: 'Approved', + props: { + ...motionProps, + variant: 'success', + className: `${badgeClassNames} bg-success/20`, + }, + }, + ]; + } - return { - title, - value: fieldValue, - type, - format, - pattern, - isEditable: - isEditableDecision && - caseState.writeEnabled && - getIsEditable(isEditable, title), - dropdownOptions, - }; - }, - ), - }, - }, - { - type: 'details', - value: { - id, - title: 'Decision', - data: Object.entries(decision ?? {}).map(([title, value]) => ({ - title, - value, - })), - }, - }, - ], - }, + if (decision?.status === 'rejected') { + return [ + { + type: 'badge', + value: 'Rejected', + props: { + ...motionProps, + variant: 'destructive', + className: badgeClassNames, + }, + }, + ]; + } + + return [ + { + type: 'callToAction', + value: 'Reject', + data: { + id, + disabled: (!isDoneWithRevision && Boolean(decision?.status)) || noAction, + decision: 'reject', + }, + }, + { + type: 'callToAction', + value: 'Approve', + data: { + id, + disabled: (!isDoneWithRevision && Boolean(decision?.status)) || noAction, + decision: 'approve', + }, + }, + ]; + }; + + const headerCell = { + id: 'header', + type: 'container', + value: [ + { + type: 'heading', + value: `${convertSnakeCaseToTitleCase(category)} - ${convertSnakeCaseToTitleCase( + docType, + )}`, + }, + { + id: 'actions', + type: 'container', + value: getDecisionStatusOrAction(isRevision, decision), + }, + ], + }; + + const detailsCell = { + type: 'container', + value: [ + { + id: 'decision', + type: 'details', + value: { + id, + title: `${category} - ${docType}`, + data: Object.entries( { - type: 'multiDocuments', - value: { - isLoading: docsData?.some(({ isLoading }) => isLoading), - data: - documents?.[docIndex]?.pages?.map( - ({ type, metadata, data }, pageIndex) => ({ - title: `${convertSnakeCaseToTitleCase( - category, - )} - ${convertSnakeCaseToTitleCase(docType)}${ - metadata?.side ? ` - ${metadata?.side}` : '' - }`, - imageUrl: - type === 'pdf' - ? octetToFileType( - results[docIndex][pageIndex], - `application/${type}`, - ) - : results[docIndex][pageIndex], - fileType: type, - }), - ) ?? [], - }, + ...additionProperties, + ...propertiesSchema?.properties, + } ?? {}, + )?.map( + ([ + title, + { type, format, pattern, isEditable = true, dropdownOptions, value }, + ]) => { + const fieldValue = value || (properties?.[title] ?? ''); + // if (value === 'bank_statement') { + console.log({ props: propertiesSchema?.properties }); + // } + const isEditableDecision = isDoneWithRevision || !decision?.status; + + return { + title, + value: fieldValue, + type, + format, + pattern, + isEditable: + isEditableDecision && + caseState.writeEnabled && + getIsEditable(isEditable, title), + dropdownOptions, + }; }, - ], - }; + ), + }, }, - ) ?? []), - { - cells: - Object.keys(entity?.data ?? {}).length === 0 - ? [] - : [ - { - type: 'heading', - value: `${toStartCase(entity?.type)} Information`, - }, - { - id: 'entity-details', - type: 'details', - value: { - title: `${toStartCase(entity?.type)} Information`, - data: [ - ...Object.entries( - omitPropsFromObject(entity?.data, 'additionalInfo', 'address') ?? {}, - ), - ...Object.entries(entity?.data?.additionalInfo ?? {}), - ] - ?.map(([title, value]) => ({ - title, - value, - type: 'string', - isEditable: false, - })) - // removing private properties from list (__kyb_snapshot in this case) - // __kyb_snapshot is state of KYB,temp solution - // payload is not for users so removing it - // TO DO: Remove this as soon as BE updated - .filter(elem => !elem.title.startsWith('__')), - }, - }, - ], + { + type: 'details', + value: { + id, + title: 'Decision', + data: Object.entries(decision ?? {}).map(([title, value]) => ({ + title, + value, + })), + }, + }, + ], + }; + + const documentsCell = { + type: 'multiDocuments', + value: { + isLoading: docsData?.some(({ isLoading }) => isLoading), + data: + documents?.[docIndex]?.pages?.map(({ type, metadata, data }, pageIndex) => ({ + title: `${convertSnakeCaseToTitleCase(category)} - ${convertSnakeCaseToTitleCase( + docType, + )}${metadata?.side ? ` - ${metadata?.side}` : ''}`, + imageUrl: + type === 'pdf' + ? octetToFileType(results[docIndex][pageIndex], `application/${type}`) + : results[docIndex][pageIndex], + fileType: type, + })) ?? [], }, - Object.keys(address ?? {})?.length === 0 - ? [] - : [ + }; + + return { + className: isRevision + ? `animate-pending-task shadow-[0_4px_4px_0_rgba(174,174,174,0.0625)] border-[1px] border-warning ${ + noAction ? '' : 'bg-warning/10' + }` + : '', + cells: [headerCell, detailsCell, documentsCell], + }; + }, + ) ?? []; + + const entityInfoBlock = + Object.keys(entity?.data ?? {}).length === 0 + ? {} + : { + cells: [ + { + type: 'heading', + value: `${toStartCase(entity?.type)} Information`, + }, + { + id: 'entity-details', + type: 'details', + value: { + title: `${toStartCase(entity?.type)} Information`, + data: [ + ...Object.entries( + omitPropsFromObject(entity?.data, 'additionalInfo', 'address') ?? {}, + ), + ...Object.entries(entity?.data?.additionalInfo ?? {}), + ] + ?.map(([title, value]) => ({ + title, + value, + type: 'string', + isEditable: false, + })) + // removing private properties from list (__kyb_snapshot in this case) + // __kyb_snapshot is state of KYB,temp solution + // payload is not for users so removing it + // TO DO: Remove this as soon as BE updated + .filter(elem => !elem.title.startsWith('__')), + }, + }, + ], + }; + + const mapBlock = + Object.keys(address ?? {})?.length === 0 + ? {} + : { + cells: [ + { + id: 'map-container', + type: 'container', + value: [ { - id: 'map-container', - type: 'container', - value: [ - { - id: 'header', - type: 'heading', - value: `${toStartCase(entity?.type)} Address`, - }, - { - type: 'details', - value: { - title: `${toStartCase(entity?.type)} Address`, - data: !isObject(address) - ? [ - { - title: 'Address', - value: address, - isEditable: false, - }, - ] - : Object.entries(address ?? {})?.map(([title, value]) => ({ - title, - value, - isEditable: false, - })), - }, - }, - { - type: 'map', - value: address, - }, - ], + id: 'header', + type: 'heading', + value: `${toStartCase(entity?.type)} Address`, + }, + { + type: 'details', + value: { + title: `${toStartCase(entity?.type)} Address`, + data: !isObject(address) + ? [ + { + title: 'Address', + value: address, + isEditable: false, + }, + ] + : Object.entries(address ?? {})?.map(([title, value]) => ({ + title, + value, + isEditable: false, + })), + }, + }, + { + type: 'map', + value: address, }, ], - ] - : []; + }, + ], + }; + + return useMemo(() => { + return entity ? [registryInfoBlock, ...taskBlocks, entityInfoBlock, mapBlock] : []; }, [ address, caseState.writeEnabled, diff --git a/packages/workflow-core/src/lib/plugins/external-plugin/email-plugin.ts b/packages/workflow-core/src/lib/plugins/external-plugin/email-plugin.ts index 8ac143eb74..2f353824bf 100644 --- a/packages/workflow-core/src/lib/plugins/external-plugin/email-plugin.ts +++ b/packages/workflow-core/src/lib/plugins/external-plugin/email-plugin.ts @@ -15,7 +15,7 @@ export class EmailPlugin extends ApiPlugin { payload: AnyRecord, headers: HeadersInit, ) { - const from = { from: {email: payload.from, ...(payload.name ? {name: payload} : {})} }; + const from = { from: { email: payload.from, ...(payload.name ? { name: payload } : {}) } }; const subject = payload.subject ? { subject: this.replaceValuePlaceholders(payload.subject as string, payload) } : {};