Skip to content

C. Integrasi Create Book

1. Integrasi endpoint tambah buku

request endpoint create
http://localhost:5002/book/create

{
    "title" : "Nextjs",
    "author" : "ihsan",
    "year" : 2020

}
response endpoint create
{
    "status": "Success",
    "message": "OK",
    "data": {}
}

Alt text

book/interface/index.ts
import {
  BaseResponsePagination,
} from "@/lib/axiosClient";

interface Book {
  id: number;
  title: string;
  author: string;
  year: number | undefined | string;
  created_at: string;
  updated_at: string;
}

export interface BookListResponse extends BaseResponsePagination {
  data: Book[];
}

export interface BookListFilter extends Partial<Book> {
  from_year?: string;
  to_year?: string;
  page : number ,
  pageSize : number 
}


export interface BookCreatePayload extends Pick<Book, "author" | "title" | "year"> {}
book/page.ts
"use client";
import Button from "@/components/Button";
import { Pagination } from "../../components/Pagination";
import { Table, Th, Thead, Tr, Tbody, Td } from "../../components/Table";
import useBookModule from "./lib";
import { Drawer } from "@/components/Drawer";
import Filter from "./module/Filter";
import { useClosure } from "@/hook";
import { useRouter } from "next/navigation";

const Book = () => {
  const { useBookList} = useBookModule();
  const router = useRouter()


  const {
    data,
    isFetching,
    isError,
    params,
    setParams,
    handleFilter,
    handleClear,
    handlePageSize,
    handlePage,
  } = useBookList();

  const { isOpen, onOpen, onClose } = useClosure();

  return (
    <>
      <Drawer
        onClose={onClose}
        onClear={handleClear}
        onSubmit={handleFilter}
        title="Filter Buku"
        isOpen={isOpen}
      >
        <Filter params={params} setParams={setParams} />
      </Drawer>
      <section className=" p-10 overflow-auto ">
        <section className="flex items-center justify-between ">
          <Button
            width="sm"
            onClick={onOpen}
            colorSchema="blue"
            title="Filter"
          />
          <Button onClick={()=> {
            router.push('/book/tambah')
          }} width="sm" colorSchema="red" title="tambah" />
        </section>

      ...

    </>
  );
};

export default Book;

Alt text

book/lib/index.ts
import { useMutation, useQuery } from "@tanstack/react-query";
import { axiosClient } from "@/lib/axiosClient";
import Swal from "sweetalert2";
import {
  BookCreatePayload,
  BookListFilter,
  BookListResponse,
} from "../interface";
import { usePagination } from "@/hook/usePagination";

const useBookModule = () => {
  ...

  const useCreateBook = () => {
    const { mutate, isLoading } = useMutation(
      (payload: BookCreatePayload) => {
        return axiosClient.post("/book/create", payload);
      },
      {
        onSuccess: (response) => {
          Swal.fire({
            position: "top-end",
            icon: "success",
            title: response.data.message,
            showConfirmButton: false,
            timer: 1500,
          });
        },
        onError: (error) => {
          alert("ok");
        },
      }
    );
    return { mutate, isLoading };
  };

  return { useBookList, useCreateBook };
};

export default useBookModule;

Membuat Komponenn Create Book

book/tambah/page.ts
"use client";
import Button from "@/components/Button";
import InputText from "@/components/InputText";
import Label from "@/components/Label";
import Select from "@/components/Select";
import { useFormik, Form, FormikProvider } from "formik";
import * as yup from "yup";
import { BookCreatePayload } from "../interface";
import useBookModule from "../lib";
import Link from "next/link";
import { ArrowLongLeftIcon } from "@heroicons/react/20/solid";

const createBookSchema = yup.object().shape({
  title: yup.string().nullable().default("").required("Wajib isi"),
  author: yup.string().nullable().default("").required("Wajib isi"),
  year: yup.number().nullable().default(undefined).required("Wajib pilih"),
});
const option = [
  {
    value: 2020,
    label: "2020",
  },
  {
    value: 2021,
    label: "2021",
  },
  {
    value: 2022,
    label: "2022",
  },
  {
    value: 2023,
    label: "2023",
  },
];

const CreateBook = () => {
  const formik = useFormik<BookCreatePayload>({
    initialValues: {},
    validationSchema: createBookSchema,
    enableReinitialize: true,
    onSubmit: () => {
      console.log("ok");
    },
  });

  return (
    <section className="flex items-center  justify-center w-full h-full">
      <section className="w-1/2">
        <Link href={"/book"}>
          <span className="flex items-center">
            {" "}
            <ArrowLongLeftIcon className="h-5 w-5 mr-2" />
            Kembali
          </span>
        </Link>
        <h2 className="text-xl font-bold text-gray-500">Tambah Buku</h2>

        <FormikProvider value={formik}>
          <Form className="space-y-5">
            <section>
              <Label htmlFor="title" title="Title" />
              <InputText
                value={"123"}
                placeholder="Judul Buku"
                id="title"
                name="title"
              />
            </section>
            <section>
              <Label htmlFor="author" title="Auhtor" />
              <InputText
                value={"123"}
                placeholder="Penulis Buku"
                id="author"
                name="author"
              />
            </section>
            <section>
              <Label htmlFor="year" title="Year" />
              <Select value={"123"} id="year" name="year" options={option} />
            </section>
            <section>
              <Button height="md" title="Simpan" colorSchema="blue" />
            </section>
          </Form>
        </FormikProvider>
      </section>
    </section>
  );
};

export default CreateBook;
book/tambah/page.ts
"use client";
import Button from "@/components/Button";
import InputText from "@/components/InputText";
import Label from "@/components/Label";
import Select from "@/components/Select";
import { useFormik, Form, FormikProvider } from "formik";
import * as yup from "yup";
import { BookCreatePayload } from "../interface";
import useBookModule from "../lib";
import Link from "next/link";
import { ArrowLongLeftIcon } from "@heroicons/react/20/solid";

const createBookSchema = yup.object().shape({
  title: yup.string().nullable().default("").required("Wajib isi"),
  author: yup.string().nullable().default("").required("Wajib isi"),
  year: yup.number().nullable().default(undefined).required("Wajib pilih"),
});
const option = [
  {
    value: 2020,
    label: "2020",
  },
  {
    value: 2021,
    label: "2021",
  },
  {
    value: 2022,
    label: "2022",
  },
  {
    value: 2023,
    label: "2023",
  },
];

const CreateBook = () => {
  const { useCreateBook } = useBookModule();
  const { mutate, isLoading } = useCreateBook();
  const onSubmit = async (values: BookCreatePayload) => {
    mutate(values, {
      onSuccess: () => {
        resetForm();
        setValues(createBookSchema.getDefault());
      },
    });
  };

  const formik = useFormik<BookCreatePayload>({
    initialValues: createBookSchema.getDefault(),
    validationSchema: createBookSchema,
    enableReinitialize: true,
    onSubmit: onSubmit,
  });

  const {
    handleChange,
    handleSubmit,
    setFieldValue,
    handleBlur,
    values,
    errors,
    resetForm,
    setValues,
  } = formik;
  return (
    <section className="flex items-center  justify-center w-full h-full">
      <section className="w-1/2">
        <Link href={"/book"}>
           <span className="flex items-center" > <ArrowLongLeftIcon className="h-5 w-5 mr-2"/>Kembali</span>
        </Link>
        <h2 className="text-xl font-bold text-gray-500">Tambah Buku</h2>

        <FormikProvider value={formik}>
          <Form className="space-y-5" onSubmit={handleSubmit}>
            <section>
              <Label htmlFor="title" title="Title" />
              <InputText
                value={values.title}
                placeholder="Judul Buku"
                id="title"
                name="title"
                onChange={handleChange}
                onBlur={handleBlur}
                isError={!!errors.title}
                messageError={errors.title}
              />
            </section>
            <section>
              <Label htmlFor="author" title="Auhtor" />
              <InputText
                value={values.author}
                placeholder="Penulis Buku"
                id="author"
                name="author"
                onChange={handleChange}
                onBlur={handleBlur}
                isError={!!errors.author}
                messageError={errors.author}
              />
            </section>
            <section>
              <Label htmlFor="year" title="Year" />
              <Select
                value={values.year}
                id="year"
                name="year"
                onChange={handleChange}
                onBlur={handleBlur}
                options={option}
                isError={!!errors.year}
                messageError={errors.year}
              />
            </section>
            <section>
              <Button
                height="md"
                title="Simpan"
                colorSchema="blue"
                isLoading={isLoading}
                isDisabled={isLoading}
              />
            </section>
          </Form>
        </FormikProvider>
      </section>
    </section>
  );
};

export default CreateBook;

Alt text

Alt text

Alt text

Alt text