Skip to content

Commit

Permalink
Submit note by photo form
Browse files Browse the repository at this point in the history
  • Loading branch information
pkirilin committed May 26, 2024
1 parent b490abd commit f00d296
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 6 deletions.
1 change: 1 addition & 0 deletions src/frontend/src/features/note/addEdit/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './ui';
export * as addEditNoteLib from './lib';
1 change: 1 addition & 0 deletions src/frontend/src/features/note/addEdit/lib/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './mapping';
65 changes: 64 additions & 1 deletion src/frontend/src/features/note/addEdit/lib/mapping.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { type noteModel, type CreateNoteRequest, type EditNoteRequest } from '@/entities/note';
import { type ProductSelectOption } from '@/entities/product';
import { type productModel, type ProductSelectOption } from '@/entities/product';
import { type Note } from '../model';

export const mapToProductSelectOption = ({
Expand Down Expand Up @@ -35,3 +35,66 @@ export const mapToEditNoteRequest = (
productQuantity,
displayOrder,
});

export const mapToFormData = ({
mealType,
pageId,
product,
productQuantity,
displayOrder,
}: Note): FormData => {
const formData = new FormData();
formData.append('mealType', mealType.toString());
formData.append('pageId', pageId.toString());
formData.append('productQuantity', productQuantity.toString());
formData.append('displayOrder', displayOrder.toString());

if (product.freeSolo) {
formData.append('productCaloriesCost', product.caloriesCost.toString());
formData.append('productCategoryId', product.category?.id.toString() ?? '');
formData.append('productCategoryName', product.category?.name ?? '');
} else {
formData.append('productId', product.id.toString());
}

formData.append('productName', product.name);
formData.append('productDefaultQuantity', product.defaultQuantity.toString());
return formData;
};

const mapProductFromFormData = (formData: FormData): productModel.AutocompleteOption => {
const id = formData.get('productId')?.toString() ?? null;
const name = formData.get('productName')?.toString() ?? '';
const caloriesCost = formData.get('productCaloriesCost')?.toString() ?? null;
const defaultQuantity = Number(formData.get('productDefaultQuantity'));
const categoryId = formData.get('productCategoryId')?.toString() ?? null;
const categoryName = formData.get('productCategoryName')?.toString() ?? '';

return id && !caloriesCost && !categoryId
? {
id: Number(id),
name,
defaultQuantity,
}
: {
freeSolo: true,
editing: true,
name,
defaultQuantity,
caloriesCost: Number(caloriesCost),
category: {
id: Number(categoryId),
name: categoryName,
},
};
};

export const mapNoteFromFormData = (formData: FormData): Note => {
const mealType = Number(formData.get('mealType'));
const pageId = Number(formData.get('pageId'));
const productQuantity = Number(formData.get('productQuantity'));
const displayOrder = Number(formData.get('displayOrder'));
const product = mapProductFromFormData(formData);

return { mealType, pageId, product, productQuantity, displayOrder };
};
4 changes: 3 additions & 1 deletion src/frontend/src/features/note/addEdit/ui/NoteInputForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { useInput, type UseInputResult } from '@/shared/hooks';
import { mapToNumericInputProps, validateQuantity } from '@/shared/lib';
import { type Note } from '../model';

export type NoteInputFormSubmitHandler = (note: Note) => Promise<void>;

export interface NoteInputFormProps {
id: string;
pageId: number;
Expand All @@ -17,7 +19,7 @@ export interface NoteInputFormProps {
>;
quantity: number;
renderProductAutocomplete: (props: productLib.AutocompleteInputProps) => ReactElement;
onSubmit: (note: Note) => Promise<void>;
onSubmit: NoteInputFormSubmitHandler;
onSubmitDisabledChange: (disabled: boolean) => void;
}

Expand Down
59 changes: 55 additions & 4 deletions src/frontend/src/pages/notes/ui/NewByPhoto.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,27 @@ import {
Grid,
Backdrop,
CircularProgress,
Stack,
} from '@mui/material';
import { useEffect, type FC } from 'react';
import { useLoaderData } from 'react-router-dom';
import { useEffect, type FC, type MouseEventHandler } from 'react';
import {
type ActionFunction,
useLoaderData,
redirect,
useNavigate,
useSubmit,
} from 'react-router-dom';
import { store } from '@/app/store';
import { categoryApi, type categoryModel } from '@/entities/category';
import { noteApi, type noteModel } from '@/entities/note';
import { ProductAutocomplete, productApi, productLib, type productModel } from '@/entities/product';
import { NoteInputForm } from '@/features/note/addEdit';
import {
NoteInputForm,
addEditNoteLib,
type NoteInputFormSubmitHandler,
} from '@/features/note/addEdit';
import { pagesApi, type Page } from '@/features/pages';
import { Button } from '@/shared/ui';
import { PrivateLayout } from '@/widgets/layout';
import { withAuthStatusCheck } from '../../lib';
import { Subheader } from './Subheader';
Expand Down Expand Up @@ -64,6 +76,20 @@ export const loader = withAuthStatusCheck(async ({ request, params }) => {
} satisfies LoaderData;
});

export const action: ActionFunction = async ({ request, params }) => {
const pageId = Number(params.id);
const formData = await request.formData();
const note = addEditNoteLib.mapNoteFromFormData(formData);

if (note.product.freeSolo) {
// TODO: create product, then create note using received product id
return redirect(`/pages/${pageId}`);
}

// TODO: create note
return redirect(`/pages/${pageId}`);
};

export const Component: FC = () => {
const {
page,
Expand All @@ -74,6 +100,9 @@ export const Component: FC = () => {
categoryAutocompleteOptions,
} = useLoaderData() as LoaderData;

const navigate = useNavigate();
const submit = useSubmit();

const productAutocompleteInput = productLib.useAutocompleteInput();
const { setValue: setProduct } = productAutocompleteInput;
const { values: productFormValues } = productLib.useFormValues();
Expand Down Expand Up @@ -112,6 +141,16 @@ export const Component: FC = () => {
setProduct,
]);

const handleCancel: MouseEventHandler = () => {
navigate(`/pages/${page.id}`);
};

const handleSubmit: NoteInputFormSubmitHandler = note => {
const formData = addEditNoteLib.mapToFormData(note);
submit(formData, { method: 'post', action: `/pages/${page.id}/notes/new/by-photo` });
return Promise.resolve();
};

return (
<PrivateLayout subheader={<Subheader page={page} mealType={mealType} />}>
<Typography variant="h5" component="h1" marginBottom={2}>
Expand Down Expand Up @@ -149,9 +188,21 @@ export const Component: FC = () => {
loading={false}
/>
)}
onSubmit={async () => {}}
onSubmit={handleSubmit}
onSubmitDisabledChange={() => {}}
/>
<Stack
direction={{ xs: 'column', md: 'row' }}
justifyContent={{ md: 'flex-end' }}
spacing={3}
>
<Button type="button" variant="outlined" onClick={handleCancel}>
Cancel
</Button>
<Button type="submit" form="note-input-form" variant="contained">
Add note
</Button>
</Stack>
</Grid>
</Grid>
</PrivateLayout>
Expand Down

0 comments on commit f00d296

Please sign in to comment.