From eab370674b7a45a08ffa15b50e2bdfc99c9bc9be Mon Sep 17 00:00:00 2001 From: Dotnara Condori Date: Wed, 4 Dec 2024 16:26:59 -0400 Subject: [PATCH 01/16] [TM-1476] WEB DESIGN: Update the tree species UI to enable users to enter in data that aligns with taxonomic backbone (#724) * [TM-1476] [TM-13476] add tree species iu * [TM-1476] [TM-13476] fix build * [TM-1476] update snapshots * [TM-1476] Fix lint * [TM-1476] update storybook --------- Co-authored-by: diego-morales-flores-1996 Co-authored-by: Limber Mamani Vallejos --- src/assets/icons/add-button.svg | 9 + src/assets/icons/edit-ta.svg | 8 + src/assets/icons/new-tag-tree-species.svg | 8 + src/assets/icons/non-scientific name.svg | 9 + src/assets/icons/trash-ta.svg | 8 + .../AutoCompleteInput/AutoCompleteInput.tsx | 15 +- .../elements/Inputs/Input/Input.tsx | 7 +- .../TreeSpeciesInput/TreeSpeciesInput.tsx | 280 ++++++++++-- .../TreeSpeciesInput.stories.storyshot | 432 +++++++++++++----- .../__snapshots__/TextArea.stories.storyshot | 6 +- .../__snapshots__/Table.stories.storyshot | 72 +-- .../elements/Tabs/Default/TabButton.tsx | 13 +- .../__snapshots__/Tabs.stories.storyshot | 24 +- .../SecondaryTabs.stories.storyshot | 12 +- src/components/extensive/Icon/Icon.tsx | 7 +- .../__snapshots__/ModalAdd.stories.storyshot | 2 +- .../ModalConfirm.stories.storyshot | 2 +- .../ModalSubmit.stories.storyshot | 2 +- .../ModalWithLogo.stories.storyshot | 2 +- .../PerPageSelector.stories.storyshot | 6 +- .../MainLayout.stories.storyshot | 4 +- .../__snapshots__/Navbar.stories.storyshot | 8 +- tailwind.config.js | 2 + 23 files changed, 702 insertions(+), 236 deletions(-) create mode 100644 src/assets/icons/add-button.svg create mode 100644 src/assets/icons/edit-ta.svg create mode 100644 src/assets/icons/new-tag-tree-species.svg create mode 100644 src/assets/icons/non-scientific name.svg create mode 100644 src/assets/icons/trash-ta.svg diff --git a/src/assets/icons/add-button.svg b/src/assets/icons/add-button.svg new file mode 100644 index 000000000..b2d5c5208 --- /dev/null +++ b/src/assets/icons/add-button.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/assets/icons/edit-ta.svg b/src/assets/icons/edit-ta.svg new file mode 100644 index 000000000..85d3d0d07 --- /dev/null +++ b/src/assets/icons/edit-ta.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/assets/icons/new-tag-tree-species.svg b/src/assets/icons/new-tag-tree-species.svg new file mode 100644 index 000000000..e79ab3b38 --- /dev/null +++ b/src/assets/icons/new-tag-tree-species.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/assets/icons/non-scientific name.svg b/src/assets/icons/non-scientific name.svg new file mode 100644 index 000000000..7bb70d7f4 --- /dev/null +++ b/src/assets/icons/non-scientific name.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/assets/icons/trash-ta.svg b/src/assets/icons/trash-ta.svg new file mode 100644 index 000000000..551bd1526 --- /dev/null +++ b/src/assets/icons/trash-ta.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/components/elements/Inputs/AutoCompleteInput/AutoCompleteInput.tsx b/src/components/elements/Inputs/AutoCompleteInput/AutoCompleteInput.tsx index 57c6b16dc..80fa54ab2 100644 --- a/src/components/elements/Inputs/AutoCompleteInput/AutoCompleteInput.tsx +++ b/src/components/elements/Inputs/AutoCompleteInput/AutoCompleteInput.tsx @@ -1,5 +1,6 @@ import { Popover, Transition } from "@headlessui/react"; import { useT } from "@transifex/react"; +import classNames from "classnames"; import { ChangeEvent, forwardRef, Fragment, Ref, useState } from "react"; import { Else, If, Then } from "react-if"; @@ -11,11 +12,16 @@ import Input, { InputProps } from "../Input/Input"; export interface AutoCompleteInputProps extends InputProps { onSearch: (query: string) => Promise; disableAutoComplete?: boolean; + classNameMenu?: string; + onSelected?: (item: string) => void; } //TODO: Bugfix: Users can enter space in this input const AutoCompleteInput = forwardRef( - ({ onSearch, disableAutoComplete, ...inputProps }: AutoCompleteInputProps, ref?: Ref) => { + ( + { onSearch, disableAutoComplete, classNameMenu, onSelected, ...inputProps }: AutoCompleteInputProps, + ref?: Ref + ) => { const t = useT(); const [list, setList] = useState([]); const [loading, setLoading] = useState(false); @@ -27,6 +33,8 @@ const AutoCompleteInput = forwardRef( inputProps.onChange?.({ target: { name: inputProps.name, value: item } } as ChangeEvent); } + onSelected?.(item); + setList([]); }; @@ -63,7 +71,10 @@ const AutoCompleteInput = forwardRef( leaveFrom="transform scale-100 opacity-100" leaveTo="transform scale-95 opacity-0" > - + diff --git a/src/components/elements/Inputs/Input/Input.tsx b/src/components/elements/Inputs/Input/Input.tsx index 9bc551e42..a1ae18309 100644 --- a/src/components/elements/Inputs/Input/Input.tsx +++ b/src/components/elements/Inputs/Input/Input.tsx @@ -14,7 +14,7 @@ export interface InputProps extends InputWrapperProps, Omit, HTMLInputElement>, "type" | "form"> { name: string; - variant?: "secondary" | "default" | "login" | "signup" | "monitored"; + variant?: "secondary" | "default" | "login" | "signup" | "monitored" | "treePlanted"; formHook?: UseFormReturn; clearable?: boolean; iconButtonProps?: IconButtonProps; @@ -112,6 +112,11 @@ const Input = forwardRef( true, "pl-4": inputProps.type === "number", "border-neutral-300": !error + }, + treePlanted: { + "py-[7.5px] py-1.5 !w-[100px] text-center border border-blueCustom-700 rounded hover:border-primary hover:shadow-blue-border opacity-60 outline-none text-14-light !font-primary": + true, + "text-center": inputProps.type === "number" } }; diff --git a/src/components/elements/Inputs/TreeSpeciesInput/TreeSpeciesInput.tsx b/src/components/elements/Inputs/TreeSpeciesInput/TreeSpeciesInput.tsx index ca047e0cd..a1c767f73 100644 --- a/src/components/elements/Inputs/TreeSpeciesInput/TreeSpeciesInput.tsx +++ b/src/components/elements/Inputs/TreeSpeciesInput/TreeSpeciesInput.tsx @@ -1,11 +1,12 @@ import { useT } from "@transifex/react"; +import classNames from "classnames"; import { remove } from "lodash"; -import { Fragment, KeyboardEvent, useCallback, useId, useRef } from "react"; +import { Fragment, KeyboardEvent, useCallback, useId, useRef, useState } from "react"; import { FieldError, FieldErrors } from "react-hook-form"; -import { When } from "react-if"; +import { Else, If, Then, When } from "react-if"; import { v4 as uuidv4 } from "uuid"; -import { IconNames } from "@/components/extensive/Icon/Icon"; +import Icon, { IconNames } from "@/components/extensive/Icon/Icon"; import List from "@/components/extensive/List/List"; import { useDebounce } from "@/hooks/useDebounce"; import { updateArrayState } from "@/utils/array"; @@ -14,6 +15,7 @@ import Button from "../../Button/Button"; import ErrorMessage from "../../ErrorMessage/ErrorMessage"; import IconButton from "../../IconButton/IconButton"; import Text from "../../Text/Text"; +import AutoCompleteInput from "../AutoCompleteInput/AutoCompleteInput"; import Input from "../Input/Input"; import InputWrapper, { InputWrapperProps } from "../InputElements/InputWrapper"; @@ -31,13 +33,21 @@ export interface TreeSpeciesInputProps extends Omit error?: FieldErrors[]; } -export type TreeSpeciesValue = { uuid?: string; name?: string; amount?: number }; +export type TreeSpeciesValue = { uuid?: string; name?: string; amount?: number; new?: boolean }; const TreeSpeciesInput = (props: TreeSpeciesInputProps) => { const id = useId(); const t = useT(); const lastInputRef = useRef(null); + const [valueAutoComplete, setValueAutoComplete] = useState(""); + const [editIndex, setEditIndex] = useState(null); + const [deleteIndex, setDeleteIndex] = useState(null); + const [editValue, setEditValue] = useState(null); + const refPlanted = useRef(null); + const refTotal = useRef(null); + const refTreeSpecies = useRef(null); + const { onChange, value, clearErrors, collection } = props; const handleCreate = useDebounce( @@ -74,7 +84,12 @@ const TreeSpeciesInput = (props: TreeSpeciesInputProps) => { const addValue = (e: React.MouseEvent | KeyboardEvent) => { e.preventDefault(); if (!props.error) { - handleCreate?.({ uuid: uuidv4(), name: undefined, amount: undefined }); + if (!props.withNumbers) { + handleCreate?.({ uuid: uuidv4(), name: valueAutoComplete, amount: 0, new: true }); + } else { + handleCreate?.({ uuid: uuidv4(), name: valueAutoComplete, amount: 0 }); + } + lastInputRef.current && lastInputRef.current.focus(); } }; @@ -88,78 +103,247 @@ const TreeSpeciesInput = (props: TreeSpeciesInputProps) => { return (
-
- - {props.title} ({props.value.length}) + +
+ + If you would like to add a species not included on the original Restoration Project, it will be flagged to + the admin as new information pending review. +
+
+
+ + {t("Scientific Name:")} - - - {t(`Total Count: ({number})`, { number: props.value.reduce((total, v) => total + (v.amount || 0), 0) })} +
+
+ setValueAutoComplete(e.target.value)} + onSearch={(query: string) => { + console.log("Query", query); + if (query === "non-scientific name") return Promise.resolve([]); + return Promise.resolve([ + "Amadea diffusa", + "Amadea occidentalis", + "Amadea puberulenta", + "Amadea lorem ipsum", + "Amadea lorem ipsum" + ]); + }} + onSelected={item => { + console.log(item); + setValueAutoComplete(item); + }} + /> + 0}> + + +
+ + + + + + + + +
+
+ +
+ + {t("No matches available")} + +
+ + + {t("You can this add, but it will be pending review from Admin.")} + +
+
+
+
+
+ + {props.title} + + {props.value.length} + +
+
+ + {props.withNumbers ? "TREES TO BE PLANTED:" : "SPECIES PLANTED:"} + + + {props.withNumbers ? props.value.reduce((total, v) => total + (v.amount || 0), 0) : "0"} + +
+ +
+ + {"TOTAL PLANTED TO DATE:"} + + + 47,800 + +
- ( -
- handleUpdate({ ...value, name: e.target.value })} - placeholder={t("Species Name")} - error={props.error?.[index]?.name ? ({} as FieldError) : undefined} - onKeyDownCapture={onKeyDownCapture} - containerClassName="flex-1" - /> - +
+ +
+ + {t(`Are you sure you want to delete “${value.name}”?`)} + +
+ + +
+
+
+ +
+ + + {t(`NEW ${value.name}`)} + +
+
+
+
+ + + + + + + + {t(value.name)} + +
+
+
handleUpdate({ ...value, amount: +e.target.value })} + onChange={e => (props.withNumbers ? handleUpdate({ ...value, amount: +e.target.value }) : {})} onKeyDownCapture={onKeyDownCapture} - containerClassName="flex-3" + containerClassName="" /> +
+ + + 7,400 + + + +
+ { + setEditIndex(value.uuid ?? null); + setEditValue(value); + }} + /> + setDeleteIndex(value.uuid ?? null)} + /> +
- handleDelete(props.value?.[index]?.uuid)} - />
)} /> -
); diff --git a/src/components/elements/Inputs/TreeSpeciesInput/__snapshots__/TreeSpeciesInput.stories.storyshot b/src/components/elements/Inputs/TreeSpeciesInput/__snapshots__/TreeSpeciesInput.stories.storyshot index 1e1feb841..0b132a4d0 100644 --- a/src/components/elements/Inputs/TreeSpeciesInput/__snapshots__/TreeSpeciesInput.stories.storyshot +++ b/src/components/elements/Inputs/TreeSpeciesInput/__snapshots__/TreeSpeciesInput.stories.storyshot @@ -9,7 +9,7 @@ exports[`Storyshots Components/Elements/Inputs/TreeSpeciesInput Default 1`] = ` data-testid="txt" htmlFor=":r23:" > - Tree Species Grown * + ADD TREE SPECIES *

+
+ If you would like to add a species not included on the original Restoration Project, it will be flagged to the admin as new information pending review. +
+

- ( - 1 - ) + Scientific Name:

-
-
- +
+
+ +
+
- +

+ TOTAL PLANTED TO DATE: +

+

+ 47,800 +

+
+
+
+
+
+
+

+ Test +

+
+
+
+
+
+ +
+
+
+

+ 7,400 +

+
+
`; @@ -104,9 +226,9 @@ exports[`Storyshots Components/Elements/Inputs/TreeSpeciesInput With Number 1`]

- ( - 1 - ) -

-

- Total Count: (23) + Scientific Name:

-
-
- -
-
-
-
- +
+
+ +
+
-
+
+
- Add Another undefined - - +
+
+

+ Test +

+
+
+
+
+
+ +
+
+
+
+ + +
+
+
`; diff --git a/src/components/elements/Inputs/textArea/__snapshots__/TextArea.stories.storyshot b/src/components/elements/Inputs/textArea/__snapshots__/TextArea.stories.storyshot index d9cc8e856..619833a88 100644 --- a/src/components/elements/Inputs/textArea/__snapshots__/TextArea.stories.storyshot +++ b/src/components/elements/Inputs/textArea/__snapshots__/TextArea.stories.storyshot @@ -7,7 +7,7 @@ exports[`Storyshots Components/Elements/Inputs/TextArea Default 1`] = ` @@ -19,11 +19,11 @@ exports[`Storyshots Components/Elements/Inputs/TextArea Default 1`] = ` } } data-testid="txt" - id=":r28:-description" + id=":r2d:-description" />