@7365admin1/layer-common 3.2.2-staging.188 → 3.2.2-staging.189

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.
@@ -2060,7 +2060,7 @@ const customizeWidgets = computed(() => {
2060
2060
  key: "visitors",
2061
2061
  title: "Visitors",
2062
2062
  description:
2063
- "See today's visitor traffic and who is currently on site.",
2063
+ "See today's visitor traffic, and how many passes are still not checked out.",
2064
2064
  },
2065
2065
  {
2066
2066
  key: "facilityBookings",
@@ -2117,7 +2117,7 @@ const customizeWidgets = computed(() => {
2117
2117
  key: "visitors",
2118
2118
  title: "Visitors",
2119
2119
  description:
2120
- "See today's visitor traffic and who is currently on site.",
2120
+ "See today's visitor traffic, and how many passes are still not checked out.",
2121
2121
  },
2122
2122
  {
2123
2123
  key: "patrolCompliance",
@@ -2288,7 +2288,7 @@ function getPropertyKpiCards() {
2288
2288
  color: KPI_TONES.info.color,
2289
2289
  tint: KPI_TONES.info.tint,
2290
2290
  value: formatNumber(toNumber(workOrderMetric?.count)),
2291
- percentage: toNumber(workOrderMetric?.percentage),
2291
+ percentage: toNumberOrNaN(workOrderMetric?.percentage),
2292
2292
  meta: getMetricMeta(workOrderMetric),
2293
2293
  raw: workOrderMetric,
2294
2294
  filter: undefined,
@@ -2300,7 +2300,7 @@ function getPropertyKpiCards() {
2300
2300
  color: KPI_TONES.err.color,
2301
2301
  tint: KPI_TONES.err.tint,
2302
2302
  value: formatNumber(toNumber(incidentMetric?.count)),
2303
- percentage: toNumber(incidentMetric?.percentage),
2303
+ percentage: toNumberOrNaN(incidentMetric?.percentage),
2304
2304
  meta: getMetricMeta(incidentMetric),
2305
2305
  raw: incidentMetric,
2306
2306
  filter: undefined,
@@ -2312,7 +2312,7 @@ function getPropertyKpiCards() {
2312
2312
  color: KPI_TONES.warn.color,
2313
2313
  tint: KPI_TONES.warn.tint,
2314
2314
  value: formatNumber(toNumber(visitorMetric?.count)),
2315
- percentage: toNumber(visitorMetric?.percentage),
2315
+ percentage: toNumberOrNaN(visitorMetric?.percentage),
2316
2316
  meta: getMetricMeta(visitorMetric),
2317
2317
  raw: visitorMetric,
2318
2318
  filter: {
@@ -2331,7 +2331,7 @@ function getPropertyKpiCards() {
2331
2331
  color: KPI_TONES.ok.color,
2332
2332
  tint: KPI_TONES.ok.tint,
2333
2333
  value: formatNumber(toNumber(facilityMetric?.count)),
2334
- percentage: toNumber(facilityMetric?.percentage),
2334
+ percentage: toNumberOrNaN(facilityMetric?.percentage),
2335
2335
  meta: getMetricMeta(facilityMetric),
2336
2336
  raw: facilityMetric,
2337
2337
  filter: undefined,
@@ -2366,7 +2366,7 @@ function getSecurityKpiCards() {
2366
2366
  color: KPI_TONES.info.color,
2367
2367
  tint: KPI_TONES.info.tint,
2368
2368
  value: formatNumber(toNumber(workOrderMetric?.count)),
2369
- percentage: toNumber(workOrderMetric?.percentage),
2369
+ percentage: toNumberOrNaN(workOrderMetric?.percentage),
2370
2370
  meta: getMetricMeta(workOrderMetric),
2371
2371
  raw: workOrderMetric,
2372
2372
  filter: undefined,
@@ -2378,7 +2378,7 @@ function getSecurityKpiCards() {
2378
2378
  color: KPI_TONES.err.color,
2379
2379
  tint: KPI_TONES.err.tint,
2380
2380
  value: formatNumber(toNumber(incidentMetric?.count)),
2381
- percentage: toNumber(incidentMetric?.percentage),
2381
+ percentage: toNumberOrNaN(incidentMetric?.percentage),
2382
2382
  meta: getMetricMeta(incidentMetric),
2383
2383
  raw: incidentMetric,
2384
2384
  filter: undefined,
@@ -2390,7 +2390,7 @@ function getSecurityKpiCards() {
2390
2390
  color: KPI_TONES.warn.color,
2391
2391
  tint: KPI_TONES.warn.tint,
2392
2392
  value: formatNumber(toNumber(visitorMetric?.count)),
2393
- percentage: toNumber(visitorMetric?.percentage),
2393
+ percentage: toNumberOrNaN(visitorMetric?.percentage),
2394
2394
  meta: getMetricMeta(visitorMetric),
2395
2395
  raw: visitorMetric,
2396
2396
  filter: {
@@ -2408,8 +2408,10 @@ function getSecurityKpiCards() {
2408
2408
  icon: "mdi-office-building",
2409
2409
  color: KPI_TONES.ok.color,
2410
2410
  tint: KPI_TONES.ok.tint,
2411
- value: `${toNumber(patrolMetric?.count)}%`,
2412
- percentage: toNumber(patrolMetric?.percentage),
2411
+ // Through the shared helper, so a `null` rate (no checkpoint was due)
2412
+ // reads as not-measured here too, not as 0%.
2413
+ value: getMetricValue(patrolMetric, "patrolCompliance"),
2414
+ percentage: toNumberOrNaN(patrolMetric?.percentage),
2413
2415
  meta: getMetricMeta(patrolMetric),
2414
2416
  raw: patrolMetric,
2415
2417
  filter: undefined,
@@ -2436,7 +2438,7 @@ const rawKpiCards = computed(() => {
2436
2438
  tint: getCardTint(mapping.color, index),
2437
2439
  color: mapping.color || getCardColor(index),
2438
2440
  value: typeof value === "string" ? value : formatNumber(value),
2439
- percentage: toNumber(metric.percentage),
2441
+ percentage: toNumberOrNaN(metric.percentage),
2440
2442
  meta: getMetricMeta(metric),
2441
2443
  raw: metric,
2442
2444
  filter: undefined as any,
@@ -2917,7 +2919,9 @@ function getMetric(keys: string[]): DashboardMetric {
2917
2919
 
2918
2920
  function getMetricValue(metric: DashboardMetric, key?: string) {
2919
2921
  if (key === "patrolCompliance") {
2920
- return `${formatNumber(toNumber(metric.count))}%`;
2922
+ const rate = toNumberOrNaN(metric.count);
2923
+ // `null` = no checkpoint was due in this period. Not 0%, not 100%.
2924
+ return Number.isFinite(rate) ? `${formatNumber(rate)}%` : "—";
2921
2925
  }
2922
2926
  const completed = toNumber(metric.completed);
2923
2927
  const total = toNumber(metric.total);
@@ -2935,11 +2939,18 @@ function getMetricMeta(metric: DashboardMetric) {
2935
2939
  parts.push(`${formatNumber(toNumber(metric.inProgress))} in progress`);
2936
2940
  if (typeof metric.pending !== "undefined")
2937
2941
  parts.push(`${formatNumber(toNumber(metric.pending))} pending`);
2938
- if (typeof metric.highSeverity !== "undefined")
2942
+ // `null` here is the API saying incident severity is not recorded at all.
2943
+ // Printing "0 high severity" would answer a question nothing measured.
2944
+ if (metric.highSeverity !== undefined && metric.highSeverity !== null)
2939
2945
  parts.push(`${formatNumber(toNumber(metric.highSeverity))} high severity`);
2940
- if (typeof metric.currentlyOnSite !== "undefined")
2946
+ // NOT a live occupancy figure. The server counts every visitor transaction
2947
+ // with a check-in and no check-out, with NO date bound, and nothing in the
2948
+ // product ever closes a stale one - so a pass left open years ago is still
2949
+ // in here. Say what it counts. Same wording the Visitor Management screen
2950
+ // already uses for the same filter ("Not Checked Out").
2951
+ if (metric.currentlyOnSite !== undefined && metric.currentlyOnSite !== null)
2941
2952
  parts.push(
2942
- `${formatNumber(toNumber(metric.currentlyOnSite))} currently on site`
2953
+ `${formatNumber(toNumber(metric.currentlyOnSite))} not checked out (all time)`
2943
2954
  );
2944
2955
  if (
2945
2956
  typeof (metric as any).missedCheckpoints !== "undefined" ||
@@ -3905,6 +3916,21 @@ function toNumber(value: any) {
3905
3916
  return Number.isFinite(n) ? n : 0;
3906
3917
  }
3907
3918
 
3919
+ /**
3920
+ * A figure the server may report as "not measured".
3921
+ *
3922
+ * `toNumber()` turns `null` into `0`, which is wrong for anything the API
3923
+ * deliberately sends as `null` - a trend with no prior period to compare
3924
+ * against, a compliance rate with no checkpoint due, a severity the incident
3925
+ * form never records. Those must read as absent, not as zero. `NaN` is what
3926
+ * the tile already treats as "no pill" / "no figure".
3927
+ */
3928
+ function toNumberOrNaN(value: any) {
3929
+ if (value === null || value === undefined || value === "") return NaN;
3930
+ const n = Number(value);
3931
+ return Number.isFinite(n) ? n : NaN;
3932
+ }
3933
+
3908
3934
  function normalizeStatus(value: any) {
3909
3935
  const text = String(value || "").trim();
3910
3936
  if (!text) return "To-Do";
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.188",
5
+ "version": "3.2.2-staging.189",
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.",