Files
frontend/components/molecules/cards/ShiftCard.tsx
T
Thanh Quy - wolf 54d5d6150c
Release package / release (pull_request) Successful in 3m23s
Refactor: Update Vietnamese text to English across multiple components
- 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.
2026-05-14 21:09:18 +07:00

111 lines
3.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import type { ShiftCardProps } from "./ShiftCard.types";
function formatWage(wage: number): string {
if (wage >= 1_000_000) return `${(wage / 1_000_000).toFixed(1)}M`;
if (wage >= 1000) return `${(wage / 1000).toFixed(0)}k`;
return wage.toLocaleString("vi-VN");
}
function getShiftPeriod(startTime: string): "morning" | "afternoon" | "evening" {
const h = parseInt(startTime.split(":")[0] ?? "0", 10);
if (h < 12) return "morning";
if (h < 18) return "afternoon";
return "evening";
}
const PERIOD_STYLES = {
morning: {
border: "border-l-indigo-500",
text: "text-indigo-700",
badge: "bg-indigo-100 text-indigo-700",
dot: "bg-indigo-400",
},
afternoon: {
border: "border-l-amber-500",
text: "text-amber-700",
badge: "bg-amber-100 text-amber-700",
dot: "bg-amber-400",
},
evening: {
border: "border-l-violet-500",
text: "text-violet-700",
badge: "bg-violet-100 text-violet-700",
dot: "bg-violet-400",
},
};
export default function ShiftCard({ shift, compact = false, onClick }: ShiftCardProps) {
const registeredCount = shift.registeredStaff?.length ?? 0;
const period = getShiftPeriod(shift.startTime);
const s = PERIOD_STYLES[period];
if (compact) {
return (
<button
type="button"
onClick={() => onClick?.(shift)}
className={`group w-full cursor-pointer rounded-xl border-l-[3px] bg-white text-left shadow-sm transition hover:-translate-y-px hover:shadow-md ${s.border}`}
>
<div className="px-2.5 py-2">
<p className={`text-xs font-bold leading-tight ${s.text}`}>
{shift.startTime}{shift.endTime}
</p>
<div className="mt-1 flex items-center justify-between gap-1">
<p className="text-[10px] text-(--color-text-muted)">{formatWage(shift.wage ?? 0)}đ</p>
<span className={`rounded-full px-1.5 py-px text-[9px] font-semibold ${s.badge}`}>
{registeredCount}/{shift.maxStaff}
</span>
</div>
</div>
</button>
);
}
return (
<button
type="button"
onClick={() => onClick?.(shift)}
className={`group w-full cursor-pointer rounded-2xl border-l-[4px] bg-white text-left shadow-sm transition hover:-translate-y-0.5 hover:shadow-lg ${s.border}`}
>
<div className="p-4">
<div className="flex items-start justify-between gap-3">
<div className="min-w-0">
<div className="flex items-center gap-2">
<span className={`h-2 w-2 shrink-0 rounded-full ${s.dot}`} />
<p className={`text-base font-bold ${s.text}`}>
{shift.startTime} {shift.endTime}
</p>
</div>
<p className="mt-1 text-xs text-(--color-text-muted)">
{(shift.wage ?? 0).toLocaleString("vi-VN")} VND/ca
</p>
</div>
<span className={`shrink-0 rounded-full px-2.5 py-1 text-xs font-semibold ${s.badge}`}>
{registeredCount}/{shift.maxStaff} staff
</span>
</div>
{registeredCount > 0 && (
<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">
Registered staff
</p>
<div className="flex flex-wrap gap-1.5">
{shift.registeredStaff!.map((staff) => (
<span
key={staff.id}
className="rounded-full bg-gray-100 px-2.5 py-0.5 text-[11px] font-medium text-(--color-text-secondary)"
>
{staff.staffId}
</span>
))}
</div>
</div>
)}
</div>
</button>
);
}