@7365admin1/layer-common 3.1.2-staging.38 → 3.1.2

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.
Files changed (32) hide show
  1. package/.github/workflows/publish-staging.yml +0 -11
  2. package/CHANGELOG.md +6 -0
  3. package/components/AddEqupmentForm.vue +1 -52
  4. package/components/CameraMain.vue +6 -5
  5. package/components/DashboardMain.vue +87 -231
  6. package/components/EquipmentManagementMain.vue +0 -56
  7. package/components/InvitationMain.vue +3 -4
  8. package/components/ManageChecklistMain.vue +38 -44
  9. package/components/Nfc/NFCPatrolReportMain.vue +38 -146
  10. package/components/Nfc/PatrolReport/DailyReportTab.vue +6 -10
  11. package/components/Nfc/PatrolReport/MonthlyReportTab.vue +9 -19
  12. package/components/Nfc/PatrolReport/PatrolActivityTable.vue +0 -20
  13. package/components/Nfc/PatrolReport/PatrolReportTab.vue +3 -5
  14. package/components/Nfc/PatrolReport/ReportFilters.vue +20 -52
  15. package/components/Nfc/PatrolReport/SummaryReportTable.vue +0 -22
  16. package/components/PhotoUpload.vue +4 -19
  17. package/components/ServiceProviderMain.vue +25 -59
  18. package/components/VisitorForm.vue +18 -78
  19. package/components/VisitorManagement.vue +16 -12
  20. package/composables/useCleaningSchedulePermission.ts +51 -16
  21. package/composables/useEquipment.ts +0 -2
  22. package/composables/useLocalAuth.ts +1 -1
  23. package/composables/useNFCPatrolDailyReport.ts +4 -3
  24. package/composables/useNFCPatrolMonthlyReport.ts +30 -62
  25. package/composables/useNFCPatrolReport.ts +0 -2
  26. package/composables/useServiceProvider.ts +0 -21
  27. package/package.json +1 -1
  28. package/types/customer.d.ts +1 -2
  29. package/types/equipment.d.ts +1 -5
  30. package/types/nfc-patrol-report.ts +1 -19
  31. package/components/Nfc/PatrolReport/MonthlyReportTable.vue +0 -69
  32. package/components/Nfc/PatrolReport/ReportDatePicker.vue +0 -61
@@ -4,9 +4,9 @@
4
4
  :model-value="filters"
5
5
  :options="options"
6
6
  @update:model-value="$emit('update:filters', $event)"
7
- @export="(type) => $emit('export', type)"
7
+ @export="$emit('export')"
8
8
  />
9
- <div class="report-export">
9
+
10
10
  <v-divider :thickness="1" class="border-opacity-100" />
11
11
 
12
12
  <template v-if="report">
@@ -30,7 +30,6 @@
30
30
  <ReportEmptyState v-else-if="!loading" />
31
31
 
32
32
  <RemarksDialog v-model="dialogRemarks" :remarks="selectedActivityRemarks" />
33
- </div>
34
33
  </div>
35
34
  </template>
36
35
 
@@ -56,7 +55,7 @@ const props = defineProps<{
56
55
 
57
56
  defineEmits<{
58
57
  "update:filters": [value: NFCPatrolReportFilters];
59
- export: [type: "pdf" | "csv"];
58
+ export: [];
60
59
  }>();
61
60
 
62
61
  const {
@@ -78,5 +77,4 @@ watch(
78
77
  },
79
78
  { immediate: true },
80
79
  );
81
-
82
80
  </script>
@@ -16,12 +16,7 @@
16
16
  />
17
17
  </v-col>
18
18
 
19
- <v-col
20
- v-if="showTimeFilter"
21
- cols="12"
22
- md="2"
23
- class="px-md-2 mb-2 mb-md-0"
24
- >
19
+ <v-col cols="12" md="2" class="px-md-2 mb-2 mb-md-0">
25
20
  <v-select
26
21
  :model-value="modelValue.timeRange"
27
22
  :items="options.timeRanges"
@@ -35,14 +30,10 @@
35
30
  />
36
31
  </v-col>
37
32
 
38
- <v-col
39
- v-if="showDateFilter"
40
- cols="12"
41
- md="2"
42
- class="px-md-2 mb-2 mb-md-0"
43
- >
44
- <ReportDatePicker
33
+ <v-col cols="12" md="2" class="px-md-2 mb-2 mb-md-0">
34
+ <v-text-field
45
35
  :model-value="modelValue.date"
36
+ type="date"
46
37
  variant="outlined"
47
38
  density="comfortable"
48
39
  rounded="lg"
@@ -55,31 +46,17 @@
55
46
  <v-spacer />
56
47
 
57
48
  <v-col cols="12" md="2" class="pl-md-2">
58
- <v-menu>
59
- <template #activator="{ props: menuProps }">
60
- <v-btn
61
- v-bind="menuProps"
62
- variant="outlined"
63
- block
64
- size="large"
65
- rounded="lg"
66
- class="text-none"
67
- prepend-icon="mdi-export"
68
- >
69
- Export
70
- </v-btn>
71
- </template>
72
-
73
- <v-list density="compact">
74
- <v-list-item @click="$emit('export', 'pdf')">
75
- <v-list-item-title>PDF</v-list-item-title>
76
- </v-list-item>
77
-
78
- <v-list-item @click="$emit('export', 'csv')">
79
- <v-list-item-title>CSV</v-list-item-title>
80
- </v-list-item>
81
- </v-list>
82
- </v-menu>
49
+ <v-btn
50
+ variant="outlined"
51
+ block
52
+ size="large"
53
+ rounded="lg"
54
+ class="text-none"
55
+ prepend-icon="mdi-export"
56
+ @click="$emit('export')"
57
+ >
58
+ Export
59
+ </v-btn>
83
60
  </v-col>
84
61
  </v-row>
85
62
  </template>
@@ -89,24 +66,15 @@ import type {
89
66
  NFCPatrolReportFilterOptions,
90
67
  NFCPatrolReportFilters,
91
68
  } from "../../../types/nfc-patrol-report";
92
- import ReportDatePicker from "./ReportDatePicker.vue";
93
69
 
94
- const props = withDefaults(
95
- defineProps<{
96
- modelValue: NFCPatrolReportFilters;
97
- options: NFCPatrolReportFilterOptions;
98
- showTimeFilter?: boolean;
99
- showDateFilter?: boolean;
100
- }>(),
101
- {
102
- showTimeFilter: true,
103
- showDateFilter: true,
104
- },
105
- );;
70
+ const props = defineProps<{
71
+ modelValue: NFCPatrolReportFilters;
72
+ options: NFCPatrolReportFilterOptions;
73
+ }>();
106
74
 
107
75
  const emit = defineEmits<{
108
76
  "update:modelValue": [value: NFCPatrolReportFilters];
109
- export: [type: "pdf" | "csv"];
77
+ export: [];
110
78
  }>();
111
79
 
112
80
  function updateFilter(key: keyof NFCPatrolReportFilters, value: unknown) {
@@ -8,8 +8,6 @@
8
8
  <tr>
9
9
  <th>Patrol Route Name</th>
10
10
  <th>Security Check Schedule</th>
11
- <th>Security Personnel</th>
12
- <th>Signature</th>
13
11
  <th>Checked</th>
14
12
  <th>Missed</th>
15
13
  <th>Status</th>
@@ -22,17 +20,6 @@
22
20
  <v-icon size="small" class="mr-1">mdi-clock-outline</v-icon>
23
21
  {{ row.securityCheckSchedule }}
24
22
  </td>
25
- <td>{{ row.guardName || "-" }}</td>
26
- <td>
27
- <v-img
28
- v-if="row.guardSignatureFileId"
29
- :src="getFileUrl(row.guardSignatureFileId)"
30
- :alt="`${row.guardName || 'Guard'} signature`"
31
- class="guard-signature"
32
- contain
33
- />
34
- <span v-else>-</span>
35
- </td>
36
23
  <td>{{ row.checked }}</td>
37
24
  <td>{{ row.missed }}</td>
38
25
  <td>
@@ -58,16 +45,7 @@ defineProps<{
58
45
  rows: NFCPatrolReportSummaryRow[];
59
46
  }>();
60
47
 
61
- const { getFileUrl } = useFile();
62
-
63
48
  function statusClass(status: NFCPatrolReportSummaryStatus) {
64
49
  return status === "Completed" ? "text-success" : "text-error";
65
50
  }
66
51
  </script>
67
-
68
- <style scoped>
69
- .guard-signature {
70
- width: 80px;
71
- height: 40px;
72
- }
73
- </style>
@@ -59,21 +59,6 @@
59
59
  </v-col>
60
60
  </v-row>
61
61
 
62
- <v-dialog v-model="showPhotoPreview" max-width="900">
63
- <v-card>
64
- <v-card-actions class="pa-2 justify-end">
65
- <v-btn
66
- icon="mdi-close"
67
- variant="text"
68
- @click="showPhotoPreview = false"
69
- />
70
- </v-card-actions>
71
- <v-card-text class="pa-2 pt-0">
72
- <v-img :src="selectedPhoto" contain max-height="80vh" />
73
- </v-card-text>
74
- </v-card>
75
- </v-dialog>
76
-
77
62
  <v-dialog v-model="photoOptionsDialog" max-width="420">
78
63
  <v-card>
79
64
  <v-card-title class="d-flex align-center pa-4">
@@ -211,8 +196,6 @@ const photos = ref<string[]>([...props.modelValue]);
211
196
  const photosIds = ref<string[]>([...props.photoIds]);
212
197
  const photoOptionsDialog = ref(false);
213
198
  const showCameraDialog = ref(false);
214
- const showPhotoPreview = ref(false);
215
- const selectedPhoto = ref("");
216
199
  const videoRef = ref<HTMLVideoElement | null>(null);
217
200
  const canvasRef = ref<HTMLCanvasElement | null>(null);
218
201
  const fileInputRef = ref<HTMLInputElement | null>(null);
@@ -222,8 +205,10 @@ const uploading = ref(false);
222
205
  const { addFile } = useFile();
223
206
 
224
207
  function viewPhoto(photoData: string) {
225
- selectedPhoto.value = photoData;
226
- showPhotoPreview.value = true;
208
+ const link = document.createElement("a");
209
+ link.href = photoData;
210
+ link.target = "_blank";
211
+ link.click();
227
212
  }
228
213
 
229
214
  watch(
@@ -548,7 +548,7 @@
548
548
  variant="flat"
549
549
  class="text-none sp-invite-submit-btn"
550
550
  height="76"
551
- :disabled="!canSubmitInvite"
551
+ :disabled="!validServiceProvider"
552
552
  :loading="disableServiceProvider"
553
553
  @click="submitServiceProviderInvite()"
554
554
  >
@@ -574,7 +574,6 @@ type ListTab = "active" | "pending" | "inactive";
574
574
 
575
575
  type TableRow = {
576
576
  _id: string;
577
- userId: string;
578
577
  serviceProviderOrgId: string;
579
578
  companyName: string;
580
579
  email: string;
@@ -734,10 +733,11 @@ const {
734
733
  updateStatus: updateServiceProviderStatus,
735
734
  invite,
736
735
  } = useServiceProvider();
737
- const { getAll: getAllMembers, getAllByUserId } = useMember();
736
+ const { getAll: getAllMembers } = useMember();
738
737
 
739
738
  const { getVerifications, cancelUserInvitation, getVerificationByEmail } =
740
739
  useVerification();
740
+ const { getOrgsByMembership } = useMember();
741
741
 
742
742
  const existingAccount = ref<any>(null);
743
743
  const checkingExistingAccount = ref(false);
@@ -759,77 +759,41 @@ const createInviteDialog = ref(false);
759
759
 
760
760
  const { getByUserType } = useMember();
761
761
  const { getOrgs } = useOrg();
762
- const { getByEmail } = useServiceProvider();
763
762
 
764
763
  async function checkExistingAccount(email: string) {
765
764
  existingAccount.value = null;
766
- messageServiceProvider.value = "";
767
765
 
768
766
  if (!email.trim() || emailRule(email) !== true) return;
769
767
 
770
768
  checkingExistingAccount.value = true;
771
769
 
772
770
  try {
773
- // Check if user exists
774
771
  const user = await getUserByEmail(email);
775
772
 
776
- if (!user?._id) return;
777
-
778
- // Check if this service provider already exists in current org/site
779
- const serviceProviders = await getByEmail({
780
- email,
781
- orgId: props.orgId,
782
- siteId: props.siteId,
783
- });
784
-
785
- console.log("serviceProviders", serviceProviders);
773
+ if (!user?._id) return;
786
774
 
787
- if (serviceProviders?.length) {
788
- messageServiceProvider.value =
789
- "This service provider already exists.";
790
- return;
791
- }
792
-
793
- // Check existing memberships
794
- const members = await getAllByUserId(user._id);
775
+ const orgs = await getOrgs({
776
+ user: user._id,
777
+ });
795
778
 
796
- const appMember = (members.items ?? []).find(
797
- (member: any) => member.type === serviceProviderInvite.value.app
779
+ const matchedOrg = orgs.items?.find(
780
+ (org: any) => org.type === serviceProviderInvite.value.app
798
781
  );
799
782
 
800
- if (!appMember) return;
801
-
802
- // Already belongs to the same org/site
803
- if (
804
- appMember.org === props.orgId &&
805
- (appMember.siteId || "") === (props.siteId || "")
806
- ) {
807
- messageServiceProvider.value =
808
- "This user is already a member of this service provider.";
809
- return;
783
+ if (matchedOrg) {
784
+ existingAccount.value = {
785
+ _id: matchedOrg.value,
786
+ text: matchedOrg.text,
787
+ ...matchedOrg,
788
+ };
810
789
  }
811
-
812
- // Existing account in another org/site
813
- existingAccount.value = {
814
- _id: appMember.org,
815
- text: appMember.orgName,
816
- org: appMember.org,
817
- orgName: appMember.orgName,
818
- siteId: appMember.siteId,
819
- siteName: appMember.siteName,
820
- };
821
790
  } catch (error) {
822
791
  existingAccount.value = null;
823
792
  } finally {
824
793
  checkingExistingAccount.value = false;
825
794
  }
826
795
  }
827
- const canSubmitInvite = computed(() => {
828
- return (
829
- validServiceProvider.value &&
830
- !messageServiceProvider.value
831
- );
832
- });
796
+
833
797
  watch(
834
798
  () => serviceProviderInvite.value.email,
835
799
  async (value) => {
@@ -975,7 +939,6 @@ function formatEmailCell(value: unknown): string {
975
939
  function mapProviderRows(raw: Record<string, any>[]): TableRow[] {
976
940
  return raw.map((row) => ({
977
941
  _id: String(row._id ?? ""),
978
- userId: String(row.user ?? ""),
979
942
  serviceProviderOrgId: String(row.serviceProviderOrgId ?? ""),
980
943
  companyName: row.name ?? "-",
981
944
  email: formatEmailCell(row.email),
@@ -998,7 +961,6 @@ function inviteTypeLabel(t: string) {
998
961
  function mapInviteRows(raw: Record<string, any>[]): TableRow[] {
999
962
  return raw.map((row) => ({
1000
963
  _id: String(row._id ?? ""),
1001
- userId: String(row.user ?? ""),
1002
964
  serviceProviderOrgId: String(row.metadata?.serviceProviderOrgId ?? ""),
1003
965
  companyName: row.metadata?.name || "-",
1004
966
  email: formatEmailCell(row.email),
@@ -1067,12 +1029,16 @@ async function openView(row: TableRow) {
1067
1029
 
1068
1030
  loadingMembers.value = true;
1069
1031
  try {
1070
- const data = await getAllByUserId(row.userId);
1071
-
1032
+ const data = await getAllMembers({
1033
+ page: 1,
1034
+ limit: 1000,
1035
+ org: row.serviceProviderOrgId,
1036
+ status: "active",
1037
+ });
1072
1038
  serviceProviderMembers.value = (data.items ?? []).map((member: any) => ({
1073
- _id: member._id,
1074
- name: member.name || "-",
1075
- role: member.role || "-",
1039
+ _id: String(member._id ?? ""),
1040
+ name: member.name || member.fullName || member.email || "-",
1041
+ role: member.roleName || member.role?.name || "-",
1076
1042
  }));
1077
1043
  } catch (error: any) {
1078
1044
  showMessage(errorConverter(error), "error");
@@ -36,17 +36,10 @@
36
36
  </template>
37
37
 
38
38
  <v-list v-if="nricSearchResults.length" class="pa-1 phone-search-results">
39
- <div class="search-results-scroll">
40
- <v-list-item v-for="(item, index) in nricSearchResults" :key="item._id || index"
41
- @click="selectNricSearchResult(item)" class="cursor-pointer nric-search-item">
42
- <VisitorSearchResultSummary :item="item" />
43
- </v-list-item>
44
- </div>
45
- <div class="search-results-close pa-1">
46
- <v-btn block variant="flat" color="red" @click.stop="closeAutofillSearchResults('nric')">
47
- Close
48
- </v-btn>
49
- </div>
39
+ <v-list-item v-for="(item, index) in nricSearchResults" :key="item._id || index"
40
+ @click="selectNricSearchResult(item)" class="cursor-pointer nric-search-item">
41
+ <VisitorSearchResultSummary :item="item" />
42
+ </v-list-item>
50
43
  </v-list>
51
44
  </v-menu>
52
45
  </v-col>
@@ -65,17 +58,10 @@
65
58
  </template>
66
59
 
67
60
  <v-list v-if="phoneSearchResults.length" class="pa-1 phone-search-results">
68
- <div class="search-results-scroll">
69
- <v-list-item v-for="(item, index) in phoneSearchResults" :key="item._id || index"
70
- @click="selectPhoneNumberSearchResult(item)" class="cursor-pointer nric-search-item">
71
- <VisitorSearchResultSummary :item="item" />
72
- </v-list-item>
73
- </div>
74
- <div class="search-results-close pa-1">
75
- <v-btn block variant="flat" color="red" @click.stop="closeAutofillSearchResults('contact')">
76
- Close
77
- </v-btn>
78
- </div>
61
+ <v-list-item v-for="(item, index) in phoneSearchResults" :key="item._id || index"
62
+ @click="selectPhoneNumberSearchResult(item)" class="cursor-pointer nric-search-item">
63
+ <VisitorSearchResultSummary :item="item" />
64
+ </v-list-item>
79
65
  </v-list>
80
66
  </v-menu>
81
67
  </v-col>
@@ -91,23 +77,15 @@
91
77
  <v-menu v-model="vehicleSearchMenu" location="bottom" offset-y :close-on-content-click="false">
92
78
  <template #activator="{ props }">
93
79
  <InputVehicleNumber v-bind="props" v-model="visitor.plateNumber" density="comfortable"
94
- @update:model-value="handleUpdateVehicleNumber" @focus="handleFocusPlateNumber"
80
+ @update:model-value="handleUpdateVehicleNumber" @focus="isPlateNumberFieldFocused = true"
95
81
  @blur="isPlateNumberFieldFocused = false" />
96
82
  </template>
97
83
 
98
84
  <v-list v-if="vehicleSearchResults.length" class="pa-1 phone-search-results">
99
- <div class="search-results-scroll">
100
- <v-list-item v-for="(item, index) in vehicleSearchResults" :key="item._id || index"
101
- @click="selectPlateNumberSearchResult(item)" class="cursor-pointer nric-search-item">
102
- <VisitorSearchResultSummary :item="item" />
103
- </v-list-item>
104
- </div>
105
- <div class="search-results-close pa-1">
106
- <v-btn block variant="flat" color="red"
107
- @click.stop="closeAutofillSearchResults('vehicleNumber')">
108
- Close
109
- </v-btn>
110
- </div>
85
+ <v-list-item v-for="(item, index) in vehicleSearchResults" :key="item._id || index"
86
+ @click="selectPlateNumberSearchResult(item)" class="cursor-pointer nric-search-item">
87
+ <VisitorSearchResultSummary :item="item" />
88
+ </v-list-item>
111
89
  </v-list>
112
90
  </v-menu>
113
91
  </v-col>
@@ -330,10 +308,10 @@
330
308
 
331
309
  <div class="nric-selected-person d-flex align-center justify-space-between ga-3 mb-5">
332
310
  <span>{{ selectedNricSearchResult.name || "Unknown" }}</span>
333
- <span v-if="!visitor.nric || currentAutofillSource === 'nric'" class="text-no-wrap">NRIC: {{ selectedNricSearchResult.nric || "N/A" }}</span>
311
+ <span class="text-no-wrap">NRIC: {{ selectedNricSearchResult.nric || "N/A" }}</span>
334
312
  </div>
335
313
 
336
- <template v-if="(!visitor.contact || currentAutofillSource === 'contact') && selectedNricContactOptions.length >= 1">
314
+ <template v-if="!visitor.contact && selectedNricContactOptions.length >= 1">
337
315
  <h3 class="nric-options-section-title font-weight-bold mb-2">Contact</h3>
338
316
  <v-radio-group v-model="selectedNricContact" hide-details color="success" class="nric-option-group">
339
317
  <v-radio v-for="contact in selectedNricContactOptions" :key="contact" :label="contact" :value="contact"
@@ -341,7 +319,7 @@
341
319
  </v-radio-group>
342
320
  </template>
343
321
 
344
- <template v-if="(!visitor.plateNumber || currentAutofillSource === 'vehicleNumber') && selectedNricPlateOptions.length >= 1">
322
+ <template v-if="!visitor.plateNumber && selectedNricPlateOptions.length >= 1">
345
323
  <h3 class="nric-options-section-title font-weight-bold mb-2 mt-5">Vehicle</h3>
346
324
  <v-radio-group v-model="selectedNricPlate" hide-details color="success" class="nric-option-group">
347
325
  <v-radio v-for="plate in selectedNricPlateOptions" :key="plate" :label="plate" :value="plate"
@@ -1066,8 +1044,8 @@ function selectAutofillSearchResult(item: Partial<TPeople>, source: Exclude<Auto
1066
1044
  const selectedPlate =
1067
1045
  findMatchingPlateOption(plateOptions, visitor.plateNumber) || plateOptions[0] || "";
1068
1046
 
1069
- const needsContactChoice = (!visitor.contact?.trim() || source === 'contact') && contactOptions.length > 1;
1070
- const needsPlateChoice = (!visitor.plateNumber?.trim() || source === 'vehicleNumber') && plateOptions.length > 1;
1047
+ const needsContactChoice = !visitor.contact?.trim() && contactOptions.length > 1;
1048
+ const needsPlateChoice = !visitor.plateNumber?.trim() && plateOptions.length > 1;
1071
1049
 
1072
1050
  if (needsContactChoice || needsPlateChoice) {
1073
1051
  nricSearchMenu.value = false;
@@ -1088,23 +1066,6 @@ function selectAutofillSearchResult(item: Partial<TPeople>, source: Exclude<Auto
1088
1066
  });
1089
1067
  }
1090
1068
 
1091
- function closeAutofillSearchResults(source: Exclude<AutofillSource, null>) {
1092
- if (source === "nric") {
1093
- nricSearchMenu.value = false;
1094
- nricSearchResults.value = [];
1095
- }
1096
-
1097
- if (source === "contact") {
1098
- phoneSearchMenu.value = false;
1099
- phoneSearchResults.value = [];
1100
- }
1101
-
1102
- if (source === "vehicleNumber") {
1103
- vehicleSearchMenu.value = false;
1104
- vehicleSearchResults.value = [];
1105
- }
1106
- }
1107
-
1108
1069
  function closeNricAutofillOptions() {
1109
1070
  dialog.nricAutofillOptions = false;
1110
1071
  selectedNricSearchResult.value = null;
@@ -1542,15 +1503,6 @@ function handleUpdateVehicleNumber() {
1542
1503
  debounceFetchPlateNumber();
1543
1504
  }
1544
1505
 
1545
- const handleFocusPlateNumber = () => {
1546
- isPlateNumberFieldFocused.value = true;
1547
- if (prop.mode === 'register') {
1548
-
1549
- handleUpdateVehicleNumber();
1550
- }
1551
- };
1552
-
1553
-
1554
1506
  function backToSelection() {
1555
1507
  emit("back");
1556
1508
  message.value = "";
@@ -2156,22 +2108,10 @@ onMounted(() => {
2156
2108
  }
2157
2109
 
2158
2110
  .phone-search-results {
2159
- display: flex;
2160
- flex-direction: column;
2161
2111
  max-height: 400px;
2162
- overflow: hidden;
2163
- }
2164
-
2165
- .search-results-scroll {
2166
- flex: 1 1 auto;
2167
- min-height: 0;
2168
2112
  overflow-y: auto;
2169
2113
  }
2170
2114
 
2171
- .search-results-close {
2172
- flex: 0 0 auto;
2173
- }
2174
-
2175
2115
  .nric-options-card {
2176
2116
  border-radius: 16px !important;
2177
2117
  }
@@ -825,8 +825,10 @@
825
825
  item-title="label"
826
826
  item-value="value"
827
827
  v-model="pass.status"
828
- :disabled="pass.status == 'Removed'"
829
- />
828
+ :disabled="
829
+ selectedVisitorObject.checkOut || pass.status == 'Removed'
830
+ "
831
+ ></v-select>
830
832
  <v-textarea
831
833
  v-if="pass.status === 'Lost' || pass.status === 'Damaged'"
832
834
  no-resize
@@ -834,7 +836,8 @@
834
836
  class="w-100"
835
837
  density="compact"
836
838
  v-model="pass.remarks"
837
- />
839
+ :disabled="selectedVisitorObject.checkOut"
840
+ ></v-textarea>
838
841
  </v-row>
839
842
  </div>
840
843
  <div v-if="keyReturnStatuses.length > 0" class="mb-2">
@@ -861,8 +864,10 @@
861
864
  item-title="label"
862
865
  item-value="value"
863
866
  v-model="key.status"
864
- :disabled="key.status == 'Removed'"
865
- />
867
+ :disabled="
868
+ selectedVisitorObject.checkOut || key.status == 'Removed'
869
+ "
870
+ ></v-select>
866
871
  <v-textarea
867
872
  v-if="key.status === 'Lost' || key.status === 'Damaged'"
868
873
  no-resize
@@ -870,7 +875,8 @@
870
875
  class="w-100"
871
876
  density="compact"
872
877
  v-model="key.remarks"
873
- />
878
+ :disabled="selectedVisitorObject.checkOut"
879
+ ></v-textarea>
874
880
  </v-row>
875
881
  </div>
876
882
 
@@ -880,11 +886,11 @@
880
886
  color="blue"
881
887
  density="comfortable"
882
888
  class="text-capitalize"
889
+ :disabled="selectedVisitorObject.checkOut"
883
890
  :loading="loading.updatingPassKeys"
884
891
  @click.stop="handleUpdatePassKeys"
892
+ >Update Pass/Keys</v-btn
885
893
  >
886
- Update Pass/Keys
887
- </v-btn>
888
894
  </v-row>
889
895
  </v-card-text>
890
896
  <v-toolbar class="pa-0" density="compact">
@@ -894,9 +900,8 @@
894
900
  variant="text"
895
901
  block
896
902
  @click="dialog.returnPassesKeys = false"
903
+ >Close</v-btn
897
904
  >
898
- Close
899
- </v-btn>
900
905
  </v-col>
901
906
  <v-col cols="6">
902
907
  <v-btn
@@ -910,9 +915,8 @@
910
915
  !canConfirmCheckout || selectedVisitorObject.checkOut
911
916
  "
912
917
  @click="proceedCheckout"
918
+ >Confirm Checkout</v-btn
913
919
  >
914
- Confirm Checkout
915
- </v-btn>
916
920
  </v-col>
917
921
  </v-row>
918
922
  </v-toolbar>