From d40e520a1d16546b977f33311d53355fada0e995 Mon Sep 17 00:00:00 2001 From: Sayaka Ono Date: Mon, 18 Nov 2024 16:02:13 -0800 Subject: [PATCH 01/29] LF-4384 Update WithStepperProgressBar not to use FixedHeaderContainer for single step form --- .../ContextForm/WithStepperProgressBar.tsx | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/packages/webapp/src/components/Form/ContextForm/WithStepperProgressBar.tsx b/packages/webapp/src/components/Form/ContextForm/WithStepperProgressBar.tsx index 3d4b91f102..37a1c3f6c5 100644 --- a/packages/webapp/src/components/Form/ContextForm/WithStepperProgressBar.tsx +++ b/packages/webapp/src/components/Form/ContextForm/WithStepperProgressBar.tsx @@ -133,19 +133,26 @@ export const WithStepperProgressBar = ({ setShowCancelFlow?.(false); }; - return ( - + isSingleStep ? ( + <>{children} + ) : ( + title)} activeStep={activeStepIndex} /> - ) - } - > + } + > + {children} + + ); + + return ( +
{children}
{shouldShowFormNavigationButtons && ( @@ -166,6 +173,6 @@ export const WithStepperProgressBar = ({ handleCancel={handleCancel} /> )} -
+ ); }; From aab542c1f1abff5d04593ad492e22a2d31721647 Mon Sep 17 00:00:00 2001 From: Sayaka Ono Date: Mon, 18 Nov 2024 16:03:28 -0800 Subject: [PATCH 02/29] LF-4384 Add animals url to FULL_WIDTH_ROUTES in App --- packages/webapp/src/App.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/webapp/src/App.jsx b/packages/webapp/src/App.jsx index cc8f2b7dbf..0b472a1607 100644 --- a/packages/webapp/src/App.jsx +++ b/packages/webapp/src/App.jsx @@ -24,11 +24,11 @@ import { NotistackSnackbar } from './containers/Snackbar/NotistackSnackbar'; import { OfflineDetector } from './containers/hooks/useOfflineDetector/OfflineDetector'; import styles from './styles.module.scss'; import Routes from './routes'; -import { ANIMALS_INVENTORY_URL } from './util/siteMapConstants'; +import { ANIMALS_INVENTORY_URL, ANIMALS_URL } from './util/siteMapConstants'; function App() { const [isCompactSideMenu, setIsCompactSideMenu] = useState(false); - const FULL_WIDTH_ROUTES = ['/map', ANIMALS_INVENTORY_URL]; + const FULL_WIDTH_ROUTES = ['/map', ANIMALS_INVENTORY_URL, ANIMALS_URL]; const isFullWidth = FULL_WIDTH_ROUTES.some((path) => matchPath(history.location.pathname, path)); return ( From 5c390de2d6e1b8014d0c04130c8288e0252486c6 Mon Sep 17 00:00:00 2001 From: Sayaka Ono Date: Mon, 18 Nov 2024 16:39:33 -0800 Subject: [PATCH 03/29] LF-4384 Refactor WithStepperProgressBar --- .../ContextForm/WithStepperProgressBar.tsx | 41 +++++++++---------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/packages/webapp/src/components/Form/ContextForm/WithStepperProgressBar.tsx b/packages/webapp/src/components/Form/ContextForm/WithStepperProgressBar.tsx index 37a1c3f6c5..f615442148 100644 --- a/packages/webapp/src/components/Form/ContextForm/WithStepperProgressBar.tsx +++ b/packages/webapp/src/components/Form/ContextForm/WithStepperProgressBar.tsx @@ -133,26 +133,8 @@ export const WithStepperProgressBar = ({ setShowCancelFlow?.(false); }; - const Wrapper = ({ children }: { children: ReactNode }) => - isSingleStep ? ( - <>{children} - ) : ( - title)} - activeStep={activeStepIndex} - /> - } - > - {children} - - ); - - return ( - + const renderContent = () => ( + <>
{children}
{shouldShowFormNavigationButtons && ( @@ -173,6 +155,23 @@ export const WithStepperProgressBar = ({ handleCancel={handleCancel} /> )} -
+ + ); + + return isSingleStep ? ( + renderContent() + ) : ( + title)} + activeStep={activeStepIndex} + /> + } + > + {renderContent()} + ); }; From 45ba5908eb2477678ec8e30fb7390ea79820207e Mon Sep 17 00:00:00 2001 From: Sayaka Ono Date: Mon, 18 Nov 2024 16:41:37 -0800 Subject: [PATCH 04/29] LF-4384 Update SingleAnimalView to use FixedHeaderContainer --- .../Animals/SingleAnimalView/index.tsx | 73 ++++++++++--------- .../SingleAnimalView/styles.module.scss | 5 ++ 2 files changed, 45 insertions(+), 33 deletions(-) diff --git a/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx b/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx index 9df89cec75..d15c5b7e40 100644 --- a/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx +++ b/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx @@ -23,6 +23,7 @@ import { enqueueErrorSnackbar, enqueueSuccessSnackbar } from '../../Snackbar/sna import AnimalReadonlyEdit from './AnimalReadonlyEdit'; import Tab, { Variant as TabVariants } from '../../../components/RouterTab/Tab'; import AnimalSingleViewHeader from '../../../components/Animals/AnimalSingleViewHeader'; +import FixedHeaderContainer from '../../../components/Animals/FixedHeaderContainer'; import { addNullstoMissingFields } from './utils'; import { useInitialAnimalData } from './useInitialAnimalData'; import { @@ -155,39 +156,45 @@ function SingleAnimalView({ isCompactSideMenu, history, match, location }: AddAn return (
-
- {defaultFormValues && ( - history.push('/animals/inventory')} - /* @ts-ignore */ - animalOrBatch={defaultFormValues} - defaultBreeds={defaultAnimalBreeds} - defaultTypes={defaultAnimalTypes} - customBreeds={customAnimalBreeds} - customTypes={customAnimalTypes} - /> - )} -
- {/* tab.path === match.url} - onClick={(tab) => history.push(tab.path)} - /> */} - + + {defaultFormValues && ( + history.push('/animals/inventory')} + /* @ts-ignore */ + animalOrBatch={defaultFormValues} + defaultBreeds={defaultAnimalBreeds} + defaultTypes={defaultAnimalTypes} + customBreeds={customAnimalBreeds} + customTypes={customAnimalTypes} + /> + )} + {/* tab.path === match.url} + onClick={(tab) => history.push(tab.path)} + /> */} + + } + > + +
); } diff --git a/packages/webapp/src/containers/Animals/SingleAnimalView/styles.module.scss b/packages/webapp/src/containers/Animals/SingleAnimalView/styles.module.scss index d0c9d3af66..26e6ac785f 100644 --- a/packages/webapp/src/containers/Animals/SingleAnimalView/styles.module.scss +++ b/packages/webapp/src/containers/Animals/SingleAnimalView/styles.module.scss @@ -18,3 +18,8 @@ flex-direction: column; gap: 20px; } + +.contentWrapper { + // avoid hiding header's box-shadow or border + margin-top: 1px; +} From 26328140118b85dc483051ba34980f15f55977a3 Mon Sep 17 00:00:00 2001 From: Sayaka Ono Date: Mon, 18 Nov 2024 17:35:19 -0800 Subject: [PATCH 05/29] LF-4384 Implement animal removal --- .../Animals/SingleAnimalView/index.tsx | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx b/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx index d15c5b7e40..547c591f49 100644 --- a/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx +++ b/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx @@ -42,6 +42,9 @@ import { import { Animal, AnimalBatch } from '../../../store/api/types'; import { AnimalOrBatchKeys } from '../types'; import { AnimalDetailsFormFields } from '../AddAnimals/types'; +import RemoveAnimalsModal, { FormFields } from '../../../components/Animals/RemoveAnimalsModal'; +import useAnimalOrBatchRemoval from '../Inventory/useAnimalOrBatchRemoval'; +import { generateInventoryId } from '../../../util/animal'; export const STEPS = { DETAILS: 'details', @@ -154,6 +157,25 @@ function SingleAnimalView({ isCompactSideMenu, history, match, location }: AddAn onGoForward(); }; + const getInventoryId = () => { + if (!selectedAnimal && !selectedBatch) { + return ''; + } + + const animalOrBatch = AnimalOrBatchKeys[selectedAnimal ? 'ANIMAL' : 'BATCH']; + return generateInventoryId(animalOrBatch, (selectedAnimal || selectedBatch)!); + }; + + const { onConfirmRemoveAnimals, removalModalOpen, setRemovalModalOpen } = useAnimalOrBatchRemoval( + [getInventoryId()], + () => ({}), + ); + + const onConfirmRemoval = (formData: FormFields) => { + onConfirmRemoveAnimals(formData); + history.push('/animals/inventory'); + }; + return (
setRemovalModalOpen(true)} isEditing={isEditing} onBack={() => history.push('/animals/inventory')} /* @ts-ignore */ @@ -194,6 +217,12 @@ function SingleAnimalView({ isCompactSideMenu, history, match, location }: AddAn isEditing={isEditing} setIsEditing={setIsEditing} /> + setRemovalModalOpen(false)} + onConfirm={onConfirmRemoval} + showSuccessMessage={false} + />
); From b7b76c585e9694272f61a63be683078f1e0cfe65 Mon Sep 17 00:00:00 2001 From: Sayaka Ono Date: Tue, 19 Nov 2024 10:12:48 -0800 Subject: [PATCH 06/29] LF-4384 Create custom RouteComponentProps type --- packages/webapp/src/types/index.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/webapp/src/types/index.ts b/packages/webapp/src/types/index.ts index 4a240ab49f..d6c6fc890a 100644 --- a/packages/webapp/src/types/index.ts +++ b/packages/webapp/src/types/index.ts @@ -13,8 +13,19 @@ * GNU General Public License for more details, see . */ +import { RouteComponentProps } from 'react-router-dom'; +import { History } from 'history'; + export enum OrganicStatus { 'NON_ORGANIC' = 'Non-Organic', 'TRANSITIONAL' = 'Transitional', 'ORGANIC' = 'Organic', } + +// Custom RouteComponentProps with a custom history type from the 'history' library +export type CustomRouteComponentProps = Omit< + RouteComponentProps, + 'history' +> & { + history: History; // Custom history type +}; From 4248a6bb145fbb68035614edd057e1ab103f012a Mon Sep 17 00:00:00 2001 From: Sayaka Ono Date: Tue, 19 Nov 2024 10:15:53 -0800 Subject: [PATCH 07/29] LF-4384 Replace RouteComponentProps with CustomRouteComponentProps --- .../webapp/src/containers/Animals/SingleAnimalView/index.tsx | 4 ++-- .../Animals/SingleAnimalView/useInitialAnimalData.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx b/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx index 547c591f49..1a2c810cc4 100644 --- a/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx +++ b/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx @@ -15,7 +15,6 @@ import { useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { RouteComponentProps } from 'react-router-dom'; import { useDispatch } from 'react-redux'; import styles from './styles.module.scss'; import { ContextForm, Variant } from '../../../components/Form/ContextForm/'; @@ -45,6 +44,7 @@ import { AnimalDetailsFormFields } from '../AddAnimals/types'; import RemoveAnimalsModal, { FormFields } from '../../../components/Animals/RemoveAnimalsModal'; import useAnimalOrBatchRemoval from '../Inventory/useAnimalOrBatchRemoval'; import { generateInventoryId } from '../../../util/animal'; +import { CustomRouteComponentProps } from '../../../types'; export const STEPS = { DETAILS: 'details', @@ -54,7 +54,7 @@ interface RouteParams { id: string; } -interface AddAnimalsProps extends RouteComponentProps { +interface AddAnimalsProps extends CustomRouteComponentProps { isCompactSideMenu: boolean; } diff --git a/packages/webapp/src/containers/Animals/SingleAnimalView/useInitialAnimalData.ts b/packages/webapp/src/containers/Animals/SingleAnimalView/useInitialAnimalData.ts index bbdcc21da4..b8b2fa3645 100644 --- a/packages/webapp/src/containers/Animals/SingleAnimalView/useInitialAnimalData.ts +++ b/packages/webapp/src/containers/Animals/SingleAnimalView/useInitialAnimalData.ts @@ -13,19 +13,19 @@ * GNU General Public License for more details, see . */ -import { RouteComponentProps } from 'react-router-dom'; import { useGetAnimalBatchesQuery, useGetAnimalsQuery } from '../../../store/api/apiSlice'; import { useAnimalOptions } from '../AddAnimals/useAnimalOptions'; import { DetailsFields } from '../AddAnimals/types'; import { generateFormDate } from './utils'; import { ANIMAL_ID_PREFIX, AnimalOrBatchKeys } from '../types'; import { generateUniqueAnimalId } from '../../../util/animal'; +import { CustomRouteComponentProps } from '../../../types'; interface RouteParams { id: string; } -interface UseInitialAnimalDataProps extends RouteComponentProps {} +interface UseInitialAnimalDataProps extends CustomRouteComponentProps {} export const useInitialAnimalData = ({ match }: UseInitialAnimalDataProps) => { const { selectedAnimal } = useGetAnimalsQuery(undefined, { From 2f1ac45be1a7d8e50332c1fe301d460f647a9d7b Mon Sep 17 00:00:00 2001 From: Sayaka Ono Date: Tue, 19 Nov 2024 10:18:31 -0800 Subject: [PATCH 08/29] LF-4384 Replace history.push with history.back in SingleAnimalView --- .../webapp/src/containers/Animals/SingleAnimalView/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx b/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx index 1a2c810cc4..9cee19256f 100644 --- a/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx +++ b/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx @@ -173,7 +173,7 @@ function SingleAnimalView({ isCompactSideMenu, history, match, location }: AddAn const onConfirmRemoval = (formData: FormFields) => { onConfirmRemoveAnimals(formData); - history.push('/animals/inventory'); + history.back(); }; return ( @@ -187,7 +187,7 @@ function SingleAnimalView({ isCompactSideMenu, history, match, location }: AddAn onEdit={initiateEdit} onRemove={() => setRemovalModalOpen(true)} isEditing={isEditing} - onBack={() => history.push('/animals/inventory')} + onBack={history.back} /* @ts-ignore */ animalOrBatch={defaultFormValues} defaultBreeds={defaultAnimalBreeds} From d8e013ab56c26a279d1e1313e0c10994e39ad097 Mon Sep 17 00:00:00 2001 From: Sayaka Ono Date: Tue, 19 Nov 2024 10:24:37 -0800 Subject: [PATCH 09/29] LF-4384 Redirect to unknown record screen when no animal or batch for the URL --- .../src/containers/Animals/SingleAnimalView/index.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx b/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx index 9cee19256f..a72ce08bd2 100644 --- a/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx +++ b/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx @@ -13,7 +13,7 @@ * GNU General Public License for more details, see . */ -import { useState } from 'react'; +import { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useDispatch } from 'react-redux'; import styles from './styles.module.scss'; @@ -101,6 +101,12 @@ function SingleAnimalView({ isCompactSideMenu, history, match, location }: AddAn location, }); + useEffect(() => { + if (!selectedAnimal && !selectedBatch) { + history.replace('/unknown_record'); + } + }, [selectedAnimal, selectedBatch, history]); + // Form submission const [updateAnimals] = useUpdateAnimalsMutation(); const [updateBatches] = useUpdateAnimalBatchesMutation(); From ace818dd62abb66e2c0771b34ff1fd8c940c1793 Mon Sep 17 00:00:00 2001 From: Sayaka Ono Date: Tue, 19 Nov 2024 10:37:59 -0800 Subject: [PATCH 10/29] LF-4384 Update MeatballsMenu and DropdownButton to accept disabled prop --- packages/webapp/src/components/Form/DropDownButton/index.jsx | 2 ++ packages/webapp/src/components/Menu/MeatballsMenu/index.tsx | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/webapp/src/components/Form/DropDownButton/index.jsx b/packages/webapp/src/components/Form/DropDownButton/index.jsx index f6ca58fec9..bbca6d8953 100644 --- a/packages/webapp/src/components/Form/DropDownButton/index.jsx +++ b/packages/webapp/src/components/Form/DropDownButton/index.jsx @@ -29,6 +29,7 @@ export default function DropdownButton({ type, classes: propClasses = {}, menuPositionOffset, + disabled = false, }) { const classes = useStyles(); const [isOpen, setOpen] = useState(defaultOpen); @@ -68,6 +69,7 @@ export default function DropdownButton({ aria-controls={isOpen ? 'composition-menu' : undefined} aria-expanded={isOpen ? 'true' : undefined} aria-haspopup="true" + disabled={disabled} > {children} {!noIcon && ( diff --git a/packages/webapp/src/components/Menu/MeatballsMenu/index.tsx b/packages/webapp/src/components/Menu/MeatballsMenu/index.tsx index 99034a691d..08b463ea49 100644 --- a/packages/webapp/src/components/Menu/MeatballsMenu/index.tsx +++ b/packages/webapp/src/components/Menu/MeatballsMenu/index.tsx @@ -22,9 +22,10 @@ import styles from './styles.module.scss'; export type MeatballsMenuProps = { classes?: { button?: string }; options: { label: ReactNode; onClick: () => void }[]; + disabled: boolean; }; -const MeatballsMenu = ({ options, classes }: MeatballsMenuProps) => { +const MeatballsMenu = ({ options, classes, disabled = false }: MeatballsMenuProps) => { return ( { /> ))} menuPositionOffset={[0, 1]} + disabled={disabled} > From 4ac69a8e04cbcdf3441597147934ea3651dc9a26 Mon Sep 17 00:00:00 2001 From: Sayaka Ono Date: Tue, 19 Nov 2024 10:39:36 -0800 Subject: [PATCH 11/29] LF-4384 Update AnimalSingleViewHeader to disable menu button while editing --- .../src/components/Animals/AnimalSingleViewHeader/index.tsx | 1 + .../Animals/AnimalSingleViewHeader/styles.module.scss | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/webapp/src/components/Animals/AnimalSingleViewHeader/index.tsx b/packages/webapp/src/components/Animals/AnimalSingleViewHeader/index.tsx index ae959cf347..75a266aa79 100644 --- a/packages/webapp/src/components/Animals/AnimalSingleViewHeader/index.tsx +++ b/packages/webapp/src/components/Animals/AnimalSingleViewHeader/index.tsx @@ -107,6 +107,7 @@ const ContainerWithButtons = ({
{!isCompactView && isEditing ?
{t('common:EDITING')}
: null} diff --git a/packages/webapp/src/components/Animals/AnimalSingleViewHeader/styles.module.scss b/packages/webapp/src/components/Animals/AnimalSingleViewHeader/styles.module.scss index 365b5e6adc..bbc8121fbf 100644 --- a/packages/webapp/src/components/Animals/AnimalSingleViewHeader/styles.module.scss +++ b/packages/webapp/src/components/Animals/AnimalSingleViewHeader/styles.module.scss @@ -82,7 +82,8 @@ padding-left: 16px; } -.editingStatusButton { +.editingStatusButton, +.editingStatusButton:disabled { background: var(--Btn-primary-hover); box-shadow: 1px 1px 0px 0px var(--Colors-Primary-Primary-teal-300); From 6054d79600aeba7d7c7e595ea44da29381963ca6 Mon Sep 17 00:00:00 2001 From: Sayaka Ono Date: Tue, 19 Nov 2024 13:07:44 -0800 Subject: [PATCH 12/29] LF-4384 Add missing desiredKeys to animalBatchController's editAnimalBatches --- packages/api/src/controllers/animalBatchController.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/api/src/controllers/animalBatchController.js b/packages/api/src/controllers/animalBatchController.js index 1691af7707..919e4dacd4 100644 --- a/packages/api/src/controllers/animalBatchController.js +++ b/packages/api/src/controllers/animalBatchController.js @@ -124,6 +124,11 @@ const animalBatchController = { 'origin_id', 'group_ids', 'animal_batch_use_relationships', + 'birth_date', + 'dam', + 'sire', + 'brought_in_date', + 'weaning_date', ]; // select only allowed properties to edit From 3f72c8060b735f07f4f24732aee7f5d593cf87bb Mon Sep 17 00:00:00 2001 From: Sayaka Ono Date: Tue, 19 Nov 2024 13:09:06 -0800 Subject: [PATCH 13/29] LF-4384 Update parseUniqueDefaultId to handle exception (fix filtered animalUseOptions) --- packages/webapp/src/util/animal.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/webapp/src/util/animal.ts b/packages/webapp/src/util/animal.ts index 2003e57efa..5718338f89 100644 --- a/packages/webapp/src/util/animal.ts +++ b/packages/webapp/src/util/animal.ts @@ -58,7 +58,10 @@ export const generateUniqueAnimalId = ( }; export const parseUniqueDefaultId = (uniqueId: string): number | null => { - if (uniqueId.startsWith(ANIMAL_ID_PREFIX.CUSTOM)) { + if ( + uniqueId.startsWith(ANIMAL_ID_PREFIX.CUSTOM) || + !uniqueId.includes(ANIMAL_ID_PREFIX.DEFAULT) + ) { return null; } return Number(uniqueId.split('_')[1]); From b3edb848fb46875e9c9ace5b87ab03eab33079c3 Mon Sep 17 00:00:00 2001 From: Sayaka Ono Date: Tue, 19 Nov 2024 13:31:41 -0800 Subject: [PATCH 14/29] LF-4384 Add styles to batch count in AnimalSingleViewHeader --- .../Animals/AnimalSingleViewHeader/styles.module.scss | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/webapp/src/components/Animals/AnimalSingleViewHeader/styles.module.scss b/packages/webapp/src/components/Animals/AnimalSingleViewHeader/styles.module.scss index bbc8121fbf..29b0cb1d4a 100644 --- a/packages/webapp/src/components/Animals/AnimalSingleViewHeader/styles.module.scss +++ b/packages/webapp/src/components/Animals/AnimalSingleViewHeader/styles.module.scss @@ -153,6 +153,8 @@ bottom: 8px; height: 24px; + min-width: 20px; + max-width: 48px; padding: 4px; border-radius: 2px; background: var(--Colors-Accent---singles-Purple-light); @@ -161,6 +163,10 @@ color: var(--Colors-Accent---singles-Purple-full); font-size: 12px; font-weight: 600; + text-align: center; + + /* Counts with more than six digits will be visually cut off */ + overflow: hidden; } .desktopBasicInfo { From f29364a07f7f644ea05766bb618faae97d8a5b54 Mon Sep 17 00:00:00 2001 From: Sayaka Ono Date: Tue, 19 Nov 2024 13:47:48 -0800 Subject: [PATCH 15/29] LF-4384 Adjust batch count width in AnimalSingleViewHeader --- .../Animals/AnimalSingleViewHeader/styles.module.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/webapp/src/components/Animals/AnimalSingleViewHeader/styles.module.scss b/packages/webapp/src/components/Animals/AnimalSingleViewHeader/styles.module.scss index 29b0cb1d4a..3b319cd318 100644 --- a/packages/webapp/src/components/Animals/AnimalSingleViewHeader/styles.module.scss +++ b/packages/webapp/src/components/Animals/AnimalSingleViewHeader/styles.module.scss @@ -154,7 +154,7 @@ height: 24px; min-width: 20px; - max-width: 48px; + max-width: 44px; padding: 4px; border-radius: 2px; background: var(--Colors-Accent---singles-Purple-light); @@ -165,7 +165,7 @@ font-weight: 600; text-align: center; - /* Counts with more than six digits will be visually cut off */ + /* Counts with more than five digits will be visually cut off */ overflow: hidden; } From a5452e1134bc103908b92a78e24f5b9de5bcffd0 Mon Sep 17 00:00:00 2001 From: Sayaka Ono Date: Tue, 19 Nov 2024 14:49:34 -0800 Subject: [PATCH 16/29] LF-4384 Update getRecordIfExists middleware helper not to include removed animals --- packages/api/src/middleware/validation/checkAnimalOrBatch.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/api/src/middleware/validation/checkAnimalOrBatch.js b/packages/api/src/middleware/validation/checkAnimalOrBatch.js index 9cc5fa9faf..3d0029007e 100644 --- a/packages/api/src/middleware/validation/checkAnimalOrBatch.js +++ b/packages/api/src/middleware/validation/checkAnimalOrBatch.js @@ -396,7 +396,7 @@ const getRecordIfExists = async (animalOrBatch, animalOrBatchKey, farm_id) => { return await AnimalOrBatchModel[animalOrBatchKey] .query() .findById(animalOrBatch.id) - .where({ farm_id }) + .where({ farm_id, animal_removal_reason_id: null }) .whereNotDeleted() .withGraphFetched(relations); }; From ad65572cf795d24581397ad92a432a46667ac008 Mon Sep 17 00:00:00 2001 From: Sayaka Ono Date: Tue, 19 Nov 2024 15:30:13 -0800 Subject: [PATCH 17/29] LF-4384 Update useAnimalOrBatchRemoval to return result --- .../Inventory/useAnimalOrBatchRemoval.ts | 63 ++++++++++--------- 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/packages/webapp/src/containers/Animals/Inventory/useAnimalOrBatchRemoval.ts b/packages/webapp/src/containers/Animals/Inventory/useAnimalOrBatchRemoval.ts index 65545e1c91..c76063ca20 100644 --- a/packages/webapp/src/containers/Animals/Inventory/useAnimalOrBatchRemoval.ts +++ b/packages/webapp/src/containers/Animals/Inventory/useAnimalOrBatchRemoval.ts @@ -13,7 +13,7 @@ * GNU General Public License for more details, see . */ -import { Dispatch, SetStateAction, useState, useEffect } from 'react'; +import { Dispatch, SetStateAction, useState } from 'react'; import { useDeleteAnimalBatchesMutation, useDeleteAnimalsMutation, @@ -52,6 +52,7 @@ const useAnimalOrBatchRemoval = ( const animalBatchRemovalArray = []; const selectedAnimalIds: string[] = []; const selectedBatchIds: string[] = []; + let result; for (const id of selectedInventoryIds) { const { kind, id: entity_id } = parseInventoryId(id); @@ -74,33 +75,36 @@ const useAnimalOrBatchRemoval = ( } } - try { - if (animalRemovalArray.length) { - await mutations['removeAnimals'].trigger(animalRemovalArray).unwrap(); + if (animalRemovalArray.length) { + result = await mutations['removeAnimals'].trigger(animalRemovalArray); + + if (result.error) { + console.log(result.error); + dispatch(enqueueErrorSnackbar(t('ANIMALS.FAILED_REMOVE_ANIMALS', { ns: 'message' }))); + } else { setSelectedInventoryIds((selectedInventoryIds) => selectedInventoryIds.filter((i) => !selectedAnimalIds.includes(i)), ); dispatch(enqueueSuccessSnackbar(t('ANIMALS.SUCCESS_REMOVE_ANIMALS', { ns: 'message' }))); } - } catch (e) { - console.log(e); - dispatch(enqueueErrorSnackbar(t('ANIMALS.FAILED_REMOVE_ANIMALS', { ns: 'message' }))); } - try { - if (animalBatchRemovalArray.length) { - await mutations['removeBatches'].trigger(animalBatchRemovalArray).unwrap(); + if (animalBatchRemovalArray.length) { + result = await mutations['removeBatches'].trigger(animalBatchRemovalArray); + + if (result.error) { + console.log(result.error); + dispatch(enqueueErrorSnackbar(t('ANIMALS.FAILED_REMOVE_BATCHES', { ns: 'message' }))); + } else { setSelectedInventoryIds((selectedInventoryIds) => selectedInventoryIds.filter((i) => !selectedBatchIds.includes(i)), ); dispatch(enqueueSuccessSnackbar(t('ANIMALS.SUCCESS_REMOVE_BATCHES', { ns: 'message' }))); } - } catch (e) { - console.log(e); - dispatch(enqueueErrorSnackbar(t('ANIMALS.FAILED_REMOVE_BATCHES', { ns: 'message' }))); } setRemovalModalOpen(false); + return result; }; const handleAnimalOrBatchDeletion = async () => { @@ -108,6 +112,7 @@ const useAnimalOrBatchRemoval = ( const selectedAnimalIds: string[] = []; const animalBatchIds: number[] = []; const selectedBatchIds: string[] = []; + let result; for (const id of selectedInventoryIds) { const { kind, id: entity_id } = parseInventoryId(id); @@ -120,40 +125,42 @@ const useAnimalOrBatchRemoval = ( } } - try { - if (animalIds.length) { - await mutations['deleteAnimals'].trigger(animalIds).unwrap(); + if (animalIds.length) { + result = await mutations['deleteAnimals'].trigger(animalIds); + + if (result.error) { + console.log(result.error); + dispatch(enqueueErrorSnackbar(t('ANIMALS.FAILED_REMOVE_ANIMALS', { ns: 'message' }))); + } else { setSelectedInventoryIds((selectedInventoryIds) => selectedInventoryIds.filter((i) => !selectedAnimalIds.includes(i)), ); dispatch(enqueueSuccessSnackbar(t('ANIMALS.SUCCESS_REMOVE_ANIMALS', { ns: 'message' }))); } - } catch (e) { - console.log(e); - dispatch(enqueueErrorSnackbar(t('ANIMALS.FAILED_REMOVE_ANIMALS', { ns: 'message' }))); } - try { - if (animalBatchIds.length) { - await mutations['deleteBatches'].trigger(animalBatchIds).unwrap(); + if (animalBatchIds.length) { + result = await mutations['deleteBatches'].trigger(animalBatchIds); + if (result.error) { + console.log(result.error); + dispatch(enqueueErrorSnackbar(t('ANIMALS.FAILED_REMOVE_BATCHES', { ns: 'message' }))); + } else { setSelectedInventoryIds((selectedInventoryIds) => selectedInventoryIds.filter((i) => !selectedBatchIds.includes(i)), ); dispatch(enqueueSuccessSnackbar(t('ANIMALS.SUCCESS_REMOVE_BATCHES', { ns: 'message' }))); } - } catch (e) { - console.log(e); - dispatch(enqueueErrorSnackbar(t('ANIMALS.FAILED_REMOVE_BATCHES', { ns: 'message' }))); } setRemovalModalOpen(false); + return result; }; - const onConfirmRemoveAnimals = (formData: FormFields) => { + const onConfirmRemoveAnimals = async (formData: FormFields) => { if (Number(formData.reason) === CREATED_IN_ERROR_ID) { - handleAnimalOrBatchDeletion(); + return handleAnimalOrBatchDeletion(); } else { - handleAnimalOrBatchRemoval(formData); + return handleAnimalOrBatchRemoval(formData); } }; From 8c432135898c5c648dd6e9aab09e017695bc8709 Mon Sep 17 00:00:00 2001 From: Sayaka Ono Date: Tue, 19 Nov 2024 15:32:38 -0800 Subject: [PATCH 18/29] LF-4384 Update onConfirmRemoval in SingleAnimalView to call history.back only after successful API call --- .../src/containers/Animals/SingleAnimalView/index.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx b/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx index a72ce08bd2..bca7adfb13 100644 --- a/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx +++ b/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx @@ -177,9 +177,12 @@ function SingleAnimalView({ isCompactSideMenu, history, match, location }: AddAn () => ({}), ); - const onConfirmRemoval = (formData: FormFields) => { - onConfirmRemoveAnimals(formData); - history.back(); + const onConfirmRemoval = async (formData: FormFields) => { + const result = await onConfirmRemoveAnimals(formData); + + if (!result.error) { + history.back(); + } }; return ( From b9d72e35b1ee979ebbf9a52cd31c2e523eb2e049 Mon Sep 17 00:00:00 2001 From: Sayaka Ono Date: Tue, 19 Nov 2024 15:41:39 -0800 Subject: [PATCH 19/29] LF-4384 Hide meatballs menu for removed animals --- .../Animals/AnimalSingleViewHeader/index.tsx | 18 ++++++++++++------ .../Animals/SingleAnimalView/index.tsx | 3 +++ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/packages/webapp/src/components/Animals/AnimalSingleViewHeader/index.tsx b/packages/webapp/src/components/Animals/AnimalSingleViewHeader/index.tsx index 75a266aa79..ca62ad45bd 100644 --- a/packages/webapp/src/components/Animals/AnimalSingleViewHeader/index.tsx +++ b/packages/webapp/src/components/Animals/AnimalSingleViewHeader/index.tsx @@ -83,6 +83,7 @@ type ContainerWithButtonsProps = { children: ReactNode; contentClassName?: string; isCompactView?: boolean; + hideMenu: boolean; isEditing?: boolean; options: { label: ReactNode; onClick: () => void }[]; onBack: () => void; @@ -93,6 +94,7 @@ const ContainerWithButtons = ({ children, contentClassName, isCompactView, + hideMenu, isEditing, options, onBack, @@ -106,17 +108,20 @@ const ContainerWithButtons = ({
{children}
{!isCompactView && isEditing ?
{t('common:EDITING')}
: null} - + {!hideMenu && ( + + )}
); }; export type AnimalSingleViewHeaderProps = { + hideMenu: boolean; isEditing?: boolean; onEdit: () => void; onRemove: () => void; @@ -129,6 +134,7 @@ export type AnimalSingleViewHeaderProps = { }; const AnimalSingleViewHeader = ({ + hideMenu, isEditing, onEdit, onRemove, @@ -164,7 +170,7 @@ const AnimalSingleViewHeader = ({ { label: , onClick: onRemove }, ]; - const commonProp = { t, isEditing, isCompactView, options: menuOptions, onBack }; + const commonProp = { t, hideMenu, isEditing, isCompactView, options: menuOptions, onBack }; const renderCompactHeader = () => (
diff --git a/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx b/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx index bca7adfb13..6057a54482 100644 --- a/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx +++ b/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx @@ -101,6 +101,8 @@ function SingleAnimalView({ isCompactSideMenu, history, match, location }: AddAn location, }); + const isRemoved = !!defaultFormValues.animal_removal_reason_id; + useEffect(() => { if (!selectedAnimal && !selectedBatch) { history.replace('/unknown_record'); @@ -193,6 +195,7 @@ function SingleAnimalView({ isCompactSideMenu, history, match, location }: AddAn <> {defaultFormValues && ( setRemovalModalOpen(true)} isEditing={isEditing} From 196e475c06a92dff56fb0634bb75e7e7d9d2cfb6 Mon Sep 17 00:00:00 2001 From: Sayaka Ono Date: Thu, 21 Nov 2024 13:42:00 -0800 Subject: [PATCH 20/29] LF-4384 Hide single animal view menu for non-admin users --- .../src/containers/Animals/SingleAnimalView/index.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx b/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx index 6057a54482..7d8fc7adeb 100644 --- a/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx +++ b/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx @@ -15,7 +15,7 @@ import { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { useDispatch } from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; import styles from './styles.module.scss'; import { ContextForm, Variant } from '../../../components/Form/ContextForm/'; import { enqueueErrorSnackbar, enqueueSuccessSnackbar } from '../../Snackbar/snackbarSlice'; @@ -45,6 +45,7 @@ import RemoveAnimalsModal, { FormFields } from '../../../components/Animals/Remo import useAnimalOrBatchRemoval from '../Inventory/useAnimalOrBatchRemoval'; import { generateInventoryId } from '../../../util/animal'; import { CustomRouteComponentProps } from '../../../types'; +import { isAdminSelector } from '../../userFarmSlice'; export const STEPS = { DETAILS: 'details', @@ -69,6 +70,8 @@ function SingleAnimalView({ isCompactSideMenu, history, match, location }: AddAn const [isEditing, setIsEditing] = useState(false); + const isAdmin = useSelector(isAdminSelector); + const initiateEdit = () => { setIsEditing(true); }; @@ -195,7 +198,7 @@ function SingleAnimalView({ isCompactSideMenu, history, match, location }: AddAn <> {defaultFormValues && ( setRemovalModalOpen(true)} isEditing={isEditing} From 035f8e788056aaa9200efa98c5bf210ce4fea7b5 Mon Sep 17 00:00:00 2001 From: Sayaka Ono Date: Thu, 21 Nov 2024 14:33:51 -0800 Subject: [PATCH 21/29] LF-4384 Fix crashing * remove onGoForward from onSave in SingleAnimalView * reset with saved data when saving the form in WithStepperProgressBar --- .../Form/ContextForm/WithStepperProgressBar.tsx | 13 +++++++++++-- .../containers/Animals/SingleAnimalView/index.tsx | 2 -- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/webapp/src/components/Form/ContextForm/WithStepperProgressBar.tsx b/packages/webapp/src/components/Form/ContextForm/WithStepperProgressBar.tsx index f615442148..23b81438d4 100644 --- a/packages/webapp/src/components/Form/ContextForm/WithStepperProgressBar.tsx +++ b/packages/webapp/src/components/Form/ContextForm/WithStepperProgressBar.tsx @@ -13,8 +13,14 @@ * GNU General Public License for more details, see . */ -import { ReactNode, useEffect, useRef, useState } from 'react'; -import { UseFormHandleSubmit, FieldValues, FormState, UseFormReset } from 'react-hook-form'; +import { ReactNode, useEffect, useState } from 'react'; +import { + UseFormHandleSubmit, + FieldValues, + FormState, + UseFormReset, + UseFormGetValues, +} from 'react-hook-form'; import { History } from 'history'; import StepperProgressBar from '../../StepperProgressBar'; import FloatingContainer from '../../FloatingContainer'; @@ -45,6 +51,7 @@ interface WithStepperProgressBarProps { onCancel: () => void; onGoForward: () => void; reset: UseFormReset; + getValues: UseFormGetValues; formState: FormState; handleSubmit: UseFormHandleSubmit; setFormResultData: (data: any) => void; @@ -70,6 +77,7 @@ export const WithStepperProgressBar = ({ onGoForward, handleSubmit, reset, + getValues, formState: { isValid, isDirty }, setFormResultData, isEditing, @@ -109,6 +117,7 @@ export const WithStepperProgressBar = ({ if (isFinalStep) { setIsSaving(true); await handleSubmit((data: FieldValues) => onSave(data, onGoForward, setFormResultData))(); + reset(getValues()); setIsSaving(false); setIsEditing?.(false); return; diff --git a/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx b/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx index 7d8fc7adeb..6dd7d93cfd 100644 --- a/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx +++ b/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx @@ -164,8 +164,6 @@ function SingleAnimalView({ isCompactSideMenu, history, match, location }: AddAn console.error(e); dispatch(enqueueErrorSnackbar(t('message:ANIMALS.FAILED_UPDATE_BATCH'))); } - - onGoForward(); }; const getInventoryId = () => { From e599d65c9a722bfe4ee94b7c3bbc0592a1f4e0f5 Mon Sep 17 00:00:00 2001 From: Sayaka Ono Date: Mon, 25 Nov 2024 14:19:42 -0800 Subject: [PATCH 22/29] LF-4384 Fix uses not being rendered after logging in * Update useInitialAnimalData hook - return isFetchingAnimalsOrBatches - return defaultFormValues when ready * Update SingleAnimalView - avoid redirecting to UnknownRecord during fetching animals - render form when default values are ready --- .../Animals/SingleAnimalView/index.tsx | 41 ++++---- .../SingleAnimalView/useInitialAnimalData.ts | 95 ++++++++++++------- 2 files changed, 85 insertions(+), 51 deletions(-) diff --git a/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx b/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx index 6dd7d93cfd..b430bce8c3 100644 --- a/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx +++ b/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx @@ -98,16 +98,17 @@ function SingleAnimalView({ isCompactSideMenu, history, match, location }: AddAn }, ]; - const { defaultFormValues, selectedAnimal, selectedBatch } = useInitialAnimalData({ - history, - match, - location, - }); + const { defaultFormValues, selectedAnimal, selectedBatch, isFetchingAnimalsOrBatches } = + useInitialAnimalData({ + history, + match, + location, + }); - const isRemoved = !!defaultFormValues.animal_removal_reason_id; + const isRemoved = !!defaultFormValues?.animal_removal_reason_id; useEffect(() => { - if (!selectedAnimal && !selectedBatch) { + if (!isFetchingAnimalsOrBatches && !selectedAnimal && !selectedBatch) { history.replace('/unknown_record'); } }, [selectedAnimal, selectedBatch, history]); @@ -218,18 +219,20 @@ function SingleAnimalView({ isCompactSideMenu, history, match, location }: AddAn } > - + {defaultFormValues && ( + + )} setRemovalModalOpen(false)} diff --git a/packages/webapp/src/containers/Animals/SingleAnimalView/useInitialAnimalData.ts b/packages/webapp/src/containers/Animals/SingleAnimalView/useInitialAnimalData.ts index b8b2fa3645..bdacc43c62 100644 --- a/packages/webapp/src/containers/Animals/SingleAnimalView/useInitialAnimalData.ts +++ b/packages/webapp/src/containers/Animals/SingleAnimalView/useInitialAnimalData.ts @@ -13,6 +13,7 @@ * GNU General Public License for more details, see . */ +import { useMemo } from 'react'; import { useGetAnimalBatchesQuery, useGetAnimalsQuery } from '../../../store/api/apiSlice'; import { useAnimalOptions } from '../AddAnimals/useAnimalOptions'; import { DetailsFields } from '../AddAnimals/types'; @@ -28,17 +29,19 @@ interface RouteParams { interface UseInitialAnimalDataProps extends CustomRouteComponentProps {} export const useInitialAnimalData = ({ match }: UseInitialAnimalDataProps) => { - const { selectedAnimal } = useGetAnimalsQuery(undefined, { - selectFromResult: ({ data }) => ({ + const { selectedAnimal, isFetchingAnimals } = useGetAnimalsQuery(undefined, { + selectFromResult: ({ data, isFetching }) => ({ selectedAnimal: data?.find( (animal) => animal.internal_identifier === Number(match.params.id), ), + isFetchingAnimals: isFetching, }), }); - const { selectedBatch } = useGetAnimalBatchesQuery(undefined, { - selectFromResult: ({ data }) => ({ + const { selectedBatch, isFetchingBatches } = useGetAnimalBatchesQuery(undefined, { + selectFromResult: ({ data, isFetching }) => ({ selectedBatch: data?.find((batch) => batch.internal_identifier === Number(match.params.id)), + isFetchingBatches: isFetching, }), }); @@ -60,6 +63,16 @@ export const useInitialAnimalData = ({ match }: UseInitialAnimalDataProps) => { 'tagColor', ); + const isOptionsLoading = [ + sexDetailsOptions, + animalUseOptions, + typeOptions, + breedOptions, + organicStatusOptions, + tagTypeOptions, + tagColorOptions, + ].some((config) => config.length === 0); + const otherAnimalUse = selectedAnimal?.animal_use_relationships?.find( (relationship) => relationship?.other_use !== null, @@ -114,33 +127,51 @@ export const useInitialAnimalData = ({ match }: UseInitialAnimalDataProps) => { ), }; - const defaultFormValues = { - ...(selectedAnimal - ? { - ...selectedAnimal, - ...commonFields, - [DetailsFields.ANIMAL_OR_BATCH]: AnimalOrBatchKeys.ANIMAL, - [DetailsFields.WEANING_DATE]: generateFormDate(selectedAnimal.weaning_date), - [DetailsFields.USE]: mapUses(selectedAnimal?.animal_use_relationships ?? []), - [DetailsFields.TAG_TYPE]: tagTypeOptions.find( - ({ value }) => value === selectedAnimal?.identifier_type_id, - ), - [DetailsFields.TAG_COLOR]: tagColorOptions.find( - ({ value }) => value === selectedAnimal?.identifier_color_id, - ), - } - : {}), - ...(selectedBatch - ? { - ...selectedBatch, - ...commonFields, - [DetailsFields.ANIMAL_OR_BATCH]: AnimalOrBatchKeys.BATCH, - [DetailsFields.SEX_DETAILS]: transformedSexDetails, - [DetailsFields.BATCH_NAME]: selectedBatch.name, - [DetailsFields.USE]: mapUses(selectedBatch?.animal_batch_use_relationships ?? []), - } - : {}), - }; + const defaultFormValues = useMemo(() => { + if (isOptionsLoading || !selectedEntity) { + return null; + } - return { defaultFormValues, selectedAnimal, selectedBatch }; + return { + ...(selectedAnimal + ? { + ...selectedAnimal, + ...commonFields, + [DetailsFields.ANIMAL_OR_BATCH]: AnimalOrBatchKeys.ANIMAL, + [DetailsFields.WEANING_DATE]: generateFormDate(selectedAnimal.weaning_date), + [DetailsFields.USE]: mapUses(selectedAnimal?.animal_use_relationships ?? []), + [DetailsFields.TAG_TYPE]: tagTypeOptions.find( + ({ value }) => value === selectedAnimal?.identifier_type_id, + ), + [DetailsFields.TAG_COLOR]: tagColorOptions.find( + ({ value }) => value === selectedAnimal?.identifier_color_id, + ), + } + : {}), + ...(selectedBatch + ? { + ...selectedBatch, + ...commonFields, + [DetailsFields.ANIMAL_OR_BATCH]: AnimalOrBatchKeys.BATCH, + [DetailsFields.SEX_DETAILS]: transformedSexDetails, + [DetailsFields.BATCH_NAME]: selectedBatch.name, + [DetailsFields.USE]: mapUses(selectedBatch?.animal_batch_use_relationships ?? []), + } + : {}), + }; + }, [ + isOptionsLoading, + selectedEntity, + commonFields, + transformedSexDetails, + tagTypeOptions, + tagColorOptions, + ]); + + return { + defaultFormValues, + selectedAnimal, + selectedBatch, + isFetchingAnimalsOrBatches: isFetchingAnimals || isFetchingBatches, + }; }; From 9241b042ea4c9373f42a12752b5883da0a4f4e21 Mon Sep 17 00:00:00 2001 From: Sayaka Ono Date: Mon, 25 Nov 2024 14:27:52 -0800 Subject: [PATCH 23/29] LF-4384 Update prop name hideMenu to showMenu for showing meatballs menu --- .../Animals/AnimalSingleViewHeader/index.tsx | 12 ++++++------ .../containers/Animals/SingleAnimalView/index.tsx | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/webapp/src/components/Animals/AnimalSingleViewHeader/index.tsx b/packages/webapp/src/components/Animals/AnimalSingleViewHeader/index.tsx index ca62ad45bd..4d5249bf31 100644 --- a/packages/webapp/src/components/Animals/AnimalSingleViewHeader/index.tsx +++ b/packages/webapp/src/components/Animals/AnimalSingleViewHeader/index.tsx @@ -83,7 +83,7 @@ type ContainerWithButtonsProps = { children: ReactNode; contentClassName?: string; isCompactView?: boolean; - hideMenu: boolean; + showMenu: boolean; isEditing?: boolean; options: { label: ReactNode; onClick: () => void }[]; onBack: () => void; @@ -94,7 +94,7 @@ const ContainerWithButtons = ({ children, contentClassName, isCompactView, - hideMenu, + showMenu = true, isEditing, options, onBack, @@ -108,7 +108,7 @@ const ContainerWithButtons = ({
{children}
{!isCompactView && isEditing ?
{t('common:EDITING')}
: null} - {!hideMenu && ( + {showMenu && ( void; onRemove: () => void; @@ -134,7 +134,7 @@ export type AnimalSingleViewHeaderProps = { }; const AnimalSingleViewHeader = ({ - hideMenu, + showMenu = true, isEditing, onEdit, onRemove, @@ -170,7 +170,7 @@ const AnimalSingleViewHeader = ({ { label: , onClick: onRemove }, ]; - const commonProp = { t, hideMenu, isEditing, isCompactView, options: menuOptions, onBack }; + const commonProp = { t, showMenu, isEditing, isCompactView, options: menuOptions, onBack }; const renderCompactHeader = () => (
diff --git a/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx b/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx index b430bce8c3..0693cbca94 100644 --- a/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx +++ b/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx @@ -197,7 +197,7 @@ function SingleAnimalView({ isCompactSideMenu, history, match, location }: AddAn <> {defaultFormValues && ( setRemovalModalOpen(true)} isEditing={isEditing} From 4d9fcc680294a9d77315274366285213c05b4439 Mon Sep 17 00:00:00 2001 From: Sayaka Ono Date: Mon, 25 Nov 2024 14:58:46 -0800 Subject: [PATCH 24/29] LF-4384 Refactor and create StepperProgressBarWrapper --- .../ContextForm/WithStepperProgressBar.tsx | 46 +++++++++++-------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/packages/webapp/src/components/Form/ContextForm/WithStepperProgressBar.tsx b/packages/webapp/src/components/Form/ContextForm/WithStepperProgressBar.tsx index 23b81438d4..6946600d03 100644 --- a/packages/webapp/src/components/Form/ContextForm/WithStepperProgressBar.tsx +++ b/packages/webapp/src/components/Form/ContextForm/WithStepperProgressBar.tsx @@ -22,7 +22,7 @@ import { UseFormGetValues, } from 'react-hook-form'; import { History } from 'history'; -import StepperProgressBar from '../../StepperProgressBar'; +import StepperProgressBar, { StepperProgressBarProps } from '../../StepperProgressBar'; import FloatingContainer from '../../FloatingContainer'; import FormNavigationButtons from '../FormNavigationButtons'; import FixedHeaderContainer from '../../Animals/FixedHeaderContainer'; @@ -142,8 +142,14 @@ export const WithStepperProgressBar = ({ setShowCancelFlow?.(false); }; - const renderContent = () => ( - <> + return ( + title)} + activeStep={activeStepIndex} + >
{children}
{shouldShowFormNavigationButtons && ( @@ -164,23 +170,27 @@ export const WithStepperProgressBar = ({ handleCancel={handleCancel} /> )} - +
); +}; - return isSingleStep ? ( - renderContent() - ) : ( - title)} - activeStep={activeStepIndex} - /> - } - > - {renderContent()} +type StepperProgressBarWrapperProps = StepperProgressBarProps & { + children: ReactNode; + isSingleStep: boolean; +}; + +const StepperProgressBarWrapper = ({ + children, + isSingleStep, + ...stepperProgressBarProps +}: StepperProgressBarWrapperProps) => { + if (isSingleStep) { + return <>{children}; + } + + return ( + }> + {children} ); }; From a46d530f2158bd6cb8efa3b63a0c59fa8d48a24a Mon Sep 17 00:00:00 2001 From: Sayaka Ono Date: Mon, 25 Nov 2024 15:19:04 -0800 Subject: [PATCH 25/29] LF-4384 Make setSelectedInventoryIds prop optional in useAnimalOrBatchRemoval hook --- .../Animals/Inventory/useAnimalOrBatchRemoval.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/webapp/src/containers/Animals/Inventory/useAnimalOrBatchRemoval.ts b/packages/webapp/src/containers/Animals/Inventory/useAnimalOrBatchRemoval.ts index c76063ca20..0c2d16555f 100644 --- a/packages/webapp/src/containers/Animals/Inventory/useAnimalOrBatchRemoval.ts +++ b/packages/webapp/src/containers/Animals/Inventory/useAnimalOrBatchRemoval.ts @@ -31,7 +31,7 @@ import { useTranslation } from 'react-i18next'; const useAnimalOrBatchRemoval = ( selectedInventoryIds: string[], - setSelectedInventoryIds: Dispatch>, + setSelectedInventoryIds?: Dispatch>, ) => { const dispatch = useDispatch(); const { t } = useTranslation(['message']); @@ -82,7 +82,7 @@ const useAnimalOrBatchRemoval = ( console.log(result.error); dispatch(enqueueErrorSnackbar(t('ANIMALS.FAILED_REMOVE_ANIMALS', { ns: 'message' }))); } else { - setSelectedInventoryIds((selectedInventoryIds) => + setSelectedInventoryIds?.((selectedInventoryIds) => selectedInventoryIds.filter((i) => !selectedAnimalIds.includes(i)), ); dispatch(enqueueSuccessSnackbar(t('ANIMALS.SUCCESS_REMOVE_ANIMALS', { ns: 'message' }))); @@ -96,7 +96,7 @@ const useAnimalOrBatchRemoval = ( console.log(result.error); dispatch(enqueueErrorSnackbar(t('ANIMALS.FAILED_REMOVE_BATCHES', { ns: 'message' }))); } else { - setSelectedInventoryIds((selectedInventoryIds) => + setSelectedInventoryIds?.((selectedInventoryIds) => selectedInventoryIds.filter((i) => !selectedBatchIds.includes(i)), ); dispatch(enqueueSuccessSnackbar(t('ANIMALS.SUCCESS_REMOVE_BATCHES', { ns: 'message' }))); @@ -132,7 +132,7 @@ const useAnimalOrBatchRemoval = ( console.log(result.error); dispatch(enqueueErrorSnackbar(t('ANIMALS.FAILED_REMOVE_ANIMALS', { ns: 'message' }))); } else { - setSelectedInventoryIds((selectedInventoryIds) => + setSelectedInventoryIds?.((selectedInventoryIds) => selectedInventoryIds.filter((i) => !selectedAnimalIds.includes(i)), ); dispatch(enqueueSuccessSnackbar(t('ANIMALS.SUCCESS_REMOVE_ANIMALS', { ns: 'message' }))); @@ -145,7 +145,7 @@ const useAnimalOrBatchRemoval = ( console.log(result.error); dispatch(enqueueErrorSnackbar(t('ANIMALS.FAILED_REMOVE_BATCHES', { ns: 'message' }))); } else { - setSelectedInventoryIds((selectedInventoryIds) => + setSelectedInventoryIds?.((selectedInventoryIds) => selectedInventoryIds.filter((i) => !selectedBatchIds.includes(i)), ); dispatch(enqueueSuccessSnackbar(t('ANIMALS.SUCCESS_REMOVE_BATCHES', { ns: 'message' }))); From 9021d49e3292f940e40430576254227210f777ef Mon Sep 17 00:00:00 2001 From: Sayaka Ono Date: Mon, 25 Nov 2024 15:24:56 -0800 Subject: [PATCH 26/29] LF-4384 Remove unnecessary code in SingleAnimalView --- .../webapp/src/containers/Animals/SingleAnimalView/index.tsx | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx b/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx index 0693cbca94..8347ec5a2e 100644 --- a/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx +++ b/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx @@ -168,17 +168,12 @@ function SingleAnimalView({ isCompactSideMenu, history, match, location }: AddAn }; const getInventoryId = () => { - if (!selectedAnimal && !selectedBatch) { - return ''; - } - const animalOrBatch = AnimalOrBatchKeys[selectedAnimal ? 'ANIMAL' : 'BATCH']; return generateInventoryId(animalOrBatch, (selectedAnimal || selectedBatch)!); }; const { onConfirmRemoveAnimals, removalModalOpen, setRemovalModalOpen } = useAnimalOrBatchRemoval( [getInventoryId()], - () => ({}), ); const onConfirmRemoval = async (formData: FormFields) => { From d7ed7096cda30ad33961ae6fb43305780b2479f6 Mon Sep 17 00:00:00 2001 From: Sayaka Ono Date: Wed, 27 Nov 2024 00:30:49 -0800 Subject: [PATCH 27/29] LF-4384 Update onSave callback in WithStepperProgressBar * handle onGoForward within the component * properly handle success actions --- .../Form/ContextForm/WithStepperProgressBar.tsx | 15 +++++++++++---- .../src/containers/Animals/AddAnimals/index.tsx | 4 ++-- .../containers/Animals/SingleAnimalView/index.tsx | 4 +++- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/packages/webapp/src/components/Form/ContextForm/WithStepperProgressBar.tsx b/packages/webapp/src/components/Form/ContextForm/WithStepperProgressBar.tsx index 6946600d03..14aeefc977 100644 --- a/packages/webapp/src/components/Form/ContextForm/WithStepperProgressBar.tsx +++ b/packages/webapp/src/components/Form/ContextForm/WithStepperProgressBar.tsx @@ -44,7 +44,7 @@ interface WithStepperProgressBarProps { stepperProgressBarTitle?: ReactNode; onSave: ( data: FieldValues, - onGoForward: () => void, + onSuccess: () => void, setFormResultData?: (data: any) => void, ) => void; onGoBack: () => void; @@ -113,13 +113,20 @@ export const WithStepperProgressBar = ({ const shouldShowFormNavigationButtons = !isSummaryPage && isEditing; + const onSuccess = () => { + reset(getValues()); + setIsEditing?.(false); + + if (hasSummaryWithinForm) { + onGoForward(); + } + }; + const onContinue = async () => { if (isFinalStep) { setIsSaving(true); - await handleSubmit((data: FieldValues) => onSave(data, onGoForward, setFormResultData))(); - reset(getValues()); + await handleSubmit((data: FieldValues) => onSave(data, onSuccess, setFormResultData))(); setIsSaving(false); - setIsEditing?.(false); return; } onGoForward(); diff --git a/packages/webapp/src/containers/Animals/AddAnimals/index.tsx b/packages/webapp/src/containers/Animals/AddAnimals/index.tsx index f85247650f..46fd696cb6 100644 --- a/packages/webapp/src/containers/Animals/AddAnimals/index.tsx +++ b/packages/webapp/src/containers/Animals/AddAnimals/index.tsx @@ -55,7 +55,7 @@ function AddAnimals({ isCompactSideMenu, history }: AddAnimalsProps) { const onSave = async ( data: any, - onGoForward: () => void, + onSuccess: () => void, setFormResultData: (data: any) => void, ) => { const details = data[STEPS.DETAILS] as AnimalDetailsFormFields[]; @@ -99,7 +99,7 @@ function AddAnimals({ isCompactSideMenu, history }: AddAnimalsProps) { } setFormResultData({ animals: animalsResult, batches: batchesResult }); - onGoForward(); + onSuccess(); }; const getFormSteps = () => [ diff --git a/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx b/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx index 8347ec5a2e..2ca3591a7b 100644 --- a/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx +++ b/packages/webapp/src/containers/Animals/SingleAnimalView/index.tsx @@ -121,7 +121,7 @@ function SingleAnimalView({ isCompactSideMenu, history, match, location }: AddAn const onSave = async ( data: AnimalDetailsFormFields & Partial, - onGoForward: () => void, + onSuccess: () => void, _setFormResultData: () => void, ) => { const broughtInId = orgins.find((origin) => origin.key === 'BROUGHT_IN')?.id; @@ -151,6 +151,7 @@ function SingleAnimalView({ isCompactSideMenu, history, match, location }: AddAn if (formattedAnimals.length) { await updateAnimals(formattedAnimals).unwrap(); dispatch(enqueueSuccessSnackbar(t('message:ANIMALS.SUCCESS_UPDATE_ANIMAL'))); + onSuccess(); } } catch (e) { console.error(e); @@ -160,6 +161,7 @@ function SingleAnimalView({ isCompactSideMenu, history, match, location }: AddAn if (formattedBatches.length) { await updateBatches(formattedBatches).unwrap(); dispatch(enqueueSuccessSnackbar(t('message:ANIMALS.SUCCESS_UPDATE_BATCH'))); + onSuccess(); } } catch (e) { console.error(e); From ebde1a2cbfc8bcc0e10917d6492b32726761ec0b Mon Sep 17 00:00:00 2001 From: Sayaka Ono Date: Wed, 27 Nov 2024 09:47:13 -0800 Subject: [PATCH 28/29] LF-4384 Remove setActiveStepIndex(0) in onSave in ContextForm --- packages/webapp/src/components/Form/ContextForm/index.tsx | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/webapp/src/components/Form/ContextForm/index.tsx b/packages/webapp/src/components/Form/ContextForm/index.tsx index 7695424a8c..9b9cdae4fb 100644 --- a/packages/webapp/src/components/Form/ContextForm/index.tsx +++ b/packages/webapp/src/components/Form/ContextForm/index.tsx @@ -45,7 +45,6 @@ export const ContextForm = ({ variant = Variant.PAGE_TITLE, isEditing = true, setIsEditing, - onSave, ...props }: ContextFormProps) => { const [activeStepIndex, setActiveStepIndex] = useState(0); @@ -108,10 +107,6 @@ export const ContextForm = ({ setIsEditing={setIsEditing} showCancelFlow={showCancelFlow} setShowCancelFlow={setShowCancelFlow} - onSave={(...args: any) => { - setActiveStepIndex(0); - onSave?.(...args); - }} {...form} {...props} > From 2325f804dd1cfeeb3953ecc3a88895cf05b579a6 Mon Sep 17 00:00:00 2001 From: Sayaka Ono Date: Wed, 27 Nov 2024 09:54:51 -0800 Subject: [PATCH 29/29] LF-4384 Update AnimalBreedSelect to replace undefined with null as value --- .../src/components/Animals/AddAnimalsFormCard/AnimalSelect.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/webapp/src/components/Animals/AddAnimalsFormCard/AnimalSelect.tsx b/packages/webapp/src/components/Animals/AddAnimalsFormCard/AnimalSelect.tsx index 0d8aec2295..6be4ebe646 100644 --- a/packages/webapp/src/components/Animals/AddAnimalsFormCard/AnimalSelect.tsx +++ b/packages/webapp/src/components/Animals/AddAnimalsFormCard/AnimalSelect.tsx @@ -96,7 +96,7 @@ export function AnimalBreedSelect({ placeholder={isTypeSelected ? undefined : t('ADD_ANIMAL.BREED_PLACEHOLDER_DISABLED')} isDisabled={!isTypeSelected || isDisabled} onChange={(option) => onChange(option)} - value={value} + value={value || null} /> )} />