@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.
@@ -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.4-staging.241",
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.",