From 8414a5b8eb599fdc659c48da215891280da6f950 Mon Sep 17 00:00:00 2001 From: seniorITdev Date: Sat, 13 Jul 2024 04:29:03 +1000 Subject: [PATCH] fixed project AutoComplete --- apps/hpc-ftsadmin/src/app/app.tsx | 13 - .../flow-form-rewrite/flow-context.tsx | 212 -- .../flow-form-rewrite/flow-destination.tsx | 2569 --------------- .../flow-form-rewrite/flow-source.tsx | 2606 --------------- .../flow-form-rewrite/flow-versions.tsx | 2607 --------------- .../components/flow-form-rewrite/flows.tsx | 2628 --------------- .../components/flow-form-rewrite/index.tsx | 2852 ----------------- .../flow-form-rewrite/linked-flows.tsx | 2774 ---------------- .../previous-reporting-details.tsx | 2508 --------------- .../flow-form-rewrite/reporting-details.tsx | 2677 ---------------- .../src/app/components/flow-form.tsx | 117 +- .../add-edit/flow-edit-rewrite/index.tsx | 1865 ----------- .../src/app/pages/add-edit/flow-edit.tsx | 1 - .../src/app/utils/fn-promises-ftsadmin.tsx | 209 ++ .../async-autocomplete-field-ftsadmin.tsx | 307 +- 15 files changed, 311 insertions(+), 23634 deletions(-) delete mode 100644 apps/hpc-ftsadmin/src/app/components/flow-form-rewrite/flow-context.tsx delete mode 100644 apps/hpc-ftsadmin/src/app/components/flow-form-rewrite/flow-destination.tsx delete mode 100644 apps/hpc-ftsadmin/src/app/components/flow-form-rewrite/flow-source.tsx delete mode 100644 apps/hpc-ftsadmin/src/app/components/flow-form-rewrite/flow-versions.tsx delete mode 100644 apps/hpc-ftsadmin/src/app/components/flow-form-rewrite/flows.tsx delete mode 100644 apps/hpc-ftsadmin/src/app/components/flow-form-rewrite/index.tsx delete mode 100644 apps/hpc-ftsadmin/src/app/components/flow-form-rewrite/linked-flows.tsx delete mode 100644 apps/hpc-ftsadmin/src/app/components/flow-form-rewrite/previous-reporting-details.tsx delete mode 100644 apps/hpc-ftsadmin/src/app/components/flow-form-rewrite/reporting-details.tsx delete mode 100644 apps/hpc-ftsadmin/src/app/pages/add-edit/flow-edit-rewrite/index.tsx create mode 100644 apps/hpc-ftsadmin/src/app/utils/fn-promises-ftsadmin.tsx diff --git a/apps/hpc-ftsadmin/src/app/app.tsx b/apps/hpc-ftsadmin/src/app/app.tsx index d92abca92..5581781bf 100644 --- a/apps/hpc-ftsadmin/src/app/app.tsx +++ b/apps/hpc-ftsadmin/src/app/app.tsx @@ -32,7 +32,6 @@ import PagePendingFlowsList from './pages/flows/pending-flows-list'; import PageOrganizationsList from './pages/organizations/organization-list'; import PageOrganization from './pages/organizations/organization'; import FlowEdit from './pages/add-edit/flow-edit'; -import FlowEditRewrite from './pages/add-edit/flow-edit-rewrite/index'; import * as paths from './paths'; import { RouteParamsValidator } from './components/route-params-validator'; import { QueryParamProvider } from 'use-query-params'; @@ -273,18 +272,6 @@ const router = createBrowserRouter( path={paths.editFlow()} element={} /> - } - /> - } - /> - } - /> } /> ) diff --git a/apps/hpc-ftsadmin/src/app/components/flow-form-rewrite/flow-context.tsx b/apps/hpc-ftsadmin/src/app/components/flow-form-rewrite/flow-context.tsx deleted file mode 100644 index e3b22a75a..000000000 --- a/apps/hpc-ftsadmin/src/app/components/flow-form-rewrite/flow-context.tsx +++ /dev/null @@ -1,212 +0,0 @@ -import dayjs from 'dayjs'; -import React, { - createContext, - useState, - ReactNode, - Dispatch, - SetStateAction, - useEffect, -} from 'react'; - -interface FlowContextType { - flowValue: any; - setFlowValue: Dispatch>; - initialValue: any; - isEdit: any; - currentVersionData: any; - environment: any; - prevDetails: any; - versionData: any; - isRestricted: any; - errorCorrection: any; - inputEntries: any; - flowId: any; - versionId: any; - initializeInputEntries: any; - rejectInputEntry: any; - currentVersionID: any; - currentFlowID: any; - currentVersionActiveStatus: any; - isPending: any; - isSuperseded: any; - isCancelled: any; - isCancellation: any; - isNewPending: any; - isUpdatePending: any; - canReactive: any; - pendingFieldsAllApplied: any; - allFieldsReviewed: any; - pendingVersionV1: any; -} - -const initialValueFormat = { - amountUSD: '', - amountOriginal: '', - exchangeRateUsed: '', - keywords: [], - flowStatus: '', - flowType: { value: 133, displayLabel: 'Standard' }, - flowDescription: '', - firstReported: dayjs().format('DD/MM/YYYY'), - decisionDate: null, - budgetYear: '', - flowDate: null, - contributionType: { value: 50, displayLabel: 'Financial' }, - earmarkingType: '', - method: { value: 156, displayLabel: 'Traditional aid' }, - cashTransfer: '', - beneficiaryGroup: '', - inactiveReason: '', - notes: '', - sourceOrganizations: [], - sourceLocations: [], - sourceUsageYears: [], - sourceProjects: [], - sourcePlans: [], - sourceGoverningEntities: [], - sourceGlobalClusters: [], - sourceEmergencies: [], - destinationOrganizations: [], - destinationLocations: [], - destinationUsageYears: [], - destinationProjects: [], - destinationPlans: [], - destinationGoverningEntities: [], - destinationGlobalClusters: [], - destinationEmergencies: [], - origCurrency: '', - includeChildrenOfParkedFlows: true, - reportDetails: [ - { - verified: 'verified', - reportSource: 'primary', - reporterReferenceCode: '', - reportChannel: '', - reportedOrganization: { value: '', displayLabel: '' }, - reportedDate: null, - reporterContactInformation: '', - sourceSystemRecordId: '', - reportFiles: [ - { - title: '', - fileName: '', - UploadFileUrl: '', - size: 0, - type: '', - }, - ], - reportFileTitle: '', - reportUrlTitle: '', - reportUrl: '', - }, - ], - parentFlow: [], - childFlow: [], - isParkedParent: false, - sources: {}, -}; - -const FlowContext = createContext(undefined); - -const FlowContextProvider: React.FC<{ - children: ReactNode; - initialValue: any; - isEdit: any; - currentVersionData: any; - environment: any; - prevDetails: any; - versionData: any; - isRestricted: any; - errorCorrection: any; - inputEntries: any; - flowId: any; - versionId: any; - initializeInputEntries: any; - rejectInputEntry: any; - currentVersionID: any; - currentFlowID: any; - currentVersionActiveStatus: any; - isPending: any; - isSuperseded: any; - isCancelled: any; - isCancellation: any; - isNewPending: any; - isUpdatePending: any; - canReactive: any; - pendingFieldsAllApplied: any; - allFieldsReviewed: any; - pendingVersionV1: any; -}> = ({ - children, - initialValue, - isEdit, - currentVersionData, - environment, - prevDetails, - versionData, - isRestricted, - errorCorrection, - inputEntries, - flowId, - versionId, - initializeInputEntries, - rejectInputEntry, - currentVersionID, - currentFlowID, - currentVersionActiveStatus, - isPending, - isSuperseded, - isCancelled, - isCancellation, - isNewPending, - isUpdatePending, - canReactive, - pendingFieldsAllApplied, - allFieldsReviewed, - pendingVersionV1, -}) => { - const [flowValue, setFlowValue] = useState(initialValueFormat); - - useEffect(() => { - setFlowValue(initialValue); - }, [initialValue]); - - return ( - - {children} - - ); -}; - -export { FlowContextProvider, FlowContext }; diff --git a/apps/hpc-ftsadmin/src/app/components/flow-form-rewrite/flow-destination.tsx b/apps/hpc-ftsadmin/src/app/components/flow-form-rewrite/flow-destination.tsx deleted file mode 100644 index ddf200abe..000000000 --- a/apps/hpc-ftsadmin/src/app/components/flow-form-rewrite/flow-destination.tsx +++ /dev/null @@ -1,2569 +0,0 @@ -import React, { - ChangeEvent, - useState, - useEffect, - useCallback, - useRef, - useContext, -} from 'react'; -import { Form, Formik, FieldArray } from 'formik'; -import tw from 'twin.macro'; -import dayjs from 'dayjs'; -import { isRight } from 'fp-ts/Either'; -import { FormikErrors } from 'formik'; -import * as t from 'io-ts'; -import { util as codecs } from '@unocha/hpc-data'; -import GppMaybeIcon from '@mui/icons-material/GppMaybe'; -import Button from '@mui/material/Button'; -import DeleteIcon from '@mui/icons-material/Delete'; -import Stack from '@mui/material/Stack'; -import ContentCopyIcon from '@mui/icons-material/ContentCopy'; -import MuiAlert from '@mui/material/Alert'; -import AlertTitle from '@mui/material/AlertTitle'; -import _, { set, values } from 'lodash'; -import useSharePath from '../Hooks/SharePath'; -import { C, dialogs } from '@unocha/hpc-ui'; -import { - Table, - TableBody, - TableCell, - TableContainer, - TableHead, - TableRow, - Paper, - Alert, - IconButton, -} from '@mui/material'; -import CloseIcon from '@mui/icons-material/Close'; -import { Environment } from '../../../environments/interface'; -import { MdAdd, MdRemove, MdClose, MdCheck } from 'react-icons/md'; -import { - usageYears, - forms, - governingEntities, - fileUpload, - flows as flowsResponse, -} from '@unocha/hpc-data'; -import { getEnv } from '../../context'; -import { editFlowSetting, copyFlow } from '../../paths'; -import { flows } from '../../paths'; -import Link from '@mui/material/Link'; -import { useNavigate, unstable_usePrompt } from 'react-router-dom'; -import { id } from 'fp-ts/lib/Refinement'; -import { FlowContext } from './flow-context'; - -export type AutoCompleteSelectionType = forms.InputSelectValueType; - -const INPUT_SELECT_VALUE_TYPE = forms.INPUT_SELECT_VALUE_TYPE; - -type UniqueDataType = { - [key: string]: string[]; -}; - -export interface DeleteFlowParams { - VersionID: number; - FlowID: number; -} - -export interface categoryType { - value: string | number; - displayLabel: string; - parentID: number | null; -} - -export interface FileAssetEntityType { - collection?: string; - createAt?: string; - filename?: string; - id?: number; - mimetype?: string; - originalname?: string; - path?: string; - size?: number; - updatedAt?: string; -} -export interface ReportFileType { - title?: string; - fileName?: string; - UploadFileUrl?: string; - type?: string; - url?: string; - fileAssetID?: number; - size?: number; - fileAssetEntity?: FileAssetEntityType; -} -export interface ReportDetailType { - verified: string; - reportSource: string; - reporterReferenceCode: string; - reportChannel: AutoCompleteSelectionType | ''; - reportedOrganization: AutoCompleteSelectionType; - reportedDate: string; - reporterContactInformation: string; - sourceSystemRecordId: string; - reportFiles: ReportFileType[]; - reportFileTitle?: string; - reportUrlTitle?: string; - reportUrl?: string; - versionId?: number; - fileAsset?: FileAssetEntityType; -} - -export interface ParentFlowType { - value: any; -} - -export interface FormValues { - id: string | null; - amountUSD: number; - keywords: AutoCompleteSelectionType[]; - flowStatus: AutoCompleteSelectionType | ''; - flowType: AutoCompleteSelectionType | ''; - flowDescription: string; - firstReported: string; - decisionDate: string | null; - budgetYear: string; - flowDate: string; - contributionType: AutoCompleteSelectionType | ''; - earmarkingType: AutoCompleteSelectionType | ''; - method: AutoCompleteSelectionType | ''; - cashTransfer: AutoCompleteSelectionType | ''; - beneficiaryGroup: AutoCompleteSelectionType | ''; - inactiveReason: any[] | string; - childMethod: object; - origCurrency: AutoCompleteSelectionType | string; - amountOriginal: number | null; - exchangeRateUsed: number | null; - notes: string; - sourceOrganizations: AutoCompleteSelectionType[]; - sourceLocations: AutoCompleteSelectionType[]; - sourceUsageYears: AutoCompleteSelectionType[]; - sourceProjects: AutoCompleteSelectionType[]; - sourcePlans: AutoCompleteSelectionType[]; - sourceGoverningEntities: AutoCompleteSelectionType[]; - sourceGlobalClusters: AutoCompleteSelectionType[]; - sourceEmergencies: AutoCompleteSelectionType[]; - destinationOrganizations: AutoCompleteSelectionType[]; - destinationLocations: AutoCompleteSelectionType[]; - destinationUsageYears: AutoCompleteSelectionType[]; - destinationProjects: AutoCompleteSelectionType[]; - destinationPlans: AutoCompleteSelectionType[]; - destinationGoverningEntities: AutoCompleteSelectionType[]; - destinationGlobalClusters: AutoCompleteSelectionType[]; - destinationEmergencies: AutoCompleteSelectionType[]; - reportDetails: ReportDetailType[]; - parentFlow?: AutoCompleteSelectionType[]; - childFlow?: AutoCompleteSelectionType[]; - isParkedParent?: boolean; - includeChildrenOfParkedFlows: boolean; - isErrorCorrectionValue: boolean; - sources?: Record; - submitAction?: string | undefined; - versions?: { - id: number | null; - isPending: boolean | null; - }[]; -} - -export interface VersionDataType { - versionId: number; - flowId: number; - createdTime: string; - createdBy: string | null; - updatedTime: string; - updatedBy: string | null; - active: boolean; - viewing: boolean; - pending?: boolean; - [key: string]: - | string - | number - | null - | boolean - | string[] - | Date - | undefined - | Record; - source: UniqueDataType; - destination: UniqueDataType; - categories: string[]; - uniqueSources: UniqueDataType; - uniqueDestinations: UniqueDataType; - uniqueCategories: string[]; - restricted?: boolean; -} - -export interface InputEntriesType { - amountUSD: forms.InputEntryType | null; - origCurrency: forms.InputEntryType | null; - keywords: forms.InputEntryType | null; - flowStatus: forms.InputEntryType | null; - flowType: forms.InputEntryType | null; - flowDescription: forms.InputEntryType | null; - contributionType: forms.InputEntryType | null; - earmarkingType: forms.InputEntryType | null; - method: forms.InputEntryType | null; - beneficiaryGroup: forms.InputEntryType | null; - inactiveReason: forms.InputEntryType | null; - amountOriginal: forms.InputEntryType | null; - exchangeRateUsed: forms.InputEntryType | null; - notes: forms.InputEntryType | null; - sourceOrganizations: forms.InputEntryType[]; - sourceLocations: forms.InputEntryType[]; - sourceUsageYears: forms.InputEntryType[]; - sourceProjects: forms.InputEntryType[]; - sourcePlans: forms.InputEntryType[]; - sourceGoverningEntities: forms.InputEntryType[]; - sourceGlobalClusters: forms.InputEntryType[]; - sourceEmergencies: forms.InputEntryType[]; - destinationOrganizations: forms.InputEntryType[]; - destinationLocations: forms.InputEntryType[]; - destinationUsageYears: forms.InputEntryType[]; - destinationProjects: forms.InputEntryType[]; - destinationPlans: forms.InputEntryType[]; - destinationGoverningEntities: forms.InputEntryType[]; - destinationGlobalClusters: forms.InputEntryType[]; - destinationEmergencies: forms.InputEntryType[]; - parentFlow: forms.InputEntryType | null; - childFlow: forms.InputEntryType[]; -} - -type UploadedItem = fileUpload.FileUploadResult | FileAssetEntityType; - -const reportChannelSchema = t.type({ - value: t.intersection([codecs.NON_EMPTY_STRING, t.string]), - displayLabel: t.intersection([codecs.NON_EMPTY_STRING, t.string]), -}); - -const reportDetailsSchema = t.type({ - reportedOrganization: INPUT_SELECT_VALUE_TYPE, - reportedDate: t.intersection([codecs.NON_EMPTY_STRING, t.string]), - reportChannel: t.intersection([codecs.NON_EMPTY_STRING, reportChannelSchema]), - reportFileTitle: t.intersection([codecs.NON_EMPTY_STRING, t.string]), -}); - -const validationSchema = t.type({ - amountUSD: t.number, - flowStatus: INPUT_SELECT_VALUE_TYPE, - flowDescription: t.intersection([codecs.NON_EMPTY_STRING, t.string]), - firstReported: t.string, - flowDate: t.intersection([codecs.NON_EMPTY_STRING, t.string]), - sourceOrganizations: INPUT_SELECT_VALUE_TYPE, - sourceUsageYears: INPUT_SELECT_VALUE_TYPE, - destinationOrganizations: INPUT_SELECT_VALUE_TYPE, - destinationUsageYears: INPUT_SELECT_VALUE_TYPE, - reportDetails: reportDetailsSchema, -}); - -interface Props { - currentVersionData: flowsResponse.FlowREST | null; - environment: Environment; - isEdit: boolean; - initialValue: FormValues; - prevDetails?: ReportDetailType[]; - versionData?: VersionDataType[]; - flowId?: string; - versionId?: string; - isRestricted: boolean; - errorCorrection?: boolean; - inputEntries: InputEntriesType; - initializeInputEntries: () => void; - rejectInputEntry: (key: string) => void; - currentVersionID?: number; - currentFlowID?: number; - currentVersionActiveStatus?: boolean; - isPending?: boolean; - isSuperseded?: boolean; - isCancelled?: boolean; - isCancellation?: boolean; - isNewPending?: boolean; - isUpdatePending?: boolean; - canReactive?: boolean; - isErrorCorrection?: boolean | null; - isApprovedFlowVersion?: boolean | null; - pendingFieldsAllApplied?: boolean; - allFieldsReviewed?: boolean; - pendingVersionV1?: boolean; -} - -const StyledRepOrgLink = tw.div` - flex - ml-1 -`; - -const StyledAddChildWarning = tw.div` - border border-solid border-yellow-600 - flex - rounded-md - text-gray-900 - bg-yellow-100 bg-opacity-50 -`; - -const StyledAddChildWarningIconDiv = tw.div` - flex - items-center - p-1 -`; -const StyledAddChildWarningText = tw.span` - py-3 px-3 pb-3 -`; -const StyledLayoutRow = tw.div` -flex -`; -const StyledHalfSection = tw.div` -w-1/2 -`; -const StyledFullSection = tw.div` -w-full -mb-6 -`; -const StyledRow = tw.div` -flex -gap-4 -w-full -`; -const StyledFormRow = tw.div` -flex -gap-2 -w-full -items-center -`; -const StyledAnchor = tw.a` -underline -ml-[15px] -opacity-100 -`; -const StyledAnchorDiv = tw.div` -text-right -w-full -`; -const StyledRadioDiv = tw.div` -relative -w-full -`; -const StyledFieldset = tw.fieldset` -w-full -box-border -rounded-xl -mt-[16px] -mb-[8px] -border-gray-100 -`; -const StyledCurrencyRow = tw.div` -w-1/2 -`; -const StyledFormButton = tw(C.Button)` -ml-[25px] -mb-6 -`; -const StyledLabel = tw.label` -block -my-4 -`; -const StyledLinkedFlowRow = tw.div` -mt-4 -`; - -const StyledParentInfo = tw.div` -border-0 -border-b -border-solid -cursor-pointer -mb-4 -pb-4 -`; - -const StyledStrong = tw.strong` -min-w-[16rem] -inline-block -`; - -const StyledList = tw.li` -list-none -`; - -const StyledDiv = tw.div` -my-6 -me-4 -mr-[23px] -lg:flex -justify-end -gap-x-4 -bg-white -z-10 -`; - -const initialReportDetail = { - verified: 'verified', - reportSource: 'primary', - reporterReferenceCode: '', - reportChannel: '', - reportFileTitle: '', - reportedOrganization: { value: '', displayLabel: '' }, - reportedDate: dayjs().format('DD/MM/YYYY'), - reporterContactInformation: '', - sourceSystemRecordId: '', -}; - -const FORM_SETTINGS = { - organization: { - behavior: 'shared', - }, - project: { - behavior: 'overlap', - }, - usageYear: { - behavior: 'shared', - }, - location: { - behavior: 'shared', - }, - globalCluster: { - behavior: 'shared', - }, - emergency: { - behavior: 'overlap', - }, - governingEntity: { - behavior: 'shared', - }, - plan: { - behavior: 'overlap', - }, -}; - -const objectTypes = [ - 'emergencies', - 'projects', - 'usageYears', - 'globalClusters', - 'locations', - 'plans', - 'organizations', -] as const; - -const flowValuesForDisplay = [ - 'amountUSD', - 'flowDate', - 'decisionDate', - 'firstReportedDate', - 'budgetYear', - 'origAmount', - 'origCurrency', - 'exchangeRate', - 'activeStatus', - 'restricted', - 'newMoney', - 'description', - 'notes', -] as const; - -let parentValue = ''; - -export const FlowDestination = () => { - const { - flowValue, - setFlowValue, - initialValue, - isEdit, - currentVersionData, - environment, - prevDetails, - versionData, - isRestricted, - errorCorrection, - inputEntries, - flowId, - versionId, - initializeInputEntries, - rejectInputEntry, - currentVersionID, - currentFlowID, - currentVersionActiveStatus, - isPending, - isSuperseded, - isCancelled, - isCancellation, - isNewPending, - isUpdatePending, - canReactive, - pendingFieldsAllApplied, - allFieldsReviewed, - pendingVersionV1, - }: any = useContext(FlowContext); - // const { - // currentVersionData, - // environment, - // initialValue, - // isEdit, - // prevDetails, - // versionData, - // isRestricted, - // errorCorrection, - // inputEntries, - // flowId, - // versionId, - // initializeInputEntries, - // rejectInputEntry, - // currentVersionID, - // currentFlowID, - // currentVersionActiveStatus, - // isPending, - // isSuperseded, - // isCancelled, - // isCancellation, - // isNewPending, - // isUpdatePending, - // canReactive, - // pendingFieldsAllApplied, - // allFieldsReviewed, - // pendingVersionV1, - // } = props; - const { confirm } = dialogs; - const env = getEnv(); - - const collapseFlowObjects = (data: any) => { - data.flowObjects = []; - - collapsePerBehavior(data.dest, 'destination'); - collapsePerBehavior(data.src, 'source'); - - function collapsePerBehavior(behaviorArr: any, ref: any) { - Object.keys(behaviorArr).forEach((type) => { - behaviorArr[type].forEach((obj: any) => { - if ( - obj !== null && - (!Object.prototype.hasOwnProperty.call(obj, 'cleared') || - !obj.cleared) - ) { - if (type === 'organization') { - obj.objectDetail = obj.implementingPartner ? 'partner' : null; - } - - const flowObj = { - refDirection: ref, - objectType: type, - objectID: obj.id, - behavior: obj.behavior || null, - objectDetail: obj.objectDetail, - }; - data.flowObjects.push(flowObj); - } - }); - }); - } - - return data as any; - }; - - const collapseCategories = (data: any) => { - data.categories = [ - data.flowType, - data.flowStatuses, - data.contributionTypes, - data.method, - data.childMethod, - data.keywords, - data.inactiveReason, - data.beneficiaryGroup, - data.pendingStatus, - data.earmarking !== null && data.earmarking.id, - ].filter((category) => category); - data.categories = data.categories - .map((value: any) => { - if (value && value.id) { - return value.id; - } else if (value[0]) { - return value[0].id; - } - }) - .filter(function (value: any) { - return value; - }) - .map((value: any) => { - return parseInt(value); - }); - - return data; - }; - const [uploadFileFlag, setUploadFileFlag] = useState(false); - const [uploadFlag, setUploadFlag] = useState(false); - const normalizeFlowData = (values: FormValues) => { - const fundingObject = { - src: { - governingEntity: values.sourceGoverningEntities.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - location: values.sourceLocations.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - organization: values.sourceOrganizations.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - project: values.sourceProjects.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - usageYear: values.sourceUsageYears.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - globalCluster: values.sourceGlobalClusters.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - emergency: values.sourceEmergencies.map((item) => ({ - id: item.value, - name: item.displayLabel, - restricted: item.restricted, - })), - plan: values.sourcePlans.map((item) => ({ - id: item.value, - name: item.displayLabel, - restricted: item.restricted, - })), - }, - dest: { - governingEntity: values.destinationGoverningEntities.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - location: values.destinationLocations.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - organization: values.destinationOrganizations.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - project: values.destinationProjects.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - usageYear: values.destinationUsageYears.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - globalCluster: values.destinationGlobalClusters.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - emergency: values.destinationEmergencies.map((item) => ({ - id: item.value, - name: item.displayLabel, - restricted: item.restricted, - })), - plan: values.destinationPlans.map((item) => ({ - id: item.value, - name: item.displayLabel, - restricted: item.restricted, - })), - }, - }; - - let data = { - id: isEdit && currentFlowID ? currentFlowID : null, - versionID: isEdit && currentVersionID ? currentVersionID : null, - amountUSD: values.amountUSD, - flowDate: dayjs(values.flowDate, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ), - decisionDate: values.decisionDate - ? dayjs(values.decisionDate, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ) - : null, - firstReportedDate: dayjs(values.firstReported, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ), - budgetYear: values.budgetYear, - origAmount: values.amountOriginal ? values.amountOriginal : null, - origCurrency: (values.origCurrency as AutoCompleteSelectionType) - ? (values.origCurrency as AutoCompleteSelectionType)?.displayLabel - : null, - exchangeRate: values.exchangeRateUsed ? values.exchangeRateUsed : null, - activeStatus: true, - restricted: false, - newMoney: true, - description: values.flowDescription, - versionStartDate: currentVersionData?.versionStartDate, - versionEndDate: currentVersionData?.versionEndDate, - flowObjects: collapseFlowObjects(fundingObject), - children: - values.childFlow && - values.childFlow.map((item: any, index: number) => { - return { - childID: JSON.parse(item.value as string).id, - origCurrency: JSON.parse(item.value as string).origCurrency, - }; - }), - parents: - values.parentFlow && - values.parentFlow.map((item: any, index: number) => { - return { - Parent: { - parentID: JSON.parse(item.value as string).id, - origCurrency: JSON.parse(item.value as string).origCurrency, - }, - childID: currentFlowID, - parentID: JSON.parse(item.value as string).id, - origCurrency: JSON.parse(item.value as string).origCurrency, - id: JSON.parse(item.value as string).id, - parents: - values.parentFlow && - values.parentFlow.map((key: any) => { - return { - child: JSON.parse(key.value as string).id, - parentID: 271736, - }; - }), - }; - }), - reportDetails: values.reportDetails.map((item, index) => { - return { - contactInfo: item.reporterContactInformation, - source: item.reportSource, - date: dayjs(item.reportedDate, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ), - versionID: currentVersionID, - newlyAdded: addReportFlag, - sourceID: null, - refCode: '7F-10073.04', - verified: true, - organizationID: item.reportedOrganization.value, - categories: [item.reportChannel && item.reportChannel.value], - organization: { - id: item.reportedOrganization.value, - name: item.reportedOrganization.displayLabel, - }, - reportFiles: - uploadFlag && - uploadedFileArray[index] && - (uploadedFileArray[index] as { id?: number })?.id - ? uploadFlag || uploadFileFlag - ? [ - { - title: item.reportUrlTitle, - type: 'url', - url: item.reportUrl, - }, - { - fileAssetID: - uploadedFileArray[index] && - (uploadedFileArray[index] as { id?: number })?.id, - reportFiles: [ - { - fieldType: 'file', - fileAssetID: - uploadedFileArray[index] && - (uploadedFileArray[index] as { id?: number })?.id, - type: 'file', - }, - ], - title: item.reportFileTitle, - type: 'file', - }, - ] - : [ - { - title: item.reportUrlTitle, - type: 'url', - url: item.reportUrl, - }, - ] - : uploadFileFlag - ? [ - { - title: item.reportUrlTitle, - type: 'url', - url: item.reportUrl, - }, - ] - : item.reportFiles - ? item.reportFiles - : [], - - reportChannel: { - group: 'reportChannel', - id: item.reportChannel && item.reportChannel.value, - name: item.reportChannel && item.reportChannel.displayLabel, - }, - }; - }), - flowType: { - id: values.flowType && values.flowType.value, - name: values.flowType && values.flowType.displayLabel, - group: 'flowType', - }, - keywords: values.keywords.map((item) => ({ - id: item.value, - name: item.displayLabel, - group: 'keywords', - })), - flowStatuses: { - id: values.flowStatus && values.flowStatus.value, - name: values.flowStatus && values.flowStatus.displayLabel, - group: 'flowStatus', - }, - contributionTypes: { - id: values.contributionType && values.contributionType.value, - name: values.contributionType && values.contributionType.displayLabel, - group: 'contributionType', - }, - method: { - id: values.method && values.method.value, - name: values.method && values.method.displayLabel, - group: 'method', - }, - childMethod: values.cashTransfer && { - id: values.cashTransfer.value, - name: values.cashTransfer.displayLabel, - group: 'method', - parentID: values.method && values.method.value, - }, - earmarking: values.earmarkingType - ? { - id: values.earmarkingType.value, - name: values.earmarkingType.displayLabel, - group: 'earmarkingType', - } - : null, - categories: [] as (string | number)[], - isCancellation: isPending ? true : !isPending ? false : null, - cancelled: isPending && isCancellation ? true : null, - pendingStatus: isPending ? true : !isPending ? false : [], - planEntities: isPending ? true : !isPending ? false : [], - planIndicated: isPending ? true : !isPending ? false : [], - isApprovedFlowVersion: - rejectFlag && approveFlag - ? true - : !(rejectFlag && approveFlag) - ? false - : null, - inactiveReason: [ - { - id: null as null | number | string, - name: '' as string | undefined, - description: null, - parentID: null, - code: null, - group: '', - includeTotals: null, - createdAt: '', - updatedAt: '', - }, - ], - isErrorCorrection: errorCorrection - ? true - : isSuperseded - ? true - : isPending - ? true - : !isSuperseded && !isPending - ? false - : null, - rejected: rejectFlag ? true : !rejectFlag ? false : null, - versions: - versionData && - versionData.map((item: VersionDataType) => { - const items = { - id: item.flowId, - versionID: item.versionId, - activeStatus: item.activeStatus, - isPending: item.isPending ? item.isPending : false, - isCancelled: item.isCancelled ? item.isCancelled : false, - }; - return items; - }), - ...fundingObject, - }; - - data = collapseCategories(data); - return data; - }; - - const [unsavedChange, setUnsavedChange] = useState(false); - const [parentCurrencyFlag, setParentCurrencyFlag] = useState(false); - const [childCurrencyFlag, setChildCurrencyFlag] = useState(false); - const [approveFlag, setApproveFlag] = useState(false); - const [rejectFlag, setRejectFlag] = useState(false); - const [validationFlag, setValidationFlag] = useState(false); - const [inactiveFlag, setInactiveFlag] = useState(false); - const [uploadedFileArray, setUploadedFileArray] = useState([ - {}, - ]); - const [addReportFlag, setAddReportFlag] = useState(false); - const [alertFlag, setAlertFlag] = useState(false); - const [sharePath, setSharePath] = useSharePath(''); - const [readOnly, setReadOnly] = useState(false); - const [linkCheck, setLinkCheck] = useState(false); - const handleSave = () => { - window.scrollTo({ top: 0, behavior: 'smooth' }); - }; - - const [showWarningMessage, setShowWarningMessage] = useState(false); - const [objects, setObjects] = useState>({}); - const [showingTypes, setShowingTypes] = useState([]); - const [newMoneyCheckboxDisabled, setNewMoneyCheckboxDisabled] = - useState(false); - - const [comparingVersions, setComparingVersions] = useState( - [] - ); - const [comparedVersions, setComparedVersions] = useState( - [] - ); - const [showSourceGoverningEntities, handleShowSourceGoverningEntities] = - useState(false); - const [ - showDestinationGoverningEntities, - handleShowDestinationGoverningEntities, - ] = useState(false); - const [sourceGoverningEntities, setSourceGoverningEntities] = - useState([]); - const [destinationGoverningEntities, setDestinationGoverningEntities] = - useState([]); - const [isShowParentFlow, setShowParentFlow] = useState( - initialValue.parentFlow && initialValue.parentFlow.length ? true : false - ); - const [isShowChildFlow, setShowChildFlow] = useState(0); - const [openAlerts, setOpenAlerts] = useState< - { message: string; id: number }[] - >([]); - const [alertId, setAlertId] = useState(0); - const handleClose = (id: number) => { - setOpenAlerts(openAlerts.filter((alert) => alert.id !== id)); - }; - const buttonText = 'Calculate The Exchange Rate'; - - const handleCalculateExchangeRate = (values: any, setFieldValue: any) => { - const { amountOriginal, amountUSD } = values; - - if (amountOriginal && amountUSD) { - const exchangeRateUsed = amountOriginal / amountUSD; - setFieldValue('exchangeRateUsed', exchangeRateUsed.toFixed(4)); - } else if (amountOriginal && !amountUSD) { - const calculatedAmountUSD = amountOriginal / values.exchangeRateUsed; - setFieldValue('amountUSD', calculatedAmountUSD.toFixed(4)); - } else if (!amountOriginal && amountUSD) { - const calculatedAmountOriginal = amountUSD * values.exchangeRateUsed; - setFieldValue('amountOriginal', calculatedAmountOriginal.toFixed(4)); - } else { - console.warn('Both original amount and USD amount are missing.'); - } - }; - useEffect(() => { - if (initialValue?.childFlow) { - setShowChildFlow(initialValue?.childFlow.length); - } - }, [initialValue]); - useEffect(() => { - const fileAssets: FileAssetEntityType[] = []; - if (isEdit) { - initialValue.reportDetails.forEach((detail: any) => { - if (detail?.fileAsset) { - fileAssets.push(detail.fileAsset); - setUploadedFileArray(fileAssets); - } else { - fileAssets.push({} as FileAssetEntityType); - setUploadedFileArray(fileAssets); - } - }); - } - }, [initialValue.reportDetails]); - useEffect(() => { - if (currentVersionActiveStatus) { - setReadOnly(false); - } else { - setReadOnly(true); - } - }, [currentVersionActiveStatus]); - useEffect(() => { - if (initialValue.parentFlow && initialValue.parentFlow.length) { - setShowParentFlow(true); - } - }, [initialValue.parentFlow]); - const [remove, setRemove] = useState(false); - const handleRemove = (index: number, values: FormValues) => { - if (window.confirm('Are you sure you want to remove this file?')) { - if ( - initialValue.reportDetails[index].reportFiles && - initialValue.reportDetails[index].reportFiles[0]?.fileName - ) { - values.reportDetails[index].reportFileTitle = ''; - initialValue.reportDetails[index].reportFiles[0].fileName = ''; - initialValue.reportDetails[index].reportFiles[0].title = ''; - initialValue.reportDetails[index].reportFiles[0].fileAssetID = - undefined; - initialValue.reportDetails[index].reportFiles[0].UploadFileUrl = ''; - const updatedArray = removeByIndexFromArray(uploadedFileArray, index); - setUploadedFileArray(updatedArray); - } else return; - setUploadFlag(false); - setRemove(true); - } else return; - }; - const removeByIndexFromArray = (array: UploadedItem[], index: number) => { - const newArray = [...array]; - newArray[index] = {}; - return newArray; - }; - if (remove === true) setRemove(false); - const SourceLink = ( - setFieldValue: any, - values: FormValues, - indexKey: number, - index: number - ) => { - setFieldValue( - `reportDetails[${index}].reportedOrganization`, - values.sourceOrganizations[indexKey] - ); - }; - const DestinationLink = ( - setFieldValue: any, - values: FormValues, - indexKey: number, - index: number - ) => { - setFieldValue( - `reportDetails[${index}].reportedOrganization`, - values.destinationOrganizations[indexKey] - ); - }; - - interface Inconsistency { - type: string; - values: { - name?: string; - year?: string; - refDirection: string; - options?: { name: string }[]; - }[]; - } - - const processDataInconsistencies = ( - inconsistencyArray: Inconsistency[] - ): string => { - let message = ''; - inconsistencyArray.forEach((inconsistencyWith) => { - if (inconsistencyWith && inconsistencyWith.type) { - const inconsistencyType = inconsistencyWith.type; - message += - inconsistencyType.charAt(0).toUpperCase() + - inconsistencyType.slice(1) + - ': '; - - if (inconsistencyWith.type === 'no-direct-link') { - message += inconsistencyWith.values.join(', '); - } else { - message += - inconsistencyWith.values - .map((value) => { - const name = value.name || value.year; - let joinedOptions = ''; - if (value.options) { - joinedOptions = value.options - .map((option) => { - return option.name || JSON.stringify(option); - }) - .join(', '); - } - const options = `is not in the list of acceptable ${value.refDirection} ${inconsistencyType}: [${joinedOptions}]`; - return `'${name}' ${options}`; - }) - .join(', ') + '. '; - } - } else { - message += JSON.stringify(inconsistencyArray); - } - }); - return message; - }; - - const handleSubmit = async ( - values: FormValues, - submitAction: string | undefined - ) => { - if (values.childFlow) { - for (let i = 0; i < values.childFlow.length; i++) { - if ( - values.destinationUsageYears.length >= 2 && - JSON.parse(values.childFlow[i].value as string).activeStatus === true - ) { - values.flowType = { - displayLabel: 'Parked', - value: '1252', - }; - } - } - } - if (isShowParentFlow && isShowChildFlow > 0) { - let childAmountSum = 0; - let parentAmountSum = 0; - values.childFlow && - values.childFlow.map((item, _index) => { - childAmountSum += JSON.parse(item.value.toString()) - ? parseInt(JSON.parse(item.value.toString()).amountUSD) - : 0; - }); - values.parentFlow && - values.parentFlow.map((item, _index) => { - parentAmountSum += JSON.parse(item.value.toString()) - ? parseInt(JSON.parse(item.value.toString()).amountUSD) - : 0; - }); - if (childAmountSum > parentAmountSum) { - if ( - !window.confirm( - `Please note, the Funding Amount on this parent flow ($${parentAmountSum}) is less than the sum of its children's amount ($${childAmountSum}). Do you want to proceed?` - ) - ) { - return; - } - } - } - if (isShowParentFlow || isShowChildFlow > 0) { - let childAmountSum = 0; - values.childFlow && - values.childFlow.map((item, _index) => { - childAmountSum += JSON.parse(item.value.toString()) - ? parseInt(JSON.parse(item.value.toString()).amountUSD) - : 0; - }); - if (childAmountSum > values.amountUSD) { - if ( - !window.confirm( - `Please note, the Funding Amount on this parent flow ($${values.amountUSD}) is less than the sum of its children's amount ($${childAmountSum}). Do you want to proceed?` - ) - ) - return; - } - } - const parentFlow = values.parentFlow; - if (parentFlow?.length) { - for (let index = 0; index < parentFlow.length; index++) { - const item = parentFlow[index]; - if ( - (typeof values?.origCurrency !== 'string' && - values.origCurrency?.displayLabel) || - !( - JSON.parse(item.value.toString()) && - JSON.parse(item.value.toString())?.origCurrency === null - ) - ) { - if ( - (typeof values?.origCurrency !== 'string' && - values.origCurrency?.displayLabel) !== - (JSON.parse(item.value.toString()) && - JSON.parse(item.value.toString())?.origCurrency) - ) { - handleSave(); - setParentCurrencyFlag(true); - return; - } - } - } - } - const childFlow = values.childFlow; - if (childFlow) { - for (let index = 0; index < childFlow.length; index++) { - const item = childFlow[index]; - if ( - (typeof values?.origCurrency !== 'string' && - values.origCurrency?.displayLabel) || - !( - JSON.parse(item.value.toString()) && - JSON.parse(item.value.toString())?.origCurrency === null - ) - ) { - if ( - (typeof values.origCurrency !== 'string' && - values.origCurrency?.displayLabel) !== - (JSON.parse(item.value.toString()) && - JSON.parse(item.value.toString()).origCurrency) - ) { - handleSave(); - setChildCurrencyFlag(true); - return; - } - } - } - } - for (let i = 0; i < values.reportDetails.length; i++) { - if ( - values.reportDetails[i].reportUrlTitle && - values.reportDetails[i].reportUrl - ) { - setUploadFileFlag(true); - } else setUploadFileFlag(false); - } - const data = normalizeFlowData(values); - const inactiveReasons = await fetchCategory('inactiveReason')(); - if (submitAction === 'approve') { - data.isApprovedFlowVersion = true; - } else if (submitAction === 'rejected') { - data.activeStatus = false; - data.rejected = true; - data.inactiveReason = [ - { - id: - inactiveReasons.find( - (item: any) => item.displayLabel === 'Rejected' - )?.value || null, - name: inactiveReasons.find( - (item: any) => item.displayLabel === 'Rejected' - )?.displayLabel, - description: null, - parentID: null, - code: null, - group: 'inactiveReason', - includeTotals: null, - createdAt: currentVersionData - ? dayjs(currentVersionData.createdAt, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ) - : '', - updatedAt: currentVersionData - ? dayjs(currentVersionData.updatedAt, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ) - : '', - }, - ]; - } else if (submitAction === 'inactive') { - if (isShowParentFlow || isShowChildFlow > 0) { - setInactiveFlag(true); - } else { - const categoryValue = - inactiveReasons.find((item: any) => item.displayLabel === 'Cancelled') - ?.value ?? null; - if (categoryValue) { - data.categories.push(parseInt(categoryValue.toString())); - } - data.activeStatus = false; - data.cancelled = true; - data.isCancellation = null; - data.rejected = null; - data.newMoney = false; - data.inactiveReason = [ - { - id: - inactiveReasons.find( - (item: any) => item.displayLabel === 'Cancelled' - )?.value || null, - name: inactiveReasons.find( - (item: any) => item.displayLabel === 'Cancelled' - )?.displayLabel, - description: null, - parentID: null, - code: null, - group: 'inactiveReason', - includeTotals: null, - createdAt: currentVersionData ? currentVersionData.createdAt : '', - updatedAt: currentVersionData ? currentVersionData.updatedAt : '', - }, - ]; - } - } - if (!inactiveFlag) { - const response = await env.model.flows.validateFlow(data); - let flag = true; - let mismatchFound = false; - for (let i = 0; i < values.reportDetails.length; i++) { - const reportOrganizationLabel = - values.reportDetails[i].reportedOrganization.displayLabel; - const reportMatchesSource = values.sourceOrganizations.some( - (sourceOrg) => sourceOrg.displayLabel === reportOrganizationLabel - ); - const reportMatchesDestination = values.destinationOrganizations.some( - (destOrg) => destOrg.displayLabel === reportOrganizationLabel - ); - - if (!reportMatchesSource && !reportMatchesDestination) { - mismatchFound = true; - break; - } - } - if (mismatchFound) { - if ( - !window.confirm( - "Your flow's Report Detail organization doesn't match the source or destination organization or that of its parked parent. Are you sure this is right?" - ) - ) { - return; - } - } - response.forEach((obj) => { - if (obj) { - const { success, message, confirmed } = obj; - if (!success) { - if (confirmed) { - const confirm = window.confirm(confirmed); - if (!confirm) { - setOpenAlerts([...openAlerts, { message, id: alertId }]); - setAlertId((prevId) => prevId + 1); - flag = false; - handleSave(); - } - } else if (message) { - setOpenAlerts([...openAlerts, { message, id: alertId }]); - setAlertId((prevId) => prevId + 1); - flag = false; - handleSave(); - } - } - } - }); - if (flag && !(isShowParentFlow || isShowChildFlow > 0)) { - setUnsavedChange(false); - if (!isEdit) { - try { - const response = await env.model.flows.createFlow({ flow: data }); - const path = editFlowSetting(response.id, response.versionID); - window.open(path, '_self'); - } catch (err: any) { - setOpenAlerts([ - ...openAlerts, - { message: err.message, id: alertId }, - ]); - setAlertId((prevId) => prevId + 1); - handleSave(); - } - } else { - const dbFlow = await env.model.flows.getFlowREST({ - id: currentFlowID!, - }); - if ( - (versionData && - currentVersionID && - Date.parse(versionData[currentVersionID - 1].updatedTime) < - Date.parse(dbFlow.updatedAt)) || - (versionData && versionData.length < dbFlow.versions.length) - ) { - window.confirm( - 'This flow cannot be saved, as a concurrency conflict has been detected. Please refresh your screen to view the most up to date data.' - ); - } else { - if (isPending && (approveFlag || rejectFlag)) { - if ( - allFieldsReviewed || - pendingFieldsAllApplied || - !pendingVersionV1 - ) { - try { - const response = await env.model.flows.updatePendingFlow({ - flow: data, - }); - if (response) { - const path = editFlowSetting( - response.id, - response.versionID - ); - setAlertFlag(true); - setSharePath(path); - } - } catch (err: any) { - setOpenAlerts([ - ...openAlerts, - { message: err.message, id: alertId }, - ]); - setAlertId((prevId) => prevId + 1); - handleSave(); - } - } else { - window.confirm( - 'Some of the revised data on this flow still needs to be accepted or rejected before this update can be approved.' - ); - } - } else { - try { - const response = await env.model.flows.updateFlow({ - flow: data, - }); - if (response) { - const path = editFlowSetting(response.id, response.versionID); - setAlertFlag(true); - setSharePath(path); - } - } catch (err: any) { - let errmessage = ''; - if (err.reason) { - const inconsistencyObject = err.reason; - errmessage = processDataInconsistencies(inconsistencyObject); - } else { - const lastIndex = err.message.lastIndexOf(':'); - errmessage = err.message.substring(lastIndex + 1); - } - setOpenAlerts([ - ...openAlerts, - { message: errmessage, id: alertId }, - ]); - setAlertId((prevId) => prevId + 1); - handleSave(); - } - } - } - } - } - } - }; - const navigate = useNavigate(); - const handleCopy = (values: FormValues) => { - if (currentFlowID && currentVersionID) { - const isCopy = true; - const path = copyFlow(); - if (typeof path === 'string') { - const valuesWithFiles = { ...values, isCopy }; - navigate(path, { state: valuesWithFiles }); - } else { - console.error('Path is not a string', path); - } - } - }; - - const handleAlert = (values: FormValues) => { - const errors = validateForm(values); - if (Object.keys(errors).length !== 0) { - setValidationFlag(true); - handleSave(); - } - }; - - const setObjectsWithArray = ( - fetchedObject: any, - objectKeys: string[], - settingArrayKeys: string[], - setFieldValue: any, - values: any - ) => { - const newObjects = { ...objects }; - const newShowingTypes = [...showingTypes]; - objectKeys.forEach((key, i) => { - if (fetchedObject[settingArrayKeys[i]]) { - newObjects[key] = checkIfExistingAndCopy( - newObjects[key], - fetchedObject, - settingArrayKeys[i] - ); - } - - const parsedResponse = newObjects[key].map((responseValue: any) => { - if (settingArrayKeys[i] === 'years') { - return { - displayLabel: - (responseValue as usageYears.UsageYear).year || - responseValue.displayLabel, - value: responseValue.id || responseValue.value, - isAutoFilled: responseValue.suggested, - }; - } else if (settingArrayKeys[i] === 'plans') { - return { - displayLabel: - (responseValue.planVersion as { planId: number; name: string }) - .name || responseValue.displayLabel, - value: responseValue.planVersion.planId || responseValue.value, - isAutoFilled: responseValue.suggested, - }; - } else if (settingArrayKeys[i] === 'governingEntities') { - return { - displayLabel: - ( - responseValue.governingEntityVersion as { - id: number; - name: string; - } - ).name || responseValue.displayLabel, - value: - responseValue.governingEntityVersion.id || responseValue.value, - isAutoFilled: responseValue.suggested, - }; - } else { - return { - displayLabel: - (responseValue as { id: number; name: string }).name || - responseValue.displayLabel, - value: responseValue.id || responseValue.value, - isAutoFilled: responseValue.suggested, - }; - } - }); - newObjects[key].forEach((obj) => { - if (obj?.suggested) { - updateFlowObjects(key, parsedResponse, setFieldValue, values); - obj.suggested = false; - } - }); - setFieldValue(key, parsedResponse); - }); - - setObjects(newObjects); - setShowingTypes(newShowingTypes); - }; - - const checkIfExistingAndCopy = ( - existingObjects: any[], - object: any, - key: string - ): any[] => { - let newObjects = object[key]; - if (key === 'locations') { - newObjects = newObjects.filter(function (location: any) { - return location.adminLevel === 0; - }); - if (existingObjects && existingObjects.length) { - existingObjects = existingObjects.filter(function (location) { - return location.adminLevel === 0 || location.value; - }); - } - } - - if (existingObjects && existingObjects.length) { - const existingObjectsIds = existingObjects.map(function (o) { - return o.id || o.value; - }); - if (Array.isArray(newObjects)) { - newObjects.forEach(function (obj) { - if (existingObjectsIds.indexOf(obj.id) === -1) { - obj.suggested = true; - existingObjects.push(obj); - } - }); - } else { - if (existingObjectsIds.indexOf(newObjects.id) === -1) { - newObjects.suggested = true; - existingObjects.push(newObjects); - } - } - } else { - if (newObjects) { - if (Array.isArray(newObjects)) { - newObjects.forEach(function (obj) { - obj.suggested = true; - }); - existingObjects = newObjects; - } else { - newObjects.suggested = true; - existingObjects = [newObjects]; - } - } - } - return existingObjects; - }; - const fetchPlanDetails = async ( - objectType: string, - plan: any, - setFieldValue: any, - values?: any - ) => { - const fetchedPlan = await environment.model.plans.getPlan(plan[0].value); - if (objectType === 'sourcePlans') { - setObjectsWithArray( - fetchedPlan, - ['sourceUsageYears', 'sourceEmergencies'], - ['years', 'emergencies'], - setFieldValue, - values - ); - setSourceGoverningEntities(fetchedPlan.governingEntities); - } - if (objectType === 'destinationPlans') { - setObjectsWithArray( - fetchedPlan, - ['destinationUsageYears', 'destinationEmergencies'], - ['years', 'emergencies'], - setFieldValue, - values - ); - setDestinationGoverningEntities(fetchedPlan.governingEntities); - } - if (fetchedPlan.locations) { - const countries = fetchedPlan.locations.filter(function (loc: any) { - return loc.adminLevel === 0; - }); - if (countries.length === 1) { - if (objectType === 'sourcePlans') { - setObjectsWithArray( - { locations: countries }, - ['sourceLocations'], - ['locations'], - setFieldValue, - values - ); - } - if (objectType === 'destinationPlans') { - setObjectsWithArray( - { locations: countries }, - ['destinationLocations'], - ['locations'], - setFieldValue, - values - ); - } - } - } - }; - - const fetchEmergencyDetails = async ( - objectType: string, - emergency: any, - setFieldValue: any, - values?: any - ) => { - if (objectType === 'destinationEmergencies') { - const fetchedEmergency = await environment.model.emergencies.getEmergency( - emergency[0].value - ); - if (fetchedEmergency.locations.length <= 1) { - setObjectsWithArray( - fetchedEmergency, - ['destinationLocations'], - ['locations'], - setFieldValue, - values - ); - } - } - }; - const fetchProjectDetails = async ( - objectType: string, - project: any, - setFieldValue: any, - values?: any - ) => { - const fetchedProject = await environment.model.projects.getProject( - project[0].value - ); - const publishedVersion = fetchedProject.projectVersions.filter(function ( - version: any - ) { - return version.id === fetchedProject.currentPublishedVersionId; - })[0]; - if (objectType === 'destinationProjects') { - const fetchedCategories = - await environment.model.categories.getCategories({ - query: 'earmarkingType', - }); - const category = fetchedCategories.filter( - (item: any) => item.name === 'Earmarked' - ); - setFieldValue('earmarkingType', { - value: category[0], - displayLabel: category[0].name, - }); - setObjectsWithArray( - publishedVersion, - [ - 'destinationPlans', - 'destinationLocations', - 'destinationGoverningEntities', - 'destinationGlobalClusters', - 'destinationOrganizations', - ], - [ - 'plans', - 'locations', - 'governingEntities', - 'globalClusters', - 'organizations', - ], - setFieldValue, - values - ); - } else { - setObjectsWithArray( - publishedVersion, - [ - 'sourcePlans', - 'sourceLocations', - 'sourceGoverningEntities', - 'sourceGlobalClusters', - 'sourceOrganizations', - ], - [ - 'plans', - 'locations', - 'governingEntities', - 'globalClusters', - 'organizations', - ], - setFieldValue, - values - ); - } - }; - const fetchOrganizationDetails = async ( - objectType: string, - organization: any, - setFieldValue: any, - values?: any - ) => { - const fetchedOrg = - await environment.model.organizations.getOrganizationsById( - organization[0].value - ); - const isGovernment = (fetchedOrg[0].categories ?? []).some(function ( - category: any - ) { - return ( - category.group === 'organizationType' && - [114, 123].includes(category.id) - ); - }); - if (isGovernment && objectType === 'sourceOrganizations') { - objects.sourceLocations = checkIfExistingAndCopy( - objects.location, - fetchedOrg[0], - 'locations' - ); - setObjectsWithArray( - objects, - ['sourceLocations'], - ['locations'], - setFieldValue, - values - ); - } - }; - const fetchAssociatedGoverningEntity = async ( - objectType: string, - globalCluster: any, - setFieldValue: any, - values?: any - ) => { - if ( - (values.sourcePlans.length === 0 && - objectType === 'sourceGlobalClusters') || - (values.destinationPlans.length === 0 && - objectType === 'destinationGlobalClusters') - ) { - return; - } - let plan = null; - let targetGoverningEntities: any = null; - if (objectType === 'sourceGlobalClusters') { - plan = values.sourcePlans[0]; - targetGoverningEntities = values.sourceGoverningEntities; - } else { - plan = values.destinationPlans[0]; - targetGoverningEntities = values.destinationGoverningEntities; - } - const fetchedGoverningEntities = - await environment.model.governingEntities.getAllPlanGoverningEntities( - plan.value - ); - const hasGoverningEntitiesWithoutGlobalCluster = - Array.isArray(targetGoverningEntities) && - fetchedGoverningEntities - .filter(function (fetchedGe: any) { - return targetGoverningEntities.find(function (selectedGe: any) { - return fetchedGe.id === selectedGe.value; - }); - }) - .some(function (fetchedGe: any) { - return ( - Array.isArray(fetchedGe.globalClusterIds) && - !fetchedGe.globalClusterIds.length - ); - }); - - if (hasGoverningEntitiesWithoutGlobalCluster) { - return; - } - const governingEntities = fetchedGoverningEntities.filter(function ( - governingEntity: any - ) { - return ( - governingEntity.globalClusterIds.indexOf( - globalCluster[globalCluster.length - 1].value - ) > -1 - ); - }); - - if (governingEntities.length) { - governingEntities.forEach(function (governingEntity: any) { - setObjectsWithArray( - { governingEntities: governingEntity }, - [ - objectType === 'sourceGlobalClusters' - ? 'sourceGoverningEntities' - : 'destinationGoverningEntities', - ], - ['governingEntities'], - setFieldValue, - values - ); - }); - } - }; - - const fetchKeywords = async ( - objectType: string, - usageYears: any, - setFieldValue: any, - values?: any - ) => { - if (usageYears.length === 2) { - const fetchedCategories = - await environment.model.categories.getCategories({ - query: 'keywords', - }); - const category = fetchedCategories.filter( - (item: any) => item.name === 'Multiyear' - ); - - const mergedKeywords = [ - ...values.keywords, - ...[ - { - value: category[0].id, - displayLabel: category[0].name, - }, - ].filter( - (item2) => - !values.keywords.some((item1: any) => item1.value === item2.value) - ), - ]; - - setFieldValue('keywords', mergedKeywords); - } else if (usageYears.length === 1) { - const filteredKeywords = values.keywords.filter( - (item: any) => item.displayLabel !== 'Multiyear' - ); - setFieldValue('keywords', filteredKeywords); - } - }; - - const handleCompareCheck = ( - checkedVersion: VersionDataType, - isChecked: boolean - ) => { - setComparingVersions((prev: VersionDataType[]) => { - if (isChecked) { - return [...prev, checkedVersion]; - } else { - return prev.filter( - (version: VersionDataType) => - version.versionId !== checkedVersion.versionId - ); - } - }); - }; - - const fetchDownload = async (index: number) => { - const fileAssetID = - initialValue.reportDetails[index]?.reportFiles[0]?.fileAssetID; - const name = initialValue.reportDetails[index]?.reportFiles[0]?.fileName; - if (fileAssetID) { - try { - const responseData = - await environment?.model.fileUpload.fileDownloadModel(fileAssetID); - if (responseData) { - const data = new Blob([responseData]); - const url = URL.createObjectURL(data); - const a = document.createElement('a'); - a.href = url; - a.download = `${name ? name : 'downloaded_file'}`; - document.body.appendChild(a); - a.click(); - setTimeout(() => { - document.body.removeChild(a); - window.URL.revokeObjectURL(url); - }, 0); - } else { - console.error('No data received for download'); - } - } catch (error) { - console.error(error, 'error'); - } - } - }; - - const fetchCategory = useCallback( - (category: string) => { - return async () => { - const response = await environment.model.categories.getCategories({ - query: category, - }); - return response.map( - (responseValue: any): categoryType => ({ - displayLabel: responseValue.name, - value: responseValue.id.toString(), - parentID: responseValue.parentID, - }) - ); - }; - }, - [environment] - ); - const extractUniqueFromArray = (array1: string[], array2: string[]) => { - return array1.filter((item: string) => !array2.includes(item)); - }; - - const compareVersions = (versions: VersionDataType[]) => { - const version1 = versions[0]; - const version2 = versions[1]; - const newVersion1 = { - ...version1, - uniqueSources: objectTypes.reduce>( - (acc, type) => { - acc[type] = extractUniqueFromArray( - version1.source[type], - version2.source[type] - ); - return acc; - }, - {} - ), - uniqueDestinations: objectTypes.reduce>( - (acc, type) => { - acc[type] = extractUniqueFromArray( - version1.destination[type], - version2.destination[type] - ); - return acc; - }, - {} - ), - uniqueCategories: extractUniqueFromArray( - version1.categories, - version2.categories - ), - }; - - const newVersion2 = { - ...version2, - uniqueSources: objectTypes.reduce>( - (acc, type) => { - acc[type] = extractUniqueFromArray( - version2.source[type], - version1.source[type] - ); - return acc; - }, - {} - ), - uniqueDestinations: objectTypes.reduce>( - (acc, type) => { - acc[type] = extractUniqueFromArray( - version2.destination[type], - version1.destination[type] - ); - return acc; - }, - {} - ), - uniqueCategories: extractUniqueFromArray( - version2.categories, - version1.categories - ), - }; - return [newVersion1, newVersion2]; - }; - const handleFileChange = async ( - event: React.ChangeEvent, - index: number - ) => { - setUploadFlag(true); - try { - const setFile: File | undefined = (event.target as HTMLInputElement) - .files?.[0]; - if (setFile instanceof File) { - const responseData = - await environment.model.fileUpload.fileUploadModel(setFile); - setUploadedFileArray((prevUploadedFile) => { - const updateUploadedFile = [...prevUploadedFile]; - updateUploadedFile[index] = responseData; - return updateUploadedFile; - }); - console.log(uploadedFileArray, 'uploadedFileArray'); - } else { - console.error('No file selected for upload.'); - } - } catch (error) { - console.log(error, 'error'); - } - }; - useEffect(() => { - if (comparingVersions.length === 2) { - const compared = compareVersions(comparingVersions); - setComparedVersions(compared); - } - }, [comparingVersions]); - - useEffect(() => { - const handleBeforeUnload = (event: BeforeUnloadEvent) => { - if (unsavedChange) { - const message = - 'You have unsaved changes! Are you sure you want to leave?'; - event.returnValue = message; // Standard for most browsers - return message; // For some older browsers - } - }; - - window.addEventListener('beforeunload', handleBeforeUnload); - - return () => { - window.removeEventListener('beforeunload', handleBeforeUnload); - }; - }, [unsavedChange]); - - useEffect(() => { - const valuesObject: Record = { - sourceOrganizations: initialValue.sourceOrganizations, - sourceLocations: initialValue.sourceLocations, - sourceUsageYears: initialValue.sourceUsageYears, - sourceProjects: initialValue.sourceProjects, - sourcePlans: initialValue.sourcePlans, - sourceGoverningEntities: initialValue.sourceGoverningEntities, - sourceGlobalClusters: initialValue.sourceGlobalClusters, - sourceEmergencies: initialValue.sourceEmergencies, - destinationOrganizations: initialValue.destinationOrganizations, - destinationLocations: initialValue.destinationLocations, - destinationUsageYears: initialValue.destinationUsageYears, - destinationProjects: initialValue.destinationProjects, - destinationPlans: initialValue.destinationPlans, - destinationGoverningEntities: initialValue.destinationGoverningEntities, - destinationGlobalClusters: initialValue.destinationGlobalClusters, - destinationEmergencies: initialValue.destinationEmergencies, - }; - setObjects(valuesObject); - }, []); - - unstable_usePrompt({ - message: 'You have unsaved changes! Are you sure you want to leave?', - when: unsavedChange, - }); - const dictExecutedForEachObject: Record< - string, - ( - objectType: string, - flowObject: any, - setFieldValue: any, - values: any - ) => Promise - > = { - sourcePlans: fetchPlanDetails, - destinationPlans: fetchPlanDetails, - destinationEmergencies: fetchEmergencyDetails, - sourceProjects: fetchProjectDetails, - destinationProjects: fetchProjectDetails, - sourceOrganizations: fetchOrganizationDetails, - sourceGlobalClusters: fetchAssociatedGoverningEntity, - destinationGlobalClusters: fetchAssociatedGoverningEntity, - sourceUsageYears: fetchKeywords, - destinationUsageYears: fetchKeywords, - }; - - const params: DeleteFlowParams = { - VersionID: currentVersionID ?? 0, - FlowID: currentFlowID ?? 0, - }; - - const deleteFlow = async () => { - if (linkCheck || isShowParentFlow || isShowChildFlow > 0) { - window.confirm( - 'All linked flows must be unlinked before this flow can be deleted. Unlink flows and choose Delete flow again.' - ); - return; - } - - try { - const response = await env.model.flows.deleteFlow(params); - const path = flows(); - window.open(path, '_self'); - } catch (err: any) { - setOpenAlerts([...openAlerts, { message: err.message, id: alertId }]); - setAlertId((prevId) => prevId + 1); - } - }; - const updateFlowObjects = async ( - objectType: string, - flowObject: any, - setFieldValue: any, - values?: any - ) => { - if (flowObject.length > 0 && dictExecutedForEachObject[objectType]) { - flowObject.sort( - ( - a: { displayLabel: string; value: number }, - b: { displayLabel: string; value: number } - ) => { - return a.displayLabel.localeCompare(b.displayLabel); - } - ); - await dictExecutedForEachObject[objectType]( - objectType, - flowObject, - setFieldValue, - values - ); - } - if (objectType === 'sourcePlans') { - handleShowSourceGoverningEntities(flowObject.length !== 0); - } - if (objectType === 'destinationPlans') { - handleShowDestinationGoverningEntities(flowObject.length !== 0); - } - }; - const handleParentLinkedFlow = ( - values: any, - setFieldValue: any, - index: number - ) => { - setFieldValue( - 'parentFlow', - values['parentFlow'].filter((_item: any, ind: number) => ind !== index) - ); - }; - const handleChildFlow = (values: any, setFieldValue: any, index: number) => { - setFieldValue( - 'childFlow', - values['childFlow'].filter((_item: any, ind: number) => ind !== index) - ); - }; - const validateForm = (values: FormValues) => { - setUnsavedChange(JSON.stringify(values) !== JSON.stringify(initialValue)); - const valuesObject: Record = { - sourceOrganizations: values.sourceOrganizations, - sourceLocations: values.sourceLocations, - sourceUsageYears: values.sourceUsageYears, - sourceProjects: values.sourceProjects, - sourcePlans: values.sourcePlans, - sourceGoverningEntities: values.sourceGoverningEntities, - sourceGlobalClusters: values.sourceGlobalClusters, - sourceEmergencies: values.sourceEmergencies, - destinationOrganizations: values.destinationOrganizations, - destinationLocations: values.destinationLocations, - destinationUsageYears: values.destinationUsageYears, - destinationProjects: values.destinationProjects, - destinationPlans: values.destinationPlans, - destinationGoverningEntities: values.destinationGoverningEntities, - destinationGlobalClusters: values.destinationGlobalClusters, - destinationEmergencies: values.destinationEmergencies, - }; - setObjects(valuesObject); - const result = validationSchema.decode(values); - if (isRight(result)) { - setValidationFlag(false); - return {}; - } else { - const errors: Record[]> = {}; - Object.keys(values).forEach((key) => { - const value = values[key as keyof FormValues]; - if ( - result.left.some((err) => err.context.find((ctx) => ctx.key === key)) - ) { - const errorKey = key as keyof FormikErrors; - if (!value) { - errors[errorKey] = 'This field is required.'; - } else if (Array.isArray(value) && value.length === 0) { - errors[errorKey] = 'This field is required.'; - } - } - if ( - key === 'amountUSD' && - (value === 0 || (value && (value === '0' || (value as number) < 0))) - ) { - errors['amountUSD'] = 'The amount must be greater than zero.'; - } - if (key === 'flowType' && !value) { - errors['flowType'] = 'This field is required.'; - } - if (key === 'method' && !value) { - errors['method'] = 'This field is required.'; - } - if (key === 'reportDetails') { - const res = result.left.filter((err) => - err.context.find((ctx) => ctx.key === key) - )[0].value; - if (res && Array.isArray(res)) { - const reportDetailError: Record[] = []; - res.forEach((_, index) => { - const error: Record = {}; - if (res[index].reportChannel === '') { - error['reportChannel'] = 'This field is required.'; - } else { - error['reportChannel'] = ''; - } - if (!res[index].reportedDate) { - error['reportedDate'] = 'This field is required.'; - } else { - error['reportedDate'] = ''; - } - console.log(res[index], '-------------->'); - if ( - (res[index].reportFileTitle === '' || - res[index].reportFileTitle === undefined) && - (uploadedFileArray[index] && - (uploadedFileArray[index] as { id?: number })?.id - ? true - : false) - ) { - error['reportFileTitle'] = 'This field is required.'; - } else { - error['reportFileTitle'] = ''; - } - if ( - res[index].reportedOrganization === null || - res[index].reportedOrganization.displayLabel === '' - ) { - error['reportedOrganization'] = 'This field is required.'; - } else { - error['reportedOrganization'] = ''; - } - - if (Object.keys(error).length > 0) { - (reportDetailError as Record[]).push(error); - } - }); - - if (reportDetailError.length >= res.length) { - res.forEach((_, index) => { - if ( - res[index].reportChannel !== '' && - res[index].reportedOrganization !== '' && - res[index].reportedDate !== '' - ) { - if ( - (res[index].reportFileTitle === undefined || - res[index].reportFileTitle === '') && - (uploadedFileArray[index] && - (uploadedFileArray[index] as { id?: number })?.id - ? false - : true) - ) { - return {}; - } else if ( - res[index].reportFileTitle !== undefined && - res[index].reportFileTitle !== '' && - uploadedFileArray[index] - ) { - return {}; - } else { - errors['reportDetails'] = reportDetailError; - } - } else { - errors['reportDetails'] = reportDetailError; - } - }); - } - } - } - }); - console.log(errors, 'errors'); - if (Object.keys(errors).length === 0) setValidationFlag(false); - return errors; - } - }; - const handleParentFlow = ( - values: any, - parentValueString: string, - setValues: any - ) => { - parentValue = parentValueString; - const defaultValueParent: flowsResponse.GetFlowResult = - JSON.parse(parentValueString); - - const indexOrgs = defaultValueParent.organizations - .map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const indexYears = defaultValueParent.usageYears - .map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const indexLocs = defaultValueParent.locations - .map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const indexEmrs = defaultValueParent.emergencies - ?.map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const indexGlos = defaultValueParent.globalClusters - ?.map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const indexPlns = defaultValueParent.plans - ?.map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - // const indexEnt = defaultValueParent.governingEntities?.findIndex((org) => org.flowObject?.refDirection === 'destination') ?? -1; - - const indexPros = defaultValueParent.projects - ?.map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const _sourceOrganizations = indexOrgs.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: `${defaultValueParent.organizations[index].name} [${defaultValueParent.organizations[index].abbreviation}]`, - value: defaultValueParent.organizations[index].id, - }; - } - }); - const _sourceUsageYears = indexYears.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: `${defaultValueParent.usageYears[index].year}`, - value: defaultValueParent.usageYears[index].id, - }; - } - }); - const _sourceLocations = indexLocs.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: `${defaultValueParent.locations[index].name}`, - value: defaultValueParent.locations[index].id, - }; - } - }); - - const _sourceEmergencies = indexEmrs?.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: - defaultValueParent.emergencies && - `${defaultValueParent.emergencies[index].name}`, - value: - defaultValueParent.emergencies && - defaultValueParent.emergencies[index].id, - }; - } - }); - const _sourceGlobalClusters = indexGlos?.map( - (index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: - defaultValueParent.globalClusters && - `${defaultValueParent.globalClusters[index].name}`, - value: - defaultValueParent.globalClusters && - defaultValueParent.globalClusters[index].id, - }; - } - } - ); - const _sourcePlans = indexPlns?.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: - defaultValueParent.plans && - `${defaultValueParent.plans[index].planVersion.name}`, - value: defaultValueParent.plans && defaultValueParent.plans[index].id, - }; - } - }); - const _sourceProjects = indexPros?.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: - defaultValueParent.projects && - `${defaultValueParent.projects[index].projectVersions[index].name}`, - value: - defaultValueParent.projects && - defaultValueParent.projects[index].id, - }; - } - }); - - setValues({ - ...values, - sourceOrganizations: _sourceOrganizations, - sourceUsageYears: _sourceUsageYears, - sourceLocations: _sourceLocations, - sourceEmergencies: _sourceEmergencies, - sourceGlobalClusters: _sourceGlobalClusters, - sourcePlans: _sourcePlans, - // sourceGoverningEntities: _sourceGoverningEntities ? [_sourceGoverningEntities] : [], - sourceProjects: _sourceProjects, - }); - }; - return ( - - handleSubmit(values, values.submitAction) - } - validate={(values) => validateForm(values)} - enableReinitialize - validateOnChange={false} - style={{ zIndex: 1 }} - > - {({ values, setFieldValue, setValues }) => { - if (values.parentFlow && values.parentFlow[0]) { - const parentValueString = String( - values.parentFlow && - values.parentFlow[0] && - values.parentFlow[0].value - ); - if (parentValue !== parentValueString) { - handleParentFlow(values, parentValueString, setValues); - } - } - return ( -
- - {showWarningMessage && ( - - - - - - You have added a Child flow for this flow. Updating the - Funding Destination(s) for this flow will update the Funding - Source(s) for the child flows. If you don't want to update - the Child flow's funding sources, unlink it first. - - - )} - - - - { - updateFlowObjects(event, value, setFieldValue, values); - }} - isAutocompleteAPI={false} - entryInfo={inputEntries.destinationUsageYears} - rejectInputEntry={rejectInputEntry} - /> - - - - - - { - updateFlowObjects(event, value, setFieldValue, values); - }} - behavior={FORM_SETTINGS.globalCluster.behavior} - isMulti - isAutocompleteAPI={false} - entryInfo={inputEntries.destinationGlobalClusters} - rejectInputEntry={rejectInputEntry} - /> - { - updateFlowObjects(event, value, setFieldValue, values); - }} - behavior={FORM_SETTINGS.plan.behavior} - isMulti - entryInfo={inputEntries.destinationPlans} - rejectInputEntry={rejectInputEntry} - /> - {showDestinationGoverningEntities && ( - - )} - { - updateFlowObjects(event, value, setFieldValue, values); - }} - isMulti - entryInfo={inputEntries.destinationEmergencies} - rejectInputEntry={rejectInputEntry} - /> - { - updateFlowObjects(event, value, setFieldValue, values); - }} - isMulti - entryInfo={inputEntries.destinationProjects} - rejectInputEntry={rejectInputEntry} - /> - -
- ); - }} -
- ); -}; -export default FlowDestination; diff --git a/apps/hpc-ftsadmin/src/app/components/flow-form-rewrite/flow-source.tsx b/apps/hpc-ftsadmin/src/app/components/flow-form-rewrite/flow-source.tsx deleted file mode 100644 index 8e5b47c93..000000000 --- a/apps/hpc-ftsadmin/src/app/components/flow-form-rewrite/flow-source.tsx +++ /dev/null @@ -1,2606 +0,0 @@ -import React, { - ChangeEvent, - useState, - useEffect, - useCallback, - useRef, - useContext, -} from 'react'; -import { Form, Formik, FieldArray } from 'formik'; -import tw from 'twin.macro'; -import dayjs from 'dayjs'; -import { isRight } from 'fp-ts/Either'; -import { FormikErrors } from 'formik'; -import * as t from 'io-ts'; -import { util as codecs } from '@unocha/hpc-data'; -import GppMaybeIcon from '@mui/icons-material/GppMaybe'; -import Button from '@mui/material/Button'; -import DeleteIcon from '@mui/icons-material/Delete'; -import Stack from '@mui/material/Stack'; -import ContentCopyIcon from '@mui/icons-material/ContentCopy'; -import MuiAlert from '@mui/material/Alert'; -import AlertTitle from '@mui/material/AlertTitle'; -import _, { set, values } from 'lodash'; -import useSharePath from '../Hooks/SharePath'; -import { C, dialogs } from '@unocha/hpc-ui'; -import { - Table, - TableBody, - TableCell, - TableContainer, - TableHead, - TableRow, - Paper, - Alert, - IconButton, -} from '@mui/material'; -import CloseIcon from '@mui/icons-material/Close'; -import { Environment } from '../../../environments/interface'; -import { MdAdd, MdRemove, MdClose, MdCheck } from 'react-icons/md'; -import { - usageYears, - forms, - governingEntities, - fileUpload, - flows as flowsResponse, -} from '@unocha/hpc-data'; -import { getEnv } from '../../context'; -import { editFlowSetting, copyFlow } from '../../paths'; -import { flows } from '../../paths'; -import Link from '@mui/material/Link'; -import { useNavigate, unstable_usePrompt } from 'react-router-dom'; -import { id } from 'fp-ts/lib/Refinement'; -import { FlowContext } from './flow-context'; - -export type AutoCompleteSelectionType = forms.InputSelectValueType; - -const INPUT_SELECT_VALUE_TYPE = forms.INPUT_SELECT_VALUE_TYPE; - -type UniqueDataType = { - [key: string]: string[]; -}; - -export interface DeleteFlowParams { - VersionID: number; - FlowID: number; -} - -export interface categoryType { - value: string | number; - displayLabel: string; - parentID: number | null; -} - -export interface FileAssetEntityType { - collection?: string; - createAt?: string; - filename?: string; - id?: number; - mimetype?: string; - originalname?: string; - path?: string; - size?: number; - updatedAt?: string; -} -export interface ReportFileType { - title?: string; - fileName?: string; - UploadFileUrl?: string; - type?: string; - url?: string; - fileAssetID?: number; - size?: number; - fileAssetEntity?: FileAssetEntityType; -} -export interface ReportDetailType { - verified: string; - reportSource: string; - reporterReferenceCode: string; - reportChannel: AutoCompleteSelectionType | ''; - reportedOrganization: AutoCompleteSelectionType; - reportedDate: string; - reporterContactInformation: string; - sourceSystemRecordId: string; - reportFiles: ReportFileType[]; - reportFileTitle?: string; - reportUrlTitle?: string; - reportUrl?: string; - versionId?: number; - fileAsset?: FileAssetEntityType; -} - -export interface ParentFlowType { - value: any; -} - -export interface FormValues { - id: string | null; - amountUSD: number; - keywords: AutoCompleteSelectionType[]; - flowStatus: AutoCompleteSelectionType | ''; - flowType: AutoCompleteSelectionType | ''; - flowDescription: string; - firstReported: string; - decisionDate: string | null; - budgetYear: string; - flowDate: string; - contributionType: AutoCompleteSelectionType | ''; - earmarkingType: AutoCompleteSelectionType | ''; - method: AutoCompleteSelectionType | ''; - cashTransfer: AutoCompleteSelectionType | ''; - beneficiaryGroup: AutoCompleteSelectionType | ''; - inactiveReason: any[] | string; - childMethod: object; - origCurrency: AutoCompleteSelectionType | string; - amountOriginal: number | null; - exchangeRateUsed: number | null; - notes: string; - sourceOrganizations: AutoCompleteSelectionType[]; - sourceLocations: AutoCompleteSelectionType[]; - sourceUsageYears: AutoCompleteSelectionType[]; - sourceProjects: AutoCompleteSelectionType[]; - sourcePlans: AutoCompleteSelectionType[]; - sourceGoverningEntities: AutoCompleteSelectionType[]; - sourceGlobalClusters: AutoCompleteSelectionType[]; - sourceEmergencies: AutoCompleteSelectionType[]; - destinationOrganizations: AutoCompleteSelectionType[]; - destinationLocations: AutoCompleteSelectionType[]; - destinationUsageYears: AutoCompleteSelectionType[]; - destinationProjects: AutoCompleteSelectionType[]; - destinationPlans: AutoCompleteSelectionType[]; - destinationGoverningEntities: AutoCompleteSelectionType[]; - destinationGlobalClusters: AutoCompleteSelectionType[]; - destinationEmergencies: AutoCompleteSelectionType[]; - reportDetails: ReportDetailType[]; - parentFlow?: AutoCompleteSelectionType[]; - childFlow?: AutoCompleteSelectionType[]; - isParkedParent?: boolean; - includeChildrenOfParkedFlows: boolean; - isErrorCorrectionValue: boolean; - sources?: Record; - submitAction?: string | undefined; - versions?: { - id: number | null; - isPending: boolean | null; - }[]; -} - -export interface VersionDataType { - versionId: number; - flowId: number; - createdTime: string; - createdBy: string | null; - updatedTime: string; - updatedBy: string | null; - active: boolean; - viewing: boolean; - pending?: boolean; - [key: string]: - | string - | number - | null - | boolean - | string[] - | Date - | undefined - | Record; - source: UniqueDataType; - destination: UniqueDataType; - categories: string[]; - uniqueSources: UniqueDataType; - uniqueDestinations: UniqueDataType; - uniqueCategories: string[]; - restricted?: boolean; -} - -export interface InputEntriesType { - amountUSD: forms.InputEntryType | null; - origCurrency: forms.InputEntryType | null; - keywords: forms.InputEntryType | null; - flowStatus: forms.InputEntryType | null; - flowType: forms.InputEntryType | null; - flowDescription: forms.InputEntryType | null; - contributionType: forms.InputEntryType | null; - earmarkingType: forms.InputEntryType | null; - method: forms.InputEntryType | null; - beneficiaryGroup: forms.InputEntryType | null; - inactiveReason: forms.InputEntryType | null; - amountOriginal: forms.InputEntryType | null; - exchangeRateUsed: forms.InputEntryType | null; - notes: forms.InputEntryType | null; - sourceOrganizations: forms.InputEntryType[]; - sourceLocations: forms.InputEntryType[]; - sourceUsageYears: forms.InputEntryType[]; - sourceProjects: forms.InputEntryType[]; - sourcePlans: forms.InputEntryType[]; - sourceGoverningEntities: forms.InputEntryType[]; - sourceGlobalClusters: forms.InputEntryType[]; - sourceEmergencies: forms.InputEntryType[]; - destinationOrganizations: forms.InputEntryType[]; - destinationLocations: forms.InputEntryType[]; - destinationUsageYears: forms.InputEntryType[]; - destinationProjects: forms.InputEntryType[]; - destinationPlans: forms.InputEntryType[]; - destinationGoverningEntities: forms.InputEntryType[]; - destinationGlobalClusters: forms.InputEntryType[]; - destinationEmergencies: forms.InputEntryType[]; - parentFlow: forms.InputEntryType | null; - childFlow: forms.InputEntryType[]; -} - -type UploadedItem = fileUpload.FileUploadResult | FileAssetEntityType; - -const reportChannelSchema = t.type({ - value: t.intersection([codecs.NON_EMPTY_STRING, t.string]), - displayLabel: t.intersection([codecs.NON_EMPTY_STRING, t.string]), -}); - -const reportDetailsSchema = t.type({ - reportedOrganization: INPUT_SELECT_VALUE_TYPE, - reportedDate: t.intersection([codecs.NON_EMPTY_STRING, t.string]), - reportChannel: t.intersection([codecs.NON_EMPTY_STRING, reportChannelSchema]), - reportFileTitle: t.intersection([codecs.NON_EMPTY_STRING, t.string]), -}); - -const validationSchema = t.type({ - amountUSD: t.number, - flowStatus: INPUT_SELECT_VALUE_TYPE, - flowDescription: t.intersection([codecs.NON_EMPTY_STRING, t.string]), - firstReported: t.string, - flowDate: t.intersection([codecs.NON_EMPTY_STRING, t.string]), - sourceOrganizations: INPUT_SELECT_VALUE_TYPE, - sourceUsageYears: INPUT_SELECT_VALUE_TYPE, - destinationOrganizations: INPUT_SELECT_VALUE_TYPE, - destinationUsageYears: INPUT_SELECT_VALUE_TYPE, - reportDetails: reportDetailsSchema, -}); - -interface Props { - currentVersionData: flowsResponse.FlowREST | null; - environment: Environment; - isEdit: boolean; - initialValue: FormValues; - prevDetails?: ReportDetailType[]; - versionData?: VersionDataType[]; - flowId?: string; - versionId?: string; - isRestricted: boolean; - errorCorrection?: boolean; - inputEntries: InputEntriesType; - initializeInputEntries: () => void; - rejectInputEntry: (key: string) => void; - currentVersionID?: number; - currentFlowID?: number; - currentVersionActiveStatus?: boolean; - isPending?: boolean; - isSuperseded?: boolean; - isCancelled?: boolean; - isCancellation?: boolean; - isNewPending?: boolean; - isUpdatePending?: boolean; - canReactive?: boolean; - isErrorCorrection?: boolean | null; - isApprovedFlowVersion?: boolean | null; - pendingFieldsallApplied?: boolean; - allFieldsReviewed?: boolean; - pendingVersionV1?: boolean; -} - -const StyledRepOrgLink = tw.div` - flex - ml-1 -`; - -const StyledAddChildWarning = tw.div` - border border-solid border-yellow-600 - flex - rounded-md - text-gray-900 - bg-yellow-100 bg-opacity-50 -`; - -const StyledAddChildWarningIconDiv = tw.div` - flex - items-center - p-1 -`; -const StyledAddChildWarningText = tw.span` - py-3 px-3 pb-3 -`; -const StyledLayoutRow = tw.div` -flex -`; -const StyledHalfSection = tw.div` -w-1/2 -`; -const StyledFullSection = tw.div` -w-full -mb-6 -`; -const StyledRow = tw.div` -flex -gap-4 -w-full -`; -const StyledFormRow = tw.div` -flex -gap-2 -w-full -items-center -`; -const StyledAnchor = tw.a` -underline -ml-[15px] -opacity-100 -`; -const StyledAnchorDiv = tw.div` -text-right -w-full -`; -const StyledRadioDiv = tw.div` -relative -w-full -`; -const StyledFieldset = tw.fieldset` -w-full -box-border -rounded-xl -mt-[16px] -mb-[8px] -border-gray-100 -`; -const StyledCurrencyRow = tw.div` -w-1/2 -`; -const StyledFormButton = tw(C.Button)` -ml-[25px] -mb-6 -`; -const StyledLabel = tw.label` -block -my-4 -`; -const StyledLinkedFlowRow = tw.div` -mt-4 -`; - -const StyledParentInfo = tw.div` -border-0 -border-b -border-solid -cursor-pointer -mb-4 -pb-4 -`; - -const StyledStrong = tw.strong` -min-w-[16rem] -inline-block -`; - -const StyledList = tw.li` -list-none -`; - -const StyledDiv = tw.div` -my-6 -me-4 -mr-[23px] -lg:flex -justify-end -gap-x-4 -bg-white -z-10 -`; - -const initialReportDetail = { - verified: 'verified', - reportSource: 'primary', - reporterReferenceCode: '', - reportChannel: '', - reportFileTitle: '', - reportedOrganization: { value: '', displayLabel: '' }, - reportedDate: dayjs().format('DD/MM/YYYY'), - reporterContactInformation: '', - sourceSystemRecordId: '', -}; - -const FORM_SETTINGS = { - organization: { - behavior: 'shared', - }, - project: { - behavior: 'overlap', - }, - usageYear: { - behavior: 'shared', - }, - location: { - behavior: 'shared', - }, - globalCluster: { - behavior: 'shared', - }, - emergency: { - behavior: 'overlap', - }, - governingEntity: { - behavior: 'shared', - }, - plan: { - behavior: 'overlap', - }, -}; - -const objectTypes = [ - 'emergencies', - 'projects', - 'usageYears', - 'globalClusters', - 'locations', - 'plans', - 'organizations', -] as const; - -const flowValuesForDisplay = [ - 'amountUSD', - 'flowDate', - 'decisionDate', - 'firstReportedDate', - 'budgetYear', - 'origAmount', - 'origCurrency', - 'exchangeRate', - 'activeStatus', - 'restricted', - 'newMoney', - 'description', - 'notes', -] as const; - -let parentValue = ''; - -export const FlowSource = () => { - const { - flowValue, - setFlowValue, - initialValue, - isEdit, - currentVersionData, - environment, - prevDetails, - versionData, - isRestricted, - errorCorrection, - inputEntries, - flowId, - versionId, - initializeInputEntries, - rejectInputEntry, - currentVersionID, - currentFlowID, - currentVersionActiveStatus, - isPending, - isSuperseded, - isCancelled, - isCancellation, - isNewPending, - isUpdatePending, - canReactive, - pendingFieldsallApplied, - allFieldsReviewed, - pendingVersionV1, - }: any = useContext(FlowContext); - // const { - // currentVersionData, - // environment, - // initialValue, - // isEdit, - // prevDetails, - // versionData, - // isRestricted, - // errorCorrection, - // inputEntries, - // flowId, - // versionId, - // initializeInputEntries, - // rejectInputEntry, - // currentVersionID, - // currentFlowID, - // currentVersionActiveStatus, - // isPending, - // isSuperseded, - // isCancelled, - // isCancellation, - // isNewPending, - // isUpdatePending, - // canReactive, - // pendingFieldsallApplied, - // allFieldsReviewed, - // pendingVersionV1, - // } = props; - const { confirm } = dialogs; - const env = getEnv(); - - const collapseFlowObjects = (data: any) => { - data.flowObjects = []; - - collapsePerBehavior(data.dest, 'destination'); - collapsePerBehavior(data.src, 'source'); - - function collapsePerBehavior(behaviorArr: any, ref: any) { - Object.keys(behaviorArr).forEach((type) => { - behaviorArr[type].forEach((obj: any) => { - if ( - obj !== null && - (!Object.prototype.hasOwnProperty.call(obj, 'cleared') || - !obj.cleared) - ) { - if (type === 'organization') { - obj.objectDetail = obj.implementingPartner ? 'partner' : null; - } - - const flowObj = { - refDirection: ref, - objectType: type, - objectID: obj.id, - behavior: obj.behavior || null, - objectDetail: obj.objectDetail, - }; - data.flowObjects.push(flowObj); - } - }); - }); - } - - return data as any; - }; - - const collapseCategories = (data: any) => { - data.categories = [ - data.flowType, - data.flowStatuses, - data.contributionTypes, - data.method, - data.childMethod, - data.keywords, - data.inactiveReason, - data.beneficiaryGroup, - data.pendingStatus, - data.earmarking !== null && data.earmarking.id, - ].filter((category) => category); - data.categories = data.categories - .map((value: any) => { - if (value && value.id) { - return value.id; - } else if (value[0]) { - return value[0].id; - } - }) - .filter(function (value: any) { - return value; - }) - .map((value: any) => { - return parseInt(value); - }); - - return data; - }; - const [uploadFileFlag, setUploadFileFlag] = useState(false); - const [uploadFlag, setUploadFlag] = useState(false); - const normalizeFlowData = (values: FormValues) => { - const fundingObject = { - src: { - governingEntity: values.sourceGoverningEntities.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - location: values.sourceLocations.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - organization: values.sourceOrganizations.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - project: values.sourceProjects.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - usageYear: values.sourceUsageYears.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - globalCluster: values.sourceGlobalClusters.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - emergency: values.sourceEmergencies.map((item) => ({ - id: item.value, - name: item.displayLabel, - restricted: item.restricted, - })), - plan: values.sourcePlans.map((item) => ({ - id: item.value, - name: item.displayLabel, - restricted: item.restricted, - })), - }, - dest: { - governingEntity: values.destinationGoverningEntities.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - location: values.destinationLocations.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - organization: values.destinationOrganizations.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - project: values.destinationProjects.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - usageYear: values.destinationUsageYears.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - globalCluster: values.destinationGlobalClusters.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - emergency: values.destinationEmergencies.map((item) => ({ - id: item.value, - name: item.displayLabel, - restricted: item.restricted, - })), - plan: values.destinationPlans.map((item) => ({ - id: item.value, - name: item.displayLabel, - restricted: item.restricted, - })), - }, - }; - - let data = { - id: isEdit && currentFlowID ? currentFlowID : null, - versionID: isEdit && currentVersionID ? currentVersionID : null, - amountUSD: values.amountUSD, - flowDate: dayjs(values.flowDate, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ), - decisionDate: values.decisionDate - ? dayjs(values.decisionDate, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ) - : null, - firstReportedDate: dayjs(values.firstReported, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ), - budgetYear: values.budgetYear, - origAmount: values.amountOriginal ? values.amountOriginal : null, - origCurrency: (values.origCurrency as AutoCompleteSelectionType) - ? (values.origCurrency as AutoCompleteSelectionType)?.displayLabel - : null, - exchangeRate: values.exchangeRateUsed ? values.exchangeRateUsed : null, - activeStatus: true, - restricted: false, - newMoney: true, - description: values.flowDescription, - versionStartDate: currentVersionData?.versionStartDate, - versionEndDate: currentVersionData?.versionEndDate, - flowObjects: collapseFlowObjects(fundingObject), - children: - values.childFlow && - values.childFlow.map((item: any, index: number) => { - return { - childID: JSON.parse(item.value as string).id, - origCurrency: JSON.parse(item.value as string).origCurrency, - }; - }), - parents: - values.parentFlow && - values.parentFlow.map((item: any, index: number) => { - return { - Parent: { - parentID: JSON.parse(item.value as string).id, - origCurrency: JSON.parse(item.value as string).origCurrency, - }, - childID: currentFlowID, - parentID: JSON.parse(item.value as string).id, - origCurrency: JSON.parse(item.value as string).origCurrency, - id: JSON.parse(item.value as string).id, - parents: - values.parentFlow && - values.parentFlow.map((key: any) => { - return { - child: JSON.parse(key.value as string).id, - parentID: 271736, - }; - }), - }; - }), - reportDetails: values.reportDetails.map((item, index) => { - return { - contactInfo: item.reporterContactInformation, - source: item.reportSource, - date: dayjs(item.reportedDate, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ), - versionID: currentVersionID, - newlyAdded: addReportFlag, - sourceID: null, - refCode: '7F-10073.04', - verified: true, - organizationID: item.reportedOrganization.value, - categories: [item.reportChannel && item.reportChannel.value], - organization: { - id: item.reportedOrganization.value, - name: item.reportedOrganization.displayLabel, - }, - reportFiles: - uploadFlag && - uploadedFileArray[index] && - (uploadedFileArray[index] as { id?: number })?.id - ? uploadFlag || uploadFileFlag - ? [ - { - title: item.reportUrlTitle, - type: 'url', - url: item.reportUrl, - }, - { - fileAssetID: - uploadedFileArray[index] && - (uploadedFileArray[index] as { id?: number })?.id, - reportFiles: [ - { - fieldType: 'file', - fileAssetID: - uploadedFileArray[index] && - (uploadedFileArray[index] as { id?: number })?.id, - type: 'file', - }, - ], - title: item.reportFileTitle, - type: 'file', - }, - ] - : [ - { - title: item.reportUrlTitle, - type: 'url', - url: item.reportUrl, - }, - ] - : uploadFileFlag - ? [ - { - title: item.reportUrlTitle, - type: 'url', - url: item.reportUrl, - }, - ] - : item.reportFiles - ? item.reportFiles - : [], - - reportChannel: { - group: 'reportChannel', - id: item.reportChannel && item.reportChannel.value, - name: item.reportChannel && item.reportChannel.displayLabel, - }, - }; - }), - flowType: { - id: values.flowType && values.flowType.value, - name: values.flowType && values.flowType.displayLabel, - group: 'flowType', - }, - keywords: values.keywords.map((item) => ({ - id: item.value, - name: item.displayLabel, - group: 'keywords', - })), - flowStatuses: { - id: values.flowStatus && values.flowStatus.value, - name: values.flowStatus && values.flowStatus.displayLabel, - group: 'flowStatus', - }, - contributionTypes: { - id: values.contributionType && values.contributionType.value, - name: values.contributionType && values.contributionType.displayLabel, - group: 'contributionType', - }, - method: { - id: values.method && values.method.value, - name: values.method && values.method.displayLabel, - group: 'method', - }, - childMethod: values.cashTransfer && { - id: values.cashTransfer.value, - name: values.cashTransfer.displayLabel, - group: 'method', - parentID: values.method && values.method.value, - }, - earmarking: values.earmarkingType - ? { - id: values.earmarkingType.value, - name: values.earmarkingType.displayLabel, - group: 'earmarkingType', - } - : null, - categories: [] as (string | number)[], - isCancellation: isPending ? true : !isPending ? false : null, - cancelled: isPending && isCancellation ? true : null, - pendingStatus: isPending ? true : !isPending ? false : [], - planEntities: isPending ? true : !isPending ? false : [], - planIndicated: isPending ? true : !isPending ? false : [], - isApprovedFlowVersion: - rejectFlag && approveFlag - ? true - : !(rejectFlag && approveFlag) - ? false - : null, - inactiveReason: [ - { - id: null as null | number | string, - name: '' as string | undefined, - description: null, - parentID: null, - code: null, - group: '', - includeTotals: null, - createdAt: '', - updatedAt: '', - }, - ], - isErrorCorrection: errorCorrection - ? true - : isSuperseded - ? true - : isPending - ? true - : !isSuperseded && !isPending - ? false - : null, - rejected: rejectFlag ? true : !rejectFlag ? false : null, - versions: - versionData && - versionData.map((item: VersionDataType) => { - const items = { - id: item.flowId, - versionID: item.versionId, - activeStatus: item.activeStatus, - isPending: item.isPending ? item.isPending : false, - isCancelled: item.isCancelled ? item.isCancelled : false, - }; - return items; - }), - ...fundingObject, - }; - - data = collapseCategories(data); - return data; - }; - - const [unsavedChange, setUnsavedChange] = useState(false); - const [parentCurrencyFlag, setParentCurrencyFlag] = useState(false); - const [childCurrencyFlag, setChildCurrencyFlag] = useState(false); - const [approveFlag, setApproveFlag] = useState(false); - const [rejectFlag, setRejectFlag] = useState(false); - const [validationFlag, setValidationFlag] = useState(false); - const [inactiveFlag, setInactiveFlag] = useState(false); - const [uploadedFileArray, setUploadedFileArray] = useState([ - {}, - ]); - const [addReportFlag, setAddReportFlag] = useState(false); - const [alertFlag, setAlertFlag] = useState(false); - const [sharePath, setSharePath] = useSharePath(''); - const [readOnly, setReadOnly] = useState(false); - const [linkCheck, setLinkCheck] = useState(false); - const handleSave = () => { - window.scrollTo({ top: 0, behavior: 'smooth' }); - }; - - const [showWarningMessage, setShowWarningMessage] = useState(false); - const [objects, setObjects] = useState>({}); - const [showingTypes, setShowingTypes] = useState([]); - const [newMoneyCheckboxDisabled, setNewMoneyCheckboxDisabled] = - useState(false); - - const [comparingVersions, setComparingVersions] = useState( - [] - ); - const [comparedVersions, setComparedVersions] = useState( - [] - ); - const [showSourceGoverningEntities, handleShowSourceGoverningEntities] = - useState(false); - const [ - showDestinationGoverningEntities, - handleShowDestinationGoverningEntities, - ] = useState(false); - const [sourceGoverningEntities, setSourceGoverningEntities] = - useState([]); - const [destinationGoverningEntities, setDestinationGoverningEntities] = - useState([]); - const [isShowParentFlow, setShowParentFlow] = useState( - initialValue.parentFlow && initialValue.parentFlow.length ? true : false - ); - const [isShowChildFlow, setShowChildFlow] = useState(0); - const [openAlerts, setOpenAlerts] = useState< - { message: string; id: number }[] - >([]); - const [alertId, setAlertId] = useState(0); - const handleClose = (id: number) => { - setOpenAlerts(openAlerts.filter((alert) => alert.id !== id)); - }; - const buttonText = 'Calculate The Exchange Rate'; - - const handleCalculateExchangeRate = (values: any, setFieldValue: any) => { - const { amountOriginal, amountUSD } = values; - - if (amountOriginal && amountUSD) { - const exchangeRateUsed = amountOriginal / amountUSD; - setFieldValue('exchangeRateUsed', exchangeRateUsed.toFixed(4)); - } else if (amountOriginal && !amountUSD) { - const calculatedAmountUSD = amountOriginal / values.exchangeRateUsed; - setFieldValue('amountUSD', calculatedAmountUSD.toFixed(4)); - } else if (!amountOriginal && amountUSD) { - const calculatedAmountOriginal = amountUSD * values.exchangeRateUsed; - setFieldValue('amountOriginal', calculatedAmountOriginal.toFixed(4)); - } else { - console.warn('Both original amount and USD amount are missing.'); - } - }; - useEffect(() => { - if (initialValue?.childFlow) { - setShowChildFlow(initialValue?.childFlow.length); - } - }, [initialValue]); - useEffect(() => { - const fileAssets: FileAssetEntityType[] = []; - if (isEdit) { - initialValue.reportDetails.forEach((detail: any) => { - if (detail?.fileAsset) { - fileAssets.push(detail.fileAsset); - setUploadedFileArray(fileAssets); - } else { - fileAssets.push({} as FileAssetEntityType); - setUploadedFileArray(fileAssets); - } - }); - } - }, [initialValue.reportDetails]); - useEffect(() => { - if (currentVersionActiveStatus) { - setReadOnly(false); - } else { - setReadOnly(true); - } - }, [currentVersionActiveStatus]); - useEffect(() => { - if (initialValue.parentFlow && initialValue.parentFlow.length) { - setShowParentFlow(true); - } - }, [initialValue.parentFlow]); - const [remove, setRemove] = useState(false); - const handleRemove = (index: number, values: FormValues) => { - if (window.confirm('Are you sure you want to remove this file?')) { - if ( - initialValue.reportDetails[index].reportFiles && - initialValue.reportDetails[index].reportFiles[0]?.fileName - ) { - values.reportDetails[index].reportFileTitle = ''; - initialValue.reportDetails[index].reportFiles[0].fileName = ''; - initialValue.reportDetails[index].reportFiles[0].title = ''; - initialValue.reportDetails[index].reportFiles[0].fileAssetID = - undefined; - initialValue.reportDetails[index].reportFiles[0].UploadFileUrl = ''; - const updatedArray = removeByIndexFromArray(uploadedFileArray, index); - setUploadedFileArray(updatedArray); - } else return; - setUploadFlag(false); - setRemove(true); - } else return; - }; - const removeByIndexFromArray = (array: UploadedItem[], index: number) => { - const newArray = [...array]; - newArray[index] = {}; - return newArray; - }; - if (remove === true) setRemove(false); - const SourceLink = ( - setFieldValue: any, - values: FormValues, - indexKey: number, - index: number - ) => { - setFieldValue( - `reportDetails[${index}].reportedOrganization`, - values.sourceOrganizations[indexKey] - ); - }; - const DestinationLink = ( - setFieldValue: any, - values: FormValues, - indexKey: number, - index: number - ) => { - setFieldValue( - `reportDetails[${index}].reportedOrganization`, - values.destinationOrganizations[indexKey] - ); - }; - - interface Inconsistency { - type: string; - values: { - name?: string; - year?: string; - refDirection: string; - options?: { name: string }[]; - }[]; - } - - const processDataInconsistencies = ( - inconsistencyArray: Inconsistency[] - ): string => { - let message = ''; - inconsistencyArray.forEach((inconsistencyWith) => { - if (inconsistencyWith && inconsistencyWith.type) { - const inconsistencyType = inconsistencyWith.type; - message += - inconsistencyType.charAt(0).toUpperCase() + - inconsistencyType.slice(1) + - ': '; - - if (inconsistencyWith.type === 'no-direct-link') { - message += inconsistencyWith.values.join(', '); - } else { - message += - inconsistencyWith.values - .map((value) => { - const name = value.name || value.year; - let joinedOptions = ''; - if (value.options) { - joinedOptions = value.options - .map((option) => { - return option.name || JSON.stringify(option); - }) - .join(', '); - } - const options = `is not in the list of acceptable ${value.refDirection} ${inconsistencyType}: [${joinedOptions}]`; - return `'${name}' ${options}`; - }) - .join(', ') + '. '; - } - } else { - message += JSON.stringify(inconsistencyArray); - } - }); - return message; - }; - - const handleSubmit = async ( - values: FormValues, - submitAction: string | undefined - ) => { - if (values.childFlow) { - for (let i = 0; i < values.childFlow.length; i++) { - if ( - values.destinationUsageYears.length >= 2 && - JSON.parse(values.childFlow[i].value as string).activeStatus === true - ) { - values.flowType = { - displayLabel: 'Parked', - value: '1252', - }; - } - } - } - if (isShowParentFlow && isShowChildFlow > 0) { - let childAmountSum = 0; - let parentAmountSum = 0; - values.childFlow && - values.childFlow.map((item, _index) => { - childAmountSum += JSON.parse(item.value.toString()) - ? parseInt(JSON.parse(item.value.toString()).amountUSD) - : 0; - }); - values.parentFlow && - values.parentFlow.map((item, _index) => { - parentAmountSum += JSON.parse(item.value.toString()) - ? parseInt(JSON.parse(item.value.toString()).amountUSD) - : 0; - }); - if (childAmountSum > parentAmountSum) { - if ( - !window.confirm( - `Please note, the Funding Amount on this parent flow ($${parentAmountSum}) is less than the sum of its children's amount ($${childAmountSum}). Do you want to proceed?` - ) - ) { - return; - } - } - } - if (isShowParentFlow || isShowChildFlow > 0) { - let childAmountSum = 0; - values.childFlow && - values.childFlow.map((item, _index) => { - childAmountSum += JSON.parse(item.value.toString()) - ? parseInt(JSON.parse(item.value.toString()).amountUSD) - : 0; - }); - if (childAmountSum > values.amountUSD) { - if ( - !window.confirm( - `Please note, the Funding Amount on this parent flow ($${values.amountUSD}) is less than the sum of its children's amount ($${childAmountSum}). Do you want to proceed?` - ) - ) - return; - } - } - const parentFlow = values.parentFlow; - if (parentFlow?.length) { - for (let index = 0; index < parentFlow.length; index++) { - const item = parentFlow[index]; - if ( - (typeof values?.origCurrency !== 'string' && - values.origCurrency?.displayLabel) || - !( - JSON.parse(item.value.toString()) && - JSON.parse(item.value.toString())?.origCurrency === null - ) - ) { - if ( - (typeof values?.origCurrency !== 'string' && - values.origCurrency?.displayLabel) !== - (JSON.parse(item.value.toString()) && - JSON.parse(item.value.toString())?.origCurrency) - ) { - handleSave(); - setParentCurrencyFlag(true); - return; - } - } - } - } - const childFlow = values.childFlow; - if (childFlow) { - for (let index = 0; index < childFlow.length; index++) { - const item = childFlow[index]; - if ( - (typeof values?.origCurrency !== 'string' && - values.origCurrency?.displayLabel) || - !( - JSON.parse(item.value.toString()) && - JSON.parse(item.value.toString())?.origCurrency === null - ) - ) { - if ( - (typeof values.origCurrency !== 'string' && - values.origCurrency?.displayLabel) !== - (JSON.parse(item.value.toString()) && - JSON.parse(item.value.toString()).origCurrency) - ) { - handleSave(); - setChildCurrencyFlag(true); - return; - } - } - } - } - for (let i = 0; i < values.reportDetails.length; i++) { - if ( - values.reportDetails[i].reportUrlTitle && - values.reportDetails[i].reportUrl - ) { - setUploadFileFlag(true); - } else setUploadFileFlag(false); - } - const data = normalizeFlowData(values); - const inactiveReasons = await fetchCategory('inactiveReason')(); - if (submitAction === 'approve') { - data.isApprovedFlowVersion = true; - } else if (submitAction === 'rejected') { - data.activeStatus = false; - data.rejected = true; - data.inactiveReason = [ - { - id: - inactiveReasons.find( - (item: any) => item.displayLabel === 'Rejected' - )?.value || null, - name: inactiveReasons.find( - (item: any) => item.displayLabel === 'Rejected' - )?.displayLabel, - description: null, - parentID: null, - code: null, - group: 'inactiveReason', - includeTotals: null, - createdAt: currentVersionData - ? dayjs(currentVersionData.createdAt, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ) - : '', - updatedAt: currentVersionData - ? dayjs(currentVersionData.updatedAt, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ) - : '', - }, - ]; - } else if (submitAction === 'inactive') { - if (isShowParentFlow || isShowChildFlow > 0) { - setInactiveFlag(true); - } else { - const categoryValue = - inactiveReasons.find((item: any) => item.displayLabel === 'Cancelled') - ?.value ?? null; - if (categoryValue) { - data.categories.push(parseInt(categoryValue.toString())); - } - data.activeStatus = false; - data.cancelled = true; - data.isCancellation = null; - data.rejected = null; - data.newMoney = false; - data.inactiveReason = [ - { - id: - inactiveReasons.find( - (item: any) => item.displayLabel === 'Cancelled' - )?.value || null, - name: inactiveReasons.find( - (item: any) => item.displayLabel === 'Cancelled' - )?.displayLabel, - description: null, - parentID: null, - code: null, - group: 'inactiveReason', - includeTotals: null, - createdAt: currentVersionData ? currentVersionData.createdAt : '', - updatedAt: currentVersionData ? currentVersionData.updatedAt : '', - }, - ]; - } - } - if (!inactiveFlag) { - const response = await env.model.flows.validateFlow(data); - let flag = true; - let mismatchFound = false; - for (let i = 0; i < values.reportDetails.length; i++) { - const reportOrganizationLabel = - values.reportDetails[i].reportedOrganization.displayLabel; - const reportMatchesSource = values.sourceOrganizations.some( - (sourceOrg) => sourceOrg.displayLabel === reportOrganizationLabel - ); - const reportMatchesDestination = values.destinationOrganizations.some( - (destOrg) => destOrg.displayLabel === reportOrganizationLabel - ); - - if (!reportMatchesSource && !reportMatchesDestination) { - mismatchFound = true; - break; - } - } - if (mismatchFound) { - if ( - !window.confirm( - "Your flow's Report Detail organization doesn't match the source or destination organization or that of its parked parent. Are you sure this is right?" - ) - ) { - return; - } - } - response.forEach((obj) => { - if (obj) { - const { success, message, confirmed } = obj; - if (!success) { - if (confirmed) { - const confirm = window.confirm(confirmed); - if (!confirm) { - setOpenAlerts([...openAlerts, { message, id: alertId }]); - setAlertId((prevId) => prevId + 1); - flag = false; - handleSave(); - } - } else if (message) { - setOpenAlerts([...openAlerts, { message, id: alertId }]); - setAlertId((prevId) => prevId + 1); - flag = false; - handleSave(); - } - } - } - }); - if (flag && !(isShowParentFlow || isShowChildFlow > 0)) { - setUnsavedChange(false); - if (!isEdit) { - try { - const response = await env.model.flows.createFlow({ flow: data }); - const path = editFlowSetting(response.id, response.versionID); - window.open(path, '_self'); - } catch (err: any) { - setOpenAlerts([ - ...openAlerts, - { message: err.message, id: alertId }, - ]); - setAlertId((prevId) => prevId + 1); - handleSave(); - } - } else { - const dbFlow = await env.model.flows.getFlowREST({ - id: currentFlowID!, - }); - if ( - (versionData && - currentVersionID && - Date.parse(versionData[currentVersionID - 1].updatedTime) < - Date.parse(dbFlow.updatedAt)) || - (versionData && versionData.length < dbFlow.versions.length) - ) { - window.confirm( - 'This flow cannot be saved, as a concurrency conflict has been detected. Please refresh your screen to view the most up to date data.' - ); - } else { - if (isPending && (approveFlag || rejectFlag)) { - if ( - allFieldsReviewed || - pendingFieldsallApplied || - !pendingVersionV1 - ) { - try { - const response = await env.model.flows.updatePendingFlow({ - flow: data, - }); - if (response) { - const path = editFlowSetting( - response.id, - response.versionID - ); - setAlertFlag(true); - setSharePath(path); - } - } catch (err: any) { - setOpenAlerts([ - ...openAlerts, - { message: err.message, id: alertId }, - ]); - setAlertId((prevId) => prevId + 1); - handleSave(); - } - } else { - window.confirm( - 'Some of the revised data on this flow still needs to be accepted or rejected before this update can be approved.' - ); - } - } else { - try { - const response = await env.model.flows.updateFlow({ - flow: data, - }); - if (response) { - const path = editFlowSetting(response.id, response.versionID); - setAlertFlag(true); - setSharePath(path); - } - } catch (err: any) { - let errmessage = ''; - if (err.reason) { - const inconsistencyObject = err.reason; - errmessage = processDataInconsistencies(inconsistencyObject); - } else { - const lastIndex = err.message.lastIndexOf(':'); - errmessage = err.message.substring(lastIndex + 1); - } - setOpenAlerts([ - ...openAlerts, - { message: errmessage, id: alertId }, - ]); - setAlertId((prevId) => prevId + 1); - handleSave(); - } - } - } - } - } - } - }; - const navigate = useNavigate(); - const handleCopy = (values: FormValues) => { - if (currentFlowID && currentVersionID) { - const isCopy = true; - const path = copyFlow(); - if (typeof path === 'string') { - const valuesWithFiles = { ...values, isCopy }; - navigate(path, { state: valuesWithFiles }); - } else { - console.error('Path is not a string', path); - } - } - }; - - const handleAlert = (values: FormValues) => { - const errors = validateForm(values); - if (Object.keys(errors).length !== 0) { - setValidationFlag(true); - handleSave(); - } - }; - - const setObjectsWithArray = ( - fetchedObject: any, - objectKeys: string[], - settingArrayKeys: string[], - setFieldValue: any, - values: any - ) => { - const newObjects = { ...objects }; - const newShowingTypes = [...showingTypes]; - objectKeys.forEach((key, i) => { - if (fetchedObject[settingArrayKeys[i]]) { - newObjects[key] = checkIfExistingAndCopy( - newObjects[key], - fetchedObject, - settingArrayKeys[i] - ); - } - - const parsedResponse = newObjects[key].map((responseValue: any) => { - if (settingArrayKeys[i] === 'years') { - return { - displayLabel: - (responseValue as usageYears.UsageYear).year || - responseValue.displayLabel, - value: responseValue.id || responseValue.value, - isAutoFilled: responseValue.suggested, - }; - } else if (settingArrayKeys[i] === 'plans') { - return { - displayLabel: - (responseValue.planVersion as { planId: number; name: string }) - .name || responseValue.displayLabel, - value: responseValue.planVersion.planId || responseValue.value, - isAutoFilled: responseValue.suggested, - }; - } else if (settingArrayKeys[i] === 'governingEntities') { - return { - displayLabel: - ( - responseValue.governingEntityVersion as { - id: number; - name: string; - } - ).name || responseValue.displayLabel, - value: - responseValue.governingEntityVersion.id || responseValue.value, - isAutoFilled: responseValue.suggested, - }; - } else { - return { - displayLabel: - (responseValue as { id: number; name: string }).name || - responseValue.displayLabel, - value: responseValue.id || responseValue.value, - isAutoFilled: responseValue.suggested, - }; - } - }); - newObjects[key].forEach((obj) => { - if (obj?.suggested) { - updateFlowObjects(key, parsedResponse, setFieldValue, values); - obj.suggested = false; - } - }); - setFieldValue(key, parsedResponse); - }); - - setObjects(newObjects); - setShowingTypes(newShowingTypes); - }; - - const checkIfExistingAndCopy = ( - existingObjects: any[], - object: any, - key: string - ): any[] => { - let newObjects = object[key]; - if (key === 'locations') { - newObjects = newObjects.filter(function (location: any) { - return location.adminLevel === 0; - }); - if (existingObjects && existingObjects.length) { - existingObjects = existingObjects.filter(function (location) { - return location.adminLevel === 0 || location.value; - }); - } - } - - if (existingObjects && existingObjects.length) { - const existingObjectsIds = existingObjects.map(function (o) { - return o.id || o.value; - }); - if (Array.isArray(newObjects)) { - newObjects.forEach(function (obj) { - if (existingObjectsIds.indexOf(obj.id) === -1) { - obj.suggested = true; - existingObjects.push(obj); - } - }); - } else { - if (existingObjectsIds.indexOf(newObjects.id) === -1) { - newObjects.suggested = true; - existingObjects.push(newObjects); - } - } - } else { - if (newObjects) { - if (Array.isArray(newObjects)) { - newObjects.forEach(function (obj) { - obj.suggested = true; - }); - existingObjects = newObjects; - } else { - newObjects.suggested = true; - existingObjects = [newObjects]; - } - } - } - return existingObjects; - }; - const fetchPlanDetails = async ( - objectType: string, - plan: any, - setFieldValue: any, - values?: any - ) => { - const fetchedPlan = await environment.model.plans.getPlan(plan[0].value); - if (objectType === 'sourcePlans') { - setObjectsWithArray( - fetchedPlan, - ['sourceUsageYears', 'sourceEmergencies'], - ['years', 'emergencies'], - setFieldValue, - values - ); - setSourceGoverningEntities(fetchedPlan.governingEntities); - } - if (objectType === 'destinationPlans') { - setObjectsWithArray( - fetchedPlan, - ['destinationUsageYears', 'destinationEmergencies'], - ['years', 'emergencies'], - setFieldValue, - values - ); - setDestinationGoverningEntities(fetchedPlan.governingEntities); - } - if (fetchedPlan.locations) { - const countries = fetchedPlan.locations.filter(function (loc: any) { - return loc.adminLevel === 0; - }); - if (countries.length === 1) { - if (objectType === 'sourcePlans') { - setObjectsWithArray( - { locations: countries }, - ['sourceLocations'], - ['locations'], - setFieldValue, - values - ); - } - if (objectType === 'destinationPlans') { - setObjectsWithArray( - { locations: countries }, - ['destinationLocations'], - ['locations'], - setFieldValue, - values - ); - } - } - } - }; - - const fetchEmergencyDetails = async ( - objectType: string, - emergency: any, - setFieldValue: any, - values?: any - ) => { - if (objectType === 'destinationEmergencies') { - const fetchedEmergency = await environment.model.emergencies.getEmergency( - emergency[0].value - ); - if (fetchedEmergency.locations.length <= 1) { - setObjectsWithArray( - fetchedEmergency, - ['destinationLocations'], - ['locations'], - setFieldValue, - values - ); - } - } - }; - const fetchProjectDetails = async ( - objectType: string, - project: any, - setFieldValue: any, - values?: any - ) => { - const fetchedProject = await environment.model.projects.getProject( - project[0].value - ); - const publishedVersion = fetchedProject.projectVersions.filter(function ( - version: any - ) { - return version.id === fetchedProject.currentPublishedVersionId; - })[0]; - if (objectType === 'destinationProjects') { - const fetchedCategories = - await environment.model.categories.getCategories({ - query: 'earmarkingType', - }); - const category = fetchedCategories.filter( - (item: any) => item.name === 'Earmarked' - ); - setFieldValue('earmarkingType', { - value: category[0], - displayLabel: category[0].name, - }); - setObjectsWithArray( - publishedVersion, - [ - 'destinationPlans', - 'destinationLocations', - 'destinationGoverningEntities', - 'destinationGlobalClusters', - 'destinationOrganizations', - ], - [ - 'plans', - 'locations', - 'governingEntities', - 'globalClusters', - 'organizations', - ], - setFieldValue, - values - ); - } else { - setObjectsWithArray( - publishedVersion, - [ - 'sourcePlans', - 'sourceLocations', - 'sourceGoverningEntities', - 'sourceGlobalClusters', - 'sourceOrganizations', - ], - [ - 'plans', - 'locations', - 'governingEntities', - 'globalClusters', - 'organizations', - ], - setFieldValue, - values - ); - } - }; - const fetchOrganizationDetails = async ( - objectType: string, - organization: any, - setFieldValue: any, - values?: any - ) => { - const fetchedOrg = - await environment.model.organizations.getOrganizationsById( - organization[0].value - ); - const isGovernment = (fetchedOrg[0].categories ?? []).some(function ( - category: any - ) { - return ( - category.group === 'organizationType' && - [114, 123].includes(category.id) - ); - }); - if (isGovernment && objectType === 'sourceOrganizations') { - objects.sourceLocations = checkIfExistingAndCopy( - objects.location, - fetchedOrg[0], - 'locations' - ); - setObjectsWithArray( - objects, - ['sourceLocations'], - ['locations'], - setFieldValue, - values - ); - } - }; - const fetchAssociatedGoverningEntity = async ( - objectType: string, - globalCluster: any, - setFieldValue: any, - values?: any - ) => { - if ( - (values.sourcePlans.length === 0 && - objectType === 'sourceGlobalClusters') || - (values.destinationPlans.length === 0 && - objectType === 'destinationGlobalClusters') - ) { - return; - } - let plan = null; - let targetGoverningEntities: any = null; - if (objectType === 'sourceGlobalClusters') { - plan = values.sourcePlans[0]; - targetGoverningEntities = values.sourceGoverningEntities; - } else { - plan = values.destinationPlans[0]; - targetGoverningEntities = values.destinationGoverningEntities; - } - const fetchedGoverningEntities = - await environment.model.governingEntities.getAllPlanGoverningEntities( - plan.value - ); - const hasGoverningEntitiesWithoutGlobalCluster = - Array.isArray(targetGoverningEntities) && - fetchedGoverningEntities - .filter(function (fetchedGe: any) { - return targetGoverningEntities.find(function (selectedGe: any) { - return fetchedGe.id === selectedGe.value; - }); - }) - .some(function (fetchedGe: any) { - return ( - Array.isArray(fetchedGe.globalClusterIds) && - !fetchedGe.globalClusterIds.length - ); - }); - - if (hasGoverningEntitiesWithoutGlobalCluster) { - return; - } - const governingEntities = fetchedGoverningEntities.filter(function ( - governingEntity: any - ) { - return ( - governingEntity.globalClusterIds.indexOf( - globalCluster[globalCluster.length - 1].value - ) > -1 - ); - }); - - if (governingEntities.length) { - governingEntities.forEach(function (governingEntity: any) { - setObjectsWithArray( - { governingEntities: governingEntity }, - [ - objectType === 'sourceGlobalClusters' - ? 'sourceGoverningEntities' - : 'destinationGoverningEntities', - ], - ['governingEntities'], - setFieldValue, - values - ); - }); - } - }; - - const fetchKeywords = async ( - objectType: string, - usageYears: any, - setFieldValue: any, - values?: any - ) => { - if (usageYears.length === 2) { - const fetchedCategories = - await environment.model.categories.getCategories({ - query: 'keywords', - }); - const category = fetchedCategories.filter( - (item: any) => item.name === 'Multiyear' - ); - - const mergedKeywords = [ - ...values.keywords, - ...[ - { - value: category[0].id, - displayLabel: category[0].name, - }, - ].filter( - (item2) => - !values.keywords.some((item1: any) => item1.value === item2.value) - ), - ]; - - setFieldValue('keywords', mergedKeywords); - } else if (usageYears.length === 1) { - const filteredKeywords = values.keywords.filter( - (item: any) => item.displayLabel !== 'Multiyear' - ); - setFieldValue('keywords', filteredKeywords); - } - }; - - const handleCompareCheck = ( - checkedVersion: VersionDataType, - isChecked: boolean - ) => { - setComparingVersions((prev: VersionDataType[]) => { - if (isChecked) { - return [...prev, checkedVersion]; - } else { - return prev.filter( - (version: VersionDataType) => - version.versionId !== checkedVersion.versionId - ); - } - }); - }; - - const fetchDownload = async (index: number) => { - const fileAssetID = - initialValue.reportDetails[index]?.reportFiles[0]?.fileAssetID; - const name = initialValue.reportDetails[index]?.reportFiles[0]?.fileName; - if (fileAssetID) { - try { - const responseData = - await environment?.model.fileUpload.fileDownloadModel(fileAssetID); - if (responseData) { - const data = new Blob([responseData]); - const url = URL.createObjectURL(data); - const a = document.createElement('a'); - a.href = url; - a.download = `${name ? name : 'downloaded_file'}`; - document.body.appendChild(a); - a.click(); - setTimeout(() => { - document.body.removeChild(a); - window.URL.revokeObjectURL(url); - }, 0); - } else { - console.error('No data received for download'); - } - } catch (error) { - console.error(error, 'error'); - } - } - }; - - const fetchCategory = useCallback( - (category: string) => { - return async () => { - const response = await environment.model.categories.getCategories({ - query: category, - }); - return response.map( - (responseValue: any): categoryType => ({ - displayLabel: responseValue.name, - value: responseValue.id.toString(), - parentID: responseValue.parentID, - }) - ); - }; - }, - [environment] - ); - const extractUniqueFromArray = (array1: string[], array2: string[]) => { - return array1.filter((item: string) => !array2.includes(item)); - }; - - const compareVersions = (versions: VersionDataType[]) => { - const version1 = versions[0]; - const version2 = versions[1]; - const newVersion1 = { - ...version1, - uniqueSources: objectTypes.reduce>( - (acc, type) => { - acc[type] = extractUniqueFromArray( - version1.source[type], - version2.source[type] - ); - return acc; - }, - {} - ), - uniqueDestinations: objectTypes.reduce>( - (acc, type) => { - acc[type] = extractUniqueFromArray( - version1.destination[type], - version2.destination[type] - ); - return acc; - }, - {} - ), - uniqueCategories: extractUniqueFromArray( - version1.categories, - version2.categories - ), - }; - - const newVersion2 = { - ...version2, - uniqueSources: objectTypes.reduce>( - (acc, type) => { - acc[type] = extractUniqueFromArray( - version2.source[type], - version1.source[type] - ); - return acc; - }, - {} - ), - uniqueDestinations: objectTypes.reduce>( - (acc, type) => { - acc[type] = extractUniqueFromArray( - version2.destination[type], - version1.destination[type] - ); - return acc; - }, - {} - ), - uniqueCategories: extractUniqueFromArray( - version2.categories, - version1.categories - ), - }; - return [newVersion1, newVersion2]; - }; - const handleFileChange = async ( - event: React.ChangeEvent, - index: number - ) => { - setUploadFlag(true); - try { - const setFile: File | undefined = (event.target as HTMLInputElement) - .files?.[0]; - if (setFile instanceof File) { - const responseData = - await environment.model.fileUpload.fileUploadModel(setFile); - setUploadedFileArray((prevUploadedFile) => { - const updateUploadedFile = [...prevUploadedFile]; - updateUploadedFile[index] = responseData; - return updateUploadedFile; - }); - console.log(uploadedFileArray, 'uploadedFileArray'); - } else { - console.error('No file selected for upload.'); - } - } catch (error) { - console.log(error, 'error'); - } - }; - useEffect(() => { - if (comparingVersions.length === 2) { - const compared = compareVersions(comparingVersions); - setComparedVersions(compared); - } - }, [comparingVersions]); - - useEffect(() => { - const handleBeforeUnload = (event: BeforeUnloadEvent) => { - if (unsavedChange) { - const message = - 'You have unsaved changes! Are you sure you want to leave?'; - event.returnValue = message; // Standard for most browsers - return message; // For some older browsers - } - }; - - window.addEventListener('beforeunload', handleBeforeUnload); - - return () => { - window.removeEventListener('beforeunload', handleBeforeUnload); - }; - }, [unsavedChange]); - - useEffect(() => { - const valuesObject: Record = { - sourceOrganizations: initialValue.sourceOrganizations, - sourceLocations: initialValue.sourceLocations, - sourceUsageYears: initialValue.sourceUsageYears, - sourceProjects: initialValue.sourceProjects, - sourcePlans: initialValue.sourcePlans, - sourceGoverningEntities: initialValue.sourceGoverningEntities, - sourceGlobalClusters: initialValue.sourceGlobalClusters, - sourceEmergencies: initialValue.sourceEmergencies, - destinationOrganizations: initialValue.destinationOrganizations, - destinationLocations: initialValue.destinationLocations, - destinationUsageYears: initialValue.destinationUsageYears, - destinationProjects: initialValue.destinationProjects, - destinationPlans: initialValue.destinationPlans, - destinationGoverningEntities: initialValue.destinationGoverningEntities, - destinationGlobalClusters: initialValue.destinationGlobalClusters, - destinationEmergencies: initialValue.destinationEmergencies, - }; - setObjects(valuesObject); - }, []); - - unstable_usePrompt({ - message: 'You have unsaved changes! Are you sure you want to leave?', - when: unsavedChange, - }); - const dictExecutedForEachObject: Record< - string, - ( - objectType: string, - flowObject: any, - setFieldValue: any, - values: any - ) => Promise - > = { - sourcePlans: fetchPlanDetails, - destinationPlans: fetchPlanDetails, - destinationEmergencies: fetchEmergencyDetails, - sourceProjects: fetchProjectDetails, - destinationProjects: fetchProjectDetails, - sourceOrganizations: fetchOrganizationDetails, - sourceGlobalClusters: fetchAssociatedGoverningEntity, - destinationGlobalClusters: fetchAssociatedGoverningEntity, - sourceUsageYears: fetchKeywords, - destinationUsageYears: fetchKeywords, - }; - - const params: DeleteFlowParams = { - VersionID: currentVersionID ?? 0, - FlowID: currentFlowID ?? 0, - }; - - const deleteFlow = async () => { - if (linkCheck || isShowParentFlow || isShowChildFlow > 0) { - window.confirm( - 'All linked flows must be unlinked before this flow can be deleted. Unlink flows and choose Delete flow again.' - ); - return; - } - - try { - const response = await env.model.flows.deleteFlow(params); - const path = flows(); - window.open(path, '_self'); - } catch (err: any) { - setOpenAlerts([...openAlerts, { message: err.message, id: alertId }]); - setAlertId((prevId) => prevId + 1); - } - }; - const updateFlowObjects = async ( - objectType: string, - flowObject: any, - setFieldValue: any, - values?: any - ) => { - if (flowObject.length > 0 && dictExecutedForEachObject[objectType]) { - flowObject.sort( - ( - a: { displayLabel: string; value: number }, - b: { displayLabel: string; value: number } - ) => { - return a.displayLabel.localeCompare(b.displayLabel); - } - ); - await dictExecutedForEachObject[objectType]( - objectType, - flowObject, - setFieldValue, - values - ); - } - if (objectType === 'sourcePlans') { - handleShowSourceGoverningEntities(flowObject.length !== 0); - } - if (objectType === 'destinationPlans') { - handleShowDestinationGoverningEntities(flowObject.length !== 0); - } - }; - const handleParentLinkedFlow = ( - values: any, - setFieldValue: any, - index: number - ) => { - setFieldValue( - 'parentFlow', - values['parentFlow'].filter((_item: any, ind: number) => ind !== index) - ); - }; - const handleChildFlow = (values: any, setFieldValue: any, index: number) => { - setFieldValue( - 'childFlow', - values['childFlow'].filter((_item: any, ind: number) => ind !== index) - ); - }; - const validateForm = (values: FormValues) => { - setUnsavedChange(JSON.stringify(values) !== JSON.stringify(initialValue)); - const valuesObject: Record = { - sourceOrganizations: values.sourceOrganizations, - sourceLocations: values.sourceLocations, - sourceUsageYears: values.sourceUsageYears, - sourceProjects: values.sourceProjects, - sourcePlans: values.sourcePlans, - sourceGoverningEntities: values.sourceGoverningEntities, - sourceGlobalClusters: values.sourceGlobalClusters, - sourceEmergencies: values.sourceEmergencies, - destinationOrganizations: values.destinationOrganizations, - destinationLocations: values.destinationLocations, - destinationUsageYears: values.destinationUsageYears, - destinationProjects: values.destinationProjects, - destinationPlans: values.destinationPlans, - destinationGoverningEntities: values.destinationGoverningEntities, - destinationGlobalClusters: values.destinationGlobalClusters, - destinationEmergencies: values.destinationEmergencies, - }; - setObjects(valuesObject); - const result = validationSchema.decode(values); - if (isRight(result)) { - setValidationFlag(false); - return {}; - } else { - const errors: Record[]> = {}; - Object.keys(values).forEach((key) => { - const value = values[key as keyof FormValues]; - if ( - result.left.some((err) => err.context.find((ctx) => ctx.key === key)) - ) { - const errorKey = key as keyof FormikErrors; - if (!value) { - errors[errorKey] = 'This field is required.'; - } else if (Array.isArray(value) && value.length === 0) { - errors[errorKey] = 'This field is required.'; - } - } - if ( - key === 'amountUSD' && - (value === 0 || (value && (value === '0' || (value as number) < 0))) - ) { - errors['amountUSD'] = 'The amount must be greater than zero.'; - } - if (key === 'flowType' && !value) { - errors['flowType'] = 'This field is required.'; - } - if (key === 'method' && !value) { - errors['method'] = 'This field is required.'; - } - if (key === 'reportDetails') { - const res = result.left.filter((err) => - err.context.find((ctx) => ctx.key === key) - )[0].value; - if (res && Array.isArray(res)) { - const reportDetailError: Record[] = []; - res.forEach((_, index) => { - const error: Record = {}; - if (res[index].reportChannel === '') { - error['reportChannel'] = 'This field is required.'; - } else { - error['reportChannel'] = ''; - } - if (!res[index].reportedDate) { - error['reportedDate'] = 'This field is required.'; - } else { - error['reportedDate'] = ''; - } - console.log(res[index], '-------------->'); - if ( - (res[index].reportFileTitle === '' || - res[index].reportFileTitle === undefined) && - (uploadedFileArray[index] && - (uploadedFileArray[index] as { id?: number })?.id - ? true - : false) - ) { - error['reportFileTitle'] = 'This field is required.'; - } else { - error['reportFileTitle'] = ''; - } - if ( - res[index].reportedOrganization === null || - res[index].reportedOrganization.displayLabel === '' - ) { - error['reportedOrganization'] = 'This field is required.'; - } else { - error['reportedOrganization'] = ''; - } - - if (Object.keys(error).length > 0) { - (reportDetailError as Record[]).push(error); - } - }); - - if (reportDetailError.length >= res.length) { - res.forEach((_, index) => { - if ( - res[index].reportChannel !== '' && - res[index].reportedOrganization !== '' && - res[index].reportedDate !== '' - ) { - if ( - (res[index].reportFileTitle === undefined || - res[index].reportFileTitle === '') && - (uploadedFileArray[index] && - (uploadedFileArray[index] as { id?: number })?.id - ? false - : true) - ) { - return {}; - } else if ( - res[index].reportFileTitle !== undefined && - res[index].reportFileTitle !== '' && - uploadedFileArray[index] - ) { - return {}; - } else { - errors['reportDetails'] = reportDetailError; - } - } else { - errors['reportDetails'] = reportDetailError; - } - }); - } - } - } - }); - console.log(errors, 'errors'); - if (Object.keys(errors).length === 0) setValidationFlag(false); - return errors; - } - }; - const handleParentFlow = ( - values: any, - parentValueString: string, - setValues: any - ) => { - parentValue = parentValueString; - const defaultValueParent: flowsResponse.GetFlowResult = - JSON.parse(parentValueString); - - const indexOrgs = defaultValueParent.organizations - .map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const indexYears = defaultValueParent.usageYears - .map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const indexLocs = defaultValueParent.locations - .map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const indexEmrs = defaultValueParent.emergencies - ?.map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const indexGlos = defaultValueParent.globalClusters - ?.map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const indexPlns = defaultValueParent.plans - ?.map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - // const indexEnt = defaultValueParent.governingEntities?.findIndex((org) => org.flowObject?.refDirection === 'destination') ?? -1; - - const indexPros = defaultValueParent.projects - ?.map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const _sourceOrganizations = indexOrgs.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: `${defaultValueParent.organizations[index].name} [${defaultValueParent.organizations[index].abbreviation}]`, - value: defaultValueParent.organizations[index].id, - }; - } - }); - const _sourceUsageYears = indexYears.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: `${defaultValueParent.usageYears[index].year}`, - value: defaultValueParent.usageYears[index].id, - }; - } - }); - const _sourceLocations = indexLocs.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: `${defaultValueParent.locations[index].name}`, - value: defaultValueParent.locations[index].id, - }; - } - }); - - const _sourceEmergencies = indexEmrs?.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: - defaultValueParent.emergencies && - `${defaultValueParent.emergencies[index].name}`, - value: - defaultValueParent.emergencies && - defaultValueParent.emergencies[index].id, - }; - } - }); - const _sourceGlobalClusters = indexGlos?.map( - (index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: - defaultValueParent.globalClusters && - `${defaultValueParent.globalClusters[index].name}`, - value: - defaultValueParent.globalClusters && - defaultValueParent.globalClusters[index].id, - }; - } - } - ); - const _sourcePlans = indexPlns?.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: - defaultValueParent.plans && - `${defaultValueParent.plans[index].planVersion.name}`, - value: defaultValueParent.plans && defaultValueParent.plans[index].id, - }; - } - }); - const _sourceProjects = indexPros?.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: - defaultValueParent.projects && - `${defaultValueParent.projects[index].projectVersions[index].name}`, - value: - defaultValueParent.projects && - defaultValueParent.projects[index].id, - }; - } - }); - - setValues({ - ...values, - sourceOrganizations: _sourceOrganizations, - sourceUsageYears: _sourceUsageYears, - sourceLocations: _sourceLocations, - sourceEmergencies: _sourceEmergencies, - sourceGlobalClusters: _sourceGlobalClusters, - sourcePlans: _sourcePlans, - // sourceGoverningEntities: _sourceGoverningEntities ? [_sourceGoverningEntities] : [], - sourceProjects: _sourceProjects, - }); - }; - return ( - - handleSubmit(values, values.submitAction) - } - validate={(values) => validateForm(values)} - enableReinitialize - validateOnChange={false} - style={{ zIndex: 1 }} - > - {({ values, setFieldValue, setValues }) => { - if (values.parentFlow && values.parentFlow[0]) { - const parentValueString = String( - values.parentFlow && - values.parentFlow[0] && - values.parentFlow[0].value - ); - if (parentValue !== parentValueString) { - handleParentFlow(values, parentValueString, setValues); - } - } - return ( -
- - {values.parentFlow && values.parentFlow.length ? ( - - Source associated with Parent Destination. To edit these - fields, remove the Parent flow or make changes directly to the - Parent flow at ( - {values.parentFlow.map((item: any) => ( - - {JSON.parse(item?.value ? item?.value.toString() : '').id} - - ))} - ) - - ) : ( - '' - )} - - {initialValue.isParkedParent && initialValue.sources ? ( - - The parent to this flow is "parked", here are its sources: -
    - {Object.entries(initialValue.sources).map( - ([objectType, objects]) => ( - - {objectType} - {(objects as any[]).map((object, index) => ( - - {object.year || object.name}   - - ))} - - ) - )} -
-
- ) : ( - '' - )} - - { - updateFlowObjects(event, value, setFieldValue, values); - }} - isMulti - entryInfo={inputEntries.sourceOrganizations} - rejectInputEntry={rejectInputEntry} - /> - - - { - updateFlowObjects(event, value, setFieldValue, values); - }} - isAutocompleteAPI={false} - entryInfo={inputEntries.sourceUsageYears} - rejectInputEntry={rejectInputEntry} - /> - - - - - - { - updateFlowObjects(event, value, setFieldValue, values); - }} - behavior={FORM_SETTINGS.emergency.behavior} - isMulti - entryInfo={inputEntries.sourceEmergencies} - rejectInputEntry={rejectInputEntry} - /> - { - updateFlowObjects(event, value, setFieldValue, values); - }} - behavior={FORM_SETTINGS.globalCluster.behavior} - isMulti - isAutocompleteAPI={false} - entryInfo={inputEntries.sourceGlobalClusters} - rejectInputEntry={rejectInputEntry} - /> - { - updateFlowObjects(event, value, setFieldValue, values); - }} - entryInfo={inputEntries.sourcePlans} - rejectInputEntry={rejectInputEntry} - /> - {showSourceGoverningEntities && ( - - )} - { - updateFlowObjects(event, value, setFieldValue, values); - }} - isMulti - entryInfo={inputEntries.sourceProjects} - rejectInputEntry={rejectInputEntry} - /> -
-
- ); - }} -
- ); -}; -export default FlowSource; diff --git a/apps/hpc-ftsadmin/src/app/components/flow-form-rewrite/flow-versions.tsx b/apps/hpc-ftsadmin/src/app/components/flow-form-rewrite/flow-versions.tsx deleted file mode 100644 index 6ede4afaa..000000000 --- a/apps/hpc-ftsadmin/src/app/components/flow-form-rewrite/flow-versions.tsx +++ /dev/null @@ -1,2607 +0,0 @@ -import React, { - ChangeEvent, - useState, - useEffect, - useCallback, - useRef, - useContext, -} from 'react'; -import { Form, Formik, FieldArray } from 'formik'; -import tw from 'twin.macro'; -import dayjs from 'dayjs'; -import { isRight } from 'fp-ts/Either'; -import { FormikErrors } from 'formik'; -import * as t from 'io-ts'; -import { util as codecs } from '@unocha/hpc-data'; -import GppMaybeIcon from '@mui/icons-material/GppMaybe'; -import Button from '@mui/material/Button'; -import DeleteIcon from '@mui/icons-material/Delete'; -import Stack from '@mui/material/Stack'; -import ContentCopyIcon from '@mui/icons-material/ContentCopy'; -import MuiAlert from '@mui/material/Alert'; -import AlertTitle from '@mui/material/AlertTitle'; -import _, { set, values } from 'lodash'; -import useSharePath from '../Hooks/SharePath'; -import { C, dialogs } from '@unocha/hpc-ui'; -import { - Table, - TableBody, - TableCell, - TableContainer, - TableHead, - TableRow, - Paper, - Alert, - IconButton, -} from '@mui/material'; -import CloseIcon from '@mui/icons-material/Close'; -import { Environment } from '../../../environments/interface'; -import { MdAdd, MdRemove, MdClose, MdCheck } from 'react-icons/md'; -import { - usageYears, - forms, - governingEntities, - fileUpload, - flows as flowsResponse, -} from '@unocha/hpc-data'; -import { getEnv } from '../../context'; -import { editFlowSetting, copyFlow } from '../../paths'; -import { flows } from '../../paths'; -import Link from '@mui/material/Link'; -import { useNavigate, unstable_usePrompt } from 'react-router-dom'; -import { id } from 'fp-ts/lib/Refinement'; -import { FlowContext } from './flow-context'; - -export type AutoCompleteSelectionType = forms.InputSelectValueType; - -const INPUT_SELECT_VALUE_TYPE = forms.INPUT_SELECT_VALUE_TYPE; - -type UniqueDataType = { - [key: string]: string[]; -}; - -export interface DeleteFlowParams { - VersionID: number; - FlowID: number; -} - -export interface categoryType { - value: string | number; - displayLabel: string; - parentID: number | null; -} - -export interface FileAssetEntityType { - collection?: string; - createAt?: string; - filename?: string; - id?: number; - mimetype?: string; - originalname?: string; - path?: string; - size?: number; - updatedAt?: string; -} -export interface ReportFileType { - title?: string; - fileName?: string; - UploadFileUrl?: string; - type?: string; - url?: string; - fileAssetID?: number; - size?: number; - fileAssetEntity?: FileAssetEntityType; -} -export interface ReportDetailType { - verified: string; - reportSource: string; - reporterReferenceCode: string; - reportChannel: AutoCompleteSelectionType | ''; - reportedOrganization: AutoCompleteSelectionType; - reportedDate: string; - reporterContactInformation: string; - sourceSystemRecordId: string; - reportFiles: ReportFileType[]; - reportFileTitle?: string; - reportUrlTitle?: string; - reportUrl?: string; - versionId?: number; - fileAsset?: FileAssetEntityType; -} - -export interface ParentFlowType { - value: any; -} - -export interface FormValues { - id: string | null; - amountUSD: number; - keywords: AutoCompleteSelectionType[]; - flowStatus: AutoCompleteSelectionType | ''; - flowType: AutoCompleteSelectionType | ''; - flowDescription: string; - firstReported: string; - decisionDate: string | null; - budgetYear: string; - flowDate: string; - contributionType: AutoCompleteSelectionType | ''; - earmarkingType: AutoCompleteSelectionType | ''; - method: AutoCompleteSelectionType | ''; - cashTransfer: AutoCompleteSelectionType | ''; - beneficiaryGroup: AutoCompleteSelectionType | ''; - inactiveReason: any[] | string; - childMethod: object; - origCurrency: AutoCompleteSelectionType | string; - amountOriginal: number | null; - exchangeRateUsed: number | null; - notes: string; - sourceOrganizations: AutoCompleteSelectionType[]; - sourceLocations: AutoCompleteSelectionType[]; - sourceUsageYears: AutoCompleteSelectionType[]; - sourceProjects: AutoCompleteSelectionType[]; - sourcePlans: AutoCompleteSelectionType[]; - sourceGoverningEntities: AutoCompleteSelectionType[]; - sourceGlobalClusters: AutoCompleteSelectionType[]; - sourceEmergencies: AutoCompleteSelectionType[]; - destinationOrganizations: AutoCompleteSelectionType[]; - destinationLocations: AutoCompleteSelectionType[]; - destinationUsageYears: AutoCompleteSelectionType[]; - destinationProjects: AutoCompleteSelectionType[]; - destinationPlans: AutoCompleteSelectionType[]; - destinationGoverningEntities: AutoCompleteSelectionType[]; - destinationGlobalClusters: AutoCompleteSelectionType[]; - destinationEmergencies: AutoCompleteSelectionType[]; - reportDetails: ReportDetailType[]; - parentFlow?: AutoCompleteSelectionType[]; - childFlow?: AutoCompleteSelectionType[]; - isParkedParent?: boolean; - includeChildrenOfParkedFlows: boolean; - isErrorCorrectionValue: boolean; - sources?: Record; - submitAction?: string | undefined; - versions?: { - id: number | null; - isPending: boolean | null; - }[]; -} - -export interface VersionDataType { - versionId: number; - flowId: number; - createdTime: string; - createdBy: string | null; - updatedTime: string; - updatedBy: string | null; - active: boolean; - viewing: boolean; - pending?: boolean; - [key: string]: - | string - | number - | null - | boolean - | string[] - | Date - | undefined - | Record; - source: UniqueDataType; - destination: UniqueDataType; - categories: string[]; - uniqueSources: UniqueDataType; - uniqueDestinations: UniqueDataType; - uniqueCategories: string[]; - restricted?: boolean; -} - -export interface InputEntriesType { - amountUSD: forms.InputEntryType | null; - origCurrency: forms.InputEntryType | null; - keywords: forms.InputEntryType | null; - flowStatus: forms.InputEntryType | null; - flowType: forms.InputEntryType | null; - flowDescription: forms.InputEntryType | null; - contributionType: forms.InputEntryType | null; - earmarkingType: forms.InputEntryType | null; - method: forms.InputEntryType | null; - beneficiaryGroup: forms.InputEntryType | null; - inactiveReason: forms.InputEntryType | null; - amountOriginal: forms.InputEntryType | null; - exchangeRateUsed: forms.InputEntryType | null; - notes: forms.InputEntryType | null; - sourceOrganizations: forms.InputEntryType[]; - sourceLocations: forms.InputEntryType[]; - sourceUsageYears: forms.InputEntryType[]; - sourceProjects: forms.InputEntryType[]; - sourcePlans: forms.InputEntryType[]; - sourceGoverningEntities: forms.InputEntryType[]; - sourceGlobalClusters: forms.InputEntryType[]; - sourceEmergencies: forms.InputEntryType[]; - destinationOrganizations: forms.InputEntryType[]; - destinationLocations: forms.InputEntryType[]; - destinationUsageYears: forms.InputEntryType[]; - destinationProjects: forms.InputEntryType[]; - destinationPlans: forms.InputEntryType[]; - destinationGoverningEntities: forms.InputEntryType[]; - destinationGlobalClusters: forms.InputEntryType[]; - destinationEmergencies: forms.InputEntryType[]; - parentFlow: forms.InputEntryType | null; - childFlow: forms.InputEntryType[]; -} - -type UploadedItem = fileUpload.FileUploadResult | FileAssetEntityType; - -const reportChannelSchema = t.type({ - value: t.intersection([codecs.NON_EMPTY_STRING, t.string]), - displayLabel: t.intersection([codecs.NON_EMPTY_STRING, t.string]), -}); - -const reportDetailsSchema = t.type({ - reportedOrganization: INPUT_SELECT_VALUE_TYPE, - reportedDate: t.intersection([codecs.NON_EMPTY_STRING, t.string]), - reportChannel: t.intersection([codecs.NON_EMPTY_STRING, reportChannelSchema]), - reportFileTitle: t.intersection([codecs.NON_EMPTY_STRING, t.string]), -}); - -const validationSchema = t.type({ - amountUSD: t.number, - flowStatus: INPUT_SELECT_VALUE_TYPE, - flowDescription: t.intersection([codecs.NON_EMPTY_STRING, t.string]), - firstReported: t.string, - flowDate: t.intersection([codecs.NON_EMPTY_STRING, t.string]), - sourceOrganizations: INPUT_SELECT_VALUE_TYPE, - sourceUsageYears: INPUT_SELECT_VALUE_TYPE, - destinationOrganizations: INPUT_SELECT_VALUE_TYPE, - destinationUsageYears: INPUT_SELECT_VALUE_TYPE, - reportDetails: reportDetailsSchema, -}); - -interface Props { - currentVersionData: flowsResponse.FlowREST | null; - environment: Environment; - isEdit: boolean; - initialValue: FormValues; - prevDetails?: ReportDetailType[]; - versionData?: VersionDataType[]; - flowId?: string; - versionId?: string; - isRestricted: boolean; - errorCorrection?: boolean; - inputEntries: InputEntriesType; - initializeInputEntries: () => void; - rejectInputEntry: (key: string) => void; - currentVersionID?: number; - currentFlowID?: number; - currentVersionActiveStatus?: boolean; - isPending?: boolean; - isSuperseded?: boolean; - isCancelled?: boolean; - isCancellation?: boolean; - isNewPending?: boolean; - isUpdatePending?: boolean; - canReactive?: boolean; - isErrorCorrection?: boolean | null; - isApprovedFlowVersion?: boolean | null; - pendingFieldsAllApplied?: boolean; - allFieldsReviewed?: boolean; - pendingVersionV1?: boolean; -} - -const StyledRepOrgLink = tw.div` - flex - ml-1 - `; - -const StyledAddChildWarning = tw.div` - border border-solid border-yellow-600 - flex - rounded-md - text-gray-900 - bg-yellow-100 bg-opacity-50 - `; - -const StyledAddChildWarningIconDiv = tw.div` - flex - items-center - p-1 - `; -const StyledAddChildWarningText = tw.span` - py-3 px-3 pb-3 - `; -const StyledLayoutRow = tw.div` - flex - `; -const StyledHalfSection = tw.div` - w-1/2 - `; -const StyledFullSection = tw.div` - w-full - mb-6 - `; -const StyledRow = tw.div` - flex - gap-4 - w-full - `; -const StyledFormRow = tw.div` - flex - gap-2 - w-full - items-center - `; -const StyledAnchor = tw.a` - underline - ml-[15px] - opacity-100 - `; -const StyledAnchorDiv = tw.div` - text-right - w-full - `; -const StyledRadioDiv = tw.div` - relative - w-full - `; -const StyledFieldset = tw.fieldset` - w-full - box-border - rounded-xl - mt-[16px] - mb-[8px] - border-gray-100 - `; -const StyledCurrencyRow = tw.div` - w-1/2 - `; -const StyledFormButton = tw(C.Button)` - ml-[25px] - mb-6 - `; -const StyledLabel = tw.label` - block - my-4 - `; -const StyledLinkedFlowRow = tw.div` - mt-4 - `; - -const StyledParentInfo = tw.div` - border-0 - border-b - border-solid - cursor-pointer - mb-4 - pb-4 - `; - -const StyledStrong = tw.strong` - min-w-[16rem] - inline-block - `; - -const StyledList = tw.li` - list-none - `; - -const StyledDiv = tw.div` - my-6 - me-4 - mr-[23px] - lg:flex - justify-end - gap-x-4 - bg-white - z-10 - `; - -const initialReportDetail = { - verified: 'verified', - reportSource: 'primary', - reporterReferenceCode: '', - reportChannel: '', - reportFileTitle: '', - reportedOrganization: { value: '', displayLabel: '' }, - reportedDate: dayjs().format('DD/MM/YYYY'), - reporterContactInformation: '', - sourceSystemRecordId: '', -}; - -const FORM_SETTINGS = { - organization: { - behavior: 'shared', - }, - project: { - behavior: 'overlap', - }, - usageYear: { - behavior: 'shared', - }, - location: { - behavior: 'shared', - }, - globalCluster: { - behavior: 'shared', - }, - emergency: { - behavior: 'overlap', - }, - governingEntity: { - behavior: 'shared', - }, - plan: { - behavior: 'overlap', - }, -}; - -const objectTypes = [ - 'emergencies', - 'projects', - 'usageYears', - 'globalClusters', - 'locations', - 'plans', - 'organizations', -] as const; - -const flowValuesForDisplay = [ - 'amountUSD', - 'flowDate', - 'decisionDate', - 'firstReportedDate', - 'budgetYear', - 'origAmount', - 'origCurrency', - 'exchangeRate', - 'activeStatus', - 'restricted', - 'newMoney', - 'description', - 'notes', -] as const; - -let parentValue = ''; - -export const FlowVersions = () => { - const { - flowValue, - setFlowValue, - initialValue, - isEdit, - currentVersionData, - environment, - prevDetails, - versionData, - isRestricted, - errorCorrection, - inputEntries, - flowId, - versionId, - initializeInputEntries, - rejectInputEntry, - currentVersionID, - currentFlowID, - currentVersionActiveStatus, - isPending, - isSuperseded, - isCancelled, - isCancellation, - isNewPending, - isUpdatePending, - canReactive, - pendingFieldsAllApplied, - allFieldsReviewed, - pendingVersionV1, - }: any = useContext(FlowContext); - // const { - // currentVersionData, - // environment, - // initialValue, - // isEdit, - // prevDetails, - // versionData, - // isRestricted, - // errorCorrection, - // inputEntries, - // flowId, - // versionId, - // initializeInputEntries, - // rejectInputEntry, - // currentVersionID, - // currentFlowID, - // currentVersionActiveStatus, - // isPending, - // isSuperseded, - // isCancelled, - // isCancellation, - // isNewPending, - // isUpdatePending, - // canReactive, - // pendingFieldsAllApplied, - // allFieldsReviewed, - // pendingVersionV1, - // } = props; - const { confirm } = dialogs; - const env = getEnv(); - - const collapseFlowObjects = (data: any) => { - data.flowObjects = []; - - collapsePerBehavior(data.dest, 'destination'); - collapsePerBehavior(data.src, 'source'); - - function collapsePerBehavior(behaviorArr: any, ref: any) { - Object.keys(behaviorArr).forEach((type) => { - behaviorArr[type].forEach((obj: any) => { - if ( - obj !== null && - (!Object.prototype.hasOwnProperty.call(obj, 'cleared') || - !obj.cleared) - ) { - if (type === 'organization') { - obj.objectDetail = obj.implementingPartner ? 'partner' : null; - } - - const flowObj = { - refDirection: ref, - objectType: type, - objectID: obj.id, - behavior: obj.behavior || null, - objectDetail: obj.objectDetail, - }; - data.flowObjects.push(flowObj); - } - }); - }); - } - - return data as any; - }; - - const collapseCategories = (data: any) => { - data.categories = [ - data.flowType, - data.flowStatuses, - data.contributionTypes, - data.method, - data.childMethod, - data.keywords, - data.inactiveReason, - data.beneficiaryGroup, - data.pendingStatus, - data.earmarking !== null && data.earmarking.id, - ].filter((category) => category); - data.categories = data.categories - .map((value: any) => { - if (value && value.id) { - return value.id; - } else if (value[0]) { - return value[0].id; - } - }) - .filter(function (value: any) { - return value; - }) - .map((value: any) => { - return parseInt(value); - }); - - return data; - }; - const [uploadFileFlag, setUploadFileFlag] = useState(false); - const [uploadFlag, setUploadFlag] = useState(false); - const normalizeFlowData = (values: FormValues) => { - const fundingObject = { - src: { - governingEntity: values.sourceGoverningEntities.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - location: values.sourceLocations.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - organization: values.sourceOrganizations.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - project: values.sourceProjects.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - usageYear: values.sourceUsageYears.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - globalCluster: values.sourceGlobalClusters.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - emergency: values.sourceEmergencies.map((item) => ({ - id: item.value, - name: item.displayLabel, - restricted: item.restricted, - })), - plan: values.sourcePlans.map((item) => ({ - id: item.value, - name: item.displayLabel, - restricted: item.restricted, - })), - }, - dest: { - governingEntity: values.destinationGoverningEntities.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - location: values.destinationLocations.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - organization: values.destinationOrganizations.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - project: values.destinationProjects.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - usageYear: values.destinationUsageYears.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - globalCluster: values.destinationGlobalClusters.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - emergency: values.destinationEmergencies.map((item) => ({ - id: item.value, - name: item.displayLabel, - restricted: item.restricted, - })), - plan: values.destinationPlans.map((item) => ({ - id: item.value, - name: item.displayLabel, - restricted: item.restricted, - })), - }, - }; - - let data = { - id: isEdit && currentFlowID ? currentFlowID : null, - versionID: isEdit && currentVersionID ? currentVersionID : null, - amountUSD: values.amountUSD, - flowDate: dayjs(values.flowDate, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ), - decisionDate: values.decisionDate - ? dayjs(values.decisionDate, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ) - : null, - firstReportedDate: dayjs(values.firstReported, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ), - budgetYear: values.budgetYear, - origAmount: values.amountOriginal ? values.amountOriginal : null, - origCurrency: (values.origCurrency as AutoCompleteSelectionType) - ? (values.origCurrency as AutoCompleteSelectionType)?.displayLabel - : null, - exchangeRate: values.exchangeRateUsed ? values.exchangeRateUsed : null, - activeStatus: true, - restricted: false, - newMoney: true, - description: values.flowDescription, - versionStartDate: currentVersionData?.versionStartDate, - versionEndDate: currentVersionData?.versionEndDate, - flowObjects: collapseFlowObjects(fundingObject), - children: - values.childFlow && - values.childFlow.map((item: any, index: number) => { - return { - childID: JSON.parse(item.value as string).id, - origCurrency: JSON.parse(item.value as string).origCurrency, - }; - }), - parents: - values.parentFlow && - values.parentFlow.map((item: any, index: number) => { - return { - Parent: { - parentID: JSON.parse(item.value as string).id, - origCurrency: JSON.parse(item.value as string).origCurrency, - }, - childID: currentFlowID, - parentID: JSON.parse(item.value as string).id, - origCurrency: JSON.parse(item.value as string).origCurrency, - id: JSON.parse(item.value as string).id, - parents: - values.parentFlow && - values.parentFlow.map((key: any) => { - return { - child: JSON.parse(key.value as string).id, - parentID: 271736, - }; - }), - }; - }), - reportDetails: values.reportDetails.map((item, index) => { - return { - contactInfo: item.reporterContactInformation, - source: item.reportSource, - date: dayjs(item.reportedDate, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ), - versionID: currentVersionID, - newlyAdded: addReportFlag, - sourceID: null, - refCode: '7F-10073.04', - verified: true, - organizationID: item.reportedOrganization.value, - categories: [item.reportChannel && item.reportChannel.value], - organization: { - id: item.reportedOrganization.value, - name: item.reportedOrganization.displayLabel, - }, - reportFiles: - uploadFlag && - uploadedFileArray[index] && - (uploadedFileArray[index] as { id?: number })?.id - ? uploadFlag || uploadFileFlag - ? [ - { - title: item.reportUrlTitle, - type: 'url', - url: item.reportUrl, - }, - { - fileAssetID: - uploadedFileArray[index] && - (uploadedFileArray[index] as { id?: number })?.id, - reportFiles: [ - { - fieldType: 'file', - fileAssetID: - uploadedFileArray[index] && - (uploadedFileArray[index] as { id?: number })?.id, - type: 'file', - }, - ], - title: item.reportFileTitle, - type: 'file', - }, - ] - : [ - { - title: item.reportUrlTitle, - type: 'url', - url: item.reportUrl, - }, - ] - : uploadFileFlag - ? [ - { - title: item.reportUrlTitle, - type: 'url', - url: item.reportUrl, - }, - ] - : item.reportFiles - ? item.reportFiles - : [], - - reportChannel: { - group: 'reportChannel', - id: item.reportChannel && item.reportChannel.value, - name: item.reportChannel && item.reportChannel.displayLabel, - }, - }; - }), - flowType: { - id: values.flowType && values.flowType.value, - name: values.flowType && values.flowType.displayLabel, - group: 'flowType', - }, - keywords: values.keywords.map((item) => ({ - id: item.value, - name: item.displayLabel, - group: 'keywords', - })), - flowStatuses: { - id: values.flowStatus && values.flowStatus.value, - name: values.flowStatus && values.flowStatus.displayLabel, - group: 'flowStatus', - }, - contributionTypes: { - id: values.contributionType && values.contributionType.value, - name: values.contributionType && values.contributionType.displayLabel, - group: 'contributionType', - }, - method: { - id: values.method && values.method.value, - name: values.method && values.method.displayLabel, - group: 'method', - }, - childMethod: values.cashTransfer && { - id: values.cashTransfer.value, - name: values.cashTransfer.displayLabel, - group: 'method', - parentID: values.method && values.method.value, - }, - earmarking: values.earmarkingType - ? { - id: values.earmarkingType.value, - name: values.earmarkingType.displayLabel, - group: 'earmarkingType', - } - : null, - categories: [] as (string | number)[], - isCancellation: isPending ? true : !isPending ? false : null, - cancelled: isPending && isCancellation ? true : null, - pendingStatus: isPending ? true : !isPending ? false : [], - planEntities: isPending ? true : !isPending ? false : [], - planIndicated: isPending ? true : !isPending ? false : [], - isApprovedFlowVersion: - rejectFlag && approveFlag - ? true - : !(rejectFlag && approveFlag) - ? false - : null, - inactiveReason: [ - { - id: null as null | number | string, - name: '' as string | undefined, - description: null, - parentID: null, - code: null, - group: '', - includeTotals: null, - createdAt: '', - updatedAt: '', - }, - ], - isErrorCorrection: errorCorrection - ? true - : isSuperseded - ? true - : isPending - ? true - : !isSuperseded && !isPending - ? false - : null, - rejected: rejectFlag ? true : !rejectFlag ? false : null, - versions: - versionData && - versionData.map((item: VersionDataType) => { - const items = { - id: item.flowId, - versionID: item.versionId, - activeStatus: item.activeStatus, - isPending: item.isPending ? item.isPending : false, - isCancelled: item.isCancelled ? item.isCancelled : false, - }; - return items; - }), - ...fundingObject, - }; - - data = collapseCategories(data); - return data; - }; - - const [unsavedChange, setUnsavedChange] = useState(false); - const [parentCurrencyFlag, setParentCurrencyFlag] = useState(false); - const [childCurrencyFlag, setChildCurrencyFlag] = useState(false); - const [approveFlag, setApproveFlag] = useState(false); - const [rejectFlag, setRejectFlag] = useState(false); - const [validationFlag, setValidationFlag] = useState(false); - const [inactiveFlag, setInactiveFlag] = useState(false); - const [uploadedFileArray, setUploadedFileArray] = useState([ - {}, - ]); - const [addReportFlag, setAddReportFlag] = useState(false); - const [alertFlag, setAlertFlag] = useState(false); - const [sharePath, setSharePath] = useSharePath(''); - const [readOnly, setReadOnly] = useState(false); - const [linkCheck, setLinkCheck] = useState(false); - const handleSave = () => { - window.scrollTo({ top: 0, behavior: 'smooth' }); - }; - - const [showWarningMessage, setShowWarningMessage] = useState(false); - const [objects, setObjects] = useState>({}); - const [showingTypes, setShowingTypes] = useState([]); - const [newMoneyCheckboxDisabled, setNewMoneyCheckboxDisabled] = - useState(false); - - const [comparingVersions, setComparingVersions] = useState( - [] - ); - const [comparedVersions, setComparedVersions] = useState( - [] - ); - const [showSourceGoverningEntities, handleShowSourceGoverningEntities] = - useState(false); - const [ - showDestinationGoverningEntities, - handleShowDestinationGoverningEntities, - ] = useState(false); - const [sourceGoverningEntities, setSourceGoverningEntities] = - useState([]); - const [destinationGoverningEntities, setDestinationGoverningEntities] = - useState([]); - const [isShowParentFlow, setShowParentFlow] = useState( - initialValue.parentFlow && initialValue.parentFlow.length ? true : false - ); - const [isShowChildFlow, setShowChildFlow] = useState(0); - const [openAlerts, setOpenAlerts] = useState< - { message: string; id: number }[] - >([]); - const [alertId, setAlertId] = useState(0); - const handleClose = (id: number) => { - setOpenAlerts(openAlerts.filter((alert) => alert.id !== id)); - }; - const buttonText = 'Calculate The Exchange Rate'; - - const handleCalculateExchangeRate = (values: any, setFieldValue: any) => { - const { amountOriginal, amountUSD } = values; - - if (amountOriginal && amountUSD) { - const exchangeRateUsed = amountOriginal / amountUSD; - setFieldValue('exchangeRateUsed', exchangeRateUsed.toFixed(4)); - } else if (amountOriginal && !amountUSD) { - const calculatedAmountUSD = amountOriginal / values.exchangeRateUsed; - setFieldValue('amountUSD', calculatedAmountUSD.toFixed(4)); - } else if (!amountOriginal && amountUSD) { - const calculatedAmountOriginal = amountUSD * values.exchangeRateUsed; - setFieldValue('amountOriginal', calculatedAmountOriginal.toFixed(4)); - } else { - console.warn('Both original amount and USD amount are missing.'); - } - }; - useEffect(() => { - if (initialValue?.childFlow) { - setShowChildFlow(initialValue?.childFlow.length); - } - }, [initialValue]); - useEffect(() => { - const fileAssets: FileAssetEntityType[] = []; - if (isEdit) { - initialValue.reportDetails.forEach((detail: any) => { - if (detail?.fileAsset) { - fileAssets.push(detail.fileAsset); - setUploadedFileArray(fileAssets); - } else { - fileAssets.push({} as FileAssetEntityType); - setUploadedFileArray(fileAssets); - } - }); - } - }, [initialValue.reportDetails]); - useEffect(() => { - if (currentVersionActiveStatus) { - setReadOnly(false); - } else { - setReadOnly(true); - } - }, [currentVersionActiveStatus]); - useEffect(() => { - if (initialValue.parentFlow && initialValue.parentFlow.length) { - setShowParentFlow(true); - } - }, [initialValue.parentFlow]); - const [remove, setRemove] = useState(false); - const handleRemove = (index: number, values: FormValues) => { - if (window.confirm('Are you sure you want to remove this file?')) { - if ( - initialValue.reportDetails[index].reportFiles && - initialValue.reportDetails[index].reportFiles[0]?.fileName - ) { - values.reportDetails[index].reportFileTitle = ''; - initialValue.reportDetails[index].reportFiles[0].fileName = ''; - initialValue.reportDetails[index].reportFiles[0].title = ''; - initialValue.reportDetails[index].reportFiles[0].fileAssetID = - undefined; - initialValue.reportDetails[index].reportFiles[0].UploadFileUrl = ''; - const updatedArray = removeByIndexFromArray(uploadedFileArray, index); - setUploadedFileArray(updatedArray); - } else return; - setUploadFlag(false); - setRemove(true); - } else return; - }; - const removeByIndexFromArray = (array: UploadedItem[], index: number) => { - const newArray = [...array]; - newArray[index] = {}; - return newArray; - }; - if (remove === true) setRemove(false); - const SourceLink = ( - setFieldValue: any, - values: FormValues, - indexKey: number, - index: number - ) => { - setFieldValue( - `reportDetails[${index}].reportedOrganization`, - values.sourceOrganizations[indexKey] - ); - }; - const DestinationLink = ( - setFieldValue: any, - values: FormValues, - indexKey: number, - index: number - ) => { - setFieldValue( - `reportDetails[${index}].reportedOrganization`, - values.destinationOrganizations[indexKey] - ); - }; - - interface Inconsistency { - type: string; - values: { - name?: string; - year?: string; - refDirection: string; - options?: { name: string }[]; - }[]; - } - - const processDataInconsistencies = ( - inconsistencyArray: Inconsistency[] - ): string => { - let message = ''; - inconsistencyArray.forEach((inconsistencyWith) => { - if (inconsistencyWith && inconsistencyWith.type) { - const inconsistencyType = inconsistencyWith.type; - message += - inconsistencyType.charAt(0).toUpperCase() + - inconsistencyType.slice(1) + - ': '; - - if (inconsistencyWith.type === 'no-direct-link') { - message += inconsistencyWith.values.join(', '); - } else { - message += - inconsistencyWith.values - .map((value) => { - const name = value.name || value.year; - let joinedOptions = ''; - if (value.options) { - joinedOptions = value.options - .map((option) => { - return option.name || JSON.stringify(option); - }) - .join(', '); - } - const options = `is not in the list of acceptable ${value.refDirection} ${inconsistencyType}: [${joinedOptions}]`; - return `'${name}' ${options}`; - }) - .join(', ') + '. '; - } - } else { - message += JSON.stringify(inconsistencyArray); - } - }); - return message; - }; - - const handleSubmit = async ( - values: FormValues, - submitAction: string | undefined - ) => { - if (values.childFlow) { - for (let i = 0; i < values.childFlow.length; i++) { - if ( - values.destinationUsageYears.length >= 2 && - JSON.parse(values.childFlow[i].value as string).activeStatus === true - ) { - values.flowType = { - displayLabel: 'Parked', - value: '1252', - }; - } - } - } - if (isShowParentFlow && isShowChildFlow > 0) { - let childAmountSum = 0; - let parentAmountSum = 0; - values.childFlow && - values.childFlow.map((item, _index) => { - childAmountSum += JSON.parse(item.value.toString()) - ? parseInt(JSON.parse(item.value.toString()).amountUSD) - : 0; - }); - values.parentFlow && - values.parentFlow.map((item, _index) => { - parentAmountSum += JSON.parse(item.value.toString()) - ? parseInt(JSON.parse(item.value.toString()).amountUSD) - : 0; - }); - if (childAmountSum > parentAmountSum) { - if ( - !window.confirm( - `Please note, the Funding Amount on this parent flow ($${parentAmountSum}) is less than the sum of its children's amount ($${childAmountSum}). Do you want to proceed?` - ) - ) { - return; - } - } - } - if (isShowParentFlow || isShowChildFlow > 0) { - let childAmountSum = 0; - values.childFlow && - values.childFlow.map((item, _index) => { - childAmountSum += JSON.parse(item.value.toString()) - ? parseInt(JSON.parse(item.value.toString()).amountUSD) - : 0; - }); - if (childAmountSum > values.amountUSD) { - if ( - !window.confirm( - `Please note, the Funding Amount on this parent flow ($${values.amountUSD}) is less than the sum of its children's amount ($${childAmountSum}). Do you want to proceed?` - ) - ) - return; - } - } - const parentFlow = values.parentFlow; - if (parentFlow?.length) { - for (let index = 0; index < parentFlow.length; index++) { - const item = parentFlow[index]; - if ( - (typeof values?.origCurrency !== 'string' && - values.origCurrency?.displayLabel) || - !( - JSON.parse(item.value.toString()) && - JSON.parse(item.value.toString())?.origCurrency === null - ) - ) { - if ( - (typeof values?.origCurrency !== 'string' && - values.origCurrency?.displayLabel) !== - (JSON.parse(item.value.toString()) && - JSON.parse(item.value.toString())?.origCurrency) - ) { - handleSave(); - setParentCurrencyFlag(true); - return; - } - } - } - } - const childFlow = values.childFlow; - if (childFlow) { - for (let index = 0; index < childFlow.length; index++) { - const item = childFlow[index]; - if ( - (typeof values?.origCurrency !== 'string' && - values.origCurrency?.displayLabel) || - !( - JSON.parse(item.value.toString()) && - JSON.parse(item.value.toString())?.origCurrency === null - ) - ) { - if ( - (typeof values.origCurrency !== 'string' && - values.origCurrency?.displayLabel) !== - (JSON.parse(item.value.toString()) && - JSON.parse(item.value.toString()).origCurrency) - ) { - handleSave(); - setChildCurrencyFlag(true); - return; - } - } - } - } - for (let i = 0; i < values.reportDetails.length; i++) { - if ( - values.reportDetails[i].reportUrlTitle && - values.reportDetails[i].reportUrl - ) { - setUploadFileFlag(true); - } else setUploadFileFlag(false); - } - const data = normalizeFlowData(values); - const inactiveReasons = await fetchCategory('inactiveReason')(); - if (submitAction === 'approve') { - data.isApprovedFlowVersion = true; - } else if (submitAction === 'rejected') { - data.activeStatus = false; - data.rejected = true; - data.inactiveReason = [ - { - id: - inactiveReasons.find( - (item: any) => item.displayLabel === 'Rejected' - )?.value || null, - name: inactiveReasons.find( - (item: any) => item.displayLabel === 'Rejected' - )?.displayLabel, - description: null, - parentID: null, - code: null, - group: 'inactiveReason', - includeTotals: null, - createdAt: currentVersionData - ? dayjs(currentVersionData.createdAt, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ) - : '', - updatedAt: currentVersionData - ? dayjs(currentVersionData.updatedAt, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ) - : '', - }, - ]; - } else if (submitAction === 'inactive') { - if (isShowParentFlow || isShowChildFlow > 0) { - setInactiveFlag(true); - } else { - const categoryValue = - inactiveReasons.find((item: any) => item.displayLabel === 'Cancelled') - ?.value ?? null; - if (categoryValue) { - data.categories.push(parseInt(categoryValue.toString())); - } - data.activeStatus = false; - data.cancelled = true; - data.isCancellation = null; - data.rejected = null; - data.newMoney = false; - data.inactiveReason = [ - { - id: - inactiveReasons.find( - (item: any) => item.displayLabel === 'Cancelled' - )?.value || null, - name: inactiveReasons.find( - (item: any) => item.displayLabel === 'Cancelled' - )?.displayLabel, - description: null, - parentID: null, - code: null, - group: 'inactiveReason', - includeTotals: null, - createdAt: currentVersionData ? currentVersionData.createdAt : '', - updatedAt: currentVersionData ? currentVersionData.updatedAt : '', - }, - ]; - } - } - if (!inactiveFlag) { - const response = await env.model.flows.validateFlow(data); - let flag = true; - let mismatchFound = false; - for (let i = 0; i < values.reportDetails.length; i++) { - const reportOrganizationLabel = - values.reportDetails[i].reportedOrganization.displayLabel; - const reportMatchesSource = values.sourceOrganizations.some( - (sourceOrg) => sourceOrg.displayLabel === reportOrganizationLabel - ); - const reportMatchesDestination = values.destinationOrganizations.some( - (destOrg) => destOrg.displayLabel === reportOrganizationLabel - ); - - if (!reportMatchesSource && !reportMatchesDestination) { - mismatchFound = true; - break; - } - } - if (mismatchFound) { - if ( - !window.confirm( - "Your flow's Report Detail organization doesn't match the source or destination organization or that of its parked parent. Are you sure this is right?" - ) - ) { - return; - } - } - response.forEach((obj) => { - if (obj) { - const { success, message, confirmed } = obj; - if (!success) { - if (confirmed) { - const confirm = window.confirm(confirmed); - if (!confirm) { - setOpenAlerts([...openAlerts, { message, id: alertId }]); - setAlertId((prevId) => prevId + 1); - flag = false; - handleSave(); - } - } else if (message) { - setOpenAlerts([...openAlerts, { message, id: alertId }]); - setAlertId((prevId) => prevId + 1); - flag = false; - handleSave(); - } - } - } - }); - if (flag && !(isShowParentFlow || isShowChildFlow > 0)) { - setUnsavedChange(false); - if (!isEdit) { - try { - const response = await env.model.flows.createFlow({ flow: data }); - const path = editFlowSetting(response.id, response.versionID); - window.open(path, '_self'); - } catch (err: any) { - setOpenAlerts([ - ...openAlerts, - { message: err.message, id: alertId }, - ]); - setAlertId((prevId) => prevId + 1); - handleSave(); - } - } else { - const dbFlow = await env.model.flows.getFlowREST({ - id: currentFlowID!, - }); - if ( - (versionData && - currentVersionID && - Date.parse(versionData[currentVersionID - 1].updatedTime) < - Date.parse(dbFlow.updatedAt)) || - (versionData && versionData.length < dbFlow.versions.length) - ) { - window.confirm( - 'This flow cannot be saved, as a concurrency conflict has been detected. Please refresh your screen to view the most up to date data.' - ); - } else { - if (isPending && (approveFlag || rejectFlag)) { - if ( - allFieldsReviewed || - pendingFieldsAllApplied || - !pendingVersionV1 - ) { - try { - const response = await env.model.flows.updatePendingFlow({ - flow: data, - }); - if (response) { - const path = editFlowSetting( - response.id, - response.versionID - ); - setAlertFlag(true); - setSharePath(path); - } - } catch (err: any) { - setOpenAlerts([ - ...openAlerts, - { message: err.message, id: alertId }, - ]); - setAlertId((prevId) => prevId + 1); - handleSave(); - } - } else { - window.confirm( - 'Some of the revised data on this flow still needs to be accepted or rejected before this update can be approved.' - ); - } - } else { - try { - const response = await env.model.flows.updateFlow({ - flow: data, - }); - if (response) { - const path = editFlowSetting(response.id, response.versionID); - setAlertFlag(true); - setSharePath(path); - } - } catch (err: any) { - let errmessage = ''; - if (err.reason) { - const inconsistencyObject = err.reason; - errmessage = processDataInconsistencies(inconsistencyObject); - } else { - const lastIndex = err.message.lastIndexOf(':'); - errmessage = err.message.substring(lastIndex + 1); - } - setOpenAlerts([ - ...openAlerts, - { message: errmessage, id: alertId }, - ]); - setAlertId((prevId) => prevId + 1); - handleSave(); - } - } - } - } - } - } - }; - const navigate = useNavigate(); - const handleCopy = (values: FormValues) => { - if (currentFlowID && currentVersionID) { - const isCopy = true; - const path = copyFlow(); - if (typeof path === 'string') { - const valuesWithFiles = { ...values, isCopy }; - navigate(path, { state: valuesWithFiles }); - } else { - console.error('Path is not a string', path); - } - } - }; - - const handleAlert = (values: FormValues) => { - const errors = validateForm(values); - if (Object.keys(errors).length !== 0) { - setValidationFlag(true); - handleSave(); - } - }; - - const setObjectsWithArray = ( - fetchedObject: any, - objectKeys: string[], - settingArrayKeys: string[], - setFieldValue: any, - values: any - ) => { - const newObjects = { ...objects }; - const newShowingTypes = [...showingTypes]; - objectKeys.forEach((key, i) => { - if (fetchedObject[settingArrayKeys[i]]) { - newObjects[key] = checkIfExistingAndCopy( - newObjects[key], - fetchedObject, - settingArrayKeys[i] - ); - } - - const parsedResponse = newObjects[key].map((responseValue: any) => { - if (settingArrayKeys[i] === 'years') { - return { - displayLabel: - (responseValue as usageYears.UsageYear).year || - responseValue.displayLabel, - value: responseValue.id || responseValue.value, - isAutoFilled: responseValue.suggested, - }; - } else if (settingArrayKeys[i] === 'plans') { - return { - displayLabel: - (responseValue.planVersion as { planId: number; name: string }) - .name || responseValue.displayLabel, - value: responseValue.planVersion.planId || responseValue.value, - isAutoFilled: responseValue.suggested, - }; - } else if (settingArrayKeys[i] === 'governingEntities') { - return { - displayLabel: - ( - responseValue.governingEntityVersion as { - id: number; - name: string; - } - ).name || responseValue.displayLabel, - value: - responseValue.governingEntityVersion.id || responseValue.value, - isAutoFilled: responseValue.suggested, - }; - } else { - return { - displayLabel: - (responseValue as { id: number; name: string }).name || - responseValue.displayLabel, - value: responseValue.id || responseValue.value, - isAutoFilled: responseValue.suggested, - }; - } - }); - newObjects[key].forEach((obj) => { - if (obj?.suggested) { - updateFlowObjects(key, parsedResponse, setFieldValue, values); - obj.suggested = false; - } - }); - setFieldValue(key, parsedResponse); - }); - - setObjects(newObjects); - setShowingTypes(newShowingTypes); - }; - - const checkIfExistingAndCopy = ( - existingObjects: any[], - object: any, - key: string - ): any[] => { - let newObjects = object[key]; - if (key === 'locations') { - newObjects = newObjects.filter(function (location: any) { - return location.adminLevel === 0; - }); - if (existingObjects && existingObjects.length) { - existingObjects = existingObjects.filter(function (location) { - return location.adminLevel === 0 || location.value; - }); - } - } - - if (existingObjects && existingObjects.length) { - const existingObjectsIds = existingObjects.map(function (o) { - return o.id || o.value; - }); - if (Array.isArray(newObjects)) { - newObjects.forEach(function (obj) { - if (existingObjectsIds.indexOf(obj.id) === -1) { - obj.suggested = true; - existingObjects.push(obj); - } - }); - } else { - if (existingObjectsIds.indexOf(newObjects.id) === -1) { - newObjects.suggested = true; - existingObjects.push(newObjects); - } - } - } else { - if (newObjects) { - if (Array.isArray(newObjects)) { - newObjects.forEach(function (obj) { - obj.suggested = true; - }); - existingObjects = newObjects; - } else { - newObjects.suggested = true; - existingObjects = [newObjects]; - } - } - } - return existingObjects; - }; - const fetchPlanDetails = async ( - objectType: string, - plan: any, - setFieldValue: any, - values?: any - ) => { - const fetchedPlan = await environment.model.plans.getPlan(plan[0].value); - if (objectType === 'sourcePlans') { - setObjectsWithArray( - fetchedPlan, - ['sourceUsageYears', 'sourceEmergencies'], - ['years', 'emergencies'], - setFieldValue, - values - ); - setSourceGoverningEntities(fetchedPlan.governingEntities); - } - if (objectType === 'destinationPlans') { - setObjectsWithArray( - fetchedPlan, - ['destinationUsageYears', 'destinationEmergencies'], - ['years', 'emergencies'], - setFieldValue, - values - ); - setDestinationGoverningEntities(fetchedPlan.governingEntities); - } - if (fetchedPlan.locations) { - const countries = fetchedPlan.locations.filter(function (loc: any) { - return loc.adminLevel === 0; - }); - if (countries.length === 1) { - if (objectType === 'sourcePlans') { - setObjectsWithArray( - { locations: countries }, - ['sourceLocations'], - ['locations'], - setFieldValue, - values - ); - } - if (objectType === 'destinationPlans') { - setObjectsWithArray( - { locations: countries }, - ['destinationLocations'], - ['locations'], - setFieldValue, - values - ); - } - } - } - }; - - const fetchEmergencyDetails = async ( - objectType: string, - emergency: any, - setFieldValue: any, - values?: any - ) => { - if (objectType === 'destinationEmergencies') { - const fetchedEmergency = await environment.model.emergencies.getEmergency( - emergency[0].value - ); - if (fetchedEmergency.locations.length <= 1) { - setObjectsWithArray( - fetchedEmergency, - ['destinationLocations'], - ['locations'], - setFieldValue, - values - ); - } - } - }; - const fetchProjectDetails = async ( - objectType: string, - project: any, - setFieldValue: any, - values?: any - ) => { - const fetchedProject = await environment.model.projects.getProject( - project[0].value - ); - const publishedVersion = fetchedProject.projectVersions.filter(function ( - version: any - ) { - return version.id === fetchedProject.currentPublishedVersionId; - })[0]; - if (objectType === 'destinationProjects') { - const fetchedCategories = - await environment.model.categories.getCategories({ - query: 'earmarkingType', - }); - const category = fetchedCategories.filter( - (item: any) => item.name === 'Earmarked' - ); - setFieldValue('earmarkingType', { - value: category[0], - displayLabel: category[0].name, - }); - setObjectsWithArray( - publishedVersion, - [ - 'destinationPlans', - 'destinationLocations', - 'destinationGoverningEntities', - 'destinationGlobalClusters', - 'destinationOrganizations', - ], - [ - 'plans', - 'locations', - 'governingEntities', - 'globalClusters', - 'organizations', - ], - setFieldValue, - values - ); - } else { - setObjectsWithArray( - publishedVersion, - [ - 'sourcePlans', - 'sourceLocations', - 'sourceGoverningEntities', - 'sourceGlobalClusters', - 'sourceOrganizations', - ], - [ - 'plans', - 'locations', - 'governingEntities', - 'globalClusters', - 'organizations', - ], - setFieldValue, - values - ); - } - }; - const fetchOrganizationDetails = async ( - objectType: string, - organization: any, - setFieldValue: any, - values?: any - ) => { - const fetchedOrg = - await environment.model.organizations.getOrganizationsById( - organization[0].value - ); - const isGovernment = (fetchedOrg[0].categories ?? []).some(function ( - category: any - ) { - return ( - category.group === 'organizationType' && - [114, 123].includes(category.id) - ); - }); - if (isGovernment && objectType === 'sourceOrganizations') { - objects.sourceLocations = checkIfExistingAndCopy( - objects.location, - fetchedOrg[0], - 'locations' - ); - setObjectsWithArray( - objects, - ['sourceLocations'], - ['locations'], - setFieldValue, - values - ); - } - }; - const fetchAssociatedGoverningEntity = async ( - objectType: string, - globalCluster: any, - setFieldValue: any, - values?: any - ) => { - if ( - (values.sourcePlans.length === 0 && - objectType === 'sourceGlobalClusters') || - (values.destinationPlans.length === 0 && - objectType === 'destinationGlobalClusters') - ) { - return; - } - let plan = null; - let targetGoverningEntities: any = null; - if (objectType === 'sourceGlobalClusters') { - plan = values.sourcePlans[0]; - targetGoverningEntities = values.sourceGoverningEntities; - } else { - plan = values.destinationPlans[0]; - targetGoverningEntities = values.destinationGoverningEntities; - } - const fetchedGoverningEntities = - await environment.model.governingEntities.getAllPlanGoverningEntities( - plan.value - ); - const hasGoverningEntitiesWithoutGlobalCluster = - Array.isArray(targetGoverningEntities) && - fetchedGoverningEntities - .filter(function (fetchedGe: any) { - return targetGoverningEntities.find(function (selectedGe: any) { - return fetchedGe.id === selectedGe.value; - }); - }) - .some(function (fetchedGe: any) { - return ( - Array.isArray(fetchedGe.globalClusterIds) && - !fetchedGe.globalClusterIds.length - ); - }); - - if (hasGoverningEntitiesWithoutGlobalCluster) { - return; - } - const governingEntities = fetchedGoverningEntities.filter(function ( - governingEntity: any - ) { - return ( - governingEntity.globalClusterIds.indexOf( - globalCluster[globalCluster.length - 1].value - ) > -1 - ); - }); - - if (governingEntities.length) { - governingEntities.forEach(function (governingEntity: any) { - setObjectsWithArray( - { governingEntities: governingEntity }, - [ - objectType === 'sourceGlobalClusters' - ? 'sourceGoverningEntities' - : 'destinationGoverningEntities', - ], - ['governingEntities'], - setFieldValue, - values - ); - }); - } - }; - - const fetchKeywords = async ( - objectType: string, - usageYears: any, - setFieldValue: any, - values?: any - ) => { - if (usageYears.length === 2) { - const fetchedCategories = - await environment.model.categories.getCategories({ - query: 'keywords', - }); - const category = fetchedCategories.filter( - (item: any) => item.name === 'Multiyear' - ); - - const mergedKeywords = [ - ...values.keywords, - ...[ - { - value: category[0].id, - displayLabel: category[0].name, - }, - ].filter( - (item2) => - !values.keywords.some((item1: any) => item1.value === item2.value) - ), - ]; - - setFieldValue('keywords', mergedKeywords); - } else if (usageYears.length === 1) { - const filteredKeywords = values.keywords.filter( - (item: any) => item.displayLabel !== 'Multiyear' - ); - setFieldValue('keywords', filteredKeywords); - } - }; - - const handleCompareCheck = ( - checkedVersion: VersionDataType, - isChecked: boolean - ) => { - setComparingVersions((prev: VersionDataType[]) => { - if (isChecked) { - return [...prev, checkedVersion]; - } else { - return prev.filter( - (version: VersionDataType) => - version.versionId !== checkedVersion.versionId - ); - } - }); - }; - - const fetchDownload = async (index: number) => { - const fileAssetID = - initialValue.reportDetails[index]?.reportFiles[0]?.fileAssetID; - const name = initialValue.reportDetails[index]?.reportFiles[0]?.fileName; - if (fileAssetID) { - try { - const responseData = - await environment?.model.fileUpload.fileDownloadModel(fileAssetID); - if (responseData) { - const data = new Blob([responseData]); - const url = URL.createObjectURL(data); - const a = document.createElement('a'); - a.href = url; - a.download = `${name ? name : 'downloaded_file'}`; - document.body.appendChild(a); - a.click(); - setTimeout(() => { - document.body.removeChild(a); - window.URL.revokeObjectURL(url); - }, 0); - } else { - console.error('No data received for download'); - } - } catch (error) { - console.error(error, 'error'); - } - } - }; - - const fetchCategory = useCallback( - (category: string) => { - return async () => { - const response = await environment.model.categories.getCategories({ - query: category, - }); - return response.map( - (responseValue: any): categoryType => ({ - displayLabel: responseValue.name, - value: responseValue.id.toString(), - parentID: responseValue.parentID, - }) - ); - }; - }, - [environment] - ); - const extractUniqueFromArray = (array1: string[], array2: string[]) => { - return array1.filter((item: string) => !array2.includes(item)); - }; - - const compareVersions = (versions: VersionDataType[]) => { - const version1 = versions[0]; - const version2 = versions[1]; - const newVersion1 = { - ...version1, - uniqueSources: objectTypes.reduce>( - (acc, type) => { - acc[type] = extractUniqueFromArray( - version1.source[type], - version2.source[type] - ); - return acc; - }, - {} - ), - uniqueDestinations: objectTypes.reduce>( - (acc, type) => { - acc[type] = extractUniqueFromArray( - version1.destination[type], - version2.destination[type] - ); - return acc; - }, - {} - ), - uniqueCategories: extractUniqueFromArray( - version1.categories, - version2.categories - ), - }; - - const newVersion2 = { - ...version2, - uniqueSources: objectTypes.reduce>( - (acc, type) => { - acc[type] = extractUniqueFromArray( - version2.source[type], - version1.source[type] - ); - return acc; - }, - {} - ), - uniqueDestinations: objectTypes.reduce>( - (acc, type) => { - acc[type] = extractUniqueFromArray( - version2.destination[type], - version1.destination[type] - ); - return acc; - }, - {} - ), - uniqueCategories: extractUniqueFromArray( - version2.categories, - version1.categories - ), - }; - return [newVersion1, newVersion2]; - }; - const handleFileChange = async ( - event: React.ChangeEvent, - index: number - ) => { - setUploadFlag(true); - try { - const setFile: File | undefined = (event.target as HTMLInputElement) - .files?.[0]; - if (setFile instanceof File) { - const responseData = - await environment.model.fileUpload.fileUploadModel(setFile); - setUploadedFileArray((prevUploadedFile) => { - const updateUploadedFile = [...prevUploadedFile]; - updateUploadedFile[index] = responseData; - return updateUploadedFile; - }); - console.log(uploadedFileArray, 'uploadedFileArray'); - } else { - console.error('No file selected for upload.'); - } - } catch (error) { - console.log(error, 'error'); - } - }; - useEffect(() => { - if (comparingVersions.length === 2) { - const compared = compareVersions(comparingVersions); - setComparedVersions(compared); - } - }, [comparingVersions]); - - useEffect(() => { - const handleBeforeUnload = (event: BeforeUnloadEvent) => { - if (unsavedChange) { - const message = - 'You have unsaved changes! Are you sure you want to leave?'; - event.returnValue = message; // Standard for most browsers - return message; // For some older browsers - } - }; - - window.addEventListener('beforeunload', handleBeforeUnload); - - return () => { - window.removeEventListener('beforeunload', handleBeforeUnload); - }; - }, [unsavedChange]); - - useEffect(() => { - const valuesObject: Record = { - sourceOrganizations: initialValue.sourceOrganizations, - sourceLocations: initialValue.sourceLocations, - sourceUsageYears: initialValue.sourceUsageYears, - sourceProjects: initialValue.sourceProjects, - sourcePlans: initialValue.sourcePlans, - sourceGoverningEntities: initialValue.sourceGoverningEntities, - sourceGlobalClusters: initialValue.sourceGlobalClusters, - sourceEmergencies: initialValue.sourceEmergencies, - destinationOrganizations: initialValue.destinationOrganizations, - destinationLocations: initialValue.destinationLocations, - destinationUsageYears: initialValue.destinationUsageYears, - destinationProjects: initialValue.destinationProjects, - destinationPlans: initialValue.destinationPlans, - destinationGoverningEntities: initialValue.destinationGoverningEntities, - destinationGlobalClusters: initialValue.destinationGlobalClusters, - destinationEmergencies: initialValue.destinationEmergencies, - }; - setObjects(valuesObject); - }, []); - - unstable_usePrompt({ - message: 'You have unsaved changes! Are you sure you want to leave?', - when: unsavedChange, - }); - const dictExecutedForEachObject: Record< - string, - ( - objectType: string, - flowObject: any, - setFieldValue: any, - values: any - ) => Promise - > = { - sourcePlans: fetchPlanDetails, - destinationPlans: fetchPlanDetails, - destinationEmergencies: fetchEmergencyDetails, - sourceProjects: fetchProjectDetails, - destinationProjects: fetchProjectDetails, - sourceOrganizations: fetchOrganizationDetails, - sourceGlobalClusters: fetchAssociatedGoverningEntity, - destinationGlobalClusters: fetchAssociatedGoverningEntity, - sourceUsageYears: fetchKeywords, - destinationUsageYears: fetchKeywords, - }; - - const params: DeleteFlowParams = { - VersionID: currentVersionID ?? 0, - FlowID: currentFlowID ?? 0, - }; - - const deleteFlow = async () => { - if (linkCheck || isShowParentFlow || isShowChildFlow > 0) { - window.confirm( - 'All linked flows must be unlinked before this flow can be deleted. Unlink flows and choose Delete flow again.' - ); - return; - } - - try { - const response = await env.model.flows.deleteFlow(params); - const path = flows(); - window.open(path, '_self'); - } catch (err: any) { - setOpenAlerts([...openAlerts, { message: err.message, id: alertId }]); - setAlertId((prevId) => prevId + 1); - } - }; - const updateFlowObjects = async ( - objectType: string, - flowObject: any, - setFieldValue: any, - values?: any - ) => { - if (flowObject.length > 0 && dictExecutedForEachObject[objectType]) { - flowObject.sort( - ( - a: { displayLabel: string; value: number }, - b: { displayLabel: string; value: number } - ) => { - return a.displayLabel.localeCompare(b.displayLabel); - } - ); - await dictExecutedForEachObject[objectType]( - objectType, - flowObject, - setFieldValue, - values - ); - } - if (objectType === 'sourcePlans') { - handleShowSourceGoverningEntities(flowObject.length !== 0); - } - if (objectType === 'destinationPlans') { - handleShowDestinationGoverningEntities(flowObject.length !== 0); - } - }; - const handleParentLinkedFlow = ( - values: any, - setFieldValue: any, - index: number - ) => { - setFieldValue( - 'parentFlow', - values['parentFlow'].filter((_item: any, ind: number) => ind !== index) - ); - }; - const handleChildFlow = (values: any, setFieldValue: any, index: number) => { - setFieldValue( - 'childFlow', - values['childFlow'].filter((_item: any, ind: number) => ind !== index) - ); - }; - const validateForm = (values: FormValues) => { - setUnsavedChange(JSON.stringify(values) !== JSON.stringify(initialValue)); - const valuesObject: Record = { - sourceOrganizations: values.sourceOrganizations, - sourceLocations: values.sourceLocations, - sourceUsageYears: values.sourceUsageYears, - sourceProjects: values.sourceProjects, - sourcePlans: values.sourcePlans, - sourceGoverningEntities: values.sourceGoverningEntities, - sourceGlobalClusters: values.sourceGlobalClusters, - sourceEmergencies: values.sourceEmergencies, - destinationOrganizations: values.destinationOrganizations, - destinationLocations: values.destinationLocations, - destinationUsageYears: values.destinationUsageYears, - destinationProjects: values.destinationProjects, - destinationPlans: values.destinationPlans, - destinationGoverningEntities: values.destinationGoverningEntities, - destinationGlobalClusters: values.destinationGlobalClusters, - destinationEmergencies: values.destinationEmergencies, - }; - setObjects(valuesObject); - const result = validationSchema.decode(values); - if (isRight(result)) { - setValidationFlag(false); - return {}; - } else { - const errors: Record[]> = {}; - Object.keys(values).forEach((key) => { - const value = values[key as keyof FormValues]; - if ( - result.left.some((err) => err.context.find((ctx) => ctx.key === key)) - ) { - const errorKey = key as keyof FormikErrors; - if (!value) { - errors[errorKey] = 'This field is required.'; - } else if (Array.isArray(value) && value.length === 0) { - errors[errorKey] = 'This field is required.'; - } - } - if ( - key === 'amountUSD' && - (value === 0 || (value && (value === '0' || (value as number) < 0))) - ) { - errors['amountUSD'] = 'The amount must be greater than zero.'; - } - if (key === 'flowType' && !value) { - errors['flowType'] = 'This field is required.'; - } - if (key === 'method' && !value) { - errors['method'] = 'This field is required.'; - } - if (key === 'reportDetails') { - const res = result.left.filter((err) => - err.context.find((ctx) => ctx.key === key) - )[0].value; - if (res && Array.isArray(res)) { - const reportDetailError: Record[] = []; - res.forEach((_, index) => { - const error: Record = {}; - if (res[index].reportChannel === '') { - error['reportChannel'] = 'This field is required.'; - } else { - error['reportChannel'] = ''; - } - if (!res[index].reportedDate) { - error['reportedDate'] = 'This field is required.'; - } else { - error['reportedDate'] = ''; - } - console.log(res[index], '-------------->'); - if ( - (res[index].reportFileTitle === '' || - res[index].reportFileTitle === undefined) && - (uploadedFileArray[index] && - (uploadedFileArray[index] as { id?: number })?.id - ? true - : false) - ) { - error['reportFileTitle'] = 'This field is required.'; - } else { - error['reportFileTitle'] = ''; - } - if ( - res[index].reportedOrganization === null || - res[index].reportedOrganization.displayLabel === '' - ) { - error['reportedOrganization'] = 'This field is required.'; - } else { - error['reportedOrganization'] = ''; - } - - if (Object.keys(error).length > 0) { - (reportDetailError as Record[]).push(error); - } - }); - - if (reportDetailError.length >= res.length) { - res.forEach((_, index) => { - if ( - res[index].reportChannel !== '' && - res[index].reportedOrganization !== '' && - res[index].reportedDate !== '' - ) { - if ( - (res[index].reportFileTitle === undefined || - res[index].reportFileTitle === '') && - (uploadedFileArray[index] && - (uploadedFileArray[index] as { id?: number })?.id - ? false - : true) - ) { - return {}; - } else if ( - res[index].reportFileTitle !== undefined && - res[index].reportFileTitle !== '' && - uploadedFileArray[index] - ) { - return {}; - } else { - errors['reportDetails'] = reportDetailError; - } - } else { - errors['reportDetails'] = reportDetailError; - } - }); - } - } - } - }); - console.log(errors, 'errors'); - if (Object.keys(errors).length === 0) setValidationFlag(false); - return errors; - } - }; - const handleParentFlow = ( - values: any, - parentValueString: string, - setValues: any - ) => { - parentValue = parentValueString; - const defaultValueParent: flowsResponse.GetFlowResult = - JSON.parse(parentValueString); - - const indexOrgs = defaultValueParent.organizations - .map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const indexYears = defaultValueParent.usageYears - .map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const indexLocs = defaultValueParent.locations - .map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const indexEmrs = defaultValueParent.emergencies - ?.map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const indexGlos = defaultValueParent.globalClusters - ?.map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const indexPlns = defaultValueParent.plans - ?.map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - // const indexEnt = defaultValueParent.governingEntities?.findIndex((org) => org.flowObject?.refDirection === 'destination') ?? -1; - - const indexPros = defaultValueParent.projects - ?.map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const _sourceOrganizations = indexOrgs.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: `${defaultValueParent.organizations[index].name} [${defaultValueParent.organizations[index].abbreviation}]`, - value: defaultValueParent.organizations[index].id, - }; - } - }); - const _sourceUsageYears = indexYears.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: `${defaultValueParent.usageYears[index].year}`, - value: defaultValueParent.usageYears[index].id, - }; - } - }); - const _sourceLocations = indexLocs.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: `${defaultValueParent.locations[index].name}`, - value: defaultValueParent.locations[index].id, - }; - } - }); - - const _sourceEmergencies = indexEmrs?.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: - defaultValueParent.emergencies && - `${defaultValueParent.emergencies[index].name}`, - value: - defaultValueParent.emergencies && - defaultValueParent.emergencies[index].id, - }; - } - }); - const _sourceGlobalClusters = indexGlos?.map( - (index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: - defaultValueParent.globalClusters && - `${defaultValueParent.globalClusters[index].name}`, - value: - defaultValueParent.globalClusters && - defaultValueParent.globalClusters[index].id, - }; - } - } - ); - const _sourcePlans = indexPlns?.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: - defaultValueParent.plans && - `${defaultValueParent.plans[index].planVersion.name}`, - value: defaultValueParent.plans && defaultValueParent.plans[index].id, - }; - } - }); - const _sourceProjects = indexPros?.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: - defaultValueParent.projects && - `${defaultValueParent.projects[index].projectVersions[index].name}`, - value: - defaultValueParent.projects && - defaultValueParent.projects[index].id, - }; - } - }); - - setValues({ - ...values, - sourceOrganizations: _sourceOrganizations, - sourceUsageYears: _sourceUsageYears, - sourceLocations: _sourceLocations, - sourceEmergencies: _sourceEmergencies, - sourceGlobalClusters: _sourceGlobalClusters, - sourcePlans: _sourcePlans, - // sourceGoverningEntities: _sourceGoverningEntities ? [_sourceGoverningEntities] : [], - sourceProjects: _sourceProjects, - }); - }; - return ( - - handleSubmit(values, values.submitAction) - } - validate={(values) => validateForm(values)} - enableReinitialize - validateOnChange={false} - style={{ zIndex: 1 }} - > - {({ values, setFieldValue, setValues }) => { - if (values.parentFlow && values.parentFlow[0]) { - const parentValueString = String( - values.parentFlow && - values.parentFlow[0] && - values.parentFlow[0].value - ); - if (parentValue !== parentValueString) { - handleParentFlow(values, parentValueString, setValues); - } - } - return ( -
- {isEdit && versionData && versionData.length > 0 && ( - - - {versionData.map((version: any, index: any) => ( -
- - - {version.flowId}-{version.versionId} - - {version.active ? ' [Active] ' : ' '} - {version.pending ? ' [Pending] ' : ' '} - {version.viewing ? '[Viewing]' : ''} - Created at {version.createdTime} by{' '} - {version.createdBy ?? 'FTS User'}, updated at{' '} - {version.updatedTime} by{' '} - {version.updatedBy ?? 'FTS User'} - - } - onChange={(e) => { - handleCompareCheck(version, e.target.checked); - }} - disabled={ - comparingVersions.length === 2 && - !comparingVersions.some( - (v) => v.versionId === version.versionId - ) - } - withoutFormik - /> -
- ))} - {comparingVersions.length === 2 && ( -
- Comparing versions{' '} - {comparedVersions.map((version, index) => ( - - {version.versionId} - {index < comparedVersions.length - 1 ? ',' : ''} - - ))}{' '} - differences: - - - - - - {comparedVersions.map((version) => ( - {`${version.flowId} ${version.versionId}`} - ))} - - - - - Sources - {comparedVersions.map((version) => ( - - {objectTypes.map( - (type) => - version.uniqueSources[type] && - version.uniqueSources[type].length > - 0 && ( -
- {type}:{' '} - {version.uniqueSources[type].join( - ', ' - )} -
- ) - )} -
- ))} -
- - Destinations - {comparedVersions.map((version) => ( - - {objectTypes.map( - (type) => - version.uniqueDestinations[type] && - version.uniqueDestinations[type].length > - 0 && ( -
- {type}:{' '} - {version.uniqueDestinations[ - type - ].join(', ')} -
- ) - )} -
- ))} -
- {(comparedVersions[0] && - comparedVersions[0].uniqueCategories.length) > - 0 || - (comparedVersions[1] && - comparedVersions[1].uniqueCategories.length > - 0) ? ( - - Categories - - {comparedVersions[0].uniqueCategories.join( - ', ' - )} - - - {comparedVersions[1].uniqueCategories.join( - ', ' - )} - - - ) : null} - {flowValuesForDisplay.map( - (value) => - comparedVersions[0] && - comparedVersions[1] && - comparedVersions[0][value] !== - comparedVersions[1][value] && ( - - {value} - {comparedVersions.map((version) => { - let displayValue: React.ReactNode; - const rawValue = version[value]; - - if (rawValue instanceof Date) { - displayValue = - rawValue.toLocaleDateString('en-CA'); - } else if (Array.isArray(rawValue)) { - displayValue = rawValue.join(', '); - } else { - displayValue = String(rawValue); - } - - return ( - - {displayValue} - - ); - })} - - ) - )} -
-
-
-
- )} -
-
- )} -
- ); - }} -
- ); -}; -export default FlowVersions; diff --git a/apps/hpc-ftsadmin/src/app/components/flow-form-rewrite/flows.tsx b/apps/hpc-ftsadmin/src/app/components/flow-form-rewrite/flows.tsx deleted file mode 100644 index be2f8d432..000000000 --- a/apps/hpc-ftsadmin/src/app/components/flow-form-rewrite/flows.tsx +++ /dev/null @@ -1,2628 +0,0 @@ -import React, { - ChangeEvent, - useState, - useEffect, - useCallback, - useRef, - useContext, -} from 'react'; -import { Form, Formik, FieldArray } from 'formik'; -import tw from 'twin.macro'; -import dayjs from 'dayjs'; -import { isRight } from 'fp-ts/Either'; -import { FormikErrors } from 'formik'; -import * as t from 'io-ts'; -import { util as codecs } from '@unocha/hpc-data'; -import GppMaybeIcon from '@mui/icons-material/GppMaybe'; -import Button from '@mui/material/Button'; -import DeleteIcon from '@mui/icons-material/Delete'; -import Stack from '@mui/material/Stack'; -import ContentCopyIcon from '@mui/icons-material/ContentCopy'; -import MuiAlert from '@mui/material/Alert'; -import AlertTitle from '@mui/material/AlertTitle'; -import _, { set, values } from 'lodash'; -import useSharePath from '../Hooks/SharePath'; -import { C, dialogs } from '@unocha/hpc-ui'; -import { - Table, - TableBody, - TableCell, - TableContainer, - TableHead, - TableRow, - Paper, - Alert, - IconButton, -} from '@mui/material'; -import CloseIcon from '@mui/icons-material/Close'; -import { Environment } from '../../../environments/interface'; -import { MdAdd, MdRemove, MdClose, MdCheck } from 'react-icons/md'; -import { - usageYears, - forms, - governingEntities, - fileUpload, - flows as flowsResponse, -} from '@unocha/hpc-data'; -import { getEnv } from '../../context'; -import { editFlowSetting, copyFlow } from '../../paths'; -import { flows } from '../../paths'; -import Link from '@mui/material/Link'; -import { useNavigate, unstable_usePrompt } from 'react-router-dom'; -import { id } from 'fp-ts/lib/Refinement'; -import { FlowContext } from './flow-context'; - -export type AutoCompleteSelectionType = forms.InputSelectValueType; - -const INPUT_SELECT_VALUE_TYPE = forms.INPUT_SELECT_VALUE_TYPE; - -type UniqueDataType = { - [key: string]: string[]; -}; - -export interface DeleteFlowParams { - VersionID: number; - FlowID: number; -} - -export interface categoryType { - value: string | number; - displayLabel: string; - parentID: number | null; -} - -export interface FileAssetEntityType { - collection?: string; - createAt?: string; - filename?: string; - id?: number; - mimetype?: string; - originalname?: string; - path?: string; - size?: number; - updatedAt?: string; -} -export interface ReportFileType { - title?: string; - fileName?: string; - UploadFileUrl?: string; - type?: string; - url?: string; - fileAssetID?: number; - size?: number; - fileAssetEntity?: FileAssetEntityType; -} -export interface ReportDetailType { - verified: string; - reportSource: string; - reporterReferenceCode: string; - reportChannel: AutoCompleteSelectionType | ''; - reportedOrganization: AutoCompleteSelectionType; - reportedDate: string; - reporterContactInformation: string; - sourceSystemRecordId: string; - reportFiles: ReportFileType[]; - reportFileTitle?: string; - reportUrlTitle?: string; - reportUrl?: string; - versionId?: number; - fileAsset?: FileAssetEntityType; -} - -export interface ParentFlowType { - value: any; -} - -export interface FormValues { - id: string | null; - amountUSD: number; - keywords: AutoCompleteSelectionType[]; - flowStatus: AutoCompleteSelectionType | ''; - flowType: AutoCompleteSelectionType | ''; - flowDescription: string; - firstReported: string; - decisionDate: string | null; - budgetYear: string; - flowDate: string; - contributionType: AutoCompleteSelectionType | ''; - earmarkingType: AutoCompleteSelectionType | ''; - method: AutoCompleteSelectionType | ''; - cashTransfer: AutoCompleteSelectionType | ''; - beneficiaryGroup: AutoCompleteSelectionType | ''; - inactiveReason: any[] | string; - childMethod: object; - origCurrency: AutoCompleteSelectionType | string; - amountOriginal: number | null; - exchangeRateUsed: number | null; - notes: string; - sourceOrganizations: AutoCompleteSelectionType[]; - sourceLocations: AutoCompleteSelectionType[]; - sourceUsageYears: AutoCompleteSelectionType[]; - sourceProjects: AutoCompleteSelectionType[]; - sourcePlans: AutoCompleteSelectionType[]; - sourceGoverningEntities: AutoCompleteSelectionType[]; - sourceGlobalClusters: AutoCompleteSelectionType[]; - sourceEmergencies: AutoCompleteSelectionType[]; - destinationOrganizations: AutoCompleteSelectionType[]; - destinationLocations: AutoCompleteSelectionType[]; - destinationUsageYears: AutoCompleteSelectionType[]; - destinationProjects: AutoCompleteSelectionType[]; - destinationPlans: AutoCompleteSelectionType[]; - destinationGoverningEntities: AutoCompleteSelectionType[]; - destinationGlobalClusters: AutoCompleteSelectionType[]; - destinationEmergencies: AutoCompleteSelectionType[]; - reportDetails: ReportDetailType[]; - parentFlow?: AutoCompleteSelectionType[]; - childFlow?: AutoCompleteSelectionType[]; - isParkedParent?: boolean; - includeChildrenOfParkedFlows: boolean; - isErrorCorrectionValue: boolean; - sources?: Record; - submitAction?: string | undefined; - versions?: { - id: number | null; - isPending: boolean | null; - }[]; -} - -export interface VersionDataType { - versionId: number; - flowId: number; - createdTime: string; - createdBy: string | null; - updatedTime: string; - updatedBy: string | null; - active: boolean; - viewing: boolean; - pending?: boolean; - [key: string]: - | string - | number - | null - | boolean - | string[] - | Date - | undefined - | Record; - source: UniqueDataType; - destination: UniqueDataType; - categories: string[]; - uniqueSources: UniqueDataType; - uniqueDestinations: UniqueDataType; - uniqueCategories: string[]; - restricted?: boolean; -} - -export interface InputEntriesType { - amountUSD: forms.InputEntryType | null; - origCurrency: forms.InputEntryType | null; - keywords: forms.InputEntryType | null; - flowStatus: forms.InputEntryType | null; - flowType: forms.InputEntryType | null; - flowDescription: forms.InputEntryType | null; - contributionType: forms.InputEntryType | null; - earmarkingType: forms.InputEntryType | null; - method: forms.InputEntryType | null; - beneficiaryGroup: forms.InputEntryType | null; - inactiveReason: forms.InputEntryType | null; - amountOriginal: forms.InputEntryType | null; - exchangeRateUsed: forms.InputEntryType | null; - notes: forms.InputEntryType | null; - sourceOrganizations: forms.InputEntryType[]; - sourceLocations: forms.InputEntryType[]; - sourceUsageYears: forms.InputEntryType[]; - sourceProjects: forms.InputEntryType[]; - sourcePlans: forms.InputEntryType[]; - sourceGoverningEntities: forms.InputEntryType[]; - sourceGlobalClusters: forms.InputEntryType[]; - sourceEmergencies: forms.InputEntryType[]; - destinationOrganizations: forms.InputEntryType[]; - destinationLocations: forms.InputEntryType[]; - destinationUsageYears: forms.InputEntryType[]; - destinationProjects: forms.InputEntryType[]; - destinationPlans: forms.InputEntryType[]; - destinationGoverningEntities: forms.InputEntryType[]; - destinationGlobalClusters: forms.InputEntryType[]; - destinationEmergencies: forms.InputEntryType[]; - parentFlow: forms.InputEntryType | null; - childFlow: forms.InputEntryType[]; -} - -type UploadedItem = fileUpload.FileUploadResult | FileAssetEntityType; - -const reportChannelSchema = t.type({ - value: t.intersection([codecs.NON_EMPTY_STRING, t.string]), - displayLabel: t.intersection([codecs.NON_EMPTY_STRING, t.string]), -}); - -const reportDetailsSchema = t.type({ - reportedOrganization: INPUT_SELECT_VALUE_TYPE, - reportedDate: t.intersection([codecs.NON_EMPTY_STRING, t.string]), - reportChannel: t.intersection([codecs.NON_EMPTY_STRING, reportChannelSchema]), - reportFileTitle: t.intersection([codecs.NON_EMPTY_STRING, t.string]), -}); - -const validationSchema = t.type({ - amountUSD: t.number, - flowStatus: INPUT_SELECT_VALUE_TYPE, - flowDescription: t.intersection([codecs.NON_EMPTY_STRING, t.string]), - firstReported: t.string, - flowDate: t.intersection([codecs.NON_EMPTY_STRING, t.string]), - sourceOrganizations: INPUT_SELECT_VALUE_TYPE, - sourceUsageYears: INPUT_SELECT_VALUE_TYPE, - destinationOrganizations: INPUT_SELECT_VALUE_TYPE, - destinationUsageYears: INPUT_SELECT_VALUE_TYPE, - reportDetails: reportDetailsSchema, -}); - -interface Props { - currentVersionData: flowsResponse.FlowREST | null; - environment: Environment; - isEdit: boolean; - initialValue: FormValues; - prevDetails?: ReportDetailType[]; - versionData?: VersionDataType[]; - flowId?: string; - versionId?: string; - isRestricted: boolean; - errorCorrection?: boolean; - inputEntries: InputEntriesType; - initializeInputEntries: () => void; - rejectInputEntry: (key: string) => void; - currentVersionID?: number; - currentFlowID?: number; - currentVersionActiveStatus?: boolean; - isPending?: boolean; - isSuperseded?: boolean; - isCancelled?: boolean; - isCancellation?: boolean; - isNewPending?: boolean; - isUpdatePending?: boolean; - canReactive?: boolean; - isErrorCorrection?: boolean | null; - isApprovedFlowVersion?: boolean | null; - pendingFieldsAllApplied?: boolean; - allFieldsReviewed?: boolean; - pendingVersionV1?: boolean; -} - -const StyledRepOrgLink = tw.div` - flex - ml-1 - `; - -const StyledAddChildWarning = tw.div` - border border-solid border-yellow-600 - flex - rounded-md - text-gray-900 - bg-yellow-100 bg-opacity-50 - `; - -const StyledAddChildWarningIconDiv = tw.div` - flex - items-center - p-1 - `; -const StyledAddChildWarningText = tw.span` - py-3 px-3 pb-3 - `; -const StyledLayoutRow = tw.div` - flex - `; -const StyledHalfSection = tw.div` - w-1/2 - `; -const StyledFullSection = tw.div` - w-full - mb-6 - `; -const StyledRow = tw.div` - flex - gap-4 - w-full - `; -const StyledFormRow = tw.div` - flex - gap-2 - w-full - items-center - `; -const StyledAnchor = tw.a` - underline - ml-[15px] - opacity-100 - `; -const StyledAnchorDiv = tw.div` - text-right - w-full - `; -const StyledRadioDiv = tw.div` - relative - w-full - `; -const StyledFieldset = tw.fieldset` - w-full - box-border - rounded-xl - mt-[16px] - mb-[8px] - border-gray-100 - `; -const StyledCurrencyRow = tw.div` - w-1/2 - `; -const StyledFormButton = tw(C.Button)` - ml-[25px] - mb-6 - `; -const StyledLabel = tw.label` - block - my-4 - `; -const StyledLinkedFlowRow = tw.div` - mt-4 - `; - -const StyledParentInfo = tw.div` - border-0 - border-b - border-solid - cursor-pointer - mb-4 - pb-4 - `; - -const StyledStrong = tw.strong` - min-w-[16rem] - inline-block - `; - -const StyledList = tw.li` - list-none - `; - -const StyledDiv = tw.div` - my-6 - me-4 - mr-[23px] - lg:flex - justify-end - gap-x-4 - bg-white - z-10 - `; - -const initialReportDetail = { - verified: 'verified', - reportSource: 'primary', - reporterReferenceCode: '', - reportChannel: '', - reportFileTitle: '', - reportedOrganization: { value: '', displayLabel: '' }, - reportedDate: dayjs().format('DD/MM/YYYY'), - reporterContactInformation: '', - sourceSystemRecordId: '', -}; - -const FORM_SETTINGS = { - organization: { - behavior: 'shared', - }, - project: { - behavior: 'overlap', - }, - usageYear: { - behavior: 'shared', - }, - location: { - behavior: 'shared', - }, - globalCluster: { - behavior: 'shared', - }, - emergency: { - behavior: 'overlap', - }, - governingEntity: { - behavior: 'shared', - }, - plan: { - behavior: 'overlap', - }, -}; - -const objectTypes = [ - 'emergencies', - 'projects', - 'usageYears', - 'globalClusters', - 'locations', - 'plans', - 'organizations', -] as const; - -const flowValuesForDisplay = [ - 'amountUSD', - 'flowDate', - 'decisionDate', - 'firstReportedDate', - 'budgetYear', - 'origAmount', - 'origCurrency', - 'exchangeRate', - 'activeStatus', - 'restricted', - 'newMoney', - 'description', - 'notes', -] as const; - -let parentValue = ''; - -export const FLowsInfo = () => { - const { - flowValue, - setFlowValue, - initialValue, - isEdit, - currentVersionData, - environment, - prevDetails, - versionData, - isRestricted, - errorCorrection, - inputEntries, - flowId, - versionId, - initializeInputEntries, - rejectInputEntry, - currentVersionID, - currentFlowID, - currentVersionActiveStatus, - isPending, - isSuperseded, - isCancelled, - isCancellation, - isNewPending, - isUpdatePending, - canReactive, - pendingFieldsAllApplied, - allFieldsReviewed, - pendingVersionV1, - }: any = useContext(FlowContext); - // const { - // currentVersionData, - // environment, - // initialValue, - // isEdit, - // prevDetails, - // versionData, - // isRestricted, - // errorCorrection, - // inputEntries, - // flowId, - // versionId, - // initializeInputEntries, - // rejectInputEntry, - // currentVersionID, - // currentFlowID, - // currentVersionActiveStatus, - // isPending, - // isSuperseded, - // isCancelled, - // isCancellation, - // isNewPending, - // isUpdatePending, - // canReactive, - // pendingFieldsAllApplied, - // allFieldsReviewed, - // pendingVersionV1, - // } = props; - const { confirm } = dialogs; - const env = getEnv(); - - const collapseFlowObjects = (data: any) => { - data.flowObjects = []; - - collapsePerBehavior(data.dest, 'destination'); - collapsePerBehavior(data.src, 'source'); - - function collapsePerBehavior(behaviorArr: any, ref: any) { - Object.keys(behaviorArr).forEach((type) => { - behaviorArr[type].forEach((obj: any) => { - if ( - obj !== null && - (!Object.prototype.hasOwnProperty.call(obj, 'cleared') || - !obj.cleared) - ) { - if (type === 'organization') { - obj.objectDetail = obj.implementingPartner ? 'partner' : null; - } - - const flowObj = { - refDirection: ref, - objectType: type, - objectID: obj.id, - behavior: obj.behavior || null, - objectDetail: obj.objectDetail, - }; - data.flowObjects.push(flowObj); - } - }); - }); - } - - return data as any; - }; - - const collapseCategories = (data: any) => { - data.categories = [ - data.flowType, - data.flowStatuses, - data.contributionTypes, - data.method, - data.childMethod, - data.keywords, - data.inactiveReason, - data.beneficiaryGroup, - data.pendingStatus, - data.earmarking !== null && data.earmarking.id, - ].filter((category) => category); - data.categories = data.categories - .map((value: any) => { - if (value && value.id) { - return value.id; - } else if (value[0]) { - return value[0].id; - } - }) - .filter(function (value: any) { - return value; - }) - .map((value: any) => { - return parseInt(value); - }); - - return data; - }; - const [uploadFileFlag, setUploadFileFlag] = useState(false); - const [uploadFlag, setUploadFlag] = useState(false); - const normalizeFlowData = (values: FormValues) => { - const fundingObject = { - src: { - governingEntity: values.sourceGoverningEntities.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - location: values.sourceLocations.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - organization: values.sourceOrganizations.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - project: values.sourceProjects.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - usageYear: values.sourceUsageYears.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - globalCluster: values.sourceGlobalClusters.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - emergency: values.sourceEmergencies.map((item) => ({ - id: item.value, - name: item.displayLabel, - restricted: item.restricted, - })), - plan: values.sourcePlans.map((item) => ({ - id: item.value, - name: item.displayLabel, - restricted: item.restricted, - })), - }, - dest: { - governingEntity: values.destinationGoverningEntities.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - location: values.destinationLocations.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - organization: values.destinationOrganizations.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - project: values.destinationProjects.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - usageYear: values.destinationUsageYears.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - globalCluster: values.destinationGlobalClusters.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - emergency: values.destinationEmergencies.map((item) => ({ - id: item.value, - name: item.displayLabel, - restricted: item.restricted, - })), - plan: values.destinationPlans.map((item) => ({ - id: item.value, - name: item.displayLabel, - restricted: item.restricted, - })), - }, - }; - - let data = { - id: isEdit && currentFlowID ? currentFlowID : null, - versionID: isEdit && currentVersionID ? currentVersionID : null, - amountUSD: values.amountUSD, - flowDate: dayjs(values.flowDate, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ), - decisionDate: values.decisionDate - ? dayjs(values.decisionDate, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ) - : null, - firstReportedDate: dayjs(values.firstReported, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ), - budgetYear: values.budgetYear, - origAmount: values.amountOriginal ? values.amountOriginal : null, - origCurrency: (values.origCurrency as AutoCompleteSelectionType) - ? (values.origCurrency as AutoCompleteSelectionType)?.displayLabel - : null, - exchangeRate: values.exchangeRateUsed ? values.exchangeRateUsed : null, - activeStatus: true, - restricted: false, - newMoney: true, - description: values.flowDescription, - versionStartDate: currentVersionData?.versionStartDate, - versionEndDate: currentVersionData?.versionEndDate, - flowObjects: collapseFlowObjects(fundingObject), - children: - values.childFlow && - values.childFlow.map((item: any, index: number) => { - return { - childID: JSON.parse(item.value as string).id, - origCurrency: JSON.parse(item.value as string).origCurrency, - }; - }), - parents: - values.parentFlow && - values.parentFlow.map((item: any, index: number) => { - return { - Parent: { - parentID: JSON.parse(item.value as string).id, - origCurrency: JSON.parse(item.value as string).origCurrency, - }, - childID: currentFlowID, - parentID: JSON.parse(item.value as string).id, - origCurrency: JSON.parse(item.value as string).origCurrency, - id: JSON.parse(item.value as string).id, - parents: - values.parentFlow && - values.parentFlow.map((key: any) => { - return { - child: JSON.parse(key.value as string).id, - parentID: 271736, - }; - }), - }; - }), - reportDetails: values.reportDetails.map((item, index) => { - return { - contactInfo: item.reporterContactInformation, - source: item.reportSource, - date: dayjs(item.reportedDate, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ), - versionID: currentVersionID, - newlyAdded: addReportFlag, - sourceID: null, - refCode: '7F-10073.04', - verified: true, - organizationID: item.reportedOrganization.value, - categories: [item.reportChannel && item.reportChannel.value], - organization: { - id: item.reportedOrganization.value, - name: item.reportedOrganization.displayLabel, - }, - reportFiles: - uploadFlag && - uploadedFileArray[index] && - (uploadedFileArray[index] as { id?: number })?.id - ? uploadFlag || uploadFileFlag - ? [ - { - title: item.reportUrlTitle, - type: 'url', - url: item.reportUrl, - }, - { - fileAssetID: - uploadedFileArray[index] && - (uploadedFileArray[index] as { id?: number })?.id, - reportFiles: [ - { - fieldType: 'file', - fileAssetID: - uploadedFileArray[index] && - (uploadedFileArray[index] as { id?: number })?.id, - type: 'file', - }, - ], - title: item.reportFileTitle, - type: 'file', - }, - ] - : [ - { - title: item.reportUrlTitle, - type: 'url', - url: item.reportUrl, - }, - ] - : uploadFileFlag - ? [ - { - title: item.reportUrlTitle, - type: 'url', - url: item.reportUrl, - }, - ] - : item.reportFiles - ? item.reportFiles - : [], - - reportChannel: { - group: 'reportChannel', - id: item.reportChannel && item.reportChannel.value, - name: item.reportChannel && item.reportChannel.displayLabel, - }, - }; - }), - flowType: { - id: values.flowType && values.flowType.value, - name: values.flowType && values.flowType.displayLabel, - group: 'flowType', - }, - keywords: values.keywords.map((item) => ({ - id: item.value, - name: item.displayLabel, - group: 'keywords', - })), - flowStatuses: { - id: values.flowStatus && values.flowStatus.value, - name: values.flowStatus && values.flowStatus.displayLabel, - group: 'flowStatus', - }, - contributionTypes: { - id: values.contributionType && values.contributionType.value, - name: values.contributionType && values.contributionType.displayLabel, - group: 'contributionType', - }, - method: { - id: values.method && values.method.value, - name: values.method && values.method.displayLabel, - group: 'method', - }, - childMethod: values.cashTransfer && { - id: values.cashTransfer.value, - name: values.cashTransfer.displayLabel, - group: 'method', - parentID: values.method && values.method.value, - }, - earmarking: values.earmarkingType - ? { - id: values.earmarkingType.value, - name: values.earmarkingType.displayLabel, - group: 'earmarkingType', - } - : null, - categories: [] as (string | number)[], - isCancellation: isPending ? true : !isPending ? false : null, - cancelled: isPending && isCancellation ? true : null, - pendingStatus: isPending ? true : !isPending ? false : [], - planEntities: isPending ? true : !isPending ? false : [], - planIndicated: isPending ? true : !isPending ? false : [], - isApprovedFlowVersion: - rejectFlag && approveFlag - ? true - : !(rejectFlag && approveFlag) - ? false - : null, - inactiveReason: [ - { - id: null as null | number | string, - name: '' as string | undefined, - description: null, - parentID: null, - code: null, - group: '', - includeTotals: null, - createdAt: '', - updatedAt: '', - }, - ], - isErrorCorrection: errorCorrection - ? true - : isSuperseded - ? true - : isPending - ? true - : !isSuperseded && !isPending - ? false - : null, - rejected: rejectFlag ? true : !rejectFlag ? false : null, - versions: - versionData && - versionData.map((item: VersionDataType) => { - const items = { - id: item.flowId, - versionID: item.versionId, - activeStatus: item.activeStatus, - isPending: item.isPending ? item.isPending : false, - isCancelled: item.isCancelled ? item.isCancelled : false, - }; - return items; - }), - ...fundingObject, - }; - - data = collapseCategories(data); - return data; - }; - - const [unsavedChange, setUnsavedChange] = useState(false); - const [parentCurrencyFlag, setParentCurrencyFlag] = useState(false); - const [childCurrencyFlag, setChildCurrencyFlag] = useState(false); - const [approveFlag, setApproveFlag] = useState(false); - const [rejectFlag, setRejectFlag] = useState(false); - const [validationFlag, setValidationFlag] = useState(false); - const [inactiveFlag, setInactiveFlag] = useState(false); - const [uploadedFileArray, setUploadedFileArray] = useState([ - {}, - ]); - const [addReportFlag, setAddReportFlag] = useState(false); - const [alertFlag, setAlertFlag] = useState(false); - const [sharePath, setSharePath] = useSharePath(''); - const [readOnly, setReadOnly] = useState(false); - const [linkCheck, setLinkCheck] = useState(false); - const handleSave = () => { - window.scrollTo({ top: 0, behavior: 'smooth' }); - }; - - const [showWarningMessage, setShowWarningMessage] = useState(false); - const [objects, setObjects] = useState>({}); - const [showingTypes, setShowingTypes] = useState([]); - const [newMoneyCheckboxDisabled, setNewMoneyCheckboxDisabled] = - useState(false); - - const [comparingVersions, setComparingVersions] = useState( - [] - ); - const [comparedVersions, setComparedVersions] = useState( - [] - ); - const [showSourceGoverningEntities, handleShowSourceGoverningEntities] = - useState(false); - const [ - showDestinationGoverningEntities, - handleShowDestinationGoverningEntities, - ] = useState(false); - const [sourceGoverningEntities, setSourceGoverningEntities] = - useState([]); - const [destinationGoverningEntities, setDestinationGoverningEntities] = - useState([]); - const [isShowParentFlow, setShowParentFlow] = useState( - initialValue.parentFlow && initialValue.parentFlow.length ? true : false - ); - const [isShowChildFlow, setShowChildFlow] = useState(0); - const [openAlerts, setOpenAlerts] = useState< - { message: string; id: number }[] - >([]); - const [alertId, setAlertId] = useState(0); - const handleClose = (id: number) => { - setOpenAlerts(openAlerts.filter((alert) => alert.id !== id)); - }; - const buttonText = 'Calculate The Exchange Rate'; - - const handleCalculateExchangeRate = (values: any, setFieldValue: any) => { - const { amountOriginal, amountUSD } = values; - - if (amountOriginal && amountUSD) { - const exchangeRateUsed = amountOriginal / amountUSD; - setFieldValue('exchangeRateUsed', exchangeRateUsed.toFixed(4)); - } else if (amountOriginal && !amountUSD) { - const calculatedAmountUSD = amountOriginal / values.exchangeRateUsed; - setFieldValue('amountUSD', calculatedAmountUSD.toFixed(4)); - } else if (!amountOriginal && amountUSD) { - const calculatedAmountOriginal = amountUSD * values.exchangeRateUsed; - setFieldValue('amountOriginal', calculatedAmountOriginal.toFixed(4)); - } else { - console.warn('Both original amount and USD amount are missing.'); - } - }; - useEffect(() => { - if (initialValue?.childFlow) { - setShowChildFlow(initialValue?.childFlow.length); - } - }, [initialValue]); - useEffect(() => { - const fileAssets: FileAssetEntityType[] = []; - if (isEdit) { - initialValue.reportDetails.forEach((detail: any) => { - if (detail?.fileAsset) { - fileAssets.push(detail.fileAsset); - setUploadedFileArray(fileAssets); - } else { - fileAssets.push({} as FileAssetEntityType); - setUploadedFileArray(fileAssets); - } - }); - } - }, [initialValue.reportDetails]); - useEffect(() => { - if (currentVersionActiveStatus) { - setReadOnly(false); - } else { - setReadOnly(true); - } - }, [currentVersionActiveStatus]); - useEffect(() => { - if (initialValue.parentFlow && initialValue.parentFlow.length) { - setShowParentFlow(true); - } - }, [initialValue.parentFlow]); - const [remove, setRemove] = useState(false); - const handleRemove = (index: number, values: FormValues) => { - if (window.confirm('Are you sure you want to remove this file?')) { - if ( - initialValue.reportDetails[index].reportFiles && - initialValue.reportDetails[index].reportFiles[0]?.fileName - ) { - values.reportDetails[index].reportFileTitle = ''; - initialValue.reportDetails[index].reportFiles[0].fileName = ''; - initialValue.reportDetails[index].reportFiles[0].title = ''; - initialValue.reportDetails[index].reportFiles[0].fileAssetID = - undefined; - initialValue.reportDetails[index].reportFiles[0].UploadFileUrl = ''; - const updatedArray = removeByIndexFromArray(uploadedFileArray, index); - setUploadedFileArray(updatedArray); - } else return; - setUploadFlag(false); - setRemove(true); - } else return; - }; - const removeByIndexFromArray = (array: UploadedItem[], index: number) => { - const newArray = [...array]; - newArray[index] = {}; - return newArray; - }; - if (remove === true) setRemove(false); - const SourceLink = ( - setFieldValue: any, - values: FormValues, - indexKey: number, - index: number - ) => { - setFieldValue( - `reportDetails[${index}].reportedOrganization`, - values.sourceOrganizations[indexKey] - ); - }; - const DestinationLink = ( - setFieldValue: any, - values: FormValues, - indexKey: number, - index: number - ) => { - setFieldValue( - `reportDetails[${index}].reportedOrganization`, - values.destinationOrganizations[indexKey] - ); - }; - - interface Inconsistency { - type: string; - values: { - name?: string; - year?: string; - refDirection: string; - options?: { name: string }[]; - }[]; - } - - const processDataInconsistencies = ( - inconsistencyArray: Inconsistency[] - ): string => { - let message = ''; - inconsistencyArray.forEach((inconsistencyWith) => { - if (inconsistencyWith && inconsistencyWith.type) { - const inconsistencyType = inconsistencyWith.type; - message += - inconsistencyType.charAt(0).toUpperCase() + - inconsistencyType.slice(1) + - ': '; - - if (inconsistencyWith.type === 'no-direct-link') { - message += inconsistencyWith.values.join(', '); - } else { - message += - inconsistencyWith.values - .map((value) => { - const name = value.name || value.year; - let joinedOptions = ''; - if (value.options) { - joinedOptions = value.options - .map((option) => { - return option.name || JSON.stringify(option); - }) - .join(', '); - } - const options = `is not in the list of acceptable ${value.refDirection} ${inconsistencyType}: [${joinedOptions}]`; - return `'${name}' ${options}`; - }) - .join(', ') + '. '; - } - } else { - message += JSON.stringify(inconsistencyArray); - } - }); - return message; - }; - - const handleSubmit = async ( - values: FormValues, - submitAction: string | undefined - ) => { - if (values.childFlow) { - for (let i = 0; i < values.childFlow.length; i++) { - if ( - values.destinationUsageYears.length >= 2 && - JSON.parse(values.childFlow[i].value as string).activeStatus === true - ) { - values.flowType = { - displayLabel: 'Parked', - value: '1252', - }; - } - } - } - if (isShowParentFlow && isShowChildFlow > 0) { - let childAmountSum = 0; - let parentAmountSum = 0; - values.childFlow && - values.childFlow.map((item, _index) => { - childAmountSum += JSON.parse(item.value.toString()) - ? parseInt(JSON.parse(item.value.toString()).amountUSD) - : 0; - }); - values.parentFlow && - values.parentFlow.map((item, _index) => { - parentAmountSum += JSON.parse(item.value.toString()) - ? parseInt(JSON.parse(item.value.toString()).amountUSD) - : 0; - }); - if (childAmountSum > parentAmountSum) { - if ( - !window.confirm( - `Please note, the Funding Amount on this parent flow ($${parentAmountSum}) is less than the sum of its children's amount ($${childAmountSum}). Do you want to proceed?` - ) - ) { - return; - } - } - } - if (isShowParentFlow || isShowChildFlow > 0) { - let childAmountSum = 0; - values.childFlow && - values.childFlow.map((item, _index) => { - childAmountSum += JSON.parse(item.value.toString()) - ? parseInt(JSON.parse(item.value.toString()).amountUSD) - : 0; - }); - if (childAmountSum > values.amountUSD) { - if ( - !window.confirm( - `Please note, the Funding Amount on this parent flow ($${values.amountUSD}) is less than the sum of its children's amount ($${childAmountSum}). Do you want to proceed?` - ) - ) - return; - } - } - const parentFlow = values.parentFlow; - if (parentFlow?.length) { - for (let index = 0; index < parentFlow.length; index++) { - const item = parentFlow[index]; - if ( - (typeof values?.origCurrency !== 'string' && - values.origCurrency?.displayLabel) || - !( - JSON.parse(item.value.toString()) && - JSON.parse(item.value.toString())?.origCurrency === null - ) - ) { - if ( - (typeof values?.origCurrency !== 'string' && - values.origCurrency?.displayLabel) !== - (JSON.parse(item.value.toString()) && - JSON.parse(item.value.toString())?.origCurrency) - ) { - handleSave(); - setParentCurrencyFlag(true); - return; - } - } - } - } - const childFlow = values.childFlow; - if (childFlow) { - for (let index = 0; index < childFlow.length; index++) { - const item = childFlow[index]; - if ( - (typeof values?.origCurrency !== 'string' && - values.origCurrency?.displayLabel) || - !( - JSON.parse(item.value.toString()) && - JSON.parse(item.value.toString())?.origCurrency === null - ) - ) { - if ( - (typeof values.origCurrency !== 'string' && - values.origCurrency?.displayLabel) !== - (JSON.parse(item.value.toString()) && - JSON.parse(item.value.toString()).origCurrency) - ) { - handleSave(); - setChildCurrencyFlag(true); - return; - } - } - } - } - for (let i = 0; i < values.reportDetails.length; i++) { - if ( - values.reportDetails[i].reportUrlTitle && - values.reportDetails[i].reportUrl - ) { - setUploadFileFlag(true); - } else setUploadFileFlag(false); - } - const data = normalizeFlowData(values); - const inactiveReasons = await fetchCategory('inactiveReason')(); - if (submitAction === 'approve') { - data.isApprovedFlowVersion = true; - } else if (submitAction === 'rejected') { - data.activeStatus = false; - data.rejected = true; - data.inactiveReason = [ - { - id: - inactiveReasons.find( - (item: any) => item.displayLabel === 'Rejected' - )?.value || null, - name: inactiveReasons.find( - (item: any) => item.displayLabel === 'Rejected' - )?.displayLabel, - description: null, - parentID: null, - code: null, - group: 'inactiveReason', - includeTotals: null, - createdAt: currentVersionData - ? dayjs(currentVersionData.createdAt, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ) - : '', - updatedAt: currentVersionData - ? dayjs(currentVersionData.updatedAt, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ) - : '', - }, - ]; - } else if (submitAction === 'inactive') { - if (isShowParentFlow || isShowChildFlow > 0) { - setInactiveFlag(true); - } else { - const categoryValue = - inactiveReasons.find((item: any) => item.displayLabel === 'Cancelled') - ?.value ?? null; - if (categoryValue) { - data.categories.push(parseInt(categoryValue.toString())); - } - data.activeStatus = false; - data.cancelled = true; - data.isCancellation = null; - data.rejected = null; - data.newMoney = false; - data.inactiveReason = [ - { - id: - inactiveReasons.find( - (item: any) => item.displayLabel === 'Cancelled' - )?.value || null, - name: inactiveReasons.find( - (item: any) => item.displayLabel === 'Cancelled' - )?.displayLabel, - description: null, - parentID: null, - code: null, - group: 'inactiveReason', - includeTotals: null, - createdAt: currentVersionData ? currentVersionData.createdAt : '', - updatedAt: currentVersionData ? currentVersionData.updatedAt : '', - }, - ]; - } - } - if (!inactiveFlag) { - const response = await env.model.flows.validateFlow(data); - let flag = true; - let mismatchFound = false; - for (let i = 0; i < values.reportDetails.length; i++) { - const reportOrganizationLabel = - values.reportDetails[i].reportedOrganization.displayLabel; - const reportMatchesSource = values.sourceOrganizations.some( - (sourceOrg) => sourceOrg.displayLabel === reportOrganizationLabel - ); - const reportMatchesDestination = values.destinationOrganizations.some( - (destOrg) => destOrg.displayLabel === reportOrganizationLabel - ); - - if (!reportMatchesSource && !reportMatchesDestination) { - mismatchFound = true; - break; - } - } - if (mismatchFound) { - if ( - !window.confirm( - "Your flow's Report Detail organization doesn't match the source or destination organization or that of its parked parent. Are you sure this is right?" - ) - ) { - return; - } - } - response.forEach((obj) => { - if (obj) { - const { success, message, confirmed } = obj; - if (!success) { - if (confirmed) { - const confirm = window.confirm(confirmed); - if (!confirm) { - setOpenAlerts([...openAlerts, { message, id: alertId }]); - setAlertId((prevId) => prevId + 1); - flag = false; - handleSave(); - } - } else if (message) { - setOpenAlerts([...openAlerts, { message, id: alertId }]); - setAlertId((prevId) => prevId + 1); - flag = false; - handleSave(); - } - } - } - }); - if (flag && !(isShowParentFlow || isShowChildFlow > 0)) { - setUnsavedChange(false); - if (!isEdit) { - try { - const response = await env.model.flows.createFlow({ flow: data }); - const path = editFlowSetting(response.id, response.versionID); - window.open(path, '_self'); - } catch (err: any) { - setOpenAlerts([ - ...openAlerts, - { message: err.message, id: alertId }, - ]); - setAlertId((prevId) => prevId + 1); - handleSave(); - } - } else { - const dbFlow = await env.model.flows.getFlowREST({ - id: currentFlowID!, - }); - if ( - (versionData && - currentVersionID && - Date.parse(versionData[currentVersionID - 1].updatedTime) < - Date.parse(dbFlow.updatedAt)) || - (versionData && versionData.length < dbFlow.versions.length) - ) { - window.confirm( - 'This flow cannot be saved, as a concurrency conflict has been detected. Please refresh your screen to view the most up to date data.' - ); - } else { - if (isPending && (approveFlag || rejectFlag)) { - if ( - allFieldsReviewed || - pendingFieldsAllApplied || - !pendingVersionV1 - ) { - try { - const response = await env.model.flows.updatePendingFlow({ - flow: data, - }); - if (response) { - const path = editFlowSetting( - response.id, - response.versionID - ); - setAlertFlag(true); - setSharePath(path); - } - } catch (err: any) { - setOpenAlerts([ - ...openAlerts, - { message: err.message, id: alertId }, - ]); - setAlertId((prevId) => prevId + 1); - handleSave(); - } - } else { - window.confirm( - 'Some of the revised data on this flow still needs to be accepted or rejected before this update can be approved.' - ); - } - } else { - try { - const response = await env.model.flows.updateFlow({ - flow: data, - }); - if (response) { - const path = editFlowSetting(response.id, response.versionID); - setAlertFlag(true); - setSharePath(path); - } - } catch (err: any) { - let errmessage = ''; - if (err.reason) { - const inconsistencyObject = err.reason; - errmessage = processDataInconsistencies(inconsistencyObject); - } else { - const lastIndex = err.message.lastIndexOf(':'); - errmessage = err.message.substring(lastIndex + 1); - } - setOpenAlerts([ - ...openAlerts, - { message: errmessage, id: alertId }, - ]); - setAlertId((prevId) => prevId + 1); - handleSave(); - } - } - } - } - } - } - }; - const navigate = useNavigate(); - const handleCopy = (values: FormValues) => { - if (currentFlowID && currentVersionID) { - const isCopy = true; - const path = copyFlow(); - if (typeof path === 'string') { - const valuesWithFiles = { ...values, isCopy }; - navigate(path, { state: valuesWithFiles }); - } else { - console.error('Path is not a string', path); - } - } - }; - - const handleAlert = (values: FormValues) => { - const errors = validateForm(values); - if (Object.keys(errors).length !== 0) { - setValidationFlag(true); - handleSave(); - } - }; - - const setObjectsWithArray = ( - fetchedObject: any, - objectKeys: string[], - settingArrayKeys: string[], - setFieldValue: any, - values: any - ) => { - const newObjects = { ...objects }; - const newShowingTypes = [...showingTypes]; - objectKeys.forEach((key, i) => { - if (fetchedObject[settingArrayKeys[i]]) { - newObjects[key] = checkIfExistingAndCopy( - newObjects[key], - fetchedObject, - settingArrayKeys[i] - ); - } - - const parsedResponse = newObjects[key].map((responseValue: any) => { - if (settingArrayKeys[i] === 'years') { - return { - displayLabel: - (responseValue as usageYears.UsageYear).year || - responseValue.displayLabel, - value: responseValue.id || responseValue.value, - isAutoFilled: responseValue.suggested, - }; - } else if (settingArrayKeys[i] === 'plans') { - return { - displayLabel: - (responseValue.planVersion as { planId: number; name: string }) - .name || responseValue.displayLabel, - value: responseValue.planVersion.planId || responseValue.value, - isAutoFilled: responseValue.suggested, - }; - } else if (settingArrayKeys[i] === 'governingEntities') { - return { - displayLabel: - ( - responseValue.governingEntityVersion as { - id: number; - name: string; - } - ).name || responseValue.displayLabel, - value: - responseValue.governingEntityVersion.id || responseValue.value, - isAutoFilled: responseValue.suggested, - }; - } else { - return { - displayLabel: - (responseValue as { id: number; name: string }).name || - responseValue.displayLabel, - value: responseValue.id || responseValue.value, - isAutoFilled: responseValue.suggested, - }; - } - }); - newObjects[key].forEach((obj) => { - if (obj?.suggested) { - updateFlowObjects(key, parsedResponse, setFieldValue, values); - obj.suggested = false; - } - }); - setFieldValue(key, parsedResponse); - }); - - setObjects(newObjects); - setShowingTypes(newShowingTypes); - }; - - const checkIfExistingAndCopy = ( - existingObjects: any[], - object: any, - key: string - ): any[] => { - let newObjects = object[key]; - if (key === 'locations') { - newObjects = newObjects.filter(function (location: any) { - return location.adminLevel === 0; - }); - if (existingObjects && existingObjects.length) { - existingObjects = existingObjects.filter(function (location) { - return location.adminLevel === 0 || location.value; - }); - } - } - - if (existingObjects && existingObjects.length) { - const existingObjectsIds = existingObjects.map(function (o) { - return o.id || o.value; - }); - if (Array.isArray(newObjects)) { - newObjects.forEach(function (obj) { - if (existingObjectsIds.indexOf(obj.id) === -1) { - obj.suggested = true; - existingObjects.push(obj); - } - }); - } else { - if (existingObjectsIds.indexOf(newObjects.id) === -1) { - newObjects.suggested = true; - existingObjects.push(newObjects); - } - } - } else { - if (newObjects) { - if (Array.isArray(newObjects)) { - newObjects.forEach(function (obj) { - obj.suggested = true; - }); - existingObjects = newObjects; - } else { - newObjects.suggested = true; - existingObjects = [newObjects]; - } - } - } - return existingObjects; - }; - const fetchPlanDetails = async ( - objectType: string, - plan: any, - setFieldValue: any, - values?: any - ) => { - const fetchedPlan = await environment.model.plans.getPlan(plan[0].value); - if (objectType === 'sourcePlans') { - setObjectsWithArray( - fetchedPlan, - ['sourceUsageYears', 'sourceEmergencies'], - ['years', 'emergencies'], - setFieldValue, - values - ); - setSourceGoverningEntities(fetchedPlan.governingEntities); - } - if (objectType === 'destinationPlans') { - setObjectsWithArray( - fetchedPlan, - ['destinationUsageYears', 'destinationEmergencies'], - ['years', 'emergencies'], - setFieldValue, - values - ); - setDestinationGoverningEntities(fetchedPlan.governingEntities); - } - if (fetchedPlan.locations) { - const countries = fetchedPlan.locations.filter(function (loc: any) { - return loc.adminLevel === 0; - }); - if (countries.length === 1) { - if (objectType === 'sourcePlans') { - setObjectsWithArray( - { locations: countries }, - ['sourceLocations'], - ['locations'], - setFieldValue, - values - ); - } - if (objectType === 'destinationPlans') { - setObjectsWithArray( - { locations: countries }, - ['destinationLocations'], - ['locations'], - setFieldValue, - values - ); - } - } - } - }; - - const fetchEmergencyDetails = async ( - objectType: string, - emergency: any, - setFieldValue: any, - values?: any - ) => { - if (objectType === 'destinationEmergencies') { - const fetchedEmergency = await environment.model.emergencies.getEmergency( - emergency[0].value - ); - if (fetchedEmergency.locations.length <= 1) { - setObjectsWithArray( - fetchedEmergency, - ['destinationLocations'], - ['locations'], - setFieldValue, - values - ); - } - } - }; - const fetchProjectDetails = async ( - objectType: string, - project: any, - setFieldValue: any, - values?: any - ) => { - const fetchedProject = await environment.model.projects.getProject( - project[0].value - ); - const publishedVersion = fetchedProject.projectVersions.filter(function ( - version: any - ) { - return version.id === fetchedProject.currentPublishedVersionId; - })[0]; - if (objectType === 'destinationProjects') { - const fetchedCategories = - await environment.model.categories.getCategories({ - query: 'earmarkingType', - }); - const category = fetchedCategories.filter( - (item: any) => item.name === 'Earmarked' - ); - setFieldValue('earmarkingType', { - value: category[0], - displayLabel: category[0].name, - }); - setObjectsWithArray( - publishedVersion, - [ - 'destinationPlans', - 'destinationLocations', - 'destinationGoverningEntities', - 'destinationGlobalClusters', - 'destinationOrganizations', - ], - [ - 'plans', - 'locations', - 'governingEntities', - 'globalClusters', - 'organizations', - ], - setFieldValue, - values - ); - } else { - setObjectsWithArray( - publishedVersion, - [ - 'sourcePlans', - 'sourceLocations', - 'sourceGoverningEntities', - 'sourceGlobalClusters', - 'sourceOrganizations', - ], - [ - 'plans', - 'locations', - 'governingEntities', - 'globalClusters', - 'organizations', - ], - setFieldValue, - values - ); - } - }; - const fetchOrganizationDetails = async ( - objectType: string, - organization: any, - setFieldValue: any, - values?: any - ) => { - const fetchedOrg = - await environment.model.organizations.getOrganizationsById( - organization[0].value - ); - const isGovernment = (fetchedOrg[0].categories ?? []).some(function ( - category: any - ) { - return ( - category.group === 'organizationType' && - [114, 123].includes(category.id) - ); - }); - if (isGovernment && objectType === 'sourceOrganizations') { - objects.sourceLocations = checkIfExistingAndCopy( - objects.location, - fetchedOrg[0], - 'locations' - ); - setObjectsWithArray( - objects, - ['sourceLocations'], - ['locations'], - setFieldValue, - values - ); - } - }; - const fetchAssociatedGoverningEntity = async ( - objectType: string, - globalCluster: any, - setFieldValue: any, - values?: any - ) => { - if ( - (values.sourcePlans.length === 0 && - objectType === 'sourceGlobalClusters') || - (values.destinationPlans.length === 0 && - objectType === 'destinationGlobalClusters') - ) { - return; - } - let plan = null; - let targetGoverningEntities: any = null; - if (objectType === 'sourceGlobalClusters') { - plan = values.sourcePlans[0]; - targetGoverningEntities = values.sourceGoverningEntities; - } else { - plan = values.destinationPlans[0]; - targetGoverningEntities = values.destinationGoverningEntities; - } - const fetchedGoverningEntities = - await environment.model.governingEntities.getAllPlanGoverningEntities( - plan.value - ); - const hasGoverningEntitiesWithoutGlobalCluster = - Array.isArray(targetGoverningEntities) && - fetchedGoverningEntities - .filter(function (fetchedGe: any) { - return targetGoverningEntities.find(function (selectedGe: any) { - return fetchedGe.id === selectedGe.value; - }); - }) - .some(function (fetchedGe: any) { - return ( - Array.isArray(fetchedGe.globalClusterIds) && - !fetchedGe.globalClusterIds.length - ); - }); - - if (hasGoverningEntitiesWithoutGlobalCluster) { - return; - } - const governingEntities = fetchedGoverningEntities.filter(function ( - governingEntity: any - ) { - return ( - governingEntity.globalClusterIds.indexOf( - globalCluster[globalCluster.length - 1].value - ) > -1 - ); - }); - - if (governingEntities.length) { - governingEntities.forEach(function (governingEntity: any) { - setObjectsWithArray( - { governingEntities: governingEntity }, - [ - objectType === 'sourceGlobalClusters' - ? 'sourceGoverningEntities' - : 'destinationGoverningEntities', - ], - ['governingEntities'], - setFieldValue, - values - ); - }); - } - }; - - const fetchKeywords = async ( - objectType: string, - usageYears: any, - setFieldValue: any, - values?: any - ) => { - if (usageYears.length === 2) { - const fetchedCategories = - await environment.model.categories.getCategories({ - query: 'keywords', - }); - const category = fetchedCategories.filter( - (item: any) => item.name === 'Multiyear' - ); - - const mergedKeywords = [ - ...values.keywords, - ...[ - { - value: category[0].id, - displayLabel: category[0].name, - }, - ].filter( - (item2) => - !values.keywords.some((item1: any) => item1.value === item2.value) - ), - ]; - - setFieldValue('keywords', mergedKeywords); - } else if (usageYears.length === 1) { - const filteredKeywords = values.keywords.filter( - (item: any) => item.displayLabel !== 'Multiyear' - ); - setFieldValue('keywords', filteredKeywords); - } - }; - - const handleCompareCheck = ( - checkedVersion: VersionDataType, - isChecked: boolean - ) => { - setComparingVersions((prev: VersionDataType[]) => { - if (isChecked) { - return [...prev, checkedVersion]; - } else { - return prev.filter( - (version: VersionDataType) => - version.versionId !== checkedVersion.versionId - ); - } - }); - }; - - const fetchDownload = async (index: number) => { - const fileAssetID = - initialValue.reportDetails[index]?.reportFiles[0]?.fileAssetID; - const name = initialValue.reportDetails[index]?.reportFiles[0]?.fileName; - if (fileAssetID) { - try { - const responseData = - await environment?.model.fileUpload.fileDownloadModel(fileAssetID); - if (responseData) { - const data = new Blob([responseData]); - const url = URL.createObjectURL(data); - const a = document.createElement('a'); - a.href = url; - a.download = `${name ? name : 'downloaded_file'}`; - document.body.appendChild(a); - a.click(); - setTimeout(() => { - document.body.removeChild(a); - window.URL.revokeObjectURL(url); - }, 0); - } else { - console.error('No data received for download'); - } - } catch (error) { - console.error(error, 'error'); - } - } - }; - - const fetchCategory = useCallback( - (category: string) => { - return async () => { - const response = await environment.model.categories.getCategories({ - query: category, - }); - return response.map( - (responseValue: any): categoryType => ({ - displayLabel: responseValue.name, - value: responseValue.id.toString(), - parentID: responseValue.parentID, - }) - ); - }; - }, - [environment] - ); - const extractUniqueFromArray = (array1: string[], array2: string[]) => { - return array1.filter((item: string) => !array2.includes(item)); - }; - - const compareVersions = (versions: VersionDataType[]) => { - const version1 = versions[0]; - const version2 = versions[1]; - const newVersion1 = { - ...version1, - uniqueSources: objectTypes.reduce>( - (acc, type) => { - acc[type] = extractUniqueFromArray( - version1.source[type], - version2.source[type] - ); - return acc; - }, - {} - ), - uniqueDestinations: objectTypes.reduce>( - (acc, type) => { - acc[type] = extractUniqueFromArray( - version1.destination[type], - version2.destination[type] - ); - return acc; - }, - {} - ), - uniqueCategories: extractUniqueFromArray( - version1.categories, - version2.categories - ), - }; - - const newVersion2 = { - ...version2, - uniqueSources: objectTypes.reduce>( - (acc, type) => { - acc[type] = extractUniqueFromArray( - version2.source[type], - version1.source[type] - ); - return acc; - }, - {} - ), - uniqueDestinations: objectTypes.reduce>( - (acc, type) => { - acc[type] = extractUniqueFromArray( - version2.destination[type], - version1.destination[type] - ); - return acc; - }, - {} - ), - uniqueCategories: extractUniqueFromArray( - version2.categories, - version1.categories - ), - }; - return [newVersion1, newVersion2]; - }; - const handleFileChange = async ( - event: React.ChangeEvent, - index: number - ) => { - setUploadFlag(true); - try { - const setFile: File | undefined = (event.target as HTMLInputElement) - .files?.[0]; - if (setFile instanceof File) { - const responseData = - await environment.model.fileUpload.fileUploadModel(setFile); - setUploadedFileArray((prevUploadedFile) => { - const updateUploadedFile = [...prevUploadedFile]; - updateUploadedFile[index] = responseData; - return updateUploadedFile; - }); - console.log(uploadedFileArray, 'uploadedFileArray'); - } else { - console.error('No file selected for upload.'); - } - } catch (error) { - console.log(error, 'error'); - } - }; - useEffect(() => { - if (comparingVersions.length === 2) { - const compared = compareVersions(comparingVersions); - setComparedVersions(compared); - } - }, [comparingVersions]); - - useEffect(() => { - const handleBeforeUnload = (event: BeforeUnloadEvent) => { - if (unsavedChange) { - const message = - 'You have unsaved changes! Are you sure you want to leave?'; - event.returnValue = message; // Standard for most browsers - return message; // For some older browsers - } - }; - - window.addEventListener('beforeunload', handleBeforeUnload); - - return () => { - window.removeEventListener('beforeunload', handleBeforeUnload); - }; - }, [unsavedChange]); - - useEffect(() => { - const valuesObject: Record = { - sourceOrganizations: initialValue.sourceOrganizations, - sourceLocations: initialValue.sourceLocations, - sourceUsageYears: initialValue.sourceUsageYears, - sourceProjects: initialValue.sourceProjects, - sourcePlans: initialValue.sourcePlans, - sourceGoverningEntities: initialValue.sourceGoverningEntities, - sourceGlobalClusters: initialValue.sourceGlobalClusters, - sourceEmergencies: initialValue.sourceEmergencies, - destinationOrganizations: initialValue.destinationOrganizations, - destinationLocations: initialValue.destinationLocations, - destinationUsageYears: initialValue.destinationUsageYears, - destinationProjects: initialValue.destinationProjects, - destinationPlans: initialValue.destinationPlans, - destinationGoverningEntities: initialValue.destinationGoverningEntities, - destinationGlobalClusters: initialValue.destinationGlobalClusters, - destinationEmergencies: initialValue.destinationEmergencies, - }; - setObjects(valuesObject); - }, []); - - unstable_usePrompt({ - message: 'You have unsaved changes! Are you sure you want to leave?', - when: unsavedChange, - }); - const dictExecutedForEachObject: Record< - string, - ( - objectType: string, - flowObject: any, - setFieldValue: any, - values: any - ) => Promise - > = { - sourcePlans: fetchPlanDetails, - destinationPlans: fetchPlanDetails, - destinationEmergencies: fetchEmergencyDetails, - sourceProjects: fetchProjectDetails, - destinationProjects: fetchProjectDetails, - sourceOrganizations: fetchOrganizationDetails, - sourceGlobalClusters: fetchAssociatedGoverningEntity, - destinationGlobalClusters: fetchAssociatedGoverningEntity, - sourceUsageYears: fetchKeywords, - destinationUsageYears: fetchKeywords, - }; - - const params: DeleteFlowParams = { - VersionID: currentVersionID ?? 0, - FlowID: currentFlowID ?? 0, - }; - - const deleteFlow = async () => { - if (linkCheck || isShowParentFlow || isShowChildFlow > 0) { - window.confirm( - 'All linked flows must be unlinked before this flow can be deleted. Unlink flows and choose Delete flow again.' - ); - return; - } - - try { - const response = await env.model.flows.deleteFlow(params); - const path = flows(); - window.open(path, '_self'); - } catch (err: any) { - setOpenAlerts([...openAlerts, { message: err.message, id: alertId }]); - setAlertId((prevId) => prevId + 1); - } - }; - const updateFlowObjects = async ( - objectType: string, - flowObject: any, - setFieldValue: any, - values?: any - ) => { - if (flowObject.length > 0 && dictExecutedForEachObject[objectType]) { - flowObject.sort( - ( - a: { displayLabel: string; value: number }, - b: { displayLabel: string; value: number } - ) => { - return a.displayLabel.localeCompare(b.displayLabel); - } - ); - await dictExecutedForEachObject[objectType]( - objectType, - flowObject, - setFieldValue, - values - ); - } - if (objectType === 'sourcePlans') { - handleShowSourceGoverningEntities(flowObject.length !== 0); - } - if (objectType === 'destinationPlans') { - handleShowDestinationGoverningEntities(flowObject.length !== 0); - } - }; - const handleParentLinkedFlow = ( - values: any, - setFieldValue: any, - index: number - ) => { - setFieldValue( - 'parentFlow', - values['parentFlow'].filter((_item: any, ind: number) => ind !== index) - ); - }; - const handleChildFlow = (values: any, setFieldValue: any, index: number) => { - setFieldValue( - 'childFlow', - values['childFlow'].filter((_item: any, ind: number) => ind !== index) - ); - }; - const validateForm = (values: FormValues) => { - setUnsavedChange(JSON.stringify(values) !== JSON.stringify(initialValue)); - const valuesObject: Record = { - sourceOrganizations: values.sourceOrganizations, - sourceLocations: values.sourceLocations, - sourceUsageYears: values.sourceUsageYears, - sourceProjects: values.sourceProjects, - sourcePlans: values.sourcePlans, - sourceGoverningEntities: values.sourceGoverningEntities, - sourceGlobalClusters: values.sourceGlobalClusters, - sourceEmergencies: values.sourceEmergencies, - destinationOrganizations: values.destinationOrganizations, - destinationLocations: values.destinationLocations, - destinationUsageYears: values.destinationUsageYears, - destinationProjects: values.destinationProjects, - destinationPlans: values.destinationPlans, - destinationGoverningEntities: values.destinationGoverningEntities, - destinationGlobalClusters: values.destinationGlobalClusters, - destinationEmergencies: values.destinationEmergencies, - }; - setObjects(valuesObject); - const result = validationSchema.decode(values); - if (isRight(result)) { - setValidationFlag(false); - return {}; - } else { - const errors: Record[]> = {}; - Object.keys(values).forEach((key) => { - const value = values[key as keyof FormValues]; - if ( - result.left.some((err) => err.context.find((ctx) => ctx.key === key)) - ) { - const errorKey = key as keyof FormikErrors; - if (!value) { - errors[errorKey] = 'This field is required.'; - } else if (Array.isArray(value) && value.length === 0) { - errors[errorKey] = 'This field is required.'; - } - } - if ( - key === 'amountUSD' && - (value === 0 || (value && (value === '0' || (value as number) < 0))) - ) { - errors['amountUSD'] = 'The amount must be greater than zero.'; - } - if (key === 'flowType' && !value) { - errors['flowType'] = 'This field is required.'; - } - if (key === 'method' && !value) { - errors['method'] = 'This field is required.'; - } - if (key === 'reportDetails') { - const res = result.left.filter((err) => - err.context.find((ctx) => ctx.key === key) - )[0].value; - if (res && Array.isArray(res)) { - const reportDetailError: Record[] = []; - res.forEach((_, index) => { - const error: Record = {}; - if (res[index].reportChannel === '') { - error['reportChannel'] = 'This field is required.'; - } else { - error['reportChannel'] = ''; - } - if (!res[index].reportedDate) { - error['reportedDate'] = 'This field is required.'; - } else { - error['reportedDate'] = ''; - } - console.log(res[index], '-------------->'); - if ( - (res[index].reportFileTitle === '' || - res[index].reportFileTitle === undefined) && - (uploadedFileArray[index] && - (uploadedFileArray[index] as { id?: number })?.id - ? true - : false) - ) { - error['reportFileTitle'] = 'This field is required.'; - } else { - error['reportFileTitle'] = ''; - } - if ( - res[index].reportedOrganization === null || - res[index].reportedOrganization.displayLabel === '' - ) { - error['reportedOrganization'] = 'This field is required.'; - } else { - error['reportedOrganization'] = ''; - } - - if (Object.keys(error).length > 0) { - (reportDetailError as Record[]).push(error); - } - }); - - if (reportDetailError.length >= res.length) { - res.forEach((_, index) => { - if ( - res[index].reportChannel !== '' && - res[index].reportedOrganization !== '' && - res[index].reportedDate !== '' - ) { - if ( - (res[index].reportFileTitle === undefined || - res[index].reportFileTitle === '') && - (uploadedFileArray[index] && - (uploadedFileArray[index] as { id?: number })?.id - ? false - : true) - ) { - return {}; - } else if ( - res[index].reportFileTitle !== undefined && - res[index].reportFileTitle !== '' && - uploadedFileArray[index] - ) { - return {}; - } else { - errors['reportDetails'] = reportDetailError; - } - } else { - errors['reportDetails'] = reportDetailError; - } - }); - } - } - } - }); - console.log(errors, 'errors'); - if (Object.keys(errors).length === 0) setValidationFlag(false); - return errors; - } - }; - const handleParentFlow = ( - values: any, - parentValueString: string, - setValues: any - ) => { - parentValue = parentValueString; - const defaultValueParent: flowsResponse.GetFlowResult = - JSON.parse(parentValueString); - - const indexOrgs = defaultValueParent.organizations - .map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const indexYears = defaultValueParent.usageYears - .map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const indexLocs = defaultValueParent.locations - .map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const indexEmrs = defaultValueParent.emergencies - ?.map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const indexGlos = defaultValueParent.globalClusters - ?.map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const indexPlns = defaultValueParent.plans - ?.map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - // const indexEnt = defaultValueParent.governingEntities?.findIndex((org) => org.flowObject?.refDirection === 'destination') ?? -1; - - const indexPros = defaultValueParent.projects - ?.map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const _sourceOrganizations = indexOrgs.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: `${defaultValueParent.organizations[index].name} [${defaultValueParent.organizations[index].abbreviation}]`, - value: defaultValueParent.organizations[index].id, - }; - } - }); - const _sourceUsageYears = indexYears.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: `${defaultValueParent.usageYears[index].year}`, - value: defaultValueParent.usageYears[index].id, - }; - } - }); - const _sourceLocations = indexLocs.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: `${defaultValueParent.locations[index].name}`, - value: defaultValueParent.locations[index].id, - }; - } - }); - - const _sourceEmergencies = indexEmrs?.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: - defaultValueParent.emergencies && - `${defaultValueParent.emergencies[index].name}`, - value: - defaultValueParent.emergencies && - defaultValueParent.emergencies[index].id, - }; - } - }); - const _sourceGlobalClusters = indexGlos?.map( - (index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: - defaultValueParent.globalClusters && - `${defaultValueParent.globalClusters[index].name}`, - value: - defaultValueParent.globalClusters && - defaultValueParent.globalClusters[index].id, - }; - } - } - ); - const _sourcePlans = indexPlns?.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: - defaultValueParent.plans && - `${defaultValueParent.plans[index].planVersion.name}`, - value: defaultValueParent.plans && defaultValueParent.plans[index].id, - }; - } - }); - const _sourceProjects = indexPros?.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: - defaultValueParent.projects && - `${defaultValueParent.projects[index].projectVersions[index].name}`, - value: - defaultValueParent.projects && - defaultValueParent.projects[index].id, - }; - } - }); - - setValues({ - ...values, - sourceOrganizations: _sourceOrganizations, - sourceUsageYears: _sourceUsageYears, - sourceLocations: _sourceLocations, - sourceEmergencies: _sourceEmergencies, - sourceGlobalClusters: _sourceGlobalClusters, - sourcePlans: _sourcePlans, - // sourceGoverningEntities: _sourceGoverningEntities ? [_sourceGoverningEntities] : [], - sourceProjects: _sourceProjects, - }); - }; - return ( - - handleSubmit(values, values.submitAction) - } - validate={(values) => validateForm(values)} - enableReinitialize - validateOnChange={false} - style={{ zIndex: 1 }} - > - {({ values, setFieldValue, setValues }) => { - if (values.parentFlow && values.parentFlow[0]) { - const parentValueString = String( - values.parentFlow && - values.parentFlow[0] && - values.parentFlow[0].value - ); - if (parentValue !== parentValueString) { - handleParentFlow(values, parentValueString, setValues); - } - } - return ( -
- - - - - - - - - - - - - - - - - - UN Treasury rates - - - { - handleCalculateExchangeRate(values, setFieldValue); - }} - color="primary" - text={buttonText} - > - - - - - - - - - - - - - - - - {(values.method as categoryType).displayLabel === - 'Cash transfer programming (CTP)' && ( - - )} - - - - - - -
- ); - }} -
- ); -}; -export default FLowsInfo; diff --git a/apps/hpc-ftsadmin/src/app/components/flow-form-rewrite/index.tsx b/apps/hpc-ftsadmin/src/app/components/flow-form-rewrite/index.tsx deleted file mode 100644 index 211342458..000000000 --- a/apps/hpc-ftsadmin/src/app/components/flow-form-rewrite/index.tsx +++ /dev/null @@ -1,2852 +0,0 @@ -import React, { useState, useEffect, useCallback } from 'react'; -import { Form, Formik } from 'formik'; -import tw from 'twin.macro'; -import dayjs from 'dayjs'; -import { isRight } from 'fp-ts/Either'; -import { FormikErrors } from 'formik'; -import * as t from 'io-ts'; -import { util as codecs } from '@unocha/hpc-data'; -import Button from '@mui/material/Button'; -import DeleteIcon from '@mui/icons-material/Delete'; -import Stack from '@mui/material/Stack'; -import ContentCopyIcon from '@mui/icons-material/ContentCopy'; -import MuiAlert from '@mui/material/Alert'; -import AlertTitle from '@mui/material/AlertTitle'; -import _ from 'lodash'; -import useSharePath from '../Hooks/SharePath'; -import { C, dialogs } from '@unocha/hpc-ui'; -import { Alert, IconButton } from '@mui/material'; -import CloseIcon from '@mui/icons-material/Close'; -import { Environment } from '../../../environments/interface'; -import { MdClose, MdCheck } from 'react-icons/md'; -import { - usageYears, - forms, - governingEntities, - fileUpload, - data, - fundingObject, - flows as flowsResponse, -} from '@unocha/hpc-data'; -import { getEnv } from '../../context'; -import { editFlowSetting, copyFlow } from '../../paths'; -import { flows } from '../../paths'; -import { useNavigate, unstable_usePrompt } from 'react-router-dom'; -import FlowSource from './flow-source'; -import FlowDestination from './flow-destination'; -import LinkedFlows from './linked-flows'; -import ReportingDetails from './reporting-details'; -import PreviousReportingDetails from './previous-reporting-details'; -import FlowVersions from './flow-versions'; -import FLowsInfo from './flows'; -import { FlowContextProvider } from './flow-context'; - -type FlowObjectType = - | 'organization' - | 'governingEntity' - | 'location' - | 'project' - | 'usageYear' - | 'globalCluster' - | 'emergency' - | 'plan'; - -export type AutoCompleteSelectionType = forms.InputSelectValueType; - -const INPUT_SELECT_VALUE_TYPE = forms.INPUT_SELECT_VALUE_TYPE; - -type UniqueDataType = { - [key: string]: string[]; -}; -type Data = data.dataType & fundingObject.fundingObjectType; -export interface DeleteFlowParams { - VersionID: number; - FlowID: number; -} - -interface CollapsedFlowObject { - refDirection: string; - objectType: string; - objectID: number | string; - behavior: string | null; - objectDetail?: string | null; -} - -interface FlowObject { - implementingPartner: string | null | undefined; - id: number; - name: string; - behavior?: string; - objectDetail?: string | null; - cleared?: boolean; - restricted?: boolean; -} - -interface FORM_FIELD { - value?: string | number; - displayLabel?: string; - id: number | string; - name: string; - behavior?: string; - objectDetail?: string | null; - cleared?: boolean; - restricted?: boolean | undefined; - implementingPartner?: string | null; -} - -interface SourceOrDestination { - governingEntity: FORM_FIELD[]; - location: FORM_FIELD[]; - organization: FORM_FIELD[]; - project: FORM_FIELD[]; - usageYear: FORM_FIELD[]; - globalCluster: FORM_FIELD[]; - emergency: FORM_FIELD[]; - plan: FORM_FIELD[]; -} - -export interface categoryType { - value: string | number; - displayLabel: string; - parentID: number | null; -} - -export interface FileAssetEntityType { - collection?: string; - createAt?: string; - filename?: string; - id?: number; - mimetype?: string; - originalname?: string; - path?: string; - size?: number; - updatedAt?: string; -} -export interface ReportFileType { - title?: string; - fileName?: string; - UploadFileUrl?: string; - type?: string; - url?: string; - fileAssetID?: number; - size?: number; - fileAssetEntity?: FileAssetEntityType; -} -export interface ReportDetailType { - verified: string; - reportSource: string; - reporterReferenceCode: string; - reportChannel: AutoCompleteSelectionType | ''; - reportedOrganization: AutoCompleteSelectionType; - reportedDate: string; - reporterContactInformation: string; - sourceSystemRecordId: string; - reportFiles: ReportFileType[]; - reportFileTitle?: string; - reportUrlTitle?: string; - reportUrl?: string; - versionId?: number; - fileAsset?: FileAssetEntityType; -} - -export interface ParentFlowType { - value: any; -} - -export interface FormValues { - id: string | null; - amountUSD: number; - keywords: AutoCompleteSelectionType[]; - flowStatus: AutoCompleteSelectionType | ''; - flowType: AutoCompleteSelectionType | ''; - flowDescription: string; - firstReported: string; - decisionDate: string | null; - budgetYear: string; - flowDate: string; - contributionType: AutoCompleteSelectionType | ''; - earmarkingType: AutoCompleteSelectionType | ''; - method: AutoCompleteSelectionType | ''; - cashTransfer: AutoCompleteSelectionType | ''; - beneficiaryGroup: AutoCompleteSelectionType | ''; - inactiveReason: any[] | string; - childMethod: object; - origCurrency: AutoCompleteSelectionType | string; - amountOriginal: number | null; - exchangeRateUsed: number | null; - notes: string; - sourceOrganizations: AutoCompleteSelectionType[]; - sourceLocations: AutoCompleteSelectionType[]; - sourceUsageYears: AutoCompleteSelectionType[]; - sourceProjects: AutoCompleteSelectionType[]; - sourcePlans: AutoCompleteSelectionType[]; - sourceGoverningEntities: AutoCompleteSelectionType[]; - sourceGlobalClusters: AutoCompleteSelectionType[]; - sourceEmergencies: AutoCompleteSelectionType[]; - destinationOrganizations: AutoCompleteSelectionType[]; - destinationLocations: AutoCompleteSelectionType[]; - destinationUsageYears: AutoCompleteSelectionType[]; - destinationProjects: AutoCompleteSelectionType[]; - destinationPlans: AutoCompleteSelectionType[]; - destinationGoverningEntities: AutoCompleteSelectionType[]; - destinationGlobalClusters: AutoCompleteSelectionType[]; - destinationEmergencies: AutoCompleteSelectionType[]; - reportDetails: ReportDetailType[]; - parentFlow?: AutoCompleteSelectionType[]; - childFlow?: AutoCompleteSelectionType[]; - isParkedParent?: boolean; - includeChildrenOfParkedFlows: boolean; - isErrorCorrectionValue: boolean; - sources?: Record; - submitAction?: string | undefined; - versions?: { - id: number | null; - isPending: boolean | null; - }[]; -} - -export interface VersionDataType { - versionId: number; - flowId: number; - createdTime: string; - createdBy: string | null; - updatedTime: string; - updatedBy: string | null; - active: boolean; - viewing: boolean; - pending?: boolean; - [key: string]: - | string - | number - | null - | boolean - | string[] - | Date - | undefined - | Record; - source: UniqueDataType; - destination: UniqueDataType; - categories: string[]; - uniqueSources: UniqueDataType; - uniqueDestinations: UniqueDataType; - uniqueCategories: string[]; - restricted?: boolean; -} - -export interface InputEntriesType { - amountUSD: forms.InputEntryType | null; - origCurrency: forms.InputEntryType | null; - keywords: forms.InputEntryType | null; - flowStatus: forms.InputEntryType | null; - flowType: forms.InputEntryType | null; - flowDescription: forms.InputEntryType | null; - contributionType: forms.InputEntryType | null; - earmarkingType: forms.InputEntryType | null; - method: forms.InputEntryType | null; - beneficiaryGroup: forms.InputEntryType | null; - inactiveReason: forms.InputEntryType | null; - amountOriginal: forms.InputEntryType | null; - exchangeRateUsed: forms.InputEntryType | null; - notes: forms.InputEntryType | null; - sourceOrganizations: forms.InputEntryType[]; - sourceLocations: forms.InputEntryType[]; - sourceUsageYears: forms.InputEntryType[]; - sourceProjects: forms.InputEntryType[]; - sourcePlans: forms.InputEntryType[]; - sourceGoverningEntities: forms.InputEntryType[]; - sourceGlobalClusters: forms.InputEntryType[]; - sourceEmergencies: forms.InputEntryType[]; - destinationOrganizations: forms.InputEntryType[]; - destinationLocations: forms.InputEntryType[]; - destinationUsageYears: forms.InputEntryType[]; - destinationProjects: forms.InputEntryType[]; - destinationPlans: forms.InputEntryType[]; - destinationGoverningEntities: forms.InputEntryType[]; - destinationGlobalClusters: forms.InputEntryType[]; - destinationEmergencies: forms.InputEntryType[]; - parentFlow: forms.InputEntryType | null; - childFlow: forms.InputEntryType[]; -} - -type UploadedItem = fileUpload.FileUploadResult | FileAssetEntityType; - -const reportChannelSchema = t.type({ - value: t.intersection([codecs.NON_EMPTY_STRING, t.string]), - displayLabel: t.intersection([codecs.NON_EMPTY_STRING, t.string]), -}); - -const reportDetailsSchema = t.type({ - reportedOrganization: INPUT_SELECT_VALUE_TYPE, - reportedDate: t.intersection([codecs.NON_EMPTY_STRING, t.string]), - reportChannel: t.intersection([codecs.NON_EMPTY_STRING, reportChannelSchema]), - reportFileTitle: t.intersection([codecs.NON_EMPTY_STRING, t.string]), -}); - -const validationSchema = t.type({ - amountUSD: t.number, - flowStatus: INPUT_SELECT_VALUE_TYPE, - flowDescription: t.intersection([codecs.NON_EMPTY_STRING, t.string]), - firstReported: t.string, - flowDate: t.intersection([codecs.NON_EMPTY_STRING, t.string]), - sourceOrganizations: INPUT_SELECT_VALUE_TYPE, - sourceUsageYears: INPUT_SELECT_VALUE_TYPE, - destinationOrganizations: INPUT_SELECT_VALUE_TYPE, - destinationUsageYears: INPUT_SELECT_VALUE_TYPE, - reportDetails: reportDetailsSchema, -}); - -interface Props { - currentVersionData: flowsResponse.FlowREST | null; - environment: Environment; - isEdit: boolean; - initialValue: FormValues; - prevDetails?: ReportDetailType[]; - versionData?: VersionDataType[]; - flowId?: string; - versionId?: string; - isRestricted: boolean; - errorCorrection?: boolean; - inputEntries: InputEntriesType; - initializeInputEntries: () => void; - rejectInputEntry: (key: string) => void; - currentVersionID?: number; - currentFlowID?: number; - currentVersionActiveStatus?: boolean; - isPending?: boolean; - isSuperseded?: boolean; - isCancelled?: boolean; - isCancellation?: boolean; - isNewPending?: boolean; - isUpdatePending?: boolean; - canReactive?: boolean; - isErrorCorrection?: boolean | null; - isApprovedFlowVersion?: boolean | null; - pendingFieldsAllApplied?: boolean; - allFieldsReviewed?: boolean; - pendingVersionV1?: boolean; -} - -const StyledRepOrgLink = tw.div` - flex - ml-1 -`; - -const StyledAddChildWarning = tw.div` - border border-solid border-yellow-600 - flex - rounded-md - text-gray-900 - bg-yellow-100 bg-opacity-50 -`; - -const StyledAddChildWarningIconDiv = tw.div` - flex - items-center - p-1 -`; -const StyledAddChildWarningText = tw.span` - py-3 px-3 pb-3 -`; -const StyledLayoutRow = tw.div` -flex -`; -const StyledHalfSection = tw.div` -w-1/2 -`; -const StyledFullSection = tw.div` -w-full -mb-6 -`; -const StyledRow = tw.div` -flex -gap-4 -w-full -`; -const StyledFormRow = tw.div` -flex -gap-2 -w-full -items-center -`; -const StyledAnchor = tw.a` -underline -ml-[15px] -opacity-100 -`; -const StyledAnchorDiv = tw.div` -text-right -w-full -`; -const StyledRadioDiv = tw.div` -relative -w-full -`; -const StyledFieldset = tw.fieldset` -w-full -box-border -rounded-xl -mt-[16px] -mb-[8px] -border-gray-100 -`; -const StyledCurrencyRow = tw.div` -w-1/2 -`; -const StyledFormButton = tw(C.Button)` -ml-[25px] -mb-6 -`; -const StyledLabel = tw.label` -block -my-4 -`; -const StyledLinkedFlowRow = tw.div` -mt-4 -`; - -const StyledParentInfo = tw.div` -border-0 -border-b -border-solid -cursor-pointer -mb-4 -pb-4 -`; - -const StyledStrong = tw.strong` -min-w-[16rem] -inline-block -`; - -const StyledList = tw.li` -list-none -`; - -const StyledDiv = tw.div` -my-6 -me-4 -mr-[23px] -lg:flex -justify-end -gap-x-4 -bg-white -z-10 -`; - -const initialReportDetail = { - verified: 'verified', - reportSource: 'primary', - reporterReferenceCode: '', - reportChannel: '', - reportFileTitle: '', - reportedOrganization: { value: '', displayLabel: '' }, - reportedDate: dayjs().format('DD/MM/YYYY'), - reporterContactInformation: '', - sourceSystemRecordId: '', -}; - -const FORM_SETTINGS = { - organization: { - behavior: 'shared', - }, - project: { - behavior: 'overlap', - }, - usageYear: { - behavior: 'shared', - }, - location: { - behavior: 'shared', - }, - globalCluster: { - behavior: 'shared', - }, - emergency: { - behavior: 'overlap', - }, - governingEntity: { - behavior: 'shared', - }, - plan: { - behavior: 'overlap', - }, -}; - -const objectTypes = [ - 'emergencies', - 'projects', - 'usageYears', - 'globalClusters', - 'locations', - 'plans', - 'organizations', -] as const; - -const flowValuesForDisplay = [ - 'amountUSD', - 'flowDate', - 'decisionDate', - 'firstReportedDate', - 'budgetYear', - 'origAmount', - 'origCurrency', - 'exchangeRate', - 'activeStatus', - 'restricted', - 'newMoney', - 'description', - 'notes', -] as const; - -let parentValue = ''; - -export const FlowRewriteForm = (props: Props) => { - const { - currentVersionData, - environment, - initialValue, - isEdit, - prevDetails, - versionData, - isRestricted, - errorCorrection, - inputEntries, - flowId, - versionId, - initializeInputEntries, - rejectInputEntry, - currentVersionID, - currentFlowID, - currentVersionActiveStatus, - isPending, - isSuperseded, - isCancelled, - isCancellation, - isNewPending, - isUpdatePending, - canReactive, - pendingFieldsAllApplied, - allFieldsReviewed, - pendingVersionV1, - } = props; - const { confirm } = dialogs; - const env = getEnv(); - const collapseFlowObjects = ( - data: fundingObject.fundingObjectType - ): FlowObject[] => { - const flowObjects: FlowObject[] = []; - - const collapsePerBehavior = ( - behaviorArr: SourceOrDestination, - ref: 'source' | 'destination' - ) => { - (Object.keys(behaviorArr) as FlowObjectType[]).forEach((type) => { - behaviorArr[type].forEach((obj) => { - if ( - obj !== null && - (!Object.prototype.hasOwnProperty.call(obj, 'cleared') || - !obj.cleared) - ) { - if (type === 'organization') { - obj.objectDetail = obj.implementingPartner ? 'partner' : null; - } - - const flowObj: CollapsedFlowObject = { - refDirection: ref, - objectType: type, - objectID: obj.id, - behavior: obj.behavior || null, - objectDetail: obj.objectDetail, - }; - flowObjects.push(flowObj as unknown as FlowObject); - } - }); - }); - }; - - collapsePerBehavior(data.dest, 'destination'); - collapsePerBehavior(data.src, 'source'); - - return flowObjects; - }; - const collapseCategories = (data: Data) => { - const categorySources = [ - data.flowType, - data.flowStatuses, - data.contributionTypes, - data.method, - data.childMethod, - data.keywords, - data.inactiveReason, - data.beneficiaryGroup, - data.pendingStatus ? { id: data.pendingStatus } : null, - data.earmarking?.id ? { id: data.earmarking.id } : null, - ]; - - data.categories = categorySources - .flatMap((category) => { - if (Array.isArray(category)) { - return category.map((item) => - typeof item === 'object' && 'id' in item ? item.id : null - ); - } else if ( - category && - typeof category === 'object' && - 'id' in category - ) { - return [category.id]; - } else if ( - typeof category === 'string' || - typeof category === 'number' - ) { - return [category]; - } else { - return []; - } - }) - .filter((id): id is string | number => id !== undefined && id !== null); - - return data; - }; - const [uploadFileFlag, setUploadFileFlag] = useState(false); - const [uploadFlag, setUploadFlag] = useState(false); - const normalizeFlowData = (values: FormValues) => { - const fundingObject: fundingObject.fundingObjectType = { - src: { - governingEntity: values.sourceGoverningEntities.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - location: values.sourceLocations.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - organization: values.sourceOrganizations.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - project: values.sourceProjects.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - usageYear: values.sourceUsageYears.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - globalCluster: values.sourceGlobalClusters.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - emergency: values.sourceEmergencies.map((item) => ({ - id: item.value, - name: item.displayLabel, - restricted: item.restricted, - })), - plan: values.sourcePlans.map((item) => ({ - id: item.value, - name: item.displayLabel, - restricted: item.restricted, - })), - }, - dest: { - governingEntity: values.destinationGoverningEntities.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - location: values.destinationLocations.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - organization: values.destinationOrganizations.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - project: values.destinationProjects.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - usageYear: values.destinationUsageYears.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - globalCluster: values.destinationGlobalClusters.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - emergency: values.destinationEmergencies.map((item) => ({ - id: item.value, - name: item.displayLabel, - restricted: item.restricted, - })), - plan: values.destinationPlans.map((item) => ({ - id: item.value, - name: item.displayLabel, - restricted: item.restricted, - })), - }, - }; - - const data: Data = { - id: isEdit && currentFlowID ? currentFlowID : null, - versionID: isEdit && currentVersionID ? currentVersionID : null, - amountUSD: values.amountUSD, - flowDate: dayjs(values.flowDate, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ), - decisionDate: values.decisionDate - ? dayjs(values.decisionDate, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ) - : null, - firstReportedDate: dayjs(values.firstReported, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ), - budgetYear: values.budgetYear, - origAmount: values.amountOriginal ? values.amountOriginal : null, - origCurrency: (values.origCurrency as AutoCompleteSelectionType) - ? (values.origCurrency as AutoCompleteSelectionType)?.displayLabel - : null, - exchangeRate: values.exchangeRateUsed ? values.exchangeRateUsed : null, - activeStatus: true, - restricted: false, - newMoney: true, - description: values.flowDescription, - versionStartDate: currentVersionData?.versionStartDate, - versionEndDate: currentVersionData?.versionEndDate, - flowObjects: collapseFlowObjects( - fundingObject as fundingObject.fundingObjectType - ), - children: - values.childFlow && - values.childFlow.map((item: any, index: number) => { - return { - childID: JSON.parse(item.value as string).id, - origCurrency: JSON.parse(item.value as string).origCurrency, - }; - }), - parents: - values.parentFlow && - values.parentFlow.map((item: any, index: number) => { - return { - Parent: { - parentID: JSON.parse(item.value as string).id, - origCurrency: JSON.parse(item.value as string).origCurrency, - }, - childID: currentFlowID, - parentID: JSON.parse(item.value as string).id, - origCurrency: JSON.parse(item.value as string).origCurrency, - id: JSON.parse(item.value as string).id, - parents: - values.parentFlow && - values.parentFlow.map((key: any) => { - return { - child: JSON.parse(key.value as string).id, - parentID: 271736, - }; - }), - }; - }), - reportDetails: values.reportDetails.map((item, index) => { - return { - contactInfo: item.reporterContactInformation, - source: item.reportSource, - date: dayjs(item.reportedDate, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ), - versionID: currentVersionID, - newlyAdded: addReportFlag, - sourceID: null, - refCode: '7F-10073.04', - verified: true, - organizationID: item.reportedOrganization.value, - categories: [item.reportChannel && item.reportChannel.value], - organization: { - id: item.reportedOrganization.value, - name: item.reportedOrganization.displayLabel, - }, - reportFiles: - uploadFlag && - uploadedFileArray[index] && - (uploadedFileArray[index] as { id?: number })?.id - ? uploadFlag || uploadFileFlag - ? [ - { - title: item.reportUrlTitle, - type: 'url', - url: item.reportUrl, - }, - { - fileAssetID: - uploadedFileArray[index] && - (uploadedFileArray[index] as { id?: number })?.id, - reportFiles: [ - { - fieldType: 'file', - fileAssetID: - uploadedFileArray[index] && - (uploadedFileArray[index] as { id?: number })?.id, - type: 'file', - }, - ], - title: item.reportFileTitle, - type: 'file', - }, - ] - : [ - { - title: item.reportUrlTitle, - type: 'url', - url: item.reportUrl, - }, - ] - : uploadFileFlag - ? [ - { - title: item.reportUrlTitle, - type: 'url', - url: item.reportUrl, - }, - ] - : item.reportFiles - ? item.reportFiles - : [], - - reportChannel: { - group: 'reportChannel', - id: item.reportChannel && item.reportChannel.value, - name: item.reportChannel && item.reportChannel.displayLabel, - }, - }; - }), - flowType: { - id: values.flowType && values.flowType.value, - name: values.flowType && values.flowType.displayLabel, - group: 'flowType', - }, - keywords: values.keywords.map((item) => ({ - id: item.value, - name: item.displayLabel, - group: 'keywords', - })), - flowStatuses: { - id: values.flowStatus && values.flowStatus.value, - name: values.flowStatus && values.flowStatus.displayLabel, - group: 'flowStatus', - }, - contributionTypes: { - id: values.contributionType && values.contributionType.value, - name: values.contributionType && values.contributionType.displayLabel, - group: 'contributionType', - }, - method: { - id: values.method && values.method.value, - name: values.method && values.method.displayLabel, - group: 'method', - }, - childMethod: values.cashTransfer && { - id: values.cashTransfer.value, - name: values.cashTransfer.displayLabel, - group: 'method', - parentID: values.method && values.method.value, - }, - earmarking: values.earmarkingType - ? { - id: values.earmarkingType.value, - name: values.earmarkingType.displayLabel, - group: 'earmarkingType', - } - : null, - categories: [] as (string | number)[], - isCancellation: isPending ? true : !isPending ? false : null, - cancelled: isPending && isCancellation ? true : null, - pendingStatus: isPending ? true : !isPending ? false : [], - planEntities: isPending ? true : !isPending ? false : [], - planIndicated: isPending ? true : !isPending ? false : [], - isApprovedFlowVersion: - rejectFlag && approveFlag - ? true - : !(rejectFlag && approveFlag) - ? false - : null, - inactiveReason: [ - { - id: null as null | number | string, - name: '' as string | undefined, - description: null, - parentID: null, - code: null, - group: '', - includeTotals: null, - createdAt: '', - updatedAt: '', - }, - ], - isErrorCorrection: errorCorrection - ? true - : isSuperseded - ? true - : isPending - ? true - : !isSuperseded && !isPending - ? false - : null, - rejected: rejectFlag ? true : !rejectFlag ? false : null, - versions: versionData?.map((item: VersionDataType) => ({ - id: item.flowId, - versionID: item.versionId, - activeStatus: - item.activeStatus === null ? undefined : item.activeStatus, - isPending: item.isPending ?? false, - isCancelled: item.isCancelled ?? false, - })) as { - id: number; - versionID: number; - activeStatus: boolean | undefined; - isPending: boolean; - isCancelled: boolean; - }[], - ...fundingObject, - }; - return collapseCategories(data); - }; - - const [unsavedChange, setUnsavedChange] = useState(false); - const [parentCurrencyFlag, setParentCurrencyFlag] = useState(false); - const [childCurrencyFlag, setChildCurrencyFlag] = useState(false); - const [approveFlag, setApproveFlag] = useState(false); - const [rejectFlag, setRejectFlag] = useState(false); - const [validationFlag, setValidationFlag] = useState(false); - const [inactiveFlag, setInactiveFlag] = useState(false); - const [uploadedFileArray, setUploadedFileArray] = useState([ - {}, - ]); - const [addReportFlag, setAddReportFlag] = useState(false); - const [alertFlag, setAlertFlag] = useState(false); - const [sharePath, setSharePath] = useSharePath(''); - const [readOnly, setReadOnly] = useState(false); - const [linkCheck, setLinkCheck] = useState(false); - const handleSave = () => { - window.scrollTo({ top: 0, behavior: 'smooth' }); - }; - - const [showWarningMessage, setShowWarningMessage] = useState(false); - const [objects, setObjects] = useState>({}); - const [showingTypes, setShowingTypes] = useState([]); - const [newMoneyCheckboxDisabled, setNewMoneyCheckboxDisabled] = - useState(false); - - const [comparingVersions, setComparingVersions] = useState( - [] - ); - const [comparedVersions, setComparedVersions] = useState( - [] - ); - const [showSourceGoverningEntities, handleShowSourceGoverningEntities] = - useState(false); - const [ - showDestinationGoverningEntities, - handleShowDestinationGoverningEntities, - ] = useState(false); - const [sourceGoverningEntities, setSourceGoverningEntities] = - useState([]); - const [destinationGoverningEntities, setDestinationGoverningEntities] = - useState([]); - const [isShowParentFlow, setShowParentFlow] = useState( - initialValue.parentFlow && initialValue.parentFlow.length ? true : false - ); - const [isShowChildFlow, setShowChildFlow] = useState(0); - const [openAlerts, setOpenAlerts] = useState< - { message: string; id: number }[] - >([]); - const [alertId, setAlertId] = useState(0); - const handleClose = (id: number) => { - setOpenAlerts(openAlerts.filter((alert) => alert.id !== id)); - }; - - useEffect(() => { - if (initialValue?.childFlow) { - setShowChildFlow(initialValue?.childFlow.length); - } - }, [initialValue]); - useEffect(() => { - const fileAssets: FileAssetEntityType[] = []; - if (isEdit) { - initialValue.reportDetails.forEach((detail) => { - if (detail?.fileAsset) { - fileAssets.push(detail.fileAsset); - setUploadedFileArray(fileAssets); - } else { - fileAssets.push({} as FileAssetEntityType); - setUploadedFileArray(fileAssets); - } - }); - } - }, [initialValue.reportDetails]); - useEffect(() => { - if (currentVersionActiveStatus) { - setReadOnly(false); - } else { - setReadOnly(true); - } - }, [currentVersionActiveStatus]); - useEffect(() => { - if (initialValue.parentFlow && initialValue.parentFlow.length) { - setShowParentFlow(true); - } - }, [initialValue.parentFlow]); - const [remove, setRemove] = useState(false); - - const removeByIndexFromArray = (array: UploadedItem[], index: number) => { - const newArray = [...array]; - newArray[index] = {}; - return newArray; - }; - if (remove === true) setRemove(false); - interface Inconsistency { - type: string; - values: { - name?: string; - year?: string; - refDirection: string; - options?: { name: string }[]; - }[]; - } - - const processDataInconsistencies = ( - inconsistencyArray: Inconsistency[] - ): string => { - let message = ''; - inconsistencyArray.forEach((inconsistencyWith) => { - if (inconsistencyWith && inconsistencyWith.type) { - const inconsistencyType = inconsistencyWith.type; - message += - inconsistencyType.charAt(0).toUpperCase() + - inconsistencyType.slice(1) + - ': '; - - if (inconsistencyWith.type === 'no-direct-link') { - message += inconsistencyWith.values.join(', '); - } else { - message += - inconsistencyWith.values - .map((value) => { - const name = value.name || value.year; - let joinedOptions = ''; - if (value.options) { - joinedOptions = value.options - .map((option) => { - return option.name || JSON.stringify(option); - }) - .join(', '); - } - const options = `is not in the list of acceptable ${value.refDirection} ${inconsistencyType}: [${joinedOptions}]`; - return `'${name}' ${options}`; - }) - .join(', ') + '. '; - } - } else { - message += JSON.stringify(inconsistencyArray); - } - }); - return message; - }; - - const handleSubmit = async ( - values: FormValues, - submitAction: string | undefined - ) => { - if (values.childFlow) { - for (let i = 0; i < values.childFlow.length; i++) { - if ( - values.destinationUsageYears.length >= 2 && - JSON.parse(values.childFlow[i].value as string).activeStatus === true - ) { - values.flowType = { - displayLabel: 'Parked', - value: '1252', - }; - } - } - } - if (isShowParentFlow && isShowChildFlow > 0) { - let childAmountSum = 0; - let parentAmountSum = 0; - values.childFlow && - values.childFlow.map((item, _index) => { - childAmountSum += JSON.parse(item.value.toString()) - ? parseInt(JSON.parse(item.value.toString()).amountUSD) - : 0; - }); - values.parentFlow && - values.parentFlow.map((item, _index) => { - parentAmountSum += JSON.parse(item.value.toString()) - ? parseInt(JSON.parse(item.value.toString()).amountUSD) - : 0; - }); - if (childAmountSum > parentAmountSum) { - if ( - !window.confirm( - `Please note, the Funding Amount on this parent flow ($${parentAmountSum}) is less than the sum of its children's amount ($${childAmountSum}). Do you want to proceed?` - ) - ) { - return; - } - } - } - if (isShowParentFlow || isShowChildFlow > 0) { - let childAmountSum = 0; - values.childFlow && - values.childFlow.map((item, _index) => { - childAmountSum += JSON.parse(item.value.toString()) - ? parseInt(JSON.parse(item.value.toString()).amountUSD) - : 0; - }); - if (childAmountSum > values.amountUSD) { - if ( - !window.confirm( - `Please note, the Funding Amount on this parent flow ($${values.amountUSD}) is less than the sum of its children's amount ($${childAmountSum}). Do you want to proceed?` - ) - ) - return; - } - } - const parentFlow = values.parentFlow; - if (parentFlow?.length) { - for (let index = 0; index < parentFlow.length; index++) { - const item = parentFlow[index]; - if ( - (typeof values?.origCurrency !== 'string' && - values.origCurrency?.displayLabel) || - !( - JSON.parse(item.value.toString()) && - JSON.parse(item.value.toString())?.origCurrency === null - ) - ) { - if ( - (typeof values?.origCurrency !== 'string' && - values.origCurrency?.displayLabel) !== - (JSON.parse(item.value.toString()) && - JSON.parse(item.value.toString())?.origCurrency) - ) { - handleSave(); - setParentCurrencyFlag(true); - return; - } - } - } - } - const childFlow = values.childFlow; - if (childFlow) { - for (let index = 0; index < childFlow.length; index++) { - const item = childFlow[index]; - if ( - (typeof values?.origCurrency !== 'string' && - values.origCurrency?.displayLabel) || - !( - JSON.parse(item.value.toString()) && - JSON.parse(item.value.toString())?.origCurrency === null - ) - ) { - if ( - (typeof values.origCurrency !== 'string' && - values.origCurrency?.displayLabel) !== - (JSON.parse(item.value.toString()) && - JSON.parse(item.value.toString()).origCurrency) - ) { - handleSave(); - setChildCurrencyFlag(true); - return; - } - } - } - } - for (let i = 0; i < values.reportDetails.length; i++) { - if ( - values.reportDetails[i].reportUrlTitle && - values.reportDetails[i].reportUrl - ) { - setUploadFileFlag(true); - } else setUploadFileFlag(false); - } - const data = normalizeFlowData(values); - const inactiveReasons = await fetchCategory('inactiveReason')(); - if (submitAction === 'approve') { - data.isApprovedFlowVersion = true; - } else if (submitAction === 'rejected') { - data.activeStatus = false; - data.rejected = true; - data.inactiveReason = [ - { - id: - inactiveReasons.find((item) => item.displayLabel === 'Rejected') - ?.value || null, - name: inactiveReasons.find((item) => item.displayLabel === 'Rejected') - ?.displayLabel, - description: null, - parentID: null, - code: null, - group: 'inactiveReason', - includeTotals: null, - createdAt: currentVersionData - ? dayjs(currentVersionData.createdAt, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ) - : '', - updatedAt: currentVersionData - ? dayjs(currentVersionData.updatedAt, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ) - : '', - }, - ]; - } else if (submitAction === 'inactive') { - if (isShowParentFlow || isShowChildFlow > 0) { - setInactiveFlag(true); - } else { - const categoryValue = - inactiveReasons.find((item) => item.displayLabel === 'Cancelled') - ?.value ?? null; - if (categoryValue) { - data.categories.push(parseInt(categoryValue.toString())); - } - data.activeStatus = false; - data.cancelled = true; - data.isCancellation = null; - data.rejected = null; - data.newMoney = false; - data.inactiveReason = [ - { - id: - inactiveReasons.find((item) => item.displayLabel === 'Cancelled') - ?.value || null, - name: inactiveReasons.find( - (item) => item.displayLabel === 'Cancelled' - )?.displayLabel, - description: null, - parentID: null, - code: null, - group: 'inactiveReason', - includeTotals: null, - createdAt: currentVersionData ? currentVersionData.createdAt : '', - updatedAt: currentVersionData ? currentVersionData.updatedAt : '', - }, - ]; - } - } - if (!inactiveFlag) { - const response = await env.model.flows.validateFlow(data); - let flag = true; - let mismatchFound = false; - for (let i = 0; i < values.reportDetails.length; i++) { - const reportOrganizationLabel = - values.reportDetails[i].reportedOrganization.displayLabel; - const reportMatchesSource = values.sourceOrganizations.some( - (sourceOrg) => sourceOrg.displayLabel === reportOrganizationLabel - ); - const reportMatchesDestination = values.destinationOrganizations.some( - (destOrg) => destOrg.displayLabel === reportOrganizationLabel - ); - - if (!reportMatchesSource && !reportMatchesDestination) { - mismatchFound = true; - break; - } - } - if (mismatchFound) { - if ( - !window.confirm( - "Your flow's Report Detail organization doesn't match the source or destination organization or that of its parked parent. Are you sure this is right?" - ) - ) { - return; - } - } - response.forEach((obj) => { - if (obj) { - const { success, message, confirmed } = obj; - if (!success) { - if (confirmed) { - const confirm = window.confirm(confirmed); - if (!confirm) { - setOpenAlerts([...openAlerts, { message, id: alertId }]); - setAlertId((prevId) => prevId + 1); - flag = false; - handleSave(); - } - } else if (message) { - setOpenAlerts([...openAlerts, { message, id: alertId }]); - setAlertId((prevId) => prevId + 1); - flag = false; - handleSave(); - } - } - } - }); - if (flag && !(isShowParentFlow || isShowChildFlow > 0)) { - setUnsavedChange(false); - if (!isEdit) { - try { - const response = await env.model.flows.createFlow({ flow: data }); - const path = editFlowSetting(response.id, response.versionID); - window.open(path, '_self'); - } catch (err: any) { - setOpenAlerts([ - ...openAlerts, - { message: err.message, id: alertId }, - ]); - setAlertId((prevId) => prevId + 1); - handleSave(); - } - } else { - const dbFlow = await env.model.flows.getFlowREST({ - id: currentFlowID!, - }); - if ( - (versionData && - currentVersionID && - Date.parse(versionData[currentVersionID - 1].updatedTime) < - Date.parse(dbFlow.updatedAt)) || - (versionData && versionData.length < dbFlow.versions.length) - ) { - window.confirm( - 'This flow cannot be saved, as a concurrency conflict has been detected. Please refresh your screen to view the most up to date data.' - ); - } else { - if (isPending && (approveFlag || rejectFlag)) { - if ( - allFieldsReviewed || - pendingFieldsAllApplied || - !pendingVersionV1 - ) { - try { - const response = await env.model.flows.updatePendingFlow({ - flow: data, - }); - if (response) { - const path = editFlowSetting( - response.id, - response.versionID - ); - setAlertFlag(true); - setSharePath(path); - } - } catch (err: any) { - setOpenAlerts([ - ...openAlerts, - { message: err.message, id: alertId }, - ]); - setAlertId((prevId) => prevId + 1); - handleSave(); - } - } else { - window.confirm( - 'Some of the revised data on this flow still needs to be accepted or rejected before this update can be approved.' - ); - } - } else { - try { - const response = await env.model.flows.updateFlow({ - flow: data, - }); - if (response) { - const path = editFlowSetting(response.id, response.versionID); - setAlertFlag(true); - setSharePath(path); - } - } catch (err: any) { - let errmessage = ''; - if (err.reason) { - const inconsistencyObject = err.reason; - errmessage = processDataInconsistencies(inconsistencyObject); - } else { - const lastIndex = err.message.lastIndexOf(':'); - errmessage = err.message.substring(lastIndex + 1); - } - setOpenAlerts([ - ...openAlerts, - { message: errmessage, id: alertId }, - ]); - setAlertId((prevId) => prevId + 1); - handleSave(); - } - } - } - } - } - } - }; - const navigate = useNavigate(); - const handleCopy = (values: FormValues) => { - if (currentFlowID && currentVersionID) { - const isCopy = true; - const path = copyFlow(); - if (typeof path === 'string') { - const valuesWithFiles = { ...values, isCopy }; - navigate(path, { state: valuesWithFiles }); - } else { - console.error('Path is not a string', path); - } - } - }; - - const handleAlert = (values: FormValues) => { - const errors = validateForm(values); - if (Object.keys(errors).length !== 0) { - setValidationFlag(true); - handleSave(); - } - }; - - const setObjectsWithArray = ( - fetchedObject: any, - objectKeys: string[], - settingArrayKeys: string[], - setFieldValue: any, - values: any - ) => { - const newObjects = { ...objects }; - const newShowingTypes = [...showingTypes]; - objectKeys.forEach((key, i) => { - if (fetchedObject[settingArrayKeys[i]]) { - newObjects[key] = checkIfExistingAndCopy( - newObjects[key], - fetchedObject, - settingArrayKeys[i] - ); - } - - const parsedResponse = newObjects[key].map((responseValue: any) => { - if (settingArrayKeys[i] === 'years') { - return { - displayLabel: - (responseValue as usageYears.UsageYear).year || - responseValue.displayLabel, - value: responseValue.id || responseValue.value, - isAutoFilled: responseValue.suggested, - }; - } else if (settingArrayKeys[i] === 'plans') { - return { - displayLabel: - (responseValue.planVersion as { planId: number; name: string }) - .name || responseValue.displayLabel, - value: responseValue.planVersion.planId || responseValue.value, - isAutoFilled: responseValue.suggested, - }; - } else if (settingArrayKeys[i] === 'governingEntities') { - return { - displayLabel: - ( - responseValue.governingEntityVersion as { - id: number; - name: string; - } - ).name || responseValue.displayLabel, - value: - responseValue.governingEntityVersion.id || responseValue.value, - isAutoFilled: responseValue.suggested, - }; - } else { - return { - displayLabel: - (responseValue as { id: number; name: string }).name || - responseValue.displayLabel, - value: responseValue.id || responseValue.value, - isAutoFilled: responseValue.suggested, - }; - } - }); - newObjects[key].forEach((obj) => { - if (obj?.suggested) { - updateFlowObjects(key, parsedResponse, setFieldValue, values); - obj.suggested = false; - } - }); - setFieldValue(key, parsedResponse); - }); - - setObjects(newObjects); - setShowingTypes(newShowingTypes); - }; - - const checkIfExistingAndCopy = ( - existingObjects: any[], - object: any, - key: string - ): any[] => { - let newObjects = object[key]; - if (key === 'locations') { - newObjects = newObjects.filter(function (location: any) { - return location.adminLevel === 0; - }); - if (existingObjects && existingObjects.length) { - existingObjects = existingObjects.filter(function (location) { - return location.adminLevel === 0 || location.value; - }); - } - } - - if (existingObjects && existingObjects.length) { - const existingObjectsIds = existingObjects.map(function (o) { - return o.id || o.value; - }); - if (Array.isArray(newObjects)) { - newObjects.forEach(function (obj) { - if (existingObjectsIds.indexOf(obj.id) === -1) { - obj.suggested = true; - existingObjects.push(obj); - } - }); - } else { - if (existingObjectsIds.indexOf(newObjects.id) === -1) { - newObjects.suggested = true; - existingObjects.push(newObjects); - } - } - } else { - if (newObjects) { - if (Array.isArray(newObjects)) { - newObjects.forEach(function (obj) { - obj.suggested = true; - }); - existingObjects = newObjects; - } else { - newObjects.suggested = true; - existingObjects = [newObjects]; - } - } - } - return existingObjects; - }; - const fetchPlanDetails = async ( - objectType: string, - plan: any, - setFieldValue: any, - values?: any - ) => { - const fetchedPlan = await environment.model.plans.getPlan(plan[0].value); - if (objectType === 'sourcePlans') { - setObjectsWithArray( - fetchedPlan, - ['sourceUsageYears', 'sourceEmergencies'], - ['years', 'emergencies'], - setFieldValue, - values - ); - setSourceGoverningEntities(fetchedPlan.governingEntities); - } - if (objectType === 'destinationPlans') { - setObjectsWithArray( - fetchedPlan, - ['destinationUsageYears', 'destinationEmergencies'], - ['years', 'emergencies'], - setFieldValue, - values - ); - setDestinationGoverningEntities(fetchedPlan.governingEntities); - } - if (fetchedPlan.locations) { - const countries = fetchedPlan.locations.filter(function (loc) { - return loc.adminLevel === 0; - }); - if (countries.length === 1) { - if (objectType === 'sourcePlans') { - setObjectsWithArray( - { locations: countries }, - ['sourceLocations'], - ['locations'], - setFieldValue, - values - ); - } - if (objectType === 'destinationPlans') { - setObjectsWithArray( - { locations: countries }, - ['destinationLocations'], - ['locations'], - setFieldValue, - values - ); - } - } - } - }; - - const fetchEmergencyDetails = async ( - objectType: string, - emergency: any, - setFieldValue: any, - values?: any - ) => { - if (objectType === 'destinationEmergencies') { - const fetchedEmergency = await environment.model.emergencies.getEmergency( - emergency[0].value - ); - if (fetchedEmergency.locations.length <= 1) { - setObjectsWithArray( - fetchedEmergency, - ['destinationLocations'], - ['locations'], - setFieldValue, - values - ); - } - } - }; - const fetchProjectDetails = async ( - objectType: string, - project: any, - setFieldValue: any, - values?: any - ) => { - const fetchedProject = await environment.model.projects.getProject( - project[0].value - ); - const publishedVersion = fetchedProject.projectVersions.filter( - function (version) { - return version.id === fetchedProject.currentPublishedVersionId; - } - )[0]; - if (objectType === 'destinationProjects') { - const fetchedCategories = - await environment.model.categories.getCategories({ - query: 'earmarkingType', - }); - const category = fetchedCategories.filter( - (item) => item.name === 'Earmarked' - ); - setFieldValue('earmarkingType', { - value: category[0], - displayLabel: category[0].name, - }); - setObjectsWithArray( - publishedVersion, - [ - 'destinationPlans', - 'destinationLocations', - 'destinationGoverningEntities', - 'destinationGlobalClusters', - 'destinationOrganizations', - ], - [ - 'plans', - 'locations', - 'governingEntities', - 'globalClusters', - 'organizations', - ], - setFieldValue, - values - ); - } else { - setObjectsWithArray( - publishedVersion, - [ - 'sourcePlans', - 'sourceLocations', - 'sourceGoverningEntities', - 'sourceGlobalClusters', - 'sourceOrganizations', - ], - [ - 'plans', - 'locations', - 'governingEntities', - 'globalClusters', - 'organizations', - ], - setFieldValue, - values - ); - } - }; - const fetchOrganizationDetails = async ( - objectType: string, - organization: any, - setFieldValue: any, - values?: any - ) => { - const fetchedOrg = - await environment.model.organizations.getOrganizationsById( - organization[0].value - ); - const isGovernment = (fetchedOrg[0].categories ?? []).some( - function (category) { - return ( - category.group === 'organizationType' && - [114, 123].includes(category.id) - ); - } - ); - if (isGovernment && objectType === 'sourceOrganizations') { - objects.sourceLocations = checkIfExistingAndCopy( - objects.location, - fetchedOrg[0], - 'locations' - ); - setObjectsWithArray( - objects, - ['sourceLocations'], - ['locations'], - setFieldValue, - values - ); - } - }; - const fetchAssociatedGoverningEntity = async ( - objectType: string, - globalCluster: any, - setFieldValue: any, - values?: any - ) => { - if ( - (values.sourcePlans.length === 0 && - objectType === 'sourceGlobalClusters') || - (values.destinationPlans.length === 0 && - objectType === 'destinationGlobalClusters') - ) { - return; - } - let plan = null; - let targetGoverningEntities: any = null; - if (objectType === 'sourceGlobalClusters') { - plan = values.sourcePlans[0]; - targetGoverningEntities = values.sourceGoverningEntities; - } else { - plan = values.destinationPlans[0]; - targetGoverningEntities = values.destinationGoverningEntities; - } - const fetchedGoverningEntities = - await environment.model.governingEntities.getAllPlanGoverningEntities( - plan.value - ); - const hasGoverningEntitiesWithoutGlobalCluster = - Array.isArray(targetGoverningEntities) && - fetchedGoverningEntities - .filter(function (fetchedGe) { - return targetGoverningEntities.find(function (selectedGe: any) { - return fetchedGe.id === selectedGe.value; - }); - }) - .some(function (fetchedGe) { - return ( - Array.isArray(fetchedGe.globalClusterIds) && - !fetchedGe.globalClusterIds.length - ); - }); - - if (hasGoverningEntitiesWithoutGlobalCluster) { - return; - } - const governingEntities = fetchedGoverningEntities.filter( - function (governingEntity) { - return ( - governingEntity.globalClusterIds.indexOf( - globalCluster[globalCluster.length - 1].value - ) > -1 - ); - } - ); - - if (governingEntities.length) { - governingEntities.forEach(function (governingEntity) { - setObjectsWithArray( - { governingEntities: governingEntity }, - [ - objectType === 'sourceGlobalClusters' - ? 'sourceGoverningEntities' - : 'destinationGoverningEntities', - ], - ['governingEntities'], - setFieldValue, - values - ); - }); - } - }; - - const fetchKeywords = async ( - objectType: string, - usageYears: any, - setFieldValue: any, - values?: any - ) => { - if (usageYears.length === 2) { - const fetchedCategories = - await environment.model.categories.getCategories({ - query: 'keywords', - }); - const category = fetchedCategories.filter( - (item) => item.name === 'Multiyear' - ); - - const mergedKeywords = [ - ...values.keywords, - ...[ - { - value: category[0].id, - displayLabel: category[0].name, - }, - ].filter( - (item2) => - !values.keywords.some((item1: any) => item1.value === item2.value) - ), - ]; - - setFieldValue('keywords', mergedKeywords); - } else if (usageYears.length === 1) { - const filteredKeywords = values.keywords.filter( - (item: any) => item.displayLabel !== 'Multiyear' - ); - setFieldValue('keywords', filteredKeywords); - } - }; - - const handleCompareCheck = ( - checkedVersion: VersionDataType, - isChecked: boolean - ) => { - setComparingVersions((prev: VersionDataType[]) => { - if (isChecked) { - return [...prev, checkedVersion]; - } else { - return prev.filter( - (version: VersionDataType) => - version.versionId !== checkedVersion.versionId - ); - } - }); - }; - - const fetchDownload = async (index: number) => { - const fileAssetID = - initialValue.reportDetails[index]?.reportFiles[0]?.fileAssetID; - const name = initialValue.reportDetails[index]?.reportFiles[0]?.fileName; - if (fileAssetID) { - try { - const responseData = - await environment?.model.fileUpload.fileDownloadModel(fileAssetID); - if (responseData) { - const data = new Blob([responseData]); - const url = URL.createObjectURL(data); - const a = document.createElement('a'); - a.href = url; - a.download = `${name ? name : 'downloaded_file'}`; - document.body.appendChild(a); - a.click(); - setTimeout(() => { - document.body.removeChild(a); - window.URL.revokeObjectURL(url); - }, 0); - } else { - console.error('No data received for download'); - } - } catch (error) { - console.error(error, 'error'); - } - } - }; - - const fetchCategory = useCallback( - (category: string) => { - return async () => { - const response = await environment.model.categories.getCategories({ - query: category, - }); - return response.map( - (responseValue): categoryType => ({ - displayLabel: responseValue.name, - value: responseValue.id.toString(), - parentID: responseValue.parentID, - }) - ); - }; - }, - [environment] - ); - const extractUniqueFromArray = (array1: string[], array2: string[]) => { - return array1.filter((item: string) => !array2.includes(item)); - }; - - const compareVersions = (versions: VersionDataType[]) => { - const version1 = versions[0]; - const version2 = versions[1]; - const newVersion1 = { - ...version1, - uniqueSources: objectTypes.reduce>( - (acc, type) => { - acc[type] = extractUniqueFromArray( - version1.source[type], - version2.source[type] - ); - return acc; - }, - {} - ), - uniqueDestinations: objectTypes.reduce>( - (acc, type) => { - acc[type] = extractUniqueFromArray( - version1.destination[type], - version2.destination[type] - ); - return acc; - }, - {} - ), - uniqueCategories: extractUniqueFromArray( - version1.categories, - version2.categories - ), - }; - - const newVersion2 = { - ...version2, - uniqueSources: objectTypes.reduce>( - (acc, type) => { - acc[type] = extractUniqueFromArray( - version2.source[type], - version1.source[type] - ); - return acc; - }, - {} - ), - uniqueDestinations: objectTypes.reduce>( - (acc, type) => { - acc[type] = extractUniqueFromArray( - version2.destination[type], - version1.destination[type] - ); - return acc; - }, - {} - ), - uniqueCategories: extractUniqueFromArray( - version2.categories, - version1.categories - ), - }; - return [newVersion1, newVersion2]; - }; - const handleFileChange = async ( - event: React.ChangeEvent, - index: number - ) => { - setUploadFlag(true); - try { - const setFile: File | undefined = (event.target as HTMLInputElement) - .files?.[0]; - if (setFile instanceof File) { - const responseData = - await environment.model.fileUpload.fileUploadModel(setFile); - setUploadedFileArray((prevUploadedFile) => { - const updateUploadedFile = [...prevUploadedFile]; - updateUploadedFile[index] = responseData; - return updateUploadedFile; - }); - console.log(uploadedFileArray, 'uploadedFileArray'); - } else { - console.error('No file selected for upload.'); - } - } catch (error) { - console.log(error, 'error'); - } - }; - useEffect(() => { - if (comparingVersions.length === 2) { - const compared = compareVersions(comparingVersions); - setComparedVersions(compared); - } - }, [comparingVersions]); - - useEffect(() => { - const handleBeforeUnload = (event: BeforeUnloadEvent) => { - if (unsavedChange) { - const message = - 'You have unsaved changes! Are you sure you want to leave?'; - event.returnValue = message; // Standard for most browsers - return message; // For some older browsers - } - }; - - window.addEventListener('beforeunload', handleBeforeUnload); - - return () => { - window.removeEventListener('beforeunload', handleBeforeUnload); - }; - }, [unsavedChange]); - - useEffect(() => { - const valuesObject: Record = { - sourceOrganizations: initialValue.sourceOrganizations, - sourceLocations: initialValue.sourceLocations, - sourceUsageYears: initialValue.sourceUsageYears, - sourceProjects: initialValue.sourceProjects, - sourcePlans: initialValue.sourcePlans, - sourceGoverningEntities: initialValue.sourceGoverningEntities, - sourceGlobalClusters: initialValue.sourceGlobalClusters, - sourceEmergencies: initialValue.sourceEmergencies, - destinationOrganizations: initialValue.destinationOrganizations, - destinationLocations: initialValue.destinationLocations, - destinationUsageYears: initialValue.destinationUsageYears, - destinationProjects: initialValue.destinationProjects, - destinationPlans: initialValue.destinationPlans, - destinationGoverningEntities: initialValue.destinationGoverningEntities, - destinationGlobalClusters: initialValue.destinationGlobalClusters, - destinationEmergencies: initialValue.destinationEmergencies, - }; - setObjects(valuesObject); - }, []); - - unstable_usePrompt({ - message: 'You have unsaved changes! Are you sure you want to leave?', - when: unsavedChange, - }); - const dictExecutedForEachObject: Record< - string, - ( - objectType: string, - flowObject: any, - setFieldValue: any, - values: any - ) => Promise - > = { - sourcePlans: fetchPlanDetails, - destinationPlans: fetchPlanDetails, - destinationEmergencies: fetchEmergencyDetails, - sourceProjects: fetchProjectDetails, - destinationProjects: fetchProjectDetails, - sourceOrganizations: fetchOrganizationDetails, - sourceGlobalClusters: fetchAssociatedGoverningEntity, - destinationGlobalClusters: fetchAssociatedGoverningEntity, - sourceUsageYears: fetchKeywords, - destinationUsageYears: fetchKeywords, - }; - - const params: DeleteFlowParams = { - VersionID: currentVersionID ?? 0, - FlowID: currentFlowID ?? 0, - }; - - const deleteFlow = async () => { - if (linkCheck || isShowParentFlow || isShowChildFlow > 0) { - window.confirm( - 'All linked flows must be unlinked before this flow can be deleted. Unlink flows and choose Delete flow again.' - ); - return; - } - - try { - const response = await env.model.flows.deleteFlow(params); - const path = flows(); - window.open(path, '_self'); - } catch (err: any) { - setOpenAlerts([...openAlerts, { message: err.message, id: alertId }]); - setAlertId((prevId) => prevId + 1); - } - }; - const updateFlowObjects = async ( - objectType: string, - flowObject: any, - setFieldValue: any, - values?: any - ) => { - if (flowObject.length > 0 && dictExecutedForEachObject[objectType]) { - flowObject.sort( - ( - a: { displayLabel: string; value: number }, - b: { displayLabel: string; value: number } - ) => { - return a.displayLabel.localeCompare(b.displayLabel); - } - ); - await dictExecutedForEachObject[objectType]( - objectType, - flowObject, - setFieldValue, - values - ); - } - if (objectType === 'sourcePlans') { - handleShowSourceGoverningEntities(flowObject.length !== 0); - } - if (objectType === 'destinationPlans') { - handleShowDestinationGoverningEntities(flowObject.length !== 0); - } - }; - const handleParentLinkedFlow = ( - values: any, - setFieldValue: any, - index: number - ) => { - setFieldValue( - 'parentFlow', - values['parentFlow'].filter((_item: any, ind: number) => ind !== index) - ); - }; - const handleChildFlow = (values: any, setFieldValue: any, index: number) => { - setFieldValue( - 'childFlow', - values['childFlow'].filter((_item: any, ind: number) => ind !== index) - ); - }; - const validateForm = (values: FormValues) => { - console.log('flowValue>>>', values); - setUnsavedChange(JSON.stringify(values) !== JSON.stringify(initialValue)); - const valuesObject: Record = { - sourceOrganizations: values.sourceOrganizations, - sourceLocations: values.sourceLocations, - sourceUsageYears: values.sourceUsageYears, - sourceProjects: values.sourceProjects, - sourcePlans: values.sourcePlans, - sourceGoverningEntities: values.sourceGoverningEntities, - sourceGlobalClusters: values.sourceGlobalClusters, - sourceEmergencies: values.sourceEmergencies, - destinationOrganizations: values.destinationOrganizations, - destinationLocations: values.destinationLocations, - destinationUsageYears: values.destinationUsageYears, - destinationProjects: values.destinationProjects, - destinationPlans: values.destinationPlans, - destinationGoverningEntities: values.destinationGoverningEntities, - destinationGlobalClusters: values.destinationGlobalClusters, - destinationEmergencies: values.destinationEmergencies, - }; - setObjects(valuesObject); - const result = validationSchema.decode(values); - if (isRight(result)) { - setValidationFlag(false); - return {}; - } else { - const errors: Record[]> = {}; - Object.keys(values).forEach((key) => { - const value = values[key as keyof FormValues]; - if ( - result.left.some((err) => err.context.find((ctx) => ctx.key === key)) - ) { - const errorKey = key as keyof FormikErrors; - if (!value) { - errors[errorKey] = 'This field is required.'; - } else if (Array.isArray(value) && value.length === 0) { - errors[errorKey] = 'This field is required.'; - } - } - if ( - key === 'amountUSD' && - (value === 0 || (value && (value === '0' || (value as number) < 0))) - ) { - errors['amountUSD'] = 'The amount must be greater than zero.'; - } - if (key === 'flowType' && !value) { - errors['flowType'] = 'This field is required.'; - } - if (key === 'method' && !value) { - errors['method'] = 'This field is required.'; - } - if (key === 'reportDetails') { - const res = result.left.filter((err) => - err.context.find((ctx) => ctx.key === key) - )[0].value; - if (res && Array.isArray(res)) { - const reportDetailError: Record[] = []; - res.forEach((_, index) => { - const error: Record = {}; - if (res[index].reportChannel === '') { - error['reportChannel'] = 'This field is required.'; - } else { - error['reportChannel'] = ''; - } - if (!res[index].reportedDate) { - error['reportedDate'] = 'This field is required.'; - } else { - error['reportedDate'] = ''; - } - console.log(res[index], '-------------->'); - if ( - (res[index].reportFileTitle === '' || - res[index].reportFileTitle === undefined) && - (uploadedFileArray[index] && - (uploadedFileArray[index] as { id?: number })?.id - ? true - : false) - ) { - error['reportFileTitle'] = 'This field is required.'; - } else { - error['reportFileTitle'] = ''; - } - if ( - res[index].reportedOrganization === null || - res[index].reportedOrganization.displayLabel === '' - ) { - error['reportedOrganization'] = 'This field is required.'; - } else { - error['reportedOrganization'] = ''; - } - - if (Object.keys(error).length > 0) { - (reportDetailError as Record[]).push(error); - } - }); - - if (reportDetailError.length >= res.length) { - res.forEach((_, index) => { - if ( - res[index].reportChannel !== '' && - res[index].reportedOrganization !== '' && - res[index].reportedDate !== '' - ) { - if ( - (res[index].reportFileTitle === undefined || - res[index].reportFileTitle === '') && - (uploadedFileArray[index] && - (uploadedFileArray[index] as { id?: number })?.id - ? false - : true) - ) { - return {}; - } else if ( - res[index].reportFileTitle !== undefined && - res[index].reportFileTitle !== '' && - uploadedFileArray[index] - ) { - return {}; - } else { - errors['reportDetails'] = reportDetailError; - } - } else { - errors['reportDetails'] = reportDetailError; - } - }); - } - } - } - }); - console.log(errors, 'errors'); - if (Object.keys(errors).length === 0) setValidationFlag(false); - return errors; - } - }; - const handleParentFlow = ( - values: any, - parentValueString: string, - setValues: any - ) => { - parentValue = parentValueString; - const defaultValueParent: flowsResponse.GetFlowResult = - JSON.parse(parentValueString); - - const indexOrgs = defaultValueParent.organizations - .map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const indexYears = defaultValueParent.usageYears - .map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const indexLocs = defaultValueParent.locations - .map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const indexEmrs = defaultValueParent.emergencies - ?.map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const indexGlos = defaultValueParent.globalClusters - ?.map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const indexPlns = defaultValueParent.plans - ?.map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - // const indexEnt = defaultValueParent.governingEntities?.findIndex((org) => org.flowObject?.refDirection === 'destination') ?? -1; - - const indexPros = defaultValueParent.projects - ?.map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const _sourceOrganizations = indexOrgs.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: `${defaultValueParent.organizations[index].name} [${defaultValueParent.organizations[index].abbreviation}]`, - value: defaultValueParent.organizations[index].id, - }; - } - }); - const _sourceUsageYears = indexYears.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: `${defaultValueParent.usageYears[index].year}`, - value: defaultValueParent.usageYears[index].id, - }; - } - }); - const _sourceLocations = indexLocs.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: `${defaultValueParent.locations[index].name}`, - value: defaultValueParent.locations[index].id, - }; - } - }); - - const _sourceEmergencies = indexEmrs?.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: - defaultValueParent.emergencies && - `${defaultValueParent.emergencies[index].name}`, - value: - defaultValueParent.emergencies && - defaultValueParent.emergencies[index].id, - }; - } - }); - const _sourceGlobalClusters = indexGlos?.map( - (index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: - defaultValueParent.globalClusters && - `${defaultValueParent.globalClusters[index].name}`, - value: - defaultValueParent.globalClusters && - defaultValueParent.globalClusters[index].id, - }; - } - } - ); - const _sourcePlans = indexPlns?.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: - defaultValueParent.plans && - `${defaultValueParent.plans[index].planVersion.name}`, - value: defaultValueParent.plans && defaultValueParent.plans[index].id, - }; - } - }); - const _sourceProjects = indexPros?.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: - defaultValueParent.projects && - `${defaultValueParent.projects[index].projectVersions[index].name}`, - value: - defaultValueParent.projects && - defaultValueParent.projects[index].id, - }; - } - }); - - setValues({ - ...values, - sourceOrganizations: _sourceOrganizations, - sourceUsageYears: _sourceUsageYears, - sourceLocations: _sourceLocations, - sourceEmergencies: _sourceEmergencies, - sourceGlobalClusters: _sourceGlobalClusters, - sourcePlans: _sourcePlans, - // sourceGoverningEntities: _sourceGoverningEntities ? [_sourceGoverningEntities] : [], - sourceProjects: _sourceProjects, - }); - }; - return ( - - - handleSubmit(values, values.submitAction) - } - validate={(values) => validateForm(values)} - enableReinitialize - validateOnChange={false} - style={{ zIndex: 1 }} - > - {({ values, setFieldValue, setValues }) => { - if (values.parentFlow && values.parentFlow[0]) { - const parentValueString = String( - values.parentFlow && - values.parentFlow[0] && - values.parentFlow[0].value - ); - if (parentValue !== parentValueString) { - handleParentFlow(values, parentValueString, setValues); - } - } - return ( -
- - {!readOnly && !isPending && ( - <> - { - handleAlert(values); - setApproveFlag(false); - setRejectFlag(false); - setFieldValue('submitAction', 'save'); - }} - /> - { - handleAlert(values); - setApproveFlag(false); - setRejectFlag(false); - setFieldValue('submitAction', 'save'); - }} - /> - { - window.confirm( - 'Are you sure you want to set this flow as inactive? Any parent or child flows linked to this flow must be unlinked before the flow can be set as inactive.' - ); - handleAlert(values); - setApproveFlag(false); - setRejectFlag(false); - setFieldValue('submitAction', 'inactive'); - }} - /> - - )} - {isPending && ( - <> - { - setApproveFlag(true); - setFieldValue('submitAction', 'approve'); - }} - /> - { - setRejectFlag(true); - setApproveFlag(true); - setFieldValue('submitAction', 'rejected'); - }} - /> - - )} - {currentVersionID ? ( - - {isEdit && ( - - )} - - - ) : ( - <> - )} - - {openAlerts.map((alert) => ( - handleClose(alert.id)} - > - - - } - sx={{ mb: 2 }} - onClose={() => handleClose(alert.id)} - > - {alert.message} - - ))} -
- {inactiveFlag && isEdit && ( - { - setInactiveFlag(false); - }} - > - Set as inactive? - All linked flows must be unlinked before this flow can be - cancelled. Unlink flows and choose flow again. - - )} -
-
- {validationFlag && ( - { - setValidationFlag(false); - }} - > - Validation - Please complete all required fields marked with an asterisk - (*) to proceed. - - )} -
-
- {parentCurrencyFlag && ( - { - setParentCurrencyFlag(false); - }} - > - This flow's foreign currency must be the same as its parked - parent flow. - - )} -
-
- {childCurrencyFlag && ( - { - setChildCurrencyFlag(false); - }} - > - The child flow must have the same currency as this parked - flow. Please update the child flow first before linking it - to this flow. - - )} -
-
- {alertFlag && ( - { - setAlertFlag(false); - }} - > - Success - Flow - - {' '} - {currentFlowID} ,V{sharePath.split('/').pop()}{' '} - - {`"${values.flowDescription}" updated`} - - )} -
- - - - - - - - - - - - - - - - - - - - - - {isPending && pendingVersionV1 && ( -
- { - Object.keys(inputEntries).forEach((key) => { - const specificKey = key as keyof InputEntriesType; - const value = inputEntries[specificKey]; - - if (value === null) { - return; - } - if (isRight(forms.INPUT_ENTRY_TYPE.decode(value))) { - setFieldValue( - key, - (value as forms.InputEntryType).value - ); - } - if (Array.isArray(value)) { - setFieldValue( - key, - (value as forms.InputEntryType[]).find( - (inputEntry) => - inputEntry.category === - forms.InputEntryCategoriesEnum.ACTIVE_FLOW - )?.value ?? [] - ); - } - }); - initializeInputEntries(); - }} - color="greenLight" - text="Accept Remaining Changes" - startIcon={MdCheck} - /> - -
- )} - - {!readOnly && !isPending && ( - <> - { - handleAlert(values); - setApproveFlag(false); - setRejectFlag(false); - setFieldValue('submitAction', 'save'); - }} - /> - { - handleAlert(values); - setApproveFlag(false); - setRejectFlag(false); - setFieldValue('submitAction', 'save'); - }} - /> - { - window.confirm( - 'Are you sure you want to set this flow as inactive? Any parent or child flows linked to this flow must be unlinked before the flow can be set as inactive.' - ); - handleAlert(values); - setApproveFlag(false); - setRejectFlag(false); - setFieldValue('submitAction', 'inactive'); - }} - /> - - )} - {isPending && ( - <> - { - setApproveFlag(true); - setFieldValue('submitAction', 'approve'); - }} - /> - { - setRejectFlag(true); - setApproveFlag(true); - setFieldValue('submitAction', 'rejected'); - }} - /> - - )} - {currentVersionID ? ( - - {isEdit && ( - - )} - - - ) : ( - <> - )} - - - ); - }} -
-
- ); -}; -export default FlowRewriteForm; diff --git a/apps/hpc-ftsadmin/src/app/components/flow-form-rewrite/linked-flows.tsx b/apps/hpc-ftsadmin/src/app/components/flow-form-rewrite/linked-flows.tsx deleted file mode 100644 index d741634cc..000000000 --- a/apps/hpc-ftsadmin/src/app/components/flow-form-rewrite/linked-flows.tsx +++ /dev/null @@ -1,2774 +0,0 @@ -import React, { - ChangeEvent, - useState, - useEffect, - useCallback, - useRef, - useContext, -} from 'react'; -import { Form, Formik, FieldArray } from 'formik'; -import tw from 'twin.macro'; -import dayjs from 'dayjs'; -import { isRight } from 'fp-ts/Either'; -import { FormikErrors } from 'formik'; -import * as t from 'io-ts'; -import { util as codecs } from '@unocha/hpc-data'; -import GppMaybeIcon from '@mui/icons-material/GppMaybe'; -import Button from '@mui/material/Button'; -import DeleteIcon from '@mui/icons-material/Delete'; -import Stack from '@mui/material/Stack'; -import ContentCopyIcon from '@mui/icons-material/ContentCopy'; -import MuiAlert from '@mui/material/Alert'; -import AlertTitle from '@mui/material/AlertTitle'; -import _, { set, values } from 'lodash'; -import useSharePath from '../Hooks/SharePath'; -import { C, dialogs } from '@unocha/hpc-ui'; -import { - Table, - TableBody, - TableCell, - TableContainer, - TableHead, - TableRow, - Paper, - Alert, - IconButton, -} from '@mui/material'; -import CloseIcon from '@mui/icons-material/Close'; -import { Environment } from '../../../environments/interface'; -import { MdAdd, MdRemove, MdClose, MdCheck } from 'react-icons/md'; -import { - usageYears, - forms, - governingEntities, - fileUpload, - flows as flowsResponse, -} from '@unocha/hpc-data'; -import { getEnv } from '../../context'; -import { editFlowSetting, copyFlow } from '../../paths'; -import { flows } from '../../paths'; -import Link from '@mui/material/Link'; -import { useNavigate, unstable_usePrompt } from 'react-router-dom'; -import { id } from 'fp-ts/lib/Refinement'; -import { FlowContext } from './flow-context'; - -export type AutoCompleteSelectionType = forms.InputSelectValueType; - -const INPUT_SELECT_VALUE_TYPE = forms.INPUT_SELECT_VALUE_TYPE; - -type UniqueDataType = { - [key: string]: string[]; -}; - -export interface DeleteFlowParams { - VersionID: number; - FlowID: number; -} - -export interface categoryType { - value: string | number; - displayLabel: string; - parentID: number | null; -} - -export interface FileAssetEntityType { - collection?: string; - createAt?: string; - filename?: string; - id?: number; - mimetype?: string; - originalname?: string; - path?: string; - size?: number; - updatedAt?: string; -} -export interface ReportFileType { - title?: string; - fileName?: string; - UploadFileUrl?: string; - type?: string; - url?: string; - fileAssetID?: number; - size?: number; - fileAssetEntity?: FileAssetEntityType; -} -export interface ReportDetailType { - verified: string; - reportSource: string; - reporterReferenceCode: string; - reportChannel: AutoCompleteSelectionType | ''; - reportedOrganization: AutoCompleteSelectionType; - reportedDate: string; - reporterContactInformation: string; - sourceSystemRecordId: string; - reportFiles: ReportFileType[]; - reportFileTitle?: string; - reportUrlTitle?: string; - reportUrl?: string; - versionId?: number; - fileAsset?: FileAssetEntityType; -} - -export interface ParentFlowType { - value: any; -} - -export interface FormValues { - id: string | null; - amountUSD: number; - keywords: AutoCompleteSelectionType[]; - flowStatus: AutoCompleteSelectionType | ''; - flowType: AutoCompleteSelectionType | ''; - flowDescription: string; - firstReported: string; - decisionDate: string | null; - budgetYear: string; - flowDate: string; - contributionType: AutoCompleteSelectionType | ''; - earmarkingType: AutoCompleteSelectionType | ''; - method: AutoCompleteSelectionType | ''; - cashTransfer: AutoCompleteSelectionType | ''; - beneficiaryGroup: AutoCompleteSelectionType | ''; - inactiveReason: any[] | string; - childMethod: object; - origCurrency: AutoCompleteSelectionType | string; - amountOriginal: number | null; - exchangeRateUsed: number | null; - notes: string; - sourceOrganizations: AutoCompleteSelectionType[]; - sourceLocations: AutoCompleteSelectionType[]; - sourceUsageYears: AutoCompleteSelectionType[]; - sourceProjects: AutoCompleteSelectionType[]; - sourcePlans: AutoCompleteSelectionType[]; - sourceGoverningEntities: AutoCompleteSelectionType[]; - sourceGlobalClusters: AutoCompleteSelectionType[]; - sourceEmergencies: AutoCompleteSelectionType[]; - destinationOrganizations: AutoCompleteSelectionType[]; - destinationLocations: AutoCompleteSelectionType[]; - destinationUsageYears: AutoCompleteSelectionType[]; - destinationProjects: AutoCompleteSelectionType[]; - destinationPlans: AutoCompleteSelectionType[]; - destinationGoverningEntities: AutoCompleteSelectionType[]; - destinationGlobalClusters: AutoCompleteSelectionType[]; - destinationEmergencies: AutoCompleteSelectionType[]; - reportDetails: ReportDetailType[]; - parentFlow?: AutoCompleteSelectionType[]; - childFlow?: AutoCompleteSelectionType[]; - isParkedParent?: boolean; - includeChildrenOfParkedFlows: boolean; - isErrorCorrectionValue: boolean; - sources?: Record; - submitAction?: string | undefined; - versions?: { - id: number | null; - isPending: boolean | null; - }[]; -} - -export interface VersionDataType { - versionId: number; - flowId: number; - createdTime: string; - createdBy: string | null; - updatedTime: string; - updatedBy: string | null; - active: boolean; - viewing: boolean; - pending?: boolean; - [key: string]: - | string - | number - | null - | boolean - | string[] - | Date - | undefined - | Record; - source: UniqueDataType; - destination: UniqueDataType; - categories: string[]; - uniqueSources: UniqueDataType; - uniqueDestinations: UniqueDataType; - uniqueCategories: string[]; - restricted?: boolean; -} - -export interface InputEntriesType { - amountUSD: forms.InputEntryType | null; - origCurrency: forms.InputEntryType | null; - keywords: forms.InputEntryType | null; - flowStatus: forms.InputEntryType | null; - flowType: forms.InputEntryType | null; - flowDescription: forms.InputEntryType | null; - contributionType: forms.InputEntryType | null; - earmarkingType: forms.InputEntryType | null; - method: forms.InputEntryType | null; - beneficiaryGroup: forms.InputEntryType | null; - inactiveReason: forms.InputEntryType | null; - amountOriginal: forms.InputEntryType | null; - exchangeRateUsed: forms.InputEntryType | null; - notes: forms.InputEntryType | null; - sourceOrganizations: forms.InputEntryType[]; - sourceLocations: forms.InputEntryType[]; - sourceUsageYears: forms.InputEntryType[]; - sourceProjects: forms.InputEntryType[]; - sourcePlans: forms.InputEntryType[]; - sourceGoverningEntities: forms.InputEntryType[]; - sourceGlobalClusters: forms.InputEntryType[]; - sourceEmergencies: forms.InputEntryType[]; - destinationOrganizations: forms.InputEntryType[]; - destinationLocations: forms.InputEntryType[]; - destinationUsageYears: forms.InputEntryType[]; - destinationProjects: forms.InputEntryType[]; - destinationPlans: forms.InputEntryType[]; - destinationGoverningEntities: forms.InputEntryType[]; - destinationGlobalClusters: forms.InputEntryType[]; - destinationEmergencies: forms.InputEntryType[]; - parentFlow: forms.InputEntryType | null; - childFlow: forms.InputEntryType[]; -} - -type UploadedItem = fileUpload.FileUploadResult | FileAssetEntityType; - -const reportChannelSchema = t.type({ - value: t.intersection([codecs.NON_EMPTY_STRING, t.string]), - displayLabel: t.intersection([codecs.NON_EMPTY_STRING, t.string]), -}); - -const reportDetailsSchema = t.type({ - reportedOrganization: INPUT_SELECT_VALUE_TYPE, - reportedDate: t.intersection([codecs.NON_EMPTY_STRING, t.string]), - reportChannel: t.intersection([codecs.NON_EMPTY_STRING, reportChannelSchema]), - reportFileTitle: t.intersection([codecs.NON_EMPTY_STRING, t.string]), -}); - -const validationSchema = t.type({ - amountUSD: t.number, - flowStatus: INPUT_SELECT_VALUE_TYPE, - flowDescription: t.intersection([codecs.NON_EMPTY_STRING, t.string]), - firstReported: t.string, - flowDate: t.intersection([codecs.NON_EMPTY_STRING, t.string]), - sourceOrganizations: INPUT_SELECT_VALUE_TYPE, - sourceUsageYears: INPUT_SELECT_VALUE_TYPE, - destinationOrganizations: INPUT_SELECT_VALUE_TYPE, - destinationUsageYears: INPUT_SELECT_VALUE_TYPE, - reportDetails: reportDetailsSchema, -}); - -interface Props { - currentVersionData: flowsResponse.FlowREST | null; - environment: Environment; - isEdit: boolean; - initialValue: FormValues; - prevDetails?: ReportDetailType[]; - versionData?: VersionDataType[]; - flowId?: string; - versionId?: string; - isRestricted: boolean; - errorCorrection?: boolean; - inputEntries: InputEntriesType; - initializeInputEntries: () => void; - rejectInputEntry: (key: string) => void; - currentVersionID?: number; - currentFlowID?: number; - currentVersionActiveStatus?: boolean; - isPending?: boolean; - isSuperseded?: boolean; - isCancelled?: boolean; - isCancellation?: boolean; - isNewPending?: boolean; - isUpdatePending?: boolean; - canReactive?: boolean; - isErrorCorrection?: boolean | null; - isApprovedFlowVersion?: boolean | null; - pendingFieldsAllApplied?: boolean; - allFieldsReviewed?: boolean; - pendingVersionV1?: boolean; -} - -const StyledRepOrgLink = tw.div` - flex - ml-1 - `; - -const StyledAddChildWarning = tw.div` - border border-solid border-yellow-600 - flex - rounded-md - text-gray-900 - bg-yellow-100 bg-opacity-50 - `; - -const StyledAddChildWarningIconDiv = tw.div` - flex - items-center - p-1 - `; -const StyledAddChildWarningText = tw.span` - py-3 px-3 pb-3 - `; -const StyledLayoutRow = tw.div` - flex - `; -const StyledHalfSection = tw.div` - w-1/2 - `; -const StyledFullSection = tw.div` - w-full - mb-6 - `; -const StyledRow = tw.div` - flex - gap-4 - w-full - `; -const StyledFormRow = tw.div` - flex - gap-2 - w-full - items-center - `; -const StyledAnchor = tw.a` - underline - ml-[15px] - opacity-100 - `; -const StyledAnchorDiv = tw.div` - text-right - w-full - `; -const StyledRadioDiv = tw.div` - relative - w-full - `; -const StyledFieldset = tw.fieldset` - w-full - box-border - rounded-xl - mt-[16px] - mb-[8px] - border-gray-100 - `; -const StyledCurrencyRow = tw.div` - w-1/2 - `; -const StyledFormButton = tw(C.Button)` - ml-[25px] - mb-6 - `; -const StyledLabel = tw.label` - block - my-4 - `; -const StyledLinkedFlowRow = tw.div` - mt-4 - `; - -const StyledParentInfo = tw.div` - border-0 - border-b - border-solid - cursor-pointer - mb-4 - pb-4 - `; - -const StyledStrong = tw.strong` - min-w-[16rem] - inline-block - `; - -const StyledList = tw.li` - list-none - `; - -const StyledDiv = tw.div` - my-6 - me-4 - mr-[23px] - lg:flex - justify-end - gap-x-4 - bg-white - z-10 - `; - -const initialReportDetail = { - verified: 'verified', - reportSource: 'primary', - reporterReferenceCode: '', - reportChannel: '', - reportFileTitle: '', - reportedOrganization: { value: '', displayLabel: '' }, - reportedDate: dayjs().format('DD/MM/YYYY'), - reporterContactInformation: '', - sourceSystemRecordId: '', -}; - -const FORM_SETTINGS = { - organization: { - behavior: 'shared', - }, - project: { - behavior: 'overlap', - }, - usageYear: { - behavior: 'shared', - }, - location: { - behavior: 'shared', - }, - globalCluster: { - behavior: 'shared', - }, - emergency: { - behavior: 'overlap', - }, - governingEntity: { - behavior: 'shared', - }, - plan: { - behavior: 'overlap', - }, -}; - -const objectTypes = [ - 'emergencies', - 'projects', - 'usageYears', - 'globalClusters', - 'locations', - 'plans', - 'organizations', -] as const; - -const flowValuesForDisplay = [ - 'amountUSD', - 'flowDate', - 'decisionDate', - 'firstReportedDate', - 'budgetYear', - 'origAmount', - 'origCurrency', - 'exchangeRate', - 'activeStatus', - 'restricted', - 'newMoney', - 'description', - 'notes', -] as const; - -let parentValue = ''; - -export const LinkedFlows = () => { - const { - flowValue, - setFlowValue, - initialValue, - isEdit, - currentVersionData, - environment, - prevDetails, - versionData, - isRestricted, - errorCorrection, - inputEntries, - flowId, - versionId, - initializeInputEntries, - rejectInputEntry, - currentVersionID, - currentFlowID, - currentVersionActiveStatus, - isPending, - isSuperseded, - isCancelled, - isCancellation, - isNewPending, - isUpdatePending, - canReactive, - pendingFieldsAllApplied, - allFieldsReviewed, - pendingVersionV1, - }: any = useContext(FlowContext); - // const { - // currentVersionData, - // environment, - // initialValue, - // isEdit, - // prevDetails, - // versionData, - // isRestricted, - // errorCorrection, - // inputEntries, - // flowId, - // versionId, - // initializeInputEntries, - // rejectInputEntry, - // currentVersionID, - // currentFlowID, - // currentVersionActiveStatus, - // isPending, - // isSuperseded, - // isCancelled, - // isCancellation, - // isNewPending, - // isUpdatePending, - // canReactive, - // pendingFieldsAllApplied, - // allFieldsReviewed, - // pendingVersionV1, - // } = props; - const { confirm } = dialogs; - const env = getEnv(); - - const collapseFlowObjects = (data: any) => { - data.flowObjects = []; - - collapsePerBehavior(data.dest, 'destination'); - collapsePerBehavior(data.src, 'source'); - - function collapsePerBehavior(behaviorArr: any, ref: any) { - Object.keys(behaviorArr).forEach((type) => { - behaviorArr[type].forEach((obj: any) => { - if ( - obj !== null && - (!Object.prototype.hasOwnProperty.call(obj, 'cleared') || - !obj.cleared) - ) { - if (type === 'organization') { - obj.objectDetail = obj.implementingPartner ? 'partner' : null; - } - - const flowObj = { - refDirection: ref, - objectType: type, - objectID: obj.id, - behavior: obj.behavior || null, - objectDetail: obj.objectDetail, - }; - data.flowObjects.push(flowObj); - } - }); - }); - } - - return data as any; - }; - - const collapseCategories = (data: any) => { - data.categories = [ - data.flowType, - data.flowStatuses, - data.contributionTypes, - data.method, - data.childMethod, - data.keywords, - data.inactiveReason, - data.beneficiaryGroup, - data.pendingStatus, - data.earmarking !== null && data.earmarking.id, - ].filter((category) => category); - data.categories = data.categories - .map((value: any) => { - if (value && value.id) { - return value.id; - } else if (value[0]) { - return value[0].id; - } - }) - .filter(function (value: any) { - return value; - }) - .map((value: any) => { - return parseInt(value); - }); - - return data; - }; - const [uploadFileFlag, setUploadFileFlag] = useState(false); - const [uploadFlag, setUploadFlag] = useState(false); - const normalizeFlowData = (values: FormValues) => { - const fundingObject = { - src: { - governingEntity: values.sourceGoverningEntities.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - location: values.sourceLocations.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - organization: values.sourceOrganizations.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - project: values.sourceProjects.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - usageYear: values.sourceUsageYears.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - globalCluster: values.sourceGlobalClusters.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - emergency: values.sourceEmergencies.map((item) => ({ - id: item.value, - name: item.displayLabel, - restricted: item.restricted, - })), - plan: values.sourcePlans.map((item) => ({ - id: item.value, - name: item.displayLabel, - restricted: item.restricted, - })), - }, - dest: { - governingEntity: values.destinationGoverningEntities.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - location: values.destinationLocations.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - organization: values.destinationOrganizations.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - project: values.destinationProjects.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - usageYear: values.destinationUsageYears.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - globalCluster: values.destinationGlobalClusters.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - emergency: values.destinationEmergencies.map((item) => ({ - id: item.value, - name: item.displayLabel, - restricted: item.restricted, - })), - plan: values.destinationPlans.map((item) => ({ - id: item.value, - name: item.displayLabel, - restricted: item.restricted, - })), - }, - }; - - let data = { - id: isEdit && currentFlowID ? currentFlowID : null, - versionID: isEdit && currentVersionID ? currentVersionID : null, - amountUSD: values.amountUSD, - flowDate: dayjs(values.flowDate, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ), - decisionDate: values.decisionDate - ? dayjs(values.decisionDate, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ) - : null, - firstReportedDate: dayjs(values.firstReported, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ), - budgetYear: values.budgetYear, - origAmount: values.amountOriginal ? values.amountOriginal : null, - origCurrency: (values.origCurrency as AutoCompleteSelectionType) - ? (values.origCurrency as AutoCompleteSelectionType)?.displayLabel - : null, - exchangeRate: values.exchangeRateUsed ? values.exchangeRateUsed : null, - activeStatus: true, - restricted: false, - newMoney: true, - description: values.flowDescription, - versionStartDate: currentVersionData?.versionStartDate, - versionEndDate: currentVersionData?.versionEndDate, - flowObjects: collapseFlowObjects(fundingObject), - children: - values.childFlow && - values.childFlow.map((item: any, index: number) => { - return { - childID: JSON.parse(item.value as string).id, - origCurrency: JSON.parse(item.value as string).origCurrency, - }; - }), - parents: - values.parentFlow && - values.parentFlow.map((item: any, index: number) => { - return { - Parent: { - parentID: JSON.parse(item.value as string).id, - origCurrency: JSON.parse(item.value as string).origCurrency, - }, - childID: currentFlowID, - parentID: JSON.parse(item.value as string).id, - origCurrency: JSON.parse(item.value as string).origCurrency, - id: JSON.parse(item.value as string).id, - parents: - values.parentFlow && - values.parentFlow.map((key: any) => { - return { - child: JSON.parse(key.value as string).id, - parentID: 271736, - }; - }), - }; - }), - reportDetails: values.reportDetails.map((item, index) => { - return { - contactInfo: item.reporterContactInformation, - source: item.reportSource, - date: dayjs(item.reportedDate, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ), - versionID: currentVersionID, - newlyAdded: addReportFlag, - sourceID: null, - refCode: '7F-10073.04', - verified: true, - organizationID: item.reportedOrganization.value, - categories: [item.reportChannel && item.reportChannel.value], - organization: { - id: item.reportedOrganization.value, - name: item.reportedOrganization.displayLabel, - }, - reportFiles: - uploadFlag && - uploadedFileArray[index] && - (uploadedFileArray[index] as { id?: number })?.id - ? uploadFlag || uploadFileFlag - ? [ - { - title: item.reportUrlTitle, - type: 'url', - url: item.reportUrl, - }, - { - fileAssetID: - uploadedFileArray[index] && - (uploadedFileArray[index] as { id?: number })?.id, - reportFiles: [ - { - fieldType: 'file', - fileAssetID: - uploadedFileArray[index] && - (uploadedFileArray[index] as { id?: number })?.id, - type: 'file', - }, - ], - title: item.reportFileTitle, - type: 'file', - }, - ] - : [ - { - title: item.reportUrlTitle, - type: 'url', - url: item.reportUrl, - }, - ] - : uploadFileFlag - ? [ - { - title: item.reportUrlTitle, - type: 'url', - url: item.reportUrl, - }, - ] - : item.reportFiles - ? item.reportFiles - : [], - - reportChannel: { - group: 'reportChannel', - id: item.reportChannel && item.reportChannel.value, - name: item.reportChannel && item.reportChannel.displayLabel, - }, - }; - }), - flowType: { - id: values.flowType && values.flowType.value, - name: values.flowType && values.flowType.displayLabel, - group: 'flowType', - }, - keywords: values.keywords.map((item) => ({ - id: item.value, - name: item.displayLabel, - group: 'keywords', - })), - flowStatuses: { - id: values.flowStatus && values.flowStatus.value, - name: values.flowStatus && values.flowStatus.displayLabel, - group: 'flowStatus', - }, - contributionTypes: { - id: values.contributionType && values.contributionType.value, - name: values.contributionType && values.contributionType.displayLabel, - group: 'contributionType', - }, - method: { - id: values.method && values.method.value, - name: values.method && values.method.displayLabel, - group: 'method', - }, - childMethod: values.cashTransfer && { - id: values.cashTransfer.value, - name: values.cashTransfer.displayLabel, - group: 'method', - parentID: values.method && values.method.value, - }, - earmarking: values.earmarkingType - ? { - id: values.earmarkingType.value, - name: values.earmarkingType.displayLabel, - group: 'earmarkingType', - } - : null, - categories: [] as (string | number)[], - isCancellation: isPending ? true : !isPending ? false : null, - cancelled: isPending && isCancellation ? true : null, - pendingStatus: isPending ? true : !isPending ? false : [], - planEntities: isPending ? true : !isPending ? false : [], - planIndicated: isPending ? true : !isPending ? false : [], - isApprovedFlowVersion: - rejectFlag && approveFlag - ? true - : !(rejectFlag && approveFlag) - ? false - : null, - inactiveReason: [ - { - id: null as null | number | string, - name: '' as string | undefined, - description: null, - parentID: null, - code: null, - group: '', - includeTotals: null, - createdAt: '', - updatedAt: '', - }, - ], - isErrorCorrection: errorCorrection - ? true - : isSuperseded - ? true - : isPending - ? true - : !isSuperseded && !isPending - ? false - : null, - rejected: rejectFlag ? true : !rejectFlag ? false : null, - versions: - versionData && - versionData.map((item: VersionDataType) => { - const items = { - id: item.flowId, - versionID: item.versionId, - activeStatus: item.activeStatus, - isPending: item.isPending ? item.isPending : false, - isCancelled: item.isCancelled ? item.isCancelled : false, - }; - return items; - }), - ...fundingObject, - }; - - data = collapseCategories(data); - return data; - }; - - const [unsavedChange, setUnsavedChange] = useState(false); - const [parentCurrencyFlag, setParentCurrencyFlag] = useState(false); - const [childCurrencyFlag, setChildCurrencyFlag] = useState(false); - const [approveFlag, setApproveFlag] = useState(false); - const [rejectFlag, setRejectFlag] = useState(false); - const [validationFlag, setValidationFlag] = useState(false); - const [inactiveFlag, setInactiveFlag] = useState(false); - const [uploadedFileArray, setUploadedFileArray] = useState([ - {}, - ]); - const [addReportFlag, setAddReportFlag] = useState(false); - const [alertFlag, setAlertFlag] = useState(false); - const [sharePath, setSharePath] = useSharePath(''); - const [readOnly, setReadOnly] = useState(false); - const [linkCheck, setLinkCheck] = useState(false); - const handleSave = () => { - window.scrollTo({ top: 0, behavior: 'smooth' }); - }; - - const [showWarningMessage, setShowWarningMessage] = useState(false); - const [objects, setObjects] = useState>({}); - const [showingTypes, setShowingTypes] = useState([]); - const [newMoneyCheckboxDisabled, setNewMoneyCheckboxDisabled] = - useState(false); - - const [comparingVersions, setComparingVersions] = useState( - [] - ); - const [comparedVersions, setComparedVersions] = useState( - [] - ); - const [showSourceGoverningEntities, handleShowSourceGoverningEntities] = - useState(false); - const [ - showDestinationGoverningEntities, - handleShowDestinationGoverningEntities, - ] = useState(false); - const [sourceGoverningEntities, setSourceGoverningEntities] = - useState([]); - const [destinationGoverningEntities, setDestinationGoverningEntities] = - useState([]); - const [isShowParentFlow, setShowParentFlow] = useState( - initialValue.parentFlow && initialValue.parentFlow.length ? true : false - ); - const [isShowChildFlow, setShowChildFlow] = useState(0); - const [openAlerts, setOpenAlerts] = useState< - { message: string; id: number }[] - >([]); - const [alertId, setAlertId] = useState(0); - const handleClose = (id: number) => { - setOpenAlerts(openAlerts.filter((alert) => alert.id !== id)); - }; - const buttonText = 'Calculate The Exchange Rate'; - - const handleCalculateExchangeRate = (values: any, setFieldValue: any) => { - const { amountOriginal, amountUSD } = values; - - if (amountOriginal && amountUSD) { - const exchangeRateUsed = amountOriginal / amountUSD; - setFieldValue('exchangeRateUsed', exchangeRateUsed.toFixed(4)); - } else if (amountOriginal && !amountUSD) { - const calculatedAmountUSD = amountOriginal / values.exchangeRateUsed; - setFieldValue('amountUSD', calculatedAmountUSD.toFixed(4)); - } else if (!amountOriginal && amountUSD) { - const calculatedAmountOriginal = amountUSD * values.exchangeRateUsed; - setFieldValue('amountOriginal', calculatedAmountOriginal.toFixed(4)); - } else { - console.warn('Both original amount and USD amount are missing.'); - } - }; - useEffect(() => { - if (initialValue?.childFlow) { - setShowChildFlow(initialValue?.childFlow.length); - } - }, [initialValue]); - useEffect(() => { - const fileAssets: FileAssetEntityType[] = []; - if (isEdit) { - initialValue.reportDetails.forEach((detail: any) => { - if (detail?.fileAsset) { - fileAssets.push(detail.fileAsset); - setUploadedFileArray(fileAssets); - } else { - fileAssets.push({} as FileAssetEntityType); - setUploadedFileArray(fileAssets); - } - }); - } - }, [initialValue.reportDetails]); - useEffect(() => { - if (currentVersionActiveStatus) { - setReadOnly(false); - } else { - setReadOnly(true); - } - }, [currentVersionActiveStatus]); - useEffect(() => { - if (initialValue.parentFlow && initialValue.parentFlow.length) { - setShowParentFlow(true); - } - }, [initialValue.parentFlow]); - const [remove, setRemove] = useState(false); - const handleRemove = (index: number, values: FormValues) => { - if (window.confirm('Are you sure you want to remove this file?')) { - if ( - initialValue.reportDetails[index].reportFiles && - initialValue.reportDetails[index].reportFiles[0]?.fileName - ) { - values.reportDetails[index].reportFileTitle = ''; - initialValue.reportDetails[index].reportFiles[0].fileName = ''; - initialValue.reportDetails[index].reportFiles[0].title = ''; - initialValue.reportDetails[index].reportFiles[0].fileAssetID = - undefined; - initialValue.reportDetails[index].reportFiles[0].UploadFileUrl = ''; - const updatedArray = removeByIndexFromArray(uploadedFileArray, index); - setUploadedFileArray(updatedArray); - } else return; - setUploadFlag(false); - setRemove(true); - } else return; - }; - const removeByIndexFromArray = (array: UploadedItem[], index: number) => { - const newArray = [...array]; - newArray[index] = {}; - return newArray; - }; - if (remove === true) setRemove(false); - const SourceLink = ( - setFieldValue: any, - values: FormValues, - indexKey: number, - index: number - ) => { - setFieldValue( - `reportDetails[${index}].reportedOrganization`, - values.sourceOrganizations[indexKey] - ); - }; - const DestinationLink = ( - setFieldValue: any, - values: FormValues, - indexKey: number, - index: number - ) => { - setFieldValue( - `reportDetails[${index}].reportedOrganization`, - values.destinationOrganizations[indexKey] - ); - }; - - interface Inconsistency { - type: string; - values: { - name?: string; - year?: string; - refDirection: string; - options?: { name: string }[]; - }[]; - } - - const processDataInconsistencies = ( - inconsistencyArray: Inconsistency[] - ): string => { - let message = ''; - inconsistencyArray.forEach((inconsistencyWith) => { - if (inconsistencyWith && inconsistencyWith.type) { - const inconsistencyType = inconsistencyWith.type; - message += - inconsistencyType.charAt(0).toUpperCase() + - inconsistencyType.slice(1) + - ': '; - - if (inconsistencyWith.type === 'no-direct-link') { - message += inconsistencyWith.values.join(', '); - } else { - message += - inconsistencyWith.values - .map((value) => { - const name = value.name || value.year; - let joinedOptions = ''; - if (value.options) { - joinedOptions = value.options - .map((option) => { - return option.name || JSON.stringify(option); - }) - .join(', '); - } - const options = `is not in the list of acceptable ${value.refDirection} ${inconsistencyType}: [${joinedOptions}]`; - return `'${name}' ${options}`; - }) - .join(', ') + '. '; - } - } else { - message += JSON.stringify(inconsistencyArray); - } - }); - return message; - }; - - const handleSubmit = async ( - values: FormValues, - submitAction: string | undefined - ) => { - if (values.childFlow) { - for (let i = 0; i < values.childFlow.length; i++) { - if ( - values.destinationUsageYears.length >= 2 && - JSON.parse(values.childFlow[i].value as string).activeStatus === true - ) { - values.flowType = { - displayLabel: 'Parked', - value: '1252', - }; - } - } - } - if (isShowParentFlow && isShowChildFlow > 0) { - let childAmountSum = 0; - let parentAmountSum = 0; - values.childFlow && - values.childFlow.map((item, _index) => { - childAmountSum += JSON.parse(item.value.toString()) - ? parseInt(JSON.parse(item.value.toString()).amountUSD) - : 0; - }); - values.parentFlow && - values.parentFlow.map((item, _index) => { - parentAmountSum += JSON.parse(item.value.toString()) - ? parseInt(JSON.parse(item.value.toString()).amountUSD) - : 0; - }); - if (childAmountSum > parentAmountSum) { - if ( - !window.confirm( - `Please note, the Funding Amount on this parent flow ($${parentAmountSum}) is less than the sum of its children's amount ($${childAmountSum}). Do you want to proceed?` - ) - ) { - return; - } - } - } - if (isShowParentFlow || isShowChildFlow > 0) { - let childAmountSum = 0; - values.childFlow && - values.childFlow.map((item, _index) => { - childAmountSum += JSON.parse(item.value.toString()) - ? parseInt(JSON.parse(item.value.toString()).amountUSD) - : 0; - }); - if (childAmountSum > values.amountUSD) { - if ( - !window.confirm( - `Please note, the Funding Amount on this parent flow ($${values.amountUSD}) is less than the sum of its children's amount ($${childAmountSum}). Do you want to proceed?` - ) - ) - return; - } - } - const parentFlow = values.parentFlow; - if (parentFlow?.length) { - for (let index = 0; index < parentFlow.length; index++) { - const item = parentFlow[index]; - if ( - (typeof values?.origCurrency !== 'string' && - values.origCurrency?.displayLabel) || - !( - JSON.parse(item.value.toString()) && - JSON.parse(item.value.toString())?.origCurrency === null - ) - ) { - if ( - (typeof values?.origCurrency !== 'string' && - values.origCurrency?.displayLabel) !== - (JSON.parse(item.value.toString()) && - JSON.parse(item.value.toString())?.origCurrency) - ) { - handleSave(); - setParentCurrencyFlag(true); - return; - } - } - } - } - const childFlow = values.childFlow; - if (childFlow) { - for (let index = 0; index < childFlow.length; index++) { - const item = childFlow[index]; - if ( - (typeof values?.origCurrency !== 'string' && - values.origCurrency?.displayLabel) || - !( - JSON.parse(item.value.toString()) && - JSON.parse(item.value.toString())?.origCurrency === null - ) - ) { - if ( - (typeof values.origCurrency !== 'string' && - values.origCurrency?.displayLabel) !== - (JSON.parse(item.value.toString()) && - JSON.parse(item.value.toString()).origCurrency) - ) { - handleSave(); - setChildCurrencyFlag(true); - return; - } - } - } - } - for (let i = 0; i < values.reportDetails.length; i++) { - if ( - values.reportDetails[i].reportUrlTitle && - values.reportDetails[i].reportUrl - ) { - setUploadFileFlag(true); - } else setUploadFileFlag(false); - } - const data = normalizeFlowData(values); - const inactiveReasons = await fetchCategory('inactiveReason')(); - if (submitAction === 'approve') { - data.isApprovedFlowVersion = true; - } else if (submitAction === 'rejected') { - data.activeStatus = false; - data.rejected = true; - data.inactiveReason = [ - { - id: - inactiveReasons.find( - (item: any) => item.displayLabel === 'Rejected' - )?.value || null, - name: inactiveReasons.find( - (item: any) => item.displayLabel === 'Rejected' - )?.displayLabel, - description: null, - parentID: null, - code: null, - group: 'inactiveReason', - includeTotals: null, - createdAt: currentVersionData - ? dayjs(currentVersionData.createdAt, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ) - : '', - updatedAt: currentVersionData - ? dayjs(currentVersionData.updatedAt, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ) - : '', - }, - ]; - } else if (submitAction === 'inactive') { - if (isShowParentFlow || isShowChildFlow > 0) { - setInactiveFlag(true); - } else { - const categoryValue = - inactiveReasons.find((item: any) => item.displayLabel === 'Cancelled') - ?.value ?? null; - if (categoryValue) { - data.categories.push(parseInt(categoryValue.toString())); - } - data.activeStatus = false; - data.cancelled = true; - data.isCancellation = null; - data.rejected = null; - data.newMoney = false; - data.inactiveReason = [ - { - id: - inactiveReasons.find( - (item: any) => item.displayLabel === 'Cancelled' - )?.value || null, - name: inactiveReasons.find( - (item: any) => item.displayLabel === 'Cancelled' - )?.displayLabel, - description: null, - parentID: null, - code: null, - group: 'inactiveReason', - includeTotals: null, - createdAt: currentVersionData ? currentVersionData.createdAt : '', - updatedAt: currentVersionData ? currentVersionData.updatedAt : '', - }, - ]; - } - } - if (!inactiveFlag) { - const response = await env.model.flows.validateFlow(data); - let flag = true; - let mismatchFound = false; - for (let i = 0; i < values.reportDetails.length; i++) { - const reportOrganizationLabel = - values.reportDetails[i].reportedOrganization.displayLabel; - const reportMatchesSource = values.sourceOrganizations.some( - (sourceOrg) => sourceOrg.displayLabel === reportOrganizationLabel - ); - const reportMatchesDestination = values.destinationOrganizations.some( - (destOrg) => destOrg.displayLabel === reportOrganizationLabel - ); - - if (!reportMatchesSource && !reportMatchesDestination) { - mismatchFound = true; - break; - } - } - if (mismatchFound) { - if ( - !window.confirm( - "Your flow's Report Detail organization doesn't match the source or destination organization or that of its parked parent. Are you sure this is right?" - ) - ) { - return; - } - } - response.forEach((obj) => { - if (obj) { - const { success, message, confirmed } = obj; - if (!success) { - if (confirmed) { - const confirm = window.confirm(confirmed); - if (!confirm) { - setOpenAlerts([...openAlerts, { message, id: alertId }]); - setAlertId((prevId) => prevId + 1); - flag = false; - handleSave(); - } - } else if (message) { - setOpenAlerts([...openAlerts, { message, id: alertId }]); - setAlertId((prevId) => prevId + 1); - flag = false; - handleSave(); - } - } - } - }); - if (flag && !(isShowParentFlow || isShowChildFlow > 0)) { - setUnsavedChange(false); - if (!isEdit) { - try { - const response = await env.model.flows.createFlow({ flow: data }); - const path = editFlowSetting(response.id, response.versionID); - window.open(path, '_self'); - } catch (err: any) { - setOpenAlerts([ - ...openAlerts, - { message: err.message, id: alertId }, - ]); - setAlertId((prevId) => prevId + 1); - handleSave(); - } - } else { - const dbFlow = await env.model.flows.getFlowREST({ - id: currentFlowID!, - }); - if ( - (versionData && - currentVersionID && - Date.parse(versionData[currentVersionID - 1].updatedTime) < - Date.parse(dbFlow.updatedAt)) || - (versionData && versionData.length < dbFlow.versions.length) - ) { - window.confirm( - 'This flow cannot be saved, as a concurrency conflict has been detected. Please refresh your screen to view the most up to date data.' - ); - } else { - if (isPending && (approveFlag || rejectFlag)) { - if ( - allFieldsReviewed || - pendingFieldsAllApplied || - !pendingVersionV1 - ) { - try { - const response = await env.model.flows.updatePendingFlow({ - flow: data, - }); - if (response) { - const path = editFlowSetting( - response.id, - response.versionID - ); - setAlertFlag(true); - setSharePath(path); - } - } catch (err: any) { - setOpenAlerts([ - ...openAlerts, - { message: err.message, id: alertId }, - ]); - setAlertId((prevId) => prevId + 1); - handleSave(); - } - } else { - window.confirm( - 'Some of the revised data on this flow still needs to be accepted or rejected before this update can be approved.' - ); - } - } else { - try { - const response = await env.model.flows.updateFlow({ - flow: data, - }); - if (response) { - const path = editFlowSetting(response.id, response.versionID); - setAlertFlag(true); - setSharePath(path); - } - } catch (err: any) { - let errmessage = ''; - if (err.reason) { - const inconsistencyObject = err.reason; - errmessage = processDataInconsistencies(inconsistencyObject); - } else { - const lastIndex = err.message.lastIndexOf(':'); - errmessage = err.message.substring(lastIndex + 1); - } - setOpenAlerts([ - ...openAlerts, - { message: errmessage, id: alertId }, - ]); - setAlertId((prevId) => prevId + 1); - handleSave(); - } - } - } - } - } - } - }; - const navigate = useNavigate(); - const handleCopy = (values: FormValues) => { - if (currentFlowID && currentVersionID) { - const isCopy = true; - const path = copyFlow(); - if (typeof path === 'string') { - const valuesWithFiles = { ...values, isCopy }; - navigate(path, { state: valuesWithFiles }); - } else { - console.error('Path is not a string', path); - } - } - }; - - const handleAlert = (values: FormValues) => { - const errors = validateForm(values); - if (Object.keys(errors).length !== 0) { - setValidationFlag(true); - handleSave(); - } - }; - - const setObjectsWithArray = ( - fetchedObject: any, - objectKeys: string[], - settingArrayKeys: string[], - setFieldValue: any, - values: any - ) => { - const newObjects = { ...objects }; - const newShowingTypes = [...showingTypes]; - objectKeys.forEach((key, i) => { - if (fetchedObject[settingArrayKeys[i]]) { - newObjects[key] = checkIfExistingAndCopy( - newObjects[key], - fetchedObject, - settingArrayKeys[i] - ); - } - - const parsedResponse = newObjects[key].map((responseValue: any) => { - if (settingArrayKeys[i] === 'years') { - return { - displayLabel: - (responseValue as usageYears.UsageYear).year || - responseValue.displayLabel, - value: responseValue.id || responseValue.value, - isAutoFilled: responseValue.suggested, - }; - } else if (settingArrayKeys[i] === 'plans') { - return { - displayLabel: - (responseValue.planVersion as { planId: number; name: string }) - .name || responseValue.displayLabel, - value: responseValue.planVersion.planId || responseValue.value, - isAutoFilled: responseValue.suggested, - }; - } else if (settingArrayKeys[i] === 'governingEntities') { - return { - displayLabel: - ( - responseValue.governingEntityVersion as { - id: number; - name: string; - } - ).name || responseValue.displayLabel, - value: - responseValue.governingEntityVersion.id || responseValue.value, - isAutoFilled: responseValue.suggested, - }; - } else { - return { - displayLabel: - (responseValue as { id: number; name: string }).name || - responseValue.displayLabel, - value: responseValue.id || responseValue.value, - isAutoFilled: responseValue.suggested, - }; - } - }); - newObjects[key].forEach((obj) => { - if (obj?.suggested) { - updateFlowObjects(key, parsedResponse, setFieldValue, values); - obj.suggested = false; - } - }); - setFieldValue(key, parsedResponse); - }); - - setObjects(newObjects); - setShowingTypes(newShowingTypes); - }; - - const checkIfExistingAndCopy = ( - existingObjects: any[], - object: any, - key: string - ): any[] => { - let newObjects = object[key]; - if (key === 'locations') { - newObjects = newObjects.filter(function (location: any) { - return location.adminLevel === 0; - }); - if (existingObjects && existingObjects.length) { - existingObjects = existingObjects.filter(function (location) { - return location.adminLevel === 0 || location.value; - }); - } - } - - if (existingObjects && existingObjects.length) { - const existingObjectsIds = existingObjects.map(function (o) { - return o.id || o.value; - }); - if (Array.isArray(newObjects)) { - newObjects.forEach(function (obj) { - if (existingObjectsIds.indexOf(obj.id) === -1) { - obj.suggested = true; - existingObjects.push(obj); - } - }); - } else { - if (existingObjectsIds.indexOf(newObjects.id) === -1) { - newObjects.suggested = true; - existingObjects.push(newObjects); - } - } - } else { - if (newObjects) { - if (Array.isArray(newObjects)) { - newObjects.forEach(function (obj) { - obj.suggested = true; - }); - existingObjects = newObjects; - } else { - newObjects.suggested = true; - existingObjects = [newObjects]; - } - } - } - return existingObjects; - }; - const fetchPlanDetails = async ( - objectType: string, - plan: any, - setFieldValue: any, - values?: any - ) => { - const fetchedPlan = await environment.model.plans.getPlan(plan[0].value); - if (objectType === 'sourcePlans') { - setObjectsWithArray( - fetchedPlan, - ['sourceUsageYears', 'sourceEmergencies'], - ['years', 'emergencies'], - setFieldValue, - values - ); - setSourceGoverningEntities(fetchedPlan.governingEntities); - } - if (objectType === 'destinationPlans') { - setObjectsWithArray( - fetchedPlan, - ['destinationUsageYears', 'destinationEmergencies'], - ['years', 'emergencies'], - setFieldValue, - values - ); - setDestinationGoverningEntities(fetchedPlan.governingEntities); - } - if (fetchedPlan.locations) { - const countries = fetchedPlan.locations.filter(function (loc: any) { - return loc.adminLevel === 0; - }); - if (countries.length === 1) { - if (objectType === 'sourcePlans') { - setObjectsWithArray( - { locations: countries }, - ['sourceLocations'], - ['locations'], - setFieldValue, - values - ); - } - if (objectType === 'destinationPlans') { - setObjectsWithArray( - { locations: countries }, - ['destinationLocations'], - ['locations'], - setFieldValue, - values - ); - } - } - } - }; - - const fetchEmergencyDetails = async ( - objectType: string, - emergency: any, - setFieldValue: any, - values?: any - ) => { - if (objectType === 'destinationEmergencies') { - const fetchedEmergency = await environment.model.emergencies.getEmergency( - emergency[0].value - ); - if (fetchedEmergency.locations.length <= 1) { - setObjectsWithArray( - fetchedEmergency, - ['destinationLocations'], - ['locations'], - setFieldValue, - values - ); - } - } - }; - const fetchProjectDetails = async ( - objectType: string, - project: any, - setFieldValue: any, - values?: any - ) => { - const fetchedProject = await environment.model.projects.getProject( - project[0].value - ); - const publishedVersion = fetchedProject.projectVersions.filter(function ( - version: any - ) { - return version.id === fetchedProject.currentPublishedVersionId; - })[0]; - if (objectType === 'destinationProjects') { - const fetchedCategories = - await environment.model.categories.getCategories({ - query: 'earmarkingType', - }); - const category = fetchedCategories.filter( - (item: any) => item.name === 'Earmarked' - ); - setFieldValue('earmarkingType', { - value: category[0], - displayLabel: category[0].name, - }); - setObjectsWithArray( - publishedVersion, - [ - 'destinationPlans', - 'destinationLocations', - 'destinationGoverningEntities', - 'destinationGlobalClusters', - 'destinationOrganizations', - ], - [ - 'plans', - 'locations', - 'governingEntities', - 'globalClusters', - 'organizations', - ], - setFieldValue, - values - ); - } else { - setObjectsWithArray( - publishedVersion, - [ - 'sourcePlans', - 'sourceLocations', - 'sourceGoverningEntities', - 'sourceGlobalClusters', - 'sourceOrganizations', - ], - [ - 'plans', - 'locations', - 'governingEntities', - 'globalClusters', - 'organizations', - ], - setFieldValue, - values - ); - } - }; - const fetchOrganizationDetails = async ( - objectType: string, - organization: any, - setFieldValue: any, - values?: any - ) => { - const fetchedOrg = - await environment.model.organizations.getOrganizationsById( - organization[0].value - ); - const isGovernment = (fetchedOrg[0].categories ?? []).some(function ( - category: any - ) { - return ( - category.group === 'organizationType' && - [114, 123].includes(category.id) - ); - }); - if (isGovernment && objectType === 'sourceOrganizations') { - objects.sourceLocations = checkIfExistingAndCopy( - objects.location, - fetchedOrg[0], - 'locations' - ); - setObjectsWithArray( - objects, - ['sourceLocations'], - ['locations'], - setFieldValue, - values - ); - } - }; - const fetchAssociatedGoverningEntity = async ( - objectType: string, - globalCluster: any, - setFieldValue: any, - values?: any - ) => { - if ( - (values.sourcePlans.length === 0 && - objectType === 'sourceGlobalClusters') || - (values.destinationPlans.length === 0 && - objectType === 'destinationGlobalClusters') - ) { - return; - } - let plan = null; - let targetGoverningEntities: any = null; - if (objectType === 'sourceGlobalClusters') { - plan = values.sourcePlans[0]; - targetGoverningEntities = values.sourceGoverningEntities; - } else { - plan = values.destinationPlans[0]; - targetGoverningEntities = values.destinationGoverningEntities; - } - const fetchedGoverningEntities = - await environment.model.governingEntities.getAllPlanGoverningEntities( - plan.value - ); - const hasGoverningEntitiesWithoutGlobalCluster = - Array.isArray(targetGoverningEntities) && - fetchedGoverningEntities - .filter(function (fetchedGe: any) { - return targetGoverningEntities.find(function (selectedGe: any) { - return fetchedGe.id === selectedGe.value; - }); - }) - .some(function (fetchedGe: any) { - return ( - Array.isArray(fetchedGe.globalClusterIds) && - !fetchedGe.globalClusterIds.length - ); - }); - - if (hasGoverningEntitiesWithoutGlobalCluster) { - return; - } - const governingEntities = fetchedGoverningEntities.filter(function ( - governingEntity: any - ) { - return ( - governingEntity.globalClusterIds.indexOf( - globalCluster[globalCluster.length - 1].value - ) > -1 - ); - }); - - if (governingEntities.length) { - governingEntities.forEach(function (governingEntity: any) { - setObjectsWithArray( - { governingEntities: governingEntity }, - [ - objectType === 'sourceGlobalClusters' - ? 'sourceGoverningEntities' - : 'destinationGoverningEntities', - ], - ['governingEntities'], - setFieldValue, - values - ); - }); - } - }; - - const fetchKeywords = async ( - objectType: string, - usageYears: any, - setFieldValue: any, - values?: any - ) => { - if (usageYears.length === 2) { - const fetchedCategories = - await environment.model.categories.getCategories({ - query: 'keywords', - }); - const category = fetchedCategories.filter( - (item: any) => item.name === 'Multiyear' - ); - - const mergedKeywords = [ - ...values.keywords, - ...[ - { - value: category[0].id, - displayLabel: category[0].name, - }, - ].filter( - (item2) => - !values.keywords.some((item1: any) => item1.value === item2.value) - ), - ]; - - setFieldValue('keywords', mergedKeywords); - } else if (usageYears.length === 1) { - const filteredKeywords = values.keywords.filter( - (item: any) => item.displayLabel !== 'Multiyear' - ); - setFieldValue('keywords', filteredKeywords); - } - }; - - const handleCompareCheck = ( - checkedVersion: VersionDataType, - isChecked: boolean - ) => { - setComparingVersions((prev: VersionDataType[]) => { - if (isChecked) { - return [...prev, checkedVersion]; - } else { - return prev.filter( - (version: VersionDataType) => - version.versionId !== checkedVersion.versionId - ); - } - }); - }; - - const fetchDownload = async (index: number) => { - const fileAssetID = - initialValue.reportDetails[index]?.reportFiles[0]?.fileAssetID; - const name = initialValue.reportDetails[index]?.reportFiles[0]?.fileName; - if (fileAssetID) { - try { - const responseData = - await environment?.model.fileUpload.fileDownloadModel(fileAssetID); - if (responseData) { - const data = new Blob([responseData]); - const url = URL.createObjectURL(data); - const a = document.createElement('a'); - a.href = url; - a.download = `${name ? name : 'downloaded_file'}`; - document.body.appendChild(a); - a.click(); - setTimeout(() => { - document.body.removeChild(a); - window.URL.revokeObjectURL(url); - }, 0); - } else { - console.error('No data received for download'); - } - } catch (error) { - console.error(error, 'error'); - } - } - }; - - const fetchCategory = useCallback( - (category: string) => { - return async () => { - const response = await environment.model.categories.getCategories({ - query: category, - }); - return response.map( - (responseValue: any): categoryType => ({ - displayLabel: responseValue.name, - value: responseValue.id.toString(), - parentID: responseValue.parentID, - }) - ); - }; - }, - [environment] - ); - const extractUniqueFromArray = (array1: string[], array2: string[]) => { - return array1.filter((item: string) => !array2.includes(item)); - }; - - const compareVersions = (versions: VersionDataType[]) => { - const version1 = versions[0]; - const version2 = versions[1]; - const newVersion1 = { - ...version1, - uniqueSources: objectTypes.reduce>( - (acc, type) => { - acc[type] = extractUniqueFromArray( - version1.source[type], - version2.source[type] - ); - return acc; - }, - {} - ), - uniqueDestinations: objectTypes.reduce>( - (acc, type) => { - acc[type] = extractUniqueFromArray( - version1.destination[type], - version2.destination[type] - ); - return acc; - }, - {} - ), - uniqueCategories: extractUniqueFromArray( - version1.categories, - version2.categories - ), - }; - - const newVersion2 = { - ...version2, - uniqueSources: objectTypes.reduce>( - (acc, type) => { - acc[type] = extractUniqueFromArray( - version2.source[type], - version1.source[type] - ); - return acc; - }, - {} - ), - uniqueDestinations: objectTypes.reduce>( - (acc, type) => { - acc[type] = extractUniqueFromArray( - version2.destination[type], - version1.destination[type] - ); - return acc; - }, - {} - ), - uniqueCategories: extractUniqueFromArray( - version2.categories, - version1.categories - ), - }; - return [newVersion1, newVersion2]; - }; - const handleFileChange = async ( - event: React.ChangeEvent, - index: number - ) => { - setUploadFlag(true); - try { - const setFile: File | undefined = (event.target as HTMLInputElement) - .files?.[0]; - if (setFile instanceof File) { - const responseData = - await environment.model.fileUpload.fileUploadModel(setFile); - setUploadedFileArray((prevUploadedFile) => { - const updateUploadedFile = [...prevUploadedFile]; - updateUploadedFile[index] = responseData; - return updateUploadedFile; - }); - console.log(uploadedFileArray, 'uploadedFileArray'); - } else { - console.error('No file selected for upload.'); - } - } catch (error) { - console.log(error, 'error'); - } - }; - useEffect(() => { - if (comparingVersions.length === 2) { - const compared = compareVersions(comparingVersions); - setComparedVersions(compared); - } - }, [comparingVersions]); - - useEffect(() => { - const handleBeforeUnload = (event: BeforeUnloadEvent) => { - if (unsavedChange) { - const message = - 'You have unsaved changes! Are you sure you want to leave?'; - event.returnValue = message; // Standard for most browsers - return message; // For some older browsers - } - }; - - window.addEventListener('beforeunload', handleBeforeUnload); - - return () => { - window.removeEventListener('beforeunload', handleBeforeUnload); - }; - }, [unsavedChange]); - - useEffect(() => { - const valuesObject: Record = { - sourceOrganizations: initialValue.sourceOrganizations, - sourceLocations: initialValue.sourceLocations, - sourceUsageYears: initialValue.sourceUsageYears, - sourceProjects: initialValue.sourceProjects, - sourcePlans: initialValue.sourcePlans, - sourceGoverningEntities: initialValue.sourceGoverningEntities, - sourceGlobalClusters: initialValue.sourceGlobalClusters, - sourceEmergencies: initialValue.sourceEmergencies, - destinationOrganizations: initialValue.destinationOrganizations, - destinationLocations: initialValue.destinationLocations, - destinationUsageYears: initialValue.destinationUsageYears, - destinationProjects: initialValue.destinationProjects, - destinationPlans: initialValue.destinationPlans, - destinationGoverningEntities: initialValue.destinationGoverningEntities, - destinationGlobalClusters: initialValue.destinationGlobalClusters, - destinationEmergencies: initialValue.destinationEmergencies, - }; - setObjects(valuesObject); - }, []); - - unstable_usePrompt({ - message: 'You have unsaved changes! Are you sure you want to leave?', - when: unsavedChange, - }); - const dictExecutedForEachObject: Record< - string, - ( - objectType: string, - flowObject: any, - setFieldValue: any, - values: any - ) => Promise - > = { - sourcePlans: fetchPlanDetails, - destinationPlans: fetchPlanDetails, - destinationEmergencies: fetchEmergencyDetails, - sourceProjects: fetchProjectDetails, - destinationProjects: fetchProjectDetails, - sourceOrganizations: fetchOrganizationDetails, - sourceGlobalClusters: fetchAssociatedGoverningEntity, - destinationGlobalClusters: fetchAssociatedGoverningEntity, - sourceUsageYears: fetchKeywords, - destinationUsageYears: fetchKeywords, - }; - - const params: DeleteFlowParams = { - VersionID: currentVersionID ?? 0, - FlowID: currentFlowID ?? 0, - }; - - const deleteFlow = async () => { - if (linkCheck || isShowParentFlow || isShowChildFlow > 0) { - window.confirm( - 'All linked flows must be unlinked before this flow can be deleted. Unlink flows and choose Delete flow again.' - ); - return; - } - - try { - const response = await env.model.flows.deleteFlow(params); - const path = flows(); - window.open(path, '_self'); - } catch (err: any) { - setOpenAlerts([...openAlerts, { message: err.message, id: alertId }]); - setAlertId((prevId) => prevId + 1); - } - }; - const updateFlowObjects = async ( - objectType: string, - flowObject: any, - setFieldValue: any, - values?: any - ) => { - if (flowObject.length > 0 && dictExecutedForEachObject[objectType]) { - flowObject.sort( - ( - a: { displayLabel: string; value: number }, - b: { displayLabel: string; value: number } - ) => { - return a.displayLabel.localeCompare(b.displayLabel); - } - ); - await dictExecutedForEachObject[objectType]( - objectType, - flowObject, - setFieldValue, - values - ); - } - if (objectType === 'sourcePlans') { - handleShowSourceGoverningEntities(flowObject.length !== 0); - } - if (objectType === 'destinationPlans') { - handleShowDestinationGoverningEntities(flowObject.length !== 0); - } - }; - const handleParentLinkedFlow = ( - values: any, - setFieldValue: any, - index: number - ) => { - setFieldValue( - 'parentFlow', - values['parentFlow'].filter((_item: any, ind: number) => ind !== index) - ); - }; - const handleChildFlow = (values: any, setFieldValue: any, index: number) => { - setFieldValue( - 'childFlow', - values['childFlow'].filter((_item: any, ind: number) => ind !== index) - ); - }; - const validateForm = (values: FormValues) => { - setUnsavedChange(JSON.stringify(values) !== JSON.stringify(initialValue)); - const valuesObject: Record = { - sourceOrganizations: values.sourceOrganizations, - sourceLocations: values.sourceLocations, - sourceUsageYears: values.sourceUsageYears, - sourceProjects: values.sourceProjects, - sourcePlans: values.sourcePlans, - sourceGoverningEntities: values.sourceGoverningEntities, - sourceGlobalClusters: values.sourceGlobalClusters, - sourceEmergencies: values.sourceEmergencies, - destinationOrganizations: values.destinationOrganizations, - destinationLocations: values.destinationLocations, - destinationUsageYears: values.destinationUsageYears, - destinationProjects: values.destinationProjects, - destinationPlans: values.destinationPlans, - destinationGoverningEntities: values.destinationGoverningEntities, - destinationGlobalClusters: values.destinationGlobalClusters, - destinationEmergencies: values.destinationEmergencies, - }; - setObjects(valuesObject); - const result = validationSchema.decode(values); - if (isRight(result)) { - setValidationFlag(false); - return {}; - } else { - const errors: Record[]> = {}; - Object.keys(values).forEach((key) => { - const value = values[key as keyof FormValues]; - if ( - result.left.some((err) => err.context.find((ctx) => ctx.key === key)) - ) { - const errorKey = key as keyof FormikErrors; - if (!value) { - errors[errorKey] = 'This field is required.'; - } else if (Array.isArray(value) && value.length === 0) { - errors[errorKey] = 'This field is required.'; - } - } - if ( - key === 'amountUSD' && - (value === 0 || (value && (value === '0' || (value as number) < 0))) - ) { - errors['amountUSD'] = 'The amount must be greater than zero.'; - } - if (key === 'flowType' && !value) { - errors['flowType'] = 'This field is required.'; - } - if (key === 'method' && !value) { - errors['method'] = 'This field is required.'; - } - if (key === 'reportDetails') { - const res = result.left.filter((err) => - err.context.find((ctx) => ctx.key === key) - )[0].value; - if (res && Array.isArray(res)) { - const reportDetailError: Record[] = []; - res.forEach((_, index) => { - const error: Record = {}; - if (res[index].reportChannel === '') { - error['reportChannel'] = 'This field is required.'; - } else { - error['reportChannel'] = ''; - } - if (!res[index].reportedDate) { - error['reportedDate'] = 'This field is required.'; - } else { - error['reportedDate'] = ''; - } - console.log(res[index], '-------------->'); - if ( - (res[index].reportFileTitle === '' || - res[index].reportFileTitle === undefined) && - (uploadedFileArray[index] && - (uploadedFileArray[index] as { id?: number })?.id - ? true - : false) - ) { - error['reportFileTitle'] = 'This field is required.'; - } else { - error['reportFileTitle'] = ''; - } - if ( - res[index].reportedOrganization === null || - res[index].reportedOrganization.displayLabel === '' - ) { - error['reportedOrganization'] = 'This field is required.'; - } else { - error['reportedOrganization'] = ''; - } - - if (Object.keys(error).length > 0) { - (reportDetailError as Record[]).push(error); - } - }); - - if (reportDetailError.length >= res.length) { - res.forEach((_, index) => { - if ( - res[index].reportChannel !== '' && - res[index].reportedOrganization !== '' && - res[index].reportedDate !== '' - ) { - if ( - (res[index].reportFileTitle === undefined || - res[index].reportFileTitle === '') && - (uploadedFileArray[index] && - (uploadedFileArray[index] as { id?: number })?.id - ? false - : true) - ) { - return {}; - } else if ( - res[index].reportFileTitle !== undefined && - res[index].reportFileTitle !== '' && - uploadedFileArray[index] - ) { - return {}; - } else { - errors['reportDetails'] = reportDetailError; - } - } else { - errors['reportDetails'] = reportDetailError; - } - }); - } - } - } - }); - console.log(errors, 'errors'); - if (Object.keys(errors).length === 0) setValidationFlag(false); - return errors; - } - }; - const handleParentFlow = ( - values: any, - parentValueString: string, - setValues: any - ) => { - parentValue = parentValueString; - const defaultValueParent: flowsResponse.GetFlowResult = - JSON.parse(parentValueString); - - const indexOrgs = defaultValueParent.organizations - .map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const indexYears = defaultValueParent.usageYears - .map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const indexLocs = defaultValueParent.locations - .map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const indexEmrs = defaultValueParent.emergencies - ?.map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const indexGlos = defaultValueParent.globalClusters - ?.map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const indexPlns = defaultValueParent.plans - ?.map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - // const indexEnt = defaultValueParent.governingEntities?.findIndex((org) => org.flowObject?.refDirection === 'destination') ?? -1; - - const indexPros = defaultValueParent.projects - ?.map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const _sourceOrganizations = indexOrgs.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: `${defaultValueParent.organizations[index].name} [${defaultValueParent.organizations[index].abbreviation}]`, - value: defaultValueParent.organizations[index].id, - }; - } - }); - const _sourceUsageYears = indexYears.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: `${defaultValueParent.usageYears[index].year}`, - value: defaultValueParent.usageYears[index].id, - }; - } - }); - const _sourceLocations = indexLocs.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: `${defaultValueParent.locations[index].name}`, - value: defaultValueParent.locations[index].id, - }; - } - }); - - const _sourceEmergencies = indexEmrs?.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: - defaultValueParent.emergencies && - `${defaultValueParent.emergencies[index].name}`, - value: - defaultValueParent.emergencies && - defaultValueParent.emergencies[index].id, - }; - } - }); - const _sourceGlobalClusters = indexGlos?.map( - (index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: - defaultValueParent.globalClusters && - `${defaultValueParent.globalClusters[index].name}`, - value: - defaultValueParent.globalClusters && - defaultValueParent.globalClusters[index].id, - }; - } - } - ); - const _sourcePlans = indexPlns?.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: - defaultValueParent.plans && - `${defaultValueParent.plans[index].planVersion.name}`, - value: defaultValueParent.plans && defaultValueParent.plans[index].id, - }; - } - }); - const _sourceProjects = indexPros?.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: - defaultValueParent.projects && - `${defaultValueParent.projects[index].projectVersions[index].name}`, - value: - defaultValueParent.projects && - defaultValueParent.projects[index].id, - }; - } - }); - - setValues({ - ...values, - sourceOrganizations: _sourceOrganizations, - sourceUsageYears: _sourceUsageYears, - sourceLocations: _sourceLocations, - sourceEmergencies: _sourceEmergencies, - sourceGlobalClusters: _sourceGlobalClusters, - sourcePlans: _sourcePlans, - // sourceGoverningEntities: _sourceGoverningEntities ? [_sourceGoverningEntities] : [], - sourceProjects: _sourceProjects, - }); - }; - return ( - - handleSubmit(values, values.submitAction) - } - validate={(values) => validateForm(values)} - enableReinitialize - validateOnChange={false} - style={{ zIndex: 1 }} - > - {({ values, setFieldValue, setValues }) => { - if (values.parentFlow && values.parentFlow[0]) { - const parentValueString = String( - values.parentFlow && - values.parentFlow[0] && - values.parentFlow[0].value - ); - if (parentValue !== parentValueString) { - handleParentFlow(values, parentValueString, setValues); - } - } - return ( -
- - Parent Flow - {isShowParentFlow && ( - - - - - {values.parentFlow && - values.parentFlow.map((item: any, index: any) => ( - - - - # - { - JSON.parse( - item?.value ? item?.value.toString() : '' - ).id - } - - - - { - JSON.parse( - item?.value ? item?.value.toString() : '' - ).description - } - - - { - JSON.parse( - item?.value ? item?.value.toString() : '' - ).src_org_name - }{' '} - |{' '} - { - JSON.parse( - item?.value ? item?.value.toString() : '' - ).src_org_abbreviation - }{' '} - |{' '} - { - JSON.parse( - item?.value ? item?.value.toString() : '' - ).budgetYear - } - - - {dayjs( - JSON.parse( - item?.value ? item?.value.toString() : '' - ) - ).format('DD/MM/YYYY')} - - - US$ - {parseFloat( - JSON.parse( - item?.value ? item?.value.toString() : '' - ).amountUSD - ).toLocaleString('en-US')} - - - {JSON.parse( - item?.value ? item?.value.toString() : '' - ).origAmount && - 'EUR' + - parseFloat( - JSON.parse( - item?.value - ? item?.value.toString() - : '' - ).origAmount - ).toLocaleString('en-US')} - - - { - handleParentLinkedFlow( - values, - setFieldValue, - index - ); - setShowParentFlow(false); - setFieldValue( - 'includeChildrenOfParkedFlows', - true - ); - setLinkCheck(false); - setNewMoneyCheckboxDisabled( - !newMoneyCheckboxDisabled - ); - }} - color="secondary" - text="unlink" - startIcon={MdRemove} - /> - - - ))} - -
-
-
- )} - Child Flow - - - - - {values.childFlow && - values.childFlow.map( - (item: any, index: any) => - isShowChildFlow > index && ( - - - - # - { - JSON.parse( - item?.value - ? item?.value.toString() - : '' - ).id - } - - - - { - JSON.parse( - item?.value ? item?.value.toString() : '' - ).description - } - - - { - JSON.parse( - item?.value ? item?.value.toString() : '' - ).dest_org_name - }{' '} - |{' '} - { - JSON.parse( - item?.value ? item?.value.toString() : '' - ).dest_org_abbreviation - }{' '} - |{' '} - { - JSON.parse( - item?.value ? item?.value.toString() : '' - ).dest_loc_name - }{' '} - |{' '} - { - JSON.parse( - item?.value ? item?.value.toString() : '' - ).budgetYear - } - - - {dayjs( - JSON.parse( - item?.value ? item?.value.toString() : '' - ).flowDate - ).format('DD/MM/YYYY')} - - - US$ - {parseFloat( - JSON.parse( - item?.value ? item?.value.toString() : '' - ).amountUSD - ).toLocaleString('en-US')} - - - {JSON.parse( - item?.value ? item?.value.toString() : '' - ).origAmount && - 'EUR' + - parseFloat( - JSON.parse( - item?.value - ? item?.value.toString() - : '' - ).origAmount - ).toLocaleString('en-US')} - - - { - handleChildFlow( - values, - setFieldValue, - index - ); - setShowChildFlow(isShowChildFlow - 1); - setLinkCheck(false); - setShowWarningMessage(false); - }} - color="secondary" - text="unlink" - startIcon={MdRemove} - /> - - - ) - )} - -
-
-
- - - {!isShowParentFlow && ( - { - dialogs.openDialog({ - type: 'custom', - title: 'Add Flow Link', - width: '700', - buttonCancel: 'Cancel', - buttonConfirm: 'Add Flow Link', - content: ( - - ), - callback: (_value: any) => { - setShowParentFlow(true); - setFieldValue( - 'includeChildrenOfParkedFlows', - false - ); - setLinkCheck(true); - setNewMoneyCheckboxDisabled( - !newMoneyCheckboxDisabled - ); - }, - }); - }} - color="primary" - text="Add Parent Flow" - startIcon={MdAdd} - /> - )} - { - dialogs.openDialog({ - type: 'custom', - title: 'Add Flow Link', - width: '700', - buttonCancel: 'Cancel', - buttonConfirm: 'Add Flow Link', - content: ( - - ), - callback: () => { - setShowWarningMessage(true); - setLinkCheck(true); - setShowChildFlow(isShowChildFlow + 1); - }, - }); - }} - color="primary" - text="Add Child Flow" - startIcon={MdAdd} - /> - - -
-
- ); - }} -
- ); -}; -export default LinkedFlows; diff --git a/apps/hpc-ftsadmin/src/app/components/flow-form-rewrite/previous-reporting-details.tsx b/apps/hpc-ftsadmin/src/app/components/flow-form-rewrite/previous-reporting-details.tsx deleted file mode 100644 index 9deba4f99..000000000 --- a/apps/hpc-ftsadmin/src/app/components/flow-form-rewrite/previous-reporting-details.tsx +++ /dev/null @@ -1,2508 +0,0 @@ -import React, { - ChangeEvent, - useState, - useEffect, - useCallback, - useRef, - useContext, -} from 'react'; -import { Form, Formik, FieldArray } from 'formik'; -import tw from 'twin.macro'; -import dayjs from 'dayjs'; -import { isRight } from 'fp-ts/Either'; -import { FormikErrors } from 'formik'; -import * as t from 'io-ts'; -import { util as codecs } from '@unocha/hpc-data'; -import GppMaybeIcon from '@mui/icons-material/GppMaybe'; -import Button from '@mui/material/Button'; -import DeleteIcon from '@mui/icons-material/Delete'; -import Stack from '@mui/material/Stack'; -import ContentCopyIcon from '@mui/icons-material/ContentCopy'; -import MuiAlert from '@mui/material/Alert'; -import AlertTitle from '@mui/material/AlertTitle'; -import _, { set, values } from 'lodash'; -import useSharePath from '../Hooks/SharePath'; -import { C, dialogs } from '@unocha/hpc-ui'; -import { - Table, - TableBody, - TableCell, - TableContainer, - TableHead, - TableRow, - Paper, - Alert, - IconButton, -} from '@mui/material'; -import CloseIcon from '@mui/icons-material/Close'; -import { Environment } from '../../../environments/interface'; -import { MdAdd, MdRemove, MdClose, MdCheck } from 'react-icons/md'; -import { - usageYears, - forms, - governingEntities, - fileUpload, - flows as flowsResponse, -} from '@unocha/hpc-data'; -import { getEnv } from '../../context'; -import { editFlowSetting, copyFlow } from '../../paths'; -import { flows } from '../../paths'; -import Link from '@mui/material/Link'; -import { useNavigate, unstable_usePrompt } from 'react-router-dom'; -import { id } from 'fp-ts/lib/Refinement'; -import { FlowContext } from './flow-context'; - -export type AutoCompleteSelectionType = forms.InputSelectValueType; - -const INPUT_SELECT_VALUE_TYPE = forms.INPUT_SELECT_VALUE_TYPE; - -type UniqueDataType = { - [key: string]: string[]; -}; - -export interface DeleteFlowParams { - VersionID: number; - FlowID: number; -} - -export interface categoryType { - value: string | number; - displayLabel: string; - parentID: number | null; -} - -export interface FileAssetEntityType { - collection?: string; - createAt?: string; - filename?: string; - id?: number; - mimetype?: string; - originalname?: string; - path?: string; - size?: number; - updatedAt?: string; -} -export interface ReportFileType { - title?: string; - fileName?: string; - UploadFileUrl?: string; - type?: string; - url?: string; - fileAssetID?: number; - size?: number; - fileAssetEntity?: FileAssetEntityType; -} -export interface ReportDetailType { - verified: string; - reportSource: string; - reporterReferenceCode: string; - reportChannel: AutoCompleteSelectionType | ''; - reportedOrganization: AutoCompleteSelectionType; - reportedDate: string; - reporterContactInformation: string; - sourceSystemRecordId: string; - reportFiles: ReportFileType[]; - reportFileTitle?: string; - reportUrlTitle?: string; - reportUrl?: string; - versionId?: number; - fileAsset?: FileAssetEntityType; -} - -export interface ParentFlowType { - value: any; -} - -export interface FormValues { - id: string | null; - amountUSD: number; - keywords: AutoCompleteSelectionType[]; - flowStatus: AutoCompleteSelectionType | ''; - flowType: AutoCompleteSelectionType | ''; - flowDescription: string; - firstReported: string; - decisionDate: string | null; - budgetYear: string; - flowDate: string; - contributionType: AutoCompleteSelectionType | ''; - earmarkingType: AutoCompleteSelectionType | ''; - method: AutoCompleteSelectionType | ''; - cashTransfer: AutoCompleteSelectionType | ''; - beneficiaryGroup: AutoCompleteSelectionType | ''; - inactiveReason: any[] | string; - childMethod: object; - origCurrency: AutoCompleteSelectionType | string; - amountOriginal: number | null; - exchangeRateUsed: number | null; - notes: string; - sourceOrganizations: AutoCompleteSelectionType[]; - sourceLocations: AutoCompleteSelectionType[]; - sourceUsageYears: AutoCompleteSelectionType[]; - sourceProjects: AutoCompleteSelectionType[]; - sourcePlans: AutoCompleteSelectionType[]; - sourceGoverningEntities: AutoCompleteSelectionType[]; - sourceGlobalClusters: AutoCompleteSelectionType[]; - sourceEmergencies: AutoCompleteSelectionType[]; - destinationOrganizations: AutoCompleteSelectionType[]; - destinationLocations: AutoCompleteSelectionType[]; - destinationUsageYears: AutoCompleteSelectionType[]; - destinationProjects: AutoCompleteSelectionType[]; - destinationPlans: AutoCompleteSelectionType[]; - destinationGoverningEntities: AutoCompleteSelectionType[]; - destinationGlobalClusters: AutoCompleteSelectionType[]; - destinationEmergencies: AutoCompleteSelectionType[]; - reportDetails: ReportDetailType[]; - parentFlow?: AutoCompleteSelectionType[]; - childFlow?: AutoCompleteSelectionType[]; - isParkedParent?: boolean; - includeChildrenOfParkedFlows: boolean; - isErrorCorrectionValue: boolean; - sources?: Record; - submitAction?: string | undefined; - versions?: { - id: number | null; - isPending: boolean | null; - }[]; -} - -export interface VersionDataType { - versionId: number; - flowId: number; - createdTime: string; - createdBy: string | null; - updatedTime: string; - updatedBy: string | null; - active: boolean; - viewing: boolean; - pending?: boolean; - [key: string]: - | string - | number - | null - | boolean - | string[] - | Date - | undefined - | Record; - source: UniqueDataType; - destination: UniqueDataType; - categories: string[]; - uniqueSources: UniqueDataType; - uniqueDestinations: UniqueDataType; - uniqueCategories: string[]; - restricted?: boolean; -} - -export interface InputEntriesType { - amountUSD: forms.InputEntryType | null; - origCurrency: forms.InputEntryType | null; - keywords: forms.InputEntryType | null; - flowStatus: forms.InputEntryType | null; - flowType: forms.InputEntryType | null; - flowDescription: forms.InputEntryType | null; - contributionType: forms.InputEntryType | null; - earmarkingType: forms.InputEntryType | null; - method: forms.InputEntryType | null; - beneficiaryGroup: forms.InputEntryType | null; - inactiveReason: forms.InputEntryType | null; - amountOriginal: forms.InputEntryType | null; - exchangeRateUsed: forms.InputEntryType | null; - notes: forms.InputEntryType | null; - sourceOrganizations: forms.InputEntryType[]; - sourceLocations: forms.InputEntryType[]; - sourceUsageYears: forms.InputEntryType[]; - sourceProjects: forms.InputEntryType[]; - sourcePlans: forms.InputEntryType[]; - sourceGoverningEntities: forms.InputEntryType[]; - sourceGlobalClusters: forms.InputEntryType[]; - sourceEmergencies: forms.InputEntryType[]; - destinationOrganizations: forms.InputEntryType[]; - destinationLocations: forms.InputEntryType[]; - destinationUsageYears: forms.InputEntryType[]; - destinationProjects: forms.InputEntryType[]; - destinationPlans: forms.InputEntryType[]; - destinationGoverningEntities: forms.InputEntryType[]; - destinationGlobalClusters: forms.InputEntryType[]; - destinationEmergencies: forms.InputEntryType[]; - parentFlow: forms.InputEntryType | null; - childFlow: forms.InputEntryType[]; -} - -type UploadedItem = fileUpload.FileUploadResult | FileAssetEntityType; - -const reportChannelSchema = t.type({ - value: t.intersection([codecs.NON_EMPTY_STRING, t.string]), - displayLabel: t.intersection([codecs.NON_EMPTY_STRING, t.string]), -}); - -const reportDetailsSchema = t.type({ - reportedOrganization: INPUT_SELECT_VALUE_TYPE, - reportedDate: t.intersection([codecs.NON_EMPTY_STRING, t.string]), - reportChannel: t.intersection([codecs.NON_EMPTY_STRING, reportChannelSchema]), - reportFileTitle: t.intersection([codecs.NON_EMPTY_STRING, t.string]), -}); - -const validationSchema = t.type({ - amountUSD: t.number, - flowStatus: INPUT_SELECT_VALUE_TYPE, - flowDescription: t.intersection([codecs.NON_EMPTY_STRING, t.string]), - firstReported: t.string, - flowDate: t.intersection([codecs.NON_EMPTY_STRING, t.string]), - sourceOrganizations: INPUT_SELECT_VALUE_TYPE, - sourceUsageYears: INPUT_SELECT_VALUE_TYPE, - destinationOrganizations: INPUT_SELECT_VALUE_TYPE, - destinationUsageYears: INPUT_SELECT_VALUE_TYPE, - reportDetails: reportDetailsSchema, -}); - -interface Props { - currentVersionData: flowsResponse.FlowREST | null; - environment: Environment; - isEdit: boolean; - initialValue: FormValues; - prevDetails?: ReportDetailType[]; - versionData?: VersionDataType[]; - flowId?: string; - versionId?: string; - isRestricted: boolean; - errorCorrection?: boolean; - inputEntries: InputEntriesType; - initializeInputEntries: () => void; - rejectInputEntry: (key: string) => void; - currentVersionID?: number; - currentFlowID?: number; - currentVersionActiveStatus?: boolean; - isPending?: boolean; - isSuperseded?: boolean; - isCancelled?: boolean; - isCancellation?: boolean; - isNewPending?: boolean; - isUpdatePending?: boolean; - canReactive?: boolean; - isErrorCorrection?: boolean | null; - isApprovedFlowVersion?: boolean | null; - pendingFieldsallApplied?: boolean; - allFieldsReviewed?: boolean; - pendingVersionV1?: boolean; -} - -const StyledRepOrgLink = tw.div` - flex - ml-1 - `; - -const StyledAddChildWarning = tw.div` - border border-solid border-yellow-600 - flex - rounded-md - text-gray-900 - bg-yellow-100 bg-opacity-50 - `; - -const StyledAddChildWarningIconDiv = tw.div` - flex - items-center - p-1 - `; -const StyledAddChildWarningText = tw.span` - py-3 px-3 pb-3 - `; -const StyledLayoutRow = tw.div` - flex - `; -const StyledHalfSection = tw.div` - w-1/2 - `; -const StyledFullSection = tw.div` - w-full - mb-6 - `; -const StyledRow = tw.div` - flex - gap-4 - w-full - `; -const StyledFormRow = tw.div` - flex - gap-2 - w-full - items-center - `; -const StyledAnchor = tw.a` - underline - ml-[15px] - opacity-100 - `; -const StyledAnchorDiv = tw.div` - text-right - w-full - `; -const StyledRadioDiv = tw.div` - relative - w-full - `; -const StyledFieldset = tw.fieldset` - w-full - box-border - rounded-xl - mt-[16px] - mb-[8px] - border-gray-100 - `; -const StyledCurrencyRow = tw.div` - w-1/2 - `; -const StyledFormButton = tw(C.Button)` - ml-[25px] - mb-6 - `; -const StyledLabel = tw.label` - block - my-4 - `; -const StyledLinkedFlowRow = tw.div` - mt-4 - `; - -const StyledParentInfo = tw.div` - border-0 - border-b - border-solid - cursor-pointer - mb-4 - pb-4 - `; - -const StyledStrong = tw.strong` - min-w-[16rem] - inline-block - `; - -const StyledList = tw.li` - list-none - `; - -const StyledDiv = tw.div` - my-6 - me-4 - mr-[23px] - lg:flex - justify-end - gap-x-4 - bg-white - z-10 - `; - -const initialReportDetail = { - verified: 'verified', - reportSource: 'primary', - reporterReferenceCode: '', - reportChannel: '', - reportFileTitle: '', - reportedOrganization: { value: '', displayLabel: '' }, - reportedDate: dayjs().format('DD/MM/YYYY'), - reporterContactInformation: '', - sourceSystemRecordId: '', -}; - -const FORM_SETTINGS = { - organization: { - behavior: 'shared', - }, - project: { - behavior: 'overlap', - }, - usageYear: { - behavior: 'shared', - }, - location: { - behavior: 'shared', - }, - globalCluster: { - behavior: 'shared', - }, - emergency: { - behavior: 'overlap', - }, - governingEntity: { - behavior: 'shared', - }, - plan: { - behavior: 'overlap', - }, -}; - -const objectTypes = [ - 'emergencies', - 'projects', - 'usageYears', - 'globalClusters', - 'locations', - 'plans', - 'organizations', -] as const; - -const flowValuesForDisplay = [ - 'amountUSD', - 'flowDate', - 'decisionDate', - 'firstReportedDate', - 'budgetYear', - 'origAmount', - 'origCurrency', - 'exchangeRate', - 'activeStatus', - 'restricted', - 'newMoney', - 'description', - 'notes', -] as const; - -let parentValue = ''; - -export const PreviousReportingDetails = () => { - const { - flowValue, - setFlowValue, - initialValue, - isEdit, - currentVersionData, - environment, - prevDetails, - versionData, - isRestricted, - errorCorrection, - inputEntries, - flowId, - versionId, - initializeInputEntries, - rejectInputEntry, - currentVersionID, - currentFlowID, - currentVersionActiveStatus, - isPending, - isSuperseded, - isCancelled, - isCancellation, - isNewPending, - isUpdatePending, - canReactive, - pendingFieldsallApplied, - allFieldsReviewed, - pendingVersionV1, - }: any = useContext(FlowContext); - // const { - // currentVersionData, - // environment, - // initialValue, - // isEdit, - // prevDetails, - // versionData, - // isRestricted, - // errorCorrection, - // inputEntries, - // flowId, - // versionId, - // initializeInputEntries, - // rejectInputEntry, - // currentVersionID, - // currentFlowID, - // currentVersionActiveStatus, - // isPending, - // isSuperseded, - // isCancelled, - // isCancellation, - // isNewPending, - // isUpdatePending, - // canReactive, - // pendingFieldsallApplied, - // allFieldsReviewed, - // pendingVersionV1, - // } = props; - const { confirm } = dialogs; - const env = getEnv(); - - const collapseFlowObjects = (data: any) => { - data.flowObjects = []; - - collapsePerBehavior(data.dest, 'destination'); - collapsePerBehavior(data.src, 'source'); - - function collapsePerBehavior(behaviorArr: any, ref: any) { - Object.keys(behaviorArr).forEach((type) => { - behaviorArr[type].forEach((obj: any) => { - if ( - obj !== null && - (!Object.prototype.hasOwnProperty.call(obj, 'cleared') || - !obj.cleared) - ) { - if (type === 'organization') { - obj.objectDetail = obj.implementingPartner ? 'partner' : null; - } - - const flowObj = { - refDirection: ref, - objectType: type, - objectID: obj.id, - behavior: obj.behavior || null, - objectDetail: obj.objectDetail, - }; - data.flowObjects.push(flowObj); - } - }); - }); - } - - return data as any; - }; - - const collapseCategories = (data: any) => { - data.categories = [ - data.flowType, - data.flowStatuses, - data.contributionTypes, - data.method, - data.childMethod, - data.keywords, - data.inactiveReason, - data.beneficiaryGroup, - data.pendingStatus, - data.earmarking !== null && data.earmarking.id, - ].filter((category) => category); - data.categories = data.categories - .map((value: any) => { - if (value && value.id) { - return value.id; - } else if (value[0]) { - return value[0].id; - } - }) - .filter(function (value: any) { - return value; - }) - .map((value: any) => { - return parseInt(value); - }); - - return data; - }; - const [uploadFileFlag, setUploadFileFlag] = useState(false); - const [uploadFlag, setUploadFlag] = useState(false); - const normalizeFlowData = (values: FormValues) => { - const fundingObject = { - src: { - governingEntity: values.sourceGoverningEntities.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - location: values.sourceLocations.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - organization: values.sourceOrganizations.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - project: values.sourceProjects.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - usageYear: values.sourceUsageYears.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - globalCluster: values.sourceGlobalClusters.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - emergency: values.sourceEmergencies.map((item) => ({ - id: item.value, - name: item.displayLabel, - restricted: item.restricted, - })), - plan: values.sourcePlans.map((item) => ({ - id: item.value, - name: item.displayLabel, - restricted: item.restricted, - })), - }, - dest: { - governingEntity: values.destinationGoverningEntities.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - location: values.destinationLocations.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - organization: values.destinationOrganizations.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - project: values.destinationProjects.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - usageYear: values.destinationUsageYears.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - globalCluster: values.destinationGlobalClusters.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - emergency: values.destinationEmergencies.map((item) => ({ - id: item.value, - name: item.displayLabel, - restricted: item.restricted, - })), - plan: values.destinationPlans.map((item) => ({ - id: item.value, - name: item.displayLabel, - restricted: item.restricted, - })), - }, - }; - - let data = { - id: isEdit && currentFlowID ? currentFlowID : null, - versionID: isEdit && currentVersionID ? currentVersionID : null, - amountUSD: values.amountUSD, - flowDate: dayjs(values.flowDate, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ), - decisionDate: values.decisionDate - ? dayjs(values.decisionDate, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ) - : null, - firstReportedDate: dayjs(values.firstReported, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ), - budgetYear: values.budgetYear, - origAmount: values.amountOriginal ? values.amountOriginal : null, - origCurrency: (values.origCurrency as AutoCompleteSelectionType) - ? (values.origCurrency as AutoCompleteSelectionType)?.displayLabel - : null, - exchangeRate: values.exchangeRateUsed ? values.exchangeRateUsed : null, - activeStatus: true, - restricted: false, - newMoney: true, - description: values.flowDescription, - versionStartDate: currentVersionData?.versionStartDate, - versionEndDate: currentVersionData?.versionEndDate, - flowObjects: collapseFlowObjects(fundingObject), - children: - values.childFlow && - values.childFlow.map((item: any, index: number) => { - return { - childID: JSON.parse(item.value as string).id, - origCurrency: JSON.parse(item.value as string).origCurrency, - }; - }), - parents: - values.parentFlow && - values.parentFlow.map((item: any, index: number) => { - return { - Parent: { - parentID: JSON.parse(item.value as string).id, - origCurrency: JSON.parse(item.value as string).origCurrency, - }, - childID: currentFlowID, - parentID: JSON.parse(item.value as string).id, - origCurrency: JSON.parse(item.value as string).origCurrency, - id: JSON.parse(item.value as string).id, - parents: - values.parentFlow && - values.parentFlow.map((key: any) => { - return { - child: JSON.parse(key.value as string).id, - parentID: 271736, - }; - }), - }; - }), - reportDetails: values.reportDetails.map((item, index) => { - return { - contactInfo: item.reporterContactInformation, - source: item.reportSource, - date: dayjs(item.reportedDate, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ), - versionID: currentVersionID, - newlyAdded: addReportFlag, - sourceID: null, - refCode: '7F-10073.04', - verified: true, - organizationID: item.reportedOrganization.value, - categories: [item.reportChannel && item.reportChannel.value], - organization: { - id: item.reportedOrganization.value, - name: item.reportedOrganization.displayLabel, - }, - reportFiles: - uploadFlag && - uploadedFileArray[index] && - (uploadedFileArray[index] as { id?: number })?.id - ? uploadFlag || uploadFileFlag - ? [ - { - title: item.reportUrlTitle, - type: 'url', - url: item.reportUrl, - }, - { - fileAssetID: - uploadedFileArray[index] && - (uploadedFileArray[index] as { id?: number })?.id, - reportFiles: [ - { - fieldType: 'file', - fileAssetID: - uploadedFileArray[index] && - (uploadedFileArray[index] as { id?: number })?.id, - type: 'file', - }, - ], - title: item.reportFileTitle, - type: 'file', - }, - ] - : [ - { - title: item.reportUrlTitle, - type: 'url', - url: item.reportUrl, - }, - ] - : uploadFileFlag - ? [ - { - title: item.reportUrlTitle, - type: 'url', - url: item.reportUrl, - }, - ] - : item.reportFiles - ? item.reportFiles - : [], - - reportChannel: { - group: 'reportChannel', - id: item.reportChannel && item.reportChannel.value, - name: item.reportChannel && item.reportChannel.displayLabel, - }, - }; - }), - flowType: { - id: values.flowType && values.flowType.value, - name: values.flowType && values.flowType.displayLabel, - group: 'flowType', - }, - keywords: values.keywords.map((item) => ({ - id: item.value, - name: item.displayLabel, - group: 'keywords', - })), - flowStatuses: { - id: values.flowStatus && values.flowStatus.value, - name: values.flowStatus && values.flowStatus.displayLabel, - group: 'flowStatus', - }, - contributionTypes: { - id: values.contributionType && values.contributionType.value, - name: values.contributionType && values.contributionType.displayLabel, - group: 'contributionType', - }, - method: { - id: values.method && values.method.value, - name: values.method && values.method.displayLabel, - group: 'method', - }, - childMethod: values.cashTransfer && { - id: values.cashTransfer.value, - name: values.cashTransfer.displayLabel, - group: 'method', - parentID: values.method && values.method.value, - }, - earmarking: values.earmarkingType - ? { - id: values.earmarkingType.value, - name: values.earmarkingType.displayLabel, - group: 'earmarkingType', - } - : null, - categories: [] as (string | number)[], - isCancellation: isPending ? true : !isPending ? false : null, - cancelled: isPending && isCancellation ? true : null, - pendingStatus: isPending ? true : !isPending ? false : [], - planEntities: isPending ? true : !isPending ? false : [], - planIndicated: isPending ? true : !isPending ? false : [], - isApprovedFlowVersion: - rejectFlag && approveFlag - ? true - : !(rejectFlag && approveFlag) - ? false - : null, - inactiveReason: [ - { - id: null as null | number | string, - name: '' as string | undefined, - description: null, - parentID: null, - code: null, - group: '', - includeTotals: null, - createdAt: '', - updatedAt: '', - }, - ], - isErrorCorrection: errorCorrection - ? true - : isSuperseded - ? true - : isPending - ? true - : !isSuperseded && !isPending - ? false - : null, - rejected: rejectFlag ? true : !rejectFlag ? false : null, - versions: - versionData && - versionData.map((item: VersionDataType) => { - const items = { - id: item.flowId, - versionID: item.versionId, - activeStatus: item.activeStatus, - isPending: item.isPending ? item.isPending : false, - isCancelled: item.isCancelled ? item.isCancelled : false, - }; - return items; - }), - ...fundingObject, - }; - - data = collapseCategories(data); - return data; - }; - - const [unsavedChange, setUnsavedChange] = useState(false); - const [parentCurrencyFlag, setParentCurrencyFlag] = useState(false); - const [childCurrencyFlag, setChildCurrencyFlag] = useState(false); - const [approveFlag, setApproveFlag] = useState(false); - const [rejectFlag, setRejectFlag] = useState(false); - const [validationFlag, setValidationFlag] = useState(false); - const [inactiveFlag, setInactiveFlag] = useState(false); - const [uploadedFileArray, setUploadedFileArray] = useState([ - {}, - ]); - const [addReportFlag, setAddReportFlag] = useState(false); - const [alertFlag, setAlertFlag] = useState(false); - const [sharePath, setSharePath] = useSharePath(''); - const [readOnly, setReadOnly] = useState(false); - const [linkCheck, setLinkCheck] = useState(false); - const handleSave = () => { - window.scrollTo({ top: 0, behavior: 'smooth' }); - }; - - const [showWarningMessage, setShowWarningMessage] = useState(false); - const [objects, setObjects] = useState>({}); - const [showingTypes, setShowingTypes] = useState([]); - const [newMoneyCheckboxDisabled, setNewMoneyCheckboxDisabled] = - useState(false); - - const [comparingVersions, setComparingVersions] = useState( - [] - ); - const [comparedVersions, setComparedVersions] = useState( - [] - ); - const [showSourceGoverningEntities, handleShowSourceGoverningEntities] = - useState(false); - const [ - showDestinationGoverningEntities, - handleShowDestinationGoverningEntities, - ] = useState(false); - const [sourceGoverningEntities, setSourceGoverningEntities] = - useState([]); - const [destinationGoverningEntities, setDestinationGoverningEntities] = - useState([]); - const [isShowParentFlow, setShowParentFlow] = useState( - initialValue.parentFlow && initialValue.parentFlow.length ? true : false - ); - const [isShowChildFlow, setShowChildFlow] = useState(0); - const [openAlerts, setOpenAlerts] = useState< - { message: string; id: number }[] - >([]); - const [alertId, setAlertId] = useState(0); - const handleClose = (id: number) => { - setOpenAlerts(openAlerts.filter((alert) => alert.id !== id)); - }; - const buttonText = 'Calculate The Exchange Rate'; - - const handleCalculateExchangeRate = (values: any, setFieldValue: any) => { - const { amountOriginal, amountUSD } = values; - - if (amountOriginal && amountUSD) { - const exchangeRateUsed = amountOriginal / amountUSD; - setFieldValue('exchangeRateUsed', exchangeRateUsed.toFixed(4)); - } else if (amountOriginal && !amountUSD) { - const calculatedAmountUSD = amountOriginal / values.exchangeRateUsed; - setFieldValue('amountUSD', calculatedAmountUSD.toFixed(4)); - } else if (!amountOriginal && amountUSD) { - const calculatedAmountOriginal = amountUSD * values.exchangeRateUsed; - setFieldValue('amountOriginal', calculatedAmountOriginal.toFixed(4)); - } else { - console.warn('Both original amount and USD amount are missing.'); - } - }; - useEffect(() => { - if (initialValue?.childFlow) { - setShowChildFlow(initialValue?.childFlow.length); - } - }, [initialValue]); - useEffect(() => { - const fileAssets: FileAssetEntityType[] = []; - if (isEdit) { - initialValue.reportDetails.forEach((detail: any) => { - if (detail?.fileAsset) { - fileAssets.push(detail.fileAsset); - setUploadedFileArray(fileAssets); - } else { - fileAssets.push({} as FileAssetEntityType); - setUploadedFileArray(fileAssets); - } - }); - } - }, [initialValue.reportDetails]); - useEffect(() => { - if (currentVersionActiveStatus) { - setReadOnly(false); - } else { - setReadOnly(true); - } - }, [currentVersionActiveStatus]); - useEffect(() => { - if (initialValue.parentFlow && initialValue.parentFlow.length) { - setShowParentFlow(true); - } - }, [initialValue.parentFlow]); - const [remove, setRemove] = useState(false); - const handleRemove = (index: number, values: FormValues) => { - if (window.confirm('Are you sure you want to remove this file?')) { - if ( - initialValue.reportDetails[index].reportFiles && - initialValue.reportDetails[index].reportFiles[0]?.fileName - ) { - values.reportDetails[index].reportFileTitle = ''; - initialValue.reportDetails[index].reportFiles[0].fileName = ''; - initialValue.reportDetails[index].reportFiles[0].title = ''; - initialValue.reportDetails[index].reportFiles[0].fileAssetID = - undefined; - initialValue.reportDetails[index].reportFiles[0].UploadFileUrl = ''; - const updatedArray = removeByIndexFromArray(uploadedFileArray, index); - setUploadedFileArray(updatedArray); - } else return; - setUploadFlag(false); - setRemove(true); - } else return; - }; - const removeByIndexFromArray = (array: UploadedItem[], index: number) => { - const newArray = [...array]; - newArray[index] = {}; - return newArray; - }; - if (remove === true) setRemove(false); - const SourceLink = ( - setFieldValue: any, - values: FormValues, - indexKey: number, - index: number - ) => { - setFieldValue( - `reportDetails[${index}].reportedOrganization`, - values.sourceOrganizations[indexKey] - ); - }; - const DestinationLink = ( - setFieldValue: any, - values: FormValues, - indexKey: number, - index: number - ) => { - setFieldValue( - `reportDetails[${index}].reportedOrganization`, - values.destinationOrganizations[indexKey] - ); - }; - - interface Inconsistency { - type: string; - values: { - name?: string; - year?: string; - refDirection: string; - options?: { name: string }[]; - }[]; - } - - const processDataInconsistencies = ( - inconsistencyArray: Inconsistency[] - ): string => { - let message = ''; - inconsistencyArray.forEach((inconsistencyWith) => { - if (inconsistencyWith && inconsistencyWith.type) { - const inconsistencyType = inconsistencyWith.type; - message += - inconsistencyType.charAt(0).toUpperCase() + - inconsistencyType.slice(1) + - ': '; - - if (inconsistencyWith.type === 'no-direct-link') { - message += inconsistencyWith.values.join(', '); - } else { - message += - inconsistencyWith.values - .map((value) => { - const name = value.name || value.year; - let joinedOptions = ''; - if (value.options) { - joinedOptions = value.options - .map((option) => { - return option.name || JSON.stringify(option); - }) - .join(', '); - } - const options = `is not in the list of acceptable ${value.refDirection} ${inconsistencyType}: [${joinedOptions}]`; - return `'${name}' ${options}`; - }) - .join(', ') + '. '; - } - } else { - message += JSON.stringify(inconsistencyArray); - } - }); - return message; - }; - - const handleSubmit = async ( - values: FormValues, - submitAction: string | undefined - ) => { - if (values.childFlow) { - for (let i = 0; i < values.childFlow.length; i++) { - if ( - values.destinationUsageYears.length >= 2 && - JSON.parse(values.childFlow[i].value as string).activeStatus === true - ) { - values.flowType = { - displayLabel: 'Parked', - value: '1252', - }; - } - } - } - if (isShowParentFlow && isShowChildFlow > 0) { - let childAmountSum = 0; - let parentAmountSum = 0; - values.childFlow && - values.childFlow.map((item, _index) => { - childAmountSum += JSON.parse(item.value.toString()) - ? parseInt(JSON.parse(item.value.toString()).amountUSD) - : 0; - }); - values.parentFlow && - values.parentFlow.map((item, _index) => { - parentAmountSum += JSON.parse(item.value.toString()) - ? parseInt(JSON.parse(item.value.toString()).amountUSD) - : 0; - }); - if (childAmountSum > parentAmountSum) { - if ( - !window.confirm( - `Please note, the Funding Amount on this parent flow ($${parentAmountSum}) is less than the sum of its children's amount ($${childAmountSum}). Do you want to proceed?` - ) - ) { - return; - } - } - } - if (isShowParentFlow || isShowChildFlow > 0) { - let childAmountSum = 0; - values.childFlow && - values.childFlow.map((item, _index) => { - childAmountSum += JSON.parse(item.value.toString()) - ? parseInt(JSON.parse(item.value.toString()).amountUSD) - : 0; - }); - if (childAmountSum > values.amountUSD) { - if ( - !window.confirm( - `Please note, the Funding Amount on this parent flow ($${values.amountUSD}) is less than the sum of its children's amount ($${childAmountSum}). Do you want to proceed?` - ) - ) - return; - } - } - const parentFlow = values.parentFlow; - if (parentFlow?.length) { - for (let index = 0; index < parentFlow.length; index++) { - const item = parentFlow[index]; - if ( - (typeof values?.origCurrency !== 'string' && - values.origCurrency?.displayLabel) || - !( - JSON.parse(item.value.toString()) && - JSON.parse(item.value.toString())?.origCurrency === null - ) - ) { - if ( - (typeof values?.origCurrency !== 'string' && - values.origCurrency?.displayLabel) !== - (JSON.parse(item.value.toString()) && - JSON.parse(item.value.toString())?.origCurrency) - ) { - handleSave(); - setParentCurrencyFlag(true); - return; - } - } - } - } - const childFlow = values.childFlow; - if (childFlow) { - for (let index = 0; index < childFlow.length; index++) { - const item = childFlow[index]; - if ( - (typeof values?.origCurrency !== 'string' && - values.origCurrency?.displayLabel) || - !( - JSON.parse(item.value.toString()) && - JSON.parse(item.value.toString())?.origCurrency === null - ) - ) { - if ( - (typeof values.origCurrency !== 'string' && - values.origCurrency?.displayLabel) !== - (JSON.parse(item.value.toString()) && - JSON.parse(item.value.toString()).origCurrency) - ) { - handleSave(); - setChildCurrencyFlag(true); - return; - } - } - } - } - for (let i = 0; i < values.reportDetails.length; i++) { - if ( - values.reportDetails[i].reportUrlTitle && - values.reportDetails[i].reportUrl - ) { - setUploadFileFlag(true); - } else setUploadFileFlag(false); - } - const data = normalizeFlowData(values); - const inactiveReasons = await fetchCategory('inactiveReason')(); - if (submitAction === 'approve') { - data.isApprovedFlowVersion = true; - } else if (submitAction === 'rejected') { - data.activeStatus = false; - data.rejected = true; - data.inactiveReason = [ - { - id: - inactiveReasons.find( - (item: any) => item.displayLabel === 'Rejected' - )?.value || null, - name: inactiveReasons.find( - (item: any) => item.displayLabel === 'Rejected' - )?.displayLabel, - description: null, - parentID: null, - code: null, - group: 'inactiveReason', - includeTotals: null, - createdAt: currentVersionData - ? dayjs(currentVersionData.createdAt, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ) - : '', - updatedAt: currentVersionData - ? dayjs(currentVersionData.updatedAt, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ) - : '', - }, - ]; - } else if (submitAction === 'inactive') { - if (isShowParentFlow || isShowChildFlow > 0) { - setInactiveFlag(true); - } else { - const categoryValue = - inactiveReasons.find((item: any) => item.displayLabel === 'Cancelled') - ?.value ?? null; - if (categoryValue) { - data.categories.push(parseInt(categoryValue.toString())); - } - data.activeStatus = false; - data.cancelled = true; - data.isCancellation = null; - data.rejected = null; - data.newMoney = false; - data.inactiveReason = [ - { - id: - inactiveReasons.find( - (item: any) => item.displayLabel === 'Cancelled' - )?.value || null, - name: inactiveReasons.find( - (item: any) => item.displayLabel === 'Cancelled' - )?.displayLabel, - description: null, - parentID: null, - code: null, - group: 'inactiveReason', - includeTotals: null, - createdAt: currentVersionData ? currentVersionData.createdAt : '', - updatedAt: currentVersionData ? currentVersionData.updatedAt : '', - }, - ]; - } - } - if (!inactiveFlag) { - const response = await env.model.flows.validateFlow(data); - let flag = true; - let mismatchFound = false; - for (let i = 0; i < values.reportDetails.length; i++) { - const reportOrganizationLabel = - values.reportDetails[i].reportedOrganization.displayLabel; - const reportMatchesSource = values.sourceOrganizations.some( - (sourceOrg) => sourceOrg.displayLabel === reportOrganizationLabel - ); - const reportMatchesDestination = values.destinationOrganizations.some( - (destOrg) => destOrg.displayLabel === reportOrganizationLabel - ); - - if (!reportMatchesSource && !reportMatchesDestination) { - mismatchFound = true; - break; - } - } - if (mismatchFound) { - if ( - !window.confirm( - "Your flow's Report Detail organization doesn't match the source or destination organization or that of its parked parent. Are you sure this is right?" - ) - ) { - return; - } - } - response.forEach((obj) => { - if (obj) { - const { success, message, confirmed } = obj; - if (!success) { - if (confirmed) { - const confirm = window.confirm(confirmed); - if (!confirm) { - setOpenAlerts([...openAlerts, { message, id: alertId }]); - setAlertId((prevId) => prevId + 1); - flag = false; - handleSave(); - } - } else if (message) { - setOpenAlerts([...openAlerts, { message, id: alertId }]); - setAlertId((prevId) => prevId + 1); - flag = false; - handleSave(); - } - } - } - }); - if (flag && !(isShowParentFlow || isShowChildFlow > 0)) { - setUnsavedChange(false); - if (!isEdit) { - try { - const response = await env.model.flows.createFlow({ flow: data }); - const path = editFlowSetting(response.id, response.versionID); - window.open(path, '_self'); - } catch (err: any) { - setOpenAlerts([ - ...openAlerts, - { message: err.message, id: alertId }, - ]); - setAlertId((prevId) => prevId + 1); - handleSave(); - } - } else { - const dbFlow = await env.model.flows.getFlowREST({ - id: currentFlowID!, - }); - if ( - (versionData && - currentVersionID && - Date.parse(versionData[currentVersionID - 1].updatedTime) < - Date.parse(dbFlow.updatedAt)) || - (versionData && versionData.length < dbFlow.versions.length) - ) { - window.confirm( - 'This flow cannot be saved, as a concurrency conflict has been detected. Please refresh your screen to view the most up to date data.' - ); - } else { - if (isPending && (approveFlag || rejectFlag)) { - if ( - allFieldsReviewed || - pendingFieldsallApplied || - !pendingVersionV1 - ) { - try { - const response = await env.model.flows.updatePendingFlow({ - flow: data, - }); - if (response) { - const path = editFlowSetting( - response.id, - response.versionID - ); - setAlertFlag(true); - setSharePath(path); - } - } catch (err: any) { - setOpenAlerts([ - ...openAlerts, - { message: err.message, id: alertId }, - ]); - setAlertId((prevId) => prevId + 1); - handleSave(); - } - } else { - window.confirm( - 'Some of the revised data on this flow still needs to be accepted or rejected before this update can be approved.' - ); - } - } else { - try { - const response = await env.model.flows.updateFlow({ - flow: data, - }); - if (response) { - const path = editFlowSetting(response.id, response.versionID); - setAlertFlag(true); - setSharePath(path); - } - } catch (err: any) { - let errmessage = ''; - if (err.reason) { - const inconsistencyObject = err.reason; - errmessage = processDataInconsistencies(inconsistencyObject); - } else { - const lastIndex = err.message.lastIndexOf(':'); - errmessage = err.message.substring(lastIndex + 1); - } - setOpenAlerts([ - ...openAlerts, - { message: errmessage, id: alertId }, - ]); - setAlertId((prevId) => prevId + 1); - handleSave(); - } - } - } - } - } - } - }; - const navigate = useNavigate(); - const handleCopy = (values: FormValues) => { - if (currentFlowID && currentVersionID) { - const isCopy = true; - const path = copyFlow(); - if (typeof path === 'string') { - const valuesWithFiles = { ...values, isCopy }; - navigate(path, { state: valuesWithFiles }); - } else { - console.error('Path is not a string', path); - } - } - }; - - const handleAlert = (values: FormValues) => { - const errors = validateForm(values); - if (Object.keys(errors).length !== 0) { - setValidationFlag(true); - handleSave(); - } - }; - - const setObjectsWithArray = ( - fetchedObject: any, - objectKeys: string[], - settingArrayKeys: string[], - setFieldValue: any, - values: any - ) => { - const newObjects = { ...objects }; - const newShowingTypes = [...showingTypes]; - objectKeys.forEach((key, i) => { - if (fetchedObject[settingArrayKeys[i]]) { - newObjects[key] = checkIfExistingAndCopy( - newObjects[key], - fetchedObject, - settingArrayKeys[i] - ); - } - - const parsedResponse = newObjects[key].map((responseValue: any) => { - if (settingArrayKeys[i] === 'years') { - return { - displayLabel: - (responseValue as usageYears.UsageYear).year || - responseValue.displayLabel, - value: responseValue.id || responseValue.value, - isAutoFilled: responseValue.suggested, - }; - } else if (settingArrayKeys[i] === 'plans') { - return { - displayLabel: - (responseValue.planVersion as { planId: number; name: string }) - .name || responseValue.displayLabel, - value: responseValue.planVersion.planId || responseValue.value, - isAutoFilled: responseValue.suggested, - }; - } else if (settingArrayKeys[i] === 'governingEntities') { - return { - displayLabel: - ( - responseValue.governingEntityVersion as { - id: number; - name: string; - } - ).name || responseValue.displayLabel, - value: - responseValue.governingEntityVersion.id || responseValue.value, - isAutoFilled: responseValue.suggested, - }; - } else { - return { - displayLabel: - (responseValue as { id: number; name: string }).name || - responseValue.displayLabel, - value: responseValue.id || responseValue.value, - isAutoFilled: responseValue.suggested, - }; - } - }); - newObjects[key].forEach((obj) => { - if (obj?.suggested) { - updateFlowObjects(key, parsedResponse, setFieldValue, values); - obj.suggested = false; - } - }); - setFieldValue(key, parsedResponse); - }); - - setObjects(newObjects); - setShowingTypes(newShowingTypes); - }; - - const checkIfExistingAndCopy = ( - existingObjects: any[], - object: any, - key: string - ): any[] => { - let newObjects = object[key]; - if (key === 'locations') { - newObjects = newObjects.filter(function (location: any) { - return location.adminLevel === 0; - }); - if (existingObjects && existingObjects.length) { - existingObjects = existingObjects.filter(function (location) { - return location.adminLevel === 0 || location.value; - }); - } - } - - if (existingObjects && existingObjects.length) { - const existingObjectsIds = existingObjects.map(function (o) { - return o.id || o.value; - }); - if (Array.isArray(newObjects)) { - newObjects.forEach(function (obj) { - if (existingObjectsIds.indexOf(obj.id) === -1) { - obj.suggested = true; - existingObjects.push(obj); - } - }); - } else { - if (existingObjectsIds.indexOf(newObjects.id) === -1) { - newObjects.suggested = true; - existingObjects.push(newObjects); - } - } - } else { - if (newObjects) { - if (Array.isArray(newObjects)) { - newObjects.forEach(function (obj) { - obj.suggested = true; - }); - existingObjects = newObjects; - } else { - newObjects.suggested = true; - existingObjects = [newObjects]; - } - } - } - return existingObjects; - }; - const fetchPlanDetails = async ( - objectType: string, - plan: any, - setFieldValue: any, - values?: any - ) => { - const fetchedPlan = await environment.model.plans.getPlan(plan[0].value); - if (objectType === 'sourcePlans') { - setObjectsWithArray( - fetchedPlan, - ['sourceUsageYears', 'sourceEmergencies'], - ['years', 'emergencies'], - setFieldValue, - values - ); - setSourceGoverningEntities(fetchedPlan.governingEntities); - } - if (objectType === 'destinationPlans') { - setObjectsWithArray( - fetchedPlan, - ['destinationUsageYears', 'destinationEmergencies'], - ['years', 'emergencies'], - setFieldValue, - values - ); - setDestinationGoverningEntities(fetchedPlan.governingEntities); - } - if (fetchedPlan.locations) { - const countries = fetchedPlan.locations.filter(function (loc: any) { - return loc.adminLevel === 0; - }); - if (countries.length === 1) { - if (objectType === 'sourcePlans') { - setObjectsWithArray( - { locations: countries }, - ['sourceLocations'], - ['locations'], - setFieldValue, - values - ); - } - if (objectType === 'destinationPlans') { - setObjectsWithArray( - { locations: countries }, - ['destinationLocations'], - ['locations'], - setFieldValue, - values - ); - } - } - } - }; - - const fetchEmergencyDetails = async ( - objectType: string, - emergency: any, - setFieldValue: any, - values?: any - ) => { - if (objectType === 'destinationEmergencies') { - const fetchedEmergency = await environment.model.emergencies.getEmergency( - emergency[0].value - ); - if (fetchedEmergency.locations.length <= 1) { - setObjectsWithArray( - fetchedEmergency, - ['destinationLocations'], - ['locations'], - setFieldValue, - values - ); - } - } - }; - const fetchProjectDetails = async ( - objectType: string, - project: any, - setFieldValue: any, - values?: any - ) => { - const fetchedProject = await environment.model.projects.getProject( - project[0].value - ); - const publishedVersion = fetchedProject.projectVersions.filter(function ( - version: any - ) { - return version.id === fetchedProject.currentPublishedVersionId; - })[0]; - if (objectType === 'destinationProjects') { - const fetchedCategories = - await environment.model.categories.getCategories({ - query: 'earmarkingType', - }); - const category = fetchedCategories.filter( - (item: any) => item.name === 'Earmarked' - ); - setFieldValue('earmarkingType', { - value: category[0], - displayLabel: category[0].name, - }); - setObjectsWithArray( - publishedVersion, - [ - 'destinationPlans', - 'destinationLocations', - 'destinationGoverningEntities', - 'destinationGlobalClusters', - 'destinationOrganizations', - ], - [ - 'plans', - 'locations', - 'governingEntities', - 'globalClusters', - 'organizations', - ], - setFieldValue, - values - ); - } else { - setObjectsWithArray( - publishedVersion, - [ - 'sourcePlans', - 'sourceLocations', - 'sourceGoverningEntities', - 'sourceGlobalClusters', - 'sourceOrganizations', - ], - [ - 'plans', - 'locations', - 'governingEntities', - 'globalClusters', - 'organizations', - ], - setFieldValue, - values - ); - } - }; - const fetchOrganizationDetails = async ( - objectType: string, - organization: any, - setFieldValue: any, - values?: any - ) => { - const fetchedOrg = - await environment.model.organizations.getOrganizationsById( - organization[0].value - ); - const isGovernment = (fetchedOrg[0].categories ?? []).some(function ( - category: any - ) { - return ( - category.group === 'organizationType' && - [114, 123].includes(category.id) - ); - }); - if (isGovernment && objectType === 'sourceOrganizations') { - objects.sourceLocations = checkIfExistingAndCopy( - objects.location, - fetchedOrg[0], - 'locations' - ); - setObjectsWithArray( - objects, - ['sourceLocations'], - ['locations'], - setFieldValue, - values - ); - } - }; - const fetchAssociatedGoverningEntity = async ( - objectType: string, - globalCluster: any, - setFieldValue: any, - values?: any - ) => { - if ( - (values.sourcePlans.length === 0 && - objectType === 'sourceGlobalClusters') || - (values.destinationPlans.length === 0 && - objectType === 'destinationGlobalClusters') - ) { - return; - } - let plan = null; - let targetGoverningEntities: any = null; - if (objectType === 'sourceGlobalClusters') { - plan = values.sourcePlans[0]; - targetGoverningEntities = values.sourceGoverningEntities; - } else { - plan = values.destinationPlans[0]; - targetGoverningEntities = values.destinationGoverningEntities; - } - const fetchedGoverningEntities = - await environment.model.governingEntities.getAllPlanGoverningEntities( - plan.value - ); - const hasGoverningEntitiesWithoutGlobalCluster = - Array.isArray(targetGoverningEntities) && - fetchedGoverningEntities - .filter(function (fetchedGe: any) { - return targetGoverningEntities.find(function (selectedGe: any) { - return fetchedGe.id === selectedGe.value; - }); - }) - .some(function (fetchedGe: any) { - return ( - Array.isArray(fetchedGe.globalClusterIds) && - !fetchedGe.globalClusterIds.length - ); - }); - - if (hasGoverningEntitiesWithoutGlobalCluster) { - return; - } - const governingEntities = fetchedGoverningEntities.filter(function ( - governingEntity: any - ) { - return ( - governingEntity.globalClusterIds.indexOf( - globalCluster[globalCluster.length - 1].value - ) > -1 - ); - }); - - if (governingEntities.length) { - governingEntities.forEach(function (governingEntity: any) { - setObjectsWithArray( - { governingEntities: governingEntity }, - [ - objectType === 'sourceGlobalClusters' - ? 'sourceGoverningEntities' - : 'destinationGoverningEntities', - ], - ['governingEntities'], - setFieldValue, - values - ); - }); - } - }; - - const fetchKeywords = async ( - objectType: string, - usageYears: any, - setFieldValue: any, - values?: any - ) => { - if (usageYears.length === 2) { - const fetchedCategories = - await environment.model.categories.getCategories({ - query: 'keywords', - }); - const category = fetchedCategories.filter( - (item: any) => item.name === 'Multiyear' - ); - - const mergedKeywords = [ - ...values.keywords, - ...[ - { - value: category[0].id, - displayLabel: category[0].name, - }, - ].filter( - (item2) => - !values.keywords.some((item1: any) => item1.value === item2.value) - ), - ]; - - setFieldValue('keywords', mergedKeywords); - } else if (usageYears.length === 1) { - const filteredKeywords = values.keywords.filter( - (item: any) => item.displayLabel !== 'Multiyear' - ); - setFieldValue('keywords', filteredKeywords); - } - }; - - const handleCompareCheck = ( - checkedVersion: VersionDataType, - isChecked: boolean - ) => { - setComparingVersions((prev: VersionDataType[]) => { - if (isChecked) { - return [...prev, checkedVersion]; - } else { - return prev.filter( - (version: VersionDataType) => - version.versionId !== checkedVersion.versionId - ); - } - }); - }; - - const fetchDownload = async (index: number) => { - const fileAssetID = - initialValue.reportDetails[index]?.reportFiles[0]?.fileAssetID; - const name = initialValue.reportDetails[index]?.reportFiles[0]?.fileName; - if (fileAssetID) { - try { - const responseData = - await environment?.model.fileUpload.fileDownloadModel(fileAssetID); - if (responseData) { - const data = new Blob([responseData]); - const url = URL.createObjectURL(data); - const a = document.createElement('a'); - a.href = url; - a.download = `${name ? name : 'downloaded_file'}`; - document.body.appendChild(a); - a.click(); - setTimeout(() => { - document.body.removeChild(a); - window.URL.revokeObjectURL(url); - }, 0); - } else { - console.error('No data received for download'); - } - } catch (error) { - console.error(error, 'error'); - } - } - }; - - const fetchCategory = useCallback( - (category: string) => { - return async () => { - const response = await environment.model.categories.getCategories({ - query: category, - }); - return response.map( - (responseValue: any): categoryType => ({ - displayLabel: responseValue.name, - value: responseValue.id.toString(), - parentID: responseValue.parentID, - }) - ); - }; - }, - [environment] - ); - const extractUniqueFromArray = (array1: string[], array2: string[]) => { - return array1.filter((item: string) => !array2.includes(item)); - }; - - const compareVersions = (versions: VersionDataType[]) => { - const version1 = versions[0]; - const version2 = versions[1]; - const newVersion1 = { - ...version1, - uniqueSources: objectTypes.reduce>( - (acc, type) => { - acc[type] = extractUniqueFromArray( - version1.source[type], - version2.source[type] - ); - return acc; - }, - {} - ), - uniqueDestinations: objectTypes.reduce>( - (acc, type) => { - acc[type] = extractUniqueFromArray( - version1.destination[type], - version2.destination[type] - ); - return acc; - }, - {} - ), - uniqueCategories: extractUniqueFromArray( - version1.categories, - version2.categories - ), - }; - - const newVersion2 = { - ...version2, - uniqueSources: objectTypes.reduce>( - (acc, type) => { - acc[type] = extractUniqueFromArray( - version2.source[type], - version1.source[type] - ); - return acc; - }, - {} - ), - uniqueDestinations: objectTypes.reduce>( - (acc, type) => { - acc[type] = extractUniqueFromArray( - version2.destination[type], - version1.destination[type] - ); - return acc; - }, - {} - ), - uniqueCategories: extractUniqueFromArray( - version2.categories, - version1.categories - ), - }; - return [newVersion1, newVersion2]; - }; - const handleFileChange = async ( - event: React.ChangeEvent, - index: number - ) => { - setUploadFlag(true); - try { - const setFile: File | undefined = (event.target as HTMLInputElement) - .files?.[0]; - if (setFile instanceof File) { - const responseData = - await environment.model.fileUpload.fileUploadModel(setFile); - setUploadedFileArray((prevUploadedFile) => { - const updateUploadedFile = [...prevUploadedFile]; - updateUploadedFile[index] = responseData; - return updateUploadedFile; - }); - console.log(uploadedFileArray, 'uploadedFileArray'); - } else { - console.error('No file selected for upload.'); - } - } catch (error) { - console.log(error, 'error'); - } - }; - useEffect(() => { - if (comparingVersions.length === 2) { - const compared = compareVersions(comparingVersions); - setComparedVersions(compared); - } - }, [comparingVersions]); - - useEffect(() => { - const handleBeforeUnload = (event: BeforeUnloadEvent) => { - if (unsavedChange) { - const message = - 'You have unsaved changes! Are you sure you want to leave?'; - event.returnValue = message; // Standard for most browsers - return message; // For some older browsers - } - }; - - window.addEventListener('beforeunload', handleBeforeUnload); - - return () => { - window.removeEventListener('beforeunload', handleBeforeUnload); - }; - }, [unsavedChange]); - - useEffect(() => { - const valuesObject: Record = { - sourceOrganizations: initialValue.sourceOrganizations, - sourceLocations: initialValue.sourceLocations, - sourceUsageYears: initialValue.sourceUsageYears, - sourceProjects: initialValue.sourceProjects, - sourcePlans: initialValue.sourcePlans, - sourceGoverningEntities: initialValue.sourceGoverningEntities, - sourceGlobalClusters: initialValue.sourceGlobalClusters, - sourceEmergencies: initialValue.sourceEmergencies, - destinationOrganizations: initialValue.destinationOrganizations, - destinationLocations: initialValue.destinationLocations, - destinationUsageYears: initialValue.destinationUsageYears, - destinationProjects: initialValue.destinationProjects, - destinationPlans: initialValue.destinationPlans, - destinationGoverningEntities: initialValue.destinationGoverningEntities, - destinationGlobalClusters: initialValue.destinationGlobalClusters, - destinationEmergencies: initialValue.destinationEmergencies, - }; - setObjects(valuesObject); - }, []); - - unstable_usePrompt({ - message: 'You have unsaved changes! Are you sure you want to leave?', - when: unsavedChange, - }); - const dictExecutedForEachObject: Record< - string, - ( - objectType: string, - flowObject: any, - setFieldValue: any, - values: any - ) => Promise - > = { - sourcePlans: fetchPlanDetails, - destinationPlans: fetchPlanDetails, - destinationEmergencies: fetchEmergencyDetails, - sourceProjects: fetchProjectDetails, - destinationProjects: fetchProjectDetails, - sourceOrganizations: fetchOrganizationDetails, - sourceGlobalClusters: fetchAssociatedGoverningEntity, - destinationGlobalClusters: fetchAssociatedGoverningEntity, - sourceUsageYears: fetchKeywords, - destinationUsageYears: fetchKeywords, - }; - - const params: DeleteFlowParams = { - VersionID: currentVersionID ?? 0, - FlowID: currentFlowID ?? 0, - }; - - const deleteFlow = async () => { - if (linkCheck || isShowParentFlow || isShowChildFlow > 0) { - window.confirm( - 'All linked flows must be unlinked before this flow can be deleted. Unlink flows and choose Delete flow again.' - ); - return; - } - - try { - const response = await env.model.flows.deleteFlow(params); - const path = flows(); - window.open(path, '_self'); - } catch (err: any) { - setOpenAlerts([...openAlerts, { message: err.message, id: alertId }]); - setAlertId((prevId) => prevId + 1); - } - }; - const updateFlowObjects = async ( - objectType: string, - flowObject: any, - setFieldValue: any, - values?: any - ) => { - if (flowObject.length > 0 && dictExecutedForEachObject[objectType]) { - flowObject.sort( - ( - a: { displayLabel: string; value: number }, - b: { displayLabel: string; value: number } - ) => { - return a.displayLabel.localeCompare(b.displayLabel); - } - ); - await dictExecutedForEachObject[objectType]( - objectType, - flowObject, - setFieldValue, - values - ); - } - if (objectType === 'sourcePlans') { - handleShowSourceGoverningEntities(flowObject.length !== 0); - } - if (objectType === 'destinationPlans') { - handleShowDestinationGoverningEntities(flowObject.length !== 0); - } - }; - const handleParentLinkedFlow = ( - values: any, - setFieldValue: any, - index: number - ) => { - setFieldValue( - 'parentFlow', - values['parentFlow'].filter((_item: any, ind: number) => ind !== index) - ); - }; - const handleChildFlow = (values: any, setFieldValue: any, index: number) => { - setFieldValue( - 'childFlow', - values['childFlow'].filter((_item: any, ind: number) => ind !== index) - ); - }; - const validateForm = (values: FormValues) => { - setUnsavedChange(JSON.stringify(values) !== JSON.stringify(initialValue)); - const valuesObject: Record = { - sourceOrganizations: values.sourceOrganizations, - sourceLocations: values.sourceLocations, - sourceUsageYears: values.sourceUsageYears, - sourceProjects: values.sourceProjects, - sourcePlans: values.sourcePlans, - sourceGoverningEntities: values.sourceGoverningEntities, - sourceGlobalClusters: values.sourceGlobalClusters, - sourceEmergencies: values.sourceEmergencies, - destinationOrganizations: values.destinationOrganizations, - destinationLocations: values.destinationLocations, - destinationUsageYears: values.destinationUsageYears, - destinationProjects: values.destinationProjects, - destinationPlans: values.destinationPlans, - destinationGoverningEntities: values.destinationGoverningEntities, - destinationGlobalClusters: values.destinationGlobalClusters, - destinationEmergencies: values.destinationEmergencies, - }; - setObjects(valuesObject); - const result = validationSchema.decode(values); - if (isRight(result)) { - setValidationFlag(false); - return {}; - } else { - const errors: Record[]> = {}; - Object.keys(values).forEach((key) => { - const value = values[key as keyof FormValues]; - if ( - result.left.some((err) => err.context.find((ctx) => ctx.key === key)) - ) { - const errorKey = key as keyof FormikErrors; - if (!value) { - errors[errorKey] = 'This field is required.'; - } else if (Array.isArray(value) && value.length === 0) { - errors[errorKey] = 'This field is required.'; - } - } - if ( - key === 'amountUSD' && - (value === 0 || (value && (value === '0' || (value as number) < 0))) - ) { - errors['amountUSD'] = 'The amount must be greater than zero.'; - } - if (key === 'flowType' && !value) { - errors['flowType'] = 'This field is required.'; - } - if (key === 'method' && !value) { - errors['method'] = 'This field is required.'; - } - if (key === 'reportDetails') { - const res = result.left.filter((err) => - err.context.find((ctx) => ctx.key === key) - )[0].value; - if (res && Array.isArray(res)) { - const reportDetailError: Record[] = []; - res.forEach((_, index) => { - const error: Record = {}; - if (res[index].reportChannel === '') { - error['reportChannel'] = 'This field is required.'; - } else { - error['reportChannel'] = ''; - } - if (!res[index].reportedDate) { - error['reportedDate'] = 'This field is required.'; - } else { - error['reportedDate'] = ''; - } - console.log(res[index], '-------------->'); - if ( - (res[index].reportFileTitle === '' || - res[index].reportFileTitle === undefined) && - (uploadedFileArray[index] && - (uploadedFileArray[index] as { id?: number })?.id - ? true - : false) - ) { - error['reportFileTitle'] = 'This field is required.'; - } else { - error['reportFileTitle'] = ''; - } - if ( - res[index].reportedOrganization === null || - res[index].reportedOrganization.displayLabel === '' - ) { - error['reportedOrganization'] = 'This field is required.'; - } else { - error['reportedOrganization'] = ''; - } - - if (Object.keys(error).length > 0) { - (reportDetailError as Record[]).push(error); - } - }); - - if (reportDetailError.length >= res.length) { - res.forEach((_, index) => { - if ( - res[index].reportChannel !== '' && - res[index].reportedOrganization !== '' && - res[index].reportedDate !== '' - ) { - if ( - (res[index].reportFileTitle === undefined || - res[index].reportFileTitle === '') && - (uploadedFileArray[index] && - (uploadedFileArray[index] as { id?: number })?.id - ? false - : true) - ) { - return {}; - } else if ( - res[index].reportFileTitle !== undefined && - res[index].reportFileTitle !== '' && - uploadedFileArray[index] - ) { - return {}; - } else { - errors['reportDetails'] = reportDetailError; - } - } else { - errors['reportDetails'] = reportDetailError; - } - }); - } - } - } - }); - console.log(errors, 'errors'); - if (Object.keys(errors).length === 0) setValidationFlag(false); - return errors; - } - }; - const handleParentFlow = ( - values: any, - parentValueString: string, - setValues: any - ) => { - parentValue = parentValueString; - const defaultValueParent: flowsResponse.GetFlowResult = - JSON.parse(parentValueString); - - const indexOrgs = defaultValueParent.organizations - .map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const indexYears = defaultValueParent.usageYears - .map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const indexLocs = defaultValueParent.locations - .map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const indexEmrs = defaultValueParent.emergencies - ?.map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const indexGlos = defaultValueParent.globalClusters - ?.map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const indexPlns = defaultValueParent.plans - ?.map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - // const indexEnt = defaultValueParent.governingEntities?.findIndex((org) => org.flowObject?.refDirection === 'destination') ?? -1; - - const indexPros = defaultValueParent.projects - ?.map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const _sourceOrganizations = indexOrgs.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: `${defaultValueParent.organizations[index].name} [${defaultValueParent.organizations[index].abbreviation}]`, - value: defaultValueParent.organizations[index].id, - }; - } - }); - const _sourceUsageYears = indexYears.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: `${defaultValueParent.usageYears[index].year}`, - value: defaultValueParent.usageYears[index].id, - }; - } - }); - const _sourceLocations = indexLocs.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: `${defaultValueParent.locations[index].name}`, - value: defaultValueParent.locations[index].id, - }; - } - }); - - const _sourceEmergencies = indexEmrs?.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: - defaultValueParent.emergencies && - `${defaultValueParent.emergencies[index].name}`, - value: - defaultValueParent.emergencies && - defaultValueParent.emergencies[index].id, - }; - } - }); - const _sourceGlobalClusters = indexGlos?.map( - (index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: - defaultValueParent.globalClusters && - `${defaultValueParent.globalClusters[index].name}`, - value: - defaultValueParent.globalClusters && - defaultValueParent.globalClusters[index].id, - }; - } - } - ); - const _sourcePlans = indexPlns?.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: - defaultValueParent.plans && - `${defaultValueParent.plans[index].planVersion.name}`, - value: defaultValueParent.plans && defaultValueParent.plans[index].id, - }; - } - }); - const _sourceProjects = indexPros?.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: - defaultValueParent.projects && - `${defaultValueParent.projects[index].projectVersions[index].name}`, - value: - defaultValueParent.projects && - defaultValueParent.projects[index].id, - }; - } - }); - - setValues({ - ...values, - sourceOrganizations: _sourceOrganizations, - sourceUsageYears: _sourceUsageYears, - sourceLocations: _sourceLocations, - sourceEmergencies: _sourceEmergencies, - sourceGlobalClusters: _sourceGlobalClusters, - sourcePlans: _sourcePlans, - // sourceGoverningEntities: _sourceGoverningEntities ? [_sourceGoverningEntities] : [], - sourceProjects: _sourceProjects, - }); - }; - return ( - - handleSubmit(values, values.submitAction) - } - validate={(values) => validateForm(values)} - enableReinitialize - validateOnChange={false} - style={{ zIndex: 1 }} - > - {({ values, setFieldValue, setValues }) => { - if (values.parentFlow && values.parentFlow[0]) { - const parentValueString = String( - values.parentFlow && - values.parentFlow[0] && - values.parentFlow[0].value - ); - if (parentValue !== parentValueString) { - handleParentFlow(values, parentValueString, setValues); - } - } - return ( -
- {isEdit && prevDetails && prevDetails.length > 0 && ( - - - - - - - Version - Type - Organization - Date Reported - Channel - Record ID - Contact - Ref Code - Verified? - Docs - - - - {prevDetails.map((row: any, index: any) => ( - - - {row.versionId} - - {row.reportSource} - - {typeof row.reportedOrganization === 'string' - ? row.reportedOrganization - : row.reportedOrganization.displayLabel} - - {row.reportedDate} - - {(row.reportChannel as AutoCompleteSelectionType) - .displayLabel ?? ''} - - {row.sourceSystemRecordId} - - {row.reporterContactInformation} - - {row.reporterReferenceCode} - - {row.verified === 'verified' ? 'Yes' : 'No'} - - - {row.reportFiles - .map((file: any) => file.title) - .join(', ')} - - - ))} - -
-
-
-
- )} -
- ); - }} -
- ); -}; -export default PreviousReportingDetails; diff --git a/apps/hpc-ftsadmin/src/app/components/flow-form-rewrite/reporting-details.tsx b/apps/hpc-ftsadmin/src/app/components/flow-form-rewrite/reporting-details.tsx deleted file mode 100644 index 20c206458..000000000 --- a/apps/hpc-ftsadmin/src/app/components/flow-form-rewrite/reporting-details.tsx +++ /dev/null @@ -1,2677 +0,0 @@ -import React, { - ChangeEvent, - useState, - useEffect, - useCallback, - useRef, - useContext, -} from 'react'; -import { Form, Formik, FieldArray } from 'formik'; -import tw from 'twin.macro'; -import dayjs from 'dayjs'; -import { isRight } from 'fp-ts/Either'; -import { FormikErrors } from 'formik'; -import * as t from 'io-ts'; -import { util as codecs } from '@unocha/hpc-data'; -import GppMaybeIcon from '@mui/icons-material/GppMaybe'; -import Button from '@mui/material/Button'; -import DeleteIcon from '@mui/icons-material/Delete'; -import Stack from '@mui/material/Stack'; -import ContentCopyIcon from '@mui/icons-material/ContentCopy'; -import MuiAlert from '@mui/material/Alert'; -import AlertTitle from '@mui/material/AlertTitle'; -import _, { set, values } from 'lodash'; -import useSharePath from '../Hooks/SharePath'; -import { C, dialogs } from '@unocha/hpc-ui'; -import { - Table, - TableBody, - TableCell, - TableContainer, - TableHead, - TableRow, - Paper, - Alert, - IconButton, -} from '@mui/material'; -import CloseIcon from '@mui/icons-material/Close'; -import { Environment } from '../../../environments/interface'; -import { MdAdd, MdRemove, MdClose, MdCheck } from 'react-icons/md'; -import { - usageYears, - forms, - governingEntities, - fileUpload, - flows as flowsResponse, -} from '@unocha/hpc-data'; -import { getEnv } from '../../context'; -import { editFlowSetting, copyFlow } from '../../paths'; -import { flows } from '../../paths'; -import Link from '@mui/material/Link'; -import { useNavigate, unstable_usePrompt } from 'react-router-dom'; -import { id } from 'fp-ts/lib/Refinement'; -import { FlowContext } from './flow-context'; - -export type AutoCompleteSelectionType = forms.InputSelectValueType; - -const INPUT_SELECT_VALUE_TYPE = forms.INPUT_SELECT_VALUE_TYPE; - -type UniqueDataType = { - [key: string]: string[]; -}; - -export interface DeleteFlowParams { - VersionID: number; - FlowID: number; -} - -export interface categoryType { - value: string | number; - displayLabel: string; - parentID: number | null; -} - -export interface FileAssetEntityType { - collection?: string; - createAt?: string; - filename?: string; - id?: number; - mimetype?: string; - originalname?: string; - path?: string; - size?: number; - updatedAt?: string; -} -export interface ReportFileType { - title?: string; - fileName?: string; - UploadFileUrl?: string; - type?: string; - url?: string; - fileAssetID?: number; - size?: number; - fileAssetEntity?: FileAssetEntityType; -} -export interface ReportDetailType { - verified: string; - reportSource: string; - reporterReferenceCode: string; - reportChannel: AutoCompleteSelectionType | ''; - reportedOrganization: AutoCompleteSelectionType; - reportedDate: string; - reporterContactInformation: string; - sourceSystemRecordId: string; - reportFiles: ReportFileType[]; - reportFileTitle?: string; - reportUrlTitle?: string; - reportUrl?: string; - versionId?: number; - fileAsset?: FileAssetEntityType; -} - -export interface ParentFlowType { - value: any; -} - -export interface FormValues { - id: string | null; - amountUSD: number; - keywords: AutoCompleteSelectionType[]; - flowStatus: AutoCompleteSelectionType | ''; - flowType: AutoCompleteSelectionType | ''; - flowDescription: string; - firstReported: string; - decisionDate: string | null; - budgetYear: string; - flowDate: string; - contributionType: AutoCompleteSelectionType | ''; - earmarkingType: AutoCompleteSelectionType | ''; - method: AutoCompleteSelectionType | ''; - cashTransfer: AutoCompleteSelectionType | ''; - beneficiaryGroup: AutoCompleteSelectionType | ''; - inactiveReason: any[] | string; - childMethod: object; - origCurrency: AutoCompleteSelectionType | string; - amountOriginal: number | null; - exchangeRateUsed: number | null; - notes: string; - sourceOrganizations: AutoCompleteSelectionType[]; - sourceLocations: AutoCompleteSelectionType[]; - sourceUsageYears: AutoCompleteSelectionType[]; - sourceProjects: AutoCompleteSelectionType[]; - sourcePlans: AutoCompleteSelectionType[]; - sourceGoverningEntities: AutoCompleteSelectionType[]; - sourceGlobalClusters: AutoCompleteSelectionType[]; - sourceEmergencies: AutoCompleteSelectionType[]; - destinationOrganizations: AutoCompleteSelectionType[]; - destinationLocations: AutoCompleteSelectionType[]; - destinationUsageYears: AutoCompleteSelectionType[]; - destinationProjects: AutoCompleteSelectionType[]; - destinationPlans: AutoCompleteSelectionType[]; - destinationGoverningEntities: AutoCompleteSelectionType[]; - destinationGlobalClusters: AutoCompleteSelectionType[]; - destinationEmergencies: AutoCompleteSelectionType[]; - reportDetails: ReportDetailType[]; - parentFlow?: AutoCompleteSelectionType[]; - childFlow?: AutoCompleteSelectionType[]; - isParkedParent?: boolean; - includeChildrenOfParkedFlows: boolean; - isErrorCorrectionValue: boolean; - sources?: Record; - submitAction?: string | undefined; - versions?: { - id: number | null; - isPending: boolean | null; - }[]; -} - -export interface VersionDataType { - versionId: number; - flowId: number; - createdTime: string; - createdBy: string | null; - updatedTime: string; - updatedBy: string | null; - active: boolean; - viewing: boolean; - pending?: boolean; - [key: string]: - | string - | number - | null - | boolean - | string[] - | Date - | undefined - | Record; - source: UniqueDataType; - destination: UniqueDataType; - categories: string[]; - uniqueSources: UniqueDataType; - uniqueDestinations: UniqueDataType; - uniqueCategories: string[]; - restricted?: boolean; -} - -export interface InputEntriesType { - amountUSD: forms.InputEntryType | null; - origCurrency: forms.InputEntryType | null; - keywords: forms.InputEntryType | null; - flowStatus: forms.InputEntryType | null; - flowType: forms.InputEntryType | null; - flowDescription: forms.InputEntryType | null; - contributionType: forms.InputEntryType | null; - earmarkingType: forms.InputEntryType | null; - method: forms.InputEntryType | null; - beneficiaryGroup: forms.InputEntryType | null; - inactiveReason: forms.InputEntryType | null; - amountOriginal: forms.InputEntryType | null; - exchangeRateUsed: forms.InputEntryType | null; - notes: forms.InputEntryType | null; - sourceOrganizations: forms.InputEntryType[]; - sourceLocations: forms.InputEntryType[]; - sourceUsageYears: forms.InputEntryType[]; - sourceProjects: forms.InputEntryType[]; - sourcePlans: forms.InputEntryType[]; - sourceGoverningEntities: forms.InputEntryType[]; - sourceGlobalClusters: forms.InputEntryType[]; - sourceEmergencies: forms.InputEntryType[]; - destinationOrganizations: forms.InputEntryType[]; - destinationLocations: forms.InputEntryType[]; - destinationUsageYears: forms.InputEntryType[]; - destinationProjects: forms.InputEntryType[]; - destinationPlans: forms.InputEntryType[]; - destinationGoverningEntities: forms.InputEntryType[]; - destinationGlobalClusters: forms.InputEntryType[]; - destinationEmergencies: forms.InputEntryType[]; - parentFlow: forms.InputEntryType | null; - childFlow: forms.InputEntryType[]; -} - -type UploadedItem = fileUpload.FileUploadResult | FileAssetEntityType; - -const reportChannelSchema = t.type({ - value: t.intersection([codecs.NON_EMPTY_STRING, t.string]), - displayLabel: t.intersection([codecs.NON_EMPTY_STRING, t.string]), -}); - -const reportDetailsSchema = t.type({ - reportedOrganization: INPUT_SELECT_VALUE_TYPE, - reportedDate: t.intersection([codecs.NON_EMPTY_STRING, t.string]), - reportChannel: t.intersection([codecs.NON_EMPTY_STRING, reportChannelSchema]), - reportFileTitle: t.intersection([codecs.NON_EMPTY_STRING, t.string]), -}); - -const validationSchema = t.type({ - amountUSD: t.number, - flowStatus: INPUT_SELECT_VALUE_TYPE, - flowDescription: t.intersection([codecs.NON_EMPTY_STRING, t.string]), - firstReported: t.string, - flowDate: t.intersection([codecs.NON_EMPTY_STRING, t.string]), - sourceOrganizations: INPUT_SELECT_VALUE_TYPE, - sourceUsageYears: INPUT_SELECT_VALUE_TYPE, - destinationOrganizations: INPUT_SELECT_VALUE_TYPE, - destinationUsageYears: INPUT_SELECT_VALUE_TYPE, - reportDetails: reportDetailsSchema, -}); - -interface Props { - currentVersionData: flowsResponse.FlowREST | null; - environment: Environment; - isEdit: boolean; - initialValue: FormValues; - prevDetails?: ReportDetailType[]; - versionData?: VersionDataType[]; - flowId?: string; - versionId?: string; - isRestricted: boolean; - errorCorrection?: boolean; - inputEntries: InputEntriesType; - initializeInputEntries: () => void; - rejectInputEntry: (key: string) => void; - currentVersionID?: number; - currentFlowID?: number; - currentVersionActiveStatus?: boolean; - isPending?: boolean; - isSuperseded?: boolean; - isCancelled?: boolean; - isCancellation?: boolean; - isNewPending?: boolean; - isUpdatePending?: boolean; - canReactive?: boolean; - isErrorCorrection?: boolean | null; - isApprovedFlowVersion?: boolean | null; - pendingFieldsallApplied?: boolean; - allFieldsReviewed?: boolean; - pendingVersionV1?: boolean; -} - -const StyledRepOrgLink = tw.div` - flex - ml-1 - `; - -const StyledAddChildWarning = tw.div` - border border-solid border-yellow-600 - flex - rounded-md - text-gray-900 - bg-yellow-100 bg-opacity-50 - `; - -const StyledAddChildWarningIconDiv = tw.div` - flex - items-center - p-1 - `; -const StyledAddChildWarningText = tw.span` - py-3 px-3 pb-3 - `; -const StyledLayoutRow = tw.div` - flex - `; -const StyledHalfSection = tw.div` - w-1/2 - `; -const StyledFullSection = tw.div` - w-full - mb-6 - `; -const StyledRow = tw.div` - flex - gap-4 - w-full - `; -const StyledFormRow = tw.div` - flex - gap-2 - w-full - items-center - `; -const StyledAnchor = tw.a` - underline - ml-[15px] - opacity-100 - `; -const StyledAnchorDiv = tw.div` - text-right - w-full - `; -const StyledRadioDiv = tw.div` - relative - w-full - `; -const StyledFieldset = tw.fieldset` - w-full - box-border - rounded-xl - mt-[16px] - mb-[8px] - border-gray-100 - `; -const StyledCurrencyRow = tw.div` - w-1/2 - `; -const StyledFormButton = tw(C.Button)` - ml-[25px] - mb-6 - `; -const StyledLabel = tw.label` - block - my-4 - `; -const StyledLinkedFlowRow = tw.div` - mt-4 - `; - -const StyledParentInfo = tw.div` - border-0 - border-b - border-solid - cursor-pointer - mb-4 - pb-4 - `; - -const StyledStrong = tw.strong` - min-w-[16rem] - inline-block - `; - -const StyledList = tw.li` - list-none - `; - -const StyledDiv = tw.div` - my-6 - me-4 - mr-[23px] - lg:flex - justify-end - gap-x-4 - bg-white - z-10 - `; - -const initialReportDetail = { - verified: 'verified', - reportSource: 'primary', - reporterReferenceCode: '', - reportChannel: '', - reportFileTitle: '', - reportedOrganization: { value: '', displayLabel: '' }, - reportedDate: dayjs().format('DD/MM/YYYY'), - reporterContactInformation: '', - sourceSystemRecordId: '', -}; - -const FORM_SETTINGS = { - organization: { - behavior: 'shared', - }, - project: { - behavior: 'overlap', - }, - usageYear: { - behavior: 'shared', - }, - location: { - behavior: 'shared', - }, - globalCluster: { - behavior: 'shared', - }, - emergency: { - behavior: 'overlap', - }, - governingEntity: { - behavior: 'shared', - }, - plan: { - behavior: 'overlap', - }, -}; - -const objectTypes = [ - 'emergencies', - 'projects', - 'usageYears', - 'globalClusters', - 'locations', - 'plans', - 'organizations', -] as const; - -const flowValuesForDisplay = [ - 'amountUSD', - 'flowDate', - 'decisionDate', - 'firstReportedDate', - 'budgetYear', - 'origAmount', - 'origCurrency', - 'exchangeRate', - 'activeStatus', - 'restricted', - 'newMoney', - 'description', - 'notes', -] as const; - -let parentValue = ''; - -export const ReportingDetails = () => { - const { - flowValue, - setFlowValue, - initialValue, - isEdit, - currentVersionData, - environment, - prevDetails, - versionData, - isRestricted, - errorCorrection, - inputEntries, - flowId, - versionId, - initializeInputEntries, - rejectInputEntry, - currentVersionID, - currentFlowID, - currentVersionActiveStatus, - isPending, - isSuperseded, - isCancelled, - isCancellation, - isNewPending, - isUpdatePending, - canReactive, - pendingFieldsallApplied, - allFieldsReviewed, - pendingVersionV1, - }: any = useContext(FlowContext); - // const { - // currentVersionData, - // environment, - // initialValue, - // isEdit, - // prevDetails, - // versionData, - // isRestricted, - // errorCorrection, - // inputEntries, - // flowId, - // versionId, - // initializeInputEntries, - // rejectInputEntry, - // currentVersionID, - // currentFlowID, - // currentVersionActiveStatus, - // isPending, - // isSuperseded, - // isCancelled, - // isCancellation, - // isNewPending, - // isUpdatePending, - // canReactive, - // pendingFieldsallApplied, - // allFieldsReviewed, - // pendingVersionV1, - // } = props; - const { confirm } = dialogs; - const env = getEnv(); - - const collapseFlowObjects = (data: any) => { - data.flowObjects = []; - - collapsePerBehavior(data.dest, 'destination'); - collapsePerBehavior(data.src, 'source'); - - function collapsePerBehavior(behaviorArr: any, ref: any) { - Object.keys(behaviorArr).forEach((type) => { - behaviorArr[type].forEach((obj: any) => { - if ( - obj !== null && - (!Object.prototype.hasOwnProperty.call(obj, 'cleared') || - !obj.cleared) - ) { - if (type === 'organization') { - obj.objectDetail = obj.implementingPartner ? 'partner' : null; - } - - const flowObj = { - refDirection: ref, - objectType: type, - objectID: obj.id, - behavior: obj.behavior || null, - objectDetail: obj.objectDetail, - }; - data.flowObjects.push(flowObj); - } - }); - }); - } - - return data as any; - }; - - const collapseCategories = (data: any) => { - data.categories = [ - data.flowType, - data.flowStatuses, - data.contributionTypes, - data.method, - data.childMethod, - data.keywords, - data.inactiveReason, - data.beneficiaryGroup, - data.pendingStatus, - data.earmarking !== null && data.earmarking.id, - ].filter((category) => category); - data.categories = data.categories - .map((value: any) => { - if (value && value.id) { - return value.id; - } else if (value[0]) { - return value[0].id; - } - }) - .filter(function (value: any) { - return value; - }) - .map((value: any) => { - return parseInt(value); - }); - - return data; - }; - const [uploadFileFlag, setUploadFileFlag] = useState(false); - const [uploadFlag, setUploadFlag] = useState(false); - const normalizeFlowData = (values: FormValues) => { - const fundingObject = { - src: { - governingEntity: values.sourceGoverningEntities.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - location: values.sourceLocations.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - organization: values.sourceOrganizations.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - project: values.sourceProjects.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - usageYear: values.sourceUsageYears.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - globalCluster: values.sourceGlobalClusters.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - emergency: values.sourceEmergencies.map((item) => ({ - id: item.value, - name: item.displayLabel, - restricted: item.restricted, - })), - plan: values.sourcePlans.map((item) => ({ - id: item.value, - name: item.displayLabel, - restricted: item.restricted, - })), - }, - dest: { - governingEntity: values.destinationGoverningEntities.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - location: values.destinationLocations.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - organization: values.destinationOrganizations.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - project: values.destinationProjects.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - usageYear: values.destinationUsageYears.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - globalCluster: values.destinationGlobalClusters.map((item) => ({ - id: item.value, - name: item.displayLabel, - })), - emergency: values.destinationEmergencies.map((item) => ({ - id: item.value, - name: item.displayLabel, - restricted: item.restricted, - })), - plan: values.destinationPlans.map((item) => ({ - id: item.value, - name: item.displayLabel, - restricted: item.restricted, - })), - }, - }; - - let data = { - id: isEdit && currentFlowID ? currentFlowID : null, - versionID: isEdit && currentVersionID ? currentVersionID : null, - amountUSD: values.amountUSD, - flowDate: dayjs(values.flowDate, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ), - decisionDate: values.decisionDate - ? dayjs(values.decisionDate, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ) - : null, - firstReportedDate: dayjs(values.firstReported, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ), - budgetYear: values.budgetYear, - origAmount: values.amountOriginal ? values.amountOriginal : null, - origCurrency: (values.origCurrency as AutoCompleteSelectionType) - ? (values.origCurrency as AutoCompleteSelectionType)?.displayLabel - : null, - exchangeRate: values.exchangeRateUsed ? values.exchangeRateUsed : null, - activeStatus: true, - restricted: false, - newMoney: true, - description: values.flowDescription, - versionStartDate: currentVersionData?.versionStartDate, - versionEndDate: currentVersionData?.versionEndDate, - flowObjects: collapseFlowObjects(fundingObject), - children: - values.childFlow && - values.childFlow.map((item: any, index: number) => { - return { - childID: JSON.parse(item.value as string).id, - origCurrency: JSON.parse(item.value as string).origCurrency, - }; - }), - parents: - values.parentFlow && - values.parentFlow.map((item: any, index: number) => { - return { - Parent: { - parentID: JSON.parse(item.value as string).id, - origCurrency: JSON.parse(item.value as string).origCurrency, - }, - childID: currentFlowID, - parentID: JSON.parse(item.value as string).id, - origCurrency: JSON.parse(item.value as string).origCurrency, - id: JSON.parse(item.value as string).id, - parents: - values.parentFlow && - values.parentFlow.map((key: any) => { - return { - child: JSON.parse(key.value as string).id, - parentID: 271736, - }; - }), - }; - }), - reportDetails: values.reportDetails.map((item, index) => { - return { - contactInfo: item.reporterContactInformation, - source: item.reportSource, - date: dayjs(item.reportedDate, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ), - versionID: currentVersionID, - newlyAdded: addReportFlag, - sourceID: null, - refCode: '7F-10073.04', - verified: true, - organizationID: item.reportedOrganization.value, - categories: [item.reportChannel && item.reportChannel.value], - organization: { - id: item.reportedOrganization.value, - name: item.reportedOrganization.displayLabel, - }, - reportFiles: - uploadFlag && - uploadedFileArray[index] && - (uploadedFileArray[index] as { id?: number })?.id - ? uploadFlag || uploadFileFlag - ? [ - { - title: item.reportUrlTitle, - type: 'url', - url: item.reportUrl, - }, - { - fileAssetID: - uploadedFileArray[index] && - (uploadedFileArray[index] as { id?: number })?.id, - reportFiles: [ - { - fieldType: 'file', - fileAssetID: - uploadedFileArray[index] && - (uploadedFileArray[index] as { id?: number })?.id, - type: 'file', - }, - ], - title: item.reportFileTitle, - type: 'file', - }, - ] - : [ - { - title: item.reportUrlTitle, - type: 'url', - url: item.reportUrl, - }, - ] - : uploadFileFlag - ? [ - { - title: item.reportUrlTitle, - type: 'url', - url: item.reportUrl, - }, - ] - : item.reportFiles - ? item.reportFiles - : [], - - reportChannel: { - group: 'reportChannel', - id: item.reportChannel && item.reportChannel.value, - name: item.reportChannel && item.reportChannel.displayLabel, - }, - }; - }), - flowType: { - id: values.flowType && values.flowType.value, - name: values.flowType && values.flowType.displayLabel, - group: 'flowType', - }, - keywords: values.keywords.map((item) => ({ - id: item.value, - name: item.displayLabel, - group: 'keywords', - })), - flowStatuses: { - id: values.flowStatus && values.flowStatus.value, - name: values.flowStatus && values.flowStatus.displayLabel, - group: 'flowStatus', - }, - contributionTypes: { - id: values.contributionType && values.contributionType.value, - name: values.contributionType && values.contributionType.displayLabel, - group: 'contributionType', - }, - method: { - id: values.method && values.method.value, - name: values.method && values.method.displayLabel, - group: 'method', - }, - childMethod: values.cashTransfer && { - id: values.cashTransfer.value, - name: values.cashTransfer.displayLabel, - group: 'method', - parentID: values.method && values.method.value, - }, - earmarking: values.earmarkingType - ? { - id: values.earmarkingType.value, - name: values.earmarkingType.displayLabel, - group: 'earmarkingType', - } - : null, - categories: [] as (string | number)[], - isCancellation: isPending ? true : !isPending ? false : null, - cancelled: isPending && isCancellation ? true : null, - pendingStatus: isPending ? true : !isPending ? false : [], - planEntities: isPending ? true : !isPending ? false : [], - planIndicated: isPending ? true : !isPending ? false : [], - isApprovedFlowVersion: - rejectFlag && approveFlag - ? true - : !(rejectFlag && approveFlag) - ? false - : null, - inactiveReason: [ - { - id: null as null | number | string, - name: '' as string | undefined, - description: null, - parentID: null, - code: null, - group: '', - includeTotals: null, - createdAt: '', - updatedAt: '', - }, - ], - isErrorCorrection: errorCorrection - ? true - : isSuperseded - ? true - : isPending - ? true - : !isSuperseded && !isPending - ? false - : null, - rejected: rejectFlag ? true : !rejectFlag ? false : null, - versions: - versionData && - versionData.map((item: VersionDataType) => { - const items = { - id: item.flowId, - versionID: item.versionId, - activeStatus: item.activeStatus, - isPending: item.isPending ? item.isPending : false, - isCancelled: item.isCancelled ? item.isCancelled : false, - }; - return items; - }), - ...fundingObject, - }; - - data = collapseCategories(data); - return data; - }; - - const [unsavedChange, setUnsavedChange] = useState(false); - const [parentCurrencyFlag, setParentCurrencyFlag] = useState(false); - const [childCurrencyFlag, setChildCurrencyFlag] = useState(false); - const [approveFlag, setApproveFlag] = useState(false); - const [rejectFlag, setRejectFlag] = useState(false); - const [validationFlag, setValidationFlag] = useState(false); - const [inactiveFlag, setInactiveFlag] = useState(false); - const [uploadedFileArray, setUploadedFileArray] = useState([ - {}, - ]); - const [addReportFlag, setAddReportFlag] = useState(false); - const [alertFlag, setAlertFlag] = useState(false); - const [sharePath, setSharePath] = useSharePath(''); - const [readOnly, setReadOnly] = useState(false); - const [linkCheck, setLinkCheck] = useState(false); - const handleSave = () => { - window.scrollTo({ top: 0, behavior: 'smooth' }); - }; - - const [showWarningMessage, setShowWarningMessage] = useState(false); - const [objects, setObjects] = useState>({}); - const [showingTypes, setShowingTypes] = useState([]); - const [newMoneyCheckboxDisabled, setNewMoneyCheckboxDisabled] = - useState(false); - - const [comparingVersions, setComparingVersions] = useState( - [] - ); - const [comparedVersions, setComparedVersions] = useState( - [] - ); - const [showSourceGoverningEntities, handleShowSourceGoverningEntities] = - useState(false); - const [ - showDestinationGoverningEntities, - handleShowDestinationGoverningEntities, - ] = useState(false); - const [sourceGoverningEntities, setSourceGoverningEntities] = - useState([]); - const [destinationGoverningEntities, setDestinationGoverningEntities] = - useState([]); - const [isShowParentFlow, setShowParentFlow] = useState( - initialValue.parentFlow && initialValue.parentFlow.length ? true : false - ); - const [isShowChildFlow, setShowChildFlow] = useState(0); - const [openAlerts, setOpenAlerts] = useState< - { message: string; id: number }[] - >([]); - const [alertId, setAlertId] = useState(0); - const handleClose = (id: number) => { - setOpenAlerts(openAlerts.filter((alert) => alert.id !== id)); - }; - const buttonText = 'Calculate The Exchange Rate'; - - const handleCalculateExchangeRate = (values: any, setFieldValue: any) => { - const { amountOriginal, amountUSD } = values; - - if (amountOriginal && amountUSD) { - const exchangeRateUsed = amountOriginal / amountUSD; - setFieldValue('exchangeRateUsed', exchangeRateUsed.toFixed(4)); - } else if (amountOriginal && !amountUSD) { - const calculatedAmountUSD = amountOriginal / values.exchangeRateUsed; - setFieldValue('amountUSD', calculatedAmountUSD.toFixed(4)); - } else if (!amountOriginal && amountUSD) { - const calculatedAmountOriginal = amountUSD * values.exchangeRateUsed; - setFieldValue('amountOriginal', calculatedAmountOriginal.toFixed(4)); - } else { - console.warn('Both original amount and USD amount are missing.'); - } - }; - useEffect(() => { - if (initialValue?.childFlow) { - setShowChildFlow(initialValue?.childFlow.length); - } - }, [initialValue]); - useEffect(() => { - const fileAssets: FileAssetEntityType[] = []; - if (isEdit) { - initialValue.reportDetails.forEach((detail: any) => { - if (detail?.fileAsset) { - fileAssets.push(detail.fileAsset); - setUploadedFileArray(fileAssets); - } else { - fileAssets.push({} as FileAssetEntityType); - setUploadedFileArray(fileAssets); - } - }); - } - }, [initialValue.reportDetails]); - useEffect(() => { - if (currentVersionActiveStatus) { - setReadOnly(false); - } else { - setReadOnly(true); - } - }, [currentVersionActiveStatus]); - useEffect(() => { - if (initialValue.parentFlow && initialValue.parentFlow.length) { - setShowParentFlow(true); - } - }, [initialValue.parentFlow]); - const [remove, setRemove] = useState(false); - const handleRemove = (index: number, values: FormValues) => { - if (window.confirm('Are you sure you want to remove this file?')) { - if ( - initialValue.reportDetails[index].reportFiles && - initialValue.reportDetails[index].reportFiles[0]?.fileName - ) { - values.reportDetails[index].reportFileTitle = ''; - initialValue.reportDetails[index].reportFiles[0].fileName = ''; - initialValue.reportDetails[index].reportFiles[0].title = ''; - initialValue.reportDetails[index].reportFiles[0].fileAssetID = - undefined; - initialValue.reportDetails[index].reportFiles[0].UploadFileUrl = ''; - const updatedArray = removeByIndexFromArray(uploadedFileArray, index); - setUploadedFileArray(updatedArray); - } else return; - setUploadFlag(false); - setRemove(true); - } else return; - }; - const removeByIndexFromArray = (array: UploadedItem[], index: number) => { - const newArray = [...array]; - newArray[index] = {}; - return newArray; - }; - if (remove === true) setRemove(false); - const SourceLink = ( - setFieldValue: any, - values: FormValues, - indexKey: number, - index: number - ) => { - setFieldValue( - `reportDetails[${index}].reportedOrganization`, - values.sourceOrganizations[indexKey] - ); - }; - const DestinationLink = ( - setFieldValue: any, - values: FormValues, - indexKey: number, - index: number - ) => { - setFieldValue( - `reportDetails[${index}].reportedOrganization`, - values.destinationOrganizations[indexKey] - ); - }; - - interface Inconsistency { - type: string; - values: { - name?: string; - year?: string; - refDirection: string; - options?: { name: string }[]; - }[]; - } - - const processDataInconsistencies = ( - inconsistencyArray: Inconsistency[] - ): string => { - let message = ''; - inconsistencyArray.forEach((inconsistencyWith) => { - if (inconsistencyWith && inconsistencyWith.type) { - const inconsistencyType = inconsistencyWith.type; - message += - inconsistencyType.charAt(0).toUpperCase() + - inconsistencyType.slice(1) + - ': '; - - if (inconsistencyWith.type === 'no-direct-link') { - message += inconsistencyWith.values.join(', '); - } else { - message += - inconsistencyWith.values - .map((value) => { - const name = value.name || value.year; - let joinedOptions = ''; - if (value.options) { - joinedOptions = value.options - .map((option) => { - return option.name || JSON.stringify(option); - }) - .join(', '); - } - const options = `is not in the list of acceptable ${value.refDirection} ${inconsistencyType}: [${joinedOptions}]`; - return `'${name}' ${options}`; - }) - .join(', ') + '. '; - } - } else { - message += JSON.stringify(inconsistencyArray); - } - }); - return message; - }; - - const handleSubmit = async ( - values: FormValues, - submitAction: string | undefined - ) => { - if (values.childFlow) { - for (let i = 0; i < values.childFlow.length; i++) { - if ( - values.destinationUsageYears.length >= 2 && - JSON.parse(values.childFlow[i].value as string).activeStatus === true - ) { - values.flowType = { - displayLabel: 'Parked', - value: '1252', - }; - } - } - } - if (isShowParentFlow && isShowChildFlow > 0) { - let childAmountSum = 0; - let parentAmountSum = 0; - values.childFlow && - values.childFlow.map((item, _index) => { - childAmountSum += JSON.parse(item.value.toString()) - ? parseInt(JSON.parse(item.value.toString()).amountUSD) - : 0; - }); - values.parentFlow && - values.parentFlow.map((item, _index) => { - parentAmountSum += JSON.parse(item.value.toString()) - ? parseInt(JSON.parse(item.value.toString()).amountUSD) - : 0; - }); - if (childAmountSum > parentAmountSum) { - if ( - !window.confirm( - `Please note, the Funding Amount on this parent flow ($${parentAmountSum}) is less than the sum of its children's amount ($${childAmountSum}). Do you want to proceed?` - ) - ) { - return; - } - } - } - if (isShowParentFlow || isShowChildFlow > 0) { - let childAmountSum = 0; - values.childFlow && - values.childFlow.map((item, _index) => { - childAmountSum += JSON.parse(item.value.toString()) - ? parseInt(JSON.parse(item.value.toString()).amountUSD) - : 0; - }); - if (childAmountSum > values.amountUSD) { - if ( - !window.confirm( - `Please note, the Funding Amount on this parent flow ($${values.amountUSD}) is less than the sum of its children's amount ($${childAmountSum}). Do you want to proceed?` - ) - ) - return; - } - } - const parentFlow = values.parentFlow; - if (parentFlow?.length) { - for (let index = 0; index < parentFlow.length; index++) { - const item = parentFlow[index]; - if ( - (typeof values?.origCurrency !== 'string' && - values.origCurrency?.displayLabel) || - !( - JSON.parse(item.value.toString()) && - JSON.parse(item.value.toString())?.origCurrency === null - ) - ) { - if ( - (typeof values?.origCurrency !== 'string' && - values.origCurrency?.displayLabel) !== - (JSON.parse(item.value.toString()) && - JSON.parse(item.value.toString())?.origCurrency) - ) { - handleSave(); - setParentCurrencyFlag(true); - return; - } - } - } - } - const childFlow = values.childFlow; - if (childFlow) { - for (let index = 0; index < childFlow.length; index++) { - const item = childFlow[index]; - if ( - (typeof values?.origCurrency !== 'string' && - values.origCurrency?.displayLabel) || - !( - JSON.parse(item.value.toString()) && - JSON.parse(item.value.toString())?.origCurrency === null - ) - ) { - if ( - (typeof values.origCurrency !== 'string' && - values.origCurrency?.displayLabel) !== - (JSON.parse(item.value.toString()) && - JSON.parse(item.value.toString()).origCurrency) - ) { - handleSave(); - setChildCurrencyFlag(true); - return; - } - } - } - } - for (let i = 0; i < values.reportDetails.length; i++) { - if ( - values.reportDetails[i].reportUrlTitle && - values.reportDetails[i].reportUrl - ) { - setUploadFileFlag(true); - } else setUploadFileFlag(false); - } - const data = normalizeFlowData(values); - const inactiveReasons = await fetchCategory('inactiveReason')(); - if (submitAction === 'approve') { - data.isApprovedFlowVersion = true; - } else if (submitAction === 'rejected') { - data.activeStatus = false; - data.rejected = true; - data.inactiveReason = [ - { - id: - inactiveReasons.find( - (item: any) => item.displayLabel === 'Rejected' - )?.value || null, - name: inactiveReasons.find( - (item: any) => item.displayLabel === 'Rejected' - )?.displayLabel, - description: null, - parentID: null, - code: null, - group: 'inactiveReason', - includeTotals: null, - createdAt: currentVersionData - ? dayjs(currentVersionData.createdAt, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ) - : '', - updatedAt: currentVersionData - ? dayjs(currentVersionData.updatedAt, 'DD/MM/YYYY').format( - 'YYYY-MM-DDTHH:mm:ss.SSS[Z]' - ) - : '', - }, - ]; - } else if (submitAction === 'inactive') { - if (isShowParentFlow || isShowChildFlow > 0) { - setInactiveFlag(true); - } else { - const categoryValue = - inactiveReasons.find((item: any) => item.displayLabel === 'Cancelled') - ?.value ?? null; - if (categoryValue) { - data.categories.push(parseInt(categoryValue.toString())); - } - data.activeStatus = false; - data.cancelled = true; - data.isCancellation = null; - data.rejected = null; - data.newMoney = false; - data.inactiveReason = [ - { - id: - inactiveReasons.find( - (item: any) => item.displayLabel === 'Cancelled' - )?.value || null, - name: inactiveReasons.find( - (item: any) => item.displayLabel === 'Cancelled' - )?.displayLabel, - description: null, - parentID: null, - code: null, - group: 'inactiveReason', - includeTotals: null, - createdAt: currentVersionData ? currentVersionData.createdAt : '', - updatedAt: currentVersionData ? currentVersionData.updatedAt : '', - }, - ]; - } - } - if (!inactiveFlag) { - const response = await env.model.flows.validateFlow(data); - let flag = true; - let mismatchFound = false; - for (let i = 0; i < values.reportDetails.length; i++) { - const reportOrganizationLabel = - values.reportDetails[i].reportedOrganization.displayLabel; - const reportMatchesSource = values.sourceOrganizations.some( - (sourceOrg) => sourceOrg.displayLabel === reportOrganizationLabel - ); - const reportMatchesDestination = values.destinationOrganizations.some( - (destOrg) => destOrg.displayLabel === reportOrganizationLabel - ); - - if (!reportMatchesSource && !reportMatchesDestination) { - mismatchFound = true; - break; - } - } - if (mismatchFound) { - if ( - !window.confirm( - "Your flow's Report Detail organization doesn't match the source or destination organization or that of its parked parent. Are you sure this is right?" - ) - ) { - return; - } - } - response.forEach((obj) => { - if (obj) { - const { success, message, confirmed } = obj; - if (!success) { - if (confirmed) { - const confirm = window.confirm(confirmed); - if (!confirm) { - setOpenAlerts([...openAlerts, { message, id: alertId }]); - setAlertId((prevId) => prevId + 1); - flag = false; - handleSave(); - } - } else if (message) { - setOpenAlerts([...openAlerts, { message, id: alertId }]); - setAlertId((prevId) => prevId + 1); - flag = false; - handleSave(); - } - } - } - }); - if (flag && !(isShowParentFlow || isShowChildFlow > 0)) { - setUnsavedChange(false); - if (!isEdit) { - try { - const response = await env.model.flows.createFlow({ flow: data }); - const path = editFlowSetting(response.id, response.versionID); - window.open(path, '_self'); - } catch (err: any) { - setOpenAlerts([ - ...openAlerts, - { message: err.message, id: alertId }, - ]); - setAlertId((prevId) => prevId + 1); - handleSave(); - } - } else { - const dbFlow = await env.model.flows.getFlowREST({ - id: currentFlowID!, - }); - if ( - (versionData && - currentVersionID && - Date.parse(versionData[currentVersionID - 1].updatedTime) < - Date.parse(dbFlow.updatedAt)) || - (versionData && versionData.length < dbFlow.versions.length) - ) { - window.confirm( - 'This flow cannot be saved, as a concurrency conflict has been detected. Please refresh your screen to view the most up to date data.' - ); - } else { - if (isPending && (approveFlag || rejectFlag)) { - if ( - allFieldsReviewed || - pendingFieldsallApplied || - !pendingVersionV1 - ) { - try { - const response = await env.model.flows.updatePendingFlow({ - flow: data, - }); - if (response) { - const path = editFlowSetting( - response.id, - response.versionID - ); - setAlertFlag(true); - setSharePath(path); - } - } catch (err: any) { - setOpenAlerts([ - ...openAlerts, - { message: err.message, id: alertId }, - ]); - setAlertId((prevId) => prevId + 1); - handleSave(); - } - } else { - window.confirm( - 'Some of the revised data on this flow still needs to be accepted or rejected before this update can be approved.' - ); - } - } else { - try { - const response = await env.model.flows.updateFlow({ - flow: data, - }); - if (response) { - const path = editFlowSetting(response.id, response.versionID); - setAlertFlag(true); - setSharePath(path); - } - } catch (err: any) { - let errmessage = ''; - if (err.reason) { - const inconsistencyObject = err.reason; - errmessage = processDataInconsistencies(inconsistencyObject); - } else { - const lastIndex = err.message.lastIndexOf(':'); - errmessage = err.message.substring(lastIndex + 1); - } - setOpenAlerts([ - ...openAlerts, - { message: errmessage, id: alertId }, - ]); - setAlertId((prevId) => prevId + 1); - handleSave(); - } - } - } - } - } - } - }; - const navigate = useNavigate(); - const handleCopy = (values: FormValues) => { - if (currentFlowID && currentVersionID) { - const isCopy = true; - const path = copyFlow(); - if (typeof path === 'string') { - const valuesWithFiles = { ...values, isCopy }; - navigate(path, { state: valuesWithFiles }); - } else { - console.error('Path is not a string', path); - } - } - }; - - const handleAlert = (values: FormValues) => { - const errors = validateForm(values); - if (Object.keys(errors).length !== 0) { - setValidationFlag(true); - handleSave(); - } - }; - - const setObjectsWithArray = ( - fetchedObject: any, - objectKeys: string[], - settingArrayKeys: string[], - setFieldValue: any, - values: any - ) => { - const newObjects = { ...objects }; - const newShowingTypes = [...showingTypes]; - objectKeys.forEach((key, i) => { - if (fetchedObject[settingArrayKeys[i]]) { - newObjects[key] = checkIfExistingAndCopy( - newObjects[key], - fetchedObject, - settingArrayKeys[i] - ); - } - - const parsedResponse = newObjects[key].map((responseValue: any) => { - if (settingArrayKeys[i] === 'years') { - return { - displayLabel: - (responseValue as usageYears.UsageYear).year || - responseValue.displayLabel, - value: responseValue.id || responseValue.value, - isAutoFilled: responseValue.suggested, - }; - } else if (settingArrayKeys[i] === 'plans') { - return { - displayLabel: - (responseValue.planVersion as { planId: number; name: string }) - .name || responseValue.displayLabel, - value: responseValue.planVersion.planId || responseValue.value, - isAutoFilled: responseValue.suggested, - }; - } else if (settingArrayKeys[i] === 'governingEntities') { - return { - displayLabel: - ( - responseValue.governingEntityVersion as { - id: number; - name: string; - } - ).name || responseValue.displayLabel, - value: - responseValue.governingEntityVersion.id || responseValue.value, - isAutoFilled: responseValue.suggested, - }; - } else { - return { - displayLabel: - (responseValue as { id: number; name: string }).name || - responseValue.displayLabel, - value: responseValue.id || responseValue.value, - isAutoFilled: responseValue.suggested, - }; - } - }); - newObjects[key].forEach((obj) => { - if (obj?.suggested) { - updateFlowObjects(key, parsedResponse, setFieldValue, values); - obj.suggested = false; - } - }); - setFieldValue(key, parsedResponse); - }); - - setObjects(newObjects); - setShowingTypes(newShowingTypes); - }; - - const checkIfExistingAndCopy = ( - existingObjects: any[], - object: any, - key: string - ): any[] => { - let newObjects = object[key]; - if (key === 'locations') { - newObjects = newObjects.filter(function (location: any) { - return location.adminLevel === 0; - }); - if (existingObjects && existingObjects.length) { - existingObjects = existingObjects.filter(function (location) { - return location.adminLevel === 0 || location.value; - }); - } - } - - if (existingObjects && existingObjects.length) { - const existingObjectsIds = existingObjects.map(function (o) { - return o.id || o.value; - }); - if (Array.isArray(newObjects)) { - newObjects.forEach(function (obj) { - if (existingObjectsIds.indexOf(obj.id) === -1) { - obj.suggested = true; - existingObjects.push(obj); - } - }); - } else { - if (existingObjectsIds.indexOf(newObjects.id) === -1) { - newObjects.suggested = true; - existingObjects.push(newObjects); - } - } - } else { - if (newObjects) { - if (Array.isArray(newObjects)) { - newObjects.forEach(function (obj) { - obj.suggested = true; - }); - existingObjects = newObjects; - } else { - newObjects.suggested = true; - existingObjects = [newObjects]; - } - } - } - return existingObjects; - }; - const fetchPlanDetails = async ( - objectType: string, - plan: any, - setFieldValue: any, - values?: any - ) => { - const fetchedPlan = await environment.model.plans.getPlan(plan[0].value); - if (objectType === 'sourcePlans') { - setObjectsWithArray( - fetchedPlan, - ['sourceUsageYears', 'sourceEmergencies'], - ['years', 'emergencies'], - setFieldValue, - values - ); - setSourceGoverningEntities(fetchedPlan.governingEntities); - } - if (objectType === 'destinationPlans') { - setObjectsWithArray( - fetchedPlan, - ['destinationUsageYears', 'destinationEmergencies'], - ['years', 'emergencies'], - setFieldValue, - values - ); - setDestinationGoverningEntities(fetchedPlan.governingEntities); - } - if (fetchedPlan.locations) { - const countries = fetchedPlan.locations.filter(function (loc: any) { - return loc.adminLevel === 0; - }); - if (countries.length === 1) { - if (objectType === 'sourcePlans') { - setObjectsWithArray( - { locations: countries }, - ['sourceLocations'], - ['locations'], - setFieldValue, - values - ); - } - if (objectType === 'destinationPlans') { - setObjectsWithArray( - { locations: countries }, - ['destinationLocations'], - ['locations'], - setFieldValue, - values - ); - } - } - } - }; - - const fetchEmergencyDetails = async ( - objectType: string, - emergency: any, - setFieldValue: any, - values?: any - ) => { - if (objectType === 'destinationEmergencies') { - const fetchedEmergency = await environment.model.emergencies.getEmergency( - emergency[0].value - ); - if (fetchedEmergency.locations.length <= 1) { - setObjectsWithArray( - fetchedEmergency, - ['destinationLocations'], - ['locations'], - setFieldValue, - values - ); - } - } - }; - const fetchProjectDetails = async ( - objectType: string, - project: any, - setFieldValue: any, - values?: any - ) => { - const fetchedProject = await environment.model.projects.getProject( - project[0].value - ); - const publishedVersion = fetchedProject.projectVersions.filter(function ( - version: any - ) { - return version.id === fetchedProject.currentPublishedVersionId; - })[0]; - if (objectType === 'destinationProjects') { - const fetchedCategories = - await environment.model.categories.getCategories({ - query: 'earmarkingType', - }); - const category = fetchedCategories.filter( - (item: any) => item.name === 'Earmarked' - ); - setFieldValue('earmarkingType', { - value: category[0], - displayLabel: category[0].name, - }); - setObjectsWithArray( - publishedVersion, - [ - 'destinationPlans', - 'destinationLocations', - 'destinationGoverningEntities', - 'destinationGlobalClusters', - 'destinationOrganizations', - ], - [ - 'plans', - 'locations', - 'governingEntities', - 'globalClusters', - 'organizations', - ], - setFieldValue, - values - ); - } else { - setObjectsWithArray( - publishedVersion, - [ - 'sourcePlans', - 'sourceLocations', - 'sourceGoverningEntities', - 'sourceGlobalClusters', - 'sourceOrganizations', - ], - [ - 'plans', - 'locations', - 'governingEntities', - 'globalClusters', - 'organizations', - ], - setFieldValue, - values - ); - } - }; - const fetchOrganizationDetails = async ( - objectType: string, - organization: any, - setFieldValue: any, - values?: any - ) => { - const fetchedOrg = - await environment.model.organizations.getOrganizationsById( - organization[0].value - ); - const isGovernment = (fetchedOrg[0].categories ?? []).some(function ( - category: any - ) { - return ( - category.group === 'organizationType' && - [114, 123].includes(category.id) - ); - }); - if (isGovernment && objectType === 'sourceOrganizations') { - objects.sourceLocations = checkIfExistingAndCopy( - objects.location, - fetchedOrg[0], - 'locations' - ); - setObjectsWithArray( - objects, - ['sourceLocations'], - ['locations'], - setFieldValue, - values - ); - } - }; - const fetchAssociatedGoverningEntity = async ( - objectType: string, - globalCluster: any, - setFieldValue: any, - values?: any - ) => { - if ( - (values.sourcePlans.length === 0 && - objectType === 'sourceGlobalClusters') || - (values.destinationPlans.length === 0 && - objectType === 'destinationGlobalClusters') - ) { - return; - } - let plan = null; - let targetGoverningEntities: any = null; - if (objectType === 'sourceGlobalClusters') { - plan = values.sourcePlans[0]; - targetGoverningEntities = values.sourceGoverningEntities; - } else { - plan = values.destinationPlans[0]; - targetGoverningEntities = values.destinationGoverningEntities; - } - const fetchedGoverningEntities = - await environment.model.governingEntities.getAllPlanGoverningEntities( - plan.value - ); - const hasGoverningEntitiesWithoutGlobalCluster = - Array.isArray(targetGoverningEntities) && - fetchedGoverningEntities - .filter(function (fetchedGe: any) { - return targetGoverningEntities.find(function (selectedGe: any) { - return fetchedGe.id === selectedGe.value; - }); - }) - .some(function (fetchedGe: any) { - return ( - Array.isArray(fetchedGe.globalClusterIds) && - !fetchedGe.globalClusterIds.length - ); - }); - - if (hasGoverningEntitiesWithoutGlobalCluster) { - return; - } - const governingEntities = fetchedGoverningEntities.filter(function ( - governingEntity: any - ) { - return ( - governingEntity.globalClusterIds.indexOf( - globalCluster[globalCluster.length - 1].value - ) > -1 - ); - }); - - if (governingEntities.length) { - governingEntities.forEach(function (governingEntity: any) { - setObjectsWithArray( - { governingEntities: governingEntity }, - [ - objectType === 'sourceGlobalClusters' - ? 'sourceGoverningEntities' - : 'destinationGoverningEntities', - ], - ['governingEntities'], - setFieldValue, - values - ); - }); - } - }; - - const fetchKeywords = async ( - objectType: string, - usageYears: any, - setFieldValue: any, - values?: any - ) => { - if (usageYears.length === 2) { - const fetchedCategories = - await environment.model.categories.getCategories({ - query: 'keywords', - }); - const category = fetchedCategories.filter( - (item: any) => item.name === 'Multiyear' - ); - - const mergedKeywords = [ - ...values.keywords, - ...[ - { - value: category[0].id, - displayLabel: category[0].name, - }, - ].filter( - (item2) => - !values.keywords.some((item1: any) => item1.value === item2.value) - ), - ]; - - setFieldValue('keywords', mergedKeywords); - } else if (usageYears.length === 1) { - const filteredKeywords = values.keywords.filter( - (item: any) => item.displayLabel !== 'Multiyear' - ); - setFieldValue('keywords', filteredKeywords); - } - }; - - const handleCompareCheck = ( - checkedVersion: VersionDataType, - isChecked: boolean - ) => { - setComparingVersions((prev: VersionDataType[]) => { - if (isChecked) { - return [...prev, checkedVersion]; - } else { - return prev.filter( - (version: VersionDataType) => - version.versionId !== checkedVersion.versionId - ); - } - }); - }; - - const fetchDownload = async (index: number) => { - const fileAssetID = - initialValue.reportDetails[index]?.reportFiles[0]?.fileAssetID; - const name = initialValue.reportDetails[index]?.reportFiles[0]?.fileName; - if (fileAssetID) { - try { - const responseData = - await environment?.model.fileUpload.fileDownloadModel(fileAssetID); - if (responseData) { - const data = new Blob([responseData]); - const url = URL.createObjectURL(data); - const a = document.createElement('a'); - a.href = url; - a.download = `${name ? name : 'downloaded_file'}`; - document.body.appendChild(a); - a.click(); - setTimeout(() => { - document.body.removeChild(a); - window.URL.revokeObjectURL(url); - }, 0); - } else { - console.error('No data received for download'); - } - } catch (error) { - console.error(error, 'error'); - } - } - }; - - const fetchCategory = useCallback( - (category: string) => { - return async () => { - const response = await environment.model.categories.getCategories({ - query: category, - }); - return response.map( - (responseValue: any): categoryType => ({ - displayLabel: responseValue.name, - value: responseValue.id.toString(), - parentID: responseValue.parentID, - }) - ); - }; - }, - [environment] - ); - const extractUniqueFromArray = (array1: string[], array2: string[]) => { - return array1.filter((item: string) => !array2.includes(item)); - }; - - const compareVersions = (versions: VersionDataType[]) => { - const version1 = versions[0]; - const version2 = versions[1]; - const newVersion1 = { - ...version1, - uniqueSources: objectTypes.reduce>( - (acc, type) => { - acc[type] = extractUniqueFromArray( - version1.source[type], - version2.source[type] - ); - return acc; - }, - {} - ), - uniqueDestinations: objectTypes.reduce>( - (acc, type) => { - acc[type] = extractUniqueFromArray( - version1.destination[type], - version2.destination[type] - ); - return acc; - }, - {} - ), - uniqueCategories: extractUniqueFromArray( - version1.categories, - version2.categories - ), - }; - - const newVersion2 = { - ...version2, - uniqueSources: objectTypes.reduce>( - (acc, type) => { - acc[type] = extractUniqueFromArray( - version2.source[type], - version1.source[type] - ); - return acc; - }, - {} - ), - uniqueDestinations: objectTypes.reduce>( - (acc, type) => { - acc[type] = extractUniqueFromArray( - version2.destination[type], - version1.destination[type] - ); - return acc; - }, - {} - ), - uniqueCategories: extractUniqueFromArray( - version2.categories, - version1.categories - ), - }; - return [newVersion1, newVersion2]; - }; - const handleFileChange = async ( - event: React.ChangeEvent, - index: number - ) => { - setUploadFlag(true); - try { - const setFile: File | undefined = (event.target as HTMLInputElement) - .files?.[0]; - if (setFile instanceof File) { - const responseData = - await environment.model.fileUpload.fileUploadModel(setFile); - setUploadedFileArray((prevUploadedFile) => { - const updateUploadedFile = [...prevUploadedFile]; - updateUploadedFile[index] = responseData; - return updateUploadedFile; - }); - console.log(uploadedFileArray, 'uploadedFileArray'); - } else { - console.error('No file selected for upload.'); - } - } catch (error) { - console.log(error, 'error'); - } - }; - useEffect(() => { - if (comparingVersions.length === 2) { - const compared = compareVersions(comparingVersions); - setComparedVersions(compared); - } - }, [comparingVersions]); - - useEffect(() => { - const handleBeforeUnload = (event: BeforeUnloadEvent) => { - if (unsavedChange) { - const message = - 'You have unsaved changes! Are you sure you want to leave?'; - event.returnValue = message; // Standard for most browsers - return message; // For some older browsers - } - }; - - window.addEventListener('beforeunload', handleBeforeUnload); - - return () => { - window.removeEventListener('beforeunload', handleBeforeUnload); - }; - }, [unsavedChange]); - - useEffect(() => { - const valuesObject: Record = { - sourceOrganizations: initialValue.sourceOrganizations, - sourceLocations: initialValue.sourceLocations, - sourceUsageYears: initialValue.sourceUsageYears, - sourceProjects: initialValue.sourceProjects, - sourcePlans: initialValue.sourcePlans, - sourceGoverningEntities: initialValue.sourceGoverningEntities, - sourceGlobalClusters: initialValue.sourceGlobalClusters, - sourceEmergencies: initialValue.sourceEmergencies, - destinationOrganizations: initialValue.destinationOrganizations, - destinationLocations: initialValue.destinationLocations, - destinationUsageYears: initialValue.destinationUsageYears, - destinationProjects: initialValue.destinationProjects, - destinationPlans: initialValue.destinationPlans, - destinationGoverningEntities: initialValue.destinationGoverningEntities, - destinationGlobalClusters: initialValue.destinationGlobalClusters, - destinationEmergencies: initialValue.destinationEmergencies, - }; - setObjects(valuesObject); - }, []); - - unstable_usePrompt({ - message: 'You have unsaved changes! Are you sure you want to leave?', - when: unsavedChange, - }); - const dictExecutedForEachObject: Record< - string, - ( - objectType: string, - flowObject: any, - setFieldValue: any, - values: any - ) => Promise - > = { - sourcePlans: fetchPlanDetails, - destinationPlans: fetchPlanDetails, - destinationEmergencies: fetchEmergencyDetails, - sourceProjects: fetchProjectDetails, - destinationProjects: fetchProjectDetails, - sourceOrganizations: fetchOrganizationDetails, - sourceGlobalClusters: fetchAssociatedGoverningEntity, - destinationGlobalClusters: fetchAssociatedGoverningEntity, - sourceUsageYears: fetchKeywords, - destinationUsageYears: fetchKeywords, - }; - - const params: DeleteFlowParams = { - VersionID: currentVersionID ?? 0, - FlowID: currentFlowID ?? 0, - }; - - const deleteFlow = async () => { - if (linkCheck || isShowParentFlow || isShowChildFlow > 0) { - window.confirm( - 'All linked flows must be unlinked before this flow can be deleted. Unlink flows and choose Delete flow again.' - ); - return; - } - - try { - const response = await env.model.flows.deleteFlow(params); - const path = flows(); - window.open(path, '_self'); - } catch (err: any) { - setOpenAlerts([...openAlerts, { message: err.message, id: alertId }]); - setAlertId((prevId) => prevId + 1); - } - }; - const updateFlowObjects = async ( - objectType: string, - flowObject: any, - setFieldValue: any, - values?: any - ) => { - if (flowObject.length > 0 && dictExecutedForEachObject[objectType]) { - flowObject.sort( - ( - a: { displayLabel: string; value: number }, - b: { displayLabel: string; value: number } - ) => { - return a.displayLabel.localeCompare(b.displayLabel); - } - ); - await dictExecutedForEachObject[objectType]( - objectType, - flowObject, - setFieldValue, - values - ); - } - if (objectType === 'sourcePlans') { - handleShowSourceGoverningEntities(flowObject.length !== 0); - } - if (objectType === 'destinationPlans') { - handleShowDestinationGoverningEntities(flowObject.length !== 0); - } - }; - const handleParentLinkedFlow = ( - values: any, - setFieldValue: any, - index: number - ) => { - setFieldValue( - 'parentFlow', - values['parentFlow'].filter((_item: any, ind: number) => ind !== index) - ); - }; - const handleChildFlow = (values: any, setFieldValue: any, index: number) => { - setFieldValue( - 'childFlow', - values['childFlow'].filter((_item: any, ind: number) => ind !== index) - ); - }; - const validateForm = (values: FormValues) => { - setUnsavedChange(JSON.stringify(values) !== JSON.stringify(initialValue)); - const valuesObject: Record = { - sourceOrganizations: values.sourceOrganizations, - sourceLocations: values.sourceLocations, - sourceUsageYears: values.sourceUsageYears, - sourceProjects: values.sourceProjects, - sourcePlans: values.sourcePlans, - sourceGoverningEntities: values.sourceGoverningEntities, - sourceGlobalClusters: values.sourceGlobalClusters, - sourceEmergencies: values.sourceEmergencies, - destinationOrganizations: values.destinationOrganizations, - destinationLocations: values.destinationLocations, - destinationUsageYears: values.destinationUsageYears, - destinationProjects: values.destinationProjects, - destinationPlans: values.destinationPlans, - destinationGoverningEntities: values.destinationGoverningEntities, - destinationGlobalClusters: values.destinationGlobalClusters, - destinationEmergencies: values.destinationEmergencies, - }; - setObjects(valuesObject); - const result = validationSchema.decode(values); - if (isRight(result)) { - setValidationFlag(false); - return {}; - } else { - const errors: Record[]> = {}; - Object.keys(values).forEach((key) => { - const value = values[key as keyof FormValues]; - if ( - result.left.some((err) => err.context.find((ctx) => ctx.key === key)) - ) { - const errorKey = key as keyof FormikErrors; - if (!value) { - errors[errorKey] = 'This field is required.'; - } else if (Array.isArray(value) && value.length === 0) { - errors[errorKey] = 'This field is required.'; - } - } - if ( - key === 'amountUSD' && - (value === 0 || (value && (value === '0' || (value as number) < 0))) - ) { - errors['amountUSD'] = 'The amount must be greater than zero.'; - } - if (key === 'flowType' && !value) { - errors['flowType'] = 'This field is required.'; - } - if (key === 'method' && !value) { - errors['method'] = 'This field is required.'; - } - if (key === 'reportDetails') { - const res = result.left.filter((err) => - err.context.find((ctx) => ctx.key === key) - )[0].value; - if (res && Array.isArray(res)) { - const reportDetailError: Record[] = []; - res.forEach((_, index) => { - const error: Record = {}; - if (res[index].reportChannel === '') { - error['reportChannel'] = 'This field is required.'; - } else { - error['reportChannel'] = ''; - } - if (!res[index].reportedDate) { - error['reportedDate'] = 'This field is required.'; - } else { - error['reportedDate'] = ''; - } - console.log(res[index], '-------------->'); - if ( - (res[index].reportFileTitle === '' || - res[index].reportFileTitle === undefined) && - (uploadedFileArray[index] && - (uploadedFileArray[index] as { id?: number })?.id - ? true - : false) - ) { - error['reportFileTitle'] = 'This field is required.'; - } else { - error['reportFileTitle'] = ''; - } - if ( - res[index].reportedOrganization === null || - res[index].reportedOrganization.displayLabel === '' - ) { - error['reportedOrganization'] = 'This field is required.'; - } else { - error['reportedOrganization'] = ''; - } - - if (Object.keys(error).length > 0) { - (reportDetailError as Record[]).push(error); - } - }); - - if (reportDetailError.length >= res.length) { - res.forEach((_, index) => { - if ( - res[index].reportChannel !== '' && - res[index].reportedOrganization !== '' && - res[index].reportedDate !== '' - ) { - if ( - (res[index].reportFileTitle === undefined || - res[index].reportFileTitle === '') && - (uploadedFileArray[index] && - (uploadedFileArray[index] as { id?: number })?.id - ? false - : true) - ) { - return {}; - } else if ( - res[index].reportFileTitle !== undefined && - res[index].reportFileTitle !== '' && - uploadedFileArray[index] - ) { - return {}; - } else { - errors['reportDetails'] = reportDetailError; - } - } else { - errors['reportDetails'] = reportDetailError; - } - }); - } - } - } - }); - console.log(errors, 'errors'); - if (Object.keys(errors).length === 0) setValidationFlag(false); - return errors; - } - }; - const handleParentFlow = ( - values: any, - parentValueString: string, - setValues: any - ) => { - parentValue = parentValueString; - const defaultValueParent: flowsResponse.GetFlowResult = - JSON.parse(parentValueString); - - const indexOrgs = defaultValueParent.organizations - .map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const indexYears = defaultValueParent.usageYears - .map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const indexLocs = defaultValueParent.locations - .map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const indexEmrs = defaultValueParent.emergencies - ?.map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const indexGlos = defaultValueParent.globalClusters - ?.map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const indexPlns = defaultValueParent.plans - ?.map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - // const indexEnt = defaultValueParent.governingEntities?.findIndex((org) => org.flowObject?.refDirection === 'destination') ?? -1; - - const indexPros = defaultValueParent.projects - ?.map((org, index) => { - return org.flowObject?.refDirection === 'destination' - ? index - : undefined; - }) - .filter((index) => index !== undefined); - - const _sourceOrganizations = indexOrgs.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: `${defaultValueParent.organizations[index].name} [${defaultValueParent.organizations[index].abbreviation}]`, - value: defaultValueParent.organizations[index].id, - }; - } - }); - const _sourceUsageYears = indexYears.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: `${defaultValueParent.usageYears[index].year}`, - value: defaultValueParent.usageYears[index].id, - }; - } - }); - const _sourceLocations = indexLocs.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: `${defaultValueParent.locations[index].name}`, - value: defaultValueParent.locations[index].id, - }; - } - }); - - const _sourceEmergencies = indexEmrs?.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: - defaultValueParent.emergencies && - `${defaultValueParent.emergencies[index].name}`, - value: - defaultValueParent.emergencies && - defaultValueParent.emergencies[index].id, - }; - } - }); - const _sourceGlobalClusters = indexGlos?.map( - (index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: - defaultValueParent.globalClusters && - `${defaultValueParent.globalClusters[index].name}`, - value: - defaultValueParent.globalClusters && - defaultValueParent.globalClusters[index].id, - }; - } - } - ); - const _sourcePlans = indexPlns?.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: - defaultValueParent.plans && - `${defaultValueParent.plans[index].planVersion.name}`, - value: defaultValueParent.plans && defaultValueParent.plans[index].id, - }; - } - }); - const _sourceProjects = indexPros?.map((index: number | undefined) => { - if (index === 0 || index) { - return { - displayLabel: - defaultValueParent.projects && - `${defaultValueParent.projects[index].projectVersions[index].name}`, - value: - defaultValueParent.projects && - defaultValueParent.projects[index].id, - }; - } - }); - - setValues({ - ...values, - sourceOrganizations: _sourceOrganizations, - sourceUsageYears: _sourceUsageYears, - sourceLocations: _sourceLocations, - sourceEmergencies: _sourceEmergencies, - sourceGlobalClusters: _sourceGlobalClusters, - sourcePlans: _sourcePlans, - // sourceGoverningEntities: _sourceGoverningEntities ? [_sourceGoverningEntities] : [], - sourceProjects: _sourceProjects, - }); - }; - return ( - - handleSubmit(values, values.submitAction) - } - validate={(values) => validateForm(values)} - enableReinitialize - validateOnChange={false} - style={{ zIndex: 1 }} - > - {({ values, setFieldValue, setValues }) => { - if (values.parentFlow && values.parentFlow[0]) { - const parentValueString = String( - values.parentFlow && - values.parentFlow[0] && - values.parentFlow[0].value - ); - if (parentValue !== parentValueString) { - handleParentFlow(values, parentValueString, setValues); - } - } - return ( -
- - {({ remove, push }) => ( - <> - {values.reportDetails.length > 0 && - values.reportDetails.map((_: any, index: any) => ( - - - - - - - {values.sourceOrganizations.length > 0 && - values.destinationOrganizations.length > 0 && ( - -
- {values.sourceOrganizations.map( - (org: any, indexKey: any) => ( - { - event.preventDefault(); - SourceLink( - setFieldValue, - values, - indexKey, - index - ); - }} - key={indexKey} - > - {org.displayLabel} - - ) - )} -
-
- {values.destinationOrganizations.map( - (org: any, indexKey: any) => ( - { - event.preventDefault(); - DestinationLink( - setFieldValue, - values, - indexKey, - index - ); - }} - key={indexKey} - > - {`${org.displayLabel}`} - - ) - )} -
-
- )} - - - -
- Report file: -
- - , - index: number - ) => { - return handleFileChange(event, index); - }} - fnPromise={fetchDownload} - value={ - uploadFlag || - (initialValue.reportDetails[index] - ?.reportFiles && - initialValue.reportDetails[index] - .reportFiles[0]?.UploadFileUrl) - } - index={index} - id={ - initialValue.reportDetails[index] - ?.reportFiles[0]?.fileAssetID - } - deleteFunction={() => { - handleRemove(index, values); - }} - /> -
- Report url: -
- - -
- {values.reportDetails.length > 1 && ( - { - if ( - window.confirm( - 'Click OK if you are sure you want to remove this reporting detail.' - ) - ) { - remove(index); - } - }} - color="secondary" - text="Remove Reporting Detail" - startIcon={MdRemove} - /> - )} -
- - - - - - - - -
-
-
- ))} - {!readOnly && ( - { - push(initialReportDetail); - setAddReportFlag(true); - setUploadedFileArray([...uploadedFileArray, {}]); - }} - color="primary" - text="Add Reporting Detail" - startIcon={MdAdd} - /> - )} - - )} -
-
- ); - }} -
- ); -}; -export default ReportingDetails; diff --git a/apps/hpc-ftsadmin/src/app/components/flow-form.tsx b/apps/hpc-ftsadmin/src/app/components/flow-form.tsx index 89e85d153..3fa9b15ec 100644 --- a/apps/hpc-ftsadmin/src/app/components/flow-form.tsx +++ b/apps/hpc-ftsadmin/src/app/components/flow-form.tsx @@ -5,7 +5,19 @@ import dayjs from 'dayjs'; import { isRight } from 'fp-ts/Either'; import { FormikErrors } from 'formik'; import * as t from 'io-ts'; -import { util as codecs } from '@unocha/hpc-data'; +import { + fnCategories, + fnEmergencies, + fnGlobalClusters, + fnLocations, + fnOrganizations, + fnPlans, + fnProjects, + fnUsageYears, + fnReportDetails, + fnGetCurrencies, + fnGetAutocompleteFlows, +} from '../utils/fn-promises-ftsadmin'; import GppMaybeIcon from '@mui/icons-material/GppMaybe'; import Button from '@mui/material/Button'; import DeleteIcon from '@mui/icons-material/Delete'; @@ -42,6 +54,7 @@ import { governingEntities as governingEntitiesType, organizations as organizationsType, flows as flowsResponse, + util as codecs, } from '@unocha/hpc-data'; import { getEnv, AppContext } from '../context'; import { editFlowSetting, copyFlow } from '../paths'; @@ -600,9 +613,9 @@ export const FlowForm = (props: Props) => { allFieldsReviewed, pendingVersionV1, } = props; - console.log('>>>>----', initialValue.sources, currentVersionData); const env = getEnv(); const { lang } = useContext(AppContext); + const environment = env; const collapseFlowObjects = ( data: fundingObject.fundingObjectType ): FlowObject[] => { @@ -1010,10 +1023,11 @@ export const FlowForm = (props: Props) => { showDestinationGoverningEntities, handleShowDestinationGoverningEntities, ] = useState(false); - const [sourceGoverningEntities, setSourceGoverningEntities] = - useState([]); + const [sourceGoverningEntities, setSourceGoverningEntities] = useState< + AutoCompleteSelectionType[] + >([]); const [destinationGoverningEntities, setDestinationGoverningEntities] = - useState([]); + useState([]); const [isShowParentFlow, setShowParentFlow] = useState( initialValue.parentFlow && initialValue.parentFlow.length ? true : false ); @@ -1676,6 +1690,13 @@ export const FlowForm = (props: Props) => { ) => { const planQuery = Number(plan[0].value); const fetchedPlan = await env.model.plans.getPlan(planQuery); + const fetchedPlanGoverningEntities = fetchedPlan.governingEntities; + const planGoverningEntities = fetchedPlanGoverningEntities.map( + (responseValue) => ({ + displayLabel: responseValue.governingEntityVersion.name, + value: responseValue.id, + }) + ); if (objectType === 'sourcePlans') { setObjectsWithArray( fetchedPlan, @@ -1684,7 +1705,7 @@ export const FlowForm = (props: Props) => { setFieldValue, values ); - setSourceGoverningEntities(fetchedPlan.governingEntities); + setSourceGoverningEntities(planGoverningEntities); } if (objectType === 'destinationPlans') { setObjectsWithArray( @@ -1694,7 +1715,7 @@ export const FlowForm = (props: Props) => { setFieldValue, values ); - setDestinationGoverningEntities(fetchedPlan.governingEntities); + setDestinationGoverningEntities(planGoverningEntities); } if (fetchedPlan.locations) { const countries = fetchedPlan.locations.filter(function (loc) { @@ -1703,7 +1724,7 @@ export const FlowForm = (props: Props) => { if (countries.length === 1) { if (objectType === 'sourcePlans') { setObjectsWithArray( - { locations: countries }, + fetchedPlan, ['sourceLocations'], ['locations'], setFieldValue, @@ -1712,7 +1733,7 @@ export const FlowForm = (props: Props) => { } if (objectType === 'destinationPlans') { setObjectsWithArray( - { locations: countries }, + fetchedPlan, ['destinationLocations'], ['locations'], setFieldValue, @@ -2655,7 +2676,7 @@ export const FlowForm = (props: Props) => { onSubmit={(values) => handleSubmit(values, values.submitAction)} validate={(values) => validateForm(values)} enableReinitialize - validateOnChange={false} + validateOnChange style={{ zIndex: 1 }} > {({ values, setFieldValue, setValues }) => { @@ -2985,9 +3006,7 @@ export const FlowForm = (props: Props) => { s.flowForm.Organization)} name="sourceOrganizations" - fnPromise={ - env.model.organizations.getAutocompleteOrganizations - } + fnPromise={(query) => fnOrganizations(query, environment)} behavior={FORM_SETTINGS.organization.behavior} onChange={(event, value) => { updateFlowObjects(event, value, setFieldValue, values); @@ -3002,7 +3021,7 @@ export const FlowForm = (props: Props) => { s.flowForm.usageYear)} name="sourceUsageYears" - fnPromise={env.model.usageYears.getUsageYears} + fnPromise={() => fnUsageYears(environment)} isMulti behavior={FORM_SETTINGS.usageYear.behavior} onChange={(event, value) => { @@ -3023,9 +3042,7 @@ export const FlowForm = (props: Props) => { s.flowForm.location)} name="sourceLocations" - fnPromise={ - env.model.locations.getAutocompleteLocations - } + fnPromise={(query) => fnLocations(query, environment)} behavior={FORM_SETTINGS.location.behavior} isMulti entryInfo={inputEntries.sourceLocations} @@ -3037,9 +3054,7 @@ export const FlowForm = (props: Props) => { s.flowForm.emergency)} name="sourceEmergencies" - fnPromise={ - env.model.emergencies.getAutocompleteEmergencies - } + fnPromise={(query) => fnEmergencies(query, environment)} onChange={(event, value) => { updateFlowObjects(event, value, setFieldValue, values); }} @@ -3052,7 +3067,7 @@ export const FlowForm = (props: Props) => { s.flowForm.globalCluster)} name="sourceGlobalClusters" - fnPromise={env.model.globalClusters.getGlobalClusters} + fnPromise={() => fnGlobalClusters(environment)} onChange={(event, value) => { updateFlowObjects(event, value, setFieldValue, values); }} @@ -3066,7 +3081,7 @@ export const FlowForm = (props: Props) => { s.flowForm.plan)} name="sourcePlans" - fnPromise={env.model.plans.getAutocompletePlans} + fnPromise={(query) => fnPlans(query, environment)} isMulti behavior={FORM_SETTINGS.plan.behavior} onChange={(event, value) => { @@ -3101,7 +3116,7 @@ export const FlowForm = (props: Props) => { s.flowForm.project)} name="sourceProjects" - fnPromise={env.model.projects.getAutocompleteProjects} + fnPromise={(query) => fnProjects(query, environment)} behavior={FORM_SETTINGS.project.behavior} onChange={(event, value) => { updateFlowObjects(event, value, setFieldValue, values); @@ -3138,9 +3153,7 @@ export const FlowForm = (props: Props) => { s.flowForm.Organization)} name="destinationOrganizations" - fnPromise={ - env.model.organizations.getAutocompleteOrganizations - } + fnPromise={(query) => fnOrganizations(query, environment)} behavior={FORM_SETTINGS.organization.behavior} isMulti entryInfo={inputEntries.destinationOrganizations} @@ -3151,7 +3164,7 @@ export const FlowForm = (props: Props) => { s.flowForm.usageYear)} name="destinationUsageYears" - fnPromise={env.model.usageYears.getUsageYears} + fnPromise={() => fnUsageYears(environment)} isMulti behavior={FORM_SETTINGS.usageYear.behavior} onChange={(event, value) => { @@ -3171,9 +3184,7 @@ export const FlowForm = (props: Props) => { s.flowForm.location)} name="destinationLocations" - fnPromise={ - env.model.locations.getAutocompleteLocations - } + fnPromise={(query) => fnLocations(query, environment)} behavior={FORM_SETTINGS.location.behavior} isMulti entryInfo={inputEntries.destinationLocations} @@ -3184,7 +3195,7 @@ export const FlowForm = (props: Props) => { s.flowForm.globalCluster)} name="destinationGlobalClusters" - fnPromise={env.model.globalClusters.getGlobalClusters} + fnPromise={() => fnGlobalClusters(environment)} onChange={(event, value) => { updateFlowObjects(event, value, setFieldValue, values); }} @@ -3197,7 +3208,7 @@ export const FlowForm = (props: Props) => { s.flowForm.plan)} name="destinationPlans" - fnPromise={env.model.plans.getAutocompletePlans} + fnPromise={(query) => fnPlans(query, environment)} onChange={(event, value) => { updateFlowObjects(event, value, setFieldValue, values); }} @@ -3229,9 +3240,7 @@ export const FlowForm = (props: Props) => { s.flowForm.emergency)} name="destinationEmergencies" - fnPromise={ - env.model.emergencies.getAutocompleteEmergencies - } + fnPromise={(query) => fnEmergencies(query, environment)} onChange={(event, value) => { updateFlowObjects(event, value, setFieldValue, values); }} @@ -3242,7 +3251,7 @@ export const FlowForm = (props: Props) => { s.flowForm.project)} name="destinationProjects" - fnPromise={env.model.projects.getAutocompleteProjects} + fnPromise={(query) => fnProjects(query, environment)} behavior={FORM_SETTINGS.project.behavior} onChange={(event, value) => { updateFlowObjects(event, value, setFieldValue, values); @@ -3300,7 +3309,9 @@ export const FlowForm = (props: Props) => { s.flowForm.origCurrency)} name="origCurrency" - fnPromise={env.model.currencies.getCurrencies} + fnPromise={(query) => + fnGetCurrencies(query, environment) + } entryInfo={ inputEntries.origCurrency ? [inputEntries.origCurrency] @@ -3417,7 +3428,20 @@ export const FlowForm = (props: Props) => { s.flowForm.keywords)} name="keywords" - fnPromise={env.model.categories.getCategories} + fnPromise={async () => { + const response = + await environment.model.categories.getCategories({ + query: 'flowType', + }); + return response.map((responseValue) => { + return { + displayLabel: responseValue.name, + value: responseValue.name + .toLocaleLowerCase() + .replace(' ', '_'), + }; + }); + }} category="keywords" isMulti isAutocompleteAPI={false} @@ -3757,7 +3781,9 @@ export const FlowForm = (props: Props) => { s.flowForm.addFlow)} name="parentFlow" - fnPromise={env.model.flows.getAutocompleteFlows} + fnPromise={(query) => + fnGetAutocompleteFlows(query, environment) + } withoutFormik values={values} setFieldValue={setFieldValue} @@ -3799,7 +3825,9 @@ export const FlowForm = (props: Props) => { s.flowForm.addFlow)} name="childFlow" - fnPromise={env.model.flows.getAutocompleteFlows} + fnPromise={(query) => + fnGetAutocompleteFlows(query, environment) + } withoutFormik values={values} setFieldValue={setFieldValue} @@ -3868,9 +3896,12 @@ export const FlowForm = (props: Props) => { )} name={`reportDetails[${index}].reportedOrganization`} placeholder="Reported by Organization" - fnPromise={ - env.model.organizations - .getAutocompleteOrganizations + // fnPromise={ + // env.model.organizations + // .getAutocompleteOrganizations + // } + fnPromise={(query) => + fnReportDetails(query, environment) } /> {values.sourceOrganizations.length > 0 && diff --git a/apps/hpc-ftsadmin/src/app/pages/add-edit/flow-edit-rewrite/index.tsx b/apps/hpc-ftsadmin/src/app/pages/add-edit/flow-edit-rewrite/index.tsx deleted file mode 100644 index ea10424ba..000000000 --- a/apps/hpc-ftsadmin/src/app/pages/add-edit/flow-edit-rewrite/index.tsx +++ /dev/null @@ -1,1865 +0,0 @@ -import React, { useState, useEffect, useCallback } from 'react'; -import { useParams, useLocation } from 'react-router-dom'; -import { Tooltip, TooltipProps, tooltipClasses } from '@mui/material'; -import { styled } from '@mui/material/styles'; -import dayjs from 'dayjs'; -import advancedFormat from 'dayjs/plugin/advancedFormat'; -import { isRight } from 'fp-ts/lib/Either'; -import * as ts from 'io-ts'; -import _, { values } from 'lodash'; -import { - C, - CLASSES, - combineClasses, - useDataLoader, - THEME, -} from '@unocha/hpc-ui'; -import { categories, flows, forms, usageYears } from '@unocha/hpc-data'; -import { t } from '../../../../i18n'; -import PageMeta from '../../../components/page-meta'; -import { AppContext, getEnv } from '../../../context'; -import tw from 'twin.macro'; -import FlowRewriteForm, { - FormValues, - ReportDetailType, - VersionDataType, - InputEntriesType, - AutoCompleteSelectionType, - ReportFileType, -} from '../../../components/flow-form-rewrite/index'; -import { - FLOWS_FILTER_INITIAL_VALUES, - FlowsFilterValues, -} from '../../../components/filters/filter-flows-table'; -import { encodeFilters } from '../../../utils/parse-filters'; -import { - getSearchKeyValues, - getFormValueFromCategory, - getFormValueCashTransferCategory, - getFormValueFromFunding, - getNameOfFundingValue, - FUNDING_SRC_TYPE, - FUNDING_OBJECT_TYPE, - compareSelectValues, - IndividualFormValueType, - isArrayFieldOfInputEntries, - enumInputEntryVsSrcObjType, -} from '../../../utils/parse-form-values'; - -dayjs.extend(advancedFormat); - -interface Props { - className?: string; - isEdit: boolean; -} - -interface Participant { - name?: string; - email?: string; -} - -const StyledLoader = tw(C.Loader)` -mx-auto -`; - -const StyledAnchor = tw.a` -underline -`; - -const StyledAnchorDiv = tw.div` -text-2xl -float-right -`; - -const StyledSubTitle = tw.h3` -text-2xl -`; - -const StyledInactiveTitle = tw.span` -text-gray-500 -`; - -const StyledTitle = tw.div` -flex -justify-between -`; -const StyledRestrictedCheckBox = tw.div` -inline-flex -items-center -justify-center -`; - -const YellowTooltip = styled(({ className, ...props }: TooltipProps) => ( - -))(({ theme }) => ({ - [`& .${tooltipClasses.tooltip}`]: { - backgroundColor: '#ffec1a', - color: 'rgba(0, 0, 0, 0.87)', - boxShadow: theme.shadows[1], - fontSize: 11, - }, -})); - -const initialFormData = { - amountUSD: '', - amountOriginal: '', - exchangeRateUsed: '', - keywords: [], - flowStatus: '', - flowType: { value: 133, displayLabel: 'Standard' }, - flowDescription: '', - firstReported: dayjs().format('DD/MM/YYYY'), - decisionDate: null, - budgetYear: '', - flowDate: null, - contributionType: { value: 50, displayLabel: 'Financial' }, - earmarkingType: '', - method: { value: 156, displayLabel: 'Traditional aid' }, - cashTransfer: '', - beneficiaryGroup: '', - inactiveReason: '', - notes: '', - sourceOrganizations: [], - sourceLocations: [], - sourceUsageYears: [], - sourceProjects: [], - sourcePlans: [], - sourceGoverningEntities: [], - sourceGlobalClusters: [], - sourceEmergencies: [], - destinationOrganizations: [], - destinationLocations: [], - destinationUsageYears: [], - destinationProjects: [], - destinationPlans: [], - destinationGoverningEntities: [], - destinationGlobalClusters: [], - destinationEmergencies: [], - origCurrency: '', - includeChildrenOfParkedFlows: true, - reportDetails: [ - { - verified: 'verified', - reportSource: 'primary', - reporterReferenceCode: '', - reportChannel: '', - reportedOrganization: { value: '', displayLabel: '' }, - reportedDate: null, - reporterContactInformation: '', - sourceSystemRecordId: '', - reportFiles: [ - { - title: '', - fileName: '', - UploadFileUrl: '', - size: 0, - type: '', - }, - ], - reportFileTitle: '', - reportUrlTitle: '', - reportUrl: '', - }, - ], - parentFlow: [], - childFlow: [], - isParkedParent: false, - sources: {}, -}; - -const initialInputEntries = { - amountUSD: null, - keywords: null, - flowStatus: null, - flowType: null, - flowDescription: null, - contributionType: null, - earmarkingType: null, - method: null, - cashTransfer: null, - beneficiaryGroup: null, - inactiveReason: null, - amountOriginal: null, - exchangeRateUsed: null, - notes: null, - sourceOrganizations: [], - sourceLocations: [], - sourceUsageYears: [], - sourceProjects: [], - sourcePlans: [], - sourceGoverningEntities: [], - sourceGlobalClusters: [], - sourceEmergencies: [], - destinationOrganizations: [], - destinationLocations: [], - destinationUsageYears: [], - destinationProjects: [], - destinationPlans: [], - destinationGoverningEntities: [], - destinationGlobalClusters: [], - destinationEmergencies: [], - parentFlow: [], - childFlow: [], - isParkedParent: false, - sources: [], -}; - -export default (props: Props) => { - const env = getEnv(); - const { flowId, versionId } = useParams<{ - flowId: string; - versionId: string; - }>(); - const [flowData, setFlowData] = useState( - JSON.parse(JSON.stringify(initialFormData)) - ); - const [inputEntries, setInputEntries] = useState( - JSON.parse(JSON.stringify(initialInputEntries)) - ); - const [previousReportDetails, setPreviousReportDetails] = useState< - ReportDetailType[] - >([]); - const [versionData, setVersionData] = useState([]); - const [isSetupInitialValue, setIsSetupInitialValue] = useState( - !props.isEdit - ); - const [latestVersion, setLatestVersion] = useState( - parseInt(versionId as string) - ); - const [currentVersionID, setCurrentVersionID] = useState(0); - const [currentFlowID, setCurrentFlowID] = useState(0); - const [currentVersionActiveStatus, setCurrentVersionActiveStatus] = - useState(true); - const [flowDetail, setFlowDetail] = useState(null); - const [activeVersionID, setActiveVersionID] = useState(0); - const [pendingVersionID, setPendingVersionID] = useState(); - const [pendingVersionV1, setPendingVersionV1] = useState(false); - const [isPendingFlow, setIsPendingFlow] = useState(false); - const [isPending, setIsPending] = useState(false); - const [isCancellation, setIsCancellation] = useState(false); - const [isCancelled, setIsCancelled] = useState(false); - const [isSuperseded, setIsSuperseded] = useState(false); - const [isNewPending, setIsNewPending] = useState(false); - const [isUpdatePending, setIsUpdatePending] = useState(false); - const [canReactive, setCanReactive] = useState(false); - const [pendingFieldsallApplied, setPendingFieldsallApplied] = - useState(false); - const [allFieldsReviewed, setAllFieldsReviewed] = useState(false); - const [isRestricted, setIsRestricted] = useState(false); - const [errorCorrection, setErrorCorrection] = useState(false); - const [parentFlow, setParentFlow] = useState([]); - const [childFlow, setChildFlow] = useState([]); - const [parentIds, setParentIds] = useState([]); - const [childIds, setChildIds] = useState([]); - // const [isParkedParent, setIsParkedParent] = useState(false); - // const [sources, setSources] = useState>({}); - - function displayUserName(participant: Participant | null): string { - if (participant?.name) { - return participant.name; - } - if (participant?.email) { - return participant.email; - } - return 'FTS user'; - } - - const [state] = useDataLoader([flowId, versionId], () => { - if (props.isEdit && parseInt(versionId as string) === latestVersion) { - const versionIds = new Array(latestVersion).fill(0); - return Promise.all( - versionIds.map((_, index) => - env.model.flows.getFlowREST({ - id: parseInt(flowId as string), - versionId: index + 1, - }) - ) - ); - } else { - return Promise.resolve([]); - } - }); - - const [fullState] = useDataLoader([flowId, latestVersion], () => { - if (props.isEdit && parseInt(versionId as string) !== latestVersion) { - const versionIds = new Array( - latestVersion - parseInt(versionId as string) - ).fill(0); - return Promise.all( - versionIds.map((_, index) => - env.model.flows.getFlowREST({ - id: parseInt(flowId as string), - versionId: parseInt(versionId as string) + index + 1, - }) - ) - ); - } else { - return Promise.resolve([]); - } - }); - - // const handleSimilarFlowLink = useCallback( - // (event: React.MouseEvent) => { - // event.preventDefault(); - // const paramsObject: Record = { - // orderBy: 'flow.updatedAt', - // orderDir: 'DESC', - // page: '0', - // rowsPerPage: '50', - // }; - - // const flowsFilterInitialValues: FlowsFilterValues = {}; - // if (flowData.sourceLocations.length > 0) { - // flowsFilterInitialValues.sourceLocations = getSearchKeyValues( - // flowData, - // 'sourceLocations' - // ); - // } - - // if (flowData.sourceOrganizations.length > 0) { - // flowsFilterInitialValues.sourceOrganizations = getSearchKeyValues( - // flowData, - // 'sourceOrganizations' - // ); - // } - - // if (flowData.destinationOrganizations.length > 0) { - // flowsFilterInitialValues.destinationOrganizations = getSearchKeyValues( - // flowData, - // 'destinationOrganizations' - // ); - // } - - // if (flowData.destinationPlans.length > 0) { - // flowsFilterInitialValues.destinationPlans = getSearchKeyValues( - // flowData, - // 'destinationPlans' - // ); - // } - // paramsObject['filters'] = JSON.stringify( - // encodeFilters(flowsFilterInitialValues, FLOWS_FILTER_INITIAL_VALUES) - // ); - - // const params = new URLSearchParams(paramsObject); - // const newUrl = `/flows/?${params.toString()}`; - // window.open(newUrl, '_blank'); - // }, - // [flowData] - // ); - - const handleRestricted = (isChecked: boolean) => { - if (isChecked) { - setIsRestricted(true); - } else { - setIsRestricted(false); - } - }; - const handleErrorCorrection = (isChecked: boolean) => { - if (isChecked) { - setErrorCorrection(true); - } else { - setErrorCorrection(false); - } - }; - - const initializeInputEntries = () => { - const tmpEntries = JSON.parse(JSON.stringify(initialInputEntries)); - Object.keys(inputEntries).forEach((key) => { - const specificKey = key as keyof InputEntriesType; - const value = inputEntries[specificKey]; - - if (isRight(ts.array(forms.INPUT_ENTRY_TYPE).decode(value))) { - tmpEntries[specificKey] = (value as forms.InputEntryType[]).filter( - (inputEntry) => - inputEntry.category !== forms.InputEntryCategoriesEnum.ACTIVE_FLOW - ); - } - }); - setPendingFieldsallApplied(true); - setInputEntries(tmpEntries); - }; - - const rejectInputEntry = (key: string) => { - const tmpEntries = JSON.parse(JSON.stringify(inputEntries)); - const specificKey = key as keyof InputEntriesType; - const value = inputEntries[specificKey]; - if (isRight(ts.array(forms.INPUT_ENTRY_TYPE).decode(value))) { - tmpEntries[specificKey] = (value as forms.InputEntryType[]).filter( - (inputEntry) => - inputEntry.category !== forms.InputEntryCategoriesEnum.ACTIVE_FLOW - ); - } else { - tmpEntries[specificKey] = null; - } - - setInputEntries(tmpEntries); - }; - - const createInputEntryActiveFlow = ( - pendingData: IndividualFormValueType, - currentData: IndividualFormValueType, - key: keyof InputEntriesType - ) => { - const inputEntry = { - category: forms.InputEntryCategoriesEnum.ACTIVE_FLOW, - value: pendingData, - kind: !pendingData - ? forms.InputEntryKindsEnum.DELETED - : !currentData - ? forms.InputEntryKindsEnum.NEW - : forms.InputEntryKindsEnum.REVISED, - } as forms.InputEntryType; - - if (compareSelectValues(pendingData, currentData)) { - if (isArrayFieldOfInputEntries(key)) { - (inputEntries[key] as forms.InputEntryType[]).push(inputEntry); - } else { - (inputEntries[key] as forms.InputEntryType) = inputEntry; - } - } - }; - - const createInputEntryExternal = ( - src: string, - objType: string, - externalData: string - ) => { - const srcInputEntryEnum = - enumInputEntryVsSrcObjType[ - src as keyof typeof enumInputEntryVsSrcObjType - ]; - const key = srcInputEntryEnum[ - objType as keyof typeof srcInputEntryEnum - ] as keyof InputEntriesType; - - const inputEntry = { - category: forms.InputEntryCategoriesEnum.EXTERNAL, - value: externalData, - kind: forms.InputEntryKindsEnum.UNMATCHED, - }; - - const tempEntries = (inputEntries[key] as forms.InputEntryType[]).filter( - (entry) => entry.category !== forms.InputEntryCategoriesEnum.ACTIVE_FLOW - ); - tempEntries.push(inputEntry); - (inputEntries[key] as forms.InputEntryType[]) = tempEntries; - }; - - useEffect(() => { - try { - const fetchData = async () => { - const parentResults = await Promise.all( - parentIds.map((id) => - env.model.flows.getFlowREST({ - id, - }) - ) - ); - - let isParkedParent = false; - const sources: Record = {}; - - if (parentResults && parentResults[0] && parentResults[0].categories) { - const parent = parentResults[0]; - isParkedParent = parent.categories.some(function (category) { - return ( - category.group === 'flowType' && - category.name.toLowerCase() === 'parked' - ); - }); - - parent.flowObjects - .filter(function (flowObject) { - return flowObject.refDirection === 'source'; - }) - .forEach(function (flowObject) { - const objectType = flowObject.objectType; - const objTypeTail = objectType[flowObject.objectType.length - 1]; - - let objectTypePlural: string; - if (objTypeTail === 'y') { - objectTypePlural = objectType.replace('y', 'ies'); - } else { - objectTypePlural = objectType + 's'; - } - if ( - !sources[objectTypePlural] || - !sources[objectTypePlural].length - ) { - sources[objectTypePlural] = []; - } - - const parentArray = - parent[objectTypePlural as keyof typeof parent]; - if (parentArray && Array.isArray(parentArray)) { - const foundObject = parentArray.find((obj: any) => { - return flowObject.objectID === obj.id; - }); - if (foundObject) { - sources[objectTypePlural].push(foundObject); - } - } - }); - - const srcUsageYear: usageYears.UsageYear[] = []; - const destUsageYear: usageYears.UsageYear[] = []; - parent.usageYears.map((item: usageYears.UsageYear) => { - if (item.flowObject && item.flowObject.refDirection === 'source') { - srcUsageYear.push(item); - } - if ( - item.flowObject && - item.flowObject.refDirection === 'destination' - ) { - destUsageYear.push(item); - } - }); - if ( - isParkedParent && - Array.isArray(srcUsageYear) && - srcUsageYear.length > 1 && - Array.isArray(destUsageYear) && - destUsageYear.length === 1 - ) { - sources.usageYears = destUsageYear; - } - } else { - isParkedParent = false; - } - - // setIsParkedParent(isParkedParent); - // setSources(sources); - - const parentFlowData = parentResults.map((value) => { - const refDirectionIndexSrc = - value && value.organizations - ? value.organizations.findIndex( - (org) => org.flowObject?.refDirection === 'source' - ) - : -1; - const refDirectionIndexDes = - value && value.organizations - ? value.organizations.findIndex( - (org) => org.flowObject?.refDirection === 'destination' - ) - : -1; - const refDirectionLocIndexDes = - value && value.locations - ? value.locations.findIndex( - (org) => org.flowObject?.refDirection === 'destination' - ) - : -1; - return { - displayLabel: `Flow ${value.id}: ${value.description} Source: ${ - value.organizations && value.organizations[refDirectionIndexSrc] - ? value.organizations[refDirectionIndexSrc].name - : '' - } | Destination: ${ - value.organizations && value.organizations[refDirectionIndexDes] - ? value.organizations[refDirectionIndexDes].name - : '' - }`, - value: JSON.stringify({ - src_org_name: - value.organizations && value.organizations[refDirectionIndexSrc] - ? value.organizations[refDirectionIndexSrc].name - : '', - src_org_abbreviation: - value.organizations && value.organizations[refDirectionIndexSrc] - ? value.organizations[refDirectionIndexSrc].abbreviation - : '', - dest_org_name: - value.organizations && value.organizations[refDirectionIndexDes] - ? value.organizations[refDirectionIndexDes].name - : '', - dest_org_abbreviation: - value.organizations && value.organizations[refDirectionIndexDes] - ? value.organizations[refDirectionIndexDes].abbreviation - : '', - dest_loc_name: - value.locations && - value.locations[refDirectionLocIndexDes] && - refDirectionLocIndexDes > -1 - ? value.locations[refDirectionLocIndexDes].name - : '', - versionId: value.versionID, - origCurrency: value.origCurrency, - ...value, - }), - }; - }); - - setFlowData({ - ...flowData, - isParkedParent, - sources, - parentFlow: parentFlowData, - includeChildrenOfParkedFlows: false, - }); - }; - - fetchData(); - } catch (error) { - console.error('Error fetching data:', error); - } - }, [parentIds, flowData?.childFlow]); - useEffect(() => { - try { - const fetchData = async () => { - const childResults = await Promise.all( - childIds.map((id) => - env.model.flows.getFlowREST({ - id, - }) - ) - ); - - const childFlowData = childResults.map((value) => { - const refDirectionIndexSrc = - value && value.organizations - ? value.organizations.findIndex( - (org) => org.flowObject?.refDirection === 'source' - ) - : -1; - const refDirectionIndexDes = - value && value.organizations - ? value.organizations.findIndex( - (org) => org.flowObject?.refDirection === 'destination' - ) - : -1; - const refDirectionLocIndexDes = - value && value.locations - ? value.locations.findIndex( - (org) => org.flowObject?.refDirection === 'destination' - ) - : -1; - return { - displayLabel: `Flow ${value.id}: ${value.description} Source: ${ - value.organizations && value.organizations[refDirectionIndexSrc] - ? value.organizations[refDirectionIndexSrc].name - : '' - } | Destination: ${ - value.organizations && value.organizations[refDirectionIndexDes] - ? value.organizations[refDirectionIndexDes].name - : '' - }`, - value: JSON.stringify({ - activeStatus: value.activeStatus, - id: value.id, - description: value.description, - src_org_name: - value.organizations && value.organizations[refDirectionIndexSrc] - ? value.organizations[refDirectionIndexSrc].name - : '', - src_org_abbreviation: - value.organizations && value.organizations[refDirectionIndexSrc] - ? value.organizations[refDirectionIndexSrc].abbreviation - : '', - dest_org_name: - value.organizations && value.organizations[refDirectionIndexDes] - ? value.organizations[refDirectionIndexDes].name - : '', - dest_org_abbreviation: - value.organizations && value.organizations[refDirectionIndexDes] - ? value.organizations[refDirectionIndexDes].abbreviation - : '', - dest_loc_name: - value.locations && - value.locations[refDirectionLocIndexDes] && - refDirectionLocIndexDes > -1 - ? value.locations[refDirectionLocIndexDes].name - : '', - budgetYear: value.budgetYear, - flowDate: value.flowDate, - amountUSD: value.amountUSD, - origAmount: value.origAmount, - versionID: value.versionID, - origCurrency: value.origCurrency, - }), - }; - }); - setFlowData({ - ...flowData, - childFlow: childFlowData, - }); - }; - - fetchData(); - } catch (error) { - console.error('Error fetching data:', error); - } - }, [childIds]); - - useEffect(() => { - if ( - props.isEdit && - state.type === 'success' && - state.data.length > 0 && - ((parseInt(versionId as string) !== latestVersion && - fullState.type === 'success' && - fullState.data.length > 0) || - parseInt(versionId as string) === latestVersion) - ) { - const currentVersionData = state.data[parseInt(versionId as string) - 1]; - setFlowDetail(currentVersionData); - setCurrentVersionID(currentVersionData.versionID); - setCurrentFlowID(currentVersionData.id); - if ( - currentVersionData.versions.length !== latestVersion || - fullState.type !== 'success' - ) { - setLatestVersion(currentVersionData.versions.length); - return undefined; - } - const fullData = [...state.data, ...fullState.data]; - const inactiveReason = ( - getFormValueFromCategory( - currentVersionData, - 'inactiveReason', - false - ) as AutoCompleteSelectionType - ).displayLabel; - setCurrentVersionActiveStatus( - currentVersionData.activeStatus || inactiveReason === 'Pending review' - ); - const isActiveVsPending = - fullData.length > 1 && inactiveReason === 'Pending review'; - const data = isActiveVsPending - ? fullData.find((flowDetailData) => flowDetailData.activeStatus) ?? - currentVersionData - : currentVersionData; - const checkExternalRef = ( - src: FUNDING_SRC_TYPE, - objType: FUNDING_OBJECT_TYPE, - id: number | string, - refType: string - ) => { - const result = ( - (data.externalReferences ?? []) as flows.FlowExternalReference[] - ).reduce((value: boolean | null | undefined, infoRef) => { - if (value) { - return true; - } else { - if (refType === 'inferred') { - return infoRef?.importInformation?.inferred?.reduce( - (val, inferredInfo) => { - if (val) { - return true; - } else { - return ( - inferredInfo.key === `flowObjects.${src}.${objType}` && - id === inferredInfo.valueId - ); - } - }, - false - ); - } - - if (refType === 'transferred') { - return infoRef?.importInformation?.transferred?.reduce( - (val, transferredInfo) => { - if (val) { - return true; - } else { - return ( - transferredInfo.key === `flowObjects.${src}.${objType}` && - id === transferredInfo.valueId - ); - } - }, - false - ); - } - - return false; - } - }, false); - - return !!result; - }; - - const amountUSD = parseFloat(data.amountUSD); - const amountOriginal = parseFloat(data.origAmount ?? '') || null; - const exchangeRateUsed = parseFloat(data.exchangeRate ?? '') || null; - const origCurrency = data.origCurrency ?? ''; - // console.log(env.model.currencies) - // const origCurrency = env.model.currencies.map(option => { - // if(option.code === data.origCurrency) { - // return { - // value: option.id, - // displayLabel: option.code, - // }; - // } - // }) - // console.log('origCurrency', origCurrency) - const keywords = getFormValueFromCategory( - data, - 'keywords', - true - ) as AutoCompleteSelectionType[]; - const earmarkingType = getFormValueFromCategory( - data, - 'earmarkingType', - false - ) as AutoCompleteSelectionType; - const sourceOrganizations = getFormValueFromFunding( - data, - 'source', - 'organization', - checkExternalRef - ); - const destinationOrganizations = getFormValueFromFunding( - data, - 'destination', - 'organization', - checkExternalRef - ); - const sourceLocations = getFormValueFromFunding( - data, - 'source', - 'location', - checkExternalRef - ); - const destinationLocations = getFormValueFromFunding( - data, - 'destination', - 'location', - checkExternalRef - ); - const sourceUsageYears = getFormValueFromFunding( - data, - 'source', - 'usageYear', - checkExternalRef - ); - const destinationUsageYears = getFormValueFromFunding( - data, - 'destination', - 'usageYear', - checkExternalRef - ); - const sourceGlobalClusters = getFormValueFromFunding( - data, - 'source', - 'globalCluster', - checkExternalRef - ); - const destinationGlobalClusters = getFormValueFromFunding( - data, - 'destination', - 'globalCluster', - checkExternalRef - ); - const sourceEmergencies = getFormValueFromFunding( - data, - 'source', - 'emergency', - checkExternalRef - ); - const destinationEmergencies = getFormValueFromFunding( - data, - 'destination', - 'emergency', - checkExternalRef - ); - const sourceProjects = getFormValueFromFunding( - data, - 'source', - 'project', - checkExternalRef - ); - const destinationProjects = getFormValueFromFunding( - data, - 'destination', - 'project', - checkExternalRef - ); - const sourcePlans = getFormValueFromFunding( - data, - 'source', - 'plan', - checkExternalRef - ); - const sourceGoverningEntities = getFormValueFromFunding( - data, - 'source', - 'governingEntity', - checkExternalRef - ); - const destinationPlans = getFormValueFromFunding( - data, - 'destination', - 'plan', - checkExternalRef - ); - const destinationGoverningEntities = getFormValueFromFunding( - data, - 'destination', - 'governingEntity', - checkExternalRef - ); - const flowDescription = data.description; - const firstReported = dayjs(data.firstReportedDate).format('DD/MM/YYYY'); - const decisionDate = data.decisionDate - ? dayjs(data.decisionDate).format('DD/MM/YYYY') - : null; - const budgetYear = data.budgetYear ?? ''; - const flowDate = dayjs(data.flowDate).format('DD/MM/YYYY'); - const notes = data.notes ?? ''; - const flowStatus = getFormValueFromCategory( - data, - 'flowStatus', - false - ) as AutoCompleteSelectionType; - const flowType = getFormValueFromCategory( - data, - 'flowType', - false - ) as AutoCompleteSelectionType; - const contributionType = getFormValueFromCategory( - data, - 'contributionType', - false - ) as AutoCompleteSelectionType; - const method = getFormValueFromCategory( - data, - 'method', - false - ) as AutoCompleteSelectionType; - const cashTransfer = getFormValueCashTransferCategory( - data, - false - ) as AutoCompleteSelectionType; - const beneficiaryGroup = getFormValueFromCategory( - data, - 'beneficiaryGroup', - false - ) as AutoCompleteSelectionType; - - const parentIds = data.parents.map((item) => item.parentID); - const childIds = data.children.map((item) => item.childID); - - setParentIds(parentIds); - setChildIds(childIds); - - const reportDetails = data.reportDetails.map((detail) => ({ - verified: detail.verified ? 'verified' : 'unverified', - reportSource: detail.source === 'Primary' ? 'primary' : 'secondary', - reporterReferenceCode: detail.refCode ?? '', - reportChannel: - (detail?.categories ?? []) - .filter((category) => category.group === 'reportChannel') - .map((category) => ({ - value: category.id, - displayLabel: category.name, - }))[0] ?? '', - reportedOrganization: { - value: detail?.organization?.id ?? 0, - displayLabel: `${detail?.organization?.name} [${detail?.organization?.abbreviation}]`, - }, - reportedDate: dayjs(detail.date).format('DD/MM/YYYY'), - reporterContactInformation: detail.contactInfo ?? '', - sourceSystemRecordId: detail.sourceID ?? '', - reportFiles: (detail?.reportFiles ?? []).reduce( - (refileData: ReportFileType[], fileData) => { - if (fileData.type !== 'url') { - refileData.push({ - title: fileData?.title, - fileName: fileData.fileAssetEntity?.originalname, - UploadFileUrl: fileData.fileAssetEntity?.path, - fileAssetID: fileData?.fileAssetID, - size: fileData.fileAssetEntity?.size, - type: fileData.fileAssetEntity?.mimetype, - }); - } - return refileData; - }, - [] - ), - reportFileTitle: - detail.reportFiles && - (detail.reportFiles.length > 1 - ? (detail.reportFiles as ReportFileType[]).filter( - (fileData) => fileData.type !== 'url' - )[0]?.title - : detail.reportFiles.filter( - (fileData) => fileData.type !== 'url' - )[0]?.title), - reportUrlTitle: - detail.reportFiles && - (detail.reportFiles as ReportFileType[]).filter( - (fileData) => fileData.type === 'url' - )[0]?.title, - reportUrl: - detail.reportFiles && - (detail.reportFiles as ReportFileType[]).filter( - (fileData) => fileData.type === 'url' - )[0]?.url, - fileAsset: - detail.reportFiles && - (detail.reportFiles.length > 1 - ? (detail.reportFiles as ReportFileType[]).filter( - (fileData) => fileData.type !== 'url' - )[0]?.fileAssetEntity - : detail.reportFiles.filter( - (fileData) => fileData.type !== 'url' - )[0]?.fileAssetEntity), - })); - const prevReportDetails = state.data.reduce( - (details, flowItemData, index) => { - if (index < parseInt(versionId as string) - 1) { - details = [ - ...details, - ...flowItemData.reportDetails.map((detail) => ({ - verified: detail.verified ? 'verified' : 'unverified', - reportSource: - detail.source === 'Primary' ? 'primary' : 'secondary', - reporterReferenceCode: detail.refCode ?? '', - reportChannel: - (detail?.categories ?? []) - .filter((category) => category.group === 'reportChannel') - .map((category) => ({ - value: category.id, - displayLabel: category.name, - }))[0] ?? '', - reportedOrganization: { - value: detail?.organization?.id ?? 0, - displayLabel: `${detail?.organization?.name} [${detail?.organization?.abbreviation}]`, - }, - reportedDate: dayjs(detail.date).format('DD/MM/YYYY'), - reporterContactInformation: detail.contactInfo ?? '', - sourceSystemRecordId: detail.sourceID ?? '', - reportFiles: (detail?.reportFiles ?? []).reduce( - (refileData: ReportFileType[], fileData) => { - if (fileData.type !== 'url') { - refileData.push({ - title: fileData?.title, - fileName: fileData.fileAssetEntity?.originalname, - UploadFileUrl: fileData.fileAssetEntity?.path, - fileAssetID: fileData?.fileAssetID, - size: fileData.fileAssetEntity?.size, - type: fileData.fileAssetEntity?.mimetype, - }); - } - return refileData; - }, - [] - ), - reportFileTitle: - detail.reportFiles && - (detail.reportFiles.length > 1 - ? (detail.reportFiles as ReportFileType[]).filter( - (fileData) => fileData.type !== 'url' - )[0]?.title - : detail.reportFiles.filter( - (fileData) => fileData.type !== 'url' - )[0]?.title), - reportUrlTitle: - detail.reportFiles && - (detail.reportFiles as ReportFileType[]).filter( - (fileData) => fileData.type === 'url' - )[0]?.title, - reportUrl: - detail.reportFiles && - (detail.reportFiles as ReportFileType[]).filter( - (fileData) => fileData.type === 'url' - )[0]?.url, - })), - ]; - } - return details; - }, - [] as ReportDetailType[] - ); - const versionDetails = fullData.map((flowItemData, index) => ({ - versionId: index + 1, - flowId: parseInt(flowId as string), - createdTime: dayjs(flowItemData.createdAt).format( - 'Do MMMM YYYY [at] h:mm:ss a' - ), - createdBy: flowItemData.createdBy?.name ?? '', - updatedTime: dayjs(flowItemData.updatedAt).format( - 'Do MMMM YYYY [at] h:mm:ss a' - ), - updatedBy: flowItemData.lastUpdatedBy?.name ?? '', - active: flowItemData.activeStatus, - viewing: index + 1 === parseInt(versionId as string), - pending: - ( - getFormValueFromCategory( - flowItemData, - 'inactiveReason', - false - ) as AutoCompleteSelectionType - ).displayLabel === 'Pending review', - cancellation: - ( - getFormValueFromCategory( - flowItemData, - 'pendingStatus', - false - ) as AutoCompleteSelectionType - ).displayLabel === 'cancellation', - cancelled: - ( - getFormValueFromCategory( - flowItemData, - 'inactiveReason', - false - ) as AutoCompleteSelectionType - ).displayLabel === 'cancelled', - superseded: - ( - getFormValueFromCategory( - flowItemData, - 'inactiveReason', - false - ) as AutoCompleteSelectionType - ).displayLabel === 'superseded', - source: { - emergencies: getNameOfFundingValue( - flowItemData, - 'source', - 'emergency' - ), - projects: getNameOfFundingValue(flowItemData, 'source', 'project'), - usageYears: getNameOfFundingValue( - flowItemData, - 'source', - 'usageYear' - ), - globalClusters: getNameOfFundingValue( - flowItemData, - 'source', - 'globalCluster' - ), - locations: getNameOfFundingValue(flowItemData, 'source', 'location'), - plans: getNameOfFundingValue(flowItemData, 'source', 'plan'), - organizations: getNameOfFundingValue( - flowItemData, - 'source', - 'organization' - ), - }, - destination: { - emergencies: getNameOfFundingValue( - flowItemData, - 'destination', - 'emergency' - ), - projects: getNameOfFundingValue( - flowItemData, - 'destination', - 'project' - ), - usageYears: getNameOfFundingValue( - flowItemData, - 'destination', - 'usageYear' - ), - globalClusters: getNameOfFundingValue( - flowItemData, - 'destination', - 'globalCluster' - ), - locations: getNameOfFundingValue( - flowItemData, - 'destination', - 'location' - ), - plans: getNameOfFundingValue(flowItemData, 'destination', 'plan'), - organizations: getNameOfFundingValue( - flowItemData, - 'destination', - 'organization' - ), - }, - categories: flowItemData.categories.map((category) => category.name), - amountUSD: flowItemData.amountUSD, - flowDate: flowItemData.flowDate, - decisionDate: flowItemData.flowDate, - firstReportedDate: flowItemData.firstReportedDate, - budgetYear: flowItemData.budgetYear, - origAmount: flowItemData.origAmount, - origCurrency: flowItemData.origCurrency, - exchangeRate: flowItemData.exchangeRate, - activeStatus: flowItemData.activeStatus, - restricted: flowItemData.restricted, - newMoney: flowItemData.newMoney, - description: flowItemData.description, - notes: flowItemData.notes, - uniqueSources: {}, - uniqueDestinations: {}, - uniqueCategories: [], - })); - - if (isActiveVsPending) { - const pendingAmountUSD = parseFloat(currentVersionData.amountUSD); - createInputEntryActiveFlow(pendingAmountUSD, amountUSD, 'amountUSD'); - - const pendingAmountOriginal = - parseFloat(currentVersionData.origAmount ?? '') || null; - createInputEntryActiveFlow( - pendingAmountOriginal, - amountOriginal, - 'amountOriginal' - ); - - const pendingExchangeRateUsed = - parseFloat(currentVersionData.exchangeRate ?? '') || null; - createInputEntryActiveFlow( - pendingExchangeRateUsed, - exchangeRateUsed, - 'exchangeRateUsed' - ); - - const pendingKeywords = getFormValueFromCategory( - currentVersionData, - 'keywords', - true - ) as AutoCompleteSelectionType[]; - createInputEntryActiveFlow(pendingKeywords, keywords, 'keywords'); - - const pendingEarmarkingType = getFormValueFromCategory( - currentVersionData, - 'earmarkingType', - false - ) as AutoCompleteSelectionType; - createInputEntryActiveFlow( - pendingEarmarkingType, - earmarkingType, - 'earmarkingType' - ); - - const pendingFlowDescription = currentVersionData.description ?? ''; - createInputEntryActiveFlow( - pendingFlowDescription, - flowDescription, - 'flowDescription' - ); - - const pendingNotes = currentVersionData.notes ?? ''; - createInputEntryActiveFlow(pendingNotes, notes, 'notes'); - - const pendingFlowType = getFormValueFromCategory( - currentVersionData, - 'flowType', - false - ) as AutoCompleteSelectionType; - createInputEntryActiveFlow(pendingFlowType, flowType, 'flowType'); - - const pendingFlowStatus = getFormValueFromCategory( - currentVersionData, - 'flowStatus', - false - ) as AutoCompleteSelectionType; - createInputEntryActiveFlow(pendingFlowStatus, flowStatus, 'flowStatus'); - - const pendingContributionType = getFormValueFromCategory( - currentVersionData, - 'contributionType', - false - ) as AutoCompleteSelectionType; - createInputEntryActiveFlow( - pendingContributionType, - contributionType, - 'contributionType' - ); - - const pendingMethod = getFormValueFromCategory( - currentVersionData, - 'method', - false - ) as AutoCompleteSelectionType; - createInputEntryActiveFlow(pendingMethod, method, 'method'); - - const pendingBeneficiaryGroup = getFormValueFromCategory( - currentVersionData, - 'beneficiaryGroup', - false - ) as AutoCompleteSelectionType; - createInputEntryActiveFlow( - pendingBeneficiaryGroup, - beneficiaryGroup, - 'beneficiaryGroup' - ); - - const pendingSourceOrganizations = getFormValueFromFunding( - currentVersionData, - 'source', - 'organization', - checkExternalRef - ); - createInputEntryActiveFlow( - pendingSourceOrganizations, - sourceOrganizations, - 'sourceOrganizations' - ); - - const pendingDestinationOrganizations = getFormValueFromFunding( - currentVersionData, - 'destination', - 'organization', - checkExternalRef - ); - createInputEntryActiveFlow( - pendingDestinationOrganizations, - destinationOrganizations, - 'destinationOrganizations' - ); - - const pendingSourceLocations = getFormValueFromFunding( - currentVersionData, - 'source', - 'location', - checkExternalRef - ); - createInputEntryActiveFlow( - pendingSourceLocations, - sourceLocations, - 'sourceLocations' - ); - - const pendingDestinationLocations = getFormValueFromFunding( - currentVersionData, - 'destination', - 'location', - checkExternalRef - ); - createInputEntryActiveFlow( - pendingDestinationLocations, - destinationLocations, - 'destinationLocations' - ); - - const pendingSourceUsageYears = getFormValueFromFunding( - currentVersionData, - 'source', - 'usageYear', - checkExternalRef - ); - createInputEntryActiveFlow( - pendingSourceUsageYears, - sourceUsageYears, - 'sourceUsageYears' - ); - - const pendingDestinationUsageYears = getFormValueFromFunding( - currentVersionData, - 'destination', - 'usageYear', - checkExternalRef - ); - createInputEntryActiveFlow( - pendingDestinationUsageYears, - destinationUsageYears, - 'destinationUsageYears' - ); - - const pendingSourceGlobalClusters = getFormValueFromFunding( - currentVersionData, - 'source', - 'globalCluster', - checkExternalRef - ); - createInputEntryActiveFlow( - pendingSourceGlobalClusters, - sourceGlobalClusters, - 'sourceGlobalClusters' - ); - - const pendingDestinationGlobalClusters = getFormValueFromFunding( - currentVersionData, - 'destination', - 'globalCluster', - checkExternalRef - ); - createInputEntryActiveFlow( - pendingDestinationGlobalClusters, - destinationGlobalClusters, - 'destinationGlobalClusters' - ); - - const pendingSourceEmergencies = getFormValueFromFunding( - currentVersionData, - 'source', - 'emergency', - checkExternalRef - ); - createInputEntryActiveFlow( - pendingSourceEmergencies, - sourceEmergencies, - 'sourceEmergencies' - ); - - const pendingDestinationEmergencies = getFormValueFromFunding( - currentVersionData, - 'destination', - 'emergency', - checkExternalRef - ); - createInputEntryActiveFlow( - pendingDestinationEmergencies, - destinationEmergencies, - 'destinationEmergencies' - ); - - const pendingSourceProjects = getFormValueFromFunding( - currentVersionData, - 'source', - 'project', - checkExternalRef - ); - createInputEntryActiveFlow( - pendingSourceProjects, - sourceProjects, - 'sourceProjects' - ); - - const pendingDestinationProjects = getFormValueFromFunding( - currentVersionData, - 'destination', - 'project', - checkExternalRef - ); - createInputEntryActiveFlow( - pendingDestinationProjects, - destinationProjects, - 'destinationProjects' - ); - - const pendingSourcePlans = getFormValueFromFunding( - currentVersionData, - 'source', - 'plan', - checkExternalRef - ); - createInputEntryActiveFlow( - pendingSourcePlans, - sourcePlans, - 'sourcePlans' - ); - - const pendingDestinationPlans = getFormValueFromFunding( - currentVersionData, - 'destination', - 'plan', - checkExternalRef - ); - createInputEntryActiveFlow( - pendingDestinationPlans, - destinationPlans, - 'destinationPlans' - ); - - // const pendingParentFlow = getFormValueFromCategory( - // currentVersionData, - // 'parentFlow', - // false - // ) as AutoCompleteSelectionType; - // createInputEntryActiveFlow(pendingParentFlow, parentFlow, 'parentFlow'); - - // const pendingChildFlow = getFormValueFromCategory( - // currentVersionData, - // 'childFlow', - // false - // ) as AutoCompleteSelectionType; - // createInputEntryActiveFlow(pendingChildFlow, childFlow, 'childFlow'); - } - - if (data.externalData && inactiveReason === 'Pending review') { - (data.externalData as flows.FlowExternalData[]).forEach( - (externalValue) => { - createInputEntryExternal( - externalValue.refDirection, - externalValue.objectType, - externalValue.data - ); - } - ); - } - const activeMatch = data.versions.filter(function ( - d: flows.FlowSearchResult - ) { - return d.activeStatus; - })[0]?.versionID; - - const pendingId = versionDetails.findIndex((data) => data.pending) + 1; - setPendingVersionID(pendingId); - - setIsPending(pendingId === currentVersionData.versionID); - setIsCancellation( - versionDetails.findIndex((data) => data.cancellation) > -1 - ); - setIsCancelled(versionDetails.findIndex((data) => data.cancelled) > -1); - setIsSuperseded(versionDetails.findIndex((data) => data.superseded) > -1); - setIsNewPending(!(activeMatch > -1)); - setIsUpdatePending(activeMatch > -1); - if (isSuperseded) { - const inactiveVersions = currentVersionData.versions - .filter((data) => !data.activeStatus) - .sort( - (a, b) => - new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime() - ); - const noActiveVersions = - inactiveVersions.length === currentVersionData.versions.length; - const isTheRightVersion = - inactiveVersions && - inactiveVersions.length > 1 && - inactiveVersions[1].versionID === currentVersionData.versionID; - const isLatestVersionDeleted = - inactiveVersions && - inactiveVersions[0] && - !!inactiveVersions[0].deletedAt - ? true - : false; - setCanReactive( - noActiveVersions && isTheRightVersion && isLatestVersionDeleted - ); - } - - setActiveVersionID(activeMatch); - setFlowData({ - ...flowData, - amountUSD, - amountOriginal, - exchangeRateUsed, - keywords, - flowStatus, - flowType, - flowDescription, - firstReported, - decisionDate, - budgetYear, - flowDate, - contributionType, - earmarkingType, - method, - cashTransfer, - beneficiaryGroup, - inactiveReason, - notes, - sourceOrganizations, - sourceLocations, - sourceUsageYears, - sourceProjects, - sourcePlans, - sourceGoverningEntities, - sourceGlobalClusters, - sourceEmergencies, - destinationOrganizations, - destinationLocations, - destinationUsageYears, - destinationProjects, - destinationPlans, - destinationGoverningEntities, - destinationGlobalClusters, - destinationEmergencies, - origCurrency, - reportDetails, - }); - setInputEntries({ ...inputEntries }); - setIsSetupInitialValue(true); - setPreviousReportDetails(prevReportDetails); - setVersionData(versionDetails); - setIsPendingFlow(versionDetails.some((detail) => detail.pending)); - setIsRestricted( - versionDetails[parseInt(versionId as string)]?.restricted - ); - } else { - setFlowDetail(null); - } - }, [state, fullState, props.isEdit]); - - useEffect(() => { - if (pendingVersionID && pendingVersionID > 1) { - setPendingVersionV1(true); - } else { - setPendingVersionV1(false); - } - }, [pendingVersionID]); - - useEffect(() => { - if (!props.isEdit) { - setFlowData(JSON.parse(JSON.stringify(initialFormData))); - } - }, [props.isEdit]); - - useEffect(() => { - if (inputEntries) { - let isEmpty = true; - Object.values(inputEntries).map((key) => { - if (!_.isEmpty(key)) isEmpty = false; - }); - if (isEmpty) { - setAllFieldsReviewed(true); - } - } - }, [inputEntries]); - const location = useLocation(); - const copyValues = location.state; - const [isTitleView, setisTitleView] = useState(false); - useEffect(() => { - const handleScroll = () => { - const scrollPosition = window.scrollY; - if (scrollPosition > 0) { - setisTitleView(true); - } else { - setisTitleView(false); - } - }; - window.addEventListener('scroll', handleScroll); - return () => { - window.removeEventListener('scroll', handleScroll); - }; - }, []); - return ( - - {({ lang }) => ( - s.components.loader), - notFound: { - ...t.get(lang, (s) => s.components.notFound), - }, - }} - > - {() => { - return ( -
- s.routes.newFlow.title)]} /> - - -
- {flowDetail - ? t.t( - lang, - (s) => - s.routes.editFlow.title + - ' ' + - flowDetail.id + - ', v' + - flowDetail.versionID - ) - : t.t(lang, (s) => s.routes.newFlow.title)} - {flowDetail && - !flowDetail.activeStatus && - !flowDetail.deletedAt && - flowData.inactiveReason === 'Pending review' && ( - {`[Inactive -Pending Review]`} - )} - {flowDetail && ( - <> - - -
- {isRestricted && ( - <> - This flow is marked as Restricted and will - not be included in the funding totals on the - FTS website. - - )} -
-
- {isPendingFlow ? ( - flowDetail.versionID === pendingVersionID ? ( - pendingVersionV1 ? ( - <>This is a pending update. - ) : ( - <> - This flow is not active because it has - been marked as {flowData.inactiveReason} - . - - ) - ) : !flowDetail.activeStatus ? ( - <> - <> - This flow is not active because it has - been marked as {flowData.inactiveReason} - . - - <> - See{' '} - - Flow {flowDetail.id}, v - {activeVersionID} - {' '} - for the current active version. and{' '} - - Flow {flowDetail.id}, v - {pendingVersionID} - {' '} - for the current pending version. - - - ) : ( - <> - There is a pending update to this flow. - Review pending{' '} - - Flow {flowDetail.id}, v - {pendingVersionID} - - . - - ) - ) : ( - '' - )} -
-
-
- - Updated{' '} - {dayjs(flowDetail.updatedAt).format( - 'Do MMMM YYYY [at] h:mm:ss a' - )}{' '} - by {displayUserName(flowDetail.lastUpdatedBy)} - - - Created{' '} - {dayjs(flowDetail.createdAt).format( - 'Do MMMM YYYY [at] h:mm:ss a' - )}{' '} - by {displayUserName(flowDetail.createdBy)} - - - )} -
-
- - {!isPending && props.isEdit && ( - { - handleErrorCorrection(e.target.checked); - }} - withoutFormik - /> - )} - { - handleRestricted(e.target.checked); - }} - withoutFormik - style={{ marginRight: 0 }} - /> - - - i - - - -
- - - Find Similar Flows - - -
-
-
-
- {isSetupInitialValue && ( - - )} -
- ); - }} -
- )} -
- ); -}; diff --git a/apps/hpc-ftsadmin/src/app/pages/add-edit/flow-edit.tsx b/apps/hpc-ftsadmin/src/app/pages/add-edit/flow-edit.tsx index 41037a249..b203a703c 100644 --- a/apps/hpc-ftsadmin/src/app/pages/add-edit/flow-edit.tsx +++ b/apps/hpc-ftsadmin/src/app/pages/add-edit/flow-edit.tsx @@ -456,7 +456,6 @@ export default (props: Props) => { ); let isParkedParent = false; - // const sources: Record = {}; const sources: flowsResponse.FormValuesSources = { organizations: [], usageYears: [], diff --git a/apps/hpc-ftsadmin/src/app/utils/fn-promises-ftsadmin.tsx b/apps/hpc-ftsadmin/src/app/utils/fn-promises-ftsadmin.tsx new file mode 100644 index 000000000..59f5eb6c0 --- /dev/null +++ b/apps/hpc-ftsadmin/src/app/utils/fn-promises-ftsadmin.tsx @@ -0,0 +1,209 @@ +import { categories, FormObjectValue, flows } from '@unocha/hpc-data'; +import { Environment } from '../../environments/interface'; + +/** Functions to pass to fnPromise prop */ + +export const fnOrganizations = async ( + query: { query: string }, + env: Environment +): Promise> => { + const response = + await env.model.organizations.getAutocompleteOrganizations(query); + return response.map((responseValue) => ({ + displayLabel: `${responseValue.name} [${responseValue.abbreviation}]`, + value: responseValue.id, + })); +}; + +export const fnUsageYears = async ( + env: Environment +): Promise> => { + const response = await env.model.usageYears.getUsageYears(); + return response.map((responseValue) => ({ + displayLabel: responseValue.year, + value: responseValue.id, + })); +}; +export const fnProjects = async ( + query: { query: string }, + env: Environment +) => { + const response = await env.model.projects.getAutocompleteProjects(query); + return response.map((responseValue) => ({ + displayLabel: `${responseValue.name} [${responseValue.code}]`, + value: responseValue.id, + })); +}; + +export const fnReportDetails = async ( + query: { query: string }, + env: Environment +) => { + const response = + await env.model.organizations.getAutocompleteOrganizations(query); + return response.map((responseValue) => { + return { + displayLabel: responseValue.name, + value: responseValue.id, + }; + }); +}; + +export const fnGetCurrencies = async ( + query: { query: string }, + env: Environment +) => { + const response = await env.model.currencies.getCurrencies(); + return response.map((responseValue) => { + return { + displayLabel: responseValue.code, + value: responseValue.id, + }; + }); +}; + +const defaultOptions = ( + response: Array<{ + name: string; + id: number; + }> +): Array => { + return response.map((responseValue) => ({ + displayLabel: responseValue.name, + value: responseValue.id, + })); +}; + +export const fnLocations = async ( + query: { query: string }, + env: Environment +): Promise> => { + const response = await env.model.locations.getAutocompleteLocations(query); + const res: Array = []; + + for (const responseValue of response) { + const hasChildren = + responseValue.children && responseValue.children.length > 0; + const parentLocation: FormObjectValue = { + displayLabel: responseValue.name, + value: responseValue.id, + hasChildren: hasChildren, + }; + res.push(parentLocation); + if (hasChildren) { + for (const responseLevelValue of responseValue.children) { + res.push({ + displayLabel: responseLevelValue.name, + value: responseLevelValue.id, + parent: parentLocation, + }); + } + } + } + return res; +}; + +export const fnPlans = async (query: { query: string }, env: Environment) => { + const response = await env.model.plans.getAutocompletePlans(query); + return defaultOptions(response); +}; + +export const fnGlobalClusters = async (env: Environment) => { + const response = await env.model.globalClusters.getGlobalClusters(); + return defaultOptions(response); +}; + +export const fnEmergencies = async ( + query: { query: string }, + env: Environment +) => { + const response = + await env.model.emergencies.getAutocompleteEmergencies(query); + return defaultOptions(response); +}; + +export const fnCategories = async ( + query: categories.CategoryGroup, + env: Environment +) => { + const response = await env.model.categories.getCategories({ + query, + }); + return defaultOptions(response); +}; + +export const fnGetAutocompleteFlows = async ( + query: { query: string }, + env: Environment +) => { + const response = await env.model.flows.getAutocompleteFlows(query); + return response.map((responseValue) => { + const value = responseValue as flows.FlowREST; + const refDirectionIndexSrc = + value && value.organizations + ? value.organizations.findIndex( + (org) => org.flowObject?.refDirection === 'source' + ) + : -1; + const refDirectionIndexDes = + value && value.organizations + ? value.organizations.findIndex( + (org) => org.flowObject?.refDirection === 'destination' + ) + : -1; + const refDirectionLocIndexDes = + value && value.locations + ? value.locations.findIndex( + (org) => org.flowObject?.refDirection === 'destination' + ) + : -1; + return { + displayLabel: `Flow ${value.id}: ${value.description} Source: ${ + value.organizations && + value.organizations[refDirectionIndexSrc] && + refDirectionIndexSrc > -1 + ? value.organizations[refDirectionIndexSrc].name + : '' + } | Destination: ${ + value.organizations && + value.organizations[refDirectionIndexDes] && + refDirectionIndexDes > -1 + ? value.organizations[refDirectionIndexDes].name + : '' + }`, + value: JSON.stringify({ + src_org_name: + value.organizations && + value.organizations[refDirectionIndexSrc] && + refDirectionIndexSrc > -1 + ? value.organizations[refDirectionIndexSrc].name + : '', + src_org_abbreviation: + value.organizations && + value.organizations[refDirectionIndexSrc] && + refDirectionIndexSrc > -1 + ? value.organizations[refDirectionIndexSrc].abbreviation + : '', + dest_org_name: + value.organizations && + value.organizations[refDirectionIndexDes] && + refDirectionIndexDes > -1 + ? value.organizations[refDirectionIndexDes].name + : '', + dest_org_abbreviation: + value.organizations && + value.organizations[refDirectionIndexDes] && + refDirectionIndexDes > -1 + ? value.organizations[refDirectionIndexDes].abbreviation + : '', + dest_loc_name: + value.locations && + value.locations[refDirectionLocIndexDes] && + refDirectionLocIndexDes > -1 + ? value.locations[refDirectionLocIndexDes].name + : '', + ...value, + }), + }; + }); +}; diff --git a/libs/hpc-ui/src/lib/components/form-fields/async-autocomplete-field-ftsadmin.tsx b/libs/hpc-ui/src/lib/components/form-fields/async-autocomplete-field-ftsadmin.tsx index a0b7d48ca..f9231fb90 100644 --- a/libs/hpc-ui/src/lib/components/form-fields/async-autocomplete-field-ftsadmin.tsx +++ b/libs/hpc-ui/src/lib/components/form-fields/async-autocomplete-field-ftsadmin.tsx @@ -68,8 +68,8 @@ type AsyncAutocompleteSelectProps = { name: string; label: string; placeholder?: string; - fnPromise?: ({ query }: { query: string }) => Promise; - optionsData?: APIAutocompleteResult; + fnPromise?: ({ query }: { query: string }) => Promise>; + optionsData?: Array; category?: categories.CategoryGroup; isMulti?: boolean; isAutocompleteAPI?: boolean; @@ -84,6 +84,23 @@ type AsyncAutocompleteSelectProps = { alreadyIsFetch?: boolean; fetchedData?: readonly FormObjectValue[]; isDisabled?: boolean; + removeOptions?: Array; +}; + +const removeFormObjectValueFromFirstArray = ( + firstArray: Array, + secondArray: Array | undefined +) => { + if (secondArray) { + return firstArray.filter( + (firstArrayObject) => + !secondArray.some( + (secondArrayObject) => + firstArrayObject.value === secondArrayObject.value + ) + ); + } + return firstArray; }; const AsyncAutocompleteSelect = ({ @@ -104,6 +121,7 @@ const AsyncAutocompleteSelect = ({ values, setFieldValue, isDisabled, + removeOptions, ...otherProps }: AsyncAutocompleteSelectProps) => { const [open, setOpen] = useState(false); @@ -121,37 +139,6 @@ const AsyncAutocompleteSelect = ({ (!isAutocompleteAPI || inputValue.length >= 3 || category !== undefined); const actualYear = new Date().getFullYear(); - function isUsageYearsResult( - result: APIAutocompleteResult - ): result is usageYears.GetUsageYearsResult { - return usageYears.GET_USAGE_YEARS_RESULT.is(result); - } - function isOrganizationsResult( - result: APIAutocompleteResult - ): result is organizations.GetOrganizationsResult { - return organizations.GET_ORGANIZATIONS_RESULT.is(result); - } - function isGlobalClustersResult( - result: APIAutocompleteResult - ): result is globalClusters.GetGlobalClustersResult { - return globalClusters.GET_GLOBAL_CLUSTERS_RESULT.is(result); - } - function isCurrenciesResult( - result: APIAutocompleteResult - ): result is currencies.GetCurrenciesResult { - return currencies.GET_CURRENCIES_RESULT.is(result); - } - function isProjectsResult( - result: APIAutocompleteResult - ): result is projects.GetProjectsAutocompleteResult { - return projects.GET_PROJECTS_AUTOCOMPLETE_RESULT.is(result); - } - function isPlansResult( - result: APIAutocompleteResult - ): result is plans.GetPlansAutocompleteResult { - return plans.GET_PLANS_AUTOCOMPLETE_RESULT.is(result); - } - useEffect(() => { let active = true; if ( @@ -185,7 +172,7 @@ const AsyncAutocompleteSelect = ({ // } (async () => { try { - let response: APIAutocompleteResult; + let response: FormObjectValue[]; if (fnPromise) { response = await fnPromise({ query: category ? category : inputValue, @@ -193,144 +180,10 @@ const AsyncAutocompleteSelect = ({ } else { response = optionsData || []; } - const parsedResponse = response.map((responseValue) => { - if (isUsageYearsResult(response)) { - return { - displayLabel: (responseValue as usageYears.UsageYear).year, - value: responseValue.id, - }; - } else if (isOrganizationsResult(response)) { - const org = responseValue as organizations.Organization; - return { - displayLabel: `${org.name} [${org.abbreviation}]`, - value: responseValue.id, - }; - } else if (isGlobalClustersResult(response)) { - return { - displayLabel: (responseValue as globalClusters.GlobalCluster) - .name, - value: responseValue.id, - }; - } else if (isPlansResult(response)) { - return { - displayLabel: (responseValue as plans.Plan).name, - value: responseValue.id, - restricted: (responseValue as plans.Plan).restricted, - }; - } else if (isCurrenciesResult(response)) { - return { - displayLabel: (responseValue as currencies.Currency).code, - value: responseValue.id, - }; - } else if (isProjectsResult(response)) { - return { - displayLabel: `${(responseValue as projects.Project).name} [${ - (responseValue as projects.Project).code - }]`, - value: responseValue.id, - }; - } else if ( - name === 'sourceGoverningEntities' || - name === 'destinationGoverningEntities' - ) { - return { - displayLabel: (responseValue as governingEntities.GoverningEntity) - .governingEntityVersion.name, - value: responseValue.id, - }; - } else if (name === 'parentFlow' || name === 'childFlow') { - const value = responseValue as flows.FlowREST; - const refDirectionIndexSrc = - value && value.organizations - ? value.organizations.findIndex( - (org) => org.flowObject?.refDirection === 'source' - ) - : -1; - const refDirectionIndexDes = - value && value.organizations - ? value.organizations.findIndex( - (org) => org.flowObject?.refDirection === 'destination' - ) - : -1; - const refDirectionLocIndexDes = - value && value.locations - ? value.locations.findIndex( - (org) => org.flowObject?.refDirection === 'destination' - ) - : -1; - return { - displayLabel: `Flow ${value.id}: ${value.description} Source: ${ - value.organizations && - value.organizations[refDirectionIndexSrc] && - refDirectionIndexSrc > -1 - ? value.organizations[refDirectionIndexSrc].name - : '' - } | Destination: ${ - value.organizations && - value.organizations[refDirectionIndexDes] && - refDirectionIndexDes > -1 - ? value.organizations[refDirectionIndexDes].name - : '' - }`, - value: JSON.stringify({ - src_org_name: - value.organizations && - value.organizations[refDirectionIndexSrc] && - refDirectionIndexSrc > -1 - ? value.organizations[refDirectionIndexSrc].name - : '', - src_org_abbreviation: - value.organizations && - value.organizations[refDirectionIndexSrc] && - refDirectionIndexSrc > -1 - ? value.organizations[refDirectionIndexSrc].abbreviation - : '', - dest_org_name: - value.organizations && - value.organizations[refDirectionIndexDes] && - refDirectionIndexDes > -1 - ? value.organizations[refDirectionIndexDes].name - : '', - dest_org_abbreviation: - value.organizations && - value.organizations[refDirectionIndexDes] && - refDirectionIndexDes > -1 - ? value.organizations[refDirectionIndexDes].abbreviation - : '', - dest_loc_name: - value.locations && - value.locations[refDirectionLocIndexDes] && - refDirectionLocIndexDes > -1 - ? value.locations[refDirectionLocIndexDes].name - : '', - ...value, - }), - }; - } else { - return { - displayLabel: (responseValue as { id: number; name: string }) - .name, - value: responseValue.id, - restricted: (responseValue as { restricted?: boolean }) - .restricted, - }; - } - }); - setData(parsedResponse); - if (active) { - if (isUsageYearsResult(response)) { - setIsUsageYear(true); + setData(removeFormObjectValueFromFirstArray(response, removeOptions)); - const preOptions = parsedResponse.filter((item) => { - const year = parseInt(item.displayLabel, 10); - if (year >= actualYear - 5 && year <= actualYear + 5) { - return item; - } - }); - setOptions(preOptions); - } else { - setOptions(parsedResponse); - } + if (active) { + setOptions(response); } setIsFetch(true); } catch (error) { @@ -561,6 +414,7 @@ const FormikAsyncAutocompleteSelect = ({ alreadyIsFetch, fetchedData, isDisabled, + removeOptions, ...otherProps }: AsyncAutocompleteSelectProps) => { const [open, setOpen] = useState(false); @@ -582,36 +436,6 @@ const FormikAsyncAutocompleteSelect = ({ (!isAutocompleteAPI || inputValue.length >= 3 || category !== undefined); const actualYear = new Date().getFullYear(); - function isUsageYearsResult( - result: APIAutocompleteResult - ): result is usageYears.GetUsageYearsResult { - return usageYears.GET_USAGE_YEARS_RESULT.is(result); - } - function isOrganizationsResult( - result: APIAutocompleteResult - ): result is organizations.GetOrganizationsResult { - return organizations.GET_ORGANIZATIONS_RESULT.is(result); - } - function isGlobalClustersResult( - result: APIAutocompleteResult - ): result is globalClusters.GetGlobalClustersResult { - return globalClusters.GET_GLOBAL_CLUSTERS_RESULT.is(result); - } - function isCurrenciesResult( - result: APIAutocompleteResult - ): result is currencies.GetCurrenciesResult { - return currencies.GET_CURRENCIES_RESULT.is(result); - } - function isProjectsResult( - result: APIAutocompleteResult - ): result is projects.GetProjectsAutocompleteResult { - return projects.GET_PROJECTS_AUTOCOMPLETE_RESULT.is(result); - } - function isPlansResult( - result: APIAutocompleteResult - ): result is plans.GetPlansAutocompleteResult { - return plans.GET_PLANS_AUTOCOMPLETE_RESULT.is(result); - } const onBlur = useCallback(() => helpers.setTouched(true), [helpers]); const errorMsg = useMemo( () => @@ -674,7 +498,7 @@ const FormikAsyncAutocompleteSelect = ({ } (async () => { try { - let response: APIAutocompleteResult; + let response: FormObjectValue[]; if (fnPromise && !alreadyIsFetch) { response = await fnPromise({ query: category ? category : debouncedInputValue, @@ -682,84 +506,9 @@ const FormikAsyncAutocompleteSelect = ({ } else { response = optionsData || []; } - const parsedResponse = response.map((responseValue) => { - if (isUsageYearsResult(response)) { - return { - displayLabel: (responseValue as usageYears.UsageYear).year, - value: responseValue.id, - }; - } else if (isOrganizationsResult(response)) { - const org = responseValue as organizations.Organization; - return { - displayLabel: `${org.name} [${org.abbreviation}]`, - value: responseValue.id, - }; - } else if (isGlobalClustersResult(response)) { - return { - displayLabel: (responseValue as globalClusters.GlobalCluster) - .name, - value: responseValue.id, - }; - } else if (isPlansResult(response)) { - return { - displayLabel: (responseValue as plans.Plan).name, - value: responseValue.id, - restricted: (responseValue as plans.Plan).restricted, - }; - } else if (isCurrenciesResult(response)) { - return { - displayLabel: (responseValue as currencies.Currency).code, - value: responseValue.id, - }; - } else if (isProjectsResult(response)) { - return { - displayLabel: `${(responseValue as projects.Project).name} [${ - (responseValue as projects.Project).code - }]`, - value: responseValue.id, - }; - } else if ( - name === 'sourceGoverningEntities' || - name === 'destinationGoverningEntities' - ) { - return { - displayLabel: (responseValue as governingEntities.GoverningEntity) - .governingEntityVersion.name, - value: responseValue.id, - }; - } else { - return { - displayLabel: ( - responseValue as { - id: number; - name: string; - } - ).name, - value: responseValue.id, - restricted: ( - responseValue as { - restricted?: boolean; - } - ).restricted, - }; - } - }); - - setData(parsedResponse); + setData(removeFormObjectValueFromFirstArray(response, removeOptions)); if (active) { - if (isUsageYearsResult(response)) { - setIsUsageYear(true); - - const preOptions = parsedResponse.filter((item) => { - const year = parseInt(item.displayLabel, 10); - if (year >= actualYear - 5 && year <= actualYear + 5) { - return item; - } - }); - setOptions(preOptions); - } else { - setOptions(parsedResponse); - } + setOptions(response); } setIsFetch(true); } catch (error) {