Fitur Restoran NextJS

Menu "use client" import { Card, CardContent, CardHeader } from "@/components/ui/card"; import { PlusIcon } from "lucide-react"; import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogFooter, } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Button } from "@/components/ui/button"; import { useEffect, useState } from "react"; interface Menuitem { id_menu: number; nama_menu: string; harga: number; menu_image: string; id_kategori:number; } const Features05Page = () => { const [menus, setMenu] = useState([]); const [namaMenu, setNamaMenu] = useState(""); const [harga, setHarga] = useState(""); const [imageFile, setImageFile] = useState(null); const [kategori,setKategori]=useState(1) const handleSubmit = async () => { const token = localStorage.getItem("adminToken"); const formData = new FormData(); formData.append("nama_menu", namaMenu); formData.append("harga", harga); formData.append("id_kategori", kategori.toString()); // pastikan string if (imageFile) { formData.append("menu_image", imageFile); } try { const response = await fetch("http://127.0.0.1:8000/api/menu/", { method: "POST", headers: { Authorization: `Bearer ${token}`, // jangan tambahkan content-type, biarkan browser mengatur sendiri }, body: formData, }); if (!response.ok) { throw new Error("Gagal menambahkan menu"); } const data = await response.json(); setMenu((prev) => [...prev, data]); // update UI langsung setNamaMenu(""); setHarga(""); setKategori(1) setImageFile(null); } catch (error) { console.error("Error:", error); } }; useEffect(() => { const token = localStorage.getItem("adminToken"); fetch("http://127.0.0.1:8000/api/menu/", { headers: { Authorization: `Bearer ${token}`, }, }) .then((response) => response.json()) .then((data: Menuitem[]) => setMenu(data)) .catch((error) => console.log("error", error)); }, []); return ( Daftar Menu Tambah Menu Tambah Menu Baru Nama setNamaMenu(e.target.value)} className="col-span-3" /> Harga setHarga(e.target.value)} className="col-span-3" /> kategori setKategori(parseInt(e.target.value))} className="col-span-3" /> Gambar setImageFile(e.target.files?.[0] || null)} className="col-span-3" /> Simpan {menus.map((menu) => ( {menu.nama_menu} {menu.harga} ))} ); }; export default Features05Page; Meja import { useEffect, useState } from "react"; import { Button } from "../ui/button"; import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, } from "../ui/dialog"; import { Input } from "../ui/input"; import { Label } from "@/components/ui/label"; import { PlusIcon } from "lucide-react"; const features = [ { title: "Identify Opportunities", description: "Find untapped areas to explore effortlessly.", }, { title: "Build Authority", description: "Craft content that resonates and inspires trust.", }, { title: "Instant Insights", description: "Get actionable insights instantly at a glance.", }, ]; interface MejaItem { id_meja: number; no_meja: number; kapasitas: number; image_meja: string; } const Features02Page = () => { const [mejas, setMeja] = useState([]); const [no_meja, setNomeja] = useState(""); const [id_meja, setIDMeja] = useState(""); const [kapasitas, setKapasitas] = useState(""); const [imageMeja, setImageMeja] = useState(null); const [open, setOpen] = useState(false); useEffect(() => { const token = localStorage.getItem("adminToken"); try { fetch("http://127.0.0.1:8000/api/meja/", { headers: { Authorization: `Bearer ${token}`, }, }) .then((response) => response.json()) .then((data: MejaItem[]) => setMeja(data)) .catch((error) => consol

Apr 7, 2025 - 15:53
 0
Fitur Restoran NextJS
  1. Menu
"use client"
import { Card, CardContent, CardHeader } from "@/components/ui/card";
import { PlusIcon } from "lucide-react";
import {
  Dialog,
  DialogTrigger,
  DialogContent,
  DialogHeader,
  DialogTitle,
  DialogFooter,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Button } from "@/components/ui/button";

import { useEffect, useState } from "react";

interface Menuitem {
  id_menu: number;
  nama_menu: string;
  harga: number;
  menu_image: string;
  id_kategori:number;
}

const Features05Page = () => {
  const [menus, setMenu] = useState([]);
  const [namaMenu, setNamaMenu] = useState("");
  const [harga, setHarga] = useState("");
  const [imageFile, setImageFile] = useState(null);
  const [kategori,setKategori]=useState(1)


  const handleSubmit = async () => {
    const token = localStorage.getItem("adminToken");
    const formData = new FormData();
    formData.append("nama_menu", namaMenu);
    formData.append("harga", harga);
    formData.append("id_kategori", kategori.toString()); // pastikan string

    if (imageFile) {
      formData.append("menu_image", imageFile);
    }

    try {
      const response = await fetch("http://127.0.0.1:8000/api/menu/", {
        method: "POST",
        headers: {
          Authorization: `Bearer ${token}`,
          // jangan tambahkan content-type, biarkan browser mengatur sendiri
        },
        body: formData,
      });

      if (!response.ok) {
        throw new Error("Gagal menambahkan menu");
      }

      const data = await response.json();
      setMenu((prev) => [...prev, data]); // update UI langsung
      setNamaMenu("");
      setHarga("");
      setKategori(1)
      setImageFile(null);
    } catch (error) {
      console.error("Error:", error);
    }
  };
  useEffect(() => {
    const token = localStorage.getItem("adminToken");
    fetch("http://127.0.0.1:8000/api/menu/", {
      headers: {
        Authorization: `Bearer ${token}`,
      },
    })
      .then((response) => response.json())
      .then((data: Menuitem[]) => setMenu(data))
      .catch((error) => console.log("error", error));
  }, []);

  return (
    

Daftar Menu

Tambah Menu Baru
setNamaMenu(e.target.value)} className="col-span-3" />
setHarga(e.target.value)} className="col-span-3" />
setKategori(parseInt(e.target.value))} className="col-span-3" />
setImageFile(e.target.files?.[0] || null)} className="col-span-3" />
{menus.map((menu) => (

{menu.nama_menu}

{menu.harga}

Error
))}
); }; export default Features05Page;
  1. Meja
import { useEffect, useState } from "react";
import { Button } from "../ui/button";
import {
  Dialog,
  DialogContent,
  DialogFooter,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from "../ui/dialog";
import { Input } from "../ui/input";
import { Label } from "@/components/ui/label";
import { PlusIcon } from "lucide-react";

const features = [
  {
    title: "Identify Opportunities",
    description: "Find untapped areas to explore effortlessly.",
  },
  {
    title: "Build Authority",
    description: "Craft content that resonates and inspires trust.",
  },
  {
    title: "Instant Insights",
    description: "Get actionable insights instantly at a glance.",
  },
];

interface MejaItem {
  id_meja: number;
  no_meja: number;
  kapasitas: number;
  image_meja: string;
}
const Features02Page = () => {
  const [mejas, setMeja] = useState([]);
  const [no_meja, setNomeja] = useState("");
  const [id_meja, setIDMeja] = useState("");
  const [kapasitas, setKapasitas] = useState("");
  const [imageMeja, setImageMeja] = useState(null);
  const [open, setOpen] = useState(false);

  useEffect(() => {
    const token = localStorage.getItem("adminToken");

    try {
      fetch("http://127.0.0.1:8000/api/meja/", {
        headers: {
          Authorization: `Bearer ${token}`,
        },
      })
        .then((response) => response.json())
        .then((data: MejaItem[]) => setMeja(data))
        .catch((error) => console.log("error ", error));
    } catch (error) {
      console.log("error ", error);
    }
  }, []);

  const handleSubmit = async () => {
    const token = localStorage.getItem("adminToken");
    const newForm = new FormData();

    newForm.append("no_meja", no_meja);
    newForm.append("kapasitas", kapasitas);
    if (imageMeja) {
      newForm.append("image_meja", imageMeja);
    }

    try {
      const response = await fetch("http://127.0.0.1:8000/api/meja/", {
        method: "POST",
        headers: {
          Authorization: `Bearer ${token}`,
        },
        body: newForm,
      });
      if (!response.ok) {
        throw new Error("Gagal menambahkan meja");
      }
      const data = await response.json();
      setMeja((prev) => [...prev, data]);
      setNomeja("");
      setKapasitas("");
      setImageMeja(null);
      setOpen(false);
    } catch (error) {
      console.log(error);
    }
  };
  return (
    

Daftar Meja

Tambah Menu Baru
setNomeja(e.target.value)} className="col-span-3" />
setKapasitas(e.target.value)} className="col-span-3" />
setImageMeja(e.target.files?.[0] || null)} className="col-span-3" />
{mejas.map((meja) => (
Image Not Found
Nomer Meja : {meja.no_meja}

Kapasitas : {meja.kapasitas}

))}
); }; export default Features02Page;
  1. Reservasi
// page
"use client"

import React from "react"
import { ReservationTable } from "./data-table"

export default function ReservationPage() {
  return (
    

Reservation List

) } // column.tsx import { ColumnDef } from "@tanstack/react-table" import { Button } from "@/components/ui/button" import { Checkbox } from "@/components/ui/checkbox" import { ArrowUpDown, Edit, Trash2 } from "lucide-react" import { Reservation } from "./data-table" export function getReservationColumns( handleUpdateClick: (reservation: Reservation) => void, handleDeleteClick: (reservation: Reservation) => void ): ColumnDef[] { return [ { id: "select", header: ({ table }) => ( table.toggleAllPageRowsSelected(!!value)} aria-label="Select all" /> ), cell: ({ row }) => ( row.toggleSelected(!!value)} aria-label="Select row" /> ), enableSorting: false, enableHiding: false, }, { header: "ID", cell: ({ row }) =>
{row.index + 1}
, }, { accessorKey: "nama_customer", header: ({ column }) => ( ), cell: ({ row }) =>
{row.getValue("nama_customer")}
, }, { accessorKey: "tanggal_reservasi", header: ({ column }) => ( ), cell: ({ row }) => { const date = new Date(row.getValue("tanggal_reservasi")) return
{date.toLocaleDateString("en-GB")}
}, }, { accessorKey: "status", header: "Status", cell: ({ row }) => { const status = row.getValue("status") as string const statusClass = { booked: "text-blue-600", confirmed: "text-green-600", pending: "text-amber-600", cancelled: "text-red-600", }[status.toLowerCase()] || "" return
{status}
}, }, { accessorKey: "id_meja", header: "Table No.", cell: ({ row }) =>
Table {row.getValue("id_meja")}
, }, { id: "actions", enableHiding: false, header: "Actions", cell: ({ row }) => { const reservation = row.original return (
) }, }, ] }
// data table

"use client";

import React, { use, useState } from "react";
import {
  ColumnFiltersState,
  SortingState,
  VisibilityState,
  flexRender,
  getCoreRowModel,
  getFilteredRowModel,
  getPaginationRowModel,
  getSortedRowModel,
  useReactTable,
} from "@tanstack/react-table";
import { Input } from "@/components/ui/input";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table";
import { getReservationColumns } from "./column";
import { Button } from "@/components/ui/button";
import { PlusIcon } from "lucide-react";
import {
  Dialog,
  DialogContent,
  DialogTitle,
  DialogTrigger,
} from "@/components/ui/dialog";
import { DialogFooter, DialogHeader } from "@/components/ui/dialog";
import { Label } from "@/components/ui/label";
import { log } from "console";
import { Select, SelectContent, SelectItem } from "@/components/ui/select";
import { SelectTrigger, SelectValue } from "@radix-ui/react-select";

export type Reservation = {
  id_reservasi: number;
  nama_customer: string;
  tanggal_reservasi: string;
  status: string;
  id_meja: number;
  id_admin: number;
};

export function ReservationTable() {
  const [data, setData] = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const [error, setError] = React.useState(null);
  const [sorting, setSorting] = React.useState([]);
  const [columnFilters, setColumnFilters] = React.useState(
    []
  );
  const [columnVisibility, setColumnVisibility] =
    React.useState({});
  const [rowSelection, setRowSelection] = React.useState({});
  const [id_admin, setIdAdmin] = useState("");
  const [nama_customer, setNama] = useState("");
  const [tanggal_reservasi, setTanggal] = useState("");
  const [status, setStatus] = useState("");
  const [id_meja, setMeja] = useState("");

  const fetchReservations = async () => {
    try {
      setLoading(true);
      const token = localStorage.getItem("adminToken");

      const response = await fetch("http://localhost:8000/api/reservasi/", {
        headers: {
          "Content-Type": "application/json",
          Authorization: `Bearer ${token}`,
        },
      });
      if (!response.ok) throw new Error("Failed to fetch reservation data");
      const result = await response.json();
      setData(Array.isArray(result) ? result : [result]);
    } catch (err) {
      setError("Failed to load reservations. Please try again later.");
    } finally {
      setLoading(false);
    }
  };

  React.useEffect(() => {
    fetchReservations();
  }, []);

  const handleSubmit = async () => {
    const formData = new FormData();
    formData.append("id_admin", id_admin);
    formData.append("nama_customer", nama_customer);
    formData.append("tanggal_reservasi", tanggal_reservasi);
    formData.append("status", status);
    formData.append("id_meja", id_meja);
    const token = localStorage.getItem("adminToken");

    try {
      const response = await fetch("http://127.0.0.1:8000/api/reservasi/", {
        method: "POST",
        headers: {
          Authorization: `Bearer ${token}`,
        },
        body: formData,
      });
      if (!response.ok) {
        throw new Error("Gagal menambahkan reservasi");
      }
      const data = await response.json();
      setData((prev) => [...prev, data]);
      setIdAdmin("");
      setNama("");
      setStatus("");
      setTanggal("");
      setMeja("");
    } catch (err) {
      console.log("Error ", err);
    }
  };

  const columns = getReservationColumns(
    (r) => console.log("Update", r),
    (r) => console.log("Delete", r)
  );

  const table = useReactTable({
    data,
    columns,
    onSortingChange: setSorting,
    onColumnFiltersChange: setColumnFilters,
    getCoreRowModel: getCoreRowModel(),
    getPaginationRowModel: getPaginationRowModel(),
    getSortedRowModel: getSortedRowModel(),
    getFilteredRowModel: getFilteredRowModel(),
    onColumnVisibilityChange: setColumnVisibility,
    onRowSelectionChange: setRowSelection,
    state: {
      sorting,
      columnFilters,
      columnVisibility,
      rowSelection,
    },
  });

  if (loading)
    return (
      
Loading reservation data...
); if (error) return (
{error}
); return (
table.getColumn("nama_customer")?.setFilterValue(e.target.value) } className="max-w-sm" /> Tambahkan Reservasi
setIdAdmin(e.target.value)} className="col-span-3" />
setMeja(e.target.value)} className="col-span-3" />
setNama(e.target.value)} className="col-span-3" />
setTanggal(e.target.value)} className="col-span-3" type="date" />
{table.getHeaderGroups().map((headerGroup) => ( {headerGroup.headers.map((header) => ( {header.isPlaceholder ? null : flexRender( header.column.columnDef.header, header.getContext() )} ))} ))} {table.getRowModel().rows?.length ? ( table.getRowModel().rows.map((row) => ( {row.getVisibleCells().map((cell) => ( {flexRender( cell.column.columnDef.cell, cell.getContext() )} ))} )) ) : ( No results. )}
); }
  1. Report
'use client'

import ProductCard from "@/components/reportcard"
import { DataTableDemo } from "./table"

export default function Report(){
    return(
        
) } // table.tsx "use client" import React, { useEffect, useState } from "react" import { ColumnDef, ColumnFiltersState, SortingState, VisibilityState, flexRender, getCoreRowModel, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useReactTable, } from "@tanstack/react-table" import { ArrowUpDown, ChevronDown, MoreHorizontal } from "lucide-react" import { Button } from "@/components/ui/button" import { Checkbox } from "@/components/ui/checkbox" import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu" import { Input } from "@/components/ui/input" import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table" // 1. Tipe data export type Payment = { id: string nama_customer: string grand_total: number status_pembayaran: "Pending" | "Processing" | "Success" | "Failed" } // 2. Kolom tetap sama export const columns: ColumnDef[] = [ { id: "select", header: ({ table }) => ( table.toggleAllPageRowsSelected(!!value)} aria-label="Select all" /> ), cell: ({ row }) => ( row.toggleSelected(!!value)} aria-label="Select row" /> ), enableSorting: false, enableHiding: false, }, { accessorKey: "status_pembayaran", header: "Status", cell: ({ row }) => (
{row.getValue("status_pembayaran")}
), }, { accessorKey: "nama_customer", header: ({ column }) => ( ), cell: ({ row }) =>
{row.getValue("nama_customer")}
, }, { accessorKey: "grand_total", header: () =>
Amount
, cell: ({ row }) => { const amount = parseFloat(row.getValue("grand_total")) return
{amount}
}, }, { id: "actions", enableHiding: false, cell: ({ row }) => { const payment = row.original return ( Actions navigator.clipboard.writeText(payment.id)} > Copy payment ID View customer View payment details ) }, }, ] // 3. Komponen utama export function DataTableDemo() { const [data, setData] = useState([]) const [loading, setLoading] = useState(true) const [sorting, setSorting] = useState([]) const [columnFilters, setColumnFilters] = useState([]) const [columnVisibility, setColumnVisibility] = useState({}) const [rowSelection, setRowSelection] = useState({}) // 4. Fetch API saat mount useEffect(() => { const fetchData = async () => { const token = localStorage.getItem("adminToken") try { const res = await fetch("http://127.0.0.1:8000/api/report/",{ headers:{ Authorization : `Bearer ${token}` } }) const json = await res.json() setData(json) } catch (error) { console.error("Failed to fetch data", error) } finally { setLoading(false) } } fetchData() }, []) const table = useReactTable({ data, columns, onSortingChange: setSorting, onColumnFiltersChange: setColumnFilters, getCoreRowModel: getCoreRowModel(), getPaginationRowModel: getPaginationRowModel(), getSortedRowModel: getSortedRowModel(), getFilteredRowModel: getFilteredRowModel(), onColumnVisibilityChange: setColumnVisibility, onRowSelectionChange: setRowSelection, state: { sorting, columnFilters, columnVisibility, rowSelection, }, }) return (
table.getColumn("nama_customer")?.setFilterValue(event.target.value) } className="max-w-sm" /> {table .getAllColumns() .filter((column) => column.getCanHide()) .map((column) => ( column.toggleVisibility(!!value) } > {column.id} ))}
{table.getHeaderGroups().map((headerGroup) => ( {headerGroup.headers.map((header) => ( {header.isPlaceholder ? null : flexRender( header.column.columnDef.header, header.getContext() )} ))} ))} {loading ? ( Loading... ) : table.getRowModel().rows?.length ? ( table.getRowModel().rows.map((row) => ( {row.getVisibleCells().map((cell) => ( {flexRender(cell.column.columnDef.cell, cell.getContext())} ))} )) ) : ( No results. )}
{table.getFilteredSelectedRowModel().rows.length} of{" "} {table.getFilteredRowModel().rows.length} row(s) selected.
) }