@dragonmastery/dragoncore-vue 0.0.21 → 0.0.23
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.
- package/dist/{AppLink-CHMMrSFI.js → AppLink-FcNGKgvG.js} +1 -1
- package/dist/{AppLink-CHMMrSFI.js.map → AppLink-FcNGKgvG.js.map} +1 -1
- package/dist/Appearance-Ch4zfWZ3.js +3 -0
- package/dist/{Appearance-DxWTyx1M.js → Appearance-shr0Aql0.js} +1 -1
- package/dist/{Appearance-DxWTyx1M.js.map → Appearance-shr0Aql0.js.map} +1 -1
- package/dist/{ChangePasswordPage--3XwluwE.js → ChangePasswordPage-C633yQiU.js} +2 -2
- package/dist/{ChangePasswordPage--3XwluwE.js.map → ChangePasswordPage-C633yQiU.js.map} +1 -1
- package/dist/ChangePasswordPage-CYuCCosx.js +7 -0
- package/dist/ConfirmDialog-DjthOYU6.js +85 -0
- package/dist/ConfirmDialog-DjthOYU6.js.map +1 -0
- package/dist/ConsentRequired-BPjsZoPY.js +211 -0
- package/dist/ConsentRequired-BPjsZoPY.js.map +1 -0
- package/dist/CreateTeamForm-CeaC41VY.js +142 -0
- package/dist/CreateTeamForm-CeaC41VY.js.map +1 -0
- package/dist/CreateTeamForm-DfgCaUwX.js +12 -0
- package/dist/CreateTeamMemberForm-Bv9gNG4z.js +140 -0
- package/dist/CreateTeamMemberForm-Bv9gNG4z.js.map +1 -0
- package/dist/CreateTeamMemberForm-CnHfpob_.js +12 -0
- package/dist/CreateUserPage-C9uOeYDJ.js +7 -0
- package/dist/{CreateUserPage-DLwXeLAq.js → CreateUserPage-CqKcY7_X.js} +2 -2
- package/dist/{CreateUserPage-DLwXeLAq.js.map → CreateUserPage-CqKcY7_X.js.map} +1 -1
- package/dist/CreditBalanceDashboard-0HiJE_OS.js +13 -0
- package/dist/CreditBalanceDashboard-k_orNn4h.js +28 -0
- package/dist/CreditBalanceDashboard-k_orNn4h.js.map +1 -0
- package/dist/CreditManagement-BVBZQDI4.js +356 -0
- package/dist/CreditManagement-BVBZQDI4.js.map +1 -0
- package/dist/CreditManagement-DXdIN-0d.js +13 -0
- package/dist/CreditTransactionHistory-DSu-6aDi.js +229 -0
- package/dist/CreditTransactionHistory-DSu-6aDi.js.map +1 -0
- package/dist/CustomerCreateSupportTicketForm-BsjX8Pja.js +14 -0
- package/dist/CustomerCreateSupportTicketForm-kf8YIGjx.js +158 -0
- package/dist/CustomerCreateSupportTicketForm-kf8YIGjx.js.map +1 -0
- package/dist/{CustomerSupportTicketDetailPage-BdyaKG1v.js → CustomerSupportTicketDetailPage-C_-YoAaP.js} +12 -9
- package/dist/{CustomerSupportTicketDetailPage-BdyaKG1v.js.map → CustomerSupportTicketDetailPage-C_-YoAaP.js.map} +1 -1
- package/dist/CustomerSupportTicketList-DdACn3ug.js +63 -0
- package/dist/{CustomerSupportTicketParent-HIxwSVdu.js → CustomerSupportTicketParent-BpBuYCrP.js} +4 -4
- package/dist/{CustomerSupportTicketParent-HIxwSVdu.js.map → CustomerSupportTicketParent-BpBuYCrP.js.map} +1 -1
- package/dist/CustomerSupportTicketParent-Djy7pNqO.js +8 -0
- package/dist/CustomerSupportTicketSuccess-DsFzpJFU.js +12 -0
- package/dist/CustomerSupportTicketSuccess-cumNSGdx.js +54 -0
- package/dist/CustomerSupportTicketSuccess-cumNSGdx.js.map +1 -0
- package/dist/EditTeamForm-BE3iX2x3.js +12 -0
- package/dist/EditTeamForm-BxRN338L.js +163 -0
- package/dist/EditTeamForm-BxRN338L.js.map +1 -0
- package/dist/EditTeamMemberForm-D7D1Zddh.js +9 -0
- package/dist/{EditTeamMemberForm-CaS2GLjV.js → EditTeamMemberForm-DfgJr5Cy.js} +7 -72
- package/dist/EditTeamMemberForm-DfgJr5Cy.js.map +1 -0
- package/dist/EditUserPage-C0K7EGjM.js +8 -0
- package/dist/{EditUserPage-DURc5rmi.js → EditUserPage-CI_jtU8P.js} +4 -4
- package/dist/{EditUserPage-DURc5rmi.js.map → EditUserPage-CI_jtU8P.js.map} +1 -1
- package/dist/EnhancedRefreshTokenHandler-C6tZCcfX.js +189 -0
- package/dist/EnhancedRefreshTokenHandler-C6tZCcfX.js.map +1 -0
- package/dist/FieldsetSection-Cd4B8Ad7.js +27 -0
- package/dist/FieldsetSection-Cd4B8Ad7.js.map +1 -0
- package/dist/{ForgotPassword-OjIPi9s9.js → ForgotPassword-Ckb9Z-wb.js} +4 -4
- package/dist/{ForgotPassword-OjIPi9s9.js.map → ForgotPassword-Ckb9Z-wb.js.map} +1 -1
- package/dist/ForgotPassword-tJVSg7PB.js +8 -0
- package/dist/{TimelineSystemEvent-BHzFr46C.js → InlineAttachments-DAn_QknY.js} +60 -661
- package/dist/InlineAttachments-DAn_QknY.js.map +1 -0
- package/dist/{LoginForm-9UFnA-fO.js → LoginForm-CMN2T1fA.js} +5 -5
- package/dist/{LoginForm-9UFnA-fO.js.map → LoginForm-CMN2T1fA.js.map} +1 -1
- package/dist/LoginForm-QFJ8NHww.js +8 -0
- package/dist/{Logout-YgTgOFUH.js → Logout-CFLYHlLr.js} +5 -5
- package/dist/{Logout-YgTgOFUH.js.map → Logout-CFLYHlLr.js.map} +1 -1
- package/dist/Logout-CjDBff3W.js +8 -0
- package/dist/MfaSetup-BZcoxJx-.js +9 -0
- package/dist/{MfaSetup-RtFMY_dj.js → MfaSetup-XqoAwBXx.js} +5 -5
- package/dist/{MfaSetup-RtFMY_dj.js.map → MfaSetup-XqoAwBXx.js.map} +1 -1
- package/dist/{MfaVerify-Cvhe8bEM.js → MfaVerify-C-A75TFZ.js} +6 -6
- package/dist/{MfaVerify-Cvhe8bEM.js.map → MfaVerify-C-A75TFZ.js.map} +1 -1
- package/dist/MfaVerify-Dy2aV5Gk.js +9 -0
- package/dist/{RecordVersionViewer-BWZ78vvE.js → RecordVersionViewer-D2j10HdK.js} +1 -1
- package/dist/{RecordVersionViewer-BWZ78vvE.js.map → RecordVersionViewer-D2j10HdK.js.map} +1 -1
- package/dist/{ResetPassword-BE4mXK9q.js → ResetPassword-Cd-Yxp8E.js} +4 -4
- package/dist/{ResetPassword-BE4mXK9q.js.map → ResetPassword-Cd-Yxp8E.js.map} +1 -1
- package/dist/ResetPassword-D6to3G6a.js +8 -0
- package/dist/{SavedFiltersPage-DQt6uc8m.js → SavedFiltersPage-DM5DvAFa.js} +62 -34
- package/dist/{SavedFiltersPage-DQt6uc8m.js.map → SavedFiltersPage-DM5DvAFa.js.map} +1 -1
- package/dist/{Signup-9TjMMnU4.js → Signup-2pqvJiVt.js} +57 -57
- package/dist/Signup-2pqvJiVt.js.map +1 -0
- package/dist/Signup-XdImA1os.js +9 -0
- package/dist/{SignupConsentFlow-QUZGKjdB.js → SignupConsentFlow-X3kXuviv.js} +106 -70
- package/dist/SignupConsentFlow-X3kXuviv.js.map +1 -0
- package/dist/{SignupRequirementsPage-DfbYmpQD.js → SignupRequirementsPage-Cf-ElkEq.js} +9 -8
- package/dist/{SignupRequirementsPage-DfbYmpQD.js.map → SignupRequirementsPage-Cf-ElkEq.js.map} +1 -1
- package/dist/StaffCreateSupportTicketForm-BlUP2XXy.js +14 -0
- package/dist/StaffCreateSupportTicketForm-D2nn4rTU.js +255 -0
- package/dist/StaffCreateSupportTicketForm-D2nn4rTU.js.map +1 -0
- package/dist/{StaffSupportTicketDetailPage-DQdfh6H1.js → StaffSupportTicketDetailPage-MFtm06BE.js} +14 -11
- package/dist/{StaffSupportTicketDetailPage-DQdfh6H1.js.map → StaffSupportTicketDetailPage-MFtm06BE.js.map} +1 -1
- package/dist/StaffSupportTicketList-LfLx0pYP.js +63 -0
- package/dist/StaffSupportTicketParent-B7mEN1oD.js +8 -0
- package/dist/{StaffSupportTicketParent-CilR4RGM.js → StaffSupportTicketParent-BvPwgOqH.js} +4 -4
- package/dist/{StaffSupportTicketParent-CilR4RGM.js.map → StaffSupportTicketParent-BvPwgOqH.js.map} +1 -1
- package/dist/StaffSupportTicketSuccess-BMCOP3ko.js +12 -0
- package/dist/StaffSupportTicketSuccess-Ca2WrcRg.js +54 -0
- package/dist/StaffSupportTicketSuccess-Ca2WrcRg.js.map +1 -0
- package/dist/{SupportStaffPage-KKugAnFm.js → SupportStaffPage-B69-kuvg.js} +8 -7
- package/dist/{SupportStaffPage-KKugAnFm.js.map → SupportStaffPage-B69-kuvg.js.map} +1 -1
- package/dist/{SupportTicketDevLifecycleBadge-EMrQHfyG.js → SupportTicketDevLifecycleBadge-BoAjMb08.js} +1 -1
- package/dist/{SupportTicketDevLifecycleBadge-EMrQHfyG.js.map → SupportTicketDevLifecycleBadge-BoAjMb08.js.map} +1 -1
- package/dist/{SupportTicketMaintenancePage-smItdkrD.js → SupportTicketMaintenancePage-Bptja-xb.js} +5 -4
- package/dist/{SupportTicketMaintenancePage-smItdkrD.js.map → SupportTicketMaintenancePage-Bptja-xb.js.map} +1 -1
- package/dist/TeamAttachmentsTab-Dk3LxX3n.js +63 -0
- package/dist/TeamHistoryTab-CRONdHcL.js +6 -0
- package/dist/{TeamHistoryTab-D5biUPmq.js → TeamHistoryTab-DM8KBEG1.js} +7 -19
- package/dist/TeamHistoryTab-DM8KBEG1.js.map +1 -0
- package/dist/TeamList-DYm_vQ2z.js +8 -0
- package/dist/TeamList-qdwlMuJv.js +141 -0
- package/dist/TeamList-qdwlMuJv.js.map +1 -0
- package/dist/TeamMemberList-4LRLT_7Z.js +7 -0
- package/dist/TeamMemberList-DyI1U1t_.js +166 -0
- package/dist/TeamMemberList-DyI1U1t_.js.map +1 -0
- package/dist/TeamMemberParent-B63pRfI6.js +10 -0
- package/dist/TeamMemberParent-D9Fxu7GD.js +83 -0
- package/dist/TeamMemberParent-D9Fxu7GD.js.map +1 -0
- package/dist/TeamMembersTab-BGcdyEE8.js +3 -0
- package/dist/{TeamMembersTab-4gmnP9sD.js → TeamMembersTab-BigqpBDH.js} +1 -1
- package/dist/{TeamMembersTab-4gmnP9sD.js.map → TeamMembersTab-BigqpBDH.js.map} +1 -1
- package/dist/{TeamNotesTab-BzGZZ1h8.js → TeamNotesTab-BgxleidZ.js} +6 -5
- package/dist/{TeamNotesTab-BzGZZ1h8.js.map → TeamNotesTab-BgxleidZ.js.map} +1 -1
- package/dist/TeamNotesTab-o7glfjoY.js +8 -0
- package/dist/TeamParent-BwXqA3rj.js +83 -0
- package/dist/TeamParent-BwXqA3rj.js.map +1 -0
- package/dist/TeamParent-CFOmyKPz.js +11 -0
- package/dist/{TimelineNoteInput-0p-M4Qie.js → TimelineNoteInput-DXaodm43.js} +3 -2
- package/dist/{TimelineNoteInput-0p-M4Qie.js.map → TimelineNoteInput-DXaodm43.js.map} +1 -1
- package/dist/TimelineSystemEvent-zCMUx5Zz.js +525 -0
- package/dist/TimelineSystemEvent-zCMUx5Zz.js.map +1 -0
- package/dist/UserListPage-Bmwg0an5.js +5 -0
- package/dist/{UserListPage-DUE5gJTo.js → UserListPage-DtA8tLff.js} +4 -3
- package/dist/{UserListPage-DUE5gJTo.js.map → UserListPage-DtA8tLff.js.map} +1 -1
- package/dist/UserProfilePage-DRbCAr9H.js +8 -0
- package/dist/{UserProfilePage-C3b93Keh.js → UserProfilePage-g4-VEDXo.js} +4 -4
- package/dist/{UserProfilePage-C3b93Keh.js.map → UserProfilePage-g4-VEDXo.js.map} +1 -1
- package/dist/{VerifyEmail-DlOmWGG-.js → VerifyEmail-CM5ehFB8.js} +7 -7
- package/dist/{VerifyEmail-DlOmWGG-.js.map → VerifyEmail-CM5ehFB8.js.map} +1 -1
- package/dist/VerifyEmail-DMHczC9f.js +10 -0
- package/dist/ViewTeam-CXyABxE6.js +8 -0
- package/dist/ViewTeam-DSbKV60o.js +220 -0
- package/dist/ViewTeam-DSbKV60o.js.map +1 -0
- package/dist/ViewTeamMember-BB0nvPOe.js +167 -0
- package/dist/ViewTeamMember-BB0nvPOe.js.map +1 -0
- package/dist/ViewTeamMember-jrOnBaDh.js +7 -0
- package/dist/ZiniaContainer-CjVhCnGB.js +18 -0
- package/dist/ZiniaContainer-CjVhCnGB.js.map +1 -0
- package/dist/{convertToLocalDateTime-CFhtN6PI.js → convertToLocalDateTime-BF25N4xd.js} +1 -2
- package/dist/convertToLocalDateTime-BF25N4xd.js.map +1 -0
- package/dist/customerSupportTicketRoutes-C7OxGAGl.js +142 -0
- package/dist/customerSupportTicketRoutes-C7OxGAGl.js.map +1 -0
- package/dist/{displayIdFormatter-Dz900Awr.js → displayIdFormatter-B-_WQHOr.js} +1 -1
- package/dist/{displayIdFormatter-Dz900Awr.js.map → displayIdFormatter-B-_WQHOr.js.map} +1 -1
- package/dist/{extractRpcErrorMessage-Di8E8-Wh.js → extractRpcErrorMessage-diUBl6Ij.js} +1 -1
- package/dist/{extractRpcErrorMessage-Di8E8-Wh.js.map → extractRpcErrorMessage-diUBl6Ij.js.map} +1 -1
- package/dist/index.d.ts +793 -834
- package/dist/index.js +66 -38
- package/dist/{mfaSchema-BnRWf0ma.js → mfaSchema-Ukqzdyck.js} +1 -1
- package/dist/{mfaSchema-BnRWf0ma.js.map → mfaSchema-Ukqzdyck.js.map} +1 -1
- package/dist/saved_filter-CfzH0BzK.js +1210 -0
- package/dist/saved_filter-CfzH0BzK.js.map +1 -0
- package/dist/signupConsentStorage-DS9vCUuC.js +27 -0
- package/dist/signupConsentStorage-DS9vCUuC.js.map +1 -0
- package/dist/{src-CEBiyg_f.css → src-C6ZmNSSU.css} +1 -1
- package/dist/{src-CEBiyg_f.css.map → src-C6ZmNSSU.css.map} +1 -1
- package/dist/src-DVe_0RO9.js +4654 -0
- package/dist/src-DVe_0RO9.js.map +1 -0
- package/dist/staffSupportTicketRoutes-CWutoQWp.js +135 -0
- package/dist/staffSupportTicketRoutes-CWutoQWp.js.map +1 -0
- package/dist/teamMemberMetadata-CQnbVepq.js +49 -0
- package/dist/teamMemberMetadata-CQnbVepq.js.map +1 -0
- package/dist/teamMetadata-DlvwO5V0.js +53 -0
- package/dist/teamMetadata-DlvwO5V0.js.map +1 -0
- package/dist/teamRoutes-KFgnsdDP.js +192 -0
- package/dist/teamRoutes-KFgnsdDP.js.map +1 -0
- package/dist/team_memberRoutes-Cjpw_ql6.js +84 -0
- package/dist/team_memberRoutes-Cjpw_ql6.js.map +1 -0
- package/dist/{useBreadcrumbs-qB6ghsAf.js → useBreadcrumbs-DIqU5AAp.js} +1 -1
- package/dist/{useBreadcrumbs-qB6ghsAf.js.map → useBreadcrumbs-DIqU5AAp.js.map} +1 -1
- package/dist/{useEmailVerificationChannel-BNi926Ho.js → useEmailVerificationChannel-B51z65PN.js} +3 -3
- package/dist/{useEmailVerificationChannel-BNi926Ho.js.map → useEmailVerificationChannel-B51z65PN.js.map} +1 -1
- package/dist/{useMutation-BTsyHKyn.js → useMutation-BLNuJoYl.js} +6 -3
- package/dist/useMutation-BLNuJoYl.js.map +1 -0
- package/dist/{useQuery-BggIE52P.js → useQuery-BzUGEOj0.js} +4 -3
- package/dist/{useQuery-BggIE52P.js.map → useQuery-BzUGEOj0.js.map} +1 -1
- package/dist/{useQueryCache-Bjm-S8v5.js → useQueryCache-alzaRWEb.js} +2 -2
- package/dist/{useQueryCache-Bjm-S8v5.js.map → useQueryCache-alzaRWEb.js.map} +1 -1
- package/dist/{useReturnUrl-qFeazn-G.js → useReturnUrl-B5V3SJf5.js} +1 -1
- package/dist/{useReturnUrl-qFeazn-G.js.map → useReturnUrl-B5V3SJf5.js.map} +1 -1
- package/dist/{useRpcAuth-rmHf7bYx.js → useRpcAuth-CJtq1dqM.js} +25 -194
- package/dist/useRpcAuth-CJtq1dqM.js.map +1 -0
- package/dist/userAuthorized-C09FHWGL.js +185 -0
- package/dist/userAuthorized-C09FHWGL.js.map +1 -0
- package/package.json +3 -3
- package/dist/Appearance-D5pwxuf4.js +0 -3
- package/dist/ChangePasswordPage-CpDPmEml.js +0 -6
- package/dist/ConsentRequired-C4IRMA0c.js +0 -213
- package/dist/ConsentRequired-C4IRMA0c.js.map +0 -1
- package/dist/CreateTeamForm-B4cIuYAf.js +0 -35
- package/dist/CreateTeamMemberForm-Chrw1y00.js +0 -35
- package/dist/CreateUserPage-WruMs7WP.js +0 -6
- package/dist/CreditBalanceDashboard-CkcsrZ_e.js +0 -35
- package/dist/CreditManagement-Ddvu9dMw.js +0 -35
- package/dist/CustomerCreateSupportTicketForm-BKperKGS.js +0 -35
- package/dist/CustomerSupportTicketList-DcbrjDa9.js +0 -35
- package/dist/CustomerSupportTicketParent-BeNzUwuP.js +0 -7
- package/dist/CustomerSupportTicketSuccess-CC967u3y.js +0 -35
- package/dist/EditTeamForm-B5Tee5wL.js +0 -35
- package/dist/EditTeamMemberForm-CaS2GLjV.js.map +0 -1
- package/dist/EditTeamMemberForm-OtcS8QWt.js +0 -6
- package/dist/EditUserPage-T4DQlKhf.js +0 -7
- package/dist/ForgotPassword-CUifhmqP.js +0 -7
- package/dist/LoginForm-Bg7GoZEA.js +0 -7
- package/dist/Logout-Bs92csWH.js +0 -7
- package/dist/MfaSetup-BACX5XP-.js +0 -8
- package/dist/MfaVerify-ak4iSdQ2.js +0 -8
- package/dist/ResetPassword-pY1uhTdl.js +0 -7
- package/dist/Signup-9TjMMnU4.js.map +0 -1
- package/dist/Signup-Bq-G3D-s.js +0 -9
- package/dist/SignupConsentFlow-QUZGKjdB.js.map +0 -1
- package/dist/StaffCreateSupportTicketForm-D0ZuisDk.js +0 -35
- package/dist/StaffSupportTicketList-CiqC05XB.js +0 -35
- package/dist/StaffSupportTicketParent-DkV329NI.js +0 -7
- package/dist/StaffSupportTicketSuccess-CUYnimaI.js +0 -35
- package/dist/TeamAttachmentsTab-DUtCD1Yi.js +0 -35
- package/dist/TeamHistoryTab-BsUoH4VK.js +0 -4
- package/dist/TeamHistoryTab-D5biUPmq.js.map +0 -1
- package/dist/TeamList-BkPIqZ8V.js +0 -35
- package/dist/TeamMemberList-1mxUGCNa.js +0 -35
- package/dist/TeamMemberParent-DzeBIElY.js +0 -35
- package/dist/TeamMembersTab-CBB2Yl_I.js +0 -3
- package/dist/TeamNotesTab-ClHl2nXd.js +0 -7
- package/dist/TeamParent-DJa9UZTP.js +0 -35
- package/dist/TimelineSystemEvent-BHzFr46C.js.map +0 -1
- package/dist/UserListPage-BTLE4J0s.js +0 -4
- package/dist/UserProfilePage-CVTORtSx.js +0 -7
- package/dist/VerifyEmail-DCP4DWIw.js +0 -9
- package/dist/ViewTeam-DVfnLMhV.js +0 -35
- package/dist/ViewTeamMember-L4v3gCIn.js +0 -35
- package/dist/convertToLocalDateTime-CFhtN6PI.js.map +0 -1
- package/dist/src-QZJyMfGX.js +0 -8951
- package/dist/src-QZJyMfGX.js.map +0 -1
- package/dist/useMutation-BTsyHKyn.js.map +0 -1
- package/dist/useRpcAuth-rmHf7bYx.js.map +0 -1
- package/dist/useSignupPendingData-BWHwUHhL.js +0 -47
- package/dist/useSignupPendingData-BWHwUHhL.js.map +0 -1
|
@@ -0,0 +1,4654 @@
|
|
|
1
|
+
import { d as useEnv, i as setRouter, o as useUserSessionStore, r as executeWithAuth } from "./useRpcAuth-CJtq1dqM.js";
|
|
2
|
+
import { i as setRefreshTokenHandler, r as getRefreshTokenHandler } from "./EnhancedRefreshTokenHandler-C6tZCcfX.js";
|
|
3
|
+
import { t as useMutation } from "./useMutation-BLNuJoYl.js";
|
|
4
|
+
import { t as useQuery } from "./useQuery-BzUGEOj0.js";
|
|
5
|
+
import { t as AppLink_default } from "./AppLink-FcNGKgvG.js";
|
|
6
|
+
import { a as useSavedFilters, c as buildQueryWithFilters, f as PINNED_PRESETS_KEY, m as usePinnedPresets, p as useInjectedPinnedPresets, t as SavedFilterPresets_default, u as extractFiltersFromQuery } from "./saved_filter-CfzH0BzK.js";
|
|
7
|
+
import { t as ConfirmDialog_default } from "./ConfirmDialog-DjthOYU6.js";
|
|
8
|
+
import { n as export_helper_default } from "./TeamMembersTab-BigqpBDH.js";
|
|
9
|
+
import { n as getBackLinkFromRoute, o as withReturnUrl, r as getValidReturnUrl } from "./useReturnUrl-B5V3SJf5.js";
|
|
10
|
+
import { t as BREADCRUMB_KEY } from "./useBreadcrumbs-DIqU5AAp.js";
|
|
11
|
+
import { t as ZiniaContainer_default } from "./ZiniaContainer-CjVhCnGB.js";
|
|
12
|
+
import { i as formatUserDate, t as formatSystemTimestamp } from "./convertToLocalDateTime-BF25N4xd.js";
|
|
13
|
+
import { t as extractRpcErrorMessage } from "./extractRpcErrorMessage-diUBl6Ij.js";
|
|
14
|
+
import { c as userAuthenticated, l as userIsSuperAdmin, o as leadOrStaffOnly } from "./userAuthorized-C09FHWGL.js";
|
|
15
|
+
import { t as staffSupportPaths } from "./staffSupportTicketRoutes-CWutoQWp.js";
|
|
16
|
+
import { a as SupportTicketTypeBadge_default, c as formatStaffCreditValue, i as SupportTicketApprovalBadge_default, o as SupportTicketPriorityBadge_default, s as formatCustomerCreditValue } from "./TimelineSystemEvent-zCMUx5Zz.js";
|
|
17
|
+
import { t as formatTicketDisplayId } from "./displayIdFormatter-B-_WQHOr.js";
|
|
18
|
+
import { t as SupportTicketDevLifecycleBadge_default } from "./SupportTicketDevLifecycleBadge-BoAjMb08.js";
|
|
19
|
+
import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createSlots, createTextVNode, createVNode, defineComponent, isRef, nextTick, normalizeClass, onMounted, openBlock, provide, readonly, ref, renderList, renderSlot, resolveComponent, toDisplayString, unref, vModelCheckbox, vModelText, watch, withCtx, withDirectives, withKeys, withModifiers } from "vue";
|
|
20
|
+
import { RouterView, useRoute, useRouter } from "vue-router";
|
|
21
|
+
import { toast } from "vue3-toastify";
|
|
22
|
+
import { CompleteSupportTicketSchema, CustomerSupportTicketReadSchema, OPERATORS, SUPPORT_TICKET_APPROVAL_FILTER_OPTIONS, SUPPORT_TICKET_DEV_LIFECYCLE_FILTER_OPTIONS, SUPPORT_TICKET_PRIORITY_FILTER_OPTIONS, SUPPORT_TICKET_STATUS_FILTER_OPTIONS, SUPPORT_TICKET_TYPE_FILTER_OPTIONS, StaffSupportTicketFiltersSchema, StaffSupportTicketReadSchema, SupportTicketDevLifecycleUpdateEnum, TeamFiltersSchema, TeamMemberFiltersSchema, supportTicketPriorityToNumber } from "@dragonmastery/dragoncore-shared";
|
|
23
|
+
import { ActionIcons, useCursorDataTable, useDataTableUrlSync, useForm, withMetadata } from "@dragonmastery/zinia-forms-core";
|
|
24
|
+
|
|
25
|
+
//#region src/plugin.ts
|
|
26
|
+
/**
|
|
27
|
+
* Dragoncore Vue Plugin
|
|
28
|
+
*
|
|
29
|
+
* Provides RPC authentication and data fetching capabilities to your Vue app.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* import { createApp } from 'vue';
|
|
34
|
+
* import { DragoncoreVue } from '@dragonmastery/dragoncore-vue';
|
|
35
|
+
* import router from './router';
|
|
36
|
+
* import { createRefreshTokenHandler } from '@dragonmastery/dragoncore-vue';
|
|
37
|
+
* import type { AppApi } from '@follow-zap/shared';
|
|
38
|
+
*
|
|
39
|
+
* const app = createApp(App);
|
|
40
|
+
* const refreshTokenHandler = createRefreshTokenHandler<AppApi>();
|
|
41
|
+
*
|
|
42
|
+
* app.use(DragoncoreVue, {
|
|
43
|
+
* router,
|
|
44
|
+
* refreshTokenHandler,
|
|
45
|
+
* });
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
const DragoncoreVue = { install(_app, options) {
|
|
49
|
+
if (!options.router) throw new Error("DragoncoreVue plugin: router is required");
|
|
50
|
+
if (!options.refreshTokenHandler) throw new Error("DragoncoreVue plugin: refreshTokenHandler is required");
|
|
51
|
+
setRouter(options.router);
|
|
52
|
+
setRefreshTokenHandler(options.refreshTokenHandler);
|
|
53
|
+
} };
|
|
54
|
+
|
|
55
|
+
//#endregion
|
|
56
|
+
//#region src/components/AppTabNavigation.vue
|
|
57
|
+
const _hoisted_1$29 = { class: "w-full" };
|
|
58
|
+
const _hoisted_2$26 = { class: "md:hidden relative" };
|
|
59
|
+
const _hoisted_3$26 = { class: "font-medium" };
|
|
60
|
+
const _hoisted_4$21 = {
|
|
61
|
+
key: 0,
|
|
62
|
+
class: "absolute z-20 w-full bg-base-100 shadow-lg"
|
|
63
|
+
};
|
|
64
|
+
const _hoisted_5$17 = ["onClick"];
|
|
65
|
+
const _hoisted_6$15 = { class: "hidden md:flex items-center overflow-x-auto" };
|
|
66
|
+
const _hoisted_7$13 = { class: "flex-1 flex" };
|
|
67
|
+
const _hoisted_8$13 = ["onClick"];
|
|
68
|
+
const _hoisted_9$12 = { class: "ml-auto shrink-0" };
|
|
69
|
+
const _sfc_main$34 = /* @__PURE__ */ defineComponent({
|
|
70
|
+
__name: "AppTabNavigation",
|
|
71
|
+
props: {
|
|
72
|
+
tabs: {},
|
|
73
|
+
activeTab: { default: "" }
|
|
74
|
+
},
|
|
75
|
+
emits: ["tab-click"],
|
|
76
|
+
setup(__props, { emit: __emit }) {
|
|
77
|
+
const props = __props;
|
|
78
|
+
const emit = __emit;
|
|
79
|
+
const route = useRoute();
|
|
80
|
+
const isMenuOpen = ref(false);
|
|
81
|
+
const handleTabClick = (tabId) => {
|
|
82
|
+
emit("tab-click", tabId);
|
|
83
|
+
isMenuOpen.value = false;
|
|
84
|
+
};
|
|
85
|
+
const activeTabLabel = computed(() => {
|
|
86
|
+
return props.tabs.find((tab) => {
|
|
87
|
+
if (tab.to && isActiveTab(tab)) return true;
|
|
88
|
+
return tab.id === props.activeTab;
|
|
89
|
+
})?.label || "Navigation";
|
|
90
|
+
});
|
|
91
|
+
const isActiveTab = (tab) => {
|
|
92
|
+
if (props.activeTab && tab.id === props.activeTab) return true;
|
|
93
|
+
if (tab.to) {
|
|
94
|
+
if (route.meta.currentTab && tab.id === route.meta.currentTab) return true;
|
|
95
|
+
if (tab.to.name && route.name === tab.to.name) {
|
|
96
|
+
if (tab.to.params) {
|
|
97
|
+
const toParams = tab.to.params;
|
|
98
|
+
const routeParams = route.params;
|
|
99
|
+
for (const key in toParams) if (routeParams[key] !== toParams[key]) return false;
|
|
100
|
+
return Object.keys(toParams).length > 0;
|
|
101
|
+
}
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
if (tab.to.path && route.path === tab.to.path) return true;
|
|
105
|
+
}
|
|
106
|
+
return false;
|
|
107
|
+
};
|
|
108
|
+
return (_ctx, _cache) => {
|
|
109
|
+
const _component_router_link = resolveComponent("router-link");
|
|
110
|
+
return openBlock(), createElementBlock(Fragment, null, [createCommentVNode(" Mobile-first tab navigation with responsive grid layout "), createElementVNode("div", _hoisted_1$29, [
|
|
111
|
+
createCommentVNode(" Mobile view: Show dropdown on small screens "),
|
|
112
|
+
createElementVNode("div", _hoisted_2$26, [
|
|
113
|
+
createElementVNode("button", {
|
|
114
|
+
onClick: _cache[0] || (_cache[0] = ($event) => isMenuOpen.value = !isMenuOpen.value),
|
|
115
|
+
class: "w-full flex items-center justify-between px-4 py-3 bg-base-100"
|
|
116
|
+
}, [createElementVNode("span", _hoisted_3$26, toDisplayString(activeTabLabel.value), 1), _cache[2] || (_cache[2] = createElementVNode("svg", {
|
|
117
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
118
|
+
class: "h-5 w-5",
|
|
119
|
+
fill: "none",
|
|
120
|
+
viewBox: "0 0 24 24",
|
|
121
|
+
stroke: "currentColor"
|
|
122
|
+
}, [createElementVNode("path", {
|
|
123
|
+
"stroke-linecap": "round",
|
|
124
|
+
"stroke-linejoin": "round",
|
|
125
|
+
"stroke-width": "2",
|
|
126
|
+
d: "M19 9l-7 7-7-7"
|
|
127
|
+
})], -1))]),
|
|
128
|
+
createCommentVNode(" Dropdown menu "),
|
|
129
|
+
isMenuOpen.value ? (openBlock(), createElementBlock("div", _hoisted_4$21, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.tabs, (tab, index) => {
|
|
130
|
+
return openBlock(), createElementBlock(Fragment, { key: index }, [tab.to ? (openBlock(), createBlock(_component_router_link, {
|
|
131
|
+
key: 0,
|
|
132
|
+
to: tab.to,
|
|
133
|
+
class: normalizeClass(["block px-4 py-3 hover:bg-base-200", [isActiveTab(tab) ? "text-primary font-medium" : "text-base-content/70"]]),
|
|
134
|
+
onClick: _cache[1] || (_cache[1] = ($event) => isMenuOpen.value = false)
|
|
135
|
+
}, {
|
|
136
|
+
default: withCtx(() => [createTextVNode(toDisplayString(tab.label), 1)]),
|
|
137
|
+
_: 2
|
|
138
|
+
}, 1032, ["to", "class"])) : (openBlock(), createElementBlock("button", {
|
|
139
|
+
key: 1,
|
|
140
|
+
onClick: ($event) => handleTabClick(tab.id),
|
|
141
|
+
class: normalizeClass(["block w-full text-left px-4 py-3 hover:bg-base-200", [__props.activeTab === tab.id ? "text-primary font-medium" : "text-base-content/70"]])
|
|
142
|
+
}, toDisplayString(tab.label), 11, _hoisted_5$17))], 64);
|
|
143
|
+
}), 128))])) : createCommentVNode("v-if", true)
|
|
144
|
+
]),
|
|
145
|
+
createCommentVNode(" Desktop view: Show horizontal tabs on medium screens and up "),
|
|
146
|
+
createElementVNode("div", _hoisted_6$15, [
|
|
147
|
+
createElementVNode("div", _hoisted_7$13, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.tabs, (tab, index) => {
|
|
148
|
+
return openBlock(), createElementBlock(Fragment, { key: index }, [tab.to ? (openBlock(), createBlock(_component_router_link, {
|
|
149
|
+
key: 0,
|
|
150
|
+
to: tab.to,
|
|
151
|
+
class: normalizeClass(["px-4 py-3 border-b-2 whitespace-nowrap flex items-center", [isActiveTab(tab) ? "font-medium text-primary border-primary" : "border-transparent hover:border-base-300 text-base-content/70 hover:text-base-content"]])
|
|
152
|
+
}, {
|
|
153
|
+
default: withCtx(() => [renderSlot(_ctx.$slots, `icon-${tab.id}`), createElementVNode("span", null, toDisplayString(tab.label), 1)]),
|
|
154
|
+
_: 2
|
|
155
|
+
}, 1032, ["to", "class"])) : (openBlock(), createElementBlock("button", {
|
|
156
|
+
key: 1,
|
|
157
|
+
onClick: ($event) => handleTabClick(tab.id),
|
|
158
|
+
class: normalizeClass(["px-4 py-3 border-b-2 whitespace-nowrap flex items-center", [__props.activeTab === tab.id ? "font-medium text-primary border-primary" : "border-transparent hover:border-base-300 text-base-content/70 hover:text-base-content"]])
|
|
159
|
+
}, [renderSlot(_ctx.$slots, `icon-${tab.id}`), createElementVNode("span", null, toDisplayString(tab.label), 1)], 10, _hoisted_8$13))], 64);
|
|
160
|
+
}), 128))]),
|
|
161
|
+
createCommentVNode(" Optional slot for additional content "),
|
|
162
|
+
createElementVNode("div", _hoisted_9$12, [renderSlot(_ctx.$slots, "actions")])
|
|
163
|
+
])
|
|
164
|
+
])], 2112);
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
var AppTabNavigation_default = _sfc_main$34;
|
|
169
|
+
|
|
170
|
+
//#endregion
|
|
171
|
+
//#region src/components/AppHeader.vue
|
|
172
|
+
const _hoisted_1$28 = { class: "bg-base-100 border-b border-base-300 z-10 w-full" };
|
|
173
|
+
const _hoisted_2$25 = {
|
|
174
|
+
key: 0,
|
|
175
|
+
class: "w-full"
|
|
176
|
+
};
|
|
177
|
+
const _hoisted_3$25 = { class: "max-w-7xl mx-auto px-3 sm:px-4 md:px-6" };
|
|
178
|
+
const _sfc_main$33 = /* @__PURE__ */ defineComponent({
|
|
179
|
+
__name: "AppHeader",
|
|
180
|
+
props: {
|
|
181
|
+
tabs: {},
|
|
182
|
+
activeTab: { default: "" }
|
|
183
|
+
},
|
|
184
|
+
emits: ["tab-click"],
|
|
185
|
+
setup(__props) {
|
|
186
|
+
return (_ctx, _cache) => {
|
|
187
|
+
return openBlock(), createElementBlock(Fragment, null, [createCommentVNode(" Full-width background with constrained content "), createElementVNode("div", _hoisted_1$28, [
|
|
188
|
+
createCommentVNode(" Tab navigation - only shown when tabs are provided "),
|
|
189
|
+
__props.tabs.length > 0 ? (openBlock(), createElementBlock("div", _hoisted_2$25, [createElementVNode("div", _hoisted_3$25, [createVNode(AppTabNavigation_default, {
|
|
190
|
+
tabs: __props.tabs,
|
|
191
|
+
"active-tab": __props.activeTab,
|
|
192
|
+
onTabClick: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("tab-click", $event))
|
|
193
|
+
}, createSlots({
|
|
194
|
+
actions: withCtx(() => [renderSlot(_ctx.$slots, "actions")]),
|
|
195
|
+
_: 2
|
|
196
|
+
}, [renderList(__props.tabs, (tab) => {
|
|
197
|
+
return {
|
|
198
|
+
name: `icon-${tab.id}`,
|
|
199
|
+
fn: withCtx(() => [renderSlot(_ctx.$slots, `icon-${tab.id}`)])
|
|
200
|
+
};
|
|
201
|
+
})]), 1032, ["tabs", "active-tab"])])])) : createCommentVNode("v-if", true),
|
|
202
|
+
createCommentVNode(" Status badge slot (moved from breadcrumbs) "),
|
|
203
|
+
renderSlot(_ctx.$slots, "status")
|
|
204
|
+
])], 2112);
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
var AppHeader_default = _sfc_main$33;
|
|
209
|
+
|
|
210
|
+
//#endregion
|
|
211
|
+
//#region src/components/InputModal.vue
|
|
212
|
+
const _hoisted_1$27 = { class: "modal-box" };
|
|
213
|
+
const _hoisted_2$24 = { class: "font-bold text-lg" };
|
|
214
|
+
const _hoisted_3$24 = { class: "py-4" };
|
|
215
|
+
const _hoisted_4$20 = { class: "form-control w-full" };
|
|
216
|
+
const _hoisted_5$16 = { class: "label" };
|
|
217
|
+
const _hoisted_6$14 = { class: "label-text" };
|
|
218
|
+
const _hoisted_7$12 = ["placeholder"];
|
|
219
|
+
const _hoisted_8$12 = {
|
|
220
|
+
key: 0,
|
|
221
|
+
class: "label"
|
|
222
|
+
};
|
|
223
|
+
const _hoisted_9$11 = { class: "label-text-alt text-error" };
|
|
224
|
+
const _hoisted_10$8 = { class: "modal-action" };
|
|
225
|
+
const _hoisted_11$8 = ["disabled"];
|
|
226
|
+
const _hoisted_12$7 = ["disabled"];
|
|
227
|
+
const _sfc_main$32 = /* @__PURE__ */ defineComponent({
|
|
228
|
+
__name: "InputModal",
|
|
229
|
+
props: {
|
|
230
|
+
modelValue: { type: Boolean },
|
|
231
|
+
title: { default: "Input" },
|
|
232
|
+
label: { default: "Value" },
|
|
233
|
+
placeholder: { default: "Enter value" },
|
|
234
|
+
confirmText: { default: "Confirm" },
|
|
235
|
+
cancelText: { default: "Cancel" },
|
|
236
|
+
processingText: { default: "Processing..." },
|
|
237
|
+
confirmButtonClass: { default: "btn-primary" },
|
|
238
|
+
isProcessing: {
|
|
239
|
+
type: Boolean,
|
|
240
|
+
default: false
|
|
241
|
+
},
|
|
242
|
+
error: { default: "" },
|
|
243
|
+
initialValue: { default: "" }
|
|
244
|
+
},
|
|
245
|
+
emits: [
|
|
246
|
+
"update:modelValue",
|
|
247
|
+
"confirm",
|
|
248
|
+
"cancel"
|
|
249
|
+
],
|
|
250
|
+
setup(__props, { emit: __emit }) {
|
|
251
|
+
const props = __props;
|
|
252
|
+
const emit = __emit;
|
|
253
|
+
const inputValue = ref(props.initialValue);
|
|
254
|
+
const inputRef = ref(null);
|
|
255
|
+
watch(() => props.modelValue, (newValue) => {
|
|
256
|
+
if (newValue) {
|
|
257
|
+
inputValue.value = props.initialValue || "";
|
|
258
|
+
nextTick(() => {
|
|
259
|
+
inputRef.value?.focus();
|
|
260
|
+
inputRef.value?.select();
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
watch(() => props.initialValue, (newValue) => {
|
|
265
|
+
if (props.modelValue) inputValue.value = newValue || "";
|
|
266
|
+
});
|
|
267
|
+
const handleConfirm = () => {
|
|
268
|
+
const value = inputValue.value.trim();
|
|
269
|
+
if (value) emit("confirm", value);
|
|
270
|
+
};
|
|
271
|
+
const handleCancel = () => {
|
|
272
|
+
emit("update:modelValue", false);
|
|
273
|
+
emit("cancel");
|
|
274
|
+
inputValue.value = "";
|
|
275
|
+
};
|
|
276
|
+
return (_ctx, _cache) => {
|
|
277
|
+
return openBlock(), createElementBlock("div", { class: normalizeClass(["modal", { "modal-open": __props.modelValue }]) }, [createElementVNode("div", _hoisted_1$27, [
|
|
278
|
+
createElementVNode("h3", _hoisted_2$24, toDisplayString(__props.title), 1),
|
|
279
|
+
createElementVNode("div", _hoisted_3$24, [createElementVNode("label", _hoisted_4$20, [
|
|
280
|
+
createElementVNode("div", _hoisted_5$16, [createElementVNode("span", _hoisted_6$14, toDisplayString(__props.label), 1)]),
|
|
281
|
+
withDirectives(createElementVNode("input", {
|
|
282
|
+
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => inputValue.value = $event),
|
|
283
|
+
type: "text",
|
|
284
|
+
placeholder: __props.placeholder,
|
|
285
|
+
class: "input input-bordered w-full",
|
|
286
|
+
onKeyup: [withKeys(handleConfirm, ["enter"]), withKeys(handleCancel, ["escape"])],
|
|
287
|
+
ref_key: "inputRef",
|
|
288
|
+
ref: inputRef
|
|
289
|
+
}, null, 40, _hoisted_7$12), [[vModelText, inputValue.value]]),
|
|
290
|
+
__props.error ? (openBlock(), createElementBlock("div", _hoisted_8$12, [createElementVNode("span", _hoisted_9$11, toDisplayString(__props.error), 1)])) : createCommentVNode("v-if", true)
|
|
291
|
+
])]),
|
|
292
|
+
createElementVNode("div", _hoisted_10$8, [createElementVNode("button", {
|
|
293
|
+
class: "btn",
|
|
294
|
+
onClick: handleCancel,
|
|
295
|
+
disabled: __props.isProcessing
|
|
296
|
+
}, toDisplayString(__props.cancelText), 9, _hoisted_11$8), createElementVNode("button", {
|
|
297
|
+
class: normalizeClass(["btn", __props.confirmButtonClass]),
|
|
298
|
+
onClick: handleConfirm,
|
|
299
|
+
disabled: !inputValue.value || inputValue.value.trim() === "" || __props.isProcessing
|
|
300
|
+
}, toDisplayString(__props.isProcessing ? __props.processingText : __props.confirmText), 11, _hoisted_12$7)])
|
|
301
|
+
]), createElementVNode("div", {
|
|
302
|
+
class: "modal-backdrop",
|
|
303
|
+
onClick: handleCancel
|
|
304
|
+
})], 2);
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
var InputModal_default = _sfc_main$32;
|
|
309
|
+
|
|
310
|
+
//#endregion
|
|
311
|
+
//#region src/components/LoginButton.vue
|
|
312
|
+
const _sfc_main$31 = {};
|
|
313
|
+
function _sfc_render(_ctx, _cache) {
|
|
314
|
+
const _component_router_link = resolveComponent("router-link");
|
|
315
|
+
return openBlock(), createBlock(_component_router_link, { to: "/auth/login" }, {
|
|
316
|
+
default: withCtx(() => [..._cache[0] || (_cache[0] = [createElementVNode("button", { class: "btn-primary btn" }, "Login", -1)])]),
|
|
317
|
+
_: 1
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
var LoginButton_default = /* @__PURE__ */ export_helper_default(_sfc_main$31, [["render", _sfc_render]]);
|
|
321
|
+
|
|
322
|
+
//#endregion
|
|
323
|
+
//#region src/components/ui/LogoPlaceholder.vue
|
|
324
|
+
const _sfc_main$30 = /* @__PURE__ */ defineComponent({
|
|
325
|
+
__name: "LogoPlaceholder",
|
|
326
|
+
props: { size: { default: "md" } },
|
|
327
|
+
setup(__props) {
|
|
328
|
+
return (_ctx, _cache) => {
|
|
329
|
+
return openBlock(), createElementBlock("div", { class: normalizeClass(["flex items-center justify-center rounded-lg bg-base-300 text-base-content/50", __props.size === "xs" ? "h-10 w-10 md:h-12 md:w-12 text-xs" : __props.size === "sm" ? "h-12 w-24 text-xs" : "h-24 w-32 text-sm"]) }, [..._cache[0] || (_cache[0] = [createElementVNode("span", { class: "font-medium" }, "Logo", -1)])], 2);
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
var LogoPlaceholder_default = _sfc_main$30;
|
|
334
|
+
|
|
335
|
+
//#endregion
|
|
336
|
+
//#region src/components/Navbar.vue
|
|
337
|
+
const _hoisted_1$26 = { class: "sticky top-0 flex h-16 w-full justify-center border-b-2 border-solid border-b-base-300 bg-base-200 bg-opacity-90 text-base-content shadow-xs z-10" };
|
|
338
|
+
const _hoisted_2$23 = { class: "navbar w-full" };
|
|
339
|
+
const _hoisted_3$23 = { class: "flex flex-1 md:gap-1 lg:gap-2" };
|
|
340
|
+
const _hoisted_4$19 = { class: "items-center gap-2 flex" };
|
|
341
|
+
const _hoisted_5$15 = { class: "font-title inline-flex text-lg text-primary transition-all duration-200 md:text-3xl" };
|
|
342
|
+
const _hoisted_6$13 = ["src"];
|
|
343
|
+
const _hoisted_7$11 = {
|
|
344
|
+
key: 0,
|
|
345
|
+
class: "hidden md:flex items-center ml-4"
|
|
346
|
+
};
|
|
347
|
+
const _hoisted_8$11 = { class: "text-sm text-base-content/70 flex items-center gap-2" };
|
|
348
|
+
const _hoisted_9$10 = {
|
|
349
|
+
key: 0,
|
|
350
|
+
class: "loading loading-spinner loading-xs"
|
|
351
|
+
};
|
|
352
|
+
const _hoisted_10$7 = { class: "font-medium" };
|
|
353
|
+
const _hoisted_11$7 = {
|
|
354
|
+
key: 2,
|
|
355
|
+
class: "text-base-content/50"
|
|
356
|
+
};
|
|
357
|
+
const _hoisted_12$6 = {
|
|
358
|
+
key: 1,
|
|
359
|
+
class: "flex md:hidden flex-col justify-center ml-2 leading-tight"
|
|
360
|
+
};
|
|
361
|
+
const _hoisted_13$5 = { class: "font-medium text-sm truncate max-w-[150px]" };
|
|
362
|
+
const _hoisted_14$4 = {
|
|
363
|
+
key: 0,
|
|
364
|
+
class: "loading loading-spinner loading-xs"
|
|
365
|
+
};
|
|
366
|
+
const _hoisted_15$3 = { class: "flex-none gap-2" };
|
|
367
|
+
const _hoisted_16$3 = {
|
|
368
|
+
key: 0,
|
|
369
|
+
class: "loading btn-primary btn"
|
|
370
|
+
};
|
|
371
|
+
const _hoisted_17$2 = {
|
|
372
|
+
key: 1,
|
|
373
|
+
for: "my-drawer-4",
|
|
374
|
+
tabindex: "0",
|
|
375
|
+
class: "btn-ghost btn-circle avatar btn placeholder",
|
|
376
|
+
id: "right-nav-label"
|
|
377
|
+
};
|
|
378
|
+
const _sfc_main$29 = /* @__PURE__ */ defineComponent({
|
|
379
|
+
__name: "Navbar",
|
|
380
|
+
props: {
|
|
381
|
+
breadcrumbs: {},
|
|
382
|
+
logoSrc: {}
|
|
383
|
+
},
|
|
384
|
+
setup(__props) {
|
|
385
|
+
const imageLoadFailed = ref(false);
|
|
386
|
+
const loading = ref(true);
|
|
387
|
+
loading.value = true;
|
|
388
|
+
const user = useUserSessionStore();
|
|
389
|
+
loading.value = false;
|
|
390
|
+
return (_ctx, _cache) => {
|
|
391
|
+
const _component_router_link = resolveComponent("router-link");
|
|
392
|
+
return openBlock(), createElementBlock("header", _hoisted_1$26, [createElementVNode("nav", _hoisted_2$23, [createElementVNode("div", _hoisted_3$23, [_cache[3] || (_cache[3] = createElementVNode("label", {
|
|
393
|
+
for: "drawer",
|
|
394
|
+
class: "btn-ghost drawer-button btn-square btn"
|
|
395
|
+
}, [createElementVNode("svg", {
|
|
396
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
397
|
+
fill: "none",
|
|
398
|
+
viewBox: "0 0 24 24",
|
|
399
|
+
"stroke-width": "1.5",
|
|
400
|
+
stroke: "currentColor",
|
|
401
|
+
class: "h-6 w-6"
|
|
402
|
+
}, [createElementVNode("path", {
|
|
403
|
+
"stroke-linecap": "round",
|
|
404
|
+
"stroke-linejoin": "round",
|
|
405
|
+
d: "M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5"
|
|
406
|
+
})])], -1)), createElementVNode("div", _hoisted_4$19, [
|
|
407
|
+
createVNode(AppLink_default, {
|
|
408
|
+
to: "/",
|
|
409
|
+
"aria-current": "page",
|
|
410
|
+
"aria-label": "Homepage"
|
|
411
|
+
}, {
|
|
412
|
+
default: withCtx(() => [createElementVNode("div", _hoisted_5$15, [!__props.logoSrc || imageLoadFailed.value ? (openBlock(), createBlock(LogoPlaceholder_default, {
|
|
413
|
+
key: 0,
|
|
414
|
+
size: "xs"
|
|
415
|
+
})) : (openBlock(), createElementBlock("img", {
|
|
416
|
+
key: 1,
|
|
417
|
+
src: __props.logoSrc,
|
|
418
|
+
alt: "logo",
|
|
419
|
+
class: "h-10 w-10 md:h-12 md:w-12",
|
|
420
|
+
onError: _cache[0] || (_cache[0] = ($event) => imageLoadFailed.value = true)
|
|
421
|
+
}, null, 40, _hoisted_6$13))])]),
|
|
422
|
+
_: 1
|
|
423
|
+
}),
|
|
424
|
+
createCommentVNode(" Breadcrumbs in navbar - Desktop view "),
|
|
425
|
+
__props.breadcrumbs && __props.breadcrumbs.length > 0 ? (openBlock(), createElementBlock("div", _hoisted_7$11, [createElementVNode("div", _hoisted_8$11, [
|
|
426
|
+
(openBlock(true), createElementBlock(Fragment, null, renderList(__props.breadcrumbs, (crumb, index) => {
|
|
427
|
+
return openBlock(), createElementBlock(Fragment, { key: index }, [
|
|
428
|
+
createCommentVNode(" Link for all but the last item "),
|
|
429
|
+
index < __props.breadcrumbs.length - 1 ? (openBlock(), createBlock(_component_router_link, {
|
|
430
|
+
key: 0,
|
|
431
|
+
to: crumb.to,
|
|
432
|
+
class: "hover:text-primary"
|
|
433
|
+
}, {
|
|
434
|
+
default: withCtx(() => [createTextVNode(toDisplayString(crumb.label), 1)]),
|
|
435
|
+
_: 2
|
|
436
|
+
}, 1032, ["to"])) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
|
|
437
|
+
createCommentVNode(" Current page (not a link) "),
|
|
438
|
+
createCommentVNode(" Show loading spinner if explicitly loading "),
|
|
439
|
+
crumb.loading ? (openBlock(), createElementBlock("span", _hoisted_9$10)) : crumb.label ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [createCommentVNode(" Show label if provided "), createElementVNode("span", _hoisted_10$7, toDisplayString(crumb.label), 1)], 2112)) : (openBlock(), createElementBlock(Fragment, { key: 2 }, [createCommentVNode(" Fallback if neither loading nor label "), _cache[1] || (_cache[1] = createElementVNode("span", { class: "font-medium text-base-content/50" }, "...", -1))], 2112))
|
|
440
|
+
], 64)),
|
|
441
|
+
createCommentVNode(" Separator between items "),
|
|
442
|
+
index < __props.breadcrumbs.length - 1 ? (openBlock(), createElementBlock("span", _hoisted_11$7, "/")) : createCommentVNode("v-if", true)
|
|
443
|
+
], 64);
|
|
444
|
+
}), 128)),
|
|
445
|
+
createCommentVNode(" Optional status badge "),
|
|
446
|
+
renderSlot(_ctx.$slots, "status")
|
|
447
|
+
])])) : createCommentVNode("v-if", true),
|
|
448
|
+
createCommentVNode(" Breadcrumbs in navbar - Mobile view (GitHub style) "),
|
|
449
|
+
__props.breadcrumbs && __props.breadcrumbs.length > 0 ? (openBlock(), createElementBlock("div", _hoisted_12$6, [
|
|
450
|
+
createCommentVNode(" Parent/previous breadcrumb (if exists) "),
|
|
451
|
+
__props.breadcrumbs.length > 1 && __props.breadcrumbs[__props.breadcrumbs.length - 2] ? (openBlock(), createBlock(_component_router_link, {
|
|
452
|
+
key: 0,
|
|
453
|
+
to: __props.breadcrumbs[__props.breadcrumbs.length - 2].to,
|
|
454
|
+
class: "text-xs text-base-content/70 hover:text-primary truncate max-w-[120px]"
|
|
455
|
+
}, {
|
|
456
|
+
default: withCtx(() => [createTextVNode(toDisplayString(__props.breadcrumbs[__props.breadcrumbs.length - 2].label), 1)]),
|
|
457
|
+
_: 1
|
|
458
|
+
}, 8, ["to"])) : createCommentVNode("v-if", true),
|
|
459
|
+
createCommentVNode(" Current page (last breadcrumb) "),
|
|
460
|
+
createElementVNode("div", _hoisted_13$5, [createCommentVNode(" Show loading spinner if explicitly loading "), __props.breadcrumbs[__props.breadcrumbs.length - 1]?.loading ? (openBlock(), createElementBlock("span", _hoisted_14$4)) : __props.breadcrumbs[__props.breadcrumbs.length - 1]?.label ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [createCommentVNode(" Show label if provided "), createTextVNode(toDisplayString(__props.breadcrumbs[__props.breadcrumbs.length - 1].label), 1)], 64)) : (openBlock(), createElementBlock(Fragment, { key: 2 }, [createCommentVNode(" Fallback "), _cache[2] || (_cache[2] = createElementVNode("span", { class: "text-base-content/50" }, "...", -1))], 2112))]),
|
|
461
|
+
createCommentVNode(" Optional status badge "),
|
|
462
|
+
renderSlot(_ctx.$slots, "mobile-status")
|
|
463
|
+
])) : createCommentVNode("v-if", true)
|
|
464
|
+
])]), createElementVNode("div", _hoisted_15$3, [_cache[5] || (_cache[5] = createElementVNode("div", { class: "form-control hidden sm:flex" }, [createCommentVNode(" <input\n type=\"text\"\n placeholder=\"Search\"\n class=\"input-bordered input input-sm\"\n /> ")], -1)), loading.value ? (openBlock(), createElementBlock("button", _hoisted_16$3)) : unref(user).currentSession ? (openBlock(), createElementBlock("label", _hoisted_17$2, [..._cache[4] || (_cache[4] = [createElementVNode("div", { class: "bg-neutral-focus text-neutral-content w-10 rounded-full" }, [createElementVNode("span", null, "U")], -1)])])) : (openBlock(), createBlock(LoginButton_default, { key: 2 }))])])]);
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
});
|
|
468
|
+
var Navbar_default = _sfc_main$29;
|
|
469
|
+
|
|
470
|
+
//#endregion
|
|
471
|
+
//#region src/components/NotFound.vue
|
|
472
|
+
const _hoisted_1$25 = { class: "flex items-center justify-center bg-base-100 mt-4" };
|
|
473
|
+
const _hoisted_2$22 = { class: "max-w-md mx-auto text-center px-4" };
|
|
474
|
+
const _hoisted_3$22 = { class: "flex flex-col sm:flex-row gap-4 justify-center" };
|
|
475
|
+
const _sfc_main$28 = /* @__PURE__ */ defineComponent({
|
|
476
|
+
__name: "NotFound",
|
|
477
|
+
setup(__props) {
|
|
478
|
+
const router = useRouter();
|
|
479
|
+
const goBack = () => {
|
|
480
|
+
if (window.history.length > 1) router.go(-1);
|
|
481
|
+
else router.push({ name: "Home" });
|
|
482
|
+
};
|
|
483
|
+
return (_ctx, _cache) => {
|
|
484
|
+
const _component_router_link = resolveComponent("router-link");
|
|
485
|
+
return openBlock(), createElementBlock("div", _hoisted_1$25, [createElementVNode("div", _hoisted_2$22, [_cache[1] || (_cache[1] = createElementVNode("div", { class: "mb-8" }, [
|
|
486
|
+
createElementVNode("h1", { class: "text-9xl font-bold text-primary mb-4" }, "404"),
|
|
487
|
+
createElementVNode("h2", { class: "text-3xl font-bold mb-4" }, "Page Not Found"),
|
|
488
|
+
createElementVNode("p", { class: "text-base-content/70 mb-8" }, " Sorry, we couldn't find the page you're looking for. The page may have been moved, deleted, or the URL might be incorrect. ")
|
|
489
|
+
], -1)), createElementVNode("div", _hoisted_3$22, [createVNode(_component_router_link, {
|
|
490
|
+
to: { name: "Home" },
|
|
491
|
+
class: "btn btn-primary"
|
|
492
|
+
}, {
|
|
493
|
+
default: withCtx(() => [..._cache[0] || (_cache[0] = [createTextVNode(" Go to Home ", -1)])]),
|
|
494
|
+
_: 1
|
|
495
|
+
}), createElementVNode("button", {
|
|
496
|
+
onClick: goBack,
|
|
497
|
+
class: "btn btn-outline"
|
|
498
|
+
}, "Go Back")])])]);
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
});
|
|
502
|
+
var NotFound_default = _sfc_main$28;
|
|
503
|
+
|
|
504
|
+
//#endregion
|
|
505
|
+
//#region src/components/RightSidebar.vue
|
|
506
|
+
const _hoisted_1$24 = { class: "drawer-side z-50" };
|
|
507
|
+
const _hoisted_2$21 = { class: "menu p-3 w-80 h-full bg-base-200 text-base-content" };
|
|
508
|
+
const _hoisted_3$21 = { class: "flex pb-2" };
|
|
509
|
+
const _hoisted_4$18 = { class: "pl-3" };
|
|
510
|
+
const _sfc_main$27 = /* @__PURE__ */ defineComponent({
|
|
511
|
+
__name: "RightSidebar",
|
|
512
|
+
props: { logoutReturnUrl: { default: "/" } },
|
|
513
|
+
setup(__props) {
|
|
514
|
+
const userSession = useUserSessionStore();
|
|
515
|
+
/**
|
|
516
|
+
* Where to redirect after logout. Default '/' (homepage) so user can browse anonymously.
|
|
517
|
+
* Apps can pass a different path via the logoutReturnUrl prop if needed.
|
|
518
|
+
*/
|
|
519
|
+
const props = __props;
|
|
520
|
+
const logoutLink = computed(() => withReturnUrl("/auth/logout", props.logoutReturnUrl));
|
|
521
|
+
let checked = ref(false);
|
|
522
|
+
function closeDrawer(_) {
|
|
523
|
+
checked.value = false;
|
|
524
|
+
}
|
|
525
|
+
return (_ctx, _cache) => {
|
|
526
|
+
return openBlock(), createElementBlock(Fragment, null, [withDirectives(createElementVNode("input", {
|
|
527
|
+
id: "my-drawer-4",
|
|
528
|
+
type: "checkbox",
|
|
529
|
+
class: "drawer-toggle",
|
|
530
|
+
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => isRef(checked) ? checked.value = $event : checked = $event)
|
|
531
|
+
}, null, 512), [[vModelCheckbox, unref(checked)]]), createElementVNode("div", _hoisted_1$24, [_cache[7] || (_cache[7] = createElementVNode("label", {
|
|
532
|
+
for: "my-drawer-4",
|
|
533
|
+
class: "drawer-overlay"
|
|
534
|
+
}, null, -1)), createElementVNode("ul", _hoisted_2$21, [
|
|
535
|
+
createElementVNode("div", _hoisted_3$21, [
|
|
536
|
+
_cache[1] || (_cache[1] = createElementVNode("div", { class: "avatar placeholder" }, [createElementVNode("div", { class: "bg-neutral-focus text-neutral-content w-10 h-10 rounded-full" }, [createElementVNode("span", null, "U")])], -1)),
|
|
537
|
+
createElementVNode("label", _hoisted_4$18, toDisplayString(unref(userSession).currentSession?.user?.username), 1),
|
|
538
|
+
_cache[2] || (_cache[2] = createElementVNode("div", { class: "grow" }, null, -1)),
|
|
539
|
+
_cache[3] || (_cache[3] = createElementVNode("label", {
|
|
540
|
+
for: "my-drawer-4",
|
|
541
|
+
class: "btn-square btn btn-outline btn-sm"
|
|
542
|
+
}, " X ", -1))
|
|
543
|
+
]),
|
|
544
|
+
createElementVNode("li", { onClick: closeDrawer }, [createVNode(AppLink_default, { to: "/user/profile" }, {
|
|
545
|
+
default: withCtx(() => [..._cache[4] || (_cache[4] = [createTextVNode("My User Profile", -1)])]),
|
|
546
|
+
_: 1
|
|
547
|
+
})]),
|
|
548
|
+
_cache[6] || (_cache[6] = createElementVNode("div", { class: "divider" }, null, -1)),
|
|
549
|
+
createElementVNode("li", { onClick: closeDrawer }, [createVNode(AppLink_default, { to: logoutLink.value }, {
|
|
550
|
+
default: withCtx(() => [..._cache[5] || (_cache[5] = [createTextVNode("Logout", -1)])]),
|
|
551
|
+
_: 1
|
|
552
|
+
}, 8, ["to"])])
|
|
553
|
+
])])], 64);
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
});
|
|
557
|
+
var RightSidebar_default = _sfc_main$27;
|
|
558
|
+
|
|
559
|
+
//#endregion
|
|
560
|
+
//#region src/composables/useBuildTag.ts
|
|
561
|
+
function useBuildTag() {
|
|
562
|
+
return readonly({ build_tag: import.meta.env.VITE_BUILD_TAG });
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
//#endregion
|
|
566
|
+
//#region src/components/Sidebar.vue
|
|
567
|
+
const _hoisted_1$23 = {
|
|
568
|
+
class: "drawer-side z-50",
|
|
569
|
+
style: {
|
|
570
|
+
"scroll-behavior": "smooth",
|
|
571
|
+
"scroll-padding-top": "5rem"
|
|
572
|
+
},
|
|
573
|
+
ref: "drawersidebar"
|
|
574
|
+
};
|
|
575
|
+
const _hoisted_2$20 = { class: "w-80 bg-base-200 h-full flex flex-col" };
|
|
576
|
+
const _hoisted_3$20 = { class: "flex-1 overflow-y-auto overflow-x-hidden min-h-0" };
|
|
577
|
+
const _hoisted_4$17 = { class: "menu p-3 w-full text-base-content" };
|
|
578
|
+
const _hoisted_5$14 = { class: "flex" };
|
|
579
|
+
const _hoisted_6$12 = { class: "font-title inline-flex text-2xl text-primary transition-all duration-200" };
|
|
580
|
+
const _hoisted_7$10 = ["src"];
|
|
581
|
+
const _hoisted_8$10 = {
|
|
582
|
+
key: 0,
|
|
583
|
+
class: "w-full"
|
|
584
|
+
};
|
|
585
|
+
const _hoisted_9$9 = { class: "menu-title" };
|
|
586
|
+
const _hoisted_10$6 = { class: "flex flex-col items-center justify-center w-full h-16" };
|
|
587
|
+
const _hoisted_11$6 = { class: "text-xs text-neutral-500" };
|
|
588
|
+
const _sfc_main$26 = /* @__PURE__ */ defineComponent({
|
|
589
|
+
__name: "Sidebar",
|
|
590
|
+
props: { logoSrc: {} },
|
|
591
|
+
setup(__props) {
|
|
592
|
+
const user = useUserSessionStore();
|
|
593
|
+
const pinnedPresets = useInjectedPinnedPresets();
|
|
594
|
+
const router = useRouter();
|
|
595
|
+
const tag = useBuildTag();
|
|
596
|
+
const close_button = ref(null);
|
|
597
|
+
const imageLoadFailed = ref(false);
|
|
598
|
+
const sidebarSections = computed(() => {
|
|
599
|
+
const allRoutes = router.getRoutes();
|
|
600
|
+
let sections = {};
|
|
601
|
+
allRoutes.forEach((route) => {
|
|
602
|
+
const meta = route.meta;
|
|
603
|
+
if (meta.side_bar?.section) {
|
|
604
|
+
const side_bar = meta.side_bar;
|
|
605
|
+
const section = meta.side_bar.section;
|
|
606
|
+
const userType = user.currentSession?.user.user_type;
|
|
607
|
+
if (!userType || !side_bar.visible_to?.includes(userType)) return;
|
|
608
|
+
if (!sections[section]) sections[section] = [];
|
|
609
|
+
sections[section].push(route);
|
|
610
|
+
}
|
|
611
|
+
});
|
|
612
|
+
sections = Object.keys(sections).sort().reduce((obj, key) => {
|
|
613
|
+
obj[key] = sections[key] || [];
|
|
614
|
+
return obj;
|
|
615
|
+
}, {});
|
|
616
|
+
return sections;
|
|
617
|
+
});
|
|
618
|
+
function capitalizeSection(section) {
|
|
619
|
+
return section.trim().toUpperCase();
|
|
620
|
+
}
|
|
621
|
+
function closeDrawer(_) {
|
|
622
|
+
close_button.value?.click();
|
|
623
|
+
}
|
|
624
|
+
function getRouteLink(route) {
|
|
625
|
+
return route.path;
|
|
626
|
+
}
|
|
627
|
+
return (_ctx, _cache) => {
|
|
628
|
+
const _component_router_link = resolveComponent("router-link");
|
|
629
|
+
return openBlock(), createElementBlock("div", _hoisted_1$23, [_cache[3] || (_cache[3] = createElementVNode("label", {
|
|
630
|
+
for: "drawer",
|
|
631
|
+
class: "drawer-overlay"
|
|
632
|
+
}, null, -1)), createElementVNode("aside", _hoisted_2$20, [createElementVNode("div", _hoisted_3$20, [createElementVNode("ul", _hoisted_4$17, [
|
|
633
|
+
createElementVNode("div", _hoisted_5$14, [
|
|
634
|
+
createElementVNode("div", _hoisted_6$12, [renderSlot(_ctx.$slots, "logo", {}, () => [!__props.logoSrc || imageLoadFailed.value ? (openBlock(), createBlock(LogoPlaceholder_default, {
|
|
635
|
+
key: 0,
|
|
636
|
+
size: "sm"
|
|
637
|
+
})) : (openBlock(), createElementBlock("img", {
|
|
638
|
+
key: 1,
|
|
639
|
+
src: __props.logoSrc,
|
|
640
|
+
alt: "logo",
|
|
641
|
+
class: "h-12",
|
|
642
|
+
onError: _cache[0] || (_cache[0] = ($event) => imageLoadFailed.value = true)
|
|
643
|
+
}, null, 40, _hoisted_7$10))])]),
|
|
644
|
+
_cache[1] || (_cache[1] = createElementVNode("div", { class: "grow" }, null, -1)),
|
|
645
|
+
createElementVNode("label", {
|
|
646
|
+
for: "drawer",
|
|
647
|
+
class: "btn-square btn btn-outline btn-sm",
|
|
648
|
+
ref_key: "close_button",
|
|
649
|
+
ref: close_button
|
|
650
|
+
}, " X ", 512)
|
|
651
|
+
]),
|
|
652
|
+
createCommentVNode(" Favorites section (pinned presets) at top "),
|
|
653
|
+
unref(pinnedPresets).pinned.value.length > 0 ? (openBlock(), createElementBlock("li", _hoisted_8$10, [_cache[2] || (_cache[2] = createElementVNode("div", { class: "menu-title" }, [createElementVNode("span", null, "FAVORITES")], -1)), (openBlock(true), createElementBlock(Fragment, null, renderList(unref(pinnedPresets).pinned.value, (preset) => {
|
|
654
|
+
return openBlock(), createBlock(_component_router_link, {
|
|
655
|
+
key: preset.id,
|
|
656
|
+
to: unref(pinnedPresets).getPresetLink(preset),
|
|
657
|
+
class: "whitespace-nowrap block w-full pl-6",
|
|
658
|
+
onClick: closeDrawer
|
|
659
|
+
}, {
|
|
660
|
+
default: withCtx(() => [createTextVNode(toDisplayString(preset.name), 1)]),
|
|
661
|
+
_: 2
|
|
662
|
+
}, 1032, ["to"]);
|
|
663
|
+
}), 128))])) : createCommentVNode("v-if", true),
|
|
664
|
+
(openBlock(true), createElementBlock(Fragment, null, renderList(sidebarSections.value, (routes, section) => {
|
|
665
|
+
return openBlock(), createElementBlock("li", {
|
|
666
|
+
key: section,
|
|
667
|
+
class: "w-full"
|
|
668
|
+
}, [createElementVNode("div", _hoisted_9$9, [createElementVNode("span", null, toDisplayString(capitalizeSection(section)), 1)]), (openBlock(true), createElementBlock(Fragment, null, renderList(routes, (route) => {
|
|
669
|
+
return openBlock(), createBlock(AppLink_default, {
|
|
670
|
+
key: route.path,
|
|
671
|
+
to: getRouteLink(route),
|
|
672
|
+
class: "whitespace-nowrap block w-full pl-6",
|
|
673
|
+
onClick: closeDrawer
|
|
674
|
+
}, {
|
|
675
|
+
default: withCtx(() => [createTextVNode(toDisplayString(route.meta?.title || route.name), 1)]),
|
|
676
|
+
_: 2
|
|
677
|
+
}, 1032, ["to"]);
|
|
678
|
+
}), 128))]);
|
|
679
|
+
}), 128))
|
|
680
|
+
])]), createElementVNode("div", _hoisted_10$6, [createElementVNode("div", _hoisted_11$6, "Version: " + toDisplayString(unref(tag).build_tag), 1)])])], 512);
|
|
681
|
+
};
|
|
682
|
+
}
|
|
683
|
+
});
|
|
684
|
+
var Sidebar_default = _sfc_main$26;
|
|
685
|
+
|
|
686
|
+
//#endregion
|
|
687
|
+
//#region src/composables/useEmailVerificationGuard.ts
|
|
688
|
+
/**
|
|
689
|
+
* Composable for email verification checks in soft/strict mode.
|
|
690
|
+
* Use to restrict features or show UI based on verification status.
|
|
691
|
+
*/
|
|
692
|
+
function useEmailVerificationGuard() {
|
|
693
|
+
const { emailVerificationMode } = useEnv();
|
|
694
|
+
const session = useUserSessionStore();
|
|
695
|
+
const requiresVerification = computed(() => emailVerificationMode === "soft" || emailVerificationMode === "strict");
|
|
696
|
+
const isVerified = computed(() => session.userSession?.user.email_verified ?? true);
|
|
697
|
+
return {
|
|
698
|
+
requiresVerification,
|
|
699
|
+
isVerified,
|
|
700
|
+
showVerificationPrompt: computed(() => requiresVerification.value && !isVerified.value && !!session.userSession),
|
|
701
|
+
emailVerificationMode
|
|
702
|
+
};
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
//#endregion
|
|
706
|
+
//#region src/components/UnverifiedEmailBanner.vue
|
|
707
|
+
const _hoisted_1$22 = {
|
|
708
|
+
key: 0,
|
|
709
|
+
class: "bg-warning border border-warning text-warning-content px-4 py-2 flex items-center justify-between gap-4"
|
|
710
|
+
};
|
|
711
|
+
const _hoisted_2$19 = { class: "text-sm" };
|
|
712
|
+
const _hoisted_3$19 = ["disabled"];
|
|
713
|
+
const _sfc_main$25 = /* @__PURE__ */ defineComponent({
|
|
714
|
+
__name: "UnverifiedEmailBanner",
|
|
715
|
+
setup(__props) {
|
|
716
|
+
const { showVerificationPrompt } = useEmailVerificationGuard();
|
|
717
|
+
const session = useUserSessionStore();
|
|
718
|
+
const resendLoading = ref(false);
|
|
719
|
+
const { mutate: resendMutate } = useMutation((api, _input) => {
|
|
720
|
+
const verifyEmail = api.verifyEmail;
|
|
721
|
+
if (!verifyEmail) throw new Error("Email verification is not configured");
|
|
722
|
+
return verifyEmail.resendVerificationEmail();
|
|
723
|
+
}, { skipAuthCheck: false });
|
|
724
|
+
const resendVerification = async () => {
|
|
725
|
+
try {
|
|
726
|
+
resendLoading.value = true;
|
|
727
|
+
if ((await resendMutate(void 0))?.ok) {
|
|
728
|
+
toast.success("Verification email sent. Please check your inbox.");
|
|
729
|
+
await session.refreshToken();
|
|
730
|
+
} else toast.error("Failed to resend verification email.");
|
|
731
|
+
} catch (error) {
|
|
732
|
+
toast.error(error instanceof Error ? error.message : "Failed to resend");
|
|
733
|
+
} finally {
|
|
734
|
+
resendLoading.value = false;
|
|
735
|
+
}
|
|
736
|
+
};
|
|
737
|
+
return (_ctx, _cache) => {
|
|
738
|
+
return unref(showVerificationPrompt) ? (openBlock(), createElementBlock("div", _hoisted_1$22, [createElementVNode("p", _hoisted_2$19, [
|
|
739
|
+
_cache[0] || (_cache[0] = createTextVNode(" Please verify your email. Check your inbox or ", -1)),
|
|
740
|
+
createElementVNode("button", {
|
|
741
|
+
type: "button",
|
|
742
|
+
class: "link link-hover font-medium underline",
|
|
743
|
+
disabled: resendLoading.value,
|
|
744
|
+
onClick: resendVerification
|
|
745
|
+
}, toDisplayString(resendLoading.value ? "Sending..." : "resend verification email"), 9, _hoisted_3$19),
|
|
746
|
+
_cache[1] || (_cache[1] = createTextVNode(". ", -1))
|
|
747
|
+
])])) : createCommentVNode("v-if", true);
|
|
748
|
+
};
|
|
749
|
+
}
|
|
750
|
+
});
|
|
751
|
+
var UnverifiedEmailBanner_default = _sfc_main$25;
|
|
752
|
+
|
|
753
|
+
//#endregion
|
|
754
|
+
//#region src/layouts/Admin.vue
|
|
755
|
+
const _hoisted_1$21 = { class: "drawer drawer-end" };
|
|
756
|
+
const _hoisted_2$18 = { class: "drawer h-[calc(100vh_-_64px_-_64px)] bg-base-100" };
|
|
757
|
+
const _hoisted_3$18 = { class: "drawer-content" };
|
|
758
|
+
const _hoisted_4$16 = { class: "pr-1 pl-1 md:pr-4 md:pl-4" };
|
|
759
|
+
const _sfc_main$24 = /* @__PURE__ */ defineComponent({
|
|
760
|
+
__name: "Admin",
|
|
761
|
+
props: {
|
|
762
|
+
logoSrc: {},
|
|
763
|
+
navbarLogoSrc: {}
|
|
764
|
+
},
|
|
765
|
+
setup(__props) {
|
|
766
|
+
return (_ctx, _cache) => {
|
|
767
|
+
return openBlock(), createElementBlock(Fragment, null, [createElementVNode("div", _hoisted_1$21, [createVNode(RightSidebar_default)]), createElementVNode("div", _hoisted_2$18, [
|
|
768
|
+
_cache[0] || (_cache[0] = createElementVNode("input", {
|
|
769
|
+
id: "my-drawer-4",
|
|
770
|
+
type: "checkbox",
|
|
771
|
+
class: "drawer-toggle"
|
|
772
|
+
}, null, -1)),
|
|
773
|
+
createElementVNode("div", _hoisted_3$18, [createVNode(Navbar_default, { logoSrc: __props.navbarLogoSrc }, null, 8, ["logoSrc"]), createElementVNode("div", _hoisted_4$16, [createVNode(unref(RouterView))])]),
|
|
774
|
+
createVNode(Sidebar_default, { logoSrc: __props.logoSrc }, createSlots({ _: 2 }, [_ctx.$slots.sidebarLogo ? {
|
|
775
|
+
name: "logo",
|
|
776
|
+
fn: withCtx(() => [renderSlot(_ctx.$slots, "sidebarLogo")]),
|
|
777
|
+
key: "0"
|
|
778
|
+
} : void 0]), 1032, ["logoSrc"])
|
|
779
|
+
])], 64);
|
|
780
|
+
};
|
|
781
|
+
}
|
|
782
|
+
});
|
|
783
|
+
var Admin_default = _sfc_main$24;
|
|
784
|
+
|
|
785
|
+
//#endregion
|
|
786
|
+
//#region src/layouts/Auth.vue
|
|
787
|
+
const _hoisted_1$20 = { class: "m-2 sm:m-4" };
|
|
788
|
+
const _hoisted_2$17 = {
|
|
789
|
+
key: 0,
|
|
790
|
+
class: "flex justify-center mb-2"
|
|
791
|
+
};
|
|
792
|
+
const _hoisted_3$17 = { class: "flex flex-wrap gap-4 text-sm" };
|
|
793
|
+
const _hoisted_4$15 = { class: "flex justify-center mb-6" };
|
|
794
|
+
const _hoisted_5$13 = ["src"];
|
|
795
|
+
const _hoisted_6$11 = { class: "min-h-screen bg-base-100 flex flex-col" };
|
|
796
|
+
const DEFAULT_SIGNUP_CONSENT_BEFORE = "By signing up you agree to these terms:";
|
|
797
|
+
const DEFAULT_SIGNUP_CONSENT_AFTER = "After you click Sign Up, we'll show you each document to review and accept.";
|
|
798
|
+
const _sfc_main$23 = /* @__PURE__ */ defineComponent({
|
|
799
|
+
__name: "Auth",
|
|
800
|
+
props: {
|
|
801
|
+
logoSrc: {},
|
|
802
|
+
backLinks: {},
|
|
803
|
+
signupConsentBeforeText: {},
|
|
804
|
+
signupConsentAfterText: {}
|
|
805
|
+
},
|
|
806
|
+
setup(__props) {
|
|
807
|
+
const props = __props;
|
|
808
|
+
const route = useRoute();
|
|
809
|
+
const imageLoadFailed = ref(false);
|
|
810
|
+
const backLinks = computed(() => {
|
|
811
|
+
const fromQuery = getBackLinkFromRoute(route);
|
|
812
|
+
if (fromQuery) return [fromQuery];
|
|
813
|
+
const fromProps = props.backLinks;
|
|
814
|
+
return !fromProps ? [] : Array.isArray(fromProps) ? fromProps : [fromProps];
|
|
815
|
+
});
|
|
816
|
+
const hasBackLinks = computed(() => backLinks.value.length > 0);
|
|
817
|
+
provide("signupConsentBeforeText", props.signupConsentBeforeText ?? DEFAULT_SIGNUP_CONSENT_BEFORE);
|
|
818
|
+
provide("signupConsentAfterText", props.signupConsentAfterText ?? DEFAULT_SIGNUP_CONSENT_AFTER);
|
|
819
|
+
return (_ctx, _cache) => {
|
|
820
|
+
return openBlock(), createElementBlock("div", _hoisted_1$20, [
|
|
821
|
+
hasBackLinks.value ? (openBlock(), createElementBlock("div", _hoisted_2$17, [createElementVNode("nav", _hoisted_3$17, [(openBlock(true), createElementBlock(Fragment, null, renderList(backLinks.value, (link, i) => {
|
|
822
|
+
return openBlock(), createBlock(AppLink_default, {
|
|
823
|
+
key: i,
|
|
824
|
+
to: link.to,
|
|
825
|
+
class: "link link-hover"
|
|
826
|
+
}, {
|
|
827
|
+
default: withCtx(() => [createTextVNode(toDisplayString(link.label ?? "Back to site"), 1)]),
|
|
828
|
+
_: 2
|
|
829
|
+
}, 1032, ["to"]);
|
|
830
|
+
}), 128))])])) : createCommentVNode("v-if", true),
|
|
831
|
+
createElementVNode("div", _hoisted_4$15, [renderSlot(_ctx.$slots, "logo", {}, () => [!__props.logoSrc || imageLoadFailed.value ? (openBlock(), createBlock(LogoPlaceholder_default, {
|
|
832
|
+
key: 0,
|
|
833
|
+
size: "md"
|
|
834
|
+
})) : (openBlock(), createElementBlock("img", {
|
|
835
|
+
key: 1,
|
|
836
|
+
src: __props.logoSrc,
|
|
837
|
+
alt: "logo",
|
|
838
|
+
class: "h-24",
|
|
839
|
+
onError: _cache[0] || (_cache[0] = ($event) => imageLoadFailed.value = true)
|
|
840
|
+
}, null, 40, _hoisted_5$13))])]),
|
|
841
|
+
createElementVNode("div", _hoisted_6$11, [createVNode(unref(RouterView))])
|
|
842
|
+
]);
|
|
843
|
+
};
|
|
844
|
+
}
|
|
845
|
+
});
|
|
846
|
+
var Auth_default = _sfc_main$23;
|
|
847
|
+
|
|
848
|
+
//#endregion
|
|
849
|
+
//#region src/layouts/Default.vue
|
|
850
|
+
const _hoisted_1$19 = { class: "m-4" };
|
|
851
|
+
const _sfc_main$22 = /* @__PURE__ */ defineComponent({
|
|
852
|
+
__name: "Default",
|
|
853
|
+
setup(__props) {
|
|
854
|
+
return (_ctx, _cache) => {
|
|
855
|
+
return openBlock(), createElementBlock("div", _hoisted_1$19, [createVNode(AppLink_default, {
|
|
856
|
+
to: "/auth/login",
|
|
857
|
+
"aria-current": "page",
|
|
858
|
+
"aria-label": "Homepage",
|
|
859
|
+
class: "flex-0 btn px-2 btn-accent"
|
|
860
|
+
}, {
|
|
861
|
+
default: withCtx(() => [..._cache[0] || (_cache[0] = [createElementVNode("div", { class: "text-lg md:text-3xl" }, [createElementVNode("span", null, "Login")], -1)])]),
|
|
862
|
+
_: 1
|
|
863
|
+
}), createVNode(unref(RouterView))]);
|
|
864
|
+
};
|
|
865
|
+
}
|
|
866
|
+
});
|
|
867
|
+
var Default_default = _sfc_main$22;
|
|
868
|
+
|
|
869
|
+
//#endregion
|
|
870
|
+
//#region src/layouts/InApp.vue
|
|
871
|
+
const _hoisted_1$18 = { class: "drawer drawer-end" };
|
|
872
|
+
const _hoisted_2$16 = { class: "drawer h-[calc(100vh_)]" };
|
|
873
|
+
const _hoisted_3$16 = { class: "drawer-content flex flex-col" };
|
|
874
|
+
const _hoisted_4$14 = {
|
|
875
|
+
key: 0,
|
|
876
|
+
class: "z-20"
|
|
877
|
+
};
|
|
878
|
+
const _hoisted_5$12 = { class: "flex-1 px-3 sm:px-4 md:px-6 pb-4" };
|
|
879
|
+
const _sfc_main$21 = /* @__PURE__ */ defineComponent({
|
|
880
|
+
__name: "InApp",
|
|
881
|
+
props: {
|
|
882
|
+
logoSrc: {},
|
|
883
|
+
navbarLogoSrc: {}
|
|
884
|
+
},
|
|
885
|
+
setup(__props) {
|
|
886
|
+
const route = useRoute();
|
|
887
|
+
const user = useUserSessionStore();
|
|
888
|
+
provide(PINNED_PRESETS_KEY, usePinnedPresets());
|
|
889
|
+
const componentBreadcrumbs = ref(null);
|
|
890
|
+
const breadcrumbSegments = ref(/* @__PURE__ */ new Map());
|
|
891
|
+
provide(BREADCRUMB_KEY, {
|
|
892
|
+
setBreadcrumbs: (breadcrumbs) => {
|
|
893
|
+
componentBreadcrumbs.value = breadcrumbs;
|
|
894
|
+
},
|
|
895
|
+
setBreadcrumbSegment: (componentId, breadcrumbs) => {
|
|
896
|
+
if (breadcrumbs === null) breadcrumbSegments.value.delete(componentId);
|
|
897
|
+
else breadcrumbSegments.value.set(componentId, breadcrumbs);
|
|
898
|
+
}
|
|
899
|
+
});
|
|
900
|
+
const shouldShowAppHeader = computed(() => {
|
|
901
|
+
return currentSectionTabs.value.length > 0;
|
|
902
|
+
});
|
|
903
|
+
const currentBreadcrumbs = computed(() => {
|
|
904
|
+
if (breadcrumbSegments.value.size > 0) {
|
|
905
|
+
const merged = [];
|
|
906
|
+
for (const segment of breadcrumbSegments.value.values()) merged.push(...segment);
|
|
907
|
+
return merged;
|
|
908
|
+
}
|
|
909
|
+
if (componentBreadcrumbs.value !== null) return componentBreadcrumbs.value;
|
|
910
|
+
if (typeof route.meta.getBreadcrumbs === "function") return route.meta.getBreadcrumbs(route);
|
|
911
|
+
if (route.meta.breadcrumbs) return route.meta.breadcrumbs;
|
|
912
|
+
const breadcrumbs = [];
|
|
913
|
+
breadcrumbs.push({
|
|
914
|
+
label: "Home",
|
|
915
|
+
to: { name: "Home" }
|
|
916
|
+
});
|
|
917
|
+
if (route.meta.section) breadcrumbs.push({
|
|
918
|
+
label: route.meta.section,
|
|
919
|
+
to: { name: route.meta.sectionRoute }
|
|
920
|
+
});
|
|
921
|
+
if (route.meta.title && route.name !== "Home") breadcrumbs.push({
|
|
922
|
+
label: route.meta.title,
|
|
923
|
+
to: route
|
|
924
|
+
});
|
|
925
|
+
return breadcrumbs;
|
|
926
|
+
});
|
|
927
|
+
const currentSectionTabs = computed(() => {
|
|
928
|
+
if (route.meta.sectionTabs) {
|
|
929
|
+
const allTabs = route.meta.sectionTabs;
|
|
930
|
+
const userType = user.currentSession?.user.user_type;
|
|
931
|
+
return allTabs.filter((tab) => {
|
|
932
|
+
if (tab.visible_to && userType) return tab.visible_to.includes(userType);
|
|
933
|
+
return true;
|
|
934
|
+
});
|
|
935
|
+
}
|
|
936
|
+
return [];
|
|
937
|
+
});
|
|
938
|
+
const currentActiveTab = computed(() => {
|
|
939
|
+
return route.meta.currentTab || "";
|
|
940
|
+
});
|
|
941
|
+
return (_ctx, _cache) => {
|
|
942
|
+
return openBlock(), createElementBlock(Fragment, null, [createCommentVNode(" Right sidebar drawer "), createElementVNode("div", _hoisted_1$18, [
|
|
943
|
+
createVNode(RightSidebar_default),
|
|
944
|
+
createCommentVNode(" Left sidebar drawer "),
|
|
945
|
+
createElementVNode("div", _hoisted_2$16, [
|
|
946
|
+
_cache[0] || (_cache[0] = createElementVNode("input", {
|
|
947
|
+
id: "drawer",
|
|
948
|
+
type: "checkbox",
|
|
949
|
+
class: "drawer-toggle"
|
|
950
|
+
}, null, -1)),
|
|
951
|
+
createElementVNode("div", _hoisted_3$16, [
|
|
952
|
+
createCommentVNode(" Fixed navbar at top with breadcrumbs "),
|
|
953
|
+
createVNode(Navbar_default, {
|
|
954
|
+
class: "sticky top-0 z-30",
|
|
955
|
+
breadcrumbs: currentBreadcrumbs.value,
|
|
956
|
+
logoSrc: __props.navbarLogoSrc
|
|
957
|
+
}, null, 8, ["breadcrumbs", "logoSrc"]),
|
|
958
|
+
createVNode(UnverifiedEmailBanner_default),
|
|
959
|
+
createCommentVNode(" Unified navigation with AppHeader (only shown when needed) "),
|
|
960
|
+
shouldShowAppHeader.value ? (openBlock(), createElementBlock("div", _hoisted_4$14, [createVNode(AppHeader_default, {
|
|
961
|
+
tabs: currentSectionTabs.value,
|
|
962
|
+
"active-tab": currentActiveTab.value
|
|
963
|
+
}, null, 8, ["tabs", "active-tab"])])) : createCommentVNode("v-if", true),
|
|
964
|
+
createCommentVNode(" Main content "),
|
|
965
|
+
createElementVNode("div", _hoisted_5$12, [createVNode(unref(RouterView))])
|
|
966
|
+
]),
|
|
967
|
+
createCommentVNode(" Left sidebar "),
|
|
968
|
+
createVNode(Sidebar_default, { logoSrc: __props.logoSrc }, createSlots({ _: 2 }, [_ctx.$slots.sidebarLogo ? {
|
|
969
|
+
name: "logo",
|
|
970
|
+
fn: withCtx(() => [renderSlot(_ctx.$slots, "sidebarLogo")]),
|
|
971
|
+
key: "0"
|
|
972
|
+
} : void 0]), 1032, ["logoSrc"])
|
|
973
|
+
])
|
|
974
|
+
])], 2112);
|
|
975
|
+
};
|
|
976
|
+
}
|
|
977
|
+
});
|
|
978
|
+
var InApp_default = _sfc_main$21;
|
|
979
|
+
|
|
980
|
+
//#endregion
|
|
981
|
+
//#region src/components/ui/FieldDisplay.vue
|
|
982
|
+
const _hoisted_1$17 = { class: "label" };
|
|
983
|
+
const _hoisted_2$15 = { class: "label-text font-medium" };
|
|
984
|
+
const _hoisted_3$15 = { class: "text-base-content" };
|
|
985
|
+
const _sfc_main$20 = /* @__PURE__ */ defineComponent({
|
|
986
|
+
__name: "FieldDisplay",
|
|
987
|
+
props: {
|
|
988
|
+
label: {},
|
|
989
|
+
value: {},
|
|
990
|
+
fullWidth: { type: Boolean }
|
|
991
|
+
},
|
|
992
|
+
setup(__props) {
|
|
993
|
+
return (_ctx, _cache) => {
|
|
994
|
+
return openBlock(), createElementBlock("div", { class: normalizeClass(["form-control", { "md:col-span-2": __props.fullWidth }]) }, [createElementVNode("label", _hoisted_1$17, [createElementVNode("span", _hoisted_2$15, toDisplayString(__props.label), 1)]), createElementVNode("div", _hoisted_3$15, toDisplayString(__props.value ?? "-"), 1)], 2);
|
|
995
|
+
};
|
|
996
|
+
}
|
|
997
|
+
});
|
|
998
|
+
var FieldDisplay_default = _sfc_main$20;
|
|
999
|
+
|
|
1000
|
+
//#endregion
|
|
1001
|
+
//#region src/components/ui/FieldGroup.vue
|
|
1002
|
+
const _hoisted_1$16 = { class: "card bg-base-100 shadow-sm" };
|
|
1003
|
+
const _hoisted_2$14 = { class: "card-body" };
|
|
1004
|
+
const _hoisted_3$14 = { class: "card-title text-lg mb-4" };
|
|
1005
|
+
const _hoisted_4$13 = { class: "grid grid-cols-1 md:grid-cols-2 gap-4" };
|
|
1006
|
+
const _sfc_main$19 = /* @__PURE__ */ defineComponent({
|
|
1007
|
+
__name: "FieldGroup",
|
|
1008
|
+
props: { title: {} },
|
|
1009
|
+
setup(__props) {
|
|
1010
|
+
return (_ctx, _cache) => {
|
|
1011
|
+
return openBlock(), createElementBlock("div", _hoisted_1$16, [createElementVNode("div", _hoisted_2$14, [createElementVNode("h2", _hoisted_3$14, toDisplayString(__props.title), 1), createElementVNode("div", _hoisted_4$13, [renderSlot(_ctx.$slots, "default")])])]);
|
|
1012
|
+
};
|
|
1013
|
+
}
|
|
1014
|
+
});
|
|
1015
|
+
var FieldGroup_default = _sfc_main$19;
|
|
1016
|
+
|
|
1017
|
+
//#endregion
|
|
1018
|
+
//#region src/components/ui/FileManager.vue
|
|
1019
|
+
const _hoisted_1$15 = { class: "w-full px-2 sm:px-0" };
|
|
1020
|
+
const _hoisted_2$13 = { class: "mb-4" };
|
|
1021
|
+
const _hoisted_3$13 = { class: "flex flex-col sm:flex-row sm:justify-between sm:items-center gap-3 mb-3" };
|
|
1022
|
+
const _hoisted_4$12 = { class: "text-lg font-medium" };
|
|
1023
|
+
const _hoisted_5$11 = { class: "flex gap-2 sm:hidden" };
|
|
1024
|
+
const _hoisted_6$10 = ["disabled"];
|
|
1025
|
+
const _hoisted_7$9 = { class: "breadcrumbs text-xs sm:text-sm overflow-x-auto -mx-2 px-2" };
|
|
1026
|
+
const _hoisted_8$9 = { class: "min-w-max" };
|
|
1027
|
+
const _hoisted_9$8 = ["onClick", "title"];
|
|
1028
|
+
const _hoisted_10$5 = ["accept"];
|
|
1029
|
+
const _hoisted_11$5 = { class: "flex flex-col items-center justify-center py-4" };
|
|
1030
|
+
const _hoisted_12$5 = { class: "text-lg font-medium" };
|
|
1031
|
+
const _hoisted_13$4 = { class: "text-sm text-base-content/70 mt-1" };
|
|
1032
|
+
const _hoisted_14$3 = {
|
|
1033
|
+
key: 0,
|
|
1034
|
+
class: "text-xs text-base-content/50 mt-3"
|
|
1035
|
+
};
|
|
1036
|
+
const _hoisted_15$2 = {
|
|
1037
|
+
key: 0,
|
|
1038
|
+
class: "mb-4"
|
|
1039
|
+
};
|
|
1040
|
+
const _hoisted_16$2 = { class: "space-y-3" };
|
|
1041
|
+
const _hoisted_17$1 = { class: "flex justify-between items-start mb-2" };
|
|
1042
|
+
const _hoisted_18$1 = { class: "flex-1" };
|
|
1043
|
+
const _hoisted_19$1 = { class: "flex items-center gap-2" };
|
|
1044
|
+
const _hoisted_20$1 = {
|
|
1045
|
+
key: 0,
|
|
1046
|
+
class: "loading loading-spinner loading-xs text-primary"
|
|
1047
|
+
};
|
|
1048
|
+
const _hoisted_21$1 = {
|
|
1049
|
+
key: 1,
|
|
1050
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1051
|
+
class: "h-4 w-4 text-success",
|
|
1052
|
+
fill: "none",
|
|
1053
|
+
viewBox: "0 0 24 24",
|
|
1054
|
+
stroke: "currentColor"
|
|
1055
|
+
};
|
|
1056
|
+
const _hoisted_22$1 = {
|
|
1057
|
+
key: 2,
|
|
1058
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1059
|
+
class: "h-4 w-4 text-error",
|
|
1060
|
+
fill: "none",
|
|
1061
|
+
viewBox: "0 0 24 24",
|
|
1062
|
+
stroke: "currentColor"
|
|
1063
|
+
};
|
|
1064
|
+
const _hoisted_23$1 = {
|
|
1065
|
+
key: 3,
|
|
1066
|
+
class: "h-4 w-4 rounded-full bg-base-300"
|
|
1067
|
+
};
|
|
1068
|
+
const _hoisted_24$1 = { class: "min-w-0 flex-1" };
|
|
1069
|
+
const _hoisted_25$1 = { class: "font-medium text-sm break-all" };
|
|
1070
|
+
const _hoisted_26$1 = { class: "text-xs text-base-content/70 mt-1 ml-6" };
|
|
1071
|
+
const _hoisted_27$1 = {
|
|
1072
|
+
key: 0,
|
|
1073
|
+
class: "text-xs text-error mt-1 ml-6"
|
|
1074
|
+
};
|
|
1075
|
+
const _hoisted_28$1 = ["onClick"];
|
|
1076
|
+
const _hoisted_29$1 = { key: 0 };
|
|
1077
|
+
const _hoisted_30$1 = { class: "flex justify-between text-xs mb-1" };
|
|
1078
|
+
const _hoisted_31$1 = { key: 0 };
|
|
1079
|
+
const _hoisted_32$1 = ["value"];
|
|
1080
|
+
const _hoisted_33$1 = {
|
|
1081
|
+
key: 1,
|
|
1082
|
+
class: "text-xs text-success mt-1"
|
|
1083
|
+
};
|
|
1084
|
+
const _hoisted_34$1 = {
|
|
1085
|
+
key: 2,
|
|
1086
|
+
class: "text-xs text-error mt-1"
|
|
1087
|
+
};
|
|
1088
|
+
const _hoisted_35$1 = {
|
|
1089
|
+
key: 1,
|
|
1090
|
+
class: "block sm:hidden mb-4"
|
|
1091
|
+
};
|
|
1092
|
+
const _hoisted_36 = ["onClick"];
|
|
1093
|
+
const _hoisted_37 = { class: "card-body py-4" };
|
|
1094
|
+
const _hoisted_38 = { class: "flex items-center gap-3" };
|
|
1095
|
+
const _hoisted_39 = { class: "card-title text-base break-words flex-1" };
|
|
1096
|
+
const _hoisted_40 = {
|
|
1097
|
+
key: 2,
|
|
1098
|
+
class: "block sm:hidden"
|
|
1099
|
+
};
|
|
1100
|
+
const _hoisted_41 = { class: "card-body" };
|
|
1101
|
+
const _hoisted_42 = { class: "flex items-center gap-2 mb-2" };
|
|
1102
|
+
const _hoisted_43 = { class: "card-title text-base break-all" };
|
|
1103
|
+
const _hoisted_44 = { class: "grid grid-cols-2 text-sm mb-3" };
|
|
1104
|
+
const _hoisted_45 = { class: "card-actions justify-between mt-3 gap-2" };
|
|
1105
|
+
const _hoisted_46 = ["onClick"];
|
|
1106
|
+
const _hoisted_47 = ["onClick"];
|
|
1107
|
+
const _hoisted_48 = {
|
|
1108
|
+
key: 3,
|
|
1109
|
+
class: "hidden sm:block overflow-x-auto"
|
|
1110
|
+
};
|
|
1111
|
+
const _hoisted_49 = { class: "table table-zebra w-full" };
|
|
1112
|
+
const _hoisted_50 = ["onClick"];
|
|
1113
|
+
const _hoisted_51 = { class: "flex items-center gap-3" };
|
|
1114
|
+
const _hoisted_52 = { class: "font-medium break-all max-w-[200px] md:max-w-[500px]" };
|
|
1115
|
+
const _hoisted_53 = {
|
|
1116
|
+
key: 0,
|
|
1117
|
+
class: "text-xs text-base-content/60 ml-2"
|
|
1118
|
+
};
|
|
1119
|
+
const _hoisted_54 = { class: "flex items-center gap-3" };
|
|
1120
|
+
const _hoisted_55 = { class: "font-medium break-all max-w-[200px] md:max-w-[500px]" };
|
|
1121
|
+
const _hoisted_56 = { class: "flex gap-2" };
|
|
1122
|
+
const _hoisted_57 = ["onClick"];
|
|
1123
|
+
const _hoisted_58 = ["onClick"];
|
|
1124
|
+
const _hoisted_59 = { class: "text-center py-8" };
|
|
1125
|
+
const _hoisted_60 = { class: "text-base-content/70 mt-2" };
|
|
1126
|
+
const _hoisted_61 = { class: "text-center py-8" };
|
|
1127
|
+
const _hoisted_62 = { class: "text-base-content/70" };
|
|
1128
|
+
const _hoisted_63 = { class: "hidden sm:block text-sm text-base-content/70 mt-2" };
|
|
1129
|
+
const _hoisted_64 = { class: "text-center py-8" };
|
|
1130
|
+
const _hoisted_65 = { class: "text-error" };
|
|
1131
|
+
const _hoisted_66 = { class: "mb-4" };
|
|
1132
|
+
const _hoisted_67 = {
|
|
1133
|
+
key: 0,
|
|
1134
|
+
class: "bg-base-200 rounded-lg p-3 space-y-1 text-sm"
|
|
1135
|
+
};
|
|
1136
|
+
const _hoisted_68 = { class: "flex items-center gap-2" };
|
|
1137
|
+
const _hoisted_69 = { class: "font-medium" };
|
|
1138
|
+
const _hoisted_70 = { class: "text-base-content/70" };
|
|
1139
|
+
const DEFAULT_MAX_FILE_SIZE = 50 * 1024 * 1024;
|
|
1140
|
+
const _sfc_main$18 = /* @__PURE__ */ defineComponent({
|
|
1141
|
+
__name: "FileManager",
|
|
1142
|
+
props: {
|
|
1143
|
+
recordId: {},
|
|
1144
|
+
recordType: {},
|
|
1145
|
+
config: {}
|
|
1146
|
+
},
|
|
1147
|
+
setup(__props) {
|
|
1148
|
+
const props = __props;
|
|
1149
|
+
const config = computed(() => props.config || {});
|
|
1150
|
+
const envConfig = useEnv();
|
|
1151
|
+
const maxFileSize = computed(() => config.value.maxFileSize ?? envConfig.maxAttachmentFileSize ?? DEFAULT_MAX_FILE_SIZE);
|
|
1152
|
+
const route = useRoute();
|
|
1153
|
+
const router = useRouter();
|
|
1154
|
+
const fileInput = ref(null);
|
|
1155
|
+
const isDragging = ref(false);
|
|
1156
|
+
const isUploading = ref(false);
|
|
1157
|
+
const uploadQueue = ref([]);
|
|
1158
|
+
const currentUploadId = ref(null);
|
|
1159
|
+
const attachments = ref([]);
|
|
1160
|
+
const folders = ref([]);
|
|
1161
|
+
const currentFolderId = ref(null);
|
|
1162
|
+
const folderPath = ref([]);
|
|
1163
|
+
const showDeleteModal = ref(false);
|
|
1164
|
+
const showCreateFolderModal = ref(false);
|
|
1165
|
+
const fileToDelete = ref(null);
|
|
1166
|
+
const { mutate: deleteAttachment } = useMutation((api, input) => api.attachments.deleteAttachment(input.id), { invalidate: /^attachments?:/ });
|
|
1167
|
+
const { mutate: createFolderMutation } = useMutation((api, input) => api.attachments.createFolder(input), { invalidate: /^attachments?:/ });
|
|
1168
|
+
const { data: attachmentsData, loading: fetchingAttachments, error: attachmentsError, refetch: refetchAttachments } = useQuery(async (api) => {
|
|
1169
|
+
const filters = {
|
|
1170
|
+
limit: 50,
|
|
1171
|
+
include_folders: true
|
|
1172
|
+
};
|
|
1173
|
+
if (currentFolderId.value === null) filters.folder_id = null;
|
|
1174
|
+
else if (currentFolderId.value) filters.folder_id = currentFolderId.value;
|
|
1175
|
+
return await api.attachments.listAttachments({
|
|
1176
|
+
record_id: props.recordId,
|
|
1177
|
+
record_type: props.recordType,
|
|
1178
|
+
filters
|
|
1179
|
+
});
|
|
1180
|
+
}, { staleTime: 120 * 1e3 });
|
|
1181
|
+
const { data: allFoldersData, refetch: refetchAllFolders } = useQuery(async (api) => {
|
|
1182
|
+
return await api.attachments.listAttachments({
|
|
1183
|
+
record_id: props.recordId,
|
|
1184
|
+
record_type: props.recordType,
|
|
1185
|
+
filters: {
|
|
1186
|
+
limit: 1e3,
|
|
1187
|
+
include_folders: true
|
|
1188
|
+
}
|
|
1189
|
+
});
|
|
1190
|
+
}, {
|
|
1191
|
+
enabled: computed(() => !!currentFolderId.value && folderPath.value.length === 0),
|
|
1192
|
+
watch: [currentFolderId, folderPath],
|
|
1193
|
+
staleTime: 300 * 1e3
|
|
1194
|
+
});
|
|
1195
|
+
const transformAttachments = computed(() => {
|
|
1196
|
+
if (!attachmentsData.value) return [];
|
|
1197
|
+
const files = [];
|
|
1198
|
+
const folderList = [];
|
|
1199
|
+
const folderItems = attachmentsData.value.folders || [];
|
|
1200
|
+
for (const item of folderItems) folderList.push({
|
|
1201
|
+
id: item.id,
|
|
1202
|
+
name: item.original_name,
|
|
1203
|
+
parent_folder_id: item.parent_folder_id ?? null,
|
|
1204
|
+
file_count: item.file_count ?? 0
|
|
1205
|
+
});
|
|
1206
|
+
const fileItems = attachmentsData.value.files || [];
|
|
1207
|
+
for (const item of fileItems) files.push({
|
|
1208
|
+
id: item.id,
|
|
1209
|
+
name: item.original_name,
|
|
1210
|
+
size: parseInt(item.file_size || "0"),
|
|
1211
|
+
type: item.content_type || "",
|
|
1212
|
+
uploadedAt: new Date(item.created_at)
|
|
1213
|
+
});
|
|
1214
|
+
folders.value = folderList;
|
|
1215
|
+
return files;
|
|
1216
|
+
});
|
|
1217
|
+
onMounted(() => {
|
|
1218
|
+
const folderIdFromUrl = route.query.folder_id;
|
|
1219
|
+
if (folderIdFromUrl) {
|
|
1220
|
+
currentFolderId.value = folderIdFromUrl;
|
|
1221
|
+
refetchAllFolders();
|
|
1222
|
+
}
|
|
1223
|
+
});
|
|
1224
|
+
watch(() => route.query.folder_id, (newFolderId) => {
|
|
1225
|
+
const folderId = newFolderId || null;
|
|
1226
|
+
if (folderId !== currentFolderId.value) {
|
|
1227
|
+
currentFolderId.value = folderId;
|
|
1228
|
+
folderPath.value = [];
|
|
1229
|
+
if (folderId) refetchAllFolders();
|
|
1230
|
+
refreshAttachments();
|
|
1231
|
+
}
|
|
1232
|
+
});
|
|
1233
|
+
watch(() => allFoldersData.value?.folders, (allFoldersList) => {
|
|
1234
|
+
if (currentFolderId.value && folderPath.value.length === 0 && allFoldersList) {
|
|
1235
|
+
const allFoldersMap = new Map(allFoldersList.map((f) => [f.id, {
|
|
1236
|
+
id: f.id,
|
|
1237
|
+
name: f.original_name,
|
|
1238
|
+
parent_folder_id: f.parent_folder_id
|
|
1239
|
+
}]));
|
|
1240
|
+
const path = [];
|
|
1241
|
+
let currentFolderIdToFind = currentFolderId.value;
|
|
1242
|
+
const visited = /* @__PURE__ */ new Set();
|
|
1243
|
+
while (currentFolderIdToFind) {
|
|
1244
|
+
if (visited.has(currentFolderIdToFind)) break;
|
|
1245
|
+
visited.add(currentFolderIdToFind);
|
|
1246
|
+
const folder = allFoldersMap.get(currentFolderIdToFind);
|
|
1247
|
+
if (!folder) break;
|
|
1248
|
+
path.unshift({
|
|
1249
|
+
id: folder.id,
|
|
1250
|
+
name: folder.name
|
|
1251
|
+
});
|
|
1252
|
+
if (!folder.parent_folder_id) break;
|
|
1253
|
+
currentFolderIdToFind = folder.parent_folder_id;
|
|
1254
|
+
}
|
|
1255
|
+
folderPath.value = path;
|
|
1256
|
+
}
|
|
1257
|
+
});
|
|
1258
|
+
watch(transformAttachments, (newAttachments) => {
|
|
1259
|
+
attachments.value = newAttachments;
|
|
1260
|
+
}, { immediate: true });
|
|
1261
|
+
const updateUrlFolder = (folderId) => {
|
|
1262
|
+
const query = { ...route.query };
|
|
1263
|
+
if (folderId) query.folder_id = folderId;
|
|
1264
|
+
else delete query.folder_id;
|
|
1265
|
+
router.replace({ query });
|
|
1266
|
+
};
|
|
1267
|
+
const enterFolder = (folderId) => {
|
|
1268
|
+
const folder = folders.value.find((f) => f.id === folderId);
|
|
1269
|
+
if (folder) {
|
|
1270
|
+
folderPath.value.push({
|
|
1271
|
+
id: folder.id,
|
|
1272
|
+
name: folder.name
|
|
1273
|
+
});
|
|
1274
|
+
currentFolderId.value = folderId;
|
|
1275
|
+
updateUrlFolder(folderId);
|
|
1276
|
+
refreshAttachments();
|
|
1277
|
+
}
|
|
1278
|
+
};
|
|
1279
|
+
const navigateToFolder = (folderId) => {
|
|
1280
|
+
if (folderId === null) {
|
|
1281
|
+
folderPath.value = [];
|
|
1282
|
+
currentFolderId.value = null;
|
|
1283
|
+
} else {
|
|
1284
|
+
const index = folderPath.value.findIndex((f) => f.id === folderId);
|
|
1285
|
+
if (index !== -1) {
|
|
1286
|
+
folderPath.value = folderPath.value.slice(0, index + 1);
|
|
1287
|
+
currentFolderId.value = folderId;
|
|
1288
|
+
} else {
|
|
1289
|
+
const folder = folders.value.find((f) => f.id === folderId);
|
|
1290
|
+
if (folder) {
|
|
1291
|
+
folderPath.value = [{
|
|
1292
|
+
id: folder.id,
|
|
1293
|
+
name: folder.name
|
|
1294
|
+
}];
|
|
1295
|
+
currentFolderId.value = folderId;
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
updateUrlFolder(folderId);
|
|
1300
|
+
refreshAttachments();
|
|
1301
|
+
};
|
|
1302
|
+
const refreshAttachments = () => {
|
|
1303
|
+
refetchAttachments();
|
|
1304
|
+
};
|
|
1305
|
+
const openFileSelector = () => {
|
|
1306
|
+
fileInput.value?.click();
|
|
1307
|
+
};
|
|
1308
|
+
const handleFileChange = async (event) => {
|
|
1309
|
+
const target = event.target;
|
|
1310
|
+
const files = target.files;
|
|
1311
|
+
if (files && files.length > 0) {
|
|
1312
|
+
for (let i = 0; i < files.length; i++) {
|
|
1313
|
+
const file = files[i];
|
|
1314
|
+
if (file) {
|
|
1315
|
+
if (file.size > maxFileSize.value) {
|
|
1316
|
+
uploadQueue.value.push({
|
|
1317
|
+
id: crypto.randomUUID(),
|
|
1318
|
+
file,
|
|
1319
|
+
status: "error",
|
|
1320
|
+
progress: 0,
|
|
1321
|
+
errorMessage: `File size (${formatFileSize(file.size)}) exceeds maximum allowed size (${formatFileSize(maxFileSize.value)})`
|
|
1322
|
+
});
|
|
1323
|
+
continue;
|
|
1324
|
+
}
|
|
1325
|
+
uploadQueue.value.push({
|
|
1326
|
+
id: crypto.randomUUID(),
|
|
1327
|
+
file,
|
|
1328
|
+
status: "pending",
|
|
1329
|
+
progress: 0
|
|
1330
|
+
});
|
|
1331
|
+
}
|
|
1332
|
+
}
|
|
1333
|
+
if (!isUploading.value) processUploadQueue();
|
|
1334
|
+
target.value = "";
|
|
1335
|
+
}
|
|
1336
|
+
};
|
|
1337
|
+
const handleFileDrop = async (event) => {
|
|
1338
|
+
isDragging.value = false;
|
|
1339
|
+
const files = event.dataTransfer?.files;
|
|
1340
|
+
if (files && files.length > 0) {
|
|
1341
|
+
for (let i = 0; i < files.length; i++) {
|
|
1342
|
+
const file = files[i];
|
|
1343
|
+
if (file) {
|
|
1344
|
+
if (file.size > maxFileSize.value) {
|
|
1345
|
+
uploadQueue.value.push({
|
|
1346
|
+
id: crypto.randomUUID(),
|
|
1347
|
+
file,
|
|
1348
|
+
status: "error",
|
|
1349
|
+
progress: 0,
|
|
1350
|
+
errorMessage: `File size (${formatFileSize(file.size)}) exceeds maximum allowed size (${formatFileSize(maxFileSize.value)})`
|
|
1351
|
+
});
|
|
1352
|
+
continue;
|
|
1353
|
+
}
|
|
1354
|
+
uploadQueue.value.push({
|
|
1355
|
+
id: crypto.randomUUID(),
|
|
1356
|
+
file,
|
|
1357
|
+
status: "pending",
|
|
1358
|
+
progress: 0
|
|
1359
|
+
});
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
if (!isUploading.value) processUploadQueue();
|
|
1363
|
+
}
|
|
1364
|
+
};
|
|
1365
|
+
const removeFromQueue = (id) => {
|
|
1366
|
+
const index = uploadQueue.value.findIndex((item) => item.id === id);
|
|
1367
|
+
if (index !== -1) uploadQueue.value.splice(index, 1);
|
|
1368
|
+
};
|
|
1369
|
+
const processUploadQueue = async () => {
|
|
1370
|
+
const nextItem = uploadQueue.value.find((item) => item.status === "pending");
|
|
1371
|
+
if (!nextItem) {
|
|
1372
|
+
isUploading.value = false;
|
|
1373
|
+
return;
|
|
1374
|
+
}
|
|
1375
|
+
isUploading.value = true;
|
|
1376
|
+
currentUploadId.value = nextItem.id;
|
|
1377
|
+
nextItem.status = "uploading";
|
|
1378
|
+
await uploadFile(nextItem);
|
|
1379
|
+
if (uploadQueue.value.some((item) => item.status === "pending")) processUploadQueue();
|
|
1380
|
+
else {
|
|
1381
|
+
isUploading.value = false;
|
|
1382
|
+
currentUploadId.value = null;
|
|
1383
|
+
}
|
|
1384
|
+
};
|
|
1385
|
+
const uploadFile = async (item) => {
|
|
1386
|
+
const progressInterval = setInterval(() => {
|
|
1387
|
+
item.progress += Math.random() * 10;
|
|
1388
|
+
item.progress = Math.round(item.progress * 100) / 100;
|
|
1389
|
+
if (item.progress >= 99) item.progress = 99;
|
|
1390
|
+
}, 200);
|
|
1391
|
+
try {
|
|
1392
|
+
const env$1 = useEnv();
|
|
1393
|
+
const userStore = useUserSessionStore();
|
|
1394
|
+
const formData = new FormData();
|
|
1395
|
+
formData.append("file", item.file);
|
|
1396
|
+
formData.append("file_name", item.file.name);
|
|
1397
|
+
formData.append("record_id", props.recordId);
|
|
1398
|
+
formData.append("record_type", props.recordType);
|
|
1399
|
+
if (currentFolderId.value) formData.append("folder_id", currentFolderId.value);
|
|
1400
|
+
const response = await fetch(`${env$1.restApiClient.apiUrl}/attachments/${props.recordType}/${props.recordId}`, {
|
|
1401
|
+
method: "POST",
|
|
1402
|
+
headers: { Authorization: `Bearer ${userStore.accessToken}` },
|
|
1403
|
+
body: formData
|
|
1404
|
+
});
|
|
1405
|
+
if (!response.ok) throw new Error(`Upload failed: ${response.statusText}`);
|
|
1406
|
+
const result = await response.json();
|
|
1407
|
+
if (result && result.id) {
|
|
1408
|
+
clearInterval(progressInterval);
|
|
1409
|
+
item.progress = 100;
|
|
1410
|
+
item.status = "success";
|
|
1411
|
+
refreshAttachments();
|
|
1412
|
+
} else {
|
|
1413
|
+
clearInterval(progressInterval);
|
|
1414
|
+
item.status = "error";
|
|
1415
|
+
item.errorMessage = "Upload failed: Invalid response";
|
|
1416
|
+
}
|
|
1417
|
+
} catch (error) {
|
|
1418
|
+
console.error("Upload failed:", error);
|
|
1419
|
+
clearInterval(progressInterval);
|
|
1420
|
+
item.status = "error";
|
|
1421
|
+
item.errorMessage = error instanceof Error ? error.message : "Upload failed";
|
|
1422
|
+
}
|
|
1423
|
+
};
|
|
1424
|
+
const createFolder = () => {
|
|
1425
|
+
showCreateFolderModal.value = true;
|
|
1426
|
+
};
|
|
1427
|
+
const handleCreateFolder = async (folderName) => {
|
|
1428
|
+
try {
|
|
1429
|
+
await createFolderMutation({
|
|
1430
|
+
record_id: props.recordId,
|
|
1431
|
+
record_type: props.recordType,
|
|
1432
|
+
folder_name: folderName,
|
|
1433
|
+
parent_folder_id: currentFolderId.value || null
|
|
1434
|
+
});
|
|
1435
|
+
showCreateFolderModal.value = false;
|
|
1436
|
+
refreshAttachments();
|
|
1437
|
+
} catch (error) {
|
|
1438
|
+
console.error("Create folder failed:", error);
|
|
1439
|
+
}
|
|
1440
|
+
};
|
|
1441
|
+
const env = useEnv();
|
|
1442
|
+
const useSession = useUserSessionStore();
|
|
1443
|
+
const downloadFile = async (file) => {
|
|
1444
|
+
if (!file) return;
|
|
1445
|
+
const res = await fetch(`${env.restApiClient.apiUrl}/attachments/${props.recordType}/${file.id}`, {
|
|
1446
|
+
method: "GET",
|
|
1447
|
+
headers: {
|
|
1448
|
+
"Content-Type": "application/json",
|
|
1449
|
+
Authorization: `Bearer ${useSession.accessToken}`
|
|
1450
|
+
}
|
|
1451
|
+
});
|
|
1452
|
+
if (!res.ok) throw new Error("Failed to download file");
|
|
1453
|
+
const blob = await res.blob();
|
|
1454
|
+
const url = URL.createObjectURL(blob);
|
|
1455
|
+
const a = document.createElement("a");
|
|
1456
|
+
a.href = url;
|
|
1457
|
+
a.download = file.name;
|
|
1458
|
+
document.body.appendChild(a);
|
|
1459
|
+
a.click();
|
|
1460
|
+
a.remove();
|
|
1461
|
+
URL.revokeObjectURL(url);
|
|
1462
|
+
};
|
|
1463
|
+
const confirmDeleteFile = (file) => {
|
|
1464
|
+
fileToDelete.value = file;
|
|
1465
|
+
showDeleteModal.value = true;
|
|
1466
|
+
};
|
|
1467
|
+
const deleteFile = async () => {
|
|
1468
|
+
if (!fileToDelete.value) return;
|
|
1469
|
+
try {
|
|
1470
|
+
await deleteAttachment({ id: fileToDelete.value.id });
|
|
1471
|
+
refreshAttachments();
|
|
1472
|
+
showDeleteModal.value = false;
|
|
1473
|
+
fileToDelete.value = null;
|
|
1474
|
+
} catch (error) {
|
|
1475
|
+
console.error("Delete failed:", error);
|
|
1476
|
+
}
|
|
1477
|
+
};
|
|
1478
|
+
const formatFileSize = (bytes) => {
|
|
1479
|
+
if (bytes === 0) return "0 Bytes";
|
|
1480
|
+
const k = 1024;
|
|
1481
|
+
const sizes = [
|
|
1482
|
+
"Bytes",
|
|
1483
|
+
"KB",
|
|
1484
|
+
"MB",
|
|
1485
|
+
"GB"
|
|
1486
|
+
];
|
|
1487
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
1488
|
+
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
|
|
1489
|
+
};
|
|
1490
|
+
const formatDate = (date) => {
|
|
1491
|
+
return new Intl.DateTimeFormat("en-US", {
|
|
1492
|
+
year: "numeric",
|
|
1493
|
+
month: "short",
|
|
1494
|
+
day: "numeric"
|
|
1495
|
+
}).format(date);
|
|
1496
|
+
};
|
|
1497
|
+
const getFileTypeLabel = (type) => {
|
|
1498
|
+
if (type.includes("pdf")) return "PDF";
|
|
1499
|
+
if (type.includes("word") || type.includes("doc")) return "DOC";
|
|
1500
|
+
if (type.includes("sheet") || type.includes("excel") || type.includes("xls")) return "XLS";
|
|
1501
|
+
if (type.includes("image")) return "IMG";
|
|
1502
|
+
return "FILE";
|
|
1503
|
+
};
|
|
1504
|
+
const getFileTypeBadgeClass = (type) => {
|
|
1505
|
+
if (type.includes("pdf")) return "badge-error";
|
|
1506
|
+
if (type.includes("word") || type.includes("doc")) return "badge-primary";
|
|
1507
|
+
if (type.includes("sheet") || type.includes("excel") || type.includes("xls")) return "badge-success";
|
|
1508
|
+
if (type.includes("image")) return "badge-warning";
|
|
1509
|
+
return "badge-neutral";
|
|
1510
|
+
};
|
|
1511
|
+
return (_ctx, _cache) => {
|
|
1512
|
+
return openBlock(), createElementBlock("div", _hoisted_1$15, [
|
|
1513
|
+
createCommentVNode(" File Manager Header "),
|
|
1514
|
+
createElementVNode("div", _hoisted_2$13, [
|
|
1515
|
+
createCommentVNode(" Mobile: Stacked layout "),
|
|
1516
|
+
createElementVNode("div", _hoisted_3$13, [
|
|
1517
|
+
createElementVNode("h3", _hoisted_4$12, toDisplayString(config.value.title || "Attachments"), 1),
|
|
1518
|
+
createCommentVNode(" Mobile: Action buttons "),
|
|
1519
|
+
createElementVNode("div", _hoisted_5$11, [createElementVNode("button", {
|
|
1520
|
+
class: "btn btn-sm btn-primary flex-1",
|
|
1521
|
+
onClick: openFileSelector,
|
|
1522
|
+
disabled: isUploading.value
|
|
1523
|
+
}, [_cache[5] || (_cache[5] = createElementVNode("svg", {
|
|
1524
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1525
|
+
class: "h-4 w-4 mr-1",
|
|
1526
|
+
fill: "none",
|
|
1527
|
+
viewBox: "0 0 24 24",
|
|
1528
|
+
stroke: "currentColor"
|
|
1529
|
+
}, [createElementVNode("path", {
|
|
1530
|
+
"stroke-linecap": "round",
|
|
1531
|
+
"stroke-linejoin": "round",
|
|
1532
|
+
"stroke-width": "2",
|
|
1533
|
+
d: "M12 4v16m8-8H4"
|
|
1534
|
+
})], -1)), createTextVNode(" " + toDisplayString(config.value.addButtonText || "Add Files"), 1)], 8, _hoisted_6$10), createElementVNode("button", {
|
|
1535
|
+
class: "btn btn-sm btn-info flex-1",
|
|
1536
|
+
onClick: createFolder
|
|
1537
|
+
}, [..._cache[6] || (_cache[6] = [createElementVNode("svg", {
|
|
1538
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1539
|
+
class: "h-4 w-4 mr-1",
|
|
1540
|
+
fill: "none",
|
|
1541
|
+
viewBox: "0 0 24 24",
|
|
1542
|
+
stroke: "currentColor"
|
|
1543
|
+
}, [createElementVNode("path", {
|
|
1544
|
+
"stroke-linecap": "round",
|
|
1545
|
+
"stroke-linejoin": "round",
|
|
1546
|
+
"stroke-width": "2",
|
|
1547
|
+
d: "M12 4v16m8-8H4"
|
|
1548
|
+
})], -1), createTextVNode(" New Folder ", -1)])])]),
|
|
1549
|
+
createCommentVNode(" Desktop: Action buttons "),
|
|
1550
|
+
createElementVNode("div", { class: "hidden sm:flex gap-2" }, [createElementVNode("button", {
|
|
1551
|
+
class: "btn btn-sm btn-info",
|
|
1552
|
+
onClick: createFolder
|
|
1553
|
+
}, "New Folder")])
|
|
1554
|
+
]),
|
|
1555
|
+
createCommentVNode(" Breadcrumb Navigation - Mobile optimized "),
|
|
1556
|
+
createElementVNode("div", _hoisted_7$9, [createElementVNode("ul", _hoisted_8$9, [createElementVNode("li", null, [createElementVNode("button", {
|
|
1557
|
+
class: normalizeClass(["btn btn-sm sm:btn-xs btn-ghost min-h-[2.5rem] sm:min-h-0 py-2 sm:py-1", { "btn-active": !currentFolderId.value }]),
|
|
1558
|
+
onClick: _cache[0] || (_cache[0] = ($event) => navigateToFolder(null))
|
|
1559
|
+
}, [..._cache[7] || (_cache[7] = [createElementVNode("svg", {
|
|
1560
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1561
|
+
class: "h-4 w-4 sm:mr-1",
|
|
1562
|
+
fill: "none",
|
|
1563
|
+
viewBox: "0 0 24 24",
|
|
1564
|
+
stroke: "currentColor"
|
|
1565
|
+
}, [createElementVNode("path", {
|
|
1566
|
+
"stroke-linecap": "round",
|
|
1567
|
+
"stroke-linejoin": "round",
|
|
1568
|
+
"stroke-width": "2",
|
|
1569
|
+
d: "M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"
|
|
1570
|
+
})], -1), createElementVNode("span", { class: "hidden sm:inline" }, "Root", -1)])], 2)]), (openBlock(true), createElementBlock(Fragment, null, renderList(folderPath.value, (folder, index) => {
|
|
1571
|
+
return openBlock(), createElementBlock("li", { key: folder.id }, [createElementVNode("button", {
|
|
1572
|
+
class: normalizeClass(["btn btn-sm sm:btn-xs btn-ghost min-h-[2.5rem] sm:min-h-0 py-2 sm:py-1 max-w-[8rem] sm:max-w-none truncate", { "btn-active": index === folderPath.value.length - 1 }]),
|
|
1573
|
+
onClick: ($event) => navigateToFolder(folder.id),
|
|
1574
|
+
title: folder.name
|
|
1575
|
+
}, toDisplayString(folder.name), 11, _hoisted_9$8)]);
|
|
1576
|
+
}), 128))])])
|
|
1577
|
+
]),
|
|
1578
|
+
createElementVNode("input", {
|
|
1579
|
+
ref_key: "fileInput",
|
|
1580
|
+
ref: fileInput,
|
|
1581
|
+
type: "file",
|
|
1582
|
+
class: "hidden",
|
|
1583
|
+
onChange: handleFileChange,
|
|
1584
|
+
multiple: "",
|
|
1585
|
+
accept: config.value.acceptedTypes
|
|
1586
|
+
}, null, 40, _hoisted_10$5),
|
|
1587
|
+
createCommentVNode(" Drag & Drop Zone (hidden on mobile) "),
|
|
1588
|
+
createElementVNode("div", {
|
|
1589
|
+
class: normalizeClass(["hidden sm:block border-2 border-dashed rounded-lg p-6 text-center mb-4 transition-colors", {
|
|
1590
|
+
"border-primary bg-primary/5 cursor-pointer": isDragging.value,
|
|
1591
|
+
"border-base-300 hover:border-primary/50": !isDragging.value
|
|
1592
|
+
}]),
|
|
1593
|
+
onDragover: _cache[1] || (_cache[1] = withModifiers(($event) => isDragging.value = true, ["prevent"])),
|
|
1594
|
+
onDragleave: _cache[2] || (_cache[2] = withModifiers(($event) => isDragging.value = false, ["prevent"])),
|
|
1595
|
+
onDrop: withModifiers(handleFileDrop, ["prevent"]),
|
|
1596
|
+
onClick: openFileSelector
|
|
1597
|
+
}, [createElementVNode("div", _hoisted_11$5, [
|
|
1598
|
+
_cache[8] || (_cache[8] = createElementVNode("svg", {
|
|
1599
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1600
|
+
class: "h-12 w-12 mb-2 text-primary",
|
|
1601
|
+
fill: "none",
|
|
1602
|
+
viewBox: "0 0 24 24",
|
|
1603
|
+
stroke: "currentColor"
|
|
1604
|
+
}, [createElementVNode("path", {
|
|
1605
|
+
"stroke-linecap": "round",
|
|
1606
|
+
"stroke-linejoin": "round",
|
|
1607
|
+
"stroke-width": "2",
|
|
1608
|
+
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"
|
|
1609
|
+
})], -1)),
|
|
1610
|
+
createElementVNode("p", _hoisted_12$5, toDisplayString(config.value.dropText || "Drag and drop files here"), 1),
|
|
1611
|
+
createElementVNode("p", _hoisted_13$4, toDisplayString(config.value.browseText || "or click to browse files"), 1),
|
|
1612
|
+
config.value.acceptText ? (openBlock(), createElementBlock("p", _hoisted_14$3, toDisplayString(config.value.acceptText), 1)) : createCommentVNode("v-if", true)
|
|
1613
|
+
])], 34),
|
|
1614
|
+
createCommentVNode(" Upload Queue "),
|
|
1615
|
+
uploadQueue.value.length > 0 ? (openBlock(), createElementBlock("div", _hoisted_15$2, [_cache[12] || (_cache[12] = createElementVNode("div", { class: "text-sm font-medium mb-2" }, "File uploads", -1)), createElementVNode("div", _hoisted_16$2, [(openBlock(true), createElementBlock(Fragment, null, renderList(uploadQueue.value, (item) => {
|
|
1616
|
+
return openBlock(), createElementBlock("div", {
|
|
1617
|
+
key: item.id,
|
|
1618
|
+
class: normalizeClass(["border border-base-200 rounded-lg p-3", {
|
|
1619
|
+
"bg-success/5 border-success/30": item.status === "success",
|
|
1620
|
+
"bg-error/5 border-error/30": item.status === "error"
|
|
1621
|
+
}])
|
|
1622
|
+
}, [
|
|
1623
|
+
createElementVNode("div", _hoisted_17$1, [
|
|
1624
|
+
createElementVNode("div", _hoisted_18$1, [
|
|
1625
|
+
createElementVNode("div", _hoisted_19$1, [
|
|
1626
|
+
createCommentVNode(" Status Icon "),
|
|
1627
|
+
item.status === "uploading" ? (openBlock(), createElementBlock("div", _hoisted_20$1)) : item.status === "success" ? (openBlock(), createElementBlock("svg", _hoisted_21$1, [..._cache[9] || (_cache[9] = [createElementVNode("path", {
|
|
1628
|
+
"stroke-linecap": "round",
|
|
1629
|
+
"stroke-linejoin": "round",
|
|
1630
|
+
"stroke-width": "2",
|
|
1631
|
+
d: "M5 13l4 4L19 7"
|
|
1632
|
+
}, null, -1)])])) : item.status === "error" ? (openBlock(), createElementBlock("svg", _hoisted_22$1, [..._cache[10] || (_cache[10] = [createElementVNode("path", {
|
|
1633
|
+
"stroke-linecap": "round",
|
|
1634
|
+
"stroke-linejoin": "round",
|
|
1635
|
+
"stroke-width": "2",
|
|
1636
|
+
d: "M6 18L18 6M6 6l12 12"
|
|
1637
|
+
}, null, -1)])])) : (openBlock(), createElementBlock("div", _hoisted_23$1)),
|
|
1638
|
+
createCommentVNode(" Filename "),
|
|
1639
|
+
createElementVNode("div", _hoisted_24$1, [createElementVNode("div", _hoisted_25$1, toDisplayString(item.file.name), 1)])
|
|
1640
|
+
]),
|
|
1641
|
+
createElementVNode("div", _hoisted_26$1, toDisplayString(formatFileSize(item.file.size)), 1),
|
|
1642
|
+
item.status === "error" && item.errorMessage ? (openBlock(), createElementBlock("div", _hoisted_27$1, toDisplayString(item.errorMessage), 1)) : createCommentVNode("v-if", true)
|
|
1643
|
+
]),
|
|
1644
|
+
createCommentVNode(" Dismiss Button (X) "),
|
|
1645
|
+
item.status === "success" || item.status === "error" ? (openBlock(), createElementBlock("button", {
|
|
1646
|
+
key: 0,
|
|
1647
|
+
class: "btn btn-xs btn-ghost btn-circle",
|
|
1648
|
+
onClick: ($event) => removeFromQueue(item.id),
|
|
1649
|
+
"aria-label": "Dismiss notification"
|
|
1650
|
+
}, [..._cache[11] || (_cache[11] = [createElementVNode("svg", {
|
|
1651
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1652
|
+
class: "h-4 w-4",
|
|
1653
|
+
fill: "none",
|
|
1654
|
+
viewBox: "0 0 24 24",
|
|
1655
|
+
stroke: "currentColor"
|
|
1656
|
+
}, [createElementVNode("path", {
|
|
1657
|
+
"stroke-linecap": "round",
|
|
1658
|
+
"stroke-linejoin": "round",
|
|
1659
|
+
"stroke-width": "2",
|
|
1660
|
+
d: "M6 18L18 6M6 6l12 12"
|
|
1661
|
+
})], -1)])], 8, _hoisted_28$1)) : createCommentVNode("v-if", true)
|
|
1662
|
+
]),
|
|
1663
|
+
createCommentVNode(" Progress Bar "),
|
|
1664
|
+
item.status === "uploading" || item.status === "pending" ? (openBlock(), createElementBlock("div", _hoisted_29$1, [createElementVNode("div", _hoisted_30$1, [createElementVNode("span", null, toDisplayString(item.status === "uploading" ? "Uploading..." : "Waiting..."), 1), item.status === "uploading" ? (openBlock(), createElementBlock("span", _hoisted_31$1, toDisplayString(item.progress.toFixed(2)) + "%", 1)) : createCommentVNode("v-if", true)]), createElementVNode("progress", {
|
|
1665
|
+
class: normalizeClass(["progress w-full", {
|
|
1666
|
+
"progress-primary": item.status === "uploading",
|
|
1667
|
+
"progress-secondary opacity-50": item.status === "pending"
|
|
1668
|
+
}]),
|
|
1669
|
+
value: item.status === "uploading" ? item.progress : 0,
|
|
1670
|
+
max: "100"
|
|
1671
|
+
}, null, 10, _hoisted_32$1)])) : createCommentVNode("v-if", true),
|
|
1672
|
+
createCommentVNode(" Success/Error Message "),
|
|
1673
|
+
item.status === "success" ? (openBlock(), createElementBlock("div", _hoisted_33$1, " Upload complete ")) : createCommentVNode("v-if", true),
|
|
1674
|
+
item.status === "error" ? (openBlock(), createElementBlock("div", _hoisted_34$1, " Upload failed - dismiss and try again ")) : createCommentVNode("v-if", true)
|
|
1675
|
+
], 2);
|
|
1676
|
+
}), 128))])])) : createCommentVNode("v-if", true),
|
|
1677
|
+
createCommentVNode(" Folder list (mobile) "),
|
|
1678
|
+
folders.value.length > 0 ? (openBlock(), createElementBlock("div", _hoisted_35$1, [(openBlock(true), createElementBlock(Fragment, null, renderList(folders.value, (folder) => {
|
|
1679
|
+
return openBlock(), createElementBlock("div", {
|
|
1680
|
+
key: folder.id,
|
|
1681
|
+
class: "card card-compact bg-base-100 shadow-sm mb-3 border border-base-200 active:scale-[0.98] transition-transform",
|
|
1682
|
+
onClick: ($event) => enterFolder(folder.id)
|
|
1683
|
+
}, [createElementVNode("div", _hoisted_37, [createElementVNode("div", _hoisted_38, [
|
|
1684
|
+
_cache[13] || (_cache[13] = createElementVNode("div", { class: "badge badge-secondary badge-lg" }, "FOLDER", -1)),
|
|
1685
|
+
createElementVNode("h3", _hoisted_39, toDisplayString(folder.name), 1),
|
|
1686
|
+
_cache[14] || (_cache[14] = createElementVNode("svg", {
|
|
1687
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1688
|
+
class: "h-5 w-5 text-base-content/50",
|
|
1689
|
+
fill: "none",
|
|
1690
|
+
viewBox: "0 0 24 24",
|
|
1691
|
+
stroke: "currentColor"
|
|
1692
|
+
}, [createElementVNode("path", {
|
|
1693
|
+
"stroke-linecap": "round",
|
|
1694
|
+
"stroke-linejoin": "round",
|
|
1695
|
+
"stroke-width": "2",
|
|
1696
|
+
d: "M9 5l7 7-7 7"
|
|
1697
|
+
})], -1))
|
|
1698
|
+
])])], 8, _hoisted_36);
|
|
1699
|
+
}), 128))])) : createCommentVNode("v-if", true),
|
|
1700
|
+
createCommentVNode(" File List for Mobile "),
|
|
1701
|
+
attachments.value.length > 0 ? (openBlock(), createElementBlock("div", _hoisted_40, [(openBlock(true), createElementBlock(Fragment, null, renderList(attachments.value, (file, index) => {
|
|
1702
|
+
return openBlock(), createElementBlock("div", {
|
|
1703
|
+
key: index,
|
|
1704
|
+
class: "card card-compact bg-base-100 shadow-sm mb-3 border border-base-200"
|
|
1705
|
+
}, [createElementVNode("div", _hoisted_41, [
|
|
1706
|
+
createElementVNode("div", _hoisted_42, [createElementVNode("div", { class: normalizeClass(["badge", getFileTypeBadgeClass(file.type)]) }, toDisplayString(getFileTypeLabel(file.type)), 3), createElementVNode("h3", _hoisted_43, toDisplayString(file.name), 1)]),
|
|
1707
|
+
createElementVNode("div", _hoisted_44, [createElementVNode("div", null, [_cache[15] || (_cache[15] = createElementVNode("span", { class: "text-base-content/70" }, "Size:", -1)), createTextVNode(" " + toDisplayString(formatFileSize(file.size)), 1)]), createElementVNode("div", null, [_cache[16] || (_cache[16] = createElementVNode("span", { class: "text-base-content/70" }, "Uploaded:", -1)), createTextVNode(" " + toDisplayString(formatDate(file.uploadedAt)), 1)])]),
|
|
1708
|
+
createElementVNode("div", _hoisted_45, [createElementVNode("button", {
|
|
1709
|
+
class: "btn btn-sm flex-1 min-h-[2.75rem]",
|
|
1710
|
+
onClick: ($event) => downloadFile(file)
|
|
1711
|
+
}, [..._cache[17] || (_cache[17] = [createElementVNode("svg", {
|
|
1712
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1713
|
+
class: "h-4 w-4 mr-1",
|
|
1714
|
+
fill: "none",
|
|
1715
|
+
viewBox: "0 0 24 24",
|
|
1716
|
+
stroke: "currentColor"
|
|
1717
|
+
}, [createElementVNode("path", {
|
|
1718
|
+
"stroke-linecap": "round",
|
|
1719
|
+
"stroke-linejoin": "round",
|
|
1720
|
+
"stroke-width": "2",
|
|
1721
|
+
d: "M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"
|
|
1722
|
+
})], -1), createTextVNode(" Download ", -1)])], 8, _hoisted_46), createElementVNode("button", {
|
|
1723
|
+
class: "btn btn-sm btn-outline btn-error flex-1 min-h-[2.75rem]",
|
|
1724
|
+
onClick: ($event) => confirmDeleteFile(file)
|
|
1725
|
+
}, [..._cache[18] || (_cache[18] = [createElementVNode("svg", {
|
|
1726
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1727
|
+
class: "h-4 w-4 mr-1",
|
|
1728
|
+
fill: "none",
|
|
1729
|
+
viewBox: "0 0 24 24",
|
|
1730
|
+
stroke: "currentColor"
|
|
1731
|
+
}, [createElementVNode("path", {
|
|
1732
|
+
"stroke-linecap": "round",
|
|
1733
|
+
"stroke-linejoin": "round",
|
|
1734
|
+
"stroke-width": "2",
|
|
1735
|
+
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"
|
|
1736
|
+
})], -1), createTextVNode(" Delete ", -1)])], 8, _hoisted_47)])
|
|
1737
|
+
])]);
|
|
1738
|
+
}), 128))])) : createCommentVNode("v-if", true),
|
|
1739
|
+
createCommentVNode(" Folder and File List for Tablet/Desktop "),
|
|
1740
|
+
folders.value.length > 0 || attachments.value.length > 0 ? (openBlock(), createElementBlock("div", _hoisted_48, [createElementVNode("table", _hoisted_49, [_cache[25] || (_cache[25] = createElementVNode("thead", null, [createElementVNode("tr", null, [
|
|
1741
|
+
createElementVNode("th", null, "Name"),
|
|
1742
|
+
createElementVNode("th", null, "Size"),
|
|
1743
|
+
createElementVNode("th", null, "Uploaded"),
|
|
1744
|
+
createElementVNode("th", null, "Actions")
|
|
1745
|
+
])], -1)), createElementVNode("tbody", null, [
|
|
1746
|
+
createCommentVNode(" Folders "),
|
|
1747
|
+
(openBlock(true), createElementBlock(Fragment, null, renderList(folders.value, (folder) => {
|
|
1748
|
+
return openBlock(), createElementBlock("tr", {
|
|
1749
|
+
key: folder.id,
|
|
1750
|
+
class: "cursor-pointer",
|
|
1751
|
+
onClick: ($event) => enterFolder(folder.id)
|
|
1752
|
+
}, [
|
|
1753
|
+
createElementVNode("td", null, [createElementVNode("div", _hoisted_51, [_cache[19] || (_cache[19] = createElementVNode("div", { class: "badge badge-secondary badge-sm" }, "FOLDER", -1)), createElementVNode("div", _hoisted_52, [createTextVNode(toDisplayString(folder.name) + " ", 1), folder.file_count !== void 0 ? (openBlock(), createElementBlock("span", _hoisted_53, " (" + toDisplayString(folder.file_count) + ") ", 1)) : createCommentVNode("v-if", true)])])]),
|
|
1754
|
+
_cache[20] || (_cache[20] = createElementVNode("td", null, "—", -1)),
|
|
1755
|
+
_cache[21] || (_cache[21] = createElementVNode("td", null, "—", -1)),
|
|
1756
|
+
_cache[22] || (_cache[22] = createElementVNode("td", null, "—", -1))
|
|
1757
|
+
], 8, _hoisted_50);
|
|
1758
|
+
}), 128)),
|
|
1759
|
+
createCommentVNode(" Files "),
|
|
1760
|
+
(openBlock(true), createElementBlock(Fragment, null, renderList(attachments.value, (file, index) => {
|
|
1761
|
+
return openBlock(), createElementBlock("tr", { key: index }, [
|
|
1762
|
+
createElementVNode("td", null, [createElementVNode("div", _hoisted_54, [createElementVNode("div", { class: normalizeClass(["badge badge-sm", getFileTypeBadgeClass(file.type)]) }, toDisplayString(getFileTypeLabel(file.type)), 3), createElementVNode("div", _hoisted_55, toDisplayString(file.name), 1)])]),
|
|
1763
|
+
createElementVNode("td", null, toDisplayString(formatFileSize(file.size)), 1),
|
|
1764
|
+
createElementVNode("td", null, toDisplayString(formatDate(file.uploadedAt)), 1),
|
|
1765
|
+
createElementVNode("td", null, [createElementVNode("div", _hoisted_56, [createElementVNode("button", {
|
|
1766
|
+
class: "btn btn-sm btn-ghost btn-circle",
|
|
1767
|
+
onClick: ($event) => downloadFile(file)
|
|
1768
|
+
}, [..._cache[23] || (_cache[23] = [createElementVNode("svg", {
|
|
1769
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1770
|
+
class: "h-4 w-4",
|
|
1771
|
+
fill: "none",
|
|
1772
|
+
viewBox: "0 0 24 24",
|
|
1773
|
+
stroke: "currentColor"
|
|
1774
|
+
}, [createElementVNode("path", {
|
|
1775
|
+
"stroke-linecap": "round",
|
|
1776
|
+
"stroke-linejoin": "round",
|
|
1777
|
+
"stroke-width": "2",
|
|
1778
|
+
d: "M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"
|
|
1779
|
+
})], -1)])], 8, _hoisted_57), createElementVNode("button", {
|
|
1780
|
+
class: "btn btn-sm btn-ghost btn-circle text-error",
|
|
1781
|
+
onClick: ($event) => confirmDeleteFile(file)
|
|
1782
|
+
}, [..._cache[24] || (_cache[24] = [createElementVNode("svg", {
|
|
1783
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1784
|
+
class: "h-4 w-4",
|
|
1785
|
+
fill: "none",
|
|
1786
|
+
viewBox: "0 0 24 24",
|
|
1787
|
+
stroke: "currentColor"
|
|
1788
|
+
}, [createElementVNode("path", {
|
|
1789
|
+
"stroke-linecap": "round",
|
|
1790
|
+
"stroke-linejoin": "round",
|
|
1791
|
+
"stroke-width": "2",
|
|
1792
|
+
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"
|
|
1793
|
+
})], -1)])], 8, _hoisted_58)])])
|
|
1794
|
+
]);
|
|
1795
|
+
}), 128))
|
|
1796
|
+
])])])) : unref(fetchingAttachments) ? (openBlock(), createElementBlock(Fragment, { key: 4 }, [createCommentVNode(" Loading State "), createElementVNode("div", _hoisted_59, [_cache[26] || (_cache[26] = createElementVNode("div", { class: "flex justify-center" }, [createElementVNode("span", { class: "loading loading-spinner loading-md" })], -1)), createElementVNode("p", _hoisted_60, toDisplayString(config.value.loadingText || "Loading attachments..."), 1)])], 2112)) : !isUploading.value ? (openBlock(), createElementBlock(Fragment, { key: 5 }, [createCommentVNode(" Empty State "), createElementVNode("div", _hoisted_61, [
|
|
1797
|
+
_cache[27] || (_cache[27] = createElementVNode("svg", {
|
|
1798
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1799
|
+
class: "h-12 w-12 mx-auto mb-3 text-base-content/30",
|
|
1800
|
+
fill: "none",
|
|
1801
|
+
viewBox: "0 0 24 24",
|
|
1802
|
+
stroke: "currentColor"
|
|
1803
|
+
}, [createElementVNode("path", {
|
|
1804
|
+
"stroke-linecap": "round",
|
|
1805
|
+
"stroke-linejoin": "round",
|
|
1806
|
+
"stroke-width": "2",
|
|
1807
|
+
d: "M9 13h6m-3-3v6m5 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
|
|
1808
|
+
})], -1)),
|
|
1809
|
+
createElementVNode("p", _hoisted_62, toDisplayString(config.value.emptyText || "No attachments yet"), 1),
|
|
1810
|
+
createCommentVNode(" Desktop instruction "),
|
|
1811
|
+
createElementVNode("p", _hoisted_63, toDisplayString(config.value.instructionText || "Use the drag and drop area above to add files"), 1)
|
|
1812
|
+
])], 2112)) : unref(attachmentsError) ? (openBlock(), createElementBlock(Fragment, { key: 6 }, [createCommentVNode(" Error State "), createElementVNode("div", _hoisted_64, [createElementVNode("p", _hoisted_65, toDisplayString(config.value.errorText || "Failed to load attachments"), 1), createElementVNode("button", {
|
|
1813
|
+
class: "btn btn-sm btn-outline mt-2",
|
|
1814
|
+
onClick: refreshAttachments
|
|
1815
|
+
}, toDisplayString(config.value.retryText || "Try Again"), 1)])], 2112)) : createCommentVNode("v-if", true),
|
|
1816
|
+
createCommentVNode(" Create Folder Modal "),
|
|
1817
|
+
createVNode(InputModal_default, {
|
|
1818
|
+
modelValue: showCreateFolderModal.value,
|
|
1819
|
+
"onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => showCreateFolderModal.value = $event),
|
|
1820
|
+
title: config.value.createFolderTitle || "Create New Folder",
|
|
1821
|
+
label: config.value.folderNameLabel || "Folder Name",
|
|
1822
|
+
placeholder: "Enter folder name",
|
|
1823
|
+
"confirm-text": config.value.createFolderButtonText || "Create",
|
|
1824
|
+
"cancel-text": config.value.cancelText || "Cancel",
|
|
1825
|
+
onConfirm: handleCreateFolder
|
|
1826
|
+
}, null, 8, [
|
|
1827
|
+
"modelValue",
|
|
1828
|
+
"title",
|
|
1829
|
+
"label",
|
|
1830
|
+
"confirm-text",
|
|
1831
|
+
"cancel-text"
|
|
1832
|
+
]),
|
|
1833
|
+
createCommentVNode(" Delete Confirmation Modal "),
|
|
1834
|
+
createVNode(ConfirmDialog_default, {
|
|
1835
|
+
modelValue: showDeleteModal.value,
|
|
1836
|
+
"onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => showDeleteModal.value = $event),
|
|
1837
|
+
title: config.value.deleteTitle || "Confirm Deletion",
|
|
1838
|
+
"confirm-text": config.value.confirmDeleteText || "Delete",
|
|
1839
|
+
"cancel-text": config.value.cancelText || "Cancel",
|
|
1840
|
+
"confirm-button-class": "btn-error",
|
|
1841
|
+
onConfirm: deleteFile
|
|
1842
|
+
}, {
|
|
1843
|
+
message: withCtx(() => [createElementVNode("p", _hoisted_66, toDisplayString(config.value.deleteMessage || "Are you sure you want to delete this file? This action cannot be undone."), 1), fileToDelete.value ? (openBlock(), createElementBlock("div", _hoisted_67, [createElementVNode("div", _hoisted_68, [createElementVNode("div", { class: normalizeClass(["badge badge-sm", getFileTypeBadgeClass(fileToDelete.value.type)]) }, toDisplayString(getFileTypeLabel(fileToDelete.value.type)), 3), createElementVNode("span", _hoisted_69, toDisplayString(fileToDelete.value.name), 1)]), createElementVNode("div", _hoisted_70, [createElementVNode("div", null, [_cache[28] || (_cache[28] = createElementVNode("span", { class: "font-medium" }, "Size:", -1)), createTextVNode(" " + toDisplayString(formatFileSize(fileToDelete.value.size)), 1)]), createElementVNode("div", null, [_cache[29] || (_cache[29] = createElementVNode("span", { class: "font-medium" }, "Uploaded:", -1)), createTextVNode(" " + toDisplayString(formatDate(fileToDelete.value.uploadedAt)), 1)])])])) : createCommentVNode("v-if", true)]),
|
|
1844
|
+
_: 1
|
|
1845
|
+
}, 8, [
|
|
1846
|
+
"modelValue",
|
|
1847
|
+
"title",
|
|
1848
|
+
"confirm-text",
|
|
1849
|
+
"cancel-text"
|
|
1850
|
+
])
|
|
1851
|
+
]);
|
|
1852
|
+
};
|
|
1853
|
+
}
|
|
1854
|
+
});
|
|
1855
|
+
var FileManager_default = _sfc_main$18;
|
|
1856
|
+
|
|
1857
|
+
//#endregion
|
|
1858
|
+
//#region src/components/ui/KeyValueEditor.vue
|
|
1859
|
+
const _hoisted_1$14 = { class: "key-value-editor col-span-full" };
|
|
1860
|
+
const _hoisted_2$12 = {
|
|
1861
|
+
key: 0,
|
|
1862
|
+
class: "mb-2"
|
|
1863
|
+
};
|
|
1864
|
+
const _hoisted_3$12 = {
|
|
1865
|
+
key: 0,
|
|
1866
|
+
class: "label p-0"
|
|
1867
|
+
};
|
|
1868
|
+
const _hoisted_4$11 = { class: "label-text" };
|
|
1869
|
+
const _hoisted_5$10 = {
|
|
1870
|
+
key: 1,
|
|
1871
|
+
class: "text-xs text-base-content/60 mt-1"
|
|
1872
|
+
};
|
|
1873
|
+
const _hoisted_6$9 = {
|
|
1874
|
+
key: 1,
|
|
1875
|
+
class: "text-error text-sm mb-2"
|
|
1876
|
+
};
|
|
1877
|
+
const _hoisted_7$8 = { class: "space-y-3" };
|
|
1878
|
+
const _hoisted_8$8 = { class: "flex-1" };
|
|
1879
|
+
const _hoisted_9$7 = [
|
|
1880
|
+
"onUpdate:modelValue",
|
|
1881
|
+
"placeholder",
|
|
1882
|
+
"onInput"
|
|
1883
|
+
];
|
|
1884
|
+
const _hoisted_10$4 = { class: "flex-1" };
|
|
1885
|
+
const _hoisted_11$4 = [
|
|
1886
|
+
"onUpdate:modelValue",
|
|
1887
|
+
"placeholder",
|
|
1888
|
+
"onInput"
|
|
1889
|
+
];
|
|
1890
|
+
const _hoisted_12$4 = ["onClick", "disabled"];
|
|
1891
|
+
const _hoisted_13$3 = {
|
|
1892
|
+
key: 2,
|
|
1893
|
+
class: "text-center py-4 text-base-content/60"
|
|
1894
|
+
};
|
|
1895
|
+
const _sfc_main$17 = /* @__PURE__ */ defineComponent({
|
|
1896
|
+
__name: "KeyValueEditor",
|
|
1897
|
+
props: {
|
|
1898
|
+
modelValue: { default: null },
|
|
1899
|
+
label: { default: "Key-Value Pairs" },
|
|
1900
|
+
helpText: { default: "Add custom metadata as key-value pairs" },
|
|
1901
|
+
keyPlaceholder: { default: "Key" },
|
|
1902
|
+
valuePlaceholder: { default: "Value" },
|
|
1903
|
+
error: { default: void 0 }
|
|
1904
|
+
},
|
|
1905
|
+
emits: ["update:modelValue"],
|
|
1906
|
+
setup(__props, { emit: __emit }) {
|
|
1907
|
+
const props = __props;
|
|
1908
|
+
const emit = __emit;
|
|
1909
|
+
const parseJsonToPairs = (jsonString) => {
|
|
1910
|
+
if (!jsonString || jsonString.trim() === "") return [{
|
|
1911
|
+
key: "",
|
|
1912
|
+
value: ""
|
|
1913
|
+
}];
|
|
1914
|
+
try {
|
|
1915
|
+
const parsed = JSON.parse(jsonString);
|
|
1916
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return [{
|
|
1917
|
+
key: "",
|
|
1918
|
+
value: ""
|
|
1919
|
+
}];
|
|
1920
|
+
const pairs$1 = Object.entries(parsed).map(([key, value]) => ({
|
|
1921
|
+
key,
|
|
1922
|
+
value: String(value)
|
|
1923
|
+
}));
|
|
1924
|
+
return pairs$1.length > 0 ? pairs$1 : [{
|
|
1925
|
+
key: "",
|
|
1926
|
+
value: ""
|
|
1927
|
+
}];
|
|
1928
|
+
} catch {
|
|
1929
|
+
return [{
|
|
1930
|
+
key: "",
|
|
1931
|
+
value: ""
|
|
1932
|
+
}];
|
|
1933
|
+
}
|
|
1934
|
+
};
|
|
1935
|
+
const pairsToJson = (pairs$1) => {
|
|
1936
|
+
const validPairs = pairs$1.filter((pair) => pair.key.trim() !== "" || pair.value.trim() !== "");
|
|
1937
|
+
if (validPairs.length === 0) return null;
|
|
1938
|
+
const obj = {};
|
|
1939
|
+
for (const pair of validPairs) if (pair.key.trim() !== "") obj[pair.key.trim()] = pair.value.trim();
|
|
1940
|
+
return Object.keys(obj).length === 0 ? null : JSON.stringify(obj);
|
|
1941
|
+
};
|
|
1942
|
+
const pairs = ref(parseJsonToPairs(props.modelValue));
|
|
1943
|
+
const isInternalUpdate = ref(false);
|
|
1944
|
+
watch(() => props.modelValue, (newValue) => {
|
|
1945
|
+
if (isInternalUpdate.value) return;
|
|
1946
|
+
const newPairs = parseJsonToPairs(newValue);
|
|
1947
|
+
if (pairsToJson(pairs.value) !== newValue) pairs.value = newPairs;
|
|
1948
|
+
}, { immediate: true });
|
|
1949
|
+
watch(pairs, async (newPairs) => {
|
|
1950
|
+
isInternalUpdate.value = true;
|
|
1951
|
+
emit("update:modelValue", pairsToJson(newPairs));
|
|
1952
|
+
await nextTick();
|
|
1953
|
+
isInternalUpdate.value = false;
|
|
1954
|
+
}, { deep: true });
|
|
1955
|
+
const addPair = () => {
|
|
1956
|
+
pairs.value.push({
|
|
1957
|
+
key: "",
|
|
1958
|
+
value: ""
|
|
1959
|
+
});
|
|
1960
|
+
};
|
|
1961
|
+
const removePair = (index) => {
|
|
1962
|
+
if (pairs.value.length > 1) pairs.value.splice(index, 1);
|
|
1963
|
+
else pairs.value[0] = {
|
|
1964
|
+
key: "",
|
|
1965
|
+
value: ""
|
|
1966
|
+
};
|
|
1967
|
+
};
|
|
1968
|
+
const updatePair = (index, field, value) => {
|
|
1969
|
+
const pair = pairs.value[index];
|
|
1970
|
+
if (!pair) return;
|
|
1971
|
+
pair[field] = value;
|
|
1972
|
+
};
|
|
1973
|
+
return (_ctx, _cache) => {
|
|
1974
|
+
return openBlock(), createElementBlock("div", _hoisted_1$14, [
|
|
1975
|
+
__props.label || __props.helpText ? (openBlock(), createElementBlock("div", _hoisted_2$12, [__props.label ? (openBlock(), createElementBlock("label", _hoisted_3$12, [createElementVNode("span", _hoisted_4$11, toDisplayString(__props.label), 1)])) : createCommentVNode("v-if", true), __props.helpText ? (openBlock(), createElementBlock("p", _hoisted_5$10, toDisplayString(__props.helpText), 1)) : createCommentVNode("v-if", true)])) : createCommentVNode("v-if", true),
|
|
1976
|
+
__props.error ? (openBlock(), createElementBlock("div", _hoisted_6$9, toDisplayString(__props.error), 1)) : createCommentVNode("v-if", true),
|
|
1977
|
+
createElementVNode("div", _hoisted_7$8, [
|
|
1978
|
+
createCommentVNode(" Key-Value Pairs List "),
|
|
1979
|
+
(openBlock(true), createElementBlock(Fragment, null, renderList(pairs.value, (pair, index) => {
|
|
1980
|
+
return openBlock(), createElementBlock("div", {
|
|
1981
|
+
key: index,
|
|
1982
|
+
class: "flex gap-2 items-start"
|
|
1983
|
+
}, [
|
|
1984
|
+
createElementVNode("div", _hoisted_8$8, [withDirectives(createElementVNode("input", {
|
|
1985
|
+
"onUpdate:modelValue": ($event) => pair.key = $event,
|
|
1986
|
+
type: "text",
|
|
1987
|
+
placeholder: __props.keyPlaceholder,
|
|
1988
|
+
class: "input input-bordered w-full",
|
|
1989
|
+
onInput: ($event) => updatePair(index, "key", $event.target.value)
|
|
1990
|
+
}, null, 40, _hoisted_9$7), [[vModelText, pair.key]])]),
|
|
1991
|
+
createElementVNode("div", _hoisted_10$4, [withDirectives(createElementVNode("input", {
|
|
1992
|
+
"onUpdate:modelValue": ($event) => pair.value = $event,
|
|
1993
|
+
type: "text",
|
|
1994
|
+
placeholder: __props.valuePlaceholder,
|
|
1995
|
+
class: "input input-bordered w-full",
|
|
1996
|
+
onInput: ($event) => updatePair(index, "value", $event.target.value)
|
|
1997
|
+
}, null, 40, _hoisted_11$4), [[vModelText, pair.value]])]),
|
|
1998
|
+
createElementVNode("button", {
|
|
1999
|
+
type: "button",
|
|
2000
|
+
class: "btn btn-error btn-sm",
|
|
2001
|
+
onClick: ($event) => removePair(index),
|
|
2002
|
+
disabled: pairs.value.length === 1 && !pair.key && !pair.value
|
|
2003
|
+
}, [..._cache[0] || (_cache[0] = [createElementVNode("svg", {
|
|
2004
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2005
|
+
class: "h-4 w-4",
|
|
2006
|
+
fill: "none",
|
|
2007
|
+
viewBox: "0 0 24 24",
|
|
2008
|
+
stroke: "currentColor"
|
|
2009
|
+
}, [createElementVNode("path", {
|
|
2010
|
+
"stroke-linecap": "round",
|
|
2011
|
+
"stroke-linejoin": "round",
|
|
2012
|
+
"stroke-width": "2",
|
|
2013
|
+
d: "M6 18L18 6M6 6l12 12"
|
|
2014
|
+
})], -1)])], 8, _hoisted_12$4)
|
|
2015
|
+
]);
|
|
2016
|
+
}), 128)),
|
|
2017
|
+
createCommentVNode(" Add New Pair Button "),
|
|
2018
|
+
createElementVNode("button", {
|
|
2019
|
+
type: "button",
|
|
2020
|
+
class: "btn btn-outline btn-sm w-full",
|
|
2021
|
+
onClick: addPair
|
|
2022
|
+
}, [..._cache[1] || (_cache[1] = [createElementVNode("svg", {
|
|
2023
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2024
|
+
class: "h-4 w-4 mr-1",
|
|
2025
|
+
fill: "none",
|
|
2026
|
+
viewBox: "0 0 24 24",
|
|
2027
|
+
stroke: "currentColor"
|
|
2028
|
+
}, [createElementVNode("path", {
|
|
2029
|
+
"stroke-linecap": "round",
|
|
2030
|
+
"stroke-linejoin": "round",
|
|
2031
|
+
"stroke-width": "2",
|
|
2032
|
+
d: "M12 4v16m8-8H4"
|
|
2033
|
+
})], -1), createTextVNode(" Add Key-Value Pair ", -1)])])
|
|
2034
|
+
]),
|
|
2035
|
+
createCommentVNode(" Empty State "),
|
|
2036
|
+
pairs.value.length === 0 ? (openBlock(), createElementBlock("div", _hoisted_13$3, " No key-value pairs. Click \"Add Key-Value Pair\" to get started. ")) : createCommentVNode("v-if", true)
|
|
2037
|
+
]);
|
|
2038
|
+
};
|
|
2039
|
+
}
|
|
2040
|
+
});
|
|
2041
|
+
var KeyValueEditor_default = /* @__PURE__ */ export_helper_default(_sfc_main$17, [["__scopeId", "data-v-010818ef"]]);
|
|
2042
|
+
|
|
2043
|
+
//#endregion
|
|
2044
|
+
//#region src/components/ui/SummarySection.vue
|
|
2045
|
+
const _hoisted_1$13 = { class: "bg-base-100 p-2 md:p-4 rounded-box overflow-hidden" };
|
|
2046
|
+
const _hoisted_2$11 = { class: "text-lg font-bold mb-2" };
|
|
2047
|
+
const _hoisted_3$11 = { class: "grid grid-auto-rows auto-rows-auto gap-x-4 gap-y-1" };
|
|
2048
|
+
const _sfc_main$16 = /* @__PURE__ */ defineComponent({
|
|
2049
|
+
__name: "SummarySection",
|
|
2050
|
+
props: { title: {} },
|
|
2051
|
+
setup(__props) {
|
|
2052
|
+
return (_ctx, _cache) => {
|
|
2053
|
+
return openBlock(), createElementBlock("div", _hoisted_1$13, [createElementVNode("h2", _hoisted_2$11, toDisplayString(__props.title), 1), createElementVNode("div", _hoisted_3$11, [renderSlot(_ctx.$slots, "default")])]);
|
|
2054
|
+
};
|
|
2055
|
+
}
|
|
2056
|
+
});
|
|
2057
|
+
var SummarySection_default = _sfc_main$16;
|
|
2058
|
+
|
|
2059
|
+
//#endregion
|
|
2060
|
+
//#region src/utils/timezones.ts
|
|
2061
|
+
const timezones = [
|
|
2062
|
+
{
|
|
2063
|
+
label: "",
|
|
2064
|
+
value: ""
|
|
2065
|
+
},
|
|
2066
|
+
{
|
|
2067
|
+
label: "US/Eastern (-04:00)",
|
|
2068
|
+
value: "US/Eastern (-04:00)"
|
|
2069
|
+
},
|
|
2070
|
+
{
|
|
2071
|
+
label: "US/East-Indiana (-04:00)",
|
|
2072
|
+
value: "US/East-Indiana (-04:00)"
|
|
2073
|
+
},
|
|
2074
|
+
{
|
|
2075
|
+
label: "US/Central (-05:00)",
|
|
2076
|
+
value: "US/Central (-05:00)"
|
|
2077
|
+
},
|
|
2078
|
+
{
|
|
2079
|
+
label: "US/Indiana-Starke (-05:00)",
|
|
2080
|
+
value: "US/Indiana-Starke (-05:00)"
|
|
2081
|
+
},
|
|
2082
|
+
{
|
|
2083
|
+
label: "US/Mountain (-06:00)",
|
|
2084
|
+
value: "US/Mountain (-06:00)"
|
|
2085
|
+
},
|
|
2086
|
+
{
|
|
2087
|
+
label: "US/Arizona (-07:00)",
|
|
2088
|
+
value: "US/Arizona (-07:00)"
|
|
2089
|
+
},
|
|
2090
|
+
{
|
|
2091
|
+
label: "US/Pacific (-07:00)",
|
|
2092
|
+
value: "US/Pacific (-07:00)"
|
|
2093
|
+
},
|
|
2094
|
+
{
|
|
2095
|
+
label: "US/Alaska (-08:00)",
|
|
2096
|
+
value: "US/Alaska (-08:00)"
|
|
2097
|
+
},
|
|
2098
|
+
{
|
|
2099
|
+
label: "US/Aleutian (-09:00)",
|
|
2100
|
+
value: "US/Aleutian (-09:00)"
|
|
2101
|
+
},
|
|
2102
|
+
{
|
|
2103
|
+
label: "US/Hawaii (-10:00)",
|
|
2104
|
+
value: "US/Hawaii (-10:00)"
|
|
2105
|
+
},
|
|
2106
|
+
{
|
|
2107
|
+
label: "US/Samoa (-11:00)",
|
|
2108
|
+
value: "US/Samoa (-11:00)"
|
|
2109
|
+
}
|
|
2110
|
+
];
|
|
2111
|
+
|
|
2112
|
+
//#endregion
|
|
2113
|
+
//#region src/middleware/userAlreadyLoggedIn.ts
|
|
2114
|
+
const userAlreadyLoggedIn = (_to, _from, next) => {
|
|
2115
|
+
if (useUserSessionStore().currentSession) next("/");
|
|
2116
|
+
else next();
|
|
2117
|
+
};
|
|
2118
|
+
|
|
2119
|
+
//#endregion
|
|
2120
|
+
//#region src/slices/user/userRoutes.ts
|
|
2121
|
+
const userRoutes = [{
|
|
2122
|
+
path: "/user",
|
|
2123
|
+
name: "User",
|
|
2124
|
+
beforeEnter: [userAuthenticated],
|
|
2125
|
+
meta: { sectionTabs: [
|
|
2126
|
+
{
|
|
2127
|
+
id: "profile",
|
|
2128
|
+
label: "Profile",
|
|
2129
|
+
to: { name: "Profile" }
|
|
2130
|
+
},
|
|
2131
|
+
{
|
|
2132
|
+
id: "appearance",
|
|
2133
|
+
label: "Appearance",
|
|
2134
|
+
to: { name: "Appearance" }
|
|
2135
|
+
},
|
|
2136
|
+
{
|
|
2137
|
+
id: "password",
|
|
2138
|
+
label: "Password",
|
|
2139
|
+
to: { name: "Password" }
|
|
2140
|
+
}
|
|
2141
|
+
] },
|
|
2142
|
+
children: [
|
|
2143
|
+
{
|
|
2144
|
+
path: "appearance",
|
|
2145
|
+
name: "Appearance",
|
|
2146
|
+
component: () => import("./Appearance-Ch4zfWZ3.js"),
|
|
2147
|
+
meta: {
|
|
2148
|
+
title: "Appearance",
|
|
2149
|
+
description: "Appearance page for Category 5 App"
|
|
2150
|
+
}
|
|
2151
|
+
},
|
|
2152
|
+
{
|
|
2153
|
+
path: "profile",
|
|
2154
|
+
name: "Profile",
|
|
2155
|
+
component: () => import("./UserProfilePage-DRbCAr9H.js"),
|
|
2156
|
+
meta: {
|
|
2157
|
+
title: "Profile",
|
|
2158
|
+
description: "Profile page for Category 5 App"
|
|
2159
|
+
}
|
|
2160
|
+
},
|
|
2161
|
+
{
|
|
2162
|
+
path: "password",
|
|
2163
|
+
name: "Password",
|
|
2164
|
+
component: () => import("./ChangePasswordPage-CYuCCosx.js"),
|
|
2165
|
+
meta: {
|
|
2166
|
+
title: "Password",
|
|
2167
|
+
description: "Password page for Category 5 App"
|
|
2168
|
+
}
|
|
2169
|
+
}
|
|
2170
|
+
]
|
|
2171
|
+
}];
|
|
2172
|
+
|
|
2173
|
+
//#endregion
|
|
2174
|
+
//#region src/slices/team/components/TeamAttachments.vue
|
|
2175
|
+
const _sfc_main$15 = /* @__PURE__ */ defineComponent({
|
|
2176
|
+
__name: "TeamAttachments",
|
|
2177
|
+
setup(__props) {
|
|
2178
|
+
const teamId = useRoute().params.id;
|
|
2179
|
+
const config = { title: "Team Attachments" };
|
|
2180
|
+
return (_ctx, _cache) => {
|
|
2181
|
+
return openBlock(), createBlock(FileManager_default, {
|
|
2182
|
+
"record-id": unref(teamId),
|
|
2183
|
+
"record-type": "team",
|
|
2184
|
+
config
|
|
2185
|
+
}, null, 8, ["record-id"]);
|
|
2186
|
+
};
|
|
2187
|
+
}
|
|
2188
|
+
});
|
|
2189
|
+
var TeamAttachments_default = _sfc_main$15;
|
|
2190
|
+
|
|
2191
|
+
//#endregion
|
|
2192
|
+
//#region src/slices/team/TeamAttachmentsTab.vue
|
|
2193
|
+
const _sfc_main$14 = /* @__PURE__ */ defineComponent({
|
|
2194
|
+
__name: "TeamAttachmentsTab",
|
|
2195
|
+
setup(__props) {
|
|
2196
|
+
return (_ctx, _cache) => {
|
|
2197
|
+
return openBlock(), createBlock(TeamAttachments_default);
|
|
2198
|
+
};
|
|
2199
|
+
}
|
|
2200
|
+
});
|
|
2201
|
+
var TeamAttachmentsTab_default = _sfc_main$14;
|
|
2202
|
+
|
|
2203
|
+
//#endregion
|
|
2204
|
+
//#region src/slices/team/teamFiltersMetadata.ts
|
|
2205
|
+
const teamFiltersSchemaWithMetadata = withMetadata(TeamFiltersSchema, "teamFilters", {
|
|
2206
|
+
unique_name: {
|
|
2207
|
+
label: "Unique Name",
|
|
2208
|
+
inputType: "text"
|
|
2209
|
+
},
|
|
2210
|
+
display_name: {
|
|
2211
|
+
label: "Display Name",
|
|
2212
|
+
inputType: "text"
|
|
2213
|
+
},
|
|
2214
|
+
legal_name: {
|
|
2215
|
+
label: "Legal Name",
|
|
2216
|
+
inputType: "text"
|
|
2217
|
+
},
|
|
2218
|
+
contact_email: {
|
|
2219
|
+
label: "Contact Email",
|
|
2220
|
+
inputType: "text"
|
|
2221
|
+
},
|
|
2222
|
+
address_city: {
|
|
2223
|
+
label: "City",
|
|
2224
|
+
inputType: "text"
|
|
2225
|
+
},
|
|
2226
|
+
includeArchived: {
|
|
2227
|
+
label: "Include Archived",
|
|
2228
|
+
inputType: "checkbox"
|
|
2229
|
+
}
|
|
2230
|
+
});
|
|
2231
|
+
|
|
2232
|
+
//#endregion
|
|
2233
|
+
//#region src/slices/team/team_member/teamMemberFiltersMetadata.ts
|
|
2234
|
+
const teamMemberFiltersSchemaWithMetadata = withMetadata(TeamMemberFiltersSchema, "teamMemberFilters", {
|
|
2235
|
+
display_name: {
|
|
2236
|
+
label: "Display Name",
|
|
2237
|
+
inputType: "text"
|
|
2238
|
+
},
|
|
2239
|
+
role: {
|
|
2240
|
+
label: "Role",
|
|
2241
|
+
inputType: "text"
|
|
2242
|
+
},
|
|
2243
|
+
email_address: {
|
|
2244
|
+
label: "Email Address",
|
|
2245
|
+
inputType: "text"
|
|
2246
|
+
},
|
|
2247
|
+
business_phone: {
|
|
2248
|
+
label: "Business Phone",
|
|
2249
|
+
inputType: "text"
|
|
2250
|
+
},
|
|
2251
|
+
mobile_phone: {
|
|
2252
|
+
label: "Mobile Phone",
|
|
2253
|
+
inputType: "text"
|
|
2254
|
+
},
|
|
2255
|
+
time_zone: {
|
|
2256
|
+
label: "Time Zone",
|
|
2257
|
+
inputType: "text"
|
|
2258
|
+
}
|
|
2259
|
+
});
|
|
2260
|
+
|
|
2261
|
+
//#endregion
|
|
2262
|
+
//#region src/slices/support_ticket/customer/components/SupportTicketTimeline.vue
|
|
2263
|
+
const _hoisted_1$12 = { class: "mt-8" };
|
|
2264
|
+
const _hoisted_2$10 = { class: "relative" };
|
|
2265
|
+
const _hoisted_3$10 = { class: "space-y-6 relative" };
|
|
2266
|
+
const _hoisted_4$10 = { class: "flex items-start group" };
|
|
2267
|
+
const _hoisted_5$9 = { class: "ml-4" };
|
|
2268
|
+
const _hoisted_6$8 = { class: "text-xs text-base-content/40 mt-1" };
|
|
2269
|
+
const _hoisted_7$7 = { class: "flex items-start group" };
|
|
2270
|
+
const _hoisted_8$7 = {
|
|
2271
|
+
key: 0,
|
|
2272
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2273
|
+
class: "h-4 w-4 animate-pulse",
|
|
2274
|
+
fill: "none",
|
|
2275
|
+
viewBox: "0 0 24 24",
|
|
2276
|
+
stroke: "currentColor"
|
|
2277
|
+
};
|
|
2278
|
+
const _hoisted_9$6 = {
|
|
2279
|
+
key: 1,
|
|
2280
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2281
|
+
class: "h-4 w-4",
|
|
2282
|
+
fill: "none",
|
|
2283
|
+
viewBox: "0 0 24 24",
|
|
2284
|
+
stroke: "currentColor"
|
|
2285
|
+
};
|
|
2286
|
+
const _hoisted_10$3 = {
|
|
2287
|
+
key: 2,
|
|
2288
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2289
|
+
class: "h-4 w-4",
|
|
2290
|
+
fill: "none",
|
|
2291
|
+
viewBox: "0 0 24 24",
|
|
2292
|
+
stroke: "currentColor"
|
|
2293
|
+
};
|
|
2294
|
+
const _hoisted_11$3 = { class: "ml-4" };
|
|
2295
|
+
const _hoisted_12$3 = { class: "font-medium text-base-content" };
|
|
2296
|
+
const _hoisted_13$2 = { class: "text-sm text-base-content/60" };
|
|
2297
|
+
const _hoisted_14$2 = {
|
|
2298
|
+
key: 0,
|
|
2299
|
+
class: "text-xs text-base-content/40 mt-1"
|
|
2300
|
+
};
|
|
2301
|
+
const _hoisted_15$1 = {
|
|
2302
|
+
key: 0,
|
|
2303
|
+
class: "flex items-start group"
|
|
2304
|
+
};
|
|
2305
|
+
const _hoisted_16$1 = { class: "ml-4" };
|
|
2306
|
+
const _sfc_main$13 = /* @__PURE__ */ defineComponent({
|
|
2307
|
+
__name: "SupportTicketTimeline",
|
|
2308
|
+
props: { support_ticket: {} },
|
|
2309
|
+
setup(__props) {
|
|
2310
|
+
return (_ctx, _cache) => {
|
|
2311
|
+
return openBlock(), createElementBlock("div", _hoisted_1$12, [_cache[8] || (_cache[8] = createElementVNode("h3", { class: "text-lg font-semibold text-base-content mb-4" }, "SupportTicket Progress", -1)), createElementVNode("div", _hoisted_2$10, [
|
|
2312
|
+
createCommentVNode(" Timeline line "),
|
|
2313
|
+
_cache[7] || (_cache[7] = createElementVNode("div", { class: "absolute left-4 top-0 bottom-0 w-0.5 bg-base-300" }, null, -1)),
|
|
2314
|
+
createCommentVNode(" Timeline items "),
|
|
2315
|
+
createElementVNode("div", _hoisted_3$10, [
|
|
2316
|
+
createCommentVNode(" Submitted "),
|
|
2317
|
+
createElementVNode("div", _hoisted_4$10, [createElementVNode("div", { class: normalizeClass(["flex-shrink-0 w-8 h-8 rounded-full flex items-center justify-center z-10", {
|
|
2318
|
+
"bg-primary text-primary-content": [
|
|
2319
|
+
"PENDING",
|
|
2320
|
+
"FOLLOWUP",
|
|
2321
|
+
"IN_PROGRESS",
|
|
2322
|
+
"COMPLETED",
|
|
2323
|
+
"CANCELLED"
|
|
2324
|
+
].includes(__props.support_ticket.status),
|
|
2325
|
+
"bg-base-300 text-base-content/40": ![
|
|
2326
|
+
"PENDING",
|
|
2327
|
+
"FOLLOWUP",
|
|
2328
|
+
"IN_PROGRESS",
|
|
2329
|
+
"COMPLETED",
|
|
2330
|
+
"CANCELLED"
|
|
2331
|
+
].includes(__props.support_ticket.status)
|
|
2332
|
+
}]) }, [..._cache[0] || (_cache[0] = [createElementVNode("svg", {
|
|
2333
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2334
|
+
class: "h-4 w-4",
|
|
2335
|
+
fill: "none",
|
|
2336
|
+
viewBox: "0 0 24 24",
|
|
2337
|
+
stroke: "currentColor"
|
|
2338
|
+
}, [createElementVNode("path", {
|
|
2339
|
+
"stroke-linecap": "round",
|
|
2340
|
+
"stroke-linejoin": "round",
|
|
2341
|
+
"stroke-width": "2",
|
|
2342
|
+
d: "M5 13l4 4L19 7"
|
|
2343
|
+
})], -1)])], 2), createElementVNode("div", _hoisted_5$9, [
|
|
2344
|
+
_cache[1] || (_cache[1] = createElementVNode("p", { class: "font-medium text-base-content" }, "Submitted", -1)),
|
|
2345
|
+
_cache[2] || (_cache[2] = createElementVNode("p", { class: "text-sm text-base-content/60" }, "Your ticket has been received", -1)),
|
|
2346
|
+
createElementVNode("p", _hoisted_6$8, toDisplayString(unref(formatSystemTimestamp)(__props.support_ticket.created_at)), 1)
|
|
2347
|
+
])]),
|
|
2348
|
+
createCommentVNode(" Under Review / In Progress / Completed "),
|
|
2349
|
+
createElementVNode("div", _hoisted_7$7, [createElementVNode("div", { class: normalizeClass(["flex-shrink-0 w-8 h-8 rounded-full flex items-center justify-center z-10", {
|
|
2350
|
+
"bg-primary text-primary-content": [
|
|
2351
|
+
"FOLLOWUP",
|
|
2352
|
+
"IN_PROGRESS",
|
|
2353
|
+
"COMPLETED",
|
|
2354
|
+
"CANCELLED"
|
|
2355
|
+
].includes(__props.support_ticket.status),
|
|
2356
|
+
"bg-base-300 text-base-content/40": ![
|
|
2357
|
+
"FOLLOWUP",
|
|
2358
|
+
"IN_PROGRESS",
|
|
2359
|
+
"COMPLETED",
|
|
2360
|
+
"CANCELLED"
|
|
2361
|
+
].includes(__props.support_ticket.status)
|
|
2362
|
+
}]) }, [__props.support_ticket.status === "PENDING" ? (openBlock(), createElementBlock("svg", _hoisted_8$7, [..._cache[3] || (_cache[3] = [createElementVNode("path", {
|
|
2363
|
+
"stroke-linecap": "round",
|
|
2364
|
+
"stroke-linejoin": "round",
|
|
2365
|
+
"stroke-width": "2",
|
|
2366
|
+
d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"
|
|
2367
|
+
}, null, -1)])])) : __props.support_ticket.status === "CANCELLED" ? (openBlock(), createElementBlock("svg", _hoisted_9$6, [..._cache[4] || (_cache[4] = [createElementVNode("path", {
|
|
2368
|
+
"stroke-linecap": "round",
|
|
2369
|
+
"stroke-linejoin": "round",
|
|
2370
|
+
"stroke-width": "2",
|
|
2371
|
+
d: "M6 18L18 6M6 6l12 12"
|
|
2372
|
+
}, null, -1)])])) : (openBlock(), createElementBlock("svg", _hoisted_10$3, [..._cache[5] || (_cache[5] = [createElementVNode("path", {
|
|
2373
|
+
"stroke-linecap": "round",
|
|
2374
|
+
"stroke-linejoin": "round",
|
|
2375
|
+
"stroke-width": "2",
|
|
2376
|
+
d: "M5 13l4 4L19 7"
|
|
2377
|
+
}, null, -1)])]))], 2), createElementVNode("div", _hoisted_11$3, [
|
|
2378
|
+
createElementVNode("p", _hoisted_12$3, [__props.support_ticket.status === "PENDING" ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [createTextVNode("Under Review")], 64)) : __props.support_ticket.status === "FOLLOWUP" ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [createTextVNode("Approved")], 64)) : __props.support_ticket.status === "IN_PROGRESS" ? (openBlock(), createElementBlock(Fragment, { key: 2 }, [createTextVNode("In Development")], 64)) : __props.support_ticket.status === "COMPLETED" ? (openBlock(), createElementBlock(Fragment, { key: 3 }, [createTextVNode("Completed")], 64)) : __props.support_ticket.status === "CANCELLED" ? (openBlock(), createElementBlock(Fragment, { key: 4 }, [createTextVNode("Not Approved")], 64)) : createCommentVNode("v-if", true)]),
|
|
2379
|
+
createElementVNode("p", _hoisted_13$2, [__props.support_ticket.status === "PENDING" ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [createTextVNode("Our team is reviewing your support_ticket")], 64)) : __props.support_ticket.status === "FOLLOWUP" ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [createTextVNode("Your ticket has been approved and is in our backlog")], 64)) : __props.support_ticket.status === "IN_PROGRESS" ? (openBlock(), createElementBlock(Fragment, { key: 2 }, [createTextVNode("We're currently working on implementing this")], 64)) : __props.support_ticket.status === "COMPLETED" ? (openBlock(), createElementBlock(Fragment, { key: 3 }, [createTextVNode("This has been implemented and deployed")], 64)) : __props.support_ticket.status === "CANCELLED" ? (openBlock(), createElementBlock(Fragment, { key: 4 }, [createTextVNode("This ticket wasn't approved for implementation")], 64)) : createCommentVNode("v-if", true)]),
|
|
2380
|
+
__props.support_ticket.updated_at && __props.support_ticket.updated_at !== __props.support_ticket.created_at ? (openBlock(), createElementBlock("p", _hoisted_14$2, toDisplayString(unref(formatSystemTimestamp)(__props.support_ticket.updated_at)), 1)) : createCommentVNode("v-if", true)
|
|
2381
|
+
])]),
|
|
2382
|
+
createCommentVNode(" Credit Information "),
|
|
2383
|
+
unref(formatCustomerCreditValue)(__props.support_ticket.credit_value) !== "TBD" && unref(formatCustomerCreditValue)(__props.support_ticket.credit_value) !== "N/A" ? (openBlock(), createElementBlock("div", _hoisted_15$1, [createElementVNode("div", { class: normalizeClass(["flex-shrink-0 w-8 h-8 rounded-full flex items-center justify-center z-10", {
|
|
2384
|
+
"bg-error text-error-content": [
|
|
2385
|
+
"FOLLOWUP",
|
|
2386
|
+
"IN_PROGRESS",
|
|
2387
|
+
"COMPLETED",
|
|
2388
|
+
"CANCELLED"
|
|
2389
|
+
].includes(__props.support_ticket.status),
|
|
2390
|
+
"bg-warning text-warning-content": ![
|
|
2391
|
+
"FOLLOWUP",
|
|
2392
|
+
"IN_PROGRESS",
|
|
2393
|
+
"COMPLETED",
|
|
2394
|
+
"CANCELLED"
|
|
2395
|
+
].includes(__props.support_ticket.status)
|
|
2396
|
+
}]) }, [..._cache[6] || (_cache[6] = [createElementVNode("svg", {
|
|
2397
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2398
|
+
class: "h-4 w-4",
|
|
2399
|
+
fill: "none",
|
|
2400
|
+
viewBox: "0 0 24 24",
|
|
2401
|
+
stroke: "currentColor"
|
|
2402
|
+
}, [createElementVNode("path", {
|
|
2403
|
+
"stroke-linecap": "round",
|
|
2404
|
+
"stroke-linejoin": "round",
|
|
2405
|
+
"stroke-width": "2",
|
|
2406
|
+
d: "M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
|
2407
|
+
})], -1)])], 2), createElementVNode("div", _hoisted_16$1, [createElementVNode("p", { class: normalizeClass(["font-medium", {
|
|
2408
|
+
"text-error": [
|
|
2409
|
+
"FOLLOWUP",
|
|
2410
|
+
"IN_PROGRESS",
|
|
2411
|
+
"COMPLETED",
|
|
2412
|
+
"CANCELLED"
|
|
2413
|
+
].includes(__props.support_ticket.status),
|
|
2414
|
+
"text-warning": ![
|
|
2415
|
+
"FOLLOWUP",
|
|
2416
|
+
"IN_PROGRESS",
|
|
2417
|
+
"COMPLETED",
|
|
2418
|
+
"CANCELLED"
|
|
2419
|
+
].includes(__props.support_ticket.status)
|
|
2420
|
+
}]) }, toDisplayString([
|
|
2421
|
+
"FOLLOWUP",
|
|
2422
|
+
"IN_PROGRESS",
|
|
2423
|
+
"COMPLETED",
|
|
2424
|
+
"CANCELLED"
|
|
2425
|
+
].includes(__props.support_ticket.status) ? "Credit Deducted" : "Credit Will Be Deducted"), 3), createElementVNode("p", { class: normalizeClass(["text-sm", {
|
|
2426
|
+
"text-error/70": [
|
|
2427
|
+
"FOLLOWUP",
|
|
2428
|
+
"IN_PROGRESS",
|
|
2429
|
+
"COMPLETED",
|
|
2430
|
+
"CANCELLED"
|
|
2431
|
+
].includes(__props.support_ticket.status),
|
|
2432
|
+
"text-warning/70": ![
|
|
2433
|
+
"FOLLOWUP",
|
|
2434
|
+
"IN_PROGRESS",
|
|
2435
|
+
"COMPLETED",
|
|
2436
|
+
"CANCELLED"
|
|
2437
|
+
].includes(__props.support_ticket.status)
|
|
2438
|
+
}]) }, [[
|
|
2439
|
+
"FOLLOWUP",
|
|
2440
|
+
"IN_PROGRESS",
|
|
2441
|
+
"COMPLETED",
|
|
2442
|
+
"CANCELLED"
|
|
2443
|
+
].includes(__props.support_ticket.status) ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [createTextVNode(toDisplayString(unref(formatCustomerCreditValue)(__props.support_ticket.credit_value)) + " credit(s) have been deducted from your account for this ticket ", 1)], 64)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [createTextVNode(toDisplayString(unref(formatCustomerCreditValue)(__props.support_ticket.credit_value)) + " credit(s) will be deducted from your account once this ticket is approved ", 1)], 64))], 2)])])) : createCommentVNode("v-if", true)
|
|
2444
|
+
])
|
|
2445
|
+
])]);
|
|
2446
|
+
};
|
|
2447
|
+
}
|
|
2448
|
+
});
|
|
2449
|
+
var SupportTicketTimeline_default = _sfc_main$13;
|
|
2450
|
+
|
|
2451
|
+
//#endregion
|
|
2452
|
+
//#region src/slices/support_ticket/shared/SupportTicketStatusBadge.vue
|
|
2453
|
+
const _hoisted_1$11 = ["aria-label"];
|
|
2454
|
+
const _sfc_main$12 = /* @__PURE__ */ defineComponent({
|
|
2455
|
+
__name: "SupportTicketStatusBadge",
|
|
2456
|
+
props: {
|
|
2457
|
+
status: {},
|
|
2458
|
+
size: { default: "md" },
|
|
2459
|
+
variant: { default: "default" }
|
|
2460
|
+
},
|
|
2461
|
+
setup(__props) {
|
|
2462
|
+
/**
|
|
2463
|
+
* SupportTicketStatusBadge - A reusable Vue component for displaying support ticket status
|
|
2464
|
+
* as color-coded badges with consistent DaisyUI styling and accessibility features.
|
|
2465
|
+
*
|
|
2466
|
+
* @example
|
|
2467
|
+
* <SupportTicketStatusBadge :status="'PENDING'" size="md" />
|
|
2468
|
+
* <SupportTicketStatusBadge :status="'COMPLETED'" size="sm" variant="outline" />
|
|
2469
|
+
*/
|
|
2470
|
+
const props = __props;
|
|
2471
|
+
/**
|
|
2472
|
+
* Configuration for each status badge
|
|
2473
|
+
*/
|
|
2474
|
+
const statusConfig = {
|
|
2475
|
+
PENDING: {
|
|
2476
|
+
color: "badge-warning",
|
|
2477
|
+
text: "Pending",
|
|
2478
|
+
ariaLabel: "Status: Pending review by support team"
|
|
2479
|
+
},
|
|
2480
|
+
FOLLOWUP: {
|
|
2481
|
+
color: "badge-info",
|
|
2482
|
+
text: "To Do",
|
|
2483
|
+
ariaLabel: "Status: Approved and ready to begin work"
|
|
2484
|
+
},
|
|
2485
|
+
IN_PROGRESS: {
|
|
2486
|
+
color: "badge-secondary",
|
|
2487
|
+
text: "Active",
|
|
2488
|
+
ariaLabel: "Status: Currently being worked on"
|
|
2489
|
+
},
|
|
2490
|
+
VERIFICATION: {
|
|
2491
|
+
color: "badge-warning",
|
|
2492
|
+
text: "Verification",
|
|
2493
|
+
ariaLabel: "Status: Please verify and leave a comment to confirm completion"
|
|
2494
|
+
},
|
|
2495
|
+
COMPLETED: {
|
|
2496
|
+
color: "badge-success",
|
|
2497
|
+
text: "Done",
|
|
2498
|
+
ariaLabel: "Status: Successfully completed"
|
|
2499
|
+
},
|
|
2500
|
+
CANCELLED: {
|
|
2501
|
+
color: "badge-error",
|
|
2502
|
+
text: "Cancelled",
|
|
2503
|
+
ariaLabel: "Status: Cancelled or rejected"
|
|
2504
|
+
}
|
|
2505
|
+
};
|
|
2506
|
+
const getStatusConfig = (status) => {
|
|
2507
|
+
const config$1 = statusConfig[status];
|
|
2508
|
+
if (!config$1) return {
|
|
2509
|
+
color: "badge-neutral",
|
|
2510
|
+
text: status || "Unknown",
|
|
2511
|
+
ariaLabel: `Status: ${status || "Unknown status"}`
|
|
2512
|
+
};
|
|
2513
|
+
return config$1;
|
|
2514
|
+
};
|
|
2515
|
+
const config = computed(() => getStatusConfig(props.status));
|
|
2516
|
+
const badgeClasses = computed(() => {
|
|
2517
|
+
const baseClasses = ["badge", "text-xs"];
|
|
2518
|
+
baseClasses.push(config.value.color);
|
|
2519
|
+
if (props.size === "sm") baseClasses.push("badge-sm", "text-xs");
|
|
2520
|
+
else if (props.size === "lg") baseClasses.push("badge-lg", "text-sm");
|
|
2521
|
+
else baseClasses.push("text-xs", "sm:text-sm");
|
|
2522
|
+
if (props.variant === "outline") baseClasses.push("badge-outline");
|
|
2523
|
+
return baseClasses.join(" ");
|
|
2524
|
+
});
|
|
2525
|
+
const displayText = computed(() => config.value.text);
|
|
2526
|
+
const ariaLabel = computed(() => config.value.ariaLabel);
|
|
2527
|
+
return (_ctx, _cache) => {
|
|
2528
|
+
return openBlock(), createElementBlock("div", {
|
|
2529
|
+
class: normalizeClass(badgeClasses.value),
|
|
2530
|
+
"aria-label": ariaLabel.value,
|
|
2531
|
+
role: "status"
|
|
2532
|
+
}, toDisplayString(displayText.value), 11, _hoisted_1$11);
|
|
2533
|
+
};
|
|
2534
|
+
}
|
|
2535
|
+
});
|
|
2536
|
+
var SupportTicketStatusBadge_default = _sfc_main$12;
|
|
2537
|
+
|
|
2538
|
+
//#endregion
|
|
2539
|
+
//#region src/slices/support_ticket/customer/customerSupportTicketRowSchema.ts
|
|
2540
|
+
/**
|
|
2541
|
+
* Reuse the existing CustomerSupportTicketReadSchema from the validation library
|
|
2542
|
+
* for the data table rows - don't recreate it!
|
|
2543
|
+
*/
|
|
2544
|
+
const customerSupportTicketRowSchemaWithMetadata = withMetadata(CustomerSupportTicketReadSchema, "customerSupportTicketRow", {});
|
|
2545
|
+
|
|
2546
|
+
//#endregion
|
|
2547
|
+
//#region src/slices/support_ticket/customer/CustomerSupportTicketList.vue
|
|
2548
|
+
const _hoisted_1$10 = { class: "mt-2" };
|
|
2549
|
+
const _hoisted_2$9 = { class: "flex flex-col sm:flex-row sm:justify-between sm:items-center gap-4 mb-4" };
|
|
2550
|
+
const _hoisted_3$9 = { class: "flex items-center gap-2" };
|
|
2551
|
+
const _hoisted_4$9 = { class: "flex gap-2" };
|
|
2552
|
+
const _sfc_main$11 = /* @__PURE__ */ defineComponent({
|
|
2553
|
+
__name: "CustomerSupportTicketList",
|
|
2554
|
+
setup(__props) {
|
|
2555
|
+
const route = useRoute();
|
|
2556
|
+
const router = useRouter();
|
|
2557
|
+
const savedFilters = useSavedFilters({
|
|
2558
|
+
context: "support_ticket_customer",
|
|
2559
|
+
routePath: "/support",
|
|
2560
|
+
getFiltersFromTable: () => extractFiltersFromQuery(route.query),
|
|
2561
|
+
applyFiltersToTable: (filters) => {
|
|
2562
|
+
router.push({ query: buildQueryWithFilters(route.query, filters) });
|
|
2563
|
+
}
|
|
2564
|
+
});
|
|
2565
|
+
const hasSupportFilters = computed(() => {
|
|
2566
|
+
const filters = extractFiltersFromQuery(route.query);
|
|
2567
|
+
return Object.keys(filters).length > 0;
|
|
2568
|
+
});
|
|
2569
|
+
const currentPaginationToken = ref();
|
|
2570
|
+
const cursorTable = useCursorDataTable(customerSupportTicketRowSchemaWithMetadata, {
|
|
2571
|
+
fetchData: async ({ cursor, pageSize, sort, filters, search }) => {
|
|
2572
|
+
const variables = {
|
|
2573
|
+
first: pageSize,
|
|
2574
|
+
sortBy: sort?.field ? sort.field : "updated_at",
|
|
2575
|
+
sortDirection: sort?.direction === "asc" ? "asc" : "desc",
|
|
2576
|
+
...cursor ? { after: cursor } : {},
|
|
2577
|
+
...currentPaginationToken.value ? { paginationToken: currentPaginationToken.value } : {},
|
|
2578
|
+
...search ? { search: typeof search === "string" ? {
|
|
2579
|
+
query: search,
|
|
2580
|
+
searchableFields: [
|
|
2581
|
+
"display_id",
|
|
2582
|
+
"title",
|
|
2583
|
+
"description"
|
|
2584
|
+
]
|
|
2585
|
+
} : search } : {},
|
|
2586
|
+
...filters
|
|
2587
|
+
};
|
|
2588
|
+
if (!filters || !filters.status) variables.status = {
|
|
2589
|
+
operator: OPERATORS.IS_NOT_ONE_OF,
|
|
2590
|
+
values: ["COMPLETED", "CANCELLED"]
|
|
2591
|
+
};
|
|
2592
|
+
const result = await executeWithAuth(async (api) => {
|
|
2593
|
+
return await api.supportTickets.listTickets(variables ?? {});
|
|
2594
|
+
}, { refreshTokenHandler: getRefreshTokenHandler() });
|
|
2595
|
+
currentPaginationToken.value = result?.pageInfo?.paginationToken;
|
|
2596
|
+
return {
|
|
2597
|
+
data: result.items || [],
|
|
2598
|
+
hasNextPage: result.pageInfo?.hasNextPage ?? false,
|
|
2599
|
+
hasPreviousPage: result.pageInfo?.hasPreviousPage ?? false,
|
|
2600
|
+
prevPageCursor: result.pageInfo?.prevPageCursor ?? void 0,
|
|
2601
|
+
nextPageCursor: result.pageInfo?.nextPageCursor ?? void 0
|
|
2602
|
+
};
|
|
2603
|
+
},
|
|
2604
|
+
columns: {
|
|
2605
|
+
display_id: {
|
|
2606
|
+
label: "Ticket ID",
|
|
2607
|
+
field: "display_id",
|
|
2608
|
+
sortable: true
|
|
2609
|
+
},
|
|
2610
|
+
title: {
|
|
2611
|
+
label: "Title",
|
|
2612
|
+
field: "title",
|
|
2613
|
+
sortable: true
|
|
2614
|
+
},
|
|
2615
|
+
type: {
|
|
2616
|
+
label: "Type",
|
|
2617
|
+
field: "type",
|
|
2618
|
+
sortable: true,
|
|
2619
|
+
filterable: true,
|
|
2620
|
+
filterType: "select",
|
|
2621
|
+
filterOptions: [...SUPPORT_TICKET_TYPE_FILTER_OPTIONS]
|
|
2622
|
+
},
|
|
2623
|
+
priority: {
|
|
2624
|
+
label: "Priority",
|
|
2625
|
+
field: "priority",
|
|
2626
|
+
sortable: true,
|
|
2627
|
+
filterable: true,
|
|
2628
|
+
filterType: "select",
|
|
2629
|
+
filterOptions: [...SUPPORT_TICKET_PRIORITY_FILTER_OPTIONS]
|
|
2630
|
+
},
|
|
2631
|
+
status: {
|
|
2632
|
+
label: "Status",
|
|
2633
|
+
field: "status",
|
|
2634
|
+
filterable: true,
|
|
2635
|
+
filterType: "select",
|
|
2636
|
+
filterOptions: [...SUPPORT_TICKET_STATUS_FILTER_OPTIONS]
|
|
2637
|
+
},
|
|
2638
|
+
credit_value: {
|
|
2639
|
+
label: "Credits",
|
|
2640
|
+
field: "credit_value",
|
|
2641
|
+
sortable: false
|
|
2642
|
+
},
|
|
2643
|
+
target_at: {
|
|
2644
|
+
label: "Delivery Est.",
|
|
2645
|
+
field: "target_at",
|
|
2646
|
+
sortable: true
|
|
2647
|
+
},
|
|
2648
|
+
updated_at: {
|
|
2649
|
+
label: "Last Updated",
|
|
2650
|
+
field: "updated_at",
|
|
2651
|
+
sortable: true
|
|
2652
|
+
},
|
|
2653
|
+
created_by: {
|
|
2654
|
+
label: "Requester",
|
|
2655
|
+
field: "created_by",
|
|
2656
|
+
sortable: false,
|
|
2657
|
+
filterable: true,
|
|
2658
|
+
filterType: "select",
|
|
2659
|
+
filterOptionsLoader: async () => {
|
|
2660
|
+
return (await executeWithAuth((api) => api.supportTickets.getRequestorsForActiveTickets(), { refreshTokenHandler: getRefreshTokenHandler() }) || []).map((u) => ({
|
|
2661
|
+
value: u.id,
|
|
2662
|
+
label: u.email
|
|
2663
|
+
}));
|
|
2664
|
+
}
|
|
2665
|
+
}
|
|
2666
|
+
},
|
|
2667
|
+
actions: { items: [{
|
|
2668
|
+
key: "view",
|
|
2669
|
+
icon: ActionIcons.eye,
|
|
2670
|
+
size: "xs",
|
|
2671
|
+
variant: "primary",
|
|
2672
|
+
type: "link",
|
|
2673
|
+
href: (row) => `/support/${row.id}`
|
|
2674
|
+
}] },
|
|
2675
|
+
search: { searchableFields: ["title"] },
|
|
2676
|
+
pagination: { pageSize: 25 },
|
|
2677
|
+
autoLoad: false
|
|
2678
|
+
});
|
|
2679
|
+
const { ZiniaDataTable } = cursorTable;
|
|
2680
|
+
useDataTableUrlSync(cursorTable.table, router);
|
|
2681
|
+
const previousFilters = ref({});
|
|
2682
|
+
onMounted(() => {
|
|
2683
|
+
previousFilters.value = extractFiltersFromQuery(route.query);
|
|
2684
|
+
});
|
|
2685
|
+
watch(() => route.query, (query) => {
|
|
2686
|
+
const filters = extractFiltersFromQuery(query);
|
|
2687
|
+
const hadPrevious = Object.keys(previousFilters.value).length > 0;
|
|
2688
|
+
if (!(Object.keys(filters).length > 0) && hadPrevious) savedFilters.clearLastUsed();
|
|
2689
|
+
previousFilters.value = filters;
|
|
2690
|
+
});
|
|
2691
|
+
return (_ctx, _cache) => {
|
|
2692
|
+
const _component_router_link = resolveComponent("router-link");
|
|
2693
|
+
return openBlock(), createElementBlock("div", _hoisted_1$10, [createElementVNode("div", _hoisted_2$9, [createElementVNode("div", _hoisted_3$9, [createVNode(unref(SavedFilterPresets_default), {
|
|
2694
|
+
presets: unref(savedFilters).presets.value,
|
|
2695
|
+
"presets-loading": unref(savedFilters).presetsLoading.value,
|
|
2696
|
+
creating: unref(savedFilters).creating.value,
|
|
2697
|
+
deleting: unref(savedFilters).deleting.value,
|
|
2698
|
+
renaming: unref(savedFilters).updating.value,
|
|
2699
|
+
"has-filters": hasSupportFilters.value,
|
|
2700
|
+
"active-preset": unref(savedFilters).activePreset.value,
|
|
2701
|
+
"apply-preset": unref(savedFilters).applyPreset,
|
|
2702
|
+
"clear-preset": unref(savedFilters).clearPreset,
|
|
2703
|
+
"save-current-filters": unref(savedFilters).saveCurrentFilters,
|
|
2704
|
+
"rename-preset": unref(savedFilters).renamePreset,
|
|
2705
|
+
"remove-preset": unref(savedFilters).removePreset
|
|
2706
|
+
}, null, 8, [
|
|
2707
|
+
"presets",
|
|
2708
|
+
"presets-loading",
|
|
2709
|
+
"creating",
|
|
2710
|
+
"deleting",
|
|
2711
|
+
"renaming",
|
|
2712
|
+
"has-filters",
|
|
2713
|
+
"active-preset",
|
|
2714
|
+
"apply-preset",
|
|
2715
|
+
"clear-preset",
|
|
2716
|
+
"save-current-filters",
|
|
2717
|
+
"rename-preset",
|
|
2718
|
+
"remove-preset"
|
|
2719
|
+
]), _cache[0] || (_cache[0] = createElementVNode("h1", { class: "text-xl sm:text-2xl font-bold" }, "Support Tickets", -1))]), createElementVNode("div", _hoisted_4$9, [createVNode(_component_router_link, {
|
|
2720
|
+
to: { name: "CustomerCreateSupportTicket" },
|
|
2721
|
+
class: "btn btn-primary btn-sm sm:btn-md"
|
|
2722
|
+
}, {
|
|
2723
|
+
default: withCtx(() => [..._cache[1] || (_cache[1] = [createTextVNode(" Create ", -1)])]),
|
|
2724
|
+
_: 1
|
|
2725
|
+
})])]), createVNode(unref(ZiniaDataTable), null, {
|
|
2726
|
+
"cell-displayId": withCtx(({ row }) => [createTextVNode(toDisplayString(unref(formatTicketDisplayId)(row.display_id, row.display_id_prefix, row.id)), 1)]),
|
|
2727
|
+
"cell-type": withCtx(({ row }) => [createVNode(SupportTicketTypeBadge_default, {
|
|
2728
|
+
type: row.type,
|
|
2729
|
+
size: "sm"
|
|
2730
|
+
}, null, 8, ["type"])]),
|
|
2731
|
+
"cell-priority": withCtx(({ row }) => [createVNode(SupportTicketPriorityBadge_default, {
|
|
2732
|
+
priority: row.priority,
|
|
2733
|
+
size: "sm"
|
|
2734
|
+
}, null, 8, ["priority"])]),
|
|
2735
|
+
"cell-status": withCtx(({ row }) => [createVNode(SupportTicketStatusBadge_default, {
|
|
2736
|
+
status: row.status,
|
|
2737
|
+
size: "sm"
|
|
2738
|
+
}, null, 8, ["status"])]),
|
|
2739
|
+
"cell-credit_value": withCtx(({ row }) => [createTextVNode(toDisplayString(unref(formatCustomerCreditValue)(row.credit_value)), 1)]),
|
|
2740
|
+
"cell-created_by": withCtx(({ row }) => [createTextVNode(toDisplayString(row.created_by_display_name), 1)]),
|
|
2741
|
+
"cell-target_at": withCtx(({ row }) => [createTextVNode(toDisplayString(unref(formatUserDate)(row.target_at) || "TBD"), 1)]),
|
|
2742
|
+
"cell-created_at": withCtx(({ row }) => [createTextVNode(toDisplayString(unref(formatSystemTimestamp)(row.created_at)), 1)]),
|
|
2743
|
+
"cell-updated_at": withCtx(({ row }) => [createTextVNode(toDisplayString(unref(formatSystemTimestamp)(row.updated_at)), 1)]),
|
|
2744
|
+
"cell-actions": withCtx(({ row }) => [createVNode(_component_router_link, {
|
|
2745
|
+
to: {
|
|
2746
|
+
name: "EditSupportTicket",
|
|
2747
|
+
params: { id: row.id }
|
|
2748
|
+
},
|
|
2749
|
+
class: "btn btn-sm btn-primary"
|
|
2750
|
+
}, {
|
|
2751
|
+
default: withCtx(() => [..._cache[2] || (_cache[2] = [createTextVNode(" View ", -1)])]),
|
|
2752
|
+
_: 1
|
|
2753
|
+
}, 8, ["to"])]),
|
|
2754
|
+
_: 1
|
|
2755
|
+
})]);
|
|
2756
|
+
};
|
|
2757
|
+
}
|
|
2758
|
+
});
|
|
2759
|
+
var CustomerSupportTicketList_default = _sfc_main$11;
|
|
2760
|
+
|
|
2761
|
+
//#endregion
|
|
2762
|
+
//#region src/slices/support_ticket/staff/components/CustomerCreditBalance.vue
|
|
2763
|
+
const _hoisted_1$9 = {
|
|
2764
|
+
key: 0,
|
|
2765
|
+
class: "flex items-center gap-2"
|
|
2766
|
+
};
|
|
2767
|
+
const _hoisted_2$8 = { class: "space-y-2" };
|
|
2768
|
+
const _hoisted_3$8 = { class: "grid grid-cols-2 gap-2 text-sm" };
|
|
2769
|
+
const _hoisted_4$8 = { class: "font-bold ml-2" };
|
|
2770
|
+
const _hoisted_5$8 = { class: "font-bold ml-2" };
|
|
2771
|
+
const _hoisted_6$7 = {
|
|
2772
|
+
key: 0,
|
|
2773
|
+
class: "alert alert-warning alert-sm"
|
|
2774
|
+
};
|
|
2775
|
+
const _sfc_main$10 = /* @__PURE__ */ defineComponent({
|
|
2776
|
+
__name: "CustomerCreditBalance",
|
|
2777
|
+
setup(__props) {
|
|
2778
|
+
const { data, loading, error } = useQuery((api) => api.customer.getCreditBalance(), { staleTime: 120 * 1e3 });
|
|
2779
|
+
const creditBalance = computed(() => data.value ?? null);
|
|
2780
|
+
const totalAvailable = computed(() => {
|
|
2781
|
+
if (!creditBalance.value) return 0;
|
|
2782
|
+
return (parseFloat(creditBalance.value.monthly) || 0) + (parseFloat(creditBalance.value.rollover) || 0);
|
|
2783
|
+
});
|
|
2784
|
+
return (_ctx, _cache) => {
|
|
2785
|
+
return openBlock(), createElementBlock("div", null, [createCommentVNode(" Loading State "), unref(loading) ? (openBlock(), createElementBlock("div", _hoisted_1$9, [..._cache[0] || (_cache[0] = [createElementVNode("span", { class: "loading loading-spinner loading-sm" }, null, -1), createElementVNode("span", { class: "text-sm" }, "Loading customer balance...", -1)])])) : unref(error) ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [createCommentVNode(" Error State "), _cache[1] || (_cache[1] = createElementVNode("div", { class: "alert alert-error alert-sm" }, [createElementVNode("span", { class: "text-xs" }, "Failed to load customer balance")], -1))], 2112)) : creditBalance.value ? (openBlock(), createElementBlock(Fragment, { key: 2 }, [createCommentVNode(" Balance Display "), createElementVNode("div", _hoisted_2$8, [
|
|
2786
|
+
createElementVNode("div", _hoisted_3$8, [createElementVNode("div", null, [_cache[2] || (_cache[2] = createElementVNode("span", { class: "text-base-content/60" }, "Monthly:", -1)), createElementVNode("span", _hoisted_4$8, toDisplayString(unref(formatStaffCreditValue)(creditBalance.value.monthly)), 1)]), createElementVNode("div", null, [_cache[3] || (_cache[3] = createElementVNode("span", { class: "text-base-content/60" }, "Rollover:", -1)), createElementVNode("span", _hoisted_5$8, toDisplayString(unref(formatStaffCreditValue)(creditBalance.value.rollover)), 1)])]),
|
|
2787
|
+
createElementVNode("div", { class: normalizeClass(["flex items-center justify-between p-2 rounded", {
|
|
2788
|
+
"bg-success/20": totalAvailable.value > 0,
|
|
2789
|
+
"bg-error/20": totalAvailable.value === 0
|
|
2790
|
+
}]) }, [_cache[4] || (_cache[4] = createElementVNode("span", { class: "text-sm font-medium" }, "Total Available:", -1)), createElementVNode("span", { class: normalizeClass(["font-bold", {
|
|
2791
|
+
"text-success": totalAvailable.value > 0,
|
|
2792
|
+
"text-error": totalAvailable.value === 0
|
|
2793
|
+
}]) }, toDisplayString(unref(formatStaffCreditValue)(totalAvailable.value.toString())), 3)], 2),
|
|
2794
|
+
createCommentVNode(" Warning if no balance "),
|
|
2795
|
+
totalAvailable.value === 0 ? (openBlock(), createElementBlock("div", _hoisted_6$7, [..._cache[5] || (_cache[5] = [createElementVNode("svg", {
|
|
2796
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2797
|
+
class: "stroke-current shrink-0 h-4 w-4",
|
|
2798
|
+
fill: "none",
|
|
2799
|
+
viewBox: "0 0 24 24"
|
|
2800
|
+
}, [createElementVNode("path", {
|
|
2801
|
+
"stroke-linecap": "round",
|
|
2802
|
+
"stroke-linejoin": "round",
|
|
2803
|
+
"stroke-width": "2",
|
|
2804
|
+
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"
|
|
2805
|
+
})], -1), createElementVNode("span", { class: "text-xs" }, "Customer has insufficient credits", -1)])])) : createCommentVNode("v-if", true)
|
|
2806
|
+
])], 2112)) : createCommentVNode("v-if", true)]);
|
|
2807
|
+
};
|
|
2808
|
+
}
|
|
2809
|
+
});
|
|
2810
|
+
var CustomerCreditBalance_default = _sfc_main$10;
|
|
2811
|
+
|
|
2812
|
+
//#endregion
|
|
2813
|
+
//#region src/slices/support_ticket/staff/components/ApproveRejectActions.vue
|
|
2814
|
+
const _hoisted_1$8 = {
|
|
2815
|
+
key: 0,
|
|
2816
|
+
class: "alert alert-warning py-2"
|
|
2817
|
+
};
|
|
2818
|
+
const _hoisted_2$7 = {
|
|
2819
|
+
key: 1,
|
|
2820
|
+
class: "space-y-3"
|
|
2821
|
+
};
|
|
2822
|
+
const _hoisted_3$7 = { class: "alert alert-info py-2" };
|
|
2823
|
+
const _hoisted_4$7 = { class: "text-xs sm:text-sm" };
|
|
2824
|
+
const _hoisted_5$7 = { class: "bg-base-100 rounded-lg p-3" };
|
|
2825
|
+
const _hoisted_6$6 = { class: "flex flex-col sm:flex-row gap-2 sm:gap-3 justify-end mt-4" };
|
|
2826
|
+
const _hoisted_7$6 = ["disabled"];
|
|
2827
|
+
const _hoisted_8$6 = {
|
|
2828
|
+
key: 0,
|
|
2829
|
+
class: "loading loading-spinner loading-sm mr-2"
|
|
2830
|
+
};
|
|
2831
|
+
const _hoisted_9$5 = ["disabled"];
|
|
2832
|
+
const _hoisted_10$2 = {
|
|
2833
|
+
key: 0,
|
|
2834
|
+
class: "loading loading-spinner loading-sm mr-2"
|
|
2835
|
+
};
|
|
2836
|
+
const _hoisted_11$2 = {
|
|
2837
|
+
key: 2,
|
|
2838
|
+
class: "alert alert-error mt-2 py-2"
|
|
2839
|
+
};
|
|
2840
|
+
const _hoisted_12$2 = { class: "text-sm" };
|
|
2841
|
+
const _hoisted_13$1 = { class: "alert alert-warning py-2" };
|
|
2842
|
+
const _hoisted_14$1 = { class: "text-xs sm:text-sm" };
|
|
2843
|
+
const _hoisted_15 = { class: "font-semibold" };
|
|
2844
|
+
const _hoisted_16 = {
|
|
2845
|
+
key: 0,
|
|
2846
|
+
class: "alert alert-info py-2"
|
|
2847
|
+
};
|
|
2848
|
+
const _hoisted_17 = { class: "text-xs sm:text-sm" };
|
|
2849
|
+
const _hoisted_18 = { class: "flex mt-4" };
|
|
2850
|
+
const _hoisted_19 = ["disabled"];
|
|
2851
|
+
const _hoisted_20 = {
|
|
2852
|
+
key: 0,
|
|
2853
|
+
class: "loading loading-spinner loading-sm mr-2"
|
|
2854
|
+
};
|
|
2855
|
+
const _hoisted_21 = {
|
|
2856
|
+
key: 1,
|
|
2857
|
+
class: "alert alert-error mt-2 py-2"
|
|
2858
|
+
};
|
|
2859
|
+
const _hoisted_22 = { class: "text-sm" };
|
|
2860
|
+
const _hoisted_23 = { class: "modal-box" };
|
|
2861
|
+
const _hoisted_24 = { class: "font-bold text-lg" };
|
|
2862
|
+
const _hoisted_25 = { class: "py-4 whitespace-pre-line" };
|
|
2863
|
+
const _hoisted_26 = { class: "modal-action" };
|
|
2864
|
+
const _hoisted_27 = { class: "modal-box" };
|
|
2865
|
+
const _hoisted_28 = { class: "form-control py-4" };
|
|
2866
|
+
const _hoisted_29 = ["disabled"];
|
|
2867
|
+
const _hoisted_30 = {
|
|
2868
|
+
key: 0,
|
|
2869
|
+
class: "alert alert-error py-2 mb-4"
|
|
2870
|
+
};
|
|
2871
|
+
const _hoisted_31 = { class: "text-sm" };
|
|
2872
|
+
const _hoisted_32 = { class: "modal-action" };
|
|
2873
|
+
const _hoisted_33 = ["disabled"];
|
|
2874
|
+
const _hoisted_34 = ["disabled"];
|
|
2875
|
+
const _hoisted_35 = {
|
|
2876
|
+
key: 0,
|
|
2877
|
+
class: "loading loading-spinner loading-xs mr-2"
|
|
2878
|
+
};
|
|
2879
|
+
const _sfc_main$9 = /* @__PURE__ */ defineComponent({
|
|
2880
|
+
__name: "ApproveRejectActions",
|
|
2881
|
+
props: { support_ticket: {} },
|
|
2882
|
+
emits: ["update"],
|
|
2883
|
+
setup(__props, { expose: __expose, emit: __emit }) {
|
|
2884
|
+
const props = __props;
|
|
2885
|
+
const emit = __emit;
|
|
2886
|
+
const error = ref(null);
|
|
2887
|
+
const confirmModal = ref(null);
|
|
2888
|
+
const modalTitle = ref("");
|
|
2889
|
+
const modalMessage = ref("");
|
|
2890
|
+
const modalButtonText = ref("");
|
|
2891
|
+
const modalButtonClass = ref("");
|
|
2892
|
+
const modalCallback = ref(null);
|
|
2893
|
+
const rejectModal = ref(null);
|
|
2894
|
+
const rejectReason = ref("");
|
|
2895
|
+
const rejectError = ref(null);
|
|
2896
|
+
const { mutate: approveSupportTicket, loading: isApproving } = useMutation((api, input) => api.supportTickets.approveTicket(input), { invalidate: /^support-tickets?:/ });
|
|
2897
|
+
const { mutate: rejectSupportTicket, loading: isRejecting } = useMutation((api, input) => api.supportTickets.rejectTicket(input), { invalidate: /^support-tickets?:/ });
|
|
2898
|
+
const { mutate: createNote } = useMutation((api, input) => api.notes.createNote(input), { invalidate: /^notes?:/ });
|
|
2899
|
+
const { mutate: revertSupportTicket, loading: isReverting } = useMutation((api, input) => api.supportTickets.revertTicket(input), { invalidate: /^support-tickets?:/ });
|
|
2900
|
+
const showApproveModal = () => {
|
|
2901
|
+
const creditDisplay = formatStaffCreditValue(props.support_ticket.credit_value, props.support_ticket.approval_status);
|
|
2902
|
+
const credits = creditDisplay === "TBD" || creditDisplay === "N/A" ? 0 : parseFloat(creditDisplay);
|
|
2903
|
+
modalTitle.value = "Approve Support Ticket?";
|
|
2904
|
+
modalMessage.value = `This will:\n\n• Deduct ${credits.toFixed(2)} credits from customer\n• Lock the support ticket item\n• Start development workflow\n\nThis action cannot be undone.`;
|
|
2905
|
+
modalButtonText.value = "Approve & Deduct";
|
|
2906
|
+
modalButtonClass.value = "btn-success";
|
|
2907
|
+
modalCallback.value = handleApprove;
|
|
2908
|
+
confirmModal.value?.showModal();
|
|
2909
|
+
};
|
|
2910
|
+
const showRejectModal = () => {
|
|
2911
|
+
rejectReason.value = "";
|
|
2912
|
+
rejectError.value = null;
|
|
2913
|
+
rejectModal.value?.showModal();
|
|
2914
|
+
};
|
|
2915
|
+
const showRevertModal = () => {
|
|
2916
|
+
modalTitle.value = "Revert Support Ticket to PENDING?";
|
|
2917
|
+
const creditDisplay = formatStaffCreditValue(props.support_ticket.credit_value, props.support_ticket.approval_status);
|
|
2918
|
+
modalMessage.value = "This will:\n\n• Change status back to PENDING\n• Unlock the support ticket item\n" + (creditDisplay !== "TBD" && creditDisplay !== "N/A" ? `• Refund ${creditDisplay} credits to customer\n` : "") + "• Allow the customer to edit again\n\nAre you sure you want to revert this decision?";
|
|
2919
|
+
modalButtonText.value = "Revert to PENDING";
|
|
2920
|
+
modalButtonClass.value = "btn-warning";
|
|
2921
|
+
modalCallback.value = handleRevert;
|
|
2922
|
+
confirmModal.value?.showModal();
|
|
2923
|
+
};
|
|
2924
|
+
const closeModal = () => {
|
|
2925
|
+
confirmModal.value?.close();
|
|
2926
|
+
modalCallback.value = null;
|
|
2927
|
+
};
|
|
2928
|
+
const closeRejectModal = () => {
|
|
2929
|
+
rejectModal.value?.close();
|
|
2930
|
+
rejectReason.value = "";
|
|
2931
|
+
rejectError.value = null;
|
|
2932
|
+
};
|
|
2933
|
+
const handleApprove = async () => {
|
|
2934
|
+
error.value = null;
|
|
2935
|
+
const creditValue = props.support_ticket.credit_value?.trim();
|
|
2936
|
+
if (!creditValue) {
|
|
2937
|
+
error.value = "Credit value is required to approve";
|
|
2938
|
+
toast.error("Credit value is required to approve");
|
|
2939
|
+
return;
|
|
2940
|
+
}
|
|
2941
|
+
closeModal();
|
|
2942
|
+
try {
|
|
2943
|
+
const response = await approveSupportTicket({
|
|
2944
|
+
id: props.support_ticket.id,
|
|
2945
|
+
credit_value: creditValue
|
|
2946
|
+
});
|
|
2947
|
+
toast.success(`Support Ticket approved! ${formatStaffCreditValue(props.support_ticket.credit_value, props.support_ticket.approval_status)} credits deducted.`);
|
|
2948
|
+
emit("update", response);
|
|
2949
|
+
} catch (e) {
|
|
2950
|
+
const errorMessage = extractRpcErrorMessage(e, "Failed to approve");
|
|
2951
|
+
error.value = errorMessage;
|
|
2952
|
+
toast.error(errorMessage);
|
|
2953
|
+
}
|
|
2954
|
+
};
|
|
2955
|
+
const handleRejectWithReason = async () => {
|
|
2956
|
+
rejectError.value = null;
|
|
2957
|
+
error.value = null;
|
|
2958
|
+
try {
|
|
2959
|
+
const reasonTrimmed = rejectReason.value.trim();
|
|
2960
|
+
if (reasonTrimmed) await createNote({
|
|
2961
|
+
record_id: props.support_ticket.id,
|
|
2962
|
+
record_type: "support_ticket",
|
|
2963
|
+
body: reasonTrimmed,
|
|
2964
|
+
tag: null,
|
|
2965
|
+
is_internal: false
|
|
2966
|
+
});
|
|
2967
|
+
const response = await rejectSupportTicket({ id: props.support_ticket.id });
|
|
2968
|
+
toast.info("Support Ticket rejected.");
|
|
2969
|
+
closeRejectModal();
|
|
2970
|
+
emit("update", response);
|
|
2971
|
+
} catch (e) {
|
|
2972
|
+
const errorMessage = extractRpcErrorMessage(e, "Failed to reject");
|
|
2973
|
+
rejectError.value = errorMessage;
|
|
2974
|
+
toast.error(errorMessage);
|
|
2975
|
+
}
|
|
2976
|
+
};
|
|
2977
|
+
const handleRevert = async () => {
|
|
2978
|
+
error.value = null;
|
|
2979
|
+
closeModal();
|
|
2980
|
+
try {
|
|
2981
|
+
const response = await revertSupportTicket({ id: props.support_ticket.id });
|
|
2982
|
+
const creditDisplay = formatStaffCreditValue(props.support_ticket.credit_value, props.support_ticket.approval_status);
|
|
2983
|
+
const refundMessage = creditDisplay !== "TBD" && creditDisplay !== "N/A" ? ` ${creditDisplay} credits refunded.` : "";
|
|
2984
|
+
toast.success(`Support Ticket reverted to PENDING.${refundMessage}`);
|
|
2985
|
+
emit("update", response);
|
|
2986
|
+
} catch (e) {
|
|
2987
|
+
const errorMessage = extractRpcErrorMessage(e, "Failed to revert");
|
|
2988
|
+
error.value = errorMessage;
|
|
2989
|
+
toast.error(errorMessage);
|
|
2990
|
+
}
|
|
2991
|
+
};
|
|
2992
|
+
__expose({
|
|
2993
|
+
showApproveModal,
|
|
2994
|
+
showRejectModal
|
|
2995
|
+
});
|
|
2996
|
+
return (_ctx, _cache) => {
|
|
2997
|
+
return openBlock(), createElementBlock(Fragment, null, [
|
|
2998
|
+
createCommentVNode(" Approve/Reject Section (PENDING only) "),
|
|
2999
|
+
props.support_ticket.approval_status === "PENDING" ? (openBlock(), createBlock(ZiniaContainer_default, { key: 0 }, {
|
|
3000
|
+
default: withCtx(() => [
|
|
3001
|
+
_cache[4] || (_cache[4] = createElementVNode("h3", { class: "card-title text-base sm:text-lg" }, "Approve or Reject", -1)),
|
|
3002
|
+
unref(formatStaffCreditValue)(props.support_ticket.credit_value, props.support_ticket.approval_status) === "TBD" ? (openBlock(), createElementBlock("div", _hoisted_1$8, [..._cache[2] || (_cache[2] = [createElementVNode("div", null, [createElementVNode("svg", {
|
|
3003
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
3004
|
+
class: "stroke-current shrink-0 h-5 w-5",
|
|
3005
|
+
fill: "none",
|
|
3006
|
+
viewBox: "0 0 24 24"
|
|
3007
|
+
}, [createElementVNode("path", {
|
|
3008
|
+
"stroke-linecap": "round",
|
|
3009
|
+
"stroke-linejoin": "round",
|
|
3010
|
+
"stroke-width": "2",
|
|
3011
|
+
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"
|
|
3012
|
+
})]), createElementVNode("span", { class: "text-xs sm:text-sm" }, "You must set an estimate before approving")], -1)])])) : (openBlock(), createElementBlock("div", _hoisted_2$7, [
|
|
3013
|
+
createElementVNode("div", _hoisted_3$7, [createElementVNode("div", null, [createElementVNode("span", _hoisted_4$7, "Estimate: " + toDisplayString(unref(formatStaffCreditValue)(props.support_ticket.credit_value, props.support_ticket.approval_status)) + " credits", 1)])]),
|
|
3014
|
+
createCommentVNode(" Show Customer's Credit Balance "),
|
|
3015
|
+
createElementVNode("div", _hoisted_5$7, [_cache[3] || (_cache[3] = createElementVNode("h4", { class: "text-xs sm:text-sm font-medium mb-2" }, "Customer Balance Check", -1)), createVNode(CustomerCreditBalance_default)])
|
|
3016
|
+
])),
|
|
3017
|
+
createElementVNode("div", _hoisted_6$6, [createElementVNode("button", {
|
|
3018
|
+
class: "btn btn-error btn-outline w-full sm:w-auto order-2 sm:order-1",
|
|
3019
|
+
onClick: withModifiers(showRejectModal, ["prevent"]),
|
|
3020
|
+
disabled: unref(isApproving) || unref(isRejecting)
|
|
3021
|
+
}, [unref(isRejecting) ? (openBlock(), createElementBlock("span", _hoisted_8$6)) : createCommentVNode("v-if", true), createTextVNode(" " + toDisplayString(unref(isRejecting) ? "Rejecting..." : "Reject"), 1)], 8, _hoisted_7$6), createElementVNode("button", {
|
|
3022
|
+
class: "btn btn-success w-full sm:w-auto order-1 sm:order-2",
|
|
3023
|
+
onClick: withModifiers(showApproveModal, ["prevent"]),
|
|
3024
|
+
disabled: unref(formatStaffCreditValue)(props.support_ticket.credit_value, props.support_ticket.approval_status) === "TBD" || unref(isApproving) || unref(isRejecting)
|
|
3025
|
+
}, [unref(isApproving) ? (openBlock(), createElementBlock("span", _hoisted_10$2)) : createCommentVNode("v-if", true), createTextVNode(" " + toDisplayString(unref(isApproving) ? "Approving..." : "Approve & Deduct"), 1)], 8, _hoisted_9$5)]),
|
|
3026
|
+
error.value ? (openBlock(), createElementBlock("div", _hoisted_11$2, [createElementVNode("span", _hoisted_12$2, toDisplayString(error.value), 1)])) : createCommentVNode("v-if", true)
|
|
3027
|
+
]),
|
|
3028
|
+
_: 1
|
|
3029
|
+
})) : props.support_ticket.approval_status === "APPROVED" || props.support_ticket.approval_status === "REJECTED" ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [createCommentVNode(" Revert Section (APPROVED/REJECTED only) "), createVNode(ZiniaContainer_default, null, {
|
|
3030
|
+
default: withCtx(() => [
|
|
3031
|
+
_cache[9] || (_cache[9] = createElementVNode("h3", { class: "card-title text-base sm:text-lg" }, "Revert Decision", -1)),
|
|
3032
|
+
createElementVNode("div", _hoisted_13$1, [_cache[8] || (_cache[8] = createElementVNode("svg", {
|
|
3033
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
3034
|
+
class: "stroke-current shrink-0 h-5 w-5",
|
|
3035
|
+
fill: "none",
|
|
3036
|
+
viewBox: "0 0 24 24"
|
|
3037
|
+
}, [createElementVNode("path", {
|
|
3038
|
+
"stroke-linecap": "round",
|
|
3039
|
+
"stroke-linejoin": "round",
|
|
3040
|
+
"stroke-width": "2",
|
|
3041
|
+
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"
|
|
3042
|
+
})], -1)), createElementVNode("div", _hoisted_14$1, [_cache[7] || (_cache[7] = createElementVNode("div", { class: "font-medium mb-1" }, "Admin Action Required", -1)), createElementVNode("div", null, [
|
|
3043
|
+
_cache[5] || (_cache[5] = createTextVNode(" This support ticket is currently ", -1)),
|
|
3044
|
+
createElementVNode("span", _hoisted_15, toDisplayString(props.support_ticket.approval_status), 1),
|
|
3045
|
+
_cache[6] || (_cache[6] = createTextVNode(". You can revert it back to PENDING status. ", -1))
|
|
3046
|
+
])])]),
|
|
3047
|
+
unref(formatStaffCreditValue)(props.support_ticket.credit_value, props.support_ticket.approval_status) !== "TBD" && unref(formatStaffCreditValue)(props.support_ticket.credit_value, props.support_ticket.approval_status) !== "N/A" ? (openBlock(), createElementBlock("div", _hoisted_16, [createElementVNode("div", _hoisted_17, " Credits: " + toDisplayString(unref(formatStaffCreditValue)(props.support_ticket.credit_value, props.support_ticket.approval_status)) + " will be refunded to customer ", 1)])) : createCommentVNode("v-if", true),
|
|
3048
|
+
createElementVNode("div", _hoisted_18, [createElementVNode("button", {
|
|
3049
|
+
class: "btn btn-warning w-full sm:w-auto",
|
|
3050
|
+
onClick: withModifiers(showRevertModal, ["prevent"]),
|
|
3051
|
+
disabled: unref(isReverting)
|
|
3052
|
+
}, [unref(isReverting) ? (openBlock(), createElementBlock("span", _hoisted_20)) : createCommentVNode("v-if", true), createTextVNode(" " + toDisplayString(unref(isReverting) ? "Reverting..." : "Revert to PENDING"), 1)], 8, _hoisted_19)]),
|
|
3053
|
+
error.value ? (openBlock(), createElementBlock("div", _hoisted_21, [createElementVNode("span", _hoisted_22, toDisplayString(error.value), 1)])) : createCommentVNode("v-if", true)
|
|
3054
|
+
]),
|
|
3055
|
+
_: 1
|
|
3056
|
+
})], 2112)) : createCommentVNode("v-if", true),
|
|
3057
|
+
createCommentVNode(" Confirmation Modal (for Approve and Revert) "),
|
|
3058
|
+
createElementVNode("dialog", {
|
|
3059
|
+
ref_key: "confirmModal",
|
|
3060
|
+
ref: confirmModal,
|
|
3061
|
+
class: "modal"
|
|
3062
|
+
}, [createElementVNode("div", _hoisted_23, [
|
|
3063
|
+
createElementVNode("h3", _hoisted_24, toDisplayString(modalTitle.value), 1),
|
|
3064
|
+
createElementVNode("p", _hoisted_25, toDisplayString(modalMessage.value), 1),
|
|
3065
|
+
createElementVNode("div", _hoisted_26, [createElementVNode("button", {
|
|
3066
|
+
class: "btn btn-ghost",
|
|
3067
|
+
onClick: closeModal
|
|
3068
|
+
}, "Cancel"), createElementVNode("button", {
|
|
3069
|
+
class: normalizeClass(["btn", modalButtonClass.value]),
|
|
3070
|
+
onClick: _cache[0] || (_cache[0] = () => modalCallback.value?.())
|
|
3071
|
+
}, toDisplayString(modalButtonText.value), 3)])
|
|
3072
|
+
]), createElementVNode("form", {
|
|
3073
|
+
method: "dialog",
|
|
3074
|
+
class: "modal-backdrop"
|
|
3075
|
+
}, [createElementVNode("button", { onClick: closeModal }, "close")])], 512),
|
|
3076
|
+
createCommentVNode(" Reject Modal with Reason "),
|
|
3077
|
+
createElementVNode("dialog", {
|
|
3078
|
+
ref_key: "rejectModal",
|
|
3079
|
+
ref: rejectModal,
|
|
3080
|
+
class: "modal"
|
|
3081
|
+
}, [createElementVNode("div", _hoisted_27, [
|
|
3082
|
+
_cache[11] || (_cache[11] = createElementVNode("h3", { class: "font-bold text-lg" }, "Reject Ticket", -1)),
|
|
3083
|
+
_cache[12] || (_cache[12] = createElementVNode("p", { class: "text-sm text-base-content/70 py-2" }, " This will lock the ticket and notify the requester. ", -1)),
|
|
3084
|
+
createElementVNode("div", _hoisted_28, [_cache[10] || (_cache[10] = createElementVNode("label", { class: "label" }, [createElementVNode("span", { class: "label-text text-sm font-medium" }, "Reason (optional)")], -1)), withDirectives(createElementVNode("textarea", {
|
|
3085
|
+
"onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => rejectReason.value = $event),
|
|
3086
|
+
class: "textarea textarea-bordered w-full",
|
|
3087
|
+
rows: "3",
|
|
3088
|
+
placeholder: "Why is this ticket being rejected?",
|
|
3089
|
+
disabled: unref(isRejecting)
|
|
3090
|
+
}, null, 8, _hoisted_29), [[vModelText, rejectReason.value]])]),
|
|
3091
|
+
rejectError.value ? (openBlock(), createElementBlock("div", _hoisted_30, [createElementVNode("span", _hoisted_31, toDisplayString(rejectError.value), 1)])) : createCommentVNode("v-if", true),
|
|
3092
|
+
createElementVNode("div", _hoisted_32, [createElementVNode("button", {
|
|
3093
|
+
class: "btn btn-ghost",
|
|
3094
|
+
onClick: closeRejectModal,
|
|
3095
|
+
disabled: unref(isRejecting)
|
|
3096
|
+
}, " Cancel ", 8, _hoisted_33), createElementVNode("button", {
|
|
3097
|
+
class: "btn btn-error",
|
|
3098
|
+
onClick: handleRejectWithReason,
|
|
3099
|
+
disabled: unref(isRejecting)
|
|
3100
|
+
}, [unref(isRejecting) ? (openBlock(), createElementBlock("span", _hoisted_35)) : createCommentVNode("v-if", true), createTextVNode(" " + toDisplayString(unref(isRejecting) ? "Rejecting..." : "Reject Ticket"), 1)], 8, _hoisted_34)])
|
|
3101
|
+
]), createElementVNode("form", {
|
|
3102
|
+
method: "dialog",
|
|
3103
|
+
class: "modal-backdrop"
|
|
3104
|
+
}, [createElementVNode("button", { onClick: closeRejectModal }, "close")])], 512)
|
|
3105
|
+
], 64);
|
|
3106
|
+
};
|
|
3107
|
+
}
|
|
3108
|
+
});
|
|
3109
|
+
var ApproveRejectActions_default = _sfc_main$9;
|
|
3110
|
+
|
|
3111
|
+
//#endregion
|
|
3112
|
+
//#region src/slices/support_ticket/staff/components/CancelInternalTaskWorkflow.vue
|
|
3113
|
+
const _hoisted_1$7 = { class: "flex justify-end mt-4" };
|
|
3114
|
+
const _hoisted_2$6 = ["disabled"];
|
|
3115
|
+
const _hoisted_3$6 = {
|
|
3116
|
+
key: 0,
|
|
3117
|
+
class: "loading loading-spinner loading-sm mr-2"
|
|
3118
|
+
};
|
|
3119
|
+
const _hoisted_4$6 = {
|
|
3120
|
+
key: 0,
|
|
3121
|
+
class: "alert alert-error mt-2 py-2"
|
|
3122
|
+
};
|
|
3123
|
+
const _hoisted_5$6 = { class: "text-sm" };
|
|
3124
|
+
const _hoisted_6$5 = { class: "modal-box" };
|
|
3125
|
+
const _hoisted_7$5 = { class: "font-bold text-lg" };
|
|
3126
|
+
const _hoisted_8$5 = { class: "py-4 whitespace-pre-line" };
|
|
3127
|
+
const _hoisted_9$4 = { class: "modal-action" };
|
|
3128
|
+
const _sfc_main$8 = /* @__PURE__ */ defineComponent({
|
|
3129
|
+
__name: "CancelInternalTaskWorkflow",
|
|
3130
|
+
props: { support_ticket: {} },
|
|
3131
|
+
emits: ["update"],
|
|
3132
|
+
setup(__props, { emit: __emit }) {
|
|
3133
|
+
const props = __props;
|
|
3134
|
+
const emit = __emit;
|
|
3135
|
+
const error = ref(null);
|
|
3136
|
+
const confirmModal = ref(null);
|
|
3137
|
+
const modalTitle = ref("");
|
|
3138
|
+
const modalMessage = ref("");
|
|
3139
|
+
const modalButtonText = ref("");
|
|
3140
|
+
const modalCallback = ref(null);
|
|
3141
|
+
const { mutate: cancelInternalTask, loading: isCancelling } = useMutation((api, input) => api.supportTickets.cancelInternalTask(input), { invalidate: /^support-tickets?:/ });
|
|
3142
|
+
const showCancelModal = () => {
|
|
3143
|
+
modalTitle.value = "Cancel Internal Task?";
|
|
3144
|
+
modalMessage.value = "This will:\n\n• Set dev lifecycle to CANCELLED\n• Record completion timestamp\n• Mark task as complete (terminal state)\n\nThis action cannot be undone. The task will remain in the system as cancelled.";
|
|
3145
|
+
modalButtonText.value = "Cancel Task";
|
|
3146
|
+
modalCallback.value = handleCancel;
|
|
3147
|
+
confirmModal.value?.showModal();
|
|
3148
|
+
};
|
|
3149
|
+
const handleCancel = async () => {
|
|
3150
|
+
error.value = null;
|
|
3151
|
+
try {
|
|
3152
|
+
const result = await cancelInternalTask({ id: props.support_ticket.id });
|
|
3153
|
+
toast.success("✅ Internal task cancelled successfully");
|
|
3154
|
+
closeModal();
|
|
3155
|
+
emit("update", result);
|
|
3156
|
+
} catch (err) {
|
|
3157
|
+
error.value = err instanceof Error ? err.message : "Failed to cancel task";
|
|
3158
|
+
toast.error(`❌ ${error.value}`);
|
|
3159
|
+
}
|
|
3160
|
+
};
|
|
3161
|
+
const closeModal = () => {
|
|
3162
|
+
confirmModal.value?.close();
|
|
3163
|
+
};
|
|
3164
|
+
return (_ctx, _cache) => {
|
|
3165
|
+
return openBlock(), createElementBlock(Fragment, null, [
|
|
3166
|
+
createCommentVNode(" Cancel Internal Task Section (INTERNAL only, not CANCELLED) "),
|
|
3167
|
+
props.support_ticket.approval_status === "INTERNAL" && props.support_ticket.dev_lifecycle !== "CANCELLED" ? (openBlock(), createBlock(ZiniaContainer_default, { key: 0 }, {
|
|
3168
|
+
default: withCtx(() => [
|
|
3169
|
+
_cache[1] || (_cache[1] = createElementVNode("h3", { class: "card-title text-base sm:text-lg" }, "Cancel Internal Task", -1)),
|
|
3170
|
+
_cache[2] || (_cache[2] = createElementVNode("div", { class: "alert alert-warning py-2" }, [createElementVNode("div", { class: "flex flex-col gap-2" }, [createElementVNode("span", { class: "font-semibold text-sm" }, "What happens when you cancel:"), createElementVNode("ul", { class: "text-xs sm:text-sm space-y-1 ml-4 list-disc" }, [
|
|
3171
|
+
createElementVNode("li", null, "Sets dev lifecycle to CANCELLED"),
|
|
3172
|
+
createElementVNode("li", null, "Records completion timestamp"),
|
|
3173
|
+
createElementVNode("li", null, "Task is marked as terminal state"),
|
|
3174
|
+
createElementVNode("li", null, "No credit impact (internal tasks have no credits)")
|
|
3175
|
+
])])], -1)),
|
|
3176
|
+
createElementVNode("div", _hoisted_1$7, [createElementVNode("button", {
|
|
3177
|
+
class: "btn btn-error w-full sm:w-auto",
|
|
3178
|
+
onClick: withModifiers(showCancelModal, ["prevent"]),
|
|
3179
|
+
disabled: unref(isCancelling)
|
|
3180
|
+
}, [unref(isCancelling) ? (openBlock(), createElementBlock("span", _hoisted_3$6)) : createCommentVNode("v-if", true), createTextVNode(" " + toDisplayString(unref(isCancelling) ? "Cancelling..." : "Cancel Internal Task"), 1)], 8, _hoisted_2$6)]),
|
|
3181
|
+
error.value ? (openBlock(), createElementBlock("div", _hoisted_4$6, [createElementVNode("span", _hoisted_5$6, toDisplayString(error.value), 1)])) : createCommentVNode("v-if", true)
|
|
3182
|
+
]),
|
|
3183
|
+
_: 1
|
|
3184
|
+
})) : createCommentVNode("v-if", true),
|
|
3185
|
+
createCommentVNode(" Confirmation Modal "),
|
|
3186
|
+
createElementVNode("dialog", {
|
|
3187
|
+
ref_key: "confirmModal",
|
|
3188
|
+
ref: confirmModal,
|
|
3189
|
+
class: "modal"
|
|
3190
|
+
}, [createElementVNode("div", _hoisted_6$5, [
|
|
3191
|
+
createElementVNode("h3", _hoisted_7$5, toDisplayString(modalTitle.value), 1),
|
|
3192
|
+
createElementVNode("p", _hoisted_8$5, toDisplayString(modalMessage.value), 1),
|
|
3193
|
+
createElementVNode("div", _hoisted_9$4, [createElementVNode("button", {
|
|
3194
|
+
class: "btn btn-ghost",
|
|
3195
|
+
onClick: closeModal
|
|
3196
|
+
}, "Cancel"), createElementVNode("button", {
|
|
3197
|
+
class: "btn btn-error",
|
|
3198
|
+
onClick: _cache[0] || (_cache[0] = () => modalCallback.value?.())
|
|
3199
|
+
}, toDisplayString(modalButtonText.value), 1)])
|
|
3200
|
+
]), createElementVNode("form", {
|
|
3201
|
+
method: "dialog",
|
|
3202
|
+
class: "modal-backdrop"
|
|
3203
|
+
}, [createElementVNode("button", { onClick: closeModal }, "close")])], 512)
|
|
3204
|
+
], 64);
|
|
3205
|
+
};
|
|
3206
|
+
}
|
|
3207
|
+
});
|
|
3208
|
+
var CancelInternalTaskWorkflow_default = _sfc_main$8;
|
|
3209
|
+
|
|
3210
|
+
//#endregion
|
|
3211
|
+
//#region src/slices/support_ticket/staff/components/CompleteSupportTicketForm.vue
|
|
3212
|
+
const _hoisted_1$6 = { class: "text-xs sm:text-sm text-base-content/70 mb-4" };
|
|
3213
|
+
const _hoisted_2$5 = { class: "font-semibold" };
|
|
3214
|
+
const _hoisted_3$5 = { class: "text-xs sm:text-sm" };
|
|
3215
|
+
const _hoisted_4$5 = { class: "grid grid-cols-2 gap-2 sm:gap-4 mt-2" };
|
|
3216
|
+
const _hoisted_5$5 = { class: "bg-base-100 p-3 rounded-lg" };
|
|
3217
|
+
const _hoisted_6$4 = { class: "text-lg sm:text-xl font-bold text-primary" };
|
|
3218
|
+
const _hoisted_7$4 = { class: "bg-base-100 p-3 rounded-lg" };
|
|
3219
|
+
const _hoisted_8$4 = { class: "text-xs text-base-content/60" };
|
|
3220
|
+
const _sfc_main$7 = /* @__PURE__ */ defineComponent({
|
|
3221
|
+
__name: "CompleteSupportTicketForm",
|
|
3222
|
+
props: { support_ticket: {} },
|
|
3223
|
+
emits: ["update"],
|
|
3224
|
+
setup(__props, { emit: __emit }) {
|
|
3225
|
+
const props = __props;
|
|
3226
|
+
const emit = __emit;
|
|
3227
|
+
const { form, zinia, ZiniaSubmitButton, ZiniaForm } = useForm(withMetadata(CompleteSupportTicketSchema.pick({ delivered_value: true }), "completeSupportTicketSchema", { delivered_value: {
|
|
3228
|
+
inputType: "text",
|
|
3229
|
+
placeholder: "100.00"
|
|
3230
|
+
} }), {
|
|
3231
|
+
storeName: `complete-support_ticket-${props.support_ticket.id}`,
|
|
3232
|
+
persistToLocalStorage: false,
|
|
3233
|
+
renderStyle: "daisy_ui",
|
|
3234
|
+
initialValues: { delivered_value: formatStaffCreditValue(props.support_ticket.credit_value, props.support_ticket.approval_status) === "TBD" || formatStaffCreditValue(props.support_ticket.credit_value, props.support_ticket.approval_status) === "N/A" ? "0.00" : formatStaffCreditValue(props.support_ticket.credit_value, props.support_ticket.approval_status) }
|
|
3235
|
+
});
|
|
3236
|
+
const { mutate: completeSupportTicket } = useMutation((api, input) => api.supportTickets.completeTicket(input), { invalidate: /^support-tickets?:/ });
|
|
3237
|
+
const isCompleted = computed(() => props.support_ticket.status === "COMPLETED");
|
|
3238
|
+
const getComparisonClass = () => {
|
|
3239
|
+
const creditDisplay = formatStaffCreditValue(props.support_ticket.credit_value, props.support_ticket.approval_status);
|
|
3240
|
+
if (!form.values.delivered_value || creditDisplay === "TBD" || creditDisplay === "N/A") return "";
|
|
3241
|
+
const actual = parseFloat(form.values.delivered_value);
|
|
3242
|
+
const final = parseFloat(creditDisplay);
|
|
3243
|
+
if (isNaN(actual) || isNaN(final)) return "";
|
|
3244
|
+
if (actual > final) return "alert-warning";
|
|
3245
|
+
if (actual === final) return "alert-success";
|
|
3246
|
+
return "alert-info";
|
|
3247
|
+
};
|
|
3248
|
+
const getComparisonMessage = () => {
|
|
3249
|
+
const creditDisplay = formatStaffCreditValue(props.support_ticket.credit_value, props.support_ticket.approval_status);
|
|
3250
|
+
if (!form.values.delivered_value || creditDisplay === "TBD" || creditDisplay === "N/A") return "";
|
|
3251
|
+
const actual = parseFloat(form.values.delivered_value);
|
|
3252
|
+
const final = parseFloat(creditDisplay);
|
|
3253
|
+
if (isNaN(actual) || isNaN(final)) return "";
|
|
3254
|
+
const variance = ((actual - final) / final * 100).toFixed(1);
|
|
3255
|
+
if (actual > final) return `📈 Took ${(actual - final).toFixed(2)} more effort (+${variance}%)`;
|
|
3256
|
+
else if (actual === final) return "🎯 Exactly on estimate!";
|
|
3257
|
+
else return `📉 Took ${(final - actual).toFixed(2)} less effort (${variance}%)`;
|
|
3258
|
+
};
|
|
3259
|
+
const getActualClass = () => {
|
|
3260
|
+
const creditDisplay = formatStaffCreditValue(props.support_ticket.credit_value, props.support_ticket.approval_status);
|
|
3261
|
+
if (!props.support_ticket.delivered_value || creditDisplay === "TBD" || creditDisplay === "N/A") return "";
|
|
3262
|
+
const actual = parseFloat(props.support_ticket.delivered_value);
|
|
3263
|
+
const final = parseFloat(creditDisplay);
|
|
3264
|
+
if (isNaN(actual) || isNaN(final)) return "";
|
|
3265
|
+
if (actual > final) return "text-warning";
|
|
3266
|
+
if (actual === final) return "text-success";
|
|
3267
|
+
return "text-info";
|
|
3268
|
+
};
|
|
3269
|
+
const getVarianceLabel = () => {
|
|
3270
|
+
const creditDisplay = formatStaffCreditValue(props.support_ticket.credit_value, props.support_ticket.approval_status);
|
|
3271
|
+
if (!props.support_ticket.delivered_value || creditDisplay === "TBD" || creditDisplay === "N/A") return "Work performed";
|
|
3272
|
+
const actual = parseFloat(props.support_ticket.delivered_value);
|
|
3273
|
+
const final = parseFloat(creditDisplay);
|
|
3274
|
+
if (isNaN(actual) || isNaN(final)) return "Work performed";
|
|
3275
|
+
const diff = actual - final;
|
|
3276
|
+
const variance = (diff / final * 100).toFixed(1);
|
|
3277
|
+
if (diff > 0) return `+${variance}% over estimate`;
|
|
3278
|
+
if (diff < 0) return `${variance}% under estimate`;
|
|
3279
|
+
return "On target";
|
|
3280
|
+
};
|
|
3281
|
+
const handleComplete = async (formData) => {
|
|
3282
|
+
const response = await completeSupportTicket({
|
|
3283
|
+
id: props.support_ticket.id,
|
|
3284
|
+
delivered_value: formData.delivered_value
|
|
3285
|
+
});
|
|
3286
|
+
if (!response) throw new Error("Failed to complete support ticket");
|
|
3287
|
+
return response;
|
|
3288
|
+
};
|
|
3289
|
+
const handleSuccess = () => {
|
|
3290
|
+
toast.success("SupportTicket marked as completed!", {});
|
|
3291
|
+
emit("update");
|
|
3292
|
+
};
|
|
3293
|
+
const handleError = (error) => {
|
|
3294
|
+
const errorMessage = error instanceof Error ? error.message : "An unknown error occurred.";
|
|
3295
|
+
toast.error(errorMessage);
|
|
3296
|
+
};
|
|
3297
|
+
return (_ctx, _cache) => {
|
|
3298
|
+
return ["APPROVED", "INTERNAL"].includes(props.support_ticket.approval_status) && !isCompleted.value ? (openBlock(), createBlock(unref(ZiniaForm), {
|
|
3299
|
+
key: 0,
|
|
3300
|
+
onHandleSubmit: handleComplete,
|
|
3301
|
+
onSuccess: handleSuccess,
|
|
3302
|
+
onError: handleError
|
|
3303
|
+
}, {
|
|
3304
|
+
default: withCtx(() => [
|
|
3305
|
+
_cache[2] || (_cache[2] = createElementVNode("h3", { class: "card-title text-base sm:text-lg" }, "Complete Support Ticket", -1)),
|
|
3306
|
+
createElementVNode("p", _hoisted_1$6, [
|
|
3307
|
+
_cache[0] || (_cache[0] = createTextVNode(" Customer was charged ", -1)),
|
|
3308
|
+
createElementVNode("span", _hoisted_2$5, toDisplayString(unref(formatStaffCreditValue)(props.support_ticket.credit_value, props.support_ticket.approval_status)), 1),
|
|
3309
|
+
_cache[1] || (_cache[1] = createTextVNode(" credits ", -1))
|
|
3310
|
+
]),
|
|
3311
|
+
createCommentVNode(" Delivered Value Field "),
|
|
3312
|
+
createVNode(unref(zinia).DeliveredValueField, {
|
|
3313
|
+
label: "Actual Effort Delivered",
|
|
3314
|
+
placeholder: "100.00",
|
|
3315
|
+
hint: "How much effort did it actually take?"
|
|
3316
|
+
}),
|
|
3317
|
+
createCommentVNode(" Variance Indicator "),
|
|
3318
|
+
unref(form).values.delivered_value && unref(formatStaffCreditValue)(props.support_ticket.credit_value, props.support_ticket.approval_status) !== "TBD" && unref(formatStaffCreditValue)(props.support_ticket.credit_value, props.support_ticket.approval_status) !== "N/A" ? (openBlock(), createElementBlock("div", {
|
|
3319
|
+
key: 0,
|
|
3320
|
+
class: normalizeClass(["alert py-2", getComparisonClass()])
|
|
3321
|
+
}, [createElementVNode("span", _hoisted_3$5, toDisplayString(getComparisonMessage()), 1)], 2)) : createCommentVNode("v-if", true),
|
|
3322
|
+
createVNode(unref(ZiniaSubmitButton), {
|
|
3323
|
+
submitText: "Mark as Completed",
|
|
3324
|
+
submittingText: "Completing..."
|
|
3325
|
+
})
|
|
3326
|
+
]),
|
|
3327
|
+
_: 1
|
|
3328
|
+
})) : isCompleted.value ? (openBlock(), createBlock(ZiniaContainer_default, { key: 1 }, {
|
|
3329
|
+
default: withCtx(() => [_cache[6] || (_cache[6] = createElementVNode("h3", { class: "card-title text-success text-base sm:text-lg" }, "✅ Completed", -1)), createElementVNode("div", _hoisted_4$5, [createElementVNode("div", _hoisted_5$5, [
|
|
3330
|
+
_cache[3] || (_cache[3] = createElementVNode("div", { class: "text-xs text-base-content/70" }, "Customer Charged", -1)),
|
|
3331
|
+
createElementVNode("div", _hoisted_6$4, toDisplayString(unref(formatStaffCreditValue)(props.support_ticket.credit_value, props.support_ticket.approval_status)), 1),
|
|
3332
|
+
_cache[4] || (_cache[4] = createElementVNode("div", { class: "text-xs text-base-content/60" }, "Fixed price", -1))
|
|
3333
|
+
]), createElementVNode("div", _hoisted_7$4, [
|
|
3334
|
+
_cache[5] || (_cache[5] = createElementVNode("div", { class: "text-xs text-base-content/70" }, "Actual Effort", -1)),
|
|
3335
|
+
createElementVNode("div", { class: normalizeClass(["text-lg sm:text-xl font-bold", getActualClass()]) }, toDisplayString(props.support_ticket.delivered_value ?? "N/A"), 3),
|
|
3336
|
+
createElementVNode("div", _hoisted_8$4, toDisplayString(getVarianceLabel()), 1)
|
|
3337
|
+
])])]),
|
|
3338
|
+
_: 1
|
|
3339
|
+
})) : createCommentVNode("v-if", true);
|
|
3340
|
+
};
|
|
3341
|
+
}
|
|
3342
|
+
});
|
|
3343
|
+
var CompleteSupportTicketForm_default = _sfc_main$7;
|
|
3344
|
+
|
|
3345
|
+
//#endregion
|
|
3346
|
+
//#region src/slices/support_ticket/staff/components/ConvertToCustomerWorkflow.vue
|
|
3347
|
+
const _hoisted_1$5 = { class: "flex justify-end mt-4" };
|
|
3348
|
+
const _hoisted_2$4 = ["disabled"];
|
|
3349
|
+
const _hoisted_3$4 = {
|
|
3350
|
+
key: 0,
|
|
3351
|
+
class: "loading loading-spinner loading-sm mr-2"
|
|
3352
|
+
};
|
|
3353
|
+
const _hoisted_4$4 = {
|
|
3354
|
+
key: 0,
|
|
3355
|
+
class: "alert alert-error mt-2 py-2"
|
|
3356
|
+
};
|
|
3357
|
+
const _hoisted_5$4 = { class: "text-sm" };
|
|
3358
|
+
const _hoisted_6$3 = { class: "modal-box" };
|
|
3359
|
+
const _hoisted_7$3 = { class: "font-bold text-lg" };
|
|
3360
|
+
const _hoisted_8$3 = { class: "py-4 whitespace-pre-line" };
|
|
3361
|
+
const _hoisted_9$3 = { class: "modal-action" };
|
|
3362
|
+
const _sfc_main$6 = /* @__PURE__ */ defineComponent({
|
|
3363
|
+
__name: "ConvertToCustomerWorkflow",
|
|
3364
|
+
props: { support_ticket: {} },
|
|
3365
|
+
emits: ["update"],
|
|
3366
|
+
setup(__props, { emit: __emit }) {
|
|
3367
|
+
const props = __props;
|
|
3368
|
+
const emit = __emit;
|
|
3369
|
+
const error = ref(null);
|
|
3370
|
+
const confirmModal = ref(null);
|
|
3371
|
+
const modalTitle = ref("");
|
|
3372
|
+
const modalMessage = ref("");
|
|
3373
|
+
const modalButtonText = ref("");
|
|
3374
|
+
const modalCallback = ref(null);
|
|
3375
|
+
const { mutate: convertToCustomer, loading: isConverting } = useMutation((api, input) => api.supportTickets.convertToCustomer(input.id), { invalidate: /^support-tickets?:/ });
|
|
3376
|
+
const showConvertModal = () => {
|
|
3377
|
+
modalTitle.value = "Convert to Customer Support Ticket?";
|
|
3378
|
+
modalMessage.value = "This will:\n\n• Change status to PENDING\n• Require approval workflow\n• Clear dev lifecycle stage\n• Reset to planning phase\n\nYou'll need to set a credit estimate before the support ticket can be approved.";
|
|
3379
|
+
modalButtonText.value = "Convert to Customer Support Ticket";
|
|
3380
|
+
modalCallback.value = handleConvert;
|
|
3381
|
+
confirmModal.value?.showModal();
|
|
3382
|
+
};
|
|
3383
|
+
const handleConvert = async () => {
|
|
3384
|
+
error.value = null;
|
|
3385
|
+
try {
|
|
3386
|
+
const result = await convertToCustomer({ id: props.support_ticket.id });
|
|
3387
|
+
toast.success("✅ Converted to customer support ticket successfully");
|
|
3388
|
+
closeModal();
|
|
3389
|
+
emit("update", result);
|
|
3390
|
+
} catch (err) {
|
|
3391
|
+
error.value = err instanceof Error ? err.message : "Failed to convert";
|
|
3392
|
+
toast.error(`❌ ${error.value}`);
|
|
3393
|
+
}
|
|
3394
|
+
};
|
|
3395
|
+
const closeModal = () => {
|
|
3396
|
+
confirmModal.value?.close();
|
|
3397
|
+
};
|
|
3398
|
+
return (_ctx, _cache) => {
|
|
3399
|
+
return openBlock(), createElementBlock(Fragment, null, [
|
|
3400
|
+
createCommentVNode(" Convert to Customer SupportTicket Section (INTERNAL only) "),
|
|
3401
|
+
props.support_ticket.approval_status === "INTERNAL" ? (openBlock(), createBlock(ZiniaContainer_default, { key: 0 }, {
|
|
3402
|
+
default: withCtx(() => [
|
|
3403
|
+
_cache[1] || (_cache[1] = createElementVNode("h3", { class: "card-title text-base sm:text-lg" }, "Convert to Customer SupportTicket", -1)),
|
|
3404
|
+
_cache[2] || (_cache[2] = createElementVNode("div", { class: "alert alert-info py-2" }, [createElementVNode("div", { class: "flex flex-col gap-2" }, [createElementVNode("span", { class: "font-semibold text-sm" }, "What happens when you convert:"), createElementVNode("ul", { class: "text-xs sm:text-sm space-y-1 ml-4 list-disc" }, [
|
|
3405
|
+
createElementVNode("li", null, "Changes status from internal task to customer support_ticket"),
|
|
3406
|
+
createElementVNode("li", null, "Requires approval workflow (goes to PENDING)"),
|
|
3407
|
+
createElementVNode("li", null, "Clears dev lifecycle (back to planning)"),
|
|
3408
|
+
createElementVNode("li", null, "Staff must set credit estimate before approval")
|
|
3409
|
+
])])], -1)),
|
|
3410
|
+
createElementVNode("div", _hoisted_1$5, [createElementVNode("button", {
|
|
3411
|
+
class: "btn btn-primary w-full sm:w-auto",
|
|
3412
|
+
onClick: withModifiers(showConvertModal, ["prevent"]),
|
|
3413
|
+
disabled: unref(isConverting)
|
|
3414
|
+
}, [unref(isConverting) ? (openBlock(), createElementBlock("span", _hoisted_3$4)) : createCommentVNode("v-if", true), createTextVNode(" " + toDisplayString(unref(isConverting) ? "Converting..." : "Convert to Customer SupportTicket"), 1)], 8, _hoisted_2$4)]),
|
|
3415
|
+
error.value ? (openBlock(), createElementBlock("div", _hoisted_4$4, [createElementVNode("span", _hoisted_5$4, toDisplayString(error.value), 1)])) : createCommentVNode("v-if", true)
|
|
3416
|
+
]),
|
|
3417
|
+
_: 1
|
|
3418
|
+
})) : createCommentVNode("v-if", true),
|
|
3419
|
+
createCommentVNode(" Confirmation Modal "),
|
|
3420
|
+
createElementVNode("dialog", {
|
|
3421
|
+
ref_key: "confirmModal",
|
|
3422
|
+
ref: confirmModal,
|
|
3423
|
+
class: "modal"
|
|
3424
|
+
}, [createElementVNode("div", _hoisted_6$3, [
|
|
3425
|
+
createElementVNode("h3", _hoisted_7$3, toDisplayString(modalTitle.value), 1),
|
|
3426
|
+
createElementVNode("p", _hoisted_8$3, toDisplayString(modalMessage.value), 1),
|
|
3427
|
+
createElementVNode("div", _hoisted_9$3, [createElementVNode("button", {
|
|
3428
|
+
class: "btn btn-ghost",
|
|
3429
|
+
onClick: closeModal
|
|
3430
|
+
}, "Cancel"), createElementVNode("button", {
|
|
3431
|
+
class: "btn btn-primary",
|
|
3432
|
+
onClick: _cache[0] || (_cache[0] = () => modalCallback.value?.())
|
|
3433
|
+
}, toDisplayString(modalButtonText.value), 1)])
|
|
3434
|
+
]), createElementVNode("form", {
|
|
3435
|
+
method: "dialog",
|
|
3436
|
+
class: "modal-backdrop"
|
|
3437
|
+
}, [createElementVNode("button", { onClick: closeModal }, "close")])], 512)
|
|
3438
|
+
], 64);
|
|
3439
|
+
};
|
|
3440
|
+
}
|
|
3441
|
+
});
|
|
3442
|
+
var ConvertToCustomerWorkflow_default = _sfc_main$6;
|
|
3443
|
+
|
|
3444
|
+
//#endregion
|
|
3445
|
+
//#region src/slices/support_ticket/staff/components/ConvertToInternalWorkflow.vue
|
|
3446
|
+
const _hoisted_1$4 = { class: "flex justify-end mt-4" };
|
|
3447
|
+
const _hoisted_2$3 = ["disabled"];
|
|
3448
|
+
const _hoisted_3$3 = {
|
|
3449
|
+
key: 0,
|
|
3450
|
+
class: "loading loading-spinner loading-sm mr-2"
|
|
3451
|
+
};
|
|
3452
|
+
const _hoisted_4$3 = {
|
|
3453
|
+
key: 0,
|
|
3454
|
+
class: "alert alert-error mt-2 py-2"
|
|
3455
|
+
};
|
|
3456
|
+
const _hoisted_5$3 = { class: "text-sm" };
|
|
3457
|
+
const _hoisted_6$2 = { class: "modal-box" };
|
|
3458
|
+
const _hoisted_7$2 = { class: "font-bold text-lg" };
|
|
3459
|
+
const _hoisted_8$2 = { class: "py-4 whitespace-pre-line" };
|
|
3460
|
+
const _hoisted_9$2 = { class: "modal-action" };
|
|
3461
|
+
const _sfc_main$5 = /* @__PURE__ */ defineComponent({
|
|
3462
|
+
__name: "ConvertToInternalWorkflow",
|
|
3463
|
+
props: { support_ticket: {} },
|
|
3464
|
+
emits: ["update"],
|
|
3465
|
+
setup(__props, { emit: __emit }) {
|
|
3466
|
+
const props = __props;
|
|
3467
|
+
const emit = __emit;
|
|
3468
|
+
const error = ref(null);
|
|
3469
|
+
const confirmModal = ref(null);
|
|
3470
|
+
const modalTitle = ref("");
|
|
3471
|
+
const modalMessage = ref("");
|
|
3472
|
+
const modalButtonText = ref("");
|
|
3473
|
+
const modalCallback = ref(null);
|
|
3474
|
+
const { mutate: convertToInternal, loading: isConverting } = useMutation((api, input) => api.supportTickets.convertToInternal(input.id), { invalidate: /^support-tickets?:/ });
|
|
3475
|
+
const showConvertModal = () => {
|
|
3476
|
+
const hasCredits = props.support_ticket.credit_value && parseFloat(props.support_ticket.credit_value) > 0;
|
|
3477
|
+
modalTitle.value = "Convert to Internal Task?";
|
|
3478
|
+
modalMessage.value = "This will:\n\n• Change status to INTERNAL\n• Bypass customer approval workflow\n" + (hasCredits ? `• Clear ${props.support_ticket.credit_value} credit estimate\n` : "") + "• Set dev lifecycle to BACKLOG\n• Allow immediate development start\n\nThis change can be useful for converting customer ideas into internal improvements.";
|
|
3479
|
+
modalButtonText.value = "Convert to Internal";
|
|
3480
|
+
modalCallback.value = handleConvert;
|
|
3481
|
+
confirmModal.value?.showModal();
|
|
3482
|
+
};
|
|
3483
|
+
const handleConvert = async () => {
|
|
3484
|
+
error.value = null;
|
|
3485
|
+
try {
|
|
3486
|
+
const result = await convertToInternal({ id: props.support_ticket.id });
|
|
3487
|
+
toast.success("✅ Converted to internal task successfully");
|
|
3488
|
+
closeModal();
|
|
3489
|
+
emit("update", result);
|
|
3490
|
+
} catch (err) {
|
|
3491
|
+
error.value = err instanceof Error ? err.message : "Failed to convert";
|
|
3492
|
+
toast.error(`❌ ${error.value}`);
|
|
3493
|
+
}
|
|
3494
|
+
};
|
|
3495
|
+
const closeModal = () => {
|
|
3496
|
+
confirmModal.value?.close();
|
|
3497
|
+
};
|
|
3498
|
+
return (_ctx, _cache) => {
|
|
3499
|
+
return openBlock(), createElementBlock(Fragment, null, [
|
|
3500
|
+
createCommentVNode(" Convert to Internal Section (PENDING only) "),
|
|
3501
|
+
props.support_ticket.approval_status === "PENDING" ? (openBlock(), createBlock(ZiniaContainer_default, { key: 0 }, {
|
|
3502
|
+
default: withCtx(() => [
|
|
3503
|
+
_cache[1] || (_cache[1] = createElementVNode("h3", { class: "card-title text-base sm:text-lg" }, "Convert to Internal Task", -1)),
|
|
3504
|
+
_cache[2] || (_cache[2] = createElementVNode("div", { class: "alert alert-info py-2" }, [createElementVNode("div", { class: "flex flex-col gap-2" }, [createElementVNode("span", { class: "font-semibold text-sm" }, "What happens when you convert:"), createElementVNode("ul", { class: "text-xs sm:text-sm space-y-1 ml-4 list-disc" }, [
|
|
3505
|
+
createElementVNode("li", null, "Changes status from customer support_ticket to internal task"),
|
|
3506
|
+
createElementVNode("li", null, "Bypasses approval workflow entirely"),
|
|
3507
|
+
createElementVNode("li", null, "Automatically clears any credit estimates (internal tasks = no credits)"),
|
|
3508
|
+
createElementVNode("li", null, "Can start development immediately")
|
|
3509
|
+
])])], -1)),
|
|
3510
|
+
createElementVNode("div", _hoisted_1$4, [createElementVNode("button", {
|
|
3511
|
+
class: "btn btn-primary w-full sm:w-auto",
|
|
3512
|
+
onClick: withModifiers(showConvertModal, ["prevent"]),
|
|
3513
|
+
disabled: unref(isConverting)
|
|
3514
|
+
}, [unref(isConverting) ? (openBlock(), createElementBlock("span", _hoisted_3$3)) : createCommentVNode("v-if", true), createTextVNode(" " + toDisplayString(unref(isConverting) ? "Converting..." : "Convert to Internal Task"), 1)], 8, _hoisted_2$3)]),
|
|
3515
|
+
error.value ? (openBlock(), createElementBlock("div", _hoisted_4$3, [createElementVNode("span", _hoisted_5$3, toDisplayString(error.value), 1)])) : createCommentVNode("v-if", true)
|
|
3516
|
+
]),
|
|
3517
|
+
_: 1
|
|
3518
|
+
})) : createCommentVNode("v-if", true),
|
|
3519
|
+
createCommentVNode(" Confirmation Modal "),
|
|
3520
|
+
createElementVNode("dialog", {
|
|
3521
|
+
ref_key: "confirmModal",
|
|
3522
|
+
ref: confirmModal,
|
|
3523
|
+
class: "modal"
|
|
3524
|
+
}, [createElementVNode("div", _hoisted_6$2, [
|
|
3525
|
+
createElementVNode("h3", _hoisted_7$2, toDisplayString(modalTitle.value), 1),
|
|
3526
|
+
createElementVNode("p", _hoisted_8$2, toDisplayString(modalMessage.value), 1),
|
|
3527
|
+
createElementVNode("div", _hoisted_9$2, [createElementVNode("button", {
|
|
3528
|
+
class: "btn btn-ghost",
|
|
3529
|
+
onClick: closeModal
|
|
3530
|
+
}, "Cancel"), createElementVNode("button", {
|
|
3531
|
+
class: "btn btn-primary",
|
|
3532
|
+
onClick: _cache[0] || (_cache[0] = () => modalCallback.value?.())
|
|
3533
|
+
}, toDisplayString(modalButtonText.value), 1)])
|
|
3534
|
+
]), createElementVNode("form", {
|
|
3535
|
+
method: "dialog",
|
|
3536
|
+
class: "modal-backdrop"
|
|
3537
|
+
}, [createElementVNode("button", { onClick: closeModal }, "close")])], 512)
|
|
3538
|
+
], 64);
|
|
3539
|
+
};
|
|
3540
|
+
}
|
|
3541
|
+
});
|
|
3542
|
+
var ConvertToInternalWorkflow_default = _sfc_main$5;
|
|
3543
|
+
|
|
3544
|
+
//#endregion
|
|
3545
|
+
//#region src/slices/support_ticket/staff/components/ReactivateInternalTaskWorkflow.vue
|
|
3546
|
+
const _hoisted_1$3 = { class: "alert alert-info py-2" };
|
|
3547
|
+
const _hoisted_2$2 = { class: "flex flex-col gap-2" };
|
|
3548
|
+
const _hoisted_3$2 = { class: "text-xs sm:text-sm space-y-1 ml-4 list-disc" };
|
|
3549
|
+
const _hoisted_4$2 = { key: 0 };
|
|
3550
|
+
const _hoisted_5$2 = { key: 1 };
|
|
3551
|
+
const _hoisted_6$1 = { class: "flex justify-end mt-4" };
|
|
3552
|
+
const _hoisted_7$1 = ["disabled"];
|
|
3553
|
+
const _hoisted_8$1 = {
|
|
3554
|
+
key: 0,
|
|
3555
|
+
class: "loading loading-spinner loading-sm mr-2"
|
|
3556
|
+
};
|
|
3557
|
+
const _hoisted_9$1 = {
|
|
3558
|
+
key: 0,
|
|
3559
|
+
class: "alert alert-error mt-2 py-2"
|
|
3560
|
+
};
|
|
3561
|
+
const _hoisted_10$1 = { class: "text-sm" };
|
|
3562
|
+
const _hoisted_11$1 = { class: "modal-box" };
|
|
3563
|
+
const _hoisted_12$1 = { class: "font-bold text-lg" };
|
|
3564
|
+
const _hoisted_13 = { class: "py-4 whitespace-pre-line" };
|
|
3565
|
+
const _hoisted_14 = { class: "modal-action" };
|
|
3566
|
+
const _sfc_main$4 = /* @__PURE__ */ defineComponent({
|
|
3567
|
+
__name: "ReactivateInternalTaskWorkflow",
|
|
3568
|
+
props: { support_ticket: {} },
|
|
3569
|
+
emits: ["update"],
|
|
3570
|
+
setup(__props, { emit: __emit }) {
|
|
3571
|
+
const props = __props;
|
|
3572
|
+
const emit = __emit;
|
|
3573
|
+
const error = ref(null);
|
|
3574
|
+
const confirmModal = ref(null);
|
|
3575
|
+
const modalTitle = ref("");
|
|
3576
|
+
const modalMessage = ref("");
|
|
3577
|
+
const modalButtonText = ref("");
|
|
3578
|
+
const modalCallback = ref(null);
|
|
3579
|
+
const { mutate: reactivateInternalTask, loading: isReactivating } = useMutation((api, input) => api.supportTickets.reactivateInternalTask(input), { invalidate: /^support-tickets?:/ });
|
|
3580
|
+
const showReactivateModal = () => {
|
|
3581
|
+
const isCancelled = props.support_ticket.dev_lifecycle === "CANCELLED";
|
|
3582
|
+
const targetState = isCancelled ? "BACKLOG" : "PO_APPROVAL";
|
|
3583
|
+
modalTitle.value = `Reopen ${isCancelled ? "Cancelled" : "Deployed"} Task?`;
|
|
3584
|
+
modalMessage.value = `This will:\n\n• Set dev lifecycle to ${targetState}\n• Clear completion timestamp\n• Resume task as active\n\n` + (isCancelled ? `Task will restart from backlog for fresh planning.` : `Task will go to PO approval stage for review/fixes.`);
|
|
3585
|
+
modalButtonText.value = "Reopen Task";
|
|
3586
|
+
modalCallback.value = handleReactivate;
|
|
3587
|
+
confirmModal.value?.showModal();
|
|
3588
|
+
};
|
|
3589
|
+
const handleReactivate = async () => {
|
|
3590
|
+
error.value = null;
|
|
3591
|
+
try {
|
|
3592
|
+
const result = await reactivateInternalTask({ id: props.support_ticket.id });
|
|
3593
|
+
toast.success("✅ Internal task reopened successfully");
|
|
3594
|
+
closeModal();
|
|
3595
|
+
emit("update", result);
|
|
3596
|
+
} catch (err) {
|
|
3597
|
+
error.value = err instanceof Error ? err.message : "Failed to reactivate task";
|
|
3598
|
+
toast.error(`❌ ${error.value}`);
|
|
3599
|
+
}
|
|
3600
|
+
};
|
|
3601
|
+
const closeModal = () => {
|
|
3602
|
+
confirmModal.value?.close();
|
|
3603
|
+
};
|
|
3604
|
+
return (_ctx, _cache) => {
|
|
3605
|
+
return openBlock(), createElementBlock(Fragment, null, [
|
|
3606
|
+
createCommentVNode(" Reactivate Terminal Internal Task Section (INTERNAL + CANCELLED or DEPLOYED) "),
|
|
3607
|
+
props.support_ticket.approval_status === "INTERNAL" && (props.support_ticket.dev_lifecycle === "CANCELLED" || props.support_ticket.dev_lifecycle === "DEPLOYED") ? (openBlock(), createBlock(ZiniaContainer_default, { key: 0 }, {
|
|
3608
|
+
default: withCtx(() => [
|
|
3609
|
+
_cache[5] || (_cache[5] = createElementVNode("h3", { class: "card-title text-base sm:text-lg" }, "Reopen Internal Task", -1)),
|
|
3610
|
+
createElementVNode("div", _hoisted_1$3, [createElementVNode("div", _hoisted_2$2, [_cache[4] || (_cache[4] = createElementVNode("span", { class: "font-semibold text-sm" }, "What happens when you reopen:", -1)), createElementVNode("ul", _hoisted_3$2, [
|
|
3611
|
+
props.support_ticket.dev_lifecycle === "CANCELLED" ? (openBlock(), createElementBlock("li", _hoisted_4$2, " Sets dev lifecycle to BACKLOG (fresh start) ")) : (openBlock(), createElementBlock("li", _hoisted_5$2, "Sets dev lifecycle to PO_APPROVAL (ready for review/fixes)")),
|
|
3612
|
+
_cache[1] || (_cache[1] = createElementVNode("li", null, "Clears completion timestamp", -1)),
|
|
3613
|
+
_cache[2] || (_cache[2] = createElementVNode("li", null, "Task becomes active again", -1)),
|
|
3614
|
+
_cache[3] || (_cache[3] = createElementVNode("li", null, "You can resume work or make additional changes", -1))
|
|
3615
|
+
])])]),
|
|
3616
|
+
createElementVNode("div", _hoisted_6$1, [createElementVNode("button", {
|
|
3617
|
+
class: "btn btn-success w-full sm:w-auto",
|
|
3618
|
+
onClick: withModifiers(showReactivateModal, ["prevent"]),
|
|
3619
|
+
disabled: unref(isReactivating)
|
|
3620
|
+
}, [unref(isReactivating) ? (openBlock(), createElementBlock("span", _hoisted_8$1)) : createCommentVNode("v-if", true), createTextVNode(" " + toDisplayString(unref(isReactivating) ? "Reopening..." : "Reopen Task"), 1)], 8, _hoisted_7$1)]),
|
|
3621
|
+
error.value ? (openBlock(), createElementBlock("div", _hoisted_9$1, [createElementVNode("span", _hoisted_10$1, toDisplayString(error.value), 1)])) : createCommentVNode("v-if", true)
|
|
3622
|
+
]),
|
|
3623
|
+
_: 1
|
|
3624
|
+
})) : createCommentVNode("v-if", true),
|
|
3625
|
+
createCommentVNode(" Confirmation Modal "),
|
|
3626
|
+
createElementVNode("dialog", {
|
|
3627
|
+
ref_key: "confirmModal",
|
|
3628
|
+
ref: confirmModal,
|
|
3629
|
+
class: "modal"
|
|
3630
|
+
}, [createElementVNode("div", _hoisted_11$1, [
|
|
3631
|
+
createElementVNode("h3", _hoisted_12$1, toDisplayString(modalTitle.value), 1),
|
|
3632
|
+
createElementVNode("p", _hoisted_13, toDisplayString(modalMessage.value), 1),
|
|
3633
|
+
createElementVNode("div", _hoisted_14, [createElementVNode("button", {
|
|
3634
|
+
class: "btn btn-ghost",
|
|
3635
|
+
onClick: closeModal
|
|
3636
|
+
}, "Cancel"), createElementVNode("button", {
|
|
3637
|
+
class: "btn btn-success",
|
|
3638
|
+
onClick: _cache[0] || (_cache[0] = () => modalCallback.value?.())
|
|
3639
|
+
}, toDisplayString(modalButtonText.value), 1)])
|
|
3640
|
+
]), createElementVNode("form", {
|
|
3641
|
+
method: "dialog",
|
|
3642
|
+
class: "modal-backdrop"
|
|
3643
|
+
}, [createElementVNode("button", { onClick: closeModal }, "close")])], 512)
|
|
3644
|
+
], 64);
|
|
3645
|
+
};
|
|
3646
|
+
}
|
|
3647
|
+
});
|
|
3648
|
+
var ReactivateInternalTaskWorkflow_default = _sfc_main$4;
|
|
3649
|
+
|
|
3650
|
+
//#endregion
|
|
3651
|
+
//#region src/slices/support_ticket/staff/StaffSupportTicketRowSchema.ts
|
|
3652
|
+
/**
|
|
3653
|
+
* Reuse the existing StaffSupportTicketReadSchema from the validation library
|
|
3654
|
+
* for the data table rows - don't recreate it!
|
|
3655
|
+
*/
|
|
3656
|
+
const adminSupportTicketRowSchemaWithMetadata = withMetadata(StaffSupportTicketReadSchema, "adminSupportTicketRow", {});
|
|
3657
|
+
|
|
3658
|
+
//#endregion
|
|
3659
|
+
//#region src/slices/support_ticket/staff/StaffSupportTicketList.vue
|
|
3660
|
+
const _hoisted_1$2 = { class: "flex flex-col sm:flex-row sm:justify-between sm:items-center gap-4 mb-4" };
|
|
3661
|
+
const _hoisted_2$1 = { class: "flex items-center gap-2" };
|
|
3662
|
+
const _hoisted_3$1 = { class: "flex flex-col sm:flex-row gap-2" };
|
|
3663
|
+
const _hoisted_4$1 = [
|
|
3664
|
+
"value",
|
|
3665
|
+
"disabled",
|
|
3666
|
+
"onChange"
|
|
3667
|
+
];
|
|
3668
|
+
const _hoisted_5$1 = ["value"];
|
|
3669
|
+
const _sfc_main$3 = /* @__PURE__ */ defineComponent({
|
|
3670
|
+
__name: "StaffSupportTicketList",
|
|
3671
|
+
setup(__props) {
|
|
3672
|
+
const route = useRoute();
|
|
3673
|
+
const router = useRouter();
|
|
3674
|
+
const savedFilters = useSavedFilters({
|
|
3675
|
+
context: "support_ticket_staff",
|
|
3676
|
+
routePath: "/staff/support",
|
|
3677
|
+
getFiltersFromTable: () => extractFiltersFromQuery(route.query),
|
|
3678
|
+
applyFiltersToTable: (filters) => {
|
|
3679
|
+
router.push({ query: buildQueryWithFilters(route.query, filters) });
|
|
3680
|
+
}
|
|
3681
|
+
});
|
|
3682
|
+
const hasSupportFilters = computed(() => {
|
|
3683
|
+
const filters = extractFiltersFromQuery(route.query);
|
|
3684
|
+
return Object.keys(filters).length > 0;
|
|
3685
|
+
});
|
|
3686
|
+
const currentPaginationToken = ref();
|
|
3687
|
+
const devLifecycleUpdateOptions = SUPPORT_TICKET_DEV_LIFECYCLE_FILTER_OPTIONS.filter((opt) => SupportTicketDevLifecycleUpdateEnum.includes(opt.value));
|
|
3688
|
+
const updatingDevLifecycleId = ref(null);
|
|
3689
|
+
const { mutate: updateTicket } = useMutation((api, input) => api.supportTickets.staffUpdateTicket(input), { invalidate: /^support-tickets?:/ });
|
|
3690
|
+
function canEditDevLifecycle(row) {
|
|
3691
|
+
if (!row.approval_status) return false;
|
|
3692
|
+
if (!["APPROVED", "INTERNAL"].includes(row.approval_status)) return false;
|
|
3693
|
+
const dl = row.dev_lifecycle;
|
|
3694
|
+
if (dl === "DEPLOYED" || dl === "CANCELLED") return false;
|
|
3695
|
+
return true;
|
|
3696
|
+
}
|
|
3697
|
+
const cursorTable = useCursorDataTable(adminSupportTicketRowSchemaWithMetadata, {
|
|
3698
|
+
fetchData: async ({ cursor, pageSize, sort, filters, search }) => {
|
|
3699
|
+
const variables = {
|
|
3700
|
+
first: pageSize,
|
|
3701
|
+
sortBy: sort?.field ? sort.field : "updated_at",
|
|
3702
|
+
sortDirection: sort?.direction === "asc" ? "asc" : "desc",
|
|
3703
|
+
...cursor ? { after: cursor } : {},
|
|
3704
|
+
...currentPaginationToken.value ? { paginationToken: currentPaginationToken.value } : {},
|
|
3705
|
+
...search ? { search: typeof search === "string" ? {
|
|
3706
|
+
query: search,
|
|
3707
|
+
searchableFields: [
|
|
3708
|
+
"display_id",
|
|
3709
|
+
"title",
|
|
3710
|
+
"description"
|
|
3711
|
+
]
|
|
3712
|
+
} : search } : {},
|
|
3713
|
+
...filters
|
|
3714
|
+
};
|
|
3715
|
+
if (!filters || !filters.dev_lifecycle) variables.dev_lifecycle = {
|
|
3716
|
+
operator: OPERATORS.IS_NOT_ONE_OF,
|
|
3717
|
+
values: ["DEPLOYED", "CANCELLED"]
|
|
3718
|
+
};
|
|
3719
|
+
const result = await executeWithAuth(async (api) => {
|
|
3720
|
+
return await api.supportTickets.staffListTickets(variables ?? {});
|
|
3721
|
+
}, { refreshTokenHandler: getRefreshTokenHandler() });
|
|
3722
|
+
currentPaginationToken.value = result?.pageInfo?.paginationToken;
|
|
3723
|
+
return {
|
|
3724
|
+
data: result.items || [],
|
|
3725
|
+
hasNextPage: result.pageInfo?.hasNextPage ?? false,
|
|
3726
|
+
hasPreviousPage: result.pageInfo?.hasPreviousPage ?? false,
|
|
3727
|
+
prevPageCursor: result.pageInfo?.prevPageCursor ?? void 0,
|
|
3728
|
+
nextPageCursor: result.pageInfo?.nextPageCursor ?? void 0
|
|
3729
|
+
};
|
|
3730
|
+
},
|
|
3731
|
+
columns: {
|
|
3732
|
+
display_id: {
|
|
3733
|
+
label: "Ticket ID",
|
|
3734
|
+
field: "display_id",
|
|
3735
|
+
sortable: true
|
|
3736
|
+
},
|
|
3737
|
+
title: {
|
|
3738
|
+
label: "Title",
|
|
3739
|
+
field: "title",
|
|
3740
|
+
sortable: true
|
|
3741
|
+
},
|
|
3742
|
+
type: {
|
|
3743
|
+
label: "Type",
|
|
3744
|
+
field: "type",
|
|
3745
|
+
sortable: true,
|
|
3746
|
+
filterable: true,
|
|
3747
|
+
filterType: "select",
|
|
3748
|
+
filterOptions: [...SUPPORT_TICKET_TYPE_FILTER_OPTIONS]
|
|
3749
|
+
},
|
|
3750
|
+
priority: {
|
|
3751
|
+
label: "Priority",
|
|
3752
|
+
field: "priority",
|
|
3753
|
+
sortable: true,
|
|
3754
|
+
filterable: true,
|
|
3755
|
+
filterType: "select",
|
|
3756
|
+
filterOptions: [...SUPPORT_TICKET_PRIORITY_FILTER_OPTIONS]
|
|
3757
|
+
},
|
|
3758
|
+
approval_status: {
|
|
3759
|
+
label: "Approval",
|
|
3760
|
+
field: "approval_status",
|
|
3761
|
+
sortable: true,
|
|
3762
|
+
filterable: true,
|
|
3763
|
+
filterType: "select",
|
|
3764
|
+
filterOptions: [...SUPPORT_TICKET_APPROVAL_FILTER_OPTIONS]
|
|
3765
|
+
},
|
|
3766
|
+
dev_lifecycle: {
|
|
3767
|
+
label: "Dev Stage",
|
|
3768
|
+
field: "dev_lifecycle",
|
|
3769
|
+
sortable: true,
|
|
3770
|
+
filterable: true,
|
|
3771
|
+
filterType: "select",
|
|
3772
|
+
filterOptions: [...SUPPORT_TICKET_DEV_LIFECYCLE_FILTER_OPTIONS]
|
|
3773
|
+
},
|
|
3774
|
+
credit_value: {
|
|
3775
|
+
label: "Credits",
|
|
3776
|
+
field: "credit_value",
|
|
3777
|
+
sortable: false
|
|
3778
|
+
},
|
|
3779
|
+
target_at: {
|
|
3780
|
+
label: "Delivery Est.",
|
|
3781
|
+
field: "target_at",
|
|
3782
|
+
sortable: true
|
|
3783
|
+
},
|
|
3784
|
+
updated_at: {
|
|
3785
|
+
label: "Last Updated",
|
|
3786
|
+
field: "updated_at",
|
|
3787
|
+
sortable: true
|
|
3788
|
+
},
|
|
3789
|
+
created_by: {
|
|
3790
|
+
label: "Requester",
|
|
3791
|
+
field: "created_by",
|
|
3792
|
+
sortable: false,
|
|
3793
|
+
filterable: true,
|
|
3794
|
+
filterType: "select",
|
|
3795
|
+
filterOptionsLoader: async () => {
|
|
3796
|
+
return (await executeWithAuth((api) => api.supportTickets.staffGetRequestorsForActiveTickets(), { refreshTokenHandler: getRefreshTokenHandler() }) || []).map((u) => ({
|
|
3797
|
+
value: u.id,
|
|
3798
|
+
label: u.email
|
|
3799
|
+
}));
|
|
3800
|
+
}
|
|
3801
|
+
}
|
|
3802
|
+
},
|
|
3803
|
+
actions: { items: [{
|
|
3804
|
+
key: "manage",
|
|
3805
|
+
icon: ActionIcons.edit,
|
|
3806
|
+
size: "xs",
|
|
3807
|
+
variant: "primary",
|
|
3808
|
+
type: "link",
|
|
3809
|
+
href: (row) => `/staff/support/${row.id}`
|
|
3810
|
+
}] },
|
|
3811
|
+
search: { searchableFields: ["title"] },
|
|
3812
|
+
pagination: { pageSize: 25 },
|
|
3813
|
+
autoLoad: false
|
|
3814
|
+
});
|
|
3815
|
+
const { ZiniaDataTable, refresh } = cursorTable;
|
|
3816
|
+
async function handleDevLifecycleChange(row, newDevLifecycle) {
|
|
3817
|
+
if (!SupportTicketDevLifecycleUpdateEnum.includes(newDevLifecycle)) return;
|
|
3818
|
+
updatingDevLifecycleId.value = row.id;
|
|
3819
|
+
try {
|
|
3820
|
+
const priority = typeof row.priority === "number" ? row.priority : supportTicketPriorityToNumber(row.priority);
|
|
3821
|
+
await updateTicket({
|
|
3822
|
+
id: row.id,
|
|
3823
|
+
title: row.title,
|
|
3824
|
+
type: row.type,
|
|
3825
|
+
priority,
|
|
3826
|
+
dev_lifecycle: newDevLifecycle
|
|
3827
|
+
});
|
|
3828
|
+
await refresh();
|
|
3829
|
+
} catch {
|
|
3830
|
+
await refresh();
|
|
3831
|
+
} finally {
|
|
3832
|
+
updatingDevLifecycleId.value = null;
|
|
3833
|
+
}
|
|
3834
|
+
}
|
|
3835
|
+
useDataTableUrlSync(cursorTable.table, router);
|
|
3836
|
+
const previousFilters = ref({});
|
|
3837
|
+
onMounted(() => {
|
|
3838
|
+
previousFilters.value = extractFiltersFromQuery(route.query);
|
|
3839
|
+
});
|
|
3840
|
+
watch(() => route.query, (query) => {
|
|
3841
|
+
const filters = extractFiltersFromQuery(query);
|
|
3842
|
+
const hadPrevious = Object.keys(previousFilters.value).length > 0;
|
|
3843
|
+
if (!(Object.keys(filters).length > 0) && hadPrevious) savedFilters.clearLastUsed();
|
|
3844
|
+
previousFilters.value = filters;
|
|
3845
|
+
});
|
|
3846
|
+
return (_ctx, _cache) => {
|
|
3847
|
+
const _component_router_link = resolveComponent("router-link");
|
|
3848
|
+
return openBlock(), createElementBlock("div", null, [createElementVNode("div", _hoisted_1$2, [createElementVNode("div", _hoisted_2$1, [createVNode(unref(SavedFilterPresets_default), {
|
|
3849
|
+
presets: unref(savedFilters).presets.value,
|
|
3850
|
+
"presets-loading": unref(savedFilters).presetsLoading.value,
|
|
3851
|
+
creating: unref(savedFilters).creating.value,
|
|
3852
|
+
deleting: unref(savedFilters).deleting.value,
|
|
3853
|
+
renaming: unref(savedFilters).updating.value,
|
|
3854
|
+
"has-filters": hasSupportFilters.value,
|
|
3855
|
+
"active-preset": unref(savedFilters).activePreset.value,
|
|
3856
|
+
"apply-preset": unref(savedFilters).applyPreset,
|
|
3857
|
+
"clear-preset": unref(savedFilters).clearPreset,
|
|
3858
|
+
"save-current-filters": unref(savedFilters).saveCurrentFilters,
|
|
3859
|
+
"rename-preset": unref(savedFilters).renamePreset,
|
|
3860
|
+
"remove-preset": unref(savedFilters).removePreset
|
|
3861
|
+
}, null, 8, [
|
|
3862
|
+
"presets",
|
|
3863
|
+
"presets-loading",
|
|
3864
|
+
"creating",
|
|
3865
|
+
"deleting",
|
|
3866
|
+
"renaming",
|
|
3867
|
+
"has-filters",
|
|
3868
|
+
"active-preset",
|
|
3869
|
+
"apply-preset",
|
|
3870
|
+
"clear-preset",
|
|
3871
|
+
"save-current-filters",
|
|
3872
|
+
"rename-preset",
|
|
3873
|
+
"remove-preset"
|
|
3874
|
+
]), _cache[0] || (_cache[0] = createElementVNode("h1", { class: "text-xl sm:text-2xl font-bold" }, "Manage Support Tickets", -1))]), createElementVNode("div", _hoisted_3$1, [createVNode(_component_router_link, {
|
|
3875
|
+
to: { name: "CustomerSupportTicketList" },
|
|
3876
|
+
class: "btn btn-outline btn-sm sm:btn-md"
|
|
3877
|
+
}, {
|
|
3878
|
+
default: withCtx(() => [..._cache[1] || (_cache[1] = [createTextVNode(" Customer View ", -1)])]),
|
|
3879
|
+
_: 1
|
|
3880
|
+
}), createVNode(_component_router_link, {
|
|
3881
|
+
to: { name: unref(staffSupportPaths).staff_create.name },
|
|
3882
|
+
class: "btn btn-primary btn-sm sm:btn-md"
|
|
3883
|
+
}, {
|
|
3884
|
+
default: withCtx(() => [..._cache[2] || (_cache[2] = [createTextVNode(" Create ", -1)])]),
|
|
3885
|
+
_: 1
|
|
3886
|
+
}, 8, ["to"])])]), createVNode(unref(ZiniaDataTable), null, {
|
|
3887
|
+
"cell-displayId": withCtx(({ row }) => [createTextVNode(toDisplayString(unref(formatTicketDisplayId)(row.display_id, row.display_id_prefix, row.id)), 1)]),
|
|
3888
|
+
"cell-type": withCtx(({ row }) => [createVNode(SupportTicketTypeBadge_default, {
|
|
3889
|
+
type: row.type,
|
|
3890
|
+
size: "sm"
|
|
3891
|
+
}, null, 8, ["type"])]),
|
|
3892
|
+
"cell-priority": withCtx(({ row }) => [createVNode(SupportTicketPriorityBadge_default, {
|
|
3893
|
+
priority: row.priority,
|
|
3894
|
+
size: "sm"
|
|
3895
|
+
}, null, 8, ["priority"])]),
|
|
3896
|
+
"cell-approval_status": withCtx(({ row }) => [createVNode(SupportTicketApprovalBadge_default, {
|
|
3897
|
+
approvalStatus: row.approval_status,
|
|
3898
|
+
size: "sm"
|
|
3899
|
+
}, null, 8, ["approvalStatus"])]),
|
|
3900
|
+
"cell-dev_lifecycle": withCtx(({ row }) => [canEditDevLifecycle(row) ? (openBlock(), createElementBlock("select", {
|
|
3901
|
+
key: 0,
|
|
3902
|
+
value: row.dev_lifecycle,
|
|
3903
|
+
class: "select select-sm select-bordered min-w-[7rem]",
|
|
3904
|
+
disabled: updatingDevLifecycleId.value === row.id,
|
|
3905
|
+
onChange: ($event) => handleDevLifecycleChange(row, $event.target.value)
|
|
3906
|
+
}, [(openBlock(true), createElementBlock(Fragment, null, renderList(unref(devLifecycleUpdateOptions), (opt) => {
|
|
3907
|
+
return openBlock(), createElementBlock("option", {
|
|
3908
|
+
key: opt.value,
|
|
3909
|
+
value: opt.value
|
|
3910
|
+
}, toDisplayString(opt.label), 9, _hoisted_5$1);
|
|
3911
|
+
}), 128))], 40, _hoisted_4$1)) : (openBlock(), createBlock(SupportTicketDevLifecycleBadge_default, {
|
|
3912
|
+
key: 1,
|
|
3913
|
+
devLifecycle: row.dev_lifecycle || "PENDING",
|
|
3914
|
+
size: "sm"
|
|
3915
|
+
}, null, 8, ["devLifecycle"]))]),
|
|
3916
|
+
"cell-credit_value": withCtx(({ row }) => [createTextVNode(toDisplayString(unref(formatStaffCreditValue)(row.credit_value, row.approval_status)), 1)]),
|
|
3917
|
+
"cell-created_by": withCtx(({ row }) => [createTextVNode(toDisplayString(row.created_by_display_name), 1)]),
|
|
3918
|
+
"cell-target_at": withCtx(({ row }) => [createTextVNode(toDisplayString(unref(formatUserDate)(row.target_at) || "TBD"), 1)]),
|
|
3919
|
+
"cell-updated_at": withCtx(({ row }) => [createTextVNode(toDisplayString(unref(formatSystemTimestamp)(row.updated_at)), 1)]),
|
|
3920
|
+
"cell-actions": withCtx(({ row }) => [createVNode(_component_router_link, {
|
|
3921
|
+
to: {
|
|
3922
|
+
name: "AdminEditSupportTicket",
|
|
3923
|
+
params: { id: row.id }
|
|
3924
|
+
},
|
|
3925
|
+
class: "btn btn-sm btn-primary"
|
|
3926
|
+
}, {
|
|
3927
|
+
default: withCtx(() => [..._cache[3] || (_cache[3] = [createTextVNode(" Manage ", -1)])]),
|
|
3928
|
+
_: 1
|
|
3929
|
+
}, 8, ["to"])]),
|
|
3930
|
+
_: 1
|
|
3931
|
+
})]);
|
|
3932
|
+
};
|
|
3933
|
+
}
|
|
3934
|
+
});
|
|
3935
|
+
var StaffSupportTicketList_default = _sfc_main$3;
|
|
3936
|
+
|
|
3937
|
+
//#endregion
|
|
3938
|
+
//#region src/slices/support_ticket/shared/CreditBalanceWidget.vue
|
|
3939
|
+
const _hoisted_1$1 = {
|
|
3940
|
+
key: 0,
|
|
3941
|
+
class: "flex items-center gap-2"
|
|
3942
|
+
};
|
|
3943
|
+
const _hoisted_2 = { class: "flex items-center gap-2" };
|
|
3944
|
+
const _hoisted_3 = { class: "font-bold" };
|
|
3945
|
+
const _hoisted_4 = { class: "space-y-3" };
|
|
3946
|
+
const _hoisted_5 = {
|
|
3947
|
+
key: 0,
|
|
3948
|
+
class: "text-sm font-medium text-base-content/60"
|
|
3949
|
+
};
|
|
3950
|
+
const _hoisted_6 = { class: "space-y-2" };
|
|
3951
|
+
const _hoisted_7 = { class: "flex justify-between items-center p-3 bg-base-200 rounded-lg" };
|
|
3952
|
+
const _hoisted_8 = { class: "font-bold" };
|
|
3953
|
+
const _hoisted_9 = { class: "flex justify-between items-center p-3 bg-base-200 rounded-lg" };
|
|
3954
|
+
const _hoisted_10 = { class: "font-bold" };
|
|
3955
|
+
const _hoisted_11 = {
|
|
3956
|
+
key: 1,
|
|
3957
|
+
class: "alert alert-warning"
|
|
3958
|
+
};
|
|
3959
|
+
const _hoisted_12 = {
|
|
3960
|
+
key: 2,
|
|
3961
|
+
class: "pt-2"
|
|
3962
|
+
};
|
|
3963
|
+
const _sfc_main$2 = /* @__PURE__ */ defineComponent({
|
|
3964
|
+
__name: "CreditBalanceWidget",
|
|
3965
|
+
props: {
|
|
3966
|
+
variant: { default: "full" },
|
|
3967
|
+
expandable: {
|
|
3968
|
+
type: Boolean,
|
|
3969
|
+
default: false
|
|
3970
|
+
},
|
|
3971
|
+
showTitle: {
|
|
3972
|
+
type: Boolean,
|
|
3973
|
+
default: true
|
|
3974
|
+
},
|
|
3975
|
+
showHistoryLink: {
|
|
3976
|
+
type: Boolean,
|
|
3977
|
+
default: true
|
|
3978
|
+
}
|
|
3979
|
+
},
|
|
3980
|
+
setup(__props) {
|
|
3981
|
+
const expanded = ref(false);
|
|
3982
|
+
const { data, loading, error } = useQuery((api) => api.customer.getCreditBalance(), { staleTime: 120 * 1e3 });
|
|
3983
|
+
const creditBalance = computed(() => data.value ?? null);
|
|
3984
|
+
const totalAvailable = computed(() => {
|
|
3985
|
+
if (!creditBalance.value) return 0;
|
|
3986
|
+
return (parseFloat(creditBalance.value.monthly) || 0) + (parseFloat(creditBalance.value.rollover) || 0);
|
|
3987
|
+
});
|
|
3988
|
+
return (_ctx, _cache) => {
|
|
3989
|
+
const _component_router_link = resolveComponent("router-link");
|
|
3990
|
+
return openBlock(), createElementBlock("div", { class: normalizeClass(["credit-balance-widget", __props.variant === "compact" ? "compact" : ""]) }, [createCommentVNode(" Loading State "), unref(loading) ? (openBlock(), createElementBlock("div", _hoisted_1$1, [..._cache[1] || (_cache[1] = [createElementVNode("span", { class: "loading loading-spinner loading-sm" }, null, -1), createElementVNode("span", { class: "text-sm" }, "Loading credits...", -1)])])) : unref(error) ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [createCommentVNode(" Error State "), _cache[2] || (_cache[2] = createElementVNode("div", { class: "alert alert-error" }, [createElementVNode("span", { class: "text-sm" }, "Failed to load credit balance")], -1))], 2112)) : __props.variant === "compact" && creditBalance.value ? (openBlock(), createElementBlock(Fragment, { key: 2 }, [createCommentVNode(" Compact Variant (Badge) "), createElementVNode("div", _hoisted_2, [createElementVNode("div", { class: normalizeClass(["badge badge-lg gap-2", {
|
|
3991
|
+
"badge-success": totalAvailable.value > 0,
|
|
3992
|
+
"badge-warning": totalAvailable.value === 0
|
|
3993
|
+
}]) }, [_cache[3] || (_cache[3] = createElementVNode("svg", {
|
|
3994
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
3995
|
+
class: "h-4 w-4",
|
|
3996
|
+
fill: "none",
|
|
3997
|
+
viewBox: "0 0 24 24",
|
|
3998
|
+
stroke: "currentColor"
|
|
3999
|
+
}, [createElementVNode("path", {
|
|
4000
|
+
"stroke-linecap": "round",
|
|
4001
|
+
"stroke-linejoin": "round",
|
|
4002
|
+
"stroke-width": "2",
|
|
4003
|
+
d: "M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
|
4004
|
+
})], -1)), createElementVNode("span", _hoisted_3, toDisplayString(unref(formatStaffCreditValue)(totalAvailable.value.toString())) + " Credits", 1)], 2), __props.expandable ? (openBlock(), createElementBlock("button", {
|
|
4005
|
+
key: 0,
|
|
4006
|
+
class: "btn btn-ghost btn-xs",
|
|
4007
|
+
onClick: _cache[0] || (_cache[0] = ($event) => expanded.value = !expanded.value)
|
|
4008
|
+
}, toDisplayString(expanded.value ? "Hide" : "Details"), 1)) : createCommentVNode("v-if", true)])], 2112)) : creditBalance.value && (__props.variant === "full" || expanded.value) ? (openBlock(), createElementBlock(Fragment, { key: 3 }, [createCommentVNode(" Expanded/Full Variant "), createElementVNode("div", _hoisted_4, [
|
|
4009
|
+
__props.showTitle ? (openBlock(), createElementBlock("h4", _hoisted_5, " Your Available Credits ")) : createCommentVNode("v-if", true),
|
|
4010
|
+
createElementVNode("div", _hoisted_6, [
|
|
4011
|
+
createElementVNode("div", _hoisted_7, [_cache[4] || (_cache[4] = createElementVNode("span", { class: "text-sm" }, "Monthly Balance:", -1)), createElementVNode("span", _hoisted_8, toDisplayString(unref(formatStaffCreditValue)(creditBalance.value.monthly)), 1)]),
|
|
4012
|
+
createElementVNode("div", _hoisted_9, [_cache[5] || (_cache[5] = createElementVNode("span", { class: "text-sm" }, "Rollover Balance:", -1)), createElementVNode("span", _hoisted_10, toDisplayString(unref(formatStaffCreditValue)(creditBalance.value.rollover)), 1)]),
|
|
4013
|
+
createElementVNode("div", { class: normalizeClass(["flex justify-between items-center p-3 rounded-lg", {
|
|
4014
|
+
"bg-success/20": totalAvailable.value > 0,
|
|
4015
|
+
"bg-warning/20": totalAvailable.value === 0
|
|
4016
|
+
}]) }, [_cache[6] || (_cache[6] = createElementVNode("span", { class: "font-medium" }, "Total Available:", -1)), createElementVNode("span", { class: normalizeClass(["text-xl font-bold", {
|
|
4017
|
+
"text-success": totalAvailable.value > 0,
|
|
4018
|
+
"text-warning": totalAvailable.value === 0
|
|
4019
|
+
}]) }, toDisplayString(unref(formatStaffCreditValue)(totalAvailable.value.toString())), 3)], 2)
|
|
4020
|
+
]),
|
|
4021
|
+
createCommentVNode(" Warning if low balance "),
|
|
4022
|
+
totalAvailable.value === 0 ? (openBlock(), createElementBlock("div", _hoisted_11, [..._cache[7] || (_cache[7] = [createElementVNode("svg", {
|
|
4023
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
4024
|
+
class: "stroke-current shrink-0 h-6 w-6",
|
|
4025
|
+
fill: "none",
|
|
4026
|
+
viewBox: "0 0 24 24"
|
|
4027
|
+
}, [createElementVNode("path", {
|
|
4028
|
+
"stroke-linecap": "round",
|
|
4029
|
+
"stroke-linejoin": "round",
|
|
4030
|
+
"stroke-width": "2",
|
|
4031
|
+
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"
|
|
4032
|
+
})], -1), createElementVNode("div", null, [createElementVNode("h3", { class: "font-bold" }, "No Credits Available"), createElementVNode("p", { class: "text-sm" }, " Contact support to purchase more credits or wait for your monthly reset. ")], -1)])])) : createCommentVNode("v-if", true),
|
|
4033
|
+
createCommentVNode(" View History Link "),
|
|
4034
|
+
__props.showHistoryLink ? (openBlock(), createElementBlock("div", _hoisted_12, [createVNode(_component_router_link, {
|
|
4035
|
+
to: { name: "CreditTransactionHistory" },
|
|
4036
|
+
class: "link link-primary text-sm"
|
|
4037
|
+
}, {
|
|
4038
|
+
default: withCtx(() => [..._cache[8] || (_cache[8] = [createTextVNode(" View Credit History → ", -1)])]),
|
|
4039
|
+
_: 1
|
|
4040
|
+
})])) : createCommentVNode("v-if", true)
|
|
4041
|
+
])], 2112)) : createCommentVNode("v-if", true)], 2);
|
|
4042
|
+
};
|
|
4043
|
+
}
|
|
4044
|
+
});
|
|
4045
|
+
var CreditBalanceWidget_default = /* @__PURE__ */ export_helper_default(_sfc_main$2, [["__scopeId", "data-v-703dc3c5"]]);
|
|
4046
|
+
|
|
4047
|
+
//#endregion
|
|
4048
|
+
//#region src/slices/support_ticket/shared/SupportTicketAttachments.vue
|
|
4049
|
+
const _sfc_main$1 = /* @__PURE__ */ defineComponent({
|
|
4050
|
+
__name: "SupportTicketAttachments",
|
|
4051
|
+
setup(__props) {
|
|
4052
|
+
const supportTicketId = useRoute().params.id;
|
|
4053
|
+
const config = { title: "Support Ticket Attachments" };
|
|
4054
|
+
return (_ctx, _cache) => {
|
|
4055
|
+
return openBlock(), createBlock(FileManager_default, {
|
|
4056
|
+
"record-id": unref(supportTicketId),
|
|
4057
|
+
"record-type": "support_ticket",
|
|
4058
|
+
config
|
|
4059
|
+
}, null, 8, ["record-id"]);
|
|
4060
|
+
};
|
|
4061
|
+
}
|
|
4062
|
+
});
|
|
4063
|
+
var SupportTicketAttachments_default = _sfc_main$1;
|
|
4064
|
+
|
|
4065
|
+
//#endregion
|
|
4066
|
+
//#region src/slices/support_ticket/staff/staffSupportTicketFiltersMetadata.ts
|
|
4067
|
+
const adminSupportTicketFiltersSchemaWithMetadata = withMetadata(StaffSupportTicketFiltersSchema, "adminSupportTicketFilters", {
|
|
4068
|
+
type: {
|
|
4069
|
+
label: "Type",
|
|
4070
|
+
inputType: "select"
|
|
4071
|
+
},
|
|
4072
|
+
status: {
|
|
4073
|
+
label: "Status",
|
|
4074
|
+
inputType: "select"
|
|
4075
|
+
},
|
|
4076
|
+
approval_status: {
|
|
4077
|
+
label: "Approval Status",
|
|
4078
|
+
inputType: "select"
|
|
4079
|
+
},
|
|
4080
|
+
priority: {
|
|
4081
|
+
label: "Priority",
|
|
4082
|
+
inputType: "select"
|
|
4083
|
+
}
|
|
4084
|
+
});
|
|
4085
|
+
|
|
4086
|
+
//#endregion
|
|
4087
|
+
//#region src/slices/support_ticket/customer/composables/useSupportTicketPermissions.ts
|
|
4088
|
+
function useSupportTicketPermissions() {
|
|
4089
|
+
const canEditField = (field, status, isLocked) => {
|
|
4090
|
+
switch (status) {
|
|
4091
|
+
case "PENDING": return !isLocked;
|
|
4092
|
+
case "CANCELLED": return true;
|
|
4093
|
+
case "FOLLOWUP":
|
|
4094
|
+
case "IN_PROGRESS": return field === "priority";
|
|
4095
|
+
case "VERIFICATION": return false;
|
|
4096
|
+
default: return false;
|
|
4097
|
+
}
|
|
4098
|
+
};
|
|
4099
|
+
const canFullyEdit = (status, isLocked) => {
|
|
4100
|
+
return status === "PENDING" && !isLocked || status === "CANCELLED";
|
|
4101
|
+
};
|
|
4102
|
+
const getEditInfo = (status, isLocked) => {
|
|
4103
|
+
const canEditTitle = canEditField("title", status, isLocked);
|
|
4104
|
+
const canEditDescription = canEditField("description", status, isLocked);
|
|
4105
|
+
const canEditType = canEditField("type", status, isLocked);
|
|
4106
|
+
const canEditPriority = canEditField("priority", status, isLocked);
|
|
4107
|
+
const canSubmit = status !== "COMPLETED" && status !== "VERIFICATION";
|
|
4108
|
+
const showLimitation = !canFullyEdit(status, isLocked);
|
|
4109
|
+
let sectionTitle;
|
|
4110
|
+
let limitationMessage;
|
|
4111
|
+
let submitText;
|
|
4112
|
+
let submittingText;
|
|
4113
|
+
switch (status) {
|
|
4114
|
+
case "CANCELLED":
|
|
4115
|
+
sectionTitle = "Resubmit SupportTicket";
|
|
4116
|
+
limitationMessage = "";
|
|
4117
|
+
submitText = "Resubmit SupportTicket";
|
|
4118
|
+
submittingText = "Resubmitting...";
|
|
4119
|
+
break;
|
|
4120
|
+
case "FOLLOWUP":
|
|
4121
|
+
sectionTitle = "Limited Editing";
|
|
4122
|
+
limitationMessage = "This support ticket has been approved for development. Only priority can be adjusted.";
|
|
4123
|
+
submitText = "Update Priority";
|
|
4124
|
+
submittingText = "Updating Priority...";
|
|
4125
|
+
break;
|
|
4126
|
+
case "IN_PROGRESS":
|
|
4127
|
+
sectionTitle = "Limited Editing";
|
|
4128
|
+
limitationMessage = "Development is in progress. Only priority can be adjusted.";
|
|
4129
|
+
submitText = "Update Priority";
|
|
4130
|
+
submittingText = "Updating Priority...";
|
|
4131
|
+
break;
|
|
4132
|
+
case "VERIFICATION":
|
|
4133
|
+
sectionTitle = "Verify & Confirm";
|
|
4134
|
+
limitationMessage = "The work has been deployed. Please verify it meets your expectations and leave a comment below to confirm completion.";
|
|
4135
|
+
submitText = "Update SupportTicket";
|
|
4136
|
+
submittingText = "Updating SupportTicket...";
|
|
4137
|
+
break;
|
|
4138
|
+
case "PENDING":
|
|
4139
|
+
sectionTitle = "SupportTicket Details";
|
|
4140
|
+
limitationMessage = isLocked ? "This support ticket is locked for review." : "Editing is temporarily limited.";
|
|
4141
|
+
submitText = "Update SupportTicket";
|
|
4142
|
+
submittingText = "Updating SupportTicket...";
|
|
4143
|
+
break;
|
|
4144
|
+
default:
|
|
4145
|
+
sectionTitle = "SupportTicket Details";
|
|
4146
|
+
limitationMessage = "Editing is limited for this support ticket status.";
|
|
4147
|
+
submitText = "Update SupportTicket";
|
|
4148
|
+
submittingText = "Updating SupportTicket...";
|
|
4149
|
+
}
|
|
4150
|
+
return {
|
|
4151
|
+
sectionTitle,
|
|
4152
|
+
showLimitation,
|
|
4153
|
+
limitationMessage,
|
|
4154
|
+
canEditTitle,
|
|
4155
|
+
canEditDescription,
|
|
4156
|
+
canEditType,
|
|
4157
|
+
canEditPriority,
|
|
4158
|
+
canSubmit,
|
|
4159
|
+
submitText,
|
|
4160
|
+
submittingText
|
|
4161
|
+
};
|
|
4162
|
+
};
|
|
4163
|
+
const getSuccessMessage = (status) => {
|
|
4164
|
+
switch (status) {
|
|
4165
|
+
case "CANCELLED": return "SupportTicket resubmitted successfully! It will be reviewed again.";
|
|
4166
|
+
case "FOLLOWUP":
|
|
4167
|
+
case "IN_PROGRESS": return "Priority updated successfully!";
|
|
4168
|
+
default: return "SupportTicket updated successfully!";
|
|
4169
|
+
}
|
|
4170
|
+
};
|
|
4171
|
+
return {
|
|
4172
|
+
canEditField,
|
|
4173
|
+
canFullyEdit,
|
|
4174
|
+
getEditInfo,
|
|
4175
|
+
getSuccessMessage
|
|
4176
|
+
};
|
|
4177
|
+
}
|
|
4178
|
+
|
|
4179
|
+
//#endregion
|
|
4180
|
+
//#region src/slices/support_ticket/customer/composables/useSupportTicketStatus.ts
|
|
4181
|
+
function useSupportTicketStatus() {
|
|
4182
|
+
const getStatusInfo = (status, isLocked) => {
|
|
4183
|
+
switch (status) {
|
|
4184
|
+
case "FOLLOWUP": return {
|
|
4185
|
+
icon: "✅",
|
|
4186
|
+
label: "Approved - To Do",
|
|
4187
|
+
description: "Your support_ticket has been approved and is scheduled for development",
|
|
4188
|
+
alertClass: "alert-success",
|
|
4189
|
+
whatsNext: "Development will begin soon. You'll be notified of progress updates."
|
|
4190
|
+
};
|
|
4191
|
+
case "IN_PROGRESS": return {
|
|
4192
|
+
icon: "🔧",
|
|
4193
|
+
label: "In Development",
|
|
4194
|
+
description: "Development work is currently in progress",
|
|
4195
|
+
alertClass: "alert-warning",
|
|
4196
|
+
whatsNext: "Development is currently in progress. You'll be notified when completed."
|
|
4197
|
+
};
|
|
4198
|
+
case "VERIFICATION": return {
|
|
4199
|
+
icon: "🔍",
|
|
4200
|
+
label: "Verification",
|
|
4201
|
+
description: "The work has been deployed. Please verify it meets your expectations and leave a comment.",
|
|
4202
|
+
alertClass: "alert-warning",
|
|
4203
|
+
whatsNext: "Please verify the implementation and leave a comment to confirm completion. Once verified, our team will mark this ticket as complete."
|
|
4204
|
+
};
|
|
4205
|
+
case "COMPLETED": return {
|
|
4206
|
+
icon: "🎉",
|
|
4207
|
+
label: "Completed",
|
|
4208
|
+
description: "Your support ticket has been successfully implemented",
|
|
4209
|
+
alertClass: "alert-success",
|
|
4210
|
+
whatsNext: "Your support ticket has been completed! Thank you for your contribution."
|
|
4211
|
+
};
|
|
4212
|
+
case "CANCELLED": return {
|
|
4213
|
+
icon: "❌",
|
|
4214
|
+
label: "Cancelled",
|
|
4215
|
+
description: "This support ticket was not approved for development",
|
|
4216
|
+
alertClass: "alert-error",
|
|
4217
|
+
whatsNext: "You can modify and resubmit your support ticket with additional details."
|
|
4218
|
+
};
|
|
4219
|
+
case "PENDING": return {
|
|
4220
|
+
icon: "⏳",
|
|
4221
|
+
label: "Under Review",
|
|
4222
|
+
description: "Your support ticket is being reviewed by our team",
|
|
4223
|
+
alertClass: "alert-info",
|
|
4224
|
+
whatsNext: isLocked ? "Your support ticket is locked for review. Limited changes may be allowed." : "Our team is reviewing your support ticket. You can still make changes while it's under review."
|
|
4225
|
+
};
|
|
4226
|
+
default: return {
|
|
4227
|
+
icon: "ℹ️",
|
|
4228
|
+
label: status,
|
|
4229
|
+
description: "Status information",
|
|
4230
|
+
alertClass: "alert-info",
|
|
4231
|
+
whatsNext: "Check back for updates on your support ticket status."
|
|
4232
|
+
};
|
|
4233
|
+
}
|
|
4234
|
+
};
|
|
4235
|
+
const isEditable = (status, _isLocked) => {
|
|
4236
|
+
return status !== "COMPLETED" && status !== "VERIFICATION";
|
|
4237
|
+
};
|
|
4238
|
+
const isApproved = (status) => {
|
|
4239
|
+
return [
|
|
4240
|
+
"FOLLOWUP",
|
|
4241
|
+
"IN_PROGRESS",
|
|
4242
|
+
"VERIFICATION",
|
|
4243
|
+
"COMPLETED"
|
|
4244
|
+
].includes(status);
|
|
4245
|
+
};
|
|
4246
|
+
const canResubmit = (status) => {
|
|
4247
|
+
return status === "CANCELLED";
|
|
4248
|
+
};
|
|
4249
|
+
return {
|
|
4250
|
+
getStatusInfo,
|
|
4251
|
+
isEditable,
|
|
4252
|
+
isApproved,
|
|
4253
|
+
canResubmit
|
|
4254
|
+
};
|
|
4255
|
+
}
|
|
4256
|
+
|
|
4257
|
+
//#endregion
|
|
4258
|
+
//#region src/middleware/skipVerifyEmailIfAlreadyVerified.ts
|
|
4259
|
+
/**
|
|
4260
|
+
* Redirects away from the verify-email page when the user is already logged in and verified.
|
|
4261
|
+
* Use as beforeEnter on the verify-email route.
|
|
4262
|
+
*/
|
|
4263
|
+
const skipVerifyEmailIfAlreadyVerified = (to, _from, next) => {
|
|
4264
|
+
if (useUserSessionStore().currentSession?.user?.email_verified) next(getValidReturnUrl(to, "/"));
|
|
4265
|
+
else next();
|
|
4266
|
+
};
|
|
4267
|
+
|
|
4268
|
+
//#endregion
|
|
4269
|
+
//#region src/slices/auth/signupConsentsGuard.ts
|
|
4270
|
+
/**
|
|
4271
|
+
* Route guard for /auth/signup-consents.
|
|
4272
|
+
* Redirects to signup if there is no token in the query (e.g. direct URL, refresh).
|
|
4273
|
+
* The token is set when redirecting from Signup.vue after signupInitiate returns consents.
|
|
4274
|
+
*/
|
|
4275
|
+
const signupConsentsGuard = (to, _from, next) => {
|
|
4276
|
+
const token = to.query.token;
|
|
4277
|
+
if (!token || token.trim() === "") {
|
|
4278
|
+
const returnUrl = to.query.returnUrl;
|
|
4279
|
+
next({
|
|
4280
|
+
path: "/auth/signup",
|
|
4281
|
+
query: returnUrl ? { returnUrl } : {}
|
|
4282
|
+
});
|
|
4283
|
+
} else next();
|
|
4284
|
+
};
|
|
4285
|
+
|
|
4286
|
+
//#endregion
|
|
4287
|
+
//#region src/slices/auth/authRoutes.ts
|
|
4288
|
+
const authPaths = {
|
|
4289
|
+
login: {
|
|
4290
|
+
path: "login",
|
|
4291
|
+
full_path: "/auth/login",
|
|
4292
|
+
name: "Login"
|
|
4293
|
+
},
|
|
4294
|
+
register: {
|
|
4295
|
+
path: "signup",
|
|
4296
|
+
full_path: "/auth/signup",
|
|
4297
|
+
name: "Signup"
|
|
4298
|
+
},
|
|
4299
|
+
forgot_password: {
|
|
4300
|
+
path: "forgot-password",
|
|
4301
|
+
full_path: "/auth/forgot-password",
|
|
4302
|
+
name: "Forgot Password"
|
|
4303
|
+
},
|
|
4304
|
+
reset_password: {
|
|
4305
|
+
path: "reset-password/:token",
|
|
4306
|
+
full_path: "/auth/reset-password",
|
|
4307
|
+
name: "Reset Password"
|
|
4308
|
+
},
|
|
4309
|
+
logout: {
|
|
4310
|
+
path: "logout",
|
|
4311
|
+
full_path: "/auth/logout",
|
|
4312
|
+
name: "Logout"
|
|
4313
|
+
},
|
|
4314
|
+
mfa_setup: {
|
|
4315
|
+
path: "mfa/setup",
|
|
4316
|
+
full_path: "/auth/mfa/setup",
|
|
4317
|
+
name: "MFA Setup"
|
|
4318
|
+
},
|
|
4319
|
+
mfa_verify: {
|
|
4320
|
+
path: "mfa/verify",
|
|
4321
|
+
full_path: "/auth/mfa/verify",
|
|
4322
|
+
name: "MFA Verify"
|
|
4323
|
+
},
|
|
4324
|
+
verify_email: {
|
|
4325
|
+
path: "verify-email",
|
|
4326
|
+
full_path: "/auth/verify-email",
|
|
4327
|
+
name: "Verify Email"
|
|
4328
|
+
},
|
|
4329
|
+
consent_required: {
|
|
4330
|
+
path: "consent-required",
|
|
4331
|
+
full_path: "/auth/consent-required",
|
|
4332
|
+
name: "Consent Required"
|
|
4333
|
+
},
|
|
4334
|
+
signup_consents: {
|
|
4335
|
+
path: "signup-consents",
|
|
4336
|
+
full_path: "/auth/signup-consents",
|
|
4337
|
+
name: "Signup Consents"
|
|
4338
|
+
}
|
|
4339
|
+
};
|
|
4340
|
+
const { allowUserSignup } = useEnv();
|
|
4341
|
+
const baseRoutes = [
|
|
4342
|
+
{
|
|
4343
|
+
path: authPaths.login.path,
|
|
4344
|
+
name: authPaths.login.name,
|
|
4345
|
+
component: () => import("./LoginForm-QFJ8NHww.js"),
|
|
4346
|
+
meta: {
|
|
4347
|
+
title: "Login",
|
|
4348
|
+
description: "Login page for Category 5 App"
|
|
4349
|
+
},
|
|
4350
|
+
beforeEnter: [userAlreadyLoggedIn]
|
|
4351
|
+
},
|
|
4352
|
+
{
|
|
4353
|
+
path: authPaths.forgot_password.path,
|
|
4354
|
+
name: authPaths.forgot_password.name,
|
|
4355
|
+
component: () => import("./ForgotPassword-tJVSg7PB.js"),
|
|
4356
|
+
meta: {
|
|
4357
|
+
title: "Forgot Password",
|
|
4358
|
+
description: "Forgot Password page for Category 5 App"
|
|
4359
|
+
},
|
|
4360
|
+
beforeEnter: [userAlreadyLoggedIn]
|
|
4361
|
+
},
|
|
4362
|
+
{
|
|
4363
|
+
path: authPaths.reset_password.path,
|
|
4364
|
+
name: authPaths.reset_password.name,
|
|
4365
|
+
component: () => import("./ResetPassword-D6to3G6a.js"),
|
|
4366
|
+
meta: {
|
|
4367
|
+
title: "Reset Password",
|
|
4368
|
+
description: "Reset Password page for Category 5 App"
|
|
4369
|
+
},
|
|
4370
|
+
beforeEnter: [userAlreadyLoggedIn]
|
|
4371
|
+
},
|
|
4372
|
+
{
|
|
4373
|
+
path: authPaths.logout.path,
|
|
4374
|
+
name: authPaths.logout.name,
|
|
4375
|
+
component: () => import("./Logout-CjDBff3W.js"),
|
|
4376
|
+
meta: {
|
|
4377
|
+
title: "Logout",
|
|
4378
|
+
description: "Logout page for Category 5 App"
|
|
4379
|
+
}
|
|
4380
|
+
},
|
|
4381
|
+
{
|
|
4382
|
+
path: authPaths.mfa_setup.path,
|
|
4383
|
+
name: authPaths.mfa_setup.name,
|
|
4384
|
+
component: () => import("./MfaSetup-BZcoxJx-.js"),
|
|
4385
|
+
meta: {
|
|
4386
|
+
title: "Set Up Two-Factor Authentication",
|
|
4387
|
+
description: "Enable MFA for your account"
|
|
4388
|
+
}
|
|
4389
|
+
},
|
|
4390
|
+
{
|
|
4391
|
+
path: authPaths.mfa_verify.path,
|
|
4392
|
+
name: authPaths.mfa_verify.name,
|
|
4393
|
+
component: () => import("./MfaVerify-Dy2aV5Gk.js"),
|
|
4394
|
+
meta: {
|
|
4395
|
+
title: "Verify Two-Factor Authentication",
|
|
4396
|
+
description: "Enter your MFA code to complete sign in"
|
|
4397
|
+
}
|
|
4398
|
+
},
|
|
4399
|
+
{
|
|
4400
|
+
path: authPaths.verify_email.path,
|
|
4401
|
+
name: authPaths.verify_email.name,
|
|
4402
|
+
component: () => import("./VerifyEmail-DMHczC9f.js"),
|
|
4403
|
+
meta: {
|
|
4404
|
+
title: "Verify Email",
|
|
4405
|
+
description: "Verify your email address"
|
|
4406
|
+
},
|
|
4407
|
+
beforeEnter: [skipVerifyEmailIfAlreadyVerified]
|
|
4408
|
+
},
|
|
4409
|
+
{
|
|
4410
|
+
path: "verify-email-required",
|
|
4411
|
+
redirect: (to) => ({
|
|
4412
|
+
path: "/auth/verify-email",
|
|
4413
|
+
query: to.query
|
|
4414
|
+
})
|
|
4415
|
+
},
|
|
4416
|
+
{
|
|
4417
|
+
path: authPaths.consent_required.path,
|
|
4418
|
+
name: authPaths.consent_required.name,
|
|
4419
|
+
component: () => import("./ConsentRequired-BPjsZoPY.js"),
|
|
4420
|
+
meta: {
|
|
4421
|
+
title: "Consent Required",
|
|
4422
|
+
description: "Accept updated terms to continue"
|
|
4423
|
+
}
|
|
4424
|
+
},
|
|
4425
|
+
{
|
|
4426
|
+
path: authPaths.signup_consents.path,
|
|
4427
|
+
name: authPaths.signup_consents.name,
|
|
4428
|
+
component: () => import("./SignupConsentFlow-X3kXuviv.js"),
|
|
4429
|
+
meta: {
|
|
4430
|
+
title: "Review and accept",
|
|
4431
|
+
description: "Review and accept terms to complete signup"
|
|
4432
|
+
},
|
|
4433
|
+
beforeEnter: [userAlreadyLoggedIn, signupConsentsGuard]
|
|
4434
|
+
}
|
|
4435
|
+
];
|
|
4436
|
+
if (allowUserSignup) baseRoutes.splice(1, 0, {
|
|
4437
|
+
path: authPaths.register.path,
|
|
4438
|
+
name: authPaths.register.name,
|
|
4439
|
+
component: () => import("./Signup-XdImA1os.js"),
|
|
4440
|
+
meta: {
|
|
4441
|
+
title: "Register",
|
|
4442
|
+
description: "Register page for Category 5 App"
|
|
4443
|
+
},
|
|
4444
|
+
beforeEnter: [userAlreadyLoggedIn]
|
|
4445
|
+
});
|
|
4446
|
+
const authRoutes = baseRoutes;
|
|
4447
|
+
|
|
4448
|
+
//#endregion
|
|
4449
|
+
//#region src/slices/auth/features/login/SocialLoginButtons.vue
|
|
4450
|
+
const _hoisted_1 = { class: "social-login-buttons space-y-3" };
|
|
4451
|
+
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
4452
|
+
__name: "SocialLoginButtons",
|
|
4453
|
+
emits: ["login"],
|
|
4454
|
+
setup(__props) {
|
|
4455
|
+
return (_ctx, _cache) => {
|
|
4456
|
+
return openBlock(), createElementBlock("div", _hoisted_1, [
|
|
4457
|
+
createElementVNode("button", {
|
|
4458
|
+
type: "button",
|
|
4459
|
+
class: "btn btn-outline w-full",
|
|
4460
|
+
onClick: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("login", "google"))
|
|
4461
|
+
}, [..._cache[3] || (_cache[3] = [createElementVNode("span", { class: "mr-2" }, "🔍", -1), createTextVNode(" Sign in with Google ", -1)])]),
|
|
4462
|
+
createElementVNode("button", {
|
|
4463
|
+
type: "button",
|
|
4464
|
+
class: "btn btn-outline w-full",
|
|
4465
|
+
onClick: _cache[1] || (_cache[1] = ($event) => _ctx.$emit("login", "github"))
|
|
4466
|
+
}, [..._cache[4] || (_cache[4] = [createElementVNode("span", { class: "mr-2" }, "🐱", -1), createTextVNode(" Sign in with GitHub ", -1)])]),
|
|
4467
|
+
createElementVNode("button", {
|
|
4468
|
+
type: "button",
|
|
4469
|
+
class: "btn btn-outline w-full",
|
|
4470
|
+
onClick: _cache[2] || (_cache[2] = ($event) => _ctx.$emit("login", "facebook"))
|
|
4471
|
+
}, [..._cache[5] || (_cache[5] = [createElementVNode("span", { class: "mr-2" }, "👤", -1), createTextVNode(" Sign in with Facebook ", -1)])])
|
|
4472
|
+
]);
|
|
4473
|
+
};
|
|
4474
|
+
}
|
|
4475
|
+
});
|
|
4476
|
+
var SocialLoginButtons_default = _sfc_main;
|
|
4477
|
+
|
|
4478
|
+
//#endregion
|
|
4479
|
+
//#region src/slices/admin/adminRoutes.ts
|
|
4480
|
+
const adminRoutes = [{
|
|
4481
|
+
path: "/admin",
|
|
4482
|
+
name: "Admin",
|
|
4483
|
+
beforeEnter: [userIsSuperAdmin],
|
|
4484
|
+
meta: { sectionTabs: [
|
|
4485
|
+
{
|
|
4486
|
+
id: "create-user",
|
|
4487
|
+
label: "Create User",
|
|
4488
|
+
to: { name: "CreateUser" }
|
|
4489
|
+
},
|
|
4490
|
+
{
|
|
4491
|
+
id: "user-management",
|
|
4492
|
+
label: "User Management",
|
|
4493
|
+
to: { name: "UserManagement" }
|
|
4494
|
+
},
|
|
4495
|
+
{
|
|
4496
|
+
id: "support-staff",
|
|
4497
|
+
label: "Support Staff",
|
|
4498
|
+
to: { name: "SupportStaff" }
|
|
4499
|
+
},
|
|
4500
|
+
{
|
|
4501
|
+
id: "credit-management",
|
|
4502
|
+
label: "Credit Management",
|
|
4503
|
+
to: { name: "CreditManagement" }
|
|
4504
|
+
},
|
|
4505
|
+
{
|
|
4506
|
+
id: "support-ticket-maintenance",
|
|
4507
|
+
label: "Support Ticket Maintenance",
|
|
4508
|
+
to: { name: "SupportTicketMaintenance" }
|
|
4509
|
+
},
|
|
4510
|
+
{
|
|
4511
|
+
id: "signup-requirements",
|
|
4512
|
+
label: "Signup Requirements",
|
|
4513
|
+
to: { name: "SignupRequirements" }
|
|
4514
|
+
}
|
|
4515
|
+
] },
|
|
4516
|
+
children: [
|
|
4517
|
+
{
|
|
4518
|
+
path: "create-user",
|
|
4519
|
+
name: "CreateUser",
|
|
4520
|
+
component: () => import("./CreateUserPage-C9uOeYDJ.js"),
|
|
4521
|
+
meta: {
|
|
4522
|
+
title: "Create User",
|
|
4523
|
+
description: "Create User page for Category 5 App",
|
|
4524
|
+
side_bar: {
|
|
4525
|
+
section: " Admin",
|
|
4526
|
+
visible_to: ["super_admin"]
|
|
4527
|
+
}
|
|
4528
|
+
}
|
|
4529
|
+
},
|
|
4530
|
+
{
|
|
4531
|
+
path: "support-staff",
|
|
4532
|
+
name: "SupportStaff",
|
|
4533
|
+
component: () => import("./SupportStaffPage-B69-kuvg.js"),
|
|
4534
|
+
meta: {
|
|
4535
|
+
title: "Support Staff",
|
|
4536
|
+
description: "Manage users who can triage support tickets",
|
|
4537
|
+
side_bar: {
|
|
4538
|
+
section: " Admin",
|
|
4539
|
+
visible_to: ["super_admin"]
|
|
4540
|
+
}
|
|
4541
|
+
}
|
|
4542
|
+
},
|
|
4543
|
+
{
|
|
4544
|
+
path: "users",
|
|
4545
|
+
name: "UserManagement",
|
|
4546
|
+
component: () => import("./UserListPage-Bmwg0an5.js"),
|
|
4547
|
+
meta: {
|
|
4548
|
+
title: "User Management",
|
|
4549
|
+
description: "View and manage all users",
|
|
4550
|
+
side_bar: {
|
|
4551
|
+
section: " Admin",
|
|
4552
|
+
visible_to: ["super_admin"]
|
|
4553
|
+
}
|
|
4554
|
+
}
|
|
4555
|
+
},
|
|
4556
|
+
{
|
|
4557
|
+
path: "users/:id/edit",
|
|
4558
|
+
name: "EditUser",
|
|
4559
|
+
component: () => import("./EditUserPage-C0K7EGjM.js"),
|
|
4560
|
+
meta: {
|
|
4561
|
+
title: "Edit User",
|
|
4562
|
+
description: "Edit user role",
|
|
4563
|
+
breadcrumbs: [
|
|
4564
|
+
{
|
|
4565
|
+
label: "Home",
|
|
4566
|
+
to: { name: "Home" }
|
|
4567
|
+
},
|
|
4568
|
+
{
|
|
4569
|
+
label: "User Management",
|
|
4570
|
+
to: { name: "UserManagement" }
|
|
4571
|
+
},
|
|
4572
|
+
{
|
|
4573
|
+
label: "Edit User",
|
|
4574
|
+
to: { name: "EditUser" }
|
|
4575
|
+
}
|
|
4576
|
+
]
|
|
4577
|
+
}
|
|
4578
|
+
},
|
|
4579
|
+
{
|
|
4580
|
+
path: "credit-management",
|
|
4581
|
+
name: "CreditManagement",
|
|
4582
|
+
component: () => import("./CreditManagement-DXdIN-0d.js"),
|
|
4583
|
+
meta: {
|
|
4584
|
+
title: "Credit Management",
|
|
4585
|
+
description: "Manage customer credits and allocations",
|
|
4586
|
+
side_bar: {
|
|
4587
|
+
section: " Admin",
|
|
4588
|
+
visible_to: ["super_admin"]
|
|
4589
|
+
}
|
|
4590
|
+
}
|
|
4591
|
+
},
|
|
4592
|
+
{
|
|
4593
|
+
path: "support-ticket-maintenance",
|
|
4594
|
+
name: "SupportTicketMaintenance",
|
|
4595
|
+
component: () => import("./SupportTicketMaintenancePage-Bptja-xb.js"),
|
|
4596
|
+
meta: {
|
|
4597
|
+
title: "Support Ticket Maintenance",
|
|
4598
|
+
description: "Admin utilities for fixing support ticket data",
|
|
4599
|
+
side_bar: {
|
|
4600
|
+
section: " Admin",
|
|
4601
|
+
visible_to: ["super_admin"]
|
|
4602
|
+
}
|
|
4603
|
+
}
|
|
4604
|
+
},
|
|
4605
|
+
{
|
|
4606
|
+
path: "signup-requirements",
|
|
4607
|
+
name: "SignupRequirements",
|
|
4608
|
+
component: () => import("./SignupRequirementsPage-Cf-ElkEq.js"),
|
|
4609
|
+
meta: {
|
|
4610
|
+
title: "Signup Requirements",
|
|
4611
|
+
description: "Configure consent checkboxes shown on signup and consent-required flows",
|
|
4612
|
+
side_bar: {
|
|
4613
|
+
section: " Admin",
|
|
4614
|
+
visible_to: ["super_admin"]
|
|
4615
|
+
}
|
|
4616
|
+
}
|
|
4617
|
+
}
|
|
4618
|
+
]
|
|
4619
|
+
}];
|
|
4620
|
+
|
|
4621
|
+
//#endregion
|
|
4622
|
+
//#region src/slices/customer/creditRoutes.ts
|
|
4623
|
+
const creditPaths = { credit_balance: {
|
|
4624
|
+
path: "",
|
|
4625
|
+
full_path: "/credits",
|
|
4626
|
+
name: "CreditBalanceDashboard"
|
|
4627
|
+
} };
|
|
4628
|
+
const creditRoutes = [{
|
|
4629
|
+
path: "/credits",
|
|
4630
|
+
name: "Credits",
|
|
4631
|
+
beforeEnter: [userAuthenticated, leadOrStaffOnly],
|
|
4632
|
+
meta: {},
|
|
4633
|
+
children: [{
|
|
4634
|
+
path: creditPaths.credit_balance.path,
|
|
4635
|
+
name: creditPaths.credit_balance.name,
|
|
4636
|
+
component: () => import("./CreditBalanceDashboard-0HiJE_OS.js"),
|
|
4637
|
+
meta: {
|
|
4638
|
+
title: "Credit Balance",
|
|
4639
|
+
description: "View your current credit balance and history.",
|
|
4640
|
+
side_bar: {
|
|
4641
|
+
section: "Support",
|
|
4642
|
+
visible_to: [
|
|
4643
|
+
"lead",
|
|
4644
|
+
"staff",
|
|
4645
|
+
"super_admin"
|
|
4646
|
+
]
|
|
4647
|
+
}
|
|
4648
|
+
}
|
|
4649
|
+
}]
|
|
4650
|
+
}];
|
|
4651
|
+
|
|
4652
|
+
//#endregion
|
|
4653
|
+
export { timezones as A, UnverifiedEmailBanner_default as B, SupportTicketStatusBadge_default as C, TeamAttachmentsTab_default as D, teamFiltersSchemaWithMetadata as E, FieldDisplay_default as F, NotFound_default as G, Sidebar_default as H, InApp_default as I, InputModal_default as J, Navbar_default as K, Default_default as L, KeyValueEditor_default as M, FileManager_default as N, userRoutes as O, FieldGroup_default as P, Auth_default as R, customerSupportTicketRowSchemaWithMetadata as S, teamMemberFiltersSchemaWithMetadata as T, useBuildTag as U, useEmailVerificationGuard as V, RightSidebar_default as W, AppTabNavigation_default as X, AppHeader_default as Y, DragoncoreVue as Z, CompleteSupportTicketForm_default as _, authPaths as a, CustomerCreditBalance_default as b, useSupportTicketPermissions as c, CreditBalanceWidget_default as d, StaffSupportTicketList_default as f, ConvertToCustomerWorkflow_default as g, ConvertToInternalWorkflow_default as h, SocialLoginButtons_default as i, SummarySection_default as j, userAlreadyLoggedIn as k, adminSupportTicketFiltersSchemaWithMetadata as l, ReactivateInternalTaskWorkflow_default as m, creditRoutes as n, authRoutes as o, adminSupportTicketRowSchemaWithMetadata as p, LoginButton_default as q, adminRoutes as r, useSupportTicketStatus as s, creditPaths as t, SupportTicketAttachments_default as u, CancelInternalTaskWorkflow_default as v, SupportTicketTimeline_default as w, CustomerSupportTicketList_default as x, ApproveRejectActions_default as y, Admin_default as z };
|
|
4654
|
+
//# sourceMappingURL=src-DVe_0RO9.js.map
|