react-app/src/components/property/AddProperty.tsx

Summary

Maintainability
A
0 mins
Test Coverage
import { Box, RadioGroup, Typography } from '@mui/material';
import React, { useContext, useState } from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import dayjs from 'dayjs';
import BuildingIcon from '@/assets/icons/building.svg';
import ParcelIcon from '@/assets/icons/parcel.svg';
import BoxedIconRadio from '../form/BoxedIconRadio';
import usePimsApi from '@/hooks/usePimsApi';
import {
  AssessedValue,
  BuildingInformationForm,
  GeneralInformationForm,
  NetBookValue,
  ParcelInformationForm,
  PropertyType,
} from './PropertyForms';
import { NavigateBackButton } from '../display/DetailViewNavigation';
import { ParcelAdd } from '@/hooks/api/useParcelsApi';
import {
  BuildingAdd,
  BuildingConstructionType,
  BuildingPredominateUse,
} from '@/hooks/api/useBuildingsApi';
import { parseFloatOrNull, parseIntOrNull } from '@/utilities/formatters';
import useDataSubmitter from '@/hooks/useDataSubmitter';
import { LoadingButton } from '@mui/lab';
import { LookupContext } from '@/contexts/lookupContext';
import { Classification } from '@/hooks/api/useLookupApi';
import useHistoryAwareNavigate from '@/hooks/useHistoryAwareNavigate';
import useUserAgencies from '@/hooks/api/useUserAgencies';

const AddProperty = () => {
  //const years = [new Date().getFullYear(), new Date().getFullYear() - 1];
  const [propertyType, setPropertyType] = useState<PropertyType>('Parcel');
  const [showErrorText, setShowErrorText] = useState(false);
  const { goToFromStateOrSetRoute } = useHistoryAwareNavigate();
  const api = usePimsApi();
  const { data: lookupData } = useContext(LookupContext);
  const { submit: submitParcel, submitting: submittingParcel } = useDataSubmitter(
    api.parcels.addParcel,
  );
  const { submit: submitBuilding, submitting: submittingBuilding } = useDataSubmitter(
    api.buildings.addBuilding,
  );
  const { menuItems: agencyOptions } = useUserAgencies();

  const formMethods = useForm({
    defaultValues: {
      Address1: '',
      PIN: '',
      PID: '',
      Postal: '',
      AdministrativeAreaId: null,
      Latitude: '',
      Longitude: '',
      LandArea: '',
      IsSensitive: false,
      ClassificationId: null,
      Description: '',
      Name: '',
      BuildingPredominateUseId: null,
      BuildingConstructionTypeId: null,
      TotalArea: '',
      RentableArea: '',
      BuildingTenancy: '',
      Location: null,
      BuildingTenancyUpdatedOn: dayjs(),
      Fiscals: [],
      Evaluations: [],
      AgencyId: null,
    },
  });

  return (
    <Box
      display={'flex'}
      gap={'1rem'}
      mt={'2rem'}
      mb={'2rem'}
      flexDirection={'column'}
      width={'38rem'}
      marginX={'auto'}
    >
      <Box>
        <NavigateBackButton
          navigateBackTitle={'Back to Property Overview'}
          onBackClick={() => goToFromStateOrSetRoute('/properties')}
        />
      </Box>
      <FormProvider {...formMethods}>
        <Typography mb={'2rem'} variant="h2">
          Add New Property
        </Typography>
        <Typography variant="h5">Property Type</Typography>
        <RadioGroup name="controlled-radio-property-type">
          <BoxedIconRadio
            onClick={() => setPropertyType('Parcel')}
            checked={propertyType === 'Parcel'}
            value={'Parcel'}
            icon={ParcelIcon}
            mainText={'Parcel'}
            subText={`PID (Parcel Identifier) is required to proceed.`}
          />
          <BoxedIconRadio
            onClick={() => setPropertyType('Building')}
            checked={propertyType === 'Building'}
            value={'Building'}
            icon={BuildingIcon}
            mainText={'Building'}
            subText={`Street address with postal code is required to proceed.`}
            boxSx={{ mt: '1rem' }}
          />
        </RadioGroup>
        <GeneralInformationForm
          agencies={agencyOptions}
          defaultLocationValue={undefined}
          propertyType={propertyType}
          adminAreas={
            lookupData?.AdministrativeAreas.map((area) => ({ label: area.Name, value: area.Id })) ??
            []
          }
        />
        {propertyType === 'Parcel' ? (
          <ParcelInformationForm
            classificationOptions={lookupData?.Classifications.map((classif) => ({
              label: classif.Name,
              value: classif.Id,
            }))}
          />
        ) : (
          <BuildingInformationForm
            predominateUseOptions={lookupData?.PredominateUses as BuildingPredominateUse[]}
            classificationOptions={lookupData?.Classifications as Classification[]}
            constructionOptions={lookupData?.ConstructionTypes as BuildingConstructionType[]}
          />
        )}
        <Typography mt={'2rem'} variant="h5">
          Net Book Value
        </Typography>
        <NetBookValue name="Fiscals" maxRows={1} />
        <AssessedValue name="Evaluations" maxRows={1} />
      </FormProvider>
      {showErrorText && (
        <Typography alignSelf={'center'} variant="h5" color={'error'}>
          Please correct issues in the form input.
        </Typography>
      )}
      <LoadingButton
        loading={submittingBuilding || submittingParcel}
        onClick={async () => {
          const isValid = await formMethods.trigger();
          if (isValid && formMethods.getValues()['Location'] != null) {
            setShowErrorText(false);
            if (propertyType === 'Parcel') {
              const formValues = formMethods.getValues();
              const addParcel: ParcelAdd = {
                ...formValues,
                LandArea: parseFloatOrNull(formValues.LandArea),
                PID: parseIntOrNull(formValues.PID.replace(/-/g, '')),
                PIN: parseIntOrNull(formValues.PIN),
                Postal: formValues.Postal.replace(/ /g, '').toUpperCase(),
                PropertyTypeId: 0,
                Fiscals: formValues.Fiscals.map((a) => ({
                  ...a,
                  Value: Number(a?.Value),
                  EffectiveDate: a?.EffectiveDate?.toDate(),
                })),
                Evaluations: formValues.Evaluations.map((a) => ({
                  ...a,
                  Value: Number(a?.Value),
                })),
              };
              addParcel.Evaluations = addParcel.Evaluations.filter((a) => a.Value);
              addParcel.Fiscals = addParcel.Fiscals.filter((a) => a.Value);
              submitParcel(addParcel).then((ret) => {
                if (ret && ret.ok) goToFromStateOrSetRoute('/properties');
              });
            } else {
              const formValues = formMethods.getValues();
              const addBuilding: BuildingAdd = {
                ...formValues,
                PID: parseIntOrNull(formValues.PID.replace(/-/g, '')),
                PIN: parseIntOrNull(formValues.PIN),
                Postal: formValues.Postal.replace(/ /g, '').toUpperCase(),
                RentableArea: parseFloatOrNull(formValues.RentableArea),
                TotalArea: parseFloatOrNull(formValues.TotalArea),
                BuildingFloorCount: 0,
                PropertyTypeId: 1,
                Fiscals: formValues.Fiscals.map((a) => ({
                  ...a,
                  Value: Number(a?.Value),
                  EffectiveDate: a?.EffectiveDate?.toDate(),
                })),
                Evaluations: formValues.Evaluations.map((a) => ({
                  ...a,
                  Value: Number(a.Value),
                })),
                BuildingTenancyUpdatedOn: formValues.BuildingTenancyUpdatedOn.toDate(),
              };
              addBuilding.Evaluations = addBuilding.Evaluations.filter((a) => a.Value);
              addBuilding.Fiscals = addBuilding.Fiscals.filter((a) => a.Value);
              submitBuilding(addBuilding).then((ret) => {
                if (ret && ret.ok) goToFromStateOrSetRoute('/properties');
              });
            }
          } else {
            console.log('Error!');
            setShowErrorText(true);
          }
        }}
        variant="contained"
        color="primary"
        sx={{ padding: '8px', width: '6rem', marginX: 'auto' }}
      >
        Submit
      </LoadingButton>
    </Box>
  );
};

export default AddProperty;