@7365admin1/layer-common 1.8.0

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 (198) hide show
  1. package/.changeset/README.md +8 -0
  2. package/.changeset/config.json +11 -0
  3. package/.editorconfig +12 -0
  4. package/.github/workflows/main.yml +17 -0
  5. package/.github/workflows/publish.yml +39 -0
  6. package/.nuxtrc +1 -0
  7. package/.playground/app.vue +41 -0
  8. package/.playground/eslint.config.mjs +6 -0
  9. package/.playground/nuxt.config.ts +22 -0
  10. package/.playground/pages/feedback.vue +30 -0
  11. package/CHANGELOG.md +263 -0
  12. package/README.md +73 -0
  13. package/app.vue +3 -0
  14. package/components/AccessCardAddForm.vue +363 -0
  15. package/components/AccessManagement.vue +420 -0
  16. package/components/Avatar/Main.vue +68 -0
  17. package/components/BillingMain.vue +66 -0
  18. package/components/BtnUploadFile.vue +139 -0
  19. package/components/BuildingForm.vue +303 -0
  20. package/components/BuildingManagement/buildings.vue +335 -0
  21. package/components/BuildingManagement/units.vue +350 -0
  22. package/components/BuildingUnitFormAdd.vue +441 -0
  23. package/components/BuildingUnitFormEdit.vue +429 -0
  24. package/components/CameraForm.vue +264 -0
  25. package/components/CameraMain.vue +352 -0
  26. package/components/Card/DeleteConfirmation.vue +51 -0
  27. package/components/Card/MemberInfoSummary.vue +44 -0
  28. package/components/Card/Toggle.vue +25 -0
  29. package/components/Chat/Bubbles.vue +53 -0
  30. package/components/Chat/Information.vue +416 -0
  31. package/components/Chat/ListCard.vue +62 -0
  32. package/components/Chat/Message.vue +158 -0
  33. package/components/Chat/Navigation.vue +150 -0
  34. package/components/ConfirmDialog.vue +66 -0
  35. package/components/Container/Standard.vue +33 -0
  36. package/components/DashboardPlaceholder.vue +1524 -0
  37. package/components/Dialog/DeleteConfirmation.vue +51 -0
  38. package/components/Dialog/ReplaceAutofillPrompt.vue +49 -0
  39. package/components/Dialog/UpdateMoreAction.vue +103 -0
  40. package/components/DocumentForm.vue +187 -0
  41. package/components/DocumentManagement.vue +376 -0
  42. package/components/Editor.vue +95 -0
  43. package/components/EntryPassMain.vue +518 -0
  44. package/components/Feedback/Form.vue +173 -0
  45. package/components/FeedbackDetail.vue +599 -0
  46. package/components/FeedbackMain.vue +588 -0
  47. package/components/FormDialog.vue +65 -0
  48. package/components/ImageCarousel.vue +138 -0
  49. package/components/Input/Date.vue +177 -0
  50. package/components/Input/DateTimePicker.vue +131 -0
  51. package/components/Input/File.vue +236 -0
  52. package/components/Input/FileV2.vue +234 -0
  53. package/components/Input/InputPhoneNumberV2.vue +164 -0
  54. package/components/Input/ListGroupSelection.vue +96 -0
  55. package/components/Input/NRICNumber.vue +53 -0
  56. package/components/Input/NewDate.vue +123 -0
  57. package/components/Input/Number.vue +124 -0
  58. package/components/Input/Password.vue +22 -0
  59. package/components/Input/PhoneNumber.vue +188 -0
  60. package/components/Input/VehicleNumber.vue +49 -0
  61. package/components/InputLabel.vue +22 -0
  62. package/components/InvitationForm.vue +359 -0
  63. package/components/InvitationMain.vue +310 -0
  64. package/components/Layout/Header.vue +129 -0
  65. package/components/Layout/NavigationDrawer.vue +44 -0
  66. package/components/ListItem.vue +35 -0
  67. package/components/ListView.vue +87 -0
  68. package/components/LocalPagination.vue +31 -0
  69. package/components/MemberMain.vue +459 -0
  70. package/components/NFC/NFCPatrolReportMain.vue +591 -0
  71. package/components/NFC/NFCPatrolRouteForm.vue +596 -0
  72. package/components/NFC/NFCPatrolRouteMain.vue +539 -0
  73. package/components/NFC/NFCTagForm.vue +236 -0
  74. package/components/NFC/NFCTagMain.vue +337 -0
  75. package/components/NFC/PatrolSettings.vue +130 -0
  76. package/components/NavigationItem.vue +83 -0
  77. package/components/NumberSettingField.vue +107 -0
  78. package/components/OnlineFormConfigurationForm.vue +290 -0
  79. package/components/OnlineFormsConfiguration.vue +429 -0
  80. package/components/PeopleForm.vue +452 -0
  81. package/components/PlaceholderComponent.vue +34 -0
  82. package/components/RolePermissionFormCreate.vue +161 -0
  83. package/components/RolePermissionFormPreviewUpdate.vue +183 -0
  84. package/components/RolePermissionMain.vue +361 -0
  85. package/components/SearchVehicleNumberUser.vue +91 -0
  86. package/components/ServiceProviderFormCreate.vue +154 -0
  87. package/components/ServiceProviderMain.vue +547 -0
  88. package/components/SignaturePad.vue +73 -0
  89. package/components/Snackbar.vue +23 -0
  90. package/components/SpecificAttr.vue +53 -0
  91. package/components/SupplyManagement.vue +292 -0
  92. package/components/SwitchContext.vue +108 -0
  93. package/components/TableList.vue +150 -0
  94. package/components/TableListSecondary.vue +164 -0
  95. package/components/TableMain.vue +142 -0
  96. package/components/TableWithButton.vue +94 -0
  97. package/components/VehicleUpdateMoreAction.vue +84 -0
  98. package/components/VideoPlayer.vue +125 -0
  99. package/components/VisitorForm.vue +659 -0
  100. package/components/VisitorFormSelection.vue +53 -0
  101. package/components/VisitorManagement.vue +490 -0
  102. package/components/WorkOrder/Create.vue +284 -0
  103. package/components/WorkOrder/Detail.vue +71 -0
  104. package/components/WorkOrder/ListView.vue +96 -0
  105. package/components/WorkOrder/Main.vue +489 -0
  106. package/components/Workorder.vue +1 -0
  107. package/composables/useAddress.ts +107 -0
  108. package/composables/useBuilding.ts +250 -0
  109. package/composables/useBuildingUnit.ts +116 -0
  110. package/composables/useCard.ts +46 -0
  111. package/composables/useCommonPermission.ts +207 -0
  112. package/composables/useCustomer.ts +113 -0
  113. package/composables/useCustomerSite.ts +56 -0
  114. package/composables/useDashboard.ts +31 -0
  115. package/composables/useDashboardData.ts +425 -0
  116. package/composables/useDocument.ts +57 -0
  117. package/composables/useFacility.ts +246 -0
  118. package/composables/useFeedback.ts +119 -0
  119. package/composables/useFile.ts +55 -0
  120. package/composables/useInvoice.ts +18 -0
  121. package/composables/useLocal.ts +131 -0
  122. package/composables/useLocalAuth.ts +137 -0
  123. package/composables/useLocalSetup.ts +13 -0
  124. package/composables/useMember.ts +111 -0
  125. package/composables/useNFCPatrolRoute.ts +77 -0
  126. package/composables/useNFCPatrolSettings.ts +19 -0
  127. package/composables/useNFCPatrolTag.ts +53 -0
  128. package/composables/useOnlineForm.ts +67 -0
  129. package/composables/useOrg.ts +129 -0
  130. package/composables/usePDFDownload.ts +25 -0
  131. package/composables/usePaymentMethod.ts +101 -0
  132. package/composables/usePeople.ts +81 -0
  133. package/composables/usePermission.ts +54 -0
  134. package/composables/usePhoneCountries.ts +561 -0
  135. package/composables/usePrice.ts +15 -0
  136. package/composables/usePromoCode.ts +36 -0
  137. package/composables/useRecapPermission.ts +26 -0
  138. package/composables/useRole.ts +104 -0
  139. package/composables/useSecurityUtils.ts +18 -0
  140. package/composables/useServiceProvider.ts +224 -0
  141. package/composables/useSite.ts +109 -0
  142. package/composables/useSiteEntryPassSettings.ts +46 -0
  143. package/composables/useSiteSettings.ts +123 -0
  144. package/composables/useSubscription.ts +150 -0
  145. package/composables/useUser.ts +132 -0
  146. package/composables/useUtils.ts +445 -0
  147. package/composables/useVerification.ts +34 -0
  148. package/composables/useVisitor.ts +120 -0
  149. package/composables/useWorkOrder.ts +85 -0
  150. package/error.vue +41 -0
  151. package/layouts/plain.vue +7 -0
  152. package/middleware/01.auth.ts +20 -0
  153. package/middleware/02.org.ts +21 -0
  154. package/middleware/03.customer.ts +13 -0
  155. package/middleware/member.ts +4 -0
  156. package/nuxt.config.ts +54 -0
  157. package/package.json +39 -0
  158. package/pages/index.vue +3 -0
  159. package/pages/payment-method-linked.vue +31 -0
  160. package/pages/require-customer.vue +56 -0
  161. package/pages/require-organization-membership.vue +47 -0
  162. package/pages/unauthorized.vue +29 -0
  163. package/plugins/API.ts +21 -0
  164. package/plugins/iconify.client.ts +5 -0
  165. package/plugins/secure-member.client.ts +86 -0
  166. package/plugins/vuetify.ts +62 -0
  167. package/public/bg-camera.jpg +0 -0
  168. package/public/bg-city.jpg +0 -0
  169. package/public/bg-condo.jpg +0 -0
  170. package/public/images/icons/delete-icon.png +0 -0
  171. package/public/sprite.svg +1 -0
  172. package/tsconfig.json +3 -0
  173. package/types/address.d.ts +13 -0
  174. package/types/building.d.ts +27 -0
  175. package/types/camera.d.ts +31 -0
  176. package/types/card.d.ts +22 -0
  177. package/types/customer.d.ts +27 -0
  178. package/types/document.d.ts +6 -0
  179. package/types/feedback.d.ts +68 -0
  180. package/types/local.d.ts +74 -0
  181. package/types/member.d.ts +21 -0
  182. package/types/online-form.d.ts +15 -0
  183. package/types/org.d.ts +13 -0
  184. package/types/people.d.ts +24 -0
  185. package/types/permission.d.ts +25 -0
  186. package/types/phone-number.d.ts +10 -0
  187. package/types/price.d.ts +17 -0
  188. package/types/promo-code.d.ts +19 -0
  189. package/types/role.d.ts +11 -0
  190. package/types/select.d.ts +4 -0
  191. package/types/service-provider.d.ts +15 -0
  192. package/types/site.d.ts +20 -0
  193. package/types/subscription.d.ts +23 -0
  194. package/types/user.d.ts +19 -0
  195. package/types/verification.d.ts +20 -0
  196. package/types/visitor.d.ts +42 -0
  197. package/types/work-order.d.ts +42 -0
  198. package/utils/phoneMasks.ts +1703 -0
@@ -0,0 +1,359 @@
1
+ <template>
2
+ <v-card width="100%">
3
+ <v-toolbar>
4
+ <v-row no-gutters class="fill-height px-6" align="center">
5
+ <span class="font-weight-bold text-h5">
6
+ {{ props.title }}
7
+ </span>
8
+ </v-row>
9
+ </v-toolbar>
10
+ <v-card-text style="max-height: 100vh; overflow-y: auto">
11
+ <v-form v-model="validForm" ref="form" :disabled="disable">
12
+ <v-row no-gutters>
13
+ <v-col cols="12" class="mt-2">
14
+ <v-row no-gutters>
15
+ <InputLabel class="text-capitalize" title="Email" required />
16
+ <v-col cols="12">
17
+ <v-text-field
18
+ v-model="invite.email"
19
+ density="comfortable"
20
+ :rules="[requiredRule, emailRule]"
21
+ :loading="loading.verifyingEmail"
22
+ ></v-text-field>
23
+ </v-col>
24
+ </v-row>
25
+ </v-col>
26
+
27
+ <v-col v-if="APP === 'organization'" cols="12" class="mt-2">
28
+ <v-row no-gutters>
29
+ <InputLabel class="text-capitalize" title="App" required />
30
+ <v-col cols="12">
31
+ <v-autocomplete
32
+ v-model="invite.app"
33
+ density="comfortable"
34
+ :rules="[requiredRule]"
35
+ :items="apps"
36
+ @update:model-value="handleUpdateApp"
37
+ ></v-autocomplete>
38
+ </v-col>
39
+ </v-row>
40
+ </v-col>
41
+
42
+ <v-col cols="12">
43
+ <v-row no-gutters>
44
+ <InputLabel class="text-capitalize" title="Role" />
45
+ <v-col cols="12">
46
+ <v-autocomplete
47
+ v-model="invite.role"
48
+ :items="roles"
49
+ item-title="name"
50
+ item-value="_id"
51
+ :rules="[requiredRule]"
52
+ density="comfortable"
53
+ ></v-autocomplete>
54
+ </v-col>
55
+ </v-row>
56
+ </v-col>
57
+
58
+ <v-col v-if="hasSite" cols="12">
59
+ <v-row no-gutters>
60
+ <InputLabel class="text-capitalize" title="Site" />
61
+ <v-col cols="12">
62
+ <v-autocomplete
63
+ v-model="invite.site"
64
+ :items="sites"
65
+ density="comfortable"
66
+ :rules="[requiredRule]"
67
+ @update:model-value="handleUpdateSite"
68
+ ></v-autocomplete>
69
+ </v-col>
70
+ </v-row>
71
+ </v-col>
72
+
73
+ <v-col cols="12" class="mt-2">
74
+ <v-checkbox v-model="createMore" density="comfortable" hide-details>
75
+ <template #label>
76
+ <span class="text-subtitle-2 font-weight-bold">
77
+ Create more
78
+ </span>
79
+ </template>
80
+ </v-checkbox>
81
+ </v-col>
82
+
83
+ <v-col cols="12" class="my-2">
84
+ <v-row no-gutters>
85
+ <v-col cols="12" class="text-center">
86
+ <span
87
+ class="text-none text-subtitle-2 font-weight-medium text-error"
88
+ >
89
+ {{ message }}
90
+ </span>
91
+ </v-col>
92
+ </v-row>
93
+ </v-col>
94
+ </v-row>
95
+ </v-form>
96
+ </v-card-text>
97
+
98
+ <v-toolbar density="compact">
99
+ <v-row no-gutters>
100
+ <v-col cols="6">
101
+ <v-btn
102
+ tile
103
+ block
104
+ variant="text"
105
+ class="text-none"
106
+ size="48"
107
+ @click="cancel"
108
+ >
109
+ Cancel
110
+ </v-btn>
111
+ </v-col>
112
+
113
+ <v-col cols="6">
114
+ <v-btn
115
+ tile
116
+ block
117
+ variant="flat"
118
+ color="black"
119
+ class="text-none"
120
+ size="48"
121
+ :disabled="!validForm"
122
+ :loading="loading.submittingForm"
123
+ @click="submit"
124
+ >
125
+ Submit
126
+ </v-btn>
127
+ </v-col>
128
+ </v-row>
129
+ </v-toolbar>
130
+ </v-card>
131
+ </template>
132
+
133
+ <script setup lang="ts">
134
+ const APP = useRuntimeConfig().public.APP;
135
+ const props = defineProps({
136
+ title: {
137
+ type: String,
138
+ default: "Invite Form",
139
+ },
140
+ mode: {
141
+ type: String,
142
+ default: "create",
143
+ },
144
+ permissions: {
145
+ type: Object,
146
+ default: () => ({}),
147
+ },
148
+ app: {
149
+ type: String,
150
+ default: "organization",
151
+ },
152
+ org: {
153
+ type: String,
154
+ default: "",
155
+ },
156
+ site: {
157
+ type: Object as PropType<TCustomerSite>,
158
+ default: () => ({
159
+ name: "",
160
+ site: "",
161
+ siteOrg: "",
162
+ siteOrgName: "",
163
+ org: "",
164
+ }),
165
+ },
166
+ invite: {
167
+ type: Object as PropType<TVerification>,
168
+ default: () => ({
169
+ email: "",
170
+ metadata: { app: "organization", role: "" },
171
+ }),
172
+ },
173
+ });
174
+
175
+ const emit = defineEmits(["cancel", "success", "success:create-more"]);
176
+
177
+ const validForm = ref(false);
178
+ const form = ref<HTMLFormElement | null>(null);
179
+ const app = computed(() => useRuntimeConfig().public.APP ?? "");
180
+
181
+ const loading = reactive({
182
+ submittingForm: false,
183
+ verifyingEmail: false,
184
+ });
185
+
186
+ const invite = ref<Record<string, any>>({
187
+ email: "",
188
+ app: "",
189
+ role: "",
190
+ org: "",
191
+ site: "",
192
+ siteName: "",
193
+ });
194
+
195
+ invite.value.app = props.app;
196
+ invite.value.org = props.org ?? "";
197
+
198
+ if (props.mode === "edit") {
199
+ invite.value.email = props.invite.email;
200
+ invite.value.app = props.invite.metadata?.app;
201
+ invite.value.role = props.invite.metadata?.role;
202
+ }
203
+
204
+ const { natureOfBusiness } = useLocal();
205
+ const { orgNature } = useLocalSetup();
206
+
207
+ const apps = computed(() => {
208
+ const items = [];
209
+ items.unshift({ title: "Organization", value: "organization" });
210
+
211
+ const _org = "security_agency";
212
+
213
+ if (props.app === _org || orgNature.value === _org) {
214
+ items.push({ title: "Security Agency", value: _org });
215
+ }
216
+
217
+ const _cleaning = "cleaning_services";
218
+
219
+ if (props.app === _cleaning || orgNature.value === _cleaning) {
220
+ items.push({ title: "Cleaning Services", value: _cleaning });
221
+ }
222
+
223
+ const _property = "property_management_agency";
224
+
225
+ if (props.app === _property || orgNature.value === _property) {
226
+ items.push({ title: "Property Management Agency", value: _property });
227
+ }
228
+
229
+ const _mechanical = "mechanical_electrical_services";
230
+
231
+ if (props.app === _mechanical || orgNature.value === _mechanical) {
232
+ items.push({
233
+ title: "Mechanical & Electrical Services",
234
+ value: _mechanical,
235
+ });
236
+ }
237
+
238
+ const _pestControl = "pest_control_services";
239
+
240
+ if (props.app === _pestControl || orgNature.value === _pestControl) {
241
+ items.push({
242
+ title: "Pest Control Services",
243
+ value: _pestControl,
244
+ });
245
+ }
246
+
247
+ const _landscaping = "landscaping_services";
248
+
249
+ if (props.app === _landscaping || orgNature.value === _landscaping) {
250
+ items.push({
251
+ title: "Landscaping Services",
252
+ value: _landscaping,
253
+ });
254
+ }
255
+
256
+ const _poolMaintenance = "pool_maintenance_services";
257
+
258
+ if (props.app === _poolMaintenance || orgNature.value === _poolMaintenance) {
259
+ items.push({
260
+ title: "Pool Maintenance Services",
261
+ value: _poolMaintenance,
262
+ });
263
+ }
264
+
265
+ return items;
266
+ });
267
+
268
+ const hasSite = computed(() => {
269
+ return natureOfBusiness.map((i) => i.value).includes(invite.value.app);
270
+ });
271
+
272
+ const sites = ref<Array<Record<string, any>>>([]);
273
+
274
+ const { getAll: getAllCustomerSite } = useCustomerSite();
275
+
276
+ const { data: siteData, refresh: refreshSiteData } = await useLazyAsyncData(
277
+ "get-sites-by-org-" + props.org,
278
+ async () => await getAllCustomerSite({ org: props.org, limit: 50 })
279
+ );
280
+
281
+ watchEffect(() => {
282
+ if (siteData.value) {
283
+ sites.value = siteData.value.items.map((i: any) => ({
284
+ title: i.name,
285
+ value: i.site,
286
+ }));
287
+ }
288
+ });
289
+
290
+ watchEffect(() => {
291
+ if (hasSite.value) {
292
+ refreshSiteData();
293
+ }
294
+ });
295
+
296
+ const roles = ref<Array<Record<string, any>>>([]);
297
+
298
+ const { getRoles } = useRole();
299
+
300
+ const { data: RolesData, refresh: refreshRoles } = await useLazyAsyncData(
301
+ "get-roles-by-type",
302
+ () => getRoles({ org: props.org, type: app.value, limit: 50 }),
303
+ { watch: [app] }
304
+ );
305
+
306
+ watchEffect(() => {
307
+ if (RolesData.value) {
308
+ roles.value = RolesData.value.items;
309
+ }
310
+ });
311
+
312
+ function handleUpdateApp(value: string) {
313
+ invite.value.role = "";
314
+ invite.value.site = "";
315
+ refreshRoles();
316
+ }
317
+
318
+ const createMore = ref(false);
319
+ const disable = ref(false);
320
+
321
+ const { requiredRule, emailRule } = useUtils();
322
+
323
+ const message = ref("");
324
+
325
+ function resetInvite() {
326
+ invite.value.email = "";
327
+ invite.value.app = "organization";
328
+ invite.value.role = "";
329
+ message.value = "";
330
+ }
331
+
332
+ function handleUpdateSite(siteId: string) {
333
+ const obj = sites.value.find((x) => x?.value === siteId);
334
+ invite.value.siteName = obj?.title || "";
335
+ }
336
+
337
+ const { inviteUser } = useUser();
338
+
339
+ async function submit() {
340
+ loading.submittingForm = true;
341
+ try {
342
+ await inviteUser(invite.value);
343
+
344
+ if (createMore.value) {
345
+ form.value?.reset();
346
+ resetInvite();
347
+ emit("success", false);
348
+ } else emit("success", true);
349
+ } catch (error: any) {
350
+ message.value = error.response._data.message;
351
+ } finally {
352
+ loading.submittingForm = false;
353
+ }
354
+ }
355
+
356
+ function cancel() {
357
+ emit("cancel");
358
+ }
359
+ </script>
@@ -0,0 +1,310 @@
1
+ <template>
2
+ <v-row no-gutters>
3
+ <v-col cols="12" class="mb-2">
4
+ <v-row no-gutters>
5
+ <v-btn
6
+ class="text-none mr-2"
7
+ rounded="pill"
8
+ variant="tonal"
9
+ size="large"
10
+ @click="inviteMember()"
11
+ v-if="props.inviteMember"
12
+ >
13
+ Invite member
14
+ </v-btn>
15
+ </v-row>
16
+ </v-col>
17
+ <v-col cols="12">
18
+ <v-card width="100%" variant="outlined" border="thin" rounded="lg">
19
+ <v-toolbar density="compact" color="grey-lighten-4">
20
+ <template #prepend>
21
+ <v-btn
22
+ fab
23
+ icon
24
+ density="comfortable"
25
+ @click="_getVerifications({ search: headerSearch, status })"
26
+ >
27
+ <v-icon>mdi-refresh</v-icon>
28
+ </v-btn>
29
+ </template>
30
+
31
+ <template #append>
32
+ <v-row no-gutters justify="end" align="center">
33
+ <span class="mr-2 text-caption text-fontgray">
34
+ {{ pageRange }}
35
+ </span>
36
+ <local-pagination
37
+ v-model="page"
38
+ :length="pages"
39
+ @update:value="getVerifications"
40
+ />
41
+ </v-row>
42
+ </template>
43
+
44
+ <template #extension>
45
+ <v-tabs>
46
+ <v-tab
47
+ :to="{
48
+ name: props.route,
49
+ params: { status: 'pending' },
50
+ }"
51
+ >
52
+ Pending
53
+ </v-tab>
54
+ <v-tab
55
+ :to="{
56
+ name: props.route,
57
+ params: { status: 'expired' },
58
+ }"
59
+ >
60
+ Expired
61
+ </v-tab>
62
+ </v-tabs>
63
+ </template>
64
+ </v-toolbar>
65
+
66
+ <v-data-table
67
+ :headers="headers"
68
+ :items="items"
69
+ item-value="_id"
70
+ items-per-page="20"
71
+ fixed-header
72
+ hide-default-footer
73
+ style="max-height: calc(100vh - (126px))"
74
+ :loading="loading"
75
+ >
76
+ <template #item.permissions="{ value }">
77
+ <span class="text-caption font-weight-bold text-capitalize">
78
+ permissions
79
+ </span>
80
+ <v-chip>{{ value.length }}</v-chip>
81
+ </template>
82
+ <template #item.createdAt="{ item }">
83
+ {{ item.createdAt ? formatDate(item.createdAt) : "" }}
84
+ </template>
85
+ <template #item.action-table="{ item }">
86
+ <v-menu
87
+ :close-on-content-click="false"
88
+ offset-y
89
+ width="150"
90
+ v-if="props.cancelInvitation"
91
+ >
92
+ <template v-slot:activator="{ props }">
93
+ <v-icon v-bind="props">mdi-dots-horizontal</v-icon>
94
+ </template>
95
+ <v-list>
96
+ <v-list-item @click="openConfirmDialog(item._id ?? '')">
97
+ Cancel Invite
98
+ </v-list-item>
99
+ </v-list>
100
+ </v-menu>
101
+ </template>
102
+ </v-data-table>
103
+ </v-card>
104
+ </v-col>
105
+
106
+ <ConfirmDialog
107
+ v-model="confirmDialog"
108
+ :loading="cancelLoading"
109
+ @submit="onConfirmCancel"
110
+ >
111
+ <template #title>
112
+ <span class="font-weight-medium text-h5">Cancel Invitation</span>
113
+ </template>
114
+ <template #description>
115
+ <p class="text-subtitle-2">
116
+ Are you sure you want to cancel this invitation? This action cannot be
117
+ undone.
118
+ </p>
119
+ </template>
120
+ <template #footer>
121
+ <v-btn
122
+ variant="text"
123
+ @click="confirmDialog = false"
124
+ :disabled="cancelLoading"
125
+ >
126
+ Close
127
+ </v-btn>
128
+ <v-btn
129
+ color="primary"
130
+ variant="flat"
131
+ @click="onConfirmCancel"
132
+ :loading="cancelLoading"
133
+ >
134
+ Cancel Invite
135
+ </v-btn>
136
+ </template>
137
+ </ConfirmDialog>
138
+ <Snackbar v-model="messageSnackbar" :text="message" :color="messageColor" />
139
+
140
+ <v-dialog v-model="dialogMember" max-width="450">
141
+ <InvitationForm
142
+ title="Invite member"
143
+ :org="org"
144
+ @cancel="dialogMember = false"
145
+ @success="handleSuccess"
146
+ @invited="getVerifications()"
147
+ :app="props.app"
148
+ />
149
+ </v-dialog>
150
+ </v-row>
151
+ </template>
152
+
153
+ <script setup lang="ts">
154
+ const props = defineProps({
155
+ app: {
156
+ type: String,
157
+ default: "organization",
158
+ },
159
+ route: {
160
+ type: String,
161
+ default: "index",
162
+ },
163
+ org: {
164
+ type: String,
165
+ default: "",
166
+ },
167
+ customerId: {
168
+ type: String,
169
+ default: "",
170
+ },
171
+ siteId: {
172
+ type: String,
173
+ default: "",
174
+ },
175
+ status: {
176
+ type: String,
177
+ default: "pending",
178
+ },
179
+ cancelInvitation: {
180
+ type: Boolean,
181
+ default: true,
182
+ },
183
+ inviteMember: {
184
+ type: Boolean,
185
+ default: true,
186
+ },
187
+ viewInvitations: {
188
+ type: Boolean,
189
+ default: true,
190
+ },
191
+ });
192
+
193
+ const { authenticate } = useLocalAuth();
194
+ authenticate();
195
+
196
+ const headers = [
197
+ {
198
+ title: "Date",
199
+ value: "createdAt",
200
+ },
201
+ {
202
+ title: "E-mail",
203
+ value: "email",
204
+ },
205
+ {
206
+ title: "Action",
207
+ value: "action-table",
208
+ },
209
+ ];
210
+
211
+ const status = (useRoute().params.status as string) ?? "";
212
+
213
+ const { getVerifications: _getVerifications, cancelUserInvitation } =
214
+ useVerification();
215
+
216
+ const page = ref(1);
217
+ const pages = ref(0);
218
+ const pageRange = ref("-- - -- of --");
219
+
220
+ const message = ref("");
221
+ const messageSnackbar = ref(false);
222
+ const messageColor = ref("");
223
+
224
+ const items = ref<Array<TMiniVerification>>([]);
225
+ const { headerSearch } = useLocal();
226
+ const { formatDate } = useUtils();
227
+
228
+ function showMessage(msg: string, color: string) {
229
+ message.value = msg;
230
+ messageColor.value = color;
231
+ messageSnackbar.value = true;
232
+ }
233
+
234
+ const {
235
+ data: getVerificationsReq,
236
+ refresh: getVerifications,
237
+ status: getVerificationsStatus,
238
+ } = useLazyAsyncData<{
239
+ items: TMiniVerification[];
240
+ pages: number;
241
+ pageRange: string;
242
+ }>("get-verifications" + props.status, () =>
243
+ _getVerifications({
244
+ page: page.value,
245
+ status: props.status,
246
+ search: headerSearch.value,
247
+ type: "user-invite,member-invite",
248
+ app: props.app
249
+ })
250
+ );
251
+
252
+ const loading = computed(() => getVerificationsStatus.value === "pending");
253
+
254
+ watchEffect(() => {
255
+ if (getVerificationsReq.value) {
256
+ items.value = getVerificationsReq.value.items;
257
+ pages.value = getVerificationsReq.value.pages;
258
+ pageRange.value = getVerificationsReq.value.pageRange;
259
+ }
260
+ });
261
+
262
+ watch([headerSearch], () => {
263
+ getVerifications();
264
+ });
265
+
266
+ const confirmDialog = ref(false);
267
+ const selectedInviteId = ref<string | null>(null);
268
+ const cancelLoading = ref(false);
269
+
270
+ function openConfirmDialog(id: string) {
271
+ selectedInviteId.value = id;
272
+ confirmDialog.value = true;
273
+ }
274
+
275
+ async function onConfirmCancel() {
276
+ if (!selectedInviteId.value) return;
277
+
278
+ cancelLoading.value = true;
279
+ try {
280
+ const res = await cancelUserInvitation(selectedInviteId.value);
281
+
282
+ showMessage(res.message || "Invitation cancelled successfully", "success");
283
+ await getVerifications();
284
+ confirmDialog.value = false;
285
+ selectedInviteId.value = null;
286
+ } catch (error: any) {
287
+ showMessage(error?.message || "Failed to cancel invitation", "error");
288
+ }
289
+ cancelLoading.value = false;
290
+ }
291
+
292
+ function handleSuccess(closeForm: boolean) {
293
+ getVerifications();
294
+ if (closeForm) {
295
+ dialogMember.value = false;
296
+ }
297
+ }
298
+
299
+ watchEffect(() => {
300
+ if (!props.viewInvitations) {
301
+ useRouter().back();
302
+ }
303
+ });
304
+
305
+ const dialogMember = ref(false);
306
+
307
+ function inviteMember() {
308
+ dialogMember.value = true;
309
+ }
310
+ </script>