@7365admin1/layer-common 3.2.2-staging.180 → 3.2.2-staging.182

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.
@@ -173,7 +173,13 @@
173
173
  :style="`max-height: calc(100vh - (${offset}px))`"
174
174
  >
175
175
  <template v-for="(_, slotName) in $slots" #[slotName]="slotProps">
176
- <slot :name="slotName" v-bind="slotProps" />
176
+ <!--
177
+ Vuetify invokes argument-less slots such as `no-data` with null
178
+ props. Vue's dynamic `renderSlot` expects an object and otherwise
179
+ crashes while reading `props.key`, leaving the previous route on
180
+ screen even though Vue Router has already updated the URL.
181
+ -->
182
+ <slot :name="slotName" v-bind="slotProps ?? {}" />
177
183
  </template>
178
184
 
179
185
  <!--
@@ -60,6 +60,23 @@ type HidFacialEnrollmentResult = {
60
60
  errors?: Array<{ code?: number; message?: string }>;
61
61
  };
62
62
 
63
+ export type HidPhysicalCardType = "pacs" | "csn";
64
+
65
+ export type HidPhysicalCard = {
66
+ id: string;
67
+ value: string;
68
+ userId: number;
69
+ cardType: HidPhysicalCardType | "unknown";
70
+ facilityCode?: number;
71
+ cardNumber?: number;
72
+ source?: "manual" | "reader" | "device";
73
+ enrolledAt?: string;
74
+ };
75
+
76
+ type HidPhysicalCardInput =
77
+ | { cardType: "pacs"; facilityCode: number; cardNumber: number }
78
+ | { cardType: "csn"; cardValue: string };
79
+
63
80
  export type HidSipAccountData = {
64
81
  orgId: string;
65
82
  site: string;
@@ -194,6 +211,55 @@ export default function useHidAmico() {
194
211
  );
195
212
  }
196
213
 
214
+ function getUserCards(readerId: string, hidUserId: string | number) {
215
+ return useNuxtApp().$api<{
216
+ data: { readerId: string; hidUserId: number; cards: HidPhysicalCard[] };
217
+ }>(`${basePath}/readers/${readerId}/users/${hidUserId}/cards`, {
218
+ method: "GET",
219
+ });
220
+ }
221
+
222
+ function assignUserCard(
223
+ readerId: string,
224
+ hidUserId: string | number,
225
+ payload: HidPhysicalCardInput,
226
+ ) {
227
+ return useNuxtApp().$api<{ data: { card: HidPhysicalCard; verified: boolean } }>(
228
+ `${basePath}/readers/${readerId}/users/${hidUserId}/cards`,
229
+ { method: "POST", body: payload },
230
+ );
231
+ }
232
+
233
+ function enrollUserCard(
234
+ readerId: string,
235
+ hidUserId: string | number,
236
+ cardType: HidPhysicalCardType,
237
+ timeoutSeconds = 30,
238
+ ) {
239
+ return useNuxtApp().$api<{ data: { card: HidPhysicalCard; verified: boolean } }>(
240
+ `${basePath}/readers/${readerId}/users/${hidUserId}/cards/enroll`,
241
+ { method: "POST", body: { cardType, timeoutSeconds } },
242
+ );
243
+ }
244
+
245
+ function cancelUserCardEnrollment(readerId: string) {
246
+ return useNuxtApp().$api<{ data: { cancelled: boolean } }>(
247
+ `${basePath}/readers/${readerId}/cards/enrollment/cancel`,
248
+ { method: "POST" },
249
+ );
250
+ }
251
+
252
+ function deleteUserCard(
253
+ readerId: string,
254
+ hidUserId: string | number,
255
+ cardId: string | number,
256
+ ) {
257
+ return useNuxtApp().$api<{ data: { deleted: boolean } }>(
258
+ `${basePath}/readers/${readerId}/users/${hidUserId}/cards/${cardId}`,
259
+ { method: "DELETE" },
260
+ );
261
+ }
262
+
197
263
  function discoverReader(payload: Pick<HidReaderPayload, "baseUrl" | "username" | "password">) {
198
264
  return useNuxtApp().$api<Record<string, unknown>>(`${basePath}/readers/discover`, {
199
265
  method: "POST",
@@ -320,6 +386,11 @@ export default function useHidAmico() {
320
386
  getUserImage,
321
387
  setUserImage,
322
388
  deleteUserImage,
389
+ getUserCards,
390
+ assignUserCard,
391
+ enrollUserCard,
392
+ cancelUserCardEnrollment,
393
+ deleteUserCard,
323
394
  getUserPinStatus,
324
395
  setUserPin,
325
396
  deleteUserPin,
@@ -28,9 +28,9 @@ export default function useHidNavigation() {
28
28
  },
29
29
  },
30
30
  {
31
- title: "Administrator",
31
+ title: "HID Cards",
32
32
  route: {
33
- name: "org-site-access-mgmt-administrator",
33
+ name: "org-site-access-mgmt-hid-cards",
34
34
  params: { org, site },
35
35
  },
36
36
  },
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@7365admin1/layer-common",
3
3
  "license": "MIT",
4
4
  "type": "module",
5
- "version": "3.2.2-staging.180",
5
+ "version": "3.2.2-staging.182",
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.",
@@ -3,9 +3,9 @@
3
3
  <HidEnabledGate
4
4
  :site="siteId"
5
5
  :org="orgId"
6
- message="Enable HID as a service for this site before managing HID administrators."
6
+ message="Enable HID as a service for this site before managing HID users."
7
7
  >
8
- <HidUserEnrollment :site="siteId" identity-type="admin" />
8
+ <HidUserEnrollment :site="siteId" />
9
9
  </HidEnabledGate>
10
10
  </v-container>
11
11
  </template>
@@ -0,0 +1,23 @@
1
+ <template>
2
+ <v-container fluid>
3
+ <HidEnabledGate
4
+ :site="siteId"
5
+ :org="orgId"
6
+ message="Enable HID as a service for this site before managing physical HID cards."
7
+ >
8
+ <HidUserEnrollment :site="siteId" card-management />
9
+ </HidEnabledGate>
10
+ </v-container>
11
+ </template>
12
+
13
+ <script setup lang="ts">
14
+ definePageMeta({
15
+ layout: "default",
16
+ middleware: ["01-auth", "02-org"],
17
+ memberOnly: true,
18
+ });
19
+
20
+ const route = useRoute();
21
+ const siteId = computed(() => String(route.params.site ?? ""));
22
+ const orgId = computed(() => String(route.params.org ?? ""));
23
+ </script>