Add error validation collection

Collect errors and prevent submission.
Add more line-by-line errors
pull/1/head
Angelo DiNardi 3 years ago
parent 4042226992
commit 12d701b99a
  1. 92
      ui/js/datasheet.jsx
  2. 6
      ui/js/gute-nest-location-row.jsx
  3. 3
      ui/js/gute-nest-row.jsx

@ -121,6 +121,8 @@ const emptyHepNestRow = (number: number): HepNestRowData => (
export const Datasheet = (props: Props) => {
let speciesCounter = 3;
const errors = {};
const [validated, setValidated] = useState(false);
const [savingData, setSavingData] = useState(false);
const [colonies, setColonies] = useState<Array<{
@ -168,6 +170,10 @@ export const Datasheet = (props: Props) => {
setValidated(true);
if (Object.keys(errors).length > 0) {
return;
}
const saveToServer = async() => {
try {
const response = await fetch(`${API_HOST}/data/sheet/save`, {
@ -254,12 +260,45 @@ export const Datasheet = (props: Props) => {
}
return true;
});
if (missingSubcoloniesFromNests.length > 0) {
errors.missingSubcoloniesFromNests = true;
}
const missingSubcoloniesFromLocations = guteNestSubcolonies.filter(item => {
if (guteLocationSubcolonies.findIndex(s => s === item) > -1) {
return false;
}
return true;
});
if (missingSubcoloniesFromLocations.length > 0) {
errors.missingSubcoloniesFromLocations = true;
}
// Do a pile of validation
if (!submitterName) {
errors.submitterName = true;
}
if (!colonyId) {
errors.colonyId = true;
}
if (!date) {
errors.date = true;
}
if (!startTime) {
errors.startTime = true;
}
if (!endTime) {
errors.endTime = true;
}
if (!nestVisibility) {
errors.nestVisibility = true;
}
if (colonySignificantChanges && !colonySignificantChangesNotes) {
errors.colonySignificantChangesNotes = true;
}
if (colonyHumanDisturbance && !colonyHumanDisturbanceNotes) {
errors.colonyHumanDisturbanceNotes = true;
}
return (
<Container>
@ -517,6 +556,14 @@ export const Datasheet = (props: Props) => {
return acc + val.chickCount;
}, 0);
const totalNestsInvalid = parseInt(totalNests) < nestCount;
const totalAdultsInvalid = parseInt(totalAdults) < adultCount;
const totalYoungInvalid = parseInt(totalYoung) < youngCount;
if (totalNestsInvalid || totalAdultsInvalid || totalYoungInvalid) {
errors.hepNestData = true;
}
return (
<React.Fragment key={`species-cell-${species.code}`}>
<Cell>{species.code}</Cell>
@ -524,7 +571,7 @@ export const Datasheet = (props: Props) => {
<Cell>
<Form.Control
type="number"
isInvalid={parseInt(totalNests) < nestCount}
isInvalid={totalNestsInvalid}
value={totalNests}
onChange={e => updateRecord(e.target.value, undefined, undefined, undefined)}
/>
@ -533,7 +580,7 @@ export const Datasheet = (props: Props) => {
<Cell>
<Form.Control
type="number"
isInvalid={parseInt(totalAdults) < adultCount}
isInvalid={totalAdultsInvalid}
value={totalAdults}
onChange={e => updateRecord(undefined, e.target.value, undefined, undefined)}
/>
@ -542,7 +589,7 @@ export const Datasheet = (props: Props) => {
<Cell>
<Form.Control
type="number"
isInvalid={parseInt(totalYoung) < youngCount}
isInvalid={totalYoungInvalid}
value={totalYoung}
onChange={e => updateRecord(undefined, undefined, undefined, e.target.value)}
/>
@ -583,6 +630,7 @@ export const Datasheet = (props: Props) => {
selected={colonySignificantChanges}
setNotes={notes => setColonySignificantChangesNotes(notes)}
setSelection={selection => setColonySignificantChanges(selection)}
invalidNotes={validated && errors.colonySignificantChangesNotes}
>
Has anything in this colony <strong>changed significantly</strong> since your last survey?
</NoteQuestion>
@ -592,6 +640,7 @@ export const Datasheet = (props: Props) => {
selected={colonyHumanDisturbance}
setNotes={notes => setColonyHumanDisturbanceNotes(notes)}
setSelection={selection => setColonyHumanDisturbance(selection)}
invalidNotes={validated && errors.colonyHumanDisturbanceNotes}
>
Have you witnessed any <strong>human disturbance</strong> at this site since your last visit?
</NoteQuestion>
@ -694,18 +743,22 @@ export const Datasheet = (props: Props) => {
<Cell>Stage 4 (count # chicks)</Cell>
<Cell>Comments</Cell>
{preparedGuteNestData.map((item, idx) =>
<GuteNestRow
{preparedGuteNestData.map((item, idx) => {
if ((item.totalAdults || 0) < (item.stage0Adults || 0)) {
errors[`gute-nest-row-${idx}`] = true;
}
return <GuteNestRow
key={`gute-nest-row-${idx}`}
validated={validated}
data={item}
update={data => {
preparedGuteNestData[idx] = data;
setGuteNestData(preparedGuteNestData);
}}
/>,
)}
/>;
})}
</div>
{missingSubcoloniesFromNests.length > 0 && <Alert variant="danger">Subcolony missing! {missingSubcoloniesFromNests}</Alert>}
{missingSubcoloniesFromNests.length > 0 && <Alert variant="danger">Subcolony missing! {missingSubcoloniesFromNests.join(", ")}</Alert>}
<br />
<br />
@ -716,20 +769,29 @@ export const Datasheet = (props: Props) => {
<Cell>Location: provide description for all subcolonies listed above.</Cell>
<Cell>Included on map?</Cell>
{preparedGuteNestLocationData.map((item, idx) =>
<GuteNestLocationRow
{preparedGuteNestLocationData.map((item, idx) => {
if (
(item.subcolony && !item.location) ||
(item.location && !item.subcolony) ||
(item.includedOnMap && (!item.subcolony || !item.location))
) {
errors[`gute-nest-location-row-${idx}`] = true;
}
return <GuteNestLocationRow
key={`gute-nest-location-row-${idx}`}
data={item}
update={data => {
preparedGuteNestLocationData[idx] = data;
setGuteNestLocationData(preparedGuteNestLocationData);
}}
/>,
)}
validated={validated}
/>;
})}
</div>
{missingSubcoloniesFromLocations.length > 0 && <Alert variant="danger">Subcolony missing! {missingSubcoloniesFromLocations}</Alert>}
{missingSubcoloniesFromLocations.length > 0 && <Alert variant="danger">Subcolony missing! {missingSubcoloniesFromLocations.join(", ")}</Alert>}
<Button disabled={savingData} onClick={() => setSavingData(true)}>Save</Button>
{validated && Object.keys(errors).length > 0 && <Alert variant="danger">Errors found. Please check. {Object.keys(errors).join(", ")}</Alert>}
<Button disabled={savingData || (validated && Object.keys(errors).length > 0)} onClick={() => setSavingData(true)}>Save</Button>
</Container>
);
};
@ -741,6 +803,7 @@ const NoteQuestion = (props: {
notes: string,
setSelection: (boolean) => mixed,
setNotes: (string) => mixed,
invalidNotes: boolean,
}) => {
return (
<React.Fragment>
@ -778,6 +841,7 @@ const NoteQuestion = (props: {
</Form.Label>
<Form.Control
type="text"
isInvalid={props.invalidNotes}
disabled={!props.selected}
value={props.notes}
onChange={e => props.setNotes(e.target.value)}

@ -9,10 +9,12 @@ import type { GuteNestLocationRowData } from "./types.js";
export const GuteNestLocationRow = (props: {|
data: GuteNestLocationRowData,
update: (GuteNestLocationRowData) => mixed,
validated: boolean,
|}) => {
const {
update,
data,
validated,
} = props;
const {
@ -31,7 +33,7 @@ export const GuteNestLocationRow = (props: {|
...data,
subcolony: e.target.value,
})}
isInvalid={!subcolony && (location || includedOnMap)}
isInvalid={validated && !subcolony && (location || includedOnMap)}
/>
</Cell>
<Cell>
@ -42,7 +44,7 @@ export const GuteNestLocationRow = (props: {|
...data,
location: e.target.value,
})}
isInvalid={!location && (subcolony || includedOnMap)}
isInvalid={validated && !location && (subcolony || includedOnMap)}
/>
</Cell>
<Cell>

@ -9,10 +9,12 @@ import type { GuteNestRowData } from "./types.js";
export const GuteNestRow = (props: {|
data: GuteNestRowData,
update: (GuteNestRowData) => mixed,
validated: boolean,
|}) => {
const {
update,
data,
validated,
} = props;
const {
@ -60,6 +62,7 @@ export const GuteNestRow = (props: {|
<Form.Control
type="number"
value={totalAdults === null ? "" : totalAdults}
isInvalid={validated && (totalAdults || 0) < (stage0Adults || 0)}
onChange={e => update({
...data,
totalAdults: e.target.value,

Loading…
Cancel
Save