30 lines
1.4 KiB
TypeScript
30 lines
1.4 KiB
TypeScript
|
|
import type { Mechanic } from "./data";
|
||
|
|
|
||
|
|
/**
|
||
|
|
* What a mechanic's badge QR actually encodes: their NAME and EMPLOYEE NUMBER
|
||
|
|
* together (client ruling, 2026-10-08).
|
||
|
|
*
|
||
|
|
* Deliberately NOT a URL. This app sits behind a login and is only reachable inside
|
||
|
|
* the network, so a badge scanned on the yard would dead-end at a sign-in screen — and
|
||
|
|
* a badge is worthless if scanning it tells you nothing you could not have written on
|
||
|
|
* the card. Plain text reads the same on any scanner, survives the app moving host,
|
||
|
|
* and stays short enough that a cheap camera picks it up at an angle.
|
||
|
|
*
|
||
|
|
* ` | ` separates the two halves so the decoded string is both human-readable and
|
||
|
|
* trivially split back into fields.
|
||
|
|
*/
|
||
|
|
export function mechanicQrPayload(m: Pick<Mechanic, "name" | "employee_code">): string {
|
||
|
|
return `${(m.name || "").trim()} | ${(m.employee_code || "").trim()}`;
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Split a decoded payload back into its two halves. Unknown input is not guessed at. */
|
||
|
|
export function parseMechanicQr(payload: string): { name: string; employeeCode: string } | null {
|
||
|
|
const parts = payload.split("|").map((p) => p.trim());
|
||
|
|
if (parts.length !== 2 || !parts[0] || !parts[1]) return null;
|
||
|
|
return { name: parts[0], employeeCode: parts[1] };
|
||
|
|
}
|
||
|
|
|
||
|
|
/** A person with no employee number cannot be issued a badge — there is nothing to encode. */
|
||
|
|
export function isBadgeReady(m: Pick<Mechanic, "employee_code">): boolean {
|
||
|
|
return Boolean((m.employee_code || "").trim());
|
||
|
|
}
|