diff --git a/express-api/src/services/parcels/parcelServices.ts b/express-api/src/services/parcels/parcelServices.ts index 2af508549a..655b2d4710 100644 --- a/express-api/src/services/parcels/parcelServices.ts +++ b/express-api/src/services/parcels/parcelServices.ts @@ -13,14 +13,14 @@ const parcelRepo = AppDataSource.getRepository(Parcel); * @throws ErrorWithCode If the parcel already exists or is unable to be added. */ const addParcel = async (parcel: DeepPartial) => { - const inPID = Number(parcel.PID); + const numberPID = Number(parcel.PID); - const matchPID = inPID.toString().search(/^\d{9}$/); - if (parcel.PID != null && matchPID === -1) { + const stringPID = numberPID.toString(); + if (parcel.PID != null && (stringPID.length > 9 || isNaN(numberPID))) { throw new ErrorWithCode('PID must be a number and in the format #########'); } - const existingParcel = parcel.PID != null ? await getParcelByPid(inPID) : undefined; + const existingParcel = parcel.PID != null ? await getParcelByPid(numberPID) : undefined; if (existingParcel) { throw new ErrorWithCode('Parcel already exists.', 409); diff --git a/react-app/src/components/property/PropertyDetail.tsx b/react-app/src/components/property/PropertyDetail.tsx index ae0bac3a74..ace61f0639 100644 --- a/react-app/src/components/property/PropertyDetail.tsx +++ b/react-app/src/components/property/PropertyDetail.tsx @@ -21,6 +21,7 @@ import { } from './PropertyDialog'; import { PropertyType } from './PropertyForms'; import MetresSquared from '@/components/text/MetresSquared'; +import { zeroPadPID } from '@/utilities/formatters'; interface IPropertyDetail { onClose: () => void; @@ -150,7 +151,7 @@ const PropertyDetail = (props: IPropertyDetail) => { } else { const info: any = { Classification: data.Classification, - PID: data.PID, + PID: data.PID ? zeroPadPID(data.PID) : undefined, PIN: data.PIN, PostalCode: data.Postal, AdministrativeArea: data.AdministrativeArea?.Name, diff --git a/react-app/src/components/property/PropertyDialog.tsx b/react-app/src/components/property/PropertyDialog.tsx index b5f8fd057b..ec468135e3 100644 --- a/react-app/src/components/property/PropertyDialog.tsx +++ b/react-app/src/components/property/PropertyDialog.tsx @@ -15,7 +15,7 @@ import { PropertyType, NetBookValue, } from './PropertyForms'; -import { parseFloatOrNull, parseIntOrNull } from '@/utilities/formatters'; +import { parseFloatOrNull, parseIntOrNull, zeroPadPID } from '@/utilities/formatters'; interface IParcelInformationEditDialog { initialValues: Parcel; @@ -59,8 +59,8 @@ export const ParcelInformationEditDialog = (props: IParcelInformationEditDialog) infoFormMethods.reset({ NotOwned: initialValues?.NotOwned, Address1: initialValues?.Address1, + PID: initialValues?.PID ? zeroPadPID(initialValues.PID) : '', PIN: String(initialValues?.PIN ?? ''), - PID: String(initialValues?.PID ?? ''), Postal: initialValues?.Postal, AdministrativeAreaId: initialValues?.AdministrativeAreaId, LandArea: String(initialValues?.LandArea ?? ''), @@ -155,7 +155,7 @@ export const BuildingInformationEditDialog = (props: IBuildingInformationEditDia TotalArea: '', RentableArea: '', BuildingTenancy: '', - BuildingTenancyUpdatedOn: dayjs(), + BuildingTenancyUpdatedOn: null, Location: null, }, }); @@ -164,7 +164,7 @@ export const BuildingInformationEditDialog = (props: IBuildingInformationEditDia infoFormMethods.reset({ Address1: initialValues?.Address1, PIN: String(initialValues?.PIN ?? ''), - PID: String(initialValues?.PID ?? ''), + PID: initialValues?.PID ? zeroPadPID(initialValues.PID) : '', Postal: initialValues?.Postal, AdministrativeAreaId: initialValues?.AdministrativeAreaId, IsSensitive: initialValues?.IsSensitive, @@ -176,7 +176,9 @@ export const BuildingInformationEditDialog = (props: IBuildingInformationEditDia TotalArea: String(initialValues?.TotalArea ?? ''), RentableArea: String(initialValues?.RentableArea ?? ''), BuildingTenancy: initialValues?.BuildingTenancy, - BuildingTenancyUpdatedOn: dayjs(initialValues?.BuildingTenancyUpdatedOn), + BuildingTenancyUpdatedOn: initialValues?.BuildingTenancyUpdatedOn + ? dayjs(initialValues?.BuildingTenancyUpdatedOn) + : null, Location: initialValues?.Location, }); }, [initialValues]); @@ -193,7 +195,8 @@ export const BuildingInformationEditDialog = (props: IBuildingInformationEditDia formValues.PIN = parseIntOrNull(formValues.PIN); formValues.TotalArea = parseFloatOrNull(formValues.TotalArea); formValues.RentableArea = parseFloatOrNull(formValues.RentableArea); - formValues.BuildingTenancyUpdatedOn = formValues.BuildingTenancyUpdatedOn.toDate(); + formValues.BuildingTenancyUpdatedOn = + formValues.BuildingTenancyUpdatedOn?.toDate() ?? null; api.buildings.updateBuildingById(initialValues.Id, formValues).then(() => postSubmit()); } }} diff --git a/react-app/src/components/property/PropertyForms.tsx b/react-app/src/components/property/PropertyForms.tsx index 072202fb2b..0a1acd4872 100644 --- a/react-app/src/components/property/PropertyForms.tsx +++ b/react-app/src/components/property/PropertyForms.tsx @@ -191,9 +191,11 @@ export const GeneralInformationForm = (props: IGeneralInformationForm) => { }} rules={{ validate: (val, formVals) => - (val.length <= 9 && - (val.length > 0 || formVals['PIN'].length > 0 || propertyType === 'Building')) || - 'Must have set either PID or PIN', + (String(val).length <= 9 && + (String(val).length > 0 || + String(formVals['PIN']).length > 0 || + propertyType === 'Building')) || + 'Must have set either PID or PIN not exceeding 9 digits.', }} /> @@ -211,9 +213,11 @@ export const GeneralInformationForm = (props: IGeneralInformationForm) => { }} rules={{ validate: (val, formVals) => - (val.length <= 9 && - (val.length > 0 || formVals['PID'].length > 0 || propertyType === 'Building')) || - 'Must have set either PID or PIN', + (String(val).length <= 9 && + (String(val).length > 0 || + String(formVals['PID']).length > 0 || + propertyType === 'Building')) || + 'Must have set either PID or PIN not exceeding 9 digits.', }} /> @@ -400,15 +404,15 @@ export const BuildingInformationForm = (props: IBuildingInformationForm) => { - val <= formVals.TotalArea || - `Cannot be larger than Total area: ${val} <= ${formVals?.TotalArea}`, - }} required label={'Net usable area'} fullWidth numeric + rules={{ + validate: (val, formVals) => + val <= formVals.TotalArea || + `Cannot be larger than Total Area: ${val} <= ${formVals?.TotalArea}`, + }} InputProps={{ endAdornment: ( diff --git a/react-app/src/components/property/PropertyTable.tsx b/react-app/src/components/property/PropertyTable.tsx index 185f671680..40db2bbdb9 100644 --- a/react-app/src/components/property/PropertyTable.tsx +++ b/react-app/src/components/property/PropertyTable.tsx @@ -130,21 +130,23 @@ const PropertyTable = (props: IPropertyTable) => { ); }, renderCell: (params) => { - const classificationName = classifications?.find((cl) => cl.Id === params.value)?.Name; + //const classificationName = classifications?.find((cl) => cl.Id === params.value)?.Name; return ( ); }, + valueGetter: (_value, row) => + classifications?.find((cl) => cl.Id === row.ClassificationId)?.Name ?? '', }, { field: 'PID', headerName: 'PID', flex: 1, - valueFormatter: (value: number | null) => value ?? 'N/A', + valueGetter: (value: number | null) => (value ? String(value).padStart(9, '0') : 'N/A'), }, { field: 'AgencyId', diff --git a/react-app/src/utilities/formatters.tsx b/react-app/src/utilities/formatters.tsx index 756057db5f..29d12e264c 100644 --- a/react-app/src/utilities/formatters.tsx +++ b/react-app/src/utilities/formatters.tsx @@ -74,10 +74,20 @@ export const formatMoney = (value?: number | ''): string => { return formatter.format(value || 0); }; -export const parseIntOrNull = (int: string) => { +export const parseIntOrNull = (int: string | number) => { + if (typeof int === 'number') { + return int; + } return int.length > 0 ? parseInt(int) : null; }; -export const parseFloatOrNull = (flt: string) => { +export const parseFloatOrNull = (flt: string | number) => { + if (typeof flt === 'number') { + return flt; + } return flt.length > 0 ? parseFloat(flt) : null; }; + +export const zeroPadPID = (pid: number | string): string => { + return String(pid).padStart(9, '0'); +};