diff --git a/.gitignore b/.gitignore index 96fab4fe..741beb55 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,6 @@ yarn-error.log* # Misc .DS_Store *.pem + +#kafka certificates +certs/ \ No newline at end of file diff --git a/apps/admin/eslint.config.js b/apps/admin/eslint.config.mjs similarity index 100% rename from apps/admin/eslint.config.js rename to apps/admin/eslint.config.mjs diff --git a/apps/admin/next.config.ts b/apps/admin/next.config.ts index cd6877f6..38e6225c 100644 --- a/apps/admin/next.config.ts +++ b/apps/admin/next.config.ts @@ -2,22 +2,23 @@ import type { NextConfig } from "next"; const nextConfig: NextConfig = { /* config options here */ - images:{ - remotePatterns:[ + + images: { + remotePatterns: [ { - protocol:"https", - hostname:"images.pexels.com", + protocol: "https", + hostname: "images.pexels.com", }, { - protocol:"https", - hostname:"img.clerk.com", + protocol: "https", + hostname: "img.clerk.com", }, { - protocol:"https", - hostname:"res.cloudinary.com", - } - ] - } + protocol: "https", + hostname: "res.cloudinary.com", + }, + ], + }, }; export default nextConfig; diff --git a/apps/admin/package.json b/apps/admin/package.json index 12eea518..d9169b17 100644 --- a/apps/admin/package.json +++ b/apps/admin/package.json @@ -10,8 +10,8 @@ "check-types": "tsc --noEmit" }, "dependencies": { - "@clerk/nextjs": "^6.31.10", - "@hookform/resolvers": "^5.2.2", + "@clerk/nextjs": "^7.0.6", + "@hookform/resolvers": "^5.0.1", "@radix-ui/react-avatar": "^1.1.4", "@radix-ui/react-checkbox": "^1.1.5", "@radix-ui/react-collapsible": "^1.1.4", @@ -26,23 +26,23 @@ "@radix-ui/react-separator": "^1.1.3", "@radix-ui/react-slot": "^1.2.0", "@radix-ui/react-tooltip": "^1.2.0", - "@tanstack/react-query": "^5.89.0", + "@tanstack/react-query": "^5.95.2", "@tanstack/react-table": "^8.21.3", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "date-fns": "^4.1.0", "lucide-react": "^0.488.0", - "next": "15.3.0", + "next": "15.4.5", "next-themes": "^0.4.6", "react": "^19.0.0", "react-day-picker": "8.10.1", "react-dom": "^19.0.0", - "react-hook-form": "^7.62.0", + "react-hook-form": "^7.55.0", "react-toastify": "^11.0.5", "recharts": "^2.15.2", "tailwind-merge": "^3.2.0", "tw-animate-css": "^1.2.5", - "zod": "^4.1.9" + "zod": "^4.3.6" }, "devDependencies": { "@repo/eslint-config": "workspace:*", diff --git a/apps/admin/public/logo.png b/apps/admin/public/logo.png new file mode 100644 index 00000000..906ee6be Binary files /dev/null and b/apps/admin/public/logo.png differ diff --git a/apps/admin/public/logo.svg b/apps/admin/public/logo.svg deleted file mode 100644 index 77d781b9..00000000 --- a/apps/admin/public/logo.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/apps/admin/public/products/1g.png b/apps/admin/public/products/1g.png deleted file mode 100644 index d73aac42..00000000 Binary files a/apps/admin/public/products/1g.png and /dev/null differ diff --git a/apps/admin/public/products/1gr.png b/apps/admin/public/products/1gr.png deleted file mode 100644 index fdc6ec5d..00000000 Binary files a/apps/admin/public/products/1gr.png and /dev/null differ diff --git a/apps/admin/public/products/1p.png b/apps/admin/public/products/1p.png deleted file mode 100644 index a589132e..00000000 Binary files a/apps/admin/public/products/1p.png and /dev/null differ diff --git a/apps/admin/public/products/2g.png b/apps/admin/public/products/2g.png deleted file mode 100644 index 5fe4a943..00000000 Binary files a/apps/admin/public/products/2g.png and /dev/null differ diff --git a/apps/admin/public/products/2gr.png b/apps/admin/public/products/2gr.png deleted file mode 100644 index 0f15bc73..00000000 Binary files a/apps/admin/public/products/2gr.png and /dev/null differ diff --git a/apps/admin/public/products/3b.png b/apps/admin/public/products/3b.png deleted file mode 100644 index db2bee27..00000000 Binary files a/apps/admin/public/products/3b.png and /dev/null differ diff --git a/apps/admin/public/products/3bl.png b/apps/admin/public/products/3bl.png deleted file mode 100644 index 6c643e85..00000000 Binary files a/apps/admin/public/products/3bl.png and /dev/null differ diff --git a/apps/admin/public/products/3gr.png b/apps/admin/public/products/3gr.png deleted file mode 100644 index 0d81d5aa..00000000 Binary files a/apps/admin/public/products/3gr.png and /dev/null differ diff --git a/apps/admin/public/products/4p.png b/apps/admin/public/products/4p.png deleted file mode 100644 index 2f76025a..00000000 Binary files a/apps/admin/public/products/4p.png and /dev/null differ diff --git a/apps/admin/public/products/4w.png b/apps/admin/public/products/4w.png deleted file mode 100644 index 6699256b..00000000 Binary files a/apps/admin/public/products/4w.png and /dev/null differ diff --git a/apps/admin/public/products/5bl.png b/apps/admin/public/products/5bl.png deleted file mode 100644 index 7afeea53..00000000 Binary files a/apps/admin/public/products/5bl.png and /dev/null differ diff --git a/apps/admin/public/products/5o.png b/apps/admin/public/products/5o.png deleted file mode 100644 index 27071598..00000000 Binary files a/apps/admin/public/products/5o.png and /dev/null differ diff --git a/apps/admin/public/products/5r.png b/apps/admin/public/products/5r.png deleted file mode 100644 index 50be51fe..00000000 Binary files a/apps/admin/public/products/5r.png and /dev/null differ diff --git a/apps/admin/public/products/6g.png b/apps/admin/public/products/6g.png deleted file mode 100644 index 08ab9749..00000000 Binary files a/apps/admin/public/products/6g.png and /dev/null differ diff --git a/apps/admin/public/products/6w.png b/apps/admin/public/products/6w.png deleted file mode 100644 index 57ad9e37..00000000 Binary files a/apps/admin/public/products/6w.png and /dev/null differ diff --git a/apps/admin/public/products/7g.png b/apps/admin/public/products/7g.png deleted file mode 100644 index 2c782d58..00000000 Binary files a/apps/admin/public/products/7g.png and /dev/null differ diff --git a/apps/admin/public/products/7p.png b/apps/admin/public/products/7p.png deleted file mode 100644 index 2965edde..00000000 Binary files a/apps/admin/public/products/7p.png and /dev/null differ diff --git a/apps/admin/public/products/8b.png b/apps/admin/public/products/8b.png deleted file mode 100644 index 611cc7eb..00000000 Binary files a/apps/admin/public/products/8b.png and /dev/null differ diff --git a/apps/admin/public/products/8gr.png b/apps/admin/public/products/8gr.png deleted file mode 100644 index a6be86cf..00000000 Binary files a/apps/admin/public/products/8gr.png and /dev/null differ diff --git a/apps/admin/public/users/1.png b/apps/admin/public/users/1.png deleted file mode 100644 index c1b3f74f..00000000 Binary files a/apps/admin/public/users/1.png and /dev/null differ diff --git a/apps/admin/public/users/10.png b/apps/admin/public/users/10.png deleted file mode 100644 index bff1ded7..00000000 Binary files a/apps/admin/public/users/10.png and /dev/null differ diff --git a/apps/admin/public/users/11.png b/apps/admin/public/users/11.png deleted file mode 100644 index 4f788106..00000000 Binary files a/apps/admin/public/users/11.png and /dev/null differ diff --git a/apps/admin/public/users/12.png b/apps/admin/public/users/12.png deleted file mode 100644 index db32c15f..00000000 Binary files a/apps/admin/public/users/12.png and /dev/null differ diff --git a/apps/admin/public/users/13.png b/apps/admin/public/users/13.png deleted file mode 100644 index c76bf680..00000000 Binary files a/apps/admin/public/users/13.png and /dev/null differ diff --git a/apps/admin/public/users/14.png b/apps/admin/public/users/14.png deleted file mode 100644 index cdb89954..00000000 Binary files a/apps/admin/public/users/14.png and /dev/null differ diff --git a/apps/admin/public/users/15.png b/apps/admin/public/users/15.png deleted file mode 100644 index b423d45a..00000000 Binary files a/apps/admin/public/users/15.png and /dev/null differ diff --git a/apps/admin/public/users/16.png b/apps/admin/public/users/16.png deleted file mode 100644 index 2604966f..00000000 Binary files a/apps/admin/public/users/16.png and /dev/null differ diff --git a/apps/admin/public/users/17.png b/apps/admin/public/users/17.png deleted file mode 100644 index 7cfd3f15..00000000 Binary files a/apps/admin/public/users/17.png and /dev/null differ diff --git a/apps/admin/public/users/18.png b/apps/admin/public/users/18.png deleted file mode 100644 index 9806973e..00000000 Binary files a/apps/admin/public/users/18.png and /dev/null differ diff --git a/apps/admin/public/users/19.png b/apps/admin/public/users/19.png deleted file mode 100644 index 2ef28526..00000000 Binary files a/apps/admin/public/users/19.png and /dev/null differ diff --git a/apps/admin/public/users/2.png b/apps/admin/public/users/2.png deleted file mode 100644 index 085e056f..00000000 Binary files a/apps/admin/public/users/2.png and /dev/null differ diff --git a/apps/admin/public/users/20.png b/apps/admin/public/users/20.png deleted file mode 100644 index 938650e7..00000000 Binary files a/apps/admin/public/users/20.png and /dev/null differ diff --git a/apps/admin/public/users/21.png b/apps/admin/public/users/21.png deleted file mode 100644 index 248964fa..00000000 Binary files a/apps/admin/public/users/21.png and /dev/null differ diff --git a/apps/admin/public/users/22.png b/apps/admin/public/users/22.png deleted file mode 100644 index 39e70fcd..00000000 Binary files a/apps/admin/public/users/22.png and /dev/null differ diff --git a/apps/admin/public/users/23.png b/apps/admin/public/users/23.png deleted file mode 100644 index b29b4a6e..00000000 Binary files a/apps/admin/public/users/23.png and /dev/null differ diff --git a/apps/admin/public/users/24.png b/apps/admin/public/users/24.png deleted file mode 100644 index 0e779852..00000000 Binary files a/apps/admin/public/users/24.png and /dev/null differ diff --git a/apps/admin/public/users/25.png b/apps/admin/public/users/25.png deleted file mode 100644 index 950290b6..00000000 Binary files a/apps/admin/public/users/25.png and /dev/null differ diff --git a/apps/admin/public/users/26.png b/apps/admin/public/users/26.png deleted file mode 100644 index 95f79de8..00000000 Binary files a/apps/admin/public/users/26.png and /dev/null differ diff --git a/apps/admin/public/users/27.png b/apps/admin/public/users/27.png deleted file mode 100644 index d95bb225..00000000 Binary files a/apps/admin/public/users/27.png and /dev/null differ diff --git a/apps/admin/public/users/28.png b/apps/admin/public/users/28.png deleted file mode 100644 index 3922f069..00000000 Binary files a/apps/admin/public/users/28.png and /dev/null differ diff --git a/apps/admin/public/users/29.png b/apps/admin/public/users/29.png deleted file mode 100644 index 2a5e55f3..00000000 Binary files a/apps/admin/public/users/29.png and /dev/null differ diff --git a/apps/admin/public/users/3.png b/apps/admin/public/users/3.png deleted file mode 100644 index caf1ecf0..00000000 Binary files a/apps/admin/public/users/3.png and /dev/null differ diff --git a/apps/admin/public/users/30.png b/apps/admin/public/users/30.png deleted file mode 100644 index af04f7c7..00000000 Binary files a/apps/admin/public/users/30.png and /dev/null differ diff --git a/apps/admin/public/users/31.png b/apps/admin/public/users/31.png deleted file mode 100644 index 476f665e..00000000 Binary files a/apps/admin/public/users/31.png and /dev/null differ diff --git a/apps/admin/public/users/32.png b/apps/admin/public/users/32.png deleted file mode 100644 index b13c3bc2..00000000 Binary files a/apps/admin/public/users/32.png and /dev/null differ diff --git a/apps/admin/public/users/33.png b/apps/admin/public/users/33.png deleted file mode 100644 index 80cba9ff..00000000 Binary files a/apps/admin/public/users/33.png and /dev/null differ diff --git a/apps/admin/public/users/34.png b/apps/admin/public/users/34.png deleted file mode 100644 index 00dc3de9..00000000 Binary files a/apps/admin/public/users/34.png and /dev/null differ diff --git a/apps/admin/public/users/35.png b/apps/admin/public/users/35.png deleted file mode 100644 index cd940c94..00000000 Binary files a/apps/admin/public/users/35.png and /dev/null differ diff --git a/apps/admin/public/users/36.png b/apps/admin/public/users/36.png deleted file mode 100644 index 20f540d7..00000000 Binary files a/apps/admin/public/users/36.png and /dev/null differ diff --git a/apps/admin/public/users/4.png b/apps/admin/public/users/4.png deleted file mode 100644 index d5e2091c..00000000 Binary files a/apps/admin/public/users/4.png and /dev/null differ diff --git a/apps/admin/public/users/5.png b/apps/admin/public/users/5.png deleted file mode 100644 index c490844e..00000000 Binary files a/apps/admin/public/users/5.png and /dev/null differ diff --git a/apps/admin/public/users/6.png b/apps/admin/public/users/6.png deleted file mode 100644 index 3bb30b0b..00000000 Binary files a/apps/admin/public/users/6.png and /dev/null differ diff --git a/apps/admin/public/users/7.png b/apps/admin/public/users/7.png deleted file mode 100644 index dba85e21..00000000 Binary files a/apps/admin/public/users/7.png and /dev/null differ diff --git a/apps/admin/public/users/8.png b/apps/admin/public/users/8.png deleted file mode 100644 index 2e03395b..00000000 Binary files a/apps/admin/public/users/8.png and /dev/null differ diff --git a/apps/admin/public/users/9.png b/apps/admin/public/users/9.png deleted file mode 100644 index fee88c12..00000000 Binary files a/apps/admin/public/users/9.png and /dev/null differ diff --git a/apps/admin/src/app/(auth)/unauthorized/page.tsx b/apps/admin/src/app/(auth)/unauthorized/page.tsx index 00a61399..45e5c563 100644 --- a/apps/admin/src/app/(auth)/unauthorized/page.tsx +++ b/apps/admin/src/app/(auth)/unauthorized/page.tsx @@ -1,13 +1,14 @@ "use client"; import { useAuth } from "@clerk/nextjs"; +import React from "react"; const Page = () => { const { signOut } = useAuth(); return (

You do not have an access!

- +
); }; diff --git a/apps/admin/src/app/(dashboard)/layout.tsx b/apps/admin/src/app/(dashboard)/layout.tsx index 1a7cfd09..37a6bd86 100644 --- a/apps/admin/src/app/(dashboard)/layout.tsx +++ b/apps/admin/src/app/(dashboard)/layout.tsx @@ -6,6 +6,7 @@ import { SidebarProvider } from "@/components/ui/sidebar"; import { cookies } from "next/headers"; import { ToastContainer } from "react-toastify"; +// dashboard layout export default async function RootLayout({ children, }: Readonly<{ diff --git a/apps/admin/src/app/(dashboard)/orders/columns.tsx b/apps/admin/src/app/(dashboard)/orders/columns.tsx index a5580f75..b2be5f4a 100644 --- a/apps/admin/src/app/(dashboard)/orders/columns.tsx +++ b/apps/admin/src/app/(dashboard)/orders/columns.tsx @@ -48,6 +48,14 @@ export const columns: ColumnDef[] = [ accessorKey: "_id", header: "ID", }, + { + accessorKey: "username", + header: "Username", + cell: ({ row }) => { + const order = row.original; + return
{order.username || "-"}
; + }, + }, { accessorKey: "email", header: ({ column }) => { @@ -74,7 +82,7 @@ export const columns: ColumnDef[] = [ `p-1 rounded-md w-max text-xs`, status === "pending" && "bg-yellow-500/40", status === "success" && "bg-green-500/40", - status === "failed" && "bg-red-500/40" + status === "failed" && "bg-red-500/40", )} > {status as string} @@ -86,11 +94,16 @@ export const columns: ColumnDef[] = [ accessorKey: "amount", header: () =>
Amount
, cell: ({ row }) => { - const amount = parseFloat(row.getValue("amount")); + const order = row.original; + const amount = + order.products?.reduce( + (sum, product) => sum + product.price * product.quantity, + 0, + ) ?? parseFloat(row.getValue("amount")); const formatted = new Intl.NumberFormat("en-US", { style: "currency", currency: "USD", - }).format(amount/100); + }).format(amount); return
{formatted}
; }, @@ -116,7 +129,7 @@ export const columns: ColumnDef[] = [ Copy order ID - + View customer View order details diff --git a/apps/admin/src/app/(dashboard)/orders/data-table.tsx b/apps/admin/src/app/(dashboard)/orders/data-table.tsx index a899d580..85c8de94 100644 --- a/apps/admin/src/app/(dashboard)/orders/data-table.tsx +++ b/apps/admin/src/app/(dashboard)/orders/data-table.tsx @@ -21,6 +21,11 @@ import { import { DataTablePagination } from "@/components/TablePagination"; import { useState } from "react"; import { Trash2 } from "lucide-react"; +import { useAuth } from "@clerk/nextjs"; +import { useMutation } from "@tanstack/react-query"; +import { toast } from "react-toastify"; +import { OrderType } from "@repo/types"; +import { useRouter } from "next/navigation"; interface DataTableProps { columns: ColumnDef[]; @@ -48,14 +53,55 @@ export function DataTable({ }, }); - console.log(rowSelection); + const { getToken } = useAuth(); + const router = useRouter(); + + const mutation = useMutation({ + mutationFn: async () => { + const token = await getToken(); + const selectedRows = table.getSelectedRowModel().rows; + + await Promise.all( + selectedRows.map(async (row) => { + const orderId = (row.original as OrderType)._id; + + const res = await fetch( + `${process.env.NEXT_PUBLIC_ORDER_SERVICE_URL}/orders/${orderId}`, + { + method: "DELETE", + headers: { + Authorization: `Bearer ${token}`, + }, + }, + ); + + if (!res.ok) { + throw new Error(`Failed to delete order ${orderId}`); + } + }), + ); + }, + onSuccess: () => { + toast.success("Order(s) deleted successfully"); + setRowSelection({}); + router.refresh(); + }, + onError: (error) => { + toast.error(error.message); + }, + }); + return (
{Object.keys(rowSelection).length > 0 && (
-
)} @@ -70,7 +116,7 @@ export function DataTable({ ? null : flexRender( header.column.columnDef.header, - header.getContext() + header.getContext(), )} ); diff --git a/apps/admin/src/app/(dashboard)/orders/page.tsx b/apps/admin/src/app/(dashboard)/orders/page.tsx index 1137f789..255618a4 100644 --- a/apps/admin/src/app/(dashboard)/orders/page.tsx +++ b/apps/admin/src/app/(dashboard)/orders/page.tsx @@ -7,16 +7,31 @@ const getData = async (): Promise => { try { const { getToken } = await auth(); const token = await getToken(); + + if (!token) { + console.error("Missing Clerk token for admin orders page."); + return []; + } + const res = await fetch( `${process.env.NEXT_PUBLIC_ORDER_SERVICE_URL}/orders`, { headers: { Authorization: `Bearer ${token}`, }, - } + cache: "no-store", + }, ); + + if (!res.ok) { + console.error( + `Failed to fetch orders: ${res.status} ${res.statusText}`, + ); + return []; + } + const data = await res.json(); - return data; + return Array.isArray(data) ? data : []; } catch (err) { console.log(err); return []; @@ -28,7 +43,7 @@ const OrdersPage = async () => { return (
-

All Payments

+

All Orders

diff --git a/apps/admin/src/app/(dashboard)/page.tsx b/apps/admin/src/app/(dashboard)/page.tsx index 1908eb4b..644c9dcf 100644 --- a/apps/admin/src/app/(dashboard)/page.tsx +++ b/apps/admin/src/app/(dashboard)/page.tsx @@ -2,40 +2,35 @@ import AppAreaChart from "@/components/AppAreaChart"; import AppBarChart from "@/components/AppBarChart"; import AppPieChart from "@/components/AppPieChart"; import CardList from "@/components/CardList"; -import TodoList from "@/components/TodoList"; import { auth } from "@clerk/nextjs/server"; const Homepage = async () => { const { getToken } = await auth(); const token = await getToken(); - const orderChartData = fetch( + // 由于子组件client component,父组件里fetch + const orderChartdata = fetch( `${process.env.NEXT_PUBLIC_ORDER_SERVICE_URL}/order-chart`, { headers: { Authorization: `Bearer ${token}`, }, - } - ); + }, + ).then((res) => res.json()); + return (
- +
- +
-
- -
-
- -
); }; diff --git a/apps/admin/src/app/(dashboard)/products/data-table.tsx b/apps/admin/src/app/(dashboard)/products/data-table.tsx index bae12744..b37e9eb5 100644 --- a/apps/admin/src/app/(dashboard)/products/data-table.tsx +++ b/apps/admin/src/app/(dashboard)/products/data-table.tsx @@ -21,6 +21,11 @@ import { import { DataTablePagination } from "@/components/TablePagination"; import { useState } from "react"; import { Trash2 } from "lucide-react"; +import { useAuth } from "@clerk/nextjs"; +import { useMutation } from "@tanstack/react-query"; +import { toast } from "react-toastify"; +import { ProductType } from "@repo/types"; +import { useRouter } from "next/navigation"; interface DataTableProps { columns: ColumnDef[]; @@ -48,13 +53,55 @@ export function DataTable({ }, }); + const { getToken } = useAuth(); + const router = useRouter(); + + const mutation = useMutation({ + mutationFn: async () => { + const token = await getToken(); + const selectedRows = table.getSelectedRowModel().rows; + + await Promise.all( + selectedRows.map(async (row) => { + const productId = (row.original as ProductType).id; + + const res = await fetch( + `${process.env.NEXT_PUBLIC_PRODUCT_SERVICE_URL}/products/${productId}`, + { + method: "DELETE", + headers: { + Authorization: `Bearer ${token}`, + }, + }, + ); + + if (!res.ok) { + throw new Error(`Failed to delete product ${productId}`); + } + }), + ); + }, + onSuccess: () => { + toast.success("Product(s) deleted successfully"); + setRowSelection({}); + router.refresh(); + }, + onError: (error) => { + toast.error(error.message); + }, + }); + return (
{Object.keys(rowSelection).length > 0 && (
-
)} @@ -69,7 +116,7 @@ export function DataTable({ ? null : flexRender( header.column.columnDef.header, - header.getContext() + header.getContext(), )} ); diff --git a/apps/admin/src/app/(dashboard)/products/page.tsx b/apps/admin/src/app/(dashboard)/products/page.tsx index 2690378f..5fd40e57 100644 --- a/apps/admin/src/app/(dashboard)/products/page.tsx +++ b/apps/admin/src/app/(dashboard)/products/page.tsx @@ -1,11 +1,11 @@ -import { ProductsType } from "@repo/types"; +import { ProductType } from "@repo/types"; import { columns } from "./columns"; import { DataTable } from "./data-table"; -const getData = async (): Promise => { +const getData = async (): Promise => { try { const res = await fetch( - `${process.env.NEXT_PUBLIC_PRODUCT_SERVICE_URL}/products` + `${process.env.NEXT_PUBLIC_PRODUCT_SERVICE_URL}/products`, ); const data = await res.json(); return data; @@ -15,11 +15,12 @@ const getData = async (): Promise => { } }; -const ProductPage = async () => { +const ProductsPage = async () => { const data = await getData(); + return (
-
+

All Products

@@ -27,4 +28,4 @@ const ProductPage = async () => { ); }; -export default ProductPage; +export default ProductsPage; diff --git a/apps/admin/src/app/(dashboard)/users/[id]/page.tsx b/apps/admin/src/app/(dashboard)/users/[id]/page.tsx index 13abf7f8..1c106b73 100644 --- a/apps/admin/src/app/(dashboard)/users/[id]/page.tsx +++ b/apps/admin/src/app/(dashboard)/users/[id]/page.tsx @@ -20,11 +20,13 @@ import { Button } from "@/components/ui/button"; import EditUser from "@/components/EditUser"; import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; import AppLineChart from "@/components/AppLineChart"; -import { auth, User } from "@clerk/nextjs/server"; +import React from "react"; +import { auth, type User } from "@clerk/nextjs/server"; const getData = async (id: string): Promise => { const { getToken } = await auth(); const token = await getToken(); + try { const res = await fetch( `${process.env.NEXT_PUBLIC_AUTH_SERVICE_URL}/users/${id}`, @@ -32,8 +34,10 @@ const getData = async (id: string): Promise => { headers: { Authorization: `Bearer ${token}`, }, - } + cache: "no-store", + }, ); + const data = await res.json(); return data; } catch (err) { @@ -42,16 +46,12 @@ const getData = async (id: string): Promise => { } }; -const SingleUserPage = async ({ - params, -}: { - params: Promise<{ id: string }>; -}) => { - const { id } = await params; +const SingleUserPage = async ({ params }: { params: { id: string } }) => { + const { id } = params; const data = await getData(id); if (!data) { - return
User not found!
; + return
User not found
; } return ( @@ -68,7 +68,7 @@ const SingleUserPage = async ({ - {data?.firstName + " " + data?.lastName || data?.username || "-"} + {data?.firstName + " " + data?.lastName || data?.lastName || "-"} @@ -147,13 +147,13 @@ const SingleUserPage = async ({ {data?.firstName?.charAt(0) || - data?.username?.charAt(0) || + data?.lastName?.charAt(0) || "-"}

{data?.firstName + " " + data?.lastName || - data?.username || + data?.lastName || "-"}

@@ -186,17 +186,13 @@ const SingleUserPage = async ({ Full name: {data?.firstName + " " + data?.lastName || - data?.username || + data?.lastName || "-"}
-
- Email: - {data.emailAddresses[0]?.emailAddress || "-"} -
Phone: - {data.phoneNumbers[0]?.phoneNumber || "-"} + {data.emailAddresses[0]?.emailAddress || "-"}
Role: @@ -208,7 +204,7 @@ const SingleUserPage = async ({

- Joined on {new Date(data.createdAt).toLocaleDateString("en-US")} + Joined on {new Date(data.createdAt).toLocaleString("zh-CN")}

diff --git a/apps/admin/src/app/(dashboard)/users/columns.tsx b/apps/admin/src/app/(dashboard)/users/columns.tsx index d2cc0250..7a414634 100644 --- a/apps/admin/src/app/(dashboard)/users/columns.tsx +++ b/apps/admin/src/app/(dashboard)/users/columns.tsx @@ -91,15 +91,15 @@ export const columns: ColumnDef[] = [ accessorKey: "status", header: "Status", cell: ({ row }) => { - const user = row.original - const status = user.banned ? "banned" : "active" + const user = row.original; + const status = user.banned ? "banned" : "active"; return (
{status as string} @@ -128,7 +128,7 @@ export const columns: ColumnDef[] = [ Copy user ID - + View customer diff --git a/apps/admin/src/app/(dashboard)/users/data-table.tsx b/apps/admin/src/app/(dashboard)/users/data-table.tsx index dbaeddc8..ad1e1e22 100644 --- a/apps/admin/src/app/(dashboard)/users/data-table.tsx +++ b/apps/admin/src/app/(dashboard)/users/data-table.tsx @@ -23,8 +23,8 @@ import { useState } from "react"; import { Trash2 } from "lucide-react"; import { useAuth } from "@clerk/nextjs"; import { useMutation } from "@tanstack/react-query"; -import { User } from "@clerk/nextjs/server"; import { toast } from "react-toastify"; +import { User } from "@clerk/nextjs/server"; import { useRouter } from "next/navigation"; interface DataTableProps { @@ -54,16 +54,17 @@ export function DataTable({ }); const { getToken } = useAuth(); - const router = useRouter() + const router = useRouter(); const mutation = useMutation({ mutationFn: async () => { const token = await getToken(); const selectedRows = table.getSelectedRowModel().rows; - Promise.all( + await Promise.all( selectedRows.map(async (row) => { const userId = (row.original as User).id; + const res = await fetch( `${process.env.NEXT_PUBLIC_AUTH_SERVICE_URL}/users/${userId}`, { @@ -71,14 +72,19 @@ export function DataTable({ headers: { Authorization: `Bearer ${token}`, }, - } + }, ); - }) + + if (!res.ok) { + throw new Error(`Failed to delete user ${userId}`); + } + }), ); }, onSuccess: () => { toast.success("User(s) deleted successfully"); - router.refresh() + setRowSelection({}); + router.refresh(); }, onError: (error) => { toast.error(error.message); @@ -90,7 +96,7 @@ export function DataTable({ {Object.keys(rowSelection).length > 0 && (
+ diff --git a/apps/admin/src/components/AddProduct.tsx b/apps/admin/src/components/AddProduct.tsx index fb109043..886a4131 100644 --- a/apps/admin/src/components/AddProduct.tsx +++ b/apps/admin/src/components/AddProduct.tsx @@ -29,7 +29,6 @@ import { import { Button } from "./ui/button"; import { Textarea } from "./ui/textarea"; import { Checkbox } from "./ui/checkbox"; -import { ScrollArea } from "./ui/scroll-area"; import { CategoryType, colors, ProductFormSchema, sizes } from "@repo/types"; import { useMutation, useQuery } from "@tanstack/react-query"; import { toast } from "react-toastify"; @@ -47,7 +46,7 @@ import { useAuth } from "@clerk/nextjs"; const fetchCategories = async () => { const res = await fetch( - `${process.env.NEXT_PUBLIC_PRODUCT_SERVICE_URL}/categories` + `${process.env.NEXT_PUBLIC_PRODUCT_SERVICE_URL}/categories`, ); if (!res.ok) { @@ -91,7 +90,7 @@ const AddProduct = () => { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, - } + }, ); if (!res.ok) { throw new Error("Failed to create product!"); @@ -106,291 +105,284 @@ const AddProduct = () => { }); return ( - - - - Add Product - -
- mutation.mutate(data))} - > - ( - - Name + + + Add Product + + Create a new product and assign it to a category. + + +
+ + mutation.mutate(data))} + > + ( + + Name + + + + + Enter the name of the product. + + + + )} + /> + ( + + Short Description + + + + + Enter the short description of the product. + + + + )} + /> + ( + + Description + +