Refactor: Update Vietnamese text to English across multiple components
Release package / release (pull_request) Successful in 3m23s
Release package / release (pull_request) Successful in 3m23s
- Translated payment page text from Vietnamese to English. - Updated staff creation page with English labels and messages. - Changed staff schedule page labels and navigation items to English. - Modified shift card and search bar components to use English text. - Updated delete confirmation and product modal components with English messages. - Translated product management tab and category sidebar to English. - Changed shift schedule components to display English text for shifts and actions. - Updated header logo alt text to improve accessibility.
This commit is contained in:
@@ -151,7 +151,7 @@ export default function ManagerSignupPage() {
|
|||||||
href="/login"
|
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"
|
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"
|
||||||
>
|
>
|
||||||
Quay lại đăng nhập
|
Back to login
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -164,10 +164,10 @@ export default function ManagerSignupPage() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<h2 className="mb-2 text-lg font-semibold text-(--color-text-primary)">
|
<h2 className="mb-2 text-lg font-semibold text-(--color-text-primary)">
|
||||||
Không thể kết nối
|
Unable to connect
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-sm text-(--color-text-muted)">
|
<p className="text-sm text-(--color-text-muted)">
|
||||||
Không thể kiểm tra trạng thái đăng ký. Vui lòng thử lại.
|
Unable to check registration status. Please try again.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<Button
|
<Button
|
||||||
@@ -185,13 +185,13 @@ export default function ManagerSignupPage() {
|
|||||||
.catch(() => setPageState("error"));
|
.catch(() => setPageState("error"));
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Thử lại
|
Retry
|
||||||
</Button>
|
</Button>
|
||||||
<Link
|
<Link
|
||||||
href="/login"
|
href="/login"
|
||||||
className="text-sm text-(--color-primary) underline"
|
className="text-sm text-(--color-primary) underline"
|
||||||
>
|
>
|
||||||
Quay lại đăng nhập
|
Back to login
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -202,15 +202,15 @@ export default function ManagerSignupPage() {
|
|||||||
{[
|
{[
|
||||||
{
|
{
|
||||||
id: "name",
|
id: "name",
|
||||||
label: "Họ tên",
|
label: "Full name",
|
||||||
icon: "fa-user",
|
icon: "fa-user",
|
||||||
placeholder: "Nguyễn Văn A",
|
placeholder: "John Doe",
|
||||||
field: "name" as const,
|
field: "name" as const,
|
||||||
type: "text",
|
type: "text",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "phone",
|
id: "phone",
|
||||||
label: "Số điện thoại",
|
label: "Phone number",
|
||||||
icon: "fa-phone",
|
icon: "fa-phone",
|
||||||
placeholder: "0987654321",
|
placeholder: "0987654321",
|
||||||
field: "phone" as const,
|
field: "phone" as const,
|
||||||
@@ -218,15 +218,15 @@ export default function ManagerSignupPage() {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "password",
|
id: "password",
|
||||||
label: "Mật khẩu",
|
label: "Password",
|
||||||
icon: "fa-lock",
|
icon: "fa-lock",
|
||||||
placeholder: "Ít nhất 6 ký tự",
|
placeholder: "At least 6 characters",
|
||||||
field: "password" as const,
|
field: "password" as const,
|
||||||
type: "password",
|
type: "password",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "eateryName",
|
id: "eateryName",
|
||||||
label: "Tên nhà hàng",
|
label: "Restaurant name",
|
||||||
icon: "fa-store",
|
icon: "fa-store",
|
||||||
placeholder: "Coffee & More",
|
placeholder: "Coffee & More",
|
||||||
field: "eateryName" as const,
|
field: "eateryName" as const,
|
||||||
@@ -280,18 +280,17 @@ export default function ManagerSignupPage() {
|
|||||||
>
|
>
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<>
|
<>
|
||||||
<i className="fa-solid fa-spinner fa-spin mr-2"></i>Đang xử
|
<i className="fa-solid fa-spinner fa-spin mr-2"></i>Processing...
|
||||||
lý...
|
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
"Đăng ký"
|
"Register"
|
||||||
)}
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
<Link
|
<Link
|
||||||
href="/login"
|
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"
|
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"
|
||||||
>
|
>
|
||||||
Đã có tài khoản? Đăng nhập
|
Already have an account? Sign in
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -41,13 +41,13 @@ export default function PaymentPage() {
|
|||||||
<div className="bg-card overflow-hidden rounded-2xl border border-(--color-border-light)">
|
<div className="bg-card overflow-hidden rounded-2xl border border-(--color-border-light)">
|
||||||
<div className="border-b border-(--color-border-light) px-4 py-3">
|
<div className="border-b border-(--color-border-light) px-4 py-3">
|
||||||
<h1 className="text-foreground text-lg font-bold md:text-xl">
|
<h1 className="text-foreground text-lg font-bold md:text-xl">
|
||||||
Trang thanh toán
|
Payment
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{items?.length === 0 ? (
|
{items?.length === 0 ? (
|
||||||
<div className="px-4 py-10 text-center text-(--color-text-muted)">
|
<div className="px-4 py-10 text-center text-(--color-text-muted)">
|
||||||
Chưa có sản phẩm nào trong giỏ hàng.
|
Your cart is empty.
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="overflow-x-auto">
|
<div className="overflow-x-auto">
|
||||||
@@ -102,7 +102,7 @@ export default function PaymentPage() {
|
|||||||
<button
|
<button
|
||||||
onClick={() => decreaseQty(id)}
|
onClick={() => decreaseQty(id)}
|
||||||
className="inline-flex h-8 w-8 items-center justify-center rounded-lg border border-(--color-border) hover:bg-(--color-border-light)"
|
className="inline-flex h-8 w-8 items-center justify-center rounded-lg border border-(--color-border) hover:bg-(--color-border-light)"
|
||||||
aria-label={`Giảm số lượng ${name}`}
|
aria-label={`Decrease quantity of ${name}`}
|
||||||
>
|
>
|
||||||
-
|
-
|
||||||
</button>
|
</button>
|
||||||
@@ -114,12 +114,12 @@ export default function PaymentPage() {
|
|||||||
setQuantity(id, Number(e.target.value))
|
setQuantity(id, Number(e.target.value))
|
||||||
}
|
}
|
||||||
className="h-8 w-16 rounded-lg border border-(--color-border) bg-transparent text-center"
|
className="h-8 w-16 rounded-lg border border-(--color-border) bg-transparent text-center"
|
||||||
title="Nhập số lượng"
|
title="Enter quantity"
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
onClick={() => increaseQty(id)}
|
onClick={() => increaseQty(id)}
|
||||||
className="inline-flex h-8 w-8 items-center justify-center rounded-lg border border-(--color-border) hover:bg-(--color-border-light)"
|
className="inline-flex h-8 w-8 items-center justify-center rounded-lg border border-(--color-border) hover:bg-(--color-border-light)"
|
||||||
aria-label={`Tăng số lượng ${name}`}
|
aria-label={`Increase quantity of ${name}`}
|
||||||
>
|
>
|
||||||
+
|
+
|
||||||
</button>
|
</button>
|
||||||
@@ -131,7 +131,7 @@ export default function PaymentPage() {
|
|||||||
variant="danger"
|
variant="danger"
|
||||||
size="md"
|
size="md"
|
||||||
style="payment"
|
style="payment"
|
||||||
aria-label={`Xóa ${name} khỏi giỏ hàng`}
|
aria-label={`Remove ${name} from cart`}
|
||||||
>
|
>
|
||||||
Delete product
|
Delete product
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -27,13 +27,13 @@ export default function CreateStaffPage() {
|
|||||||
|
|
||||||
const validate = () => {
|
const validate = () => {
|
||||||
const next = { name: "", phone: "", password: "", submit: "" };
|
const next = { name: "", phone: "", password: "", submit: "" };
|
||||||
if (!form.name.trim()) next.name = "Vui lòng nhập họ tên";
|
if (!form.name.trim()) next.name = "Please enter full name";
|
||||||
if (!form.phone.trim()) next.phone = "Vui lòng nhập số điện thoại";
|
if (!form.phone.trim()) next.phone = "Please enter phone number";
|
||||||
else if (!validatePhone(form.phone))
|
else if (!validatePhone(form.phone))
|
||||||
next.phone = "Số điện thoại không hợp lệ (vd: 0987654321)";
|
next.phone = "Invalid phone number (e.g. 0987654321)";
|
||||||
if (!form.password.trim()) next.password = "Vui lòng nhập mật khẩu";
|
if (!form.password.trim()) next.password = "Please enter password";
|
||||||
else if (form.password.length < 6)
|
else if (form.password.length < 6)
|
||||||
next.password = "Mật khẩu phải có ít nhất 6 ký tự";
|
next.password = "Password must be at least 6 characters";
|
||||||
setErrors(next);
|
setErrors(next);
|
||||||
return !next.name && !next.phone && !next.password;
|
return !next.name && !next.phone && !next.password;
|
||||||
};
|
};
|
||||||
@@ -55,17 +55,17 @@ export default function CreateStaffPage() {
|
|||||||
} else {
|
} else {
|
||||||
const errorCode = (await res.text().catch(() => "")).trim();
|
const errorCode = (await res.text().catch(() => "")).trim();
|
||||||
const errorMap: Record<string, string> = {
|
const errorMap: Record<string, string> = {
|
||||||
ExistedUser: "Số điện thoại đã được đăng ký",
|
ExistedUser: "Phone number already registered",
|
||||||
InvalidPhoneNumber: "Số điện thoại không hợp lệ",
|
InvalidPhoneNumber: "Invalid phone number",
|
||||||
InvalidManager: "Không tìm thấy tài khoản manager",
|
InvalidManager: "Manager account not found",
|
||||||
};
|
};
|
||||||
setErrors({
|
setErrors({
|
||||||
...errors,
|
...errors,
|
||||||
submit: errorMap[errorCode] ?? "Đã có lỗi xảy ra, vui lòng thử lại",
|
submit: errorMap[errorCode] ?? "An error occurred, please try again",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch {
|
} 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 {
|
} finally {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}
|
}
|
||||||
@@ -79,10 +79,10 @@ export default function CreateStaffPage() {
|
|||||||
<i className="fa-solid fa-user-plus text-2xl text-(--color-primary)"></i>
|
<i className="fa-solid fa-user-plus text-2xl text-(--color-primary)"></i>
|
||||||
</div>
|
</div>
|
||||||
<h1 className="mb-1 text-2xl font-bold text-(--color-primary-dark)">
|
<h1 className="mb-1 text-2xl font-bold text-(--color-primary-dark)">
|
||||||
Tạo tài khoản nhân viên
|
Create Staff Account
|
||||||
</h1>
|
</h1>
|
||||||
<p className="text-sm text-(--color-text-muted)">
|
<p className="text-sm text-(--color-text-muted)">
|
||||||
Thêm nhân viên mới cho nhà hàng
|
Add a new staff member to the restaurant
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -90,15 +90,15 @@ export default function CreateStaffPage() {
|
|||||||
{[
|
{[
|
||||||
{
|
{
|
||||||
id: "name",
|
id: "name",
|
||||||
label: "Họ tên",
|
label: "Full name",
|
||||||
icon: "fa-user",
|
icon: "fa-user",
|
||||||
placeholder: "Nguyễn Văn A",
|
placeholder: "John Doe",
|
||||||
field: "name" as const,
|
field: "name" as const,
|
||||||
type: "text",
|
type: "text",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "phone",
|
id: "phone",
|
||||||
label: "Số điện thoại",
|
label: "Phone number",
|
||||||
icon: "fa-phone",
|
icon: "fa-phone",
|
||||||
placeholder: "0987654321",
|
placeholder: "0987654321",
|
||||||
field: "phone" as const,
|
field: "phone" as const,
|
||||||
@@ -106,9 +106,9 @@ export default function CreateStaffPage() {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "password",
|
id: "password",
|
||||||
label: "Mật khẩu",
|
label: "Password",
|
||||||
icon: "fa-lock",
|
icon: "fa-lock",
|
||||||
placeholder: "Ít nhất 6 ký tự",
|
placeholder: "At least 6 characters",
|
||||||
field: "password" as const,
|
field: "password" as const,
|
||||||
type: "password",
|
type: "password",
|
||||||
},
|
},
|
||||||
@@ -160,18 +160,17 @@ export default function CreateStaffPage() {
|
|||||||
>
|
>
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<>
|
<>
|
||||||
<i className="fa-solid fa-spinner fa-spin mr-2"></i>Đang xử
|
<i className="fa-solid fa-spinner fa-spin mr-2"></i>Processing...
|
||||||
lý...
|
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
"Tạo tài khoản"
|
"Create account"
|
||||||
)}
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
<Link
|
<Link
|
||||||
href="/manager"
|
href="/manager"
|
||||||
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"
|
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"
|
||||||
>
|
>
|
||||||
Quay lại Dashboard
|
Back to Dashboard
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ export default function StaffSchedulePage() {
|
|||||||
<nav className="flex-1 space-y-0.5 overflow-y-auto p-3">
|
<nav className="flex-1 space-y-0.5 overflow-y-auto p-3">
|
||||||
{/* View toggle */}
|
{/* View toggle */}
|
||||||
<p className="mb-1 px-3 pt-2 text-[10px] font-bold tracking-widest text-(--color-text-muted) uppercase">
|
<p className="mb-1 px-3 pt-2 text-[10px] font-bold tracking-widest text-(--color-text-muted) uppercase">
|
||||||
Chế độ xem
|
View
|
||||||
</p>
|
</p>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@@ -108,7 +108,7 @@ export default function StaffSchedulePage() {
|
|||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<i className={`fa-solid fa-table-columns w-4 text-center ${view === "week" ? "text-(--color-primary)" : ""}`}></i>
|
<i className={`fa-solid fa-table-columns w-4 text-center ${view === "week" ? "text-(--color-primary)" : ""}`}></i>
|
||||||
<span className="flex-1 text-left">Theo tuần</span>
|
<span className="flex-1 text-left">Weekly</span>
|
||||||
{view === "week" && (
|
{view === "week" && (
|
||||||
<span className="h-1.5 w-1.5 rounded-full bg-(--color-primary)"></span>
|
<span className="h-1.5 w-1.5 rounded-full bg-(--color-primary)"></span>
|
||||||
)}
|
)}
|
||||||
@@ -123,7 +123,7 @@ export default function StaffSchedulePage() {
|
|||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<i className={`fa-solid fa-calendar w-4 text-center ${view === "month" ? "text-(--color-primary)" : ""}`}></i>
|
<i className={`fa-solid fa-calendar w-4 text-center ${view === "month" ? "text-(--color-primary)" : ""}`}></i>
|
||||||
<span className="flex-1 text-left">Theo tháng</span>
|
<span className="flex-1 text-left">Monthly</span>
|
||||||
{view === "month" && (
|
{view === "month" && (
|
||||||
<span className="h-1.5 w-1.5 rounded-full bg-(--color-primary)"></span>
|
<span className="h-1.5 w-1.5 rounded-full bg-(--color-primary)"></span>
|
||||||
)}
|
)}
|
||||||
@@ -132,7 +132,7 @@ export default function StaffSchedulePage() {
|
|||||||
{/* Navigation */}
|
{/* Navigation */}
|
||||||
<div className="mt-2 pt-2">
|
<div className="mt-2 pt-2">
|
||||||
<p className="mb-1 px-3 text-[10px] font-bold tracking-widest text-(--color-text-muted) uppercase">
|
<p className="mb-1 px-3 text-[10px] font-bold tracking-widest text-(--color-text-muted) uppercase">
|
||||||
Điều hướng
|
Navigation
|
||||||
</p>
|
</p>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@@ -140,7 +140,7 @@ export default function StaffSchedulePage() {
|
|||||||
className="flex w-full cursor-pointer items-center gap-3 rounded-xl border-none bg-transparent px-3 py-2.5 text-sm font-medium text-(--color-text-secondary) transition-all hover:bg-gray-50 hover:text-(--color-primary-dark)"
|
className="flex w-full cursor-pointer items-center gap-3 rounded-xl border-none bg-transparent px-3 py-2.5 text-sm font-medium text-(--color-text-secondary) transition-all hover:bg-gray-50 hover:text-(--color-primary-dark)"
|
||||||
>
|
>
|
||||||
<i className="fa-solid fa-crosshairs w-4 text-center"></i>
|
<i className="fa-solid fa-crosshairs w-4 text-center"></i>
|
||||||
<span className="flex-1 text-left">Hôm nay</span>
|
<span className="flex-1 text-left">Today</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -148,7 +148,7 @@ export default function StaffSchedulePage() {
|
|||||||
{isManager && (
|
{isManager && (
|
||||||
<div className="mt-2 pt-2">
|
<div className="mt-2 pt-2">
|
||||||
<p className="mb-1 px-3 text-[10px] font-bold tracking-widest text-(--color-text-muted) uppercase">
|
<p className="mb-1 px-3 text-[10px] font-bold tracking-widest text-(--color-text-muted) uppercase">
|
||||||
Quản lý
|
Manager
|
||||||
</p>
|
</p>
|
||||||
<Link
|
<Link
|
||||||
href="/manager"
|
href="/manager"
|
||||||
@@ -165,7 +165,7 @@ export default function StaffSchedulePage() {
|
|||||||
className="mt-1 flex w-full cursor-pointer items-center gap-3 rounded-xl border-none bg-(--color-primary)/10 px-3 py-2.5 text-sm font-semibold text-(--color-primary) transition-all hover:bg-(--color-primary)/20"
|
className="mt-1 flex w-full cursor-pointer items-center gap-3 rounded-xl border-none bg-(--color-primary)/10 px-3 py-2.5 text-sm font-semibold text-(--color-primary) transition-all hover:bg-(--color-primary)/20"
|
||||||
>
|
>
|
||||||
<i className="fa-solid fa-plus w-4 text-center"></i>
|
<i className="fa-solid fa-plus w-4 text-center"></i>
|
||||||
<span className="flex-1 text-left">Tạo ca mới</span>
|
<span className="flex-1 text-left">Create shift</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -175,7 +175,7 @@ export default function StaffSchedulePage() {
|
|||||||
{isManager && (
|
{isManager && (
|
||||||
<div className="rounded-xl bg-gradient-to-br from-(--color-primary)/10 to-(--color-primary)/5 p-3">
|
<div className="rounded-xl bg-gradient-to-br from-(--color-primary)/10 to-(--color-primary)/5 p-3">
|
||||||
<p className="text-[10px] font-bold tracking-wider text-(--color-text-muted) uppercase">
|
<p className="text-[10px] font-bold tracking-wider text-(--color-text-muted) uppercase">
|
||||||
Ngân sách tuần
|
Weekly budget
|
||||||
</p>
|
</p>
|
||||||
<p className="mt-1 text-xl font-bold text-(--color-primary)">
|
<p className="mt-1 text-xl font-bold text-(--color-primary)">
|
||||||
{weeklyBudget >= 1_000_000
|
{weeklyBudget >= 1_000_000
|
||||||
@@ -187,12 +187,12 @@ export default function StaffSchedulePage() {
|
|||||||
)}
|
)}
|
||||||
<div className="rounded-xl bg-gray-50 p-3">
|
<div className="rounded-xl bg-gray-50 p-3">
|
||||||
<p className="text-[10px] font-bold tracking-wider text-(--color-text-muted) uppercase">
|
<p className="text-[10px] font-bold tracking-wider text-(--color-text-muted) uppercase">
|
||||||
Ca tuần này
|
Shifts this week
|
||||||
</p>
|
</p>
|
||||||
<p className="mt-1 text-xl font-bold text-(--color-text-secondary)">
|
<p className="mt-1 text-xl font-bold text-(--color-text-secondary)">
|
||||||
{totalShiftsThisWeek}
|
{totalShiftsThisWeek}
|
||||||
</p>
|
</p>
|
||||||
<p className="text-[10px] text-(--color-text-muted)">ca làm</p>
|
<p className="text-[10px] text-(--color-text-muted)">shifts</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
@@ -242,12 +242,12 @@ export default function StaffSchedulePage() {
|
|||||||
{/* Title */}
|
{/* Title */}
|
||||||
<div>
|
<div>
|
||||||
<h1 className="text-foreground text-base font-bold md:text-lg">
|
<h1 className="text-foreground text-base font-bold md:text-lg">
|
||||||
{isManager ? "Quản lý ca làm" : "Đăng ký ca làm"}
|
{isManager ? "Manage Shifts" : "Register Shifts"}
|
||||||
</h1>
|
</h1>
|
||||||
<p className="text-xs text-(--color-text-muted)">
|
<p className="text-xs text-(--color-text-muted)">
|
||||||
{view === "week"
|
{view === "week"
|
||||||
? `Tuần: ${weekLabel}`
|
? `Week: ${weekLabel}`
|
||||||
: `Tháng: ${MONTH_NAMES[currentDate.getMonth()]} ${currentDate.getFullYear()}`}
|
: `Month: ${MONTH_NAMES[currentDate.getMonth()]} ${currentDate.getFullYear()}`}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -263,7 +263,7 @@ export default function StaffSchedulePage() {
|
|||||||
: "bg-transparent text-(--color-text-secondary)"
|
: "bg-transparent text-(--color-text-secondary)"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
Tuần
|
Week
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@@ -274,7 +274,7 @@ export default function StaffSchedulePage() {
|
|||||||
: "bg-transparent text-(--color-text-secondary)"
|
: "bg-transparent text-(--color-text-secondary)"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
Tháng
|
Month
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -293,7 +293,7 @@ export default function StaffSchedulePage() {
|
|||||||
onClick={goToToday}
|
onClick={goToToday}
|
||||||
className="cursor-pointer rounded-lg border border-(--color-border-light) bg-white px-3 py-1.5 text-xs font-semibold text-(--color-text-secondary) transition hover:border-(--color-primary)/30 hover:bg-(--color-primary)/5 hover:text-(--color-primary)"
|
className="cursor-pointer rounded-lg border border-(--color-border-light) bg-white px-3 py-1.5 text-xs font-semibold text-(--color-text-secondary) transition hover:border-(--color-primary)/30 hover:bg-(--color-primary)/5 hover:text-(--color-primary)"
|
||||||
>
|
>
|
||||||
Hôm nay
|
Today
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
title="Next"
|
title="Next"
|
||||||
@@ -313,7 +313,7 @@ export default function StaffSchedulePage() {
|
|||||||
className="hidden cursor-pointer items-center gap-2 rounded-xl border-none bg-(--color-primary) px-4 py-2 text-xs font-bold text-white shadow-sm transition hover:opacity-90 md:flex"
|
className="hidden cursor-pointer items-center gap-2 rounded-xl border-none bg-(--color-primary) px-4 py-2 text-xs font-bold text-white shadow-sm transition hover:opacity-90 md:flex"
|
||||||
>
|
>
|
||||||
<i className="fa-solid fa-plus"></i>
|
<i className="fa-solid fa-plus"></i>
|
||||||
Tạo ca mới
|
Create shift
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -373,7 +373,7 @@ export default function StaffSchedulePage() {
|
|||||||
{/* FAB for mobile manager */}
|
{/* FAB for mobile manager */}
|
||||||
{isManager && (
|
{isManager && (
|
||||||
<button
|
<button
|
||||||
title="Tạo ca mới"
|
title="Create shift"
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => { setCreateDate(undefined); setCreateOpen(true); }}
|
onClick={() => { setCreateDate(undefined); setCreateOpen(true); }}
|
||||||
className="fixed right-4 bottom-6 z-30 flex h-14 w-14 cursor-pointer items-center justify-center rounded-full border-none bg-(--color-primary) text-white shadow-xl transition hover:opacity-90 md:hidden"
|
className="fixed right-4 bottom-6 z-30 flex h-14 w-14 cursor-pointer items-center justify-center rounded-full border-none bg-(--color-primary) text-white shadow-xl transition hover:opacity-90 md:hidden"
|
||||||
|
|||||||
@@ -83,14 +83,14 @@ export default function ShiftCard({ shift, compact = false, onClick }: ShiftCard
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<span className={`shrink-0 rounded-full px-2.5 py-1 text-xs font-semibold ${s.badge}`}>
|
<span className={`shrink-0 rounded-full px-2.5 py-1 text-xs font-semibold ${s.badge}`}>
|
||||||
{registeredCount}/{shift.maxStaff} người
|
{registeredCount}/{shift.maxStaff} staff
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{registeredCount > 0 && (
|
{registeredCount > 0 && (
|
||||||
<div className="mt-3 border-t border-gray-100 pt-3">
|
<div className="mt-3 border-t border-gray-100 pt-3">
|
||||||
<p className="mb-2 text-[10px] font-semibold tracking-wider text-(--color-text-muted) uppercase">
|
<p className="mb-2 text-[10px] font-semibold tracking-wider text-(--color-text-muted) uppercase">
|
||||||
Nhân viên đăng ký
|
Registered staff
|
||||||
</p>
|
</p>
|
||||||
<div className="flex flex-wrap gap-1.5">
|
<div className="flex flex-wrap gap-1.5">
|
||||||
{shift.registeredStaff!.map((staff) => (
|
{shift.registeredStaff!.map((staff) => (
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ export default function SearchBar({
|
|||||||
value,
|
value,
|
||||||
onChange,
|
onChange,
|
||||||
onClear,
|
onClear,
|
||||||
placeholder = "Tìm kiếm...",
|
placeholder = "Search...",
|
||||||
className = "",
|
className = "",
|
||||||
}: SearchBarProps) {
|
}: SearchBarProps) {
|
||||||
return (
|
return (
|
||||||
@@ -17,14 +17,14 @@ export default function SearchBar({
|
|||||||
value={value}
|
value={value}
|
||||||
onChange={(e) => onChange(e.target.value)}
|
onChange={(e) => onChange(e.target.value)}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
aria-label="Tìm kiếm món ăn"
|
aria-label="Search items"
|
||||||
className="bg-card text-foreground border-border placeholder:text-muted-foreground focus:border-primary focus:ring-primary focus:ring-opacity-20 w-full rounded-xl border py-2 pr-9 pl-9 text-sm transition-all duration-150 outline-none focus:ring-2"
|
className="bg-card text-foreground border-border placeholder:text-muted-foreground focus:border-primary focus:ring-primary focus:ring-opacity-20 w-full rounded-xl border py-2 pr-9 pl-9 text-sm transition-all duration-150 outline-none focus:ring-2"
|
||||||
/>
|
/>
|
||||||
{value && (
|
{value && (
|
||||||
<button
|
<button
|
||||||
onClick={onClear}
|
onClick={onClear}
|
||||||
title="Xóa tìm kiếm"
|
title="Clear search"
|
||||||
aria-label="Xóa tìm kiếm"
|
aria-label="Clear search"
|
||||||
className="absolute top-1/2 right-3 -translate-y-1/2 cursor-pointer border-none bg-transparent p-0 text-(--color-text-muted) transition-colors duration-150 hover:text-(--color-primary)"
|
className="absolute top-1/2 right-3 -translate-y-1/2 cursor-pointer border-none bg-transparent p-0 text-(--color-text-muted) transition-colors duration-150 hover:text-(--color-primary)"
|
||||||
>
|
>
|
||||||
<i className="fa-solid fa-xmark text-sm"></i>
|
<i className="fa-solid fa-xmark text-sm"></i>
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ export default function DeleteConfirm({
|
|||||||
<div className="flex h-12 w-12 items-center justify-center rounded-full bg-red-100">
|
<div className="flex h-12 w-12 items-center justify-center rounded-full bg-red-100">
|
||||||
<i className="fa-solid fa-trash-can text-xl text-red-500"></i>
|
<i className="fa-solid fa-trash-can text-xl text-red-500"></i>
|
||||||
</div>
|
</div>
|
||||||
<h3 className="text-foreground text-base font-bold">Xóa "{name}"?</h3>
|
<h3 className="text-foreground text-base font-bold">Delete "{name}"?</h3>
|
||||||
<p className="text-sm text-(--color-text-muted)">
|
<p className="text-sm text-(--color-text-muted)">
|
||||||
Hành động này không thể hoàn tác.
|
This action cannot be undone.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex gap-3">
|
<div className="flex gap-3">
|
||||||
@@ -27,13 +27,13 @@ export default function DeleteConfirm({
|
|||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
className="flex-1 cursor-pointer rounded-xl border border-(--color-border) bg-white px-4 py-2.5 text-sm font-medium text-(--color-text-secondary) transition hover:bg-(--color-border-light)"
|
className="flex-1 cursor-pointer rounded-xl border border-(--color-border) bg-white px-4 py-2.5 text-sm font-medium text-(--color-text-secondary) transition hover:bg-(--color-border-light)"
|
||||||
>
|
>
|
||||||
Hủy
|
Cancel
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={onConfirm}
|
onClick={onConfirm}
|
||||||
className="flex-1 cursor-pointer rounded-xl border-none bg-red-500 px-4 py-2.5 text-sm font-semibold text-white transition hover:bg-red-600 active:scale-95"
|
className="flex-1 cursor-pointer rounded-xl border-none bg-red-500 px-4 py-2.5 text-sm font-semibold text-white transition hover:bg-red-600 active:scale-95"
|
||||||
>
|
>
|
||||||
Xóa
|
Delete
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ export default function ProductModal({
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
throw new Error("Upload ảnh thất bại.");
|
throw new Error("Image upload failed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
const raw = await res.text();
|
const raw = await res.text();
|
||||||
@@ -54,12 +54,12 @@ export default function ProductModal({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!filename) {
|
if (!filename) {
|
||||||
throw new Error("Không nhận được filename ảnh từ server.");
|
throw new Error("No image filename received from server.");
|
||||||
}
|
}
|
||||||
|
|
||||||
setForm((prev) => ({ ...prev, imageUrl: filename }));
|
setForm((prev) => ({ ...prev, imageUrl: filename }));
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
setUploadError(error?.message || "Không thể upload ảnh.");
|
setUploadError(error?.message || "Unable to upload image.");
|
||||||
} finally {
|
} finally {
|
||||||
setUploading(false);
|
setUploading(false);
|
||||||
}
|
}
|
||||||
@@ -93,11 +93,11 @@ export default function ProductModal({
|
|||||||
<div className="w-full max-w-lg rounded-2xl bg-white shadow-2xl">
|
<div className="w-full max-w-lg rounded-2xl bg-white shadow-2xl">
|
||||||
<div className="flex items-center justify-between border-b border-(--color-border-light) px-6 py-4">
|
<div className="flex items-center justify-between border-b border-(--color-border-light) px-6 py-4">
|
||||||
<h2 className="text-foreground text-lg font-bold">
|
<h2 className="text-foreground text-lg font-bold">
|
||||||
{isEdit ? "Chỉnh sửa món" : "Thêm món mới"}
|
{isEdit ? "Edit item" : "Add new item"}
|
||||||
</h2>
|
</h2>
|
||||||
<button
|
<button
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
title="Đóng"
|
title="Close"
|
||||||
className="flex h-8 w-8 cursor-pointer items-center justify-center rounded-full border-none bg-transparent text-(--color-text-muted) transition-colors hover:bg-(--color-border-light) hover:text-(--color-primary)"
|
className="flex h-8 w-8 cursor-pointer items-center justify-center rounded-full border-none bg-transparent text-(--color-text-muted) transition-colors hover:bg-(--color-border-light) hover:text-(--color-primary)"
|
||||||
>
|
>
|
||||||
<i className="fa-solid fa-xmark"></i>
|
<i className="fa-solid fa-xmark"></i>
|
||||||
@@ -107,7 +107,7 @@ export default function ProductModal({
|
|||||||
<form onSubmit={handleSubmit} className="space-y-4 px-6 py-5">
|
<form onSubmit={handleSubmit} className="space-y-4 px-6 py-5">
|
||||||
<div>
|
<div>
|
||||||
<label className="mb-1 block text-sm font-medium text-(--color-text-secondary)">
|
<label className="mb-1 block text-sm font-medium text-(--color-text-secondary)">
|
||||||
Tên món <span className="text-red-500">*</span>
|
Item name <span className="text-red-500">*</span>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
required
|
required
|
||||||
@@ -115,13 +115,13 @@ export default function ProductModal({
|
|||||||
value={form.name}
|
value={form.name}
|
||||||
onChange={(e) => setForm({ ...form, name: e.target.value })}
|
onChange={(e) => setForm({ ...form, name: e.target.value })}
|
||||||
className={inputCls}
|
className={inputCls}
|
||||||
placeholder="Ví dụ: Cà Phê Đen"
|
placeholder="e.g. Black Coffee"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label className="mb-1 block text-sm font-medium text-(--color-text-secondary)">
|
<label className="mb-1 block text-sm font-medium text-(--color-text-secondary)">
|
||||||
Giá (đ) <span className="text-red-500">*</span>
|
Price (₫) <span className="text-red-500">*</span>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
required
|
required
|
||||||
@@ -139,7 +139,7 @@ export default function ProductModal({
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label className="mb-1 block text-sm font-medium text-(--color-text-secondary)">
|
<label className="mb-1 block text-sm font-medium text-(--color-text-secondary)">
|
||||||
Ảnh món
|
Item image
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
@@ -154,7 +154,7 @@ export default function ProductModal({
|
|||||||
{uploading && (
|
{uploading && (
|
||||||
<p className="text-sm text-(--color-text-muted)">
|
<p className="text-sm text-(--color-text-muted)">
|
||||||
<i className="fa-solid fa-spinner mr-1 animate-spin"></i>
|
<i className="fa-solid fa-spinner mr-1 animate-spin"></i>
|
||||||
Đang upload ảnh...
|
Uploading image...
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -163,7 +163,7 @@ export default function ProductModal({
|
|||||||
<div className="mt-2">
|
<div className="mt-2">
|
||||||
<img
|
<img
|
||||||
src={previewUrl}
|
src={previewUrl}
|
||||||
alt="Preview ảnh món"
|
alt="Item image preview"
|
||||||
className="h-24 w-24 rounded-lg border border-(--color-border-light) object-cover"
|
className="h-24 w-24 rounded-lg border border-(--color-border-light) object-cover"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -179,7 +179,7 @@ export default function ProductModal({
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label className="mb-1 block text-sm font-medium text-(--color-text-secondary)">
|
<label className="mb-1 block text-sm font-medium text-(--color-text-secondary)">
|
||||||
Mô tả
|
Description
|
||||||
</label>
|
</label>
|
||||||
<textarea
|
<textarea
|
||||||
rows={3}
|
rows={3}
|
||||||
@@ -188,19 +188,19 @@ export default function ProductModal({
|
|||||||
setForm({ ...form, description: e.target.value })
|
setForm({ ...form, description: e.target.value })
|
||||||
}
|
}
|
||||||
className={`${inputCls} resize-none`}
|
className={`${inputCls} resize-none`}
|
||||||
placeholder="Mô tả ngắn về món..."
|
placeholder="Short description..."
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="bg-background flex items-center justify-between rounded-xl border border-(--color-border-light) px-4 py-3">
|
<div className="bg-background flex items-center justify-between rounded-xl border border-(--color-border-light) px-4 py-3">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-foreground text-sm font-medium">Trạng thái</p>
|
<p className="text-foreground text-sm font-medium">Status</p>
|
||||||
<p className="text-xs text-(--color-text-muted)">
|
<p className="text-xs text-(--color-text-muted)">
|
||||||
{form.available ? "Còn hàng" : "Tạm hết"}
|
{form.available ? "In stock" : "Out of stock"}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
title="Chuyển trạng thái"
|
title="Toggle status"
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setForm({ ...form, available: !form.available })}
|
onClick={() => setForm({ ...form, available: !form.available })}
|
||||||
className={`relative h-6 w-11 cursor-pointer rounded-full border-none transition-colors duration-200 ${
|
className={`relative h-6 w-11 cursor-pointer rounded-full border-none transition-colors duration-200 ${
|
||||||
@@ -221,14 +221,14 @@ export default function ProductModal({
|
|||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
className="flex-1 cursor-pointer rounded-xl border border-(--color-border) bg-white px-4 py-2.5 text-sm font-medium text-(--color-text-secondary) transition hover:bg-(--color-border-light)"
|
className="flex-1 cursor-pointer rounded-xl border border-(--color-border) bg-white px-4 py-2.5 text-sm font-medium text-(--color-text-secondary) transition hover:bg-(--color-border-light)"
|
||||||
>
|
>
|
||||||
Hủy
|
Cancel
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={uploading}
|
disabled={uploading}
|
||||||
className="flex-1 cursor-pointer rounded-xl border-none bg-(--color-primary) px-4 py-2.5 text-sm font-semibold text-white transition hover:bg-(--color-primary-dark) active:scale-95 disabled:opacity-60"
|
className="flex-1 cursor-pointer rounded-xl border-none bg-(--color-primary) px-4 py-2.5 text-sm font-semibold text-white transition hover:bg-(--color-primary-dark) active:scale-95 disabled:opacity-60"
|
||||||
>
|
>
|
||||||
{isEdit ? "Lưu thay đổi" : "Thêm món"}
|
{isEdit ? "Save changes" : "Add item"}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -59,12 +59,12 @@ export default function ProductsTab() {
|
|||||||
type="text"
|
type="text"
|
||||||
value={search}
|
value={search}
|
||||||
onChange={(e) => setSearch(e.target.value)}
|
onChange={(e) => setSearch(e.target.value)}
|
||||||
placeholder="Tìm kiếm món..."
|
placeholder="Search items..."
|
||||||
className="text-foreground w-full rounded-xl border border-(--color-border) bg-white py-2 pr-9 pl-9 text-sm transition outline-none focus:border-(--color-primary) focus:ring-2 focus:ring-(--color-primary)/20"
|
className="text-foreground w-full rounded-xl border border-(--color-border) bg-white py-2 pr-9 pl-9 text-sm transition outline-none focus:border-(--color-primary) focus:ring-2 focus:ring-(--color-primary)/20"
|
||||||
/>
|
/>
|
||||||
{search && (
|
{search && (
|
||||||
<button
|
<button
|
||||||
title="Xóa tìm kiếm"
|
title="Clear search"
|
||||||
onClick={() => setSearch("")}
|
onClick={() => setSearch("")}
|
||||||
className="absolute top-1/2 right-3 -translate-y-1/2 cursor-pointer border-none bg-transparent text-(--color-text-muted) hover:text-(--color-primary)"
|
className="absolute top-1/2 right-3 -translate-y-1/2 cursor-pointer border-none bg-transparent text-(--color-text-muted) hover:text-(--color-primary)"
|
||||||
>
|
>
|
||||||
@@ -81,26 +81,26 @@ export default function ProductsTab() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
className="text-foreground cursor-pointer rounded-xl border border-(--color-border) bg-white px-3 py-2 text-sm transition outline-none focus:border-(--color-primary)"
|
className="text-foreground cursor-pointer rounded-xl border border-(--color-border) bg-white px-3 py-2 text-sm transition outline-none focus:border-(--color-primary)"
|
||||||
title="Lọc theo trạng thái"
|
title="Filter by status"
|
||||||
>
|
>
|
||||||
<option value="all">Tất cả trạng thái</option>
|
<option value="all">All statuses</option>
|
||||||
<option value="available">Còn hàng</option>
|
<option value="available">In stock</option>
|
||||||
<option value="unavailable">Tạm hết</option>
|
<option value="unavailable">Out of stock</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
title="Thêm món"
|
title="Add item"
|
||||||
onClick={() => setModalProduct("new")}
|
onClick={() => setModalProduct("new")}
|
||||||
className="flex cursor-pointer items-center gap-2 rounded-xl border-none bg-(--color-primary) px-4 py-2 text-sm font-semibold text-white transition hover:bg-(--color-primary-dark) active:scale-95"
|
className="flex cursor-pointer items-center gap-2 rounded-xl border-none bg-(--color-primary) px-4 py-2 text-sm font-semibold text-white transition hover:bg-(--color-primary-dark) active:scale-95"
|
||||||
>
|
>
|
||||||
<i className="fa-solid fa-plus"></i>
|
<i className="fa-solid fa-plus"></i>
|
||||||
<span className="hidden sm:inline">Thêm món</span>
|
<span className="hidden sm:inline">Add item</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p className="text-sm text-(--color-text-muted)">
|
<p className="text-sm text-(--color-text-muted)">
|
||||||
Hiển thị <strong className="text-foreground">{filtered.length}</strong>{" "}
|
Showing <strong className="text-foreground">{filtered.length}</strong>{" "}
|
||||||
/ {products.length} món
|
/ {products.length} items
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{/* Table */}
|
{/* Table */}
|
||||||
@@ -109,19 +109,19 @@ export default function ProductsTab() {
|
|||||||
<thead className="bg-background">
|
<thead className="bg-background">
|
||||||
<tr>
|
<tr>
|
||||||
<th className="px-4 py-3 text-left font-semibold text-(--color-text-secondary)">
|
<th className="px-4 py-3 text-left font-semibold text-(--color-text-secondary)">
|
||||||
Ảnh
|
Image
|
||||||
</th>
|
</th>
|
||||||
<th className="px-4 py-3 text-left font-semibold text-(--color-text-secondary)">
|
<th className="px-4 py-3 text-left font-semibold text-(--color-text-secondary)">
|
||||||
Tên món
|
Item name
|
||||||
</th>
|
</th>
|
||||||
<th className="px-4 py-3 text-right font-semibold text-(--color-text-secondary)">
|
<th className="px-4 py-3 text-right font-semibold text-(--color-text-secondary)">
|
||||||
Giá
|
Price
|
||||||
</th>
|
</th>
|
||||||
<th className="px-4 py-3 text-center font-semibold text-(--color-text-secondary)">
|
<th className="px-4 py-3 text-center font-semibold text-(--color-text-secondary)">
|
||||||
Trạng thái
|
Status
|
||||||
</th>
|
</th>
|
||||||
<th className="px-4 py-3 text-center font-semibold text-(--color-text-secondary)">
|
<th className="px-4 py-3 text-center font-semibold text-(--color-text-secondary)">
|
||||||
Thao tác
|
Actions
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@@ -133,7 +133,7 @@ export default function ProductsTab() {
|
|||||||
className="py-12 text-center text-(--color-text-muted)"
|
className="py-12 text-center text-(--color-text-muted)"
|
||||||
>
|
>
|
||||||
<i className="fa-solid fa-mug-hot mb-2 block text-3xl opacity-30"></i>
|
<i className="fa-solid fa-mug-hot mb-2 block text-3xl opacity-30"></i>
|
||||||
<span className="ml-3">Không tìm thấy món nào</span>
|
<span className="ml-3">No items found</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
) : (
|
) : (
|
||||||
@@ -165,7 +165,7 @@ export default function ProductsTab() {
|
|||||||
<td className="px-4 py-3 text-center">
|
<td className="px-4 py-3 text-center">
|
||||||
<button
|
<button
|
||||||
onClick={() => toggleProductAvailability(p)}
|
onClick={() => toggleProductAvailability(p)}
|
||||||
title="Nhấn để đổi trạng thái"
|
title="Click to toggle status"
|
||||||
className="cursor-pointer border-none bg-transparent"
|
className="cursor-pointer border-none bg-transparent"
|
||||||
>
|
>
|
||||||
<StatusBadge available={p.available ?? true} />
|
<StatusBadge available={p.available ?? true} />
|
||||||
@@ -175,14 +175,14 @@ export default function ProductsTab() {
|
|||||||
<div className="flex items-center justify-center gap-1.5">
|
<div className="flex items-center justify-center gap-1.5">
|
||||||
<button
|
<button
|
||||||
onClick={() => setModalProduct(p)}
|
onClick={() => setModalProduct(p)}
|
||||||
title="Chỉnh sửa"
|
title="Edit"
|
||||||
className="flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg border border-(--color-border-light) bg-transparent text-(--color-text-muted) transition hover:border-(--color-primary-light) hover:text-(--color-primary)"
|
className="flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg border border-(--color-border-light) bg-transparent text-(--color-text-muted) transition hover:border-(--color-primary-light) hover:text-(--color-primary)"
|
||||||
>
|
>
|
||||||
<i className="fa-solid fa-pen text-xs"></i>
|
<i className="fa-solid fa-pen text-xs"></i>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => setDeleteTarget(p)}
|
onClick={() => setDeleteTarget(p)}
|
||||||
title="Xóa"
|
title="Delete"
|
||||||
className="flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg border border-transparent bg-transparent text-(--color-text-muted) transition hover:border-red-200 hover:bg-red-50 hover:text-red-500"
|
className="flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg border border-transparent bg-transparent text-(--color-text-muted) transition hover:border-red-200 hover:bg-red-50 hover:text-red-500"
|
||||||
>
|
>
|
||||||
<i className="fa-solid fa-trash text-xs"></i>
|
<i className="fa-solid fa-trash text-xs"></i>
|
||||||
|
|||||||
@@ -37,14 +37,14 @@ export default function CategorySidebar({
|
|||||||
className={`text-xs font-bold tracking-widest whitespace-nowrap text-(--color-text-muted) uppercase ${isOpen ? "block" : "hidden"} xl:block`}
|
className={`text-xs font-bold tracking-widest whitespace-nowrap text-(--color-text-muted) uppercase ${isOpen ? "block" : "hidden"} xl:block`}
|
||||||
>
|
>
|
||||||
<i className="fa-solid fa-utensils mr-2 text-(--color-primary)"></i>
|
<i className="fa-solid fa-utensils mr-2 text-(--color-primary)"></i>
|
||||||
Thực Đơn
|
Menu
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
{/* Toggle button — hidden on xl+ (sidebar is always expanded there) */}
|
{/* Toggle button — hidden on xl+ (sidebar is always expanded there) */}
|
||||||
<button
|
<button
|
||||||
onClick={onToggle}
|
onClick={onToggle}
|
||||||
title={isOpen ? "Thu gọn menu" : "Mở rộng menu"}
|
title={isOpen ? "Collapse menu" : "Expand menu"}
|
||||||
aria-label={isOpen ? "Thu gọn menu" : "Mở rộng menu"}
|
aria-label={isOpen ? "Collapse menu" : "Expand menu"}
|
||||||
className="flex h-8 w-8 shrink-0 cursor-pointer items-center justify-center rounded-lg border-none bg-transparent text-(--color-text-muted) transition-colors duration-150 hover:bg-(--color-border-light) hover:text-(--color-primary) xl:hidden"
|
className="flex h-8 w-8 shrink-0 cursor-pointer items-center justify-center rounded-lg border-none bg-transparent text-(--color-text-muted) transition-colors duration-150 hover:bg-(--color-border-light) hover:text-(--color-primary) xl:hidden"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
|
|||||||
@@ -144,15 +144,15 @@ export default function MobileShiftView({ onShiftClick }: MobileShiftViewProps)
|
|||||||
? "bg-(--color-primary)/10 text-(--color-primary)"
|
? "bg-(--color-primary)/10 text-(--color-primary)"
|
||||||
: "bg-gray-100 text-(--color-text-muted)"
|
: "bg-gray-100 text-(--color-text-muted)"
|
||||||
}`}>
|
}`}>
|
||||||
{selectedShifts.length} ca làm
|
{selectedShifts.length} shifts
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{selectedShifts.length === 0 ? (
|
{selectedShifts.length === 0 ? (
|
||||||
<div className="rounded-2xl border border-dashed border-(--color-border-light) py-10 text-center">
|
<div className="rounded-2xl border border-dashed border-(--color-border-light) py-10 text-center">
|
||||||
<i className="fa-regular fa-calendar-xmark mb-3 text-3xl text-gray-200"></i>
|
<i className="fa-regular fa-calendar-xmark mb-3 text-3xl text-gray-200"></i>
|
||||||
<p className="text-sm font-medium text-(--color-text-muted)">Không có ca làm</p>
|
<p className="text-sm font-medium text-(--color-text-muted)">No shifts</p>
|
||||||
<p className="mt-0.5 text-xs text-(--color-text-muted)">Chưa có ca nào được tạo hôm này</p>
|
<p className="mt-0.5 text-xs text-(--color-text-muted)">No shifts created for this day</p>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="space-y-2.5">
|
<div className="space-y-2.5">
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ export default function MonthlyCalendar({ onShiftClick, onDateSelect }: MonthlyC
|
|||||||
<div className="mt-1.5 space-y-1">
|
<div className="mt-1.5 space-y-1">
|
||||||
<span className="inline-flex items-center gap-1 rounded-full bg-(--color-primary)/10 px-1.5 py-0.5 text-[10px] font-semibold text-(--color-primary)">
|
<span className="inline-flex items-center gap-1 rounded-full bg-(--color-primary)/10 px-1.5 py-0.5 text-[10px] font-semibold text-(--color-primary)">
|
||||||
<i className="fa-solid fa-clock text-[8px]"></i>
|
<i className="fa-solid fa-clock text-[8px]"></i>
|
||||||
{shiftCount} ca
|
{shiftCount} shifts
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -110,7 +110,7 @@ export default function MonthlyCalendar({ onShiftClick, onDateSelect }: MonthlyC
|
|||||||
{/* Add indicator for manager */}
|
{/* Add indicator for manager */}
|
||||||
{shiftCount === 0 && onDateSelect && (
|
{shiftCount === 0 && onDateSelect && (
|
||||||
<p className="mt-1 text-[10px] text-(--color-text-muted) opacity-0 transition group-hover:opacity-100">
|
<p className="mt-1 text-[10px] text-(--color-text-muted) opacity-0 transition group-hover:opacity-100">
|
||||||
+ Thêm ca
|
+ Add shift
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ export default function ShiftCreateModal({
|
|||||||
{/* Department */}
|
{/* Department */}
|
||||||
<div>
|
<div>
|
||||||
<label className="mb-1 block text-xs font-semibold text-(--color-text-secondary)">
|
<label className="mb-1 block text-xs font-semibold text-(--color-text-secondary)">
|
||||||
Bộ phận
|
Department
|
||||||
</label>
|
</label>
|
||||||
<select
|
<select
|
||||||
title="Department"
|
title="Department"
|
||||||
@@ -205,7 +205,7 @@ export default function ShiftCreateModal({
|
|||||||
<div className="grid grid-cols-2 gap-3">
|
<div className="grid grid-cols-2 gap-3">
|
||||||
<div>
|
<div>
|
||||||
<label className="mb-1 block text-xs font-semibold text-(--color-text-secondary)">
|
<label className="mb-1 block text-xs font-semibold text-(--color-text-secondary)">
|
||||||
Số nhân viên tối đa
|
Max staff
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
title="Max Staff"
|
title="Max Staff"
|
||||||
@@ -219,7 +219,7 @@ export default function ShiftCreateModal({
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="mb-1 block text-xs font-semibold text-(--color-text-secondary)">
|
<label className="mb-1 block text-xs font-semibold text-(--color-text-secondary)">
|
||||||
Lương ca (VND)
|
Shift wage (VND)
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
title="Wage"
|
title="Wage"
|
||||||
@@ -248,14 +248,14 @@ export default function ShiftCreateModal({
|
|||||||
className="flex-1 cursor-pointer rounded-xl border-none bg-(--color-primary) px-4 py-2.5 text-sm font-semibold text-white transition hover:opacity-90"
|
className="flex-1 cursor-pointer rounded-xl border-none bg-(--color-primary) px-4 py-2.5 text-sm font-semibold text-white transition hover:opacity-90"
|
||||||
>
|
>
|
||||||
<i className="fa-solid fa-plus mr-2"></i>
|
<i className="fa-solid fa-plus mr-2"></i>
|
||||||
Tạo ca làm
|
Create shift
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
className="cursor-pointer rounded-xl border border-(--color-border-light) bg-transparent px-4 py-2.5 text-sm font-medium text-(--color-text-secondary) transition hover:bg-gray-50"
|
className="cursor-pointer rounded-xl border border-(--color-border-light) bg-transparent px-4 py-2.5 text-sm font-medium text-(--color-text-secondary) transition hover:bg-gray-50"
|
||||||
>
|
>
|
||||||
Hủy
|
Cancel
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -41,10 +41,10 @@ export default function ShiftDetailModal({
|
|||||||
setSuccess(null);
|
setSuccess(null);
|
||||||
const result = await registerShift(shift.id, user.id, user.name);
|
const result = await registerShift(shift.id, user.id, user.name);
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
setSuccess("Đăng ký ca thành công!");
|
setSuccess("Shift registered successfully!");
|
||||||
setTimeout(onClose, 1200);
|
setTimeout(onClose, 1200);
|
||||||
} else {
|
} else {
|
||||||
setError(result.error ?? "Có lỗi xảy ra.");
|
setError(result.error ?? "An error occurred.");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -52,13 +52,13 @@ export default function ShiftDetailModal({
|
|||||||
if (!user) return;
|
if (!user) return;
|
||||||
setError(null);
|
setError(null);
|
||||||
unregisterShift(shift.id, user.id);
|
unregisterShift(shift.id, user.id);
|
||||||
setSuccess("Đã hủy đăng ký ca.");
|
setSuccess("Shift registration cancelled.");
|
||||||
setTimeout(onClose, 1200);
|
setTimeout(onClose, 1200);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleManagerUnregister = (staffId: string) => {
|
const handleManagerUnregister = (staffId: string) => {
|
||||||
unregisterShift(shift.id, staffId);
|
unregisterShift(shift.id, staffId);
|
||||||
setSuccess("Đã xóa nhân viên khỏi ca.");
|
setSuccess("Staff removed from shift.");
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDelete = async () => {
|
const handleDelete = async () => {
|
||||||
@@ -67,10 +67,10 @@ export default function ShiftDetailModal({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const statusLabel = {
|
const statusLabel = {
|
||||||
available: "Còn trống",
|
available: "Available",
|
||||||
registered: "Đã đăng ký",
|
registered: "Registered",
|
||||||
approved_leave: "Nghỉ phép",
|
approved_leave: "On leave",
|
||||||
absent: "Vắng mặt",
|
absent: "Absent",
|
||||||
};
|
};
|
||||||
|
|
||||||
const statusColor = {
|
const statusColor = {
|
||||||
@@ -93,7 +93,7 @@ export default function ShiftDetailModal({
|
|||||||
{/* {dept && <i className={`${dept.icon} text-(--color-primary)`}></i>} */}
|
{/* {dept && <i className={`${dept.icon} text-(--color-primary)`}></i>} */}
|
||||||
<div>
|
<div>
|
||||||
<h2 className="text-foreground text-base font-bold">
|
<h2 className="text-foreground text-base font-bold">
|
||||||
Chi tiết ca làm
|
Shift Details
|
||||||
</h2>
|
</h2>
|
||||||
{/* <p className="text-xs text-(--color-text-muted)">{dept?.name}</p> */}
|
{/* <p className="text-xs text-(--color-text-muted)">{dept?.name}</p> */}
|
||||||
</div>
|
</div>
|
||||||
@@ -123,7 +123,7 @@ export default function ShiftDetailModal({
|
|||||||
<div className="grid grid-cols-2 gap-3">
|
<div className="grid grid-cols-2 gap-3">
|
||||||
<div className="rounded-xl bg-gray-50 p-3">
|
<div className="rounded-xl bg-gray-50 p-3">
|
||||||
<p className="text-[10px] font-semibold text-(--color-text-muted) uppercase">
|
<p className="text-[10px] font-semibold text-(--color-text-muted) uppercase">
|
||||||
Ngày
|
Date
|
||||||
</p>
|
</p>
|
||||||
<p className="text-foreground mt-1 text-sm font-bold">
|
<p className="text-foreground mt-1 text-sm font-bold">
|
||||||
{parseShiftDate(shift.date as Date | string | undefined)?.toLocaleDateString(
|
{parseShiftDate(shift.date as Date | string | undefined)?.toLocaleDateString(
|
||||||
@@ -139,7 +139,7 @@ export default function ShiftDetailModal({
|
|||||||
</div>
|
</div>
|
||||||
<div className="rounded-xl bg-gray-50 p-3">
|
<div className="rounded-xl bg-gray-50 p-3">
|
||||||
<p className="text-[10px] font-semibold text-(--color-text-muted) uppercase">
|
<p className="text-[10px] font-semibold text-(--color-text-muted) uppercase">
|
||||||
Giờ làm
|
Working hours
|
||||||
</p>
|
</p>
|
||||||
<p className="text-foreground mt-1 text-sm font-bold">
|
<p className="text-foreground mt-1 text-sm font-bold">
|
||||||
{shift.startTime} – {shift.endTime}
|
{shift.startTime} – {shift.endTime}
|
||||||
@@ -147,13 +147,13 @@ export default function ShiftDetailModal({
|
|||||||
</div>
|
</div>
|
||||||
<div className="rounded-xl bg-gray-50 p-3">
|
<div className="rounded-xl bg-gray-50 p-3">
|
||||||
<p className="text-[10px] font-semibold text-(--color-text-muted) uppercase">
|
<p className="text-[10px] font-semibold text-(--color-text-muted) uppercase">
|
||||||
Thời lượng
|
Duration
|
||||||
</p>
|
</p>
|
||||||
<p className="text-foreground mt-1 text-sm font-bold">{""} giờ</p>
|
<p className="text-foreground mt-1 text-sm font-bold">{""} giờ</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="rounded-xl bg-gray-50 p-3">
|
<div className="rounded-xl bg-gray-50 p-3">
|
||||||
<p className="text-[10px] font-semibold text-(--color-text-muted) uppercase">
|
<p className="text-[10px] font-semibold text-(--color-text-muted) uppercase">
|
||||||
Lương ca
|
Shift wage
|
||||||
</p>
|
</p>
|
||||||
<p className="mt-1 text-sm font-bold text-(--color-primary)">
|
<p className="mt-1 text-sm font-bold text-(--color-primary)">
|
||||||
{(shift.wage ?? 0).toLocaleString("vi-VN")} VND
|
{(shift.wage ?? 0).toLocaleString("vi-VN")} VND
|
||||||
@@ -164,12 +164,12 @@ export default function ShiftDetailModal({
|
|||||||
{/* Registered staff */}
|
{/* Registered staff */}
|
||||||
<div>
|
<div>
|
||||||
<p className="mb-2 text-xs font-semibold text-(--color-text-secondary)">
|
<p className="mb-2 text-xs font-semibold text-(--color-text-secondary)">
|
||||||
Nhân viên đã đăng ký ({registeredStaff.length}/
|
Registered staff ({registeredStaff.length}/
|
||||||
{shift.maxStaff})
|
{shift.maxStaff})
|
||||||
</p>
|
</p>
|
||||||
{registeredStaff.length === 0 ? (
|
{registeredStaff.length === 0 ? (
|
||||||
<p className="text-xs text-(--color-text-muted) italic">
|
<p className="text-xs text-(--color-text-muted) italic">
|
||||||
Chưa có ai đăng ký
|
No staff registered yet
|
||||||
</p>
|
</p>
|
||||||
) : (
|
) : (
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
@@ -193,7 +193,7 @@ export default function ShiftDetailModal({
|
|||||||
className="cursor-pointer rounded-lg border-none bg-transparent px-2 py-1 text-xs text-red-500 transition hover:bg-red-50"
|
className="cursor-pointer rounded-lg border-none bg-transparent px-2 py-1 text-xs text-red-500 transition hover:bg-red-50"
|
||||||
>
|
>
|
||||||
<i className="fa-solid fa-user-minus mr-1"></i>
|
<i className="fa-solid fa-user-minus mr-1"></i>
|
||||||
Xóa
|
Remove
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -226,7 +226,7 @@ export default function ShiftDetailModal({
|
|||||||
className="flex-1 cursor-pointer rounded-xl border-none bg-(--color-primary) px-4 py-2.5 text-sm font-semibold text-white transition hover:opacity-90"
|
className="flex-1 cursor-pointer rounded-xl border-none bg-(--color-primary) px-4 py-2.5 text-sm font-semibold text-white transition hover:opacity-90"
|
||||||
>
|
>
|
||||||
<i className="fa-solid fa-calendar-plus mr-2"></i>
|
<i className="fa-solid fa-calendar-plus mr-2"></i>
|
||||||
Đăng ký ca
|
Register
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
{isRegistered && (
|
{isRegistered && (
|
||||||
@@ -236,7 +236,7 @@ export default function ShiftDetailModal({
|
|||||||
className="flex-1 cursor-pointer rounded-xl border border-red-200 bg-transparent px-4 py-2.5 text-sm font-semibold text-red-600 transition hover:bg-red-50"
|
className="flex-1 cursor-pointer rounded-xl border border-red-200 bg-transparent px-4 py-2.5 text-sm font-semibold text-red-600 transition hover:bg-red-50"
|
||||||
>
|
>
|
||||||
<i className="fa-solid fa-calendar-minus mr-2"></i>
|
<i className="fa-solid fa-calendar-minus mr-2"></i>
|
||||||
Hủy đăng ký
|
Unregister
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
{isManager && (
|
{isManager && (
|
||||||
@@ -246,7 +246,7 @@ export default function ShiftDetailModal({
|
|||||||
className="cursor-pointer rounded-xl border border-red-200 bg-transparent px-4 py-2.5 text-sm font-semibold text-red-600 transition hover:bg-red-50"
|
className="cursor-pointer rounded-xl border border-red-200 bg-transparent px-4 py-2.5 text-sm font-semibold text-red-600 transition hover:bg-red-50"
|
||||||
>
|
>
|
||||||
<i className="fa-solid fa-trash mr-2"></i>
|
<i className="fa-solid fa-trash mr-2"></i>
|
||||||
Xóa ca
|
Delete shift
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
<button
|
<button
|
||||||
@@ -254,7 +254,7 @@ export default function ShiftDetailModal({
|
|||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
className="cursor-pointer rounded-xl border border-(--color-border-light) bg-transparent px-4 py-2.5 text-sm font-medium text-(--color-text-secondary) transition hover:bg-gray-50"
|
className="cursor-pointer rounded-xl border border-(--color-border-light) bg-transparent px-4 py-2.5 text-sm font-medium text-(--color-text-secondary) transition hover:bg-gray-50"
|
||||||
>
|
>
|
||||||
Đóng
|
Close
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -116,14 +116,14 @@ export default function WeeklySchedule({
|
|||||||
{formatDateShort(new Date(selectedDateRef))}
|
{formatDateShort(new Date(selectedDateRef))}
|
||||||
</h3>
|
</h3>
|
||||||
<span className="rounded-full bg-(--color-primary)/10 px-2.5 py-1 text-xs font-semibold text-(--color-primary)">
|
<span className="rounded-full bg-(--color-primary)/10 px-2.5 py-1 text-xs font-semibold text-(--color-primary)">
|
||||||
{dayShifts.length} ca
|
{dayShifts.length} shifts
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{dayShifts.length === 0 && !onCreateShift ? (
|
{dayShifts.length === 0 && !onCreateShift ? (
|
||||||
<div className="rounded-2xl border border-dashed border-(--color-border-light) py-10 text-center">
|
<div className="rounded-2xl border border-dashed border-(--color-border-light) py-10 text-center">
|
||||||
<i className="fa-regular fa-calendar-xmark mb-2 text-3xl text-gray-200"></i>
|
<i className="fa-regular fa-calendar-xmark mb-2 text-3xl text-gray-200"></i>
|
||||||
<p className="text-sm text-(--color-text-muted)">Không có ca làm hôm nay</p>
|
<p className="text-sm text-(--color-text-muted)">No shifts today</p>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="space-y-2.5">
|
<div className="space-y-2.5">
|
||||||
@@ -137,7 +137,7 @@ export default function WeeklySchedule({
|
|||||||
className="flex w-full cursor-pointer items-center justify-center gap-2 rounded-2xl border border-dashed border-(--color-border-light) bg-transparent py-3 text-sm font-medium text-(--color-text-muted) transition hover:border-(--color-primary) hover:text-(--color-primary)"
|
className="flex w-full cursor-pointer items-center justify-center gap-2 rounded-2xl border border-dashed border-(--color-border-light) bg-transparent py-3 text-sm font-medium text-(--color-text-muted) transition hover:border-(--color-primary) hover:text-(--color-primary)"
|
||||||
>
|
>
|
||||||
<i className="fa-solid fa-plus"></i>
|
<i className="fa-solid fa-plus"></i>
|
||||||
Thêm ca làm
|
Add shift
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -156,7 +156,7 @@ export default function WeeklySchedule({
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th className="w-28 border-r border-b border-(--color-border-light) bg-gray-50/80 px-4 py-3 text-left text-[11px] font-semibold tracking-wider text-(--color-text-muted) uppercase">
|
<th className="w-28 border-r border-b border-(--color-border-light) bg-gray-50/80 px-4 py-3 text-left text-[11px] font-semibold tracking-wider text-(--color-text-muted) uppercase">
|
||||||
Bộ phận
|
Department
|
||||||
</th>
|
</th>
|
||||||
{weekDates.map((date, i) => {
|
{weekDates.map((date, i) => {
|
||||||
const today = isToday(new Date(date));
|
const today = isToday(new Date(date));
|
||||||
@@ -221,7 +221,7 @@ export default function WeeklySchedule({
|
|||||||
className="mt-auto flex cursor-pointer items-center justify-center gap-1 rounded-lg border border-dashed border-gray-200 bg-transparent py-1.5 text-[10px] font-medium text-gray-300 transition hover:border-(--color-primary)/50 hover:text-(--color-primary)"
|
className="mt-auto flex cursor-pointer items-center justify-center gap-1 rounded-lg border border-dashed border-gray-200 bg-transparent py-1.5 text-[10px] font-medium text-gray-300 transition hover:border-(--color-primary)/50 hover:text-(--color-primary)"
|
||||||
>
|
>
|
||||||
<i className="fa-solid fa-plus"></i>
|
<i className="fa-solid fa-plus"></i>
|
||||||
Thêm
|
Add
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+1
-1
@@ -47,7 +47,7 @@ export default function Header() {
|
|||||||
<div className="relative h-10 w-10 shrink-0 md:h-11 md:w-11">
|
<div className="relative h-10 w-10 shrink-0 md:h-11 md:w-11">
|
||||||
<Image
|
<Image
|
||||||
src={SHOP_INFO.logo}
|
src={SHOP_INFO.logo}
|
||||||
alt={`Logo ${SHOP_INFO.name}`}
|
alt={`${SHOP_INFO.name} logo`}
|
||||||
fill
|
fill
|
||||||
className="object-contain transition-transform duration-200 group-hover:scale-105"
|
className="object-contain transition-transform duration-200 group-hover:scale-105"
|
||||||
sizes="44px"
|
sizes="44px"
|
||||||
|
|||||||
Reference in New Issue
Block a user