@7365admin1/layer-common 3.0.13 → 3.0.15

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,17 @@
1
1
  # @iservice365/layer-common
2
2
 
3
+ ## 3.0.15
4
+
5
+ ### Patch Changes
6
+
7
+ - ddf32e8: Update Layer-common version
8
+
9
+ ## 3.0.14
10
+
11
+ ### Patch Changes
12
+
13
+ - 47d94a5: update service provider flow
14
+
3
15
  ## 3.0.13
4
16
 
5
17
  ### Patch Changes
@@ -15,6 +15,8 @@
15
15
  <v-btn fab icon density="comfortable" @click="getBuildings()">
16
16
  <v-icon>mdi-refresh</v-icon>
17
17
  </v-btn>
18
+ <v-text-field v-model="searchInput" autocomplete="off" placeholder="Search" density="compact" hide-details dense clearable
19
+ class="mx-2" style="width: 200px;" />
18
20
  </template>
19
21
 
20
22
  <template #append>
@@ -219,9 +221,11 @@ const props = defineProps({
219
221
  const site = (useRoute().params.site as string) ?? "";
220
222
  const status = (useRoute().params.status as string) ?? "active";
221
223
 
222
- const { headerSearch } = useLocal();
224
+ const { debounce } = useUtils();
223
225
  const { getAll: _getBuildings, deleteById } = useBuilding();
224
226
 
227
+ const searchInput = ref("");
228
+ const headerSearch = ref("");
225
229
  const page = ref(1);
226
230
  const pages = ref(0);
227
231
  const pageRange = ref("-- - -- of --");
@@ -252,6 +256,15 @@ const {
252
256
 
253
257
  const loading = computed(() => getBuildingReqStatus.value === "pending");
254
258
 
259
+ const debounceSearch = debounce(() => {
260
+ headerSearch.value = searchInput.value?.trim() || "";
261
+ page.value = 1;
262
+ }, 500);
263
+
264
+ watch(searchInput, () => {
265
+ debounceSearch();
266
+ });
267
+
255
268
  watchEffect(() => {
256
269
  if (getBuildingReq.value) {
257
270
  items.value = getBuildingReq.value.items;
@@ -15,6 +15,8 @@
15
15
  <v-btn fab icon density="comfortable" @click="getBuildingUnit()">
16
16
  <v-icon>mdi-refresh</v-icon>
17
17
  </v-btn>
18
+ <v-text-field v-model="searchInput" placeholder="Search" density="compact" hide-details dense clearable
19
+ class="mx-2" style="width: 200px;" />
18
20
  </template>
19
21
 
20
22
  <template #append>
@@ -156,12 +158,12 @@ const status = (useRoute().params.status as string) ?? "active";
156
158
 
157
159
  const { smAndUp } = useDisplay();
158
160
 
159
- const { toOrdinal } = useUtils();
161
+ const { debounce, formatDateDDMMYYYYLocal, toOrdinal } = useUtils();
160
162
 
161
- const { headerSearch } = useLocal();
162
163
  const { getAll, deleteById } = useBuildingUnit();
163
- const { formatDateDDMMYYYYLocal } = useUtils();
164
164
 
165
+ const searchInput = ref("");
166
+ const headerSearch = ref("");
165
167
  const page = ref(1);
166
168
  const pages = ref(0);
167
169
  const pageRange = ref("-- - -- of --");
@@ -192,6 +194,15 @@ const {
192
194
 
193
195
  const loading = computed(() => getBuildingReqStatus.value === "pending");
194
196
 
197
+ const debounceSearch = debounce(() => {
198
+ headerSearch.value = searchInput.value?.trim() || "";
199
+ page.value = 1;
200
+ }, 500);
201
+
202
+ watch(searchInput, () => {
203
+ debounceSearch();
204
+ });
205
+
195
206
  watchEffect(() => {
196
207
  if (getBuildingReq.value) {
197
208
  items.value = getBuildingReq.value.items;
@@ -653,7 +653,15 @@
653
653
  <button
654
654
  class="figma-row-action"
655
655
  type="button"
656
- @click="navigateTo(dashboardPath('incident-reports'))"
656
+ @click="
657
+ navigateTo(
658
+ item.type === 'facility-booking'
659
+ ? `${dashboardPath('facility/bookings')}?booking=${
660
+ item.id
661
+ }`
662
+ : dashboardPath(`incident-reports/${item.id}`)
663
+ )
664
+ "
657
665
  >
658
666
  {{ item.actionLabel || "Review" }}
659
667
  </button>
@@ -1146,6 +1154,8 @@ type DashboardListItem = {
1146
1154
  tone?: string;
1147
1155
  color?: string;
1148
1156
  actionLabel?: string;
1157
+ type?: string;
1158
+ raw?: Record<string, any>;
1149
1159
  };
1150
1160
 
1151
1161
  type TaskItem = {
@@ -1236,21 +1246,36 @@ function canViewWidget(key: string) {
1236
1246
 
1237
1247
  const widgetToModulePermissionMap: Record<string, string[]> = {
1238
1248
  workOrders: ["work-orders:see-all-work-orders"],
1239
- incidents: ["incident-reports:see-incident-reports", "incident-reports:see-all-incident-reports"],
1249
+ incidents: [
1250
+ "incident-reports:see-incident-reports",
1251
+ "incident-reports:see-all-incident-reports",
1252
+ ],
1240
1253
  visitors: ["visitor:see-all-visitor"],
1241
1254
  facilityBookings: ["facility-booking:see-all-facility-booking"],
1242
- patrolCompliance: ["virtual-patrol:see-all-virtual-patrol-logs", "virtual-patrol:see-all-virtual-patrol-route"],
1255
+ patrolCompliance: [
1256
+ "virtual-patrol:see-all-virtual-patrol-logs",
1257
+ "virtual-patrol:see-all-virtual-patrol-route",
1258
+ ],
1243
1259
  staffStatus: ["attendance:see-all-attendance"],
1244
1260
  attendance: ["attendance:see-all-attendance"],
1245
1261
  feedbacks: ["feedbacks:see-all-feedbacks"],
1246
- upcomingEvents: ["bulletin-boards:see-all-bulletin-boards", "bulletin-board:see-all-bulletin-board"],
1262
+ upcomingEvents: [
1263
+ "bulletin-boards:see-all-bulletin-boards",
1264
+ "bulletin-board:see-all-bulletin-board",
1265
+ ],
1247
1266
  workOrderStatus: ["work-orders:see-all-work-orders"],
1248
- activePatrol: ["virtual-patrol:see-all-virtual-patrol-logs", "virtual-patrol:see-all-virtual-patrol-route"],
1249
- taskSchedule: ["cleaning-schedule-mgmt:see-all-schedules"]
1267
+ activePatrol: [
1268
+ "virtual-patrol:see-all-virtual-patrol-logs",
1269
+ "virtual-patrol:see-all-virtual-patrol-route",
1270
+ ],
1271
+ taskSchedule: ["cleaning-schedule-mgmt:see-all-schedules"],
1250
1272
  };
1251
1273
 
1252
1274
  const modulePerms = widgetToModulePermissionMap[key];
1253
- if (modulePerms && modulePerms.some(p => userAppRole.value.permissions?.includes(p))) {
1275
+ if (
1276
+ modulePerms &&
1277
+ modulePerms.some((p) => userAppRole.value.permissions?.includes(p))
1278
+ ) {
1254
1279
  return true;
1255
1280
  }
1256
1281
 
@@ -2034,23 +2059,26 @@ function computeFacilityMetric(): DashboardMetric {
2034
2059
  ).toLowerCase();
2035
2060
  return val === selected.toLowerCase();
2036
2061
  });
2062
+ const ongoing = items.filter((i: any) => {
2063
+ const s = String(i.status || "").toLowerCase();
2064
+ return (
2065
+ s.includes("ongoing") ||
2066
+ s.includes("approved") ||
2067
+ s.includes("in-progress")
2068
+ );
2069
+ }).length;
2070
+ const waitingApproval = items.filter((i: any) => {
2071
+ const s = String(i.status || "").toLowerCase();
2072
+ return (
2073
+ s.includes("pending") || s.includes("review") || s.includes("approval")
2074
+ );
2075
+ }).length;
2076
+
2037
2077
  return {
2038
2078
  ...metric,
2039
- count: items.length,
2040
- ongoing: items.filter((i: any) => {
2041
- const s = String(i.status || "").toLowerCase();
2042
- return (
2043
- s.includes("ongoing") ||
2044
- s.includes("approved") ||
2045
- s.includes("in-progress")
2046
- );
2047
- }).length,
2048
- waitingApproval: items.filter((i: any) => {
2049
- const s = String(i.status || "").toLowerCase();
2050
- return (
2051
- s.includes("pending") || s.includes("review") || s.includes("approval")
2052
- );
2053
- }).length,
2079
+ count: ongoing + waitingApproval,
2080
+ ongoing,
2081
+ waitingApproval,
2054
2082
  };
2055
2083
  }
2056
2084
 
@@ -2413,7 +2441,9 @@ function getMetricMeta(metric: DashboardMetric) {
2413
2441
  parts.push(`${formatNumber(toNumber(metric.ongoing))} ongoing`);
2414
2442
  if (typeof metric.waitingApproval !== "undefined")
2415
2443
  parts.push(
2416
- `${formatNumber(toNumber(metric.waitingApproval))} waiting approval`
2444
+ `${formatNumber(toNumber(metric.waitingApproval))} ${
2445
+ isPropertyMode.value ? "for approval" : "waiting approval"
2446
+ }`
2417
2447
  );
2418
2448
  if (typeof metric.lowStock !== "undefined")
2419
2449
  parts.push(`${formatNumber(toNumber(metric.lowStock))} low stock`);
@@ -2446,6 +2476,10 @@ function getFilteredVisitorMetric(): DashboardMetric {
2446
2476
  };
2447
2477
  }
2448
2478
 
2479
+ if (!items || !items.length) {
2480
+ return metric;
2481
+ }
2482
+
2449
2483
  const filtered = items.filter(
2450
2484
  (item: any) => getVisitorFilterValue(item) === selected
2451
2485
  );
@@ -2487,6 +2521,8 @@ function normalizeListItems(keys: string[]): DashboardListItem[] {
2487
2521
  icon: item.icon || getListIcon(context),
2488
2522
  tone: item.tone,
2489
2523
  actionLabel: item.actionLabel,
2524
+ type: item.type,
2525
+ raw: item,
2490
2526
  }));
2491
2527
  }
2492
2528
 
@@ -2865,16 +2901,26 @@ function dashboardPath(path: string) {
2865
2901
  return `/${props.orgId}/${props.site}/${path}`;
2866
2902
  }
2867
2903
 
2904
+ function getSchedulePath() {
2905
+ const service = props.serviceType;
2906
+ if (service === "cleaning_services") return "cleaning-schedule";
2907
+ if (service === "landscaping_services") return "landscape-schedule";
2908
+ if (service === "pest_control_services") return "pest-schedule";
2909
+ if (service === "pool_maintenance_services") return "pool-schedule";
2910
+ if (service === "mechanical_electrical_services") return "technician-schedule";
2911
+ return "schedule-task";
2912
+ }
2913
+
2868
2914
  function goToDashboardRoute(routeKey: string) {
2869
2915
  if (!props.orgId || !props.site) return;
2870
2916
  const pathMap: Record<string, string> = {
2871
2917
  attendance: "attendance",
2872
2918
  feedbacks: "feedbacks",
2873
- scheduleTask: "schedule-task",
2919
+ scheduleTask: getSchedulePath(),
2874
2920
  virtualPatrol: "virtual-patrol/logs",
2875
2921
  manpower: "manpower-monitoring/attendance",
2876
2922
  incidentReports: "incident-reports",
2877
- "virtual-patrol": "virtual-patrol",
2923
+ "virtual-patrol": "virtual-patrol/logs",
2878
2924
  "work-orders": "work-orders",
2879
2925
  "event-mgmt": "event-mgmt",
2880
2926
  calendar: "calendar",
@@ -2896,10 +2942,15 @@ function goToListItem(item: TaskItem | FeedbackItem, routeKey: string) {
2896
2942
  }
2897
2943
  const pathMap: Record<string, string> = {
2898
2944
  feedbacks: "feedbacks",
2899
- scheduleTask: "schedule-task",
2945
+ scheduleTask: getSchedulePath(),
2900
2946
  };
2901
2947
  const path = pathMap[routeKey] || routeKey;
2902
- router.push(`/${props.orgId}/${props.site}/${path}/${id}`);
2948
+ const scheduleId = item.raw?.schedule?._id || item.raw?.schedule;
2949
+ if (routeKey === "scheduleTask" && scheduleId) {
2950
+ router.push(`/${props.orgId}/${props.site}/${path}/${scheduleId}/${id}`);
2951
+ } else {
2952
+ router.push(`/${props.orgId}/${props.site}/${path}/${id}`);
2953
+ }
2903
2954
  }
2904
2955
 
2905
2956
  // ─── Widget Management ────────────────────────────────────────────────────────
@@ -319,7 +319,7 @@
319
319
  v-model="serviceProvider.type"
320
320
  item-title="title"
321
321
  item-value="value"
322
- :items="natureOfBusiness"
322
+ :items="natureOfBusinessV3"
323
323
  density="comfortable"
324
324
  :rules="[requiredRule]"
325
325
  ></v-select>
@@ -402,7 +402,7 @@
402
402
  variant="flat"
403
403
  color="black"
404
404
  class="text-none"
405
- size="large"
405
+ size="small"
406
406
  :disabled="!validServiceProvider"
407
407
  :loading="disableServiceProvider"
408
408
  @click="submitServiceProviderAdd"
@@ -415,39 +415,68 @@
415
415
  </v-card>
416
416
  </v-dialog>
417
417
 
418
- <v-dialog v-model="createInviteDialog" width="680" persistent>
419
- <v-card width="100%" rounded="lg" class="sp-invite-card">
420
- <v-toolbar flat color="grey-lighten-4" height="76">
421
- <v-row no-gutters class="fill-height px-6" align="center">
422
- <span class="font-weight-bold text-h5">
423
- Invite Service Provider
424
- </span>
425
- </v-row>
426
- </v-toolbar>
427
- <v-card-text class="sp-invite-body">
428
- <v-form
429
- v-model="validServiceProvider"
430
- :disabled="disableServiceProvider"
431
- >
432
- <v-row no-gutters>
433
- <v-col cols="12">
434
- <v-row no-gutters>
435
- <InputLabel class="text-capitalize" title="Email" required />
436
- <v-col cols="12">
437
- <v-text-field
438
- v-model="serviceProviderInvite.email"
439
- variant="outlined"
440
- density="comfortable"
441
- :rules="[requiredRule, emailRule]"
442
- ></v-text-field>
443
- </v-col>
444
- </v-row>
445
- </v-col>
418
+ <v-dialog v-model="createInviteDialog" width="580" persistent>
419
+ <v-card width="100%" rounded="lg" class="sp-invite-card">
420
+ <v-toolbar flat color="grey-lighten-4" height="76">
421
+ <v-row no-gutters class="fill-height px-6" align="center">
422
+ <span class="font-weight-bold text-h5">
423
+ Invite Service Provider
424
+ </span>
425
+ </v-row>
426
+ </v-toolbar>
446
427
 
447
- <v-col cols="12">
448
- <v-divider class="mb-6" />
449
- </v-col>
428
+ <v-card-text class="sp-invite-body">
429
+ <v-form
430
+ v-model="validServiceProvider"
431
+ :disabled="disableServiceProvider"
432
+ >
433
+ <v-row no-gutters>
434
+ <!-- Email -->
435
+ <v-col cols="12">
436
+ <v-row no-gutters>
437
+ <InputLabel class="text-capitalize" title="Email" required />
438
+ <v-col cols="12">
439
+ <v-text-field
440
+ v-model="serviceProviderInvite.email"
441
+ variant="outlined"
442
+ density="comfortable"
443
+ :rules="[requiredRule, emailRule]"
444
+ ></v-text-field>
445
+ </v-col>
446
+ </v-row>
447
+ </v-col>
450
448
 
449
+ <!-- Existing account block -->
450
+ <v-col cols="12" v-if="existingAccount">
451
+ <v-divider class="mb-6" />
452
+
453
+ <div class="sp-existing-title">Existing Account Verified</div>
454
+
455
+ <div class="sp-existing-copy">
456
+ {{ serviceProviderInvite.email }} is already onboarded.
457
+ Sending this invite will add this site to the list of
458
+ locations this company manages.
459
+ </div>
460
+
461
+ <v-row no-gutters>
462
+ <InputLabel title="Organization" />
463
+ <v-col cols="12">
464
+ <v-text-field
465
+ :model-value="existingAccount.text"
466
+ readonly
467
+ variant="outlined"
468
+ density="comfortable"
469
+ />
470
+ </v-col>
471
+ </v-row>
472
+ </v-col>
473
+
474
+ <v-col cols="12">
475
+ <v-divider class="mb-6" />
476
+ </v-col>
477
+
478
+ <!-- App & Site: only shown when no existing account is verified -->
479
+ <template v-if="!existingAccount">
451
480
  <v-col cols="12">
452
481
  <v-row no-gutters>
453
482
  <InputLabel class="text-capitalize" title="App" required />
@@ -460,7 +489,6 @@
460
489
  variant="outlined"
461
490
  density="comfortable"
462
491
  :rules="[requiredRule]"
463
- @update:model-value="loadInviteRoles"
464
492
  ></v-select>
465
493
  </v-col>
466
494
  </v-row>
@@ -483,79 +511,64 @@
483
511
  </v-col>
484
512
  </v-row>
485
513
  </v-col>
514
+ </template>
486
515
 
487
- <v-col cols="12">
488
- <v-row no-gutters>
489
- <InputLabel class="text-capitalize" title="Role" required />
490
- <v-col cols="12">
491
- <v-select
492
- v-model="serviceProviderInvite.role"
493
- :items="serviceProviderInviteRoles"
494
- item-title="name"
495
- item-value="_id"
496
- variant="outlined"
497
- density="comfortable"
498
- :loading="loadingInviteRoles"
499
- :rules="[requiredRule]"
500
- ></v-select>
501
- </v-col>
502
- </v-row>
503
- </v-col>
504
-
505
- <v-col cols="12" class="my-2">
506
- <v-row no-gutters>
507
- <v-col cols="12" class="text-center">
508
- <span
509
- class="text-none text-subtitle-2 font-weight-medium text-error"
510
- >
511
- {{ messageServiceProvider }}
512
- </span>
513
- </v-col>
514
- </v-row>
515
- </v-col>
516
- </v-row>
517
- </v-form>
518
- </v-card-text>
519
-
520
- <v-toolbar flat height="76" class="sp-invite-footer">
521
- <v-row no-gutters class="fill-height">
522
- <v-col cols="6" class="fill-height">
523
- <v-btn
524
- block
525
- variant="flat"
526
- class="text-none sp-invite-footer-btn"
527
- height="76"
528
- @click="setServiceProvider({ mode: 'invite', dialog: false })"
529
- >
530
- Cancel
531
- </v-btn>
532
- </v-col>
533
-
534
- <v-col cols="6" class="fill-height">
535
- <v-btn
536
- block
537
- variant="flat"
538
- class="text-none sp-invite-submit-btn"
539
- height="76"
540
- :disabled="!validServiceProvider"
541
- :loading="disableServiceProvider"
542
- @click="submitServiceProviderInvite()"
543
- >
544
- Submit
545
- </v-btn>
516
+ <!-- Error message -->
517
+ <v-col cols="12" class="my-2">
518
+ <v-row no-gutters>
519
+ <v-col cols="12" class="text-center">
520
+ <span
521
+ class="text-none text-subtitle-2 font-weight-medium text-error"
522
+ >
523
+ {{ messageServiceProvider }}
524
+ </span>
525
+ </v-col>
526
+ </v-row>
546
527
  </v-col>
547
528
  </v-row>
548
- </v-toolbar>
549
- </v-card>
550
- </v-dialog>
529
+ </v-form>
530
+ </v-card-text>
531
+
532
+ <v-toolbar flat height="76" class="sp-invite-footer">
533
+ <v-row no-gutters class="fill-height">
534
+ <v-col cols="6" class="fill-height">
535
+ <v-btn
536
+ block
537
+ variant="flat"
538
+ class="text-none sp-invite-footer-btn"
539
+ height="76"
540
+ @click="setServiceProvider({ mode: 'invite', dialog: false })"
541
+ >
542
+ Back
543
+ </v-btn>
544
+ </v-col>
545
+
546
+ <v-col cols="6" class="fill-height">
547
+ <v-btn
548
+ block
549
+ variant="flat"
550
+ class="text-none sp-invite-submit-btn"
551
+ height="76"
552
+ :disabled="!validServiceProvider"
553
+ :loading="disableServiceProvider"
554
+ @click="submitServiceProviderInvite()"
555
+ >
556
+ Submit
557
+ </v-btn>
558
+ </v-col>
559
+ </v-row>
560
+ </v-toolbar>
561
+ </v-card>
562
+ </v-dialog>
551
563
 
552
564
  <Snackbar v-model="messageSnackbar" :text="message" :color="messageColor" />
553
565
  </template>
554
566
 
555
567
  <script lang="ts" setup>
556
568
  import useServiceProvider from "../composables/useServiceProvider";
569
+ import useUser from "../composables/useUser";
557
570
  import useVerification from "../composables/useVerification";
558
- import useRole from "../composables/useRole";
571
+ // import useRole from "../composables/useRole";
559
572
  import { errorConverter } from "../utils/data";
560
573
 
561
574
  type ListTab = "active" | "pending" | "inactive";
@@ -674,8 +687,9 @@ const headers = [
674
687
  },
675
688
  ];
676
689
 
677
- const { natureOfBusiness } = useLocal();
690
+ const { natureOfBusinessV3 } = useLocal();
678
691
  const { requiredRule, emailRule, debounce } = useUtils();
692
+ const {getUserByEmail} = useUser()
679
693
 
680
694
  const listTab = ref<ListTab>("active");
681
695
  const page = ref(1);
@@ -705,13 +719,12 @@ const serviceProvider = ref({
705
719
  orgName: "",
706
720
  category: "",
707
721
  });
708
- const defaultInviteApp = "property_management_agency";
722
+ const defaultInviteApp = "security_agency";
709
723
  const serviceProviderInvite = ref({
710
724
  email: "",
711
725
  app: defaultInviteApp,
712
726
  siteId: props.siteId,
713
727
  siteName: props.siteName,
714
- role: "",
715
728
  });
716
729
 
717
730
  const {
@@ -722,8 +735,14 @@ const {
722
735
  } = useServiceProvider();
723
736
  const { getAll: getAllMembers } = useMember();
724
737
 
725
- const { getVerifications, cancelUserInvitation } = useVerification();
726
- const { getRoles } = useRole();
738
+ const { getVerifications, cancelUserInvitation, getVerificationByEmail } = useVerification();
739
+ const {
740
+ getOrgsByMembership,
741
+ } = useMember();
742
+
743
+ const existingAccount = ref<any>(null);
744
+ const checkingExistingAccount = ref(false);
745
+ // const { getRoles } = useRole();
727
746
 
728
747
  const { getSiteById } = useSite();
729
748
 
@@ -736,11 +755,53 @@ const searchText = ref("");
736
755
 
737
756
  const createDialog = ref(false);
738
757
  const createInviteDialog = ref(false);
739
- const loadingInviteRoles = ref(false);
740
- const serviceProviderInviteRoles = ref<Array<Record<string, any>>>([]);
758
+ // const loadingInviteRoles = ref(false);
759
+ // const serviceProviderInviteRoles = ref<Array<Record<string, any>>>([]);
760
+
761
+ const { getByUserType } = useMember();
762
+
763
+ async function checkExistingAccount(email: string) {
764
+ // existingAccount.value = null;
765
+
766
+ if (!email.trim() || emailRule(email) !== true) return;
767
+
768
+ checkingExistingAccount.value = true;
769
+
770
+ try {
771
+ const user = await getUserByEmail(email);
772
+
773
+ if (!user?._id) return;
774
+
775
+ const member = await getByUserType(user._id, "organization");
776
+ console.log("member raw:", member);
777
+ console.log("onboardingCompleted:", member?.onboardingCompleted);
778
+
779
+ if (member?.onboardingCompleted) {
780
+ existingAccount.value = {
781
+ _id: member.org,
782
+ text: member.orgName,
783
+ ...member,
784
+ };
785
+ }
786
+ } catch (error) {
787
+ console.error(error);
788
+ existingAccount.value = null;
789
+ } finally {
790
+ checkingExistingAccount.value = false;
791
+ }
792
+ }
793
+
794
+
795
+ watch(
796
+ () => serviceProviderInvite.value.email,
797
+ async (value) => {
798
+ console.log("typing:", value);
799
+ await checkExistingAccount(value);
800
+ }
801
+ );
741
802
 
742
803
  const serviceProviderInviteApps = computed(() =>
743
- natureOfBusiness.map((item) => ({
804
+ natureOfBusinessV3.map((item) => ({
744
805
  ...item,
745
806
  title:
746
807
  item.value === "cleaning_services"
@@ -801,7 +862,7 @@ function rowActionLabel(row: TableRow) {
801
862
 
802
863
  function typeDisplay(type: string, nature?: string) {
803
864
  if (nature && String(nature).trim()) return String(nature);
804
- const list = natureOfBusiness.value as Array<{ title?: string; value?: string }>;
865
+ const list = natureOfBusinessV3.value as Array<{ title?: string; value?: string }>;
805
866
  const hit = list?.find((x) => x.value === type);
806
867
  return hit?.title ?? type ?? "-";
807
868
  }
@@ -822,25 +883,25 @@ function statusChipColor(statusLabel: string) {
822
883
  return "primary";
823
884
  }
824
885
 
825
- async function loadInviteRoles() {
826
- loadingInviteRoles.value = true;
827
- serviceProviderInvite.value.role = "";
828
- try {
829
- const response = await getRoles({
830
- org: props.orgId,
831
- type: serviceProviderInvite.value.app,
832
- limit: 50,
833
- });
834
- serviceProviderInviteRoles.value = response?.items ?? [];
835
- serviceProviderInvite.value.role =
836
- serviceProviderInviteRoles.value[0]?._id ?? "";
837
- } catch (error: any) {
838
- serviceProviderInviteRoles.value = [];
839
- showMessage(errorConverter(error), "error");
840
- } finally {
841
- loadingInviteRoles.value = false;
842
- }
843
- }
886
+ // async function loadInviteRoles() {
887
+ // loadingInviteRoles.value = true;
888
+ // serviceProviderInvite.value.role = "";
889
+ // try {
890
+ // const response = await getRoles({
891
+ // org: props.orgId,
892
+ // type: serviceProviderInvite.value.app,
893
+ // limit: 50,
894
+ // });
895
+ // serviceProviderInviteRoles.value = response?.items ?? [];
896
+ // serviceProviderInvite.value.role =
897
+ // serviceProviderInviteRoles.value[0]?._id ?? "";
898
+ // } catch (error: any) {
899
+ // serviceProviderInviteRoles.value = [];
900
+ // showMessage(errorConverter(error), "error");
901
+ // } finally {
902
+ // loadingInviteRoles.value = false;
903
+ // }
904
+ // }
844
905
 
845
906
  function setInviteSiteName(siteId: string) {
846
907
  const selectedSite = serviceProviderInviteSites.value.find(
@@ -1067,37 +1128,38 @@ function setServiceProvider({
1067
1128
  createDialog.value = dialog;
1068
1129
  }
1069
1130
 
1070
- if (dialog) {
1071
- serviceProvider.value = {
1072
- name: "",
1073
- type: "",
1131
+ if (dialog) {
1132
+ serviceProvider.value = {
1133
+ name: "",
1134
+ type: "",
1135
+ email: "",
1136
+ description: "",
1137
+ orgId: props.orgId,
1138
+ siteId: props.siteId,
1139
+ siteName: site.value?.name ?? "",
1140
+ orgName: "Org Name",
1141
+ category: mode === "add" ? "internal" : "external",
1142
+ };
1143
+
1144
+ if (mode === "invite") {
1145
+ existingAccount.value = null;
1146
+
1147
+ serviceProviderInvite.value = {
1074
1148
  email: "",
1075
- description: "",
1076
- orgId: props.orgId,
1149
+ app: defaultInviteApp,
1077
1150
  siteId: props.siteId,
1078
- siteName: site.value?.name ?? "",
1079
- orgName: "Org Name",
1080
- category: mode === "add" ? "internal" : "external",
1151
+ siteName: site.value?.name || props.siteName,
1081
1152
  };
1082
-
1083
- if (mode === "invite") {
1084
- serviceProviderInvite.value = {
1085
- email: "",
1086
- app: defaultInviteApp,
1087
- siteId: props.siteId,
1088
- siteName: site.value?.name || props.siteName,
1089
- role: "",
1090
- };
1091
- createMoreServiceProvider.value = false;
1092
- void loadInviteRoles();
1093
- }
1094
- return;
1095
1153
  }
1096
1154
 
1097
- serviceProvider.value.description = data.description ?? "";
1098
- serviceProvider.value.email = data.email ?? "";
1099
- serviceProvider.value.name = data.name ?? "";
1100
- serviceProvider.value.type = data.type ?? "";
1155
+ createMoreServiceProvider.value = false;
1156
+ return;
1157
+ }
1158
+
1159
+ serviceProvider.value.description = data.description ?? "";
1160
+ serviceProvider.value.email = data.email ?? "";
1161
+ serviceProvider.value.name = data.name ?? "";
1162
+ serviceProvider.value.type = data.type ?? "";
1101
1163
  }
1102
1164
 
1103
1165
  async function submitServiceProviderAdd() {
@@ -1130,7 +1192,6 @@ async function submitServiceProviderInvite() {
1130
1192
  email: serviceProviderInvite.value.email.trim(),
1131
1193
  name: "",
1132
1194
  app: serviceProviderInvite.value.app,
1133
- role: serviceProviderInvite.value.role,
1134
1195
  orgId: props.orgId,
1135
1196
  siteId: serviceProviderInvite.value.siteId,
1136
1197
  siteName:
@@ -1318,4 +1379,17 @@ async function submitServiceProviderInvite() {
1318
1379
  font-size: 1.5rem;
1319
1380
  font-weight: 700;
1320
1381
  }
1382
+ .sp-existing-title {
1383
+ font-size: 1.125rem;
1384
+ font-weight: 700;
1385
+ color: #101828;
1386
+ margin-bottom: 16px;
1387
+ }
1388
+
1389
+ .sp-existing-copy {
1390
+ font-size: 1rem;
1391
+ color: #344054;
1392
+ line-height: 1.5;
1393
+ margin-bottom: 24px;
1394
+ }
1321
1395
  </style>
@@ -206,7 +206,7 @@ const { canManageSiteInformation,
206
206
  const { getSiteById, updateSitebyId, updateSiteInformation } =
207
207
  useSiteSettings();
208
208
  const { requiredRule } = useUtils();
209
- const { getFileUrl } = useFile();
209
+ const { getFileUrl, getFileById } = useFile();
210
210
 
211
211
  const blocks = ref(0);
212
212
  const guardPosts = ref(0);
@@ -229,6 +229,23 @@ const siteDocuments = ref<string[]>([]);
229
229
  const siteDocumentsNames = ref<Record<string, string>>({});
230
230
  const savingSiteInfo = ref<boolean>(false);
231
231
 
232
+ watch(
233
+ siteDocuments,
234
+ async (ids) => {
235
+ for (const id of ids) {
236
+ if (!siteDocumentsNames.value[id]) {
237
+ try {
238
+ const file = (await getFileById(id)) as any;
239
+ siteDocumentsNames.value[id] = file?.data?.name ?? file?.name ?? "";
240
+ } catch {
241
+ siteDocumentsNames.value[id] = "";
242
+ }
243
+ }
244
+ }
245
+ },
246
+ { deep: true }
247
+ );
248
+
232
249
  const coverPhotoUrl = computed(() =>
233
250
  coverPhoto.value.length > 0 ? getFileUrl(coverPhoto.value[0]) : ""
234
251
  );
@@ -65,6 +65,17 @@ export default function useLocal() {
65
65
  { title: "Pest Control Services", value: "pest_control_services" },
66
66
  { title: "Pool Maintenance Services", value: "pool_maintenance_services" },
67
67
  ];
68
+ const natureOfBusinessV3 = [
69
+ { title: "Security", value: "security_agency" },
70
+ { title: "Cleaning", value: "cleaning_services" },
71
+ {
72
+ title: "Mechanical & Electrical ",
73
+ value: "mechanical_electrical_services",
74
+ },
75
+ { title: "Landscaping", value: "landscaping_services" },
76
+ { title: "Pest Control", value: "pest_control_services" },
77
+ { title: "Pool Maintenance", value: "pool_maintenance_services" },
78
+ ];
68
79
 
69
80
 
70
81
  const landingPage = useCookie("landing-page", cookieConfig);
@@ -143,6 +154,7 @@ export default function useLocal() {
143
154
  headerSearch,
144
155
  natureOfBusiness,
145
156
  natureOfBusinessV2,
157
+ natureOfBusinessV3,
146
158
  landingPage,
147
159
  subjects,
148
160
  };
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.0.13",
5
+ "version": "3.0.15",
6
6
  "author": "7365admin1",
7
7
  "main": "./nuxt.config.ts",
8
8
  "publishConfig": {