chore: update
This commit is contained in:
+1
-1
@@ -12,7 +12,7 @@ import { useQuery } from "@apollo/client/react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
const GET_EATERY_COUNT = gql`{ allEateries { ownerId name } }`;
|
||||
const GET_EATERY_COUNT = gql`{ allEateries { id } }`;
|
||||
|
||||
/**
|
||||
* Main page — sidebar + product grid layout.
|
||||
|
||||
@@ -1,19 +1,27 @@
|
||||
"use client";
|
||||
|
||||
import { eateryClient } from "@/lib/apollo-clients";
|
||||
import { useAuth } from "@/lib/auth-context";
|
||||
import { addManagerMenuItem, gqlFetch } from "@/lib/graphql";
|
||||
import {
|
||||
MenuItemEntity,
|
||||
addMenuItemMutation,
|
||||
allEateriesQuery,
|
||||
} from "@/lib/types";
|
||||
import { gql } from "@apollo/client";
|
||||
import { useMutation, useQuery } from "@apollo/client/react";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
|
||||
interface MenuItem {
|
||||
id: string;
|
||||
name: string;
|
||||
price: number;
|
||||
}
|
||||
const GET_EATERY_MENU = gql`{ allEateries { id menuItems { id name } } }`;
|
||||
|
||||
interface Eatery {
|
||||
id: string;
|
||||
ownerId: string;
|
||||
}
|
||||
const ADD_MENU_ITEM = gql`
|
||||
mutation addMenuItem($menuItem: AddMenuItemInput!) {
|
||||
addMenuItem(menuItem: $menuItem) {
|
||||
id
|
||||
name
|
||||
price
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
function formatPrice(price: number) {
|
||||
return price.toLocaleString("vi-VN") + "đ";
|
||||
@@ -21,8 +29,7 @@ function formatPrice(price: number) {
|
||||
|
||||
export default function MenuItemsTab() {
|
||||
const { user } = useAuth();
|
||||
const [eateryId, setEateryId] = useState<string | null>(null);
|
||||
const [menuItems, setMenuItems] = useState<MenuItem[]>([]);
|
||||
const [menuItems, setMenuItems] = useState<MenuItemEntity[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
@@ -32,43 +39,30 @@ export default function MenuItemsTab() {
|
||||
const [submitting, setSubmitting] = useState(false);
|
||||
const [submitError, setSubmitError] = useState<string | null>(null);
|
||||
|
||||
const loadEateryId = useCallback(async (): Promise<string | null> => {
|
||||
if (!user) return null;
|
||||
const data = await gqlFetch<{ allEateries: Eatery[] }>(
|
||||
"{ allEateries { id ownerId } }",
|
||||
);
|
||||
return (
|
||||
data.allEateries.find((e) => e.ownerId === String(user.id))?.id ?? null
|
||||
);
|
||||
}, [user]);
|
||||
|
||||
const loadMenuItems = useCallback(async (id: string): Promise<MenuItem[]> => {
|
||||
const data = await gqlFetch<{ menuItemsByEatery: MenuItem[] }>(
|
||||
`query($eateryId: String!) {
|
||||
menuItemsByEatery(eateryId: $eateryId) { id name price }
|
||||
}`,
|
||||
{ eateryId: id },
|
||||
);
|
||||
return data.menuItemsByEatery ?? [];
|
||||
}, []);
|
||||
const {
|
||||
data,
|
||||
loading: gqlLoading,
|
||||
error: gqlError,
|
||||
} = useQuery<allEateriesQuery>(GET_EATERY_MENU, {
|
||||
client: eateryClient,
|
||||
fetchPolicy: "no-cache",
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
async function init() {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
try {
|
||||
const id = await loadEateryId();
|
||||
setEateryId(id);
|
||||
if (id) setMenuItems(await loadMenuItems(id));
|
||||
else setMenuItems([]);
|
||||
} catch {
|
||||
setError("Không thể tải dữ liệu menu. Kiểm tra kết nối backend.");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
if (!gqlLoading) {
|
||||
if (data) setMenuItems(data.allEateries[0].menuItems);
|
||||
else
|
||||
setError(
|
||||
gqlError?.message ||
|
||||
"Không thể tải dữ liệu menu. Kiểm tra kết nối backend.",
|
||||
);
|
||||
}
|
||||
init();
|
||||
}, [loadEateryId, loadMenuItems]);
|
||||
|
||||
setLoading(false);
|
||||
}, [data, gqlLoading, gqlError]);
|
||||
|
||||
const handleAdd = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
@@ -76,11 +70,23 @@ export default function MenuItemsTab() {
|
||||
setSubmitting(true);
|
||||
setSubmitError(null);
|
||||
try {
|
||||
const added = await addManagerMenuItem(
|
||||
newName.trim(),
|
||||
parseFloat(newPrice),
|
||||
const [addMenuItem, { data }] = useMutation<addMenuItemMutation>(
|
||||
GET_EATERY_MENU,
|
||||
{
|
||||
client: eateryClient,
|
||||
fetchPolicy: "no-cache",
|
||||
},
|
||||
);
|
||||
if (added) setMenuItems((prev) => [...prev, added]);
|
||||
|
||||
await addMenuItem({
|
||||
variables: {
|
||||
name: newName,
|
||||
price: newPrice,
|
||||
},
|
||||
});
|
||||
|
||||
if (data) setMenuItems((prev) => [...prev, data.addMenuItem]);
|
||||
|
||||
setNewName("");
|
||||
setNewPrice("");
|
||||
setShowForm(false);
|
||||
@@ -116,17 +122,6 @@ export default function MenuItemsTab() {
|
||||
);
|
||||
}
|
||||
|
||||
if (!eateryId) {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center py-16 text-(--color-text-muted)">
|
||||
<i className="fa-solid fa-store mb-2 block text-3xl opacity-30"></i>
|
||||
<p className="text-sm">
|
||||
Quán của bạn chưa được khởi tạo trong hệ thống.
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
{/* Toolbar */}
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
import type { Eatery } from "./types";
|
||||
|
||||
export async function gqlFetch<T = Record<string, unknown>>(
|
||||
query: string,
|
||||
variables?: Record<string, unknown>,
|
||||
): Promise<T> {
|
||||
const res = await fetch("/api/eatery/graphql", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
credentials: "include",
|
||||
body: JSON.stringify({ query, variables }),
|
||||
});
|
||||
|
||||
if (!res.ok) throw new Error(`GraphQL request failed: ${res.status}`);
|
||||
return res.json() as Promise<T>;
|
||||
}
|
||||
|
||||
export async function addManagerMenuItem(
|
||||
name: string,
|
||||
price: number,
|
||||
): Promise<{ id: string; name: string; price: number } | null> {
|
||||
const data = await gqlFetch<{
|
||||
addMenuItem: { id: string; name: string; price: number } | null;
|
||||
}>(
|
||||
`mutation($name: String!, $price: Float!) {
|
||||
addMenuItem(name: $name, price: $price) { id name price }
|
||||
}`,
|
||||
{ name, price },
|
||||
);
|
||||
return data.addMenuItem;
|
||||
}
|
||||
|
||||
export async function fetchManagerEatery(): Promise<Eatery | null> {
|
||||
const data = await gqlFetch<{ eateriesByOwner: Eatery | null }>(`
|
||||
query {
|
||||
eateriesByOwner {
|
||||
id
|
||||
ownerId
|
||||
name
|
||||
isVerified
|
||||
}
|
||||
}
|
||||
`);
|
||||
return data.eateriesByOwner;
|
||||
}
|
||||
@@ -147,6 +147,7 @@ export interface Department {
|
||||
}
|
||||
|
||||
export interface MenuItemEntity {
|
||||
id: string;
|
||||
name: string;
|
||||
price: number;
|
||||
eatery: EateryEntity;
|
||||
@@ -165,3 +166,7 @@ export interface EateryEntity {
|
||||
export interface allEateriesQuery {
|
||||
allEateries: EateryEntity[];
|
||||
}
|
||||
|
||||
export interface addMenuItemMutation {
|
||||
addMenuItem: MenuItemEntity;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user