Commit ce98635f authored by ThinhNC's avatar ThinhNC

feat(frontend): add route-aware page titles

parent 20366e62
......@@ -12,6 +12,7 @@ File này lưu trữ các quyết định thiết kế dài hạn và trạng th
- **Phong cách Icon**: Tự thiết kế các inline SVG dạng blob dày, tròn trịa, nhiều màu sắc pastel thay vì dùng icon nét mảnh phẳng thông thường.
- **Hệ thống Light/Dark Theme**: Màu nền, surface, chữ, border, trạng thái và bóng Claymorphism phải đi qua semantic CSS variables được ánh xạ trong `tailwind.config.js`; không gắn màu light-only trực tiếp trong component. Lựa chọn `light`/`dark` được lưu cục bộ bằng Zustand, áp dụng lên `data-theme``zaui-theme`, đồng thời mọi màn hình dùng toggle chung để chuyển đổi nhất quán.
- **Quản lý Routing**: Sử dụng cấu hình router của ZMP UI / React Router tích hợp bên trong template để dẫn hướng giữa các màn hình nghiệp vụ và `/style-guide`.
- **Tiêu đề trang**: Mỗi route cập nhật `document.title` theo mẫu `<Tên trang> | FinWise` thông qua component dùng chung trong router; route chưa nhận diện dùng tiêu đề mô tả sản phẩm mặc định.
- **Khoảng trống cho header hệ thống**: Zalo Mini App mặc định hiển thị `zaui-header` ở phía trên. Mọi page/layout phải chừa đủ khoảng cách phía trên (tính cả safe area khi cần) để nội dung và phần tử tương tác không bị header che khuất.
- **Cấu hình API**: Base URL mặc định là `http://localhost:7777/api/v1` (tương tác trực tiếp với port 7777 của Backend).
- **Vite/ZMP entry**: Giữ `index.html` tại root repository và không cấu hình Vite `root: "./src"`. ZMP CLI khởi chạy dev server với project root; cấu hình khác sẽ khiến iframe app trả 404. Build output chuẩn là `www/` tại root.
......
{
"app": {
"title": "zmp-blank-templates",
"title": "FinWise - Sổ tay chi tiêu & Báo cáo tài chính",
"textColor": {
"light": "black",
"dark": "white"
......
......@@ -11,6 +11,7 @@ import { queryClient } from "@/lib/query-client";
import { useAuthStore } from "@/stores/auth-store";
import { authService } from "@/services/auth.service";
import { AuthGuard } from "@/components/shared/AuthGuard";
import { DocumentTitle } from "@/components/shared/DocumentTitle";
import { ThemeControl } from "@/components/shared/ThemeControl";
import { applyTheme, useThemeStore } from "@/stores/theme-store";
......@@ -63,6 +64,7 @@ const Layout = () => {
<SnackbarProvider>
<ThemeControl />
<ZMPRouter>
<DocumentTitle />
<AuthInitializer>
<AnimationRoutes>
{/* Public Auth Routes */}
......
import React, { useEffect } from "react";
import { useLocation } from "zmp-ui";
const APP_NAME = "FinWise";
const DEFAULT_TITLE = `${APP_NAME} | Sổ tay Chi tiêu & Báo cáo Tài chính`;
const PAGE_TITLES: ReadonlyArray<{
matches: (pathname: string) => boolean;
title: string;
}> = [
{ matches: (pathname) => pathname === "/", title: "Trang chủ" },
{ matches: (pathname) => pathname === "/login", title: "Đăng nhập" },
{ matches: (pathname) => pathname === "/register", title: "Đăng ký" },
{ matches: (pathname) => pathname === "/forgot-password", title: "Quên mật khẩu" },
{ matches: (pathname) => pathname === "/reset-password", title: "Đặt lại mật khẩu" },
{ matches: (pathname) => pathname === "/profile", title: "Tài khoản" },
{ matches: (pathname) => pathname === "/wallets", title: "Ví của tôi" },
{ matches: (pathname) => pathname.startsWith("/wallets/"), title: "Chi tiết ví" },
{ matches: (pathname) => pathname === "/style-guide", title: "Style Guide" },
];
function getDocumentTitle(pathname: string): string {
const pageTitle = PAGE_TITLES.find((page) => page.matches(pathname))?.title;
return pageTitle ? `${pageTitle} | ${APP_NAME}` : DEFAULT_TITLE;
}
export const DocumentTitle: React.FC = () => {
const { pathname } = useLocation();
useEffect(() => {
document.title = getDocumentTitle(pathname);
}, [pathname]);
return null;
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment