@iservice365/layer-common 1.5.6 → 1.5.7

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @iservice365/layer-common
2
2
 
3
+ ## 1.5.7
4
+
5
+ ### Patch Changes
6
+
7
+ - cec19dc: Dashboard static data - follow up release
8
+
3
9
  ## 1.5.6
4
10
 
5
11
  ### Patch Changes
@@ -40,9 +40,14 @@
40
40
  </v-chip>
41
41
  </v-col>
42
42
  <v-col cols="4" class="text-right">
43
- <v-avatar :color="card.color" size="56" rounded="lg">
44
- <v-icon :icon="card.icon" color="white" size="28"></v-icon>
45
- </v-avatar>
43
+ <div class="d-flex justify-end">
44
+ <div
45
+ class="avatar-custom"
46
+ :style="{ backgroundColor: card.color }"
47
+ >
48
+ <v-icon :icon="card.icon" color="white" size="28"></v-icon>
49
+ </div>
50
+ </div>
46
51
  </v-col>
47
52
  </v-row>
48
53
  <v-row no-gutters class="mt-4">
@@ -54,7 +59,7 @@
54
59
  hide-details
55
60
  variant="outlined"
56
61
  @update:model-value="
57
- updateCardPeriod(card.label.toLowerCase(), $event)
62
+ updateCardPeriodDynamic(card.label, $event)
58
63
  "
59
64
  ></v-select>
60
65
  </v-col>
@@ -65,7 +70,7 @@
65
70
  </v-row>
66
71
 
67
72
  <!-- Line Chart -->
68
- <v-row class="mb-4">
73
+ <!-- <v-row class="mb-4">
69
74
  <v-col cols="12">
70
75
  <v-card flat border elevation="0">
71
76
  <v-card-title class="pa-4 pa-md-6">
@@ -97,7 +102,7 @@
97
102
  style="min-width: 800px; width: 100%; height: 100%"
98
103
  preserveAspectRatio="xMidYMid meet"
99
104
  >
100
- <!-- Y-axis labels -->
105
+
101
106
  <text x="20" y="30" font-size="12" fill="#666">6</text>
102
107
  <text x="20" y="80" font-size="12" fill="#666">5</text>
103
108
  <text x="20" y="130" font-size="12" fill="#666">4</text>
@@ -106,7 +111,7 @@
106
111
  <text x="20" y="280" font-size="12" fill="#666">1</text>
107
112
  <text x="20" y="310" font-size="12" fill="#666">0</text>
108
113
 
109
- <!-- Grid lines -->
114
+
110
115
  <line
111
116
  x1="60"
112
117
  y1="20"
@@ -164,14 +169,14 @@
164
169
  stroke-width="1"
165
170
  />
166
171
 
167
- <!-- Visitor line data -->
172
+
168
173
  <polyline
169
174
  :points="visitorPoints.map((p) => `${p.x},${p.y}`).join(' ')"
170
175
  fill="none"
171
176
  stroke="#2196F3"
172
177
  stroke-width="3"
173
178
  />
174
- <!-- Data points -->
179
+
175
180
  <circle
176
181
  v-for="point in visitorPoints"
177
182
  :key="point.x"
@@ -180,7 +185,7 @@
180
185
  r="5"
181
186
  fill="#2196F3"
182
187
  />
183
- <!-- X-axis labels -->
188
+
184
189
  <text
185
190
  v-for="(label, idx) in visitorLabels"
186
191
  :key="idx"
@@ -197,10 +202,10 @@
197
202
  </v-card-text>
198
203
  </v-card>
199
204
  </v-col>
200
- </v-row>
205
+ </v-row> -->
201
206
 
202
207
  <!-- Bar Chart -->
203
- <v-row class="mb-4">
208
+ <!-- <v-row class="mb-4">
204
209
  <v-col cols="12">
205
210
  <v-card flat border elevation="0">
206
211
  <v-card-title class="pa-4 pa-md-6">
@@ -227,6 +232,7 @@
227
232
  style="max-width: 200px"
228
233
  clearable
229
234
  class="pr-4"
235
+ @update:model-value="selectedService = $event"
230
236
  ></v-select>
231
237
  <v-select
232
238
  v-model="feedbackPeriod"
@@ -240,7 +246,6 @@
240
246
  </v-row>
241
247
  </v-card-title>
242
248
  <v-card-text class="pa-4 pa-md-6 pt-2">
243
- <!-- Legend -->
244
249
  <div class="d-flex justify-center gap-4 mb-4">
245
250
  <div class="d-flex align-center">
246
251
  <div class="legend-box mr-2" style="background: #2196f3"></div>
@@ -261,7 +266,6 @@
261
266
  style="min-width: 800px; width: 100%; height: 100%"
262
267
  preserveAspectRatio="xMidYMid meet"
263
268
  >
264
- <!-- Y-axis labels -->
265
269
  <text x="20" y="20" font-size="12" fill="#999">100</text>
266
270
  <text x="20" y="80" font-size="12" fill="#999">80</text>
267
271
  <text x="20" y="140" font-size="12" fill="#999">60</text>
@@ -269,7 +273,6 @@
269
273
  <text x="20" y="260" font-size="12" fill="#999">20</text>
270
274
  <text x="30" y="295" font-size="12" fill="#999">0</text>
271
275
 
272
- <!-- Grid lines -->
273
276
  <line
274
277
  x1="60"
275
278
  y1="20"
@@ -319,9 +322,7 @@
319
322
  stroke-width="1"
320
323
  />
321
324
 
322
- <!-- Bars with data -->
323
325
  <g v-for="(bar, idx) in feedbackBars" :key="idx">
324
- <!-- Bar -->
325
326
  <rect
326
327
  :x="bar.x"
327
328
  :y="bar.y"
@@ -330,7 +331,7 @@
330
331
  :fill="bar.color"
331
332
  rx="4"
332
333
  />
333
- <!-- Value label -->
334
+
334
335
  <text
335
336
  :x="bar.x + bar.width / 2"
336
337
  :y="bar.y - 8"
@@ -341,7 +342,7 @@
341
342
  >
342
343
  {{ bar.value }}
343
344
  </text>
344
- <!-- X-axis label -->
345
+
345
346
  <text
346
347
  :x="bar.x + bar.width / 2"
347
348
  y="310"
@@ -357,14 +358,14 @@
357
358
  </v-card-text>
358
359
  </v-card>
359
360
  </v-col>
360
- </v-row>
361
+ </v-row> -->
361
362
 
362
363
  <!-- Pie Charts -->
363
- <v-row class="mb-4">
364
+ <!-- <v-row class="mb-4">
364
365
  <v-col v-for="pie in pieChartList" :key="pie.id" cols="12" md="6" lg="4">
365
366
  <v-card flat border elevation="0" class="h-100">
366
367
  <v-card-text class="pa-4 pa-md-6">
367
- <!-- Header with title and total -->
368
+
368
369
  <div class="mb-3">
369
370
  <h3 class="text-h6 font-weight-bold mb-1">{{ pie.title }}</h3>
370
371
  <p class="text-body-2 text-grey-darken-1">
@@ -372,9 +373,9 @@
372
373
  </p>
373
374
  </div>
374
375
 
375
- <!-- Dropdowns -->
376
+
376
377
  <div class="mb-4 d-flex flex-column gap-2">
377
- <!-- Facility/Building selector for Bookings only -->
378
+
378
379
  <v-select
379
380
  v-if="pie.id === 1"
380
381
  v-model="selectedBooking"
@@ -388,7 +389,7 @@
388
389
  clearable
389
390
  class="pb-4"
390
391
  ></v-select>
391
- <!-- Period selector -->
392
+
392
393
  <v-select
393
394
  :model-value="pie.period"
394
395
  :items="['This Week', 'This Month', 'This Year']"
@@ -399,7 +400,7 @@
399
400
  ></v-select>
400
401
  </div>
401
402
 
402
- <!-- Legend -->
403
+
403
404
  <div class="d-flex flex-wrap gap-3 mb-4">
404
405
  <div
405
406
  v-for="(segment, idx) in pie.segments"
@@ -414,7 +415,7 @@
414
415
  </div>
415
416
  </div>
416
417
 
417
- <!-- Donut Chart -->
418
+
418
419
  <div class="d-flex justify-center align-center">
419
420
  <div class="position-relative">
420
421
  <svg viewBox="0 0 200 200" width="220" height="220">
@@ -432,7 +433,7 @@
432
433
  class="donut-segment"
433
434
  />
434
435
  </svg>
435
- <!-- Center value -->
436
+
436
437
  <div class="donut-center">
437
438
  <p class="text-h5 font-weight-bold">{{ pie.centerValue }}</p>
438
439
  </div>
@@ -441,10 +442,10 @@
441
442
  </v-card-text>
442
443
  </v-card>
443
444
  </v-col>
444
- </v-row>
445
+ </v-row> -->
445
446
 
446
447
  <!-- Facility Section -->
447
- <v-row v-if="facilityBookings.length" class="mt-4">
448
+ <!-- <v-row v-if="facilityBookings.length" class="mt-4">
448
449
  <v-col cols="12" class="mb-4">
449
450
  <h2 class="text-h5 font-weight-bold">Facility</h2>
450
451
  </v-col>
@@ -478,18 +479,16 @@
478
479
  </v-card-text>
479
480
  </v-card>
480
481
  </v-col>
481
- </v-row>
482
+ </v-row> -->
482
483
  </v-container>
483
484
  </template>
484
485
 
485
486
  <script setup lang="ts">
486
- import { useDisplay } from "vuetify";
487
-
488
- const display = useDisplay();
489
487
  const { getServiceProviderNames } = useServiceProvider();
490
488
  const { getAll: getAllBuildings } = useBuilding();
491
489
  const { getSiteById } = useSite();
492
490
  const route = useRoute();
491
+ const { APP_NAME } = useRuntimeConfig().public;
493
492
 
494
493
  // Get siteId from route params
495
494
  const siteId = computed(() => (route.params.site as string) || "");
@@ -531,6 +530,14 @@ interface CardPeriods {
531
530
  const isDashboardLoading = ref(false);
532
531
  const isFeedbackTicketLoading = ref(false);
533
532
 
533
+ // Get dashboard data based on APP_NAME
534
+ const {
535
+ cards: dashboardCards,
536
+ feedbackItems,
537
+ feedbackChartDataMap,
538
+ periodMultipliers,
539
+ } = useDashboardData(APP_NAME);
540
+
534
541
  // Period states for each section
535
542
  const visitorPeriod = ref<Period>("This Week");
536
543
  const feedbackPeriod = ref<Period>("This Week");
@@ -538,9 +545,15 @@ const bookingsPeriod = ref<Period>("This Week");
538
545
  const buildingPeriod = ref<Period>("This Week");
539
546
  const workOrdersPeriod = ref<Period>("This Week");
540
547
 
541
- // Service provider states
548
+ // Service provider states - now using feedback items from composable
542
549
  const selectedService = ref<any>(null);
543
- const serviceList = ref<Array<{ _id: string; name: string }>>([]);
550
+ const serviceList = ref<Array<{ _id: string; name: string }>>(feedbackItems);
551
+
552
+ // Per-card periods keyed by label
553
+ const dynamicCardPeriods = ref<Record<string, Period>>({});
554
+ function updateCardPeriodDynamic(label: string, period: string) {
555
+ dynamicCardPeriods.value[label] = period as Period;
556
+ }
544
557
 
545
558
  // Booking filter - list of facilities/buildings
546
559
  const selectedBooking = ref<any>(null);
@@ -868,7 +881,7 @@ const dataByPeriod: Record<string, any> = {
868
881
  },
869
882
  };
870
883
 
871
- // Computed properties for reactive data with site-based multiplier
884
+ // Computed properties for reactive data with site-based multiplier and APP_NAME-based cards
872
885
  const countCardList = computed(() => {
873
886
  // Calculate multiplier based on siteId (different sites get different multipliers)
874
887
  const siteHash = siteId.value
@@ -876,74 +889,31 @@ const countCardList = computed(() => {
876
889
  : 0;
877
890
  const siteMultiplier = siteId.value ? 0.6 + (siteHash % 40) / 100 : 1; // Between 0.6 and 1.0
878
891
 
879
- const applyMultiplier = (value: string) => {
880
- const numValue = parseInt(value.replace(/,/g, ""));
881
- const newValue = Math.round(numValue * siteMultiplier);
892
+ const applyMultiplier = (value: number) => {
893
+ const newValue = Math.round(value * siteMultiplier);
882
894
  return newValue >= 1000 ? newValue.toLocaleString() : newValue.toString();
883
895
  };
884
896
 
885
- return [
886
- {
887
- id: 1,
888
- label: "Guest",
889
- value: applyMultiplier(dataByPeriod[cardPeriods.value.guest].guest.value),
890
- icon: "mdi-account-multiple",
891
- color: "primary",
892
- percentage: dataByPeriod[cardPeriods.value.guest].guest.percentage,
893
- chipColor: dataByPeriod[cardPeriods.value.guest].guest.chipColor,
894
- period: cardPeriods.value.guest,
895
- },
896
- {
897
- id: 2,
898
- label: "Pickup",
899
- value: applyMultiplier(
900
- dataByPeriod[cardPeriods.value.pickup].pickup.value
901
- ),
902
- icon: "mdi-package",
903
- color: "error",
904
- percentage: dataByPeriod[cardPeriods.value.pickup].pickup.percentage,
905
- chipColor: dataByPeriod[cardPeriods.value.pickup].pickup.chipColor,
906
- period: cardPeriods.value.pickup,
907
- },
908
- {
909
- id: 3,
910
- label: "Drop-off",
911
- value: applyMultiplier(
912
- dataByPeriod[cardPeriods.value.dropoff].dropoff.value
913
- ),
914
- icon: "mdi-package-down",
915
- color: "warning",
916
- percentage: dataByPeriod[cardPeriods.value.dropoff].dropoff.percentage,
917
- chipColor: dataByPeriod[cardPeriods.value.dropoff].dropoff.chipColor,
918
- period: cardPeriods.value.dropoff,
919
- },
920
- {
921
- id: 4,
922
- label: "Contractor",
923
- value: applyMultiplier(
924
- dataByPeriod[cardPeriods.value.contractor].contractor.value
925
- ),
926
- icon: "mdi-hard-hat",
927
- color: "success",
928
- percentage:
929
- dataByPeriod[cardPeriods.value.contractor].contractor.percentage,
930
- chipColor:
931
- dataByPeriod[cardPeriods.value.contractor].contractor.chipColor,
932
- period: cardPeriods.value.contractor,
933
- },
934
- {
935
- id: 5,
936
- label: "Delivery",
937
- value: applyMultiplier(
938
- dataByPeriod[cardPeriods.value.delivery].delivery.value
939
- ),
940
- icon: "mdi-truck",
941
- color: "grey",
942
- percentage: dataByPeriod[cardPeriods.value.delivery].delivery.percentage,
943
- chipColor: dataByPeriod[cardPeriods.value.delivery].delivery.chipColor,
944
- period: cardPeriods.value.delivery,
945
- },
946
- ];
897
+ // Map dashboard cards to card list format
898
+ return dashboardCards.map((card, idx) => {
899
+ const label = card.title;
900
+ const period =
901
+ dynamicCardPeriods.value[label] ||
902
+ (dynamicCardPeriods.value[label] = "This Week");
903
+ const periodFactor = periodMultipliers[period] ?? 1;
904
+ const multipliedValue = Math.round(card.value * periodFactor);
905
+
906
+ return {
907
+ id: idx + 1,
908
+ label,
909
+ value: applyMultiplier(multipliedValue),
910
+ icon: card.icon,
911
+ color: card.color,
912
+ percentage: `${card.percentage > 0 ? "+" : ""}${card.percentage} %`,
913
+ chipColor: card.isPositive ? "success" : "error",
914
+ period,
915
+ };
916
+ });
947
917
  });
948
918
 
949
919
  // Computed reactive data
@@ -961,32 +931,19 @@ const visitorLabels = [
961
931
  ];
962
932
 
963
933
  const feedbackBars = computed(() => {
964
- const baseFeedback = dataByPeriod[feedbackPeriod.value].feedback;
965
-
966
934
  // If no service is selected, return the base data
967
935
  if (!selectedService.value) {
968
- return baseFeedback;
936
+ return dataByPeriod[feedbackPeriod.value].feedback;
969
937
  }
970
938
 
971
- // If a service is selected, multiply values by a consistent factor
972
- // Use the service ID to generate a consistent multiplier for that service
973
- const serviceHash = selectedService.value
974
- .split("")
975
- .reduce((acc, char) => acc + char.charCodeAt(0), 0);
976
- const multiplier = 0.3 + (serviceHash % 50) / 100; // Between 0.3 and 0.8
977
-
978
- return baseFeedback.map((bar: any) => {
979
- const newValue = Math.round(bar.value * multiplier);
980
- const newHeight = bar.height * multiplier;
981
- const newY = 290 - newHeight;
939
+ // If a service is selected, use the feedback chart data from composable
940
+ const chartData = feedbackChartDataMap[selectedService.value];
941
+ if (chartData && chartData[feedbackPeriod.value]) {
942
+ return chartData[feedbackPeriod.value];
943
+ }
982
944
 
983
- return {
984
- ...bar,
985
- value: newValue,
986
- height: newHeight,
987
- y: newY,
988
- };
989
- });
945
+ // Fallback to base data if service data not found
946
+ return dataByPeriod[feedbackPeriod.value].feedback;
990
947
  });
991
948
 
992
949
  // Function to update individual card periods
@@ -1307,15 +1264,9 @@ watch(selectedService, () => {
1307
1264
  fetchFeedbackData();
1308
1265
  });
1309
1266
 
1310
- // Fetch service providers and buildings/facilities on mount
1267
+ // Fetch buildings/facilities on mount
1311
1268
  onMounted(async () => {
1312
1269
  try {
1313
- // Fetch service providers for feedback dropdown
1314
- const serviceResponse = await getServiceProviderNames({ limit: 100 });
1315
- if (serviceResponse && serviceResponse.items) {
1316
- serviceList.value = serviceResponse.items;
1317
- }
1318
-
1319
1270
  // Fetch buildings/facilities for bookings dropdown
1320
1271
  // Using buildings as facilities - you can adjust to use actual facilities API
1321
1272
  const buildingsResponse = await getAllBuildings({
@@ -1499,6 +1450,16 @@ svg rect {
1499
1450
  border-radius: 12px !important;
1500
1451
  }
1501
1452
 
1453
+ .avatar-custom {
1454
+ width: 56px;
1455
+ height: 56px;
1456
+ border-radius: 12px;
1457
+ display: flex;
1458
+ align-items: center;
1459
+ justify-content: center;
1460
+ flex-shrink: 0;
1461
+ }
1462
+
1502
1463
  /* Better chip styling */
1503
1464
  .v-chip {
1504
1465
  font-weight: 600;
@@ -58,7 +58,7 @@ const loading = ref(false);
58
58
 
59
59
  const page = ref(1);
60
60
  const pages = ref(0);
61
- const pageRange = ref("-- - -- of --");
61
+ const pageRange = ref("1-10 of 10");
62
62
  const items = ref<Array<Record<string, any>>>([]);
63
63
 
64
64
  const headers: Array<Record<string, any>> = [
@@ -0,0 +1,425 @@
1
+ export interface DashboardCard {
2
+ title: string;
3
+ value: number;
4
+ percentage: number;
5
+ isPositive: boolean;
6
+ icon: string;
7
+ color: string;
8
+ }
9
+
10
+ export interface ModuleData {
11
+ name: string;
12
+ cards: DashboardCard[];
13
+ modules: string[];
14
+ }
15
+
16
+ export interface FeedbackData {
17
+ _id: string;
18
+ name: string;
19
+ }
20
+
21
+ export interface FeedbackChartData {
22
+ "This Week": any[];
23
+ "This Month": any[];
24
+ "This Year": any[];
25
+ }
26
+
27
+ export interface PeriodMultiplier {
28
+ "This Week": number;
29
+ "This Month": number;
30
+ "This Year": number;
31
+ }
32
+
33
+ const dashboardDataMap: Record<string, ModuleData> = {
34
+ security: {
35
+ name: 'Security',
36
+ cards: [
37
+ {
38
+ title: 'Feedback',
39
+ value: 45,
40
+ percentage: 12.5,
41
+ isPositive: true,
42
+ icon: 'mdi-comment-multiple',
43
+ color: '#1E88E5',
44
+ },
45
+ {
46
+ title: 'Work Orders',
47
+ value: 28,
48
+ percentage: 8.3,
49
+ isPositive: true,
50
+ icon: 'mdi-clipboard-list',
51
+ color: '#D32F2F',
52
+ },
53
+ {
54
+ title: 'Vehicle Management',
55
+ value: 12,
56
+ percentage: 5.2,
57
+ isPositive: true,
58
+ icon: 'mdi-truck',
59
+ color: '#FFA726',
60
+ },
61
+ {
62
+ title: 'Building Management',
63
+ value: 35,
64
+ percentage: 15.4,
65
+ isPositive: true,
66
+ icon: 'mdi-building',
67
+ color: '#43A047',
68
+ },
69
+ {
70
+ title: 'Visitor Management',
71
+ value: 22,
72
+ percentage: 6.8,
73
+ isPositive: true,
74
+ icon: 'mdi-account-multiple',
75
+ color: '#7E57C2',
76
+ },
77
+ {
78
+ title: 'Incident Reports',
79
+ value: 9,
80
+ percentage: -3.5,
81
+ isPositive: false,
82
+ icon: 'mdi-alert-circle',
83
+ color: '#EF5350',
84
+ },
85
+ {
86
+ title: 'Guest Management',
87
+ value: 18,
88
+ percentage: 4.2,
89
+ isPositive: true,
90
+ icon: 'mdi-account-badge',
91
+ color: '#AB47BC',
92
+ },
93
+ ],
94
+ modules: [
95
+ 'Feedback',
96
+ 'Work Orders',
97
+ 'Vehicle Management',
98
+ 'Building Management',
99
+ 'Visitor Management',
100
+ 'Incident Reports',
101
+ 'Guest Management',
102
+ ],
103
+ },
104
+ hygiene: {
105
+ name: 'Hygiene',
106
+ cards: [
107
+ {
108
+ title: 'Feedback',
109
+ value: 52,
110
+ percentage: 14.2,
111
+ isPositive: true,
112
+ icon: 'mdi-comment-multiple',
113
+ color: '#1E88E5',
114
+ },
115
+ {
116
+ title: 'Work Orders',
117
+ value: 38,
118
+ percentage: 11.3,
119
+ isPositive: true,
120
+ icon: 'mdi-clipboard-list',
121
+ color: '#D32F2F',
122
+ },
123
+ {
124
+ title: 'Schedule Task Ticket',
125
+ value: 25,
126
+ percentage: 7.8,
127
+ isPositive: true,
128
+ icon: 'mdi-calendar-check',
129
+ color: '#FFA726',
130
+ },
131
+ {
132
+ title: 'Attendance',
133
+ value: 64,
134
+ percentage: 18.9,
135
+ isPositive: true,
136
+ icon: 'mdi-clock-check',
137
+ color: '#43A047',
138
+ },
139
+ {
140
+ title: 'Supply Management',
141
+ value: 42,
142
+ percentage: 12.5,
143
+ isPositive: true,
144
+ icon: 'mdi-warehouse',
145
+ color: '#7E57C2',
146
+ },
147
+ {
148
+ title: 'Request Items',
149
+ value: 19,
150
+ percentage: 5.1,
151
+ isPositive: true,
152
+ icon: 'mdi-cart-plus',
153
+ color: '#29B6F6',
154
+ },
155
+ {
156
+ title: 'Cleaning Schedule',
157
+ value: 31,
158
+ percentage: 9.4,
159
+ isPositive: true,
160
+ icon: 'mdi-broom',
161
+ color: '#66BB6A',
162
+ },
163
+ ],
164
+ modules: [
165
+ 'Feedback',
166
+ 'Work Orders',
167
+ 'Schedule Task Ticket',
168
+ 'Attendance',
169
+ 'Supply Management',
170
+ 'Request Items',
171
+ 'Cleaning Schedule - Checklist, Area, Unit',
172
+ ],
173
+ },
174
+ landscaping: {
175
+ name: 'Landscaping',
176
+ cards: [
177
+ {
178
+ title: 'Feedback',
179
+ value: 33,
180
+ percentage: 10.5,
181
+ isPositive: true,
182
+ icon: 'mdi-comment-multiple',
183
+ color: '#1E88E5',
184
+ },
185
+ {
186
+ title: 'Work Orders',
187
+ value: 47,
188
+ percentage: 13.2,
189
+ isPositive: true,
190
+ icon: 'mdi-clipboard-list',
191
+ color: '#D32F2F',
192
+ },
193
+ ],
194
+ modules: [
195
+ 'Feedback',
196
+ 'Work Orders',
197
+ ],
198
+ },
199
+ mechanical_electrical: {
200
+ name: 'Mechanical & Electrical',
201
+ cards: [
202
+ {
203
+ title: 'Feedback',
204
+ value: 38,
205
+ percentage: 11.8,
206
+ isPositive: true,
207
+ icon: 'mdi-comment-multiple',
208
+ color: '#1E88E5',
209
+ },
210
+ {
211
+ title: 'Work Orders',
212
+ value: 52,
213
+ percentage: 15.7,
214
+ isPositive: true,
215
+ icon: 'mdi-clipboard-list',
216
+ color: '#D32F2F',
217
+ },
218
+ ],
219
+ modules: [
220
+ 'Feedback',
221
+ 'Work Orders',
222
+ ],
223
+ },
224
+ pool: {
225
+ name: 'Pool',
226
+ cards: [
227
+ {
228
+ title: 'Feedback',
229
+ value: 29,
230
+ percentage: 9.3,
231
+ isPositive: true,
232
+ icon: 'mdi-comment-multiple',
233
+ color: '#1E88E5',
234
+ },
235
+ {
236
+ title: 'Work Orders',
237
+ value: 41,
238
+ percentage: 12.1,
239
+ isPositive: true,
240
+ icon: 'mdi-clipboard-list',
241
+ color: '#D32F2F',
242
+ },
243
+ ],
244
+ modules: [
245
+ 'Feedback',
246
+ 'Work Orders',
247
+ ],
248
+ },
249
+ pest: {
250
+ name: 'Pest',
251
+ cards: [
252
+ {
253
+ title: 'Feedback',
254
+ value: 26,
255
+ percentage: 8.6,
256
+ isPositive: true,
257
+ icon: 'mdi-comment-multiple',
258
+ color: '#1E88E5',
259
+ },
260
+ {
261
+ title: 'Work Orders',
262
+ value: 35,
263
+ percentage: 10.2,
264
+ isPositive: true,
265
+ icon: 'mdi-clipboard-list',
266
+ color: '#D32F2F',
267
+ },
268
+ ],
269
+ modules: [
270
+ 'Feedback',
271
+ 'Work Orders',
272
+ ],
273
+ },
274
+ };
275
+
276
+ // Feedback items data for dropdowns
277
+ const feedbackItemsMap: Record<string, FeedbackData[]> = {
278
+ security: [
279
+ { _id: "sec-1", name: "Perimeter Security" },
280
+ { _id: "sec-2", name: "Access Control" },
281
+ { _id: "sec-3", name: "CCTV Monitoring" },
282
+ { _id: "sec-4", name: "Guard Services" },
283
+ ],
284
+ hygiene: [
285
+ { _id: "hyg-1", name: "Cleaning Services" },
286
+ { _id: "hyg-2", name: "Disinfection" },
287
+ { _id: "hyg-3", name: "Waste Management" },
288
+ { _id: "hyg-4", name: "Sanitation" },
289
+ ],
290
+ landscaping: [
291
+ { _id: "land-1", name: "Lawn Care" },
292
+ { _id: "land-2", name: "Garden Maintenance" },
293
+ { _id: "land-3", name: "Landscaping Design" },
294
+ { _id: "land-4", name: "Tree Service" },
295
+ ],
296
+ mechanical_electrical: [
297
+ { _id: "me-1", name: "Electrical Services" },
298
+ { _id: "me-2", name: "HVAC Maintenance" },
299
+ { _id: "me-3", name: "Equipment Repair" },
300
+ { _id: "me-4", name: "System Inspection" },
301
+ ],
302
+ pool: [
303
+ { _id: "pool-1", name: "Water Treatment" },
304
+ { _id: "pool-2", name: "Equipment Maintenance" },
305
+ { _id: "pool-3", name: "Cleaning Services" },
306
+ { _id: "pool-4", name: "Safety Inspection" },
307
+ ],
308
+ pest: [
309
+ { _id: "pest-1", name: "Pest Control" },
310
+ { _id: "pest-2", name: "Fumigation" },
311
+ { _id: "pest-3", name: "Prevention Services" },
312
+ { _id: "pest-4", name: "Inspection" },
313
+ ],
314
+ };
315
+
316
+ // Feedback chart data based on selected service
317
+ const feedbackChartDataMap: Record<string, FeedbackChartData> = {
318
+ "sec-1": {
319
+ "This Week": [
320
+ { x: 100, y: 260, width: 60, height: 30, value: 5, label: "1", color: "#2196F3" },
321
+ { x: 200, y: 194, width: 60, height: 96, value: 16, label: "2", color: "#2196F3" },
322
+ { x: 300, y: 230, width: 60, height: 60, value: 10, label: "3", color: "#2196F3" },
323
+ { x: 400, y: 248, width: 60, height: 42, value: 7, label: "4", color: "#2196F3" },
324
+ { x: 500, y: 272, width: 60, height: 18, value: 3, label: "5", color: "#2196F3" },
325
+ { x: 600, y: 260, width: 60, height: 30, value: 5, label: "6", color: "#2196F3" },
326
+ { x: 700, y: 212, width: 60, height: 78, value: 13, label: "7", color: "#2196F3" },
327
+ { x: 800, y: 200, width: 60, height: 90, value: 15, label: "8", color: "#2196F3" },
328
+ { x: 900, y: 80, width: 60, height: 210, value: 70, label: "9", color: "#2196F3" },
329
+ ],
330
+ "This Month": [
331
+ { x: 100, y: 254, width: 60, height: 36, value: 6, label: "1", color: "#2196F3" },
332
+ { x: 200, y: 140, width: 60, height: 150, value: 25, label: "2", color: "#2196F3" },
333
+ { x: 300, y: 194, width: 60, height: 96, value: 16, label: "3", color: "#2196F3" },
334
+ { x: 400, y: 212, width: 60, height: 78, value: 13, label: "4", color: "#2196F3" },
335
+ { x: 500, y: 230, width: 60, height: 60, value: 10, label: "5", color: "#2196F3" },
336
+ { x: 600, y: 248, width: 60, height: 42, value: 7, label: "6", color: "#2196F3" },
337
+ { x: 700, y: 158, width: 60, height: 132, value: 22, label: "7", color: "#2196F3" },
338
+ { x: 800, y: 176, width: 60, height: 114, value: 19, label: "8", color: "#2196F3" },
339
+ { x: 900, y: 50, width: 60, height: 240, value: 80, label: "9", color: "#2196F3" },
340
+ ],
341
+ "This Year": [
342
+ { x: 100, y: 236, width: 60, height: 54, value: 9, label: "1", color: "#2196F3" },
343
+ { x: 200, y: 104, width: 60, height: 186, value: 31, label: "2", color: "#2196F3" },
344
+ { x: 300, y: 176, width: 60, height: 114, value: 19, label: "3", color: "#2196F3" },
345
+ { x: 400, y: 194, width: 60, height: 96, value: 16, label: "4", color: "#2196F3" },
346
+ { x: 500, y: 212, width: 60, height: 78, value: 13, label: "5", color: "#2196F3" },
347
+ { x: 600, y: 230, width: 60, height: 60, value: 10, label: "6", color: "#2196F3" },
348
+ { x: 700, y: 122, width: 60, height: 168, value: 28, label: "7", color: "#2196F3" },
349
+ { x: 800, y: 158, width: 60, height: 132, value: 22, label: "8", color: "#2196F3" },
350
+ { x: 900, y: 20, width: 60, height: 270, value: 90, label: "9", color: "#2196F3" },
351
+ ],
352
+ },
353
+ "sec-2": {
354
+ "This Week": [
355
+ { x: 100, y: 272, width: 60, height: 18, value: 3, label: "1", color: "#4CAF50" },
356
+ { x: 200, y: 176, width: 60, height: 114, value: 19, label: "2", color: "#4CAF50" },
357
+ { x: 300, y: 230, width: 60, height: 60, value: 10, label: "3", color: "#4CAF50" },
358
+ { x: 400, y: 248, width: 60, height: 42, value: 7, label: "4", color: "#4CAF50" },
359
+ { x: 500, y: 260, width: 60, height: 30, value: 5, label: "5", color: "#4CAF50" },
360
+ { x: 600, y: 272, width: 60, height: 18, value: 3, label: "6", color: "#4CAF50" },
361
+ { x: 700, y: 194, width: 60, height: 96, value: 16, label: "7", color: "#4CAF50" },
362
+ { x: 800, y: 188, width: 60, height: 102, value: 17, label: "8", color: "#4CAF50" },
363
+ { x: 900, y: 32, width: 60, height: 258, value: 86, label: "9", color: "#4CAF50" },
364
+ ],
365
+ "This Month": [
366
+ { x: 100, y: 254, width: 60, height: 36, value: 6, label: "1", color: "#4CAF50" },
367
+ { x: 200, y: 140, width: 60, height: 150, value: 25, label: "2", color: "#4CAF50" },
368
+ { x: 300, y: 194, width: 60, height: 96, value: 16, label: "3", color: "#4CAF50" },
369
+ { x: 400, y: 212, width: 60, height: 78, value: 13, label: "4", color: "#4CAF50" },
370
+ { x: 500, y: 230, width: 60, height: 60, value: 10, label: "5", color: "#4CAF50" },
371
+ { x: 600, y: 248, width: 60, height: 42, value: 7, label: "6", color: "#4CAF50" },
372
+ { x: 700, y: 158, width: 60, height: 132, value: 22, label: "7", color: "#4CAF50" },
373
+ { x: 800, y: 176, width: 60, height: 114, value: 19, label: "8", color: "#4CAF50" },
374
+ { x: 900, y: 50, width: 60, height: 240, value: 80, label: "9", color: "#4CAF50" },
375
+ ],
376
+ "This Year": [
377
+ { x: 100, y: 236, width: 60, height: 54, value: 9, label: "1", color: "#4CAF50" },
378
+ { x: 200, y: 104, width: 60, height: 186, value: 31, label: "2", color: "#4CAF50" },
379
+ { x: 300, y: 176, width: 60, height: 114, value: 19, label: "3", color: "#4CAF50" },
380
+ { x: 400, y: 194, width: 60, height: 96, value: 16, label: "4", color: "#4CAF50" },
381
+ { x: 500, y: 212, width: 60, height: 78, value: 13, label: "5", color: "#4CAF50" },
382
+ { x: 600, y: 230, width: 60, height: 60, value: 10, label: "6", color: "#4CAF50" },
383
+ { x: 700, y: 122, width: 60, height: 168, value: 28, label: "7", color: "#4CAF50" },
384
+ { x: 800, y: 158, width: 60, height: 132, value: 22, label: "8", color: "#4CAF50" },
385
+ { x: 900, y: 20, width: 60, height: 270, value: 90, label: "9", color: "#4CAF50" },
386
+ ],
387
+ },
388
+ };
389
+
390
+ // Period multipliers for card data
391
+ const periodMultipliers: PeriodMultiplier = {
392
+ "This Week": 1.0,
393
+ "This Month": 4.3, // approx. weeks in a month
394
+ "This Year": 52.0, // weeks in a year
395
+ };
396
+
397
+ export const useDashboardData = (appName: string) => {
398
+ const normalizedName = appName.toLowerCase();
399
+
400
+ // Try exact match first
401
+ let moduleKey = normalizedName;
402
+
403
+ // If exact match not found, try partial matching
404
+ if (!dashboardDataMap[moduleKey]) {
405
+ if (normalizedName.includes('landscaping')) moduleKey = 'landscaping';
406
+ else if (normalizedName.includes('mechanical') || normalizedName.includes('electrical')) moduleKey = 'mechanical_electrical';
407
+ else if (normalizedName.includes('pool')) moduleKey = 'pool';
408
+ else if (normalizedName.includes('pest')) moduleKey = 'pest';
409
+ else if (normalizedName.includes('hygiene')) moduleKey = 'hygiene';
410
+ else if (normalizedName.includes('security')) moduleKey = 'security';
411
+ else moduleKey = 'security'; // default fallback
412
+ }
413
+
414
+ const moduleData = dashboardDataMap[moduleKey] || dashboardDataMap.security;
415
+ const feedbackItems = feedbackItemsMap[moduleKey] || feedbackItemsMap.security;
416
+
417
+ return {
418
+ moduleData,
419
+ cards: moduleData.cards,
420
+ modules: moduleData.modules,
421
+ feedbackItems,
422
+ feedbackChartDataMap,
423
+ periodMultipliers,
424
+ };
425
+ };
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@iservice365/layer-common",
3
3
  "license": "MIT",
4
4
  "type": "module",
5
- "version": "1.5.6",
5
+ "version": "1.5.7",
6
6
  "main": "./nuxt.config.ts",
7
7
  "scripts": {
8
8
  "dev": "nuxi dev .playground",