62 lines
2.4 KiB
TypeScript
62 lines
2.4 KiB
TypeScript
import type { Metadata } from "next";
|
|
import { notFound, redirect } from "next/navigation";
|
|
import { auth } from "@/auth";
|
|
import { TopNav } from "@/components/navigation/top-nav";
|
|
import { prisma } from "@/lib/db/prisma";
|
|
import { hasPermission } from "@/lib/auth/permissions";
|
|
import { Permission } from "@/generated/prisma/enums";
|
|
import { getActingBusinessContext } from "@/lib/business/get-acting-business-context";
|
|
import { listTimeOff } from "@/services/staff/staff.service";
|
|
import { TimeOffList } from "@/features/staff/components/time-off-list";
|
|
import { createOwnerTimeOffActionSet } from "@/features/owner/actions/time-off-action-set";
|
|
|
|
export const metadata: Metadata = { title: "Staff Time Off" };
|
|
export const dynamic = "force-dynamic";
|
|
|
|
function toCalendarDate(date: Date): string {
|
|
return date.toISOString().slice(0, 10);
|
|
}
|
|
|
|
export default async function OwnerStaffTimeOffPage({ params }: { params: Promise<{ id: string }> }) {
|
|
const session = await auth();
|
|
if (!session?.user) redirect("/sign-in");
|
|
|
|
const canManage = await hasPermission(session.user.id, Permission.MANAGE_STAFF);
|
|
if (!canManage) redirect("/staff");
|
|
|
|
const context = await getActingBusinessContext();
|
|
if (!context) redirect("/staff");
|
|
|
|
const { id } = await params;
|
|
const target = await prisma.staffProfile.findFirst({
|
|
where: { id, businessId: context.businessId },
|
|
include: { user: { select: { name: true } } },
|
|
});
|
|
if (!target) notFound();
|
|
|
|
const { upcoming, past } = await listTimeOff(prisma, id);
|
|
// Whole-day rows only — partial-day "Block Time" entries are managed from the owner calendar (see owner-block-time-button.tsx).
|
|
const wholeDay = (rows: typeof upcoming) => rows.filter((r) => r.startMinutes === null && r.endMinutes === null);
|
|
const toEditable = (rows: typeof upcoming) =>
|
|
wholeDay(rows).map((t) => ({
|
|
id: t.id,
|
|
startDate: toCalendarDate(t.startDate),
|
|
endDate: toCalendarDate(t.endDate),
|
|
reason: t.reason,
|
|
}));
|
|
|
|
return (
|
|
<div className="pb-12">
|
|
<TopNav title={`${target.user.name ?? "Staff"} — Time Off`} onBack sticky className="bg-stone" />
|
|
<main className="mx-auto max-w-2xl px-6 py-6">
|
|
<TimeOffList
|
|
upcoming={toEditable(upcoming)}
|
|
past={toEditable(past)}
|
|
actions={createOwnerTimeOffActionSet(id)}
|
|
appointmentHrefBase="/owner/appointments"
|
|
/>
|
|
</main>
|
|
</div>
|
|
);
|
|
}
|