@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,599 @@
1
+ <template>
2
+ <div class="feedback-detail-wrapper">
3
+ <v-row no-gutters class="fill-height">
4
+
5
+ <v-col cols="12" xl="7" lg="7" md="7" class="fill-height">
6
+ <div class="panel-container border-e">
7
+ <ChatMessage :type="'feedback'" />
8
+ </div>
9
+ </v-col>
10
+
11
+ <v-col cols="12" xl="5" lg="5" md="5" class="fill-height">
12
+ <div class="panel-container">
13
+ <ChatInformation
14
+ :item="feedback"
15
+ :service-providers="_serviceProviders"
16
+ :type="'feedback'"
17
+ @edit="openEditDialog"
18
+ @mark-complete-request="showCompleteDialog = true"
19
+ @delete="showDeleteDialog = true"
20
+ @update-work-order-id="updateWorkOrderId"
21
+ />
22
+ </div>
23
+ </v-col>
24
+ </v-row>
25
+ </div>
26
+
27
+ <FeedbackForm
28
+ v-model="showCreateDialog"
29
+ :feedback="_feedback"
30
+ @update:feedback="(val: TFeedbackUpdate) => (_feedback = val)"
31
+ :is-edit-mode="isEditMode"
32
+ :loading="submitting"
33
+ :categories="categories"
34
+ :theme="'light'"
35
+ :errored-images="[]"
36
+ :max-files="5"
37
+ :message-fn="(msg:any) => console.log(msg)"
38
+ @close="handleCloseDialog"
39
+ @submit="submitFeedback"
40
+ @file-added="handleFileAdded"
41
+ @file-deleted="deleteFile"
42
+ />
43
+
44
+ <v-dialog v-model="showCompleteDialog" max-width="450px">
45
+ <v-card class="rounded-xl pa-0 d-flex flex-column" style="max-height: 90vh">
46
+ <!-- Title Bar -->
47
+ <v-card-title class="d-flex justify-space-between align-center pa-4">
48
+ <span class="text-h6">Completion Confirmation</span>
49
+ <v-icon @click="showCompleteDialog = false">mdi-close</v-icon>
50
+ </v-card-title>
51
+
52
+ <!-- Scrollable form content -->
53
+ <v-card-text class="px-4 pt-0 overflow-y-auto" style="flex: 1 1 auto">
54
+ <InputFile
55
+ ref="completionFileInput"
56
+ :attachments="completionAttachments"
57
+ :max-files="3"
58
+ :errored-images="[]"
59
+ @add="handleCompletionFileAdded"
60
+ @delete="handleCompletionFileDeleted"
61
+ />
62
+
63
+ <div class="mb-4">
64
+ <label class="text-subtitle-2 mb-1 d-block">
65
+ Full Name <span class="text-error">*</span>
66
+ </label>
67
+ <v-text-field
68
+ placeholder="Enter your full name"
69
+ variant="outlined"
70
+ density="comfortable"
71
+ v-model="feedback.name"
72
+ hide-details
73
+ class="mt-1"
74
+ ></v-text-field>
75
+ </div>
76
+
77
+ <div class="mb-4">
78
+ <label class="text-subtitle-2 mb-1 d-block">
79
+ Signature <span class="text-error">*</span>
80
+ </label>
81
+ <SignaturePad v-model="feedback.signature" />
82
+ </div>
83
+ </v-card-text>
84
+
85
+ <v-card-actions class="px-4 pb-4">
86
+ <v-btn
87
+ block
88
+ color="primary-button"
89
+ size="large"
90
+ variant="flat"
91
+ :loading="completeLoading"
92
+ @click="markFeedbackAsComplete"
93
+ class="text-capitalize"
94
+ >
95
+ Mark as complete
96
+ </v-btn>
97
+ </v-card-actions>
98
+ </v-card>
99
+ </v-dialog>
100
+
101
+ <ConfirmDialog
102
+ v-model="showDeleteDialog"
103
+ :loading="deleteLoading"
104
+ @submit="deleteFeedback"
105
+ :image-src="'/images/icons/delete-icon.png'"
106
+ >
107
+ <template #image>
108
+ <v-img
109
+ height="120"
110
+ src="/images/icons/delete-icon.png"
111
+ alt="Delete Icon"
112
+ contain
113
+ />
114
+ </template>
115
+
116
+ <template #title> Are you sure you want to delete this feedback? </template>
117
+
118
+ <template #footer>
119
+ <v-btn
120
+ color="primary-button"
121
+ variant="flat"
122
+ class="font-weight-bold py-5 d-flex text-capitalize align-center justify-center"
123
+ @click="deleteFeedback"
124
+ :loading="deleteLoading"
125
+ block
126
+ >
127
+ Confirm
128
+ </v-btn>
129
+ </template>
130
+ </ConfirmDialog>
131
+
132
+ <Snackbar v-model="messageSnackbar" :text="message" :color="messageColor" />
133
+ </template>
134
+
135
+ <script lang="ts" setup>
136
+ const route = useRoute();
137
+ const id = route.params.id;
138
+
139
+ const {
140
+ feedback,
141
+ getFeedbackById,
142
+ feedbacks,
143
+ getFeedbacks: _getFeedbacks,
144
+ updateFeedback,
145
+ updateFeedbackServiceProvider,
146
+ updateStatusComplete,
147
+ deleteFeedback: _deleteFeedback,
148
+ } = useFeedback();
149
+
150
+ const { getServiceProviderNames } = useServiceProvider();
151
+
152
+ const _getFeedbackById = async () => {
153
+ try {
154
+ const data = await getFeedbackById(id as string);
155
+ feedback.value = data;
156
+ } catch (error) {
157
+ console.error("Error fetching feedback:", error);
158
+ }
159
+ };
160
+ const page = ref(1);
161
+ const pages = ref(0);
162
+ const pageRange = ref("-- - -- of --");
163
+ const items = ref<Array<Record<string, any>>>([]);
164
+
165
+ const {
166
+ data: getAllFeedbackReq,
167
+ status: getAllReqStatus,
168
+ refresh: getAllReqRefresh,
169
+ } = useLazyAsyncData("get-all-feedbacks", () =>
170
+ _getFeedbacks({
171
+ page: page.value,
172
+ site: route.params.site as string,
173
+ })
174
+ );
175
+
176
+ const loading = computed(() => getAllReqStatus.value === "pending");
177
+
178
+ watchEffect(() => {
179
+ if (getAllFeedbackReq.value) {
180
+ items.value = getAllFeedbackReq.value.items;
181
+ pages.value = getAllFeedbackReq.value.pages;
182
+ pageRange.value = getAllFeedbackReq.value.pageRange;
183
+ }
184
+ });
185
+
186
+ const handleSelectFeedback = async (id: string) => {
187
+ try {
188
+ await useRouter().push({ params: { id } });
189
+
190
+ const data = await getFeedbackById(id);
191
+ feedback.value = data;
192
+ } catch (error) {
193
+ console.error("Error selecting feedback:", error);
194
+ }
195
+ };
196
+
197
+ _getFeedbackById();
198
+
199
+ const _serviceProviders = ref<TServiceProviderName[]>([]);
200
+
201
+ const _getServiceProviderNames = async () => {
202
+ try {
203
+ const response = await getServiceProviderNames();
204
+ if (!response) return;
205
+
206
+ _serviceProviders.value = response.items.map((provider) => ({
207
+ _id: provider._id as string,
208
+ name: provider.name,
209
+ }));
210
+ } catch (error) {
211
+ console.error("Error fetching service providers:", error);
212
+ }
213
+ };
214
+
215
+ _getServiceProviderNames();
216
+
217
+ const showCreateDialog = ref(false);
218
+ const showCompleteDialog = ref(false);
219
+ const showDeleteDialog = ref(false);
220
+ const completeNotes = ref("");
221
+
222
+ const completionAttachments = ref<string[]>([]);
223
+
224
+ const completeLoading = ref(false);
225
+ const deleteLoading = ref(false);
226
+
227
+ const isEditMode = ref(false);
228
+
229
+ const _feedback = ref<TFeedbackCreate>({
230
+ attachments: [],
231
+ category: "",
232
+ subject: "",
233
+ location: "",
234
+ description: "",
235
+ });
236
+
237
+ const submitting = ref(false);
238
+ const message = ref("");
239
+ const messageColor = ref("");
240
+ const messageSnackbar = ref(false);
241
+
242
+ function showMessage(msg: string, color: string) {
243
+ message.value = msg;
244
+ messageColor.value = color;
245
+ messageSnackbar.value = true;
246
+ }
247
+
248
+ function openEditDialog() {
249
+ isEditMode.value = true;
250
+ _feedback.value = { ...feedback.value };
251
+ showCreateDialog.value = true;
252
+ }
253
+
254
+ function handleCloseDialog() {
255
+ resetFeedbackForm();
256
+ isEditMode.value = false;
257
+ showCreateDialog.value = false;
258
+ }
259
+
260
+ const { addFile, deleteFile: _deleteFile } = useFile();
261
+
262
+ async function handleFileAdded(file: File) {
263
+ try {
264
+ const res = await addFile(file);
265
+
266
+ if (res?.id && res?.name) {
267
+ const url = `https://seven365-storage.sgp1.cdn.digitaloceanspaces.com/dev/${res.id}`;
268
+
269
+ _feedback.value.attachments = _feedback.value.attachments ?? [];
270
+ _feedback.value.attachments.push(url);
271
+ }
272
+ } catch (error) {
273
+ console.error("Error uploading file:", error);
274
+ showMessage("Failed to upload file", "error");
275
+ }
276
+ }
277
+
278
+ async function deleteFile(value: string) {
279
+ try {
280
+ await _deleteFile(value);
281
+ _feedback.value.attachments = (_feedback.value.attachments ?? []).filter(
282
+ (file) => file !== value
283
+ );
284
+ } catch (error) {
285
+ showMessage("Failed to delete file", "error");
286
+ }
287
+ }
288
+
289
+ const resetFeedbackForm = () => {
290
+ _feedback.value = {
291
+ attachments: [],
292
+ category: "",
293
+ subject: "",
294
+ location: "",
295
+ description: "",
296
+ };
297
+ };
298
+
299
+ const completionFileInput = ref<any>(null);
300
+ const completionFileNames = ref<Record<string, string>>({});
301
+
302
+ async function handleCompletionFileAdded(file: File) {
303
+ try {
304
+ file.name;
305
+
306
+ const res = await addFile(file);
307
+
308
+ if (res?.id && res?.name) {
309
+ const url = `https://seven365-storage.sgp1.cdn.digitaloceanspaces.com/dev/${res.id}`;
310
+
311
+ if (!completionAttachments.value) {
312
+ completionAttachments.value = [];
313
+ }
314
+
315
+ completionAttachments.value.push(url);
316
+
317
+ completionFileNames.value[url] = res.name;
318
+
319
+ if (completionFileInput.value) {
320
+ completionFileInput.value.updateFileName(url, res.name);
321
+ }
322
+ }
323
+ } catch (error) {
324
+ console.error("Error uploading completion file:", error);
325
+ showMessage("Failed to upload file", "error");
326
+ }
327
+ }
328
+
329
+ async function handleCompletionFileDeleted(value: string) {
330
+ try {
331
+ await _deleteFile(value);
332
+
333
+ completionAttachments.value = completionAttachments.value || [];
334
+
335
+ completionAttachments.value = completionAttachments.value.filter(
336
+ (file) => file !== value
337
+ );
338
+ } catch (error) {
339
+ console.log(error);
340
+ showMessage("Failed to delete file", "error");
341
+ }
342
+ }
343
+
344
+ const resetCompletionForm = () => {
345
+ completionAttachments.value = [];
346
+
347
+ if (completionFileInput.value) {
348
+ completionFileInput.value.clearFiles?.();
349
+ }
350
+
351
+ feedback.value.name = "";
352
+ feedback.value.signature = "";
353
+ };
354
+
355
+ const { serviceProviderCategories, getServiceProviderCategories } =
356
+ useServiceProvider();
357
+
358
+ const categories = computed(() =>
359
+ serviceProviderCategories.value.map((name) => ({
360
+ title: name.charAt(0).toUpperCase() + name.slice(1),
361
+ value: name,
362
+ }))
363
+ );
364
+
365
+ getServiceProviderCategories();
366
+ async function markFeedbackAsComplete() {
367
+ if (!feedback.value?._id) {
368
+ console.warn("Update called without valid feedback ID.");
369
+ return;
370
+ }
371
+
372
+ if (!feedback.value.name || !feedback.value.signature) {
373
+ console.warn("Signature or name is missing:", feedback.value.signature);
374
+ showMessage("Please provide both name and signature.", "error");
375
+ return;
376
+ }
377
+
378
+ try {
379
+ completeLoading.value = true;
380
+
381
+ const payload: TFeedbackStatusComplete = {
382
+ name: feedback.value.name,
383
+ signature: feedback.value.signature,
384
+ attachments: completionAttachments.value || [],
385
+ };
386
+
387
+ const response = await updateStatusComplete(feedback.value._id, payload);
388
+ const message = response?.message || "Feedback marked as complete";
389
+ showMessage(message, "success");
390
+
391
+ showCompleteDialog.value = false;
392
+ resetCompletionForm();
393
+ await _getFeedbackById();
394
+ } catch (error) {
395
+ showMessage("Failed to mark feedback as complete", "error");
396
+ console.error("Error updating feedback status:", error);
397
+ } finally {
398
+ completeLoading.value = false;
399
+ }
400
+ }
401
+
402
+ async function deleteFeedback() {
403
+ if (!feedback.value?._id) {
404
+ console.warn("Delete called without valid feedback ID.");
405
+ return;
406
+ }
407
+
408
+ try {
409
+ deleteLoading.value = true;
410
+
411
+ const response = await _deleteFeedback(feedback.value._id);
412
+ const message = response?.message || "Feedback deleted successfully";
413
+ showMessage(message, "success");
414
+
415
+ showDeleteDialog.value = false;
416
+ await _getFeedbacks();
417
+
418
+ const org = useRoute().params.org || "customer1";
419
+ const site = useRoute().params.site || "site1";
420
+
421
+ await useRouter().push({
422
+ name: "org-site-feedbacks",
423
+ params: { org, site },
424
+ });
425
+ } catch (error) {
426
+ showMessage("Failed to delete feedback", "error");
427
+ console.error("Error deleting feedback:", error);
428
+ } finally {
429
+ deleteLoading.value = false;
430
+ }
431
+ }
432
+
433
+ async function submitFeedback(payload: TFeedbackUpdate) {
434
+ if (!isEditMode.value || !feedback.value?._id) {
435
+ console.warn("Update called without valid edit mode or feedback ID.");
436
+ return;
437
+ }
438
+
439
+ try {
440
+ submitting.value = true;
441
+
442
+ const payload = {
443
+ category: _feedback.value.category,
444
+ subject: _feedback.value.subject,
445
+ location: _feedback.value.location,
446
+ description: _feedback.value.description,
447
+ };
448
+
449
+ const response = await updateFeedback(feedback.value._id, payload);
450
+ const message = response?.message || "Feedback updated successfully";
451
+ showMessage(message, "success");
452
+
453
+ showCreateDialog.value = false;
454
+ await _getFeedbackById();
455
+
456
+ resetFeedbackForm();
457
+ } catch (error) {
458
+ showMessage("Something went wrong", "error");
459
+ console.error("Error updating feedback:", error);
460
+ } finally {
461
+ submitting.value = false;
462
+ }
463
+ }
464
+
465
+ async function updateWorkOrderId(workOrderId: string) {
466
+ const payload = {
467
+ category: feedback.value.category,
468
+ subject: feedback.value.subject,
469
+ location: feedback.value.location,
470
+ description: feedback.value.description,
471
+ workOrderId: workOrderId,
472
+ };
473
+ const response = await updateFeedback(feedback.value._id, payload);
474
+ const message =
475
+ response?.message || "Feedback updated with Work Order Number successfully";
476
+ showMessage(message, "success");
477
+
478
+ showCreateDialog.value = false;
479
+ await _getFeedbackById();
480
+
481
+ resetFeedbackForm();
482
+ }
483
+ </script>
484
+
485
+ <style scoped>
486
+ .feedback-detail-wrapper {
487
+ height: calc(100vh - 80px); /* Account for header and padding */
488
+ max-height: calc(100vh - 80px);
489
+ overflow: hidden;
490
+ position: relative;
491
+ background-color: rgb(var(--v-theme-surface));
492
+ }
493
+
494
+ .panel-container {
495
+ height: 100%;
496
+ max-height: 100%;
497
+ overflow: hidden;
498
+ display: flex;
499
+ flex-direction: column;
500
+ background-color: rgb(var(--v-theme-surface));
501
+ }
502
+
503
+ .border-e {
504
+ border-right: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
505
+ }
506
+
507
+ .fill-height {
508
+ height: 100%;
509
+ max-height: 100%;
510
+ overflow: hidden;
511
+ }
512
+
513
+ /* Ensure the root row doesn't create scrolling */
514
+ .v-row.fill-height {
515
+ margin: 0;
516
+ height: 100%;
517
+ max-height: 100%;
518
+ overflow: hidden;
519
+ align-items: stretch;
520
+ }
521
+
522
+ /* Better column spacing */
523
+ .v-col {
524
+ padding: 0;
525
+ display: flex;
526
+ flex-direction: column;
527
+ }
528
+
529
+ /* Ensure responsive behavior */
530
+ @media (max-width: 1280px) {
531
+ .feedback-detail-wrapper {
532
+ height: calc(100vh - 72px);
533
+ max-height: calc(100vh - 72px);
534
+ }
535
+ }
536
+
537
+ @media (max-width: 960px) {
538
+ .feedback-detail-wrapper {
539
+ height: calc(100vh - 64px); /* Mobile header height */
540
+ max-height: calc(100vh - 64px);
541
+ }
542
+
543
+ .border-e {
544
+ border-right: none;
545
+ border-bottom: 1px solid
546
+ rgba(var(--v-border-color), var(--v-border-opacity));
547
+ }
548
+
549
+ .v-col {
550
+ height: auto;
551
+ min-height: 300px;
552
+ }
553
+ }
554
+
555
+ /* Individual component styling */
556
+ :deep(.chat-navigation) {
557
+ height: 100%;
558
+ overflow-y: auto;
559
+ background-color: rgb(var(--v-theme-surface));
560
+ }
561
+
562
+ :deep(.chat-message) {
563
+ height: 100%;
564
+ overflow-y: auto;
565
+ background-color: rgb(var(--v-theme-surface));
566
+ }
567
+
568
+ :deep(.chat-information) {
569
+ height: 100%;
570
+ overflow-y: auto;
571
+ background-color: rgb(var(--v-theme-surface));
572
+ padding: 16px;
573
+ }
574
+
575
+ /* Smooth scrollbars */
576
+ :deep(*::-webkit-scrollbar) {
577
+ width: 6px;
578
+ }
579
+
580
+ :deep(*::-webkit-scrollbar-track) {
581
+ background: transparent;
582
+ }
583
+
584
+ :deep(*::-webkit-scrollbar-thumb) {
585
+ background: rgba(var(--v-border-color), 0.3);
586
+ border-radius: 3px;
587
+ }
588
+
589
+ :deep(*::-webkit-scrollbar-thumb:hover) {
590
+ background: rgba(var(--v-border-color), 0.5);
591
+ }
592
+
593
+ /* Remove default margins/padding that might cause issues */
594
+ :deep(.v-container) {
595
+ padding: 0;
596
+ margin: 0;
597
+ max-width: none;
598
+ }
599
+ </style>