diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 5ebbba1..474a6e4 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,26 +1,26 @@ // For format details, see https://aka.ms/devcontainer.json. For config options, see the // README at: https://github.com/devcontainers/templates/tree/main/src/alpine { - "name": "Alpine", - // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile - "image": "mcr.microsoft.com/devcontainers/base:alpine-3.22", + "name": "Alpine", + // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile + "image": "mcr.microsoft.com/devcontainers/base:alpine-3.22", - "features": { - "ghcr.io/muhmdraouf/devcontainers-features/alpine-apk:0": { - "packages": "pnpm", - "upgradePackages": true - } - }, + "features": { + "ghcr.io/muhmdraouf/devcontainers-features/alpine-apk:0": { + "packages": "pnpm", + "upgradePackages": true + } + } - // Use 'forwardPorts' to make a list of ports inside the container available locally. - // "forwardPorts": [], + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], - // Use 'postCreateCommand' to run commands after the container is created. - // "postCreateCommand": "uname -a", + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "uname -a", - // Configure tool-specific properties. - // "customizations": {}, + // Configure tool-specific properties. + // "customizations": {}, - // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. - // "remoteUser": "root" + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + // "remoteUser": "root" } diff --git a/README.md b/README.md index 019fe74..f3fdc1b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Coffee Shop Frontend -Dự án Frontend cho hệ thống đặt món cà phê, xây dựng bằng Next.js App Router, React 19, TypeScript và Tailwind CSS v4. +Dự án Frontend cho hệ thống đặt món cà phê, xây dựng bằng Next.js App Router, +React 19, TypeScript và Tailwind CSS v4. --- @@ -9,14 +10,18 @@ Dự án Frontend cho hệ thống đặt món cà phê, xây dựng bằng Next Giao diện người dùng (frontend) cho hệ thống đặt và bán đồ uống trực tuyến. ### Trang Người Dùng (User Page - /) + Dành cho khách hàng: + - Duyệt thực đơn theo danh mục (sidebar collapsible) - Tìm kiếm món theo tên / mô tả - Xem card sản phẩm với giá và nút Mua - Lọc tự động theo trạng thái available ### Trang Quản Lý (Manager Page - chưa triển khai) + Dành cho chủ quán / nhân viên: + - Quản lý thực đơn (thêm, sửa, xóa món) - Theo dõi và xử lý đơn hàng @@ -25,26 +30,32 @@ Dành cho chủ quán / nhân viên: ## Cách Chạy Dự Án ### Yêu cầu hệ thống + - Node.js >= 18 - pnpm (khuyến nghị) hoặc npm ### Cài đặt + ```bash pnpm install ``` ### Dev + ```bash pnpm dev ``` + Mở trình duyệt tại http://localhost:3000 ### Build + ```bash pnpm build && pnpm start ``` ### Lint + ```bash pnpm lint ``` @@ -85,16 +96,16 @@ frondend/ ## Công Nghệ Sử Dụng -| Công nghệ | Phiên bản | Mục đích | -|-----------|-----------|----------| -| Next.js | 16.1.7 | React Framework (App Router) | -| React | 19.2.3 | Thư viện UI | -| TypeScript | ^5 | Kiểu dữ liệu tĩnh | -| Tailwind CSS | ^4 | Utility-first CSS framework | -| Geist Font | - | Font chữ (Google Fonts via next/font) | -| FontAwesome | 6.7.2 | Icon library (CDN) | -| pnpm | - | Package manager | -| ESLint | ^9 | Linting | +| Công nghệ | Phiên bản | Mục đích | +| ------------ | --------- | ------------------------------------- | +| Next.js | 16.1.7 | React Framework (App Router) | +| React | 19.2.3 | Thư viện UI | +| TypeScript | ^5 | Kiểu dữ liệu tĩnh | +| Tailwind CSS | ^4 | Utility-first CSS framework | +| Geist Font | - | Font chữ (Google Fonts via next/font) | +| FontAwesome | 6.7.2 | Icon library (CDN) | +| pnpm | - | Package manager | +| ESLint | ^9 | Linting | --- @@ -102,7 +113,8 @@ frondend/ - Trang chủ (app/page.tsx) là điểm vào chính của User Page - Design tokens định nghĩa trong app/globals.css dưới dạng CSS custom properties -- Mock data nằm trong lib/constants.ts - thay bằng API calls khi backend sẵn sàng +- Mock data nằm trong lib/constants.ts - thay bằng API calls khi backend sẵn + sàng - Dark mode: biến CSS đã chuẩn bị sẵn trong globals.css nhưng chưa kích hoạt - Ảnh sản phẩm: thêm ảnh thực vào public/imgs/products/ - Xem WORKFLOW.md để hiểu kiến trúc tổng thể và quy trình mở rộng dự án diff --git a/TODO.md b/TODO.md index 39ec01b..e0b819e 100644 --- a/TODO.md +++ b/TODO.md @@ -3,49 +3,66 @@ ## Completed Optimizations ### A. Dead Code Removed + - [x] lib/constants.ts - Removed unused NAV_LINKS export - [x] lib/types.ts - Removed unused NavLink interface -- [x] components/Navbar.tsx - Removed trivial handleClick wrapper; inlined onCategoryChange call +- [x] components/Navbar.tsx - Removed trivial handleClick wrapper; inlined + onCategoryChange call - [x] components/Navbar.tsx - Removed unused Link import ### B. Bugs / Inaccuracies Fixed -- [x] layouts/header.tsx - Fixed JSDoc: 3-column -> 2-column layout (no center section exists) + +- [x] layouts/header.tsx - Fixed JSDoc: 3-column -> 2-column layout (no center + section exists) - [x] app/page.tsx - Added available !== false filter to product list -- [x] app/page.tsx - Fixed setState-in-effect lint error: moved initial sidebar state to lazy useState initializer +- [x] app/page.tsx - Fixed setState-in-effect lint error: moved initial sidebar + state to lazy useState initializer - [x] next.config.ts - Added explanatory JSDoc comment ### C. Documentation Updated -- [x] README.md - Fixed file structure tree, removed SCSS, fixed dark mode note, updated tech table -- [x] components/COMPONENTS.md - Fixed CartProduct styling (was outdated w-64/text-red-500/bg-blue-600); added Navbar, Header, Footer sections + +- [x] README.md - Fixed file structure tree, removed SCSS, fixed dark mode note, + updated tech table +- [x] components/COMPONENTS.md - Fixed CartProduct styling (was outdated + w-64/text-red-500/bg-blue-600); added Navbar, Header, Footer sections ### D. New Documentation Created -- [x] WORKFLOW.md - Architecture, data flow, design token system, how-to guides, dev workflow + +- [x] WORKFLOW.md - Architecture, data flow, design token system, how-to guides, + dev workflow ### E. Mini-test Results + - [x] npm run lint - PASSED (0 errors, 0 warnings) -- [x] npm run build - PASSED (Compiled successfully, TypeScript clean, static pages generated) +- [x] npm run build - PASSED (Compiled successfully, TypeScript clean, static + pages generated) --- ## Pending Features (Future Work) ### Cart & Ordering + - [ ] Implement add-to-cart logic (onBuy callback in CartProduct) - [ ] Cart sidebar or modal with item list and total - [ ] Order submission flow - [ ] Payment page ### Backend Integration + - [ ] Replace MOCK_PRODUCTS with real API calls (lib/api.ts) - [ ] Replace MOCK_USERS with real authentication -- [ ] Product images: replace placeholder with real images in public/imgs/products/ +- [ ] Product images: replace placeholder with real images in + public/imgs/products/ ### Manager Page + - [ ] Create app/manager/page.tsx - [ ] Menu management (add/edit/delete products) - [ ] Order tracking dashboard ### UX Improvements + - [ ] Dark mode toggle (CSS variables already prepared in globals.css) - [ ] Loading skeleton for product grid - [ ] Toast notifications for cart actions diff --git a/app/layout.tsx b/app/layout.tsx index 2bbd2a1..c4e4c0d 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,9 +1,10 @@ +import CartFab from "@/components/CartFab"; +import Footer from "@/layouts/footer"; +import Header from "@/layouts/header"; import type { Metadata } from "next"; import { Geist, Geist_Mono } from "next/font/google"; + import "./globals.css"; -import Header from "@/layouts/header"; -import Footer from "@/layouts/footer"; -import CartFab from "@/components/CartFab"; import { Providers } from "./providers"; const geistSans = Geist({ @@ -43,16 +44,14 @@ export default function RootLayout({ /> {/* Sticky top header */}
{/* Page content (grows to fill remaining height) */} -
- {children} -
+
{children}
{/* Footer always at bottom */}