This commit is contained in:
+74
-20
@@ -8,28 +8,43 @@ import { prisma } from "@/lib/prisma";
|
||||
* on?" Active claims are the headline list; below that we show a generic
|
||||
* "scan a card to start" hint so a fresh operator knows what to do.
|
||||
*/
|
||||
export default async function OperatorHomePage() {
|
||||
const user = await requireOperator();
|
||||
|
||||
const claims = await prisma.operation.findMany({
|
||||
where: { claimedByUserId: user.id, status: "in_progress" },
|
||||
orderBy: { claimedAt: "desc" },
|
||||
include: {
|
||||
machine: { select: { name: true } },
|
||||
part: {
|
||||
const OP_INCLUDE = {
|
||||
machine: { select: { name: true } },
|
||||
part: {
|
||||
select: {
|
||||
code: true,
|
||||
name: true,
|
||||
qty: true,
|
||||
assembly: {
|
||||
select: {
|
||||
code: true,
|
||||
name: true,
|
||||
assembly: {
|
||||
select: {
|
||||
code: true,
|
||||
project: { select: { code: true, name: true } },
|
||||
},
|
||||
},
|
||||
qty: true,
|
||||
project: { select: { code: true, name: true } },
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
},
|
||||
} as const;
|
||||
|
||||
export default async function OperatorHomePage() {
|
||||
const user = await requireOperator();
|
||||
|
||||
const [claims, resumable] = await Promise.all([
|
||||
prisma.operation.findMany({
|
||||
where: { claimedByUserId: user.id, status: "in_progress" },
|
||||
orderBy: { claimedAt: "desc" },
|
||||
include: OP_INCLUDE,
|
||||
}),
|
||||
// B1: partial ops are unclaimed after a release and only re-surface when
|
||||
// someone physically re-scans the card. List them here so any operator
|
||||
// can pick up where the last shift left off.
|
||||
prisma.operation.findMany({
|
||||
where: { status: "partial", claimedByUserId: null },
|
||||
orderBy: { updatedAt: "desc" },
|
||||
take: 50,
|
||||
include: OP_INCLUDE,
|
||||
}),
|
||||
]);
|
||||
|
||||
return (
|
||||
<div className="mx-auto max-w-3xl px-4 py-6 space-y-6">
|
||||
@@ -40,11 +55,13 @@ export default async function OperatorHomePage() {
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{claims.length === 0 ? (
|
||||
{claims.length === 0 && resumable.length === 0 ? (
|
||||
<div className="rounded-xl bg-white border border-slate-200 p-6 text-slate-600 text-sm text-center">
|
||||
You have no active steps. Scan a traveler QR to begin.
|
||||
</div>
|
||||
) : (
|
||||
) : null}
|
||||
|
||||
{claims.length > 0 ? (
|
||||
<div className="space-y-3">
|
||||
<h2 className="text-sm font-semibold text-slate-900 uppercase tracking-wide">
|
||||
Active ({claims.length})
|
||||
@@ -70,7 +87,44 @@ export default async function OperatorHomePage() {
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
) : null}
|
||||
|
||||
{resumable.length > 0 ? (
|
||||
<div className="space-y-3">
|
||||
<h2 className="text-sm font-semibold text-slate-900 uppercase tracking-wide">
|
||||
Resumable ({resumable.length})
|
||||
</h2>
|
||||
<p className="text-xs text-slate-500 -mt-1">
|
||||
Previously started and released with units still to run. Tap to pick up where the last shift left off.
|
||||
</p>
|
||||
{resumable.map((c) => {
|
||||
const total = c.part.qty * c.part.assembly.qty;
|
||||
const remaining = Math.max(total - c.unitsCompleted, 0);
|
||||
return (
|
||||
<Link
|
||||
key={c.id}
|
||||
href={`/op/scan/${c.qrToken}`}
|
||||
className="block rounded-xl bg-white border border-amber-300 p-4 hover:border-amber-500 hover:shadow-sm transition"
|
||||
>
|
||||
<div className="text-xs text-slate-500">
|
||||
{c.part.assembly.project.code} · {c.part.assembly.code}
|
||||
</div>
|
||||
<div className="font-medium mt-0.5">{c.part.name}</div>
|
||||
<div className="text-sm text-slate-700 mt-1">
|
||||
Step {c.sequence}: {c.name}
|
||||
</div>
|
||||
<div className="text-xs text-slate-600 mt-1 flex flex-wrap gap-x-3">
|
||||
<span className="font-mono">{c.part.code}</span>
|
||||
{c.machine ? <span>{c.machine.name}</span> : null}
|
||||
<span className="text-amber-700 font-medium">
|
||||
{c.unitsCompleted} of {total} done · {remaining} remaining
|
||||
</span>
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user