chore: update

This commit is contained in:
TakahashiNg
2026-05-14 02:44:43 +00:00
parent 9c88751c79
commit e7c7d9b1a2
7 changed files with 51 additions and 45 deletions
@@ -70,13 +70,13 @@ export default function MobileShiftView({
const dateStr = formatDateISO(date); const dateStr = formatDateISO(date);
const dayShifts = shifts.filter((s) => s.date === dateStr); const dayShifts = shifts.filter((s) => s.date === dateStr);
const dots: string[] = []; const dots: string[] = [];
if (dayShifts.some((s) => s.status === "available")) // if (dayShifts.some((s) => s.status === "available"))
dots.push("bg-amber-400"); // dots.push("bg-amber-400");
if (dayShifts.some((s) => s.status === "registered")) // if (dayShifts.some((s) => s.status === "registered"))
dots.push("bg-green-500"); // dots.push("bg-green-500");
if (dayShifts.some((s) => s.status === "approved_leave")) // if (dayShifts.some((s) => s.status === "approved_leave"))
dots.push("bg-purple-400"); // dots.push("bg-purple-400");
if (dayShifts.some((s) => s.status === "absent")) dots.push("bg-red-400"); // if (dayShifts.some((s) => s.status === "absent")) dots.push("bg-red-400");
return dots; return dots;
}; };
@@ -62,13 +62,13 @@ export default function MonthlyCalendar({
const getShiftSummary = (date: Date) => { const getShiftSummary = (date: Date) => {
const dateStr = formatDateISO(date); const dateStr = formatDateISO(date);
const dayShifts = shifts.filter((s) => s.date === dateStr); const dayShifts = shifts.filter((s) => s.date === dateStr);
const available = dayShifts.filter((s) => s.status === "available").length; // const available = dayShifts.filter((s) => s.status === "available").length;
const registered = dayShifts.filter( // const registered = dayShifts.filter(
(s) => s.status === "registered", // (s) => s.status === "registered",
).length; // ).length;
const leave = dayShifts.filter((s) => s.status === "approved_leave").length; // const leave = dayShifts.filter((s) => s.status === "approved_leave").length;
const absent = dayShifts.filter((s) => s.status === "absent").length; // const absent = dayShifts.filter((s) => s.status === "absent").length;
return { total: dayShifts.length, available, registered, leave, absent }; return { total: dayShifts.length };
}; };
return ( return (
@@ -119,7 +119,7 @@ export default function MonthlyCalendar({
{date.getDate()} {date.getDate()}
</span> </span>
{summary.total > 0 && ( {/* {summary.total > 0 && (
<div className="mt-2 space-y-1"> <div className="mt-2 space-y-1">
{summary.available > 0 && ( {summary.available > 0 && (
<div className="flex items-center gap-1.5"> <div className="flex items-center gap-1.5">
@@ -154,7 +154,7 @@ export default function MonthlyCalendar({
</div> </div>
)} )}
</div> </div>
)} )} */}
</button> </button>
); );
})} })}
@@ -50,7 +50,7 @@ export default function ShiftCreateModal({
} }
createShift({ createShift({
date: new Date(date), date,
startTime, startTime,
endTime, endTime,
wage, wage,
@@ -19,12 +19,12 @@ export default function ShiftDetailModal({
if (!isOpen || !shift) return null; if (!isOpen || !shift) return null;
const dept = DEPARTMENTS.find((d) => d.id === shift.department); // const dept = DEPARTMENTS.find((d) => d.id === shift.department);
const isManager = user?.role === "manager"; const isManager = user?.role === "manager";
const isRegistered = user const isRegistered = user
? shift.registeredStaff.some((s) => s.id === user.id) ? shift.registeredStaff!.some((s) => s.id === user.id)
: false; : false;
const isFull = shift.registeredStaff.length >= shift.maxStaff; const isFull = shift.registeredStaff!.length >= shift.maxStaff;
const handleRegister = () => { const handleRegister = () => {
if (!user) return; if (!user) return;
@@ -47,7 +47,7 @@ export default function ShiftDetailModal({
setTimeout(onClose, 1200); setTimeout(onClose, 1200);
}; };
const handleManagerUnregister = (staffId: number) => { const handleManagerUnregister = (staffId: string) => {
unregisterShift(shift.id, staffId); unregisterShift(shift.id, staffId);
setSuccess("Đã xóa nhân viên khỏi ca."); setSuccess("Đã xóa nhân viên khỏi ca.");
}; };
@@ -81,12 +81,12 @@ export default function ShiftDetailModal({
{/* Header */} {/* Header */}
<div className="flex items-center justify-between border-b border-(--color-border-light) px-5 py-4"> <div className="flex items-center justify-between border-b border-(--color-border-light) px-5 py-4">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
{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 Chi tiết ca làm
</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>
</div> </div>
<button <button
@@ -102,13 +102,13 @@ export default function ShiftDetailModal({
{/* Body */} {/* Body */}
<div className="space-y-4 px-5 py-4"> <div className="space-y-4 px-5 py-4">
{/* Status badge */} {/* Status badge */}
<div className="flex items-center gap-2"> {/* <div className="flex items-center gap-2">
<span <span
className={`rounded-full px-3 py-1 text-xs font-semibold ${statusColor[shift.status]}`} className={`rounded-full px-3 py-1 text-xs font-semibold ${statusColor[shift.status]}`}
> >
{statusLabel[shift.status]} {statusLabel[shift.status]}
</span> </span>
</div> </div> */}
{/* Shift info grid */} {/* Shift info grid */}
<div className="grid grid-cols-2 gap-3"> <div className="grid grid-cols-2 gap-3">
@@ -141,7 +141,7 @@ export default function ShiftDetailModal({
Thời lượng Thời lượng
</p> </p>
<p className="text-foreground mt-1 text-sm font-bold"> <p className="text-foreground mt-1 text-sm font-bold">
{shift.durationHours} giờ {""} giờ
</p> </p>
</div> </div>
<div className="rounded-xl bg-gray-50 p-3"> <div className="rounded-xl bg-gray-50 p-3">
@@ -157,16 +157,16 @@ 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 ({shift.registeredStaff.length}/ Nhân viên đã đăng ({shift.registeredStaff!.length}/
{shift.maxStaff}) {shift.maxStaff})
</p> </p>
{shift.registeredStaff.length === 0 ? ( {(shift.registeredStaff && shift.registeredStaff.length === 0) ? (
<p className="text-xs text-(--color-text-muted) italic"> <p className="text-xs text-(--color-text-muted) italic">
Chưa ai đăng Chưa ai đăng
</p> </p>
) : ( ) : (
<div className="space-y-2"> <div className="space-y-2">
{shift.registeredStaff.map((staff) => ( {shift.registeredStaff!.map((staff) => (
<div <div
key={staff.id} key={staff.id}
className="flex items-center justify-between rounded-xl bg-gray-50 px-3 py-2" className="flex items-center justify-between rounded-xl bg-gray-50 px-3 py-2"
@@ -176,7 +176,7 @@ export default function ShiftDetailModal({
<i className="fa-solid fa-user text-[10px] text-(--color-primary)"></i> <i className="fa-solid fa-user text-[10px] text-(--color-primary)"></i>
</div> </div>
<span className="text-foreground text-sm font-medium"> <span className="text-foreground text-sm font-medium">
{staff.name} {staff.staffId}
</span> </span>
</div> </div>
{isManager && ( {isManager && (
@@ -212,7 +212,7 @@ export default function ShiftDetailModal({
{/* Footer actions */} {/* Footer actions */}
<div className="flex gap-2 border-t border-(--color-border-light) px-5 py-4"> <div className="flex gap-2 border-t border-(--color-border-light) px-5 py-4">
{!isRegistered && {/* {!isRegistered &&
!isFull && !isFull &&
shift.status !== "approved_leave" && shift.status !== "approved_leave" &&
shift.status !== "absent" && ( shift.status !== "absent" && (
@@ -224,7 +224,7 @@ export default function ShiftDetailModal({
<i className="fa-solid fa-calendar-plus mr-2"></i> <i className="fa-solid fa-calendar-plus mr-2"></i>
Đăng ký ca Đăng ký ca
</button> </button>
)} )} */}
{isRegistered && ( {isRegistered && (
<button <button
type="button" type="button"
@@ -37,7 +37,7 @@ function formatDateISO(d: Date): string {
} }
function isToday(d: Date): boolean { function isToday(d: Date): boolean {
const today = Date.now(); const today = new Date(Date.now());
return ( return (
d.getDate() === today.getDate() && d.getDate() === today.getDate() &&
d.getMonth() === today.getMonth() && d.getMonth() === today.getMonth() &&
@@ -81,7 +81,7 @@ export default function WeeklySchedule({
}, [weekDates, getShiftsForDate]); }, [weekDates, getShiftsForDate]);
const selectedDateStr = useMemo(() => { const selectedDateStr = useMemo(() => {
const inWeek = weekDates.find((d) => formatDateISO(d) === selectedDate); const inWeek = weekDates.find((d) => d === selectedDate);
return inWeek ?? weekDates[0] ?? currentDate; return inWeek ?? weekDates[0] ?? currentDate;
}, [selectedDate, weekDates, currentDate]); }, [selectedDate, weekDates, currentDate]);
@@ -215,14 +215,14 @@ export default function WeeklySchedule({
<th <th
key={i} key={i}
className={`border-r border-b border-(--color-border-light) px-2 py-3 text-center text-xs ${ className={`border-r border-b border-(--color-border-light) px-2 py-3 text-center text-xs ${
isToday(date) isToday(new Date(date))
? "bg-(--color-primary)/10 font-bold text-(--color-primary)" ? "bg-(--color-primary)/10 font-bold text-(--color-primary)"
: "bg-gray-50 font-semibold text-(--color-text-muted)" : "bg-gray-50 font-semibold text-(--color-text-muted)"
}`} }`}
> >
<span className="block uppercase">{DAY_LABELS[i]}</span> <span className="block uppercase">{DAY_LABELS[i]}</span>
<span className="mt-0.5 block text-[11px] font-normal"> <span className="mt-0.5 block text-[11px] font-normal">
{formatDateShort(date)} {date}
</span> </span>
</th> </th>
))} ))}
@@ -242,8 +242,8 @@ export default function WeeklySchedule({
</div> </div>
</td> </td>
{weekDates.map((date, i) => { {weekDates.map((date, i) => {
const dateStr = formatDateISO(date); const dateStr = date;
const shifts = getShiftsForDate(date); const shifts = getShiftsForDate(new Date(date));
// .filter( // .filter(
// (s) => s.department === dept.id, // (s) => s.department === dept.id,
// ); // );
@@ -251,7 +251,7 @@ export default function WeeklySchedule({
<td <td
key={i} key={i}
className={`border-r border-b border-(--color-border-light) p-1.5 align-top ${ className={`border-r border-b border-(--color-border-light) p-1.5 align-top ${
isToday(date) ? "bg-(--color-primary)/5" : "" isToday(new Date(date)) ? "bg-(--color-primary)/5" : ""
}`} }`}
> >
<div className="flex min-h-20 flex-col gap-1"> <div className="flex min-h-20 flex-col gap-1">
+5 -5
View File
@@ -146,7 +146,7 @@ function generateMockShifts(): ShiftEntity[] {
// Determine registration status // Determine registration status
const registered: { id: number; name: string }[] = []; const registered: { id: number; name: string }[] = [];
let status: ShiftEntity["status"] = "available"; // let status: ShiftEntity["status"] = "available";
// Past shifts (before April 10) are mostly registered // Past shifts (before April 10) are mostly registered
if (day < 10) { if (day < 10) {
@@ -180,12 +180,12 @@ function generateMockShifts(): ShiftEntity[] {
date: dateStr, date: dateStr,
startTime: slot.start, startTime: slot.start,
endTime: slot.end, endTime: slot.end,
durationHours: slot.hours, // durationHours: slot.hours,
wage: slot.wage, wage: slot.wage,
department: dept, // department: dept,
maxStaff: dept === "bar" ? 3 : 2, maxStaff: dept === "bar" ? 3 : 2,
registeredStaff: registered, // registeredStaff: registered,
status, // status,
}); });
} }
} }
+7 -1
View File
@@ -2,7 +2,7 @@
export type UserRole = "manager" | "staff" | "customer"; export type UserRole = "manager" | "staff" | "customer";
export interface User { export interface User {
id: number; id: string;
name: string; name: string;
role: UserRole; role: UserRole;
avatar: string | null; avatar: string | null;
@@ -104,6 +104,12 @@ export interface ShiftEntity {
registeredStaff?: ShiftRegistrationEntity[]; registeredStaff?: ShiftRegistrationEntity[];
} }
export interface Department {
id: string;
name: string;
icon: string;
}
export interface MenuItemEntity { export interface MenuItemEntity {
id?: string; id?: string;
name: string; name: string;