@7365admin1/layer-common 4.97.1-staging.570 → 4.97.1-staging.572
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.
|
@@ -206,6 +206,13 @@
|
|
|
206
206
|
</div>
|
|
207
207
|
</div>
|
|
208
208
|
</v-card>
|
|
209
|
+
<!-- How long the pass lasts, from the site's setting; the same words
|
|
210
|
+
as the resident app's invite form. -->
|
|
211
|
+
<div v-if="hidQrUsage" class="text-caption text-primary font-weight-medium mt-2">
|
|
212
|
+
{{ hidQrUsage === "singleUse"
|
|
213
|
+
? "HID: Single use, expires after the first entry"
|
|
214
|
+
: "HID: Valid all day, until 11:59 pm" }}
|
|
215
|
+
</div>
|
|
209
216
|
<v-alert
|
|
210
217
|
v-if="!hidPortalName"
|
|
211
218
|
type="warning"
|
|
@@ -341,6 +348,12 @@ const props = defineProps({
|
|
|
341
348
|
type: String,
|
|
342
349
|
default: "",
|
|
343
350
|
},
|
|
351
|
+
// The site's HID pass usage, for the hint under the HID QR Code card. Null
|
|
352
|
+
// shows no hint (not loaded, or a caller that does not pass it).
|
|
353
|
+
hidQrUsage: {
|
|
354
|
+
type: String as PropType<"wholeDay" | "singleUse" | null>,
|
|
355
|
+
default: null,
|
|
356
|
+
},
|
|
344
357
|
excludedCardIds: {
|
|
345
358
|
type: Array as PropType<string[]>,
|
|
346
359
|
default: () => [],
|
|
@@ -254,6 +254,7 @@
|
|
|
254
254
|
:loading="entryPassSettingsPending || siteDataPending" :site-id="prop.site"
|
|
255
255
|
:unit-id="visitor.unit || null" :visitor-type="prop.type" :hid-qr-code-enabled="hidQrCodePassAllowed"
|
|
256
256
|
:hid-qr-printer-configured="hasHidQrPrinterConfig"
|
|
257
|
+
:hid-qr-usage="hidQrUsage"
|
|
257
258
|
:hid-reader-name="hidQrReader?.name || ''"
|
|
258
259
|
:hid-portal-name="hidQrReader?.portalName || ''"
|
|
259
260
|
@update:available-qr-count="(val) => availableQrCount = val" />
|
|
@@ -622,7 +623,7 @@ import useSiteEntryPassSettings from "../composables/useSiteEntryPassSettings";
|
|
|
622
623
|
import useAccessManagement from "../composables/useAccessManagement";
|
|
623
624
|
import usePeople from "../composables/usePeople";
|
|
624
625
|
import useHidAmico from "../composables/useHidAmico";
|
|
625
|
-
import { minutesUntilEndOfDay } from "../utils/hid-qr-validity";
|
|
626
|
+
import { hidQrUsageFromSettings, minutesUntilEndOfDay } from "../utils/hid-qr-validity";
|
|
626
627
|
|
|
627
628
|
const prop = defineProps({
|
|
628
629
|
type: {
|
|
@@ -659,7 +660,7 @@ type AutofillSource = "nric" | "contact" | "vehicleNumber" | null;
|
|
|
659
660
|
const currentAutofillSource = ref<AutofillSource>(null);
|
|
660
661
|
|
|
661
662
|
const { requiredRule, debounce, UTCToLocalTIme, maskNRIC } = useUtils();
|
|
662
|
-
const { getSiteById } = useSiteSettings();
|
|
663
|
+
const { getSiteById, getOvernightParkingAvailabilityV2 } = useSiteSettings();
|
|
663
664
|
const { currentUser } = useLocalAuth();
|
|
664
665
|
const { getBlocksSelection, getLevelsSelection, getUnitSelection } =
|
|
665
666
|
useBuilding();
|
|
@@ -979,6 +980,12 @@ const hidQrCodePassAllowed = computed(() => {
|
|
|
979
980
|
);
|
|
980
981
|
});
|
|
981
982
|
|
|
983
|
+
// The site's Whole day / Single usage choice for HID visitor passes, shown
|
|
984
|
+
// under the HID QR Code card as the resident app's invite form shows it.
|
|
985
|
+
// Null until read, and when it cannot be read: then no hint, not a guess.
|
|
986
|
+
// Loaded by the watcher below `siteData`.
|
|
987
|
+
const hidQrUsage = ref<"wholeDay" | "singleUse" | null>(null);
|
|
988
|
+
|
|
982
989
|
const showEntryPassInformation = computed(() => {
|
|
983
990
|
return Boolean(
|
|
984
991
|
entryPassSettings.value?.data?.settings?.nfcPass ||
|
|
@@ -1591,6 +1598,23 @@ watch(
|
|
|
1591
1598
|
{ immediate: true },
|
|
1592
1599
|
);
|
|
1593
1600
|
|
|
1601
|
+
// Below `siteData` for the same reason as the reader watcher above:
|
|
1602
|
+
// `hidQrCodePassAllowed` reads it. Only fetched where HID QR is offered.
|
|
1603
|
+
watch(
|
|
1604
|
+
[hidQrCodePassAllowed, () => prop.site],
|
|
1605
|
+
async ([allowed, site]) => {
|
|
1606
|
+
hidQrUsage.value = null;
|
|
1607
|
+
if (!allowed || !site) return;
|
|
1608
|
+
try {
|
|
1609
|
+
const settings = await getOvernightParkingAvailabilityV2(String(site), "site");
|
|
1610
|
+
hidQrUsage.value = hidQrUsageFromSettings(settings);
|
|
1611
|
+
} catch {
|
|
1612
|
+
hidQrUsage.value = null;
|
|
1613
|
+
}
|
|
1614
|
+
},
|
|
1615
|
+
{ immediate: true },
|
|
1616
|
+
);
|
|
1617
|
+
|
|
1594
1618
|
const {
|
|
1595
1619
|
data: blocksListData,
|
|
1596
1620
|
refresh: refreshBlockListData,
|
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.97.1-staging.
|
|
5
|
+
"version": "4.97.1-staging.572",
|
|
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.",
|
package/utils/hid-qr-validity.ts
CHANGED
|
@@ -4,6 +4,20 @@
|
|
|
4
4
|
* (`minutesUntilEndOfDay` in its VisitorForm.tsx). Never less than 1: the API
|
|
5
5
|
* refuses a zero validity.
|
|
6
6
|
*/
|
|
7
|
+
/**
|
|
8
|
+
* How long the site's HID visitor pass lasts: the `usage` on the HID entry of
|
|
9
|
+
* `visitorQrCodes` (Site Settings > Resident Visitors). Anything but
|
|
10
|
+
* "singleUse" is the whole visit day - the same reading as core's
|
|
11
|
+
* `getHidVisitorQrUsage` and the resident app's invite form.
|
|
12
|
+
*/
|
|
13
|
+
export function hidQrUsageFromSettings(settings: unknown): "wholeDay" | "singleUse" {
|
|
14
|
+
const codes = (settings as { visitorQrCodes?: unknown } | null)?.visitorQrCodes;
|
|
15
|
+
const hid = Array.isArray(codes)
|
|
16
|
+
? codes.find((code) => (code as { type?: unknown } | null)?.type === "hid")
|
|
17
|
+
: undefined;
|
|
18
|
+
return (hid as { usage?: unknown } | undefined)?.usage === "singleUse" ? "singleUse" : "wholeDay";
|
|
19
|
+
}
|
|
20
|
+
|
|
7
21
|
export function minutesUntilEndOfDay(now: Date = new Date()) {
|
|
8
22
|
const midnight = new Date(now);
|
|
9
23
|
midnight.setHours(24, 0, 0, 0);
|
package/utils/robot-setup.ts
CHANGED
|
@@ -88,6 +88,7 @@ export function offlineReason(robot: Record<string, any>, state: Record<string,
|
|
|
88
88
|
const why = state.reason ? ` (${state.reason})` : "";
|
|
89
89
|
if (robot?.brand === "ounitech") return `${name}: the Ounitech cloud did not answer${why}. Ask Ounitech to link this robot's serial to our account.`;
|
|
90
90
|
if (robot?.brand === "padbot") return `${name}: the PadBot cloud did not answer${why}. Check the robot's key and token.`;
|
|
91
|
+
if (robot?.brand === "oneway") return `${name}: OneWay's RMS did not answer${why}. Check the robot's API key and server address, and ask OneWay to put this robot under our company key.`;
|
|
91
92
|
return `${name}: its cloud did not answer${why}.`;
|
|
92
93
|
}
|
|
93
94
|
return `${name}: its cloud says it is offline - switched off, charging dock unplugged or out of Wi-Fi.`;
|
|
@@ -129,7 +130,7 @@ export function robotSetupSteps(input: TSetupInput): TSetupStep[] {
|
|
|
129
130
|
}
|
|
130
131
|
|
|
131
132
|
// 2. Robots added.
|
|
132
|
-
const prereq = "Before adding: Ounitech must link each robot's serial to our Seven365 account; for PadBot, save the robot's points (charger, stops) in the PadBot app first.";
|
|
133
|
+
const prereq = "Before adding: Ounitech must link each robot's serial to our Seven365 account; for PadBot, save the robot's points (charger, stops) in the PadBot app first; for OneWay, get our company API key from OneWay and have the robot's routes and charging point set in OneWay's RMS.";
|
|
133
134
|
if (!robots) {
|
|
134
135
|
steps.push({ key: "robots", title: "Robots added", status: "check", reason: "Could not read this site's robots.", button: { label: "Open fleet", target: "fleet" } });
|
|
135
136
|
} else {
|