Skip to content

Commit

Permalink
Merge pull request #3378 from LiteFarmOrg/LF-4159-create-animal-creat…
Browse files Browse the repository at this point in the history
…ion-details-views-for-animal-batch

LF-4159 Create animal creation details views for animal batch
  • Loading branch information
SayakaOno authored Aug 16, 2024
2 parents a4535e0 + 559106f commit 8e5913e
Show file tree
Hide file tree
Showing 13 changed files with 290 additions and 38 deletions.
3 changes: 3 additions & 0 deletions packages/webapp/public/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,13 @@
"CREATE_INDIVIDUAL_PROFILES": "Create individual animal profiles",
"CREATE_INDIVIDUAL_PROFILES_TOOLTIP": "Select this option if you want to track and manage each animal separately. This allows for detailed records and individualised care plans, all animals will be conveniently grouped. If you don't select 'Create Individual Animal Profiles' you'll create an Animal Batch. This is ideal for\u00a0managing animals collectively. In batch mode, individual animal details are not tracked.",
"GENERAL_DETAILS": "General details",
"GENERAL_DETAILS_BATCH": "Batch general details",
"GROUP_NAME": "Group name",
"GROUP_NAME_PLACEHOLDER": "Type in group name",
"ORIGIN": "Origin",
"ORIGIN_BATCH": "Batch origin",
"OTHER_DETAILS": "Other details",
"OTHER_DETAILS_BATCH": "Batch other details",
"OUT_OF_COUNT_one": "{{animalNumber}} out of {{count}}",
"OUT_OF_COUNT_other": "{{animalNumber}} out of {{count}}",
"PLACEHOLDER": {
Expand Down
3 changes: 3 additions & 0 deletions packages/webapp/public/locales/es/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,13 @@
"CREATE_INDIVIDUAL_PROFILES": "MISSING",
"CREATE_INDIVIDUAL_PROFILES_TOOLTIP": "MISSING",
"GENERAL_DETAILS": "MISSING",
"GENERAL_DETAILS_BATCH": "MISSING",
"GROUP_NAME": "MISSING",
"GROUP_NAME_PLACEHOLDER": "MISSING",
"ORIGIN": "MISSING",
"ORIGIN_BATCH": "MISSING",
"OTHER_DETAILS": "MISSING",
"OTHER_DETAILS_BATCH": "MISSING",
"OUT_OF_COUNT_one": "MISSING",
"OUT_OF_COUNT_many": "MISSING",
"OUT_OF_COUNT_other": "MISSING",
Expand Down
3 changes: 3 additions & 0 deletions packages/webapp/public/locales/fr/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,13 @@
"CREATE_INDIVIDUAL_PROFILES": "MISSING",
"CREATE_INDIVIDUAL_PROFILES_TOOLTIP": "MISSING",
"GENERAL_DETAILS": "MISSING",
"GENERAL_DETAILS_BATCH": "MISSING",
"GROUP_NAME": "MISSING",
"GROUP_NAME_PLACEHOLDER": "MISSING",
"ORIGIN": "MISSING",
"ORIGIN_BATCH": "MISSING",
"OTHER_DETAILS": "MISSING",
"OTHER_DETAILS_BATCH": "MISSING",
"OUT_OF_COUNT_one": "MISSING",
"OUT_OF_COUNT_many": "MISSING",
"OUT_OF_COUNT_other": "MISSING",
Expand Down
3 changes: 3 additions & 0 deletions packages/webapp/public/locales/pt/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,13 @@
"CREATE_INDIVIDUAL_PROFILES": "MISSING",
"CREATE_INDIVIDUAL_PROFILES_TOOLTIP": "MISSING",
"GENERAL_DETAILS": "MISSING",
"GENERAL_DETAILS_BATCH": "MISSING",
"GROUP_NAME": "MISSING",
"GROUP_NAME_PLACEHOLDER": "MISSING",
"ORIGIN": "MISSING",
"ORIGIN_BATCH": "MISSING",
"OTHER_DETAILS": "MISSING",
"OTHER_DETAILS_BATCH": "MISSING",
"OUT_OF_COUNT_one": "MISSING",
"OUT_OF_COUNT_many": "MISSING",
"OUT_OF_COUNT_other": "MISSING",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,36 +19,40 @@ import Input, { getInputErrors } from '../../Form/Input';
import RadioGroup from '../../Form/RadioGroup';
import ReactSelect from '../../Form/ReactSelect';
import InputBaseLabel from '../../Form/InputBase/InputBaseLabel';
import NumberInput from '../../Form/NumberInput';
import SexDetails from '../../Form/SexDetails';
import { type Details as SexDetailsType } from '../../Form/SexDetails/SexDetailsPopover';
import { AnimalOrBatchKeys } from '../../../containers/Animals/types';
import { DetailsFields, type Option, type CommonDetailsProps } from './type';
import styles from './styles.module.scss';
import { hookFormMaxCharsValidation } from '../../Form/hookformValidationUtils';

export type GeneralDetailsProps = CommonDetailsProps & {
typeOptions: Option[DetailsFields.TYPE][];
breedOptions: Option[DetailsFields.BREED][];
sexOptions: Option[DetailsFields.SEX][];
useOptions: Option[DetailsFields.USE][];
animalOrBatch: AnimalOrBatchKeys;
isOtherUseSelected?: boolean;
sexDetailsOptions?: SexDetailsType;
};

const GeneralDetails = ({
t,
typeOptions,
breedOptions,
sexOptions,
useOptions,
animalOrBatch,
isOtherUseSelected,
sexDetailsOptions,
}: GeneralDetailsProps) => {
const {
control,
register,
trigger,
watch,
formState: { errors },
} = useFormContext();

const watchBatchCount = watch(DetailsFields.COUNT) || 0;

const sexInputs = useMemo(() => {
if (animalOrBatch === AnimalOrBatchKeys.ANIMAL) {
return (
Expand All @@ -66,8 +70,32 @@ const GeneralDetails = ({
</>
);
}
return 'TODO: LF-4159';
}, [animalOrBatch, t, sexOptions, control]);

return (
<div className={styles.countAndSexDetailsWrapper}>
<NumberInput
name={DetailsFields.COUNT}
control={control}
defaultValue={0}
label={t('common:COUNT')}
className={styles.countInput}
allowDecimal={false}
showStepper
/>
<Controller
name={DetailsFields.SEX_DETAILS}
control={control}
render={({ field }) => (
<SexDetails
initialDetails={sexDetailsOptions!}
maxCount={watchBatchCount}
onConfirm={(details) => field.onChange(details)}
/>
)}
/>
</div>
);
}, [animalOrBatch, t, sexOptions, control, watchBatchCount]);

return (
<div className={styles.sectionWrapper}>
Expand Down Expand Up @@ -95,7 +123,7 @@ const GeneralDetails = ({
label={t('ANIMAL.ANIMAL_TYPE')}
value={value}
onChange={onChange}
options={typeOptions}
isDisabled
/>
)}
/>
Expand All @@ -108,7 +136,7 @@ const GeneralDetails = ({
optional
value={value}
onChange={onChange}
options={breedOptions}
isDisabled
/>
)}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ const AnimalDetails = ({
<ExpandableItem
itemKey={key}
isExpanded={isExpanded}
iconClickOnly={false}
onClick={() => toggleExpanded(key)}
mainContent={title}
expandedContent={<div className={styles.expandedContentWrapper}>{content}</div>}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,16 @@
flex-direction: column;
gap: 16px;
}

.countAndSexDetailsWrapper {
display: flex;
align-items: start;
gap: 16px;
}

.countInput {
flex-basis: 104px;
& + div {
flex: 1;
}
}
11 changes: 7 additions & 4 deletions packages/webapp/src/components/Animals/AddAnimalsDetails/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import { UseFormReturn } from 'react-hook-form';
import { TFunction } from 'react-i18next';
import { Option as AnimalSelectOption } from '../AddAnimalsFormCard/AnimalSelect';

export type ReactSelectOption<T extends string | number> = {
label: string;
Expand All @@ -28,6 +29,8 @@ export enum DetailsFields {
BREED = 'breed',
SEX = 'sex',
USE = 'use',
COUNT = 'count',
SEX_DETAILS = 'sexDetails',
OTHER_USE = 'other_use',

// UNIQUE
Expand Down Expand Up @@ -55,9 +58,9 @@ export enum DetailsFields {
}

export type Option = {
[DetailsFields.TYPE]: ReactSelectOption<string>; // TODO: LF-4159
[DetailsFields.BREED]: ReactSelectOption<string>; // TODO: LF-4159
[DetailsFields.USE]: ReactSelectOption<number | string>; // TODO: LF-4159
[DetailsFields.TYPE]: AnimalSelectOption;
[DetailsFields.BREED]: AnimalSelectOption;
[DetailsFields.USE]: ReactSelectOption<number>;
[DetailsFields.TAG_COLOR]: ReactSelectOption<number>;
[DetailsFields.TAG_TYPE]: ReactSelectOption<number>;
[DetailsFields.TAG_PLACEMENT]: ReactSelectOption<number>;
Expand Down Expand Up @@ -91,7 +94,7 @@ export type FormValues = {
[DetailsFields.PRICE]?: number;
};

export interface FormMethods extends UseFormReturn<FormValues> {}
export interface FormMethods extends UseFormReturn<Partial<FormValues>> {}

export type CommonDetailsProps = {
t: TFunction;
Expand Down
99 changes: 99 additions & 0 deletions packages/webapp/src/components/Animals/AddBatchDetails/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* Copyright 2024 LiteFarm.org
* This file is part of LiteFarm.
*
* LiteFarm is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LiteFarm is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details, see <https://www.gnu.org/licenses/>.
*/

import { useTranslation } from 'react-i18next';
import clsx from 'clsx';
import GeneralDetails, { type GeneralDetailsProps } from '../AddAnimalsDetails/General';
import OtherDetails, { type OtherDetailsProps } from '../AddAnimalsDetails/Other';
import Origin, { type OriginProps } from '../AddAnimalsDetails/Origin';
import ExpandableItem from '../../Expandable/ExpandableItem';
import useExpandable from '../../Expandable/useExpandableItem';
import { AnimalOrBatchKeys } from '../../../containers/Animals/types';
import styles from '../AddAnimalsDetails/styles.module.scss';

enum sectionKeys {
GENERAL,
ORIGIN,
OTHER,
}

export type BatchDetailsProps = {
generalDetailProps: Omit<GeneralDetailsProps, 't' | 'animalOrBatch'>;
otherDetailsProps: Omit<OtherDetailsProps, 't' | 'animalOrBatch'>;
originProps: Omit<OriginProps, 't'>;
};

const BatchDetails = ({
generalDetailProps,
otherDetailsProps,
originProps,
}: BatchDetailsProps) => {
const { expandedIds, toggleExpanded } = useExpandable({ isSingleExpandable: true });
const { t } = useTranslation(['translation', 'common', 'animal']);
const commonProps = { t };

const sections = [
{
key: sectionKeys.GENERAL,
title: t('ADD_ANIMAL.GENERAL_DETAILS_BATCH'),
content: (
<GeneralDetails
{...commonProps}
{...generalDetailProps}
animalOrBatch={AnimalOrBatchKeys.BATCH}
/>
),
},
{
key: sectionKeys.OTHER,
title: t('ADD_ANIMAL.OTHER_DETAILS_BATCH'),
content: (
<OtherDetails
{...commonProps}
{...otherDetailsProps}
animalOrBatch={AnimalOrBatchKeys.BATCH}
/>
),
},
{
key: sectionKeys.ORIGIN,
title: t('ADD_ANIMAL.ORIGIN_BATCH'),
content: <Origin {...commonProps} {...originProps} />,
},
];

return (
<div className={styles.detailsWrapper}>
{sections.map(({ key, title, content }) => {
const isExpanded = expandedIds.includes(key);

return (
<div key={key} className={clsx(styles.section, isExpanded && styles.expanded)}>
<ExpandableItem
itemKey={key}
isExpanded={isExpanded}
iconClickOnly={false}
onClick={() => toggleExpanded(key)}
mainContent={title}
expandedContent={<div className={styles.expandedContentWrapper}>{content}</div>}
/>
</div>
);
})}
</div>
);
};

export default BatchDetails;
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,18 @@ import AnimalCreationDetails, {
AnimalDetailsProps,
} from '../../../components/Animals/AddAnimalsDetails';
import AnimalDetails from '../../../components/Animals/AddAnimalsDetails';
import { FormMethods } from '../../../components/Animals/AddAnimalsDetails/type';
import { DetailsFields, FormMethods } from '../../../components/Animals/AddAnimalsDetails/type';
import {
typeOptions,
breedOptions,
sexOptions,
useOptions,
tagTypeOptions,
tagColorOptions,
tagPlacementOptions,
organicStatusOptions,
originOptions,
defaultValues,
} from './mockData';
import { AnimalOrigins } from '../../../containers/Animals/types';

// https://storybook.js.org/docs/writing-stories/typescript
const meta: Meta<AnimalDetailsProps> = {
Expand All @@ -44,16 +44,23 @@ type Story = StoryObj<typeof AnimalCreationDetails>;

export const Default: Story = {
render: () => {
const formMethods: FormMethods = useForm();
const formMethods: FormMethods = useForm({
defaultValues,
});

const originId = formMethods.watch(DetailsFields.ORIGIN);
const origin = !originId
? undefined
: originId === 1
? AnimalOrigins.BROUGHT_IN
: AnimalOrigins.BORN_AT_FARM;

return (
<Suspense>
<div style={{ padding: '16px' }}>
<FormProvider {...formMethods}>
<AnimalDetails
generalDetailProps={{
typeOptions,
breedOptions,
sexOptions,
useOptions,
}}
Expand All @@ -68,6 +75,7 @@ export const Default: Story = {
originProps={{
currency: '$',
originOptions,
origin,
}}
/>
</FormProvider>
Expand Down
Loading

0 comments on commit 8e5913e

Please sign in to comment.