diff --git a/app/(feed)/feed/page.tsx b/app/(feed)/feed/page.tsx index 7695e90..ab70930 100644 --- a/app/(feed)/feed/page.tsx +++ b/app/(feed)/feed/page.tsx @@ -16,10 +16,10 @@ export default function FeedPage() { {/* Page title */}

- Khám phá quán nước + Explore Shops

- Tìm và chọn quán yêu thích của bạn + Find and choose your favorite shop

@@ -35,7 +35,7 @@ export default function FeedPage() { }} className="cursor-pointer border-none bg-transparent text-sm text-(--color-primary) hover:underline" > - Xóa bộ lọc + Clear filters )} @@ -46,7 +46,7 @@ export default function FeedPage() {
- Lọc quán + Filter shops
{/* Name search */} @@ -54,7 +54,7 @@ export default function FeedPage() { value={searchName} onChange={setSearchName} onClear={() => setSearchName("")} - placeholder="Tìm theo tên quán..." + placeholder="Search by shop name..." className="min-w-0 flex-1" /> @@ -65,13 +65,13 @@ export default function FeedPage() { type="text" value={searchAddress} onChange={(e) => setSearchAddress(e.target.value)} - placeholder="Tìm theo địa chỉ..." + placeholder="Search by address..." className="bg-background text-foreground focus:ring-opacity-20 w-full rounded-xl border border-(--color-border) py-2.5 pr-9 pl-9 text-sm transition-all duration-150 outline-none placeholder:text-(--color-text-muted) focus:border-(--color-primary) focus:ring-2 focus:ring-(--color-primary)" /> {searchAddress && (
@@ -106,7 +106,7 @@ export default function LoginOtpPage() {

- Mã OTP đã được gửi đến số {phone} + OTP code sent to {phone}

@@ -116,7 +116,7 @@ export default function LoginOtpPage() { htmlFor="otp" className="mb-2 block text-sm font-medium text-(--color-text-secondary)" > - Mã OTP + OTP code
@@ -128,7 +128,7 @@ export default function LoginOtpPage() { setOtp(e.target.value); setErrors({ otp: "", general: "" }); }} - placeholder="Nhập mã OTP" + placeholder="Enter OTP code" maxLength={6} disabled={isLoading} className={`text-foreground focus:ring-opacity-20 w-full rounded-xl border bg-white px-4 py-3 text-center text-lg tracking-widest transition-all duration-150 outline-none placeholder:text-sm placeholder:tracking-normal placeholder:text-(--color-text-muted) focus:border-(--color-primary) focus:ring-2 focus:ring-(--color-primary) disabled:opacity-60 lg:pl-11 ${errors.otp ? "border-red-400" : "border-(--color-border)"}`} @@ -151,10 +151,10 @@ export default function LoginOtpPage() { {isLoading ? ( <> - Đang xử lý... + Processing... ) : ( - "Đăng nhập" + "Sign in" )} @@ -163,7 +163,7 @@ export default function LoginOtpPage() { onClick={() => router.push("/login")} className="flex w-full items-center justify-center rounded-xl border-2 border-(--color-primary) bg-white py-3 font-semibold text-(--color-primary) transition-all duration-150 hover:bg-(--color-primary) hover:text-white active:scale-98" > - Thay đổi số điện thoại + Change phone number
diff --git a/app/(main)/login/page.tsx b/app/(main)/login/page.tsx index e877088..5ca3e9d 100644 --- a/app/(main)/login/page.tsx +++ b/app/(main)/login/page.tsx @@ -25,7 +25,7 @@ export default function LoginPage() { {SHOP_INFO.name}

- Nhập số điện thoại để đăng nhập + Enter your phone number to sign in

diff --git a/app/(main)/login/password/page.tsx b/app/(main)/login/password/page.tsx index bf89b58..d954120 100644 --- a/app/(main)/login/password/page.tsx +++ b/app/(main)/login/password/page.tsx @@ -32,7 +32,7 @@ export default function LoginPasswordPage() { e.preventDefault(); if (!password.trim()) { - setErrors({ password: "Vui lòng nhập mật khẩu", general: "" }); + setErrors({ password: "Please enter your password", general: "" }); return; } @@ -55,20 +55,20 @@ export default function LoginPasswordPage() { router.push("/manager"); } else { const STATUS_ERROR_MAP: Record = { - 400: "Sai thông tin đăng nhập, vui lòng thử lại", - 401: "Mật khẩu không đúng", - 403: "Tài khoản bị khóa", - 404: "Tài khoản không tồn tại", + 400: "Incorrect login details, please try again", + 401: "Incorrect password", + 403: "Account is locked", + 404: "Account does not exist", }; const msg = STATUS_ERROR_MAP[res.status] ?? (res.status >= 500 - ? "Lỗi máy chủ, vui lòng thử lại sau" - : "Đã có lỗi xảy ra, vui lòng thử lại"); + ? "Server error, please try again later" + : "An error occurred, please try again"); setErrors({ password: "", general: msg }); } } catch { - setErrors({ password: "", general: "Không thể kết nối, vui lòng thử lại" }); + setErrors({ password: "", general: "Unable to connect, please try again" }); } finally { setIsLoading(false); } @@ -94,7 +94,7 @@ export default function LoginPasswordPage() {

{SHOP_INFO.name}

-

Đăng nhập quản lý

+

Manager sign in

{errors.general && } @@ -112,7 +112,7 @@ export default function LoginPasswordPage() { htmlFor="password" className="mb-2 block text-sm font-medium text-(--color-text-secondary)" > - Mật khẩu + Password
@@ -124,7 +124,7 @@ export default function LoginPasswordPage() { setPassword(e.target.value); setErrors({ password: "", general: "" }); }} - placeholder="Nhập mật khẩu" + placeholder="Enter password" disabled={isLoading} className={`text-foreground focus:ring-opacity-20 w-full rounded-xl border bg-white px-10 py-3 transition-all duration-150 outline-none placeholder:text-(--color-text-muted) focus:border-(--color-primary) focus:ring-2 focus:ring-(--color-primary) disabled:opacity-60 lg:pl-11 ${errors.password ? "border-red-400" : "border-(--color-border)"}`} /> @@ -132,7 +132,7 @@ export default function LoginPasswordPage() { type="button" onClick={() => setShowPassword(!showPassword)} className="absolute top-1/2 right-4 -translate-y-1/2 text-(--color-text-muted) transition-colors hover:text-(--color-primary)" - aria-label={showPassword ? "Ẩn mật khẩu" : "Hiện mật khẩu"} + aria-label={showPassword ? "Hide password" : "Show password"} > @@ -154,10 +154,10 @@ export default function LoginPasswordPage() { {isLoading ? ( <> - Đang xử lý... + Processing... ) : ( - "Đăng nhập" + "Sign in" )} @@ -166,7 +166,7 @@ export default function LoginPasswordPage() { onClick={() => router.push("/login")} className="flex w-full items-center justify-center rounded-xl border-2 border-(--color-primary) bg-white py-3 font-semibold text-(--color-primary) transition-all duration-150 hover:bg-(--color-primary) hover:text-white active:scale-98" > - Thay đổi số điện thoại + Change phone number
diff --git a/app/(main)/manager-signup/page.tsx b/app/(main)/manager-signup/page.tsx index 7cab9f8..caad475 100644 --- a/app/(main)/manager-signup/page.tsx +++ b/app/(main)/manager-signup/page.tsx @@ -37,12 +37,12 @@ export default function ManagerSignupPage() { const validate = () => { const next = { name: "", phone: "", password: "", eateryName: "", submit: "" }; - if (!form.name.trim()) next.name = "Vui lòng nhập họ tên"; - if (!form.phone.trim()) next.phone = "Vui lòng nhập số điện thoại"; - else if (!validatePhone(form.phone)) next.phone = "Số điện thoại không hợp lệ (VD: 0987654321)"; - if (!form.password.trim()) next.password = "Vui lòng nhập mật khẩu"; - else if (form.password.length < 6) next.password = "Mật khẩu ít nhất 6 ký tự"; - if (!form.eateryName.trim()) next.eateryName = "Vui lòng nhập tên nhà hàng"; + if (!form.name.trim()) next.name = "Please enter your full name"; + if (!form.phone.trim()) next.phone = "Please enter your phone number"; + else if (!validatePhone(form.phone)) next.phone = "Invalid phone number (e.g. 0987654321)"; + if (!form.password.trim()) next.password = "Please enter your password"; + else if (form.password.length < 6) next.password = "Password must be at least 6 characters"; + if (!form.eateryName.trim()) next.eateryName = "Please enter the restaurant name"; setErrors(next); return !next.name && !next.phone && !next.password && !next.eateryName; }; @@ -64,13 +64,13 @@ export default function ManagerSignupPage() { } else { const errorCode = (await res.text().catch(() => "")).trim(); const errorMap: Record = { - ExistedUser: "Số điện thoại đã được đăng ký", - InvalidPhoneNumber: "Số điện thoại không hợp lệ", + ExistedUser: "Phone number already registered", + InvalidPhoneNumber: "Invalid phone number", }; - setErrors({ ...errors, submit: errorMap[errorCode] ?? "Đã có lỗi xảy ra, vui lòng thử lại" }); + setErrors({ ...errors, submit: errorMap[errorCode] ?? "An error occurred, please try again" }); } } catch { - setErrors({ ...errors, submit: "Không thể kết nối, vui lòng thử lại" }); + setErrors({ ...errors, submit: "Unable to connect, please try again" }); } finally { setIsLoading(false); } @@ -85,14 +85,14 @@ export default function ManagerSignupPage() { {SHOP_INFO.name}

{SHOP_INFO.name}

-

Đăng ký tài khoản quản lý

+

Create a manager account

{/* Checking */} {pageState === "checking" && (
-

Đang kiểm tra...

+

Checking...

)} @@ -103,8 +103,8 @@ export default function ManagerSignupPage() {
-

Đăng ký đã đóng

-

Hệ thống đã có nhà hàng. Chức năng đăng ký không còn khả dụng.

+

Registration closed

+

The system already has a restaurant. Registration is no longer available.

c.id === activeCategory)?.name ?? "Tất cả"; + MENU_CATEGORIES.find((c) => c.id === activeCategory)?.name ?? "All"; return (
@@ -69,7 +69,7 @@ export default function Home() { setSearchQuery(q); }} onClear={() => setSearchQuery("")} - placeholder="Tìm kiếm món..." + placeholder="Search items..." className="sm:max-w-xs" />
diff --git a/app/(main)/payment/page.tsx b/app/(main)/payment/page.tsx index 653c83e..edbfd09 100644 --- a/app/(main)/payment/page.tsx +++ b/app/(main)/payment/page.tsx @@ -46,22 +46,22 @@ export default function PaymentPage() { - Tên sản phẩm + Product name - Giá tiền + Price - Mô tả + Description - Số lượng + Quantity - Xóa + Delete @@ -116,7 +116,7 @@ export default function PaymentPage() { style="payment" aria-label={`Xóa ${item.name} khỏi giỏ hàng`} > - Xóa sản phẩm + Delete product diff --git a/app/(main)/register/page.tsx b/app/(main)/register/page.tsx index f609496..6b308c3 100644 --- a/app/(main)/register/page.tsx +++ b/app/(main)/register/page.tsx @@ -33,10 +33,10 @@ export default function RegisterPage() { body: JSON.stringify({ phone }), }); if (!res.ok) { - setOtpSendError("Không thể gửi OTP, vui lòng thử lại"); + setOtpSendError("Unable to send OTP, please try again"); } } catch { - setOtpSendError("Không thể kết nối, vui lòng thử lại"); + setOtpSendError("Unable to connect, please try again"); } finally { setOtpSending(false); } @@ -61,14 +61,14 @@ export default function RegisterPage() { e.preventDefault(); if (!phone.trim()) { - setErrors({ ...errors, phone: "Vui lòng nhập số điện thoại" }); + setErrors({ ...errors, phone: "Please enter your phone number" }); return; } if (!validatePhone(phone)) { setErrors({ ...errors, - phone: "Số điện thoại không hợp lệ (VD: 0987654321)", + phone: "Invalid phone number (e.g. 0987654321)", }); return; } @@ -88,14 +88,14 @@ export default function RegisterPage() { } else { const errorCode = (await res.text().catch(() => "")).trim(); const phoneErrorMap: Record = { - ExistedUser: "Số điện thoại đã được đăng ký", - InvalidPhoneNumber: "Số điện thoại không hợp lệ", + ExistedUser: "Phone number already registered", + InvalidPhoneNumber: "Invalid phone number", }; - const msg = phoneErrorMap[errorCode] ?? "Đã có lỗi xảy ra, vui lòng thử lại"; + const msg = phoneErrorMap[errorCode] ?? "An error occurred, please try again"; setErrors({ phone: msg, otp: "" }); } } catch { - setErrors({ phone: "Không thể kết nối, vui lòng thử lại", otp: "" }); + setErrors({ phone: "Unable to connect, please try again", otp: "" }); } finally { setIsLoading(false); } @@ -105,7 +105,7 @@ export default function RegisterPage() { e.preventDefault(); if (!otp.trim()) { - setErrors({ ...errors, otp: "Vui lòng nhập mã OTP" }); + setErrors({ ...errors, otp: "Please enter your OTP code" }); return; } @@ -128,12 +128,12 @@ export default function RegisterPage() { const errorCode = (await res.text().catch(() => "")).trim(); const msg = errorCode === "InvalidOTP" - ? "Mã OTP không đúng hoặc đã hết hạn" - : "Đã có lỗi xảy ra, vui lòng thử lại"; + ? "Incorrect or expired OTP code" + : "An error occurred, please try again"; setErrors({ phone: "", otp: msg }); } } catch { - setErrors({ phone: "", otp: "Không thể kết nối, vui lòng thử lại" }); + setErrors({ phone: "", otp: "Unable to connect, please try again" }); } finally { setIsLoading(false); } @@ -166,8 +166,8 @@ export default function RegisterPage() {

{step === "phone" - ? "Đăng ký tài khoản khách hàng" - : "Xác thực số điện thoại"} + ? "Create a customer account" + : "Verify your phone number"}

@@ -203,7 +203,7 @@ export default function RegisterPage() { htmlFor="phone" className="mb-2 block text-sm font-medium text-(--color-text-secondary)" > - Số điện thoại + Phone number
@@ -227,7 +227,7 @@ export default function RegisterPage() {

)}

- Nhập số điện thoại Việt Nam (10 số, bắt đầu bằng 0) + Enter a Vietnamese phone number (10 digits, starting with 0)

@@ -244,10 +244,10 @@ export default function RegisterPage() { {isLoading ? ( <> - Đang xử lý... + Processing... ) : ( - "Tiếp tục" + "Continue" )} @@ -256,7 +256,7 @@ export default function RegisterPage() { href="/login" className="flex w-full items-center justify-center rounded-xl border-2 border-(--color-primary) bg-white py-3 font-semibold text-(--color-primary) no-underline transition-all duration-150 hover:bg-(--color-primary) hover:text-white active:scale-98" > - Quay lại đăng nhập + Back to sign in @@ -272,11 +272,11 @@ export default function RegisterPage() { {otpSending ? ( <> - Đang gửi OTP đến {phone}... + Sending OTP to {phone}... ) : ( <> - Mã OTP đã được gửi đến số {phone} + OTP code sent to {phone} )}

@@ -300,7 +300,7 @@ export default function RegisterPage() { htmlFor="otp" className="mb-2 block text-sm font-medium text-(--color-text-secondary)" > - Mã OTP + OTP code
@@ -312,7 +312,7 @@ export default function RegisterPage() { setOtp(e.target.value); setErrors({ ...errors, otp: "" }); }} - placeholder="Nhập mã OTP" + placeholder="Enter OTP code" maxLength={6} disabled={isLoading} className={`text-foreground focus:ring-opacity-20 w-full rounded-xl border bg-white px-4 py-3 text-center text-lg tracking-widest transition-all duration-150 outline-none placeholder:text-sm placeholder:tracking-normal placeholder:text-(--color-text-muted) focus:border-(--color-primary) focus:ring-2 focus:ring-(--color-primary) disabled:opacity-60 lg:pl-11 ${errors.otp ? "border-red-400" : "border-(--color-border)"} `} @@ -339,10 +339,10 @@ export default function RegisterPage() { {isLoading ? ( <> - Đang xử lý... + Processing... ) : ( - "Hoàn tất đăng ký" + "Complete registration" )} @@ -354,7 +354,7 @@ export default function RegisterPage() { style="login" disabled={isLoading} > - Thay đổi số điện thoại + Change phone number
@@ -369,10 +369,10 @@ export default function RegisterPage() { {otpSending ? ( <> - Đang gửi lại... + Resending... ) : ( - "Gửi lại mã OTP" + "Resend OTP code" )} diff --git a/app/(manager)/manager/analytics/page.tsx b/app/(manager)/manager/analytics/page.tsx index c0d738e..b38ab8e 100644 --- a/app/(manager)/manager/analytics/page.tsx +++ b/app/(manager)/manager/analytics/page.tsx @@ -28,10 +28,10 @@ import { useMemo, useState } from "react"; // ─── Constants ──────────────────────────────────────────────────────────────── const PERIOD_LABELS: Record = { - day: "Theo ngày", - week: "Theo tuần", - month: "Theo tháng", - year: "Theo năm", + day: "By day", + week: "By week", + month: "By month", + year: "By year", }; const CATEGORY_COLORS = [ @@ -67,7 +67,7 @@ const CHART_META: Record = { function CategorySelect({ value, onChange, - label = "Danh mục:", + label = "Category:", }: { value: string; onChange: (v: string) => void; @@ -78,12 +78,12 @@ function CategorySelect({
setPeriod(e.target.value as AnalyticsPeriod)} className="text-foreground block rounded-lg border border-(--color-border) bg-(--color-bg-card) px-2 py-1.5 text-xs sm:hidden" @@ -226,12 +226,12 @@ export default function AnalyticsPage() { {/* ── Summary Cards ── */}

- Tổng quan + Overview

- Biểu đồ doanh thu + Revenue Chart

{CHART_TYPES.map((t) => ( @@ -298,7 +298,7 @@ export default function AnalyticsPage() { {activeChart === "line" && ( <>

- Doanh thu theo thời gian — {PERIOD_LABELS[period]} + Revenue over time — {PERIOD_LABELS[period]}

@@ -306,7 +306,7 @@ export default function AnalyticsPage() { {activeChart === "bar" && ( <>

- So sánh doanh thu nửa đầu và nửa sau kỳ hiện tại + Comparing revenue of the first and second half of the current period

- Tỷ trọng doanh thu theo danh mục sản phẩm + Revenue share by product category

@@ -330,7 +330,7 @@ export default function AnalyticsPage() {

- Top sản phẩm bán chạy + Top best-selling products

- {p.unitsSold} ly + {p.unitsSold} cups {formatCurrency(p.revenue)} @@ -377,17 +377,17 @@ export default function AnalyticsPage() {

- Phân tích chi tiết sản phẩm + Detailed product analytics

- Click vào tiêu đề cột để sắp xếp. Hiển thị {filteredSales.length}{" "} - sản phẩm. + Click column headers to sort. Showing {filteredSales.length}{" "} + products.

@@ -395,7 +395,7 @@ export default function AnalyticsPage() {
- Tổng doanh thu:{" "} + Total revenue:{" "} {formatCurrencyFull(filteredRevenue)} @@ -403,7 +403,7 @@ export default function AnalyticsPage() {
- Tổng lợi nhuận:{" "} + Total profit:{" "} {formatCurrencyFull(filteredProfit)} @@ -411,15 +411,15 @@ export default function AnalyticsPage() {
- Tổng sản lượng:{" "} + Total units:{" "} - {filteredUnits.toLocaleString()} ly + {filteredUnits.toLocaleString()} cups
- Biên LN trung bình:{" "} + Avg. profit margin:{" "} {avgMargin.toFixed(1)}% diff --git a/app/(manager)/manager/page.tsx b/app/(manager)/manager/page.tsx index 10601ce..78bf7c5 100644 --- a/app/(manager)/manager/page.tsx +++ b/app/(manager)/manager/page.tsx @@ -18,7 +18,7 @@ export default function ManagerPage() { const tabs = [ { id: "products" as const, - label: "Thực đơn", + label: "Menu", icon: "fa-solid fa-utensils", count: products.length, }, @@ -30,7 +30,7 @@ export default function ManagerPage() { }, { id: "categories" as const, - label: "Danh mục", + label: "Categories", icon: "fa-solid fa-tags", count: categories.length, }, @@ -58,7 +58,7 @@ export default function ManagerPage() {
@@ -119,9 +119,9 @@ export default function ManagerPage() {

- {user?.name ?? "Quản lý"} + {user?.name ?? "Manager"}

-

Quản lý quán

+

Store Manager

@@ -130,14 +130,14 @@ export default function ManagerPage() { className="hover:bg-background flex flex-1 items-center justify-center gap-1.5 rounded-xl border border-(--color-border-light) bg-transparent py-2 text-xs font-medium text-(--color-text-secondary) no-underline transition" > - Trang chủ + Home
@@ -148,18 +148,18 @@ export default function ManagerPage() {

- {tabs.find((t) => t.id === activeTab)?.label ?? "Quản lý"} + {tabs.find((t) => t.id === activeTab)?.label ?? "Manager"}

- Quản lý{" "} + Manage{" "} {activeTab === "products" - ? "thực đơn" + ? "menu items" : activeTab === "combos" - ? "combo" + ? "combos" : activeTab === "categories" - ? "danh mục" + ? "categories" : "menu"}{" "} - của quán + for your store

@@ -184,7 +184,7 @@ export default function ManagerPage() { className="flex items-center gap-1.5 rounded-xl border-none bg-(--color-accent-light) px-3 py-2 text-xs font-medium text-(--color-primary) no-underline transition hover:bg-(--color-accent-light)/70" > - Tài chính + Finance
@@ -195,14 +195,14 @@ export default function ManagerPage() { className="flex items-center gap-1.5 rounded-xl bg-(--color-accent-light) px-3 py-2 text-xs font-medium text-(--color-primary) no-underline transition hover:opacity-80" > - Thống kê tài chính + Financial Analytics - Trang chủ + Home
diff --git a/app/(staff)/staff/schedule/page.tsx b/app/(staff)/staff/schedule/page.tsx index 7fa8850..625f8ec 100644 --- a/app/(staff)/staff/schedule/page.tsx +++ b/app/(staff)/staff/schedule/page.tsx @@ -12,18 +12,18 @@ import Link from "next/link"; import { useState } from "react"; const MONTH_NAMES = [ - "Tháng 1", - "Tháng 2", - "Tháng 3", - "Tháng 4", - "Tháng 5", - "Tháng 6", - "Tháng 7", - "Tháng 8", - "Tháng 9", - "Tháng 10", - "Tháng 11", - "Tháng 12", + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December", ]; function getMonday(d: Date): Date { @@ -95,7 +95,7 @@ export default function StaffSchedulePage() {
-

Lịch làm việc

+

Work Schedule

{isManager ? "Manager" : "Staff"}

@@ -105,7 +105,7 @@ export default function StaffSchedulePage() { {/* View toggle */}
@@ -220,7 +220,7 @@ export default function StaffSchedulePage() {

- Đăng ký ca làm + Register Shift

{view === "week" @@ -241,7 +241,7 @@ export default function StaffSchedulePage() { : "bg-transparent text-(--color-text-secondary)" }`} > - Tuần + Week

{/* Navigation arrows */}
)} {/* Mobile nav */}
)} @@ -77,7 +77,7 @@ export default function PaymentSummaryCard({ variant="secondary" className="w-full" > - Quay về + Return
diff --git a/components/molecules/cards/ProductCard.tsx b/components/molecules/cards/ProductCard.tsx index 9bcede9..de0a79d 100644 --- a/components/molecules/cards/ProductCard.tsx +++ b/components/molecules/cards/ProductCard.tsx @@ -69,7 +69,7 @@ export default function ProductCard({ icon="fa-cart-plus" aria-label={`Mua ${productName}`} > - Mua + Buy
diff --git a/components/molecules/cards/ShopCard.tsx b/components/molecules/cards/ShopCard.tsx index cc27ef9..8803239 100644 --- a/components/molecules/cards/ShopCard.tsx +++ b/components/molecules/cards/ShopCard.tsx @@ -28,7 +28,7 @@ export default function ShopCard({ name, address, image }: ShopCardProps) { className="inline-flex shrink-0 items-center gap-1.5 rounded-xl bg-(--color-primary) px-3.5 py-2 text-xs font-semibold text-white no-underline transition-all duration-150 hover:bg-(--color-primary-dark) active:scale-95" > - Xem menu + View menu diff --git a/components/organisms/forms/LoginForm.tsx b/components/organisms/forms/LoginForm.tsx index eb34a2e..a3cfafe 100644 --- a/components/organisms/forms/LoginForm.tsx +++ b/components/organisms/forms/LoginForm.tsx @@ -17,11 +17,11 @@ export default function LoginForm() { const validate = (): boolean => { if (!phone.trim()) { - setErrors({ phone: "Vui lòng nhập số điện thoại", general: "" }); + setErrors({ phone: "Please enter your phone number", general: "" }); return false; } if (!PHONE_REGEX.test(phone)) { - setErrors({ phone: "Số điện thoại không hợp lệ (VD: 0987654321)", general: "" }); + setErrors({ phone: "Invalid phone number (e.g. 0987654321)", general: "" }); return false; } return true; @@ -48,12 +48,12 @@ export default function LoginForm() { sessionStorage.setItem("login_role", role); router.push(role === "manager" ? "/login/password" : "/login/otp"); } else if (res.status === 404) { - setErrors({ phone: "", general: "Số điện thoại chưa đăng ký" }); + setErrors({ phone: "", general: "Phone number not registered" }); } else { - setErrors({ phone: "", general: "Đã có lỗi xảy ra, vui lòng thử lại" }); + setErrors({ phone: "", general: "An error occurred, please try again" }); } } catch { - setErrors({ phone: "", general: "Không thể kết nối, vui lòng thử lại" }); + setErrors({ phone: "", general: "Unable to connect, please try again" }); } finally { setIsLoading(false); } @@ -69,7 +69,7 @@ export default function LoginForm() { htmlFor="phone" className="mb-2 block text-sm font-medium text-(--color-text-secondary)" > - Số điện thoại + Phone number
@@ -90,7 +90,7 @@ export default function LoginForm() { )}

- Nhập số điện thoại Việt Nam (10 số, bắt đầu bằng 0) + Enter a Vietnamese phone number (10 digits, starting with 0)

@@ -105,10 +105,10 @@ export default function LoginForm() { {isLoading ? ( <> - Đang xử lý... + Processing... ) : ( - "Tiếp tục" + "Continue" )} @@ -116,7 +116,7 @@ export default function LoginForm() { href="/register" className="flex w-full items-center justify-center rounded-xl border-2 border-(--color-primary) bg-white py-3 font-semibold text-(--color-primary) no-underline transition-all duration-150 hover:bg-(--color-primary) hover:text-white active:scale-98" > - Đăng ký tài khoản + Create account diff --git a/components/organisms/manager/CategoriesTab.tsx b/components/organisms/manager/CategoriesTab.tsx index dcc03b4..598499d 100644 --- a/components/organisms/manager/CategoriesTab.tsx +++ b/components/organisms/manager/CategoriesTab.tsx @@ -23,15 +23,15 @@ export default function CategoriesTab() {

- {categories.length} danh - mục + {categories.length}{" "} + categories

@@ -50,19 +50,19 @@ export default function CategoriesTab() {

{cat.name}

-

{count} món

+

{count} items

diff --git a/components/organisms/manager/CategoryModal.tsx b/components/organisms/manager/CategoryModal.tsx index b93e808..92c618c 100644 --- a/components/organisms/manager/CategoryModal.tsx +++ b/components/organisms/manager/CategoryModal.tsx @@ -52,7 +52,7 @@ export default function CategoryModal({

- {isEdit ? "Chỉnh sửa danh mục" : "Thêm danh mục mới"} + {isEdit ? "Edit category" : "Add new category"}

- Cảm ơn quý khách + Thank you - Chúng tôi trân trọng đánh giá của bạn! + We appreciate your feedback!
) : ( @@ -65,21 +65,21 @@ export default function ReviewModal({ isOpen, onClose }: ReviewModalProps) { id="review-modal-title" className="text-foreground mb-1 text-xl font-bold" > - Đánh giá của bạn + Your Review

- Hãy cho chúng tôi biết trải nghiệm của bạn hôm nay + Tell us about your experience today

{/* Star rating */}

- Mức độ hài lòng + Satisfaction level

{[1, 2, 3, 4, 5].map((star) => { const isActive = star <= (hovered || rating); @@ -90,7 +90,7 @@ export default function ReviewModal({ isOpen, onClose }: ReviewModalProps) { onClick={() => setRating(star)} onMouseEnter={() => setHovered(star)} onMouseLeave={() => setHovered(0)} - aria-label={`${star} sao`} + aria-label={`${star} star`} aria-pressed={rating === star} className="text-3xl transition-transform hover:scale-110 active:scale-95 sm:text-4xl" > @@ -108,7 +108,7 @@ export default function ReviewModal({ isOpen, onClose }: ReviewModalProps) { {rating > 0 && (

{ - ["", "Rất tệ", "Tệ", "Bình thường", "Tốt", "Xuất sắc"][ + ["", "Very poor", "Poor", "Average", "Good", "Excellent"][ rating ] } @@ -120,10 +120,10 @@ export default function ReviewModal({ isOpen, onClose }: ReviewModalProps) {