@dragonmastery/dragoncore-vue 0.0.29 → 0.0.30
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/{ChangePasswordPage-C7rqJfii.js → ChangePasswordPage-D1LGJ02W.js} +1 -1
- package/dist/{ChangePasswordPage-nr0B06HB.js → ChangePasswordPage-Dy8lFUcI.js} +1 -1
- package/dist/{ChangePasswordPage-nr0B06HB.js.map → ChangePasswordPage-Dy8lFUcI.js.map} +1 -1
- package/dist/{ConsentFlowStep-DstxorHZ.js → ConsentFlowStep-DsVhXa91.js} +2 -2
- package/dist/{ConsentFlowStep-DstxorHZ.js.map → ConsentFlowStep-DsVhXa91.js.map} +1 -1
- package/dist/{ConsentRequired-ELUidmNv.js → ConsentRequired-B3eLxJgx.js} +3 -3
- package/dist/{ConsentRequired-ELUidmNv.js.map → ConsentRequired-B3eLxJgx.js.map} +1 -1
- package/dist/CreateTeamForm-5V_ks5Ie.js +12 -0
- package/dist/{CreateTeamForm-DNkueBzR.js → CreateTeamForm-B7MsOsiV.js} +4 -4
- package/dist/{CreateTeamForm-DNkueBzR.js.map → CreateTeamForm-B7MsOsiV.js.map} +1 -1
- package/dist/{CreateTeamMemberForm-CSF-tD6B.js → CreateTeamMemberForm-CayF2tIJ.js} +5 -5
- package/dist/{CreateTeamMemberForm-ITp4XFn9.js → CreateTeamMemberForm-DeUyXnVa.js} +4 -4
- package/dist/{CreateTeamMemberForm-ITp4XFn9.js.map → CreateTeamMemberForm-DeUyXnVa.js.map} +1 -1
- package/dist/{CreditBalanceDashboard-CLQ8NZnY.js → CreditBalanceDashboard-CoIEyZWh.js} +2 -2
- package/dist/{CreditBalanceDashboard-CLQ8NZnY.js.map → CreditBalanceDashboard-CoIEyZWh.js.map} +1 -1
- package/dist/{CreditBalanceDashboard-jdvZa-ZT.js → CreditBalanceDashboard-D_TsFlTp.js} +5 -5
- package/dist/{CreditManagement-Dus4O1BY.js → CreditManagement-CCyU_yja.js} +2 -2
- package/dist/{CreditManagement-Dus4O1BY.js.map → CreditManagement-CCyU_yja.js.map} +1 -1
- package/dist/{CreditManagement-DvGikLLe.js → CreditManagement-CdkqQM7F.js} +5 -5
- package/dist/{CreditTransactionHistory-BZZGQxTV.js → CreditTransactionHistory-UPg9uDNy.js} +3 -3
- package/dist/{CreditTransactionHistory-BZZGQxTV.js.map → CreditTransactionHistory-UPg9uDNy.js.map} +1 -1
- package/dist/{CustomerCreateSupportTicketForm-C3CgjqXg.js → CustomerCreateSupportTicketForm-CiTTUqtW.js} +5 -5
- package/dist/{CustomerCreateSupportTicketForm-CeG8IKA1.js → CustomerCreateSupportTicketForm-DFH1JtlA.js} +3 -3
- package/dist/{CustomerCreateSupportTicketForm-CeG8IKA1.js.map → CustomerCreateSupportTicketForm-DFH1JtlA.js.map} +1 -1
- package/dist/{CustomerSupportTicketDetailPage-CUkf9swo.js → CustomerSupportTicketDetailPage-DAwiE2t6.js} +5 -5
- package/dist/{CustomerSupportTicketDetailPage-CUkf9swo.js.map → CustomerSupportTicketDetailPage-DAwiE2t6.js.map} +1 -1
- package/dist/CustomerSupportTicketList-CKZl8jxx.js +64 -0
- package/dist/{CustomerSupportTicketParent-D19kei4H.js → CustomerSupportTicketParent-D3Gj4Hel.js} +2 -2
- package/dist/{CustomerSupportTicketParent-BaKfkSlU.js → CustomerSupportTicketParent-rl4Ym8oa.js} +3 -3
- package/dist/{CustomerSupportTicketParent-BaKfkSlU.js.map → CustomerSupportTicketParent-rl4Ym8oa.js.map} +1 -1
- package/dist/{CustomerSupportTicketSuccess-Cc75m_p-.js → CustomerSupportTicketSuccess-BEhFZgtn.js} +2 -2
- package/dist/{CustomerSupportTicketSuccess-Cc75m_p-.js.map → CustomerSupportTicketSuccess-BEhFZgtn.js.map} +1 -1
- package/dist/{CustomerSupportTicketSuccess-ca10puM-.js → CustomerSupportTicketSuccess-BJO2xsQR.js} +4 -4
- package/dist/{DefaultReferralTeamPage-fO3tmwOb.js → DefaultReferralTeamPage-D3UIrIZK.js} +2 -2
- package/dist/{DefaultReferralTeamPage-fO3tmwOb.js.map → DefaultReferralTeamPage-D3UIrIZK.js.map} +1 -1
- package/dist/EditTeamForm-Bf4rSgQg.js +12 -0
- package/dist/{EditTeamForm-DdvKHlNj.js → EditTeamForm-C1_-p3lZ.js} +4 -4
- package/dist/{EditTeamForm-DdvKHlNj.js.map → EditTeamForm-C1_-p3lZ.js.map} +1 -1
- package/dist/{EditTeamMemberForm-CIqEjFF8.js → EditTeamMemberForm-Bh6zVNyJ.js} +3 -3
- package/dist/{EditTeamMemberForm-Fyf8Zxfh.js → EditTeamMemberForm-D9cofrUM.js} +3 -3
- package/dist/{EditTeamMemberForm-Fyf8Zxfh.js.map → EditTeamMemberForm-D9cofrUM.js.map} +1 -1
- package/dist/{EditUserPage-D3AWaHT2.js → EditUserPage-CQgp-08o.js} +1 -1
- package/dist/{EditUserPage-BBzGmOrx.js → EditUserPage-CwsO8naT.js} +2 -2
- package/dist/{EditUserPage-BBzGmOrx.js.map → EditUserPage-CwsO8naT.js.map} +1 -1
- package/dist/{ExternalLinkIcon-FidcmNOa.js → ExternalLinkIcon-BKVV5Gjm.js} +1 -1
- package/dist/{ExternalLinkIcon-FidcmNOa.js.map → ExternalLinkIcon-BKVV5Gjm.js.map} +1 -1
- package/dist/{FieldsetSection-CH1jAwcc.js → FieldsetSection-Br_sygWW.js} +1 -1
- package/dist/{FieldsetSection-CH1jAwcc.js.map → FieldsetSection-Br_sygWW.js.map} +1 -1
- package/dist/{RecordVersionViewer-NLn1gVys.js → RecordVersionViewer-DKIdX_BX.js} +1 -1
- package/dist/{RecordVersionViewer-NLn1gVys.js.map → RecordVersionViewer-DKIdX_BX.js.map} +1 -1
- package/dist/{SavedFiltersPage-B9aQYpwf.js → SavedFiltersPage-Cz01ZeHx.js} +45 -45
- package/dist/{SavedFiltersPage-B9aQYpwf.js.map → SavedFiltersPage-Cz01ZeHx.js.map} +1 -1
- package/dist/{Signup-EykiX-bQ.js → Signup-CkhRQErA.js} +4 -12
- package/dist/Signup-CkhRQErA.js.map +1 -0
- package/dist/{Signup-Ceh7XSea.js → Signup-cOvXCtJj.js} +2 -2
- package/dist/{SignupConsentFlow-CRtiMpcS.js → SignupConsentFlow-CKMFsnf5.js} +10 -7
- package/dist/SignupConsentFlow-CKMFsnf5.js.map +1 -0
- package/dist/{SignupRequirementsPage-CohJluxQ.js → SignupRequirementsPage-33z--rhH.js} +4 -4
- package/dist/{SignupRequirementsPage-CohJluxQ.js.map → SignupRequirementsPage-33z--rhH.js.map} +1 -1
- package/dist/{StaffCreateSupportTicketForm-ANtaO4pe.js → StaffCreateSupportTicketForm-BtR-Aowv.js} +4 -4
- package/dist/{StaffCreateSupportTicketForm-ANtaO4pe.js.map → StaffCreateSupportTicketForm-BtR-Aowv.js.map} +1 -1
- package/dist/{StaffCreateSupportTicketForm-CtU12OGq.js → StaffCreateSupportTicketForm-D7ctCaXe.js} +5 -5
- package/dist/{StaffSupportTicketDetailPage-B63QXyum.js → StaffSupportTicketDetailPage-LqnNfU34.js} +7 -7
- package/dist/{StaffSupportTicketDetailPage-B63QXyum.js.map → StaffSupportTicketDetailPage-LqnNfU34.js.map} +1 -1
- package/dist/StaffSupportTicketList-GyzlONKe.js +64 -0
- package/dist/{StaffSupportTicketParent-yoC-_Lku.js → StaffSupportTicketParent-DPvdLUii.js} +3 -3
- package/dist/{StaffSupportTicketParent-yoC-_Lku.js.map → StaffSupportTicketParent-DPvdLUii.js.map} +1 -1
- package/dist/{StaffSupportTicketParent-ByUwsYGx.js → StaffSupportTicketParent-Dyybqx74.js} +2 -2
- package/dist/{StaffSupportTicketSuccess-CB4Oa_2J.js → StaffSupportTicketSuccess-B3N-RMoT.js} +2 -2
- package/dist/{StaffSupportTicketSuccess-CB4Oa_2J.js.map → StaffSupportTicketSuccess-B3N-RMoT.js.map} +1 -1
- package/dist/{StaffSupportTicketSuccess-BMh5amWI.js → StaffSupportTicketSuccess-DvonYilY.js} +4 -4
- package/dist/{SupportStaffPage-CkFLlle4.js → SupportStaffPage-geoITTqt.js} +3 -3
- package/dist/{SupportStaffPage-CkFLlle4.js.map → SupportStaffPage-geoITTqt.js.map} +1 -1
- package/dist/{SupportTicketDevLifecycleBadge-BYKZjEv6.js → SupportTicketDevLifecycleBadge-D8-Cv1Np.js} +1 -1
- package/dist/{SupportTicketDevLifecycleBadge-BYKZjEv6.js.map → SupportTicketDevLifecycleBadge-D8-Cv1Np.js.map} +1 -1
- package/dist/TeamAttachmentsTab-ChP4DaUP.js +64 -0
- package/dist/{TeamHistoryTab-p3hDxCc3.js → TeamHistoryTab-CxzA4u_G.js} +3 -3
- package/dist/{TeamHistoryTab-p3hDxCc3.js.map → TeamHistoryTab-CxzA4u_G.js.map} +1 -1
- package/dist/TeamHistoryTab-wRpRizDE.js +6 -0
- package/dist/{TeamList-B4gWPzce.js → TeamList-_SsqJicG.js} +3 -3
- package/dist/{TeamList-B4gWPzce.js.map → TeamList-_SsqJicG.js.map} +1 -1
- package/dist/TeamList-cp8Pa2xg.js +8 -0
- package/dist/TeamMemberList-B16SuLwM.js +7 -0
- package/dist/{TeamMemberList-D0-dM5kI.js → TeamMemberList-BYUANoBg.js} +3 -3
- package/dist/{TeamMemberList-D0-dM5kI.js.map → TeamMemberList-BYUANoBg.js.map} +1 -1
- package/dist/{TeamMemberParent-C9OEziOK.js → TeamMemberParent-BJl8nBmP.js} +4 -4
- package/dist/{TeamMemberParent-CJGWXjuM.js → TeamMemberParent-DmYcHU3n.js} +3 -3
- package/dist/{TeamMemberParent-CJGWXjuM.js.map → TeamMemberParent-DmYcHU3n.js.map} +1 -1
- package/dist/{TeamNotesTab-BnkgZd-5.js → TeamNotesTab-BQN9niw-.js} +1 -1
- package/dist/{TeamNotesTab-DPw9YEwK.js → TeamNotesTab-Cego-QT3.js} +2 -2
- package/dist/{TeamNotesTab-DPw9YEwK.js.map → TeamNotesTab-Cego-QT3.js.map} +1 -1
- package/dist/{TeamParent-KQmJgJ9x.js → TeamParent-BUnqP-dr.js} +3 -3
- package/dist/{TeamParent-KQmJgJ9x.js.map → TeamParent-BUnqP-dr.js.map} +1 -1
- package/dist/TeamParent-BseZ6Zoi.js +11 -0
- package/dist/{TimelineNoteInput-DXZhcUkH.js → TimelineNoteInput-BBZv3X4p.js} +2 -2
- package/dist/{TimelineNoteInput-DXZhcUkH.js.map → TimelineNoteInput-BBZv3X4p.js.map} +1 -1
- package/dist/{TimelineSystemEvent-Ch1sZiyO.js → TimelineSystemEvent-D5fkhkZT.js} +1 -1
- package/dist/{TimelineSystemEvent-Ch1sZiyO.js.map → TimelineSystemEvent-D5fkhkZT.js.map} +1 -1
- package/dist/UserListPage-BABli3QG.js +5 -0
- package/dist/{UserListPage-A0_eNpQ1.js → UserListPage-CDMSZpXK.js} +2 -2
- package/dist/{UserListPage-A0_eNpQ1.js.map → UserListPage-CDMSZpXK.js.map} +1 -1
- package/dist/{UserProfilePage-FNLYK9kj.js → UserProfilePage-BYitd7QV.js} +1 -1
- package/dist/{UserProfilePage-FNLYK9kj.js.map → UserProfilePage-BYitd7QV.js.map} +1 -1
- package/dist/{UserProfilePage-BWK97ODt.js → UserProfilePage-Dmxp7oqP.js} +1 -1
- package/dist/{VerifyEmail-BYYsE-M_.js → VerifyEmail-CLDngljq.js} +2 -2
- package/dist/{VerifyEmail-BVwHQpbw.js → VerifyEmail-CWUhRA1o.js} +2 -2
- package/dist/{VerifyEmail-BVwHQpbw.js.map → VerifyEmail-CWUhRA1o.js.map} +1 -1
- package/dist/ViewTeam-rLNxVgS2.js +8 -0
- package/dist/{ViewTeam-BV7SjH8R.js → ViewTeam-ttqX2In8.js} +4 -4
- package/dist/{ViewTeam-BV7SjH8R.js.map → ViewTeam-ttqX2In8.js.map} +1 -1
- package/dist/ViewTeamMember-B5U8kZBw.js +7 -0
- package/dist/{ViewTeamMember-Cf5yXdv6.js → ViewTeamMember-DqWZ3F_h.js} +4 -4
- package/dist/{ViewTeamMember-Cf5yXdv6.js.map → ViewTeamMember-DqWZ3F_h.js.map} +1 -1
- package/dist/{ZiniaContainer-BV6sojLa.js → ZiniaContainer-BPIfQOc7.js} +1 -1
- package/dist/{ZiniaContainer-BV6sojLa.js.map → ZiniaContainer-BPIfQOc7.js.map} +1 -1
- package/dist/{convertToLocalDateTime-C13-PrSA.js → convertToLocalDateTime-BKBxm2Rc.js} +1 -1
- package/dist/{convertToLocalDateTime-C13-PrSA.js.map → convertToLocalDateTime-BKBxm2Rc.js.map} +1 -1
- package/dist/{customerSupportTicketRoutes-_HjQcEAD.js → customerSupportTicketRoutes-C-DKBy5g.js} +8 -8
- package/dist/{customerSupportTicketRoutes-_HjQcEAD.js.map → customerSupportTicketRoutes-C-DKBy5g.js.map} +1 -1
- package/dist/{displayIdFormatter-Cr-QaEk1.js → displayIdFormatter-Ca4Al9iB.js} +1 -1
- package/dist/{displayIdFormatter-Cr-QaEk1.js.map → displayIdFormatter-Ca4Al9iB.js.map} +1 -1
- package/dist/{extractRpcErrorMessage-CAaeVysa.js → extractRpcErrorMessage-Df8-CJGV.js} +1 -1
- package/dist/{extractRpcErrorMessage-CAaeVysa.js.map → extractRpcErrorMessage-Df8-CJGV.js.map} +1 -1
- package/dist/index.d.ts +763 -753
- package/dist/index.js +48 -47
- package/dist/{saved_filter-C6YHkEMV.js → saved_filter-C2N9l_a9.js} +3 -3
- package/dist/{saved_filter-C6YHkEMV.js.map → saved_filter-C2N9l_a9.js.map} +1 -1
- package/dist/{signupConsentStorage-foqtLkIk.js → signupConsentStorage-pWSoHuhO.js} +10 -2
- package/dist/signupConsentStorage-pWSoHuhO.js.map +1 -0
- package/dist/{src-BIX3mMjo.js → src-C8B9TJiH.js} +31 -26
- package/dist/src-C8B9TJiH.js.map +1 -0
- package/dist/{staffSupportTicketRoutes-WPaItK5S.js → staffSupportTicketRoutes-CyMecWpC.js} +8 -8
- package/dist/{staffSupportTicketRoutes-WPaItK5S.js.map → staffSupportTicketRoutes-CyMecWpC.js.map} +1 -1
- package/dist/{teamMemberMetadata-DX0W-B7p.js → teamMemberMetadata-C4urCwBU.js} +1 -1
- package/dist/{teamMemberMetadata-DX0W-B7p.js.map → teamMemberMetadata-C4urCwBU.js.map} +1 -1
- package/dist/{teamMetadata-26Mwjb2i.js → teamMetadata-NTjPt89L.js} +1 -1
- package/dist/{teamMetadata-26Mwjb2i.js.map → teamMetadata-NTjPt89L.js.map} +1 -1
- package/dist/{teamRoutes-CQWRPy3J.js → teamRoutes-CFDsHPkd.js} +12 -12
- package/dist/{teamRoutes-CQWRPy3J.js.map → teamRoutes-CFDsHPkd.js.map} +1 -1
- package/dist/{team_memberRoutes-Cxgte_vj.js → team_memberRoutes-BgjY9Kwq.js} +7 -7
- package/dist/{team_memberRoutes-Cxgte_vj.js.map → team_memberRoutes-BgjY9Kwq.js.map} +1 -1
- package/dist/{useBreadcrumbs-DIqU5AAp.js → useBreadcrumbs-CPWXm0hm.js} +1 -1
- package/dist/{useBreadcrumbs-DIqU5AAp.js.map → useBreadcrumbs-CPWXm0hm.js.map} +1 -1
- package/dist/{useEmailVerificationChannel-C4bvvG2b.js → useEmailVerificationChannel-QuMSgzzM.js} +1 -1
- package/dist/{useEmailVerificationChannel-C4bvvG2b.js.map → useEmailVerificationChannel-QuMSgzzM.js.map} +1 -1
- package/dist/{userAuthorized-klLUHGxT.js → userAuthorized-3RiCDXxr.js} +1 -1
- package/dist/{userAuthorized-klLUHGxT.js.map → userAuthorized-3RiCDXxr.js.map} +1 -1
- package/package.json +2 -2
- package/dist/CreateTeamForm-CCfgSWUA.js +0 -12
- package/dist/CustomerSupportTicketList-D1pcZzcX.js +0 -64
- package/dist/EditTeamForm-BzTAypZT.js +0 -12
- package/dist/Signup-EykiX-bQ.js.map +0 -1
- package/dist/SignupConsentFlow-CRtiMpcS.js.map +0 -1
- package/dist/StaffSupportTicketList-CqK8PVq4.js +0 -64
- package/dist/TeamAttachmentsTab-BG_K7uwG.js +0 -64
- package/dist/TeamHistoryTab-BSEOYC_5.js +0 -6
- package/dist/TeamList-iAH9mOdd.js +0 -8
- package/dist/TeamMemberList-uwSe9zdv.js +0 -7
- package/dist/TeamParent-D_IbzH8B.js +0 -11
- package/dist/UserListPage-CjpxiETO.js +0 -5
- package/dist/ViewTeam-BvLIv9Dd.js +0 -8
- package/dist/ViewTeamMember-DtQCZU-X.js +0 -7
- package/dist/signupConsentStorage-foqtLkIk.js.map +0 -1
- package/dist/src-BIX3mMjo.js.map +0 -1
- /package/dist/{Appearance-CHCv4Fd1.js → Appearance-BhzkZJOL.js} +0 -0
- /package/dist/{TeamMembersTab-CeOJAhhR.js → TeamMembersTab-D7y2nV__.js} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TimelineSystemEvent-Ch1sZiyO.js","names":["priorityConfig: Record<SupportTicketPriority, PriorityBadgeConfig>","typeConfig: Record<SupportTicketType, TypeBadgeConfig>","approvalConfig: Record<SupportTicketApproval, ApprovalBadgeConfig>","relative: string"],"sources":["../src/slices/support_ticket/utils/creditValueFormatter.ts","../src/slices/support_ticket/shared/SupportTicketPriorityBadge.vue","../src/slices/support_ticket/shared/SupportTicketTypeBadge.vue","../src/slices/support_ticket/shared/SupportTicketApprovalBadge.vue","../src/slices/support_ticket/utils/formatTicketDate.ts","../src/slices/support_ticket/shared/TimelineItem.vue","../src/slices/support_ticket/shared/TimelineSystemEvent.vue"],"sourcesContent":["import type { SupportTicketApproval } from '@dragonmastery/dragoncore-shared';\n\n/**\n * Helper function to check if credit value is empty\n */\nfunction isCreditValueEmpty(value: string | null | undefined): boolean {\n return value === null || value === undefined || value.trim() === '';\n}\n\n/**\n * Core credit formatting logic\n */\nfunction formatCreditValueCore(creditValue: string | null | undefined): string {\n // Use same logic as backend formatter\n if (isCreditValueEmpty(creditValue)) {\n return 'TBD';\n }\n\n const trimmed = creditValue!.trim();\n const num = parseFloat(trimmed);\n\n // Explicit zero is valid - preserve it (same as backend)\n if (num === 0) {\n return '0';\n }\n\n // Remove trailing zeros for non-zero values (same as backend)\n // Examples: \"100.00\" -> \"100\", \"9.50\" -> \"9.5\", \"123.45\" -> \"123.45\"\n return trimmed.replace(/\\.?0+$/, '');\n}\n\n/**\n * Formats credit value for staff views (includes internal ticket logic)\n *\n * @param creditValue - The credit value from the database\n * @param approvalStatus - The approval status to determine display logic\n * @returns Formatted string for display\n *\n * @example\n * formatStaffCreditValue(\"5.50\", \"PENDING\") // \"5.5\"\n * formatStaffCreditValue(\"10\", \"INTERNAL\") // \"N/A\"\n */\nexport function formatStaffCreditValue(\n creditValue: string | null | undefined,\n approvalStatus?: SupportTicketApproval,\n): string {\n // Internal tickets don't use credits\n if (approvalStatus === 'INTERNAL') {\n return 'N/A';\n }\n\n return formatCreditValueCore(creditValue);\n}\n\n/**\n * Formats credit value for customer views (status-based logic)\n *\n * @param creditValue - The credit value from the database\n * @param status - The computed status from the customer query\n * @returns Formatted string for display\n *\n * @example\n * formatCustomerCreditValue(\"5.50\", \"PENDING\") // \"5.5\"\n * formatCustomerCreditValue(\"5.50\", \"FOLLOWUP\") // \"5.5\"\n */\nexport function formatCustomerCreditValue(creditValue: string | null | undefined): string {\n // Note: Internal tickets (status would be different) are handled by backend\n // Customers don't see internal tickets, so we don't need to check for INTERNAL here\n return formatCreditValueCore(creditValue);\n}\n","<template>\n <div :class=\"badgeClasses\" :aria-label=\"ariaLabel\" role=\"status\">\n {{ displayText }}\n </div>\n</template>\n\n<script setup lang=\"ts\">\n/**\n * SupportTicketPriorityBadge - A reusable Vue component for displaying support ticket priority\n * as color-coded badges with consistent DaisyUI styling and accessibility features.\n *\n * @example\n * <SupportTicketPriorityBadge :priority=\"'HIGH'\" size=\"md\" />\n * <SupportTicketPriorityBadge :priority=\"'CRITICAL'\" size=\"sm\" variant=\"outline\" />\n */\nimport type { SupportTicketPriority } from '@dragonmastery/dragoncore-shared';\nimport { computed } from 'vue';\n\n/**\n * Props for the SupportTicketPriorityBadge component\n */\ninterface Props {\n /** The support ticket priority to display */\n priority: SupportTicketPriority;\n /** Size of the badge - defaults to 'md' */\n size?: 'sm' | 'md' | 'lg';\n /** Visual variant of the badge - defaults to 'default' */\n variant?: 'default' | 'outline';\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n size: 'md',\n variant: 'default',\n});\n\n/**\n * Configuration for each priority badge\n */\ninterface PriorityBadgeConfig {\n /** DaisyUI badge color class */\n color: string;\n /** Display text for the badge */\n text: string;\n /** Accessibility label for screen readers */\n ariaLabel: string;\n}\n\nconst priorityConfig: Record<SupportTicketPriority, PriorityBadgeConfig> = {\n LOW: {\n color: 'badge-neutral',\n text: 'Low',\n ariaLabel: 'Priority: Low priority',\n },\n MEDIUM: {\n color: 'badge-neutral',\n text: 'Medium',\n ariaLabel: 'Priority: Medium priority',\n },\n HIGH: {\n color: 'badge-neutral',\n text: 'High',\n ariaLabel: 'Priority: High priority',\n },\n CRITICAL: {\n color: 'badge-neutral',\n text: 'Critical',\n ariaLabel: 'Priority: Critical priority',\n },\n};\n\nconst getPriorityConfig = (priority: SupportTicketPriority): PriorityBadgeConfig => {\n const config = priorityConfig[priority];\n if (!config) {\n return {\n color: 'badge-neutral',\n text: priority || 'Unknown',\n ariaLabel: `Priority: ${priority || 'Unknown priority'}`,\n };\n }\n return config;\n};\n\nconst config = computed(() => getPriorityConfig(props.priority));\n\nconst badgeClasses = computed(() => {\n const baseClasses = ['badge', 'text-xs'];\n\n // Add color class\n baseClasses.push(config.value.color);\n\n // Add size class with responsive text sizing\n if (props.size === 'sm') {\n baseClasses.push('badge-sm', 'text-xs');\n } else if (props.size === 'lg') {\n baseClasses.push('badge-lg', 'text-sm');\n } else {\n // md size - responsive text\n baseClasses.push('text-xs', 'sm:text-sm');\n }\n\n // Add variant class\n if (props.variant === 'outline') {\n baseClasses.push('badge-outline');\n }\n\n return baseClasses.join(' ');\n});\n\nconst displayText = computed(() => config.value.text);\nconst ariaLabel = computed(() => config.value.ariaLabel);\n</script>\n","<template>\n <div :class=\"badgeClasses\" :aria-label=\"ariaLabel\" role=\"status\">\n {{ displayText }}\n </div>\n</template>\n\n<script setup lang=\"ts\">\n/**\n * SupportTicketTypeBadge - A reusable Vue component for displaying support ticket type\n * as color-coded badges with consistent DaisyUI styling and accessibility features.\n *\n * @example\n * <SupportTicketTypeBadge :type=\"'BUG'\" size=\"md\" />\n * <SupportTicketTypeBadge :type=\"'FEATURE_REQUEST'\" size=\"sm\" variant=\"outline\" />\n */\nimport type { SupportTicketType } from '@dragonmastery/dragoncore-shared';\nimport { computed } from 'vue';\n\n/**\n * Props for the SupportTicketTypeBadge component\n */\ninterface Props {\n /** The support ticket type to display */\n type: SupportTicketType;\n /** Size of the badge - defaults to 'md' */\n size?: 'sm' | 'md' | 'lg';\n /** Visual variant of the badge - defaults to 'default' */\n variant?: 'default' | 'outline';\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n size: 'md',\n variant: 'default',\n});\n\n/**\n * Configuration for each type badge\n */\ninterface TypeBadgeConfig {\n /** DaisyUI badge color class */\n color: string;\n /** Display text for the badge */\n text: string;\n /** Accessibility label for screen readers */\n ariaLabel: string;\n}\n\nconst typeConfig: Record<SupportTicketType, TypeBadgeConfig> = {\n BUG: {\n color: 'badge-neutral',\n text: 'Bug',\n ariaLabel: 'Type: Bug report requiring fix',\n },\n FEATURE_REQUEST: {\n color: 'badge-neutral',\n text: 'Feature',\n ariaLabel: 'Type: New feature request',\n },\n IMPROVEMENT: {\n color: 'badge-neutral',\n text: 'Improvement',\n ariaLabel: 'Type: Enhancement to existing feature',\n },\n OPERATIONAL: {\n color: 'badge-neutral',\n text: 'Ops',\n ariaLabel: 'Type: Operational/admin work',\n },\n};\n\nconst getTypeConfig = (type: SupportTicketType): TypeBadgeConfig => {\n const config = typeConfig[type];\n if (!config) {\n return {\n color: 'badge-neutral',\n text: type || 'Unknown',\n ariaLabel: `Type: ${type || 'Unknown type'}`,\n };\n }\n return config;\n};\n\nconst config = computed(() => getTypeConfig(props.type));\n\nconst badgeClasses = computed(() => {\n const baseClasses = ['badge', 'text-xs'];\n\n // Add color class\n baseClasses.push(config.value.color);\n\n // Add size class with responsive text sizing\n if (props.size === 'sm') {\n baseClasses.push('badge-sm', 'text-xs');\n } else if (props.size === 'lg') {\n baseClasses.push('badge-lg', 'text-sm');\n } else {\n // md size - responsive text\n baseClasses.push('text-xs', 'sm:text-sm');\n }\n\n // Add variant class\n if (props.variant === 'outline') {\n baseClasses.push('badge-outline');\n }\n\n return baseClasses.join(' ');\n});\n\nconst displayText = computed(() => config.value.text);\nconst ariaLabel = computed(() => config.value.ariaLabel);\n</script>\n","<template>\n <div :class=\"badgeClasses\" :aria-label=\"ariaLabel\" role=\"status\">\n {{ displayText }}\n </div>\n</template>\n\n<script setup lang=\"ts\">\n/**\n * SupportTicketApprovalBadge - A reusable Vue component for displaying support ticket approval status\n * as color-coded badges with consistent DaisyUI styling and accessibility features.\n *\n * @example\n * <SupportTicketApprovalBadge :approvalStatus=\"'PENDING'\" size=\"md\" />\n * <SupportTicketApprovalBadge :approvalStatus=\"'APPROVED'\" size=\"sm\" variant=\"outline\" />\n */\nimport type { SupportTicketApproval } from '@dragonmastery/dragoncore-shared';\nimport { computed } from 'vue';\n\n/**\n * Props for the SupportTicketApprovalBadge component\n */\ninterface Props {\n /** The support ticket approval status to display */\n approvalStatus: SupportTicketApproval;\n /** Size of the badge - defaults to 'md' */\n size?: 'sm' | 'md' | 'lg';\n /** Visual variant of the badge - defaults to 'default' */\n variant?: 'default' | 'outline';\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n size: 'md',\n variant: 'default',\n});\n\n/**\n * Configuration for each approval status badge\n */\ninterface ApprovalBadgeConfig {\n /** DaisyUI badge color class */\n color: string;\n /** Display text for the badge */\n text: string;\n /** Accessibility label for screen readers */\n ariaLabel: string;\n}\n\nconst approvalConfig: Record<SupportTicketApproval, ApprovalBadgeConfig> = {\n PENDING: {\n color: 'badge-warning',\n text: 'Pending',\n ariaLabel: 'Approval: Awaiting staff decision',\n },\n APPROVED: {\n color: 'badge-success',\n text: 'Approved',\n ariaLabel: 'Approval: Approved by staff',\n },\n REJECTED: {\n color: 'badge-error',\n text: 'Rejected',\n ariaLabel: 'Approval: Rejected by staff',\n },\n INTERNAL: {\n color: 'badge-info',\n text: 'Internal',\n ariaLabel: 'Approval: Internal staff ticket',\n },\n};\n\nconst getApprovalConfig = (approvalStatus: SupportTicketApproval): ApprovalBadgeConfig => {\n const config = approvalConfig[approvalStatus];\n if (!config) {\n return {\n color: 'badge-neutral',\n text: approvalStatus || 'Unknown',\n ariaLabel: `Approval: ${approvalStatus || 'Unknown status'}`,\n };\n }\n return config;\n};\n\nconst config = computed(() => getApprovalConfig(props.approvalStatus));\n\nconst badgeClasses = computed(() => {\n const baseClasses = ['badge', 'text-xs'];\n\n // Add color class\n baseClasses.push(config.value.color);\n\n // Add size class with responsive text sizing\n if (props.size === 'sm') {\n baseClasses.push('badge-sm', 'text-xs');\n } else if (props.size === 'lg') {\n baseClasses.push('badge-lg', 'text-sm');\n } else {\n // md size - responsive text\n baseClasses.push('text-xs', 'sm:text-sm');\n }\n\n // Add variant class\n if (props.variant === 'outline') {\n baseClasses.push('badge-outline');\n }\n\n return baseClasses.join(' ');\n});\n\nconst displayText = computed(() => config.value.text);\nconst ariaLabel = computed(() => config.value.ariaLabel);\n</script>\n","/**\n * Takes an ISO date string and returns:\n * - formatted: \"Jan 15, 2025\"\n * - relative: \"3 days ago\" / \"2 hours ago\" / \"just now\"\n * - localTime: \"2:30 PM\" (user's local time)\n */\nexport function formatTicketDate(isoString: string): {\n formatted: string;\n relative: string;\n localTime: string;\n} {\n const date = new Date(isoString);\n if (isNaN(date.getTime())) {\n return { formatted: isoString, relative: '', localTime: '' };\n }\n\n const formatted = date.toLocaleDateString(undefined, {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n });\n\n const localTime = date.toLocaleTimeString(undefined, {\n hour: 'numeric',\n minute: '2-digit',\n });\n\n const now = new Date();\n const diffMs = now.getTime() - date.getTime();\n const diffSec = Math.floor(diffMs / 1000);\n const diffMin = Math.floor(diffSec / 60);\n const diffHour = Math.floor(diffMin / 60);\n const diffDay = Math.floor(diffHour / 24);\n\n let relative: string;\n if (Math.abs(diffSec) < 60) {\n relative = 'just now';\n } else if (diffSec < 0) {\n const sec = Math.abs(diffSec);\n const min = Math.floor(sec / 60);\n const hr = Math.floor(min / 60);\n const day = Math.floor(hr / 24);\n if (min < 60) relative = `in ${min} minute${min === 1 ? '' : 's'}`;\n else if (hr < 24) relative = `in ${hr} hour${hr === 1 ? '' : 's'}`;\n else relative = `in ${day} day${day === 1 ? '' : 's'}`;\n } else if (diffMin < 60) {\n relative = diffMin === 1 ? '1 minute ago' : `${diffMin} minutes ago`;\n } else if (diffHour < 24) {\n relative = diffHour === 1 ? '1 hour ago' : `${diffHour} hours ago`;\n } else if (diffDay < 30) {\n relative = diffDay === 1 ? '1 day ago' : `${diffDay} days ago`;\n } else {\n const diffWeeks = Math.floor(diffDay / 7);\n const diffMonths = Math.floor(diffDay / 30);\n if (diffWeeks < 4) {\n relative = diffWeeks === 1 ? '1 week ago' : `${diffWeeks} weeks ago`;\n } else if (diffMonths < 12) {\n relative = diffMonths === 1 ? '1 month ago' : `${diffMonths} months ago`;\n } else {\n const diffYears = Math.floor(diffMonths / 12);\n relative = diffYears === 1 ? '1 year ago' : `${diffYears} years ago`;\n }\n }\n\n return { formatted, relative, localTime };\n}\n","<template>\n <div\n :class=\"[\n 'card card-bordered p-4 w-full',\n variant === 'internal'\n ? 'bg-warning/10 border-warning/30'\n : 'bg-base-100',\n ]\"\n >\n <div class=\"flex items-center gap-2 mb-3 flex-wrap\">\n <span\n v-if=\"variant === 'internal'\"\n class=\"badge badge-warning badge-sm gap-1 shrink-0\"\n aria-label=\"Internal note\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke-width=\"1.5\"\n stroke=\"currentColor\"\n class=\"w-3.5 h-3.5\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n d=\"M16.5 10.5V6.75a4.5 4.5 0 10-9 0v3.75m-.75 11.25h10.5a2.25 2.25 0 002.25-2.25v-6.75a2.25 2.25 0 00-2.25-2.25H6.75a2.25 2.25 0 00-2.25 2.25v6.75a2.25 2.25 0 002.25 2.25z\"\n />\n </svg>\n Internal\n </span>\n <span\n v-else\n class=\"w-6 h-6 rounded-full bg-primary text-primary-content text-xs flex items-center justify-center shrink-0\"\n aria-hidden=\"true\"\n >\n {{ authorInitial }}\n </span>\n <span class=\"font-semibold text-sm\">{{ authorName }}</span>\n <span class=\"text-base-content/50 text-sm\">· {{ relativeTime }}</span>\n </div>\n <div class=\"text-sm text-base-content break-words whitespace-pre-wrap\">\n <slot />\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue';\nimport { formatTicketDate } from '../utils/formatTicketDate';\n\ninterface Props {\n authorName: string;\n createdAt: string;\n variant: 'customer' | 'internal';\n}\n\nconst props = defineProps<Props>();\n\nconst authorInitial = computed(() => {\n const name = props.authorName?.trim() || '?';\n return name.charAt(0).toUpperCase();\n});\n\nconst relativeTime = computed(() => {\n return props.createdAt ? formatTicketDate(props.createdAt).relative : '';\n});\n</script>\n","<template>\n <div class=\"py-2 flex items-start gap-2 text-sm\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke-width=\"1.5\"\n stroke=\"currentColor\"\n class=\"w-4 h-4 text-base-content/30 shrink-0 mt-0.5\"\n aria-hidden=\"true\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n d=\"M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.324.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 011.37.49l1.296 2.247a1.125 1.125 0 01-.26 1.431l-1.003.827c-.293.24-.438.613-.431.992a6.759 6.759 0 010 .255c-.007.378.138.75.43.99l1.005.828c.424.35.534.954.26 1.43l-1.298 2.247a1.125 1.125 0 01-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.57 6.57 0 01-.22.128c-.331.183-.581.495-.644.869l-.213 1.28c-.09.543-.56.941-1.11.941h-2.594c-.55 0-1.02-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 01-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 01-1.369-.49l-1.297-2.247a1.125 1.125 0 01.26-1.431l1.004-.827c.292-.24.437-.613.43-.992a6.932 6.932 0 010-.255c.007-.378-.138-.75-.43-.99l-1.004-.828a1.125 1.125 0 01-.26-1.43l1.297-2.247a1.125 1.125 0 011.37-.491l1.216.456c.356.133.751.072 1.076-.124a6.57 6.57 0 01.22-.128c.332-.183.582-.495.644-.869l.214-1.281z\"\n />\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n d=\"M15 12a3 3 0 11-6 0 3 3 0 016 0z\"\n />\n </svg>\n <div class=\"flex-1 min-w-0 space-y-0.5\">\n <div class=\"flex flex-wrap items-baseline gap-x-2 gap-y-1\">\n <span class=\"text-base-content/60 font-medium\">{{ author }}</span>\n <span class=\"text-base-content/40 text-xs\" aria-hidden=\"true\">·</span>\n <span class=\"font-semibold text-base-content\">{{ displayAction }}</span>\n <template v-if=\"type\">\n <span class=\"text-base-content/40 text-xs\" aria-hidden=\"true\">·</span>\n <span\n class=\"badge badge-sm badge-outline border-base-content/20 text-base-content/80 font-normal px-1.5 py-0 capitalize\"\n >\n {{ type }}\n </span>\n </template>\n <template v-if=\"changes && changes.length > 1\">\n <template v-if=\"details\">\n <span class=\"text-base-content/40 text-xs\" aria-hidden=\"true\">·</span>\n <span class=\"text-base-content/70\">{{ details }}</span>\n </template>\n </template>\n <template v-else-if=\"hasChangeDetails\">\n <span class=\"text-base-content/40 text-xs\" aria-hidden=\"true\">·</span>\n <span class=\"text-base-content/70\">\n <template v-if=\"detailsPrefix\">{{ detailsPrefix }} </template>\n <template v-if=\"oldValue != null && newValue != null\">\n <span class=\"line-through text-base-content/50\">{{ oldValue }}</span>\n <span class=\"mx-1 text-base-content/40\">→</span>\n <span>{{ newValue }}</span>\n </template>\n <template v-else-if=\"displayDetails\">{{ displayDetails }}</template>\n </span>\n </template>\n </div>\n <ul\n v-if=\"changes && changes.length > 1\"\n class=\"mt-1.5 ml-6 list-disc list-inside text-base-content/70 text-sm space-y-0.5\"\n >\n <li v-for=\"(change, i) in changes\" :key=\"i\">\n <span class=\"italic text-base-content/60\">{{ change.action }}:</span>\n <template v-if=\"change.oldValue != null && change.newValue != null\">\n <span class=\"line-through text-base-content/50 ml-1\">{{ change.oldValue }}</span>\n <span class=\"mx-1 text-base-content/40\">→</span>\n <span>{{ change.newValue }}</span>\n </template>\n <template v-else-if=\"change.newValue != null\">\n <span class=\"ml-1\">{{ change.newValue }}</span>\n </template>\n </li>\n </ul>\n <div class=\"text-base-content/40 text-xs\">\n <button\n type=\"button\"\n class=\"cursor-pointer hover:text-base-content/60 hover:underline focus:outline-none focus:underline\"\n :title=\"fullDateTime\"\n @click=\"showFull = !showFull\"\n >\n {{ displayTime }}\n </button>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, ref } from 'vue';\nimport { formatTicketDate } from '../utils/formatTicketDate';\n\ninterface SystemEventChange {\n action: string;\n oldValue: string | null;\n newValue: string | null;\n fieldName?: string;\n}\n\ninterface Props {\n author: string;\n message: string;\n timestamp: string;\n action?: string;\n type?: string | null;\n details?: string | null;\n oldValue?: string | null;\n newValue?: string | null;\n changes?: SystemEventChange[];\n}\n\nconst props = defineProps<Props>();\nconst showFull = ref(false);\n\nconst displayAction = computed(() => props.action ?? props.message);\nconst displayDetails = computed(() => {\n if (props.details) return props.details;\n if (props.oldValue != null && props.newValue != null) {\n return `${props.oldValue} → ${props.newValue}`;\n }\n return props.newValue ?? null;\n});\nconst hasChangeDetails = computed(\n () =>\n (props.oldValue != null && props.newValue != null) ||\n props.details != null ||\n props.newValue != null,\n);\nconst detailsPrefix = computed(() => {\n if (!props.details || (props.oldValue == null && props.newValue == null)) return null;\n if (props.details.includes(' · ')) {\n const parts = props.details.split(' · ');\n return parts.length > 1 ? parts[0]! : null;\n }\n return props.details;\n});\n\n/** Use relative time when within ~18 hours, otherwise full date and time */\nconst RECENT_THRESHOLD_HOURS = 18;\n\nconst shortTime = computed(() => {\n if (!props.timestamp) return '';\n const { relative, formatted, localTime } = formatTicketDate(props.timestamp);\n const dateTime = [formatted, localTime].filter(Boolean).join(', ');\n if (!relative && !dateTime) return '';\n const date = new Date(props.timestamp);\n const hoursAgo = (Date.now() - date.getTime()) / (1000 * 60 * 60);\n const isRecent = hoursAgo >= 0 && hoursAgo < RECENT_THRESHOLD_HOURS;\n return isRecent ? relative : dateTime;\n});\n\nconst fullDateTime = computed(() => {\n if (!props.timestamp) return '';\n const { formatted, localTime } = formatTicketDate(props.timestamp);\n return [formatted, localTime].filter(Boolean).join(', ');\n});\n\nconst displayTime = computed(() =>\n showFull.value ? fullDateTime.value : shortTime.value,\n);\n</script>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TimelineSystemEvent-D5fkhkZT.js","names":["priorityConfig: Record<SupportTicketPriority, PriorityBadgeConfig>","typeConfig: Record<SupportTicketType, TypeBadgeConfig>","approvalConfig: Record<SupportTicketApproval, ApprovalBadgeConfig>","relative: string"],"sources":["../src/slices/support_ticket/utils/creditValueFormatter.ts","../src/slices/support_ticket/shared/SupportTicketPriorityBadge.vue","../src/slices/support_ticket/shared/SupportTicketTypeBadge.vue","../src/slices/support_ticket/shared/SupportTicketApprovalBadge.vue","../src/slices/support_ticket/utils/formatTicketDate.ts","../src/slices/support_ticket/shared/TimelineItem.vue","../src/slices/support_ticket/shared/TimelineSystemEvent.vue"],"sourcesContent":["import type { SupportTicketApproval } from '@dragonmastery/dragoncore-shared';\n\n/**\n * Helper function to check if credit value is empty\n */\nfunction isCreditValueEmpty(value: string | null | undefined): boolean {\n return value === null || value === undefined || value.trim() === '';\n}\n\n/**\n * Core credit formatting logic\n */\nfunction formatCreditValueCore(creditValue: string | null | undefined): string {\n // Use same logic as backend formatter\n if (isCreditValueEmpty(creditValue)) {\n return 'TBD';\n }\n\n const trimmed = creditValue!.trim();\n const num = parseFloat(trimmed);\n\n // Explicit zero is valid - preserve it (same as backend)\n if (num === 0) {\n return '0';\n }\n\n // Remove trailing zeros for non-zero values (same as backend)\n // Examples: \"100.00\" -> \"100\", \"9.50\" -> \"9.5\", \"123.45\" -> \"123.45\"\n return trimmed.replace(/\\.?0+$/, '');\n}\n\n/**\n * Formats credit value for staff views (includes internal ticket logic)\n *\n * @param creditValue - The credit value from the database\n * @param approvalStatus - The approval status to determine display logic\n * @returns Formatted string for display\n *\n * @example\n * formatStaffCreditValue(\"5.50\", \"PENDING\") // \"5.5\"\n * formatStaffCreditValue(\"10\", \"INTERNAL\") // \"N/A\"\n */\nexport function formatStaffCreditValue(\n creditValue: string | null | undefined,\n approvalStatus?: SupportTicketApproval,\n): string {\n // Internal tickets don't use credits\n if (approvalStatus === 'INTERNAL') {\n return 'N/A';\n }\n\n return formatCreditValueCore(creditValue);\n}\n\n/**\n * Formats credit value for customer views (status-based logic)\n *\n * @param creditValue - The credit value from the database\n * @param status - The computed status from the customer query\n * @returns Formatted string for display\n *\n * @example\n * formatCustomerCreditValue(\"5.50\", \"PENDING\") // \"5.5\"\n * formatCustomerCreditValue(\"5.50\", \"FOLLOWUP\") // \"5.5\"\n */\nexport function formatCustomerCreditValue(creditValue: string | null | undefined): string {\n // Note: Internal tickets (status would be different) are handled by backend\n // Customers don't see internal tickets, so we don't need to check for INTERNAL here\n return formatCreditValueCore(creditValue);\n}\n","<template>\n <div :class=\"badgeClasses\" :aria-label=\"ariaLabel\" role=\"status\">\n {{ displayText }}\n </div>\n</template>\n\n<script setup lang=\"ts\">\n/**\n * SupportTicketPriorityBadge - A reusable Vue component for displaying support ticket priority\n * as color-coded badges with consistent DaisyUI styling and accessibility features.\n *\n * @example\n * <SupportTicketPriorityBadge :priority=\"'HIGH'\" size=\"md\" />\n * <SupportTicketPriorityBadge :priority=\"'CRITICAL'\" size=\"sm\" variant=\"outline\" />\n */\nimport type { SupportTicketPriority } from '@dragonmastery/dragoncore-shared';\nimport { computed } from 'vue';\n\n/**\n * Props for the SupportTicketPriorityBadge component\n */\ninterface Props {\n /** The support ticket priority to display */\n priority: SupportTicketPriority;\n /** Size of the badge - defaults to 'md' */\n size?: 'sm' | 'md' | 'lg';\n /** Visual variant of the badge - defaults to 'default' */\n variant?: 'default' | 'outline';\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n size: 'md',\n variant: 'default',\n});\n\n/**\n * Configuration for each priority badge\n */\ninterface PriorityBadgeConfig {\n /** DaisyUI badge color class */\n color: string;\n /** Display text for the badge */\n text: string;\n /** Accessibility label for screen readers */\n ariaLabel: string;\n}\n\nconst priorityConfig: Record<SupportTicketPriority, PriorityBadgeConfig> = {\n LOW: {\n color: 'badge-neutral',\n text: 'Low',\n ariaLabel: 'Priority: Low priority',\n },\n MEDIUM: {\n color: 'badge-neutral',\n text: 'Medium',\n ariaLabel: 'Priority: Medium priority',\n },\n HIGH: {\n color: 'badge-neutral',\n text: 'High',\n ariaLabel: 'Priority: High priority',\n },\n CRITICAL: {\n color: 'badge-neutral',\n text: 'Critical',\n ariaLabel: 'Priority: Critical priority',\n },\n};\n\nconst getPriorityConfig = (priority: SupportTicketPriority): PriorityBadgeConfig => {\n const config = priorityConfig[priority];\n if (!config) {\n return {\n color: 'badge-neutral',\n text: priority || 'Unknown',\n ariaLabel: `Priority: ${priority || 'Unknown priority'}`,\n };\n }\n return config;\n};\n\nconst config = computed(() => getPriorityConfig(props.priority));\n\nconst badgeClasses = computed(() => {\n const baseClasses = ['badge', 'text-xs'];\n\n // Add color class\n baseClasses.push(config.value.color);\n\n // Add size class with responsive text sizing\n if (props.size === 'sm') {\n baseClasses.push('badge-sm', 'text-xs');\n } else if (props.size === 'lg') {\n baseClasses.push('badge-lg', 'text-sm');\n } else {\n // md size - responsive text\n baseClasses.push('text-xs', 'sm:text-sm');\n }\n\n // Add variant class\n if (props.variant === 'outline') {\n baseClasses.push('badge-outline');\n }\n\n return baseClasses.join(' ');\n});\n\nconst displayText = computed(() => config.value.text);\nconst ariaLabel = computed(() => config.value.ariaLabel);\n</script>\n","<template>\n <div :class=\"badgeClasses\" :aria-label=\"ariaLabel\" role=\"status\">\n {{ displayText }}\n </div>\n</template>\n\n<script setup lang=\"ts\">\n/**\n * SupportTicketTypeBadge - A reusable Vue component for displaying support ticket type\n * as color-coded badges with consistent DaisyUI styling and accessibility features.\n *\n * @example\n * <SupportTicketTypeBadge :type=\"'BUG'\" size=\"md\" />\n * <SupportTicketTypeBadge :type=\"'FEATURE_REQUEST'\" size=\"sm\" variant=\"outline\" />\n */\nimport type { SupportTicketType } from '@dragonmastery/dragoncore-shared';\nimport { computed } from 'vue';\n\n/**\n * Props for the SupportTicketTypeBadge component\n */\ninterface Props {\n /** The support ticket type to display */\n type: SupportTicketType;\n /** Size of the badge - defaults to 'md' */\n size?: 'sm' | 'md' | 'lg';\n /** Visual variant of the badge - defaults to 'default' */\n variant?: 'default' | 'outline';\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n size: 'md',\n variant: 'default',\n});\n\n/**\n * Configuration for each type badge\n */\ninterface TypeBadgeConfig {\n /** DaisyUI badge color class */\n color: string;\n /** Display text for the badge */\n text: string;\n /** Accessibility label for screen readers */\n ariaLabel: string;\n}\n\nconst typeConfig: Record<SupportTicketType, TypeBadgeConfig> = {\n BUG: {\n color: 'badge-neutral',\n text: 'Bug',\n ariaLabel: 'Type: Bug report requiring fix',\n },\n FEATURE_REQUEST: {\n color: 'badge-neutral',\n text: 'Feature',\n ariaLabel: 'Type: New feature request',\n },\n IMPROVEMENT: {\n color: 'badge-neutral',\n text: 'Improvement',\n ariaLabel: 'Type: Enhancement to existing feature',\n },\n OPERATIONAL: {\n color: 'badge-neutral',\n text: 'Ops',\n ariaLabel: 'Type: Operational/admin work',\n },\n};\n\nconst getTypeConfig = (type: SupportTicketType): TypeBadgeConfig => {\n const config = typeConfig[type];\n if (!config) {\n return {\n color: 'badge-neutral',\n text: type || 'Unknown',\n ariaLabel: `Type: ${type || 'Unknown type'}`,\n };\n }\n return config;\n};\n\nconst config = computed(() => getTypeConfig(props.type));\n\nconst badgeClasses = computed(() => {\n const baseClasses = ['badge', 'text-xs'];\n\n // Add color class\n baseClasses.push(config.value.color);\n\n // Add size class with responsive text sizing\n if (props.size === 'sm') {\n baseClasses.push('badge-sm', 'text-xs');\n } else if (props.size === 'lg') {\n baseClasses.push('badge-lg', 'text-sm');\n } else {\n // md size - responsive text\n baseClasses.push('text-xs', 'sm:text-sm');\n }\n\n // Add variant class\n if (props.variant === 'outline') {\n baseClasses.push('badge-outline');\n }\n\n return baseClasses.join(' ');\n});\n\nconst displayText = computed(() => config.value.text);\nconst ariaLabel = computed(() => config.value.ariaLabel);\n</script>\n","<template>\n <div :class=\"badgeClasses\" :aria-label=\"ariaLabel\" role=\"status\">\n {{ displayText }}\n </div>\n</template>\n\n<script setup lang=\"ts\">\n/**\n * SupportTicketApprovalBadge - A reusable Vue component for displaying support ticket approval status\n * as color-coded badges with consistent DaisyUI styling and accessibility features.\n *\n * @example\n * <SupportTicketApprovalBadge :approvalStatus=\"'PENDING'\" size=\"md\" />\n * <SupportTicketApprovalBadge :approvalStatus=\"'APPROVED'\" size=\"sm\" variant=\"outline\" />\n */\nimport type { SupportTicketApproval } from '@dragonmastery/dragoncore-shared';\nimport { computed } from 'vue';\n\n/**\n * Props for the SupportTicketApprovalBadge component\n */\ninterface Props {\n /** The support ticket approval status to display */\n approvalStatus: SupportTicketApproval;\n /** Size of the badge - defaults to 'md' */\n size?: 'sm' | 'md' | 'lg';\n /** Visual variant of the badge - defaults to 'default' */\n variant?: 'default' | 'outline';\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n size: 'md',\n variant: 'default',\n});\n\n/**\n * Configuration for each approval status badge\n */\ninterface ApprovalBadgeConfig {\n /** DaisyUI badge color class */\n color: string;\n /** Display text for the badge */\n text: string;\n /** Accessibility label for screen readers */\n ariaLabel: string;\n}\n\nconst approvalConfig: Record<SupportTicketApproval, ApprovalBadgeConfig> = {\n PENDING: {\n color: 'badge-warning',\n text: 'Pending',\n ariaLabel: 'Approval: Awaiting staff decision',\n },\n APPROVED: {\n color: 'badge-success',\n text: 'Approved',\n ariaLabel: 'Approval: Approved by staff',\n },\n REJECTED: {\n color: 'badge-error',\n text: 'Rejected',\n ariaLabel: 'Approval: Rejected by staff',\n },\n INTERNAL: {\n color: 'badge-info',\n text: 'Internal',\n ariaLabel: 'Approval: Internal staff ticket',\n },\n};\n\nconst getApprovalConfig = (approvalStatus: SupportTicketApproval): ApprovalBadgeConfig => {\n const config = approvalConfig[approvalStatus];\n if (!config) {\n return {\n color: 'badge-neutral',\n text: approvalStatus || 'Unknown',\n ariaLabel: `Approval: ${approvalStatus || 'Unknown status'}`,\n };\n }\n return config;\n};\n\nconst config = computed(() => getApprovalConfig(props.approvalStatus));\n\nconst badgeClasses = computed(() => {\n const baseClasses = ['badge', 'text-xs'];\n\n // Add color class\n baseClasses.push(config.value.color);\n\n // Add size class with responsive text sizing\n if (props.size === 'sm') {\n baseClasses.push('badge-sm', 'text-xs');\n } else if (props.size === 'lg') {\n baseClasses.push('badge-lg', 'text-sm');\n } else {\n // md size - responsive text\n baseClasses.push('text-xs', 'sm:text-sm');\n }\n\n // Add variant class\n if (props.variant === 'outline') {\n baseClasses.push('badge-outline');\n }\n\n return baseClasses.join(' ');\n});\n\nconst displayText = computed(() => config.value.text);\nconst ariaLabel = computed(() => config.value.ariaLabel);\n</script>\n","/**\n * Takes an ISO date string and returns:\n * - formatted: \"Jan 15, 2025\"\n * - relative: \"3 days ago\" / \"2 hours ago\" / \"just now\"\n * - localTime: \"2:30 PM\" (user's local time)\n */\nexport function formatTicketDate(isoString: string): {\n formatted: string;\n relative: string;\n localTime: string;\n} {\n const date = new Date(isoString);\n if (isNaN(date.getTime())) {\n return { formatted: isoString, relative: '', localTime: '' };\n }\n\n const formatted = date.toLocaleDateString(undefined, {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n });\n\n const localTime = date.toLocaleTimeString(undefined, {\n hour: 'numeric',\n minute: '2-digit',\n });\n\n const now = new Date();\n const diffMs = now.getTime() - date.getTime();\n const diffSec = Math.floor(diffMs / 1000);\n const diffMin = Math.floor(diffSec / 60);\n const diffHour = Math.floor(diffMin / 60);\n const diffDay = Math.floor(diffHour / 24);\n\n let relative: string;\n if (Math.abs(diffSec) < 60) {\n relative = 'just now';\n } else if (diffSec < 0) {\n const sec = Math.abs(diffSec);\n const min = Math.floor(sec / 60);\n const hr = Math.floor(min / 60);\n const day = Math.floor(hr / 24);\n if (min < 60) relative = `in ${min} minute${min === 1 ? '' : 's'}`;\n else if (hr < 24) relative = `in ${hr} hour${hr === 1 ? '' : 's'}`;\n else relative = `in ${day} day${day === 1 ? '' : 's'}`;\n } else if (diffMin < 60) {\n relative = diffMin === 1 ? '1 minute ago' : `${diffMin} minutes ago`;\n } else if (diffHour < 24) {\n relative = diffHour === 1 ? '1 hour ago' : `${diffHour} hours ago`;\n } else if (diffDay < 30) {\n relative = diffDay === 1 ? '1 day ago' : `${diffDay} days ago`;\n } else {\n const diffWeeks = Math.floor(diffDay / 7);\n const diffMonths = Math.floor(diffDay / 30);\n if (diffWeeks < 4) {\n relative = diffWeeks === 1 ? '1 week ago' : `${diffWeeks} weeks ago`;\n } else if (diffMonths < 12) {\n relative = diffMonths === 1 ? '1 month ago' : `${diffMonths} months ago`;\n } else {\n const diffYears = Math.floor(diffMonths / 12);\n relative = diffYears === 1 ? '1 year ago' : `${diffYears} years ago`;\n }\n }\n\n return { formatted, relative, localTime };\n}\n","<template>\n <div\n :class=\"[\n 'card card-bordered p-4 w-full',\n variant === 'internal'\n ? 'bg-warning/10 border-warning/30'\n : 'bg-base-100',\n ]\"\n >\n <div class=\"flex items-center gap-2 mb-3 flex-wrap\">\n <span\n v-if=\"variant === 'internal'\"\n class=\"badge badge-warning badge-sm gap-1 shrink-0\"\n aria-label=\"Internal note\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke-width=\"1.5\"\n stroke=\"currentColor\"\n class=\"w-3.5 h-3.5\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n d=\"M16.5 10.5V6.75a4.5 4.5 0 10-9 0v3.75m-.75 11.25h10.5a2.25 2.25 0 002.25-2.25v-6.75a2.25 2.25 0 00-2.25-2.25H6.75a2.25 2.25 0 00-2.25 2.25v6.75a2.25 2.25 0 002.25 2.25z\"\n />\n </svg>\n Internal\n </span>\n <span\n v-else\n class=\"w-6 h-6 rounded-full bg-primary text-primary-content text-xs flex items-center justify-center shrink-0\"\n aria-hidden=\"true\"\n >\n {{ authorInitial }}\n </span>\n <span class=\"font-semibold text-sm\">{{ authorName }}</span>\n <span class=\"text-base-content/50 text-sm\">· {{ relativeTime }}</span>\n </div>\n <div class=\"text-sm text-base-content break-words whitespace-pre-wrap\">\n <slot />\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue';\nimport { formatTicketDate } from '../utils/formatTicketDate';\n\ninterface Props {\n authorName: string;\n createdAt: string;\n variant: 'customer' | 'internal';\n}\n\nconst props = defineProps<Props>();\n\nconst authorInitial = computed(() => {\n const name = props.authorName?.trim() || '?';\n return name.charAt(0).toUpperCase();\n});\n\nconst relativeTime = computed(() => {\n return props.createdAt ? formatTicketDate(props.createdAt).relative : '';\n});\n</script>\n","<template>\n <div class=\"py-2 flex items-start gap-2 text-sm\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke-width=\"1.5\"\n stroke=\"currentColor\"\n class=\"w-4 h-4 text-base-content/30 shrink-0 mt-0.5\"\n aria-hidden=\"true\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n d=\"M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.324.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 011.37.49l1.296 2.247a1.125 1.125 0 01-.26 1.431l-1.003.827c-.293.24-.438.613-.431.992a6.759 6.759 0 010 .255c-.007.378.138.75.43.99l1.005.828c.424.35.534.954.26 1.43l-1.298 2.247a1.125 1.125 0 01-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.57 6.57 0 01-.22.128c-.331.183-.581.495-.644.869l-.213 1.28c-.09.543-.56.941-1.11.941h-2.594c-.55 0-1.02-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 01-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 01-1.369-.49l-1.297-2.247a1.125 1.125 0 01.26-1.431l1.004-.827c.292-.24.437-.613.43-.992a6.932 6.932 0 010-.255c.007-.378-.138-.75-.43-.99l-1.004-.828a1.125 1.125 0 01-.26-1.43l1.297-2.247a1.125 1.125 0 011.37-.491l1.216.456c.356.133.751.072 1.076-.124a6.57 6.57 0 01.22-.128c.332-.183.582-.495.644-.869l.214-1.281z\"\n />\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n d=\"M15 12a3 3 0 11-6 0 3 3 0 016 0z\"\n />\n </svg>\n <div class=\"flex-1 min-w-0 space-y-0.5\">\n <div class=\"flex flex-wrap items-baseline gap-x-2 gap-y-1\">\n <span class=\"text-base-content/60 font-medium\">{{ author }}</span>\n <span class=\"text-base-content/40 text-xs\" aria-hidden=\"true\">·</span>\n <span class=\"font-semibold text-base-content\">{{ displayAction }}</span>\n <template v-if=\"type\">\n <span class=\"text-base-content/40 text-xs\" aria-hidden=\"true\">·</span>\n <span\n class=\"badge badge-sm badge-outline border-base-content/20 text-base-content/80 font-normal px-1.5 py-0 capitalize\"\n >\n {{ type }}\n </span>\n </template>\n <template v-if=\"changes && changes.length > 1\">\n <template v-if=\"details\">\n <span class=\"text-base-content/40 text-xs\" aria-hidden=\"true\">·</span>\n <span class=\"text-base-content/70\">{{ details }}</span>\n </template>\n </template>\n <template v-else-if=\"hasChangeDetails\">\n <span class=\"text-base-content/40 text-xs\" aria-hidden=\"true\">·</span>\n <span class=\"text-base-content/70\">\n <template v-if=\"detailsPrefix\">{{ detailsPrefix }} </template>\n <template v-if=\"oldValue != null && newValue != null\">\n <span class=\"line-through text-base-content/50\">{{ oldValue }}</span>\n <span class=\"mx-1 text-base-content/40\">→</span>\n <span>{{ newValue }}</span>\n </template>\n <template v-else-if=\"displayDetails\">{{ displayDetails }}</template>\n </span>\n </template>\n </div>\n <ul\n v-if=\"changes && changes.length > 1\"\n class=\"mt-1.5 ml-6 list-disc list-inside text-base-content/70 text-sm space-y-0.5\"\n >\n <li v-for=\"(change, i) in changes\" :key=\"i\">\n <span class=\"italic text-base-content/60\">{{ change.action }}:</span>\n <template v-if=\"change.oldValue != null && change.newValue != null\">\n <span class=\"line-through text-base-content/50 ml-1\">{{ change.oldValue }}</span>\n <span class=\"mx-1 text-base-content/40\">→</span>\n <span>{{ change.newValue }}</span>\n </template>\n <template v-else-if=\"change.newValue != null\">\n <span class=\"ml-1\">{{ change.newValue }}</span>\n </template>\n </li>\n </ul>\n <div class=\"text-base-content/40 text-xs\">\n <button\n type=\"button\"\n class=\"cursor-pointer hover:text-base-content/60 hover:underline focus:outline-none focus:underline\"\n :title=\"fullDateTime\"\n @click=\"showFull = !showFull\"\n >\n {{ displayTime }}\n </button>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, ref } from 'vue';\nimport { formatTicketDate } from '../utils/formatTicketDate';\n\ninterface SystemEventChange {\n action: string;\n oldValue: string | null;\n newValue: string | null;\n fieldName?: string;\n}\n\ninterface Props {\n author: string;\n message: string;\n timestamp: string;\n action?: string;\n type?: string | null;\n details?: string | null;\n oldValue?: string | null;\n newValue?: string | null;\n changes?: SystemEventChange[];\n}\n\nconst props = defineProps<Props>();\nconst showFull = ref(false);\n\nconst displayAction = computed(() => props.action ?? props.message);\nconst displayDetails = computed(() => {\n if (props.details) return props.details;\n if (props.oldValue != null && props.newValue != null) {\n return `${props.oldValue} → ${props.newValue}`;\n }\n return props.newValue ?? null;\n});\nconst hasChangeDetails = computed(\n () =>\n (props.oldValue != null && props.newValue != null) ||\n props.details != null ||\n props.newValue != null,\n);\nconst detailsPrefix = computed(() => {\n if (!props.details || (props.oldValue == null && props.newValue == null)) return null;\n if (props.details.includes(' · ')) {\n const parts = props.details.split(' · ');\n return parts.length > 1 ? parts[0]! : null;\n }\n return props.details;\n});\n\n/** Use relative time when within ~18 hours, otherwise full date and time */\nconst RECENT_THRESHOLD_HOURS = 18;\n\nconst shortTime = computed(() => {\n if (!props.timestamp) return '';\n const { relative, formatted, localTime } = formatTicketDate(props.timestamp);\n const dateTime = [formatted, localTime].filter(Boolean).join(', ');\n if (!relative && !dateTime) return '';\n const date = new Date(props.timestamp);\n const hoursAgo = (Date.now() - date.getTime()) / (1000 * 60 * 60);\n const isRecent = hoursAgo >= 0 && hoursAgo < RECENT_THRESHOLD_HOURS;\n return isRecent ? relative : dateTime;\n});\n\nconst fullDateTime = computed(() => {\n if (!props.timestamp) return '';\n const { formatted, localTime } = formatTicketDate(props.timestamp);\n return [formatted, localTime].filter(Boolean).join(', ');\n});\n\nconst displayTime = computed(() =>\n showFull.value ? fullDateTime.value : shortTime.value,\n);\n</script>\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { r as executeWithAuth } from "./useRpcAuth-CJtq1dqM.js";
|
|
2
2
|
import { r as getRefreshTokenHandler } from "./EnhancedRefreshTokenHandler-C6tZCcfX.js";
|
|
3
|
-
import { t as formatSystemTimestamp } from "./convertToLocalDateTime-
|
|
3
|
+
import { t as formatSystemTimestamp } from "./convertToLocalDateTime-BKBxm2Rc.js";
|
|
4
4
|
import { computed, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, normalizeClass, openBlock, resolveComponent, toDisplayString, unref, withCtx } from "vue";
|
|
5
5
|
import { UserReadSchema } from "@dragonmastery/dragoncore-shared";
|
|
6
6
|
import { useCursorDataTable, withMetadata } from "@dragonmastery/zinia-forms-core";
|
|
@@ -151,4 +151,4 @@ var UserListPage_default = _sfc_main;
|
|
|
151
151
|
|
|
152
152
|
//#endregion
|
|
153
153
|
export { userRowSchemaWithMetadata as n, UserTypeBadge_default as r, UserListPage_default as t };
|
|
154
|
-
//# sourceMappingURL=UserListPage-
|
|
154
|
+
//# sourceMappingURL=UserListPage-CDMSZpXK.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UserListPage-
|
|
1
|
+
{"version":3,"file":"UserListPage-CDMSZpXK.js","names":["mappedUsers: UserRow[]"],"sources":["../src/slices/admin/components/UserTypeBadge.vue","../src/slices/admin/features/user_management/userRowSchema.ts","../src/slices/admin/features/user_management/UserListPage.vue"],"sourcesContent":["<template>\n <span class=\"badge badge-sm\" :class=\"badgeClasses\">\n {{ typeLabel }}\n </span>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue';\n\ninterface Props {\n userType: 'consumer' | 'lead' | 'staff' | 'super_admin';\n size?: 'xs' | 'sm' | 'md' | 'lg';\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n size: 'sm',\n});\n\nconst typeConfig = {\n consumer: {\n label: 'Consumer',\n variant: 'neutral',\n },\n lead: {\n label: 'Lead',\n variant: 'info',\n },\n staff: {\n label: 'Staff',\n variant: 'warning',\n },\n super_admin: {\n label: 'Admin',\n variant: 'error',\n },\n};\n\nconst typeLabel = computed(() => {\n return typeConfig[props.userType]?.label || props.userType;\n});\n\nconst badgeClasses = computed(() => {\n const config = typeConfig[props.userType];\n const baseClasses = `badge-${props.size}`;\n\n if (!config) {\n return `${baseClasses} badge-neutral`;\n }\n\n return `${baseClasses} badge-${config.variant}`;\n});\n</script>\n","import { withMetadata } from '@dragonmastery/zinia-forms-core';\nimport { UserReadSchema } from '@dragonmastery/dragoncore-shared';\nimport type { z } from 'zod';\n\nexport const userRowSchemaWithMetadata = withMetadata(UserReadSchema, 'userRowSchema', {\n username: { label: 'Username' },\n email: { label: 'Email' },\n user_type: { label: 'Role' },\n email_verified: { label: 'Verified' },\n created_at: { label: 'Created' },\n});\n\nexport type UserRow = z.infer<typeof UserReadSchema>;\n","<template>\n <div class=\"mt-2\">\n <!-- Header with title and actions -->\n <div class=\"flex justify-between items-center mb-4\">\n <h1 class=\"text-2xl font-bold\">User Management</h1>\n </div>\n\n <!-- Zinia Data Table -->\n <ZiniaDataTable>\n <!-- Custom cell templates -->\n <template #cell-user_type=\"{ row }\">\n <UserTypeBadge :user-type=\"row.user_type\" />\n </template>\n\n <template #cell-email_verified=\"{ row }\">\n <span\n class=\"badge badge-sm\"\n :class=\"row.email_verified ? 'badge-success' : 'badge-error'\"\n >\n {{ row.email_verified ? 'Verified' : 'Not Verified' }}\n </span>\n </template>\n\n <template #cell-created_at=\"{ row }\">\n {{ formatSystemTimestamp(row.created_at) }}\n </template>\n\n <template #cell-actions=\"{ row }\">\n <router-link\n :to=\"{ name: 'EditUser', params: { id: row.id } }\"\n class=\"btn btn-sm btn-primary\"\n >\n Edit\n </router-link>\n </template>\n </ZiniaDataTable>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { executeWithAuth } from '../../../../composables/useRpcAuth';\nimport { getRefreshTokenHandler } from '../../../../utils/EnhancedRefreshTokenHandler';\nimport { formatSystemTimestamp } from '../../../../utils/convertToLocalDateTime';\nimport { useCursorDataTable } from '@dragonmastery/zinia-forms-core';\nimport UserTypeBadge from '../../components/UserTypeBadge.vue';\nimport { userRowSchemaWithMetadata, type UserRow } from './userRowSchema';\n\n// Set up data table\nconst { ZiniaDataTable } = useCursorDataTable(userRowSchemaWithMetadata, {\n fetchData: async () => {\n const users = await executeWithAuth(\n async (api) => {\n return await api.users.listUsers();\n },\n { refreshTokenHandler: getRefreshTokenHandler() },\n );\n\n // Map response to UserRow format\n const mappedUsers: UserRow[] = users.map((user) => ({\n id: user.id,\n username: user.username,\n email: user.email,\n email_verified: user.email_verified,\n user_type: user.user_type,\n created_at: user.created_at,\n updated_at: user.updated_at ?? null,\n }));\n\n return {\n data: mappedUsers,\n hasNextPage: false,\n hasPreviousPage: false,\n prevPageCursor: undefined,\n nextPageCursor: undefined,\n };\n },\n\n // Column configuration\n columns: {\n username: { label: 'Username', field: 'username', sortable: true },\n email: { label: 'Email', field: 'email', sortable: true },\n user_type: { label: 'Role', field: 'user_type', sortable: true },\n email_verified: {\n label: 'Verified',\n field: 'email_verified',\n sortable: true,\n },\n created_at: { label: 'Created', field: 'created_at', sortable: true },\n },\n\n // Action buttons\n actions: {\n items: [\n {\n key: 'edit',\n icon: 'edit',\n size: 'xs',\n variant: 'primary',\n type: 'link',\n href: (row: UserRow) => `/admin/users/${row.id}/edit`,\n },\n ],\n },\n\n pagination: {\n pageSize: 100,\n },\n});\n</script>\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UserProfilePage-FNLYK9kj.js","names":[],"sources":["../src/slices/user/features/user_profile/userProfileSchema.ts","../src/slices/user/features/user_profile/UserProfilePage.vue"],"sourcesContent":["import { withMetadata } from '@dragonmastery/zinia-forms-core';\nimport { UserProfileBaseSchema, UserProfileUpdateSchema } from '@dragonmastery/dragoncore-shared';\nimport { z } from 'zod';\n\n// Define the login form type\nexport type UserProfileForm = z.infer<typeof UserProfileBaseSchema>;\n\n// Enhance the schema with metadata\nexport const userProfileSchemaWithMetadata = withMetadata(\n UserProfileUpdateSchema,\n 'userProfileSchema',\n {\n first_name: {\n inputType: 'text',\n placeholder: 'Enter first name',\n helpText: 'Enter the first name',\n autocomplete: 'first-name',\n autofocus: true,\n },\n\n last_name: {\n inputType: 'text',\n placeholder: 'Enter last name',\n helpText: 'Enter the last name',\n autocomplete: 'last-name',\n },\n\n bio: {\n inputType: 'textarea',\n placeholder: 'Enter bio',\n helpText: 'Enter a short bio',\n },\n },\n);\n","<template>\n <div v-if=\"form.isLoading\" class=\"flex justify-center items-center p-8\">\n <span class=\"loading loading-spinner loading-lg\"></span>\n </div>\n <div v-else-if=\"form.loadError\" class=\"alert alert-error mb-4\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"stroke-current shrink-0 h-6 w-6\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z\"\n />\n </svg>\n <span>{{ form.loadError }}</span>\n </div>\n <div v-else class=\"max-w-md mx-auto bg-base-200 p-6 rounded-xl shadow-md container\">\n <h1 class=\"text-2xl font-bold mb-6 text-center\">Update User Profile</h1>\n\n <!-- Email & verification status -->\n <div v-if=\"session.userSession?.user.email\" class=\"mb-6 p-4 rounded-lg bg-base-300\">\n <div class=\"flex items-center justify-between gap-2\">\n <div>\n <p class=\"text-sm text-base-content/70\">Email</p>\n <p class=\"font-medium\">{{ session.userSession.user.email }}</p>\n <p\n v-if=\"emailVerificationMode !== 'disabled'\"\n class=\"text-sm mt-1\"\n :class=\"session.userSession.user.email_verified ? 'text-success' : 'text-warning'\"\n >\n {{ session.userSession.user.email_verified ? 'Verified' : 'Not verified' }}\n </p>\n </div>\n <button\n v-if=\"\n emailVerificationMode !== 'disabled' &&\n !session.userSession.user.email_verified\n \"\n type=\"button\"\n class=\"btn btn-outline btn-sm\"\n :disabled=\"resendLoading\"\n @click=\"resendVerification\"\n >\n {{ resendLoading ? 'Sending...' : 'Resend verification' }}\n </button>\n </div>\n </div>\n\n <ZiniaForm @handle-submit=\"handleSubmit\" @success=\"handleSuccess\" @error=\"handleError\">\n <zinia.FirstNameField />\n <zinia.LastNameField />\n <zinia.BioField />\n\n <ZiniaSubmitButton submitText=\"Update\" submittingText=\"Updating...\" />\n </ZiniaForm>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport type { DragoncoreApi } from '@dragonmastery/dragoncore-shared';\nimport type { EmailVerificationApi } from '@dragonmastery/dragoncore-shared';\nimport type { UserProfileUpdateDto } from '@dragonmastery/dragoncore-shared';\nimport { useForm } from '@dragonmastery/zinia-forms-core';\nimport { ref } from 'vue';\nimport { toast } from 'vue3-toastify';\nimport { useEnv } from '../../../../composables/useEnv';\nimport { useMutation } from '../../../../composables/useMutation';\nimport { useQuery } from '../../../../composables/useQuery';\nimport { useUserSessionStore } from '../../../../composables/useUserSessionStore';\nimport { userProfileSchemaWithMetadata } from './userProfileSchema';\n\n//user session\nconst session = useUserSessionStore();\nconst { emailVerificationMode } = useEnv();\nconst resendLoading = ref(false);\n\nconst { mutate: resendMutate } = useMutation(\n (api, _input?: unknown) => {\n const verifyEmail = (api as DragoncoreApi).verifyEmail;\n if (!verifyEmail) throw new Error('Email verification is not configured');\n return (verifyEmail as EmailVerificationApi).resendVerificationEmail();\n },\n { skipAuthCheck: false },\n);\n\nconst resendVerification = async () => {\n try {\n resendLoading.value = true;\n const result = await resendMutate(undefined);\n if (result?.ok) {\n toast.success('Verification email sent. Please check your inbox.');\n await session.refreshToken();\n } else {\n toast.error('Failed to resend verification email.');\n }\n } catch (error) {\n toast.error(error instanceof Error ? error.message : 'Failed to resend');\n } finally {\n resendLoading.value = false;\n }\n};\n\n// fetch user profile data\nconst { data: userProfileData, loading: userProfileFetching } = useQuery(\n (api) => api.userProfiles.getCurrentUserProfile(),\n {\n enabled: !!session.userSession?.user.userId,\n staleTime: 5 * 60 * 1000,\n },\n);\n\n// Create a type-safe form using our schema with metadata\nconst { form, zinia, ZiniaForm, ZiniaSubmitButton } = useForm(userProfileSchemaWithMetadata, {\n storeName: 'user-profile-form',\n persistToLocalStorage: false,\n renderStyle: 'daisy_ui',\n fetchData: async () => {\n while (userProfileFetching.value) {\n await new Promise((resolve) => setTimeout(resolve, 100));\n }\n\n if (!userProfileData.value) {\n return {\n user_id: session.userSession?.user.userId || '',\n bio: '',\n first_name: '',\n last_name: '',\n };\n }\n\n return {\n user_id: userProfileData.value.user_id,\n bio: userProfileData.value.bio || '',\n first_name: userProfileData.value.first_name || '',\n last_name: userProfileData.value.last_name || '',\n };\n },\n});\n\nconst { mutate: updateUserProfile } = useMutation(\n (api, input: UserProfileUpdateDto) => api.userProfiles.updateUserProfile(input),\n { invalidate: /^user:profile/ },\n);\n\n// Handle form submission\nconst handleSubmit = async (data: UserProfileUpdateDto) => {\n if (!session.userSession?.user.userId) {\n throw new Error('User session not found');\n }\n\n const result = await updateUserProfile({\n user_id: session.userSession?.user.userId,\n first_name: data.first_name,\n last_name: data.last_name,\n bio: data.bio,\n });\n if (!result) throw new Error('Update user profile failed');\n\n return result;\n};\n\n// Handle success\nconst handleSuccess = (_data: any) => {\n toast.success('User profile updated successfully!');\n};\n\n// Handle error\nconst handleError = (error: any) => {\n toast.error(error.message || 'Update user profile failed');\n};\n</script>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"UserProfilePage-BYitd7QV.js","names":[],"sources":["../src/slices/user/features/user_profile/userProfileSchema.ts","../src/slices/user/features/user_profile/UserProfilePage.vue"],"sourcesContent":["import { withMetadata } from '@dragonmastery/zinia-forms-core';\nimport { UserProfileBaseSchema, UserProfileUpdateSchema } from '@dragonmastery/dragoncore-shared';\nimport { z } from 'zod';\n\n// Define the login form type\nexport type UserProfileForm = z.infer<typeof UserProfileBaseSchema>;\n\n// Enhance the schema with metadata\nexport const userProfileSchemaWithMetadata = withMetadata(\n UserProfileUpdateSchema,\n 'userProfileSchema',\n {\n first_name: {\n inputType: 'text',\n placeholder: 'Enter first name',\n helpText: 'Enter the first name',\n autocomplete: 'first-name',\n autofocus: true,\n },\n\n last_name: {\n inputType: 'text',\n placeholder: 'Enter last name',\n helpText: 'Enter the last name',\n autocomplete: 'last-name',\n },\n\n bio: {\n inputType: 'textarea',\n placeholder: 'Enter bio',\n helpText: 'Enter a short bio',\n },\n },\n);\n","<template>\n <div v-if=\"form.isLoading\" class=\"flex justify-center items-center p-8\">\n <span class=\"loading loading-spinner loading-lg\"></span>\n </div>\n <div v-else-if=\"form.loadError\" class=\"alert alert-error mb-4\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"stroke-current shrink-0 h-6 w-6\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z\"\n />\n </svg>\n <span>{{ form.loadError }}</span>\n </div>\n <div v-else class=\"max-w-md mx-auto bg-base-200 p-6 rounded-xl shadow-md container\">\n <h1 class=\"text-2xl font-bold mb-6 text-center\">Update User Profile</h1>\n\n <!-- Email & verification status -->\n <div v-if=\"session.userSession?.user.email\" class=\"mb-6 p-4 rounded-lg bg-base-300\">\n <div class=\"flex items-center justify-between gap-2\">\n <div>\n <p class=\"text-sm text-base-content/70\">Email</p>\n <p class=\"font-medium\">{{ session.userSession.user.email }}</p>\n <p\n v-if=\"emailVerificationMode !== 'disabled'\"\n class=\"text-sm mt-1\"\n :class=\"session.userSession.user.email_verified ? 'text-success' : 'text-warning'\"\n >\n {{ session.userSession.user.email_verified ? 'Verified' : 'Not verified' }}\n </p>\n </div>\n <button\n v-if=\"\n emailVerificationMode !== 'disabled' &&\n !session.userSession.user.email_verified\n \"\n type=\"button\"\n class=\"btn btn-outline btn-sm\"\n :disabled=\"resendLoading\"\n @click=\"resendVerification\"\n >\n {{ resendLoading ? 'Sending...' : 'Resend verification' }}\n </button>\n </div>\n </div>\n\n <ZiniaForm @handle-submit=\"handleSubmit\" @success=\"handleSuccess\" @error=\"handleError\">\n <zinia.FirstNameField />\n <zinia.LastNameField />\n <zinia.BioField />\n\n <ZiniaSubmitButton submitText=\"Update\" submittingText=\"Updating...\" />\n </ZiniaForm>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport type { DragoncoreApi } from '@dragonmastery/dragoncore-shared';\nimport type { EmailVerificationApi } from '@dragonmastery/dragoncore-shared';\nimport type { UserProfileUpdateDto } from '@dragonmastery/dragoncore-shared';\nimport { useForm } from '@dragonmastery/zinia-forms-core';\nimport { ref } from 'vue';\nimport { toast } from 'vue3-toastify';\nimport { useEnv } from '../../../../composables/useEnv';\nimport { useMutation } from '../../../../composables/useMutation';\nimport { useQuery } from '../../../../composables/useQuery';\nimport { useUserSessionStore } from '../../../../composables/useUserSessionStore';\nimport { userProfileSchemaWithMetadata } from './userProfileSchema';\n\n//user session\nconst session = useUserSessionStore();\nconst { emailVerificationMode } = useEnv();\nconst resendLoading = ref(false);\n\nconst { mutate: resendMutate } = useMutation(\n (api, _input?: unknown) => {\n const verifyEmail = (api as DragoncoreApi).verifyEmail;\n if (!verifyEmail) throw new Error('Email verification is not configured');\n return (verifyEmail as EmailVerificationApi).resendVerificationEmail();\n },\n { skipAuthCheck: false },\n);\n\nconst resendVerification = async () => {\n try {\n resendLoading.value = true;\n const result = await resendMutate(undefined);\n if (result?.ok) {\n toast.success('Verification email sent. Please check your inbox.');\n await session.refreshToken();\n } else {\n toast.error('Failed to resend verification email.');\n }\n } catch (error) {\n toast.error(error instanceof Error ? error.message : 'Failed to resend');\n } finally {\n resendLoading.value = false;\n }\n};\n\n// fetch user profile data\nconst { data: userProfileData, loading: userProfileFetching } = useQuery(\n (api) => api.userProfiles.getCurrentUserProfile(),\n {\n enabled: !!session.userSession?.user.userId,\n staleTime: 5 * 60 * 1000,\n },\n);\n\n// Create a type-safe form using our schema with metadata\nconst { form, zinia, ZiniaForm, ZiniaSubmitButton } = useForm(userProfileSchemaWithMetadata, {\n storeName: 'user-profile-form',\n persistToLocalStorage: false,\n renderStyle: 'daisy_ui',\n fetchData: async () => {\n while (userProfileFetching.value) {\n await new Promise((resolve) => setTimeout(resolve, 100));\n }\n\n if (!userProfileData.value) {\n return {\n user_id: session.userSession?.user.userId || '',\n bio: '',\n first_name: '',\n last_name: '',\n };\n }\n\n return {\n user_id: userProfileData.value.user_id,\n bio: userProfileData.value.bio || '',\n first_name: userProfileData.value.first_name || '',\n last_name: userProfileData.value.last_name || '',\n };\n },\n});\n\nconst { mutate: updateUserProfile } = useMutation(\n (api, input: UserProfileUpdateDto) => api.userProfiles.updateUserProfile(input),\n { invalidate: /^user:profile/ },\n);\n\n// Handle form submission\nconst handleSubmit = async (data: UserProfileUpdateDto) => {\n if (!session.userSession?.user.userId) {\n throw new Error('User session not found');\n }\n\n const result = await updateUserProfile({\n user_id: session.userSession?.user.userId,\n first_name: data.first_name,\n last_name: data.last_name,\n bio: data.bio,\n });\n if (!result) throw new Error('Update user profile failed');\n\n return result;\n};\n\n// Handle success\nconst handleSuccess = (_data: any) => {\n toast.success('User profile updated successfully!');\n};\n\n// Handle error\nconst handleError = (error: any) => {\n toast.error(error.message || 'Update user profile failed');\n};\n</script>\n"],"mappings":"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"}
|
|
@@ -3,6 +3,6 @@ import "./EnhancedRefreshTokenHandler-C6tZCcfX.js";
|
|
|
3
3
|
import "./useQueryCache-alzaRWEb.js";
|
|
4
4
|
import "./useMutation-BLNuJoYl.js";
|
|
5
5
|
import "./useQuery-BzUGEOj0.js";
|
|
6
|
-
import { t as UserProfilePage_default } from "./UserProfilePage-
|
|
6
|
+
import { t as UserProfilePage_default } from "./UserProfilePage-BYitd7QV.js";
|
|
7
7
|
|
|
8
8
|
export { UserProfilePage_default as default };
|
|
@@ -4,7 +4,7 @@ import "./useQueryCache-alzaRWEb.js";
|
|
|
4
4
|
import "./useMutation-BLNuJoYl.js";
|
|
5
5
|
import "./useQuery-BzUGEOj0.js";
|
|
6
6
|
import "./AppLink-FcNGKgvG.js";
|
|
7
|
-
import "./useEmailVerificationChannel-
|
|
8
|
-
import { t as VerifyEmail_default } from "./VerifyEmail-
|
|
7
|
+
import "./useEmailVerificationChannel-QuMSgzzM.js";
|
|
8
|
+
import { t as VerifyEmail_default } from "./VerifyEmail-CWUhRA1o.js";
|
|
9
9
|
|
|
10
10
|
export { VerifyEmail_default as default };
|
|
@@ -3,7 +3,7 @@ import { t as useMutation } from "./useMutation-BLNuJoYl.js";
|
|
|
3
3
|
import { t as useQuery } from "./useQuery-BzUGEOj0.js";
|
|
4
4
|
import { t as AppLink_default } from "./AppLink-FcNGKgvG.js";
|
|
5
5
|
import { o as withReturnUrl, r as getValidReturnUrl, t as getAndClearEmailVerificationReturnUrl } from "./useReturnUrl-B5V3SJf5.js";
|
|
6
|
-
import { t as useEmailVerificationChannel } from "./useEmailVerificationChannel-
|
|
6
|
+
import { t as useEmailVerificationChannel } from "./useEmailVerificationChannel-QuMSgzzM.js";
|
|
7
7
|
import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createStaticVNode, createTextVNode, createVNode, defineComponent, onMounted, onUnmounted, openBlock, ref, toDisplayString, unref, withCtx } from "vue";
|
|
8
8
|
import { useRoute, useRouter } from "vue-router";
|
|
9
9
|
import { toast } from "vue3-toastify";
|
|
@@ -259,4 +259,4 @@ var VerifyEmail_default = _sfc_main;
|
|
|
259
259
|
|
|
260
260
|
//#endregion
|
|
261
261
|
export { VerifyEmail_default as t };
|
|
262
|
-
//# sourceMappingURL=VerifyEmail-
|
|
262
|
+
//# sourceMappingURL=VerifyEmail-CWUhRA1o.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VerifyEmail-BVwHQpbw.js","names":["resendCountdownInterval: ReturnType<typeof setInterval> | null"],"sources":["../src/slices/auth/features/verify_email/VerifyEmail.vue"],"sourcesContent":["<template>\n <div class=\"max-w-md mx-auto bg-base-200 p-6 rounded-xl shadow-md container\">\n <div class=\"text-center\">\n <!-- State A: No token (after signup, waiting for email) -->\n <div v-if=\"!token && status !== 'loading' && status !== 'success'\" class=\"space-y-4\">\n <h3 class=\"text-lg font-semibold\">Check your email</h3>\n <p class=\"text-sm text-base-content/70 text-left\">\n We've sent a verification email to your inbox. It may take a couple of minutes to\n arrive. Be sure to check your junk or spam folder if you don't see it.\n </p>\n <p class=\"text-sm text-base-content/70 text-left\">\n When you receive the email, click the link inside. You'll land on a page where you\n need to click the \"Verify email\" button to complete verification.\n </p>\n <p\n v-if=\"emailVerificationMode === 'strict'\"\n class=\"text-sm text-base-content/80 text-left font-medium\"\n >\n Application access is restricted until email verification is completed.\n </p>\n <div class=\"flex flex-col gap-2 items-center pt-2\">\n <AppLink\n v-if=\"emailVerificationMode !== 'strict'\"\n :to=\"appLink\"\n class=\"btn btn-outline btn-sm\"\n >\n Continue to app\n </AppLink>\n <button\n v-if=\"isLoggedIn && verifyEmailApi\"\n type=\"button\"\n class=\"btn btn-outline btn-sm\"\n :disabled=\"resendLoading || resendCountdown > 0\"\n @click=\"resendVerification\"\n >\n {{\n resendLoading\n ? 'Sending...'\n : resendCountdown > 0\n ? `Try again in ${resendCountdown}`\n : 'Resend verification email'\n }}\n </button>\n </div>\n </div>\n\n <!-- State B: Token present, waiting for user to click verify -->\n <div\n v-else-if=\"token && status !== 'loading' && status !== 'success' && status !== 'error'\"\n class=\"space-y-4\"\n >\n <h3 class=\"text-lg font-semibold\">Verify your email</h3>\n <p class=\"text-sm text-base-content/70\">\n Click the button below to complete verification. You'll be redirected once it's done.\n </p>\n <p\n v-if=\"emailVerificationMode === 'strict'\"\n class=\"text-sm text-base-content/80 font-medium\"\n >\n Application access is restricted until email verification is completed.\n </p>\n <button\n type=\"button\"\n class=\"btn btn-primary\"\n :disabled=\"verifyLoading\"\n @click=\"handleVerify\"\n >\n {{ verifyLoading ? 'Verifying...' : 'Verify email' }}\n </button>\n </div>\n\n <!-- Loading (after clicking verify) -->\n <div v-else-if=\"status === 'loading'\" class=\"space-y-4\">\n <span class=\"loading loading-spinner loading-lg text-primary\"></span>\n <p class=\"text-sm text-base-content/70\">Verifying your email...</p>\n </div>\n\n <!-- Success -->\n <div v-else-if=\"status === 'success'\" class=\"space-y-4\">\n <div\n class=\"w-14 h-14 rounded-full bg-success/20 flex items-center justify-center mx-auto\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"w-7 h-7 text-success\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n </div>\n <h3 class=\"text-lg font-semibold\">Email verified!</h3>\n <p v-if=\"redirectTarget\" class=\"text-sm text-base-content/70\">Redirecting you...</p>\n <p v-else class=\"text-sm text-base-content/70\">\n Your email has been verified. Switch back to your other tab to continue, or\n <AppLink :to=\"appLink\" class=\"link link-primary\">continue to the app</AppLink>.\n </p>\n <p v-if=\"redirectTarget\" class=\"text-sm text-base-content/60\">\n If you aren't redirected automatically,\n <AppLink :to=\"redirectTarget\" class=\"link link-primary\">click here</AppLink>.\n </p>\n </div>\n\n <!-- Error -->\n <div v-else class=\"space-y-4\">\n <div\n class=\"w-14 h-14 rounded-full bg-error/20 flex items-center justify-center mx-auto\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"w-7 h-7 text-error\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"15\" y1=\"9\" x2=\"9\" y2=\"15\" />\n <line x1=\"9\" y1=\"9\" x2=\"15\" y2=\"15\" />\n </svg>\n </div>\n <h3 class=\"text-lg font-semibold\">Verification failed</h3>\n <p class=\"text-sm text-base-content/70\">{{ errorMessage }}</p>\n <div class=\"flex flex-col gap-2 items-center\">\n <AppLink :to=\"loginLink\" class=\"btn btn-outline btn-sm\">Back to login</AppLink>\n <button\n v-if=\"verifyEmailApi\"\n type=\"button\"\n class=\"btn btn-outline btn-sm\"\n :disabled=\"resendLoading || resendCountdown > 0\"\n @click=\"resendVerification\"\n >\n {{\n resendLoading\n ? 'Sending...'\n : resendCountdown > 0\n ? `Try again in ${resendCountdown}`\n : 'Resend verification email'\n }}\n </button>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport type { DragoncoreApi, EmailVerificationApi } from '@dragonmastery/dragoncore-shared';\nimport { computed, onMounted, onUnmounted, ref } from 'vue';\nimport { useRoute, useRouter } from 'vue-router';\nimport { toast } from 'vue3-toastify';\nimport AppLink from '../../../../components/AppLink.vue';\nimport { useEnv } from '../../../../composables/useEnv';\nimport { useMutation } from '../../../../composables/useMutation';\nimport { useQuery } from '../../../../composables/useQuery';\nimport { useUserSessionStore } from '../../../../composables/useUserSessionStore';\nimport {\n getAndClearEmailVerificationReturnUrl,\n getValidReturnUrl,\n withReturnUrl,\n} from '../../../../utils/useReturnUrl';\nimport { useEmailVerificationChannel } from '../../useEmailVerificationChannel';\n\nconst AUTH_CHANNEL = 'auth';\n/** Frontend countdown (60s). Backend uses 59s so it's ready when button enables. */\nconst RESEND_COOLDOWN_SECONDS = 60;\n\nconst route = useRoute();\nconst router = useRouter();\nconst returnUrl = computed(() => route.query.returnUrl as string | undefined);\nconst loginLink = computed(() => withReturnUrl('/auth/login', returnUrl.value));\nconst appLink = computed(() => getValidReturnUrl(route, '/'));\nconst sessionStore = useUserSessionStore();\nconst { emailVerificationMode } = useEnv();\n\n// Support token from query (?token=xxx) or params (/verify-email/:token)\nconst token = (route.query.token ?? route.params.token) as string;\n\nconst status = ref<'idle' | 'loading' | 'success' | 'error'>('idle');\nconst errorMessage = ref('');\nconst verifyEmailApi = ref(false);\nconst resendLoading = ref(false);\nconst resendCountdown = ref(0);\nlet resendCountdownInterval: ReturnType<typeof setInterval> | null = null;\nconst verifyLoading = ref(false);\nconst redirectTarget = ref<string | null>(null);\n\nconst isLoggedIn = computed(() => !!sessionStore.userSession?.user.userId);\n\n// When on \"Check your email\" (no token), listen for verification in another tab\nconst isAwaitingVerification = computed(\n () => !token && status.value !== 'loading' && status.value !== 'success',\n);\nuseEmailVerificationChannel(\n isAwaitingVerification,\n (targetUrl) => router.push(targetUrl),\n () => getValidReturnUrl(route, '/'),\n);\n\nconst { mutate: verifyMutate } = useMutation(\n (api, tokenToVerify: string) => {\n const verifyEmail = (api as DragoncoreApi).verifyEmail;\n if (!verifyEmail) throw new Error('Email verification is not configured');\n return (verifyEmail as EmailVerificationApi).verifyEmail(tokenToVerify);\n },\n { skipAuthCheck: true, credentials: 'include' },\n);\n\nconst { mutate: resendMutate } = useMutation(\n (api, _input?: unknown) => {\n const verifyEmail = (api as DragoncoreApi).verifyEmail;\n if (!verifyEmail) throw new Error('Email verification is not configured');\n return (verifyEmail as EmailVerificationApi).resendVerificationEmail();\n },\n { skipAuthCheck: false },\n);\n\nasync function handleVerify() {\n if (!token) return;\n\n if (emailVerificationMode === 'disabled') {\n status.value = 'error';\n errorMessage.value = 'Email verification is not enabled for this application.';\n return;\n }\n\n try {\n status.value = 'loading';\n verifyLoading.value = true;\n errorMessage.value = '';\n const result = await verifyMutate(token);\n verifyEmailApi.value = true;\n if (result?.ok) {\n status.value = 'success';\n const hadSession = !!(\n result.session?.access_token && result.session?.user_details_token\n );\n if (hadSession) {\n sessionStore.setSession(result.session!.user_details_token);\n sessionStore.setAccessToken(result.session!.access_token);\n } else {\n try {\n await sessionStore.refreshToken();\n } catch {\n // User may need to log in again; that's ok\n }\n }\n const channel = new BroadcastChannel(AUTH_CHANNEL);\n channel.postMessage({ type: 'email_verified' });\n channel.close();\n const storedReturnUrl = getAndClearEmailVerificationReturnUrl();\n const target = storedReturnUrl ?? (hadSession ? '/' : null);\n if (target) {\n redirectTarget.value = target;\n setTimeout(() => router.push(target), 1000);\n }\n } else {\n status.value = 'error';\n errorMessage.value =\n 'The link may have expired. Please try again or resend the verification email.';\n }\n } catch (error) {\n status.value = 'error';\n errorMessage.value =\n error instanceof Error\n ? error.message\n : 'Something went wrong. The link may have expired.';\n verifyEmailApi.value = true;\n } finally {\n verifyLoading.value = false;\n }\n}\n\nfunction startResendCountdown(seconds: number) {\n if (resendCountdownInterval) {\n clearInterval(resendCountdownInterval);\n resendCountdownInterval = null;\n }\n resendCountdown.value = seconds;\n resendCountdownInterval = setInterval(() => {\n resendCountdown.value = Math.max(0, resendCountdown.value - 1);\n if (resendCountdown.value <= 0 && resendCountdownInterval) {\n clearInterval(resendCountdownInterval);\n resendCountdownInterval = null;\n }\n }, 1000);\n}\n\nconst resendVerification = async () => {\n try {\n resendLoading.value = true;\n const result = await resendMutate(undefined);\n if (result?.ok) {\n if (result.sent) {\n toast.success('Verification email sent. Please check your inbox.');\n startResendCountdown(RESEND_COOLDOWN_SECONDS);\n } else if (result.seconds_until_next_send != null) {\n toast.info(`Please wait ${result.seconds_until_next_send} seconds before resending.`);\n startResendCountdown(result.seconds_until_next_send);\n } else {\n toast.success('Verification email sent. Please check your inbox.');\n startResendCountdown(RESEND_COOLDOWN_SECONDS);\n }\n } else {\n toast.error('Failed to resend verification email.');\n }\n } catch (error) {\n toast.error(error instanceof Error ? error.message : 'Failed to resend');\n } finally {\n resendLoading.value = false;\n }\n};\n\n// When landing on \"Check your email\" (no token), we just sent the email at signup.\n// Start resend button disabled with countdown to match backend cooldown.\nonMounted(() => {\n if (!token && status.value !== 'loading' && status.value !== 'success') {\n startResendCountdown(RESEND_COOLDOWN_SECONDS);\n }\n});\n\nonUnmounted(() => {\n resendCountdownInterval && clearInterval(resendCountdownInterval);\n});\n\n// Detect if verifyEmail API is available (for resend button)\nuseQuery(\n (api) => {\n verifyEmailApi.value = !!(api as DragoncoreApi).verifyEmail;\n return Promise.resolve(true);\n },\n { enabled: isLoggedIn, staleTime: 60 * 60 * 1000 },\n);\n</script>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"VerifyEmail-CWUhRA1o.js","names":["resendCountdownInterval: ReturnType<typeof setInterval> | null"],"sources":["../src/slices/auth/features/verify_email/VerifyEmail.vue"],"sourcesContent":["<template>\n <div class=\"max-w-md mx-auto bg-base-200 p-6 rounded-xl shadow-md container\">\n <div class=\"text-center\">\n <!-- State A: No token (after signup, waiting for email) -->\n <div v-if=\"!token && status !== 'loading' && status !== 'success'\" class=\"space-y-4\">\n <h3 class=\"text-lg font-semibold\">Check your email</h3>\n <p class=\"text-sm text-base-content/70 text-left\">\n We've sent a verification email to your inbox. It may take a couple of minutes to\n arrive. Be sure to check your junk or spam folder if you don't see it.\n </p>\n <p class=\"text-sm text-base-content/70 text-left\">\n When you receive the email, click the link inside. You'll land on a page where you\n need to click the \"Verify email\" button to complete verification.\n </p>\n <p\n v-if=\"emailVerificationMode === 'strict'\"\n class=\"text-sm text-base-content/80 text-left font-medium\"\n >\n Application access is restricted until email verification is completed.\n </p>\n <div class=\"flex flex-col gap-2 items-center pt-2\">\n <AppLink\n v-if=\"emailVerificationMode !== 'strict'\"\n :to=\"appLink\"\n class=\"btn btn-outline btn-sm\"\n >\n Continue to app\n </AppLink>\n <button\n v-if=\"isLoggedIn && verifyEmailApi\"\n type=\"button\"\n class=\"btn btn-outline btn-sm\"\n :disabled=\"resendLoading || resendCountdown > 0\"\n @click=\"resendVerification\"\n >\n {{\n resendLoading\n ? 'Sending...'\n : resendCountdown > 0\n ? `Try again in ${resendCountdown}`\n : 'Resend verification email'\n }}\n </button>\n </div>\n </div>\n\n <!-- State B: Token present, waiting for user to click verify -->\n <div\n v-else-if=\"token && status !== 'loading' && status !== 'success' && status !== 'error'\"\n class=\"space-y-4\"\n >\n <h3 class=\"text-lg font-semibold\">Verify your email</h3>\n <p class=\"text-sm text-base-content/70\">\n Click the button below to complete verification. You'll be redirected once it's done.\n </p>\n <p\n v-if=\"emailVerificationMode === 'strict'\"\n class=\"text-sm text-base-content/80 font-medium\"\n >\n Application access is restricted until email verification is completed.\n </p>\n <button\n type=\"button\"\n class=\"btn btn-primary\"\n :disabled=\"verifyLoading\"\n @click=\"handleVerify\"\n >\n {{ verifyLoading ? 'Verifying...' : 'Verify email' }}\n </button>\n </div>\n\n <!-- Loading (after clicking verify) -->\n <div v-else-if=\"status === 'loading'\" class=\"space-y-4\">\n <span class=\"loading loading-spinner loading-lg text-primary\"></span>\n <p class=\"text-sm text-base-content/70\">Verifying your email...</p>\n </div>\n\n <!-- Success -->\n <div v-else-if=\"status === 'success'\" class=\"space-y-4\">\n <div\n class=\"w-14 h-14 rounded-full bg-success/20 flex items-center justify-center mx-auto\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"w-7 h-7 text-success\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n </div>\n <h3 class=\"text-lg font-semibold\">Email verified!</h3>\n <p v-if=\"redirectTarget\" class=\"text-sm text-base-content/70\">Redirecting you...</p>\n <p v-else class=\"text-sm text-base-content/70\">\n Your email has been verified. Switch back to your other tab to continue, or\n <AppLink :to=\"appLink\" class=\"link link-primary\">continue to the app</AppLink>.\n </p>\n <p v-if=\"redirectTarget\" class=\"text-sm text-base-content/60\">\n If you aren't redirected automatically,\n <AppLink :to=\"redirectTarget\" class=\"link link-primary\">click here</AppLink>.\n </p>\n </div>\n\n <!-- Error -->\n <div v-else class=\"space-y-4\">\n <div\n class=\"w-14 h-14 rounded-full bg-error/20 flex items-center justify-center mx-auto\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"w-7 h-7 text-error\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"15\" y1=\"9\" x2=\"9\" y2=\"15\" />\n <line x1=\"9\" y1=\"9\" x2=\"15\" y2=\"15\" />\n </svg>\n </div>\n <h3 class=\"text-lg font-semibold\">Verification failed</h3>\n <p class=\"text-sm text-base-content/70\">{{ errorMessage }}</p>\n <div class=\"flex flex-col gap-2 items-center\">\n <AppLink :to=\"loginLink\" class=\"btn btn-outline btn-sm\">Back to login</AppLink>\n <button\n v-if=\"verifyEmailApi\"\n type=\"button\"\n class=\"btn btn-outline btn-sm\"\n :disabled=\"resendLoading || resendCountdown > 0\"\n @click=\"resendVerification\"\n >\n {{\n resendLoading\n ? 'Sending...'\n : resendCountdown > 0\n ? `Try again in ${resendCountdown}`\n : 'Resend verification email'\n }}\n </button>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport type { DragoncoreApi, EmailVerificationApi } from '@dragonmastery/dragoncore-shared';\nimport { computed, onMounted, onUnmounted, ref } from 'vue';\nimport { useRoute, useRouter } from 'vue-router';\nimport { toast } from 'vue3-toastify';\nimport AppLink from '../../../../components/AppLink.vue';\nimport { useEnv } from '../../../../composables/useEnv';\nimport { useMutation } from '../../../../composables/useMutation';\nimport { useQuery } from '../../../../composables/useQuery';\nimport { useUserSessionStore } from '../../../../composables/useUserSessionStore';\nimport {\n getAndClearEmailVerificationReturnUrl,\n getValidReturnUrl,\n withReturnUrl,\n} from '../../../../utils/useReturnUrl';\nimport { useEmailVerificationChannel } from '../../useEmailVerificationChannel';\n\nconst AUTH_CHANNEL = 'auth';\n/** Frontend countdown (60s). Backend uses 59s so it's ready when button enables. */\nconst RESEND_COOLDOWN_SECONDS = 60;\n\nconst route = useRoute();\nconst router = useRouter();\nconst returnUrl = computed(() => route.query.returnUrl as string | undefined);\nconst loginLink = computed(() => withReturnUrl('/auth/login', returnUrl.value));\nconst appLink = computed(() => getValidReturnUrl(route, '/'));\nconst sessionStore = useUserSessionStore();\nconst { emailVerificationMode } = useEnv();\n\n// Support token from query (?token=xxx) or params (/verify-email/:token)\nconst token = (route.query.token ?? route.params.token) as string;\n\nconst status = ref<'idle' | 'loading' | 'success' | 'error'>('idle');\nconst errorMessage = ref('');\nconst verifyEmailApi = ref(false);\nconst resendLoading = ref(false);\nconst resendCountdown = ref(0);\nlet resendCountdownInterval: ReturnType<typeof setInterval> | null = null;\nconst verifyLoading = ref(false);\nconst redirectTarget = ref<string | null>(null);\n\nconst isLoggedIn = computed(() => !!sessionStore.userSession?.user.userId);\n\n// When on \"Check your email\" (no token), listen for verification in another tab\nconst isAwaitingVerification = computed(\n () => !token && status.value !== 'loading' && status.value !== 'success',\n);\nuseEmailVerificationChannel(\n isAwaitingVerification,\n (targetUrl) => router.push(targetUrl),\n () => getValidReturnUrl(route, '/'),\n);\n\nconst { mutate: verifyMutate } = useMutation(\n (api, tokenToVerify: string) => {\n const verifyEmail = (api as DragoncoreApi).verifyEmail;\n if (!verifyEmail) throw new Error('Email verification is not configured');\n return (verifyEmail as EmailVerificationApi).verifyEmail(tokenToVerify);\n },\n { skipAuthCheck: true, credentials: 'include' },\n);\n\nconst { mutate: resendMutate } = useMutation(\n (api, _input?: unknown) => {\n const verifyEmail = (api as DragoncoreApi).verifyEmail;\n if (!verifyEmail) throw new Error('Email verification is not configured');\n return (verifyEmail as EmailVerificationApi).resendVerificationEmail();\n },\n { skipAuthCheck: false },\n);\n\nasync function handleVerify() {\n if (!token) return;\n\n if (emailVerificationMode === 'disabled') {\n status.value = 'error';\n errorMessage.value = 'Email verification is not enabled for this application.';\n return;\n }\n\n try {\n status.value = 'loading';\n verifyLoading.value = true;\n errorMessage.value = '';\n const result = await verifyMutate(token);\n verifyEmailApi.value = true;\n if (result?.ok) {\n status.value = 'success';\n const hadSession = !!(\n result.session?.access_token && result.session?.user_details_token\n );\n if (hadSession) {\n sessionStore.setSession(result.session!.user_details_token);\n sessionStore.setAccessToken(result.session!.access_token);\n } else {\n try {\n await sessionStore.refreshToken();\n } catch {\n // User may need to log in again; that's ok\n }\n }\n const channel = new BroadcastChannel(AUTH_CHANNEL);\n channel.postMessage({ type: 'email_verified' });\n channel.close();\n const storedReturnUrl = getAndClearEmailVerificationReturnUrl();\n const target = storedReturnUrl ?? (hadSession ? '/' : null);\n if (target) {\n redirectTarget.value = target;\n setTimeout(() => router.push(target), 1000);\n }\n } else {\n status.value = 'error';\n errorMessage.value =\n 'The link may have expired. Please try again or resend the verification email.';\n }\n } catch (error) {\n status.value = 'error';\n errorMessage.value =\n error instanceof Error\n ? error.message\n : 'Something went wrong. The link may have expired.';\n verifyEmailApi.value = true;\n } finally {\n verifyLoading.value = false;\n }\n}\n\nfunction startResendCountdown(seconds: number) {\n if (resendCountdownInterval) {\n clearInterval(resendCountdownInterval);\n resendCountdownInterval = null;\n }\n resendCountdown.value = seconds;\n resendCountdownInterval = setInterval(() => {\n resendCountdown.value = Math.max(0, resendCountdown.value - 1);\n if (resendCountdown.value <= 0 && resendCountdownInterval) {\n clearInterval(resendCountdownInterval);\n resendCountdownInterval = null;\n }\n }, 1000);\n}\n\nconst resendVerification = async () => {\n try {\n resendLoading.value = true;\n const result = await resendMutate(undefined);\n if (result?.ok) {\n if (result.sent) {\n toast.success('Verification email sent. Please check your inbox.');\n startResendCountdown(RESEND_COOLDOWN_SECONDS);\n } else if (result.seconds_until_next_send != null) {\n toast.info(`Please wait ${result.seconds_until_next_send} seconds before resending.`);\n startResendCountdown(result.seconds_until_next_send);\n } else {\n toast.success('Verification email sent. Please check your inbox.');\n startResendCountdown(RESEND_COOLDOWN_SECONDS);\n }\n } else {\n toast.error('Failed to resend verification email.');\n }\n } catch (error) {\n toast.error(error instanceof Error ? error.message : 'Failed to resend');\n } finally {\n resendLoading.value = false;\n }\n};\n\n// When landing on \"Check your email\" (no token), we just sent the email at signup.\n// Start resend button disabled with countdown to match backend cooldown.\nonMounted(() => {\n if (!token && status.value !== 'loading' && status.value !== 'success') {\n startResendCountdown(RESEND_COOLDOWN_SECONDS);\n }\n});\n\nonUnmounted(() => {\n resendCountdownInterval && clearInterval(resendCountdownInterval);\n});\n\n// Detect if verifyEmail API is available (for resend button)\nuseQuery(\n (api) => {\n verifyEmailApi.value = !!(api as DragoncoreApi).verifyEmail;\n return Promise.resolve(true);\n },\n { enabled: isLoggedIn, staleTime: 60 * 60 * 1000 },\n);\n</script>\n"],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import "./useRpcAuth-CJtq1dqM.js";
|
|
2
|
+
import "./ZiniaContainer-BPIfQOc7.js";
|
|
3
|
+
import "./userAuthorized-3RiCDXxr.js";
|
|
4
|
+
import "./team_memberRoutes-BgjY9Kwq.js";
|
|
5
|
+
import "./teamRoutes-CFDsHPkd.js";
|
|
6
|
+
import { t as ViewTeam_default } from "./ViewTeam-ttqX2In8.js";
|
|
7
|
+
|
|
8
|
+
export { ViewTeam_default as default };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { t as ZiniaContainer_default } from "./ZiniaContainer-
|
|
2
|
-
import { t as formatSystemTimestamp } from "./convertToLocalDateTime-
|
|
3
|
-
import { t as teamPaths } from "./teamRoutes-
|
|
1
|
+
import { t as ZiniaContainer_default } from "./ZiniaContainer-BPIfQOc7.js";
|
|
2
|
+
import { t as formatSystemTimestamp } from "./convertToLocalDateTime-BKBxm2Rc.js";
|
|
3
|
+
import { t as teamPaths } from "./teamRoutes-CFDsHPkd.js";
|
|
4
4
|
import { computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, inject, openBlock, resolveComponent, toDisplayString, unref, withCtx } from "vue";
|
|
5
5
|
import { useRoute } from "vue-router";
|
|
6
6
|
import { toast } from "vue3-toastify";
|
|
@@ -316,4 +316,4 @@ var ViewTeam_default = _sfc_main;
|
|
|
316
316
|
|
|
317
317
|
//#endregion
|
|
318
318
|
export { ViewTeam_default as t };
|
|
319
|
-
//# sourceMappingURL=ViewTeam-
|
|
319
|
+
//# sourceMappingURL=ViewTeam-ttqX2In8.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ViewTeam-BV7SjH8R.js","names":[],"sources":["../src/slices/team/ViewTeam.vue"],"sourcesContent":["<template>\n <div v-if=\"isLoading\" class=\"flex justify-center items-center p-8\">\n <span class=\"loading loading-spinner loading-lg\"></span>\n </div>\n\n <div v-else-if=\"error\" class=\"alert alert-error mb-4\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"stroke-current shrink-0 h-6 w-6\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z\"\n />\n </svg>\n <span>{{ error.message }}</span>\n </div>\n\n <ZiniaContainer v-else-if=\"teamData\">\n <!-- Header with Title -->\n <div class=\"mb-4\">\n <h1 class=\"text-xl sm:text-2xl font-bold text-base-content break-words leading-tight\">\n {{ teamData.display_name }}\n </h1>\n <div class=\"flex flex-wrap items-center gap-2 mt-2\">\n <span class=\"badge badge-sm badge-primary\">{{ teamData.unique_name }}</span>\n <span v-if=\"teamData.archived_at\" class=\"badge badge-sm badge-error\">Archived</span>\n <span v-else class=\"badge badge-sm badge-success\">Active</span>\n </div>\n </div>\n\n <!-- Description -->\n <div v-if=\"teamData.description\" class=\"prose prose-sm sm:prose-base max-w-none mb-4\">\n <p class=\"text-base-content/80 whitespace-pre-wrap text-sm sm:text-base leading-relaxed\">\n {{ teamData.description }}\n </p>\n </div>\n\n <!-- Team Information Grid -->\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4 mt-6\">\n <!-- Basic Information -->\n <div v-if=\"teamData.legal_name\" class=\"card bg-base-100 shadow-sm\">\n <div class=\"card-body\">\n <h3 class=\"card-title text-base mb-3\">Basic Information</h3>\n <div v-if=\"teamData.legal_name\" class=\"text-sm\">\n <span class=\"font-medium text-base-content/70\">Legal Name:</span>\n <span class=\"ml-2\">{{ teamData.legal_name }}</span>\n </div>\n </div>\n </div>\n\n <!-- Contact Information -->\n <div\n v-if=\"\n teamData.contact_name ||\n teamData.contact_email ||\n teamData.contact_business_phone ||\n teamData.contact_mobile_phone\n \"\n class=\"card bg-base-100 shadow-sm\"\n >\n <div class=\"card-body\">\n <h3 class=\"card-title text-base mb-3\">Contact Information</h3>\n <div v-if=\"teamData.contact_name\" class=\"text-sm\">\n <span class=\"font-medium text-base-content/70\">Name:</span>\n <span class=\"ml-2\">{{ teamData.contact_name }}</span>\n </div>\n <div v-if=\"teamData.contact_email\" class=\"text-sm mt-2\">\n <span class=\"font-medium text-base-content/70\">Email:</span>\n <a :href=\"`mailto:${teamData.contact_email}`\" class=\"ml-2 link link-primary\">\n {{ teamData.contact_email }}\n </a>\n </div>\n <div v-if=\"teamData.contact_business_phone\" class=\"text-sm mt-2\">\n <span class=\"font-medium text-base-content/70\">Business Phone:</span>\n <span class=\"ml-2\">{{ teamData.contact_business_phone }}</span>\n </div>\n <div v-if=\"teamData.contact_mobile_phone\" class=\"text-sm mt-2\">\n <span class=\"font-medium text-base-content/70\">Mobile Phone:</span>\n <span class=\"ml-2\">{{ teamData.contact_mobile_phone }}</span>\n </div>\n <div v-if=\"teamData.contact_time_zone\" class=\"text-sm mt-2\">\n <span class=\"font-medium text-base-content/70\">Time Zone:</span>\n <span class=\"ml-2\">{{ teamData.contact_time_zone }}</span>\n </div>\n </div>\n </div>\n\n <!-- Address Information -->\n <div\n v-if=\"teamData.address_full || teamData.address_city || teamData.address_zip\"\n class=\"card bg-base-100 shadow-sm\"\n >\n <div class=\"card-body\">\n <h3 class=\"card-title text-base mb-3\">Address</h3>\n <div v-if=\"teamData.address_full\" class=\"text-sm\">\n <span class=\"font-medium text-base-content/70\">Address:</span>\n <span class=\"ml-2\">{{ teamData.address_full }}</span>\n </div>\n <div v-if=\"teamData.address_city\" class=\"text-sm mt-2\">\n <span class=\"font-medium text-base-content/70\">City:</span>\n <span class=\"ml-2\">{{ teamData.address_city }}</span>\n </div>\n <div v-if=\"teamData.address_zip\" class=\"text-sm mt-2\">\n <span class=\"font-medium text-base-content/70\">Zip:</span>\n <span class=\"ml-2\">{{ teamData.address_zip }}</span>\n </div>\n </div>\n </div>\n\n <!-- Web Presence -->\n <div v-if=\"teamData.twitter_username || teamData.url\" class=\"card bg-base-100 shadow-sm\">\n <div class=\"card-body\">\n <h3 class=\"card-title text-base mb-3\">Web Presence</h3>\n <div v-if=\"teamData.twitter_username\" class=\"text-sm\">\n <span class=\"font-medium text-base-content/70\">Twitter:</span>\n <span class=\"ml-2\">@{{ teamData.twitter_username }}</span>\n </div>\n <div v-if=\"teamData.url\" class=\"text-sm mt-2\">\n <span class=\"font-medium text-base-content/70\">URL:</span>\n <a\n :href=\"teamData.url\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"ml-2 link link-primary\"\n >\n {{ teamData.url }}\n </a>\n </div>\n </div>\n </div>\n\n <!-- Referral Tag -->\n <div v-if=\"teamData.referral_tag\" class=\"card bg-base-100 shadow-sm\">\n <div class=\"card-body\">\n <h3 class=\"card-title text-base mb-3\">Referral Tag</h3>\n <p class=\"text-sm text-base-content/70 mb-3\">\n Share a link so referral events are routed to this team. The <code class=\"text-xs\">ref</code> parameter tags visitors for attribution.\n </p>\n\n <div v-if=\"referralAppLink\" class=\"mb-3\">\n <div class=\"text-xs font-medium text-base-content/60 mb-1\">App link (direct)</div>\n <div class=\"flex items-center gap-2\">\n <code class=\"flex-1 px-3 py-2 bg-base-200 rounded-lg text-sm font-mono break-all\">\n {{ referralAppLink }}\n </code>\n <button\n type=\"button\"\n class=\"btn btn-sm btn-ghost shrink-0\"\n title=\"Copy app link\"\n @click=\"copyToClipboard(referralAppLink, 'App link copied')\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\" />\n </svg>\n </button>\n </div>\n </div>\n\n <div v-if=\"referralMarketingLink\">\n <div class=\"text-xs font-medium text-base-content/60 mb-1\">Marketing link</div>\n <div class=\"flex items-center gap-2\">\n <code class=\"flex-1 px-3 py-2 bg-base-200 rounded-lg text-sm font-mono break-all\">\n {{ referralMarketingLink }}\n </code>\n <button\n type=\"button\"\n class=\"btn btn-sm btn-ghost shrink-0\"\n title=\"Copy marketing link\"\n @click=\"copyToClipboard(referralMarketingLink, 'Marketing link copied')\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\" />\n </svg>\n </button>\n </div>\n </div>\n\n <div v-if=\"!referralAppLink && !referralMarketingLink\" class=\"flex items-center gap-2\">\n <code class=\"flex-1 px-3 py-2 bg-base-200 rounded-lg text-sm font-mono\">\n {{ teamData.referral_tag }}\n </code>\n <button\n type=\"button\"\n class=\"btn btn-sm btn-ghost shrink-0\"\n title=\"Copy tag\"\n @click=\"copyToClipboard(teamData.referral_tag!, 'Referral tag copied')\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\" />\n </svg>\n </button>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Metadata -->\n <div class=\"mt-4 pt-4 border-t border-base-300 text-xs sm:text-sm text-base-content/50\">\n <div class=\"flex flex-col sm:flex-row sm:items-center gap-1 sm:gap-4\">\n <span v-if=\"teamData.created_by\"\n >Created by {{ teamData.created_by_display_name ?? teamData.created_by }}</span\n >\n <span v-if=\"teamData.created_at\">\n Created {{ formatSystemTimestamp(teamData.created_at) }}\n </span>\n <span\n v-if=\"teamData.updated_at && teamData.updated_at !== teamData.created_at\"\n class=\"text-xs\"\n >\n Updated {{ formatSystemTimestamp(teamData.updated_at) }}\n </span>\n </div>\n </div>\n\n <!-- Action Buttons -->\n <div class=\"flex flex-col sm:flex-row gap-3 justify-center mt-6\">\n <router-link\n :to=\"{\n name: teamPaths.edit.name,\n params: { id: team_id },\n }\"\n class=\"btn btn-primary\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke-width=\"1.5\"\n stroke=\"currentColor\"\n class=\"w-4 h-4 mr-2\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n d=\"M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L10.582 16.07a4.5 4.5 0 01-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 011.13-1.897l8.932-8.931zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0115.75 21H5.25A2.25 2.25 0 013 18.75V8.25A2.25 2.25 0 015.25 6H10\"\n />\n </svg>\n Edit Team\n </router-link>\n </div>\n </ZiniaContainer>\n</template>\n\n<script setup lang=\"ts\">\nimport type { TeamReadDto } from '@dragonmastery/dragoncore-shared';\nimport { computed, inject } from 'vue';\nimport { useRoute } from 'vue-router';\nimport { toast } from 'vue3-toastify';\nimport ZiniaContainer from '../../components/ui/ZiniaContainer.vue';\nimport { formatSystemTimestamp } from '../../utils/convertToLocalDateTime';\nimport { teamPaths } from './teamRoutes';\n\ninterface Props {\n team: TeamReadDto | null;\n isLoading?: boolean;\n error?: Error | null;\n}\n\nconst props = defineProps<Props>();\n\nconst route = useRoute();\nconst team_id = route.params.id as string;\n\nconst referralAppBaseUrl = inject<string>('referralAppBaseUrl') ?? '';\nconst referralMarketingBaseUrl = inject<string>('referralMarketingBaseUrl') ?? '';\n\nconst teamData = computed(() => props.team);\n\nfunction buildRefLink(base: string): string {\n const tag = teamData.value?.referral_tag;\n if (!tag) return '';\n const b = base.trim().replace(/\\/$/, '');\n if (!b) return '';\n const sep = b.includes('?') ? '&' : '?';\n return `${b}${sep}ref=${encodeURIComponent(tag)}`;\n}\n\nconst referralAppLink = computed(() => buildRefLink(referralAppBaseUrl));\nconst referralMarketingLink = computed(() => buildRefLink(referralMarketingBaseUrl));\n\nasync function copyToClipboard(text: string, successMessage: string) {\n try {\n await navigator.clipboard.writeText(text);\n toast.success(successMessage);\n } catch {\n toast.error('Failed to copy');\n }\n}\n</script>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ViewTeam-ttqX2In8.js","names":[],"sources":["../src/slices/team/ViewTeam.vue"],"sourcesContent":["<template>\n <div v-if=\"isLoading\" class=\"flex justify-center items-center p-8\">\n <span class=\"loading loading-spinner loading-lg\"></span>\n </div>\n\n <div v-else-if=\"error\" class=\"alert alert-error mb-4\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"stroke-current shrink-0 h-6 w-6\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z\"\n />\n </svg>\n <span>{{ error.message }}</span>\n </div>\n\n <ZiniaContainer v-else-if=\"teamData\">\n <!-- Header with Title -->\n <div class=\"mb-4\">\n <h1 class=\"text-xl sm:text-2xl font-bold text-base-content break-words leading-tight\">\n {{ teamData.display_name }}\n </h1>\n <div class=\"flex flex-wrap items-center gap-2 mt-2\">\n <span class=\"badge badge-sm badge-primary\">{{ teamData.unique_name }}</span>\n <span v-if=\"teamData.archived_at\" class=\"badge badge-sm badge-error\">Archived</span>\n <span v-else class=\"badge badge-sm badge-success\">Active</span>\n </div>\n </div>\n\n <!-- Description -->\n <div v-if=\"teamData.description\" class=\"prose prose-sm sm:prose-base max-w-none mb-4\">\n <p class=\"text-base-content/80 whitespace-pre-wrap text-sm sm:text-base leading-relaxed\">\n {{ teamData.description }}\n </p>\n </div>\n\n <!-- Team Information Grid -->\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4 mt-6\">\n <!-- Basic Information -->\n <div v-if=\"teamData.legal_name\" class=\"card bg-base-100 shadow-sm\">\n <div class=\"card-body\">\n <h3 class=\"card-title text-base mb-3\">Basic Information</h3>\n <div v-if=\"teamData.legal_name\" class=\"text-sm\">\n <span class=\"font-medium text-base-content/70\">Legal Name:</span>\n <span class=\"ml-2\">{{ teamData.legal_name }}</span>\n </div>\n </div>\n </div>\n\n <!-- Contact Information -->\n <div\n v-if=\"\n teamData.contact_name ||\n teamData.contact_email ||\n teamData.contact_business_phone ||\n teamData.contact_mobile_phone\n \"\n class=\"card bg-base-100 shadow-sm\"\n >\n <div class=\"card-body\">\n <h3 class=\"card-title text-base mb-3\">Contact Information</h3>\n <div v-if=\"teamData.contact_name\" class=\"text-sm\">\n <span class=\"font-medium text-base-content/70\">Name:</span>\n <span class=\"ml-2\">{{ teamData.contact_name }}</span>\n </div>\n <div v-if=\"teamData.contact_email\" class=\"text-sm mt-2\">\n <span class=\"font-medium text-base-content/70\">Email:</span>\n <a :href=\"`mailto:${teamData.contact_email}`\" class=\"ml-2 link link-primary\">\n {{ teamData.contact_email }}\n </a>\n </div>\n <div v-if=\"teamData.contact_business_phone\" class=\"text-sm mt-2\">\n <span class=\"font-medium text-base-content/70\">Business Phone:</span>\n <span class=\"ml-2\">{{ teamData.contact_business_phone }}</span>\n </div>\n <div v-if=\"teamData.contact_mobile_phone\" class=\"text-sm mt-2\">\n <span class=\"font-medium text-base-content/70\">Mobile Phone:</span>\n <span class=\"ml-2\">{{ teamData.contact_mobile_phone }}</span>\n </div>\n <div v-if=\"teamData.contact_time_zone\" class=\"text-sm mt-2\">\n <span class=\"font-medium text-base-content/70\">Time Zone:</span>\n <span class=\"ml-2\">{{ teamData.contact_time_zone }}</span>\n </div>\n </div>\n </div>\n\n <!-- Address Information -->\n <div\n v-if=\"teamData.address_full || teamData.address_city || teamData.address_zip\"\n class=\"card bg-base-100 shadow-sm\"\n >\n <div class=\"card-body\">\n <h3 class=\"card-title text-base mb-3\">Address</h3>\n <div v-if=\"teamData.address_full\" class=\"text-sm\">\n <span class=\"font-medium text-base-content/70\">Address:</span>\n <span class=\"ml-2\">{{ teamData.address_full }}</span>\n </div>\n <div v-if=\"teamData.address_city\" class=\"text-sm mt-2\">\n <span class=\"font-medium text-base-content/70\">City:</span>\n <span class=\"ml-2\">{{ teamData.address_city }}</span>\n </div>\n <div v-if=\"teamData.address_zip\" class=\"text-sm mt-2\">\n <span class=\"font-medium text-base-content/70\">Zip:</span>\n <span class=\"ml-2\">{{ teamData.address_zip }}</span>\n </div>\n </div>\n </div>\n\n <!-- Web Presence -->\n <div v-if=\"teamData.twitter_username || teamData.url\" class=\"card bg-base-100 shadow-sm\">\n <div class=\"card-body\">\n <h3 class=\"card-title text-base mb-3\">Web Presence</h3>\n <div v-if=\"teamData.twitter_username\" class=\"text-sm\">\n <span class=\"font-medium text-base-content/70\">Twitter:</span>\n <span class=\"ml-2\">@{{ teamData.twitter_username }}</span>\n </div>\n <div v-if=\"teamData.url\" class=\"text-sm mt-2\">\n <span class=\"font-medium text-base-content/70\">URL:</span>\n <a\n :href=\"teamData.url\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"ml-2 link link-primary\"\n >\n {{ teamData.url }}\n </a>\n </div>\n </div>\n </div>\n\n <!-- Referral Tag -->\n <div v-if=\"teamData.referral_tag\" class=\"card bg-base-100 shadow-sm\">\n <div class=\"card-body\">\n <h3 class=\"card-title text-base mb-3\">Referral Tag</h3>\n <p class=\"text-sm text-base-content/70 mb-3\">\n Share a link so referral events are routed to this team. The <code class=\"text-xs\">ref</code> parameter tags visitors for attribution.\n </p>\n\n <div v-if=\"referralAppLink\" class=\"mb-3\">\n <div class=\"text-xs font-medium text-base-content/60 mb-1\">App link (direct)</div>\n <div class=\"flex items-center gap-2\">\n <code class=\"flex-1 px-3 py-2 bg-base-200 rounded-lg text-sm font-mono break-all\">\n {{ referralAppLink }}\n </code>\n <button\n type=\"button\"\n class=\"btn btn-sm btn-ghost shrink-0\"\n title=\"Copy app link\"\n @click=\"copyToClipboard(referralAppLink, 'App link copied')\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\" />\n </svg>\n </button>\n </div>\n </div>\n\n <div v-if=\"referralMarketingLink\">\n <div class=\"text-xs font-medium text-base-content/60 mb-1\">Marketing link</div>\n <div class=\"flex items-center gap-2\">\n <code class=\"flex-1 px-3 py-2 bg-base-200 rounded-lg text-sm font-mono break-all\">\n {{ referralMarketingLink }}\n </code>\n <button\n type=\"button\"\n class=\"btn btn-sm btn-ghost shrink-0\"\n title=\"Copy marketing link\"\n @click=\"copyToClipboard(referralMarketingLink, 'Marketing link copied')\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\" />\n </svg>\n </button>\n </div>\n </div>\n\n <div v-if=\"!referralAppLink && !referralMarketingLink\" class=\"flex items-center gap-2\">\n <code class=\"flex-1 px-3 py-2 bg-base-200 rounded-lg text-sm font-mono\">\n {{ teamData.referral_tag }}\n </code>\n <button\n type=\"button\"\n class=\"btn btn-sm btn-ghost shrink-0\"\n title=\"Copy tag\"\n @click=\"copyToClipboard(teamData.referral_tag!, 'Referral tag copied')\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\" />\n </svg>\n </button>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Metadata -->\n <div class=\"mt-4 pt-4 border-t border-base-300 text-xs sm:text-sm text-base-content/50\">\n <div class=\"flex flex-col sm:flex-row sm:items-center gap-1 sm:gap-4\">\n <span v-if=\"teamData.created_by\"\n >Created by {{ teamData.created_by_display_name ?? teamData.created_by }}</span\n >\n <span v-if=\"teamData.created_at\">\n Created {{ formatSystemTimestamp(teamData.created_at) }}\n </span>\n <span\n v-if=\"teamData.updated_at && teamData.updated_at !== teamData.created_at\"\n class=\"text-xs\"\n >\n Updated {{ formatSystemTimestamp(teamData.updated_at) }}\n </span>\n </div>\n </div>\n\n <!-- Action Buttons -->\n <div class=\"flex flex-col sm:flex-row gap-3 justify-center mt-6\">\n <router-link\n :to=\"{\n name: teamPaths.edit.name,\n params: { id: team_id },\n }\"\n class=\"btn btn-primary\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke-width=\"1.5\"\n stroke=\"currentColor\"\n class=\"w-4 h-4 mr-2\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n d=\"M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L10.582 16.07a4.5 4.5 0 01-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 011.13-1.897l8.932-8.931zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0115.75 21H5.25A2.25 2.25 0 013 18.75V8.25A2.25 2.25 0 015.25 6H10\"\n />\n </svg>\n Edit Team\n </router-link>\n </div>\n </ZiniaContainer>\n</template>\n\n<script setup lang=\"ts\">\nimport type { TeamReadDto } from '@dragonmastery/dragoncore-shared';\nimport { computed, inject } from 'vue';\nimport { useRoute } from 'vue-router';\nimport { toast } from 'vue3-toastify';\nimport ZiniaContainer from '../../components/ui/ZiniaContainer.vue';\nimport { formatSystemTimestamp } from '../../utils/convertToLocalDateTime';\nimport { teamPaths } from './teamRoutes';\n\ninterface Props {\n team: TeamReadDto | null;\n isLoading?: boolean;\n error?: Error | null;\n}\n\nconst props = defineProps<Props>();\n\nconst route = useRoute();\nconst team_id = route.params.id as string;\n\nconst referralAppBaseUrl = inject<string>('referralAppBaseUrl') ?? '';\nconst referralMarketingBaseUrl = inject<string>('referralMarketingBaseUrl') ?? '';\n\nconst teamData = computed(() => props.team);\n\nfunction buildRefLink(base: string): string {\n const tag = teamData.value?.referral_tag;\n if (!tag) return '';\n const b = base.trim().replace(/\\/$/, '');\n if (!b) return '';\n const sep = b.includes('?') ? '&' : '?';\n return `${b}${sep}ref=${encodeURIComponent(tag)}`;\n}\n\nconst referralAppLink = computed(() => buildRefLink(referralAppBaseUrl));\nconst referralMarketingLink = computed(() => buildRefLink(referralMarketingBaseUrl));\n\nasync function copyToClipboard(text: string, successMessage: string) {\n try {\n await navigator.clipboard.writeText(text);\n toast.success(successMessage);\n } catch {\n toast.error('Failed to copy');\n }\n}\n</script>\n"],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import "./useRpcAuth-CJtq1dqM.js";
|
|
2
|
+
import "./ZiniaContainer-BPIfQOc7.js";
|
|
3
|
+
import "./userAuthorized-3RiCDXxr.js";
|
|
4
|
+
import "./team_memberRoutes-BgjY9Kwq.js";
|
|
5
|
+
import { t as ViewTeamMember_default } from "./ViewTeamMember-DqWZ3F_h.js";
|
|
6
|
+
|
|
7
|
+
export { ViewTeamMember_default as default };
|