feat(MoveToShelf): move selected books to shelf

This commit is contained in:
0ry5 2024-09-30 21:32:24 +02:00
parent 65e9aa2e0b
commit c03aa30cfd
12 changed files with 331 additions and 69 deletions
frontend/src/shared/components/modals

View file

@ -6,6 +6,7 @@ import { DeleteBookModalProps } from "./types";
export const DeleteBookModal = ({
uuid,
title,
open,
onClose,
}: Omit<DeleteBookModalProps, "type">): React.JSX.Element => {
@ -26,7 +27,7 @@ export const DeleteBookModal = ({
<Modal show={open} onHide={onClose} centered>
<ModalHeader
onClose={onClose}
title={"Move to Shelf"}
title={`Delete Book "${title}"`}
icon={<ImBin size={50} className='ml-0 mr-auto' />}
/>
<Modal.Body
@ -34,6 +35,7 @@ export const DeleteBookModal = ({
borderTop: "none",
}}
>
Do you really want to delete this book?
<div className='d-flex mx-auto mb-auto mt-2 w-100'>
<Button
style={{

View file

@ -6,8 +6,9 @@ import { CheckoutBookModal } from "./CheckoutModal";
import { ScannerModal } from "./ScannerModal";
import { DeleteBookModal } from "./DeleteBookModal";
import { ModalContextType } from "../../../App";
import { MoveShelfModal } from "./MoveShelfModal";
const { auth, book, checkout, scanner, del } = modalTypes;
const { auth, book, checkout, scanner, del, moveShelf } = modalTypes;
export const ModalSelector = ({
activeModal,
@ -48,7 +49,15 @@ export const ModalSelector = ({
<DeleteBookModal
open={activeModal?.type === del}
onClose={activeModal?.type === del ? activeModal.onClose : setActiveModal}
uuid={activeModal?.type === checkout ? activeModal.uuid : ""}
uuid={activeModal?.type === del ? activeModal.uuid : ""}
title={activeModal?.type === del ? activeModal.title : ""}
/>
<MoveShelfModal
books={activeModal?.type === moveShelf ? activeModal.books : []}
open={activeModal?.type === moveShelf}
onClose={
activeModal?.type === moveShelf ? activeModal.onClose : setActiveModal
}
/>
</>
);

View file

@ -0,0 +1,100 @@
import { useMutation } from "@tanstack/react-query";
import { Button, Col, Form, Modal, Row } from "react-bootstrap";
import { ImBook } from "react-icons/im";
import { ModalHeader } from "./ModalHeader";
import { MoveShelfAction, MoveShelfModalProps } from "./types";
import { useForm, useWatch } from "react-hook-form";
import { bookShelfs } from "../../../types/Book";
export const MoveShelfModal = ({
books,
open,
onClose,
}: Omit<MoveShelfModalProps, "type">): React.JSX.Element => {
const { control, register, formState, setError } = useForm<MoveShelfAction>({
mode: "onChange",
});
const values = useWatch({ control });
const { mutate: mv } = useMutation({
mutationFn: async () => {
if (!values.target) {
setError("target", { message: "Taget shelf is required" });
return;
}
await fetch(`/api/shelf/move`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ ...values, books }),
});
onClose();
},
});
return (
<Modal show={open} onHide={onClose} centered>
<ModalHeader
onClose={onClose}
title={"Move to Shelf"}
icon={<ImBook size={50} className='ml-0 mr-auto' />}
/>
<Modal.Body
style={{
borderTop: "none",
}}
>
<Form.Group as={Row} className='mb-2'>
<Col sm='2'>
<Form.Label>Shelf</Form.Label>
</Col>
<Col>
<Form.Select
{...register("target", { required: true })}
isInvalid={!!formState.errors.target}
>
{Object.keys(bookShelfs).map((key) => (
<option
key='key'
value={bookShelfs[key as keyof typeof bookShelfs]}
>
{key}
</option>
))}
</Form.Select>
<Form.Control.Feedback type='invalid'>
{!values.target
? "Target shelf is required"
: formState.errors.target?.message}
</Form.Control.Feedback>
</Col>
</Form.Group>
<div className='d-flex mx-auto mb-auto mt-2 w-100'>
<Button
style={{
borderRadius: "5px",
marginLeft: "auto",
marginRight: "10px",
}}
onClick={() => onClose()}
>
Cancel
</Button>
<Button
style={{
borderRadius: "5px",
marginLeft: "0px",
marginRight: "10px",
}}
onClick={() => mv()}
>
Move
</Button>
</div>
</Modal.Body>
</Modal>
);
};

View file

@ -11,6 +11,7 @@ export const modalTypes = {
checkout: "checkout",
scanner: "scanner",
del: "del",
moveShelf: "moveShelf",
} as const;
export type ModalTypes = keyof typeof modalTypes;
@ -37,11 +38,21 @@ export type ScannnerModal = {
} & BaseModalProps;
export type DeleteBookModalProps = { type: "del" } & BaseModalProps &
Pick<Book, "uuid">;
Pick<Book, "uuid" | "title">;
export type MoveShelfModalProps = { type: "moveShelf" } & BaseModalProps & {
books: Book["uuid"][];
};
export interface MoveShelfAction {
target: Book["shelf"];
books: Book["uuid"][];
}
export type ActiveModalProps =
| Omit<AuthModalProps, "open" | "onClose">
| Omit<BookModalProps, "open">
| Omit<CheckoutBookModalProps, "open">
| Omit<ScannnerModal, "open" | "onClose">
| Omit<DeleteBookModalProps, "open">;
| Omit<DeleteBookModalProps, "open">
| Omit<MoveShelfModalProps, "open">;