74 lines
3.4 KiB
TypeScript
74 lines
3.4 KiB
TypeScript
import Link from "next/link";
|
|
import { notFound } from "next/navigation";
|
|
import { getFormatter, getTranslations } from "next-intl/server";
|
|
import { ArrowLeft } from "lucide-react";
|
|
import { REPORT_EDITABLE, type ReportStatus } from "@/lib/reports/content";
|
|
import { can, ServiceError } from "@/server/services/context";
|
|
import { getMobileReportState } from "@/server/services/reports/queries";
|
|
import { readCtx } from "@/server/services/reports/read-ctx";
|
|
import { ReportStatusBadge } from "../status-badge";
|
|
import { StepIndicator } from "../step-indicator";
|
|
import { SignFlow } from "./sign-flow";
|
|
|
|
/** /m/orders/[id]/sign — signature or documented reason, then submit the completion report. */
|
|
export async function SignScreen({ workOrderId }: { workOrderId: string }) {
|
|
const t = await getTranslations("reports");
|
|
const format = await getFormatter();
|
|
const ctx = await readCtx();
|
|
let state: Awaited<ReturnType<typeof getMobileReportState>>;
|
|
try {
|
|
state = await getMobileReportState(ctx, workOrderId, "completion");
|
|
} catch (err) {
|
|
if (err instanceof ServiceError && err.code === "not_found") notFound();
|
|
throw err;
|
|
}
|
|
const { workOrder, report, content, timeZone } = state;
|
|
const base = `/m/orders/${workOrderId}`;
|
|
const steps = [t("mobile.stepReview"), t("mobile.stepEdit"), t("mobile.stepSign"), t("mobile.stepSubmit")];
|
|
|
|
return (
|
|
<main className="mx-auto w-full max-w-2xl flex-1 space-y-4 p-4">
|
|
<Link href={`${base}/report?type=completion`} className="inline-flex min-h-11 items-center gap-1.5 text-[13px] font-semibold text-muted-foreground hover:text-foreground">
|
|
<ArrowLeft className="size-4" aria-hidden />
|
|
{t("mobile.review")}
|
|
</Link>
|
|
<header>
|
|
<p className="text-xs text-muted-foreground">
|
|
{workOrder.number} · {workOrder.title}
|
|
</p>
|
|
<h1 className="text-[22px]">{t("sign.title")}</h1>
|
|
</header>
|
|
|
|
{!report || !content ? (
|
|
<p className="shadow-card rounded-xl border bg-card p-4 text-[14px]">
|
|
{t("sign.noReport")}{" "}
|
|
<Link href={`${base}/report?type=completion`} className="font-semibold underline">
|
|
{t("mobile.createCompletion")}
|
|
</Link>
|
|
</p>
|
|
) : (
|
|
<>
|
|
<StepIndicator steps={steps} current={3} label={t("mobile.stepOf", { current: 3, total: steps.length })} />
|
|
<div className="flex flex-wrap items-center gap-2">
|
|
<ReportStatusBadge status={report.status as ReportStatus} label={t(`status.${report.status}`)} />
|
|
<span className="text-[13px] text-muted-foreground">
|
|
{content.reportNumber} · {t("field.version")} {report.version}
|
|
</span>
|
|
</div>
|
|
<SignFlow
|
|
reportId={report.id}
|
|
reportNumber={content.reportNumber}
|
|
orderNumber={workOrder.number}
|
|
dateLabel={format.dateTime(new Date(), { dateStyle: "medium", timeZone })}
|
|
canNotRequired={!workOrder.signatureRequired || can(ctx, "report:approve")}
|
|
existing={content.signature ? { outcome: content.signature.outcome, signerName: content.signature.signerName, reason: content.signature.reason } : null}
|
|
editable={REPORT_EDITABLE.includes(report.status as ReportStatus)}
|
|
doneHref={`${base}/report?type=completion`}
|
|
aiDrafted={report.aiDrafted}
|
|
/>
|
|
</>
|
|
)}
|
|
</main>
|
|
);
|
|
}
|