+ `
+
1.11RDFxmlxml
+
+
+
+
+
+
+ (DE-101)962361321
+ 9783898641227
+ Pp. : DM 79.00, EUR 41.00 (ab 1.1.2002), sfr 70.00, S 577.00
+ 3898641228
+ Pp. : DM 79.00, EUR 41.00 (ab 1.1.2002), sfr 70.00, S 577.00
+ (OCoLC)76300394
+
+ Gunter Saake ; Kai-Uwe Sattler
+
+ mockedbook
+
+
+
+
+ 1. Aufl.
+ dpunkt-Verl.
+ Heidelberg
+ Heidelberg : dpunkt-Verl.
+ 25 cm
+ Ill.
+ Literaturverz. S. 483 - 486
+
+
+
+
+
+
+
+
+ 2024-10-13T04:31:46.000
+
+
+
+ 2024
+
+ eine Einführung mit Java
+ XVI, 494 S.
+
+
+ 11.19783898641227`,
+};
+
+describe("tryDeutscheNationalBibliothekApi", () => {
+ it("should parse dnb response to book", async () => {
+ global.fetch = jest.fn(() => Promise.resolve(dnbBookMock)) as jest.Mock;
+
+ const book = await tryDeutscheNationalBibliothekApi("mocked-isbn");
+
+ expect(book).toStrictEqual({
+ published: 2024,
+ title: "mockedbook",
+ });
+ });
+
+ afterAll(() => {
+ jest.clearAllMocks();
+ cleanup();
+ });
+});
diff --git a/frontend/src/pages/Main/utils/__tests__/tryGoogleBooksApi.test.ts b/frontend/src/pages/Main/utils/__tests__/tryGoogleBooksApi.test.ts
new file mode 100644
index 0000000..5e93a95
--- /dev/null
+++ b/frontend/src/pages/Main/utils/__tests__/tryGoogleBooksApi.test.ts
@@ -0,0 +1,33 @@
+import { cleanup } from "@testing-library/react";
+import { tryGoogleBooksApi } from "../tryGoogleBooksApi";
+
+const goolgeBooksMock = {
+ json: () => ({
+ items: [
+ {
+ volumeInfo: {
+ publishedDate: "2024-10-31",
+ title: "mockedbook",
+ },
+ },
+ ],
+ }),
+};
+
+describe("tryGoogleBooksApi", () => {
+ it("should parse google response to book", async () => {
+ global.fetch = jest.fn(() => Promise.resolve(goolgeBooksMock)) as jest.Mock;
+
+ const book = await tryGoogleBooksApi("mocked-isbn");
+
+ expect(book).toStrictEqual({
+ published: "2024",
+ title: "mockedbook",
+ });
+ });
+
+ afterAll(() => {
+ jest.clearAllMocks();
+ cleanup();
+ });
+});
diff --git a/frontend/src/shared/components/modals/BookModal.tsx b/frontend/src/shared/components/modals/BookModal.tsx
index 8ae20ce..0c7ced6 100644
--- a/frontend/src/shared/components/modals/BookModal.tsx
+++ b/frontend/src/shared/components/modals/BookModal.tsx
@@ -1,13 +1,14 @@
import React, { useCallback, useEffect, useState } from "react";
import { Button, Col, Form, Modal, Row } from "react-bootstrap";
-import { ImBook, ImCamera } from "react-icons/im";
+import { ImBook, ImCamera, ImCancelCircle } from "react-icons/im";
import { ModalHeader } from "./ModalHeader";
import { useForm, useWatch } from "react-hook-form";
-import { Book, bookShelfs } from "../../../types/Book";
+import { Book } from "../../../types/Book";
import { useScanner } from "../../utils/useScanner";
import { BookModalProps } from "./types";
import { tryGoogleBooksApi } from "../../../pages/Main/utils/tryGoogleBooksApi";
import { tryDeutscheNationalBibliothekApi } from "../../../pages/Main/utils/tryDeutscheNationalBibliothekApi";
+import { useQuery } from "@tanstack/react-query";
type BookForm = Pick
;
@@ -19,6 +20,19 @@ export const BookModal = ({
const isEdit = !!book;
const [showScanner, setShowScanner] = useState(false);
+ const [addNew, setAddNew] = useState(false);
+
+ const { data: shelves, isLoading } = useQuery({
+ queryFn: async () => {
+ const response = await fetch(`/api/shelves/list`);
+ const data = await response.text();
+ return data
+ .split(",")
+ .map((s) => s.replaceAll('"', "").replace("[", "").replace("]", ""));
+ },
+ queryKey: ["shleves"],
+ });
+
const { control, register, formState, setError, setValue, reset } =
useForm({
mode: "onChange",
@@ -84,7 +98,7 @@ export const BookModal = ({
}
if (error) return;
const createdBook = await fetch(
- isEdit ? "api/books/edit" : "/api/books/create",
+ isEdit ? "/api/books/edit" : "/api/books/create",
{
method: "POST",
body: JSON.stringify(data),
@@ -213,22 +227,52 @@ export const BookModal = ({
Shelf
-
- {Object.keys(bookShelfs).map((key) => (
-
+ ) : (
+