diff --git a/WNPRC_EHR/src/client/feeding/base/FeedingFormContainer.tsx b/WNPRC_EHR/src/client/feeding/base/FeedingFormContainer.tsx index 36e18eab5..fdb3198d6 100644 --- a/WNPRC_EHR/src/client/feeding/base/FeedingFormContainer.tsx +++ b/WNPRC_EHR/src/client/feeding/base/FeedingFormContainer.tsx @@ -25,7 +25,7 @@ import SubmitModal from "../../components/SubmitModal"; import { getAnimalIdsFromLocation, groupCommands, - lookupAnimalInfo, + lookupAnimalStatuses, saveRowsDirect, setupJsonData, sleep, @@ -142,7 +142,7 @@ const FeedingFormContainer: React.FunctionComponent = (props) => { const validate = () => { return new Promise((resolve, reject) => { - let promises = []; + let idsToLookUp = []; try { for (let record of formData) @@ -161,34 +161,32 @@ const FeedingFormContainer: React.FunctionComponent = (props) => { } else { - promises.push(lookupAnimalInfo(record["Id"]["value"])); + idsToLookUp.push(record["Id"]["value"]); } } } catch(err) { console.log(JSON.stringify(err)); } - Promise.all(promises).then((results) => { - - try - { - for (let result of results) - { - if (result["calculated_status"] == "Dead") - { - setErrorTextExternal("Cannot update dead animal record: " + result["Id"]); - resolve(false); - } - } - } catch (err) { - console.log(JSON.stringify(err)); + lookupAnimalStatuses(idsToLookUp).then((statuses) => { + const missing = idsToLookUp.filter( + (id) => !statuses.has(String(id).toLowerCase()) + ); + if (missing.length > 0) { + setErrorTextExternal("One or more animals not found. Unable to submit records.") + resolve(false); + return; + } + const dead = idsToLookUp.find( + (id) => statuses.get(String(id).toLowerCase()) == "Dead" + ); + if (dead !== undefined) { + setErrorTextExternal("Cannot update dead animal record: " + dead); + resolve(false); + return; } resolve(true); }).catch((d)=>{ - if (d.rows.length == 0){ - setErrorTextExternal("One or more animals not found. Unable to submit records.") - } else { - setErrorTextExternal("Unknown error. Unable to submit records.") - } + setErrorTextExternal("Unknown error. Unable to submit records.") console.log(d); resolve(false); }); diff --git a/WNPRC_EHR/src/client/query/helpers.ts b/WNPRC_EHR/src/client/query/helpers.ts index 9afb98bdc..e3387fd70 100644 --- a/WNPRC_EHR/src/client/query/helpers.ts +++ b/WNPRC_EHR/src/client/query/helpers.ts @@ -180,6 +180,30 @@ export const lookupAnimalInfo = (id:string) => { }); }; +export const lookupAnimalStatuses = ( + ids: Array +): Promise> => { + if (ids.length === 0) { + return Promise.resolve(new Map()); + } + return labkeyActionSelectWithPromise({ + schemaName: "study", + queryName: "demographics", + columns: "Id,calculated_status", + filterArray: [Filter.create("Id", ids.join(";"), Filter.Types.IN)], + }).then( + (data) => + // Keyed lower-case: the forms lower-case the ids they submit. An id with no row is + // absent from the map, which is how callers detect an animal that does not exist. + new Map( + (data["rows"] || []).map((row) => [ + String(row["Id"]).toLowerCase(), + row["calculated_status"], + ]) + ) + ); +}; + export const insertTaskCommand = (taskid, title) => { let taskObject = { diff --git a/WNPRC_EHR/src/client/weight/containers/Forms/EnterWeightFormContainer.tsx b/WNPRC_EHR/src/client/weight/containers/Forms/EnterWeightFormContainer.tsx index b7572f600..d7d2b6f91 100644 --- a/WNPRC_EHR/src/client/weight/containers/Forms/EnterWeightFormContainer.tsx +++ b/WNPRC_EHR/src/client/weight/containers/Forms/EnterWeightFormContainer.tsx @@ -36,7 +36,7 @@ import { getQCStateMap, labkeyActionSelectWithPromise } from "../../query/actions"; -import { lookupAnimalInfo, saveRowsDirect } from '../../../query/helpers'; +import { lookupAnimalStatuses, saveRowsDirect } from '../../../query/helpers'; import AnimalInfoPane from "../../components/AnimalInfoPane"; import EnterWeightForm from "./EnterWeightForm"; import { @@ -182,29 +182,39 @@ const EnterWeightFormContainer: React.FunctionComponent = props => { setFormIds(); }, [ids]); + // Keyed on the id list rather than formdata: liftUpVal hands back a new array on every + // keystroke, so depending on formdata re-checks every animal in the room on each edit. + const animalIdKey = formdata.map((entry) => entry.animalid.value).join(";"); + useEffect(() => { - (async () => { - try { - const results = await Promise.all( - formdata.map(async (entry) => { - try { - const info = await lookupAnimalInfo(entry.animalid.value); - return info["calculated_status"] === "Alive"; - } catch (error) { - return false; - } - }) - ); - if (results.length === 0 || results.includes(false)) { + const animalIds = formdata + .map((entry) => entry.animalid.value) + .filter((id) => id !== "" && id !== undefined); + // A short list means some row has no animal yet, which is not saveable. + if (animalIds.length === 0 || animalIds.length !== formdata.length) { + setEnableSave(false); + return; + } + let cancelled = false; + lookupAnimalStatuses(animalIds) + .then((statuses) => { + if (!cancelled) { + setEnableSave( + animalIds.every( + (id) => statuses.get(String(id).toLowerCase()) === "Alive" + ) + ); + } + }) + .catch(() => { + if (!cancelled) { setEnableSave(false); - } else { - setEnableSave(true); } - } catch (error) { - return; - } - })(); - }, [formdata]); + }); + return () => { + cancelled = true; + }; + }, [animalIdKey]); useEffect(() => { let check = false;