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

[TM-1402] Prepopulate tree rows #752

Merged
merged 8 commits into from
Dec 17, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ const RHFSeedingTableInput = (props: PropsWithChildren<RHFSeedingTableInputProps
{...props}
title={t("Seed species or Mix")}
buttonCaptionSuffix={t("Species or mix")}
withPreviousCounts={false}
useTaxonomicBackbone={false}
value={value ?? []}
onChange={onChange}
collection={collection}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ const RHFTreeSpeciesInput = (props: PropsWithChildren<RHFTreeSpeciesInputProps>)
{...props}
title={t("Tree Species")}
buttonCaptionSuffix={t("Species")}
withPreviousCounts={true}
useTaxonomicBackbone={true}
value={value ?? []}
onChange={onChange}
collection={collection}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ export const Default: Story = {
label: "Tree Species Grown",
description:
"List the tree species that you expect to restore on this project, across all sites. Please enter the scientific name for each tree species.",
withPreviousCounts: false,
useTaxonomicBackbone: true,
required: true,
value: [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { EstablishmentEntityType, useEstablishmentTrees } from "@/connections/Es
import { useEntityContext } from "@/context/entity.provider";
import { useModalContext } from "@/context/modal.provider";
import { useDebounce } from "@/hooks/useDebounce";
import { useValueChanged } from "@/hooks/useValueChanged";
import { isReportModelName } from "@/types/common";
import { updateArrayState } from "@/utils/array";

Expand All @@ -29,6 +30,8 @@ export interface TreeSpeciesInputProps extends Omit<InputWrapperProps, "error">
title: string;
buttonCaptionSuffix: string;
withNumbers?: boolean;
withPreviousCounts: boolean;
useTaxonomicBackbone: boolean;
value: TreeSpeciesValue[];
onChange: (value: any[]) => void;
clearErrors: () => void;
Expand Down Expand Up @@ -101,16 +104,31 @@ const TreeSpeciesInput = (props: TreeSpeciesInputProps) => {
const { entityUuid, entityName } = useEntityContext();
const isEntity = entityName != null && entityUuid != null;
const isReport = isEntity && isReportModelName(entityName);
const handleBaseEntityTrees = isReport || (isEntity && ["sites", "nurseries"].includes(entityName));
const handleBaseEntityTrees =
props.withPreviousCounts && (isReport || (isEntity && ["sites", "nurseries"].includes(entityName)));
const displayPreviousCounts = props.withPreviousCounts && isReport;

const entity = (handleBaseEntityTrees ? entityName : undefined) as EstablishmentEntityType;
const uuid = handleBaseEntityTrees ? entityUuid : undefined;
const [, { establishmentTrees, previousPlantingCounts }] = useEstablishmentTrees({ entity, uuid });
const [establishmentLoaded, { establishmentTrees, previousPlantingCounts }] = useEstablishmentTrees({ entity, uuid });
const shouldPrepopulate = value.length == 0 && Object.values(previousPlantingCounts ?? {}).length > 0;
useValueChanged(shouldPrepopulate, function () {
if (shouldPrepopulate) {
onChange(
Object.entries(previousPlantingCounts!).map(([name, previousCount]) => ({
uuid: uuidv4(),
name,
taxon_id: previousCount.taxonId,
amount: 0
}))
);
}
});

const totalWithPrevious = useMemo(
() =>
props.value.reduce(
(total, { name, amount }) => total + (amount ?? 0) + (previousPlantingCounts?.[name ?? ""] ?? 0),
(total, { name, amount }) => total + (amount ?? 0) + (previousPlantingCounts?.[name ?? ""]?.amount ?? 0),
0
),
[previousPlantingCounts, props.value]
Expand Down Expand Up @@ -157,7 +175,7 @@ const TreeSpeciesInput = (props: TreeSpeciesInputProps) => {
handleCreate?.({
uuid: uuidv4(),
name: valueAutoComplete,
taxon_id: taxonId,
taxon_id: props.useTaxonomicBackbone ? taxonId : undefined,
amount: props.withNumbers ? 0 : undefined
});

Expand All @@ -183,7 +201,7 @@ const TreeSpeciesInput = (props: TreeSpeciesInputProps) => {
handleUpdate({
...editValue,
name: valueAutoComplete,
taxon_id: findTaxonId(valueAutoComplete)
taxon_id: props.useTaxonomicBackbone ? taxonId : undefined
});

setValueAutoComplete("");
Expand All @@ -202,6 +220,8 @@ const TreeSpeciesInput = (props: TreeSpeciesInputProps) => {
addValue(e);
};

if (!establishmentLoaded || shouldPrepopulate) return null;

return (
<InputWrapper
inputId={id}
Expand Down Expand Up @@ -235,6 +255,8 @@ const TreeSpeciesInput = (props: TreeSpeciesInputProps) => {
value={valueAutoComplete}
onChange={e => setValueAutoComplete(e.target.value)}
onSearch={async search => {
if (!props.useTaxonomicBackbone) return [];

const result = await autocompleteSearch(search);
setSearchResult(result);
return result;
Expand Down Expand Up @@ -289,23 +311,26 @@ const TreeSpeciesInput = (props: TreeSpeciesInputProps) => {
</div>
</When>
<div className="mb-1 mt-9 flex gap-6 border-b pb-4">
<div className={classNames({ "w-[75%]": !isReport, "w-[50%]": isReport })} ref={refTreeSpecies}>
<div
className={classNames({ "w-[75%]": !displayPreviousCounts, "w-[50%]": displayPreviousCounts })}
ref={refTreeSpecies}
>
<Text variant="text-14-bold" className="uppercase text-black">
{props.title}
</Text>
<Text variant="text-20-bold" className="text-primary">
{props.value.length}
</Text>
</div>
<div className={classNames({ "border-r pr-6": isReport })} ref={refPlanted}>
<div className={classNames({ "border-r pr-6": displayPreviousCounts })} ref={refPlanted}>
<Text variant="text-14-bold" className="uppercase text-black">
{isReport ? t("SPECIES PLANTED:") : t("TREES TO BE PLANTED:")}
</Text>
<Text variant="text-20-bold" className="text-primary">
{props.withNumbers ? props.value.reduce((total, v) => total + (v.amount || 0), 0).toLocaleString() : "0"}
</Text>
</div>
<When condition={isReport}>
<When condition={displayPreviousCounts}>
<div>
<Text variant="text-14-bold" className="uppercase text-black">
{t("TOTAL PLANTED TO DATE:")}
Expand Down Expand Up @@ -368,7 +393,7 @@ const TreeSpeciesInput = (props: TreeSpeciesInputProps) => {
}
>
<div className="flex items-center gap-1">
<When condition={value.taxon_id == null}>
<When condition={props.useTaxonomicBackbone && value.taxon_id == null}>
<div title={t("Non-Scientific Name")}>
<Icon name={IconNames.NON_SCIENTIFIC_NAME} className="min-h-8 min-w-8 h-8 w-8" />
</div>
Expand Down Expand Up @@ -410,9 +435,9 @@ const TreeSpeciesInput = (props: TreeSpeciesInputProps) => {
containerClassName=""
/>
</div>
<When condition={isReport}>
<When condition={displayPreviousCounts}>
<Text variant="text-14-light" className="text-black ">
{(previousPlantingCounts?.[value.name ?? ""] ?? 0).toLocaleString()}
{(previousPlantingCounts?.[value.name ?? ""]?.amount ?? 0).toLocaleString()}
</Text>
</When>
<div className="flex flex-1 justify-end gap-6">
Expand All @@ -426,11 +451,21 @@ const TreeSpeciesInput = (props: TreeSpeciesInputProps) => {
autoCompleteRef.current?.focus();
}}
/>
<IconButton
iconProps={{ name: IconNames.TRASH_TA, width: 24 }}
className="text-blueCustom-700 hover:text-primary"
onClick={() => setDeleteIndex(value.uuid ?? null)}
/>
<When
condition={
!displayPreviousCounts ||
previousPlantingCounts == null ||
// If we're using previous counts, only allow delete if this row has never been
// reported on before.
Object.keys(previousPlantingCounts).find(name => name === value.name) == null
}
>
<IconButton
iconProps={{ name: IconNames.TRASH_TA, width: 24 }}
className="text-blueCustom-700 hover:text-primary"
onClick={() => setDeleteIndex(value.uuid ?? null)}
/>
</When>
</div>
</div>
)}
Expand Down
4 changes: 4 additions & 0 deletions src/components/extensive/WizardForm/WizardForm.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,8 @@ const getSteps = (edit?: boolean): FormStepSchema[] => {
description: "TRee species input description",
fieldProps: {
title: "Tree Species",
withPreviousCounts: false,
useTaxonomicBackbone: false,
buttonCaptionSuffix: "Species",
required: true
},
Expand All @@ -204,6 +206,8 @@ const getSteps = (edit?: boolean): FormStepSchema[] => {

fieldProps: {
title: "Tree Species",
withPreviousCounts: false,
useTaxonomicBackbone: false,
buttonCaptionSuffix: "Species",
required: true,
withNumbers: true
Expand Down
15 changes: 13 additions & 2 deletions src/generated/v3/entityService/entityServiceSchemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,17 @@
*
* @version 1.0
*/
export type PreviousPlantingCountDto = {
/**
* Taxonomic ID for this tree species row
*/
taxonId: string | null;
/**
* Number of trees of this type that have been planted in all previous reports on this entity.
*/
amount: number;
};

export type ScientificNameDto = {
/**
* The scientific name for this tree species
Expand All @@ -20,9 +31,9 @@ export type EstablishmentsTreesDto = {
/**
* If the entity in this request is a report, the sum totals of previous planting by species.
*
* @example {"Aster persaliens":256,"Cirsium carniolicum":1024}
* @example {"Aster persaliens":{"amount":256},"Cirsium carniolicum":{"taxonId":"wfo-0000130112","amount":1024}}
*/
previousPlantingCounts: {
[key: string]: number;
[key: string]: PreviousPlantingCountDto;
} | null;
};
2 changes: 1 addition & 1 deletion src/helpers/customForms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -732,7 +732,7 @@ const getFieldValidation = (question: FormQuestionRead, t: typeof useT, framewor
const arrayItemShape = question.with_numbers
? yup.object({
name: yup.string().required(),
amount: yup.number().min(1).required()
amount: yup.number().min(0).required()
})
: yup.object({
name: yup.string().required()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -599,6 +599,8 @@ export const getSteps = (t: typeof useT, uuid: string): FormStepSchema[] => {
),
fieldProps: {
title: t("Tree Species"),
withPreviousCounts: false,
useTaxonomicBackbone: true,
buttonCaptionSuffix: t("Species"),
withNumbers: false
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,8 @@ export const getSteps = (t: typeof useT, uuid: string): FormStepSchema[] => [
),
fieldProps: {
title: t("Tree Species"),
withPreviousCounts: false,
useTaxonomicBackbone: true,
buttonCaptionSuffix: t("Species"),
withNumbers: true
}
Expand Down
Loading