Skip to content
This repository has been archived by the owner on Sep 16, 2024. It is now read-only.

Commit

Permalink
fix: Bb 265 fix soilleaf test data validation (#266)
Browse files Browse the repository at this point in the history
* Remove EmptyFieldDetails

* Update Interfaces

Just testing it out

* Make Cheked radio button optional

* Cleanup and fix for validationSchema

data validation is working at this point

* Define field type to BB Field Interface

* Remove null options from necessary tests values

* Explain empty string hack in comment

* Lint

* Remove dead code

* Change numbers into empty strings

This way input fields are not initialized to a valid input

* HasLeafTest instead of soil for leaf tests validation

* Fix leafTests not being added to exported file

* Removed $ from HasSoilTest and HasLeafTest
  • Loading branch information
GDamaso authored Jul 14, 2024
1 parent 3cf6030 commit f5fd0c3
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 97 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import CustomRadioButton from '@Commons/Input/RadioButton/CustomRadioButton';
import CustomSelect from '@Commons/Input/Select/CustomSelect';
import initialFarmDetails from '@Constants/InitialFarmDetails';
import ComponentText from '@Constants/ComponentText';
import emptyFieldDetails from '@Constants/EmptyFieldDetails';
import { FIELDS_AND_SOIL } from '@Constants/ModuleIDs';
import soilTestOptions from '@Constants/SoilTestOptions';
import InputModuleInterface from '@Interface/InputModuleinterface';
Expand Down Expand Up @@ -48,18 +47,16 @@ const FieldsAndSoilComponent: FC<InputModuleProps> = ({
// Builds field info inside the field form module.
const [, setFieldsInfo] = useState(farmDetails);
const [fieldIndex, setFieldIndex] = useState(farmDetails.Fields.length);
const [initialFieldValues, setInitialFieldValues] = useState(
initialFarmDetails.Fields[fieldIndex],
);
// Only triggered once, it would show list and persists.
const [isSubmitted, setSubmitted] = useState<boolean>(farmDetails.Fields.length > 0);
// Would trigger when new field button is clicked.
const [isFieldAdded, setFieldAdd] = useState<boolean>(false);
// For checked attribute
const [isSoilTestEnabled, setSoilTestEnabled] = useState<boolean | null>(null);
const [isLeafTestEnabled, setLeafTestEnabled] = useState<boolean | null>(null);

const hasSoilTestSchema = (hasSoilTest: string, message: string = 'Required') => Yup.number().when(hasSoilTest, (value, schema) => (value ? schema.notRequired() : schema.required(message)));
const radioOptions = [
{ id: 'true', label: 'Yes', value: true },
{ id: 'false', label: 'No', value: false },
];
const initialValues: FieldDetailInterface = initialFarmDetails.Fields[0];

const validationSchema = Yup.object().shape({
FieldName: Yup.string().max(24).required('Required'),
Expand All @@ -70,14 +67,36 @@ const FieldsAndSoilComponent: FC<InputModuleProps> = ({
Comment: Yup.string().max(200, 'Comments should be lower than 200 chars'),
HasSoilTest: Yup.boolean().nullable().required('A Soil Test must be either `Yes` or `No`'),
HasLeafTest: Yup.boolean().nullable().required('A Leaf Test must be either `Yes` or `No`'),
TestingMethod: hasSoilTestSchema('HasSoilTest', 'Must enter Testing Method'),
sampleDate: hasSoilTestSchema('HasSoilTest', 'Must enter Sample Date'),
valNO3H: hasSoilTestSchema('HasSoilTest'),
ValP: hasSoilTestSchema('HasSoilTest'),
valK: hasSoilTestSchema('HasSoilTest'),
valPH: hasSoilTestSchema('HasSoilTest'),
leafTissueP: hasSoilTestSchema('HasLeafTest'),
leafTissueK: hasSoilTestSchema('HasLeafTest'),
SoilTest: Yup.object().when('HasSoilTest', {
is: true,
then: (object) =>
object
.shape({
TestingMethod: Yup.string().when('HasSoilTest', {
is: true,
then: (schema) => schema.required(),
otherwise: (schema) => schema.notRequired(),
}),
sampleDate: Yup.string().required(),
valNO3H: Yup.number().min(0).max(7).required(),
ValP: Yup.number().min(0).max(7).required(),
valK: Yup.number().min(0).max(7).required(),
valPH: Yup.number().min(0).max(7).required(),
})
.required(),
otherwise: (schema) => schema.notRequired(),
}),
LeafTest: Yup.object().when('HasLeafTest', {
is: true,
then: (schema) =>
schema
.shape({
leafTissueP: Yup.number().min(0).max(7).required(),
leafTissueK: Yup.number().min(0).max(7).required(),
})
.required(),
otherwise: (schema) => schema.notRequired(),
}),
});

/**
Expand All @@ -90,7 +109,8 @@ const FieldsAndSoilComponent: FC<InputModuleProps> = ({
const addFieldData = (values: FieldDetailInterface): void => {
setTimeout(() => {
const farmInfo: FarmDetailsInterface = { ...farmDetails };
farmInfo.Fields.push({

const newField: FieldDetailInterface = {
Id: fieldIndex,
FieldName: values.FieldName,
Area: values.Area,
Expand All @@ -117,17 +137,21 @@ const FieldsAndSoilComponent: FC<InputModuleProps> = ({
plantAgeYears: '',
numberOfPlantsPerAcre: 0,
distanceBtwnPlantsRows: '',
willPlantsBePruned: undefined,
willPlantsBePruned: false,
whereWillPruningsGo: '',
willSawdustBeApplied: undefined,
willSawdustBeApplied: false,
},
],
});
};

farmInfo.Fields.push(newField);

// splice or pop to remove Crops after getting pushed to array
if (farmInfo.Fields[fieldIndex].Crops.length === 1) {
// splice or pop to remove Crops after getting pushed to array
// Crops is not optional so this line is needed
farmInfo.Fields[fieldIndex].Crops.splice(0, 1);
}

setFieldsInfo(farmInfo);
setFieldIndex((prevIndex) => prevIndex + 1);
setSubmitted(true);
Expand All @@ -137,17 +161,9 @@ const FieldsAndSoilComponent: FC<InputModuleProps> = ({

const addNewField = () => {
handleFormState(FIELDS_AND_SOIL, undefined, ACTIVE);
setInitialFieldValues(emptyFieldDetails);
setFieldAdd(true);
setSoilTestEnabled(null);
setLeafTestEnabled(null);
};

const radioOptions = [
{ id: 'true', label: 'Yes', value: true },
{ id: 'false', label: 'No', value: false },
];

return (
<>
{isSubmitted && (
Expand All @@ -166,7 +182,7 @@ const FieldsAndSoilComponent: FC<InputModuleProps> = ({

{(isFieldAdded || !isSubmitted) && (
<Formik
initialValues={initialFieldValues}
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={addFieldData}
validate={(values) => {
Expand Down Expand Up @@ -203,6 +219,7 @@ const FieldsAndSoilComponent: FC<InputModuleProps> = ({
width="70%"
/>
</StyledTextAreaContainer>

<StyledTestContainer>
<HeaderLabel>Add Soil Test</HeaderLabel>
<StyledRadioGroupContainer>
Expand All @@ -213,10 +230,8 @@ const FieldsAndSoilComponent: FC<InputModuleProps> = ({
id={`HasSoilTest${option.id}`}
name="HasSoilTest"
type="radio"
checked={isSoilTestEnabled === option.value}
onChange={() => {
setFieldValue('HasSoilTest', option.value);
setSoilTestEnabled(option.value);
}}
/>
))}
Expand All @@ -234,6 +249,7 @@ const FieldsAndSoilComponent: FC<InputModuleProps> = ({
</p>
</StyledWarningBlock>
)}

{values.HasSoilTest && (
<>
<StyledSelectContainer>
Expand Down Expand Up @@ -262,8 +278,8 @@ const FieldsAndSoilComponent: FC<InputModuleProps> = ({
<InputFieldsGroup>
<CustomField
label="P (ppm), phosphorous"
id="SoilTest.valP"
name="SoilTest.valP"
id="SoilTest.ValP"
name="SoilTest.ValP"
type="number"
/>
<CustomField
Expand All @@ -284,6 +300,7 @@ const FieldsAndSoilComponent: FC<InputModuleProps> = ({
</>
)}
</StyledTestContainer>

<StyledTestContainer>
<HeaderLabel>Add Leaf Test</HeaderLabel>
<StyledRadioGroupContainer>
Expand All @@ -294,10 +311,8 @@ const FieldsAndSoilComponent: FC<InputModuleProps> = ({
id={`HasLeafTest${option.id}`}
name="HasLeafTest"
type="radio"
checked={isLeafTestEnabled === option.value}
onChange={() => {
setFieldValue('HasLeafTest', option.value);
setLeafTestEnabled(option.value);
}}
/>
))}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ interface CustomRadioProps {
id: string;
type: string;
width?: string;
checked: boolean;
checked?: boolean;
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
}

Expand Down
27 changes: 0 additions & 27 deletions frontend/src/Constants/EmptyFieldDetails.ts

This file was deleted.

32 changes: 19 additions & 13 deletions frontend/src/Constants/InitialFarmDetails.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
/**
/*
* @desc This populates the initial values of Formik input fields,
* which must be initialized. It does not like null or undefined
* values which changes components from being controlled
* to uncontrolled.
* to uncontrolled. Number values are being initialized to empty strings
* because of this. It's a small hack to get the behaviour we want.
* @author @GDamaso
*
*/
import FarmDetailsInterface from '@Interface/FarmDetailsInterface';

const initialFarmDetails: FarmDetailsInterface = {
/*
* This has an 'any' type because we need to initialize some numbers to an empty string
* to get the correct behaviour from formik/yup validation. It should be a FarmDetailInterface
* otherwise, which do not take strings instead of numbers... mostly.
*/
const initialFarmDetails: any = {
Year: '',
FarmName: '',
FarmRegion: '',
Expand All @@ -16,23 +22,23 @@ const initialFarmDetails: FarmDetailsInterface = {
{
Id: 0,
FieldName: '',
Area: 0,
Area: '',
Comment: '',
HasSoilTest: null,
HasLeafTest: null,
SoilTest: { TestingMethod: '', sampleDate: '', valNO3H: 0, ValP: 0, valK: 0, valPH: 0 },
LeafTest: { leafTissueP: 0, leafTissueK: 0 },
HasSoilTest: '',
HasLeafTest: '',
SoilTest: { TestingMethod: '', sampleDate: '', valNO3H: '', ValP: '', valK: '', valPH: '' },
LeafTest: { leafTissueP: '', leafTissueK: '' },
Crops: [
{
id: 0,
cropId: '',
yield: 0,
yield: '',
plantAgeYears: '',
numberOfPlantsPerAcre: 0,
numberOfPlantsPerAcre: '',
distanceBtwnPlantsRows: '',
willPlantsBePruned: undefined,
willPlantsBePruned: false,
whereWillPruningsGo: '',
willSawdustBeApplied: undefined,
willSawdustBeApplied: false,
},
],
},
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/Interface/FieldDetailsInterface.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ interface FieldDetailInterface {
Id: number;
FieldName: string;
Area: number;
Comment?: string | null;
HasSoilTest: boolean | null;
HasLeafTest: boolean | null;
Comment?: string | undefined;
HasSoilTest?: boolean;
HasLeafTest?: boolean;
SoilTest: SoilTestInterface;
LeafTest: LeafTestInterface;
Crops: CropsDetailsInterface[];
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/Interface/NmpInterface.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ interface NmpInterface {
HasMixedLiveStock: boolean;
HasHorticulturalCrops: boolean;
HasBerries: boolean;
LeafTests: any;
LeafTests: boolean;
LeafTestingMethod: string;
UserJourney: number;
};
Expand Down
38 changes: 22 additions & 16 deletions frontend/src/Utils/convertToNMP.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import FarmDetailsInterface from '@Interface/FarmDetailsInterface';
import NmpInterface from '@Interface/NmpInterface';
import NmpFieldInterface from '@Interface/NmpFieldInterface';
import { templateFieldNMP } from '@Constants/templateNMP';
import FieldDetailInterface from '@Interface/FieldDetailsInterface';

/**
* @desc Convert the FarmDetailsInterface to the NmpInterface structure.
Expand All @@ -13,22 +14,27 @@ const convertToNMP = (
newDetails: FarmDetailsInterface,
prevDetails: NmpInterface,
): NmpInterface => {
const newFields: NmpFieldInterface[] = newDetails.Fields.map((field) => ({
...templateFieldNMP,
Id: field.Id,
Area: field.Area,
Comment: field.Comment || templateFieldNMP.Comment,
FieldName: field.FieldName,
HasSoilTest: field.HasSoilTest || templateFieldNMP.HasSoilTest,
SoilTest: {
...templateFieldNMP.SoilTest,
valNO3H: field.SoilTest?.valNO3H || templateFieldNMP.SoilTest.valNO3H,
ValP: field.SoilTest?.ValP || templateFieldNMP.SoilTest.ValP,
valK: field.SoilTest?.valK || templateFieldNMP.SoilTest.valK,
valPH: field.SoilTest?.valPH || templateFieldNMP.SoilTest.valPH,
},
LeafTest: field.LeafTest || templateFieldNMP.LeafTest,
}));
const newFields: NmpFieldInterface[] = newDetails.Fields.map((field: FieldDetailInterface) => {
return {
...templateFieldNMP,
Id: field.Id,
Area: field.Area,
Comment: field.Comment || templateFieldNMP.Comment,
FieldName: field.FieldName,
HasSoilTest: field.HasSoilTest || templateFieldNMP.HasSoilTest,
SoilTest: {
...templateFieldNMP.SoilTest,
valNO3H: field.SoilTest?.valNO3H || templateFieldNMP.SoilTest.valNO3H,
ValP: field.SoilTest?.ValP || templateFieldNMP.SoilTest.ValP,
valK: field.SoilTest?.valK || templateFieldNMP.SoilTest.valK,
valPH: field.SoilTest?.valPH || templateFieldNMP.SoilTest.valPH,
},
LeafTest: {
leafTissueP: field.LeafTest?.leafTissueP || templateFieldNMP.LeafTest.leafTissueP,
leafTissueK: field.LeafTest?.leafTissueK || templateFieldNMP.LeafTest.leafTissueK,
},
};
});

return {
...prevDetails,
Expand Down

0 comments on commit f5fd0c3

Please sign in to comment.