@dragonmastery/dragoncore-vue 0.0.2 → 0.0.4

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 (186) hide show
  1. package/LICENSE +2 -2
  2. package/dist/{ChangePasswordPage-Btu5lf-r.js → ChangePasswordPage-DCews8GU.js} +2 -2
  3. package/dist/{ChangePasswordPage-Btu5lf-r.js.map → ChangePasswordPage-DCews8GU.js.map} +1 -1
  4. package/dist/ChangePasswordPage-Dm5vW0nl.js +6 -0
  5. package/dist/CreateTeamForm-zVlGgmL9.js +27 -0
  6. package/dist/CreateTeamMemberForm-DkCbsJDn.js +27 -0
  7. package/dist/{CreateUserPage-Cmx8xjjv.js → CreateUserPage-B8qeBZij.js} +2 -2
  8. package/dist/{CreateUserPage-Cmx8xjjv.js.map → CreateUserPage-B8qeBZij.js.map} +1 -1
  9. package/dist/CreateUserPage-WjYDkwpb.js +6 -0
  10. package/dist/CreditBalanceDashboard-BTW4IK66.js +27 -0
  11. package/dist/CreditManagement-0JxmCIAd.js +27 -0
  12. package/dist/CustomerCreateSupportTicketForm-CQcv4vrX.js +27 -0
  13. package/dist/CustomerSupportTicketDetailPage-DQa_Zvfe.js +703 -0
  14. package/dist/CustomerSupportTicketDetailPage-DQa_Zvfe.js.map +1 -0
  15. package/dist/CustomerSupportTicketList-CMPRQ_7O.js +27 -0
  16. package/dist/CustomerSupportTicketParent-BOYIren9.js +7 -0
  17. package/dist/{CustomerSupportTicketParent-2mONd9kL.js → CustomerSupportTicketParent-sT8hpgrA.js} +6 -6
  18. package/dist/CustomerSupportTicketParent-sT8hpgrA.js.map +1 -0
  19. package/dist/CustomerSupportTicketSuccess-CnRWm6gX.js +27 -0
  20. package/dist/EditTeamForm-BM90JTjr.js +27 -0
  21. package/dist/EditTeamMemberForm-B8-pI6Xm.js +6 -0
  22. package/dist/{EditTeamMemberForm-ru4WgLz-.js → EditTeamMemberForm-CKbKomrL.js} +27 -5
  23. package/dist/EditTeamMemberForm-CKbKomrL.js.map +1 -0
  24. package/dist/EditUserPage-BG-Fkx_c.js +7 -0
  25. package/dist/{EditUserPage-BxJ5QvIM.js → EditUserPage-XqF25iwz.js} +4 -4
  26. package/dist/{EditUserPage-BxJ5QvIM.js.map → EditUserPage-XqF25iwz.js.map} +1 -1
  27. package/dist/ForgotPassword-CjWv2V7p.js +7 -0
  28. package/dist/{ForgotPassword-CqhenzUG.js → ForgotPassword-D3bjL48L.js} +2 -2
  29. package/dist/{ForgotPassword-CqhenzUG.js.map → ForgotPassword-D3bjL48L.js.map} +1 -1
  30. package/dist/LoginForm--br4Il85.js +7 -0
  31. package/dist/{LoginForm-_PZ51Uwe.js → LoginForm-C85U2E2r.js} +3 -3
  32. package/dist/{LoginForm-_PZ51Uwe.js.map → LoginForm-C85U2E2r.js.map} +1 -1
  33. package/dist/Logout-DHT-5Qz3.js +6 -0
  34. package/dist/{Logout-BMjiqHnS.js → Logout-DZuWLh0O.js} +3 -3
  35. package/dist/{Logout-BMjiqHnS.js.map → Logout-DZuWLh0O.js.map} +1 -1
  36. package/dist/ResetPassword-DAn7dYAp.js +27 -0
  37. package/dist/SavedFiltersPage-BNasEKOY.js +391 -0
  38. package/dist/SavedFiltersPage-BNasEKOY.js.map +1 -0
  39. package/dist/Signup-VZa7U-Ur.js +7 -0
  40. package/dist/{Signup-c2-_yMOM.js → Signup-hpV8J5cM.js} +3 -3
  41. package/dist/{Signup-c2-_yMOM.js.map → Signup-hpV8J5cM.js.map} +1 -1
  42. package/dist/StaffCreateSupportTicketForm-DoHCw60c.js +27 -0
  43. package/dist/StaffSupportTicketDetailPage-D49ibqrO.js +1884 -0
  44. package/dist/StaffSupportTicketDetailPage-D49ibqrO.js.map +1 -0
  45. package/dist/StaffSupportTicketList-BgCIa_9v.js +27 -0
  46. package/dist/StaffSupportTicketParent-C7Mm7W_0.js +7 -0
  47. package/dist/{StaffSupportTicketParent-Cx1buQZw.js → StaffSupportTicketParent-CxrPxXSH.js} +6 -6
  48. package/dist/StaffSupportTicketParent-CxrPxXSH.js.map +1 -0
  49. package/dist/StaffSupportTicketSuccess-DZF2WpZc.js +27 -0
  50. package/dist/SupportStaffPage-nd0HowtH.js +156 -0
  51. package/dist/SupportStaffPage-nd0HowtH.js.map +1 -0
  52. package/dist/SupportTicketDevLifecycleBadge-Cl4y47Sy.js +116 -0
  53. package/dist/SupportTicketDevLifecycleBadge-Cl4y47Sy.js.map +1 -0
  54. package/dist/SupportTicketMaintenancePage-rcJ7EfDj.js +56 -0
  55. package/dist/SupportTicketMaintenancePage-rcJ7EfDj.js.map +1 -0
  56. package/dist/TeamAttachmentsTab-BoOIuTU1.js +27 -0
  57. package/dist/{TeamHistoryTab-gB3H2KZv.js → TeamHistoryTab-CNelXR3Q.js} +19 -6
  58. package/dist/TeamHistoryTab-CNelXR3Q.js.map +1 -0
  59. package/dist/TeamHistoryTab-siesF93u.js +4 -0
  60. package/dist/TeamList-TpS3BhPd.js +27 -0
  61. package/dist/TeamMemberList-CQTxcWNS.js +27 -0
  62. package/dist/TeamMemberParent-Bt0kbyKQ.js +27 -0
  63. package/dist/{NoteList-C0hRPNMO.js → TeamNotesTab-BhVRLG8h.js} +30 -69
  64. package/dist/TeamNotesTab-BhVRLG8h.js.map +1 -0
  65. package/dist/TeamNotesTab-Crp-afAe.js +7 -0
  66. package/dist/TeamParent-BvLiiJq6.js +27 -0
  67. package/dist/TimelineNoteInput-BRsQ2QTz.js +490 -0
  68. package/dist/TimelineNoteInput-BRsQ2QTz.js.map +1 -0
  69. package/dist/{InlineAttachments-I39rOvip.js → TimelineSystemEvent-B69B3eeL.js} +589 -126
  70. package/dist/TimelineSystemEvent-B69B3eeL.js.map +1 -0
  71. package/dist/UserListPage-D68AjrjM.js +4 -0
  72. package/dist/{UserListPage-WU56KiWj.js → UserListPage-OGYOLwlw.js} +3 -3
  73. package/dist/{UserListPage-WU56KiWj.js.map → UserListPage-OGYOLwlw.js.map} +1 -1
  74. package/dist/UserProfilePage-Q68NAGQQ.js +7 -0
  75. package/dist/{UserProfilePage-BtLUY1kt.js → UserProfilePage-uAIfC_NW.js} +4 -4
  76. package/dist/{UserProfilePage-BtLUY1kt.js.map → UserProfilePage-uAIfC_NW.js.map} +1 -1
  77. package/dist/ViewTeam-Bb1WH_Us.js +27 -0
  78. package/dist/ViewTeamMember-CBTAnAhS.js +27 -0
  79. package/dist/{convertToLocalDateTime-D4IoNvRj.js → convertToLocalDateTime-DOSGtMn8.js} +13 -3
  80. package/dist/convertToLocalDateTime-DOSGtMn8.js.map +1 -0
  81. package/dist/{displayIdFormatter-Dz900Awr.js → displayIdFormatter-BoKcrgF5.js} +1 -1
  82. package/dist/{displayIdFormatter-Dz900Awr.js.map → displayIdFormatter-BoKcrgF5.js.map} +1 -1
  83. package/dist/extractRpcErrorMessage-C_UbKgHL.js +20 -0
  84. package/dist/extractRpcErrorMessage-C_UbKgHL.js.map +1 -0
  85. package/dist/index.d.ts +1594 -1320
  86. package/dist/index.js +25 -40
  87. package/dist/{src-o5fMIo5_.js → src-ChwBeNHB.js} +4006 -1522
  88. package/dist/src-ChwBeNHB.js.map +1 -0
  89. package/dist/{useMutation-CFwe7H9j.js → useMutation-B4_S4Xoa.js} +3 -3
  90. package/dist/{useMutation-CFwe7H9j.js.map → useMutation-B4_S4Xoa.js.map} +1 -1
  91. package/dist/{useQuery-p7oJO7OD.js → useQuery-B7ndu5_P.js} +3 -3
  92. package/dist/{useQuery-p7oJO7OD.js.map → useQuery-B7ndu5_P.js.map} +1 -1
  93. package/dist/{useQueryCache-ByayvZgZ.js → useQueryCache-DqcDMsxb.js} +2 -2
  94. package/dist/{useQueryCache-ByayvZgZ.js.map → useQueryCache-DqcDMsxb.js.map} +1 -1
  95. package/dist/{useRpcAuth-BLlRSHy8.js → useRpcAuth-Dp2sec-X.js} +13 -4
  96. package/dist/useRpcAuth-Dp2sec-X.js.map +1 -0
  97. package/package.json +8 -8
  98. package/dist/ChangePasswordPage-mBBuQMkT.js +0 -6
  99. package/dist/CreateTeamForm-n2ut93vM.js +0 -43
  100. package/dist/CreateTeamMemberForm-CcH3AxNL.js +0 -43
  101. package/dist/CreateUserPage-CDrGuW9B.js +0 -6
  102. package/dist/CreditBalanceDashboard-DLz0ioP3.js +0 -43
  103. package/dist/CreditManagement-D3q5S-qc.js +0 -43
  104. package/dist/CustomerCreateSupportTicketForm-Ci7QYkG-.js +0 -43
  105. package/dist/CustomerEditSupportTicketForm-Dd5ZB74k.js +0 -159
  106. package/dist/CustomerEditSupportTicketForm-Dd5ZB74k.js.map +0 -1
  107. package/dist/CustomerEditSupportTicketForm-lLchVjnw.js +0 -9
  108. package/dist/CustomerSupportTicketAttachmentsTab-gBrVO97t.js +0 -43
  109. package/dist/CustomerSupportTicketCustomerNotesTab-D0jhzbOY.js +0 -8
  110. package/dist/CustomerSupportTicketCustomerNotesTab-D1aa9It7.js +0 -23
  111. package/dist/CustomerSupportTicketCustomerNotesTab-D1aa9It7.js.map +0 -1
  112. package/dist/CustomerSupportTicketHistoryTab-BNTf8EZq.js +0 -6
  113. package/dist/CustomerSupportTicketHistoryTab-CFYN_Sa4.js +0 -17
  114. package/dist/CustomerSupportTicketHistoryTab-CFYN_Sa4.js.map +0 -1
  115. package/dist/CustomerSupportTicketList-BkOzFxMP.js +0 -6
  116. package/dist/CustomerSupportTicketList-C2nUPawb.js +0 -166
  117. package/dist/CustomerSupportTicketList-C2nUPawb.js.map +0 -1
  118. package/dist/CustomerSupportTicketParent-2mONd9kL.js.map +0 -1
  119. package/dist/CustomerSupportTicketParent-N8ko1yFE.js +0 -7
  120. package/dist/CustomerSupportTicketSuccess-w_-9NXT4.js +0 -43
  121. package/dist/CustomerViewSupportTicket-CVwNH0lS.js +0 -11
  122. package/dist/CustomerViewSupportTicket-tZkxragu.js +0 -363
  123. package/dist/CustomerViewSupportTicket-tZkxragu.js.map +0 -1
  124. package/dist/EditTeamForm-BioqiTWE.js +0 -43
  125. package/dist/EditTeamMemberForm-DCq0Gsn_.js +0 -7
  126. package/dist/EditTeamMemberForm-ru4WgLz-.js.map +0 -1
  127. package/dist/EditUserPage-XOBuxUxd.js +0 -7
  128. package/dist/FieldsetSection-CsHN38_o.js +0 -27
  129. package/dist/FieldsetSection-CsHN38_o.js.map +0 -1
  130. package/dist/ForgotPassword-CpqvcSFg.js +0 -7
  131. package/dist/InlineAttachments-I39rOvip.js.map +0 -1
  132. package/dist/LoginForm-AM0qkfbU.js +0 -7
  133. package/dist/Logout-BfiBjlaH.js +0 -6
  134. package/dist/NoteList-C0hRPNMO.js.map +0 -1
  135. package/dist/NotificationEmailsPage-BjRqtW95.js +0 -141
  136. package/dist/NotificationEmailsPage-BjRqtW95.js.map +0 -1
  137. package/dist/NotificationEmailsPage-bx-9rg3x.js +0 -7
  138. package/dist/ResetPassword-BQLkR9TZ.js +0 -43
  139. package/dist/Signup-CnCcQlB8.js +0 -7
  140. package/dist/StaffCreateSupportTicketForm-ChVFDJdA.js +0 -43
  141. package/dist/StaffEditSupportTicketForm-DY1Zkf5k.js +0 -9
  142. package/dist/StaffEditSupportTicketForm-DuUKuIGg.js +0 -263
  143. package/dist/StaffEditSupportTicketForm-DuUKuIGg.js.map +0 -1
  144. package/dist/StaffSupportTicketAttachmentsTab-DpDXsHXP.js +0 -43
  145. package/dist/StaffSupportTicketCustomerNotesTab-CusqQV2-.js +0 -23
  146. package/dist/StaffSupportTicketCustomerNotesTab-CusqQV2-.js.map +0 -1
  147. package/dist/StaffSupportTicketCustomerNotesTab-rbJHJ0_V.js +0 -8
  148. package/dist/StaffSupportTicketHistoryTab-D24myEm3.js +0 -17
  149. package/dist/StaffSupportTicketHistoryTab-D24myEm3.js.map +0 -1
  150. package/dist/StaffSupportTicketHistoryTab-nmVma5vp.js +0 -6
  151. package/dist/StaffSupportTicketInternalNotesTab-D8HM--dp.js +0 -23
  152. package/dist/StaffSupportTicketInternalNotesTab-D8HM--dp.js.map +0 -1
  153. package/dist/StaffSupportTicketInternalNotesTab-DihYd5XI.js +0 -8
  154. package/dist/StaffSupportTicketList-DelptSmK.js +0 -43
  155. package/dist/StaffSupportTicketParent-BCrj3ckV.js +0 -7
  156. package/dist/StaffSupportTicketParent-Cx1buQZw.js.map +0 -1
  157. package/dist/StaffSupportTicketSuccess-BYxtY5wZ.js +0 -43
  158. package/dist/StaffSupportTicketWorkflowTab-BrDDBeK9.js +0 -9
  159. package/dist/StaffSupportTicketWorkflowTab-DmVTPzxS.js +0 -1234
  160. package/dist/StaffSupportTicketWorkflowTab-DmVTPzxS.js.map +0 -1
  161. package/dist/SupportTicketHistoryTab-CLMopA7a.js +0 -220
  162. package/dist/SupportTicketHistoryTab-CLMopA7a.js.map +0 -1
  163. package/dist/SupportTicketStatusBadge-YdZzjvkh.js +0 -163
  164. package/dist/SupportTicketStatusBadge-YdZzjvkh.js.map +0 -1
  165. package/dist/TeamAttachmentsTab-BxUpTWYh.js +0 -43
  166. package/dist/TeamHistoryTab-CUCT9MRG.js +0 -5
  167. package/dist/TeamHistoryTab-gB3H2KZv.js.map +0 -1
  168. package/dist/TeamList-By6pzWm5.js +0 -43
  169. package/dist/TeamMemberList-CYV9fWEb.js +0 -43
  170. package/dist/TeamMemberParent-CVvGqpxD.js +0 -43
  171. package/dist/TeamNotesTab-pfXTDhg6.js +0 -23
  172. package/dist/TeamNotesTab-pfXTDhg6.js.map +0 -1
  173. package/dist/TeamNotesTab-u4cDC67X.js +0 -8
  174. package/dist/TeamParent-BxT1KubK.js +0 -43
  175. package/dist/UserListPage-DsQdH2Sm.js +0 -4
  176. package/dist/UserProfilePage-B73JhjUu.js +0 -7
  177. package/dist/ViewTeam-DzX-obEl.js +0 -43
  178. package/dist/ViewTeamMember-PF6S_4Pb.js +0 -43
  179. package/dist/ZiniaContainer-C7c7Vwkh.js +0 -18
  180. package/dist/ZiniaContainer-C7c7Vwkh.js.map +0 -1
  181. package/dist/convertToLocalDateTime-D4IoNvRj.js.map +0 -1
  182. package/dist/creditValueFormatter-DftEzu8d.js +0 -128
  183. package/dist/creditValueFormatter-DftEzu8d.js.map +0 -1
  184. package/dist/src-o5fMIo5_.js.map +0 -1
  185. package/dist/useRpcAuth-BLlRSHy8.js.map +0 -1
  186. /package/dist/{TeamMembersTab-CpE9BaCi.js → TeamMembersTab-DTJxmb-M.js} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"file":"InlineAttachments-I39rOvip.js","names":["files: Attachment[]","queueItem: QueueItem"],"sources":["../src/components/ConfirmDialog.vue","../src/components/ImageModal.vue","../src/slices/support_ticket/shared/InlineAttachments.vue"],"sourcesContent":["<template>\n <dialog\n ref=\"dialogRef\"\n :class=\"['modal', { 'modal-open': isOpen }]\"\n @click=\"handleBackdropClick\"\n >\n <div class=\"modal-box\" @click.stop>\n <h3 class=\"font-bold text-lg mb-4\">{{ title }}</h3>\n <div class=\"py-4\">\n <slot name=\"message\">\n <p>{{ message }}</p>\n </slot>\n </div>\n <div class=\"modal-action\">\n <button\n class=\"btn btn-outline\"\n @click.prevent=\"handleCancel\"\n :disabled=\"isProcessing\"\n type=\"button\"\n >\n {{ cancelText }}\n </button>\n <button\n class=\"btn\"\n :class=\"confirmButtonClass\"\n @click.prevent=\"handleConfirm\"\n :disabled=\"isProcessing\"\n type=\"button\"\n >\n {{ isProcessing ? processingText : confirmText }}\n </button>\n </div>\n </div>\n </dialog>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, watch } from 'vue';\n\ninterface Props {\n modelValue: boolean;\n title?: string;\n message?: string;\n confirmText?: string;\n cancelText?: string;\n processingText?: string;\n confirmButtonClass?: string;\n isProcessing?: boolean;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n title: 'Confirm',\n message: 'Are you sure?',\n confirmText: 'Confirm',\n cancelText: 'Cancel',\n processingText: 'Processing...',\n confirmButtonClass: 'btn-primary',\n isProcessing: false,\n});\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: boolean];\n confirm: [];\n cancel: [];\n}>();\n\nconst dialogRef = ref<HTMLDialogElement | null>(null);\nconst isOpen = ref(props.modelValue);\n\nwatch(\n () => props.modelValue,\n (newValue) => {\n isOpen.value = newValue;\n if (newValue && dialogRef.value) {\n dialogRef.value.showModal();\n } else if (dialogRef.value) {\n dialogRef.value.close();\n }\n },\n { immediate: true },\n);\n\nwatch(isOpen, (newValue) => {\n if (newValue && dialogRef.value) {\n dialogRef.value.showModal();\n } else if (dialogRef.value) {\n dialogRef.value.close();\n }\n});\n\nconst handleConfirm = () => {\n emit('confirm');\n};\n\nconst handleCancel = () => {\n isOpen.value = false;\n emit('update:modelValue', false);\n emit('cancel');\n};\n\nconst handleBackdropClick = (event: MouseEvent) => {\n // Close when clicking the backdrop (modal itself)\n if (event.target === dialogRef.value) {\n handleCancel();\n }\n};\n</script>\n","<template>\n <dialog\n ref=\"dialogRef\"\n class=\"modal\"\n :class=\"{ 'modal-open': isOpen }\"\n @click=\"handleBackdropClick\"\n @keydown=\"handleKeydown\"\n >\n <div class=\"modal-box w-full max-w-full h-full max-h-full p-0 flex flex-col bg-base-100\">\n <!-- Header -->\n <div\n class=\"flex items-center justify-between p-3 sm:p-4 border-b border-base-300 flex-shrink-0 bg-base-100/95 backdrop-blur\"\n >\n <div class=\"flex-1 min-w-0 mr-2\">\n <h3 class=\"font-semibold text-sm sm:text-base truncate\">\n {{ imageName }}\n </h3>\n <p\n v-if=\"imageIndex !== null && totalImages !== null\"\n class=\"text-xs text-base-content/60 mt-0.5\"\n >\n {{ imageIndex + 1 }} / {{ totalImages }}\n </p>\n </div>\n <div class=\"flex items-center gap-1 sm:gap-2 flex-shrink-0\">\n <!-- Navigation buttons (if multiple images) -->\n <button\n v-if=\"showNavigation && imageIndex !== null && imageIndex > 0\"\n @click.prevent=\"goToPrevious\"\n class=\"btn btn-sm btn-circle btn-ghost\"\n type=\"button\"\n title=\"Previous image\"\n aria-label=\"Previous image\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"h-5 w-5\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M15 19l-7-7 7-7\"\n />\n </svg>\n </button>\n <button\n v-if=\"showNavigation && imageIndex !== null && imageIndex < (totalImages || 0) - 1\"\n @click.prevent=\"goToNext\"\n class=\"btn btn-sm btn-circle btn-ghost\"\n type=\"button\"\n title=\"Next image\"\n aria-label=\"Next image\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"h-5 w-5\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M9 5l7 7-7 7\"\n />\n </svg>\n </button>\n <!-- Download button -->\n <button\n v-if=\"props.onDownload\"\n @click.prevent=\"handleDownload\"\n class=\"btn btn-sm btn-circle btn-ghost\"\n type=\"button\"\n title=\"Download\"\n aria-label=\"Download image\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"h-5 w-5\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4\"\n />\n </svg>\n </button>\n <!-- Close button -->\n <button\n @click.prevent=\"handleClose\"\n class=\"btn btn-sm btn-circle btn-ghost\"\n type=\"button\"\n title=\"Close\"\n aria-label=\"Close modal\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"h-5 w-5\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n </button>\n </div>\n </div>\n\n <!-- Image container -->\n <div\n ref=\"imageContainerRef\"\n class=\"flex-1 flex items-center justify-center overflow-hidden bg-base-200 relative\"\n >\n <!-- Loading state -->\n <div v-if=\"isLoading\" class=\"absolute inset-0 flex items-center justify-center\">\n <span class=\"loading loading-spinner loading-lg\"></span>\n </div>\n\n <!-- Error state -->\n <div\n v-if=\"hasError\"\n class=\"absolute inset-0 flex flex-col items-center justify-center p-4 text-center\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"h-12 w-12 text-error mb-2\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\"\n />\n </svg>\n <p class=\"text-sm text-base-content/70\">Failed to load image</p>\n </div>\n\n <!-- Image -->\n <img\n v-if=\"imageSrc && !hasError\"\n ref=\"imageRef\"\n :src=\"imageSrc\"\n :alt=\"imageName\"\n class=\"max-w-full max-h-full object-contain\"\n :class=\"{\n 'transition-transform duration-300 ease-out':\n !isDragging && !isPinching && !isResetting,\n }\"\n :style=\"imageStyle\"\n @load=\"handleImageLoad\"\n @error=\"handleImageError\"\n @dblclick=\"resetZoom\"\n @touchstart.stop=\"handleImageTouchStart\"\n @touchmove.stop=\"handleImageTouchMove\"\n @touchend.stop=\"handleImageTouchEnd\"\n />\n\n <!-- Zoom controls -->\n <div\n v-if=\"imageSrc && !hasError\"\n class=\"zoom-controls absolute bottom-4 left-1/2 transform -translate-x-1/2 flex gap-1 sm:gap-2 bg-base-100/90 backdrop-blur rounded-lg p-1.5 sm:p-2 shadow-lg z-10\"\n @touchstart.stop\n @touchmove.stop\n @touchend.stop\n @click.stop\n >\n <button\n @click.prevent=\"zoomOut\"\n class=\"btn btn-sm btn-circle btn-ghost\"\n type=\"button\"\n :disabled=\"scale <= minScale\"\n title=\"Zoom out\"\n aria-label=\"Zoom out\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"h-4 w-4\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0zM13 10H7\"\n />\n </svg>\n </button>\n <button\n @click.prevent=\"resetZoom\"\n class=\"text-xs flex items-center px-2 text-base-content/70 hover:text-base-content hover:bg-base-200 rounded transition-colors cursor-pointer\"\n type=\"button\"\n title=\"Reset zoom to 100%\"\n aria-label=\"Reset zoom to 100%\"\n >\n {{ Math.round(scale * 100) }}%\n </button>\n <button\n @click.prevent=\"zoomIn\"\n class=\"btn btn-sm btn-circle btn-ghost\"\n type=\"button\"\n :disabled=\"scale >= maxScale\"\n title=\"Zoom in\"\n aria-label=\"Zoom in\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"h-4 w-4\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0zM10 7v6m3-3H7\"\n />\n </svg>\n </button>\n <button\n @click.prevent=\"rotateImage\"\n class=\"btn btn-sm btn-circle btn-ghost\"\n type=\"button\"\n title=\"Rotate image\"\n aria-label=\"Rotate image\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n stroke-width=\"1.5\"\n stroke=\"currentColor\"\n aria-hidden=\"true\"\n data-slot=\"icon\"\n fill=\"none\"\n class=\"size-6\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n d=\"M18.363 5.634A8.997 9.002 29.494 0 0 7.5 4.206 8.997 9.002 29.494 0 0 3.306 14.33 8.997 9.002 29.494 0 0 11.996 21a8.997 9.002 29.494 0 0 8.694-6.673m-2.327-8.693L20.87 8.14m.017-4.994v5.015m0 0h-5.013\"\n ></path>\n </svg>\n </button>\n </div>\n </div>\n </div>\n <form method=\"dialog\" class=\"modal-backdrop\">\n <button type=\"button\" @click.prevent=\"handleClose\">close</button>\n </form>\n </dialog>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue';\n\ninterface Props {\n isOpen: boolean;\n imageSrc?: string;\n imageName?: string;\n imageIndex?: number | null;\n totalImages?: number | null;\n onDownload?: () => void;\n onPrevious?: () => void;\n onNext?: () => void;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n imageSrc: '',\n imageName: '',\n imageIndex: null,\n totalImages: null,\n onDownload: undefined,\n onPrevious: undefined,\n onNext: undefined,\n});\n\nconst emit = defineEmits<{\n close: [];\n}>();\n\nconst dialogRef = ref<HTMLDialogElement | null>(null);\nconst imageRef = ref<HTMLImageElement | null>(null);\nconst imageContainerRef = ref<HTMLDivElement | null>(null);\nconst isOpen = ref(props.isOpen);\nconst isLoading = ref(false);\nconst hasError = ref(false);\n\n// Zoom and pan state\nconst scale = ref(1);\nconst translateX = ref(0);\nconst translateY = ref(0);\nconst rotation = ref(0); // Rotation in degrees (can go beyond 360 for smooth transitions)\nconst minScale = 0.5;\nconst maxScale = 5;\nconst zoomStep = 0.05; // Flat 5% increments (0.05 = 5%)\n\n// Animation state\nconst isDragging = ref(false);\nconst isPinching = ref(false);\nconst isResetting = ref(false); // Track when resetting to disable transition\n\n// Touch state for pinch zoom and pan\nconst touchState = ref<{\n type: 'pinch' | 'pan';\n initialDistance?: number;\n initialScale?: number;\n initialTranslateX?: number;\n initialTranslateY?: number;\n initialTouches?: Touch[];\n lastPanX?: number;\n lastPanY?: number;\n} | null>(null);\n\n// Mouse drag state for panning\nconst mouseDragState = ref<{\n isDragging: boolean;\n startX: number;\n startY: number;\n startTranslateX: number;\n startTranslateY: number;\n} | null>(null);\n\n// Mobile detection\nconst isMobile = ref(false);\n\nconst imageStyle = computed(() => ({\n transform: `scale(${scale.value}) translate(${translateX.value}px, ${translateY.value}px) rotate(${rotation.value}deg)`,\n cursor: mouseDragState.value?.isDragging ? 'grabbing' : scale.value > 1 ? 'grab' : 'default',\n touchAction: 'none' as const, // Prevent default touch behaviors\n userSelect: 'none' as const, // Prevent text selection during drag\n willChange: isDragging.value || isPinching.value ? 'transform' : 'auto', // Optimize for animations\n}));\n\nconst showNavigation = computed(() => {\n return (\n props.totalImages !== null && props.totalImages > 1 && (props.onPrevious || props.onNext)\n );\n});\n\n// Watch for modal open/close\nwatch(\n () => props.isOpen,\n (newValue) => {\n isOpen.value = newValue;\n if (newValue && dialogRef.value) {\n dialogRef.value.showModal();\n // Reset zoom and rotation when opening\n isResetting.value = true;\n scale.value = 1;\n translateX.value = 0;\n translateY.value = 0;\n rotation.value = 0;\n touchState.value = null;\n mouseDragState.value = null;\n isDragging.value = false;\n isPinching.value = false;\n isLoading.value = true;\n hasError.value = false;\n // Re-enable transitions after modal opens\n nextTick(() => {\n setTimeout(() => {\n isResetting.value = false;\n }, 50);\n });\n\n // Add event listeners with passive: false only when modal is open\n nextTick(() => {\n if (imageContainerRef.value) {\n imageContainerRef.value.addEventListener('wheel', handleWheel, {\n passive: false,\n });\n imageContainerRef.value.addEventListener('mousedown', handleMouseDown);\n // Container-level touch handlers (for areas outside the image)\n imageContainerRef.value.addEventListener('touchstart', handleTouchStart, {\n passive: false,\n });\n imageContainerRef.value.addEventListener('touchmove', handleTouchMove, {\n passive: false,\n });\n imageContainerRef.value.addEventListener('touchend', handleTouchEnd, {\n passive: true,\n });\n imageContainerRef.value.addEventListener('touchcancel', handleTouchEnd, {\n passive: true,\n });\n }\n // Add global mouse listeners for drag\n document.addEventListener('mousemove', handleMouseMove);\n document.addEventListener('mouseup', handleMouseUp);\n });\n } else if (dialogRef.value) {\n dialogRef.value.close();\n\n // Remove event listeners when modal closes\n if (imageContainerRef.value) {\n imageContainerRef.value.removeEventListener('wheel', handleWheel);\n imageContainerRef.value.removeEventListener('mousedown', handleMouseDown);\n imageContainerRef.value.removeEventListener('touchstart', handleTouchStart);\n imageContainerRef.value.removeEventListener('touchmove', handleTouchMove);\n imageContainerRef.value.removeEventListener('touchend', handleTouchEnd);\n imageContainerRef.value.removeEventListener('touchcancel', handleTouchEnd);\n }\n // Remove global mouse listeners\n document.removeEventListener('mousemove', handleMouseMove);\n document.removeEventListener('mouseup', handleMouseUp);\n // Clear states when modal closes\n touchState.value = null;\n mouseDragState.value = null;\n }\n },\n { immediate: true },\n);\n\n// Watch for image source changes\nwatch(\n () => props.imageSrc,\n () => {\n if (props.isOpen && props.imageSrc) {\n isLoading.value = true;\n hasError.value = false;\n // Reset zoom and rotation when image changes\n scale.value = 1;\n translateX.value = 0;\n translateY.value = 0;\n rotation.value = 0;\n }\n },\n);\n\n// Watch for image index changes (navigation)\nwatch(\n () => props.imageIndex,\n () => {\n if (props.isOpen) {\n resetZoom();\n isLoading.value = true;\n hasError.value = false;\n }\n },\n);\n\n// Mobile detection\nonMounted(() => {\n isMobile.value = window.innerWidth < 768;\n window.addEventListener('resize', () => {\n isMobile.value = window.innerWidth < 768;\n });\n});\n\n// Keyboard navigation\nconst handleKeydown = (event: KeyboardEvent) => {\n if (!props.isOpen) return;\n\n switch (event.key) {\n case 'Escape':\n handleClose();\n break;\n case 'ArrowLeft':\n if (showNavigation.value && props.imageIndex !== null && props.imageIndex > 0) {\n event.preventDefault();\n goToPrevious();\n }\n break;\n case 'ArrowRight':\n if (\n showNavigation.value &&\n props.imageIndex !== null &&\n props.imageIndex < (props.totalImages || 0) - 1\n ) {\n event.preventDefault();\n goToNext();\n }\n break;\n case '+':\n case '=':\n event.preventDefault();\n zoomIn();\n break;\n case '-':\n event.preventDefault();\n zoomOut();\n break;\n case '0':\n event.preventDefault();\n resetZoom();\n break;\n }\n};\n\n// Zoom functions - using flat 5% increments\nconst zoomIn = () => {\n if (scale.value < maxScale) {\n const newScale = scale.value + zoomStep;\n scale.value = Math.min(maxScale, newScale);\n }\n};\n\nconst zoomOut = () => {\n if (scale.value > minScale) {\n const newScale = scale.value - zoomStep;\n scale.value = Math.max(minScale, newScale);\n // Reset pan if zoomed out to fit\n if (scale.value <= 1) {\n translateX.value = 0;\n translateY.value = 0;\n }\n }\n};\n\nconst resetZoom = () => {\n // Disable transitions to prevent counter-clockwise animation\n isResetting.value = true;\n\n scale.value = 1;\n translateX.value = 0;\n translateY.value = 0;\n rotation.value = 0;\n\n touchState.value = null;\n mouseDragState.value = null;\n isDragging.value = false;\n isPinching.value = false;\n\n // Re-enable transitions after reset\n nextTick(() => {\n setTimeout(() => {\n isResetting.value = false;\n }, 50);\n });\n};\n\nconst rotateImage = () => {\n // Rotate 90 degrees clockwise\n // Don't use modulo - let it accumulate so we can control reset direction\n rotation.value = rotation.value + 90;\n};\n\n// Mouse wheel zoom - fixed to zoom towards cursor with smooth updates\nconst handleWheel = (event: WheelEvent) => {\n if (!imageRef.value || !props.isOpen) return;\n\n // Always prevent default to avoid page scrolling\n event.preventDefault();\n\n // Calculate zoom delta based on wheel direction\n // Use deltaY for vertical scroll, deltaX for horizontal (trackpad support)\n // Reverse sign: scroll down (positive delta) should zoom out, scroll up (negative delta) should zoom in\n const delta = event.deltaY !== 0 ? event.deltaY : event.deltaX;\n const scrollDirection = delta > 0 ? -1 : 1; // Negative for scroll down (zoom out), positive for scroll up (zoom in)\n\n const oldScale = scale.value;\n // Apply flat 5% increment based on scroll direction\n const newScale =\n scrollDirection > 0\n ? oldScale + zoomStep // Zoom in: add 0.05\n : oldScale - zoomStep; // Zoom out: subtract 0.05\n\n const clampedScale = Math.max(minScale, Math.min(maxScale, newScale));\n\n if (Math.abs(clampedScale - oldScale) > 0.001) {\n // Get the image container bounds\n const containerRect = imageContainerRef.value?.getBoundingClientRect();\n if (!containerRect) return;\n\n // Get mouse position relative to container center\n const mouseX = event.clientX - containerRect.left - containerRect.width / 2;\n const mouseY = event.clientY - containerRect.top - containerRect.height / 2;\n\n // Calculate the point on the image (in image coordinates) that the mouse is over\n // This accounts for current translation and scale\n const imagePointX = (mouseX - translateX.value) / oldScale;\n const imagePointY = (mouseY - translateY.value) / oldScale;\n\n // Apply new scale\n scale.value = clampedScale;\n\n // Adjust translation so the same image point stays under the mouse\n // After zoom, we want: mouseX = imagePointX * clampedScale + translateX\n translateX.value = mouseX - imagePointX * clampedScale;\n translateY.value = mouseY - imagePointY * clampedScale;\n\n // Reset pan if zoomed out to fit\n if (scale.value <= 1) {\n translateX.value = 0;\n translateY.value = 0;\n }\n }\n};\n\n// Mouse drag for panning\nconst handleMouseDown = (event: MouseEvent) => {\n if (!imageRef.value || !props.isOpen || scale.value <= 1) return;\n\n // Only start drag on left mouse button\n if (event.button !== 0) return;\n\n event.preventDefault();\n\n isDragging.value = true;\n mouseDragState.value = {\n isDragging: true,\n startX: event.clientX,\n startY: event.clientY,\n startTranslateX: translateX.value,\n startTranslateY: translateY.value,\n };\n\n // Change cursor to grabbing\n if (imageRef.value) {\n imageRef.value.style.cursor = 'grabbing';\n }\n};\n\nconst handleMouseMove = (event: MouseEvent) => {\n if (!mouseDragState.value || !mouseDragState.value.isDragging || !props.isOpen) return;\n\n event.preventDefault();\n\n // Use requestAnimationFrame for smoother updates\n requestAnimationFrame(() => {\n if (!mouseDragState.value) return;\n\n const deltaX = event.clientX - mouseDragState.value.startX;\n const deltaY = event.clientY - mouseDragState.value.startY;\n\n // Pan relative to current scale\n translateX.value = mouseDragState.value.startTranslateX + deltaX / scale.value;\n translateY.value = mouseDragState.value.startTranslateY + deltaY / scale.value;\n\n // Clamp translation to reasonable bounds\n const maxTranslate = 300;\n translateX.value = Math.max(-maxTranslate, Math.min(maxTranslate, translateX.value));\n translateY.value = Math.max(-maxTranslate, Math.min(maxTranslate, translateY.value));\n });\n};\n\nconst handleMouseUp = () => {\n if (mouseDragState.value) {\n mouseDragState.value.isDragging = false;\n }\n mouseDragState.value = null;\n isDragging.value = false;\n\n // Reset cursor\n if (imageRef.value) {\n imageRef.value.style.cursor = scale.value > 1 ? 'grab' : 'default';\n }\n};\n\n// Touch gestures - improved implementation\nconst getTouchDistance = (touches: Touch[]): number => {\n if (touches.length < 2) return 0;\n const touch1 = touches[0];\n const touch2 = touches[1];\n if (!touch1 || !touch2) return 0;\n const dx = touch1.clientX - touch2.clientX;\n const dy = touch1.clientY - touch2.clientY;\n return Math.sqrt(dx * dx + dy * dy);\n};\n\nconst getTouchCenter = (touches: Touch[]): { x: number; y: number } | null => {\n if (touches.length === 0) return null;\n if (touches.length === 1) {\n const touch = touches[0];\n if (!touch) return null;\n return { x: touch.clientX, y: touch.clientY };\n }\n // For 2 touches, return the center point\n const touch1 = touches[0];\n const touch2 = touches[1];\n if (!touch1 || !touch2) return null;\n return {\n x: (touch1.clientX + touch2.clientX) / 2,\n y: (touch1.clientY + touch2.clientY) / 2,\n };\n};\n\n// Handle touch events on the image directly\nconst handleImageTouchStart = (event: TouchEvent) => {\n if (!imageRef.value || !props.isOpen) return;\n\n event.preventDefault();\n event.stopPropagation();\n\n const touches = Array.from(event.touches);\n\n if (touches.length === 2) {\n // Pinch zoom gesture\n isPinching.value = true;\n const distance = getTouchDistance(touches);\n const center = getTouchCenter(touches);\n\n if (center) {\n touchState.value = {\n type: 'pinch',\n initialDistance: distance,\n initialScale: scale.value,\n initialTranslateX: translateX.value,\n initialTranslateY: translateY.value,\n initialTouches: touches,\n };\n }\n } else if (touches.length === 1 && scale.value > 1) {\n // Single touch pan (only when zoomed in)\n isDragging.value = true;\n const touch = touches[0];\n if (touch) {\n touchState.value = {\n type: 'pan',\n lastPanX: touch.clientX,\n lastPanY: touch.clientY,\n };\n }\n } else {\n // Clear any existing touch state\n touchState.value = null;\n isDragging.value = false;\n isPinching.value = false;\n }\n};\n\nconst handleImageTouchMove = (event: TouchEvent) => {\n if (!imageRef.value || !props.isOpen || !touchState.value) return;\n\n event.preventDefault();\n event.stopPropagation();\n\n handleTouchMove(event);\n};\n\nconst handleImageTouchEnd = (event: TouchEvent) => {\n if (!imageRef.value || !props.isOpen) return;\n\n event.preventDefault();\n event.stopPropagation();\n\n handleTouchEnd();\n};\n\n// Handle touch events on the container (for areas outside the image)\nconst handleTouchStart = (event: TouchEvent) => {\n if (!imageRef.value || !props.isOpen) return;\n\n // Don't handle touch if it's on the zoom controls\n const target = event.target as HTMLElement;\n if (target.closest('.zoom-controls')) {\n return;\n }\n\n // If touch is on the image, let handleImageTouchStart handle it\n if (target === imageRef.value || imageRef.value.contains(target)) {\n return;\n }\n\n event.preventDefault(); // Prevent scrolling\n\n const touches = Array.from(event.touches);\n\n if (touches.length === 2) {\n // Pinch zoom gesture\n isPinching.value = true;\n const distance = getTouchDistance(touches);\n const center = getTouchCenter(touches);\n\n if (center) {\n touchState.value = {\n type: 'pinch',\n initialDistance: distance,\n initialScale: scale.value,\n initialTranslateX: translateX.value,\n initialTranslateY: translateY.value,\n initialTouches: touches,\n };\n }\n } else if (touches.length === 1 && scale.value > 1) {\n // Single touch pan (only when zoomed in)\n isDragging.value = true;\n const touch = touches[0];\n if (touch) {\n touchState.value = {\n type: 'pan',\n lastPanX: touch.clientX,\n lastPanY: touch.clientY,\n };\n }\n } else {\n // Clear any existing touch state\n touchState.value = null;\n isDragging.value = false;\n isPinching.value = false;\n }\n};\n\nconst handleTouchMove = (event: TouchEvent) => {\n if (!imageRef.value || !props.isOpen || !touchState.value) return;\n\n const touches = Array.from(event.touches);\n\n // Use requestAnimationFrame for smoother updates\n requestAnimationFrame(() => {\n if (!touchState.value) return;\n\n if (touchState.value.type === 'pinch' && touches.length === 2) {\n // Handle pinch zoom\n event.preventDefault();\n\n const distance = getTouchDistance(touches);\n if (touchState.value.initialDistance && touchState.value.initialScale !== undefined) {\n const scaleChange = distance / touchState.value.initialDistance;\n const newScale = Math.max(\n minScale,\n Math.min(maxScale, touchState.value.initialScale * scaleChange),\n );\n scale.value = newScale;\n\n // Optionally adjust translation based on pinch center\n // This keeps the pinch center point stable during zoom\n }\n } else if (touchState.value.type === 'pan' && touches.length === 1 && scale.value > 1) {\n // Handle single touch pan (only when zoomed in)\n event.preventDefault();\n\n const touch = touches[0];\n if (\n touch &&\n touchState.value.lastPanX !== undefined &&\n touchState.value.lastPanY !== undefined\n ) {\n const deltaX = touch.clientX - touchState.value.lastPanX;\n const deltaY = touch.clientY - touchState.value.lastPanY;\n\n // Pan relative to current scale\n translateX.value += deltaX / scale.value;\n translateY.value += deltaY / scale.value;\n\n // Clamp translation\n const maxTranslate = 200;\n translateX.value = Math.max(-maxTranslate, Math.min(maxTranslate, translateX.value));\n translateY.value = Math.max(-maxTranslate, Math.min(maxTranslate, translateY.value));\n\n touchState.value.lastPanX = touch.clientX;\n touchState.value.lastPanY = touch.clientY;\n }\n } else {\n // Touch count changed or invalid state - reset\n touchState.value = null;\n isDragging.value = false;\n isPinching.value = false;\n }\n });\n};\n\nconst handleTouchEnd = () => {\n touchState.value = null;\n isDragging.value = false;\n isPinching.value = false;\n};\n\n// Image load handlers\nconst handleImageLoad = () => {\n isLoading.value = false;\n hasError.value = false;\n};\n\nconst handleImageError = () => {\n isLoading.value = false;\n hasError.value = true;\n};\n\n// Navigation\nconst goToPrevious = () => {\n if (props.onPrevious) {\n props.onPrevious();\n }\n};\n\nconst goToNext = () => {\n if (props.onNext) {\n props.onNext();\n }\n};\n\n// Actions\nconst handleDownload = () => {\n if (props.onDownload) {\n props.onDownload();\n }\n};\n\nconst handleClose = () => {\n isOpen.value = false;\n emit('close');\n};\n\nconst handleBackdropClick = (event: MouseEvent) => {\n if (event.target === dialogRef.value) {\n handleClose();\n }\n};\n\n// Cleanup\nonUnmounted(() => {\n window.removeEventListener('resize', () => {});\n // Clean up event listeners\n if (imageContainerRef.value) {\n imageContainerRef.value.removeEventListener('wheel', handleWheel);\n imageContainerRef.value.removeEventListener('mousedown', handleMouseDown);\n imageContainerRef.value.removeEventListener('touchstart', handleTouchStart);\n imageContainerRef.value.removeEventListener('touchmove', handleTouchMove);\n imageContainerRef.value.removeEventListener('touchend', handleTouchEnd);\n imageContainerRef.value.removeEventListener('touchcancel', handleTouchEnd);\n }\n // Remove global mouse listeners\n document.removeEventListener('mousemove', handleMouseMove);\n document.removeEventListener('mouseup', handleMouseUp);\n});\n</script>\n","<template>\n <div class=\"mt-4 sm:mt-6\">\n <div\n class=\"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-2 sm:gap-0 mb-3\"\n >\n <h3 class=\"text-base sm:text-lg font-semibold\">Attachments</h3>\n <button\n v-if=\"canUpload\"\n @click.prevent=\"openFileSelector\"\n class=\"btn btn-sm btn-primary w-full sm:w-auto\"\n :disabled=\"isUploading\"\n type=\"button\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"h-4 w-4 mr-1\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M12 4v16m8-8H4\"\n />\n </svg>\n Add Files\n </button>\n </div>\n\n <input ref=\"fileInput\" type=\"file\" multiple class=\"hidden\" @change=\"handleFileSelect\" />\n\n <!-- Drag & Drop Zone (hidden on mobile, shown on desktop) -->\n <div\n v-if=\"canUpload\"\n class=\"hidden sm:block border-2 border-dashed rounded-lg p-4 sm:p-6 text-center mb-4 transition-colors cursor-pointer\"\n :class=\"{\n 'border-primary bg-primary/5': isDragging,\n 'border-base-300 hover:border-primary/50': !isDragging,\n }\"\n @dragover.prevent=\"isDragging = true\"\n @dragleave.prevent=\"isDragging = false\"\n @drop.prevent=\"handleFileDrop\"\n @click.prevent.stop=\"openFileSelector\"\n >\n <div class=\"flex flex-col items-center justify-center py-2 sm:py-4\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"h-8 w-8 sm:h-12 sm:w-12 mb-2 text-primary\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12\"\n />\n </svg>\n <p class=\"text-sm sm:text-lg font-medium\">Drag and drop files here</p>\n <p class=\"text-xs sm:text-sm text-base-content/70 mt-1\">or click to browse files</p>\n <p v-if=\"!recordId\" class=\"text-xs text-base-content/50 mt-2 sm:mt-3\">\n Files will be queued until ticket is created\n </p>\n </div>\n </div>\n\n <!-- Upload Queue -->\n <div v-if=\"uploadQueue.length > 0\" class=\"mb-4 space-y-2\">\n <div\n v-for=\"item in uploadQueue\"\n :key=\"item.id\"\n class=\"flex flex-col sm:flex-row sm:items-center gap-2 sm:gap-3 p-2 sm:p-3 bg-base-200 rounded-lg\"\n >\n <div class=\"flex-1 min-w-0\">\n <div class=\"text-xs sm:text-sm font-medium truncate\">\n {{ item.file.name }}\n </div>\n <div\n v-if=\"item.status === 'uploading'\"\n class=\"w-full bg-base-300 rounded-full h-1.5 mt-1\"\n >\n <div\n class=\"bg-primary h-1.5 rounded-full transition-all\"\n :style=\"{ width: `${item.progress}%` }\"\n ></div>\n </div>\n <div v-if=\"item.status === 'error'\" class=\"text-xs text-error mt-1 break-words\">\n {{ item.errorMessage }}\n </div>\n </div>\n <div class=\"flex gap-2 sm:gap-1\">\n <button\n v-if=\"item.status === 'error'\"\n @click.prevent=\"retryUpload(item)\"\n class=\"btn btn-xs btn-ghost flex-1 sm:flex-none\"\n type=\"button\"\n >\n Retry\n </button>\n <button\n v-if=\"item.status !== 'uploading'\"\n @click.prevent=\"removeFromQueue(item.id)\"\n class=\"btn btn-xs btn-ghost text-error flex-1 sm:flex-none\"\n type=\"button\"\n >\n Remove\n </button>\n </div>\n </div>\n </div>\n\n <!-- Attachments List -->\n <div v-if=\"(attachments.length > 0 || attachmentsLoading) && recordId\" class=\"space-y-2\">\n <div v-if=\"attachmentsLoading\" class=\"flex justify-center py-4\">\n <span class=\"loading loading-spinner loading-sm\"></span>\n </div>\n <div\n v-for=\"file in attachments\"\n :key=\"file.id\"\n class=\"flex flex-col sm:flex-row sm:items-center gap-2 sm:gap-3 p-2 sm:p-3 bg-base-100 border border-base-300 rounded-lg hover:bg-base-200 transition-colors\"\n :class=\"{ 'cursor-pointer': isImage(file.type) }\"\n @click.prevent=\"isImage(file.type) && viewImage(file)\"\n >\n <div class=\"flex items-center gap-2 sm:gap-3 flex-1 min-w-0 w-full sm:w-auto\">\n <div class=\"flex-shrink-0\">\n <!-- Image thumbnail preview -->\n <div\n v-if=\"isImage(file.type)\"\n class=\"w-10 h-10 sm:w-12 sm:h-12 rounded overflow-hidden bg-base-200 flex items-center justify-center\"\n >\n <img\n v-if=\"getImageUrlSync(file.id)\"\n :src=\"getImageUrlSync(file.id)\"\n :alt=\"file.name\"\n class=\"w-full h-full object-cover\"\n @error=\"handleImageError\"\n />\n <div v-else class=\"w-full h-full flex items-center justify-center\">\n <span class=\"loading loading-spinner loading-xs\"></span>\n </div>\n </div>\n <!-- File type badge for non-images -->\n <div v-else class=\"badge badge-sm\" :class=\"getFileTypeBadgeClass(file.type)\">\n {{ getFileTypeLabel(file.type) }}\n </div>\n </div>\n <div class=\"flex-1 min-w-0\">\n <div class=\"text-sm sm:text-base font-medium truncate\">\n {{ file.name }}\n </div>\n <div class=\"text-xs text-base-content/60\">\n {{ formatFileSize(file.size) }} •\n {{ formatDate(file.uploadedAt) }}\n </div>\n </div>\n </div>\n <div class=\"flex gap-1 justify-end sm:justify-start\" @click.stop>\n <button\n v-if=\"isImage(file.type)\"\n @click.prevent=\"viewImage(file)\"\n class=\"btn btn-sm btn-ghost btn-circle\"\n title=\"View Image\"\n type=\"button\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"h-4 w-4\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M15 12a3 3 0 11-6 0 3 3 0 016 0z\"\n />\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z\"\n />\n </svg>\n </button>\n <button\n @click.prevent=\"downloadFile(file, $event)\"\n class=\"btn btn-sm btn-ghost btn-circle\"\n title=\"Download\"\n type=\"button\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"h-4 w-4\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4\"\n />\n </svg>\n </button>\n <button\n v-if=\"canDelete\"\n @click.prevent=\"confirmDelete(file)\"\n class=\"btn btn-sm btn-ghost btn-circle text-error\"\n title=\"Delete\"\n type=\"button\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"h-4 w-4\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16\"\n />\n </svg>\n </button>\n </div>\n </div>\n </div>\n\n <div\n v-else-if=\"!attachmentsLoading && recordId\"\n class=\"text-center py-8 text-base-content/50\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"h-12 w-12 mx-auto mb-2 opacity-50\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M15.172 7l-6.586 6.586a2 2 0 102.828 2.828l6.414-6.586a4 4 0 00-5.656-5.656l-6.415 6.585a6 6 0 108.486 8.486L20.5 13\"\n />\n </svg>\n <p>No attachments</p>\n </div>\n\n <!-- Image View Modal -->\n <ImageModal\n :is-open=\"!!viewingImage\"\n :image-src=\"viewingImage ? getImageUrlSync(viewingImage.id) : ''\"\n :image-name=\"viewingImage?.name || ''\"\n :image-index=\"viewingImageIndex\"\n :total-images=\"imageAttachments.length\"\n :on-download=\"\n viewingImage\n ? () => {\n if (viewingImage) downloadFile(viewingImage, undefined);\n }\n : undefined\n \"\n :on-previous=\"canGoToPrevious ? goToPreviousImage : undefined\"\n :on-next=\"canGoToNext ? goToNextImage : undefined\"\n @close=\"closeImageModal\"\n />\n\n <!-- Delete Confirmation Modal -->\n <ConfirmDialog\n v-model=\"showDeleteModal\"\n title=\"Delete Attachment\"\n :message=\"deleteMessage\"\n confirm-text=\"Delete\"\n cancel-text=\"Cancel\"\n confirm-button-class=\"btn-error\"\n @confirm=\"deleteFile\"\n @cancel=\"closeDeleteModal\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport ConfirmDialog from '../../../components/ConfirmDialog.vue';\nimport ImageModal from '../../../components/ImageModal.vue';\nimport { useMutation } from '../../../composables/useMutation';\nimport { useQuery } from '../../../composables/useQuery';\nimport { useEnv } from '../../../composables/useEnv';\nimport { useUserSessionStore } from '../../../composables/useUserSessionStore';\nimport { computed, onUnmounted, ref, watch } from 'vue';\n\ninterface Attachment {\n id: string;\n name: string;\n size: number;\n type: string;\n uploadedAt: Date;\n}\n\ninterface QueueItem {\n id: string;\n file: File;\n status: 'pending' | 'uploading' | 'success' | 'error';\n progress: number;\n errorMessage?: string;\n}\n\ninterface Props {\n recordId?: string; // Optional for create forms\n canUpload?: boolean;\n canDelete?: boolean;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n canUpload: true,\n canDelete: true,\n});\n\nconst emit = defineEmits<{\n uploaded: [];\n deleted: [];\n filesQueued: [files: File[]];\n}>();\n\n// Expose methods for parent components (e.g., to get queued files after creation)\nconst uploadQueuedFiles = async (ticketId: string) => {\n // Upload all pending files with the new ticket ID\n const pendingItems = uploadQueue.value.filter((item) => item.status === 'pending');\n for (const item of pendingItems) {\n item.status = 'uploading';\n await uploadFile(item, ticketId);\n }\n};\n\ndefineExpose({\n getQueuedFiles: () =>\n uploadQueue.value.filter((item) => item.status === 'pending').map((item) => item.file),\n uploadQueuedFiles,\n});\n\nconst fileInput = ref<HTMLInputElement | null>(null);\nconst isDragging = ref(false);\nconst isUploading = ref(false);\nconst uploadQueue = ref<QueueItem[]>([]);\nconst fileToDelete = ref<Attachment | null>(null);\nconst showDeleteModal = ref(false);\nconst viewingImage = ref<Attachment | null>(null);\nconst imageUrls = ref<Map<string, string>>(new Map()); // Cache of image object URLs\n\nconst env = useEnv();\nconst userStore = useUserSessionStore();\n\n// Query attachments (only if recordId exists)\nconst {\n data: attachmentsData,\n loading: attachmentsLoading,\n refetch: refreshAttachments,\n} = useQuery(\n async (api) => {\n if (!props.recordId) return { files: [], folders: [] };\n return await api.attachments.listAttachments({\n record_id: props.recordId,\n record_type: 'support_ticket',\n filters: {\n limit: 100,\n include_folders: false,\n folder_id: null, // Only root level attachments for Jira-style\n },\n });\n },\n {\n enabled: computed(() => !!props.recordId),\n staleTime: 2 * 60 * 1000,\n },\n);\n\nconst attachments = computed<Attachment[]>(() => {\n if (!attachmentsData.value) return [];\n const files: Attachment[] = [];\n const fileItems = attachmentsData.value.files || [];\n for (const item of fileItems) {\n files.push({\n id: item.id,\n name: item.original_name,\n size: parseInt(item.file_size || '0'),\n type: item.content_type || '',\n uploadedAt: new Date(item.created_at),\n });\n }\n return files;\n});\n\nconst deleteMessage = computed(() => {\n if (!fileToDelete.value)\n return 'Are you sure you want to delete this attachment? This action cannot be undone.';\n return `Are you sure you want to delete \"${fileToDelete.value.name}\"? This action cannot be undone.`;\n});\n\n// Filter to only image attachments for navigation\nconst imageAttachments = computed(() => {\n return attachments.value.filter((file) => isImage(file.type));\n});\n\n// Current viewing image index\nconst viewingImageIndex = computed(() => {\n if (!viewingImage.value) return null;\n const index = imageAttachments.value.findIndex((img) => img.id === viewingImage.value?.id);\n return index >= 0 ? index : null;\n});\n\nconst canGoToPrevious = computed(() => {\n return viewingImageIndex.value !== null && viewingImageIndex.value > 0;\n});\n\nconst canGoToNext = computed(() => {\n return (\n viewingImageIndex.value !== null &&\n viewingImageIndex.value < imageAttachments.value.length - 1\n );\n});\n\n// Mutations\nconst { mutate: deleteAttachment } = useMutation(\n (api, input: { id: string }) => api.attachments.deleteAttachment(input.id),\n { invalidate: /^attachments?:/ },\n);\n\n// File type helpers\nconst getFileTypeLabel = (mimeType: string): string => {\n if (mimeType.startsWith('image/')) return 'IMG';\n if (mimeType.startsWith('video/')) return 'VID';\n if (mimeType.startsWith('audio/')) return 'AUD';\n if (mimeType.includes('pdf')) return 'PDF';\n if (mimeType.includes('word') || mimeType.includes('document')) return 'DOC';\n if (mimeType.includes('excel') || mimeType.includes('spreadsheet')) return 'XLS';\n if (mimeType.includes('zip') || mimeType.includes('archive')) return 'ZIP';\n return 'FILE';\n};\n\nconst getFileTypeBadgeClass = (mimeType: string): string => {\n if (mimeType.startsWith('image/')) return 'badge-primary';\n if (mimeType.startsWith('video/')) return 'badge-secondary';\n if (mimeType.includes('pdf')) return 'badge-error';\n if (mimeType.includes('word') || mimeType.includes('document')) return 'badge-info';\n return 'badge-ghost';\n};\n\nconst formatFileSize = (bytes: number): string => {\n if (bytes === 0) return '0 B';\n const k = 1024;\n const sizes = ['B', 'KB', 'MB', 'GB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;\n};\n\nconst formatDate = (date: Date): string => {\n return new Intl.DateTimeFormat('en-US', {\n month: 'short',\n day: 'numeric',\n year: 'numeric',\n }).format(date);\n};\n\n// Image helpers\nconst isImage = (mimeType: string): boolean => {\n return mimeType.startsWith('image/');\n};\n\nconst getImageUrl = async (fileId: string): Promise<string> => {\n // Check if we already have a cached URL\n if (imageUrls.value.has(fileId)) {\n return imageUrls.value.get(fileId)!;\n }\n\n // Fetch image with bearer token\n try {\n const res = await fetch(\n `${env.restApiClient.apiUrl}/attachments/support_ticket/${fileId}`,\n {\n method: 'GET',\n headers: {\n Authorization: `Bearer ${userStore.accessToken}`,\n },\n },\n );\n\n if (!res.ok) {\n throw new Error('Failed to load image');\n }\n\n const blob = await res.blob();\n const url = URL.createObjectURL(blob);\n imageUrls.value.set(fileId, url);\n return url;\n } catch (error) {\n console.error('Failed to load image:', error);\n // Return empty string or placeholder\n return '';\n }\n};\n\n// Computed property to get image URLs for thumbnails\nconst getImageUrlSync = (fileId: string): string => {\n // For thumbnails, we'll use a loading state and fetch async\n // Return empty initially, will be updated when loaded\n return imageUrls.value.get(fileId) || '';\n};\n\n// Load image for thumbnail\nconst loadImageThumbnail = async (fileId: string) => {\n if (!imageUrls.value.has(fileId)) {\n await getImageUrl(fileId);\n }\n};\n\nconst handleImageError = (event: Event) => {\n const img = event.target as HTMLImageElement;\n img.style.display = 'none';\n // Could show a placeholder icon here\n};\n\n// Cleanup object URLs when component unmounts\nonUnmounted(() => {\n imageUrls.value.forEach((url) => {\n URL.revokeObjectURL(url);\n });\n imageUrls.value.clear();\n});\n\nconst viewImage = async (file: Attachment) => {\n viewingImage.value = file;\n // Load the image URL if not already loaded\n if (!imageUrls.value.has(file.id)) {\n await getImageUrl(file.id);\n }\n};\n\nconst goToPreviousImage = () => {\n if (!canGoToPrevious.value || viewingImageIndex.value === null) return;\n const previousImage = imageAttachments.value[viewingImageIndex.value - 1];\n if (previousImage) {\n viewImage(previousImage);\n }\n};\n\nconst goToNextImage = () => {\n if (!canGoToNext.value || viewingImageIndex.value === null) return;\n const nextImage = imageAttachments.value[viewingImageIndex.value + 1];\n if (nextImage) {\n viewImage(nextImage);\n }\n};\n\nconst closeImageModal = () => {\n viewingImage.value = null;\n};\n\n// File upload\nconst openFileSelector = (event?: Event) => {\n // Always prevent default and stop propagation\n if (event) {\n event.preventDefault();\n event.stopPropagation();\n }\n\n // Prevent if already uploading\n if (isUploading.value) {\n return;\n }\n\n // Allow file selection even without recordId (for create forms)\n // Files will be queued and uploaded after ticket creation\n fileInput.value?.click();\n};\n\nconst processFiles = (files: File[]) => {\n const fileArray = Array.from(files);\n fileArray.forEach((file) => {\n const queueItem: QueueItem = {\n id: `${Date.now()}-${Math.random()}`,\n file,\n status: 'pending',\n progress: 0,\n };\n uploadQueue.value.push(queueItem);\n });\n\n emit('filesQueued', fileArray);\n\n // If recordId exists, upload immediately. Otherwise, queue for later\n if (props.recordId) {\n processUploadQueue();\n }\n};\n\nconst handleFileSelect = (event: Event) => {\n const target = event.target as HTMLInputElement;\n const files = target.files;\n if (!files) return;\n\n processFiles(Array.from(files));\n target.value = ''; // Reset input\n};\n\nconst handleFileDrop = (event: DragEvent) => {\n isDragging.value = false;\n\n const files = event.dataTransfer?.files;\n if (!files || files.length === 0) return;\n\n processFiles(Array.from(files));\n};\n\nconst processUploadQueue = async (ticketId?: string) => {\n const nextItem = uploadQueue.value.find((item) => item.status === 'pending');\n if (!nextItem) {\n isUploading.value = false;\n return;\n }\n\n isUploading.value = true;\n nextItem.status = 'uploading';\n\n await uploadFile(nextItem, ticketId);\n\n // Process next item\n if (uploadQueue.value.some((item) => item.status === 'pending')) {\n processUploadQueue(ticketId);\n } else {\n isUploading.value = false;\n }\n};\n\nconst uploadFile = async (item: QueueItem, ticketId?: string) => {\n const recordId = ticketId || props.recordId;\n if (!recordId) {\n item.status = 'error';\n item.errorMessage = 'Ticket ID is required for upload';\n return;\n }\n\n const progressInterval = setInterval(() => {\n item.progress += Math.random() * 10;\n item.progress = Math.min(99, Math.round(item.progress * 100) / 100);\n }, 200);\n\n try {\n const formData = new FormData();\n formData.append('file', item.file);\n formData.append('file_name', item.file.name);\n formData.append('record_id', recordId);\n formData.append('record_type', 'support_ticket');\n\n const response = await fetch(\n `${env.restApiClient.apiUrl}/attachments/support_ticket/${recordId}`,\n {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${userStore.accessToken}`,\n },\n body: formData,\n },\n );\n\n if (!response.ok) {\n throw new Error(`Upload failed: ${response.statusText}`);\n }\n\n const result = await response.json();\n if (result && result.id) {\n clearInterval(progressInterval);\n item.progress = 100;\n item.status = 'success';\n setTimeout(() => {\n removeFromQueue(item.id);\n refreshAttachments();\n emit('uploaded');\n }, 500);\n } else {\n throw new Error('Invalid response');\n }\n } catch (error) {\n clearInterval(progressInterval);\n item.status = 'error';\n item.errorMessage = error instanceof Error ? error.message : 'Upload failed';\n }\n};\n\nconst removeFromQueue = (id: string) => {\n const index = uploadQueue.value.findIndex((item) => item.id === id);\n if (index !== -1) {\n uploadQueue.value.splice(index, 1);\n }\n};\n\nconst retryUpload = (item: QueueItem) => {\n item.status = 'pending';\n item.progress = 0;\n item.errorMessage = undefined;\n if (props.recordId) {\n processUploadQueue();\n }\n};\n\n// File download\nconst downloadFile = async (file: Attachment, event?: Event) => {\n if (event) {\n event.preventDefault();\n event.stopPropagation();\n }\n try {\n const res = await fetch(\n `${env.restApiClient.apiUrl}/attachments/support_ticket/${file.id}`,\n {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${userStore.accessToken}`,\n },\n },\n );\n if (!res.ok) {\n throw new Error('Failed to download file');\n }\n const blob = await res.blob();\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = file.name;\n document.body.appendChild(a);\n a.click();\n a.remove();\n URL.revokeObjectURL(url);\n } catch (error) {\n console.error('Download failed:', error);\n }\n};\n\n// File delete\nconst confirmDelete = (file: Attachment) => {\n fileToDelete.value = file;\n showDeleteModal.value = true;\n};\n\nconst closeDeleteModal = () => {\n showDeleteModal.value = false;\n fileToDelete.value = null;\n};\n\nconst deleteFile = async () => {\n if (!fileToDelete.value) return;\n\n try {\n await deleteAttachment({ id: fileToDelete.value.id });\n refreshAttachments();\n emit('deleted');\n closeDeleteModal();\n } catch (error) {\n console.error('Delete failed:', error);\n }\n};\n\n// Watch for recordId changes\nwatch(\n () => props.recordId,\n (newRecordId, oldRecordId) => {\n if (newRecordId && newRecordId !== oldRecordId) {\n refreshAttachments();\n // If we have queued files and now have a recordId, upload them\n if (uploadQueue.value.some((item) => item.status === 'pending')) {\n processUploadQueue(newRecordId);\n }\n }\n },\n);\n\n// Load image thumbnails when attachments are loaded\nwatch(\n () => attachments.value,\n (newAttachments) => {\n newAttachments.forEach((file) => {\n if (isImage(file.type) && !imageUrls.value.has(file.id)) {\n loadImageThumbnail(file.id);\n }\n });\n },\n { immediate: true },\n);\n</script>\n"],"mappings":"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"}
@@ -1,7 +0,0 @@
1
- import "./useRpcAuth-BLlRSHy8.js";
2
- import "./useQueryCache-ByayvZgZ.js";
3
- import "./useMutation-CFwe7H9j.js";
4
- import "./AppLink-CHMMrSFI.js";
5
- import { t as LoginForm_default } from "./LoginForm-_PZ51Uwe.js";
6
-
7
- export { LoginForm_default as default };
@@ -1,6 +0,0 @@
1
- import "./useRpcAuth-BLlRSHy8.js";
2
- import "./useQueryCache-ByayvZgZ.js";
3
- import "./useMutation-CFwe7H9j.js";
4
- import { t as Logout_default } from "./Logout-BMjiqHnS.js";
5
-
6
- export { Logout_default as default };
@@ -1 +0,0 @@
1
- {"version":3,"file":"NoteList-C0hRPNMO.js","names":["variables: NoteFiltersDto"],"sources":["../src/composables/useUserLookup.ts","../src/slices/note/noteUpdateMetadata.ts","../src/slices/note/components/EditNoteModal.vue","../src/slices/note/noteFormMetadata.ts","../src/slices/note/noteRowSchema.ts","../src/slices/note/components/NoteList.vue"],"sourcesContent":["import { computed } from 'vue';\nimport type { DragoncoreApi } from '@dragonmastery/dragoncore-shared';\nimport type { QueryFunction, UseQueryOptions } from './types';\nimport { useQuery } from './useQuery';\n\n/**\n * Team member item with user identification fields\n */\nexport interface TeamMemberItem {\n user_id: string | null;\n display_name?: string | null;\n email_address?: string | null;\n}\n\n/**\n * Response type for user team members query\n */\nexport interface UserTeamMembersResponse {\n items: TeamMemberItem[];\n}\n\n/**\n * Generic composable for looking up user information by user ID\n * Fetches team members from the user's teams and caches them\n * Provides a map of user_id -> display_name for easy lookups\n *\n * @param queryFn - Function that queries team members from the API\n * @param options - Optional query options (cacheKey defaults to 'user-team-members')\n */\nexport function useUserLookup<TApi extends Record<string, any> = DragoncoreApi>(\n queryFn: QueryFunction<TApi, UserTeamMembersResponse>,\n options?: Omit<UseQueryOptions, 'cacheKey'> & { cacheKey?: string },\n) {\n // Fetch user team members for lookups\n const { data: userTeamMembers, loading: isUserTeamMembersLoading } = useQuery<\n TApi,\n UserTeamMembersResponse\n >(queryFn, {\n cacheKey: options?.cacheKey ?? 'user-team-members',\n staleTime: options?.staleTime ?? 24 * 60 * 60 * 1000, // 24 hours\n ...options,\n });\n\n // Create a user lookup map: user_id -> display_name (or email_address as fallback)\n const userMap = computed(() => {\n const map = new Map<string, string>();\n userTeamMembers.value?.items?.forEach((member: TeamMemberItem) => {\n if (member.user_id) {\n // Use display_name if available, otherwise fall back to email_address\n const displayName = member.display_name || member.email_address;\n if (displayName) {\n map.set(member.user_id, displayName);\n }\n }\n });\n return map;\n });\n\n /**\n * Get the display name for a user ID\n * @param userId - The user ID to look up\n * @returns The display name if found, or null if not found\n */\n const getUserName = (userId: string | null | undefined): string | null => {\n if (!userId) return null;\n return userMap.value.get(userId) || null;\n };\n\n /**\n * Get the display name for a user ID, with a fallback\n * @param userId - The user ID to look up\n * @param fallback - The fallback text to use if not found (default: the userId itself)\n * @returns The display name if found, or the fallback (or userId) if not found\n */\n const getUserNameWithFallback = (\n userId: string | null | undefined,\n fallback?: string,\n ): string => {\n if (!userId) return fallback || '';\n const displayName = userMap.value.get(userId);\n if (displayName) return displayName;\n // If not found, return the fallback if provided, otherwise return the userId\n return fallback !== undefined ? fallback : userId;\n };\n\n return {\n userTeamMembers,\n isUserTeamMembersLoading,\n userMap,\n getUserName,\n getUserNameWithFallback,\n };\n}\n","import { withMetadata } from '@dragonmastery/zinia-forms-core';\nimport { NoteUpdateSchema } from '@dragonmastery/dragoncore-shared';\n\nexport const noteUpdateMetadata = withMetadata(\n NoteUpdateSchema.pick({ body: true, tag: true }),\n 'noteUpdateForm',\n {\n body: {\n label: 'Note',\n placeholder: 'Enter your note here...',\n inputType: 'textarea',\n helpText: 'Update the note content',\n },\n tag: {\n label: 'Tag',\n inputType: 'combobox',\n helpText: 'Optional tag to categorize this note',\n },\n },\n);\n","<template>\n <dialog ref=\"modal\" class=\"modal\">\n <div class=\"modal-box\">\n <h3 class=\"font-bold text-lg mb-4\">Edit Note</h3>\n\n <ZiniaForm\n @handle-submit=\"handleSubmit\"\n @success=\"handleSuccess\"\n @error=\"handleError\"\n title=\"\"\n subtitle=\"\"\n >\n <zinia.TagField :select-options=\"form.extraData.tag || []\" :allow-create=\"true\" />\n <zinia.BodyField />\n\n <!-- Show visibility status (read-only) -->\n <div class=\"form-control\">\n <label class=\"label\">\n <span class=\"label-text\">Visibility</span>\n <span class=\"badge\" :class=\"isInternalNote ? 'badge-warning' : 'badge-info'\">\n {{ isInternalNote ? 'Internal' : 'External' }}\n </span>\n </label>\n </div>\n\n <div v-if=\"form.submitError\" class=\"alert alert-error mt-2\">\n <span>{{ form.submitError }}</span>\n </div>\n\n <div class=\"flex justify-end gap-2 mt-6\">\n <button type=\"button\" class=\"btn btn-ghost\" @click=\"closeModal\">Cancel</button>\n <ZiniaSubmitButton submitText=\"Update Note\" submittingText=\"Updating...\" />\n </div>\n\n <ZiniaFormErrorsSummary title=\"Please fix the following errors:\" />\n </ZiniaForm>\n </div>\n <form method=\"dialog\" class=\"modal-backdrop\">\n <button @click=\"closeModal\">close</button>\n </form>\n </dialog>\n</template>\n\n<script setup lang=\"ts\">\nimport { useForm } from '@dragonmastery/zinia-forms-core';\nimport { ref, watch } from 'vue';\nimport { toast } from 'vue3-toastify';\nimport { useMutation } from '../../../composables/useMutation';\nimport { useQuery } from '../../../composables/useQuery';\nimport type { NoteRow } from '../noteRowSchema';\nimport { noteUpdateMetadata } from '../noteUpdateMetadata';\n\ninterface Props {\n note: NoteRow | null;\n isOpen: boolean;\n}\n\ninterface Emits {\n (e: 'close'): void;\n (e: 'success'): void;\n}\n\nconst props = defineProps<Props>();\nconst emit = defineEmits<Emits>();\n\nconst modal = ref<HTMLDialogElement>();\n\n// Internal note toggle state\nconst isInternalNote = ref(false);\n\n// Fetch note tags for combobox\nconst {\n data: noteTagsData,\n loading: noteTagsLoading,\n error: noteTagsError,\n refetch: refetchNoteTags,\n} = useQuery((api) => api.notes.getNoteTags());\n\n// Load note tags for combobox options\nconst loadNoteTags = async () => {\n // Wait for query to complete\n while (noteTagsLoading.value) {\n await new Promise((resolve) => setTimeout(resolve, 100));\n }\n\n if (noteTagsError.value) {\n return [];\n }\n\n const tags = noteTagsData.value || [];\n\n return tags.map((tag: string) => ({\n value: tag,\n label: tag,\n }));\n};\n\nconst {\n form,\n zinia,\n ZiniaForm,\n ZiniaSubmitButton,\n ZiniaFormErrorsSummary,\n clearSavedFormState,\n refreshFormData,\n} = useForm(noteUpdateMetadata, {\n storeName: `edit-note-form-${props.note?.id || 'new'}`,\n persistToLocalStorage: false,\n renderStyle: 'daisy_ui',\n dataLoaders: {\n tag: loadNoteTags,\n },\n fetchData: async () => {\n if (!props.note) {\n return { body: '', tag: null };\n }\n return {\n body: props.note.body || '',\n tag: props.note.tag || null,\n };\n },\n});\n\nconst { mutate: updateNote } = useMutation(\n (api, input: { id: string; body: string; tag?: string | null }) =>\n api.notes.updateNote(input),\n {\n invalidate: /^notes?:/,\n onSuccess: () => {\n // Refetch tags to include any new tags\n refetchNoteTags();\n },\n },\n);\n\nconst handleSubmit = async (formData: any) => {\n if (!props.note) {\n throw new Error('No note selected for editing');\n }\n\n const response = await updateNote({\n id: props.note.id,\n body: formData.body,\n tag: formData.tag || null,\n });\n\n if (!response) {\n throw new Error('Failed to update note');\n }\n\n return response;\n};\n\nconst handleSuccess = async () => {\n clearSavedFormState();\n refreshFormData(); // Reset form to initial state\n toast.success('Note updated successfully!');\n emit('success');\n closeModal();\n};\n\nconst handleError = (error: Error | unknown) => {\n form.setSubmitError(error instanceof Error ? error.message : 'An unknown error occurred');\n};\n\nconst closeModal = () => {\n emit('close');\n};\n\n// Watch for modal open/close\nwatch(\n () => props.isOpen,\n (isOpen) => {\n if (isOpen && modal.value) {\n modal.value.showModal();\n } else if (!isOpen && modal.value) {\n modal.value.close();\n // Reset form when modal closes\n refreshFormData();\n }\n },\n);\n\n// Watch for note changes to refresh form data\nwatch(\n () => props.note,\n () => {\n if (props.note && props.isOpen) {\n form.setValue('body', props.note.body || '');\n form.setValue('tag', props.note.tag || null);\n isInternalNote.value = props.note.is_internal || false;\n }\n },\n { immediate: true },\n);\n</script>\n","import { withMetadata } from '@dragonmastery/zinia-forms-core';\nimport { NoteCreateSchema } from '@dragonmastery/dragoncore-shared';\n\nexport const noteCreateMetadata = withMetadata(\n NoteCreateSchema.pick({ body: true, is_internal: true, tag: true }),\n 'noteCreateForm',\n {\n body: {\n label: 'Note',\n placeholder: 'Enter your note here...',\n inputType: 'textarea',\n helpText: 'Add a note about this record',\n },\n is_internal: {\n label: 'Internal Note',\n helpText: 'Check this box to make this note visible only to staff',\n },\n tag: {\n label: 'Tag',\n inputType: 'combobox',\n helpText: 'Optional tag to categorize this note',\n },\n },\n);\n","import { withMetadata } from '@dragonmastery/zinia-forms-core';\nimport { NoteReadSchema } from '@dragonmastery/dragoncore-shared';\nimport { z } from 'zod';\n\nexport const noteRowSchemaWithMetadata = withMetadata(NoteReadSchema, 'noteRowSchema', {\n body: { label: 'Note' },\n tag: { label: 'Tag', sortable: true },\n is_internal: { label: 'Visibility', sortable: true },\n created_at: { label: 'Created', sortable: true },\n created_by: { label: 'Created By', sortable: true },\n updated_at: { label: 'Updated', sortable: true },\n});\n\nexport type NoteRow = z.infer<typeof NoteReadSchema>;\n","<template>\n <div class=\"space-y-6\">\n <!-- Add Note Form -->\n <div class=\"mt-4\">\n <ZiniaForm\n @handle-submit=\"handleSubmit\"\n @success=\"handleSuccess\"\n @error=\"handleError\"\n title=\"\"\n subtitle=\"\"\n >\n <zinia.TagField :select-options=\"form.extraData.tag || []\" :allow-create=\"true\" />\n <zinia.BodyField />\n\n <div v-if=\"form.submitError\" class=\"alert alert-error mt-2\">\n <span>{{ form.submitError }}</span>\n </div>\n\n <div class=\"flex justify-end mt-6\">\n <ZiniaSubmitButton submitText=\"Add Note\" submittingText=\"Adding...\" />\n </div>\n\n <ZiniaFormErrorsSummary title=\"Please fix the following errors:\" />\n </ZiniaForm>\n </div>\n\n <!-- Notes Table -->\n <ZiniaDataTable>\n <template #cell-created_by=\"{ row }\">\n {{ getUserNameWithFallback(row.created_by) }}\n </template>\n <template #cell-created_at=\"{ row }\">\n {{ formatSystemTimestamp(row.created_at) }}\n </template>\n\n <template #cell-tag=\"{ row }\">\n {{ row.tag || '-' }}\n </template>\n\n <template #cell-updated_at=\"{ row }\">\n {{ row.updated_at ? formatSystemTimestamp(row.updated_at) : '-' }}\n </template>\n\n <template #cell-body=\"{ row }\">\n <div class=\"whitespace-pre-wrap\">\n {{ row.body || 'No content' }}\n </div>\n </template>\n </ZiniaDataTable>\n\n <!-- Edit Modal -->\n <EditNoteModal\n :note=\"selectedNote\"\n :is-open=\"isEditModalOpen\"\n @close=\"closeEditModal\"\n @success=\"handleEditSuccess\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { executeWithAuth } from '../../../composables/useRpcAuth';\nimport { getRefreshTokenHandler } from '../../../utils/EnhancedRefreshTokenHandler';\nimport { useMutation } from '../../../composables/useMutation';\nimport { useQuery } from '../../../composables/useQuery';\nimport { useUserLookup } from '../../../composables/useUserLookup';\nimport { formatSystemTimestamp } from '../../../utils/convertToLocalDateTime';\nimport EditNoteModal from './EditNoteModal.vue';\nimport { noteCreateMetadata } from '../noteFormMetadata';\nimport { noteRowSchemaWithMetadata, type NoteRow } from '../noteRowSchema';\nimport { ActionIcons, useCursorDataTable, useForm } from '@dragonmastery/zinia-forms-core';\nimport { OPERATORS, type NoteFiltersDto } from '@dragonmastery/dragoncore-shared';\nimport { computed, ref, watch } from 'vue';\nimport { toast } from 'vue3-toastify';\n\ninterface Props {\n recordId: string;\n recordType: string;\n mode?: 'customer' | 'internal';\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n mode: 'customer',\n});\n\n// Edit modal state\nconst selectedNote = ref<NoteRow | null>(null);\nconst isEditModalOpen = ref(false);\n\n// Computed properties for component intelligence\nconst isInternalNote = computed(() => {\n // Determine internal state based on mode\n return props.mode === 'internal';\n});\n\n// User lookup for mapping user IDs to usernames\nconst { getUserNameWithFallback } = useUserLookup((api) => api.teamMembers.getUserTeamMembers());\n\n// Query filters state\nconst queryFilters = ref<NoteFiltersDto>({\n record_id: { operator: OPERATORS.EQUALS, value: props.recordId },\n record_type: { operator: OPERATORS.EQUALS, value: props.recordType as any },\n});\n\n// Pagination token for breadcrumb navigation\nconst currentPaginationToken = ref<string | undefined | null>();\n\n// Fetch note tags for filter and form\nconst {\n data: noteTagsData,\n loading: noteTagsLoading,\n error: noteTagsError,\n refetch: refetchNoteTags,\n} = useQuery((api) => api.notes.getNoteTags());\n\n// Load note tags for filter options and form combobox\n// This function reads from noteTagsData.value, which is reactive\n// When refetchNoteTags() is called, noteTagsData.value updates\n// The next time this function is called (when filter dropdown opens), it will get fresh data\nconst loadNoteTags = async () => {\n // If query is loading, wait for it to complete to ensure we have fresh data\n while (noteTagsLoading.value) {\n await new Promise((resolve) => setTimeout(resolve, 100));\n }\n\n if (noteTagsError.value) {\n return [];\n }\n\n const tags = noteTagsData.value || [];\n\n return tags.map((tag: string) => ({\n value: tag,\n label: tag,\n }));\n};\n\n// Form setup\nconst { form, zinia, ZiniaForm, ZiniaSubmitButton, ZiniaFormErrorsSummary, refreshFormData } =\n useForm(noteCreateMetadata, {\n storeName: `note-form-${props.recordId}`,\n persistToLocalStorage: false,\n renderStyle: 'daisy_ui',\n dataLoaders: {\n tag: loadNoteTags,\n },\n fetchData: async () => ({\n body: '',\n tag: null,\n is_internal: isInternalNote.value,\n }),\n });\n\n// Data table configuration\nconst { ZiniaDataTable, refresh } = useCursorDataTable(noteRowSchemaWithMetadata, {\n fetchData: async ({ cursor, pageSize, sort, filters, search }) => {\n // Build query variables\n const variables: NoteFiltersDto = {\n first: pageSize,\n sortBy: sort?.field ? (sort.field as string) : 'created_at',\n sortDirection: (sort?.direction === 'asc' ? 'asc' : 'desc') as any,\n ...(cursor ? { after: cursor } : {}),\n ...(currentPaginationToken.value\n ? { paginationToken: currentPaginationToken.value }\n : {}),\n ...(search ? { search } : {}),\n record_id: { operator: OPERATORS.EQUALS, value: props.recordId },\n record_type: { operator: OPERATORS.EQUALS, value: props.recordType as any },\n ...filters,\n };\n\n // Apply visibility filter based on mode\n if (props.mode === 'customer') {\n variables.is_internal = { operator: OPERATORS.EQUALS, value: false };\n } else if (props.mode === 'internal') {\n variables.is_internal = { operator: OPERATORS.EQUALS, value: true };\n }\n // For 'all' mode, no filter is applied (shows everything)\n\n // Update query filters and execute\n queryFilters.value = variables;\n const result = await executeWithAuth(\n async (api) => {\n return await api.notes.getNotes(variables);\n },\n { refreshTokenHandler: getRefreshTokenHandler() },\n );\n currentPaginationToken.value = result?.pageInfo?.paginationToken;\n\n // Return paginated data\n return {\n data: result?.items || [],\n hasNextPage: result?.pageInfo?.hasNextPage ?? false,\n hasPreviousPage: result?.pageInfo?.hasPreviousPage ?? false,\n prevPageCursor: result?.pageInfo?.prevPageCursor ?? undefined,\n nextPageCursor: result?.pageInfo?.nextPageCursor ?? undefined,\n };\n },\n\n // Column configuration\n columns: {\n created_by: {\n label: 'Created By',\n field: 'created_by',\n sortable: true,\n verticalAlign: 'top',\n },\n updated_at: {\n label: 'Updated',\n field: 'updated_at',\n sortable: true,\n verticalAlign: 'top',\n },\n tag: {\n label: 'Tag',\n field: 'tag',\n sortable: true,\n filterable: true,\n filterType: 'select',\n filterOptionsLoader: loadNoteTags,\n verticalAlign: 'top',\n },\n body: {\n label: 'Note',\n field: 'body',\n sortable: false,\n },\n },\n\n // Action buttons\n actions: {\n column: {\n verticalAlign: 'top',\n },\n items: [\n {\n key: 'edit',\n icon: ActionIcons.edit,\n size: 'xs',\n variant: 'primary',\n type: 'button',\n onClick: (row: NoteRow) => openEditModal(row),\n },\n ],\n },\n\n // Pagination settings\n pagination: {\n pageSize: 25,\n },\n});\n\n// Mutations\nconst { mutate: createNote } = useMutation((api, input: any) => api.notes.createNote(input), {\n invalidate: /^notes?:/,\n onSuccess: () => {\n // Refetch tags to include any new tags\n refetchNoteTags();\n },\n});\n\n// Form handlers\nconst handleSubmit = async (formData: any) => {\n const result = await createNote({\n record_id: props.recordId,\n record_type: props.recordType,\n body: formData.body,\n tag: formData.tag || null,\n is_internal: isInternalNote.value,\n });\n refresh();\n return result;\n};\n\nconst handleSuccess = async () => {\n refreshFormData();\n toast.success('Note added successfully!');\n refresh();\n};\n\nconst handleError = (error: Error | unknown) => {\n form.setSubmitError(error instanceof Error ? error.message : 'An unknown error occurred');\n};\n\n// Edit modal handlers\nconst openEditModal = (note: NoteRow) => {\n selectedNote.value = note;\n isEditModalOpen.value = true;\n};\n\nconst closeEditModal = () => {\n isEditModalOpen.value = false;\n selectedNote.value = null;\n};\n\nconst handleEditSuccess = async () => {\n // Refetch tags to include any new tags from the updated note\n await refetchNoteTags();\n // Refresh the data table to show updated note\n refresh();\n};\n\n// Watch for changes in recordId or recordType to refresh the data table\nwatch(\n () => [props.recordId, props.recordType],\n () => {\n if (props.recordId && props.recordType) {\n refresh();\n }\n },\n);\n\n// Watch for changes in noteTagsData to refresh form's data loaders\n// This ensures the create note form's tag combobox gets updated options\nwatch(\n noteTagsData,\n async () => {\n // Reload the tag data loader to refresh form.extraData.tag\n if (form.extraData && form.extraData.tag !== undefined) {\n const newTags = await loadNoteTags();\n form.extraData.tag = newTags;\n }\n },\n { deep: true },\n);\n</script>\n"],"mappings":"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"}
@@ -1,141 +0,0 @@
1
- import { t as useMutation } from "./useMutation-CFwe7H9j.js";
2
- import { t as useQuery } from "./useQuery-p7oJO7OD.js";
3
- import { Fragment, createCommentVNode, createElementBlock, createElementVNode, createVNode, defineComponent, inject, openBlock, ref, toDisplayString, unref, withCtx } from "vue";
4
- import { UpdateNotificationEmailsSchema, createNewEmailEntry } from "@dragonmastery/dragoncore-shared";
5
- import { useForm, withMetadata } from "@dragonmastery/zinia-forms-core";
6
- import { toast } from "vue3-toastify";
7
-
8
- //#region src/slices/admin/features/notification-emails/notificationEmailsMetadata.ts
9
- const notificationEmailsSchemaWithMetadata = withMetadata(UpdateNotificationEmailsSchema, "notificationEmailsSchema", { emails: {
10
- label: "Notification Email Addresses",
11
- ariaLabels: {
12
- addButton: "Add email address",
13
- removeButton: "Remove email address",
14
- moveUpButton: "Move email up",
15
- moveDownButton: "Move email down",
16
- item: "Email address"
17
- }
18
- } });
19
-
20
- //#endregion
21
- //#region src/slices/admin/features/notification-emails/NotificationEmailsPage.vue
22
- const _hoisted_1 = { class: "max-w-2xl mx-auto bg-base-200 p-6 rounded-xl shadow-md container" };
23
- const _hoisted_2 = {
24
- key: 0,
25
- class: "flex justify-center py-8"
26
- };
27
- const _hoisted_3 = { class: "alert alert-error mb-4" };
28
- const _hoisted_4 = { class: "space-y-4" };
29
- const _hoisted_5 = { class: "border border-base-300 rounded-lg p-4 bg-base-50" };
30
- const _hoisted_6 = { class: "flex items-start justify-between mb-3" };
31
- const _hoisted_7 = { class: "flex-1" };
32
- const _hoisted_8 = { class: "font-semibold text-lg mb-2" };
33
- const _hoisted_9 = { class: "space-y-2" };
34
- const _hoisted_10 = {
35
- key: 0,
36
- class: "alert alert-error mb-4"
37
- };
38
- const _hoisted_11 = { class: "flex justify-center mt-6" };
39
- const _sfc_main = /* @__PURE__ */ defineComponent({
40
- __name: "NotificationEmailsPage",
41
- setup(__props) {
42
- const { data, loading: fetching, error } = useQuery((api) => api.appSettings.getNotificationEmails(), { staleTime: 600 * 1e3 });
43
- const notificationEmailsData = ref(null);
44
- const { form, zinia, ziniaGeneric, ZiniaForm, ZiniaSubmitButton, ZiniaResetButton, ZiniaFormErrorsSummary } = useForm(notificationEmailsSchemaWithMetadata, {
45
- storeName: "notification-emails-form",
46
- persistToLocalStorage: false,
47
- renderStyle: "daisy_ui",
48
- fetchData: async () => {
49
- while (fetching.value) await new Promise((resolve) => setTimeout(resolve, 100));
50
- if (!data.value) throw new Error("Notification emails not found");
51
- notificationEmailsData.value = data.value;
52
- return { emails: (data.value?.emails || []).map((email) => ({
53
- id: `email-${Math.random().toString(36).substr(2, 9)}`,
54
- email: email.email
55
- })) };
56
- }
57
- });
58
- const { mutate: updateNotificationEmails } = useMutation((api, formData) => {
59
- return api.appSettings.updateNotificationEmails(formData);
60
- }, { invalidate: /^app-settings:/ });
61
- const handleSubmit = async (formData) => {
62
- await updateNotificationEmails(formData);
63
- return formData;
64
- };
65
- const handleSuccess = async (_result) => {
66
- toast.success("Notification emails updated successfully!");
67
- };
68
- const handleError = (error$1) => {
69
- form.setSubmitError(error$1 instanceof Error ? error$1.message : "An unknown error occurred");
70
- toast.error("Failed to update notification emails. Please try again.");
71
- };
72
- return (_ctx, _cache) => {
73
- return openBlock(), createElementBlock("div", _hoisted_1, [
74
- _cache[2] || (_cache[2] = createElementVNode("h1", { class: "text-2xl font-bold mb-6 text-center" }, "Support Ticket Notification Emails", -1)),
75
- createCommentVNode(" Loading State "),
76
- unref(fetching) ? (openBlock(), createElementBlock("div", _hoisted_2, [..._cache[0] || (_cache[0] = [createElementVNode("span", { class: "loading loading-spinner loading-lg" }, null, -1)])])) : unref(error) ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [createCommentVNode(" Error State "), createElementVNode("div", _hoisted_3, [createElementVNode("span", null, "Error loading notification emails: " + toDisplayString(unref(error).message), 1)])], 2112)) : notificationEmailsData.value ? (openBlock(), createElementBlock(Fragment, { key: 2 }, [createCommentVNode(" Form "), createElementVNode("div", null, [createVNode(unref(ZiniaForm), {
77
- onHandleSubmit: handleSubmit,
78
- onSuccess: handleSuccess,
79
- onError: handleError,
80
- title: "Configure Notification Emails",
81
- subtitle: "Configure which staff members receive email notifications when new support tickets are created."
82
- }, {
83
- default: withCtx(() => [
84
- createElementVNode("div", _hoisted_4, [
85
- createCommentVNode(" Email addresses array field "),
86
- createVNode(unref(zinia).EmailsField, {
87
- name: "emails",
88
- label: "Notification Email Addresses",
89
- createItem: unref(createNewEmailEntry),
90
- autoPrefixFields: true,
91
- ariaLabels: {
92
- addButton: "Add email address",
93
- removeButton: "Remove email address",
94
- moveUpButton: "Move email up",
95
- moveDownButton: "Move email down",
96
- item: "Email address"
97
- }
98
- }, {
99
- itemRenderer: withCtx(({ item: _, index, fields }) => [createElementVNode("div", _hoisted_5, [createElementVNode("div", _hoisted_6, [createElementVNode("div", _hoisted_7, [createElementVNode("h4", _hoisted_8, "Email Address #" + toDisplayString(index + 1), 1), createElementVNode("div", _hoisted_9, [createVNode(unref(ziniaGeneric).TextField, {
100
- name: fields.email,
101
- label: "Email Address",
102
- placeholder: "Enter email address",
103
- type: "email",
104
- class: "input input-bordered"
105
- }, null, 8, ["name"])])])])])]),
106
- _: 1
107
- }, 8, ["createItem"]),
108
- createCommentVNode(" Information alert "),
109
- _cache[1] || (_cache[1] = createElementVNode("div", { class: "alert alert-info" }, [createElementVNode("svg", {
110
- xmlns: "http://www.w3.org/2000/svg",
111
- fill: "none",
112
- viewBox: "0 0 24 24",
113
- class: "stroke-current shrink-0 w-6 h-6"
114
- }, [createElementVNode("path", {
115
- "stroke-linecap": "round",
116
- "stroke-linejoin": "round",
117
- "stroke-width": "2",
118
- d: "M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
119
- })]), createElementVNode("div", null, [createElementVNode("h3", { class: "font-bold" }, "How it works"), createElementVNode("div", { class: "text-sm" }, [createElementVNode("p", null, " Add email addresses for staff members who should receive notifications. When a new support ticket is created, all listed recipients will receive an email notification with the ticket details. "), createElementVNode("p", { class: "mt-2" }, " Click \"Add Email\" to add more recipients. Each email is validated individually. ")])])], -1))
120
- ]),
121
- createCommentVNode(" Form Status Messages "),
122
- unref(form).submitError ? (openBlock(), createElementBlock("div", _hoisted_10, [createElementVNode("span", null, toDisplayString(unref(form).submitError), 1)])) : createCommentVNode("v-if", true),
123
- createCommentVNode(" Submit Button "),
124
- createElementVNode("div", _hoisted_11, [createVNode(unref(ZiniaSubmitButton), {
125
- submitText: "Update Notification Emails",
126
- submittingText: "Updating..."
127
- })]),
128
- createVNode(unref(ZiniaFormErrorsSummary), { title: "Please fix the following errors:" }),
129
- createVNode(unref(ZiniaResetButton))
130
- ]),
131
- _: 1
132
- })])], 2112)) : createCommentVNode("v-if", true)
133
- ]);
134
- };
135
- }
136
- });
137
- var NotificationEmailsPage_default = _sfc_main;
138
-
139
- //#endregion
140
- export { notificationEmailsSchemaWithMetadata as n, NotificationEmailsPage_default as t };
141
- //# sourceMappingURL=NotificationEmailsPage-BjRqtW95.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"NotificationEmailsPage-BjRqtW95.js","names":[],"sources":["../src/slices/admin/features/notification-emails/notificationEmailsMetadata.ts","../src/slices/admin/features/notification-emails/NotificationEmailsPage.vue"],"sourcesContent":["import {\n type UseFormTyped,\n withMetadata,\n ZINIA_FIELDS_KEY,\n ZINIA_FORM_KEY,\n} from '@dragonmastery/zinia-forms-core';\nimport { UpdateNotificationEmailsSchema } from '@dragonmastery/dragoncore-shared';\nimport { inject } from 'vue';\n\n// Create an enhanced schema with metadata attached\nexport const notificationEmailsSchemaWithMetadata = withMetadata(\n UpdateNotificationEmailsSchema,\n 'notificationEmailsSchema',\n {\n emails: {\n label: 'Notification Email Addresses',\n ariaLabels: {\n addButton: 'Add email address',\n removeButton: 'Remove email address',\n moveUpButton: 'Move email up',\n moveDownButton: 'Move email down',\n item: 'Email address',\n },\n },\n },\n);\n\nexport type NotificationEmailsFormDto = UseFormTyped<typeof UpdateNotificationEmailsSchema>;\n\nexport const injectNotificationEmailsForm = () =>\n inject<NotificationEmailsFormDto['form']>(ZINIA_FORM_KEY);\nexport const injectNotificationEmailsZinia = () =>\n inject<NotificationEmailsFormDto['zinia']>(ZINIA_FIELDS_KEY);\n","<template>\n <div class=\"max-w-2xl mx-auto bg-base-200 p-6 rounded-xl shadow-md container\">\n <h1 class=\"text-2xl font-bold mb-6 text-center\">Support Ticket Notification Emails</h1>\n\n <!-- Loading State -->\n <div v-if=\"fetching\" class=\"flex justify-center py-8\">\n <span class=\"loading loading-spinner loading-lg\"></span>\n </div>\n\n <!-- Error State -->\n <div v-else-if=\"error\" class=\"alert alert-error mb-4\">\n <span>Error loading notification emails: {{ error.message }}</span>\n </div>\n\n <!-- Form -->\n <div v-else-if=\"notificationEmailsData\">\n <ZiniaForm\n @handle-submit=\"handleSubmit\"\n @success=\"handleSuccess\"\n @error=\"handleError\"\n title=\"Configure Notification Emails\"\n subtitle=\"Configure which staff members receive email notifications when new support tickets are created.\"\n >\n <div class=\"space-y-4\">\n <!-- Email addresses array field -->\n <zinia.EmailsField\n name=\"emails\"\n label=\"Notification Email Addresses\"\n :createItem=\"createNewEmailEntry\"\n :autoPrefixFields=\"true\"\n :ariaLabels=\"{\n addButton: 'Add email address',\n removeButton: 'Remove email address',\n moveUpButton: 'Move email up',\n moveDownButton: 'Move email down',\n item: 'Email address',\n }\"\n >\n <template #itemRenderer=\"{ item: _, index, fields }\">\n <div class=\"border border-base-300 rounded-lg p-4 bg-base-50\">\n <div class=\"flex items-start justify-between mb-3\">\n <div class=\"flex-1\">\n <h4 class=\"font-semibold text-lg mb-2\">Email Address #{{ index + 1 }}</h4>\n <div class=\"space-y-2\">\n <ziniaGeneric.TextField\n :name=\"fields.email\"\n label=\"Email Address\"\n placeholder=\"Enter email address\"\n type=\"email\"\n class=\"input input-bordered\"\n />\n </div>\n </div>\n </div>\n </div>\n </template>\n </zinia.EmailsField>\n\n <!-- Information alert -->\n <div class=\"alert alert-info\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n class=\"stroke-current shrink-0 w-6 h-6\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z\"\n ></path>\n </svg>\n <div>\n <h3 class=\"font-bold\">How it works</h3>\n <div class=\"text-sm\">\n <p>\n Add email addresses for staff members who should receive notifications. When\n a new support ticket is created, all listed recipients will receive an email\n notification with the ticket details.\n </p>\n <p class=\"mt-2\">\n Click \"Add Email\" to add more recipients. Each email is validated\n individually.\n </p>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Form Status Messages -->\n <div v-if=\"form.submitError\" class=\"alert alert-error mb-4\">\n <span>{{ form.submitError }}</span>\n </div>\n\n <!-- Submit Button -->\n <div class=\"flex justify-center mt-6\">\n <ZiniaSubmitButton\n submitText=\"Update Notification Emails\"\n submittingText=\"Updating...\"\n />\n </div>\n\n <ZiniaFormErrorsSummary title=\"Please fix the following errors:\" />\n <ZiniaResetButton />\n </ZiniaForm>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { useMutation } from '../../../../composables/useMutation';\nimport { useQuery } from '../../../../composables/useQuery';\nimport { useForm } from '@dragonmastery/zinia-forms-core';\nimport type { UpdateNotificationEmails } from '@dragonmastery/dragoncore-shared';\nimport { createNewEmailEntry } from '@dragonmastery/dragoncore-shared';\nimport { ref } from 'vue';\nimport { toast } from 'vue3-toastify';\nimport { notificationEmailsSchemaWithMetadata } from './notificationEmailsMetadata';\n\n// Fetch notification emails data\nconst {\n data,\n loading: fetching,\n error,\n} = useQuery((api) => api.appSettings.getNotificationEmails(), {\n staleTime: 10 * 60 * 1000,\n});\n\nconst notificationEmailsData = ref<any | null>(null);\n\n// Create form with notification emails data\nconst {\n form,\n zinia,\n ziniaGeneric,\n ZiniaForm,\n ZiniaSubmitButton,\n ZiniaResetButton,\n ZiniaFormErrorsSummary,\n} = useForm(notificationEmailsSchemaWithMetadata, {\n storeName: 'notification-emails-form',\n persistToLocalStorage: false,\n renderStyle: 'daisy_ui',\n fetchData: async () => {\n while (fetching.value) {\n await new Promise((resolve) => setTimeout(resolve, 100));\n }\n\n if (!data.value) {\n throw new Error('Notification emails not found');\n }\n\n notificationEmailsData.value = data.value;\n\n // Transform the API response to match EmailEntry type\n const emails = data.value?.emails || [];\n const transformedEmails = emails.map((email: any) => ({\n id: `email-${Math.random().toString(36).substr(2, 9)}`,\n email: email.email,\n }));\n\n return {\n emails: transformedEmails,\n } satisfies UpdateNotificationEmails;\n },\n});\n\nconst { mutate: updateNotificationEmails } = useMutation(\n (api, formData: UpdateNotificationEmails) => {\n return api.appSettings.updateNotificationEmails(formData);\n },\n { invalidate: /^app-settings:/ },\n);\n\nconst handleSubmit = async (formData: UpdateNotificationEmails) => {\n await updateNotificationEmails(formData);\n return formData;\n};\n\nconst handleSuccess = async (_result: any) => {\n toast.success('Notification emails updated successfully!');\n};\n\nconst handleError = (error: Error | unknown) => {\n form.setSubmitError(error instanceof Error ? error.message : 'An unknown error occurred');\n toast.error('Failed to update notification emails. Please try again.');\n};\n</script>\n"],"mappings":"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"}
@@ -1,7 +0,0 @@
1
- import "./useRpcAuth-BLlRSHy8.js";
2
- import "./useQueryCache-ByayvZgZ.js";
3
- import "./useMutation-CFwe7H9j.js";
4
- import "./useQuery-p7oJO7OD.js";
5
- import { t as NotificationEmailsPage_default } from "./NotificationEmailsPage-BjRqtW95.js";
6
-
7
- export { NotificationEmailsPage_default as default };
@@ -1,43 +0,0 @@
1
- import "./useRpcAuth-BLlRSHy8.js";
2
- import "./useQueryCache-ByayvZgZ.js";
3
- import "./useMutation-CFwe7H9j.js";
4
- import "./useQuery-p7oJO7OD.js";
5
- import { g as ResetPassword_default } from "./src-o5fMIo5_.js";
6
- import "./AppLink-CHMMrSFI.js";
7
- import "./InlineAttachments-I39rOvip.js";
8
- import "./TeamMembersTab-4gmnP9sD.js";
9
- import "./Appearance-BfPdKMXw.js";
10
- import "./useBreadcrumbs-DmgSucoe.js";
11
- import "./FieldsetSection-CsHN38_o.js";
12
- import "./ZiniaContainer-C7c7Vwkh.js";
13
- import "./NoteList-C0hRPNMO.js";
14
- import "./UserProfilePage-BtLUY1kt.js";
15
- import "./ChangePasswordPage-Btu5lf-r.js";
16
- import "./TeamHistoryTab-gB3H2KZv.js";
17
- import "./TeamNotesTab-pfXTDhg6.js";
18
- import "./EditTeamMemberForm-ru4WgLz-.js";
19
- import "./SupportTicketStatusBadge-YdZzjvkh.js";
20
- import "./creditValueFormatter-DftEzu8d.js";
21
- import "./CustomerSupportTicketList-C2nUPawb.js";
22
- import "./CustomerEditSupportTicketForm-Dd5ZB74k.js";
23
- import "./CustomerViewSupportTicket-tZkxragu.js";
24
- import "./CustomerSupportTicketParent-2mONd9kL.js";
25
- import "./CustomerSupportTicketCustomerNotesTab-D1aa9It7.js";
26
- import "./SupportTicketHistoryTab-CLMopA7a.js";
27
- import "./CustomerSupportTicketHistoryTab-CFYN_Sa4.js";
28
- import "./StaffSupportTicketWorkflowTab-DmVTPzxS.js";
29
- import "./StaffEditSupportTicketForm-DuUKuIGg.js";
30
- import "./StaffSupportTicketParent-Cx1buQZw.js";
31
- import "./StaffSupportTicketCustomerNotesTab-CusqQV2-.js";
32
- import "./StaffSupportTicketInternalNotesTab-D8HM--dp.js";
33
- import "./StaffSupportTicketHistoryTab-D24myEm3.js";
34
- import "./LoginForm-_PZ51Uwe.js";
35
- import "./Signup-c2-_yMOM.js";
36
- import "./ForgotPassword-CqhenzUG.js";
37
- import "./Logout-BMjiqHnS.js";
38
- import "./UserListPage-WU56KiWj.js";
39
- import "./CreateUserPage-Cmx8xjjv.js";
40
- import "./NotificationEmailsPage-BjRqtW95.js";
41
- import "./EditUserPage-BxJ5QvIM.js";
42
-
43
- export { ResetPassword_default as default };
@@ -1,7 +0,0 @@
1
- import "./useRpcAuth-BLlRSHy8.js";
2
- import "./useQueryCache-ByayvZgZ.js";
3
- import "./useMutation-CFwe7H9j.js";
4
- import "./AppLink-CHMMrSFI.js";
5
- import { t as Signup_default } from "./Signup-c2-_yMOM.js";
6
-
7
- export { Signup_default as default };
@@ -1,43 +0,0 @@
1
- import "./useRpcAuth-BLlRSHy8.js";
2
- import "./useQueryCache-ByayvZgZ.js";
3
- import "./useMutation-CFwe7H9j.js";
4
- import "./useQuery-p7oJO7OD.js";
5
- import { E as StaffCreateSupportTicketForm_default } from "./src-o5fMIo5_.js";
6
- import "./AppLink-CHMMrSFI.js";
7
- import "./InlineAttachments-I39rOvip.js";
8
- import "./TeamMembersTab-4gmnP9sD.js";
9
- import "./Appearance-BfPdKMXw.js";
10
- import "./useBreadcrumbs-DmgSucoe.js";
11
- import "./FieldsetSection-CsHN38_o.js";
12
- import "./ZiniaContainer-C7c7Vwkh.js";
13
- import "./NoteList-C0hRPNMO.js";
14
- import "./UserProfilePage-BtLUY1kt.js";
15
- import "./ChangePasswordPage-Btu5lf-r.js";
16
- import "./TeamHistoryTab-gB3H2KZv.js";
17
- import "./TeamNotesTab-pfXTDhg6.js";
18
- import "./EditTeamMemberForm-ru4WgLz-.js";
19
- import "./SupportTicketStatusBadge-YdZzjvkh.js";
20
- import "./creditValueFormatter-DftEzu8d.js";
21
- import "./CustomerSupportTicketList-C2nUPawb.js";
22
- import "./CustomerEditSupportTicketForm-Dd5ZB74k.js";
23
- import "./CustomerViewSupportTicket-tZkxragu.js";
24
- import "./CustomerSupportTicketParent-2mONd9kL.js";
25
- import "./CustomerSupportTicketCustomerNotesTab-D1aa9It7.js";
26
- import "./SupportTicketHistoryTab-CLMopA7a.js";
27
- import "./CustomerSupportTicketHistoryTab-CFYN_Sa4.js";
28
- import "./StaffSupportTicketWorkflowTab-DmVTPzxS.js";
29
- import "./StaffEditSupportTicketForm-DuUKuIGg.js";
30
- import "./StaffSupportTicketParent-Cx1buQZw.js";
31
- import "./StaffSupportTicketCustomerNotesTab-CusqQV2-.js";
32
- import "./StaffSupportTicketInternalNotesTab-D8HM--dp.js";
33
- import "./StaffSupportTicketHistoryTab-D24myEm3.js";
34
- import "./LoginForm-_PZ51Uwe.js";
35
- import "./Signup-c2-_yMOM.js";
36
- import "./ForgotPassword-CqhenzUG.js";
37
- import "./Logout-BMjiqHnS.js";
38
- import "./UserListPage-WU56KiWj.js";
39
- import "./CreateUserPage-Cmx8xjjv.js";
40
- import "./NotificationEmailsPage-BjRqtW95.js";
41
- import "./EditUserPage-BxJ5QvIM.js";
42
-
43
- export { StaffCreateSupportTicketForm_default as default };
@@ -1,9 +0,0 @@
1
- import "./useRpcAuth-BLlRSHy8.js";
2
- import "./useQueryCache-ByayvZgZ.js";
3
- import "./useMutation-CFwe7H9j.js";
4
- import "./useQuery-p7oJO7OD.js";
5
- import "./InlineAttachments-I39rOvip.js";
6
- import "./FieldsetSection-CsHN38_o.js";
7
- import { t as StaffEditSupportTicketForm_default } from "./StaffEditSupportTicketForm-DuUKuIGg.js";
8
-
9
- export { StaffEditSupportTicketForm_default as default };