feat(MoveToShelf): move selected books to shelf
This commit is contained in:
parent
65e9aa2e0b
commit
c03aa30cfd
12 changed files with 331 additions and 69 deletions
frontend/src/shared/components/modals
|
@ -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={{
|
||||
|
|
|
@ -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
|
||||
}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
|
100
frontend/src/shared/components/modals/MoveShelfModal.tsx
Normal file
100
frontend/src/shared/components/modals/MoveShelfModal.tsx
Normal 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>
|
||||
);
|
||||
};
|
|
@ -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">;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue