@7365admin1/layer-common 4.35.1-staging.385 → 4.37.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.
Files changed (69) hide show
  1. package/CHANGELOG.md +16 -4
  2. package/assets/css/primitives.css +0 -43
  3. package/components/AccessCardAddForm.vue +4 -5
  4. package/components/AccessCardAssignToUnitForm.vue +2 -3
  5. package/components/AccessCardPreviewDialog.vue +3 -4
  6. package/components/AppSelect.vue +3 -77
  7. package/components/CameraForm.vue +6 -20
  8. package/components/DashboardMain.vue +60 -66
  9. package/components/Dialog/UpdateMoreAction.vue +1 -11
  10. package/components/DocumentForm.vue +112 -407
  11. package/components/DocumentManagement.vue +12 -213
  12. package/components/EntryPass/QrTemplatePreview.vue +25 -21
  13. package/components/EntryPassInformation.vue +24 -119
  14. package/components/Facility/BookingSetup.vue +0 -63
  15. package/components/HidAccessLogDashboard.vue +17 -74
  16. package/components/HidIntercomManagement.vue +14 -180
  17. package/components/HidQrCodeConfiguration.vue +195 -17
  18. package/components/HidReaderManagement.vue +0 -398
  19. package/components/HidReaderUserRoster.vue +3 -44
  20. package/components/HidUserEnrollment.vue +155 -845
  21. package/components/InvitationClientForm.vue +1 -19
  22. package/components/Layout/NavigationDrawer.vue +1 -4
  23. package/components/NotificationBell.vue +7 -59
  24. package/components/RolePermissionFormCreate.vue +3 -4
  25. package/components/RolePermissionFormPreviewUpdate.vue +5 -12
  26. package/components/RolePermissionMain.vue +0 -1
  27. package/components/ServiceProviderInvitationPrompt.vue +155 -0
  28. package/components/ServiceProviderMain.vue +30 -178
  29. package/components/VisitorForm.vue +0 -12
  30. package/components/VisitorManagement.vue +10 -285
  31. package/components/VisitorSocketPopUp.vue +1 -2
  32. package/composables/useANPRSettings.ts +15 -45
  33. package/composables/useAccessManagement.ts +0 -5
  34. package/composables/useCleaningPermission.ts +0 -2
  35. package/composables/useCommonPermission.ts +0 -32
  36. package/composables/useDocument.ts +0 -7
  37. package/composables/useFacility.ts +0 -11
  38. package/composables/useHidAmico.ts +0 -159
  39. package/composables/useHidNavigation.ts +1 -25
  40. package/composables/usePeople.ts +0 -19
  41. package/composables/usePropertyPermission.ts +0 -19
  42. package/composables/useSecurityPermission.ts +0 -19
  43. package/composables/useServiceProvider.ts +0 -3
  44. package/composables/useServiceProviderInvitation.ts +3 -101
  45. package/composables/useSiteEntryPassSettings.ts +0 -26
  46. package/composables/useWebUsb.ts +11 -14
  47. package/package.json +2 -2
  48. package/pages/[org]/[site]/access-mgmt/administrator/index.vue +1 -1
  49. package/pages/[org]/[site]/access-mgmt/hid-cards/index.vue +1 -1
  50. package/pages/[org]/[site]/access-mgmt/hid-readers/index.vue +1 -1
  51. package/plugins/API.ts +0 -11
  52. package/types/document.d.ts +0 -14
  53. package/types/facility.d.ts +0 -4
  54. package/types/people.d.ts +1 -28
  55. package/utils/module-routes.ts +1 -8
  56. package/utils/nav-sections.ts +2 -8
  57. package/utils/notification-target.ts +8 -277
  58. package/utils/permission-labels.ts +2 -20
  59. package/components/ClientInvitations.vue +0 -291
  60. package/components/HidAccessPermissions.vue +0 -424
  61. package/components/HidProfileQrCode.vue +0 -332
  62. package/composables/useHidReaderSelection.ts +0 -50
  63. package/composables/useSiteCategory.ts +0 -45
  64. package/pages/[org]/[site]/access-mgmt/hid-qr-code/index.vue +0 -23
  65. package/utils/dashboard-widget-prefs.ts +0 -54
  66. package/utils/hid-permission-assignments.ts +0 -190
  67. package/utils/hid-reader-selection.ts +0 -52
  68. package/utils/occupancy-role.ts +0 -109
  69. package/utils/sp-inviter-row.ts +0 -97
@@ -28,22 +28,6 @@ export type HidReaderPayload = {
28
28
  lastCallbackType?: string;
29
29
  };
30
30
 
31
- export type HidProfileQr = {
32
- readerId: string;
33
- userId: string;
34
- memberId: string;
35
- hidUserId: string;
36
- registration: string;
37
- readerName: string;
38
- portalName: string;
39
- qrEnabled: boolean;
40
- issued: boolean;
41
- qrValue: string;
42
- issuedAt: string;
43
- /** null when the permission lookup itself failed, so "unknown" stays distinct from "no". */
44
- assigned: boolean | null;
45
- };
46
-
47
31
  type HidIdentityPayload = {
48
32
  site?: string;
49
33
  hidUserId?: string | number;
@@ -155,28 +139,6 @@ export type HidSipAccountData = {
155
139
  provisionedAt: string;
156
140
  };
157
141
 
158
- /** One row of the site's SIP account list - who owns the extension, never its password. */
159
- export type HidSipAccountListItem = {
160
- _id: string;
161
- userId: string;
162
- name: string;
163
- email: string;
164
- /**
165
- * What the owner is called after their name on the contact list: their
166
- * "Blk 1/Level 1/Unit 1" when they live here, and their membership type -
167
- * "Security Agency" - when they do not. "" only when the site knows neither.
168
- *
169
- * Optional because an API still on the `@7365admin1/core` release that
170
- * predates it answers without the field; the contact picker falls back to the
171
- * bare name rather than showing a dangling separator.
172
- */
173
- unitLabel?: string;
174
- extension: string;
175
- username: string;
176
- status: string;
177
- provisionedAt: string;
178
- };
179
-
180
142
  /**
181
143
  * True only for the specific validation error an API that predates core #1878
182
144
  * returns when the discover body carries `site`. Deliberately narrow: after
@@ -204,36 +166,6 @@ export default function useHidAmico() {
204
166
  });
205
167
  }
206
168
 
207
- /**
208
- * The signed-in member's own QR code on one reader.
209
- *
210
- * No user id in the path: the server takes the caller from the session, so
211
- * these cannot be pointed at somebody else. `assigned` in the response says
212
- * whether the HID permissions screen actually admits this member to the
213
- * reader - issuing a code does not grant access, and the screen has to be
214
- * able to say so.
215
- */
216
- function getProfileQr(readerId: string) {
217
- return useNuxtApp().$api<{ data: HidProfileQr }>(
218
- `${basePath}/readers/${readerId}/profile-qr`,
219
- { method: "GET" },
220
- );
221
- }
222
-
223
- function issueProfileQr(readerId: string) {
224
- return useNuxtApp().$api<{ data: HidProfileQr }>(
225
- `${basePath}/readers/${readerId}/profile-qr`,
226
- { method: "POST" },
227
- );
228
- }
229
-
230
- function deleteProfileQr(readerId: string) {
231
- return useNuxtApp().$api<{ data: HidProfileQr }>(
232
- `${basePath}/readers/${readerId}/profile-qr`,
233
- { method: "DELETE" },
234
- );
235
- }
236
-
237
169
  function createReader(payload: HidReaderPayload) {
238
170
  return useNuxtApp().$api<HidApiRecord>(`${basePath}/readers`, {
239
171
  method: "POST",
@@ -325,36 +257,6 @@ export default function useHidAmico() {
325
257
  });
326
258
  }
327
259
 
328
- /**
329
- * Which credentials a reader accepts at the door.
330
- *
331
- * Separate from `setReaderConfiguration` on purpose. That one is the generic
332
- * configuration endpoint, gated by an allowlist of writable objects; this is
333
- * a dedicated route that validates the four methods against the reader's own
334
- * `capabilities` and confirms the write by reading the device back, so a
335
- * refusal here names the credential the hardware would not take.
336
- */
337
- function setReaderIdentificationMethods(readerId: string, payload: HidApiRecord) {
338
- return useNuxtApp().$api<HidApiRecord>(
339
- `${basePath}/readers/${readerId}/identification-methods`,
340
- { method: "PUT", body: payload },
341
- );
342
- }
343
-
344
- /**
345
- * Put a reader back to the settings iService holds for it.
346
- *
347
- * A POST rather than a GET because it WRITES: reading the reader's
348
- * configuration is only the first half, and anything that drifted is
349
- * re-applied before this returns.
350
- */
351
- function reconcileReaderIdentificationMethods(readerId: string) {
352
- return useNuxtApp().$api<HidApiRecord>(
353
- `${basePath}/readers/${readerId}/identification-methods/reconcile`,
354
- { method: "POST" },
355
- );
356
- }
357
-
358
260
  function getIdentities(readerId: string, query: HidApiRecord = {}) {
359
261
  return useNuxtApp().$api<HidApiRecord>(`${basePath}/readers/${readerId}/identities`, {
360
262
  method: "GET",
@@ -512,27 +414,6 @@ export default function useHidAmico() {
512
414
  );
513
415
  }
514
416
 
515
- function getUserPasswordStatus(readerId: string, hidUserId: string | number) {
516
- return useNuxtApp().$api<HidApiRecord>(
517
- `${basePath}/readers/${readerId}/users/${hidUserId}/password`,
518
- { method: "GET" },
519
- );
520
- }
521
-
522
- function setUserPassword(readerId: string, hidUserId: string | number, password: string) {
523
- return useNuxtApp().$api<HidApiRecord>(
524
- `${basePath}/readers/${readerId}/users/${hidUserId}/password`,
525
- { method: "PUT", body: { password } },
526
- );
527
- }
528
-
529
- function deleteUserPassword(readerId: string, hidUserId: string | number) {
530
- return useNuxtApp().$api<HidApiRecord>(
531
- `${basePath}/readers/${readerId}/users/${hidUserId}/password`,
532
- { method: "DELETE" },
533
- );
534
- }
535
-
536
417
  function deleteUserPin(readerId: string, hidUserId: string | number) {
537
418
  return useNuxtApp().$api<{ data: { pinEnrolled: boolean } }>(
538
419
  `${basePath}/readers/${readerId}/users/${hidUserId}/pin`,
@@ -593,36 +474,6 @@ export default function useHidAmico() {
593
474
  );
594
475
  }
595
476
 
596
- function getSipAccounts(siteId: string, orgId: string) {
597
- return useNuxtApp().$api<{ data: HidSipAccountListItem[] }>(
598
- `${basePath}/sites/${siteId}/intercom/sip-accounts`,
599
- { method: "GET", query: { orgId } },
600
- );
601
- }
602
-
603
- /**
604
- * Wake the resident's phone for a call the web phone has just placed.
605
- *
606
- * The SIP INVITE is the call and travels over the WebSocket, not through the
607
- * API; this only rings the resident's mobile so somebody is there to answer
608
- * it. It is therefore fired after the INVITE and never awaited in a way that
609
- * could fail the call — see `startWebCall` in `HidIntercomManagement.vue`.
610
- *
611
- * `notified: false` with a reason is a normal response, not an error: staff
612
- * extensions and external SIP addresses have no resident behind them.
613
- */
614
- function notifyIntercomCall(
615
- siteId: string,
616
- payload: { orgId: string; destination: string; callId: string; readerId?: string },
617
- ) {
618
- return useNuxtApp().$api<{
619
- data: { notified: boolean; delivered?: number; reason?: string };
620
- }>(
621
- `${basePath}/sites/${siteId}/intercom/notify-call`,
622
- { method: "POST", body: payload },
623
- );
624
- }
625
-
626
477
  function getPermissionCandidates(
627
478
  siteId: string,
628
479
  query: {
@@ -654,9 +505,6 @@ export default function useHidAmico() {
654
505
 
655
506
  return {
656
507
  getReaders,
657
- getProfileQr,
658
- issueProfileQr,
659
- deleteProfileQr,
660
508
  discoverReader,
661
509
  createReader,
662
510
  updateReader,
@@ -671,8 +519,6 @@ export default function useHidAmico() {
671
519
  issueVisitorQr,
672
520
  getReaderConfiguration,
673
521
  setReaderConfiguration,
674
- setReaderIdentificationMethods,
675
- reconcileReaderIdentificationMethods,
676
522
  getLogs,
677
523
  setUserImage,
678
524
  deleteUserImage,
@@ -684,9 +530,6 @@ export default function useHidAmico() {
684
530
  getUserPinStatus,
685
531
  setUserPin,
686
532
  deleteUserPin,
687
- getUserPasswordStatus,
688
- setUserPassword,
689
- deleteUserPassword,
690
533
  getIdentities,
691
534
  getReaderUsers,
692
535
  getReaderAccessLogs,
@@ -697,8 +540,6 @@ export default function useHidAmico() {
697
540
  makeIntercomCall,
698
541
  finalizeIntercomCall,
699
542
  ensureSipAccount,
700
- getSipAccounts,
701
- notifyIntercomCall,
702
543
  getSitePermissions,
703
544
  getPermissionCandidates,
704
545
  updateSitePermissions,
@@ -46,33 +46,9 @@ export default function useHidNavigation() {
46
46
  },
47
47
  },
48
48
  {
49
- // "HID Reader Users" now points at `access-mgmt/administrator`, not at
50
- // `access-mgmt/hid-users`.
51
- //
52
- // Both routes mount a roster of the reader's users, but only this one
53
- // can act on them. `administrator` renders HidUserEnrollment WITHOUT
54
- // `card-management`, and that prop is what gates the Enroll action:
55
- // <template v-if="!props.cardManagement" #actions>
56
- // `hid-users` renders HidReaderUserRoster, which is read-only apart
57
- // from PIN management. So the menu entry with this name used to lead
58
- // to the screen that cannot enrol, while the screen that can was
59
- // reachable only by typing the URL.
60
- //
61
- // `hid-users` is left in place and simply unlisted - the same state
62
- // `administrator` was in - so any existing link to it still resolves.
63
49
  title: "HID Reader Users",
64
50
  route: {
65
- name: "org-site-access-mgmt-administrator",
66
- params: { org, site },
67
- },
68
- },
69
- {
70
- // The signed-in member's own pass, not somebody else's. Every other
71
- // entry in this group acts on a resident or a visitor; this one has
72
- // no subject but the caller.
73
- title: "HID QR Code",
74
- route: {
75
- name: "org-site-access-mgmt-hid-qr-code",
51
+ name: "org-site-access-mgmt-hid-users",
76
52
  params: { org, site },
77
53
  },
78
54
  },
@@ -115,24 +115,6 @@ export default function () {
115
115
  });
116
116
  }
117
117
 
118
- /**
119
- * The blocks, levels and units at a site that actually have an occupant.
120
- * The other half of the unit picker: this narrows the cascade, then
121
- * `getPeopleByUnit` answers "which person in this unit?".
122
- */
123
- async function getOccupiedStructure(
124
- site: string,
125
- { type = "", status = "active", block = "", level = "" } = {}
126
- ) {
127
- return await useNuxtApp().$api<Record<string, any>>(
128
- `/api/people/site/${site}/occupied-structure`,
129
- {
130
- method: "GET",
131
- query: { type, status, block, level },
132
- }
133
- );
134
- }
135
-
136
118
  async function getPeopleByUnit(
137
119
  _id: string,
138
120
  { status = "active", type = "" } = {}
@@ -166,7 +148,6 @@ export default function () {
166
148
  findPersonByPlateNumberMultipleResult,
167
149
  findPersonByContact,
168
150
  getPeopleByUnit,
169
- getOccupiedStructure,
170
151
  searchCompanyList,
171
152
  findUsersByPlateNumber,
172
153
  reviewResidentPerson,
@@ -42,7 +42,6 @@ export default function usePropertyPermission() {
42
42
  siteSettingsPermissions,
43
43
 
44
44
  inventoryPermissions,
45
- robotPermissions,
46
45
  } = useCommonPermissions();
47
46
 
48
47
 
@@ -580,23 +579,6 @@ export default function usePropertyPermission() {
580
579
  description:
581
580
  "Allows the user to view the list of all passes and keys on mobile. Checked by the iMA365 mobile app.",
582
581
  },
583
- // DV-0396: the same three writes Security offers, enforced by API-core on
584
- // /api/keys and /api/qr-code-templates for every app that calls them.
585
- "add-passes-and-keys": {
586
- check: true,
587
- description:
588
- "Allows the user to add pass templates and to create or generate passes and keys.",
589
- },
590
- "update-passes-and-keys": {
591
- check: true,
592
- description:
593
- "Allows the user to edit pass templates, passes and keys, restore them, and change a pass or key back to Available.",
594
- },
595
- "delete-passes-and-keys": {
596
- check: true,
597
- description:
598
- "Allows the user to delete pass templates, passes and keys.",
599
- },
600
582
  },
601
583
  "online-forms": {
602
584
  "see-all-online-forms": {
@@ -619,7 +601,6 @@ export default function usePropertyPermission() {
619
601
  "Allows the user to view the list of all resident transactions on mobile. Checked by the iMA365 mobile app.",
620
602
  },
621
603
  },
622
- "robot-mgmt": robotPermissions,
623
604
  "site-settings": siteSettingsPermissions
624
605
  };
625
606
 
@@ -669,31 +669,12 @@ export default function useSecurityPermission() {
669
669
  },
670
670
  // Property's descriptions minus its "Checked by the iMA365 mobile app."
671
671
  // sentence, which is not true of this application.
672
- // Add / update / delete (DV-0396), also offered by Property Management and
673
- // enforced by API-core on /api/keys and /api/qr-code-templates. The security web app's
674
- // Templates and Passes & Keys pages and the guard app's pass & key screen
675
- // read them. See All is also what shows those two web pages.
676
672
  "passes-and-keys-mgmt": {
677
673
  "see-all-passes-and-keys": {
678
674
  check: true,
679
675
  description:
680
676
  "Allows the user to view the list of all passes and keys on mobile.",
681
677
  },
682
- "add-passes-and-keys": {
683
- check: true,
684
- description:
685
- "Allows the user to add pass templates and to create or generate passes and keys.",
686
- },
687
- "update-passes-and-keys": {
688
- check: true,
689
- description:
690
- "Allows the user to edit pass templates, passes and keys, restore them, and change a pass or key back to Available.",
691
- },
692
- "delete-passes-and-keys": {
693
- check: true,
694
- description:
695
- "Allows the user to delete pass templates, passes and keys.",
696
- },
697
678
  },
698
679
  "resident-transactions": {
699
680
  "see-all-resident-transactions": {
@@ -58,8 +58,6 @@ export default function useServiceProvider() {
58
58
  orgId = "",
59
59
  siteId = "",
60
60
  status = "",
61
- /** "engagements": also providers engaged through an accepted invitation. */
62
- include = "",
63
61
  } = {}) {
64
62
  return useNuxtApp().$api<Record<string, any>>("/api/service-providers", {
65
63
  method: "GET",
@@ -71,7 +69,6 @@ export default function useServiceProvider() {
71
69
  orgId,
72
70
  siteId,
73
71
  ...(status ? { status } : {}),
74
- ...(include ? { include } : {}),
75
72
  },
76
73
  });
77
74
  }
@@ -18,21 +18,6 @@ export type TServiceProviderInvitation = {
18
18
  expireAt?: string;
19
19
  deletedAt?: string | null;
20
20
  metadata?: Record<string, any>;
21
- /** A lapsed "pending" reads "expired"; `status` stays the stored value. */
22
- viewStatus?: string;
23
- /** The company that accepted it, or the new company's name (sign-up). */
24
- companyName?: string;
25
- providerOrgId?: string;
26
- service?: string;
27
- invitedByName?: string;
28
- invitedAt?: string | null;
29
- /** When it was accepted, declined, cancelled or expired. */
30
- answeredAt?: string | null;
31
- /** Shown only once accepted. */
32
- contactEmail?: string;
33
- contactPhone?: string;
34
- /** Accepted and still engaged on the site. */
35
- onSite?: boolean;
36
21
  history?: Array<{
37
22
  action: string;
38
23
  at: string;
@@ -41,32 +26,6 @@ export type TServiceProviderInvitation = {
41
26
  }>;
42
27
  };
43
28
 
44
- /** One card of "Client invitations" (the service provider's side). */
45
- export type TReceivedServiceProviderInvitation = {
46
- _id: string;
47
- /** The client organisation that sent it. */
48
- orgName: string;
49
- siteName: string;
50
- siteId?: string;
51
- /** The service asked for, when the sender recorded one (e.g. "security"). */
52
- service?: string;
53
- invitedByName?: string;
54
- createdAt?: string;
55
- expireAt?: string;
56
- /** When it was accepted, declined or withdrawn. */
57
- answeredAt?: string | null;
58
- /** pending | complete | declined | expired | cancelled */
59
- status: string;
60
- statusLabel: string;
61
- /** The company that accepted it (whose Sites list gained the site). */
62
- providerOrgId?: string;
63
- providerOrgName?: string;
64
- /** Accepted AND on the Sites list of the company on screen. */
65
- onThisOrg?: boolean;
66
- /** Accepted, but the site is on no company's Sites list: offer to add it. */
67
- needsSiteLink?: boolean;
68
- };
69
-
70
29
  /** The words on screen. Kept beside the server's own list on purpose — a
71
30
  * status the server invents must never render as a raw stored value. */
72
31
  export const SERVICE_PROVIDER_INVITE_LABELS: Record<string, string> = {
@@ -88,9 +47,7 @@ export default function useServiceProviderInvitation() {
88
47
 
89
48
  function getInvitations({
90
49
  org = "",
91
- siteId = "",
92
50
  status = "",
93
- search = "",
94
51
  page = 1,
95
52
  limit = 20,
96
53
  } = {}): Promise<{
@@ -100,14 +57,7 @@ export default function useServiceProviderInvitation() {
100
57
  }> {
101
58
  return useNuxtApp().$api(base, {
102
59
  method: "GET",
103
- query: {
104
- org,
105
- status,
106
- page,
107
- limit,
108
- ...(siteId ? { siteId } : {}),
109
- ...(search ? { search } : {}),
110
- },
60
+ query: { org, status, page, limit },
111
61
  });
112
62
  }
113
63
 
@@ -170,14 +120,8 @@ export default function useServiceProviderInvitation() {
170
120
 
171
121
  // ---- the invited service provider ----------------------------------------
172
122
 
173
- function getInvitation(
174
- id: string,
175
- org?: string,
176
- ): Promise<TReceivedServiceProviderInvitation & { tab?: string | null }> {
177
- return useNuxtApp().$api(`${base}/${id}`, {
178
- method: "GET",
179
- query: org ? { org } : {},
180
- });
123
+ function getInvitation(id: string): Promise<TServiceProviderInvitation> {
124
+ return useNuxtApp().$api(`${base}/${id}`, { method: "GET" });
181
125
  }
182
126
 
183
127
  function declineInvitation(id: string) {
@@ -186,45 +130,6 @@ export default function useServiceProviderInvitation() {
186
130
  });
187
131
  }
188
132
 
189
- /**
190
- * Adds the site to `org`'s Sites list - the company on screen, which the
191
- * server checks the invited account belongs to.
192
- */
193
- function acceptInvitation(id: string, org?: string) {
194
- return useNuxtApp().$api<{ message: string }>(`${base}/${id}/accept`, {
195
- method: "PUT",
196
- body: org ? { org } : {},
197
- });
198
- }
199
-
200
- /**
201
- * An accepted invitation whose site never reached this company's Sites
202
- * list: add it now. Safe to repeat - the server adds it once.
203
- */
204
- function linkInvitationSite(id: string, org: string) {
205
- return useNuxtApp().$api<{ message: string }>(`${base}/${id}/link-site`, {
206
- method: "PUT",
207
- body: { org },
208
- });
209
- }
210
-
211
- /**
212
- * "Client invitations": one tab of the invitations sent to the signed-in
213
- * account, plus the count in every tab. `org` is the company on screen.
214
- */
215
- function getReceivedInvitations({
216
- org,
217
- status = "pending",
218
- }: { org?: string; status?: string } = {}): Promise<{
219
- items: TReceivedServiceProviderInvitation[];
220
- counts?: Record<string, number>;
221
- }> {
222
- return useNuxtApp().$api(`${base}/received`, {
223
- method: "GET",
224
- query: { status, ...(org ? { org } : {}) },
225
- });
226
- }
227
-
228
133
  return {
229
134
  getInvitations,
230
135
  cancelInvitation,
@@ -236,8 +141,5 @@ export default function useServiceProviderInvitation() {
236
141
  rejectInvitation,
237
142
  getInvitation,
238
143
  declineInvitation,
239
- acceptInvitation,
240
- linkInvitationSite,
241
- getReceivedInvitations,
242
144
  };
243
145
  }
@@ -27,35 +27,9 @@ export default function useSiteEntryPassSettings() {
27
27
  );
28
28
  }
29
29
 
30
- /**
31
- * The encrypted ACM URL the access-card screens hand to API-core, which
32
- * decrypts it and sends the ACM commands to that host.
33
- *
34
- * Resolves the site's own "Enter entrypass URL" setting first, the way
35
- * `VisitorForm` does for contractor passes. The access-card forms used to
36
- * call `/api/encrypt-acm-url` with no `url`, so every site's door/lift
37
- * levels and access groups came from the route's hardcoded default host
38
- * whatever the site had configured. A site with no URL set, or whose
39
- * settings cannot be read, still gets that default.
40
- */
41
- async function getEncryptedAcmUrl(siteId: string): Promise<string> {
42
- let rawUrl = "";
43
- try {
44
- const settings: any = await getBySiteId(siteId);
45
- rawUrl = String(settings?.data?.settings?.url ?? "").trim();
46
- } catch {
47
- // No entry pass settings for this site yet - the default host applies.
48
- }
49
- const { encrypted } = await $fetch<{ encrypted: string }>(
50
- `/api/encrypt-acm-url${rawUrl ? `?url=${encodeURIComponent(rawUrl)}` : ""}`,
51
- );
52
- return encrypted;
53
- }
54
-
55
30
  return {
56
31
  getBySiteId,
57
32
  getById,
58
33
  save,
59
- getEncryptedAcmUrl,
60
34
  };
61
35
  }
@@ -345,19 +345,16 @@ export default function useWebUsb() {
345
345
  70,
346
346
  );
347
347
 
348
- // The pass used to print five copies of the same QR - four 140px ones at
349
- // the corners around a 250px centre - so a strip could be cut apart. It now
350
- // prints a single large QR filling that same band (y 90 to 440, above the
351
- // company name at y 470), which scans far more reliably on a thermal print.
352
- // Generated at the size it is drawn at: the old corner copies were
353
- // downscaled from the 250px canvas, which softened their modules.
354
- const qrSize = 350;
355
- const qrCanvas = await QRCode.toCanvas(qrUrlImage, {
356
- width: qrSize,
357
- margin: 1,
358
- });
348
+ const qrSmall = 140;
349
+ const qrCenter = 250;
350
+ const margin = 20;
351
+ const qrCanvas = await QRCode.toCanvas(qrUrlImage, { width: qrCenter });
359
352
 
360
- ctx.drawImage(qrCanvas, (canvas.width - qrSize) / 2, 90, qrSize, qrSize);
353
+ ctx.drawImage(qrCanvas, margin, 90, qrSmall, qrSmall);
354
+ ctx.drawImage(qrCanvas, canvas.width - qrSmall - margin, 90, qrSmall, qrSmall);
355
+ ctx.drawImage(qrCanvas, (canvas.width - qrCenter) / 2, 110, qrCenter, qrCenter);
356
+ ctx.drawImage(qrCanvas, margin, 300, qrSmall, qrSmall);
357
+ ctx.drawImage(qrCanvas, canvas.width - qrSmall - margin, 300, qrSmall, qrSmall);
361
358
 
362
359
  ctx.font = "25px Arial";
363
360
  ctx.fillText(companyName || "", canvas.width / 2, 470);
@@ -404,8 +401,8 @@ export default function useWebUsb() {
404
401
  /**
405
402
  * The self-service onboarding QR: one large QR code, a "SCAN QR CODE"-style
406
403
  * subtext, and a dark site-name banner along the bottom - a single-purpose
407
- * gate sign, not the visitor-pass receipt `createReceiptLayout` produces
408
- * (that one pairs its QR with company, date, access and instruction lines).
404
+ * gate sign, not the multi-copy visitor-pass receipt `createReceiptLayout`
405
+ * produces (that one prints several QRs to be cut apart and handed out).
409
406
  */
410
407
  async function createOnboardingQrLayout(
411
408
  qrUrlImage: string,
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.35.1-staging.385",
5
+ "version": "4.37.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.",
@@ -36,7 +36,7 @@
36
36
  "build": "nuxt build .playground",
37
37
  "generate": "nuxt generate .playground",
38
38
  "preview": "nuxt preview .playground",
39
- "test": "esbuild composables/useANPRSettings.ts --format=esm --outfile=test/.build/useANPRSettings.mjs --log-level=error && esbuild composables/useVisitorSocket.ts --format=esm --outfile=test/.build/useVisitorSocket.mjs --log-level=error && esbuild composables/usePlateToastWindow.ts --format=esm --outfile=test/.build/usePlateToastWindow.mjs --log-level=error && esbuild utils/client-invite-modules.ts --bundle --platform=node --format=esm --outfile=test/.build/client-invite-modules.mjs --log-level=error && esbuild utils/robot-display.ts --bundle --platform=node --format=esm --outfile=test/.build/robot-display.mjs --log-level=error && esbuild utils/building-map.ts --bundle --platform=node --format=esm --outfile=test/.build/building-map.mjs --log-level=error && esbuild utils/robot-building.ts --bundle --platform=node --format=esm --outfile=test/.build/robot-building.mjs --log-level=error && esbuild utils/robot-fleet-core.ts --bundle --platform=node --format=esm --outfile=test/.build/robot-fleet-core.mjs --log-level=error && node --experimental-strip-types --test \"test/*.test.mjs\" && yarn test:units",
39
+ "test": "esbuild composables/useVisitorSocket.ts --format=esm --outfile=test/.build/useVisitorSocket.mjs --log-level=error && esbuild composables/usePlateToastWindow.ts --format=esm --outfile=test/.build/usePlateToastWindow.mjs --log-level=error && esbuild utils/client-invite-modules.ts --bundle --platform=node --format=esm --outfile=test/.build/client-invite-modules.mjs --log-level=error && esbuild utils/robot-display.ts --bundle --platform=node --format=esm --outfile=test/.build/robot-display.mjs --log-level=error && esbuild utils/building-map.ts --bundle --platform=node --format=esm --outfile=test/.build/building-map.mjs --log-level=error && esbuild utils/robot-building.ts --bundle --platform=node --format=esm --outfile=test/.build/robot-building.mjs --log-level=error && esbuild utils/robot-fleet-core.ts --bundle --platform=node --format=esm --outfile=test/.build/robot-fleet-core.mjs --log-level=error && node --experimental-strip-types --test \"test/*.test.mjs\" && yarn test:units",
40
40
  "test:units": "node --experimental-strip-types --test \"utils/*.test.ts\"",
41
41
  "release": "yarn run build && changeset publish"
42
42
  },
@@ -5,7 +5,7 @@
5
5
  :org="orgId"
6
6
  message="Enable HID as a service for this site before managing HID users."
7
7
  >
8
- <HidUserEnrollment :site="siteId" :org="orgId" />
8
+ <HidUserEnrollment :site="siteId" />
9
9
  </HidEnabledGate>
10
10
  </v-container>
11
11
  </template>
@@ -5,7 +5,7 @@
5
5
  :org="orgId"
6
6
  message="Enable HID as a service for this site before managing physical HID cards."
7
7
  >
8
- <HidUserEnrollment :site="siteId" :org="orgId" card-management />
8
+ <HidUserEnrollment :site="siteId" card-management />
9
9
  </HidEnabledGate>
10
10
  </v-container>
11
11
  </template>
@@ -5,7 +5,7 @@
5
5
  :org="orgId"
6
6
  message="Enable HID as a service for this site before managing HID readers."
7
7
  >
8
- <HidReaderManagement :site="siteId" :org="orgId" />
8
+ <HidReaderManagement :site="siteId" />
9
9
  </HidEnabledGate>
10
10
  </v-container>
11
11
  </template>