@7365admin1/layer-common 4.0.4-staging.241 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -4
- package/components/EntryPass/SelfServiceQrPreview.vue +79 -0
- package/components/EntryPassMain.vue +289 -0
- package/components/PublicOnboarding/ContractorRegistrationForm.vue +278 -0
- package/components/PublicOnboarding/LocationFields.vue +125 -0
- package/components/PublicOnboarding/TypeSelectCard.vue +34 -0
- package/components/PublicOnboarding/VisitorRegistrationForm.vue +273 -0
- package/components/VisitorManagement.vue +205 -14
- package/composables/useContactPicker.ts +36 -0
- package/composables/usePublicVisitorOnboarding.ts +73 -0
- package/composables/useWebUsb.ts +64 -1
- package/package.json +1 -1
package/composables/useWebUsb.ts
CHANGED
|
@@ -227,6 +227,7 @@ export default function useWebUsb() {
|
|
|
227
227
|
address?: string,
|
|
228
228
|
qrHeader?: string,
|
|
229
229
|
qrSubText?: string,
|
|
230
|
+
layout?: "receipt" | "onboarding",
|
|
230
231
|
) => {
|
|
231
232
|
if (!isWebUsbSupported.value) {
|
|
232
233
|
throw new Error("Web USB is not supported in this browser");
|
|
@@ -245,7 +246,9 @@ export default function useWebUsb() {
|
|
|
245
246
|
};
|
|
246
247
|
|
|
247
248
|
let printTestResult;
|
|
248
|
-
if (forQr && urlImage) {
|
|
249
|
+
if (forQr && urlImage && layout === "onboarding") {
|
|
250
|
+
printTestResult = await printOnboardingQrCode(device, urlImage, qrHeader, qrSubText);
|
|
251
|
+
} else if (forQr && urlImage) {
|
|
249
252
|
printTestResult = await printQrCode(
|
|
250
253
|
device,
|
|
251
254
|
urlImage,
|
|
@@ -399,6 +402,66 @@ export default function useWebUsb() {
|
|
|
399
402
|
return canvas;
|
|
400
403
|
}
|
|
401
404
|
|
|
405
|
+
/**
|
|
406
|
+
* The self-service onboarding QR: one large QR code, a "SCAN QR CODE"-style
|
|
407
|
+
* subtext, and a dark site-name banner along the bottom - a single-purpose
|
|
408
|
+
* gate sign, not the multi-copy visitor-pass receipt `createReceiptLayout`
|
|
409
|
+
* produces (that one prints several QRs to be cut apart and handed out).
|
|
410
|
+
*/
|
|
411
|
+
async function createOnboardingQrLayout(
|
|
412
|
+
qrUrlImage: string,
|
|
413
|
+
header?: string,
|
|
414
|
+
subText?: string,
|
|
415
|
+
): Promise<HTMLCanvasElement> {
|
|
416
|
+
const canvas = document.createElement("canvas");
|
|
417
|
+
canvas.width = 576;
|
|
418
|
+
canvas.height = 760;
|
|
419
|
+
const ctx = canvas.getContext("2d")!;
|
|
420
|
+
ctx.fillStyle = "#fff";
|
|
421
|
+
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
422
|
+
ctx.textAlign = "center";
|
|
423
|
+
|
|
424
|
+
const qrSize = 400;
|
|
425
|
+
const qrCanvas = await QRCode.toCanvas(qrUrlImage, { width: qrSize, margin: 1 });
|
|
426
|
+
ctx.drawImage(qrCanvas, (canvas.width - qrSize) / 2, 40, qrSize, qrSize);
|
|
427
|
+
|
|
428
|
+
ctx.fillStyle = "#000";
|
|
429
|
+
ctx.font = "bold 26px Arial";
|
|
430
|
+
ctx.fillText((subText || "SCAN QR CODE").toUpperCase(), canvas.width / 2, 480);
|
|
431
|
+
|
|
432
|
+
const bannerHeight = 110;
|
|
433
|
+
const bannerY = canvas.height - bannerHeight;
|
|
434
|
+
ctx.fillStyle = "#000";
|
|
435
|
+
ctx.fillRect(0, bannerY, canvas.width, bannerHeight);
|
|
436
|
+
ctx.fillStyle = "#fff";
|
|
437
|
+
ctx.font = "bold 34px Arial";
|
|
438
|
+
ctx.fillText((header || "").toUpperCase(), canvas.width / 2, bannerY + bannerHeight / 2 + 12);
|
|
439
|
+
|
|
440
|
+
return canvas;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
const printOnboardingQrCode = async (
|
|
444
|
+
device: USBDevice,
|
|
445
|
+
urlImage: string,
|
|
446
|
+
header?: string,
|
|
447
|
+
subText?: string,
|
|
448
|
+
) => {
|
|
449
|
+
try {
|
|
450
|
+
const { endpointNumber } = getPrinterConnection(device);
|
|
451
|
+
const canvas = await createOnboardingQrLayout(urlImage, header, subText);
|
|
452
|
+
const rasterData = canvasToRaster(canvas);
|
|
453
|
+
await device.transferOut(endpointNumber, rasterData.buffer);
|
|
454
|
+
|
|
455
|
+
const CUT = new Uint8Array([0x1d, 0x56, 0x41, 0x10]);
|
|
456
|
+
await device.transferOut(endpointNumber, CUT.buffer);
|
|
457
|
+
|
|
458
|
+
return { success: true, message: "Onboarding QR print sent successfully" };
|
|
459
|
+
} catch (error: unknown) {
|
|
460
|
+
console.error("[WebUSB] printOnboardingQrCode error:", error);
|
|
461
|
+
return { success: false, error: getErrorMessage(error, "Unable to print onboarding QR code") };
|
|
462
|
+
}
|
|
463
|
+
};
|
|
464
|
+
|
|
402
465
|
function canvasToRaster(canvas: HTMLCanvasElement): Uint8Array {
|
|
403
466
|
const ctx = canvas.getContext("2d");
|
|
404
467
|
if (!ctx) throw new Error("Canvas 2D context not available");
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@7365admin1/layer-common",
|
|
3
3
|
"license": "MIT",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "4.0
|
|
5
|
+
"version": "4.1.0",
|
|
6
6
|
"author": "7365admin1",
|
|
7
7
|
"main": "./nuxt.config.ts",
|
|
8
8
|
"//files": "What a consumer extending this layer actually loads. Without this npm ships the whole working tree - the changesets, the CI workflows, the render harness in tools/ and any scratch directory that happened to exist at publish time. Nuxt resolves a layer by directory, so every runtime directory below has to stay listed; adding a new top-level runtime directory means adding it here too.",
|