@7365admin1/layer-common 3.0.25 → 3.0.27

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.
@@ -17,18 +17,16 @@
17
17
  class="mb-3"
18
18
  />
19
19
 
20
- <template v-if="mode === 'add'">
21
- <div class="field-label">Base URL / IP address <span>*</span></div>
22
- <v-text-field
23
- v-model="draft.baseUrl"
24
- aria-label="Base URL / IP address"
25
- placeholder="http://192.168.x.x."
26
- variant="outlined"
27
- density="compact"
28
- hide-details="auto"
29
- class="mb-3"
30
- />
31
- </template>
20
+ <div class="field-label">Base URL / IP address <span>*</span></div>
21
+ <v-text-field
22
+ v-model="draft.baseUrl"
23
+ aria-label="Base URL / IP address"
24
+ placeholder="https://your domain URL"
25
+ variant="outlined"
26
+ density="compact"
27
+ hide-details="auto"
28
+ class="mb-3"
29
+ />
32
30
 
33
31
  <div class="field-label">Device ID <span>*</span></div>
34
32
  <v-text-field
@@ -175,10 +173,6 @@ function submit() {
175
173
  status: monitorEnabled.value ? "active" : "inactive",
176
174
  };
177
175
 
178
- if (props.mode === "edit") {
179
- delete payload.baseUrl;
180
- }
181
-
182
176
  emit("submit", payload);
183
177
  }
184
178
  </script>
@@ -859,12 +859,32 @@ function getFriendlyHidError(error: any) {
859
859
  return "Unable to verify the HID reader session. Please check the reader username and password, then try again.";
860
860
  }
861
861
 
862
+ if (
863
+ message.includes("status 401") ||
864
+ message.includes("401 Authorization Required") ||
865
+ lowerMessage.includes("authorization required")
866
+ ) {
867
+ return "Unable to authorize the HID gateway connection. Please check the relay credentials on the server, then try again.";
868
+ }
869
+
870
+ if (message.includes("status 403") || lowerMessage.includes("forbidden")) {
871
+ return "The HID gateway rejected this request. Please check the relay access permissions and try again.";
872
+ }
873
+
874
+ if (message.includes("status 404") || lowerMessage.includes("not found")) {
875
+ return "The HID gateway endpoint could not be found. Please check the reader Base URL and try again.";
876
+ }
877
+
878
+ if (lowerMessage.includes("<html") || lowerMessage.includes("<!doctype")) {
879
+ return "The HID gateway returned an unexpected response. Please check the relay configuration and try again.";
880
+ }
881
+
862
882
  if (message.includes("reader is not active")) {
863
883
  return "This HID reader is not active. Please enable the reader before syncing.";
864
884
  }
865
885
 
866
886
  if (message.includes("HID Amico request failed:")) {
867
- return message;
887
+ return "The HID device rejected the request. Please check the reader connection and try again.";
868
888
  }
869
889
 
870
890
  return message || "The HID device rejected the request. Please check the reader connection and try again.";
@@ -77,6 +77,22 @@
77
77
  </v-autocomplete>
78
78
  </v-col>
79
79
 
80
+ <v-col v-if="props.unitId" cols="12">
81
+ <EntryPassInformation
82
+ v-model="memberPassType"
83
+ v-model:quantity="memberPassQuantity"
84
+ v-model:cards="memberPassCards"
85
+ :settings="props.settings"
86
+ :loading="props.settingsLoading"
87
+ :site-id="props.site"
88
+ :unit-id="props.unitId"
89
+ :visitor-type="props.type"
90
+ :hid-qr-code-enabled="props.hidQrCodeEnabled"
91
+ :hid-qr-printer-configured="props.hidQrPrinterConfigured"
92
+ :excluded-card-ids="props.selectedNfcCards.map((c) => c._id)"
93
+ />
94
+ </v-col>
95
+
80
96
  <v-col cols="12">
81
97
  <InputLabel
82
98
  class="text-capitalize"
@@ -164,6 +180,30 @@ const props = defineProps({
164
180
  type: Boolean,
165
181
  default: false,
166
182
  },
183
+ settings: {
184
+ type: Object as PropType<Record<string, any> | null>,
185
+ default: null,
186
+ },
187
+ settingsLoading: {
188
+ type: Boolean,
189
+ default: false,
190
+ },
191
+ unitId: {
192
+ type: String as PropType<string | null>,
193
+ default: null,
194
+ },
195
+ hidQrCodeEnabled: {
196
+ type: Boolean,
197
+ default: false,
198
+ },
199
+ hidQrPrinterConfigured: {
200
+ type: Boolean,
201
+ default: false,
202
+ },
203
+ selectedNfcCards: {
204
+ type: Array as PropType<{ _id: string; cardNo: string }[]>,
205
+ default: () => [],
206
+ },
167
207
  });
168
208
 
169
209
  const { requiredRule } = useUtils();
@@ -201,6 +241,9 @@ const dialog = reactive({
201
241
  });
202
242
 
203
243
  const selectedPass = ref<string>("");
244
+ const memberPassType = ref<string | null>(null);
245
+ const memberPassQuantity = ref<number | null>(1);
246
+ const memberPassCards = ref<{ _id: string; cardNo: string }[]>([]);
204
247
 
205
248
  const members = defineModel<TMemberInfo[]>({ required: true, default: [] });
206
249
  const committedMembers = ref<TMemberInfo[]>([]);
@@ -303,12 +346,27 @@ watch(scannedPassValue, (newVal) => {
303
346
  showMessage("Scanned pass not available", "error");
304
347
  });
305
348
 
349
+ function resetAccessCard() {
350
+ memberPassType.value = null;
351
+ memberPassQuantity.value = 1;
352
+ memberPassCards.value = [];
353
+ }
354
+
306
355
  function handleClearForm() {
307
356
  formRef.value?.reset();
357
+ resetAccessCard();
308
358
  }
309
359
 
310
360
  async function handleAddMember() {
311
- committedMembers.value.push({ ...memberForm });
361
+ committedMembers.value.push({
362
+ ...memberForm,
363
+ ...(memberPassType.value ? {
364
+ passType: memberPassType.value,
365
+ passQuantity: memberPassQuantity.value,
366
+ passCards: memberPassCards.value,
367
+ } : {}),
368
+ } as any);
369
+ resetAccessCard();
312
370
  handleClearForm();
313
371
  }
314
372
 
@@ -145,11 +145,6 @@
145
145
  </template>
146
146
 
147
147
  <script setup lang="ts">
148
- import {
149
- getPermissionCount,
150
- updateRolePermissionsInList,
151
- } from "../utils/rolePermissionCounts";
152
-
153
148
  const props = defineProps({
154
149
  orgId: {
155
150
  type: String,
@@ -270,10 +265,22 @@ const selectedPermissions = ref<Array<string>>([]);
270
265
  const originalPermissions = ref<Array<string>>([]);
271
266
  const edit = ref(false);
272
267
 
273
- const { convertPermissionsToArray } = useUtils();
274
-
275
268
  const roleId = ref("");
276
269
 
270
+ function getPermissionCount(permissions: unknown): number {
271
+ return Array.isArray(permissions) ? permissions.length : 0;
272
+ }
273
+
274
+ function updateRolePermissionsInList(
275
+ roles: Array<Record<string, any>>,
276
+ roleId: string,
277
+ permissions: string[]
278
+ ) {
279
+ return roles.map((role) =>
280
+ role._id === roleId ? { ...role, permissions } : role
281
+ );
282
+ }
283
+
277
284
  const { getRoleById: _getRoleById, deleteRole } = useRole();
278
285
 
279
286
  const { data: role, refresh: getRoleById } = useLazyAsyncData(
@@ -340,7 +347,6 @@ function successfulUpdate() {
340
347
  savedPermissions
341
348
  );
342
349
  void refreshRolesAfterUpdate(savedPermissions);
343
- useLocalSetup(props.type);
344
350
  }
345
351
 
346
352
  async function refreshRolesAfterUpdate(savedPermissions: string[]) {
@@ -371,7 +371,9 @@ function show(message: string, color: string) {
371
371
  }
372
372
 
373
373
  // ANPR Settings
374
- const { getANPRSettingBySite, createUpdateANPRSettings } = useANPRSettings();
374
+ const { getANPRSettingBySite, createUpdateANPRSettings } = useANPRSettings(
375
+ props.siteId
376
+ );
375
377
  const isSaving = ref(false);
376
378
 
377
379
  // Reactive object to hold the state of the 3 switches
@@ -204,12 +204,17 @@
204
204
  v-model:cards="passCards" :settings="entryPassSettings"
205
205
  :loading="entryPassSettingsPending || siteDataPending" :site-id="prop.site"
206
206
  :unit-id="visitor.unit || null" :visitor-type="prop.type" :hid-qr-code-enabled="hidQrCodePassAllowed"
207
- :hid-qr-printer-configured="hasHidQrPrinterConfig" />
207
+ :hid-qr-printer-configured="hasHidQrPrinterConfig"
208
+ @update:available-qr-count="(val) => availableQrCount = val" />
208
209
  </v-col>
209
210
 
210
211
  <v-col v-show="withStep3 && contractorStep === 3" cols="12">
211
212
  <MemberInformation v-model="visitor.members" :type="prop.type" :contractor-type="visitor.contractorType"
212
- :site="prop.site" :selected-visitor-pass="visitor.visitorPass" :clearable="true" />
213
+ :site="prop.site" :selected-visitor-pass="visitor.visitorPass" :clearable="true"
214
+ :settings="entryPassSettings" :settings-loading="entryPassSettingsPending || siteDataPending"
215
+ :unit-id="visitor.unit || null"
216
+ :hid-qr-code-enabled="hidQrCodePassAllowed" :hid-qr-printer-configured="hasHidQrPrinterConfig"
217
+ :selected-nfc-cards="passType === 'NFC' ? passCards : []" />
213
218
  </v-col>
214
219
 
215
220
  <v-col v-if="prop.mode === 'add'" cols="12" class="mt-2">
@@ -394,6 +399,7 @@ const visitor = reactive<Partial<TVisitorPayload>>({
394
399
  const passType = ref<string | null>(null);
395
400
  const passQuantity = ref<number | null>(1);
396
401
  const passCards = ref<{ _id: string; cardNo: string }[]>([]);
402
+ const availableQrCount = ref<number | null>(null);
397
403
  const hidQrPrintPayload = ref<string | null>(null);
398
404
  const hidQrPrinted = ref(false);
399
405
 
@@ -628,10 +634,10 @@ function selectNricSearchResult(item: Partial<TPeople>) {
628
634
  if (!visitor.company) {
629
635
  visitor.company = companyNames.value?.[0] || visitor.company;
630
636
  }
631
- visitor.block = (item.block as any) ?? (visitor.block as any) ?? "";
632
- visitor.level = (item.level as any) ?? (visitor.level as any) ?? "";
633
- visitor.unit = item.unit ?? visitor.unit ?? "";
634
- visitor.unitName = item.unitName ?? visitor.unitName;
637
+ // visitor.block = (item.block as any) ?? (visitor.block as any) ?? "";
638
+ // visitor.level = (item.level as any) ?? (visitor.level as any) ?? "";
639
+ // visitor.unit = item.unit ?? visitor.unit ?? "";
640
+ // visitor.unitName = item.unitName ?? visitor.unitName;
635
641
 
636
642
  setTimeout(() => {
637
643
  currentAutofillSource.value = null;
@@ -990,6 +996,20 @@ async function handleNextPage() {
990
996
  return;
991
997
  }
992
998
  const step = contractorStep.value;
999
+ if (step === 2 && passType.value === "QR") {
1000
+ if (availableQrCount.value === null) {
1001
+ errorMessage.value = "Please wait while QR passes are being generated...";
1002
+ return;
1003
+ }
1004
+ if (availableQrCount.value === 0) {
1005
+ errorMessage.value = "No QR passes available. Add a non-physical card to this unit in Access Management first.";
1006
+ return;
1007
+ }
1008
+ }
1009
+ if (step === 2 && passType.value === "NFC" && passCards.value.length === 0) {
1010
+ errorMessage.value = "Please select at least one NFC card before proceeding.";
1011
+ return;
1012
+ }
993
1013
  if (step < 3) contractorStep.value++;
994
1014
  else await submit();
995
1015
  }
@@ -1098,7 +1118,15 @@ async function submit() {
1098
1118
  type: passType.value === "QR" ? "QRCODE" : passType.value,
1099
1119
  nfcCards: passCards.value,
1100
1120
  acm_url: acmUrl,
1101
- visitorId,
1121
+ user: {
1122
+ visitorId,
1123
+ name: visitor.name,
1124
+ nric: visitor.nric,
1125
+ contact: visitor.contact,
1126
+ company: visitor.company,
1127
+ type: visitor.type,
1128
+ plateNumber: visitor.plateNumber,
1129
+ },
1102
1130
  });
1103
1131
 
1104
1132
  if (passType.value === "QR") {