@atlashub/smartstack 3.30.0 → 3.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunks/{AgentSkillsPage-CVq3qZoe.js → AgentSkillsPage-CDMhqrhE.js} +2 -2
- package/dist/chunks/{AgentSkillsPage-CVq3qZoe.js.map → AgentSkillsPage-CDMhqrhE.js.map} +1 -1
- package/dist/chunks/{AgentSkillsPage-DJb49NMA.js → AgentSkillsPage-DcvOMm5k.js} +2 -2
- package/dist/chunks/{AgentSkillsPage-DJb49NMA.js.map → AgentSkillsPage-DcvOMm5k.js.map} +1 -1
- package/dist/chunks/{AgentWorkloadPage-D_nk3gKj.js → AgentWorkloadPage-DYBPNzjQ.js} +2 -2
- package/dist/chunks/{AgentWorkloadPage-D_nk3gKj.js.map → AgentWorkloadPage-DYBPNzjQ.js.map} +1 -1
- package/dist/chunks/{AgentWorkloadPage-oHEi-sFh.js → AgentWorkloadPage-YpJSDaWc.js} +2 -2
- package/dist/chunks/{AgentWorkloadPage-oHEi-sFh.js.map → AgentWorkloadPage-YpJSDaWc.js.map} +1 -1
- package/dist/chunks/{ApiCatalogDetailPage-Cr0q2HnB.js → ApiCatalogDetailPage-9r1axtCg.js} +3 -3
- package/dist/chunks/{ApiCatalogDetailPage-Cr0q2HnB.js.map → ApiCatalogDetailPage-9r1axtCg.js.map} +1 -1
- package/dist/chunks/{ApiCatalogDetailPage-DX8buBkV.js → ApiCatalogDetailPage-TjCQ8_A8.js} +2 -2
- package/dist/chunks/{ApiCatalogDetailPage-DX8buBkV.js.map → ApiCatalogDetailPage-TjCQ8_A8.js.map} +1 -1
- package/dist/chunks/{ApiCatalogPage-DqboIzZE.js → ApiCatalogPage-COxazTnz.js} +2 -2
- package/dist/chunks/{ApiCatalogPage-DqboIzZE.js.map → ApiCatalogPage-COxazTnz.js.map} +1 -1
- package/dist/chunks/{ApiCatalogPage-DN7sazvI.js → ApiCatalogPage-QRysH0pT.js} +2 -2
- package/dist/chunks/{ApiCatalogPage-DN7sazvI.js.map → ApiCatalogPage-QRysH0pT.js.map} +1 -1
- package/dist/chunks/{ApplicationDetailPage-CCNjr64K.js → ApplicationDetailPage-Dbx01Ikm.js} +4 -4
- package/dist/chunks/{ApplicationDetailPage-CCNjr64K.js.map → ApplicationDetailPage-Dbx01Ikm.js.map} +1 -1
- package/dist/chunks/{ApplicationDetailPage--9YwwS5A.js → ApplicationDetailPage-jSHy3MPz.js} +2 -2
- package/dist/chunks/{ApplicationDetailPage--9YwwS5A.js.map → ApplicationDetailPage-jSHy3MPz.js.map} +1 -1
- package/dist/chunks/{ApplicationsDashboardPage-Bs-Xgca4.js → ApplicationsDashboardPage-CclKc0wI.js} +3 -3
- package/dist/chunks/{ApplicationsDashboardPage-Bs-Xgca4.js.map → ApplicationsDashboardPage-CclKc0wI.js.map} +1 -1
- package/dist/chunks/{ApplicationsDashboardPage-BSsHN3Yj.js → ApplicationsDashboardPage-CxWmOc1x.js} +2 -2
- package/dist/chunks/{ApplicationsDashboardPage-BSsHN3Yj.js.map → ApplicationsDashboardPage-CxWmOc1x.js.map} +1 -1
- package/dist/chunks/{ApplicationsGridPage-s1WEzOXS.js → ApplicationsGridPage-BJXWXwyI.js} +2 -2
- package/dist/chunks/{ApplicationsGridPage-s1WEzOXS.js.map → ApplicationsGridPage-BJXWXwyI.js.map} +1 -1
- package/dist/chunks/{ApplicationsGridPage-DDysNWJ5.js → ApplicationsGridPage-D2l8cM3o.js} +2 -2
- package/dist/chunks/{ApplicationsGridPage-DDysNWJ5.js.map → ApplicationsGridPage-D2l8cM3o.js.map} +1 -1
- package/dist/chunks/{ApplicationsListPage-B3CSMiV0.js → ApplicationsListPage-CMosl3my.js} +2 -2
- package/dist/chunks/{ApplicationsListPage-B3CSMiV0.js.map → ApplicationsListPage-CMosl3my.js.map} +1 -1
- package/dist/chunks/{ApplicationsListPage-B6ZCecIl.js → ApplicationsListPage-Dc6NGQ61.js} +2 -2
- package/dist/chunks/{ApplicationsListPage-B6ZCecIl.js.map → ApplicationsListPage-Dc6NGQ61.js.map} +1 -1
- package/dist/chunks/{ApplicationsPage-BBaiBM--.js → ApplicationsPage-DH7tpMlF.js} +2 -2
- package/dist/chunks/{ApplicationsPage-BBaiBM--.js.map → ApplicationsPage-DH7tpMlF.js.map} +1 -1
- package/dist/chunks/{ApplicationsPage-ztPwoAGt.js → ApplicationsPage-DI-iMqoJ.js} +4 -4
- package/dist/chunks/{ApplicationsPage-ztPwoAGt.js.map → ApplicationsPage-DI-iMqoJ.js.map} +1 -1
- package/dist/chunks/{AssignmentRulesPage-DFSVFFXr.js → AssignmentRulesPage-B5UbujbZ.js} +2 -2
- package/dist/chunks/{AssignmentRulesPage-DFSVFFXr.js.map → AssignmentRulesPage-B5UbujbZ.js.map} +1 -1
- package/dist/chunks/{AssignmentRulesPage-CK4L4rBO.js → AssignmentRulesPage-E79QBSLb.js} +2 -2
- package/dist/chunks/{AssignmentRulesPage-CK4L4rBO.js.map → AssignmentRulesPage-E79QBSLb.js.map} +1 -1
- package/dist/chunks/{AssignmentsPage-JCLpyg94.js → AssignmentsPage-CDFaL1gT.js} +2 -2
- package/dist/chunks/{AssignmentsPage-JCLpyg94.js.map → AssignmentsPage-CDFaL1gT.js.map} +1 -1
- package/dist/chunks/{AssignmentsPage-Bp7oQD7Q.js → AssignmentsPage-CPeKJjyK.js} +2 -2
- package/dist/chunks/{AssignmentsPage-Bp7oQD7Q.js.map → AssignmentsPage-CPeKJjyK.js.map} +1 -1
- package/dist/chunks/{AuthCallbackPage-Bl9xlJ3h.js → AuthCallbackPage-BZ3Ocos5.js} +2 -2
- package/dist/chunks/{AuthCallbackPage-Bl9xlJ3h.js.map → AuthCallbackPage-BZ3Ocos5.js.map} +1 -1
- package/dist/chunks/{AuthCallbackPage-CzMHz4jy.js → AuthCallbackPage-Bml48QpH.js} +2 -2
- package/dist/chunks/{AuthCallbackPage-CzMHz4jy.js.map → AuthCallbackPage-Bml48QpH.js.map} +1 -1
- package/dist/chunks/{ConfirmEmailPage-M7mJgXvn.js → ConfirmEmailPage-DP1XPaKK.js} +2 -2
- package/dist/chunks/{ConfirmEmailPage-M7mJgXvn.js.map → ConfirmEmailPage-DP1XPaKK.js.map} +1 -1
- package/dist/chunks/{ConfirmEmailPage-D_8T1vqV.js → ConfirmEmailPage-DyzslZ06.js} +2 -2
- package/dist/chunks/{ConfirmEmailPage-D_8T1vqV.js.map → ConfirmEmailPage-DyzslZ06.js.map} +1 -1
- package/dist/chunks/{CreateSupportTicketPage-BNEGavlu.js → CreateSupportTicketPage-Bz2KrMik.js} +2 -2
- package/dist/chunks/{CreateSupportTicketPage-BNEGavlu.js.map → CreateSupportTicketPage-Bz2KrMik.js.map} +1 -1
- package/dist/chunks/{CreateSupportTicketPage-C2X2mfds.js → CreateSupportTicketPage-hKjKM0Bh.js} +2 -2
- package/dist/chunks/{CreateSupportTicketPage-C2X2mfds.js.map → CreateSupportTicketPage-hKjKM0Bh.js.map} +1 -1
- package/dist/chunks/{DashboardPage-4oy2YqvT.js → DashboardPage-B4nAd8Tj.js} +2 -2
- package/dist/chunks/{DashboardPage-4oy2YqvT.js.map → DashboardPage-B4nAd8Tj.js.map} +1 -1
- package/dist/chunks/{DashboardPage-D5MRMxEV.js → DashboardPage-C9qgPBS-.js} +3 -3
- package/dist/chunks/{DashboardPage-D5MRMxEV.js.map → DashboardPage-C9qgPBS-.js.map} +1 -1
- package/dist/chunks/{DashboardPage-CO-8B8EI.js → DashboardPage-CjbNGMo1.js} +3 -3
- package/dist/chunks/{DashboardPage-CO-8B8EI.js.map → DashboardPage-CjbNGMo1.js.map} +1 -1
- package/dist/chunks/{DashboardPage-CPArUG-S.js → DashboardPage-rN7IFlTR.js} +2 -2
- package/dist/chunks/{DashboardPage-CPArUG-S.js.map → DashboardPage-rN7IFlTR.js.map} +1 -1
- package/dist/chunks/{EscalationConfigPage-DnjLFXnL.js → EscalationConfigPage-CGv2L62M.js} +2 -2
- package/dist/chunks/{EscalationConfigPage-DnjLFXnL.js.map → EscalationConfigPage-CGv2L62M.js.map} +1 -1
- package/dist/chunks/{EscalationConfigPage-CwdnfJbJ.js → EscalationConfigPage-DpYDmsgw.js} +2 -2
- package/dist/chunks/{EscalationConfigPage-CwdnfJbJ.js.map → EscalationConfigPage-DpYDmsgw.js.map} +1 -1
- package/dist/chunks/{ForceChangePasswordPage-ZEIfyqwE.js → ForceChangePasswordPage-CLI_fpF4.js} +2 -2
- package/dist/chunks/{ForceChangePasswordPage-ZEIfyqwE.js.map → ForceChangePasswordPage-CLI_fpF4.js.map} +1 -1
- package/dist/chunks/{ForceChangePasswordPage-sh-3h_H9.js → ForceChangePasswordPage-Db6sOrZN.js} +2 -2
- package/dist/chunks/{ForceChangePasswordPage-sh-3h_H9.js.map → ForceChangePasswordPage-Db6sOrZN.js.map} +1 -1
- package/dist/chunks/{ForgotPasswordPage-B4M6-xeM.js → ForgotPasswordPage-BhMz2B6A.js} +2 -2
- package/dist/chunks/{ForgotPasswordPage-B4M6-xeM.js.map → ForgotPasswordPage-BhMz2B6A.js.map} +1 -1
- package/dist/chunks/{ForgotPasswordPage-MIu-U7p0.js → ForgotPasswordPage-D06arMXO.js} +2 -2
- package/dist/chunks/{ForgotPasswordPage-MIu-U7p0.js.map → ForgotPasswordPage-D06arMXO.js.map} +1 -1
- package/dist/chunks/{GroupDetailPage-4XK3Bs_r.js → GroupDetailPage-BCM8KBCd.js} +5 -5
- package/dist/chunks/{GroupDetailPage-4XK3Bs_r.js.map → GroupDetailPage-BCM8KBCd.js.map} +1 -1
- package/dist/chunks/{GroupDetailPage-C-kvtd2T.js → GroupDetailPage-CGMV3bWt.js} +2 -2
- package/dist/chunks/{GroupDetailPage-C-kvtd2T.js.map → GroupDetailPage-CGMV3bWt.js.map} +1 -1
- package/dist/chunks/{MyAccessRequestsPage-CP41FzHi.js → MyAccessRequestsPage-BBrwEomx.js} +2 -2
- package/dist/chunks/{MyAccessRequestsPage-CP41FzHi.js.map → MyAccessRequestsPage-BBrwEomx.js.map} +1 -1
- package/dist/chunks/{MyAccessRequestsPage-DzrXTrVi.js → MyAccessRequestsPage-CrlWe3gd.js} +2 -2
- package/dist/chunks/{MyAccessRequestsPage-DzrXTrVi.js.map → MyAccessRequestsPage-CrlWe3gd.js.map} +1 -1
- package/dist/chunks/{MyTenantsPage-V_SwYio2.js → MyTenantsPage-BOV34_rJ.js} +3 -3
- package/dist/chunks/{MyTenantsPage-V_SwYio2.js.map → MyTenantsPage-BOV34_rJ.js.map} +1 -1
- package/dist/chunks/{MyTenantsPage-CZRkMbh8.js → MyTenantsPage-CK4-klmd.js} +2 -2
- package/dist/chunks/{MyTenantsPage-CZRkMbh8.js.map → MyTenantsPage-CK4-klmd.js.map} +1 -1
- package/dist/chunks/{MyTicketsPage-DnvAIeyr.js → MyTicketsPage-CFZ1G4dG.js} +2 -2
- package/dist/chunks/{MyTicketsPage-DnvAIeyr.js.map → MyTicketsPage-CFZ1G4dG.js.map} +1 -1
- package/dist/chunks/{MyTicketsPage-DOUhaLal.js → MyTicketsPage-DuhpwhZx.js} +2 -2
- package/dist/chunks/{MyTicketsPage-DOUhaLal.js.map → MyTicketsPage-DuhpwhZx.js.map} +1 -1
- package/dist/chunks/{NavigationAppsPage-DfTa4jCG.js → NavigationAppsPage-BnNQRfBP.js} +2 -2
- package/dist/chunks/{NavigationAppsPage-DfTa4jCG.js.map → NavigationAppsPage-BnNQRfBP.js.map} +1 -1
- package/dist/chunks/{NavigationAppsPage-DXvpLsbt.js → NavigationAppsPage-DdJxEoTZ.js} +2 -2
- package/dist/chunks/{NavigationAppsPage-DXvpLsbt.js.map → NavigationAppsPage-DdJxEoTZ.js.map} +1 -1
- package/dist/chunks/{NotificationsPage-I1yCk7tk.js → NotificationsPage-BllOlagk.js} +2 -2
- package/dist/chunks/{NotificationsPage-I1yCk7tk.js.map → NotificationsPage-BllOlagk.js.map} +1 -1
- package/dist/chunks/{NotificationsPage-D76MdAs-.js → NotificationsPage-D1T_ozHl.js} +2 -2
- package/dist/chunks/{NotificationsPage-D76MdAs-.js.map → NotificationsPage-D1T_ozHl.js.map} +1 -1
- package/dist/chunks/{OnboardingWizardPage-BRUzcl1A.js → OnboardingWizardPage-CioLaCYz.js} +2 -2
- package/dist/chunks/{OnboardingWizardPage-BRUzcl1A.js.map → OnboardingWizardPage-CioLaCYz.js.map} +1 -1
- package/dist/chunks/{OnboardingWizardPage-DtWUPCh3.js → OnboardingWizardPage-CrAQt7qL.js} +2 -2
- package/dist/chunks/{OnboardingWizardPage-DtWUPCh3.js.map → OnboardingWizardPage-CrAQt7qL.js.map} +1 -1
- package/dist/chunks/{PermissionDetailPage-CUNKbl7t.js → PermissionDetailPage-BIG78-1-.js} +2 -2
- package/dist/chunks/{PermissionDetailPage-CUNKbl7t.js.map → PermissionDetailPage-BIG78-1-.js.map} +1 -1
- package/dist/chunks/{PermissionDetailPage-DJJGbXoX.js → PermissionDetailPage-CvPqugYu.js} +2 -2
- package/dist/chunks/{PermissionDetailPage-DJJGbXoX.js.map → PermissionDetailPage-CvPqugYu.js.map} +1 -1
- package/dist/chunks/{PermissionsPage-B8wmawPV.js → PermissionsPage-CDSuc8vw.js} +2 -2
- package/dist/chunks/{PermissionsPage-B8wmawPV.js.map → PermissionsPage-CDSuc8vw.js.map} +1 -1
- package/dist/chunks/{PermissionsPage-Dbjcctuh.js → PermissionsPage-XaOrGrPZ.js} +2 -2
- package/dist/chunks/{PermissionsPage-Dbjcctuh.js.map → PermissionsPage-XaOrGrPZ.js.map} +1 -1
- package/dist/chunks/{PortalDashboardPage-BeNfBZmb.js → PortalDashboardPage-BsWVXkMe.js} +2 -2
- package/dist/chunks/{PortalDashboardPage-BeNfBZmb.js.map → PortalDashboardPage-BsWVXkMe.js.map} +1 -1
- package/dist/chunks/{PortalDashboardPage-zii0ll57.js → PortalDashboardPage-oSD7oQhJ.js} +2 -2
- package/dist/chunks/{PortalDashboardPage-zii0ll57.js.map → PortalDashboardPage-oSD7oQhJ.js.map} +1 -1
- package/dist/chunks/{PreferencesPage-BCpuIGzv.js → PreferencesPage-DD0_XWdT.js} +2 -2
- package/dist/chunks/{PreferencesPage-BCpuIGzv.js.map → PreferencesPage-DD0_XWdT.js.map} +1 -1
- package/dist/chunks/{PreferencesPage-BmvrBaAD.js → PreferencesPage-ca2BOdoH.js} +2 -2
- package/dist/chunks/{PreferencesPage-BmvrBaAD.js.map → PreferencesPage-ca2BOdoH.js.map} +1 -1
- package/dist/chunks/{ProfilePage-mf5wI0-n.js → ProfilePage-Bex_JN5N.js} +2 -2
- package/dist/chunks/{ProfilePage-mf5wI0-n.js.map → ProfilePage-Bex_JN5N.js.map} +1 -1
- package/dist/chunks/{ProfilePage-eowQd59_.js → ProfilePage-C8tUIOnb.js} +2 -2
- package/dist/chunks/{ProfilePage-eowQd59_.js.map → ProfilePage-C8tUIOnb.js.map} +1 -1
- package/dist/chunks/{ReferencesManagementPage-CLsaUNqA.js → ReferencesManagementPage-B-FXS2ln.js} +2 -2
- package/dist/chunks/{ReferencesManagementPage-CLsaUNqA.js.map → ReferencesManagementPage-B-FXS2ln.js.map} +1 -1
- package/dist/chunks/{ReferencesManagementPage-8UPgkVE8.js → ReferencesManagementPage-C8KZprkI.js} +3 -3
- package/dist/chunks/{ReferencesManagementPage-8UPgkVE8.js.map → ReferencesManagementPage-C8KZprkI.js.map} +1 -1
- package/dist/chunks/{RegisterPage-CNyHSbqs.js → RegisterPage-BYt__zKJ.js} +2 -2
- package/dist/chunks/{RegisterPage-CNyHSbqs.js.map → RegisterPage-BYt__zKJ.js.map} +1 -1
- package/dist/chunks/{RegisterPage-57X-ILDb.js → RegisterPage-MWcVu-LY.js} +2 -2
- package/dist/chunks/{RegisterPage-57X-ILDb.js.map → RegisterPage-MWcVu-LY.js.map} +1 -1
- package/dist/chunks/{ResetPasswordPage-CyV8l-Zo.js → ResetPasswordPage-DaJiMj5Z.js} +2 -2
- package/dist/chunks/{ResetPasswordPage-CyV8l-Zo.js.map → ResetPasswordPage-DaJiMj5Z.js.map} +1 -1
- package/dist/chunks/{ResetPasswordPage-JW8-mh_k.js → ResetPasswordPage-rCLUIj_T.js} +2 -2
- package/dist/chunks/{ResetPasswordPage-JW8-mh_k.js.map → ResetPasswordPage-rCLUIj_T.js.map} +1 -1
- package/dist/chunks/{ResolutionModal-CjwE73NX.js → ResolutionModal-DeuPnLWg.js} +2 -2
- package/dist/chunks/{ResolutionModal-CjwE73NX.js.map → ResolutionModal-DeuPnLWg.js.map} +1 -1
- package/dist/chunks/{ResolutionModal-wddG59kg.js → ResolutionModal-j7Rp6apG.js} +2 -2
- package/dist/chunks/{ResolutionModal-wddG59kg.js.map → ResolutionModal-j7Rp6apG.js.map} +1 -1
- package/dist/chunks/{RoleDetailPage-CrioVHFI.js → RoleDetailPage-CLtZWX17.js} +3 -3
- package/dist/chunks/{RoleDetailPage-CrioVHFI.js.map → RoleDetailPage-CLtZWX17.js.map} +1 -1
- package/dist/chunks/{RoleDetailPage-TUOGR1ow.js → RoleDetailPage-TGyGmLMM.js} +2 -2
- package/dist/chunks/{RoleDetailPage-TUOGR1ow.js.map → RoleDetailPage-TGyGmLMM.js.map} +1 -1
- package/dist/chunks/{RolesPage-sJBWaNff.js → RolesPage-C0c5G9e7.js} +2 -2
- package/dist/chunks/{RolesPage-sJBWaNff.js.map → RolesPage-C0c5G9e7.js.map} +1 -1
- package/dist/chunks/{RolesPage-CAcols3D.js → RolesPage-Dm03fBBf.js} +2 -2
- package/dist/chunks/{RolesPage-CAcols3D.js.map → RolesPage-Dm03fBBf.js.map} +1 -1
- package/dist/chunks/{SlaConfigPage-BPGRloOS.js → SlaConfigPage-B4WDzEKi.js} +2 -2
- package/dist/chunks/{SlaConfigPage-BPGRloOS.js.map → SlaConfigPage-B4WDzEKi.js.map} +1 -1
- package/dist/chunks/{SlaConfigPage-D5TRn7Ir.js → SlaConfigPage-Cwo9NwxH.js} +2 -2
- package/dist/chunks/{SlaConfigPage-D5TRn7Ir.js.map → SlaConfigPage-Cwo9NwxH.js.map} +1 -1
- package/dist/chunks/{SupportPermissionsPage-UXmYLrIq.js → SupportPermissionsPage-CL12dFy-.js} +2 -2
- package/dist/chunks/{SupportPermissionsPage-UXmYLrIq.js.map → SupportPermissionsPage-CL12dFy-.js.map} +1 -1
- package/dist/chunks/{SupportPermissionsPage-Dc2bWTzG.js → SupportPermissionsPage-CneIhl30.js} +2 -2
- package/dist/chunks/{SupportPermissionsPage-Dc2bWTzG.js.map → SupportPermissionsPage-CneIhl30.js.map} +1 -1
- package/dist/chunks/{TemplatesPage-nTY85sNA.js → TemplatesPage-DStKmwHT.js} +2 -2
- package/dist/chunks/{TemplatesPage-nTY85sNA.js.map → TemplatesPage-DStKmwHT.js.map} +1 -1
- package/dist/chunks/{TemplatesPage-dmPlqqiD.js → TemplatesPage-X4Rrhs9p.js} +2 -2
- package/dist/chunks/{TemplatesPage-dmPlqqiD.js.map → TemplatesPage-X4Rrhs9p.js.map} +1 -1
- package/dist/chunks/{TenantCard-BhT-31ls.js → TenantCard-BUBYWtvR.js} +2 -2
- package/dist/chunks/{TenantCard-BhT-31ls.js.map → TenantCard-BUBYWtvR.js.map} +1 -1
- package/dist/chunks/{TenantCard-BUXfstRZ.js → TenantCard-CAgiB-NG.js} +2 -2
- package/dist/chunks/{TenantCard-BUXfstRZ.js.map → TenantCard-CAgiB-NG.js.map} +1 -1
- package/dist/chunks/{TenantScopeSelector-3_mzBLNI.js → TenantScopeSelector-B9vtpIZx.js} +2 -2
- package/dist/chunks/{TenantScopeSelector-3_mzBLNI.js.map → TenantScopeSelector-B9vtpIZx.js.map} +1 -1
- package/dist/chunks/{TenantScopeSelector-B-SRDR2R.js → TenantScopeSelector-BAoah-mL.js} +2 -2
- package/dist/chunks/{TenantScopeSelector-B-SRDR2R.js.map → TenantScopeSelector-BAoah-mL.js.map} +1 -1
- package/dist/chunks/{TicketDetailPage-xN3wPnFL.js → TicketDetailPage-BFcP4X8s.js} +2 -2
- package/dist/chunks/{TicketDetailPage-xN3wPnFL.js.map → TicketDetailPage-BFcP4X8s.js.map} +1 -1
- package/dist/chunks/{TicketDetailPage-B4cR3rOC.js → TicketDetailPage-D_Npnt4A.js} +2 -2
- package/dist/chunks/{TicketDetailPage-B4cR3rOC.js.map → TicketDetailPage-D_Npnt4A.js.map} +1 -1
- package/dist/chunks/{TicketsPage-Dwi2xpMI.js → TicketsPage-DBP9kalU.js} +2 -2
- package/dist/chunks/{TicketsPage-Dwi2xpMI.js.map → TicketsPage-DBP9kalU.js.map} +1 -1
- package/dist/chunks/{TicketsPage-CkHgXSxU.js → TicketsPage-p21DLhUb.js} +2 -2
- package/dist/chunks/{TicketsPage-CkHgXSxU.js.map → TicketsPage-p21DLhUb.js.map} +1 -1
- package/dist/chunks/{UserCreateTicketPage-D2a3EOey.js → UserCreateTicketPage-DOwShnG8.js} +2 -2
- package/dist/chunks/{UserCreateTicketPage-D2a3EOey.js.map → UserCreateTicketPage-DOwShnG8.js.map} +1 -1
- package/dist/chunks/{UserCreateTicketPage-bcbSLglE.js → UserCreateTicketPage-lvlvp2u6.js} +2 -2
- package/dist/chunks/{UserCreateTicketPage-bcbSLglE.js.map → UserCreateTicketPage-lvlvp2u6.js.map} +1 -1
- package/dist/chunks/{UserDashboardPage-ZMsx8LWw.js → UserDashboardPage-C_tm7Pld.js} +2 -2
- package/dist/chunks/{UserDashboardPage-ZMsx8LWw.js.map → UserDashboardPage-C_tm7Pld.js.map} +1 -1
- package/dist/chunks/{UserDashboardPage-DwnDRNoW.js → UserDashboardPage-Dp6q6FEW.js} +2 -2
- package/dist/chunks/{UserDashboardPage-DwnDRNoW.js.map → UserDashboardPage-Dp6q6FEW.js.map} +1 -1
- package/dist/chunks/{UserDetailPage-CZyV-zsg.js → UserDetailPage-6grZ6gmV.js} +5 -5
- package/dist/chunks/{UserDetailPage-CZyV-zsg.js.map → UserDetailPage-6grZ6gmV.js.map} +1 -1
- package/dist/chunks/{UserDetailPage-BRFowOFL.js → UserDetailPage-DXLxO7LF.js} +2 -2
- package/dist/chunks/{UserDetailPage-BRFowOFL.js.map → UserDetailPage-DXLxO7LF.js.map} +1 -1
- package/dist/chunks/{UserTicketDetailPage-BstGk_BP.js → UserTicketDetailPage-Ch9IfCPo.js} +2 -2
- package/dist/chunks/{UserTicketDetailPage-BstGk_BP.js.map → UserTicketDetailPage-Ch9IfCPo.js.map} +1 -1
- package/dist/chunks/{UserTicketDetailPage-DzB_pELt.js → UserTicketDetailPage-a4II5VEE.js} +2 -2
- package/dist/chunks/{UserTicketDetailPage-DzB_pELt.js.map → UserTicketDetailPage-a4II5VEE.js.map} +1 -1
- package/dist/chunks/{UsersGroupsPage-BygTv_kK.js → UsersGroupsPage-B7Er0V4l.js} +3 -3
- package/dist/chunks/{UsersGroupsPage-BygTv_kK.js.map → UsersGroupsPage-B7Er0V4l.js.map} +1 -1
- package/dist/chunks/{UsersGroupsPage-DTmhzttW.js → UsersGroupsPage-BeAv4QfV.js} +2 -2
- package/dist/chunks/{UsersGroupsPage-DTmhzttW.js.map → UsersGroupsPage-BeAv4QfV.js.map} +1 -1
- package/dist/chunks/{UsersPage-DcwLyMAX.js → UsersPage-0M1FLqOe.js} +2 -2
- package/dist/chunks/{UsersPage-DcwLyMAX.js.map → UsersPage-0M1FLqOe.js.map} +1 -1
- package/dist/chunks/{UsersPage-TIqSHgHj.js → UsersPage-ZR9r9vvf.js} +2 -2
- package/dist/chunks/{UsersPage-TIqSHgHj.js.map → UsersPage-ZR9r9vvf.js.map} +1 -1
- package/dist/chunks/{accessRequestsApi-3FjMFbpa.js → accessRequestsApi-BJH8EE1K.js} +2 -2
- package/dist/chunks/{accessRequestsApi-3FjMFbpa.js.map → accessRequestsApi-BJH8EE1K.js.map} +1 -1
- package/dist/chunks/{accessRequestsApi-B6dsJzvH.js → accessRequestsApi-CBpF5d54.js} +2 -2
- package/dist/chunks/{accessRequestsApi-B6dsJzvH.js.map → accessRequestsApi-CBpF5d54.js.map} +1 -1
- package/dist/chunks/{aiApi-9G4wG_mT.js → aiApi-CkkWAvNB.js} +2 -2
- package/dist/chunks/{aiApi-9G4wG_mT.js.map → aiApi-CkkWAvNB.js.map} +1 -1
- package/dist/chunks/{aiApi-DXOdsoxr.js → aiApi-Dl7a2lWz.js} +2 -2
- package/dist/chunks/{aiApi-DXOdsoxr.js.map → aiApi-Dl7a2lWz.js.map} +1 -1
- package/dist/chunks/{applicationAnalyticsApi-DhOd6idI.js → applicationAnalyticsApi-BwcSE_H1.js} +2 -2
- package/dist/chunks/{applicationAnalyticsApi-DhOd6idI.js.map → applicationAnalyticsApi-BwcSE_H1.js.map} +1 -1
- package/dist/chunks/{applicationAnalyticsApi-D0DEp9Y-.js → applicationAnalyticsApi-DKMmDvWk.js} +2 -2
- package/dist/chunks/{applicationAnalyticsApi-D0DEp9Y-.js.map → applicationAnalyticsApi-DKMmDvWk.js.map} +1 -1
- package/dist/chunks/{groupsApi-Db8G2lLs.js → groupsApi-BzDV3_Jc.js} +2 -2
- package/dist/chunks/{groupsApi-Db8G2lLs.js.map → groupsApi-BzDV3_Jc.js.map} +1 -1
- package/dist/chunks/{groupsApi-lbxNsHFv.js → groupsApi-CQ4vFMdP.js} +2 -2
- package/dist/chunks/{groupsApi-lbxNsHFv.js.map → groupsApi-CQ4vFMdP.js.map} +1 -1
- package/dist/chunks/{index-DEtq-xUL.js → index-BBmMbSZV.js} +8 -8
- package/dist/chunks/{index-DEtq-xUL.js.map → index-BBmMbSZV.js.map} +1 -1
- package/dist/chunks/{index-D0HS542b.js → index-BLlESTfA.js} +2 -2
- package/dist/chunks/{index-D0HS542b.js.map → index-BLlESTfA.js.map} +1 -1
- package/dist/chunks/{index-DUS-tunb.js → index-BPMjxWVx.js} +2 -2
- package/dist/chunks/{index-DUS-tunb.js.map → index-BPMjxWVx.js.map} +1 -1
- package/dist/chunks/{index-TiWOcC0g.js → index-CEbwdURd.js} +2 -2
- package/dist/chunks/{index-TiWOcC0g.js.map → index-CEbwdURd.js.map} +1 -1
- package/dist/chunks/{index-DF93KQFR.js → index-CUZygY5Q.js} +2 -2
- package/dist/chunks/{index-DF93KQFR.js.map → index-CUZygY5Q.js.map} +1 -1
- package/dist/chunks/{index-BI2dc1FS.js → index-Ci1SqFiY.js} +2 -2
- package/dist/chunks/{index-BI2dc1FS.js.map → index-Ci1SqFiY.js.map} +1 -1
- package/dist/chunks/{index-CTGSmYvs.js → index-Cib93xtp.js} +2 -2
- package/dist/chunks/{index-CTGSmYvs.js.map → index-Cib93xtp.js.map} +1 -1
- package/dist/chunks/{index-DqbVFB1H.js → index-CoHIgn5H.js} +2 -2
- package/dist/chunks/{index-DqbVFB1H.js.map → index-CoHIgn5H.js.map} +1 -1
- package/dist/chunks/{index-CN2WRyg1.js → index-CpY95_ro.js} +294 -292
- package/dist/chunks/{index-CN2WRyg1.js.map → index-CpY95_ro.js.map} +1 -1
- package/dist/chunks/{index-DjC1u2hI.js → index-D-2xSu5W.js} +3 -3
- package/dist/chunks/{index-DjC1u2hI.js.map → index-D-2xSu5W.js.map} +1 -1
- package/dist/chunks/{index-Bn8HzILk.js → index-D18t9DhC.js} +4 -4
- package/dist/chunks/{index-Bn8HzILk.js.map → index-D18t9DhC.js.map} +1 -1
- package/dist/chunks/{index-cAikSVW0.js → index-DK5czlkn.js} +9 -9
- package/dist/chunks/{index-cAikSVW0.js.map → index-DK5czlkn.js.map} +1 -1
- package/dist/chunks/{index-DLekpNSE.js → index-DQd324n7.js} +2 -2
- package/dist/chunks/{index-DLekpNSE.js.map → index-DQd324n7.js.map} +1 -1
- package/dist/chunks/{index-CgtbaFf5.js → index-Dbq-x5H9.js} +2 -2
- package/dist/chunks/{index-CgtbaFf5.js.map → index-Dbq-x5H9.js.map} +1 -1
- package/dist/chunks/{index-xhRXN1Jq.js → index-Det9dEaQ.js} +2 -2
- package/dist/chunks/{index-xhRXN1Jq.js.map → index-Det9dEaQ.js.map} +1 -1
- package/dist/chunks/{index-HsAOBno4.js → index-bgT9XOKZ.js} +2 -2
- package/dist/chunks/{index-HsAOBno4.js.map → index-bgT9XOKZ.js.map} +1 -1
- package/dist/chunks/{index-CUICSveU.js → index-h7ZrwrQg.js} +2 -2
- package/dist/chunks/{index-CUICSveU.js.map → index-h7ZrwrQg.js.map} +1 -1
- package/dist/chunks/{index-DwqLhQ8S.js → index-k4USDz2P.js} +2 -2
- package/dist/chunks/{index-DwqLhQ8S.js.map → index-k4USDz2P.js.map} +1 -1
- package/dist/chunks/{tenantIconMap-CHeS7oLt.js → tenantIconMap-7ihIWxAh.js} +2 -2
- package/dist/chunks/{tenantIconMap-CHeS7oLt.js.map → tenantIconMap-7ihIWxAh.js.map} +1 -1
- package/dist/chunks/{tenantIconMap-__FKj6CN.js → tenantIconMap-Dk6K-UTE.js} +2 -2
- package/dist/chunks/{tenantIconMap-__FKj6CN.js.map → tenantIconMap-Dk6K-UTE.js.map} +1 -1
- package/dist/chunks/{ticketingApi-DF4RwD_6.js → ticketingApi-BCMKkzlv.js} +2 -2
- package/dist/chunks/{ticketingApi-DF4RwD_6.js.map → ticketingApi-BCMKkzlv.js.map} +1 -1
- package/dist/chunks/{ticketingApi-Cj239hYB.js → ticketingApi-Dwn7pl5z.js} +2 -2
- package/dist/chunks/{ticketingApi-Cj239hYB.js.map → ticketingApi-Dwn7pl5z.js.map} +1 -1
- package/dist/chunks/{useAccessRequests-CFam8zFR.js → useAccessRequests-Du7CvowE.js} +3 -3
- package/dist/chunks/{useAccessRequests-CFam8zFR.js.map → useAccessRequests-Du7CvowE.js.map} +1 -1
- package/dist/chunks/{useAccessRequests-CViOUwyF.js → useAccessRequests-gJ7yhWyi.js} +2 -2
- package/dist/chunks/{useAccessRequests-CViOUwyF.js.map → useAccessRequests-gJ7yhWyi.js.map} +1 -1
- package/dist/chunks/{useUserAccessRequests-CslSQeBJ.js → useUserAccessRequests-5wWea2Jg.js} +2 -2
- package/dist/chunks/{useUserAccessRequests-CslSQeBJ.js.map → useUserAccessRequests-5wWea2Jg.js.map} +1 -1
- package/dist/chunks/{useUserAccessRequests-B-Cs6NX1.js → useUserAccessRequests-Bk_v8egy.js} +2 -2
- package/dist/chunks/{useUserAccessRequests-B-Cs6NX1.js.map → useUserAccessRequests-Bk_v8egy.js.map} +1 -1
- package/dist/components/routing/ProtectedRoute.d.ts.map +1 -1
- package/dist/smartstack.cjs +1 -1
- package/dist/smartstack.js +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DashboardPage-4oy2YqvT.js","sources":["../../src/components/dashboard/DeviceBreakdownChart.tsx","../../src/components/dashboard/EngagementMetricsCard.tsx","../../src/pages/platform/administration/DashboardPage.tsx"],"sourcesContent":["import React from 'react';\r\nimport { Monitor, Smartphone, Tablet } from 'lucide-react';\r\nimport type { DeviceAnalyticsDto } from '@/services/api/applicationAnalyticsApi';\r\n\r\ninterface DeviceBreakdownChartProps {\r\n readonly data: DeviceAnalyticsDto | null;\r\n}\r\n\r\nconst deviceIcons: Record<string, React.ReactNode> = {\r\n Desktop: <Monitor className=\"w-4 h-4\" />,\r\n Mobile: <Smartphone className=\"w-4 h-4\" />,\r\n Tablet: <Tablet className=\"w-4 h-4\" />,\r\n Unknown: <Monitor className=\"w-4 h-4 opacity-50\" />\r\n};\r\n\r\nconst deviceColors = [\r\n '#3b82f6',\r\n '#22c55e',\r\n '#f59e0b',\r\n '#6b7280'\r\n];\r\n\r\nconst browserColors = [\r\n '#3b82f6',\r\n '#8b5cf6',\r\n '#22c55e',\r\n '#f59e0b',\r\n '#ef4444'\r\n];\r\n\r\nexport const DeviceBreakdownChart: React.FC<DeviceBreakdownChartProps> = ({ data }) => {\r\n if (!data || (!data.byDeviceType?.length && !data.byBrowser?.length)) {\r\n return (\r\n <div className=\"text-center py-8 text-[var(--text-secondary)]\">\r\n No device data available\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-6\">\r\n {/* Device Type Breakdown */}\r\n <div>\r\n <h4 className=\"text-sm font-medium text-[var(--text-secondary)] mb-3\">\r\n By Device Type\r\n </h4>\r\n <div className=\"space-y-3\">\r\n {data.byDeviceType.map((device, index) => (\r\n <div key={device.deviceType} className=\"flex items-center gap-3\">\r\n <div className=\"flex items-center gap-2 w-28\">\r\n {deviceIcons[device.deviceType] || deviceIcons.Unknown}\r\n <span className=\"text-sm\">{device.deviceType}</span>\r\n </div>\r\n <div className=\"flex-1 h-6 bg-[var(--bg-secondary)] rounded-full overflow-hidden\">\r\n <div\r\n className=\"h-full rounded-full transition-all duration-500\"\r\n style={{\r\n width: `${device.percentage}%`,\r\n backgroundColor: deviceColors[index % deviceColors.length]\r\n }}\r\n />\r\n </div>\r\n <div className=\"w-20 text-right\">\r\n <span className=\"font-medium\">{device.count}</span>\r\n <span className=\"text-xs text-[var(--text-secondary)] ml-1\">\r\n ({device.percentage.toFixed(1)}%)\r\n </span>\r\n </div>\r\n </div>\r\n ))}\r\n </div>\r\n </div>\r\n\r\n {/* Browser Breakdown */}\r\n <div>\r\n <h4 className=\"text-sm font-medium text-[var(--text-secondary)] mb-3\">\r\n By Browser\r\n </h4>\r\n <div className=\"space-y-3\">\r\n {data.byBrowser.map((browser, index) => {\r\n const maxCount = Math.max(...data.byBrowser.map(b => b.count), 1);\r\n const percentage = (browser.count / maxCount) * 100;\r\n\r\n return (\r\n <div key={browser.browser} className=\"flex items-center gap-3\">\r\n <div className=\"w-24 text-sm\">{browser.browser}</div>\r\n <div className=\"flex-1 h-6 bg-[var(--bg-secondary)] rounded-full overflow-hidden\">\r\n <div\r\n className=\"h-full rounded-full transition-all duration-500\"\r\n style={{\r\n width: `${percentage}%`,\r\n backgroundColor: browserColors[index % browserColors.length]\r\n }}\r\n />\r\n </div>\r\n <div className=\"w-12 text-right font-medium\">{browser.count}</div>\r\n </div>\r\n );\r\n })}\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n};\r\n","import React from 'react';\r\nimport type { EngagementMetricsDto } from '@/services/api/applicationAnalyticsApi';\r\n\r\ninterface EngagementMetricsCardProps {\r\n readonly data: EngagementMetricsDto | null;\r\n}\r\n\r\nconst sessionColors = ['#ef4444', '#f59e0b', '#22c55e', '#3b82f6'];\r\n\r\nexport const EngagementMetricsCard: React.FC<EngagementMetricsCardProps> = ({ data }) => {\r\n if (!data) {\r\n return (\r\n <div className=\"text-center py-8 text-[var(--text-secondary)]\">\r\n No engagement data available\r\n </div>\r\n );\r\n }\r\n\r\n const maxBucketCount = Math.max(...data.sessionDistribution.map(b => b.count), 1);\r\n const maxHourCount = Math.max(...data.peakUsageHours.map(h => h.accessCount), 1);\r\n\r\n return (\r\n <div className=\"space-y-6\">\r\n {/* Session Duration Distribution */}\r\n <div>\r\n <h4 className=\"text-sm font-medium text-[var(--text-secondary)] mb-3\">\r\n Session Duration Distribution\r\n </h4>\r\n <div className=\"space-y-3\">\r\n {data.sessionDistribution.map((bucket, index) => {\r\n const percentage = (bucket.count / maxBucketCount) * 100;\r\n\r\n return (\r\n <div key={bucket.bucket} className=\"flex items-center gap-3\">\r\n <div className=\"w-20 text-sm\">{bucket.label}</div>\r\n <div className=\"flex-1 h-6 bg-[var(--bg-secondary)] rounded-full overflow-hidden\">\r\n <div\r\n className=\"h-full rounded-full transition-all duration-500\"\r\n style={{\r\n width: `${percentage}%`,\r\n backgroundColor: sessionColors[index % sessionColors.length]\r\n }}\r\n />\r\n </div>\r\n <div className=\"w-16 text-right\">\r\n <span className=\"font-medium\">{bucket.count}</span>\r\n <span className=\"text-xs text-[var(--text-secondary)] ml-1\">\r\n sessions\r\n </span>\r\n </div>\r\n </div>\r\n );\r\n })}\r\n </div>\r\n </div>\r\n\r\n {/* Peak Usage Hours */}\r\n <div>\r\n <h4 className=\"text-sm font-medium text-[var(--text-secondary)] mb-3\">\r\n Peak Usage Hours\r\n </h4>\r\n <div className=\"flex items-end gap-1 h-32 overflow-x-auto pb-2\">\r\n {data.peakUsageHours.map((hourData) => {\r\n const heightPercentage = (hourData.accessCount / maxHourCount) * 100;\r\n\r\n return (\r\n <div\r\n key={hourData.hour}\r\n className=\"flex-1 min-w-[20px] flex flex-col items-center gap-1\"\r\n >\r\n <div\r\n className=\"w-full bg-gradient-to-t from-blue-500 to-cyan-500 rounded-t transition-all duration-300 hover:opacity-80\"\r\n style={{\r\n height: `${heightPercentage}%`,\r\n minHeight: hourData.accessCount > 0 ? '4px' : '0'\r\n }}\r\n title={`${hourData.hour}h: ${hourData.accessCount} accesses`}\r\n />\r\n {hourData.hour % 3 === 0 && (\r\n <span className=\"text-xs text-[var(--text-secondary)]\">\r\n {hourData.hour}h\r\n </span>\r\n )}\r\n </div>\r\n );\r\n })}\r\n </div>\r\n </div>\r\n\r\n {/* Engagement Summary */}\r\n <div className=\"grid grid-cols-2 gap-4 pt-4 border-t border-[var(--border-color)]\">\r\n <div className=\"text-center p-3 bg-[var(--bg-secondary)] rounded-lg\">\r\n <div className=\"text-2xl font-bold text-blue-600\">\r\n {data.dailyActiveUsers}\r\n </div>\r\n <div className=\"text-xs text-[var(--text-secondary)] mt-1\">\r\n Daily Active Users\r\n </div>\r\n </div>\r\n <div className=\"text-center p-3 bg-[var(--bg-secondary)] rounded-lg\">\r\n <div className=\"text-2xl font-bold text-green-600\">\r\n {(data.retentionRate * 100).toFixed(1)}%\r\n </div>\r\n <div className=\"text-xs text-[var(--text-secondary)] mt-1\">\r\n Retention Rate\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n};\r\n","import { useState, useEffect, useCallback, useRef } from 'react';\r\nimport type { ReactElement } from 'react';\r\nimport { useNavigate } from 'react-router-dom';\r\nimport { useTranslation } from 'react-i18next';\r\nimport {\r\n Users,\r\n UserCheck,\r\n UserX,\r\n UserPlus,\r\n Activity,\r\n AlertTriangle,\r\n Key,\r\n Shield,\r\n TrendingUp,\r\n RefreshCw,\r\n Loader2,\r\n Clock,\r\n Globe,\r\n Monitor,\r\n} from 'lucide-react';\r\nimport {\r\n adminApi,\r\n type UserDashboardOverviewDto,\r\n type UserStatusCountDto,\r\n type UserRoleDistributionDto,\r\n type UserTrendDto,\r\n type SecurityAlertDto,\r\n type ActiveSessionsStatsDto,\r\n type LatestActiveSessionDto,\r\n} from '@/services/api/adminApi';\r\nimport { applicationAnalyticsApi } from '@/services/api/applicationAnalyticsApi';\r\nimport { Breadcrumb } from '@/components/ui/Breadcrumb';\r\nimport { useTenant } from '@/contexts/TenantContext';\r\nimport type { DeviceAnalyticsDto, EngagementMetricsDto } from '@/services/api/applicationAnalyticsApi';\r\nimport { DeviceBreakdownChart } from '@/components/dashboard/DeviceBreakdownChart';\r\nimport { EngagementMetricsCard } from '@/components/dashboard/EngagementMetricsCard';\r\n\r\nconst statusColors: Record<string, string> = {\r\n Active: '#22c55e',\r\n Inactive: '#ef4444',\r\n};\r\n\r\nexport function AdminDashboardPage(): ReactElement {\r\n const { t } = useTranslation(['admin', 'navigation']);\r\n const navigate = useNavigate();\r\n const { currentTenant, isGlobalView } = useTenant();\r\n const [loading, setLoading] = useState(true);\r\n const [refreshing, setRefreshing] = useState(false);\r\n const [period, setPeriod] = useState(30);\r\n\r\n const [overview, setOverview] = useState<UserDashboardOverviewDto | null>(null);\r\n const [statusData, setStatusData] = useState<UserStatusCountDto[]>([]);\r\n const [roleData, setRoleData] = useState<UserRoleDistributionDto[]>([]);\r\n const [trends, setTrends] = useState<UserTrendDto[]>([]);\r\n const [latestSessions, setLatestSessions] = useState<LatestActiveSessionDto[]>([]);\r\n const [securityAlerts, setSecurityAlerts] = useState<SecurityAlertDto[]>([]);\r\n const [sessionStats, setSessionStats] = useState<ActiveSessionsStatsDto | null>(null);\r\n const [deviceStats, setDeviceStats] = useState<DeviceAnalyticsDto | null>(null);\r\n const [engagementMetrics, setEngagementMetrics] = useState<EngagementMetricsDto | null>(null);\r\n const [error, setError] = useState<string | null>(null);\r\n\r\n // Ref to track if component is still mounted (StrictMode protection)\r\n const abortControllerRef = useRef<AbortController | null>(null);\r\n\r\n const loadData = useCallback(async (signal?: AbortSignal) => {\r\n try {\r\n setError(null);\r\n const [\r\n overviewRes,\r\n statusRes,\r\n roleRes,\r\n trendsRes,\r\n latestSessionsRes,\r\n alertsRes,\r\n sessionsRes,\r\n deviceRes,\r\n engagementRes,\r\n ] = await Promise.all([\r\n adminApi.dashboard.getOverview(period, { signal }),\r\n adminApi.dashboard.getByStatus({ signal }),\r\n adminApi.dashboard.getByRole({ signal }),\r\n adminApi.dashboard.getTrends(period, { signal }),\r\n adminApi.dashboard.getLatestActiveSessions(5, { signal }),\r\n adminApi.dashboard.getSecurityAlerts(3, 24, { signal }),\r\n adminApi.dashboard.getActiveSessions({ signal }),\r\n applicationAnalyticsApi.getDeviceStats(period, { signal }),\r\n applicationAnalyticsApi.getEngagementMetrics(period, { signal }),\r\n ]);\r\n\r\n // Only update state if request wasn't aborted\r\n if (!signal?.aborted) {\r\n setOverview(overviewRes ?? null);\r\n setStatusData(statusRes ?? []);\r\n setRoleData(roleRes ?? []);\r\n setTrends(trendsRes ?? []);\r\n setLatestSessions(latestSessionsRes ?? []);\r\n setSecurityAlerts(alertsRes ?? []);\r\n setSessionStats(sessionsRes ?? null);\r\n setDeviceStats(deviceRes ?? null);\r\n setEngagementMetrics(engagementRes ?? null);\r\n }\r\n } catch (err: unknown) {\r\n // Ignore abort errors (expected in StrictMode)\r\n if (err instanceof Error && err.name === 'CanceledError') {\r\n return;\r\n }\r\n console.error('Failed to load dashboard data:', err);\r\n const axiosError = err as { response?: { status?: number; data?: { message?: string } } };\r\n if (axiosError.response?.status === 401) {\r\n setError('Session expirée. Veuillez vous reconnecter.');\r\n } else if (axiosError.response?.status === 403) {\r\n setError('Vous n\\'avez pas les permissions nécessaires pour accéder au dashboard.');\r\n } else {\r\n setError('Erreur lors du chargement des données. Vérifiez que l\\'API est accessible.');\r\n }\r\n } finally {\r\n if (!signal?.aborted) {\r\n setLoading(false);\r\n setRefreshing(false);\r\n }\r\n }\r\n }, [period, currentTenant?.id, isGlobalView]);\r\n\r\n useEffect(() => {\r\n // Abort any previous request before starting a new one\r\n abortControllerRef.current?.abort();\r\n const controller = new AbortController();\r\n abortControllerRef.current = controller;\r\n\r\n loadData(controller.signal);\r\n\r\n // Cleanup: abort request when component unmounts or period changes\r\n return () => {\r\n controller.abort();\r\n };\r\n }, [loadData]);\r\n\r\n const handleRefresh = () => {\r\n // Abort any previous request before starting a new one\r\n abortControllerRef.current?.abort();\r\n const controller = new AbortController();\r\n abortControllerRef.current = controller;\r\n\r\n setRefreshing(true);\r\n loadData(controller.signal);\r\n };\r\n\r\n if (loading) {\r\n return (\r\n <div className=\"flex items-center justify-center min-h-[400px]\">\r\n <Loader2 className=\"w-8 h-8 animate-spin text-[var(--color-primary-600)]\" />\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div className=\"space-y-6\">\r\n {/* Breadcrumb */}\r\n <Breadcrumb\r\n items={[\r\n { label: t('header.title') },\r\n { label: t('dashboard.title') }\r\n ]}\r\n />\r\n\r\n {/* Error Banner */}\r\n {error && (\r\n <div className=\"bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg p-4 flex items-center gap-3\">\r\n <AlertTriangle className=\"w-5 h-5 text-red-600 dark:text-red-400 flex-shrink-0\" />\r\n <div className=\"flex-1\">\r\n <p className=\"text-red-800 dark:text-red-200 font-medium\">{error}</p>\r\n </div>\r\n <button\r\n onClick={handleRefresh}\r\n className=\"text-red-600 dark:text-red-400 hover:text-red-800 dark:hover:text-red-200\"\r\n >\r\n <RefreshCw className=\"w-5 h-5\" />\r\n </button>\r\n </div>\r\n )}\r\n\r\n {/* Header */}\r\n <div className=\"flex items-center justify-between\">\r\n <div>\r\n <h1 className=\"text-2xl font-bold text-[var(--text-primary)] flex items-center gap-2\">\r\n <Users className=\"w-6 h-6\" />\r\n {t('admin:header.title')}\r\n </h1>\r\n <p className=\"text-[var(--text-secondary)] mt-1\">\r\n Vue d'ensemble de la gestion des utilisateurs\r\n </p>\r\n </div>\r\n <div className=\"flex items-center gap-3\">\r\n <select\r\n value={period}\r\n onChange={(e) => setPeriod(Number(e.target.value))}\r\n className=\"input\"\r\n >\r\n <option value={7}>7 derniers jours</option>\r\n <option value={30}>30 derniers jours</option>\r\n <option value={90}>90 derniers jours</option>\r\n </select>\r\n <button\r\n onClick={handleRefresh}\r\n disabled={refreshing}\r\n className=\"btn btn-secondary flex items-center gap-2\"\r\n >\r\n <RefreshCw className={`w-4 h-4 ${refreshing ? 'animate-spin' : ''}`} />\r\n Actualiser\r\n </button>\r\n </div>\r\n </div>\r\n\r\n {/* KPI Cards */}\r\n <div className=\"grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-4\">\r\n <KpiCard\r\n title=\"Total Utilisateurs\"\r\n value={overview?.totalUsers ?? 0}\r\n icon={<Users className=\"w-5 h-5\" />}\r\n color=\"blue\"\r\n />\r\n <KpiCard\r\n title=\"Actifs\"\r\n value={overview?.activeUsers ?? 0}\r\n icon={<UserCheck className=\"w-5 h-5\" />}\r\n color=\"green\"\r\n />\r\n <KpiCard\r\n title=\"Inactifs\"\r\n value={overview?.inactiveUsers ?? 0}\r\n icon={<UserX className=\"w-5 h-5\" />}\r\n color=\"red\"\r\n />\r\n <KpiCard\r\n title=\"Nouveaux\"\r\n value={overview?.newUsers ?? 0}\r\n icon={<UserPlus className=\"w-5 h-5\" />}\r\n color=\"blue\"\r\n subtitle={`${period} derniers jours`}\r\n />\r\n <KpiCard\r\n title=\"Sessions\"\r\n value={overview?.totalSessions ?? 0}\r\n icon={<Activity className=\"w-5 h-5\" />}\r\n color=\"green\"\r\n subtitle={`${period} derniers jours`}\r\n />\r\n <KpiCard\r\n title=\"Connexions Echouées\"\r\n value={overview?.failedLogins ?? 0}\r\n icon={<AlertTriangle className=\"w-5 h-5\" />}\r\n color={(overview?.failedLogins ?? 0) > 10 ? 'red' : 'yellow'}\r\n subtitle={`${period} derniers jours`}\r\n />\r\n </div>\r\n\r\n {/* Security Alerts */}\r\n {(securityAlerts?.length ?? 0) > 0 && (\r\n <div className=\"card p-4 border-l-4 border-red-500\">\r\n <h3 className=\"font-semibold text-red-600 flex items-center gap-2 mb-3\">\r\n <AlertTriangle className=\"w-5 h-5\" />\r\n Alertes Sécurité ({securityAlerts?.length ?? 0})\r\n </h3>\r\n <div className=\"space-y-2 max-h-40 overflow-y-auto\">\r\n {(securityAlerts ?? []).slice(0, 5).map((alert) => (\r\n <button\r\n type=\"button\"\r\n key={alert.userId}\r\n className=\"w-full flex items-center justify-between p-2 bg-red-50 dark:bg-red-900/20 rounded cursor-pointer hover:bg-red-100 dark:hover:bg-red-900/30 text-left\"\r\n onClick={() => navigate(`/administration/users/${alert.userId}`)}\r\n >\r\n <div>\r\n <span className=\"font-medium\">{alert.fullName}</span>\r\n <span className=\"ml-2 text-sm text-[var(--text-secondary)]\">{alert.email}</span>\r\n </div>\r\n <div className=\"flex items-center gap-2\">\r\n <span className=\"text-xs text-red-600 font-medium\">\r\n {alert.failedAttempts} échecs\r\n </span>\r\n <span className=\"text-xs text-[var(--text-secondary)]\">\r\n {alert.ipAddresses?.length ?? 0} IP(s)\r\n </span>\r\n </div>\r\n </button>\r\n ))}\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* Charts Row */}\r\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\r\n {/* Status Distribution */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <UserCheck className=\"w-5 h-5\" />\r\n Utilisateurs par Statut\r\n </h3>\r\n <div className=\"space-y-3\">\r\n {(statusData ?? []).map((item) => {\r\n const total = (statusData ?? []).reduce((sum, s) => sum + s.count, 0);\r\n const percentage = total > 0 ? (item.count / total) * 100 : 0;\r\n return (\r\n <div key={item.status} className=\"flex items-center gap-3\">\r\n <div className=\"w-24 text-sm\">{item.status === 'Active' ? 'Actifs' : 'Inactifs'}</div>\r\n <div className=\"flex-1 h-6 bg-[var(--bg-secondary)] rounded-full overflow-hidden\">\r\n <div\r\n className=\"h-full rounded-full transition-all duration-500\"\r\n style={{\r\n width: `${percentage}%`,\r\n backgroundColor: statusColors[item.status] || '#6b7280',\r\n }}\r\n />\r\n </div>\r\n <div className=\"w-20 text-right\">\r\n <span className=\"font-medium\">{item.count}</span>\r\n <span className=\"text-xs text-[var(--text-secondary)] ml-1\">\r\n ({percentage.toFixed(0)}%)\r\n </span>\r\n </div>\r\n </div>\r\n );\r\n })}\r\n </div>\r\n </div>\r\n\r\n {/* Role Distribution */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <Key className=\"w-5 h-5\" />\r\n Utilisateurs par Rôle\r\n </h3>\r\n <div className=\"space-y-3\">\r\n {(roleData?.length ?? 0) > 0 ? (\r\n (roleData ?? []).map((item, index) => {\r\n const maxCount = Math.max(...(roleData ?? []).map(r => r.count), 1);\r\n const percentage = (item.count / maxCount) * 100;\r\n const colors = ['#3b82f6', '#8b5cf6', '#22c55e', '#f59e0b', '#ef4444'];\r\n return (\r\n <div key={item.roleName} className=\"flex items-center gap-3\">\r\n <div className=\"w-32 text-sm truncate\" title={item.roleName}>{item.roleName}</div>\r\n <div className=\"flex-1 h-6 bg-[var(--bg-secondary)] rounded-full overflow-hidden\">\r\n <div\r\n className=\"h-full rounded-full transition-all duration-500\"\r\n style={{\r\n width: `${percentage}%`,\r\n backgroundColor: colors[index % colors.length],\r\n }}\r\n />\r\n </div>\r\n <div className=\"w-12 text-right font-medium\">{item.count}</div>\r\n </div>\r\n );\r\n })\r\n ) : (\r\n <div className=\"text-center py-4 text-[var(--text-secondary)]\">\r\n Aucun rôle configuré\r\n </div>\r\n )}\r\n </div>\r\n </div>\r\n </div>\r\n\r\n {/* System Stats */}\r\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\r\n {/* System Overview */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <Shield className=\"w-5 h-5\" />\r\n Configuration Système\r\n </h3>\r\n <div className=\"grid grid-cols-2 gap-4\">\r\n <div className=\"text-center p-4 bg-[var(--bg-secondary)] rounded-lg\">\r\n <div className=\"text-3xl font-bold text-purple-600\">{overview?.totalRoles ?? 0}</div>\r\n <div className=\"text-sm text-[var(--text-secondary)]\">Rôles</div>\r\n </div>\r\n <div className=\"text-center p-4 bg-[var(--bg-secondary)] rounded-lg\">\r\n <div className=\"text-3xl font-bold text-green-600\">{overview?.totalPermissions ?? 0}</div>\r\n <div className=\"text-sm text-[var(--text-secondary)]\">Permissions</div>\r\n </div>\r\n <div className=\"text-center p-4 bg-[var(--bg-secondary)] rounded-lg\">\r\n <div className=\"text-3xl font-bold text-blue-600\">{overview?.usersLoggedInRecently ?? 0}</div>\r\n <div className=\"text-sm text-[var(--text-secondary)]\">Connectés récemment</div>\r\n </div>\r\n <div className=\"text-center p-4 bg-[var(--bg-secondary)] rounded-lg\">\r\n <div className=\"text-3xl font-bold text-orange-600\">{sessionStats?.totalActiveSessions ?? 0}</div>\r\n <div className=\"text-sm text-[var(--text-secondary)]\">Sessions actives</div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n {/* Active Sessions Stats */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <Monitor className=\"w-5 h-5\" />\r\n Sessions Actives\r\n </h3>\r\n {sessionStats && ((sessionStats.byBrowser?.length ?? 0) > 0 || (sessionStats.byCountry?.length ?? 0) > 0) ? (\r\n <div className=\"grid grid-cols-2 gap-4\">\r\n <div>\r\n <h4 className=\"text-sm font-medium text-[var(--text-secondary)] mb-2\">Par Navigateur</h4>\r\n <div className=\"space-y-2\">\r\n {(sessionStats.byBrowser ?? []).map((item) => (\r\n <div key={item.browser} className=\"flex items-center justify-between text-sm\">\r\n <span>{item.browser}</span>\r\n <span className=\"font-medium\">{item.count}</span>\r\n </div>\r\n ))}\r\n </div>\r\n </div>\r\n <div>\r\n <h4 className=\"text-sm font-medium text-[var(--text-secondary)] mb-2 flex items-center gap-1\">\r\n <Globe className=\"w-4 h-4\" /> Par Pays\r\n </h4>\r\n <div className=\"space-y-2\">\r\n {(sessionStats.byCountry?.length ?? 0) > 0 ? (\r\n (sessionStats.byCountry ?? []).map((item) => (\r\n <div key={item.country} className=\"flex items-center justify-between text-sm\">\r\n <span>{item.country}</span>\r\n <span className=\"font-medium\">{item.count}</span>\r\n </div>\r\n ))\r\n ) : (\r\n <span className=\"text-[var(--text-secondary)] text-sm\">Non disponible</span>\r\n )}\r\n </div>\r\n </div>\r\n </div>\r\n ) : (\r\n <div className=\"text-center py-8 text-[var(--text-secondary)]\">\r\n Aucune session active\r\n </div>\r\n )}\r\n </div>\r\n </div>\r\n\r\n {/* Device & Engagement Metrics */}\r\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\r\n {/* Device Analytics */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <Monitor className=\"w-5 h-5\" />\r\n Appareils & Navigateurs\r\n </h3>\r\n <DeviceBreakdownChart data={deviceStats} />\r\n </div>\r\n\r\n {/* Engagement Metrics */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <Activity className=\"w-5 h-5\" />\r\n Engagement Utilisateurs\r\n </h3>\r\n <EngagementMetricsCard data={engagementMetrics} />\r\n </div>\r\n </div>\r\n\r\n {/* Trends Chart */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <TrendingUp className=\"w-5 h-5\" />\r\n Tendances ({period} derniers jours)\r\n </h3>\r\n <div className=\"h-64\">\r\n <TrendChart data={trends ?? []} />\r\n </div>\r\n </div>\r\n\r\n {/* Latest Active Sessions */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <Clock className=\"w-5 h-5\" />\r\n Dernières Sessions Actives\r\n </h3>\r\n {(latestSessions?.length ?? 0) > 0 ? (\r\n <div className=\"overflow-x-auto\">\r\n <table className=\"w-full\">\r\n <thead>\r\n <tr className=\"border-b border-[var(--border-color)]\">\r\n <th className=\"text-left p-3 font-medium\">Utilisateur</th>\r\n <th className=\"text-right p-3 font-medium\">Durée</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n {(latestSessions ?? []).map((session) => (\r\n <tr\r\n key={session.userId + session.loginAt}\r\n className=\"border-b border-[var(--border-color)] hover:bg-[var(--bg-secondary)] cursor-pointer\"\r\n onClick={() => navigate(`/administration/users/${session.userId}`)}\r\n >\r\n <td className=\"p-3 font-medium\">{session.fullName}</td>\r\n <td className=\"p-3 text-right\">\r\n <span className=\"px-2 py-1 rounded text-xs font-medium bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-400\">\r\n {session.duration}\r\n </span>\r\n </td>\r\n </tr>\r\n ))}\r\n </tbody>\r\n </table>\r\n </div>\r\n ) : (\r\n <div className=\"text-center py-8 text-[var(--text-secondary)]\">\r\n Aucune session active\r\n </div>\r\n )}\r\n </div>\r\n </div>\r\n );\r\n}\r\n\r\nfunction KpiCard({\r\n title,\r\n value,\r\n icon,\r\n color,\r\n subtitle,\r\n}: {\r\n title: string;\r\n value: string | number;\r\n icon: React.ReactNode;\r\n color: 'blue' | 'green' | 'yellow' | 'red';\r\n subtitle?: string;\r\n}) {\r\n const colorClasses = {\r\n blue: 'bg-blue-50 text-blue-600 border-blue-200 dark:bg-blue-900/20 dark:border-blue-800',\r\n green: 'bg-green-50 text-green-600 border-green-200 dark:bg-green-900/20 dark:border-green-800',\r\n yellow: 'bg-yellow-50 text-yellow-600 border-yellow-200 dark:bg-yellow-900/20 dark:border-yellow-800',\r\n red: 'bg-red-50 text-red-600 border-red-200 dark:bg-red-900/20 dark:border-red-800',\r\n };\r\n\r\n return (\r\n <div className={`card p-4 border ${colorClasses[color]}`}>\r\n <div className=\"flex items-center justify-between mb-2\">\r\n <span className=\"text-sm font-medium opacity-80\">{title}</span>\r\n {icon}\r\n </div>\r\n <div className=\"text-2xl font-bold\">{value}</div>\r\n {subtitle && <div className=\"text-xs opacity-70 mt-1\">{subtitle}</div>}\r\n </div>\r\n );\r\n}\r\n\r\nfunction TrendChart({ data }: { data: UserTrendDto[] }) {\r\n if (data.length === 0) {\r\n return (\r\n <div className=\"flex items-center justify-center h-full text-[var(--text-secondary)]\">\r\n Aucune donnée de tendance disponible\r\n </div>\r\n );\r\n }\r\n\r\n const maxValue = Math.max(...data.flatMap((d) => [d.newUsers, d.logins]), 1);\r\n\r\n return (\r\n <div className=\"flex flex-col h-full\">\r\n <div className=\"flex items-center gap-4 mb-4\">\r\n <div className=\"flex items-center gap-2\">\r\n <div className=\"w-3 h-3 rounded bg-blue-500\" />\r\n <span className=\"text-sm\">Nouveaux utilisateurs</span>\r\n </div>\r\n <div className=\"flex items-center gap-2\">\r\n <div className=\"w-3 h-3 rounded bg-green-500\" />\r\n <span className=\"text-sm\">Connexions</span>\r\n </div>\r\n </div>\r\n <div className=\"flex-1 flex items-end gap-1 overflow-x-auto pb-4\">\r\n {data.map((item) => (\r\n <div key={`${item.date}`} className=\"flex-1 min-w-[20px] flex gap-0.5\">\r\n <div\r\n className=\"flex-1 bg-blue-500 rounded-t transition-all duration-300 hover:opacity-80\"\r\n style={{\r\n height: `${(item.newUsers / maxValue) * 100}%`,\r\n minHeight: item.newUsers > 0 ? '4px' : '0',\r\n }}\r\n title={`Nouveaux: ${item.newUsers}`}\r\n />\r\n <div\r\n className=\"flex-1 bg-green-500 rounded-t transition-all duration-300 hover:opacity-80\"\r\n style={{\r\n height: `${(item.logins / maxValue) * 100}%`,\r\n minHeight: item.logins > 0 ? '4px' : '0',\r\n }}\r\n title={`Connexions: ${item.logins}`}\r\n />\r\n </div>\r\n ))}\r\n </div>\r\n <div className=\"flex justify-between text-xs text-[var(--text-secondary)] mt-2\">\r\n <span>{data[0] && new Date(data[0].date).toLocaleDateString('fr-FR')}</span>\r\n <span>{data.at(-1) && new Date(data.at(-1)!.date).toLocaleDateString('fr-FR')}</span>\r\n </div>\r\n </div>\r\n );\r\n}\r\n"],"names":["deviceIcons","jsx","Monitor","Smartphone","Tablet","deviceColors","browserColors","DeviceBreakdownChart","data","jsxs","device","index","browser","maxCount","b","percentage","sessionColors","EngagementMetricsCard","maxBucketCount","maxHourCount","h","bucket","hourData","heightPercentage","statusColors","AdminDashboardPage","useTranslation","navigate","useNavigate","currentTenant","isGlobalView","useTenant","loading","setLoading","useState","refreshing","setRefreshing","period","setPeriod","overview","setOverview","statusData","setStatusData","roleData","setRoleData","trends","setTrends","latestSessions","setLatestSessions","securityAlerts","setSecurityAlerts","sessionStats","setSessionStats","deviceStats","setDeviceStats","engagementMetrics","setEngagementMetrics","error","setError","abortControllerRef","useRef","loadData","useCallback","signal","overviewRes","statusRes","roleRes","trendsRes","latestSessionsRes","alertsRes","sessionsRes","deviceRes","engagementRes","adminApi","applicationAnalyticsApi","err","axiosError","useEffect","controller","handleRefresh","Loader2","Breadcrumb","AlertTriangle","RefreshCw","Users","e","KpiCard","UserCheck","UserX","UserPlus","Activity","alert","item","total","sum","s","Key","r","colors","Shield","Globe","TrendingUp","TrendChart","Clock","session","title","value","icon","color","subtitle","colorClasses","maxValue","d"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DashboardPage-B4nAd8Tj.js","sources":["../../src/components/dashboard/DeviceBreakdownChart.tsx","../../src/components/dashboard/EngagementMetricsCard.tsx","../../src/pages/platform/administration/DashboardPage.tsx"],"sourcesContent":["import React from 'react';\r\nimport { Monitor, Smartphone, Tablet } from 'lucide-react';\r\nimport type { DeviceAnalyticsDto } from '@/services/api/applicationAnalyticsApi';\r\n\r\ninterface DeviceBreakdownChartProps {\r\n readonly data: DeviceAnalyticsDto | null;\r\n}\r\n\r\nconst deviceIcons: Record<string, React.ReactNode> = {\r\n Desktop: <Monitor className=\"w-4 h-4\" />,\r\n Mobile: <Smartphone className=\"w-4 h-4\" />,\r\n Tablet: <Tablet className=\"w-4 h-4\" />,\r\n Unknown: <Monitor className=\"w-4 h-4 opacity-50\" />\r\n};\r\n\r\nconst deviceColors = [\r\n '#3b82f6',\r\n '#22c55e',\r\n '#f59e0b',\r\n '#6b7280'\r\n];\r\n\r\nconst browserColors = [\r\n '#3b82f6',\r\n '#8b5cf6',\r\n '#22c55e',\r\n '#f59e0b',\r\n '#ef4444'\r\n];\r\n\r\nexport const DeviceBreakdownChart: React.FC<DeviceBreakdownChartProps> = ({ data }) => {\r\n if (!data || (!data.byDeviceType?.length && !data.byBrowser?.length)) {\r\n return (\r\n <div className=\"text-center py-8 text-[var(--text-secondary)]\">\r\n No device data available\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-6\">\r\n {/* Device Type Breakdown */}\r\n <div>\r\n <h4 className=\"text-sm font-medium text-[var(--text-secondary)] mb-3\">\r\n By Device Type\r\n </h4>\r\n <div className=\"space-y-3\">\r\n {data.byDeviceType.map((device, index) => (\r\n <div key={device.deviceType} className=\"flex items-center gap-3\">\r\n <div className=\"flex items-center gap-2 w-28\">\r\n {deviceIcons[device.deviceType] || deviceIcons.Unknown}\r\n <span className=\"text-sm\">{device.deviceType}</span>\r\n </div>\r\n <div className=\"flex-1 h-6 bg-[var(--bg-secondary)] rounded-full overflow-hidden\">\r\n <div\r\n className=\"h-full rounded-full transition-all duration-500\"\r\n style={{\r\n width: `${device.percentage}%`,\r\n backgroundColor: deviceColors[index % deviceColors.length]\r\n }}\r\n />\r\n </div>\r\n <div className=\"w-20 text-right\">\r\n <span className=\"font-medium\">{device.count}</span>\r\n <span className=\"text-xs text-[var(--text-secondary)] ml-1\">\r\n ({device.percentage.toFixed(1)}%)\r\n </span>\r\n </div>\r\n </div>\r\n ))}\r\n </div>\r\n </div>\r\n\r\n {/* Browser Breakdown */}\r\n <div>\r\n <h4 className=\"text-sm font-medium text-[var(--text-secondary)] mb-3\">\r\n By Browser\r\n </h4>\r\n <div className=\"space-y-3\">\r\n {data.byBrowser.map((browser, index) => {\r\n const maxCount = Math.max(...data.byBrowser.map(b => b.count), 1);\r\n const percentage = (browser.count / maxCount) * 100;\r\n\r\n return (\r\n <div key={browser.browser} className=\"flex items-center gap-3\">\r\n <div className=\"w-24 text-sm\">{browser.browser}</div>\r\n <div className=\"flex-1 h-6 bg-[var(--bg-secondary)] rounded-full overflow-hidden\">\r\n <div\r\n className=\"h-full rounded-full transition-all duration-500\"\r\n style={{\r\n width: `${percentage}%`,\r\n backgroundColor: browserColors[index % browserColors.length]\r\n }}\r\n />\r\n </div>\r\n <div className=\"w-12 text-right font-medium\">{browser.count}</div>\r\n </div>\r\n );\r\n })}\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n};\r\n","import React from 'react';\r\nimport type { EngagementMetricsDto } from '@/services/api/applicationAnalyticsApi';\r\n\r\ninterface EngagementMetricsCardProps {\r\n readonly data: EngagementMetricsDto | null;\r\n}\r\n\r\nconst sessionColors = ['#ef4444', '#f59e0b', '#22c55e', '#3b82f6'];\r\n\r\nexport const EngagementMetricsCard: React.FC<EngagementMetricsCardProps> = ({ data }) => {\r\n if (!data) {\r\n return (\r\n <div className=\"text-center py-8 text-[var(--text-secondary)]\">\r\n No engagement data available\r\n </div>\r\n );\r\n }\r\n\r\n const maxBucketCount = Math.max(...data.sessionDistribution.map(b => b.count), 1);\r\n const maxHourCount = Math.max(...data.peakUsageHours.map(h => h.accessCount), 1);\r\n\r\n return (\r\n <div className=\"space-y-6\">\r\n {/* Session Duration Distribution */}\r\n <div>\r\n <h4 className=\"text-sm font-medium text-[var(--text-secondary)] mb-3\">\r\n Session Duration Distribution\r\n </h4>\r\n <div className=\"space-y-3\">\r\n {data.sessionDistribution.map((bucket, index) => {\r\n const percentage = (bucket.count / maxBucketCount) * 100;\r\n\r\n return (\r\n <div key={bucket.bucket} className=\"flex items-center gap-3\">\r\n <div className=\"w-20 text-sm\">{bucket.label}</div>\r\n <div className=\"flex-1 h-6 bg-[var(--bg-secondary)] rounded-full overflow-hidden\">\r\n <div\r\n className=\"h-full rounded-full transition-all duration-500\"\r\n style={{\r\n width: `${percentage}%`,\r\n backgroundColor: sessionColors[index % sessionColors.length]\r\n }}\r\n />\r\n </div>\r\n <div className=\"w-16 text-right\">\r\n <span className=\"font-medium\">{bucket.count}</span>\r\n <span className=\"text-xs text-[var(--text-secondary)] ml-1\">\r\n sessions\r\n </span>\r\n </div>\r\n </div>\r\n );\r\n })}\r\n </div>\r\n </div>\r\n\r\n {/* Peak Usage Hours */}\r\n <div>\r\n <h4 className=\"text-sm font-medium text-[var(--text-secondary)] mb-3\">\r\n Peak Usage Hours\r\n </h4>\r\n <div className=\"flex items-end gap-1 h-32 overflow-x-auto pb-2\">\r\n {data.peakUsageHours.map((hourData) => {\r\n const heightPercentage = (hourData.accessCount / maxHourCount) * 100;\r\n\r\n return (\r\n <div\r\n key={hourData.hour}\r\n className=\"flex-1 min-w-[20px] flex flex-col items-center gap-1\"\r\n >\r\n <div\r\n className=\"w-full bg-gradient-to-t from-blue-500 to-cyan-500 rounded-t transition-all duration-300 hover:opacity-80\"\r\n style={{\r\n height: `${heightPercentage}%`,\r\n minHeight: hourData.accessCount > 0 ? '4px' : '0'\r\n }}\r\n title={`${hourData.hour}h: ${hourData.accessCount} accesses`}\r\n />\r\n {hourData.hour % 3 === 0 && (\r\n <span className=\"text-xs text-[var(--text-secondary)]\">\r\n {hourData.hour}h\r\n </span>\r\n )}\r\n </div>\r\n );\r\n })}\r\n </div>\r\n </div>\r\n\r\n {/* Engagement Summary */}\r\n <div className=\"grid grid-cols-2 gap-4 pt-4 border-t border-[var(--border-color)]\">\r\n <div className=\"text-center p-3 bg-[var(--bg-secondary)] rounded-lg\">\r\n <div className=\"text-2xl font-bold text-blue-600\">\r\n {data.dailyActiveUsers}\r\n </div>\r\n <div className=\"text-xs text-[var(--text-secondary)] mt-1\">\r\n Daily Active Users\r\n </div>\r\n </div>\r\n <div className=\"text-center p-3 bg-[var(--bg-secondary)] rounded-lg\">\r\n <div className=\"text-2xl font-bold text-green-600\">\r\n {(data.retentionRate * 100).toFixed(1)}%\r\n </div>\r\n <div className=\"text-xs text-[var(--text-secondary)] mt-1\">\r\n Retention Rate\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n};\r\n","import { useState, useEffect, useCallback, useRef } from 'react';\r\nimport type { ReactElement } from 'react';\r\nimport { useNavigate } from 'react-router-dom';\r\nimport { useTranslation } from 'react-i18next';\r\nimport {\r\n Users,\r\n UserCheck,\r\n UserX,\r\n UserPlus,\r\n Activity,\r\n AlertTriangle,\r\n Key,\r\n Shield,\r\n TrendingUp,\r\n RefreshCw,\r\n Loader2,\r\n Clock,\r\n Globe,\r\n Monitor,\r\n} from 'lucide-react';\r\nimport {\r\n adminApi,\r\n type UserDashboardOverviewDto,\r\n type UserStatusCountDto,\r\n type UserRoleDistributionDto,\r\n type UserTrendDto,\r\n type SecurityAlertDto,\r\n type ActiveSessionsStatsDto,\r\n type LatestActiveSessionDto,\r\n} from '@/services/api/adminApi';\r\nimport { applicationAnalyticsApi } from '@/services/api/applicationAnalyticsApi';\r\nimport { Breadcrumb } from '@/components/ui/Breadcrumb';\r\nimport { useTenant } from '@/contexts/TenantContext';\r\nimport type { DeviceAnalyticsDto, EngagementMetricsDto } from '@/services/api/applicationAnalyticsApi';\r\nimport { DeviceBreakdownChart } from '@/components/dashboard/DeviceBreakdownChart';\r\nimport { EngagementMetricsCard } from '@/components/dashboard/EngagementMetricsCard';\r\n\r\nconst statusColors: Record<string, string> = {\r\n Active: '#22c55e',\r\n Inactive: '#ef4444',\r\n};\r\n\r\nexport function AdminDashboardPage(): ReactElement {\r\n const { t } = useTranslation(['admin', 'navigation']);\r\n const navigate = useNavigate();\r\n const { currentTenant, isGlobalView } = useTenant();\r\n const [loading, setLoading] = useState(true);\r\n const [refreshing, setRefreshing] = useState(false);\r\n const [period, setPeriod] = useState(30);\r\n\r\n const [overview, setOverview] = useState<UserDashboardOverviewDto | null>(null);\r\n const [statusData, setStatusData] = useState<UserStatusCountDto[]>([]);\r\n const [roleData, setRoleData] = useState<UserRoleDistributionDto[]>([]);\r\n const [trends, setTrends] = useState<UserTrendDto[]>([]);\r\n const [latestSessions, setLatestSessions] = useState<LatestActiveSessionDto[]>([]);\r\n const [securityAlerts, setSecurityAlerts] = useState<SecurityAlertDto[]>([]);\r\n const [sessionStats, setSessionStats] = useState<ActiveSessionsStatsDto | null>(null);\r\n const [deviceStats, setDeviceStats] = useState<DeviceAnalyticsDto | null>(null);\r\n const [engagementMetrics, setEngagementMetrics] = useState<EngagementMetricsDto | null>(null);\r\n const [error, setError] = useState<string | null>(null);\r\n\r\n // Ref to track if component is still mounted (StrictMode protection)\r\n const abortControllerRef = useRef<AbortController | null>(null);\r\n\r\n const loadData = useCallback(async (signal?: AbortSignal) => {\r\n try {\r\n setError(null);\r\n const [\r\n overviewRes,\r\n statusRes,\r\n roleRes,\r\n trendsRes,\r\n latestSessionsRes,\r\n alertsRes,\r\n sessionsRes,\r\n deviceRes,\r\n engagementRes,\r\n ] = await Promise.all([\r\n adminApi.dashboard.getOverview(period, { signal }),\r\n adminApi.dashboard.getByStatus({ signal }),\r\n adminApi.dashboard.getByRole({ signal }),\r\n adminApi.dashboard.getTrends(period, { signal }),\r\n adminApi.dashboard.getLatestActiveSessions(5, { signal }),\r\n adminApi.dashboard.getSecurityAlerts(3, 24, { signal }),\r\n adminApi.dashboard.getActiveSessions({ signal }),\r\n applicationAnalyticsApi.getDeviceStats(period, { signal }),\r\n applicationAnalyticsApi.getEngagementMetrics(period, { signal }),\r\n ]);\r\n\r\n // Only update state if request wasn't aborted\r\n if (!signal?.aborted) {\r\n setOverview(overviewRes ?? null);\r\n setStatusData(statusRes ?? []);\r\n setRoleData(roleRes ?? []);\r\n setTrends(trendsRes ?? []);\r\n setLatestSessions(latestSessionsRes ?? []);\r\n setSecurityAlerts(alertsRes ?? []);\r\n setSessionStats(sessionsRes ?? null);\r\n setDeviceStats(deviceRes ?? null);\r\n setEngagementMetrics(engagementRes ?? null);\r\n }\r\n } catch (err: unknown) {\r\n // Ignore abort errors (expected in StrictMode)\r\n if (err instanceof Error && err.name === 'CanceledError') {\r\n return;\r\n }\r\n console.error('Failed to load dashboard data:', err);\r\n const axiosError = err as { response?: { status?: number; data?: { message?: string } } };\r\n if (axiosError.response?.status === 401) {\r\n setError('Session expirée. Veuillez vous reconnecter.');\r\n } else if (axiosError.response?.status === 403) {\r\n setError('Vous n\\'avez pas les permissions nécessaires pour accéder au dashboard.');\r\n } else {\r\n setError('Erreur lors du chargement des données. Vérifiez que l\\'API est accessible.');\r\n }\r\n } finally {\r\n if (!signal?.aborted) {\r\n setLoading(false);\r\n setRefreshing(false);\r\n }\r\n }\r\n }, [period, currentTenant?.id, isGlobalView]);\r\n\r\n useEffect(() => {\r\n // Abort any previous request before starting a new one\r\n abortControllerRef.current?.abort();\r\n const controller = new AbortController();\r\n abortControllerRef.current = controller;\r\n\r\n loadData(controller.signal);\r\n\r\n // Cleanup: abort request when component unmounts or period changes\r\n return () => {\r\n controller.abort();\r\n };\r\n }, [loadData]);\r\n\r\n const handleRefresh = () => {\r\n // Abort any previous request before starting a new one\r\n abortControllerRef.current?.abort();\r\n const controller = new AbortController();\r\n abortControllerRef.current = controller;\r\n\r\n setRefreshing(true);\r\n loadData(controller.signal);\r\n };\r\n\r\n if (loading) {\r\n return (\r\n <div className=\"flex items-center justify-center min-h-[400px]\">\r\n <Loader2 className=\"w-8 h-8 animate-spin text-[var(--color-primary-600)]\" />\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div className=\"space-y-6\">\r\n {/* Breadcrumb */}\r\n <Breadcrumb\r\n items={[\r\n { label: t('header.title') },\r\n { label: t('dashboard.title') }\r\n ]}\r\n />\r\n\r\n {/* Error Banner */}\r\n {error && (\r\n <div className=\"bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg p-4 flex items-center gap-3\">\r\n <AlertTriangle className=\"w-5 h-5 text-red-600 dark:text-red-400 flex-shrink-0\" />\r\n <div className=\"flex-1\">\r\n <p className=\"text-red-800 dark:text-red-200 font-medium\">{error}</p>\r\n </div>\r\n <button\r\n onClick={handleRefresh}\r\n className=\"text-red-600 dark:text-red-400 hover:text-red-800 dark:hover:text-red-200\"\r\n >\r\n <RefreshCw className=\"w-5 h-5\" />\r\n </button>\r\n </div>\r\n )}\r\n\r\n {/* Header */}\r\n <div className=\"flex items-center justify-between\">\r\n <div>\r\n <h1 className=\"text-2xl font-bold text-[var(--text-primary)] flex items-center gap-2\">\r\n <Users className=\"w-6 h-6\" />\r\n {t('admin:header.title')}\r\n </h1>\r\n <p className=\"text-[var(--text-secondary)] mt-1\">\r\n Vue d'ensemble de la gestion des utilisateurs\r\n </p>\r\n </div>\r\n <div className=\"flex items-center gap-3\">\r\n <select\r\n value={period}\r\n onChange={(e) => setPeriod(Number(e.target.value))}\r\n className=\"input\"\r\n >\r\n <option value={7}>7 derniers jours</option>\r\n <option value={30}>30 derniers jours</option>\r\n <option value={90}>90 derniers jours</option>\r\n </select>\r\n <button\r\n onClick={handleRefresh}\r\n disabled={refreshing}\r\n className=\"btn btn-secondary flex items-center gap-2\"\r\n >\r\n <RefreshCw className={`w-4 h-4 ${refreshing ? 'animate-spin' : ''}`} />\r\n Actualiser\r\n </button>\r\n </div>\r\n </div>\r\n\r\n {/* KPI Cards */}\r\n <div className=\"grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-4\">\r\n <KpiCard\r\n title=\"Total Utilisateurs\"\r\n value={overview?.totalUsers ?? 0}\r\n icon={<Users className=\"w-5 h-5\" />}\r\n color=\"blue\"\r\n />\r\n <KpiCard\r\n title=\"Actifs\"\r\n value={overview?.activeUsers ?? 0}\r\n icon={<UserCheck className=\"w-5 h-5\" />}\r\n color=\"green\"\r\n />\r\n <KpiCard\r\n title=\"Inactifs\"\r\n value={overview?.inactiveUsers ?? 0}\r\n icon={<UserX className=\"w-5 h-5\" />}\r\n color=\"red\"\r\n />\r\n <KpiCard\r\n title=\"Nouveaux\"\r\n value={overview?.newUsers ?? 0}\r\n icon={<UserPlus className=\"w-5 h-5\" />}\r\n color=\"blue\"\r\n subtitle={`${period} derniers jours`}\r\n />\r\n <KpiCard\r\n title=\"Sessions\"\r\n value={overview?.totalSessions ?? 0}\r\n icon={<Activity className=\"w-5 h-5\" />}\r\n color=\"green\"\r\n subtitle={`${period} derniers jours`}\r\n />\r\n <KpiCard\r\n title=\"Connexions Echouées\"\r\n value={overview?.failedLogins ?? 0}\r\n icon={<AlertTriangle className=\"w-5 h-5\" />}\r\n color={(overview?.failedLogins ?? 0) > 10 ? 'red' : 'yellow'}\r\n subtitle={`${period} derniers jours`}\r\n />\r\n </div>\r\n\r\n {/* Security Alerts */}\r\n {(securityAlerts?.length ?? 0) > 0 && (\r\n <div className=\"card p-4 border-l-4 border-red-500\">\r\n <h3 className=\"font-semibold text-red-600 flex items-center gap-2 mb-3\">\r\n <AlertTriangle className=\"w-5 h-5\" />\r\n Alertes Sécurité ({securityAlerts?.length ?? 0})\r\n </h3>\r\n <div className=\"space-y-2 max-h-40 overflow-y-auto\">\r\n {(securityAlerts ?? []).slice(0, 5).map((alert) => (\r\n <button\r\n type=\"button\"\r\n key={alert.userId}\r\n className=\"w-full flex items-center justify-between p-2 bg-red-50 dark:bg-red-900/20 rounded cursor-pointer hover:bg-red-100 dark:hover:bg-red-900/30 text-left\"\r\n onClick={() => navigate(`/administration/users/${alert.userId}`)}\r\n >\r\n <div>\r\n <span className=\"font-medium\">{alert.fullName}</span>\r\n <span className=\"ml-2 text-sm text-[var(--text-secondary)]\">{alert.email}</span>\r\n </div>\r\n <div className=\"flex items-center gap-2\">\r\n <span className=\"text-xs text-red-600 font-medium\">\r\n {alert.failedAttempts} échecs\r\n </span>\r\n <span className=\"text-xs text-[var(--text-secondary)]\">\r\n {alert.ipAddresses?.length ?? 0} IP(s)\r\n </span>\r\n </div>\r\n </button>\r\n ))}\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* Charts Row */}\r\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\r\n {/* Status Distribution */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <UserCheck className=\"w-5 h-5\" />\r\n Utilisateurs par Statut\r\n </h3>\r\n <div className=\"space-y-3\">\r\n {(statusData ?? []).map((item) => {\r\n const total = (statusData ?? []).reduce((sum, s) => sum + s.count, 0);\r\n const percentage = total > 0 ? (item.count / total) * 100 : 0;\r\n return (\r\n <div key={item.status} className=\"flex items-center gap-3\">\r\n <div className=\"w-24 text-sm\">{item.status === 'Active' ? 'Actifs' : 'Inactifs'}</div>\r\n <div className=\"flex-1 h-6 bg-[var(--bg-secondary)] rounded-full overflow-hidden\">\r\n <div\r\n className=\"h-full rounded-full transition-all duration-500\"\r\n style={{\r\n width: `${percentage}%`,\r\n backgroundColor: statusColors[item.status] || '#6b7280',\r\n }}\r\n />\r\n </div>\r\n <div className=\"w-20 text-right\">\r\n <span className=\"font-medium\">{item.count}</span>\r\n <span className=\"text-xs text-[var(--text-secondary)] ml-1\">\r\n ({percentage.toFixed(0)}%)\r\n </span>\r\n </div>\r\n </div>\r\n );\r\n })}\r\n </div>\r\n </div>\r\n\r\n {/* Role Distribution */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <Key className=\"w-5 h-5\" />\r\n Utilisateurs par Rôle\r\n </h3>\r\n <div className=\"space-y-3\">\r\n {(roleData?.length ?? 0) > 0 ? (\r\n (roleData ?? []).map((item, index) => {\r\n const maxCount = Math.max(...(roleData ?? []).map(r => r.count), 1);\r\n const percentage = (item.count / maxCount) * 100;\r\n const colors = ['#3b82f6', '#8b5cf6', '#22c55e', '#f59e0b', '#ef4444'];\r\n return (\r\n <div key={item.roleName} className=\"flex items-center gap-3\">\r\n <div className=\"w-32 text-sm truncate\" title={item.roleName}>{item.roleName}</div>\r\n <div className=\"flex-1 h-6 bg-[var(--bg-secondary)] rounded-full overflow-hidden\">\r\n <div\r\n className=\"h-full rounded-full transition-all duration-500\"\r\n style={{\r\n width: `${percentage}%`,\r\n backgroundColor: colors[index % colors.length],\r\n }}\r\n />\r\n </div>\r\n <div className=\"w-12 text-right font-medium\">{item.count}</div>\r\n </div>\r\n );\r\n })\r\n ) : (\r\n <div className=\"text-center py-4 text-[var(--text-secondary)]\">\r\n Aucun rôle configuré\r\n </div>\r\n )}\r\n </div>\r\n </div>\r\n </div>\r\n\r\n {/* System Stats */}\r\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\r\n {/* System Overview */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <Shield className=\"w-5 h-5\" />\r\n Configuration Système\r\n </h3>\r\n <div className=\"grid grid-cols-2 gap-4\">\r\n <div className=\"text-center p-4 bg-[var(--bg-secondary)] rounded-lg\">\r\n <div className=\"text-3xl font-bold text-purple-600\">{overview?.totalRoles ?? 0}</div>\r\n <div className=\"text-sm text-[var(--text-secondary)]\">Rôles</div>\r\n </div>\r\n <div className=\"text-center p-4 bg-[var(--bg-secondary)] rounded-lg\">\r\n <div className=\"text-3xl font-bold text-green-600\">{overview?.totalPermissions ?? 0}</div>\r\n <div className=\"text-sm text-[var(--text-secondary)]\">Permissions</div>\r\n </div>\r\n <div className=\"text-center p-4 bg-[var(--bg-secondary)] rounded-lg\">\r\n <div className=\"text-3xl font-bold text-blue-600\">{overview?.usersLoggedInRecently ?? 0}</div>\r\n <div className=\"text-sm text-[var(--text-secondary)]\">Connectés récemment</div>\r\n </div>\r\n <div className=\"text-center p-4 bg-[var(--bg-secondary)] rounded-lg\">\r\n <div className=\"text-3xl font-bold text-orange-600\">{sessionStats?.totalActiveSessions ?? 0}</div>\r\n <div className=\"text-sm text-[var(--text-secondary)]\">Sessions actives</div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n {/* Active Sessions Stats */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <Monitor className=\"w-5 h-5\" />\r\n Sessions Actives\r\n </h3>\r\n {sessionStats && ((sessionStats.byBrowser?.length ?? 0) > 0 || (sessionStats.byCountry?.length ?? 0) > 0) ? (\r\n <div className=\"grid grid-cols-2 gap-4\">\r\n <div>\r\n <h4 className=\"text-sm font-medium text-[var(--text-secondary)] mb-2\">Par Navigateur</h4>\r\n <div className=\"space-y-2\">\r\n {(sessionStats.byBrowser ?? []).map((item) => (\r\n <div key={item.browser} className=\"flex items-center justify-between text-sm\">\r\n <span>{item.browser}</span>\r\n <span className=\"font-medium\">{item.count}</span>\r\n </div>\r\n ))}\r\n </div>\r\n </div>\r\n <div>\r\n <h4 className=\"text-sm font-medium text-[var(--text-secondary)] mb-2 flex items-center gap-1\">\r\n <Globe className=\"w-4 h-4\" /> Par Pays\r\n </h4>\r\n <div className=\"space-y-2\">\r\n {(sessionStats.byCountry?.length ?? 0) > 0 ? (\r\n (sessionStats.byCountry ?? []).map((item) => (\r\n <div key={item.country} className=\"flex items-center justify-between text-sm\">\r\n <span>{item.country}</span>\r\n <span className=\"font-medium\">{item.count}</span>\r\n </div>\r\n ))\r\n ) : (\r\n <span className=\"text-[var(--text-secondary)] text-sm\">Non disponible</span>\r\n )}\r\n </div>\r\n </div>\r\n </div>\r\n ) : (\r\n <div className=\"text-center py-8 text-[var(--text-secondary)]\">\r\n Aucune session active\r\n </div>\r\n )}\r\n </div>\r\n </div>\r\n\r\n {/* Device & Engagement Metrics */}\r\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\r\n {/* Device Analytics */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <Monitor className=\"w-5 h-5\" />\r\n Appareils & Navigateurs\r\n </h3>\r\n <DeviceBreakdownChart data={deviceStats} />\r\n </div>\r\n\r\n {/* Engagement Metrics */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <Activity className=\"w-5 h-5\" />\r\n Engagement Utilisateurs\r\n </h3>\r\n <EngagementMetricsCard data={engagementMetrics} />\r\n </div>\r\n </div>\r\n\r\n {/* Trends Chart */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <TrendingUp className=\"w-5 h-5\" />\r\n Tendances ({period} derniers jours)\r\n </h3>\r\n <div className=\"h-64\">\r\n <TrendChart data={trends ?? []} />\r\n </div>\r\n </div>\r\n\r\n {/* Latest Active Sessions */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <Clock className=\"w-5 h-5\" />\r\n Dernières Sessions Actives\r\n </h3>\r\n {(latestSessions?.length ?? 0) > 0 ? (\r\n <div className=\"overflow-x-auto\">\r\n <table className=\"w-full\">\r\n <thead>\r\n <tr className=\"border-b border-[var(--border-color)]\">\r\n <th className=\"text-left p-3 font-medium\">Utilisateur</th>\r\n <th className=\"text-right p-3 font-medium\">Durée</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n {(latestSessions ?? []).map((session) => (\r\n <tr\r\n key={session.userId + session.loginAt}\r\n className=\"border-b border-[var(--border-color)] hover:bg-[var(--bg-secondary)] cursor-pointer\"\r\n onClick={() => navigate(`/administration/users/${session.userId}`)}\r\n >\r\n <td className=\"p-3 font-medium\">{session.fullName}</td>\r\n <td className=\"p-3 text-right\">\r\n <span className=\"px-2 py-1 rounded text-xs font-medium bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-400\">\r\n {session.duration}\r\n </span>\r\n </td>\r\n </tr>\r\n ))}\r\n </tbody>\r\n </table>\r\n </div>\r\n ) : (\r\n <div className=\"text-center py-8 text-[var(--text-secondary)]\">\r\n Aucune session active\r\n </div>\r\n )}\r\n </div>\r\n </div>\r\n );\r\n}\r\n\r\nfunction KpiCard({\r\n title,\r\n value,\r\n icon,\r\n color,\r\n subtitle,\r\n}: {\r\n title: string;\r\n value: string | number;\r\n icon: React.ReactNode;\r\n color: 'blue' | 'green' | 'yellow' | 'red';\r\n subtitle?: string;\r\n}) {\r\n const colorClasses = {\r\n blue: 'bg-blue-50 text-blue-600 border-blue-200 dark:bg-blue-900/20 dark:border-blue-800',\r\n green: 'bg-green-50 text-green-600 border-green-200 dark:bg-green-900/20 dark:border-green-800',\r\n yellow: 'bg-yellow-50 text-yellow-600 border-yellow-200 dark:bg-yellow-900/20 dark:border-yellow-800',\r\n red: 'bg-red-50 text-red-600 border-red-200 dark:bg-red-900/20 dark:border-red-800',\r\n };\r\n\r\n return (\r\n <div className={`card p-4 border ${colorClasses[color]}`}>\r\n <div className=\"flex items-center justify-between mb-2\">\r\n <span className=\"text-sm font-medium opacity-80\">{title}</span>\r\n {icon}\r\n </div>\r\n <div className=\"text-2xl font-bold\">{value}</div>\r\n {subtitle && <div className=\"text-xs opacity-70 mt-1\">{subtitle}</div>}\r\n </div>\r\n );\r\n}\r\n\r\nfunction TrendChart({ data }: { data: UserTrendDto[] }) {\r\n if (data.length === 0) {\r\n return (\r\n <div className=\"flex items-center justify-center h-full text-[var(--text-secondary)]\">\r\n Aucune donnée de tendance disponible\r\n </div>\r\n );\r\n }\r\n\r\n const maxValue = Math.max(...data.flatMap((d) => [d.newUsers, d.logins]), 1);\r\n\r\n return (\r\n <div className=\"flex flex-col h-full\">\r\n <div className=\"flex items-center gap-4 mb-4\">\r\n <div className=\"flex items-center gap-2\">\r\n <div className=\"w-3 h-3 rounded bg-blue-500\" />\r\n <span className=\"text-sm\">Nouveaux utilisateurs</span>\r\n </div>\r\n <div className=\"flex items-center gap-2\">\r\n <div className=\"w-3 h-3 rounded bg-green-500\" />\r\n <span className=\"text-sm\">Connexions</span>\r\n </div>\r\n </div>\r\n <div className=\"flex-1 flex items-end gap-1 overflow-x-auto pb-4\">\r\n {data.map((item) => (\r\n <div key={`${item.date}`} className=\"flex-1 min-w-[20px] flex gap-0.5\">\r\n <div\r\n className=\"flex-1 bg-blue-500 rounded-t transition-all duration-300 hover:opacity-80\"\r\n style={{\r\n height: `${(item.newUsers / maxValue) * 100}%`,\r\n minHeight: item.newUsers > 0 ? '4px' : '0',\r\n }}\r\n title={`Nouveaux: ${item.newUsers}`}\r\n />\r\n <div\r\n className=\"flex-1 bg-green-500 rounded-t transition-all duration-300 hover:opacity-80\"\r\n style={{\r\n height: `${(item.logins / maxValue) * 100}%`,\r\n minHeight: item.logins > 0 ? '4px' : '0',\r\n }}\r\n title={`Connexions: ${item.logins}`}\r\n />\r\n </div>\r\n ))}\r\n </div>\r\n <div className=\"flex justify-between text-xs text-[var(--text-secondary)] mt-2\">\r\n <span>{data[0] && new Date(data[0].date).toLocaleDateString('fr-FR')}</span>\r\n <span>{data.at(-1) && new Date(data.at(-1)!.date).toLocaleDateString('fr-FR')}</span>\r\n </div>\r\n </div>\r\n );\r\n}\r\n"],"names":["deviceIcons","jsx","Monitor","Smartphone","Tablet","deviceColors","browserColors","DeviceBreakdownChart","data","jsxs","device","index","browser","maxCount","b","percentage","sessionColors","EngagementMetricsCard","maxBucketCount","maxHourCount","h","bucket","hourData","heightPercentage","statusColors","AdminDashboardPage","useTranslation","navigate","useNavigate","currentTenant","isGlobalView","useTenant","loading","setLoading","useState","refreshing","setRefreshing","period","setPeriod","overview","setOverview","statusData","setStatusData","roleData","setRoleData","trends","setTrends","latestSessions","setLatestSessions","securityAlerts","setSecurityAlerts","sessionStats","setSessionStats","deviceStats","setDeviceStats","engagementMetrics","setEngagementMetrics","error","setError","abortControllerRef","useRef","loadData","useCallback","signal","overviewRes","statusRes","roleRes","trendsRes","latestSessionsRes","alertsRes","sessionsRes","deviceRes","engagementRes","adminApi","applicationAnalyticsApi","err","axiosError","useEffect","controller","handleRefresh","Loader2","Breadcrumb","AlertTriangle","RefreshCw","Users","e","KpiCard","UserCheck","UserX","UserPlus","Activity","alert","item","total","sum","s","Key","r","colors","Shield","Globe","TrendingUp","TrendChart","Clock","session","title","value","icon","color","subtitle","colorClasses","maxValue","d"],"mappings":"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"}
|
|
@@ -3,8 +3,8 @@ import { useState as c, useRef as le, useCallback as ne, useEffect as ce } from
|
|
|
3
3
|
import { useNavigate as ie } from "react-router-dom";
|
|
4
4
|
import { useTranslation as de } from "react-i18next";
|
|
5
5
|
import { Monitor as y, Tablet as oe, Smartphone as me, Loader2 as he, AlertTriangle as S, RefreshCw as B, Users as P, UserCheck as M, UserX as ue, UserPlus as xe, Activity as E, Key as ve, Shield as ge, Globe as be, TrendingUp as Ne, Clock as fe } from "lucide-react";
|
|
6
|
-
import { a as pe, k as x, B as ye } from "./index-
|
|
7
|
-
import { a as I } from "./applicationAnalyticsApi-
|
|
6
|
+
import { a as pe, k as x, B as ye } from "./index-CpY95_ro.js";
|
|
7
|
+
import { a as I } from "./applicationAnalyticsApi-DKMmDvWk.js";
|
|
8
8
|
const L = {
|
|
9
9
|
Desktop: /* @__PURE__ */ e(y, { className: "w-4 h-4" }),
|
|
10
10
|
Mobile: /* @__PURE__ */ e(me, { className: "w-4 h-4" }),
|
|
@@ -569,4 +569,4 @@ function Ae({ data: a }) {
|
|
|
569
569
|
export {
|
|
570
570
|
Be as AdminDashboardPage
|
|
571
571
|
};
|
|
572
|
-
//# sourceMappingURL=DashboardPage-
|
|
572
|
+
//# sourceMappingURL=DashboardPage-C9qgPBS-.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DashboardPage-D5MRMxEV.js","sources":["../../src/components/dashboard/DeviceBreakdownChart.tsx","../../src/components/dashboard/EngagementMetricsCard.tsx","../../src/pages/platform/administration/DashboardPage.tsx"],"sourcesContent":["import React from 'react';\r\nimport { Monitor, Smartphone, Tablet } from 'lucide-react';\r\nimport type { DeviceAnalyticsDto } from '@/services/api/applicationAnalyticsApi';\r\n\r\ninterface DeviceBreakdownChartProps {\r\n readonly data: DeviceAnalyticsDto | null;\r\n}\r\n\r\nconst deviceIcons: Record<string, React.ReactNode> = {\r\n Desktop: <Monitor className=\"w-4 h-4\" />,\r\n Mobile: <Smartphone className=\"w-4 h-4\" />,\r\n Tablet: <Tablet className=\"w-4 h-4\" />,\r\n Unknown: <Monitor className=\"w-4 h-4 opacity-50\" />\r\n};\r\n\r\nconst deviceColors = [\r\n '#3b82f6',\r\n '#22c55e',\r\n '#f59e0b',\r\n '#6b7280'\r\n];\r\n\r\nconst browserColors = [\r\n '#3b82f6',\r\n '#8b5cf6',\r\n '#22c55e',\r\n '#f59e0b',\r\n '#ef4444'\r\n];\r\n\r\nexport const DeviceBreakdownChart: React.FC<DeviceBreakdownChartProps> = ({ data }) => {\r\n if (!data || (!data.byDeviceType?.length && !data.byBrowser?.length)) {\r\n return (\r\n <div className=\"text-center py-8 text-[var(--text-secondary)]\">\r\n No device data available\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-6\">\r\n {/* Device Type Breakdown */}\r\n <div>\r\n <h4 className=\"text-sm font-medium text-[var(--text-secondary)] mb-3\">\r\n By Device Type\r\n </h4>\r\n <div className=\"space-y-3\">\r\n {data.byDeviceType.map((device, index) => (\r\n <div key={device.deviceType} className=\"flex items-center gap-3\">\r\n <div className=\"flex items-center gap-2 w-28\">\r\n {deviceIcons[device.deviceType] || deviceIcons.Unknown}\r\n <span className=\"text-sm\">{device.deviceType}</span>\r\n </div>\r\n <div className=\"flex-1 h-6 bg-[var(--bg-secondary)] rounded-full overflow-hidden\">\r\n <div\r\n className=\"h-full rounded-full transition-all duration-500\"\r\n style={{\r\n width: `${device.percentage}%`,\r\n backgroundColor: deviceColors[index % deviceColors.length]\r\n }}\r\n />\r\n </div>\r\n <div className=\"w-20 text-right\">\r\n <span className=\"font-medium\">{device.count}</span>\r\n <span className=\"text-xs text-[var(--text-secondary)] ml-1\">\r\n ({device.percentage.toFixed(1)}%)\r\n </span>\r\n </div>\r\n </div>\r\n ))}\r\n </div>\r\n </div>\r\n\r\n {/* Browser Breakdown */}\r\n <div>\r\n <h4 className=\"text-sm font-medium text-[var(--text-secondary)] mb-3\">\r\n By Browser\r\n </h4>\r\n <div className=\"space-y-3\">\r\n {data.byBrowser.map((browser, index) => {\r\n const maxCount = Math.max(...data.byBrowser.map(b => b.count), 1);\r\n const percentage = (browser.count / maxCount) * 100;\r\n\r\n return (\r\n <div key={browser.browser} className=\"flex items-center gap-3\">\r\n <div className=\"w-24 text-sm\">{browser.browser}</div>\r\n <div className=\"flex-1 h-6 bg-[var(--bg-secondary)] rounded-full overflow-hidden\">\r\n <div\r\n className=\"h-full rounded-full transition-all duration-500\"\r\n style={{\r\n width: `${percentage}%`,\r\n backgroundColor: browserColors[index % browserColors.length]\r\n }}\r\n />\r\n </div>\r\n <div className=\"w-12 text-right font-medium\">{browser.count}</div>\r\n </div>\r\n );\r\n })}\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n};\r\n","import React from 'react';\r\nimport type { EngagementMetricsDto } from '@/services/api/applicationAnalyticsApi';\r\n\r\ninterface EngagementMetricsCardProps {\r\n readonly data: EngagementMetricsDto | null;\r\n}\r\n\r\nconst sessionColors = ['#ef4444', '#f59e0b', '#22c55e', '#3b82f6'];\r\n\r\nexport const EngagementMetricsCard: React.FC<EngagementMetricsCardProps> = ({ data }) => {\r\n if (!data) {\r\n return (\r\n <div className=\"text-center py-8 text-[var(--text-secondary)]\">\r\n No engagement data available\r\n </div>\r\n );\r\n }\r\n\r\n const maxBucketCount = Math.max(...data.sessionDistribution.map(b => b.count), 1);\r\n const maxHourCount = Math.max(...data.peakUsageHours.map(h => h.accessCount), 1);\r\n\r\n return (\r\n <div className=\"space-y-6\">\r\n {/* Session Duration Distribution */}\r\n <div>\r\n <h4 className=\"text-sm font-medium text-[var(--text-secondary)] mb-3\">\r\n Session Duration Distribution\r\n </h4>\r\n <div className=\"space-y-3\">\r\n {data.sessionDistribution.map((bucket, index) => {\r\n const percentage = (bucket.count / maxBucketCount) * 100;\r\n\r\n return (\r\n <div key={bucket.bucket} className=\"flex items-center gap-3\">\r\n <div className=\"w-20 text-sm\">{bucket.label}</div>\r\n <div className=\"flex-1 h-6 bg-[var(--bg-secondary)] rounded-full overflow-hidden\">\r\n <div\r\n className=\"h-full rounded-full transition-all duration-500\"\r\n style={{\r\n width: `${percentage}%`,\r\n backgroundColor: sessionColors[index % sessionColors.length]\r\n }}\r\n />\r\n </div>\r\n <div className=\"w-16 text-right\">\r\n <span className=\"font-medium\">{bucket.count}</span>\r\n <span className=\"text-xs text-[var(--text-secondary)] ml-1\">\r\n sessions\r\n </span>\r\n </div>\r\n </div>\r\n );\r\n })}\r\n </div>\r\n </div>\r\n\r\n {/* Peak Usage Hours */}\r\n <div>\r\n <h4 className=\"text-sm font-medium text-[var(--text-secondary)] mb-3\">\r\n Peak Usage Hours\r\n </h4>\r\n <div className=\"flex items-end gap-1 h-32 overflow-x-auto pb-2\">\r\n {data.peakUsageHours.map((hourData) => {\r\n const heightPercentage = (hourData.accessCount / maxHourCount) * 100;\r\n\r\n return (\r\n <div\r\n key={hourData.hour}\r\n className=\"flex-1 min-w-[20px] flex flex-col items-center gap-1\"\r\n >\r\n <div\r\n className=\"w-full bg-gradient-to-t from-blue-500 to-cyan-500 rounded-t transition-all duration-300 hover:opacity-80\"\r\n style={{\r\n height: `${heightPercentage}%`,\r\n minHeight: hourData.accessCount > 0 ? '4px' : '0'\r\n }}\r\n title={`${hourData.hour}h: ${hourData.accessCount} accesses`}\r\n />\r\n {hourData.hour % 3 === 0 && (\r\n <span className=\"text-xs text-[var(--text-secondary)]\">\r\n {hourData.hour}h\r\n </span>\r\n )}\r\n </div>\r\n );\r\n })}\r\n </div>\r\n </div>\r\n\r\n {/* Engagement Summary */}\r\n <div className=\"grid grid-cols-2 gap-4 pt-4 border-t border-[var(--border-color)]\">\r\n <div className=\"text-center p-3 bg-[var(--bg-secondary)] rounded-lg\">\r\n <div className=\"text-2xl font-bold text-blue-600\">\r\n {data.dailyActiveUsers}\r\n </div>\r\n <div className=\"text-xs text-[var(--text-secondary)] mt-1\">\r\n Daily Active Users\r\n </div>\r\n </div>\r\n <div className=\"text-center p-3 bg-[var(--bg-secondary)] rounded-lg\">\r\n <div className=\"text-2xl font-bold text-green-600\">\r\n {(data.retentionRate * 100).toFixed(1)}%\r\n </div>\r\n <div className=\"text-xs text-[var(--text-secondary)] mt-1\">\r\n Retention Rate\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n};\r\n","import { useState, useEffect, useCallback, useRef } from 'react';\r\nimport type { ReactElement } from 'react';\r\nimport { useNavigate } from 'react-router-dom';\r\nimport { useTranslation } from 'react-i18next';\r\nimport {\r\n Users,\r\n UserCheck,\r\n UserX,\r\n UserPlus,\r\n Activity,\r\n AlertTriangle,\r\n Key,\r\n Shield,\r\n TrendingUp,\r\n RefreshCw,\r\n Loader2,\r\n Clock,\r\n Globe,\r\n Monitor,\r\n} from 'lucide-react';\r\nimport {\r\n adminApi,\r\n type UserDashboardOverviewDto,\r\n type UserStatusCountDto,\r\n type UserRoleDistributionDto,\r\n type UserTrendDto,\r\n type SecurityAlertDto,\r\n type ActiveSessionsStatsDto,\r\n type LatestActiveSessionDto,\r\n} from '@/services/api/adminApi';\r\nimport { applicationAnalyticsApi } from '@/services/api/applicationAnalyticsApi';\r\nimport { Breadcrumb } from '@/components/ui/Breadcrumb';\r\nimport { useTenant } from '@/contexts/TenantContext';\r\nimport type { DeviceAnalyticsDto, EngagementMetricsDto } from '@/services/api/applicationAnalyticsApi';\r\nimport { DeviceBreakdownChart } from '@/components/dashboard/DeviceBreakdownChart';\r\nimport { EngagementMetricsCard } from '@/components/dashboard/EngagementMetricsCard';\r\n\r\nconst statusColors: Record<string, string> = {\r\n Active: '#22c55e',\r\n Inactive: '#ef4444',\r\n};\r\n\r\nexport function AdminDashboardPage(): ReactElement {\r\n const { t } = useTranslation(['admin', 'navigation']);\r\n const navigate = useNavigate();\r\n const { currentTenant, isGlobalView } = useTenant();\r\n const [loading, setLoading] = useState(true);\r\n const [refreshing, setRefreshing] = useState(false);\r\n const [period, setPeriod] = useState(30);\r\n\r\n const [overview, setOverview] = useState<UserDashboardOverviewDto | null>(null);\r\n const [statusData, setStatusData] = useState<UserStatusCountDto[]>([]);\r\n const [roleData, setRoleData] = useState<UserRoleDistributionDto[]>([]);\r\n const [trends, setTrends] = useState<UserTrendDto[]>([]);\r\n const [latestSessions, setLatestSessions] = useState<LatestActiveSessionDto[]>([]);\r\n const [securityAlerts, setSecurityAlerts] = useState<SecurityAlertDto[]>([]);\r\n const [sessionStats, setSessionStats] = useState<ActiveSessionsStatsDto | null>(null);\r\n const [deviceStats, setDeviceStats] = useState<DeviceAnalyticsDto | null>(null);\r\n const [engagementMetrics, setEngagementMetrics] = useState<EngagementMetricsDto | null>(null);\r\n const [error, setError] = useState<string | null>(null);\r\n\r\n // Ref to track if component is still mounted (StrictMode protection)\r\n const abortControllerRef = useRef<AbortController | null>(null);\r\n\r\n const loadData = useCallback(async (signal?: AbortSignal) => {\r\n try {\r\n setError(null);\r\n const [\r\n overviewRes,\r\n statusRes,\r\n roleRes,\r\n trendsRes,\r\n latestSessionsRes,\r\n alertsRes,\r\n sessionsRes,\r\n deviceRes,\r\n engagementRes,\r\n ] = await Promise.all([\r\n adminApi.dashboard.getOverview(period, { signal }),\r\n adminApi.dashboard.getByStatus({ signal }),\r\n adminApi.dashboard.getByRole({ signal }),\r\n adminApi.dashboard.getTrends(period, { signal }),\r\n adminApi.dashboard.getLatestActiveSessions(5, { signal }),\r\n adminApi.dashboard.getSecurityAlerts(3, 24, { signal }),\r\n adminApi.dashboard.getActiveSessions({ signal }),\r\n applicationAnalyticsApi.getDeviceStats(period, { signal }),\r\n applicationAnalyticsApi.getEngagementMetrics(period, { signal }),\r\n ]);\r\n\r\n // Only update state if request wasn't aborted\r\n if (!signal?.aborted) {\r\n setOverview(overviewRes ?? null);\r\n setStatusData(statusRes ?? []);\r\n setRoleData(roleRes ?? []);\r\n setTrends(trendsRes ?? []);\r\n setLatestSessions(latestSessionsRes ?? []);\r\n setSecurityAlerts(alertsRes ?? []);\r\n setSessionStats(sessionsRes ?? null);\r\n setDeviceStats(deviceRes ?? null);\r\n setEngagementMetrics(engagementRes ?? null);\r\n }\r\n } catch (err: unknown) {\r\n // Ignore abort errors (expected in StrictMode)\r\n if (err instanceof Error && err.name === 'CanceledError') {\r\n return;\r\n }\r\n console.error('Failed to load dashboard data:', err);\r\n const axiosError = err as { response?: { status?: number; data?: { message?: string } } };\r\n if (axiosError.response?.status === 401) {\r\n setError('Session expirée. Veuillez vous reconnecter.');\r\n } else if (axiosError.response?.status === 403) {\r\n setError('Vous n\\'avez pas les permissions nécessaires pour accéder au dashboard.');\r\n } else {\r\n setError('Erreur lors du chargement des données. Vérifiez que l\\'API est accessible.');\r\n }\r\n } finally {\r\n if (!signal?.aborted) {\r\n setLoading(false);\r\n setRefreshing(false);\r\n }\r\n }\r\n }, [period, currentTenant?.id, isGlobalView]);\r\n\r\n useEffect(() => {\r\n // Abort any previous request before starting a new one\r\n abortControllerRef.current?.abort();\r\n const controller = new AbortController();\r\n abortControllerRef.current = controller;\r\n\r\n loadData(controller.signal);\r\n\r\n // Cleanup: abort request when component unmounts or period changes\r\n return () => {\r\n controller.abort();\r\n };\r\n }, [loadData]);\r\n\r\n const handleRefresh = () => {\r\n // Abort any previous request before starting a new one\r\n abortControllerRef.current?.abort();\r\n const controller = new AbortController();\r\n abortControllerRef.current = controller;\r\n\r\n setRefreshing(true);\r\n loadData(controller.signal);\r\n };\r\n\r\n if (loading) {\r\n return (\r\n <div className=\"flex items-center justify-center min-h-[400px]\">\r\n <Loader2 className=\"w-8 h-8 animate-spin text-[var(--color-primary-600)]\" />\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div className=\"space-y-6\">\r\n {/* Breadcrumb */}\r\n <Breadcrumb\r\n items={[\r\n { label: t('header.title') },\r\n { label: t('dashboard.title') }\r\n ]}\r\n />\r\n\r\n {/* Error Banner */}\r\n {error && (\r\n <div className=\"bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg p-4 flex items-center gap-3\">\r\n <AlertTriangle className=\"w-5 h-5 text-red-600 dark:text-red-400 flex-shrink-0\" />\r\n <div className=\"flex-1\">\r\n <p className=\"text-red-800 dark:text-red-200 font-medium\">{error}</p>\r\n </div>\r\n <button\r\n onClick={handleRefresh}\r\n className=\"text-red-600 dark:text-red-400 hover:text-red-800 dark:hover:text-red-200\"\r\n >\r\n <RefreshCw className=\"w-5 h-5\" />\r\n </button>\r\n </div>\r\n )}\r\n\r\n {/* Header */}\r\n <div className=\"flex items-center justify-between\">\r\n <div>\r\n <h1 className=\"text-2xl font-bold text-[var(--text-primary)] flex items-center gap-2\">\r\n <Users className=\"w-6 h-6\" />\r\n {t('admin:header.title')}\r\n </h1>\r\n <p className=\"text-[var(--text-secondary)] mt-1\">\r\n Vue d'ensemble de la gestion des utilisateurs\r\n </p>\r\n </div>\r\n <div className=\"flex items-center gap-3\">\r\n <select\r\n value={period}\r\n onChange={(e) => setPeriod(Number(e.target.value))}\r\n className=\"input\"\r\n >\r\n <option value={7}>7 derniers jours</option>\r\n <option value={30}>30 derniers jours</option>\r\n <option value={90}>90 derniers jours</option>\r\n </select>\r\n <button\r\n onClick={handleRefresh}\r\n disabled={refreshing}\r\n className=\"btn btn-secondary flex items-center gap-2\"\r\n >\r\n <RefreshCw className={`w-4 h-4 ${refreshing ? 'animate-spin' : ''}`} />\r\n Actualiser\r\n </button>\r\n </div>\r\n </div>\r\n\r\n {/* KPI Cards */}\r\n <div className=\"grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-4\">\r\n <KpiCard\r\n title=\"Total Utilisateurs\"\r\n value={overview?.totalUsers ?? 0}\r\n icon={<Users className=\"w-5 h-5\" />}\r\n color=\"blue\"\r\n />\r\n <KpiCard\r\n title=\"Actifs\"\r\n value={overview?.activeUsers ?? 0}\r\n icon={<UserCheck className=\"w-5 h-5\" />}\r\n color=\"green\"\r\n />\r\n <KpiCard\r\n title=\"Inactifs\"\r\n value={overview?.inactiveUsers ?? 0}\r\n icon={<UserX className=\"w-5 h-5\" />}\r\n color=\"red\"\r\n />\r\n <KpiCard\r\n title=\"Nouveaux\"\r\n value={overview?.newUsers ?? 0}\r\n icon={<UserPlus className=\"w-5 h-5\" />}\r\n color=\"blue\"\r\n subtitle={`${period} derniers jours`}\r\n />\r\n <KpiCard\r\n title=\"Sessions\"\r\n value={overview?.totalSessions ?? 0}\r\n icon={<Activity className=\"w-5 h-5\" />}\r\n color=\"green\"\r\n subtitle={`${period} derniers jours`}\r\n />\r\n <KpiCard\r\n title=\"Connexions Echouées\"\r\n value={overview?.failedLogins ?? 0}\r\n icon={<AlertTriangle className=\"w-5 h-5\" />}\r\n color={(overview?.failedLogins ?? 0) > 10 ? 'red' : 'yellow'}\r\n subtitle={`${period} derniers jours`}\r\n />\r\n </div>\r\n\r\n {/* Security Alerts */}\r\n {(securityAlerts?.length ?? 0) > 0 && (\r\n <div className=\"card p-4 border-l-4 border-red-500\">\r\n <h3 className=\"font-semibold text-red-600 flex items-center gap-2 mb-3\">\r\n <AlertTriangle className=\"w-5 h-5\" />\r\n Alertes Sécurité ({securityAlerts?.length ?? 0})\r\n </h3>\r\n <div className=\"space-y-2 max-h-40 overflow-y-auto\">\r\n {(securityAlerts ?? []).slice(0, 5).map((alert) => (\r\n <button\r\n type=\"button\"\r\n key={alert.userId}\r\n className=\"w-full flex items-center justify-between p-2 bg-red-50 dark:bg-red-900/20 rounded cursor-pointer hover:bg-red-100 dark:hover:bg-red-900/30 text-left\"\r\n onClick={() => navigate(`/administration/users/${alert.userId}`)}\r\n >\r\n <div>\r\n <span className=\"font-medium\">{alert.fullName}</span>\r\n <span className=\"ml-2 text-sm text-[var(--text-secondary)]\">{alert.email}</span>\r\n </div>\r\n <div className=\"flex items-center gap-2\">\r\n <span className=\"text-xs text-red-600 font-medium\">\r\n {alert.failedAttempts} échecs\r\n </span>\r\n <span className=\"text-xs text-[var(--text-secondary)]\">\r\n {alert.ipAddresses?.length ?? 0} IP(s)\r\n </span>\r\n </div>\r\n </button>\r\n ))}\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* Charts Row */}\r\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\r\n {/* Status Distribution */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <UserCheck className=\"w-5 h-5\" />\r\n Utilisateurs par Statut\r\n </h3>\r\n <div className=\"space-y-3\">\r\n {(statusData ?? []).map((item) => {\r\n const total = (statusData ?? []).reduce((sum, s) => sum + s.count, 0);\r\n const percentage = total > 0 ? (item.count / total) * 100 : 0;\r\n return (\r\n <div key={item.status} className=\"flex items-center gap-3\">\r\n <div className=\"w-24 text-sm\">{item.status === 'Active' ? 'Actifs' : 'Inactifs'}</div>\r\n <div className=\"flex-1 h-6 bg-[var(--bg-secondary)] rounded-full overflow-hidden\">\r\n <div\r\n className=\"h-full rounded-full transition-all duration-500\"\r\n style={{\r\n width: `${percentage}%`,\r\n backgroundColor: statusColors[item.status] || '#6b7280',\r\n }}\r\n />\r\n </div>\r\n <div className=\"w-20 text-right\">\r\n <span className=\"font-medium\">{item.count}</span>\r\n <span className=\"text-xs text-[var(--text-secondary)] ml-1\">\r\n ({percentage.toFixed(0)}%)\r\n </span>\r\n </div>\r\n </div>\r\n );\r\n })}\r\n </div>\r\n </div>\r\n\r\n {/* Role Distribution */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <Key className=\"w-5 h-5\" />\r\n Utilisateurs par Rôle\r\n </h3>\r\n <div className=\"space-y-3\">\r\n {(roleData?.length ?? 0) > 0 ? (\r\n (roleData ?? []).map((item, index) => {\r\n const maxCount = Math.max(...(roleData ?? []).map(r => r.count), 1);\r\n const percentage = (item.count / maxCount) * 100;\r\n const colors = ['#3b82f6', '#8b5cf6', '#22c55e', '#f59e0b', '#ef4444'];\r\n return (\r\n <div key={item.roleName} className=\"flex items-center gap-3\">\r\n <div className=\"w-32 text-sm truncate\" title={item.roleName}>{item.roleName}</div>\r\n <div className=\"flex-1 h-6 bg-[var(--bg-secondary)] rounded-full overflow-hidden\">\r\n <div\r\n className=\"h-full rounded-full transition-all duration-500\"\r\n style={{\r\n width: `${percentage}%`,\r\n backgroundColor: colors[index % colors.length],\r\n }}\r\n />\r\n </div>\r\n <div className=\"w-12 text-right font-medium\">{item.count}</div>\r\n </div>\r\n );\r\n })\r\n ) : (\r\n <div className=\"text-center py-4 text-[var(--text-secondary)]\">\r\n Aucun rôle configuré\r\n </div>\r\n )}\r\n </div>\r\n </div>\r\n </div>\r\n\r\n {/* System Stats */}\r\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\r\n {/* System Overview */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <Shield className=\"w-5 h-5\" />\r\n Configuration Système\r\n </h3>\r\n <div className=\"grid grid-cols-2 gap-4\">\r\n <div className=\"text-center p-4 bg-[var(--bg-secondary)] rounded-lg\">\r\n <div className=\"text-3xl font-bold text-purple-600\">{overview?.totalRoles ?? 0}</div>\r\n <div className=\"text-sm text-[var(--text-secondary)]\">Rôles</div>\r\n </div>\r\n <div className=\"text-center p-4 bg-[var(--bg-secondary)] rounded-lg\">\r\n <div className=\"text-3xl font-bold text-green-600\">{overview?.totalPermissions ?? 0}</div>\r\n <div className=\"text-sm text-[var(--text-secondary)]\">Permissions</div>\r\n </div>\r\n <div className=\"text-center p-4 bg-[var(--bg-secondary)] rounded-lg\">\r\n <div className=\"text-3xl font-bold text-blue-600\">{overview?.usersLoggedInRecently ?? 0}</div>\r\n <div className=\"text-sm text-[var(--text-secondary)]\">Connectés récemment</div>\r\n </div>\r\n <div className=\"text-center p-4 bg-[var(--bg-secondary)] rounded-lg\">\r\n <div className=\"text-3xl font-bold text-orange-600\">{sessionStats?.totalActiveSessions ?? 0}</div>\r\n <div className=\"text-sm text-[var(--text-secondary)]\">Sessions actives</div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n {/* Active Sessions Stats */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <Monitor className=\"w-5 h-5\" />\r\n Sessions Actives\r\n </h3>\r\n {sessionStats && ((sessionStats.byBrowser?.length ?? 0) > 0 || (sessionStats.byCountry?.length ?? 0) > 0) ? (\r\n <div className=\"grid grid-cols-2 gap-4\">\r\n <div>\r\n <h4 className=\"text-sm font-medium text-[var(--text-secondary)] mb-2\">Par Navigateur</h4>\r\n <div className=\"space-y-2\">\r\n {(sessionStats.byBrowser ?? []).map((item) => (\r\n <div key={item.browser} className=\"flex items-center justify-between text-sm\">\r\n <span>{item.browser}</span>\r\n <span className=\"font-medium\">{item.count}</span>\r\n </div>\r\n ))}\r\n </div>\r\n </div>\r\n <div>\r\n <h4 className=\"text-sm font-medium text-[var(--text-secondary)] mb-2 flex items-center gap-1\">\r\n <Globe className=\"w-4 h-4\" /> Par Pays\r\n </h4>\r\n <div className=\"space-y-2\">\r\n {(sessionStats.byCountry?.length ?? 0) > 0 ? (\r\n (sessionStats.byCountry ?? []).map((item) => (\r\n <div key={item.country} className=\"flex items-center justify-between text-sm\">\r\n <span>{item.country}</span>\r\n <span className=\"font-medium\">{item.count}</span>\r\n </div>\r\n ))\r\n ) : (\r\n <span className=\"text-[var(--text-secondary)] text-sm\">Non disponible</span>\r\n )}\r\n </div>\r\n </div>\r\n </div>\r\n ) : (\r\n <div className=\"text-center py-8 text-[var(--text-secondary)]\">\r\n Aucune session active\r\n </div>\r\n )}\r\n </div>\r\n </div>\r\n\r\n {/* Device & Engagement Metrics */}\r\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\r\n {/* Device Analytics */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <Monitor className=\"w-5 h-5\" />\r\n Appareils & Navigateurs\r\n </h3>\r\n <DeviceBreakdownChart data={deviceStats} />\r\n </div>\r\n\r\n {/* Engagement Metrics */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <Activity className=\"w-5 h-5\" />\r\n Engagement Utilisateurs\r\n </h3>\r\n <EngagementMetricsCard data={engagementMetrics} />\r\n </div>\r\n </div>\r\n\r\n {/* Trends Chart */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <TrendingUp className=\"w-5 h-5\" />\r\n Tendances ({period} derniers jours)\r\n </h3>\r\n <div className=\"h-64\">\r\n <TrendChart data={trends ?? []} />\r\n </div>\r\n </div>\r\n\r\n {/* Latest Active Sessions */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <Clock className=\"w-5 h-5\" />\r\n Dernières Sessions Actives\r\n </h3>\r\n {(latestSessions?.length ?? 0) > 0 ? (\r\n <div className=\"overflow-x-auto\">\r\n <table className=\"w-full\">\r\n <thead>\r\n <tr className=\"border-b border-[var(--border-color)]\">\r\n <th className=\"text-left p-3 font-medium\">Utilisateur</th>\r\n <th className=\"text-right p-3 font-medium\">Durée</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n {(latestSessions ?? []).map((session) => (\r\n <tr\r\n key={session.userId + session.loginAt}\r\n className=\"border-b border-[var(--border-color)] hover:bg-[var(--bg-secondary)] cursor-pointer\"\r\n onClick={() => navigate(`/administration/users/${session.userId}`)}\r\n >\r\n <td className=\"p-3 font-medium\">{session.fullName}</td>\r\n <td className=\"p-3 text-right\">\r\n <span className=\"px-2 py-1 rounded text-xs font-medium bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-400\">\r\n {session.duration}\r\n </span>\r\n </td>\r\n </tr>\r\n ))}\r\n </tbody>\r\n </table>\r\n </div>\r\n ) : (\r\n <div className=\"text-center py-8 text-[var(--text-secondary)]\">\r\n Aucune session active\r\n </div>\r\n )}\r\n </div>\r\n </div>\r\n );\r\n}\r\n\r\nfunction KpiCard({\r\n title,\r\n value,\r\n icon,\r\n color,\r\n subtitle,\r\n}: {\r\n title: string;\r\n value: string | number;\r\n icon: React.ReactNode;\r\n color: 'blue' | 'green' | 'yellow' | 'red';\r\n subtitle?: string;\r\n}) {\r\n const colorClasses = {\r\n blue: 'bg-blue-50 text-blue-600 border-blue-200 dark:bg-blue-900/20 dark:border-blue-800',\r\n green: 'bg-green-50 text-green-600 border-green-200 dark:bg-green-900/20 dark:border-green-800',\r\n yellow: 'bg-yellow-50 text-yellow-600 border-yellow-200 dark:bg-yellow-900/20 dark:border-yellow-800',\r\n red: 'bg-red-50 text-red-600 border-red-200 dark:bg-red-900/20 dark:border-red-800',\r\n };\r\n\r\n return (\r\n <div className={`card p-4 border ${colorClasses[color]}`}>\r\n <div className=\"flex items-center justify-between mb-2\">\r\n <span className=\"text-sm font-medium opacity-80\">{title}</span>\r\n {icon}\r\n </div>\r\n <div className=\"text-2xl font-bold\">{value}</div>\r\n {subtitle && <div className=\"text-xs opacity-70 mt-1\">{subtitle}</div>}\r\n </div>\r\n );\r\n}\r\n\r\nfunction TrendChart({ data }: { data: UserTrendDto[] }) {\r\n if (data.length === 0) {\r\n return (\r\n <div className=\"flex items-center justify-center h-full text-[var(--text-secondary)]\">\r\n Aucune donnée de tendance disponible\r\n </div>\r\n );\r\n }\r\n\r\n const maxValue = Math.max(...data.flatMap((d) => [d.newUsers, d.logins]), 1);\r\n\r\n return (\r\n <div className=\"flex flex-col h-full\">\r\n <div className=\"flex items-center gap-4 mb-4\">\r\n <div className=\"flex items-center gap-2\">\r\n <div className=\"w-3 h-3 rounded bg-blue-500\" />\r\n <span className=\"text-sm\">Nouveaux utilisateurs</span>\r\n </div>\r\n <div className=\"flex items-center gap-2\">\r\n <div className=\"w-3 h-3 rounded bg-green-500\" />\r\n <span className=\"text-sm\">Connexions</span>\r\n </div>\r\n </div>\r\n <div className=\"flex-1 flex items-end gap-1 overflow-x-auto pb-4\">\r\n {data.map((item) => (\r\n <div key={`${item.date}`} className=\"flex-1 min-w-[20px] flex gap-0.5\">\r\n <div\r\n className=\"flex-1 bg-blue-500 rounded-t transition-all duration-300 hover:opacity-80\"\r\n style={{\r\n height: `${(item.newUsers / maxValue) * 100}%`,\r\n minHeight: item.newUsers > 0 ? '4px' : '0',\r\n }}\r\n title={`Nouveaux: ${item.newUsers}`}\r\n />\r\n <div\r\n className=\"flex-1 bg-green-500 rounded-t transition-all duration-300 hover:opacity-80\"\r\n style={{\r\n height: `${(item.logins / maxValue) * 100}%`,\r\n minHeight: item.logins > 0 ? '4px' : '0',\r\n }}\r\n title={`Connexions: ${item.logins}`}\r\n />\r\n </div>\r\n ))}\r\n </div>\r\n <div className=\"flex justify-between text-xs text-[var(--text-secondary)] mt-2\">\r\n <span>{data[0] && new Date(data[0].date).toLocaleDateString('fr-FR')}</span>\r\n <span>{data.at(-1) && new Date(data.at(-1)!.date).toLocaleDateString('fr-FR')}</span>\r\n </div>\r\n </div>\r\n );\r\n}\r\n"],"names":["deviceIcons","jsx","Monitor","Smartphone","Tablet","deviceColors","browserColors","DeviceBreakdownChart","data","jsxs","device","index","browser","maxCount","b","percentage","sessionColors","EngagementMetricsCard","maxBucketCount","maxHourCount","h","bucket","hourData","heightPercentage","statusColors","AdminDashboardPage","t","useTranslation","navigate","useNavigate","currentTenant","isGlobalView","useTenant","loading","setLoading","useState","refreshing","setRefreshing","period","setPeriod","overview","setOverview","statusData","setStatusData","roleData","setRoleData","trends","setTrends","latestSessions","setLatestSessions","securityAlerts","setSecurityAlerts","sessionStats","setSessionStats","deviceStats","setDeviceStats","engagementMetrics","setEngagementMetrics","error","setError","abortControllerRef","useRef","loadData","useCallback","signal","overviewRes","statusRes","roleRes","trendsRes","latestSessionsRes","alertsRes","sessionsRes","deviceRes","engagementRes","adminApi","applicationAnalyticsApi","err","axiosError","useEffect","controller","handleRefresh","Loader2","Breadcrumb","AlertTriangle","RefreshCw","Users","e","KpiCard","UserCheck","UserX","UserPlus","Activity","alert","item","total","sum","s","Key","r","colors","Shield","Globe","TrendingUp","TrendChart","Clock","session","title","value","icon","color","subtitle","maxValue","d"],"mappings":";;;;;;;AAQA,MAAMA,IAA+C;AAAA,EACnD,SAAS,gBAAAC,EAACC,GAAA,EAAQ,WAAU,UAAA,CAAU;AAAA,EACtC,QAAQ,gBAAAD,EAACE,IAAA,EAAW,WAAU,UAAA,CAAU;AAAA,EACxC,QAAQ,gBAAAF,EAACG,IAAA,EAAO,WAAU,UAAA,CAAU;AAAA,EACpC,SAAS,gBAAAH,EAACC,GAAA,EAAQ,WAAU,qBAAA,CAAqB;AACnD,GAEMG,IAAe;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAEMC,IAAgB;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAEaC,KAA4D,CAAC,EAAE,MAAAC,QACtE,CAACA,KAAS,CAACA,EAAK,cAAc,UAAU,CAACA,EAAK,WAAW,SAEzD,gBAAAP,EAAC,OAAA,EAAI,WAAU,iDAAgD,UAAA,4BAE/D,IAKF,gBAAAQ,EAAC,OAAA,EAAI,WAAU,yCAEb,UAAA;AAAA,EAAA,gBAAAA,EAAC,OAAA,EACC,UAAA;AAAA,IAAA,gBAAAR,EAAC,MAAA,EAAG,WAAU,yDAAwD,UAAA,kBAEtE;AAAA,IACA,gBAAAA,EAAC,OAAA,EAAI,WAAU,aACZ,UAAAO,EAAK,aAAa,IAAI,CAACE,GAAQC,MAC9B,gBAAAF,EAAC,OAAA,EAA4B,WAAU,2BACrC,UAAA;AAAA,MAAA,gBAAAA,EAAC,OAAA,EAAI,WAAU,gCACZ,UAAA;AAAA,QAAAT,EAAYU,EAAO,UAAU,KAAKV,EAAY;AAAA,QAC/C,gBAAAC,EAAC,QAAA,EAAK,WAAU,WAAW,YAAO,WAAA,CAAW;AAAA,MAAA,GAC/C;AAAA,MACA,gBAAAA,EAAC,OAAA,EAAI,WAAU,oEACb,UAAA,gBAAAA;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,WAAU;AAAA,UACV,OAAO;AAAA,YACL,OAAO,GAAGS,EAAO,UAAU;AAAA,YAC3B,iBAAiBL,EAAaM,IAAQN,EAAa,MAAM;AAAA,UAAA;AAAA,QAC3D;AAAA,MAAA,GAEJ;AAAA,MACA,gBAAAI,EAAC,OAAA,EAAI,WAAU,mBACb,UAAA;AAAA,QAAA,gBAAAR,EAAC,QAAA,EAAK,WAAU,eAAe,UAAAS,EAAO,OAAM;AAAA,QAC5C,gBAAAD,EAAC,QAAA,EAAK,WAAU,6CAA4C,UAAA;AAAA,UAAA;AAAA,UACxDC,EAAO,WAAW,QAAQ,CAAC;AAAA,UAAE;AAAA,QAAA,EAAA,CACjC;AAAA,MAAA,EAAA,CACF;AAAA,IAAA,KAnBQA,EAAO,UAoBjB,CACD,EAAA,CACH;AAAA,EAAA,GACF;AAAA,oBAGC,OAAA,EACC,UAAA;AAAA,IAAA,gBAAAT,EAAC,MAAA,EAAG,WAAU,yDAAwD,UAAA,cAEtE;AAAA,IACA,gBAAAA,EAAC,SAAI,WAAU,aACZ,YAAK,UAAU,IAAI,CAACW,GAASD,MAAU;AACtC,YAAME,IAAW,KAAK,IAAI,GAAGL,EAAK,UAAU,IAAI,CAAAM,MAAKA,EAAE,KAAK,GAAG,CAAC,GAC1DC,IAAcH,EAAQ,QAAQC,IAAY;AAEhD,aACE,gBAAAJ,EAAC,OAAA,EAA0B,WAAU,2BACnC,UAAA;AAAA,QAAA,gBAAAR,EAAC,OAAA,EAAI,WAAU,gBAAgB,UAAAW,EAAQ,SAAQ;AAAA,QAC/C,gBAAAX,EAAC,OAAA,EAAI,WAAU,oEACb,UAAA,gBAAAA;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,WAAU;AAAA,YACV,OAAO;AAAA,cACL,OAAO,GAAGc,CAAU;AAAA,cACpB,iBAAiBT,EAAcK,IAAQL,EAAc,MAAM;AAAA,YAAA;AAAA,UAC7D;AAAA,QAAA,GAEJ;AAAA,QACA,gBAAAL,EAAC,OAAA,EAAI,WAAU,+BAA+B,YAAQ,MAAA,CAAM;AAAA,MAAA,EAAA,GAXpDW,EAAQ,OAYlB;AAAA,IAEJ,CAAC,EAAA,CACH;AAAA,EAAA,EAAA,CACF;AAAA,GACF,GC9FEI,IAAgB,CAAC,WAAW,WAAW,WAAW,SAAS,GAEpDC,KAA8D,CAAC,EAAE,MAAAT,QAAW;AACvF,MAAI,CAACA;AACH,WACE,gBAAAP,EAAC,OAAA,EAAI,WAAU,iDAAgD,UAAA,gCAE/D;AAIJ,QAAMiB,IAAiB,KAAK,IAAI,GAAGV,EAAK,oBAAoB,IAAI,CAAAM,MAAKA,EAAE,KAAK,GAAG,CAAC,GAC1EK,IAAe,KAAK,IAAI,GAAGX,EAAK,eAAe,IAAI,CAAAY,MAAKA,EAAE,WAAW,GAAG,CAAC;AAE/E,SACE,gBAAAX,EAAC,OAAA,EAAI,WAAU,aAEb,UAAA;AAAA,IAAA,gBAAAA,EAAC,OAAA,EACC,UAAA;AAAA,MAAA,gBAAAR,EAAC,MAAA,EAAG,WAAU,yDAAwD,UAAA,iCAEtE;AAAA,MACA,gBAAAA,EAAC,SAAI,WAAU,aACZ,YAAK,oBAAoB,IAAI,CAACoB,GAAQV,MAAU;AAC/C,cAAMI,IAAcM,EAAO,QAAQH,IAAkB;AAErD,eACE,gBAAAT,EAAC,OAAA,EAAwB,WAAU,2BACjC,UAAA;AAAA,UAAA,gBAAAR,EAAC,OAAA,EAAI,WAAU,gBAAgB,UAAAoB,EAAO,OAAM;AAAA,UAC5C,gBAAApB,EAAC,OAAA,EAAI,WAAU,oEACb,UAAA,gBAAAA;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,WAAU;AAAA,cACV,OAAO;AAAA,gBACL,OAAO,GAAGc,CAAU;AAAA,gBACpB,iBAAiBC,EAAcL,IAAQK,EAAc,MAAM;AAAA,cAAA;AAAA,YAC7D;AAAA,UAAA,GAEJ;AAAA,UACA,gBAAAP,EAAC,OAAA,EAAI,WAAU,mBACb,UAAA;AAAA,YAAA,gBAAAR,EAAC,QAAA,EAAK,WAAU,eAAe,UAAAoB,EAAO,OAAM;AAAA,YAC5C,gBAAApB,EAAC,QAAA,EAAK,WAAU,6CAA4C,UAAA,WAAA,CAE5D;AAAA,UAAA,EAAA,CACF;AAAA,QAAA,EAAA,GAhBQoB,EAAO,MAiBjB;AAAA,MAEJ,CAAC,EAAA,CACH;AAAA,IAAA,GACF;AAAA,sBAGC,OAAA,EACC,UAAA;AAAA,MAAA,gBAAApB,EAAC,MAAA,EAAG,WAAU,yDAAwD,UAAA,oBAEtE;AAAA,MACA,gBAAAA,EAAC,SAAI,WAAU,kDACZ,YAAK,eAAe,IAAI,CAACqB,MAAa;AACrC,cAAMC,IAAoBD,EAAS,cAAcH,IAAgB;AAEjE,eACE,gBAAAV;AAAA,UAAC;AAAA,UAAA;AAAA,YAEC,WAAU;AAAA,YAEV,UAAA;AAAA,cAAA,gBAAAR;AAAA,gBAAC;AAAA,gBAAA;AAAA,kBACC,WAAU;AAAA,kBACV,OAAO;AAAA,oBACL,QAAQ,GAAGsB,CAAgB;AAAA,oBAC3B,WAAWD,EAAS,cAAc,IAAI,QAAQ;AAAA,kBAAA;AAAA,kBAEhD,OAAO,GAAGA,EAAS,IAAI,MAAMA,EAAS,WAAW;AAAA,gBAAA;AAAA,cAAA;AAAA,cAElDA,EAAS,OAAO,MAAM,KACrB,gBAAAb,EAAC,QAAA,EAAK,WAAU,wCACb,UAAA;AAAA,gBAAAa,EAAS;AAAA,gBAAK;AAAA,cAAA,EAAA,CACjB;AAAA,YAAA;AAAA,UAAA;AAAA,UAdGA,EAAS;AAAA,QAAA;AAAA,MAkBpB,CAAC,EAAA,CACH;AAAA,IAAA,GACF;AAAA,IAGA,gBAAAb,EAAC,OAAA,EAAI,WAAU,qEACb,UAAA;AAAA,MAAA,gBAAAA,EAAC,OAAA,EAAI,WAAU,uDACb,UAAA;AAAA,QAAA,gBAAAR,EAAC,OAAA,EAAI,WAAU,oCACZ,UAAAO,EAAK,kBACR;AAAA,QACA,gBAAAP,EAAC,OAAA,EAAI,WAAU,6CAA4C,UAAA,qBAAA,CAE3D;AAAA,MAAA,GACF;AAAA,MACA,gBAAAQ,EAAC,OAAA,EAAI,WAAU,uDACb,UAAA;AAAA,QAAA,gBAAAA,EAAC,OAAA,EAAI,WAAU,qCACX,UAAA;AAAA,WAAAD,EAAK,gBAAgB,KAAK,QAAQ,CAAC;AAAA,UAAE;AAAA,QAAA,GACzC;AAAA,QACA,gBAAAP,EAAC,OAAA,EAAI,WAAU,6CAA4C,UAAA,iBAAA,CAE3D;AAAA,MAAA,EAAA,CACF;AAAA,IAAA,EAAA,CACF;AAAA,EAAA,GACF;AAEJ,GCzEMuB,KAAuC;AAAA,EAC3C,QAAQ;AAAA,EACR,UAAU;AACZ;AAEO,SAASC,KAAmC;AACjD,QAAM,EAAE,GAAAC,EAAA,IAAMC,GAAe,CAAC,SAAS,YAAY,CAAC,GAC9CC,IAAWC,GAAA,GACX,EAAE,eAAAC,GAAe,cAAAC,EAAA,IAAiBC,GAAA,GAClC,CAACC,GAASC,CAAU,IAAIC,EAAS,EAAI,GACrC,CAACC,GAAYC,CAAa,IAAIF,EAAS,EAAK,GAC5C,CAACG,GAAQC,CAAS,IAAIJ,EAAS,EAAE,GAEjC,CAACK,GAAUC,CAAW,IAAIN,EAA0C,IAAI,GACxE,CAACO,GAAYC,CAAa,IAAIR,EAA+B,CAAA,CAAE,GAC/D,CAACS,GAAUC,CAAW,IAAIV,EAAoC,CAAA,CAAE,GAChE,CAACW,GAAQC,CAAS,IAAIZ,EAAyB,CAAA,CAAE,GACjD,CAACa,GAAgBC,CAAiB,IAAId,EAAmC,CAAA,CAAE,GAC3E,CAACe,GAAgBC,CAAiB,IAAIhB,EAA6B,CAAA,CAAE,GACrE,CAACiB,GAAcC,CAAe,IAAIlB,EAAwC,IAAI,GAC9E,CAACmB,GAAaC,CAAc,IAAIpB,EAAoC,IAAI,GACxE,CAACqB,GAAmBC,EAAoB,IAAItB,EAAsC,IAAI,GACtF,CAACuB,GAAOC,CAAQ,IAAIxB,EAAwB,IAAI,GAGhDyB,IAAqBC,GAA+B,IAAI,GAExDC,IAAWC,GAAY,OAAOC,MAAyB;AAC3D,QAAI;AACF,MAAAL,EAAS,IAAI;AACb,YAAM;AAAA,QACJM;AAAA,QACAC;AAAA,QACAC;AAAA,QACAC;AAAA,QACAC;AAAA,QACAC;AAAA,QACAC;AAAA,QACAC;AAAA,QACAC;AAAA,MAAA,IACE,MAAM,QAAQ,IAAI;AAAA,QACpBC,EAAS,UAAU,YAAYpC,GAAQ,EAAE,QAAA0B,GAAQ;AAAA,QACjDU,EAAS,UAAU,YAAY,EAAE,QAAAV,GAAQ;AAAA,QACzCU,EAAS,UAAU,UAAU,EAAE,QAAAV,GAAQ;AAAA,QACvCU,EAAS,UAAU,UAAUpC,GAAQ,EAAE,QAAA0B,GAAQ;AAAA,QAC/CU,EAAS,UAAU,wBAAwB,GAAG,EAAE,QAAAV,GAAQ;AAAA,QACxDU,EAAS,UAAU,kBAAkB,GAAG,IAAI,EAAE,QAAAV,GAAQ;AAAA,QACtDU,EAAS,UAAU,kBAAkB,EAAE,QAAAV,GAAQ;AAAA,QAC/CW,EAAwB,eAAerC,GAAQ,EAAE,QAAA0B,GAAQ;AAAA,QACzDW,EAAwB,qBAAqBrC,GAAQ,EAAE,QAAA0B,GAAQ;AAAA,MAAA,CAChE;AAGD,MAAKA,GAAQ,YACXvB,EAAYwB,KAAe,IAAI,GAC/BtB,EAAcuB,KAAa,EAAE,GAC7BrB,EAAYsB,KAAW,EAAE,GACzBpB,EAAUqB,KAAa,EAAE,GACzBnB,EAAkBoB,KAAqB,EAAE,GACzClB,EAAkBmB,MAAa,EAAE,GACjCjB,EAAgBkB,MAAe,IAAI,GACnChB,EAAeiB,MAAa,IAAI,GAChCf,GAAqBgB,MAAiB,IAAI;AAAA,IAE9C,SAASG,GAAc;AAErB,UAAIA,aAAe,SAASA,EAAI,SAAS;AACvC;AAEF,cAAQ,MAAM,kCAAkCA,CAAG;AACnD,YAAMC,IAAaD;AACnB,MAAIC,EAAW,UAAU,WAAW,MAClClB,EAAS,6CAA6C,IAC7CkB,EAAW,UAAU,WAAW,MACzClB,EAAS,wEAAyE,IAElFA,EAAS,2EAA4E;AAAA,IAEzF,UAAA;AACE,MAAKK,GAAQ,YACX9B,EAAW,EAAK,GAChBG,EAAc,EAAK;AAAA,IAEvB;AAAA,EACF,GAAG,CAACC,GAAQR,GAAe,IAAIC,CAAY,CAAC;AAE5C,EAAA+C,GAAU,MAAM;AAEd,IAAAlB,EAAmB,SAAS,MAAA;AAC5B,UAAMmB,IAAa,IAAI,gBAAA;AACvB,WAAAnB,EAAmB,UAAUmB,GAE7BjB,EAASiB,EAAW,MAAM,GAGnB,MAAM;AACX,MAAAA,EAAW,MAAA;AAAA,IACb;AAAA,EACF,GAAG,CAACjB,CAAQ,CAAC;AAEb,QAAMkB,IAAgB,MAAM;AAE1B,IAAApB,EAAmB,SAAS,MAAA;AAC5B,UAAMmB,IAAa,IAAI,gBAAA;AACvB,IAAAnB,EAAmB,UAAUmB,GAE7B1C,EAAc,EAAI,GAClByB,EAASiB,EAAW,MAAM;AAAA,EAC5B;AAEA,SAAI9C,IAEA,gBAAAhC,EAAC,SAAI,WAAU,kDACb,4BAACgF,IAAA,EAAQ,WAAU,wDAAuD,EAAA,CAC5E,IAKF,gBAAAxE,EAAC,OAAA,EAAI,WAAU,aAEb,UAAA;AAAA,IAAA,gBAAAR;AAAA,MAACiF;AAAA,MAAA;AAAA,QACC,OAAO;AAAA,UACL,EAAE,OAAOxD,EAAE,cAAc,EAAA;AAAA,UACzB,EAAE,OAAOA,EAAE,iBAAiB,EAAA;AAAA,QAAE;AAAA,MAChC;AAAA,IAAA;AAAA,IAIDgC,KACC,gBAAAjD,EAAC,OAAA,EAAI,WAAU,iHACb,UAAA;AAAA,MAAA,gBAAAR,EAACkF,GAAA,EAAc,WAAU,uDAAA,CAAuD;AAAA,MAChF,gBAAAlF,EAAC,SAAI,WAAU,UACb,4BAAC,KAAA,EAAE,WAAU,8CAA8C,UAAAyD,EAAA,CAAM,EAAA,CACnE;AAAA,MACA,gBAAAzD;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,SAAS+E;AAAA,UACT,WAAU;AAAA,UAEV,UAAA,gBAAA/E,EAACmF,GAAA,EAAU,WAAU,UAAA,CAAU;AAAA,QAAA;AAAA,MAAA;AAAA,IACjC,GACF;AAAA,IAIF,gBAAA3E,EAAC,OAAA,EAAI,WAAU,qCACb,UAAA;AAAA,MAAA,gBAAAA,EAAC,OAAA,EACC,UAAA;AAAA,QAAA,gBAAAA,EAAC,MAAA,EAAG,WAAU,yEACZ,UAAA;AAAA,UAAA,gBAAAR,EAACoF,GAAA,EAAM,WAAU,UAAA,CAAU;AAAA,UAC1B3D,EAAE,oBAAoB;AAAA,QAAA,GACzB;AAAA,QACA,gBAAAzB,EAAC,KAAA,EAAE,WAAU,qCAAoC,UAAA,gDAAA,CAEjD;AAAA,MAAA,GACF;AAAA,MACA,gBAAAQ,EAAC,OAAA,EAAI,WAAU,2BACb,UAAA;AAAA,QAAA,gBAAAA;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,OAAO6B;AAAA,YACP,UAAU,CAACgD,MAAM/C,EAAU,OAAO+C,EAAE,OAAO,KAAK,CAAC;AAAA,YACjD,WAAU;AAAA,YAEV,UAAA;AAAA,cAAA,gBAAArF,EAAC,UAAA,EAAO,OAAO,GAAG,UAAA,oBAAgB;AAAA,cAClC,gBAAAA,EAAC,UAAA,EAAO,OAAO,IAAI,UAAA,qBAAiB;AAAA,cACpC,gBAAAA,EAAC,UAAA,EAAO,OAAO,IAAI,UAAA,oBAAA,CAAiB;AAAA,YAAA;AAAA,UAAA;AAAA,QAAA;AAAA,QAEtC,gBAAAQ;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,SAASuE;AAAA,YACT,UAAU5C;AAAA,YACV,WAAU;AAAA,YAEV,UAAA;AAAA,cAAA,gBAAAnC,EAACmF,KAAU,WAAW,WAAWhD,IAAa,iBAAiB,EAAE,IAAI;AAAA,cAAE;AAAA,YAAA;AAAA,UAAA;AAAA,QAAA;AAAA,MAEzE,EAAA,CACF;AAAA,IAAA,GACF;AAAA,IAGA,gBAAA3B,EAAC,OAAA,EAAI,WAAU,wDACb,UAAA;AAAA,MAAA,gBAAAR;AAAA,QAACsF;AAAA,QAAA;AAAA,UACC,OAAM;AAAA,UACN,OAAO/C,GAAU,cAAc;AAAA,UAC/B,MAAM,gBAAAvC,EAACoF,GAAA,EAAM,WAAU,UAAA,CAAU;AAAA,UACjC,OAAM;AAAA,QAAA;AAAA,MAAA;AAAA,MAER,gBAAApF;AAAA,QAACsF;AAAA,QAAA;AAAA,UACC,OAAM;AAAA,UACN,OAAO/C,GAAU,eAAe;AAAA,UAChC,MAAM,gBAAAvC,EAACuF,GAAA,EAAU,WAAU,UAAA,CAAU;AAAA,UACrC,OAAM;AAAA,QAAA;AAAA,MAAA;AAAA,MAER,gBAAAvF;AAAA,QAACsF;AAAA,QAAA;AAAA,UACC,OAAM;AAAA,UACN,OAAO/C,GAAU,iBAAiB;AAAA,UAClC,MAAM,gBAAAvC,EAACwF,IAAA,EAAM,WAAU,UAAA,CAAU;AAAA,UACjC,OAAM;AAAA,QAAA;AAAA,MAAA;AAAA,MAER,gBAAAxF;AAAA,QAACsF;AAAA,QAAA;AAAA,UACC,OAAM;AAAA,UACN,OAAO/C,GAAU,YAAY;AAAA,UAC7B,MAAM,gBAAAvC,EAACyF,IAAA,EAAS,WAAU,UAAA,CAAU;AAAA,UACpC,OAAM;AAAA,UACN,UAAU,GAAGpD,CAAM;AAAA,QAAA;AAAA,MAAA;AAAA,MAErB,gBAAArC;AAAA,QAACsF;AAAA,QAAA;AAAA,UACC,OAAM;AAAA,UACN,OAAO/C,GAAU,iBAAiB;AAAA,UAClC,MAAM,gBAAAvC,EAAC0F,GAAA,EAAS,WAAU,UAAA,CAAU;AAAA,UACpC,OAAM;AAAA,UACN,UAAU,GAAGrD,CAAM;AAAA,QAAA;AAAA,MAAA;AAAA,MAErB,gBAAArC;AAAA,QAACsF;AAAA,QAAA;AAAA,UACC,OAAM;AAAA,UACN,OAAO/C,GAAU,gBAAgB;AAAA,UACjC,MAAM,gBAAAvC,EAACkF,GAAA,EAAc,WAAU,UAAA,CAAU;AAAA,UACzC,QAAQ3C,GAAU,gBAAgB,KAAK,KAAK,QAAQ;AAAA,UACpD,UAAU,GAAGF,CAAM;AAAA,QAAA;AAAA,MAAA;AAAA,IACrB,GACF;AAAA,KAGEY,GAAgB,UAAU,KAAK,KAC/B,gBAAAzC,EAAC,OAAA,EAAI,WAAU,sCACb,UAAA;AAAA,MAAA,gBAAAA,EAAC,MAAA,EAAG,WAAU,2DACZ,UAAA;AAAA,QAAA,gBAAAR,EAACkF,GAAA,EAAc,WAAU,UAAA,CAAU;AAAA,QAAE;AAAA,QAClBjC,GAAgB,UAAU;AAAA,QAAE;AAAA,MAAA,GACjD;AAAA,MACA,gBAAAjD,EAAC,OAAA,EAAI,WAAU,sCACX,WAAAiD,KAAkB,CAAA,GAAI,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC0C,MACvC,gBAAAnF;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,MAAK;AAAA,UAEL,WAAU;AAAA,UACV,SAAS,MAAMmB,EAAS,yBAAyBgE,EAAM,MAAM,EAAE;AAAA,UAE/D,UAAA;AAAA,YAAA,gBAAAnF,EAAC,OAAA,EACC,UAAA;AAAA,cAAA,gBAAAR,EAAC,QAAA,EAAK,WAAU,eAAe,UAAA2F,EAAM,UAAS;AAAA,cAC9C,gBAAA3F,EAAC,QAAA,EAAK,WAAU,6CAA6C,YAAM,MAAA,CAAM;AAAA,YAAA,GAC3E;AAAA,YACA,gBAAAQ,EAAC,OAAA,EAAI,WAAU,2BACb,UAAA;AAAA,cAAA,gBAAAA,EAAC,QAAA,EAAK,WAAU,oCACb,UAAA;AAAA,gBAAAmF,EAAM;AAAA,gBAAe;AAAA,cAAA,GACxB;AAAA,cACA,gBAAAnF,EAAC,QAAA,EAAK,WAAU,wCACb,UAAA;AAAA,gBAAAmF,EAAM,aAAa,UAAU;AAAA,gBAAE;AAAA,cAAA,EAAA,CAClC;AAAA,YAAA,EAAA,CACF;AAAA,UAAA;AAAA,QAAA;AAAA,QAfKA,EAAM;AAAA,MAAA,CAiBd,EAAA,CACH;AAAA,IAAA,GACF;AAAA,IAIF,gBAAAnF,EAAC,OAAA,EAAI,WAAU,yCAEb,UAAA;AAAA,MAAA,gBAAAA,EAAC,OAAA,EAAI,WAAU,YACb,UAAA;AAAA,QAAA,gBAAAA,EAAC,MAAA,EAAG,WAAU,8CACZ,UAAA;AAAA,UAAA,gBAAAR,EAACuF,GAAA,EAAU,WAAU,UAAA,CAAU;AAAA,UAAE;AAAA,QAAA,GAEnC;AAAA,QACA,gBAAAvF,EAAC,SAAI,WAAU,aACX,gBAAc,CAAA,GAAI,IAAI,CAAC4F,MAAS;AAChC,gBAAMC,KAASpD,KAAc,CAAA,GAAI,OAAO,CAACqD,GAAKC,MAAMD,IAAMC,EAAE,OAAO,CAAC,GAC9DjF,IAAa+E,IAAQ,IAAKD,EAAK,QAAQC,IAAS,MAAM;AAC5D,iBACE,gBAAArF,EAAC,OAAA,EAAsB,WAAU,2BAC/B,UAAA;AAAA,YAAA,gBAAAR,EAAC,SAAI,WAAU,gBAAgB,YAAK,WAAW,WAAW,WAAW,WAAA,CAAW;AAAA,YAChF,gBAAAA,EAAC,OAAA,EAAI,WAAU,oEACb,UAAA,gBAAAA;AAAA,cAAC;AAAA,cAAA;AAAA,gBACC,WAAU;AAAA,gBACV,OAAO;AAAA,kBACL,OAAO,GAAGc,CAAU;AAAA,kBACpB,iBAAiBS,GAAaqE,EAAK,MAAM,KAAK;AAAA,gBAAA;AAAA,cAChD;AAAA,YAAA,GAEJ;AAAA,YACA,gBAAApF,EAAC,OAAA,EAAI,WAAU,mBACb,UAAA;AAAA,cAAA,gBAAAR,EAAC,QAAA,EAAK,WAAU,eAAe,UAAA4F,EAAK,OAAM;AAAA,cAC1C,gBAAApF,EAAC,QAAA,EAAK,WAAU,6CAA4C,UAAA;AAAA,gBAAA;AAAA,gBACxDM,EAAW,QAAQ,CAAC;AAAA,gBAAE;AAAA,cAAA,EAAA,CAC1B;AAAA,YAAA,EAAA,CACF;AAAA,UAAA,EAAA,GAhBQ8E,EAAK,MAiBf;AAAA,QAEJ,CAAC,EAAA,CACH;AAAA,MAAA,GACF;AAAA,MAGA,gBAAApF,EAAC,OAAA,EAAI,WAAU,YACb,UAAA;AAAA,QAAA,gBAAAA,EAAC,MAAA,EAAG,WAAU,8CACZ,UAAA;AAAA,UAAA,gBAAAR,EAACgG,IAAA,EAAI,WAAU,UAAA,CAAU;AAAA,UAAE;AAAA,QAAA,GAE7B;AAAA,QACA,gBAAAhG,EAAC,OAAA,EAAI,WAAU,aACX,cAAU,UAAU,KAAK,KACxB2C,KAAY,CAAA,GAAI,IAAI,CAACiD,GAAMlF,MAAU;AACpC,gBAAME,IAAW,KAAK,IAAI,IAAI+B,KAAY,CAAA,GAAI,IAAI,CAAAsD,MAAKA,EAAE,KAAK,GAAG,CAAC,GAC5DnF,IAAc8E,EAAK,QAAQhF,IAAY,KACvCsF,IAAS,CAAC,WAAW,WAAW,WAAW,WAAW,SAAS;AACrE,iBACE,gBAAA1F,EAAC,OAAA,EAAwB,WAAU,2BACjC,UAAA;AAAA,YAAA,gBAAAR,EAAC,SAAI,WAAU,yBAAwB,OAAO4F,EAAK,UAAW,YAAK,SAAA,CAAS;AAAA,YAC5E,gBAAA5F,EAAC,OAAA,EAAI,WAAU,oEACb,UAAA,gBAAAA;AAAA,cAAC;AAAA,cAAA;AAAA,gBACC,WAAU;AAAA,gBACV,OAAO;AAAA,kBACL,OAAO,GAAGc,CAAU;AAAA,kBACpB,iBAAiBoF,EAAOxF,IAAQwF,EAAO,MAAM;AAAA,gBAAA;AAAA,cAC/C;AAAA,YAAA,GAEJ;AAAA,YACA,gBAAAlG,EAAC,OAAA,EAAI,WAAU,+BAA+B,YAAK,MAAA,CAAM;AAAA,UAAA,EAAA,GAXjD4F,EAAK,QAYf;AAAA,QAEJ,CAAC,IAED,gBAAA5F,EAAC,SAAI,WAAU,iDAAgD,kCAE/D,EAAA,CAEJ;AAAA,MAAA,EAAA,CACF;AAAA,IAAA,GACF;AAAA,IAGA,gBAAAQ,EAAC,OAAA,EAAI,WAAU,yCAEb,UAAA;AAAA,MAAA,gBAAAA,EAAC,OAAA,EAAI,WAAU,YACb,UAAA;AAAA,QAAA,gBAAAA,EAAC,MAAA,EAAG,WAAU,8CACZ,UAAA;AAAA,UAAA,gBAAAR,EAACmG,IAAA,EAAO,WAAU,UAAA,CAAU;AAAA,UAAE;AAAA,QAAA,GAEhC;AAAA,QACA,gBAAA3F,EAAC,OAAA,EAAI,WAAU,0BACb,UAAA;AAAA,UAAA,gBAAAA,EAAC,OAAA,EAAI,WAAU,uDACb,UAAA;AAAA,YAAA,gBAAAR,EAAC,OAAA,EAAI,WAAU,sCAAsC,UAAAuC,GAAU,cAAc,GAAE;AAAA,YAC/E,gBAAAvC,EAAC,OAAA,EAAI,WAAU,wCAAuC,UAAA,QAAA,CAAK;AAAA,UAAA,GAC7D;AAAA,UACA,gBAAAQ,EAAC,OAAA,EAAI,WAAU,uDACb,UAAA;AAAA,YAAA,gBAAAR,EAAC,OAAA,EAAI,WAAU,qCAAqC,UAAAuC,GAAU,oBAAoB,GAAE;AAAA,YACpF,gBAAAvC,EAAC,OAAA,EAAI,WAAU,wCAAuC,UAAA,cAAA,CAAW;AAAA,UAAA,GACnE;AAAA,UACA,gBAAAQ,EAAC,OAAA,EAAI,WAAU,uDACb,UAAA;AAAA,YAAA,gBAAAR,EAAC,OAAA,EAAI,WAAU,oCAAoC,UAAAuC,GAAU,yBAAyB,GAAE;AAAA,YACxF,gBAAAvC,EAAC,OAAA,EAAI,WAAU,wCAAuC,UAAA,sBAAA,CAAmB;AAAA,UAAA,GAC3E;AAAA,UACA,gBAAAQ,EAAC,OAAA,EAAI,WAAU,uDACb,UAAA;AAAA,YAAA,gBAAAR,EAAC,OAAA,EAAI,WAAU,sCAAsC,UAAAmD,GAAc,uBAAuB,GAAE;AAAA,YAC5F,gBAAAnD,EAAC,OAAA,EAAI,WAAU,wCAAuC,UAAA,mBAAA,CAAgB;AAAA,UAAA,EAAA,CACxE;AAAA,QAAA,EAAA,CACF;AAAA,MAAA,GACF;AAAA,MAGA,gBAAAQ,EAAC,OAAA,EAAI,WAAU,YACb,UAAA;AAAA,QAAA,gBAAAA,EAAC,MAAA,EAAG,WAAU,8CACZ,UAAA;AAAA,UAAA,gBAAAR,EAACC,GAAA,EAAQ,WAAU,UAAA,CAAU;AAAA,UAAE;AAAA,QAAA,GAEjC;AAAA,QACCkD,OAAkBA,EAAa,WAAW,UAAU,KAAK,MAAMA,EAAa,WAAW,UAAU,KAAK,KACrG,gBAAA3C,EAAC,OAAA,EAAI,WAAU,0BACb,UAAA;AAAA,UAAA,gBAAAA,EAAC,OAAA,EACC,UAAA;AAAA,YAAA,gBAAAR,EAAC,MAAA,EAAG,WAAU,yDAAwD,UAAA,kBAAc;AAAA,YACpF,gBAAAA,EAAC,OAAA,EAAI,WAAU,aACX,aAAa,aAAa,CAAA,GAAI,IAAI,CAAC4F,MACnC,gBAAApF,EAAC,OAAA,EAAuB,WAAU,6CAChC,UAAA;AAAA,cAAA,gBAAAR,EAAC,QAAA,EAAM,YAAK,QAAA,CAAQ;AAAA,cACpB,gBAAAA,EAAC,QAAA,EAAK,WAAU,eAAe,YAAK,MAAA,CAAM;AAAA,YAAA,KAFlC4F,EAAK,OAGf,CACD,EAAA,CACH;AAAA,UAAA,GACF;AAAA,4BACC,OAAA,EACC,UAAA;AAAA,YAAA,gBAAApF,EAAC,MAAA,EAAG,WAAU,iFACZ,UAAA;AAAA,cAAA,gBAAAR,EAACoG,IAAA,EAAM,WAAU,UAAA,CAAU;AAAA,cAAE;AAAA,YAAA,GAC/B;AAAA,8BACC,OAAA,EAAI,WAAU,aACX,WAAAjD,EAAa,WAAW,UAAU,KAAK,KACtCA,EAAa,aAAa,CAAA,GAAI,IAAI,CAACyC,MAClC,gBAAApF,EAAC,OAAA,EAAuB,WAAU,6CAChC,UAAA;AAAA,cAAA,gBAAAR,EAAC,QAAA,EAAM,YAAK,QAAA,CAAQ;AAAA,cACpB,gBAAAA,EAAC,QAAA,EAAK,WAAU,eAAe,YAAK,MAAA,CAAM;AAAA,YAAA,EAAA,GAFlC4F,EAAK,OAGf,CACD,sBAEA,QAAA,EAAK,WAAU,wCAAuC,UAAA,iBAAA,CAAc,EAAA,CAEzE;AAAA,UAAA,EAAA,CACF;AAAA,QAAA,EAAA,CACF,IAEA,gBAAA5F,EAAC,OAAA,EAAI,WAAU,iDAAgD,UAAA,wBAAA,CAE/D;AAAA,MAAA,EAAA,CAEJ;AAAA,IAAA,GACF;AAAA,IAGA,gBAAAQ,EAAC,OAAA,EAAI,WAAU,yCAEb,UAAA;AAAA,MAAA,gBAAAA,EAAC,OAAA,EAAI,WAAU,YACb,UAAA;AAAA,QAAA,gBAAAA,EAAC,MAAA,EAAG,WAAU,8CACZ,UAAA;AAAA,UAAA,gBAAAR,EAACC,GAAA,EAAQ,WAAU,UAAA,CAAU;AAAA,UAAE;AAAA,QAAA,GAEjC;AAAA,QACA,gBAAAD,EAACM,IAAA,EAAqB,MAAM+C,EAAA,CAAa;AAAA,MAAA,GAC3C;AAAA,MAGA,gBAAA7C,EAAC,OAAA,EAAI,WAAU,YACb,UAAA;AAAA,QAAA,gBAAAA,EAAC,MAAA,EAAG,WAAU,8CACZ,UAAA;AAAA,UAAA,gBAAAR,EAAC0F,GAAA,EAAS,WAAU,UAAA,CAAU;AAAA,UAAE;AAAA,QAAA,GAElC;AAAA,QACA,gBAAA1F,EAACgB,IAAA,EAAsB,MAAMuC,EAAA,CAAmB;AAAA,MAAA,EAAA,CAClD;AAAA,IAAA,GACF;AAAA,IAGA,gBAAA/C,EAAC,OAAA,EAAI,WAAU,YACb,UAAA;AAAA,MAAA,gBAAAA,EAAC,MAAA,EAAG,WAAU,8CACZ,UAAA;AAAA,QAAA,gBAAAR,EAACqG,IAAA,EAAW,WAAU,UAAA,CAAU;AAAA,QAAE;AAAA,QACtBhE;AAAA,QAAO;AAAA,MAAA,GACrB;AAAA,MACA,gBAAArC,EAAC,OAAA,EAAI,WAAU,QACb,UAAA,gBAAAA,EAACsG,MAAW,MAAMzD,KAAU,CAAA,EAAC,CAAG,EAAA,CAClC;AAAA,IAAA,GACF;AAAA,IAGA,gBAAArC,EAAC,OAAA,EAAI,WAAU,YACb,UAAA;AAAA,MAAA,gBAAAA,EAAC,MAAA,EAAG,WAAU,8CACZ,UAAA;AAAA,QAAA,gBAAAR,EAACuG,IAAA,EAAM,WAAU,UAAA,CAAU;AAAA,QAAE;AAAA,MAAA,GAE/B;AAAA,OACExD,GAAgB,UAAU,KAAK,IAC/B,gBAAA/C,EAAC,OAAA,EAAI,WAAU,mBACb,UAAA,gBAAAQ,EAAC,SAAA,EAAM,WAAU,UACf,UAAA;AAAA,QAAA,gBAAAR,EAAC,SAAA,EACC,UAAA,gBAAAQ,EAAC,MAAA,EAAG,WAAU,yCACZ,UAAA;AAAA,UAAA,gBAAAR,EAAC,MAAA,EAAG,WAAU,6BAA4B,UAAA,eAAW;AAAA,UACrD,gBAAAA,EAAC,MAAA,EAAG,WAAU,8BAA6B,UAAA,QAAA,CAAK;AAAA,QAAA,EAAA,CAClD,EAAA,CACF;AAAA,0BACC,SAAA,EACG,WAAA+C,KAAkB,IAAI,IAAI,CAACyD,MAC3B,gBAAAhG;AAAA,UAAC;AAAA,UAAA;AAAA,YAEC,WAAU;AAAA,YACV,SAAS,MAAMmB,EAAS,yBAAyB6E,EAAQ,MAAM,EAAE;AAAA,YAEjE,UAAA;AAAA,cAAA,gBAAAxG,EAAC,MAAA,EAAG,WAAU,mBAAmB,UAAAwG,EAAQ,UAAS;AAAA,cAClD,gBAAAxG,EAAC,MAAA,EAAG,WAAU,kBACZ,UAAA,gBAAAA,EAAC,UAAK,WAAU,8GACb,UAAAwG,EAAQ,SAAA,CACX,EAAA,CACF;AAAA,YAAA;AAAA,UAAA;AAAA,UATKA,EAAQ,SAASA,EAAQ;AAAA,QAAA,CAWjC,EAAA,CACH;AAAA,MAAA,GACF,GACF,IAEA,gBAAAxG,EAAC,OAAA,EAAI,WAAU,iDAAgD,UAAA,wBAAA,CAE/D;AAAA,IAAA,EAAA,CAEJ;AAAA,EAAA,GACF;AAEJ;AAEA,SAASsF,EAAQ;AAAA,EACf,OAAAmB;AAAA,EACA,OAAAC;AAAA,EACA,MAAAC;AAAA,EACA,OAAAC;AAAA,EACA,UAAAC;AACF,GAMG;AAQD,2BACG,OAAA,EAAI,WAAW,mBARG;AAAA,IACnB,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,KAAK;AAAA,EAAA,EAI2CD,CAAK,CAAC,IACpD,UAAA;AAAA,IAAA,gBAAApG,EAAC,OAAA,EAAI,WAAU,0CACb,UAAA;AAAA,MAAA,gBAAAR,EAAC,QAAA,EAAK,WAAU,kCAAkC,UAAAyG,GAAM;AAAA,MACvDE;AAAA,IAAA,GACH;AAAA,IACA,gBAAA3G,EAAC,OAAA,EAAI,WAAU,sBAAsB,UAAA0G,GAAM;AAAA,IAC1CG,KAAY,gBAAA7G,EAAC,OAAA,EAAI,WAAU,2BAA2B,UAAA6G,EAAA,CAAS;AAAA,EAAA,GAClE;AAEJ;AAEA,SAASP,GAAW,EAAE,MAAA/F,KAAkC;AACtD,MAAIA,EAAK,WAAW;AAClB,WACE,gBAAAP,EAAC,OAAA,EAAI,WAAU,wEAAuE,UAAA,wCAEtF;AAIJ,QAAM8G,IAAW,KAAK,IAAI,GAAGvG,EAAK,QAAQ,CAACwG,MAAM,CAACA,EAAE,UAAUA,EAAE,MAAM,CAAC,GAAG,CAAC;AAE3E,SACE,gBAAAvG,EAAC,OAAA,EAAI,WAAU,wBACb,UAAA;AAAA,IAAA,gBAAAA,EAAC,OAAA,EAAI,WAAU,gCACb,UAAA;AAAA,MAAA,gBAAAA,EAAC,OAAA,EAAI,WAAU,2BACb,UAAA;AAAA,QAAA,gBAAAR,EAAC,OAAA,EAAI,WAAU,8BAAA,CAA8B;AAAA,QAC7C,gBAAAA,EAAC,QAAA,EAAK,WAAU,WAAU,UAAA,wBAAA,CAAqB;AAAA,MAAA,GACjD;AAAA,MACA,gBAAAQ,EAAC,OAAA,EAAI,WAAU,2BACb,UAAA;AAAA,QAAA,gBAAAR,EAAC,OAAA,EAAI,WAAU,+BAAA,CAA+B;AAAA,QAC9C,gBAAAA,EAAC,QAAA,EAAK,WAAU,WAAU,UAAA,aAAA,CAAU;AAAA,MAAA,EAAA,CACtC;AAAA,IAAA,GACF;AAAA,IACA,gBAAAA,EAAC,OAAA,EAAI,WAAU,oDACZ,UAAAO,EAAK,IAAI,CAACqF,MACT,gBAAApF,EAAC,OAAA,EAAyB,WAAU,oCAClC,UAAA;AAAA,MAAA,gBAAAR;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,WAAU;AAAA,UACV,OAAO;AAAA,YACL,QAAQ,GAAI4F,EAAK,WAAWkB,IAAY,GAAG;AAAA,YAC3C,WAAWlB,EAAK,WAAW,IAAI,QAAQ;AAAA,UAAA;AAAA,UAEzC,OAAO,aAAaA,EAAK,QAAQ;AAAA,QAAA;AAAA,MAAA;AAAA,MAEnC,gBAAA5F;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,WAAU;AAAA,UACV,OAAO;AAAA,YACL,QAAQ,GAAI4F,EAAK,SAASkB,IAAY,GAAG;AAAA,YACzC,WAAWlB,EAAK,SAAS,IAAI,QAAQ;AAAA,UAAA;AAAA,UAEvC,OAAO,eAAeA,EAAK,MAAM;AAAA,QAAA;AAAA,MAAA;AAAA,IACnC,EAAA,GAhBQ,GAAGA,EAAK,IAAI,EAiBtB,CACD,EAAA,CACH;AAAA,IACA,gBAAApF,EAAC,OAAA,EAAI,WAAU,kEACb,UAAA;AAAA,MAAA,gBAAAR,EAAC,QAAA,EAAM,UAAAO,EAAK,CAAC,KAAK,IAAI,KAAKA,EAAK,CAAC,EAAE,IAAI,EAAE,mBAAmB,OAAO,EAAA,CAAE;AAAA,wBACpE,QAAA,EAAM,UAAAA,EAAK,GAAG,EAAE,KAAK,IAAI,KAAKA,EAAK,GAAG,EAAE,EAAG,IAAI,EAAE,mBAAmB,OAAO,EAAA,CAAE;AAAA,IAAA,EAAA,CAChF;AAAA,EAAA,GACF;AAEJ;"}
|
|
1
|
+
{"version":3,"file":"DashboardPage-C9qgPBS-.js","sources":["../../src/components/dashboard/DeviceBreakdownChart.tsx","../../src/components/dashboard/EngagementMetricsCard.tsx","../../src/pages/platform/administration/DashboardPage.tsx"],"sourcesContent":["import React from 'react';\r\nimport { Monitor, Smartphone, Tablet } from 'lucide-react';\r\nimport type { DeviceAnalyticsDto } from '@/services/api/applicationAnalyticsApi';\r\n\r\ninterface DeviceBreakdownChartProps {\r\n readonly data: DeviceAnalyticsDto | null;\r\n}\r\n\r\nconst deviceIcons: Record<string, React.ReactNode> = {\r\n Desktop: <Monitor className=\"w-4 h-4\" />,\r\n Mobile: <Smartphone className=\"w-4 h-4\" />,\r\n Tablet: <Tablet className=\"w-4 h-4\" />,\r\n Unknown: <Monitor className=\"w-4 h-4 opacity-50\" />\r\n};\r\n\r\nconst deviceColors = [\r\n '#3b82f6',\r\n '#22c55e',\r\n '#f59e0b',\r\n '#6b7280'\r\n];\r\n\r\nconst browserColors = [\r\n '#3b82f6',\r\n '#8b5cf6',\r\n '#22c55e',\r\n '#f59e0b',\r\n '#ef4444'\r\n];\r\n\r\nexport const DeviceBreakdownChart: React.FC<DeviceBreakdownChartProps> = ({ data }) => {\r\n if (!data || (!data.byDeviceType?.length && !data.byBrowser?.length)) {\r\n return (\r\n <div className=\"text-center py-8 text-[var(--text-secondary)]\">\r\n No device data available\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-6\">\r\n {/* Device Type Breakdown */}\r\n <div>\r\n <h4 className=\"text-sm font-medium text-[var(--text-secondary)] mb-3\">\r\n By Device Type\r\n </h4>\r\n <div className=\"space-y-3\">\r\n {data.byDeviceType.map((device, index) => (\r\n <div key={device.deviceType} className=\"flex items-center gap-3\">\r\n <div className=\"flex items-center gap-2 w-28\">\r\n {deviceIcons[device.deviceType] || deviceIcons.Unknown}\r\n <span className=\"text-sm\">{device.deviceType}</span>\r\n </div>\r\n <div className=\"flex-1 h-6 bg-[var(--bg-secondary)] rounded-full overflow-hidden\">\r\n <div\r\n className=\"h-full rounded-full transition-all duration-500\"\r\n style={{\r\n width: `${device.percentage}%`,\r\n backgroundColor: deviceColors[index % deviceColors.length]\r\n }}\r\n />\r\n </div>\r\n <div className=\"w-20 text-right\">\r\n <span className=\"font-medium\">{device.count}</span>\r\n <span className=\"text-xs text-[var(--text-secondary)] ml-1\">\r\n ({device.percentage.toFixed(1)}%)\r\n </span>\r\n </div>\r\n </div>\r\n ))}\r\n </div>\r\n </div>\r\n\r\n {/* Browser Breakdown */}\r\n <div>\r\n <h4 className=\"text-sm font-medium text-[var(--text-secondary)] mb-3\">\r\n By Browser\r\n </h4>\r\n <div className=\"space-y-3\">\r\n {data.byBrowser.map((browser, index) => {\r\n const maxCount = Math.max(...data.byBrowser.map(b => b.count), 1);\r\n const percentage = (browser.count / maxCount) * 100;\r\n\r\n return (\r\n <div key={browser.browser} className=\"flex items-center gap-3\">\r\n <div className=\"w-24 text-sm\">{browser.browser}</div>\r\n <div className=\"flex-1 h-6 bg-[var(--bg-secondary)] rounded-full overflow-hidden\">\r\n <div\r\n className=\"h-full rounded-full transition-all duration-500\"\r\n style={{\r\n width: `${percentage}%`,\r\n backgroundColor: browserColors[index % browserColors.length]\r\n }}\r\n />\r\n </div>\r\n <div className=\"w-12 text-right font-medium\">{browser.count}</div>\r\n </div>\r\n );\r\n })}\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n};\r\n","import React from 'react';\r\nimport type { EngagementMetricsDto } from '@/services/api/applicationAnalyticsApi';\r\n\r\ninterface EngagementMetricsCardProps {\r\n readonly data: EngagementMetricsDto | null;\r\n}\r\n\r\nconst sessionColors = ['#ef4444', '#f59e0b', '#22c55e', '#3b82f6'];\r\n\r\nexport const EngagementMetricsCard: React.FC<EngagementMetricsCardProps> = ({ data }) => {\r\n if (!data) {\r\n return (\r\n <div className=\"text-center py-8 text-[var(--text-secondary)]\">\r\n No engagement data available\r\n </div>\r\n );\r\n }\r\n\r\n const maxBucketCount = Math.max(...data.sessionDistribution.map(b => b.count), 1);\r\n const maxHourCount = Math.max(...data.peakUsageHours.map(h => h.accessCount), 1);\r\n\r\n return (\r\n <div className=\"space-y-6\">\r\n {/* Session Duration Distribution */}\r\n <div>\r\n <h4 className=\"text-sm font-medium text-[var(--text-secondary)] mb-3\">\r\n Session Duration Distribution\r\n </h4>\r\n <div className=\"space-y-3\">\r\n {data.sessionDistribution.map((bucket, index) => {\r\n const percentage = (bucket.count / maxBucketCount) * 100;\r\n\r\n return (\r\n <div key={bucket.bucket} className=\"flex items-center gap-3\">\r\n <div className=\"w-20 text-sm\">{bucket.label}</div>\r\n <div className=\"flex-1 h-6 bg-[var(--bg-secondary)] rounded-full overflow-hidden\">\r\n <div\r\n className=\"h-full rounded-full transition-all duration-500\"\r\n style={{\r\n width: `${percentage}%`,\r\n backgroundColor: sessionColors[index % sessionColors.length]\r\n }}\r\n />\r\n </div>\r\n <div className=\"w-16 text-right\">\r\n <span className=\"font-medium\">{bucket.count}</span>\r\n <span className=\"text-xs text-[var(--text-secondary)] ml-1\">\r\n sessions\r\n </span>\r\n </div>\r\n </div>\r\n );\r\n })}\r\n </div>\r\n </div>\r\n\r\n {/* Peak Usage Hours */}\r\n <div>\r\n <h4 className=\"text-sm font-medium text-[var(--text-secondary)] mb-3\">\r\n Peak Usage Hours\r\n </h4>\r\n <div className=\"flex items-end gap-1 h-32 overflow-x-auto pb-2\">\r\n {data.peakUsageHours.map((hourData) => {\r\n const heightPercentage = (hourData.accessCount / maxHourCount) * 100;\r\n\r\n return (\r\n <div\r\n key={hourData.hour}\r\n className=\"flex-1 min-w-[20px] flex flex-col items-center gap-1\"\r\n >\r\n <div\r\n className=\"w-full bg-gradient-to-t from-blue-500 to-cyan-500 rounded-t transition-all duration-300 hover:opacity-80\"\r\n style={{\r\n height: `${heightPercentage}%`,\r\n minHeight: hourData.accessCount > 0 ? '4px' : '0'\r\n }}\r\n title={`${hourData.hour}h: ${hourData.accessCount} accesses`}\r\n />\r\n {hourData.hour % 3 === 0 && (\r\n <span className=\"text-xs text-[var(--text-secondary)]\">\r\n {hourData.hour}h\r\n </span>\r\n )}\r\n </div>\r\n );\r\n })}\r\n </div>\r\n </div>\r\n\r\n {/* Engagement Summary */}\r\n <div className=\"grid grid-cols-2 gap-4 pt-4 border-t border-[var(--border-color)]\">\r\n <div className=\"text-center p-3 bg-[var(--bg-secondary)] rounded-lg\">\r\n <div className=\"text-2xl font-bold text-blue-600\">\r\n {data.dailyActiveUsers}\r\n </div>\r\n <div className=\"text-xs text-[var(--text-secondary)] mt-1\">\r\n Daily Active Users\r\n </div>\r\n </div>\r\n <div className=\"text-center p-3 bg-[var(--bg-secondary)] rounded-lg\">\r\n <div className=\"text-2xl font-bold text-green-600\">\r\n {(data.retentionRate * 100).toFixed(1)}%\r\n </div>\r\n <div className=\"text-xs text-[var(--text-secondary)] mt-1\">\r\n Retention Rate\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n};\r\n","import { useState, useEffect, useCallback, useRef } from 'react';\r\nimport type { ReactElement } from 'react';\r\nimport { useNavigate } from 'react-router-dom';\r\nimport { useTranslation } from 'react-i18next';\r\nimport {\r\n Users,\r\n UserCheck,\r\n UserX,\r\n UserPlus,\r\n Activity,\r\n AlertTriangle,\r\n Key,\r\n Shield,\r\n TrendingUp,\r\n RefreshCw,\r\n Loader2,\r\n Clock,\r\n Globe,\r\n Monitor,\r\n} from 'lucide-react';\r\nimport {\r\n adminApi,\r\n type UserDashboardOverviewDto,\r\n type UserStatusCountDto,\r\n type UserRoleDistributionDto,\r\n type UserTrendDto,\r\n type SecurityAlertDto,\r\n type ActiveSessionsStatsDto,\r\n type LatestActiveSessionDto,\r\n} from '@/services/api/adminApi';\r\nimport { applicationAnalyticsApi } from '@/services/api/applicationAnalyticsApi';\r\nimport { Breadcrumb } from '@/components/ui/Breadcrumb';\r\nimport { useTenant } from '@/contexts/TenantContext';\r\nimport type { DeviceAnalyticsDto, EngagementMetricsDto } from '@/services/api/applicationAnalyticsApi';\r\nimport { DeviceBreakdownChart } from '@/components/dashboard/DeviceBreakdownChart';\r\nimport { EngagementMetricsCard } from '@/components/dashboard/EngagementMetricsCard';\r\n\r\nconst statusColors: Record<string, string> = {\r\n Active: '#22c55e',\r\n Inactive: '#ef4444',\r\n};\r\n\r\nexport function AdminDashboardPage(): ReactElement {\r\n const { t } = useTranslation(['admin', 'navigation']);\r\n const navigate = useNavigate();\r\n const { currentTenant, isGlobalView } = useTenant();\r\n const [loading, setLoading] = useState(true);\r\n const [refreshing, setRefreshing] = useState(false);\r\n const [period, setPeriod] = useState(30);\r\n\r\n const [overview, setOverview] = useState<UserDashboardOverviewDto | null>(null);\r\n const [statusData, setStatusData] = useState<UserStatusCountDto[]>([]);\r\n const [roleData, setRoleData] = useState<UserRoleDistributionDto[]>([]);\r\n const [trends, setTrends] = useState<UserTrendDto[]>([]);\r\n const [latestSessions, setLatestSessions] = useState<LatestActiveSessionDto[]>([]);\r\n const [securityAlerts, setSecurityAlerts] = useState<SecurityAlertDto[]>([]);\r\n const [sessionStats, setSessionStats] = useState<ActiveSessionsStatsDto | null>(null);\r\n const [deviceStats, setDeviceStats] = useState<DeviceAnalyticsDto | null>(null);\r\n const [engagementMetrics, setEngagementMetrics] = useState<EngagementMetricsDto | null>(null);\r\n const [error, setError] = useState<string | null>(null);\r\n\r\n // Ref to track if component is still mounted (StrictMode protection)\r\n const abortControllerRef = useRef<AbortController | null>(null);\r\n\r\n const loadData = useCallback(async (signal?: AbortSignal) => {\r\n try {\r\n setError(null);\r\n const [\r\n overviewRes,\r\n statusRes,\r\n roleRes,\r\n trendsRes,\r\n latestSessionsRes,\r\n alertsRes,\r\n sessionsRes,\r\n deviceRes,\r\n engagementRes,\r\n ] = await Promise.all([\r\n adminApi.dashboard.getOverview(period, { signal }),\r\n adminApi.dashboard.getByStatus({ signal }),\r\n adminApi.dashboard.getByRole({ signal }),\r\n adminApi.dashboard.getTrends(period, { signal }),\r\n adminApi.dashboard.getLatestActiveSessions(5, { signal }),\r\n adminApi.dashboard.getSecurityAlerts(3, 24, { signal }),\r\n adminApi.dashboard.getActiveSessions({ signal }),\r\n applicationAnalyticsApi.getDeviceStats(period, { signal }),\r\n applicationAnalyticsApi.getEngagementMetrics(period, { signal }),\r\n ]);\r\n\r\n // Only update state if request wasn't aborted\r\n if (!signal?.aborted) {\r\n setOverview(overviewRes ?? null);\r\n setStatusData(statusRes ?? []);\r\n setRoleData(roleRes ?? []);\r\n setTrends(trendsRes ?? []);\r\n setLatestSessions(latestSessionsRes ?? []);\r\n setSecurityAlerts(alertsRes ?? []);\r\n setSessionStats(sessionsRes ?? null);\r\n setDeviceStats(deviceRes ?? null);\r\n setEngagementMetrics(engagementRes ?? null);\r\n }\r\n } catch (err: unknown) {\r\n // Ignore abort errors (expected in StrictMode)\r\n if (err instanceof Error && err.name === 'CanceledError') {\r\n return;\r\n }\r\n console.error('Failed to load dashboard data:', err);\r\n const axiosError = err as { response?: { status?: number; data?: { message?: string } } };\r\n if (axiosError.response?.status === 401) {\r\n setError('Session expirée. Veuillez vous reconnecter.');\r\n } else if (axiosError.response?.status === 403) {\r\n setError('Vous n\\'avez pas les permissions nécessaires pour accéder au dashboard.');\r\n } else {\r\n setError('Erreur lors du chargement des données. Vérifiez que l\\'API est accessible.');\r\n }\r\n } finally {\r\n if (!signal?.aborted) {\r\n setLoading(false);\r\n setRefreshing(false);\r\n }\r\n }\r\n }, [period, currentTenant?.id, isGlobalView]);\r\n\r\n useEffect(() => {\r\n // Abort any previous request before starting a new one\r\n abortControllerRef.current?.abort();\r\n const controller = new AbortController();\r\n abortControllerRef.current = controller;\r\n\r\n loadData(controller.signal);\r\n\r\n // Cleanup: abort request when component unmounts or period changes\r\n return () => {\r\n controller.abort();\r\n };\r\n }, [loadData]);\r\n\r\n const handleRefresh = () => {\r\n // Abort any previous request before starting a new one\r\n abortControllerRef.current?.abort();\r\n const controller = new AbortController();\r\n abortControllerRef.current = controller;\r\n\r\n setRefreshing(true);\r\n loadData(controller.signal);\r\n };\r\n\r\n if (loading) {\r\n return (\r\n <div className=\"flex items-center justify-center min-h-[400px]\">\r\n <Loader2 className=\"w-8 h-8 animate-spin text-[var(--color-primary-600)]\" />\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div className=\"space-y-6\">\r\n {/* Breadcrumb */}\r\n <Breadcrumb\r\n items={[\r\n { label: t('header.title') },\r\n { label: t('dashboard.title') }\r\n ]}\r\n />\r\n\r\n {/* Error Banner */}\r\n {error && (\r\n <div className=\"bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg p-4 flex items-center gap-3\">\r\n <AlertTriangle className=\"w-5 h-5 text-red-600 dark:text-red-400 flex-shrink-0\" />\r\n <div className=\"flex-1\">\r\n <p className=\"text-red-800 dark:text-red-200 font-medium\">{error}</p>\r\n </div>\r\n <button\r\n onClick={handleRefresh}\r\n className=\"text-red-600 dark:text-red-400 hover:text-red-800 dark:hover:text-red-200\"\r\n >\r\n <RefreshCw className=\"w-5 h-5\" />\r\n </button>\r\n </div>\r\n )}\r\n\r\n {/* Header */}\r\n <div className=\"flex items-center justify-between\">\r\n <div>\r\n <h1 className=\"text-2xl font-bold text-[var(--text-primary)] flex items-center gap-2\">\r\n <Users className=\"w-6 h-6\" />\r\n {t('admin:header.title')}\r\n </h1>\r\n <p className=\"text-[var(--text-secondary)] mt-1\">\r\n Vue d'ensemble de la gestion des utilisateurs\r\n </p>\r\n </div>\r\n <div className=\"flex items-center gap-3\">\r\n <select\r\n value={period}\r\n onChange={(e) => setPeriod(Number(e.target.value))}\r\n className=\"input\"\r\n >\r\n <option value={7}>7 derniers jours</option>\r\n <option value={30}>30 derniers jours</option>\r\n <option value={90}>90 derniers jours</option>\r\n </select>\r\n <button\r\n onClick={handleRefresh}\r\n disabled={refreshing}\r\n className=\"btn btn-secondary flex items-center gap-2\"\r\n >\r\n <RefreshCw className={`w-4 h-4 ${refreshing ? 'animate-spin' : ''}`} />\r\n Actualiser\r\n </button>\r\n </div>\r\n </div>\r\n\r\n {/* KPI Cards */}\r\n <div className=\"grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-4\">\r\n <KpiCard\r\n title=\"Total Utilisateurs\"\r\n value={overview?.totalUsers ?? 0}\r\n icon={<Users className=\"w-5 h-5\" />}\r\n color=\"blue\"\r\n />\r\n <KpiCard\r\n title=\"Actifs\"\r\n value={overview?.activeUsers ?? 0}\r\n icon={<UserCheck className=\"w-5 h-5\" />}\r\n color=\"green\"\r\n />\r\n <KpiCard\r\n title=\"Inactifs\"\r\n value={overview?.inactiveUsers ?? 0}\r\n icon={<UserX className=\"w-5 h-5\" />}\r\n color=\"red\"\r\n />\r\n <KpiCard\r\n title=\"Nouveaux\"\r\n value={overview?.newUsers ?? 0}\r\n icon={<UserPlus className=\"w-5 h-5\" />}\r\n color=\"blue\"\r\n subtitle={`${period} derniers jours`}\r\n />\r\n <KpiCard\r\n title=\"Sessions\"\r\n value={overview?.totalSessions ?? 0}\r\n icon={<Activity className=\"w-5 h-5\" />}\r\n color=\"green\"\r\n subtitle={`${period} derniers jours`}\r\n />\r\n <KpiCard\r\n title=\"Connexions Echouées\"\r\n value={overview?.failedLogins ?? 0}\r\n icon={<AlertTriangle className=\"w-5 h-5\" />}\r\n color={(overview?.failedLogins ?? 0) > 10 ? 'red' : 'yellow'}\r\n subtitle={`${period} derniers jours`}\r\n />\r\n </div>\r\n\r\n {/* Security Alerts */}\r\n {(securityAlerts?.length ?? 0) > 0 && (\r\n <div className=\"card p-4 border-l-4 border-red-500\">\r\n <h3 className=\"font-semibold text-red-600 flex items-center gap-2 mb-3\">\r\n <AlertTriangle className=\"w-5 h-5\" />\r\n Alertes Sécurité ({securityAlerts?.length ?? 0})\r\n </h3>\r\n <div className=\"space-y-2 max-h-40 overflow-y-auto\">\r\n {(securityAlerts ?? []).slice(0, 5).map((alert) => (\r\n <button\r\n type=\"button\"\r\n key={alert.userId}\r\n className=\"w-full flex items-center justify-between p-2 bg-red-50 dark:bg-red-900/20 rounded cursor-pointer hover:bg-red-100 dark:hover:bg-red-900/30 text-left\"\r\n onClick={() => navigate(`/administration/users/${alert.userId}`)}\r\n >\r\n <div>\r\n <span className=\"font-medium\">{alert.fullName}</span>\r\n <span className=\"ml-2 text-sm text-[var(--text-secondary)]\">{alert.email}</span>\r\n </div>\r\n <div className=\"flex items-center gap-2\">\r\n <span className=\"text-xs text-red-600 font-medium\">\r\n {alert.failedAttempts} échecs\r\n </span>\r\n <span className=\"text-xs text-[var(--text-secondary)]\">\r\n {alert.ipAddresses?.length ?? 0} IP(s)\r\n </span>\r\n </div>\r\n </button>\r\n ))}\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* Charts Row */}\r\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\r\n {/* Status Distribution */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <UserCheck className=\"w-5 h-5\" />\r\n Utilisateurs par Statut\r\n </h3>\r\n <div className=\"space-y-3\">\r\n {(statusData ?? []).map((item) => {\r\n const total = (statusData ?? []).reduce((sum, s) => sum + s.count, 0);\r\n const percentage = total > 0 ? (item.count / total) * 100 : 0;\r\n return (\r\n <div key={item.status} className=\"flex items-center gap-3\">\r\n <div className=\"w-24 text-sm\">{item.status === 'Active' ? 'Actifs' : 'Inactifs'}</div>\r\n <div className=\"flex-1 h-6 bg-[var(--bg-secondary)] rounded-full overflow-hidden\">\r\n <div\r\n className=\"h-full rounded-full transition-all duration-500\"\r\n style={{\r\n width: `${percentage}%`,\r\n backgroundColor: statusColors[item.status] || '#6b7280',\r\n }}\r\n />\r\n </div>\r\n <div className=\"w-20 text-right\">\r\n <span className=\"font-medium\">{item.count}</span>\r\n <span className=\"text-xs text-[var(--text-secondary)] ml-1\">\r\n ({percentage.toFixed(0)}%)\r\n </span>\r\n </div>\r\n </div>\r\n );\r\n })}\r\n </div>\r\n </div>\r\n\r\n {/* Role Distribution */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <Key className=\"w-5 h-5\" />\r\n Utilisateurs par Rôle\r\n </h3>\r\n <div className=\"space-y-3\">\r\n {(roleData?.length ?? 0) > 0 ? (\r\n (roleData ?? []).map((item, index) => {\r\n const maxCount = Math.max(...(roleData ?? []).map(r => r.count), 1);\r\n const percentage = (item.count / maxCount) * 100;\r\n const colors = ['#3b82f6', '#8b5cf6', '#22c55e', '#f59e0b', '#ef4444'];\r\n return (\r\n <div key={item.roleName} className=\"flex items-center gap-3\">\r\n <div className=\"w-32 text-sm truncate\" title={item.roleName}>{item.roleName}</div>\r\n <div className=\"flex-1 h-6 bg-[var(--bg-secondary)] rounded-full overflow-hidden\">\r\n <div\r\n className=\"h-full rounded-full transition-all duration-500\"\r\n style={{\r\n width: `${percentage}%`,\r\n backgroundColor: colors[index % colors.length],\r\n }}\r\n />\r\n </div>\r\n <div className=\"w-12 text-right font-medium\">{item.count}</div>\r\n </div>\r\n );\r\n })\r\n ) : (\r\n <div className=\"text-center py-4 text-[var(--text-secondary)]\">\r\n Aucun rôle configuré\r\n </div>\r\n )}\r\n </div>\r\n </div>\r\n </div>\r\n\r\n {/* System Stats */}\r\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\r\n {/* System Overview */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <Shield className=\"w-5 h-5\" />\r\n Configuration Système\r\n </h3>\r\n <div className=\"grid grid-cols-2 gap-4\">\r\n <div className=\"text-center p-4 bg-[var(--bg-secondary)] rounded-lg\">\r\n <div className=\"text-3xl font-bold text-purple-600\">{overview?.totalRoles ?? 0}</div>\r\n <div className=\"text-sm text-[var(--text-secondary)]\">Rôles</div>\r\n </div>\r\n <div className=\"text-center p-4 bg-[var(--bg-secondary)] rounded-lg\">\r\n <div className=\"text-3xl font-bold text-green-600\">{overview?.totalPermissions ?? 0}</div>\r\n <div className=\"text-sm text-[var(--text-secondary)]\">Permissions</div>\r\n </div>\r\n <div className=\"text-center p-4 bg-[var(--bg-secondary)] rounded-lg\">\r\n <div className=\"text-3xl font-bold text-blue-600\">{overview?.usersLoggedInRecently ?? 0}</div>\r\n <div className=\"text-sm text-[var(--text-secondary)]\">Connectés récemment</div>\r\n </div>\r\n <div className=\"text-center p-4 bg-[var(--bg-secondary)] rounded-lg\">\r\n <div className=\"text-3xl font-bold text-orange-600\">{sessionStats?.totalActiveSessions ?? 0}</div>\r\n <div className=\"text-sm text-[var(--text-secondary)]\">Sessions actives</div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n {/* Active Sessions Stats */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <Monitor className=\"w-5 h-5\" />\r\n Sessions Actives\r\n </h3>\r\n {sessionStats && ((sessionStats.byBrowser?.length ?? 0) > 0 || (sessionStats.byCountry?.length ?? 0) > 0) ? (\r\n <div className=\"grid grid-cols-2 gap-4\">\r\n <div>\r\n <h4 className=\"text-sm font-medium text-[var(--text-secondary)] mb-2\">Par Navigateur</h4>\r\n <div className=\"space-y-2\">\r\n {(sessionStats.byBrowser ?? []).map((item) => (\r\n <div key={item.browser} className=\"flex items-center justify-between text-sm\">\r\n <span>{item.browser}</span>\r\n <span className=\"font-medium\">{item.count}</span>\r\n </div>\r\n ))}\r\n </div>\r\n </div>\r\n <div>\r\n <h4 className=\"text-sm font-medium text-[var(--text-secondary)] mb-2 flex items-center gap-1\">\r\n <Globe className=\"w-4 h-4\" /> Par Pays\r\n </h4>\r\n <div className=\"space-y-2\">\r\n {(sessionStats.byCountry?.length ?? 0) > 0 ? (\r\n (sessionStats.byCountry ?? []).map((item) => (\r\n <div key={item.country} className=\"flex items-center justify-between text-sm\">\r\n <span>{item.country}</span>\r\n <span className=\"font-medium\">{item.count}</span>\r\n </div>\r\n ))\r\n ) : (\r\n <span className=\"text-[var(--text-secondary)] text-sm\">Non disponible</span>\r\n )}\r\n </div>\r\n </div>\r\n </div>\r\n ) : (\r\n <div className=\"text-center py-8 text-[var(--text-secondary)]\">\r\n Aucune session active\r\n </div>\r\n )}\r\n </div>\r\n </div>\r\n\r\n {/* Device & Engagement Metrics */}\r\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\r\n {/* Device Analytics */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <Monitor className=\"w-5 h-5\" />\r\n Appareils & Navigateurs\r\n </h3>\r\n <DeviceBreakdownChart data={deviceStats} />\r\n </div>\r\n\r\n {/* Engagement Metrics */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <Activity className=\"w-5 h-5\" />\r\n Engagement Utilisateurs\r\n </h3>\r\n <EngagementMetricsCard data={engagementMetrics} />\r\n </div>\r\n </div>\r\n\r\n {/* Trends Chart */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <TrendingUp className=\"w-5 h-5\" />\r\n Tendances ({period} derniers jours)\r\n </h3>\r\n <div className=\"h-64\">\r\n <TrendChart data={trends ?? []} />\r\n </div>\r\n </div>\r\n\r\n {/* Latest Active Sessions */}\r\n <div className=\"card p-4\">\r\n <h3 className=\"font-semibold mb-4 flex items-center gap-2\">\r\n <Clock className=\"w-5 h-5\" />\r\n Dernières Sessions Actives\r\n </h3>\r\n {(latestSessions?.length ?? 0) > 0 ? (\r\n <div className=\"overflow-x-auto\">\r\n <table className=\"w-full\">\r\n <thead>\r\n <tr className=\"border-b border-[var(--border-color)]\">\r\n <th className=\"text-left p-3 font-medium\">Utilisateur</th>\r\n <th className=\"text-right p-3 font-medium\">Durée</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n {(latestSessions ?? []).map((session) => (\r\n <tr\r\n key={session.userId + session.loginAt}\r\n className=\"border-b border-[var(--border-color)] hover:bg-[var(--bg-secondary)] cursor-pointer\"\r\n onClick={() => navigate(`/administration/users/${session.userId}`)}\r\n >\r\n <td className=\"p-3 font-medium\">{session.fullName}</td>\r\n <td className=\"p-3 text-right\">\r\n <span className=\"px-2 py-1 rounded text-xs font-medium bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-400\">\r\n {session.duration}\r\n </span>\r\n </td>\r\n </tr>\r\n ))}\r\n </tbody>\r\n </table>\r\n </div>\r\n ) : (\r\n <div className=\"text-center py-8 text-[var(--text-secondary)]\">\r\n Aucune session active\r\n </div>\r\n )}\r\n </div>\r\n </div>\r\n );\r\n}\r\n\r\nfunction KpiCard({\r\n title,\r\n value,\r\n icon,\r\n color,\r\n subtitle,\r\n}: {\r\n title: string;\r\n value: string | number;\r\n icon: React.ReactNode;\r\n color: 'blue' | 'green' | 'yellow' | 'red';\r\n subtitle?: string;\r\n}) {\r\n const colorClasses = {\r\n blue: 'bg-blue-50 text-blue-600 border-blue-200 dark:bg-blue-900/20 dark:border-blue-800',\r\n green: 'bg-green-50 text-green-600 border-green-200 dark:bg-green-900/20 dark:border-green-800',\r\n yellow: 'bg-yellow-50 text-yellow-600 border-yellow-200 dark:bg-yellow-900/20 dark:border-yellow-800',\r\n red: 'bg-red-50 text-red-600 border-red-200 dark:bg-red-900/20 dark:border-red-800',\r\n };\r\n\r\n return (\r\n <div className={`card p-4 border ${colorClasses[color]}`}>\r\n <div className=\"flex items-center justify-between mb-2\">\r\n <span className=\"text-sm font-medium opacity-80\">{title}</span>\r\n {icon}\r\n </div>\r\n <div className=\"text-2xl font-bold\">{value}</div>\r\n {subtitle && <div className=\"text-xs opacity-70 mt-1\">{subtitle}</div>}\r\n </div>\r\n );\r\n}\r\n\r\nfunction TrendChart({ data }: { data: UserTrendDto[] }) {\r\n if (data.length === 0) {\r\n return (\r\n <div className=\"flex items-center justify-center h-full text-[var(--text-secondary)]\">\r\n Aucune donnée de tendance disponible\r\n </div>\r\n );\r\n }\r\n\r\n const maxValue = Math.max(...data.flatMap((d) => [d.newUsers, d.logins]), 1);\r\n\r\n return (\r\n <div className=\"flex flex-col h-full\">\r\n <div className=\"flex items-center gap-4 mb-4\">\r\n <div className=\"flex items-center gap-2\">\r\n <div className=\"w-3 h-3 rounded bg-blue-500\" />\r\n <span className=\"text-sm\">Nouveaux utilisateurs</span>\r\n </div>\r\n <div className=\"flex items-center gap-2\">\r\n <div className=\"w-3 h-3 rounded bg-green-500\" />\r\n <span className=\"text-sm\">Connexions</span>\r\n </div>\r\n </div>\r\n <div className=\"flex-1 flex items-end gap-1 overflow-x-auto pb-4\">\r\n {data.map((item) => (\r\n <div key={`${item.date}`} className=\"flex-1 min-w-[20px] flex gap-0.5\">\r\n <div\r\n className=\"flex-1 bg-blue-500 rounded-t transition-all duration-300 hover:opacity-80\"\r\n style={{\r\n height: `${(item.newUsers / maxValue) * 100}%`,\r\n minHeight: item.newUsers > 0 ? '4px' : '0',\r\n }}\r\n title={`Nouveaux: ${item.newUsers}`}\r\n />\r\n <div\r\n className=\"flex-1 bg-green-500 rounded-t transition-all duration-300 hover:opacity-80\"\r\n style={{\r\n height: `${(item.logins / maxValue) * 100}%`,\r\n minHeight: item.logins > 0 ? '4px' : '0',\r\n }}\r\n title={`Connexions: ${item.logins}`}\r\n />\r\n </div>\r\n ))}\r\n </div>\r\n <div className=\"flex justify-between text-xs text-[var(--text-secondary)] mt-2\">\r\n <span>{data[0] && new Date(data[0].date).toLocaleDateString('fr-FR')}</span>\r\n <span>{data.at(-1) && new Date(data.at(-1)!.date).toLocaleDateString('fr-FR')}</span>\r\n </div>\r\n </div>\r\n );\r\n}\r\n"],"names":["deviceIcons","jsx","Monitor","Smartphone","Tablet","deviceColors","browserColors","DeviceBreakdownChart","data","jsxs","device","index","browser","maxCount","b","percentage","sessionColors","EngagementMetricsCard","maxBucketCount","maxHourCount","h","bucket","hourData","heightPercentage","statusColors","AdminDashboardPage","t","useTranslation","navigate","useNavigate","currentTenant","isGlobalView","useTenant","loading","setLoading","useState","refreshing","setRefreshing","period","setPeriod","overview","setOverview","statusData","setStatusData","roleData","setRoleData","trends","setTrends","latestSessions","setLatestSessions","securityAlerts","setSecurityAlerts","sessionStats","setSessionStats","deviceStats","setDeviceStats","engagementMetrics","setEngagementMetrics","error","setError","abortControllerRef","useRef","loadData","useCallback","signal","overviewRes","statusRes","roleRes","trendsRes","latestSessionsRes","alertsRes","sessionsRes","deviceRes","engagementRes","adminApi","applicationAnalyticsApi","err","axiosError","useEffect","controller","handleRefresh","Loader2","Breadcrumb","AlertTriangle","RefreshCw","Users","e","KpiCard","UserCheck","UserX","UserPlus","Activity","alert","item","total","sum","s","Key","r","colors","Shield","Globe","TrendingUp","TrendChart","Clock","session","title","value","icon","color","subtitle","maxValue","d"],"mappings":"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"}
|