diff --git a/.claude/skills/agent-orchestrator/SKILL.md b/.claude/skills/agent-orchestrator/SKILL.md index 02570fa..90839a1 100644 --- a/.claude/skills/agent-orchestrator/SKILL.md +++ b/.claude/skills/agent-orchestrator/SKILL.md @@ -1,30 +1,39 @@ --- name: agent-orchestrator description: > - Breaks down large, multi-step software tasks into structured sub-agents on the Claude Code CLI using the Task tool. - Use this skill whenever the user describes a complex project or feature that has multiple components - e.g., "build a login API with JWT and unit tests", "set up a CI/CD pipeline with Docker and GitHub Actions", "create a full-stack todo app with auth, REST API, and frontend". - Trigger this skill when the task clearly has more than one distinct sub-system, layer, or concern that could be worked on in parallel or in sequence. - DO NOT trigger for simple, single-step tasks like "write a function to reverse a string" or "fix this bug". + Breaks down large, multi-step software tasks into structured sub-agents on the + Claude Code CLI using the Task tool. Use this skill whenever the user + describes a complex project or feature that has multiple components - e.g., + "build a login API with JWT and unit tests", "set up a CI/CD pipeline with + Docker and GitHub Actions", "create a full-stack todo app with auth, REST API, + and frontend". Trigger this skill when the task clearly has more than one + distinct sub-system, layer, or concern that could be worked on in parallel or + in sequence. DO NOT trigger for simple, single-step tasks like "write a + function to reverse a string" or "fix this bug". --- # Agent Orchestrator -A skill for decomposing large engineering tasks into parallel and sequential sub-agents on Claude Code CLI using the **Task tool**. +A skill for decomposing large engineering tasks into parallel and sequential +sub-agents on Claude Code CLI using the **Task tool**. ## When to Use Trigger when the user's task has **multiple distinct components** - for example: + - "Build a REST API with authentication, rate limiting, and unit tests" - "Set up a monorepo with shared packages, CI pipeline, and deployment configs" -- "Create a data pipeline: ingest transform store visualize" +- "Create a data pipeline: ingest transform store visualize" -Do **not** trigger for single-step tasks (e.g., "rename this variable", "add a README"). +Do **not** trigger for single-step tasks (e.g., "rename this variable", "add a +README"). --- ## Prompt Template -Copy the block below and paste it into your Agent Code CLI session. Replace the placeholder in the `TASK` variable with your actual task description. +Copy the block below and paste it into your Agent Code CLI session. Replace the +placeholder in the `TASK` variable with your actual task description. --- @@ -143,19 +152,25 @@ Begin now with STEP 1. ## Tips for Customizing the Template -- **Replace the TASK value** with your actual task string. Keep it on one line, in quotes. -- **Add context if needed**: Append lines after `TASK:` like `STACK: "Node.js, PostgreSQL, Jest"` or `CONSTRAINTS: "Use ESM modules only"` - the orchestrator will incorporate them. +- **Replace the TASK value** with your actual task string. Keep it on one line, + in quotes. +- **Add context if needed**: Append lines after `TASK:` like + `STACK: "Node.js, PostgreSQL, Jest"` or + `CONSTRAINTS: "Use ESM modules only"` - the orchestrator will incorporate + them. - **For monorepos or specific file layouts**: Add a `STRUCTURE:` hint, e.g.: ``` STRUCTURE: "src/api/, src/auth/, src/tests/, docker-compose.yml" ``` -- **To limit parallelism** (e.g., on resource-constrained machines): Add `MAX_PARALLEL_AGENTS: 2` after the TASK line. +- **To limit parallelism** (e.g., on resource-constrained machines): Add + `MAX_PARALLEL_AGENTS: 2` after the TASK line. --- ## Example Usage **Input task:** + > "Build a login API with JWT authentication and unit tests" **Expected orchestrator output (before execution):** @@ -180,12 +195,15 @@ Dependency Plan: Starting execution. Spawning parallel sub-agents now... ``` -T1 and T2 spawn immediately. T3 spawns once T1 completes. T4 and T5 spawn once T3 completes. T6 spawns last. +T1 and T2 spawn immediately. T3 spawns once T1 completes. T4 and T5 spawn once +T3 completes. T6 spawns last. --- ## Notes - This skill requires Agent Code CLI with the **Task tool** enabled. -- Each spawned sub-agent has no memory of the others - pass all needed context explicitly in the Task prompt. -- For very large tasks (10+ sub-tasks), consider breaking the orchestration into phases and applying this skill recursively per phase. +- Each spawned sub-agent has no memory of the others - pass all needed context + explicitly in the Task prompt. +- For very large tasks (10+ sub-tasks), consider breaking the orchestration into + phases and applying this skill recursively per phase. diff --git a/AGENTS.md b/AGENTS.md index 56e2499..1c8acf7 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -17,8 +17,10 @@ Chứa route/page/layout theo Next.js App Router. - **`(main)/`** - Main shopping interface (duyệt menu, đăng nhập, đăng ký, thanh toán) - **`(feed)/`** - Feed/discovery page (khám phá quán) - - **`(manager)/`** - Manager dashboard (quản lý sản phẩm, đơn hàng) - **[ĐANG - PHÁT TRIỂN]** + - **`(manager)/`** - Manager dashboard (quản lý sản phẩm, phân tích tài + chính) - **[ĐANG PHÁT TRIỂN ~70%]** + - **`(staff)/`** - Staff shift schedule (lịch làm việc nhân viên) - **[HOÀN + THÀNH]** - **Tài liệu:** `app/APP.md` - Chi tiết routes, pages, CSS tokens ### `components/` - Reusable UI Components (Atomic Design) @@ -80,7 +82,14 @@ Sections phức tạp kết hợp molecules + atoms, có logic, data filtering: - **`cart/`** - CartFab, CartSummary, CartList - **`product-grid/`** - ProductGrid, ProductFilters - **`forms/`** - LoginForm, RegisterForm, CheckoutForm, ReviewForm -- **`modals/`** - ReviewModal, ConfirmModal +- **`modals/`** - ReviewModal, ConfirmModal, CashPaymentModal, QRPaymentModal, + PaymentSuccessModal +- **`manager/`** - ProductModal (image upload), ComboModal, CategoryModal, + DeleteConfirm, StatusBadge, ProductsTab, CombosTab, CategoriesTab +- **`analytics/`** - BarChart, LineChart, PieChart (SVG), ProductTable, + SummaryCard +- **`shift-schedule/`** - WeeklySchedule, MonthlyCalendar, MobileShiftView, + ShiftCreateModal, ShiftDetailModal - **`shop-grid/`** - ShopGrid, ShopFilters - **`hero-section/`** - HeroSection - **`featured-section/`** - FeaturedProducts, FeaturedShops @@ -103,6 +112,7 @@ Page layouts, không có data cụ thể, children composition: - **`main-layout/`** - MainLayout (header + sidebar + content + footer) - **`feed-layout/`** - FeedLayout - **`manager-layout/`** - ManagerLayout +- **`staff-layout/`** - StaffLayout (navigation shell for staff pages) - **`checkout-layout/`** - CheckoutLayout - **`auth-layout/`** - AuthLayout @@ -161,8 +171,12 @@ Chứa logic dùng chung, context, constants, types: - **`auth-context.tsx`** - AuthProvider + useAuth() hook (login, logout, register) - **`cart-context.tsx`** - CartProvider + useCart() hook (add, remove, quantity - operations) + operations, clearCart) - **`menu-context.tsx`** - MenuProvider + useMenu() hook (category state) +- **`manager-context.tsx`** - ManagerProvider + useManager() hook (CRUD for + products, combos, categories) +- **`shift-context.tsx`** - ShiftProvider + useShift() hook (staff shift + management: create, update, delete, date selection) - **Tài liệu:** `lib/LIB.md` - Chi tiết types, constants, contexts ### `public/` - Static Assets @@ -233,11 +247,41 @@ components/ │ ├── product-grid/ │ │ ├── ProductGrid.tsx │ │ └── ProductGrid.types.ts +│ ├── modals/ +│ │ ├── ReviewModal.tsx +│ │ ├── CashPaymentModal.tsx +│ │ ├── QRPaymentModal.tsx +│ │ └── PaymentSuccessModal.tsx +│ ├── manager/ +│ │ ├── ProductModal.tsx +│ │ ├── ComboModal.tsx +│ │ ├── CategoryModal.tsx +│ │ ├── DeleteConfirm.tsx +│ │ ├── StatusBadge.tsx +│ │ ├── ProductsTab.tsx +│ │ ├── CombosTab.tsx +│ │ └── CategoriesTab.tsx +│ ├── analytics/ +│ │ ├── BarChart.tsx +│ │ ├── LineChart.tsx +│ │ ├── PieChart.tsx +│ │ ├── ProductTable.tsx +│ │ └── SummaryCard.tsx +│ ├── shift-schedule/ +│ │ ├── WeeklySchedule.tsx +│ │ ├── MonthlyCalendar.tsx +│ │ ├── MobileShiftView.tsx +│ │ ├── ShiftCreateModal.tsx +│ │ └── ShiftDetailModal.tsx │ └── index.ts ├── templates/ │ ├── main-layout/ │ │ ├── MainLayout.tsx │ │ └── MainLayout.types.ts +│ ├── manager-layout/ +│ │ └── ManagerLayout.tsx +│ ├── staff-layout/ +│ │ └── StaffLayout.tsx │ └── index.ts └── ATOMIC_DESIGN.md ``` @@ -314,9 +358,15 @@ components/ - **Mock data first** - Use `lib/constants.ts` for development, replace with API later - **Contexts for state sharing:** - - `AuthContext` (lib/auth-context.tsx) - User state + auth operations - - `CartContext` (lib/cart-context.tsx) - Shopping cart + operations - - `MenuContext` (lib/menu-context.tsx) - Active category state + - `AuthContext` (lib/auth-context.tsx) - User state + auth operations → + `useAuth()` + - `CartContext` (lib/cart-context.tsx) - Shopping cart + operations → + `useCart()` (includes `clearCart`) + - `MenuContext` (lib/menu-context.tsx) - Active category state → `useMenu()` + - `ManagerContext` (lib/manager-context.tsx) - Manager dashboard state (CRUD + for products/combos/categories) → `useManager()` + - `ShiftContext` (lib/shift-context.tsx) - Staff shift management (create, + update, delete shifts, date selection) → `useShift()` - **localStorage keys:** `coffee-shop-user`, `coffee-shop-cart` (defined in contexts) @@ -625,21 +675,33 @@ className = "w-full sm:w-1/2 md:w-1/3 p-4 md:p-6 hidden md:block"; ## 5) Project Status +> Last Updated: 2026-04-18 + ### ✅ Completed Features - User authentication (login, register, logout) - Product grid display with category filtering - Shopping cart with add/remove/update operations -- Payment page with review modal +- Payment page with PaymentSummaryCard + review modal +- Cash payment modal (CashPaymentModal) with change calculation +- QR payment modal (QRPaymentModal) with QR code generation (`qrcode.react`) and + 5-second auto-confirm countdown +- Payment success modal (PaymentSuccessModal) with cart clear - Shop discovery (feed page) - Responsive design (mobile, tablet, desktop) - Header + Footer with navigation - Sidebar category filter +- Manager dashboard — Products, Combos, Categories tabs with full CRUD +- Product image upload in ProductModal +- Financial Analytics dashboard (LineChart, BarChart, PieChart, ProductTable) +- Staff shift schedule (`/staff/schedule`) — weekly/monthly views, mobile view, + CRUD shifts, department filter ### 🚀 In Progress +- Manager dashboard (~70% complete) - `app/(manager)/` route group + - Remaining: order management, inventory tracking, real API integration - Atomic Design refactoring (components reorganization) -- Manager dashboard (quản lý sản phẩm) - `app/(manager)/` route group ### 📋 Planned Features diff --git a/README.md b/README.md index c355a6e..5c11532 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,8 @@ 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. +_Last Updated: 2026-04-18_ + --- ## Mô Tả Dự Án @@ -11,7 +13,9 @@ Giao diện người dùng (frontend) cho hệ thống đặt và bán đồ u ### Tính Năng Hiện Tại -#### 1. **Trang Đăng Nhập & Đăng Ký** (`app/(main)/login`, `app/(main)/register`) +#### Tính Năng Khách Hàng (Customer Features) + +##### 1. **Trang Đăng Nhập & Đăng Ký** (`app/(main)/login`, `app/(main)/register`) - Form đăng nhập với validation (username, password) - Form đăng ký với xác thực OTP @@ -19,7 +23,7 @@ Giao diện người dùng (frontend) cho hệ thống đặt và bán đồ u - Hỗ trợ 3 loại tài khoản: Manager, Staff, Customer - Hiển thị thông tin shop trong form -#### 2. **Trang Khám Phá Quán Nước** (`app/(feed)/feed`) +##### 2. **Trang Khám Phá Quán Nước** (`app/(feed)/feed`) - Danh sách các quán cà phê - Tìm kiếm theo tên quán và địa chỉ @@ -27,9 +31,7 @@ Giao diện người dùng (frontend) cho hệ thống đặt và bán đồ u - Responsive layout (grid 1/2/3 cột) - Empty state khi không tìm thấy quán -#### 3. **Trang Chính - Duyệt Thực Đơn** (`app/(main)`) - -Dành cho khách hàng: +##### 3. **Trang Chính - Duyệt Thực Đơn** (`app/(main)`) - Sidebar collapsible (64px/240px) - danh mục sản phẩm - Grid sản phẩm responsive (1-5 cột tuỳ thiết bị) @@ -38,41 +40,52 @@ Dành cho khách hàng: - Lọc tự động theo trạng thái available - Mobile menu: scrollable category tabs (< md) -#### 4. **Trang Thanh Toán** (`app/(main)/payment`) +##### 4. **Trang Thanh Toán** (`app/(main)/payment`) - Bảng danh sách sản phẩm trong giỏ hàng với điều chỉnh số lượng - Invoice aside sticky với tổng giá và nút thanh toán (Tiền mặt, QR) - Modal đánh giá 5 sao dành riêng cho khách hàng (ReviewModal) +- **CashPaymentModal:** nhập tiền mặt, tính tiền thối, báo lỗi nếu tiền không đủ +- **QRPaymentModal:** tạo mã QR thanh toán (qrcode.react), tự xác nhận sau 5 + giây đếm ngược +- **PaymentSuccessModal:** xác nhận thanh toán thành công, tự động xoá giỏ hàng -#### 5. **Hệ Thống Giỏ Hàng** (`lib/cart-context.tsx`) +##### 5. **Hệ Thống Giỏ Hàng** (`lib/cart-context.tsx`) - Lưu trữ trạng thái giỏ trong localStorage - Thêm/xóa/tăng/giảm số lượng sản phẩm - Tính tổng giá và số mặt hàng - Persist dữ liệu giữa các session +- `clearCart()` để xoá toàn bộ giỏ sau thanh toán -#### 6. **Hệ Thống Xác Thực** (`lib/auth-context.tsx`) +##### 6. **Hệ Thống Xác Thực** (`lib/auth-context.tsx`) - Quản lý trạng thái người dùng (login/logout/register) - Lưu thông tin user trong localStorage - Mock auth database với 3 loại tài khoản - Hỗ trợ hoàn tất đăng ký qua OTP -#### 7. **Hệ Thống Danh Mục** (`lib/menu-context.tsx`) +##### 7. **Hệ Thống Danh Mục** (`lib/menu-context.tsx`) - Chia sẻ trạng thái category giữa Header mobile và Sidebar - Tự động clear search khi thay đổi category -#### 8. **Manager Dashboard** (`app/(manager)/manager`) +#### Tính Năng Quản Lý (Manager Features) -Dành cho quản lý: +##### 8. **Manager Dashboard** (`app/(manager)/manager`) — ~70% hoàn thành - Sidebar desktop: Brand, tab navigation (Thực đơn / Combo / Danh mục), link tới Analytics -- CRUD sản phẩm, combo, danh mục qua modals - Auth guard: tự động redirect non-manager về `/` +- **Products tab:** CRUD sản phẩm qua ProductModal, bao gồm: + - Upload ảnh sản phẩm với xem trước, nút "Đổi ảnh" và xoá ảnh + - Giao diện vùng kéo thả với dashed border + - Toggle trạng thái available + - Dialog xác nhận xoá +- **Combos tab:** CRUD combo qua ComboModal, toggle trạng thái, xác nhận xoá +- **Categories tab:** CRUD danh mục qua CategoryModal, xác nhận xoá -#### 9. **Trang Phân Tích Tài Chính** (`app/(manager)/manager/analytics`) +##### 9. **Trang Phân Tích Tài Chính** (`app/(manager)/manager/analytics`) - Summary cards: Doanh thu, đơn hàng, lợi nhuận, giá trị đơn trung bình (so sánh kỳ trước) @@ -81,6 +94,24 @@ Dành cho quản lý: - Bảng top 5 sản phẩm và bảng chi tiết có thể sắp xếp - Lọc theo danh mục +#### Tính Năng Nhân Viên (Staff Features) + +##### 10. **Lịch Làm Việc Nhân Viên** (`app/(staff)/staff/schedule`) + +- Xem lịch theo tuần và theo tháng +- Mobile shift view (danh sách ca theo ngày) +- Lọc theo phòng ban / bộ phận +- Modal tạo ca làm việc mới (ShiftCreateModal) +- Modal xem chi tiết ca (ShiftDetailModal) +- Auth guard: chỉ staff/manager mới truy cập được + +#### Cải Thiện Tiếp Cận (Accessibility) + +- Thuộc tính `title` trên các nút icon (tooltip cho screen reader) +- ARIA roles trên modals: `role="dialog"`, `aria-modal`, `aria-labelledby` +- Semantic HTML: nhãn form với `htmlFor` đúng chuẩn +- `alt` text đầy đủ cho ảnh sản phẩm + --- ## Cách Chạy Dự Án @@ -144,9 +175,12 @@ frondend/ | | +-- layout.tsx # Feed layout | | +-- feed/page.tsx # Trang khám phá quán nước (/feed) | +-- (manager)/ # Manager route group -| +-- layout.tsx # Manager layout - auth guard + ManagerProvider -| +-- manager/page.tsx # Manager Dashboard (/manager) -| +-- manager/analytics/page.tsx # Financial Analytics (/manager/analytics) +| | +-- layout.tsx # Manager layout - auth guard + ManagerProvider +| | +-- manager/page.tsx # Manager Dashboard (/manager) +| | +-- manager/analytics/page.tsx # Financial Analytics (/manager/analytics) +| +-- (staff)/ # Staff route group +| +-- layout.tsx # Staff layout - auth guard +| +-- staff/schedule/page.tsx # Lịch làm việc nhân viên (/staff/schedule) +-- components/ # Atomic Design UI components | +-- atoms/ # Nguyên tử: Button, Input, Badge, Text... | +-- molecules/ # Phân tử: ProductCard, ShopCard, SearchBar... @@ -202,8 +236,9 @@ frondend/ | ---------------- | --------- | ------------------------------------- | | 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 | +| TypeScript | ^5.9.3 | Kiểu dữ liệu tĩnh | | Tailwind CSS | ^4.2.2 | Utility-first CSS framework | +| qrcode.react | ^4.2.0 | Tạo mã QR thanh toán | | Geist Font | - | Font chữ (Google Fonts via next/font) | | FontAwesome | 6.7.2 | Icon library (CDN) | | pnpm | - | Package manager | @@ -224,14 +259,15 @@ frondend/ - **Thanh Toán:** `app/(main)/payment/page.tsx` - **Manager Dashboard:** `app/(manager)/manager/page.tsx` - **Phân Tích Tài Chính:** `app/(manager)/manager/analytics/page.tsx` +- **Lịch Làm Việc Nhân Viên:** `app/(staff)/staff/schedule/page.tsx` ### Tài Khoản Demo -| Loại tài khoản | Tên đăng nhập | Mật khẩu | -| -------------- | ------------- | ------------- | -| Manager | admin | admin | -| Staff | Nguyễn Văn An | Nguyễn Văn An | -| Customer | 0987654321 | user1 | +| Loại tài khoản | Tên đăng nhập | Mật khẩu / OTP | +| -------------- | ------------- | -------------------------- | +| Manager | admin | admin | +| Staff | Nguyễn Văn An | Nguyễn Văn An | +| Customer | 0987654321 | bất kỳ 6 chữ số (mock OTP) | ### Design & Styling diff --git a/TODO.md b/TODO.md index cb9d54c..6d6ea4a 100644 --- a/TODO.md +++ b/TODO.md @@ -1,5 +1,9 @@ # Coffee Shop Frontend - TODO +_Last Updated: 2026-04-18_ + +--- + ## Completed Features & Implementations ### A. Dead Code Removed @@ -37,17 +41,66 @@ - [x] npm run build - PASSED (Compiled successfully, TypeScript clean, static pages generated) +### F. Cart & Payment (Completed) + +- [x] Cart checkout flow — cart context with addToCart, removeFromCart, + setQuantity, clearCart +- [x] Payment page implementation (`app/(main)/payment`) +- [x] CashPaymentModal: cash input, change calculation, insufficient cash error +- [x] QRPaymentModal: QR code generation via qrcode.react, 5-second countdown + auto-confirm +- [x] PaymentSuccessModal: success confirmation, auto-clears cart + +### G. Manager Dashboard — ~70% Complete (In Progress) + +- [x] Manager Dashboard page (`app/(manager)/manager/page.tsx`) with auth guard +- [x] Products tab with CRUD (ProductModal) +- [x] Image upload in ProductModal: file input, preview, "Đổi ảnh" button, + remove button, dashed border drop zone +- [x] Combos tab with CRUD (ComboModal) +- [x] Categories tab with CRUD (CategoryModal) +- [x] Delete confirmation dialogs for all entities +- [x] Status toggle buttons (available/unavailable) +- [x] Sidebar navigation with link to Analytics + +### H. Financial Analytics Dashboard (Completed) + +- [x] Analytics page (`app/(manager)/manager/analytics`) +- [x] Summary cards: Revenue, Orders, Profit, Average Order Value (with period + comparison) +- [x] Period selector: Day / Week / Month / Year +- [x] SVG charts: LineChart, BarChart, PieChart with hover tooltips +- [x] Top 5 products table and sortable detail table +- [x] Category filter + +### I. Staff Shift Schedule (Completed) + +- [x] Staff schedule module (`app/(staff)/staff/schedule`) +- [x] Weekly calendar view +- [x] Monthly calendar view +- [x] Mobile shift view (list per day) +- [x] ShiftCreateModal: create new shifts +- [x] ShiftDetailModal: view shift details +- [x] Department/role filtering +- [x] Auth guard for staff/manager only + +### J. Accessibility Improvements (Completed) + +- [x] title attributes on icon buttons (tooltips for screen readers) +- [x] ARIA roles on modals: role="dialog", aria-modal, aria-labelledby +- [x] Semantic HTML: form labels with correct htmlFor +- [x] Image alt text for product images + --- ## Pending Features (Future Work) ### Cart & Ordering -- [ ] Implement cart checkout flow (app/(main)/cart or modal) -- [ ] Cart sidebar/modal with item list and total +- [ ] Cart sidebar/modal with item list and total (quick-access without going to + payment page) - [ ] Order submission API integration -- [ ] Payment page implementation (app/(main)/payment) -- [ ] Order history/tracking page +- [ ] Order history/tracking page for customers - [ ] Toast notifications for cart actions ### Authentication & User Management @@ -58,22 +111,22 @@ - [ ] Password reset/recovery flow - [ ] Session management and token refresh -### Manager Features +### Manager Features (Remaining ~30%) -- [ ] Manager dashboard page (app/(manager)/page.tsx) -- [ ] Product management (add/edit/delete) -- [ ] Category management -- [ ] Order management & tracking -- [ ] Sales analytics/dashboard -- [ ] Inventory management +- [ ] Order management & tracking for manager +- [ ] Inventory management beyond available toggle (stock counts, low-stock + alerts) +- [ ] Staff management tab in Manager Dashboard +- [ ] Shift approval workflow (manager approves staff shift requests) ### Backend Integration - [ ] Replace MOCK_PRODUCTS with API calls (GET /api/products) - [ ] Replace MOCK_SHOPS with API calls (GET /api/shops) - [ ] Replace MOCK_USERS with real authentication (POST /api/auth/login) -- [ ] Real product images (replace placeholder.jpg) -- [ ] Image upload for products +- [ ] Real product images hosted on server/CDN (replace public/imgs/products/) +- [ ] Real analytics data from backend (GET /api/analytics) +- [ ] Real shift/schedule data from backend ### UX Improvements @@ -85,11 +138,12 @@ - [ ] Filter by price range - [ ] Quantity selector in product card - [ ] Related products suggestions +- [ ] Push notifications for order status updates ### Performance & SEO -- [ ] Dynamic route generation for products (app/(main)/product/[id]/page.tsx) -- [ ] Dynamic route generation for shops (app/(feed)/shop/[id]/page.tsx) +- [ ] Dynamic route generation for products (`app/(main)/product/[id]/page.tsx`) +- [ ] Dynamic route generation for shops (`app/(feed)/shop/[id]/page.tsx`) - [ ] Meta tags and Open Graph for SEO - [ ] Image optimization and lazy loading - [ ] Code splitting and dynamic imports @@ -97,7 +151,7 @@ ### Accessibility & Testing - [ ] Keyboard navigation testing -- [ ] ARIA labels audit -- [ ] Unit tests for contexts -- [ ] E2E tests for user flows -- [ ] Accessibility audit (WCAG 2.1 AA) +- [ ] Full ARIA labels audit (WCAG 2.1 AA) +- [ ] Unit tests for contexts (auth, cart, menu, manager) +- [ ] E2E tests for user flows (checkout, login, manager CRUD) +- [ ] Accessibility audit tool (axe, Lighthouse) diff --git a/app/(main)/payment/page.tsx b/app/(main)/payment/page.tsx index f3b92b7..01c680f 100644 --- a/app/(main)/payment/page.tsx +++ b/app/(main)/payment/page.tsx @@ -131,7 +131,6 @@ export default function PaymentPage() { /> - ); } diff --git a/app/(manager)/manager/page.tsx b/app/(manager)/manager/page.tsx index 2d0280c..05d64a0 100644 --- a/app/(manager)/manager/page.tsx +++ b/app/(manager)/manager/page.tsx @@ -57,7 +57,7 @@ export default function ManagerPage() { - - + + diff --git a/components/organisms/manager/ProductModal.tsx b/components/organisms/manager/ProductModal.tsx index 20c708c..4c52f4d 100644 --- a/components/organisms/manager/ProductModal.tsx +++ b/components/organisms/manager/ProductModal.tsx @@ -185,7 +185,7 @@ export default function ProductModal({ @@ -197,9 +197,7 @@ export default function ProductModal({ className="flex w-full cursor-pointer flex-col items-center justify-center gap-2 rounded-xl border-2 border-dashed border-(--color-border) bg-transparent px-4 py-6 text-(--color-text-muted) transition hover:border-(--color-primary) hover:text-(--color-primary)" > - - Nhấn để chọn ảnh - + Nhấn để chọn ảnh PNG, JPG, WEBP (tối đa 5MB) )} diff --git a/components/organisms/modals/CashPaymentModal.tsx b/components/organisms/modals/CashPaymentModal.tsx index 6521044..2b01547 100644 --- a/components/organisms/modals/CashPaymentModal.tsx +++ b/components/organisms/modals/CashPaymentModal.tsx @@ -2,6 +2,7 @@ import Button from "@/components/atoms/buttons/Button"; import { useEffect, useState } from "react"; + import type { CashPaymentModalProps } from "./Modal.types"; const formatPrice = (value: number) => @@ -41,27 +42,25 @@ export default function CashPaymentModal({

Thanh toán tiền mặt

{/* Invoice list */}
-

+

Hóa đơn

-
+
{items.map((item, index) => (
- - {item.name} - + {item.name}
- + x{item.quantity} @@ -70,10 +69,8 @@ export default function CashPaymentModal({
))} -
- - Tổng cộng - +
+ Tổng cộng {formatPrice(totalAmount)} @@ -97,7 +94,7 @@ export default function CashPaymentModal({ value={cashReceived} onChange={(e) => setCashReceived(e.target.value)} placeholder="0" - className="w-full rounded-lg border border-(--color-border) bg-transparent px-3 py-2 text-right text-lg font-semibold focus:outline-none focus:ring-2 focus:ring-(--color-primary)" + className="w-full rounded-lg border border-(--color-border) bg-transparent px-3 py-2 text-right text-lg font-semibold focus:ring-2 focus:ring-(--color-primary) focus:outline-none" /> {isInsufficient && (

diff --git a/components/organisms/modals/PaymentSuccessModal.tsx b/components/organisms/modals/PaymentSuccessModal.tsx index cb34ba9..dc2da63 100644 --- a/components/organisms/modals/PaymentSuccessModal.tsx +++ b/components/organisms/modals/PaymentSuccessModal.tsx @@ -1,7 +1,7 @@ "use client"; -import { useEffect } from "react"; import { useRouter } from "next/navigation"; +import { useEffect } from "react"; interface PaymentSuccessModalProps { isOpen: boolean; @@ -41,7 +41,7 @@ export default function PaymentSuccessModal({

-

+

Thanh toán thành công!

diff --git a/components/organisms/modals/QRPaymentModal.tsx b/components/organisms/modals/QRPaymentModal.tsx index b3062dd..adfb40b 100644 --- a/components/organisms/modals/QRPaymentModal.tsx +++ b/components/organisms/modals/QRPaymentModal.tsx @@ -2,6 +2,7 @@ import { QRCodeSVG } from "qrcode.react"; import { useEffect, useState } from "react"; + import type { QRPaymentModalProps } from "./Modal.types"; const formatPrice = (value: number) => @@ -9,7 +10,13 @@ const formatPrice = (value: number) => const COUNTDOWN_SECONDS = 5; -export default function QRPaymentModal({ isOpen, onClose, onConfirm, items, totalAmount }: QRPaymentModalProps) { +export default function QRPaymentModal({ + isOpen, + onClose, + onConfirm, + items, + totalAmount, +}: QRPaymentModalProps) { const [qrValue, setQrValue] = useState(""); const [timeLeft, setTimeLeft] = useState(COUNTDOWN_SECONDS); @@ -47,32 +54,46 @@ export default function QRPaymentModal({ isOpen, onClose, onConfirm, items, tota aria-modal="true" aria-labelledby="qr-modal-title" > -

); diff --git a/layouts/LAYOUTS.md b/layouts/LAYOUTS.md index 17e0648..8cf059e 100644 --- a/layouts/LAYOUTS.md +++ b/layouts/LAYOUTS.md @@ -2,6 +2,8 @@ > Tài liệu chi tiết về layout components (Header, Footer) và responsive behavior +> **Last Updated:** 2026-04-18 + --- ## Overview @@ -21,180 +23,197 @@ layouts/ ## Header (layouts/header.tsx) -**File:** layouts/header.tsx **Type:** Client component **Description:** Sticky -top navigation bar with brand info and authentication status display. +**File:** layouts/header.tsx **Type:** Client component (`"use client"`) +**Description:** Sticky top navigation bar with brand info and authentication +status display. Uses `useAuth()` context for real auth state and `useRouter()` +for navigation. ### Layout ``` ┌─────────────────────────────────────────────────────┐ -│ [Logo] [Shop Name] [Tagline] │ [Auth Status] │ +│ [Logo] [Shop Name] [Tagline] │ [Auth Button(s)] │ └─────────────────────────────────────────────────────┘ -height: 72px (var(--spacing-header-height)) +height: var(--spacing-header-height) (72px) ``` **2-Column Layout:** -- **Left:** Shop branding (logo + name + tagline) -- **Right:** Auth status indicator +- **Left:** Shop branding (logo + name + tagline) — wrapped in `` +- **Right:** Auth status indicator (varies by user role) ### Features #### Logo & Branding -- Shop logo (40x40px) -- Shop name (bold text) +- Shop logo rendered with `next/image` (fill, 40x40px / 44x44px on md+) +- Shop name (bold, color transitions on hover) - Tagline (hidden on mobile < md, visible md+) +- Entire left section is a link to `/` -**Responsive:** | Breakpoint | Logo | Name | Tagline | -|-----------|------|------|---------| | < sm (640px) | Yes | Yes | Hidden | | -sm-md | Yes | Yes | Hidden | | md+ (768px) | Yes | Yes | Visible | +**Responsive:** + +| Breakpoint | Logo | Name | Tagline | +| ------------ | --------- | ---- | ------- | +| < sm (640px) | h-10/w-10 | Yes | Hidden | +| sm-md | h-10/w-10 | Yes | Hidden | +| md+ (768px) | h-11/w-11 | Yes | Visible | #### Authentication Status -The header cycles through 3 auth states (for UI demo): +The header reads from `useAuth()` and reflects the actual logged-in user role. -**State 1: Guest (Not logged in)** +**State 1: Guest (user = null)** ``` -[brown button] "Dang nhap" +[brown button] "Đăng nhập" ← icon always shown, label hidden on xs ``` -- Guest state (user = null) -- Brown primary button -- Click: toggles to next state +- `title="Đăng nhập"` on button +- Clicking navigates to `/login` +- Icon: `fa-solid fa-right-to-bracket` -**State 2: Manager** +**State 2: Manager (user.role === "manager")** ``` -[caramel/gold badge] "👔 Quản lý" +[Dashboard link] [Logout icon button] ``` -- Shows manager role -- Gold/caramel colored badge -- User tie icon -- Name: Nguyễn Văn An +- Dashboard link → `/manager` +- Icon: `fa-solid fa-user-tie` +- Label "Dashboard" hidden on xs, visible sm+ +- Logout button: `title="Đăng xuất"`, `aria-label="Đăng xuất"` +- Logout icon: `fa-solid fa-right-from-bracket` +- Hover: red tint on logout button -**State 3: Staff** +**State 3: Staff (user.role === "staff")** ``` -[border button] "👤 [Name]" +[Ca làm link] [Avatar + Name button (logout on click)] ``` -- Shows staff role with avatar placeholder -- Bordered button style -- Name: Trần Thị Bình -- Click: toggles back to Guest state +- Ca làm link → `/staff/schedule` +- Icon: `fa-solid fa-calendar-check` +- Label "Ca làm" hidden on xs, visible sm+ +- Staff button: `title="Nhấn để đăng xuất"`, `aria-label="Đăng xuất"` +- Avatar: colored circle with `fa-solid fa-user` +- Name hidden on xs, visible sm+ + +**State 4: Customer (user.role === "customer")** + +``` +[Customer icon + "Khách hàng" button (logout on click)] +``` + +- `title="Khách hàng - {user.phone} - Nhấn để đăng xuất"` +- Avatar circle with `fa-solid fa-user` +- Label "Khách hàng" hidden on xs, visible sm+ ### Responsive Behavior -| Breakpoint | Layout | -| ------------- | ------------------------------- | -| < sm | Stacked vertically | -| sm-md (640px) | Side-by-side, reduced spacing | -| md+ (768px) | Full width, comfortable spacing | +| Breakpoint | Layout | +| ------------- | -------------------------------------- | +| < sm (640px) | Button labels hidden, icons only | +| sm-md (640px) | Button labels visible, reduced spacing | +| md+ (768px) | Full layout including tagline | **Mobile (<640px):** -- Logo smaller -- Name only (no tagline) -- Auth button text hidden, icon shown +- Logo 40x40px +- Shop name only (no tagline) +- Auth button shows icon only (label hidden via `hidden sm:inline`) - Touch-friendly padding -**Desktop (≥640px):** +**Desktop (≥768px):** -- Normal logo size +- Logo 44x44px - Full layout with tagline -- Button with text and icon +- Buttons show icon + text label - Comfortable spacing +### Accessibility + +- Logo image: `alt="Logo {SHOP_INFO.name}"` +- Guest button: `title="Đăng nhập"` +- Manager logout button: `title="Đăng xuất"`, `aria-label="Đăng xuất"` +- Staff logout button: `title="Nhấn để đăng xuất"`, `aria-label="Đăng xuất"` +- Customer button: `title="Khách hàng - {phone} - Nhấn để đăng xuất"` +- Icons are presentational (no aria-hidden needed — buttons have + title/aria-label) + ### Styling -| Element | Classes | -| -------------------- | --------------------------------------------------------- | -| Header wrapper | `sticky top-0 z-50 bg-white shadow-md` | -| Container | `max-w-7xl mx-auto px-4 md:px-6 h-72px flex items-center` | -| Left section (brand) | `flex items-center gap-3 flex-1` | -| Right section (auth) | `flex items-center gap-3 shrink-0` | -| Logo image | `w-10 h-10 md:w-12 md:h-12` | -| Brand text | `font-bold text-sm md:text-base` | -| Tagline | `hidden md:block text-xs text-muted-foreground` | -| Auth button | `px-4 py-2 rounded-lg text-sm font-medium` | +| Element | Classes | +| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | +| Header wrapper | `sticky top-0 z-50 h-(--spacing-header-height) w-full border-b bg-(--color-bg-header) shadow-[...]` | +| Container | `mx-auto flex h-full max-w-screen-2xl items-center justify-between gap-6 px-6 md:px-8 lg:px-12` | +| Left section (brand) | `group flex shrink-0 items-center gap-4 no-underline` (Link) | +| Logo wrapper | `relative h-10 w-10 shrink-0 md:h-11 md:w-11` | +| Brand text | `text-base font-bold text-(--color-primary-dark) md:text-lg` | +| Tagline | `hidden text-xs text-(--color-text-muted) md:block` | +| Right section (auth) | `flex shrink-0 items-center gap-3` | +| Guest button | `flex items-center gap-2.5 rounded-xl bg-(--color-primary) px-5 py-2.5 text-sm font-semibold text-white` | +| Manager link | `flex items-center gap-2 rounded-xl border border-(--color-accent) bg-(--color-accent-light)` | +| Logout button | `flex items-center gap-2 rounded-xl border border-(--color-border) bg-transparent px-3 py-2.5 hover:border-red-300 hover:bg-red-50 hover:text-red-500` | +| Staff button | `flex items-center gap-2.5 rounded-xl border border-(--color-border) bg-background` | +| Customer button | `flex items-center gap-2.5 rounded-xl bg-(--color-primary-light) px-4 py-2 text-white` | ### CSS Variables Used ```css ---spacing-header-height: 72px; ---color-primary: brown; ---color-primary-dark: darker brown; ---color-text-primary: text color; ---color-text-muted: gray text; ---color-shadow-sm: subtle shadow; +--spacing-header-height /* 72px — header height */ +--color-bg-header /* header background */ +--color-border /* border color */ +--color-shadow-sm /* subtle shadow */ +--color-primary /* brand primary (brown) */ +--color-primary-dark /* darker brown */ +--color-primary-light /* lighter brown */ +--color-accent /* accent/gold color */ +--color-accent-light /* light accent background */ +--color-text-muted /* gray/muted text */ +--color-text-secondary /* secondary text color */ +--color-border-light /* light border */ ``` ### Dependencies -- **next/image** - Logo image rendering -- **next/link** - Navigation links -- **lib/constants:** SHOP_INFO, MOCK_USERS -- **lib/types:** User -- **FontAwesome icons:** fa-sign-in-alt, fa-sign-out-alt, fa-user-tie, - fa-user-circle - -### Key Code Snippets - -**Auth Demo State Machine:** - -```typescript -const [user, setUser] = useState(null); - -const handleAuthClick = () => { - if (!user) { - setUser(MOCK_USERS.manager); - } else if (user.role === "manager") { - setUser(MOCK_USERS.staff); - } else { - setUser(null); - } -}; -``` - -**Responsive Brand Text:** - -```typescript -
- {SHOP_INFO.name} - - {SHOP_INFO.tagline} - -
-``` +- **next/image** — Logo image rendering +- **next/link** — Brand link, dashboard link, schedule link +- **next/navigation** — `useRouter` for programmatic navigation +- **lib/auth-context:** `useAuth` — user state, logout +- **lib/constants:** `SHOP_INFO` --- ## Footer (layouts/footer.tsx) -**File:** layouts/footer.tsx **Type:** Client component (uses constants) +**File:** layouts/footer.tsx **Type:** Server component (no `"use client"`) **Description:** Site footer with shop information, social links, and WiFi -details. +details. Copyright year is dynamic via `new Date().getFullYear()`. ### Layout ``` -┌────────────────────────────────────────────┐ -│ [Brand Info] │ [Social + WiFi] │ -├────────────────────────────────────────────┤ -│ © 2024 Coffee Shop. Made with ❤️ in VN │ -└────────────────────────────────────────────┘ +┌────────────────────────────────────────────────────────────────┐ +│ [Brand Info] │ [Social + WiFi] │ +├────────────────────────────────────────────────────────────────┤ +│ © {year} Coffee Shop. All rights reserved. | Powered by ... │ +└────────────────────────────────────────────────────────────────┘ ``` **12-Column Grid Layout:** -| Breakpoint | Brand Info | Social + WiFi | -| ------------ | ----------- | ------------- | -| Mobile | col-span-12 | col-span-12 | -| md (768px) | col-span-6 | col-span-6 | -| lg+ (1024px) | col-span-6 | col-span-6 | +| Breakpoint | Brand Info | Right column (Social + WiFi) | +| ------------ | ----------- | -------------------------------- | +| Mobile | col-span-12 | col-span-12 | +| md (768px) | col-span-6 | col-span-6 | +| lg+ (1024px) | col-span-8 | col-span-4 | +| xl+ | col-span-6 | col-span-6 (with 2-col sub-grid) | + +The right column (Social + WiFi) uses an internal sub-grid: + +- Mobile/lg: stacked (1 column) +- xl+: side-by-side (2 columns) ### Sections @@ -202,179 +221,114 @@ details. **Content:** -- Shop logo (40x40px) -- Shop name (bold) -- Tagline (gray text) -- Address with location icon -- Phone with phone icon -- Email with envelope icon -- Open hours with clock icon +- Shop logo (40x40px, `next/image`) +- Shop name (bold, accent color) +- Tagline (gray, 75% opacity) +- Address with `fa-solid fa-location-dot` +- Phone (clickable `tel:` link) with `fa-solid fa-phone` +- Email (clickable `mailto:` link) with `fa-solid fa-envelope` +- Open hours with `fa-solid fa-clock` -**Responsive:** +#### 2. Social Links -``` -Mobile: -└─ Logo -└─ Name & Tagline (stacked) -└─ Address -└─ Phone -└─ Email -└─ Open Hours +**Links (heading: "Kết nối"):** -Desktop: -└─ Logo + Name/Tagline (flexbox, side-by-side) -└─ Address, Phone, Email, Hours (stacked below) -``` - -#### 2. Social Links (Top Right) - -**Links:** - -- Facebook icon → SHOP_INFO.facebook -- TikTok icon → SHOP_INFO.tiktok -- Website icon → SHOP_INFO.website +- Facebook → `SOCIAL_LINKS.facebook` (branded blue icon, opens `_blank`) +- TikTok → `SOCIAL_LINKS.tiktok` (black icon, opens `_blank`) +- Website → `SOCIAL_LINKS.website` (primary color icon, uses `next/link`) **Styling:** -- Icons in circle backgrounds -- Hover effect (color change) -- Flex row layout -- Centered alignment +- Each item: icon badge (8x8 rounded-lg) + label text +- Hover: accent color + full opacity -#### 3. WiFi Card (Bottom Right) +#### 3. WiFi Card -**Content:** +**Content (heading: "WiFi Miễn Phí"):** -- "📶 WiFi miễn phí" label -- Network name (monospace) -- Password (monospace, can be hidden/shown) +- WiFi icon (`fa-solid fa-wifi`) +- Network name (monospace, accent-bordered) +- Password (monospace, accent-bordered, always visible — no toggle) + +**Note:** Current implementation shows password in plain text (no hide/show +toggle). This differs from older documentation. **Styling:** -- Light gray background -- Rounded borders +- Semi-transparent dark panel (`bg-(--color-primary-dark) bg-opacity-30`) +- Rounded xl border +- Stacked label + value rows (no overflow risk) - Monospace font for credentials -- Eye icon toggle for password visibility -**Example:** - -``` -📶 WiFi miễn phí -┌────────────────────────┐ -│ Network: CoffeeShop │ -│ Password: •••••••• │ -│ (eye icon) │ -└────────────────────────┘ -``` - -#### 4. Copyright Bar (Bottom) +#### 4. Bottom Bar **Content:** -- Copyright text: "© 2024 Coffee Shop" -- "Made with ❤️ in Vietnam" -- Centered - -**Styling:** - -- Small text -- Gray color -- Subtle separator line above +- Left: `© {year} {SHOP_INFO.name}. All rights reserved.` +- Right: `Được vận hành ❤ bằng Drinkool` +- Responsive: stacked on mobile, side-by-side on sm+ ### Responsive Behavior **Mobile (<768px):** - Single column layout -- Stacked sections +- Stacked sections (brand, then social+WiFi) - Full width -- Padding around edges **Tablet (768px):** -- 2-column layout -- Brand info left, Social + WiFi right -- Equal width columns +- 2-column: brand (6 cols) | social+WiFi (6 cols) +- Social and WiFi stacked within right column -**Desktop (≥768px):** +**Desktop (≥1024px):** -- 2-column layout with more spacing -- Brand info slightly smaller -- Comfortable padding +- Brand 8 cols, right 4 cols +- Social and WiFi stacked in right col + +**XL (≥1280px):** + +- Brand 6 cols, right 6 cols +- Social and WiFi side-by-side in right col sub-grid ### Styling -| Element | Classes | -| -------------- | --------------------------------------------------------- | -| Footer wrapper | `bg-gray-100 border-t` | -| Container | `max-w-7xl mx-auto px-4 py-8` | -| Grid | `grid grid-cols-12 gap-8` | -| Brand section | `col-span-12 md:col-span-6` | -| Social section | `col-span-12 md:col-span-6` | -| Logo | `w-10 h-10` | -| Info text | `text-sm text-gray-600` | -| Social icons | `w-10 h-10 rounded-full flex items-center justify-center` | -| WiFi card | `bg-white p-4 rounded-lg border` | -| Copyright bar | `border-t mt-8 pt-6 text-center text-xs text-gray-500` | +| Element | Classes | +| ----------------- | -------------------------------------------------------------------------------------------------------------------- | +| Footer wrapper | `w-full overflow-x-hidden bg-(--color-bg-footer) text-(--color-text-on-dark)` | +| Container | `mx-auto max-w-screen-2xl px-4 py-10 md:px-6 lg:px-8` | +| Grid | `grid grid-cols-12 gap-x-8 gap-y-8` | +| Brand section | `col-span-12 md:col-span-6 lg:col-span-8 xl:col-span-6` | +| Right section | `col-span-12 grid grid-cols-1 gap-6 md:col-span-6 lg:col-span-4 xl:col-span-6 xl:grid-cols-2` | +| Logo | `relative h-10 w-10 shrink-0` | +| Shop name | `text-lg font-bold text-(--color-accent)` | +| Tagline | `text-sm leading-relaxed opacity-75` | +| Contact list | `flex flex-col gap-2 text-sm opacity-80` | +| Social icon badge | `flex h-8 w-8 shrink-0 items-center justify-center rounded-lg` | +| WiFi card | `rounded-xl border border-(--color-primary-light) bg-(--color-primary-dark) p-4` | +| WiFi value | `rounded border border-(--color-accent) px-2 py-1 font-mono font-bold text-(--color-accent)` | +| Bottom bar | `border-t border-white border-opacity-10` | +| Copyright row | `mx-auto flex max-w-screen-2xl flex-col sm:flex-row items-center justify-between gap-2 px-4 py-4 text-xs opacity-50` | ### CSS Variables Used ```css ---color-primary: brand color; ---color-text-secondary: secondary text color; ---color-text-muted: muted/gray text color; ---color-accent: accent color; ---color-border: border color; ---color-bg-*: background colors; ---color-shadow-sm: subtle shadow; +--color-bg-footer /* dark footer background */ +--color-text-on-dark /* light text for dark backgrounds */ +--color-accent /* accent/gold color */ +--color-primary /* brand primary (brown) */ +--color-primary-dark /* darker brown */ +--color-primary-light /* lighter brown */ +--color-border /* border color */ ``` ### Dependencies -- **next/image** - Shop logo -- **next/link** - Social links -- **lib/constants:** SHOP_INFO, SOCIAL_LINKS -- **FontAwesome icons:** location-dot, phone, envelope, clock, facebook, tiktok, - globe, wifi, eye, eye-slash - -### Key Code Snippets - -**Brand Info Section:** - -```typescript -
- {SHOP_INFO.name} -
-

{SHOP_INFO.name}

-

{SHOP_INFO.tagline}

-

{SHOP_INFO.address}

- {/* etc */} -
-
-``` - -**Social Links:** - -```typescript -
- - - - {/* etc */} -
-``` - -**WiFi Display:** - -```typescript -
-

📶 WiFi miễn phí

-

{SHOP_INFO.wifi.name}

-

- {showPassword ? SHOP_INFO.wifi.password : "••••••••"} -

-
-``` +- **next/image** — Shop logo +- **next/link** — Website social link +- **lib/constants:** `SHOP_INFO`, `SOCIAL_LINKS` +- **FontAwesome icons:** `location-dot`, `phone`, `envelope`, `clock`, + `fa-brands fa-facebook-f`, `fa-brands fa-tiktok`, `globe`, `wifi`, `heart` --- @@ -398,7 +352,7 @@ export default function RootLayout({ children }) { **Result:** -- Header: Always at top (sticky) +- Header: Always at top (sticky, z-50) - Content: Takes full width between header/footer - Footer: Always at bottom @@ -409,30 +363,22 @@ export default function RootLayout({ children }) { ### Header Responsive Pattern ```css -/* Mobile first */ -.header { - flex-direction: column; - gap: 1rem; - padding: 1rem; +/* Mobile first — icon-only auth buttons */ +.header-auth-label { + display: none; /* hidden on xs */ } -/* Tablet+ */ +/* sm+ — show button labels */ @media (min-width: 640px) { - .header { - flex-direction: row; - justify-content: space-between; - padding: 1.5rem; + .header-auth-label { + display: inline; /* hidden sm:inline */ } } -/* Desktop+ */ +/* md+ — show tagline */ @media (min-width: 768px) { - .header { - padding: 2rem; - } - .tagline { - display: block; /* Show tagline on desktop */ + display: block; /* hidden md:block */ } } ``` @@ -440,17 +386,14 @@ export default function RootLayout({ children }) { ### Footer Responsive Pattern ```css -/* Mobile: stacked */ +/* Mobile: single column */ .footer-grid { - grid-template-columns: 1fr; + grid-template-columns: repeat(12, 1fr); } -/* Tablet: 2 columns */ -@media (min-width: 768px) { - .footer-grid { - grid-template-columns: 1fr 1fr; - } -} +/* md: brand 6 cols, right 6 cols */ +/* lg: brand 8 cols, right 4 cols */ +/* xl: brand 6 cols, right 6 cols — right col uses xl:grid-cols-2 */ ``` --- @@ -483,33 +426,38 @@ CSS variables are set up for dark mode support. To enable: ### Header -- Logo has alt text -- Auth button has aria-label -- Icons have semantic meaning -- Good contrast ratios +- Logo image has descriptive `alt` text: `"Logo {SHOP_INFO.name}"` +- Guest button: `title="Đăng nhập"` +- Manager logout button: `title="Đăng xuất"` + `aria-label="Đăng xuất"` +- Staff logout button: `title="Nhấn để đăng xuất"` + `aria-label="Đăng xuất"` +- Customer button: `title="Khách hàng - {phone} - Nhấn để đăng xuất"` +- Interactive elements have hover and active states (visual feedback) +- Touch targets are sized appropriately (px-4/5 + py-2/2.5) ### Footer -- Headings use semantic tags -- Links have descriptive text -- Icons are decorative (aria-hidden) -- Monospace font for technical info (WiFi credentials) +- Phone and email are clickable `` links (`tel:`, `mailto:`) +- Social links open in `_blank` with `rel="noopener noreferrer"` +- Section headings use `

` semantic tags +- Icons are decorative within labelled list items +- WiFi credentials in monospace font for readability ### General -- Touch targets ≥ 48px on mobile -- Sufficient color contrast -- Semantic HTML structure -- ARIA labels where needed +- Touch targets ≥ 44px (py-2.5 + px-4/5 buttons) +- `active:scale-95` on interactive buttons for tactile feedback +- Semantic HTML structure (`
`, `