From 2c923a17e11d2a2298b478752f11bf83fbb82462 Mon Sep 17 00:00:00 2001 From: Manojava Koushik <111366021+manojava-gk@users.noreply.github.com> Date: Mon, 12 Aug 2024 21:47:55 +0530 Subject: [PATCH] fix(company data): extended error handling (#958) --- CHANGELOG.md | 3 + .../components/CompanyAddressList.tsx | 34 +++-- .../CompanyData/components/DetailsOverlay.tsx | 8 +- .../pages/CompanyData/components/EditForm.tsx | 21 ++- .../CompanyData/components/FormFields.tsx | 4 +- .../components/StatusInformation.tsx | 137 +++++++++++------- .../companyData/companyDataApiSlice.tsx | 19 ++- src/features/companyData/slice.ts | 87 ++++++----- src/utils/dataMapper.ts | 17 +++ 9 files changed, 217 insertions(+), 113 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8998f543f..c6bb6e0a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,9 @@ ### Feature - Use scroll to top button from shared components +- Company data + - Integrate /ready api to trigger once the new record is created + - Show sharing state error details in the company overlay details page - Subscription Overlay - implement loading state for provider subscription detail overlay - Technical User Management diff --git a/src/components/pages/CompanyData/components/CompanyAddressList.tsx b/src/components/pages/CompanyData/components/CompanyAddressList.tsx index 2ac52d56d..a2e4ec14f 100644 --- a/src/components/pages/CompanyData/components/CompanyAddressList.tsx +++ b/src/components/pages/CompanyData/components/CompanyAddressList.tsx @@ -39,8 +39,10 @@ import DetailsOverlay from './DetailsOverlay' import { setSelectedCompanyData, setSelectedCompanyStatus, + setSharingStateInfo, } from 'features/companyData/slice' import LoadingProgress from 'components/shared/basic/LoadingProgress' +import { statusColorMap } from 'utils/dataMapper' export const CompanyAddressList = ({ handleButtonClick, @@ -75,7 +77,9 @@ export const CompanyAddressList = ({ ?.filter( (state) => state.sharingStateType === SharingStateStatusType.Pending || - state.sharingStateType === SharingStateStatusType.Initial + state.sharingStateType === SharingStateStatusType.Initial || + state.sharingStateType === SharingStateStatusType.Ready || + state.sharingStateType === SharingStateStatusType.Error ) .map((state) => state.externalId) @@ -122,10 +126,16 @@ export const CompanyAddressList = ({ .sharingStateType const onRowClick = (params: GridCellParams) => { + const sharingStateInfo = sharingStates + ?.filter( + (state) => state.sharingStateType === SharingStateStatusType.Error + ) + .filter((state) => state.externalId === params.row.externalId) const status = getStatus(params.row.externalId) setDetails(true) dispatch(setSelectedCompanyStatus(status)) dispatch(setSelectedCompanyData(params.row)) + if (sharingStateInfo) dispatch(setSharingStateInfo(sharingStateInfo[0])) } const renderIcon = (status: string | undefined) => { @@ -133,7 +143,8 @@ export const CompanyAddressList = ({ return } else if ( status === SharingStateStatusType.Pending || - status === SharingStateStatusType.Initial + status === SharingStateStatusType.Initial || + status === SharingStateStatusType.Ready ) { return } else { @@ -141,19 +152,6 @@ export const CompanyAddressList = ({ } } - const getStatusColor = (status: string | undefined) => { - if (status === SharingStateStatusType.Success) { - return 'success' - } else if ( - status === SharingStateStatusType.Pending || - status === SharingStateStatusType.Initial - ) { - return 'warning' - } else { - return 'error' - } - } - const errorObj = { status: 0, } @@ -232,7 +230,11 @@ export const CompanyAddressList = ({ > @@ -64,7 +68,7 @@ export default function DetailsOverlay({ onCloseWithIcon={handleClose} /> - + (false) const [isValid, setIsValid] = useState(false) const [updateData] = useUpdateCompanySiteAndAddressMutation() + const [updateReadyState] = useUpdateCompanyStatusToReadyMutation() const companyData = useSelector(companyDataSelector) const [success, setSuccess] = useState(false) const [error, setError] = useState(false) @@ -79,6 +81,7 @@ export default function EditForm({ }) const [input, setInput] = useState(companyDataInitialData) const inputParams = cloneDeep(newForm ? companyDataInitialData : companyData) + if (companyInfo) { inputParams.externalId = `${companyInfo?.bpn}_${new Date().toISOString()}` inputParams.legalEntity.legalEntityBpn = companyInfo?.bpn @@ -120,9 +123,11 @@ export default function EditForm({ } } - const handleCreation = async () => { + const updateStateToReady = async (response: CompanyDataType[]) => { try { - await updateData([input]) + await updateReadyState({ + externalIds: [response[0].externalId], + }) .unwrap() .then(() => { setSuccess(true) @@ -133,6 +138,18 @@ export default function EditForm({ setLoading(false) } + const handleCreation = async () => { + try { + await updateData([input]) + .unwrap() + .then((response) => { + updateStateToReady(response) + }) + } catch (e) { + setError(true) + } + } + const getTitle = () => { if (newForm) { return isAddress diff --git a/src/components/pages/CompanyData/components/FormFields.tsx b/src/components/pages/CompanyData/components/FormFields.tsx index b0d0691dc..0a713fabf 100644 --- a/src/components/pages/CompanyData/components/FormFields.tsx +++ b/src/components/pages/CompanyData/components/FormFields.tsx @@ -290,9 +290,7 @@ export const FormFields = ({ current.street && current.city && current.postalCode && - current.countryCode && - current.identifierNumber && - current.countryIdentifier + current.countryCode onValid( formValid ? { diff --git a/src/components/pages/CompanyData/components/StatusInformation.tsx b/src/components/pages/CompanyData/components/StatusInformation.tsx index 796754090..eac0dfa80 100644 --- a/src/components/pages/CompanyData/components/StatusInformation.tsx +++ b/src/components/pages/CompanyData/components/StatusInformation.tsx @@ -25,9 +25,17 @@ import { useSelector } from 'react-redux' import HourglassBottomIcon from '@mui/icons-material/HourglassBottom' import WarningAmberIcon from '@mui/icons-material/WarningAmber' import CheckCircleIcon from '@mui/icons-material/CheckCircle' -import { SharingStateStatusType } from 'features/companyData/companyDataApiSlice' +import type { + SharingStateStatusType, + SharingStateType, +} from 'features/companyData/companyDataApiSlice' +import { statusColorMap } from 'utils/dataMapper' -export default function StatusInformation() { +export default function StatusInformation({ + error, +}: { + readonly error?: SharingStateType +}) { const { t } = useTranslation() const status = useSelector(statusSelector) @@ -39,61 +47,92 @@ export default function StatusInformation() { Error: , } - const getStatusColor = (status: string | undefined) => { - if (status === SharingStateStatusType.Success) { - return 'success' - } else if ( - status === SharingStateStatusType.Pending || - status === SharingStateStatusType.Initial - ) { - return 'warning' - } else { - return 'error' - } - } - return ( - - - {t('content.companyData.statusInfo.title')} - + <> - + > + {t('content.companyData.statusInfo.title')} + + + + - + {error && ( + + + + + {error.sharingErrorMessage} + + + + )} + ) } diff --git a/src/features/companyData/companyDataApiSlice.tsx b/src/features/companyData/companyDataApiSlice.tsx index 742c9fe07..6dfe4cc7a 100644 --- a/src/features/companyData/companyDataApiSlice.tsx +++ b/src/features/companyData/companyDataApiSlice.tsx @@ -165,7 +165,7 @@ export interface CompanyDataType { deliveryServiceType: string | undefined | null deliveryServiceQualifier: string | undefined | null deliveryServiceNumber: string | undefined | null - } + } | null confidenceCriteria: { sharedByOwner: true checkedByExternalDataSource: true @@ -211,6 +211,10 @@ export enum SharingStateStatusType { Initial = 'Initial', } +export interface ReadyStateRequestBody { + externalIds: string[] +} + export const apiSlice = createApi({ reducerPath: 'rtk/companyData', baseQuery: fetchBaseQuery(apiBpdmGateQuery()), @@ -241,7 +245,7 @@ export const apiSlice = createApi({ }), }), updateCompanySiteAndAddress: builder.mutation< - CompanyDataResponse, + CompanyDataType[], CompanyDataType[] >({ query: (data: CompanyDataType[]) => ({ @@ -250,6 +254,16 @@ export const apiSlice = createApi({ body: data, }), }), + updateCompanyStatusToReady: builder.mutation< + CompanyDataType[], + ReadyStateRequestBody + >({ + query: (data) => ({ + url: '/sharing-state/ready', + method: 'POST', + body: data, + }), + }), }), }) @@ -258,4 +272,5 @@ export const { useFetchInputCompanyBusinessPartnersMutation, useFetchOutputCompanyBusinessPartnersMutation, useUpdateCompanySiteAndAddressMutation, + useUpdateCompanyStatusToReadyMutation, } = apiSlice diff --git a/src/features/companyData/slice.ts b/src/features/companyData/slice.ts index c8db36fad..6e1d507a2 100644 --- a/src/features/companyData/slice.ts +++ b/src/features/companyData/slice.ts @@ -20,13 +20,17 @@ import { createSlice } from '@reduxjs/toolkit' import type { RootState } from 'features/store' -import { type CompanyDataType } from './companyDataApiSlice' +import { + type SharingStateType, + type CompanyDataType, +} from './companyDataApiSlice' const name = 'companies/companyData' export interface CompanyDataState { row: CompanyDataType status: string + sharingStateInfo: SharingStateType } export const companyDataInitialData: CompanyDataType = { @@ -47,12 +51,12 @@ export const companyDataInitialData: CompanyDataType = { }, ], roles: ['SUPPLIER'], - isOwnCompanyData: false, + isOwnCompanyData: true, legalEntity: { legalEntityBpn: '', legalName: '', shortName: '', - legalForm: '', + legalForm: null, confidenceCriteria: { sharedByOwner: false, checkedByExternalDataSource: false, @@ -70,7 +74,7 @@ export const companyDataInitialData: CompanyDataType = { ], }, site: { - siteBpn: '', + siteBpn: null, name: '', confidenceCriteria: { sharedByOwner: false, @@ -89,8 +93,8 @@ export const companyDataInitialData: CompanyDataType = { ], }, address: { - addressBpn: '', - name: '', + addressBpn: null, + name: null, addressType: '', physicalPostalAddress: { geographicCoordinates: { @@ -99,43 +103,30 @@ export const companyDataInitialData: CompanyDataType = { altitude: 0, }, country: '', - administrativeAreaLevel1: '', - administrativeAreaLevel2: '', - administrativeAreaLevel3: '', + administrativeAreaLevel1: null, + administrativeAreaLevel2: null, + administrativeAreaLevel3: null, postalCode: '', city: '', - district: '', + district: null, street: { - namePrefix: '', - additionalNamePrefix: '', + namePrefix: null, + additionalNamePrefix: null, name: '', - nameSuffix: '', - additionalNameSuffix: '', - houseNumber: '', - houseNumberSupplement: '', - milestone: '', - direction: '', + nameSuffix: null, + additionalNameSuffix: null, + houseNumber: null, + houseNumberSupplement: null, + milestone: null, + direction: null, }, - companyPostalCode: '', - industrialZone: '', - building: '', - floor: '', - door: '', - }, - alternativePostalAddress: { - geographicCoordinates: { - longitude: 0, - latitude: 0, - altitude: 0, - }, - country: null, - administrativeAreaLevel1: null, - postalCode: null, - city: null, - deliveryServiceType: null, - deliveryServiceQualifier: null, - deliveryServiceNumber: null, + companyPostalCode: null, + industrialZone: null, + building: null, + floor: null, + door: null, }, + alternativePostalAddress: null, confidenceCriteria: { sharedByOwner: true, checkedByExternalDataSource: true, @@ -159,6 +150,14 @@ export const companyDataInitialData: CompanyDataType = { export const initialState: CompanyDataState = { status: '', row: companyDataInitialData, + sharingStateInfo: { + externalId: '', + sharingStateType: '', + sharingErrorCode: '', + sharingErrorMessage: '', + sharingProcessStarted: '', + taskId: '', + }, } const companyDataSlice = createSlice({ @@ -173,6 +172,10 @@ const companyDataSlice = createSlice({ ...state, status: actions.payload, }), + setSharingStateInfo: (state, actions) => ({ + ...state, + sharingStateInfo: actions.payload, + }), }, }) @@ -182,7 +185,13 @@ export const companyDataSelector = (state: RootState): CompanyDataType => export const statusSelector = (state: RootState): string => state.companyData.status -export const { setSelectedCompanyData, setSelectedCompanyStatus } = - companyDataSlice.actions +export const sharingStateInfoSelector = (state: RootState): SharingStateType => + state.companyData.sharingStateInfo + +export const { + setSelectedCompanyData, + setSelectedCompanyStatus, + setSharingStateInfo, +} = companyDataSlice.actions export default companyDataSlice diff --git a/src/utils/dataMapper.ts b/src/utils/dataMapper.ts index ecf658891..75c9b5806 100644 --- a/src/utils/dataMapper.ts +++ b/src/utils/dataMapper.ts @@ -24,6 +24,23 @@ import type { RegistrationRequestDataGrid, } from 'features/admin/registration/types' import type { BusinessPartner } from 'features/newPartnerNetwork/types' +import { SharingStateStatusType } from 'features/companyData/companyDataApiSlice' + +type StatusColorType = + | 'success' + | 'warning' + | 'info' + | 'primary' + | 'error' + | undefined + +export const statusColorMap: Record = { + [SharingStateStatusType.Success]: 'success', + [SharingStateStatusType.Initial]: 'warning', + [SharingStateStatusType.Pending]: 'info', + [SharingStateStatusType.Ready]: 'primary', + [SharingStateStatusType.Error]: 'error', +} // Temporary solution for mapping api response to DataGrid component type const mapBusinessPartnerToDataGrid = (