Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/449 step 2 validation fe #674

Merged
merged 39 commits into from
Nov 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
fba4018
feat: created new component to deal with agency information
mgaseta Nov 2, 2023
09463f5
feat: separated commom texts to use on the component
mgaseta Nov 2, 2023
b492c02
feat: adjusting texts
mgaseta Nov 2, 2023
43d6fef
feat: changng type of agency options
mgaseta Nov 6, 2023
f0ef395
Merge branch 'main' into feat/588-modularize-client-selection-and-loc…
mgaseta Nov 6, 2023
fde2f29
fix: fixing form review component
mgaseta Nov 6, 2023
a9af20e
Merge branch 'feat/588-modularize-client-selection-and-location-code-…
mgaseta Nov 6, 2023
889d6c0
Merge branch 'main' into feat/588-modularize-client-selection-and-loc…
mgaseta Nov 7, 2023
bead2c0
fix: adjusting declaration of states
mgaseta Nov 7, 2023
c697669
feat: adjusted types and replaced agency fields
mgaseta Nov 8, 2023
3542bc8
fix: adjusting onblur event
mgaseta Nov 8, 2023
618e1b8
feat: changing useEffect of ownership step
mgaseta Nov 8, 2023
4ffdf39
Merge branch 'main' into feat/449-step-2-validation-fe
mgaseta Nov 10, 2023
c3879e0
Merge branch 'main' into feat/449-step-2-validation-fe
mgaseta Nov 13, 2023
91a4f65
feat: validation for the portion field
mgaseta Nov 14, 2023
f48cb36
feat: adding new handling functions and other minor fixes
mgaseta Nov 15, 2023
668ee0a
Merge branch 'main' into feat/449-step-2-validation-fe
mgaseta Nov 15, 2023
d6c44c2
Merge branch 'main' into feat/449-step-2-validation-fe
mgaseta Nov 16, 2023
fbfc855
fix: small fixes
mgaseta Nov 16, 2023
aff660d
feat: removing add button from inside accordion
mgaseta Nov 16, 2023
62d70cc
fix: fixing applicant fields component
mgaseta Nov 21, 2023
72159f6
fix: minor adjustments
mgaseta Nov 21, 2023
f132bea
feat: update progress bar for ownership step
mgaseta Nov 21, 2023
04b03f1
Merge branch 'main' into feat/449-step-2-validation-fe
mgaseta Nov 21, 2023
1a006ab
fix: adjusting multioptobj fields validation
mgaseta Nov 21, 2023
8712ea5
feat: adjusting style of applicant field
mgaseta Nov 21, 2023
de9faba
feat: adjusting ownership style
mgaseta Nov 22, 2023
dd8248b
fix: fixed location input when creating a new owner
mgaseta Nov 22, 2023
550094a
fix: removing unused functions
mgaseta Nov 22, 2023
0ca1852
Merge branch 'main' into feat/449-step-2-validation-fe
mgaseta Nov 22, 2023
2faff68
Merge branch 'feat/449-step-2-validation-fe' of github.com:bcgov/nr-s…
mgaseta Nov 22, 2023
4ecedfb
fix: fixing form review
mgaseta Nov 22, 2023
9e55cea
fix: removing unused entry of the mock server
mgaseta Nov 22, 2023
5c3e1a3
fix: fixing options size
mgaseta Nov 22, 2023
9fd9c9b
fix: removing onclick function
mgaseta Nov 24, 2023
1e8a921
fix: fixing style for small screens
mgaseta Nov 24, 2023
94b732f
Merge branch 'main' into feat/449-step-2-validation-fe
mgaseta Nov 24, 2023
9fd2061
fix: adjusting class name on scss
mgaseta Nov 27, 2023
b96c524
Merge branch 'main' into feat/449-step-2-validation-fe
mgaseta Nov 27, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ interface ApplicantAgencyFieldsProps {
defaultAgency: string;
defaultCode: string;
setAllValues: Function;
showDefaultCheckbox?: boolean;
inputsColSize?: number;
readOnly?: boolean;
}

Expand Down
138 changes: 93 additions & 45 deletions frontend/src/components/ApplicantAgencyFields/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React, { useEffect, useState } from 'react';
import {
Row, Column, TextInput, Checkbox, ComboBox, InlineLoading
} from '@carbon/react';
Expand All @@ -9,6 +9,7 @@ import { getForestClientLocation } from '../../api-service/forestClientsAPI';

import ComboBoxEvent from '../../types/ComboBoxEvent';
import MultiOptionsObj from '../../types/MultiOptionsObject';
import { FormInputType } from '../../types/FormInputType';
import { LOCATION_CODE_LIMIT } from '../../shared-constants/shared-constants';
import { formatLocationCode } from '../SeedlotRegistrationSteps/CollectionStep/utils';
import { FilterObj, filterInput } from '../../utils/filterUtils';
Expand All @@ -20,29 +21,36 @@ import supportTexts from './constants';
import './styles.scss';

const ApplicantAgencyFields = ({
useDefault, agency, locationCode, fieldsProps, agencyOptions,
defaultAgency, defaultCode, setAllValues, readOnly
useDefault, agency, locationCode, fieldsProps, agencyOptions, defaultAgency,
defaultCode, setAllValues, showDefaultCheckbox = true, inputsColSize = 6, readOnly
}: ApplicantAgencyFieldsProps) => {
const agencyClone = structuredClone(agency);
const locationCodeClone = structuredClone(locationCode);
const useDefaultClone = structuredClone(useDefault);

const [forestClientNumber, setForestClientNumber] = useState<string>(
agencyClone.value ? getForestClientNumber(agencyClone.value) : ''
const [agencyClone, setAgencyClone] = useState<FormInputType & {value: string}>(agency);
const [locationCodeClone, setLocationCodeClone] = useState<FormInputType & {value: string}>(
locationCode
);
const [useDefaultClone, setUseDefaultClone] = useState<FormInputType & {value: boolean}>(
useDefault
);

const [shouldUpdateValues, setShouldUpdateValues] = useState<boolean>(false);

const [forestClientNumber, setForestClientNumber] = useState<string>('');
const [invalidLocationMessage, setInvalidLocationMessage] = useState<string>(
locationCodeClone.isInvalid && agencyClone.value
? supportTexts.locationCode.invalidLocationForSelectedAgency
: supportTexts.locationCode.invalidText
);
const [locationCodeHelperText, setLocationCodeHelperText] = useState<string>(
supportTexts.locationCode.helperTextEnabled
supportTexts.locationCode.helperTextDisabled
);

const updateAfterLocValidation = (isInvalid: boolean) => {
locationCodeClone.isInvalid = isInvalid;
setLocationCodeClone({
...locationCodeClone,
isInvalid
});
setLocationCodeHelperText(supportTexts.locationCode.helperTextEnabled);
setAllValues(agencyClone, locationCodeClone, useDefaultClone);
setShouldUpdateValues(true);
};

const validateLocationCodeMutation = useMutation({
Expand All @@ -64,11 +72,22 @@ const ApplicantAgencyFields = ({
: supportTexts.locationCode.helperTextDisabled
);

agencyClone.value = checked ? defaultAgency : '';
locationCodeClone.value = checked ? defaultCode : '';
useDefaultClone.value = checked;

setAllValues(agencyClone, locationCodeClone, useDefaultClone);
setAgencyClone({
...agencyClone,
value: checked ? defaultAgency : '',
isInvalid: false
});
setLocationCodeClone({
...locationCodeClone,
value: checked ? defaultCode : '',
isInvalid: false
});
setUseDefaultClone({
...useDefaultClone,
value: checked
});

setShouldUpdateValues(true);
};

const handleAgencyInput = (value: MultiOptionsObj) => {
Expand All @@ -78,50 +97,78 @@ const ApplicantAgencyFields = ({
? supportTexts.locationCode.helperTextEnabled
: supportTexts.locationCode.helperTextDisabled
);
agencyClone.value = value ? value.label : '';
locationCodeClone.value = value ? locationCodeClone.value : '';
setAllValues(agencyClone, locationCodeClone, useDefaultClone);
setAgencyClone({
...agencyClone,
value: value ? value.label : ''
});
setLocationCodeClone({
...locationCodeClone,
value: value ? locationCodeClone.value : ''
});
setShouldUpdateValues(true);
};

const handleLocationCodeChange = (value: string) => {
locationCodeClone.value = value.slice(0, LOCATION_CODE_LIMIT);
const locationCodeUpdated = { ...locationCodeClone };
locationCodeUpdated.value = value.slice(0, LOCATION_CODE_LIMIT);
const isInRange = validator.isInt(value, { min: 0, max: 99 });
if (!isInRange) {
setInvalidLocationMessage(supportTexts.locationCode.invalidText);
locationCodeClone.isInvalid = true;
locationCodeUpdated.isInvalid = true;
}
setAllValues(agencyClone, locationCodeClone, useDefaultClone);
setLocationCodeClone(locationCodeUpdated);
};

const handleLocationCodeBlur = (value: string) => {
const formattedCode = value.length ? formatLocationCode(value) : '';
setLocationCodeClone({
...locationCodeClone,
value: formattedCode
});
setShouldUpdateValues(true);
if (formattedCode === '') return;
locationCodeClone.value = formattedCode;
setAllValues(agencyClone, locationCodeClone, useDefaultClone);
if (forestClientNumber) {
validateLocationCodeMutation.mutate([forestClientNumber, formattedCode]);
setLocationCodeHelperText('');
validateLocationCodeMutation.mutate([forestClientNumber, formattedCode]);
}
};

useEffect(() => {
if (shouldUpdateValues) {
setAllValues(agencyClone, locationCodeClone, useDefaultClone);
} else {
setAgencyClone(agency);
setLocationCodeClone(locationCode);
setUseDefaultClone(useDefault);
setForestClientNumber(agency.value ? getForestClientNumber(agencyClone.value) : '');
}
setShouldUpdateValues(false);
}, [useDefault, agency, locationCode, shouldUpdateValues]);

return (
<div className="agency-information-section">
{
showDefaultCheckbox
? (
<Row className="agency-information-row">
<Column sm={4} md={8} lg={16} xlg={16}>
<Checkbox
id={useDefaultClone.id}
name={fieldsProps.useDefaultCheckbox.name}
labelText={fieldsProps.useDefaultCheckbox.labelText}
readOnly={readOnly}
checked={useDefaultClone.value}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
handleDefaultCheckBox(e.target.checked);
}}
/>
</Column>
</Row>
)
: null
}
<Row className="agency-information-row">
<Column sm={4} md={8} lg={16} xlg={16}>
<Checkbox
id={useDefaultClone.id}
name={fieldsProps.useDefaultCheckbox.name}
labelText={fieldsProps.useDefaultCheckbox.labelText}
readOnly={readOnly}
checked={useDefaultClone.value}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
handleDefaultCheckBox(e.target.checked);
}}
/>
</Column>
</Row>
<Row className="agency-information-row">
<Column sm={4} md={4} lg={8} xlg={6}>
<Column sm={4} md={4} lg={inputsColSize} xlg={inputsColSize}>
<ComboBox
id={agencyClone.id}
name={fieldsProps.agencyInput.name}
Expand All @@ -130,7 +177,7 @@ const ApplicantAgencyFields = ({
helperText={supportTexts.agency.helperText}
invalidText={fieldsProps.agencyInput.invalidText}
items={agencyOptions}
readOnly={useDefaultClone.value || readOnly}
readOnly={(showDefaultCheckbox ? useDefaultClone.value : false) || readOnly}
selectedItem={agencyClone.value}
onChange={(e: ComboBoxEvent) => handleAgencyInput(e.selectedItem)}
invalid={agencyClone.isInvalid}
Expand All @@ -140,7 +187,7 @@ const ApplicantAgencyFields = ({
size="md"
/>
</Column>
<Column sm={4} md={4} lg={8} xlg={6}>
<Column sm={4} md={4} lg={inputsColSize} xlg={inputsColSize}>
<TextInput
id={locationCodeClone.id}
className="location-code-input"
Expand All @@ -152,14 +199,15 @@ const ApplicantAgencyFields = ({
helperText={locationCodeHelperText}
invalid={locationCodeClone.isInvalid}
invalidText={invalidLocationMessage}
readOnly={useDefaultClone.value || readOnly}
readOnly={(showDefaultCheckbox ? useDefaultClone.value : false) || readOnly}
disabled={!forestClientNumber}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
handleLocationCodeChange(e.target.value);
}}
onWheel={(e: React.ChangeEvent<HTMLInputElement>) => e.target.blur()}
onBlur={(e: React.ChangeEvent<HTMLInputElement>) => {
if (!e.target.readOnly) {
if (!e.target.readOnly
&& locationCode.value !== e.target.value) {
handleLocationCodeBlur(e.target.value);
}
}}
Expand Down
40 changes: 40 additions & 0 deletions frontend/src/components/ApplicantAgencyFields/styles.scss
Original file line number Diff line number Diff line change
@@ -1,11 +1,51 @@
@use '@bcgov-nr/nr-theme/design-tokens/variables.scss' as vars;
@use '@carbon/type';

.agency-information-section {
.agency-information-row {
margin-bottom: 1.5rem;
}

.#{vars.$bcgov-prefix}--combo-box--readonly {
border-block-end: 0;

input[role=combobox] {
background-color: transparent;
padding-inline-end: 0;
--#{vars.$bcgov-prefix}-layout-density-padding-inline-local: 0;
border-block-end: 0;
}

button,
& + .#{vars.$bcgov-prefix}--form__helper-text {
display: none;
}
}

.#{vars.$bcgov-prefix}--combo-box {
li,
.#{vars.$bcgov-prefix}--list-box__menu-item__option {
white-space: normal;
block-size: auto;
}
}


.#{vars.$bcgov-prefix}--text-input-wrapper--readonly {
input[type=number] {
background-color: transparent;
--bx-layout-density-padding-inline-local: 0;
border-block-end: 0;
}

.#{vars.$bcgov-prefix}--form__helper-text {
display: none;
}
}

.location-code-input {
padding-top: 0.1rem;

input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
Expand Down
22 changes: 2 additions & 20 deletions frontend/src/components/FormReview/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import InterimStorage from '../SeedlotRegistrationSteps/InterimStep';
import CollectionStep from '../SeedlotRegistrationSteps/CollectionStep';
import ExtractionAndStorage from '../SeedlotRegistrationSteps/ExtractionAndStorageStep';
import { OrchardForm } from '../SeedlotRegistrationSteps/OrchardStep/definitions';
import { initCollectionState } from '../../views/Seedlot/SeedlotRegistrationForm/utils';
import { initCollectionState, initOwnershipState } from '../../views/Seedlot/SeedlotRegistrationForm/utils';

const mockFormData = [
{
Expand Down Expand Up @@ -88,25 +88,7 @@ const interimStorageMock = {
facilityType: 'VRM'
};

const ownershipMock = {
id: 0,
useDefaultAgencyInfo: true,
ownerAgency: '0032 - Strong Seeds Orchard - SSO',
ownerCode: '32',
ownerPortion: '100',
reservedPerc: '100',
surplusPerc: '0',
fundingSource: {
code: 'LFP',
description: 'Licensee Funded Program',
label: 'LFP - Licensee Funded Program'
},
methodOfPayment: {
code: 'ITC',
description: 'Invoice to client address',
label: 'ITC - Invoice to client address'
}
};
const ownershipMock = initOwnershipState(defaultAgency, defaultCode);

const collectionMock = initCollectionState(defaultAgency, defaultCode);

Expand Down
Loading