@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,236 @@
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 text-capitalize">
6
+ {{ title }}
7
+ </span>
8
+ </v-row>
9
+ </v-toolbar>
10
+
11
+ <v-card-text
12
+ style="max-height: 100vh; overflow-y: auto"
13
+ class="pa-5 my-5 px-7"
14
+ >
15
+ <v-form ref="formRef" v-model="valid" @submit.prevent="submit">
16
+ <v-row no-gutters>
17
+ <v-col cols="12" class="mb-4">
18
+ <label class="text-subtitle-2 font-weight-medium mb-2">
19
+ Name <span class="text-red">*</span>
20
+ </label>
21
+ <v-text-field
22
+ v-model="form.name"
23
+ placeholder="Enter name"
24
+ variant="outlined"
25
+ density="comfortable"
26
+ :rules="[rules.required]"
27
+ hide-details="auto"
28
+ />
29
+ </v-col>
30
+
31
+ <v-col cols="12" class="mb-4">
32
+ <label class="text-subtitle-2 font-weight-medium mb-2">
33
+ Tag ID <span class="text-red">*</span>
34
+ </label>
35
+ <v-text-field
36
+ v-model="form.tagID"
37
+ placeholder="Enter tag id"
38
+ variant="outlined"
39
+ density="comfortable"
40
+ :rules="[rules.required, rules.noSpaces]"
41
+ hide-details="auto"
42
+ @input="handleTagIDInput"
43
+ />
44
+ </v-col>
45
+
46
+ </v-row>
47
+ </v-form>
48
+ </v-card-text>
49
+
50
+ <v-toolbar class="pa-0" density="compact">
51
+ <v-row no-gutters>
52
+ <v-col cols="6" class="pa-0">
53
+ <v-btn
54
+ block
55
+ variant="text"
56
+ class="text-none"
57
+ size="large"
58
+ @click="$emit('cancel')"
59
+ height="48"
60
+ :disabled="loading"
61
+ >
62
+ Cancel
63
+ </v-btn>
64
+ </v-col>
65
+
66
+ <v-col cols="6" class="pa-0">
67
+ <v-btn
68
+ block
69
+ tile
70
+ variant="flat"
71
+ class="text-none"
72
+ size="large"
73
+ height="48"
74
+ color="black"
75
+ @click="submit"
76
+ :loading="loading"
77
+ :disabled="!valid || loading || !hasChanges"
78
+ >
79
+ Submit
80
+ </v-btn>
81
+ </v-col>
82
+ </v-row>
83
+ </v-toolbar>
84
+ </v-card>
85
+ </template>
86
+
87
+ <script setup lang="ts">
88
+
89
+ import useNFCPatrolTag from "../../composables/useNFCPatrolTag";
90
+
91
+ const props = defineProps({
92
+ title: {
93
+ type: String,
94
+ default: "Add NFC Tag",
95
+ },
96
+ site: {
97
+ type: String,
98
+ required: true,
99
+ },
100
+ orgId: {
101
+ type: String,
102
+ required: true,
103
+ },
104
+ mode: {
105
+ type: String as PropType<"create" | "edit">,
106
+ default: "create",
107
+ },
108
+ nfcTag: {
109
+ type: Object as PropType<any>,
110
+ default: () => ({
111
+ name: "",
112
+ tagID: "",
113
+ status: "active",
114
+ }),
115
+ },
116
+ });
117
+
118
+ const emit = defineEmits(["cancel", "success", "error"]);
119
+
120
+ const formRef = ref();
121
+ const valid = ref(false);
122
+ const loading = ref(false);
123
+
124
+ const form = ref({
125
+ name: "",
126
+ tagID: "",
127
+ status: "active",
128
+ });
129
+
130
+
131
+ const originalForm = ref({
132
+ name: "",
133
+ tagID: "",
134
+ status: "active",
135
+ });
136
+
137
+ const statusOptions = [
138
+ { title: "Active", value: "active" },
139
+ { title: "Inactive", value: "inactive" },
140
+ ];
141
+
142
+ const rules = {
143
+ required: (v: any) => !!v || "This field is required",
144
+ noSpaces: (v: any) => !/\s/.test(v) || "Spaces are not allowed",
145
+ };
146
+
147
+ const hasChanges = computed(() => {
148
+ if (props.mode === "create") {
149
+
150
+ return true;
151
+ }
152
+
153
+
154
+ return (
155
+ form.value.name !== originalForm.value.name ||
156
+ form.value.tagID !== originalForm.value.tagID ||
157
+ form.value.status !== originalForm.value.status
158
+ );
159
+ });
160
+
161
+
162
+ watchEffect(() => {
163
+ if (props.mode === "edit" && props.nfcTag) {
164
+ form.value = {
165
+ name: props.nfcTag.name || "",
166
+ tagID: props.nfcTag.tagID || "",
167
+ status: props.nfcTag.status || "active",
168
+ };
169
+
170
+ originalForm.value = {
171
+ name: props.nfcTag.name || "",
172
+ tagID: props.nfcTag.tagID || "",
173
+ status: props.nfcTag.status || "active",
174
+ };
175
+ }
176
+ });
177
+
178
+ const { add: addNFCTag, updateById: updateNFCTag } = useNFCPatrolTag();
179
+
180
+ function handleTagIDInput(event: any) {
181
+
182
+ const value = event.target.value;
183
+ form.value.tagID = value.toUpperCase().replace(/\s/g, "");
184
+ }
185
+
186
+ async function submit() {
187
+ const { valid: isValid } = await formRef.value.validate();
188
+
189
+ if (!isValid) return;
190
+
191
+
192
+ if (props.mode === "edit" && !hasChanges.value) {
193
+ return;
194
+ }
195
+
196
+ loading.value = true;
197
+
198
+ try {
199
+
200
+ const payload: any = {
201
+ site: props.site,
202
+ tagID: form.value.tagID,
203
+ name: form.value.name,
204
+ };
205
+
206
+
207
+ if (props.mode === "edit") {
208
+ payload._id = props.nfcTag._id;
209
+ payload.updateType = "Edit";
210
+ }
211
+
212
+ if (props.mode === "create") {
213
+ await addNFCTag(payload);
214
+ } else {
215
+ await updateNFCTag(props.nfcTag._id, payload);
216
+ }
217
+
218
+ emit("success");
219
+
220
+
221
+ if (props.mode === "create") {
222
+ form.value = {
223
+ name: "",
224
+ tagID: "",
225
+ status: "active",
226
+ };
227
+ formRef.value.reset();
228
+ }
229
+ } catch (error: any) {
230
+ console.error("Error submitting NFC tag:", error);
231
+ emit("error", error);
232
+ } finally {
233
+ loading.value = false;
234
+ }
235
+ }
236
+ </script>
@@ -0,0 +1,337 @@
1
+ <template>
2
+ <v-row no-gutters>
3
+ <v-col cols="12">
4
+ <v-card width="100%" variant="outlined" border="thin" rounded="lg">
5
+ <v-toolbar density="compact" color="grey-lighten-4 pl-2 pr-4">
6
+ <template #prepend>
7
+ <v-btn fab icon density="comfortable" @click="getNFCTagRefresh()">
8
+ <v-icon>mdi-refresh</v-icon>
9
+ </v-btn>
10
+ </template>
11
+
12
+ <template #append>
13
+ <v-btn
14
+ variant="flat"
15
+ color="primary"
16
+ class="text-none"
17
+ @click="dialogAdd = true"
18
+ >
19
+ Add
20
+ </v-btn>
21
+ </template>
22
+ </v-toolbar>
23
+
24
+ <v-card-text class="pa-0">
25
+ <v-data-table
26
+ :headers="headers"
27
+ :items="items"
28
+ fixed-header
29
+ hide-default-footer
30
+ @click:row="handleRowClick"
31
+ style="max-height: 300px"
32
+ >
33
+ </v-data-table>
34
+ </v-card-text>
35
+
36
+ <v-toolbar density="compact" color="grey-lighten-4">
37
+ <template #append>
38
+ <v-row no-gutters justify="end" align="center">
39
+ <span class="mr-2 text-caption text-font gray">
40
+ {{ pageRange }}
41
+ </span>
42
+ <local-pagination
43
+ v-model="page"
44
+ :length="pages"
45
+ @update:value="$emit('update:value', $event)"
46
+ />
47
+ </v-row>
48
+ </template>
49
+ </v-toolbar>
50
+ </v-card>
51
+ </v-col>
52
+
53
+ <!-- Add Dialog -->
54
+ <v-dialog v-model="dialogAdd" persistent width="450">
55
+ <NFCTagForm
56
+ title="Add NFC Tag"
57
+ :site="props.site"
58
+ :org-id="props.orgId"
59
+ @cancel="dialogAdd = false"
60
+ @success="handleSuccess"
61
+ @error="handleError"
62
+ />
63
+ </v-dialog>
64
+
65
+ <!-- Edit Dialog -->
66
+ <v-dialog v-model="dialogEdit" persistent width="450">
67
+ <NFCTagForm
68
+ title="Edit NFC Tag"
69
+ :site="props.site"
70
+ :org-id="props.orgId"
71
+ @cancel="dialogEdit = false"
72
+ @success="handleSuccess"
73
+ @error="handleError"
74
+ mode="edit"
75
+ :nfc-tag="selectedTag"
76
+ />
77
+ </v-dialog>
78
+
79
+ <!-- Preview Dialog -->
80
+ <v-dialog v-model="dialogPreview" persistent width="540">
81
+ <v-card width="100%">
82
+ <v-toolbar>
83
+ <v-row no-gutters class="fill-height px-6" align="center">
84
+ <span class="font-weight-bold text-h5 text-capitalize">
85
+ NFC Tag Details
86
+ </span>
87
+ </v-row>
88
+ </v-toolbar>
89
+
90
+ <v-card-text
91
+ style="max-height: 100vh; overflow-y: auto"
92
+ class="pa-5 my-5 px-7"
93
+ >
94
+ <v-row no-gutters>
95
+ <v-col cols="12" class="mb-2">
96
+ Name:
97
+ <span class="font-weight-bold">
98
+ {{ selectedTag.name }}
99
+ </span>
100
+ </v-col>
101
+
102
+ <v-col cols="12" class="mb-2">
103
+ Tag ID:
104
+ <span class="font-weight-bold">
105
+ {{ selectedTag.tagID }}
106
+ </span>
107
+ </v-col>
108
+
109
+
110
+ </v-row>
111
+ </v-card-text>
112
+
113
+ <v-toolbar class="pa-0" density="compact">
114
+ <v-row no-gutters>
115
+ <v-col cols="6" class="pa-0">
116
+ <v-btn
117
+ block
118
+ variant="text"
119
+ class="text-none"
120
+ size="large"
121
+ @click="dialogPreview = false"
122
+ height="48"
123
+ >
124
+ Close
125
+ </v-btn>
126
+ </v-col>
127
+
128
+ <v-col cols="6" class="pa-0">
129
+ <v-menu>
130
+ <template #activator="{ props }">
131
+ <v-btn
132
+ block
133
+ variant="flat"
134
+ color="black"
135
+ class="text-none"
136
+ height="48"
137
+ v-bind="props"
138
+ tile
139
+ >
140
+ More actions
141
+ </v-btn>
142
+ </template>
143
+
144
+ <v-list class="pa-0">
145
+ <v-list-item @click="openDialogEdit()">
146
+ <v-list-item-title class="text-subtitle-2">
147
+ Edit NFC Tag
148
+ </v-list-item-title>
149
+ </v-list-item>
150
+
151
+ <v-list-item @click="openDialogDelete()" class="text-red">
152
+ <v-list-item-title class="text-subtitle-2">
153
+ Delete NFC Tag
154
+ </v-list-item-title>
155
+ </v-list-item>
156
+ </v-list>
157
+ </v-menu>
158
+ </v-col>
159
+ </v-row>
160
+ </v-toolbar>
161
+ </v-card>
162
+ </v-dialog>
163
+
164
+ <!-- Delete Dialog -->
165
+ <v-dialog v-model="dialogDelete" persistent width="540">
166
+ <v-card width="100%">
167
+ <v-card-text
168
+ style="max-height: 100vh; overflow-y: auto"
169
+ class="pa-5 my-5 px-7 text-center"
170
+ >
171
+ Are you sure you want to delete this NFC Tag?
172
+ </v-card-text>
173
+
174
+ <v-toolbar class="pa-0" density="compact">
175
+ <v-row no-gutters>
176
+ <v-col cols="6" class="pa-0">
177
+ <v-btn
178
+ block
179
+ variant="text"
180
+ class="text-none"
181
+ size="large"
182
+ tile
183
+ @click="dialogDelete = false"
184
+ height="48"
185
+ >
186
+ Cancel
187
+ </v-btn>
188
+ </v-col>
189
+
190
+ <v-col cols="6" class="pa-0">
191
+ <v-btn
192
+ block
193
+ tile
194
+ variant="flat"
195
+ class="text-none"
196
+ size="large"
197
+ height="48"
198
+ color="black"
199
+ @click="submitDelete()"
200
+ >
201
+ Delete
202
+ </v-btn>
203
+ </v-col>
204
+ </v-row>
205
+ </v-toolbar>
206
+ </v-card>
207
+ </v-dialog>
208
+
209
+ <Snackbar v-model="messageSnackbar" :text="message" :color="messageColor" />
210
+ </v-row>
211
+ </template>
212
+
213
+ <script setup lang="ts">
214
+
215
+ import useNFCPatrolTag from "../../composables/useNFCPatrolTag";
216
+
217
+ const events = defineEmits(["update:value", "row-click"]);
218
+
219
+ const props = defineProps({
220
+ site: {
221
+ type: String,
222
+ required: true,
223
+ },
224
+ siteName: {
225
+ type: String,
226
+ default: "",
227
+ },
228
+ orgId: {
229
+ type: String,
230
+ required: true,
231
+ },
232
+ headers: {
233
+ type: Array as PropType<Array<any>>,
234
+ default: () => [
235
+ { title: "ID", value: "tagID" },
236
+ { title: "Name", value: "name" },
237
+ { title: "Status", value: "status" },
238
+ ],
239
+ },
240
+ });
241
+
242
+ const items = ref<Array<any>>([]);
243
+ const page = ref(1);
244
+ const pages = ref(0);
245
+ const pageRange = ref("1-20 of 1");
246
+
247
+ const { getAll: getAllNFCTags, deleteById: deleteNFCTagById } = useNFCPatrolTag();
248
+
249
+ const { data: getNFCTagReq, refresh: getNFCTagRefresh } = await useLazyAsyncData(
250
+ `get-nfc-tags-${props.site}`,
251
+ () => getAllNFCTags({ site: props.site, page: page.value }),
252
+ {
253
+ watch: [page],
254
+ }
255
+ );
256
+
257
+ watchEffect(() => {
258
+ if (getNFCTagReq.value) {
259
+ items.value = getNFCTagReq.value.items;
260
+ pageRange.value = getNFCTagReq.value.pageRange;
261
+ pages.value = getNFCTagReq.value.pages;
262
+ }
263
+ });
264
+
265
+ const dialogAdd = ref(false);
266
+ const dialogEdit = ref(false);
267
+ const dialogPreview = ref(false);
268
+ const dialogDelete = ref(false);
269
+
270
+ const message = ref("");
271
+ const messageSnackbar = ref(false);
272
+ const messageColor = ref("");
273
+
274
+ function openDialogEdit() {
275
+ dialogEdit.value = true;
276
+
277
+ if (dialogPreview.value) dialogPreview.value = false;
278
+ }
279
+
280
+ function openDialogDelete() {
281
+ dialogDelete.value = true;
282
+
283
+ if (dialogPreview.value) dialogPreview.value = false;
284
+ }
285
+
286
+ function handleSuccess() {
287
+ if (dialogAdd.value) {
288
+ dialogAdd.value = false;
289
+ showMessage("NFC Tag created successfully!", "success");
290
+ }
291
+
292
+ if (dialogEdit.value) {
293
+ dialogEdit.value = false;
294
+ showMessage("NFC Tag updated successfully!", "success");
295
+ }
296
+
297
+ if (dialogPreview.value) dialogPreview.value = false;
298
+
299
+ if (dialogDelete.value) dialogDelete.value = false;
300
+
301
+ getNFCTagRefresh();
302
+ }
303
+
304
+ function handleError(error: any) {
305
+ const errorMessage = error?.data?.message || error?.message || "An error occurred";
306
+ showMessage(errorMessage, "error");
307
+ }
308
+
309
+ function showMessage(msg: string, color: string) {
310
+ message.value = msg;
311
+ messageColor.value = color;
312
+ messageSnackbar.value = true;
313
+ }
314
+
315
+ const selectedTag = ref<any>({
316
+ name: "",
317
+ tagID: "",
318
+ status: "active",
319
+ });
320
+
321
+ function handleRowClick(_: any, data: any) {
322
+ dialogPreview.value = true;
323
+ selectedTag.value = JSON.parse(JSON.stringify(data.item));
324
+ }
325
+
326
+ async function submitDelete() {
327
+ try {
328
+ await deleteNFCTagById(selectedTag.value._id ?? "");
329
+ await getNFCTagRefresh();
330
+ dialogDelete.value = false;
331
+ showMessage("NFC Tag deleted successfully!", "success");
332
+ } catch (error) {
333
+ console.error("Error deleting NFC tag:", error);
334
+ handleError(error);
335
+ }
336
+ }
337
+ </script>
@@ -0,0 +1,130 @@
1
+ <template>
2
+ <v-row no-gutters>
3
+ <v-col cols="12">
4
+ <v-card width="100%" variant="outlined" border="thin" rounded="lg">
5
+ <v-row no-gutters class="pa-6" align="center">
6
+ <v-col cols="12" md="7" class="pr-md-8">
7
+ <div class="text-subtitle-1 font-weight-medium">
8
+ Early Start Allowance
9
+ </div>
10
+ <div class="text-body-2 text-medium-emphasis mt-1">
11
+ The number of minutes before the scheduled time that a guard is
12
+ allowed to click ‘Start Patrol’. For example,<br />
13
+ if set to 10 minutes, a guard can start their 8:00 AM patrol as
14
+ early as 7:50 AM.
15
+ </div>
16
+ </v-col>
17
+
18
+ <v-col cols="12" md="5" class="d-flex justify-md-end mt-4">
19
+ <v-text-field
20
+ v-model="earlyStartAllowance"
21
+ type="number"
22
+ min="0"
23
+ variant="outlined"
24
+ density="default"
25
+ suffix="mins"
26
+ hide-details="auto"
27
+ style="max-width: 167px"
28
+ >
29
+ <template #label>
30
+ Early Start Allowance
31
+ <span class="text-error">*</span>
32
+ </template>
33
+ </v-text-field>
34
+ </v-col>
35
+ </v-row>
36
+
37
+ <v-row no-gutters class="pa-6 pt-0">
38
+ <v-col cols="12" class="d-flex justify-end">
39
+ <v-btn
40
+ text="Save"
41
+ color="primary"
42
+ class="text-none"
43
+ size="large"
44
+ variant="flat"
45
+ @click="submit"
46
+ :loading="loading"
47
+ />
48
+ </v-col>
49
+ </v-row>
50
+ </v-card>
51
+ </v-col>
52
+ <Snackbar v-model="messageSnackbar" :text="message" :color="messageColor" />
53
+ </v-row>
54
+ </template>
55
+
56
+ <script setup lang="ts">
57
+ import useNFCPatrolSettings from "../../composables/useNFCPatrolSettings";
58
+
59
+ const props = defineProps({
60
+ site: {
61
+ type: String,
62
+ required: true,
63
+ },
64
+ siteName: {
65
+ type: String,
66
+ default: "",
67
+ },
68
+ orgId: {
69
+ type: String,
70
+ required: true,
71
+ },
72
+ });
73
+
74
+ const loading = ref<boolean>(false);
75
+
76
+ const message = ref<string>("");
77
+ const messageSnackbar = ref<boolean>(false);
78
+ const messageColor = ref<string>("");
79
+
80
+ function handleError(error: any) {
81
+ const errorMessage =
82
+ error?.data?.message || error?.message || "An error occurred";
83
+ showMessage(errorMessage, "error");
84
+ }
85
+
86
+ function showMessage(msg: string, color: string) {
87
+ message.value = msg;
88
+ messageColor.value = color;
89
+ messageSnackbar.value = true;
90
+ }
91
+
92
+ const earlyStartAllowance = ref<any>(0);
93
+
94
+ const {
95
+ getBySite: getNfcPatrolSettings,
96
+ updateBySite: updateNfcPatrolSettings,
97
+ } = useNFCPatrolSettings();
98
+
99
+ const { data: nfcPatrolSetting } = await useLazyAsyncData(
100
+ `fetch-nfc-patrol-settings-${props.site}`,
101
+ async () => getNfcPatrolSettings(props.site)
102
+ );
103
+
104
+ watchEffect(() => {
105
+ if (nfcPatrolSetting.value) {
106
+ earlyStartAllowance.value = nfcPatrolSetting.value.earlyStartAllowance ?? 0;
107
+ }
108
+ });
109
+
110
+ async function submit() {
111
+ if (
112
+ [null, ""].includes(earlyStartAllowance.value) ||
113
+ earlyStartAllowance.value < 0
114
+ )
115
+ return showMessage("Please complete all required fields *", "error");
116
+
117
+ loading.value = true;
118
+
119
+ try {
120
+ const response: any = await updateNfcPatrolSettings(props.site, {
121
+ earlyStartAllowance: earlyStartAllowance.value,
122
+ });
123
+ showMessage(response.message, "success");
124
+ } catch (error) {
125
+ handleError(error);
126
+ } finally {
127
+ loading.value = false;
128
+ }
129
+ }
130
+ </script>