@atlashub/smartstack 3.21.0 → 3.24.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-7si3Ng8e.js → AgentSkillsPage-BWQSCYl-.js} +2 -2
- package/dist/chunks/{AgentSkillsPage-7si3Ng8e.js.map → AgentSkillsPage-BWQSCYl-.js.map} +1 -1
- package/dist/chunks/{AgentSkillsPage-D0cD1QdM.js → AgentSkillsPage-IQcMnBaD.js} +2 -2
- package/dist/chunks/{AgentSkillsPage-D0cD1QdM.js.map → AgentSkillsPage-IQcMnBaD.js.map} +1 -1
- package/dist/chunks/{AgentWorkloadPage-H_7ze33H.js → AgentWorkloadPage-DqrjkvWL.js} +2 -2
- package/dist/chunks/{AgentWorkloadPage-H_7ze33H.js.map → AgentWorkloadPage-DqrjkvWL.js.map} +1 -1
- package/dist/chunks/{AgentWorkloadPage-D4d86cdV.js → AgentWorkloadPage-w-HiyFYP.js} +2 -2
- package/dist/chunks/{AgentWorkloadPage-D4d86cdV.js.map → AgentWorkloadPage-w-HiyFYP.js.map} +1 -1
- package/dist/chunks/{ApiCatalogDetailPage-2ktkRrCb.js → ApiCatalogDetailPage-D3L8Yf4G.js} +3 -3
- package/dist/chunks/{ApiCatalogDetailPage-2ktkRrCb.js.map → ApiCatalogDetailPage-D3L8Yf4G.js.map} +1 -1
- package/dist/chunks/{ApiCatalogDetailPage-BQ53xuwD.js → ApiCatalogDetailPage-MPT3Kz6H.js} +2 -2
- package/dist/chunks/{ApiCatalogDetailPage-BQ53xuwD.js.map → ApiCatalogDetailPage-MPT3Kz6H.js.map} +1 -1
- package/dist/chunks/{ApiCatalogPage-BEqTDJz8.js → ApiCatalogPage-D4Hg3uiS.js} +2 -2
- package/dist/chunks/{ApiCatalogPage-BEqTDJz8.js.map → ApiCatalogPage-D4Hg3uiS.js.map} +1 -1
- package/dist/chunks/{ApiCatalogPage-BBkWSLI8.js → ApiCatalogPage-DRg5Cz0r.js} +2 -2
- package/dist/chunks/{ApiCatalogPage-BBkWSLI8.js.map → ApiCatalogPage-DRg5Cz0r.js.map} +1 -1
- package/dist/chunks/{ApplicationDetailPage-BYJ2YMPq.js → ApplicationDetailPage-Caizuyn2.js} +2 -2
- package/dist/chunks/{ApplicationDetailPage-BYJ2YMPq.js.map → ApplicationDetailPage-Caizuyn2.js.map} +1 -1
- package/dist/chunks/{ApplicationDetailPage-D8-bf1as.js → ApplicationDetailPage-CuCW6aMB.js} +4 -4
- package/dist/chunks/{ApplicationDetailPage-D8-bf1as.js.map → ApplicationDetailPage-CuCW6aMB.js.map} +1 -1
- package/dist/chunks/{ApplicationsDashboardPage-BBlLms2r.js → ApplicationsDashboardPage-B2MW8-Kc.js} +2 -2
- package/dist/chunks/{ApplicationsDashboardPage-BBlLms2r.js.map → ApplicationsDashboardPage-B2MW8-Kc.js.map} +1 -1
- package/dist/chunks/{ApplicationsDashboardPage-DTWZxJJM.js → ApplicationsDashboardPage-BDIjFIYZ.js} +3 -3
- package/dist/chunks/{ApplicationsDashboardPage-DTWZxJJM.js.map → ApplicationsDashboardPage-BDIjFIYZ.js.map} +1 -1
- package/dist/chunks/{ApplicationsGridPage-BQaMsK1K.js → ApplicationsGridPage-DV-FihKj.js} +2 -2
- package/dist/chunks/{ApplicationsGridPage-BQaMsK1K.js.map → ApplicationsGridPage-DV-FihKj.js.map} +1 -1
- package/dist/chunks/{ApplicationsGridPage-DbVcvezt.js → ApplicationsGridPage-DXsTfXPI.js} +2 -2
- package/dist/chunks/{ApplicationsGridPage-DbVcvezt.js.map → ApplicationsGridPage-DXsTfXPI.js.map} +1 -1
- package/dist/chunks/{ApplicationsListPage-DYKM2Yeo.js → ApplicationsListPage--CGkyBuJ.js} +2 -2
- package/dist/chunks/{ApplicationsListPage-DYKM2Yeo.js.map → ApplicationsListPage--CGkyBuJ.js.map} +1 -1
- package/dist/chunks/{ApplicationsListPage-C91v2rZt.js → ApplicationsListPage-JUX823bh.js} +2 -2
- package/dist/chunks/{ApplicationsListPage-C91v2rZt.js.map → ApplicationsListPage-JUX823bh.js.map} +1 -1
- package/dist/chunks/{ApplicationsPage-BCbgotIx.js → ApplicationsPage-6zgFye6w.js} +2 -2
- package/dist/chunks/{ApplicationsPage-BCbgotIx.js.map → ApplicationsPage-6zgFye6w.js.map} +1 -1
- package/dist/chunks/{ApplicationsPage-CW3-Hjlu.js → ApplicationsPage-CQPuuiO6.js} +4 -4
- package/dist/chunks/{ApplicationsPage-CW3-Hjlu.js.map → ApplicationsPage-CQPuuiO6.js.map} +1 -1
- package/dist/chunks/{AssignmentRulesPage-D8vfGDBN.js → AssignmentRulesPage-CFffeEbo.js} +2 -2
- package/dist/chunks/{AssignmentRulesPage-D8vfGDBN.js.map → AssignmentRulesPage-CFffeEbo.js.map} +1 -1
- package/dist/chunks/{AssignmentRulesPage-CxktlEMB.js → AssignmentRulesPage-D78UeUId.js} +2 -2
- package/dist/chunks/{AssignmentRulesPage-CxktlEMB.js.map → AssignmentRulesPage-D78UeUId.js.map} +1 -1
- package/dist/chunks/{AssignmentsPage-DmfBYQAD.js → AssignmentsPage-Cww2ifZF.js} +2 -2
- package/dist/chunks/{AssignmentsPage-DmfBYQAD.js.map → AssignmentsPage-Cww2ifZF.js.map} +1 -1
- package/dist/chunks/{AssignmentsPage-sRCCBmRc.js → AssignmentsPage-DE_QS2LO.js} +2 -2
- package/dist/chunks/{AssignmentsPage-sRCCBmRc.js.map → AssignmentsPage-DE_QS2LO.js.map} +1 -1
- package/dist/chunks/{AuthCallbackPage-C7XiZxKb.js → AuthCallbackPage-CA2nO6DG.js} +2 -2
- package/dist/chunks/{AuthCallbackPage-C7XiZxKb.js.map → AuthCallbackPage-CA2nO6DG.js.map} +1 -1
- package/dist/chunks/{AuthCallbackPage-BCe_bwJM.js → AuthCallbackPage-CDUAoX-N.js} +2 -2
- package/dist/chunks/{AuthCallbackPage-BCe_bwJM.js.map → AuthCallbackPage-CDUAoX-N.js.map} +1 -1
- package/dist/chunks/{ConfirmEmailPage-BUfGSqxF.js → ConfirmEmailPage-BqsILAYH.js} +2 -2
- package/dist/chunks/{ConfirmEmailPage-BUfGSqxF.js.map → ConfirmEmailPage-BqsILAYH.js.map} +1 -1
- package/dist/chunks/{ConfirmEmailPage-Buj4x-rx.js → ConfirmEmailPage-INeHCuMB.js} +2 -2
- package/dist/chunks/{ConfirmEmailPage-Buj4x-rx.js.map → ConfirmEmailPage-INeHCuMB.js.map} +1 -1
- package/dist/chunks/{CreateSupportTicketPage-CKDX_HQm.js → CreateSupportTicketPage-BWeuV2aU.js} +2 -2
- package/dist/chunks/{CreateSupportTicketPage-CKDX_HQm.js.map → CreateSupportTicketPage-BWeuV2aU.js.map} +1 -1
- package/dist/chunks/{CreateSupportTicketPage-0LgY-_pu.js → CreateSupportTicketPage-OBwF4v7b.js} +2 -2
- package/dist/chunks/{CreateSupportTicketPage-0LgY-_pu.js.map → CreateSupportTicketPage-OBwF4v7b.js.map} +1 -1
- package/dist/chunks/{DashboardPage-CUZ80NGV.js → DashboardPage-CKHqWrdS.js} +3 -3
- package/dist/chunks/{DashboardPage-CUZ80NGV.js.map → DashboardPage-CKHqWrdS.js.map} +1 -1
- package/dist/chunks/{DashboardPage-CaNOAstg.js → DashboardPage-COmc9b__.js} +3 -3
- package/dist/chunks/{DashboardPage-CaNOAstg.js.map → DashboardPage-COmc9b__.js.map} +1 -1
- package/dist/chunks/{DashboardPage-B48_rQFi.js → DashboardPage-CfKZHiSj.js} +2 -2
- package/dist/chunks/{DashboardPage-B48_rQFi.js.map → DashboardPage-CfKZHiSj.js.map} +1 -1
- package/dist/chunks/{DashboardPage-CUZV1J9t.js → DashboardPage-CwEZZ3jx.js} +2 -2
- package/dist/chunks/{DashboardPage-CUZV1J9t.js.map → DashboardPage-CwEZZ3jx.js.map} +1 -1
- package/dist/chunks/{EscalationConfigPage-CdzAbnGy.js → EscalationConfigPage--7lgZ0kJ.js} +2 -2
- package/dist/chunks/{EscalationConfigPage-CdzAbnGy.js.map → EscalationConfigPage--7lgZ0kJ.js.map} +1 -1
- package/dist/chunks/{EscalationConfigPage-CYGIl_e6.js → EscalationConfigPage-DPyiBcqV.js} +2 -2
- package/dist/chunks/{EscalationConfigPage-CYGIl_e6.js.map → EscalationConfigPage-DPyiBcqV.js.map} +1 -1
- package/dist/chunks/{ForceChangePasswordPage-lRpkwcX7.js → ForceChangePasswordPage-BE-6umub.js} +2 -2
- package/dist/chunks/{ForceChangePasswordPage-lRpkwcX7.js.map → ForceChangePasswordPage-BE-6umub.js.map} +1 -1
- package/dist/chunks/{ForceChangePasswordPage-CvmYAV3r.js → ForceChangePasswordPage-CnsYoWmV.js} +2 -2
- package/dist/chunks/{ForceChangePasswordPage-CvmYAV3r.js.map → ForceChangePasswordPage-CnsYoWmV.js.map} +1 -1
- package/dist/chunks/{ForgotPasswordPage-0u49E4Pw.js → ForgotPasswordPage-CSq4DnFF.js} +2 -2
- package/dist/chunks/{ForgotPasswordPage-0u49E4Pw.js.map → ForgotPasswordPage-CSq4DnFF.js.map} +1 -1
- package/dist/chunks/{ForgotPasswordPage-CxQUqKOm.js → ForgotPasswordPage-DZLVolAC.js} +2 -2
- package/dist/chunks/{ForgotPasswordPage-CxQUqKOm.js.map → ForgotPasswordPage-DZLVolAC.js.map} +1 -1
- package/dist/chunks/{GroupDetailPage-DFBvVO1S.js → GroupDetailPage-Bf9Wb_2j.js} +5 -5
- package/dist/chunks/{GroupDetailPage-DFBvVO1S.js.map → GroupDetailPage-Bf9Wb_2j.js.map} +1 -1
- package/dist/chunks/{GroupDetailPage-B2FkKrGG.js → GroupDetailPage-R-hf3rJ7.js} +2 -2
- package/dist/chunks/{GroupDetailPage-B2FkKrGG.js.map → GroupDetailPage-R-hf3rJ7.js.map} +1 -1
- package/dist/chunks/{MyAccessRequestsPage-C9IX4c0K.js → MyAccessRequestsPage-BIisvWM6.js} +2 -2
- package/dist/chunks/{MyAccessRequestsPage-C9IX4c0K.js.map → MyAccessRequestsPage-BIisvWM6.js.map} +1 -1
- package/dist/chunks/{MyAccessRequestsPage-D6pVULNM.js → MyAccessRequestsPage-BLSV7Tbx.js} +2 -2
- package/dist/chunks/{MyAccessRequestsPage-D6pVULNM.js.map → MyAccessRequestsPage-BLSV7Tbx.js.map} +1 -1
- package/dist/chunks/{MyTenantsPage-BEcYYdGR.js → MyTenantsPage-D-7k9CP1.js} +3 -3
- package/dist/chunks/{MyTenantsPage-BEcYYdGR.js.map → MyTenantsPage-D-7k9CP1.js.map} +1 -1
- package/dist/chunks/{MyTenantsPage-D9f85zjF.js → MyTenantsPage-DqGW6aDt.js} +2 -2
- package/dist/chunks/{MyTenantsPage-D9f85zjF.js.map → MyTenantsPage-DqGW6aDt.js.map} +1 -1
- package/dist/chunks/{MyTicketsPage-DJR8h6y1.js → MyTicketsPage--DgDsnZA.js} +2 -2
- package/dist/chunks/{MyTicketsPage-DJR8h6y1.js.map → MyTicketsPage--DgDsnZA.js.map} +1 -1
- package/dist/chunks/{MyTicketsPage-DiOUExKJ.js → MyTicketsPage-CqJ3Aqob.js} +2 -2
- package/dist/chunks/{MyTicketsPage-DiOUExKJ.js.map → MyTicketsPage-CqJ3Aqob.js.map} +1 -1
- package/dist/chunks/{NavigationAppsPage-CeHbxfZw.js → NavigationAppsPage-Bebis_RT.js} +2 -2
- package/dist/chunks/{NavigationAppsPage-CeHbxfZw.js.map → NavigationAppsPage-Bebis_RT.js.map} +1 -1
- package/dist/chunks/{NavigationAppsPage-If7tmCFY.js → NavigationAppsPage-THNPOAjv.js} +2 -2
- package/dist/chunks/{NavigationAppsPage-If7tmCFY.js.map → NavigationAppsPage-THNPOAjv.js.map} +1 -1
- package/dist/chunks/{NotificationsPage-C29Lln5o.js → NotificationsPage-CAbNW_Cn.js} +2 -2
- package/dist/chunks/{NotificationsPage-C29Lln5o.js.map → NotificationsPage-CAbNW_Cn.js.map} +1 -1
- package/dist/chunks/{NotificationsPage-BiaLRb0s.js → NotificationsPage-DxwizUhL.js} +2 -2
- package/dist/chunks/{NotificationsPage-BiaLRb0s.js.map → NotificationsPage-DxwizUhL.js.map} +1 -1
- package/dist/chunks/{OnboardingWizardPage-DQrBKNBq.js → OnboardingWizardPage-C6HlbJ3K.js} +2 -2
- package/dist/chunks/{OnboardingWizardPage-DQrBKNBq.js.map → OnboardingWizardPage-C6HlbJ3K.js.map} +1 -1
- package/dist/chunks/{OnboardingWizardPage-BQah4cI8.js → OnboardingWizardPage-CyC2zONO.js} +2 -2
- package/dist/chunks/{OnboardingWizardPage-BQah4cI8.js.map → OnboardingWizardPage-CyC2zONO.js.map} +1 -1
- package/dist/chunks/{PermissionDetailPage-Ckjdjvf9.js → PermissionDetailPage-BDHiNgky.js} +2 -2
- package/dist/chunks/{PermissionDetailPage-Ckjdjvf9.js.map → PermissionDetailPage-BDHiNgky.js.map} +1 -1
- package/dist/chunks/{PermissionDetailPage-Dh8v7mGj.js → PermissionDetailPage-C5K17ydY.js} +2 -2
- package/dist/chunks/{PermissionDetailPage-Dh8v7mGj.js.map → PermissionDetailPage-C5K17ydY.js.map} +1 -1
- package/dist/chunks/{PermissionsPage-l0PnY-EE.js → PermissionsPage-COI5LJPo.js} +2 -2
- package/dist/chunks/{PermissionsPage-l0PnY-EE.js.map → PermissionsPage-COI5LJPo.js.map} +1 -1
- package/dist/chunks/{PermissionsPage-DLy9U3P3.js → PermissionsPage-CkOwH2_d.js} +2 -2
- package/dist/chunks/{PermissionsPage-DLy9U3P3.js.map → PermissionsPage-CkOwH2_d.js.map} +1 -1
- package/dist/chunks/{PortalDashboardPage-DFBx38-x.js → PortalDashboardPage-CoEC4CmC.js} +2 -2
- package/dist/chunks/{PortalDashboardPage-DFBx38-x.js.map → PortalDashboardPage-CoEC4CmC.js.map} +1 -1
- package/dist/chunks/{PortalDashboardPage-rQYhrX0q.js → PortalDashboardPage-DrYymEf-.js} +2 -2
- package/dist/chunks/{PortalDashboardPage-rQYhrX0q.js.map → PortalDashboardPage-DrYymEf-.js.map} +1 -1
- package/dist/chunks/{PreferencesPage-BBu8yZQB.js → PreferencesPage-CJRaU3ba.js} +2 -2
- package/dist/chunks/{PreferencesPage-BBu8yZQB.js.map → PreferencesPage-CJRaU3ba.js.map} +1 -1
- package/dist/chunks/{PreferencesPage-B81MsNV1.js → PreferencesPage-Cqr9mAab.js} +2 -2
- package/dist/chunks/{PreferencesPage-B81MsNV1.js.map → PreferencesPage-Cqr9mAab.js.map} +1 -1
- package/dist/chunks/{ProfilePage-DDrl10zj.js → ProfilePage-BZVpg6-l.js} +2 -2
- package/dist/chunks/{ProfilePage-DDrl10zj.js.map → ProfilePage-BZVpg6-l.js.map} +1 -1
- package/dist/chunks/{ProfilePage-DPoXwdnc.js → ProfilePage-Cu_FITeL.js} +2 -2
- package/dist/chunks/{ProfilePage-DPoXwdnc.js.map → ProfilePage-Cu_FITeL.js.map} +1 -1
- package/dist/chunks/{ReferencesManagementPage-eFsKjIEK.js → ReferencesManagementPage-DUlVk9Ps.js} +3 -3
- package/dist/chunks/{ReferencesManagementPage-eFsKjIEK.js.map → ReferencesManagementPage-DUlVk9Ps.js.map} +1 -1
- package/dist/chunks/{ReferencesManagementPage-DhVsuElE.js → ReferencesManagementPage-ZCuYtqd7.js} +2 -2
- package/dist/chunks/{ReferencesManagementPage-DhVsuElE.js.map → ReferencesManagementPage-ZCuYtqd7.js.map} +1 -1
- package/dist/chunks/{RegisterPage-CiQib3-6.js → RegisterPage-C4xmVwh9.js} +2 -2
- package/dist/chunks/{RegisterPage-CiQib3-6.js.map → RegisterPage-C4xmVwh9.js.map} +1 -1
- package/dist/chunks/{RegisterPage-bXCcJD88.js → RegisterPage-DGyzoIHT.js} +2 -2
- package/dist/chunks/{RegisterPage-bXCcJD88.js.map → RegisterPage-DGyzoIHT.js.map} +1 -1
- package/dist/chunks/{ResetPasswordPage-Dqiahhnj.js → ResetPasswordPage-DqDD6VPR.js} +2 -2
- package/dist/chunks/{ResetPasswordPage-Dqiahhnj.js.map → ResetPasswordPage-DqDD6VPR.js.map} +1 -1
- package/dist/chunks/{ResetPasswordPage-CubPG3yv.js → ResetPasswordPage-Glu-aeqv.js} +2 -2
- package/dist/chunks/{ResetPasswordPage-CubPG3yv.js.map → ResetPasswordPage-Glu-aeqv.js.map} +1 -1
- package/dist/chunks/{ResolutionModal-Bg7XZmR1.js → ResolutionModal-CxjANAOP.js} +2 -2
- package/dist/chunks/{ResolutionModal-Bg7XZmR1.js.map → ResolutionModal-CxjANAOP.js.map} +1 -1
- package/dist/chunks/{ResolutionModal-DqRk_T0n.js → ResolutionModal-Duat18qV.js} +2 -2
- package/dist/chunks/{ResolutionModal-DqRk_T0n.js.map → ResolutionModal-Duat18qV.js.map} +1 -1
- package/dist/chunks/{RoleDetailPage-Blau6_4c.js → RoleDetailPage-BQffUSnt.js} +3 -3
- package/dist/chunks/{RoleDetailPage-Blau6_4c.js.map → RoleDetailPage-BQffUSnt.js.map} +1 -1
- package/dist/chunks/{RoleDetailPage-CiRVxxIP.js → RoleDetailPage-JTm5lD1_.js} +2 -2
- package/dist/chunks/{RoleDetailPage-CiRVxxIP.js.map → RoleDetailPage-JTm5lD1_.js.map} +1 -1
- package/dist/chunks/{RolesPage-Pm-RN3lP.js → RolesPage-B9rRzciI.js} +2 -2
- package/dist/chunks/{RolesPage-Pm-RN3lP.js.map → RolesPage-B9rRzciI.js.map} +1 -1
- package/dist/chunks/{RolesPage-Cb8joqdJ.js → RolesPage-BN8_zMOC.js} +2 -2
- package/dist/chunks/{RolesPage-Cb8joqdJ.js.map → RolesPage-BN8_zMOC.js.map} +1 -1
- package/dist/chunks/{SlaConfigPage-B86McKM6.js → SlaConfigPage-B7kZNig4.js} +2 -2
- package/dist/chunks/{SlaConfigPage-B86McKM6.js.map → SlaConfigPage-B7kZNig4.js.map} +1 -1
- package/dist/chunks/{SlaConfigPage-BY7gvYU6.js → SlaConfigPage-okvZfA_K.js} +2 -2
- package/dist/chunks/{SlaConfigPage-BY7gvYU6.js.map → SlaConfigPage-okvZfA_K.js.map} +1 -1
- package/dist/chunks/{SupportPermissionsPage-BYxcLMSd.js → SupportPermissionsPage-DGAPqJbl.js} +2 -2
- package/dist/chunks/{SupportPermissionsPage-BYxcLMSd.js.map → SupportPermissionsPage-DGAPqJbl.js.map} +1 -1
- package/dist/chunks/{SupportPermissionsPage-MXqXNJIZ.js → SupportPermissionsPage-Dg_wLOme.js} +2 -2
- package/dist/chunks/{SupportPermissionsPage-MXqXNJIZ.js.map → SupportPermissionsPage-Dg_wLOme.js.map} +1 -1
- package/dist/chunks/{TemplatesPage-BDguJ401.js → TemplatesPage-DT9fhlAU.js} +2 -2
- package/dist/chunks/{TemplatesPage-BDguJ401.js.map → TemplatesPage-DT9fhlAU.js.map} +1 -1
- package/dist/chunks/{TemplatesPage-DdnGgioU.js → TemplatesPage-DiEk538p.js} +2 -2
- package/dist/chunks/{TemplatesPage-DdnGgioU.js.map → TemplatesPage-DiEk538p.js.map} +1 -1
- package/dist/chunks/{TenantCard-ffwWsgFQ.js → TenantCard-BbSYk9_Z.js} +2 -2
- package/dist/chunks/{TenantCard-ffwWsgFQ.js.map → TenantCard-BbSYk9_Z.js.map} +1 -1
- package/dist/chunks/{TenantCard-CUjb6og9.js → TenantCard-CEkiKxcZ.js} +2 -2
- package/dist/chunks/{TenantCard-CUjb6og9.js.map → TenantCard-CEkiKxcZ.js.map} +1 -1
- package/dist/chunks/{TenantScopeSelector-Dz7i1I43.js → TenantScopeSelector-BWfYxvEa.js} +2 -2
- package/dist/chunks/{TenantScopeSelector-Dz7i1I43.js.map → TenantScopeSelector-BWfYxvEa.js.map} +1 -1
- package/dist/chunks/{TenantScopeSelector-Cym_Zyps.js → TenantScopeSelector-D-BKgQPV.js} +2 -2
- package/dist/chunks/{TenantScopeSelector-Cym_Zyps.js.map → TenantScopeSelector-D-BKgQPV.js.map} +1 -1
- package/dist/chunks/{TicketDetailPage-GOh9GX7E.js → TicketDetailPage-C1mNS9Up.js} +2 -2
- package/dist/chunks/{TicketDetailPage-GOh9GX7E.js.map → TicketDetailPage-C1mNS9Up.js.map} +1 -1
- package/dist/chunks/{TicketDetailPage-Du8WMyqf.js → TicketDetailPage-ieVDRh42.js} +2 -2
- package/dist/chunks/{TicketDetailPage-Du8WMyqf.js.map → TicketDetailPage-ieVDRh42.js.map} +1 -1
- package/dist/chunks/{TicketsPage-Bqd6moQy.js → TicketsPage-CnuWsnIW.js} +2 -2
- package/dist/chunks/{TicketsPage-Bqd6moQy.js.map → TicketsPage-CnuWsnIW.js.map} +1 -1
- package/dist/chunks/{TicketsPage-WdU4Bb7M.js → TicketsPage-jjyY15_D.js} +2 -2
- package/dist/chunks/{TicketsPage-WdU4Bb7M.js.map → TicketsPage-jjyY15_D.js.map} +1 -1
- package/dist/chunks/{UserCreateTicketPage-Cm1emgwR.js → UserCreateTicketPage-B8Tvf-ag.js} +2 -2
- package/dist/chunks/{UserCreateTicketPage-Cm1emgwR.js.map → UserCreateTicketPage-B8Tvf-ag.js.map} +1 -1
- package/dist/chunks/{UserCreateTicketPage-BPw-5Y_D.js → UserCreateTicketPage-DnOsDlfO.js} +2 -2
- package/dist/chunks/{UserCreateTicketPage-BPw-5Y_D.js.map → UserCreateTicketPage-DnOsDlfO.js.map} +1 -1
- package/dist/chunks/{UserDashboardPage-BP5WeXPS.js → UserDashboardPage-BrtkJ-NB.js} +2 -2
- package/dist/chunks/{UserDashboardPage-BP5WeXPS.js.map → UserDashboardPage-BrtkJ-NB.js.map} +1 -1
- package/dist/chunks/{UserDashboardPage-B53C8fUq.js → UserDashboardPage-KLB5CQP5.js} +2 -2
- package/dist/chunks/{UserDashboardPage-B53C8fUq.js.map → UserDashboardPage-KLB5CQP5.js.map} +1 -1
- package/dist/chunks/{UserDetailPage-B110bmGX.js → UserDetailPage-U7smBQoF.js} +5 -5
- package/dist/chunks/{UserDetailPage-B110bmGX.js.map → UserDetailPage-U7smBQoF.js.map} +1 -1
- package/dist/chunks/{UserDetailPage-CV2VCE46.js → UserDetailPage-_J6lcKAU.js} +2 -2
- package/dist/chunks/{UserDetailPage-CV2VCE46.js.map → UserDetailPage-_J6lcKAU.js.map} +1 -1
- package/dist/chunks/{UserTicketDetailPage-CCNJON1V.js → UserTicketDetailPage-CWoYQgH-.js} +2 -2
- package/dist/chunks/{UserTicketDetailPage-CCNJON1V.js.map → UserTicketDetailPage-CWoYQgH-.js.map} +1 -1
- package/dist/chunks/{UserTicketDetailPage-V0mLXrox.js → UserTicketDetailPage-DkufSlvZ.js} +2 -2
- package/dist/chunks/{UserTicketDetailPage-V0mLXrox.js.map → UserTicketDetailPage-DkufSlvZ.js.map} +1 -1
- package/dist/chunks/{UsersGroupsPage-CmdaU-z-.js → UsersGroupsPage-C38s2-Rq.js} +3 -3
- package/dist/chunks/{UsersGroupsPage-CmdaU-z-.js.map → UsersGroupsPage-C38s2-Rq.js.map} +1 -1
- package/dist/chunks/{UsersGroupsPage-BgfAMgEP.js → UsersGroupsPage-Dq3rAteo.js} +2 -2
- package/dist/chunks/{UsersGroupsPage-BgfAMgEP.js.map → UsersGroupsPage-Dq3rAteo.js.map} +1 -1
- package/dist/chunks/{UsersPage-Bg7033pp.js → UsersPage-B5C5KEUR.js} +2 -2
- package/dist/chunks/{UsersPage-Bg7033pp.js.map → UsersPage-B5C5KEUR.js.map} +1 -1
- package/dist/chunks/{UsersPage-TYAfwPY1.js → UsersPage-CXC9Hvq6.js} +2 -2
- package/dist/chunks/{UsersPage-TYAfwPY1.js.map → UsersPage-CXC9Hvq6.js.map} +1 -1
- package/dist/chunks/{accessRequestsApi-DZeDvzwv.js → accessRequestsApi-B-4TJ5_U.js} +2 -2
- package/dist/chunks/{accessRequestsApi-DZeDvzwv.js.map → accessRequestsApi-B-4TJ5_U.js.map} +1 -1
- package/dist/chunks/{accessRequestsApi-ZXFPCid2.js → accessRequestsApi-DZSfThpd.js} +2 -2
- package/dist/chunks/{accessRequestsApi-ZXFPCid2.js.map → accessRequestsApi-DZSfThpd.js.map} +1 -1
- package/dist/chunks/{aiApi-CsH8DXgs.js → aiApi-B20Teu2v.js} +2 -2
- package/dist/chunks/{aiApi-CsH8DXgs.js.map → aiApi-B20Teu2v.js.map} +1 -1
- package/dist/chunks/{aiApi-CVPzFTXa.js → aiApi-DMGz-RPM.js} +2 -2
- package/dist/chunks/{aiApi-CVPzFTXa.js.map → aiApi-DMGz-RPM.js.map} +1 -1
- package/dist/chunks/{applicationAnalyticsApi-B8AhFYLr.js → applicationAnalyticsApi-Bwa75Fzd.js} +2 -2
- package/dist/chunks/{applicationAnalyticsApi-B8AhFYLr.js.map → applicationAnalyticsApi-Bwa75Fzd.js.map} +1 -1
- package/dist/chunks/{applicationAnalyticsApi-Ce_1qOk-.js → applicationAnalyticsApi-CLBqRPfN.js} +2 -2
- package/dist/chunks/{applicationAnalyticsApi-Ce_1qOk-.js.map → applicationAnalyticsApi-CLBqRPfN.js.map} +1 -1
- package/dist/chunks/{groupsApi-BgCk2fsp.js → groupsApi-QzXI-5xu.js} +2 -2
- package/dist/chunks/{groupsApi-BgCk2fsp.js.map → groupsApi-QzXI-5xu.js.map} +1 -1
- package/dist/chunks/{groupsApi-BIbG665N.js → groupsApi-hB9kSWEd.js} +2 -2
- package/dist/chunks/{groupsApi-BIbG665N.js.map → groupsApi-hB9kSWEd.js.map} +1 -1
- package/dist/chunks/{index-Cb3LotuT.js → index--NGcBYUu.js} +3 -3
- package/dist/chunks/{index-Cb3LotuT.js.map → index--NGcBYUu.js.map} +1 -1
- package/dist/chunks/{index-C33zcyF4.js → index--aPwOFjF.js} +2 -2
- package/dist/chunks/{index-C33zcyF4.js.map → index--aPwOFjF.js.map} +1 -1
- package/dist/chunks/{index-sMr9qND_.js → index-0VrOtwP0.js} +2 -2
- package/dist/chunks/{index-sMr9qND_.js.map → index-0VrOtwP0.js.map} +1 -1
- package/dist/chunks/{index-DDKetfKq.js → index-37U271aw.js} +2 -2
- package/dist/chunks/{index-DDKetfKq.js.map → index-37U271aw.js.map} +1 -1
- package/dist/chunks/{index-B9fS7ir6.js → index-B7qZTuQ-.js} +2 -2
- package/dist/chunks/{index-B9fS7ir6.js.map → index-B7qZTuQ-.js.map} +1 -1
- package/dist/chunks/{index-CdjBY7L8.js → index-Bedzmqr-.js} +2 -2
- package/dist/chunks/{index-CdjBY7L8.js.map → index-Bedzmqr-.js.map} +1 -1
- package/dist/chunks/{index-CHG_O1fS.js → index-Betxo5g5.js} +2 -2
- package/dist/chunks/{index-CHG_O1fS.js.map → index-Betxo5g5.js.map} +1 -1
- package/dist/chunks/{index-jiGu-H8x.js → index-BmaJz475.js} +2 -2
- package/dist/chunks/{index-jiGu-H8x.js.map → index-BmaJz475.js.map} +1 -1
- package/dist/chunks/{index-C53JoVNk.js → index-Buhqag3v.js} +2 -2
- package/dist/chunks/{index-C53JoVNk.js.map → index-Buhqag3v.js.map} +1 -1
- package/dist/chunks/{index-DO0Rw7hX.js → index-C3VxlfKq.js} +2 -2
- package/dist/chunks/{index-DO0Rw7hX.js.map → index-C3VxlfKq.js.map} +1 -1
- package/dist/chunks/{index-CSQ60fpG.js → index-CgpRo8Oe.js} +2 -2
- package/dist/chunks/{index-CSQ60fpG.js.map → index-CgpRo8Oe.js.map} +1 -1
- package/dist/chunks/{index-B-e-ELsf.js → index-DOY0w8Iu.js} +8 -8
- package/dist/chunks/{index-B-e-ELsf.js.map → index-DOY0w8Iu.js.map} +1 -1
- package/dist/chunks/{index-D2REDIRX.js → index-DwuvIOrQ.js} +2 -2
- package/dist/chunks/{index-D2REDIRX.js.map → index-DwuvIOrQ.js.map} +1 -1
- package/dist/chunks/{index-DCcl7Qof.js → index-DzedSLdI.js} +2 -2
- package/dist/chunks/{index-DCcl7Qof.js.map → index-DzedSLdI.js.map} +1 -1
- package/dist/chunks/{index-2wUhd9Lu.js → index-IgLVXPg8.js} +10 -10
- package/dist/chunks/index-IgLVXPg8.js.map +1 -0
- package/dist/chunks/{index-CwSaRXXg.js → index-lpIzhufD.js} +1916 -1900
- package/dist/chunks/index-lpIzhufD.js.map +1 -0
- package/dist/chunks/{index-Cuwn2q-f.js → index-mLUKwbGl.js} +4 -4
- package/dist/chunks/{index-Cuwn2q-f.js.map → index-mLUKwbGl.js.map} +1 -1
- package/dist/chunks/{index-B0mk2tNY.js → index-tO6MMIFB.js} +2 -2
- package/dist/chunks/{index-B0mk2tNY.js.map → index-tO6MMIFB.js.map} +1 -1
- package/dist/chunks/{tenantIconMap-BpNANQ5s.js → tenantIconMap-BQD9byc8.js} +2 -2
- package/dist/chunks/{tenantIconMap-BpNANQ5s.js.map → tenantIconMap-BQD9byc8.js.map} +1 -1
- package/dist/chunks/{tenantIconMap-DtdUgvJO.js → tenantIconMap-CTMuSt18.js} +2 -2
- package/dist/chunks/{tenantIconMap-DtdUgvJO.js.map → tenantIconMap-CTMuSt18.js.map} +1 -1
- package/dist/chunks/{ticketingApi-Bu4rKwLl.js → ticketingApi-BNIdox5t.js} +2 -2
- package/dist/chunks/{ticketingApi-Bu4rKwLl.js.map → ticketingApi-BNIdox5t.js.map} +1 -1
- package/dist/chunks/{ticketingApi-r4Avm9iS.js → ticketingApi-J0vC_t7r.js} +2 -2
- package/dist/chunks/{ticketingApi-r4Avm9iS.js.map → ticketingApi-J0vC_t7r.js.map} +1 -1
- package/dist/chunks/{useAccessRequests-B9bF4swg.js → useAccessRequests-DCNNLnxk.js} +3 -3
- package/dist/chunks/{useAccessRequests-B9bF4swg.js.map → useAccessRequests-DCNNLnxk.js.map} +1 -1
- package/dist/chunks/{useAccessRequests-JyPUX3Om.js → useAccessRequests-DT7X4FAK.js} +2 -2
- package/dist/chunks/{useAccessRequests-JyPUX3Om.js.map → useAccessRequests-DT7X4FAK.js.map} +1 -1
- package/dist/chunks/{useUserAccessRequests-DjPQenC2.js → useUserAccessRequests-BYbmG4c7.js} +2 -2
- package/dist/chunks/{useUserAccessRequests-DjPQenC2.js.map → useUserAccessRequests-BYbmG4c7.js.map} +1 -1
- package/dist/chunks/{useUserAccessRequests-BB6FHW14.js → useUserAccessRequests-CylKxRN6.js} +2 -2
- package/dist/chunks/{useUserAccessRequests-BB6FHW14.js.map → useUserAccessRequests-CylKxRN6.js.map} +1 -1
- package/dist/hooks/useCollapsibleState.d.ts +5 -2
- package/dist/hooks/useCollapsibleState.d.ts.map +1 -1
- package/dist/i18n/config.d.ts +1 -0
- package/dist/i18n/config.d.ts.map +1 -1
- package/dist/main.d.ts +0 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/smartstack.cjs +1 -1
- package/dist/smartstack.js +1 -1
- package/dist/utils/permissions.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/chunks/index-2wUhd9Lu.js.map +0 -1
- package/dist/chunks/index-CwSaRXXg.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UserDetailPage-B110bmGX.js","sources":["../../src/components/platform/administration/UserRoleAssignment.tsx","../../src/components/platform/administration/permissions/UserPermissionMatrix.tsx","../../src/components/ui/ViewModeToggle.tsx","../../src/components/platform/administration/UserGroupsTab.tsx","../../src/components/ui/SelectWithOther.tsx","../../src/components/platform/administration/users/UserInfoTab.tsx","../../src/components/ui/UnlockAccountModal.tsx","../../src/components/platform/administration/users/UserSecurityTab.tsx","../../src/components/platform/administration/users/UserActivitySessionsTab.tsx","../../src/components/platform/administration/users/UserTenantsTab.tsx","../../src/components/platform/administration/users/UserHistoryTab.tsx","../../src/components/platform/administration/users/UserApplicationsTab.tsx","../../src/hooks/useUserDetail.ts","../../src/hooks/useUserSecurity.ts","../../src/hooks/useUserSections.ts","../../src/hooks/useUserTenants.ts","../../src/pages/platform/administration/users/UserDetailPage.tsx"],"sourcesContent":["import { useState, useMemo, useRef, useCallback, useEffect } from 'react';\r\nimport type { ReactElement } from 'react';\r\nimport { useTranslation } from 'react-i18next';\r\nimport { Link } from 'react-router-dom';\r\nimport { Plus, Trash2, Loader2, Search, Building2, Globe, X, ChevronDown, Filter, AlertCircle, Users, Lock } from 'lucide-react';\r\nimport { adminApi, type RoleListDto, type UserConsolidatedRoleDto } from '@/services/api/adminApi';\r\nimport { getCustomRoleIcon } from '@/utils/roleUtils';\r\nimport { TenantScopeSelector, type ScopeValue } from '@/components/ui/TenantScopeSelector';\r\n\r\ninterface AdminTenantInfo {\r\n tenantId: string;\r\n tenantSlug: string;\r\n tenantName: string;\r\n tenantType: string;\r\n}\r\n\r\ninterface TenantMembership {\r\n tenantId: string;\r\n tenantSlug: string;\r\n tenantUserId: string;\r\n tenantName: string;\r\n}\r\n\r\ninterface UserRoleAssignmentProps {\r\n readonly userId: string;\r\n readonly assignedRoles: UserConsolidatedRoleDto[];\r\n readonly onSave: () => Promise<void>;\r\n readonly onGlobalRolesUpdate: (roleIds: string[]) => Promise<void>;\r\n readonly roles: RoleListDto[];\r\n readonly loading?: boolean;\r\n readonly globalRoleIds: string[];\r\n readonly tenantId?: string;\r\n readonly isGlobalScope?: boolean;\r\n readonly adminTenants?: AdminTenantInfo[];\r\n readonly tenantMemberships?: TenantMembership[];\r\n}\r\n\r\nconst CATEGORY_STYLES: Record<string, { bg: string; text: string }> = {\r\n Global: { bg: 'bg-[var(--accent-bg)]', text: 'text-[var(--color-accent-500)]' },\r\n Admin: { bg: 'bg-[var(--error-bg)]', text: 'text-[var(--error-text)]' },\r\n Manager: { bg: 'bg-[var(--warning-bg)]', text: 'text-[var(--warning-text)]' },\r\n Contributor: { bg: 'bg-[var(--success-bg)]', text: 'text-[var(--success-text)]' },\r\n Viewer: { bg: 'bg-[var(--info-bg)]', text: 'text-[var(--info-text)]' },\r\n Custom: { bg: 'bg-[var(--accent-bg)]', text: 'text-[var(--color-accent-700)]' },\r\n};\r\n\r\nconst DEFAULT_CATEGORY_STYLE = { bg: 'bg-[var(--bg-secondary)]', text: 'text-[var(--text-secondary)]' };\r\n\r\nconst SOURCE_STYLES: Record<string, { bg: string; text: string; icon: React.ElementType }> = {\r\n Direct: { bg: 'bg-[var(--success-bg)]', text: 'text-[var(--success-text)]', icon: Globe },\r\n Group: { bg: 'bg-[var(--accent-bg)]', text: 'text-[var(--color-accent-700)]', icon: Users },\r\n Custom: { bg: 'bg-[var(--warning-bg)]', text: 'text-[var(--warning-text)]', icon: Lock },\r\n};\r\n\r\nexport function UserRoleAssignment({\r\n userId,\r\n assignedRoles = [],\r\n onSave,\r\n onGlobalRolesUpdate,\r\n roles: rolesProp,\r\n loading = false,\r\n globalRoleIds,\r\n tenantId,\r\n isGlobalScope = true,\r\n adminTenants = [],\r\n tenantMemberships = [],\r\n}: UserRoleAssignmentProps): ReactElement {\r\n const { t } = useTranslation(['admin', 'groups']);\r\n const roles = Array.isArray(rolesProp) ? rolesProp : [];\r\n\r\n const [searchQuery, setSearchQuery] = useState('');\r\n const [scopeFilter, setScopeFilter] = useState<string>('all');\r\n const [removing, setRemoving] = useState<string | null>(null);\r\n const [modalOpen, setModalOpen] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n const removingRef = useRef(false);\r\n\r\n // Build tenant options from user's memberships only\r\n const tenantOptions = useMemo(() => {\r\n return tenantMemberships\r\n .map(m => ({ id: m.tenantId, name: m.tenantName }))\r\n .sort((a, b) => a.name.localeCompare(b.name));\r\n }, [tenantMemberships]);\r\n\r\n // --- Overview table: filtered by scope + search ---\r\n\r\n const filteredAssignedRoles = useMemo(() => {\r\n // First: scope filter\r\n let scoped = assignedRoles;\r\n if (scopeFilter === 'global') {\r\n scoped = scoped.filter(ar => !ar.tenantId);\r\n } else if (scopeFilter !== 'all') {\r\n scoped = scoped.filter(ar => !ar.tenantId || ar.tenantId === scopeFilter);\r\n }\r\n\r\n // Then: text search\r\n if (!searchQuery.trim()) return scoped;\r\n const query = searchQuery.toLowerCase().trim();\r\n return scoped.filter(ar =>\r\n ar.roleName.toLowerCase().includes(query) ||\r\n ar.tenantName?.toLowerCase().includes(query) ||\r\n ar.sourceGroupName?.toLowerCase().includes(query)\r\n );\r\n }, [assignedRoles, searchQuery, scopeFilter]);\r\n\r\n // Build a map of roleId -> RoleListDto for category lookup\r\n const roleMap = useMemo(() => {\r\n const map = new Map<string, RoleListDto>();\r\n for (const r of roles) map.set(r.id, r);\r\n return map;\r\n }, [roles]);\r\n\r\n const handleRemoveRole = useCallback(async (roleId: string, roleTenantId: string | null) => {\r\n if (removingRef.current) return;\r\n removingRef.current = true;\r\n setRemoving(roleId + (roleTenantId || 'global'));\r\n setError(null);\r\n\r\n try {\r\n if (!roleTenantId) {\r\n // Global scope: remove from global role IDs via callback\r\n const newRoleIds = globalRoleIds.filter(id => id !== roleId);\r\n await onGlobalRolesUpdate(newRoleIds);\r\n } else {\r\n // Tenant scope: use individual remove endpoint\r\n const membership = tenantMemberships.find(m => m.tenantId === roleTenantId);\r\n if (membership) {\r\n await adminApi.tenants.removeRole(roleTenantId, membership.tenantUserId, roleId);\r\n }\r\n }\r\n await onSave();\r\n } catch (err) {\r\n console.error('Failed to remove role assignment:', err);\r\n setError(t('admin:userRoles.errors.removeFailed', 'Erreur lors du retrait du rôle'));\r\n } finally {\r\n setRemoving(null);\r\n removingRef.current = false;\r\n }\r\n }, [globalRoleIds, tenantMemberships, onGlobalRolesUpdate, onSave, t]);\r\n\r\n const handleOpenModal = useCallback(() => setModalOpen(true), []);\r\n const handleCloseModal = useCallback(() => setModalOpen(false), []);\r\n\r\n const handleAssigned = useCallback(async () => {\r\n await onSave();\r\n }, [onSave]);\r\n\r\n return (\r\n <div className=\"space-y-4\">\r\n {/* Error alert */}\r\n {error && (\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--error-bg)] border border-[var(--error-border)] flex items-center gap-3\">\r\n <AlertCircle className=\"w-5 h-5 text-[var(--error-text)] flex-shrink-0\" />\r\n <p className=\"flex-1 text-[var(--error-text)]\">{error}</p>\r\n <button onClick={() => setError(null)} className=\"ml-auto\">\r\n <X className=\"w-4 h-4 text-[var(--error-text)]\" />\r\n </button>\r\n </div>\r\n )}\r\n\r\n {/* Header: search + scope filter + assign button */}\r\n <div className=\"flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3\">\r\n <div className=\"flex items-center gap-3 flex-1\">\r\n <div className=\"relative flex-1 max-w-md\">\r\n <Search className=\"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-[var(--text-muted)]\" />\r\n <input\r\n type=\"text\"\r\n value={searchQuery}\r\n onChange={(e) => setSearchQuery(e.target.value)}\r\n placeholder={t('admin:userRoles.search', 'Rechercher un rôle...')}\r\n className=\"w-full pl-10 pr-4 py-2 text-sm bg-[var(--bg-secondary)] border border-[var(--border-color)] rounded-[var(--radius-input)] text-[var(--text-primary)] placeholder-[var(--text-muted)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n />\r\n </div>\r\n <div className=\"relative\">\r\n <select\r\n value={scopeFilter}\r\n onChange={(e) => setScopeFilter(e.target.value)}\r\n className=\"px-3 py-2 pr-8 text-sm bg-[var(--bg-secondary)] border border-[var(--border-color)] rounded-[var(--radius-input)] text-[var(--text-primary)] appearance-none focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n >\r\n <option value=\"all\">{t('admin:userRoles.scopeAll', 'Tous les tenants')}</option>\r\n <option value=\"global\">{t('admin:roles.global', 'Global')}</option>\r\n {tenantOptions.map(to => (\r\n <option key={to.id} value={to.id}>{to.name}</option>\r\n ))}\r\n </select>\r\n <ChevronDown className=\"absolute right-2.5 top-1/2 -translate-y-1/2 w-4 h-4 pointer-events-none text-[var(--text-tertiary)]\" />\r\n </div>\r\n </div>\r\n <button\r\n onClick={handleOpenModal}\r\n className=\"flex items-center gap-2 px-4 py-2 rounded-[var(--radius-button)] bg-[var(--color-accent-600)] text-white hover:bg-[var(--color-accent-700)] transition-colors text-sm font-medium\"\r\n >\r\n <Plus className=\"w-4 h-4\" />\r\n {t('admin:userRoles.assignRole', 'Assigner un rôle')}\r\n </button>\r\n </div>\r\n\r\n {/* Overview table */}\r\n {loading ? (\r\n <div className=\"flex items-center justify-center py-12\">\r\n <Loader2 className=\"w-6 h-6 animate-spin text-[var(--color-accent-500)]\" />\r\n </div>\r\n ) : (\r\n <div className=\"overflow-x-auto\">\r\n <table className=\"w-full border border-[var(--border-color)] rounded-[var(--radius-card)] overflow-hidden\">\r\n <thead className=\"bg-[var(--bg-tertiary)]\">\r\n <tr>\r\n <th className=\"text-left px-4 py-3 text-sm font-medium text-[var(--text-secondary)]\">\r\n {t('admin:roles.name', 'Rôle')}\r\n </th>\r\n <th className=\"text-left px-4 py-3 text-sm font-medium text-[var(--text-secondary)]\">\r\n {t('admin:roles.category', 'Catégorie')}\r\n </th>\r\n <th className=\"text-left px-4 py-3 text-sm font-medium text-[var(--text-secondary)]\">\r\n {t('admin:roles.tenant', 'Tenant')}\r\n </th>\r\n <th className=\"text-left px-4 py-3 text-sm font-medium text-[var(--text-secondary)]\">\r\n {t('admin:userRoles.source', 'Source')}\r\n </th>\r\n <th className=\"text-left px-4 py-3 text-sm font-medium text-[var(--text-secondary)] w-24\">\r\n {t('admin:roles.actions', 'Actions')}\r\n </th>\r\n </tr>\r\n </thead>\r\n <tbody className=\"divide-y divide-[var(--border-color)]\">\r\n {filteredAssignedRoles.length === 0 ? (\r\n <tr>\r\n <td colSpan={5} className=\"px-4 py-8 text-center text-[var(--text-muted)]\">\r\n {assignedRoles.length === 0\r\n ? t('admin:userRoles.noAssignedRoles', 'Aucun rôle assigné à cet utilisateur')\r\n : t('admin:userRoles.noRoles', 'Aucun rôle trouvé')}\r\n </td>\r\n </tr>\r\n ) : (\r\n filteredAssignedRoles.map((ar) => {\r\n const roleDetail = roleMap.get(ar.roleId);\r\n const category = roleDetail?.category || 'Custom';\r\n const catStyle = CATEGORY_STYLES[category] || DEFAULT_CATEGORY_STYLE;\r\n const customIcon = roleDetail ? getCustomRoleIcon(roleDetail.code) : null;\r\n const isGlobal = !ar.tenantId;\r\n const isGroupSourced = ar.source === 'Group';\r\n const sourceStyle = SOURCE_STYLES[ar.source] || SOURCE_STYLES.Direct;\r\n const SourceIcon = sourceStyle.icon;\r\n const removingKey = ar.roleId + (ar.tenantId || 'global');\r\n const isRemoving = removing === removingKey;\r\n\r\n return (\r\n <tr key={`${ar.roleId}-${ar.tenantId || 'global'}-${ar.source}`} className=\"hover:bg-[var(--bg-hover)] transition-colors\">\r\n <td className=\"px-4 py-3\">\r\n <div className=\"flex items-center gap-2\">\r\n {customIcon && <span>{customIcon}</span>}\r\n <Link\r\n to={`/administration/permissions/roles/${ar.roleId}`}\r\n className=\"font-medium text-[var(--text-primary)] hover:text-[var(--color-accent-600)] hover:underline transition-colors\"\r\n >\r\n {ar.roleName}\r\n </Link>\r\n </div>\r\n {ar.roleShortName && (\r\n <p className=\"text-xs text-[var(--text-tertiary)] mt-0.5\">{ar.roleShortName}</p>\r\n )}\r\n </td>\r\n <td className=\"px-4 py-3\">\r\n <span className={`px-2 py-1 text-xs rounded-full ${catStyle.bg} ${catStyle.text}`}>\r\n {category}\r\n </span>\r\n </td>\r\n <td className=\"px-4 py-3\">\r\n {isGlobal ? (\r\n <span className=\"inline-flex items-center gap-1 px-2 py-1 text-xs rounded-full bg-[var(--info-bg)] text-[var(--info-text)]\">\r\n <Globe className=\"w-3 h-3\" />\r\n {t('admin:roles.global', 'Global')}\r\n </span>\r\n ) : (\r\n <span className=\"inline-flex items-center gap-1 px-2 py-1 text-xs rounded-full bg-[var(--accent-bg)] text-[var(--color-accent-700)]\">\r\n <Building2 className=\"w-3 h-3\" />\r\n {ar.tenantName || t('admin:roles.unknownTenant', 'Tenant')}\r\n </span>\r\n )}\r\n </td>\r\n <td className=\"px-4 py-3\">\r\n <span className={`inline-flex items-center gap-1 px-2 py-1 text-xs rounded-full ${sourceStyle.bg} ${sourceStyle.text}`}>\r\n <SourceIcon className=\"w-3 h-3\" />\r\n {ar.source === 'Direct'\r\n ? t('admin:userRoles.sourceDirect', 'Direct')\r\n : ar.source === 'Group'\r\n ? ar.sourceGroupName || t('admin:userRoles.sourceGroup', 'Groupe')\r\n : t('admin:userRoles.sourceCustom', 'Personnel')}\r\n </span>\r\n </td>\r\n <td className=\"px-4 py-3\">\r\n {isGroupSourced ? (\r\n <span title={t('admin:userRoles.groupRoleLocked', 'Rôle hérité du groupe, non supprimable')}>\r\n <Lock className=\"w-4 h-4 text-[var(--text-muted)]\" />\r\n </span>\r\n ) : (\r\n <button\r\n onClick={() => handleRemoveRole(ar.roleId, ar.tenantId)}\r\n disabled={isRemoving}\r\n className=\"p-1.5 rounded-[var(--radius-button)] text-[var(--error-text)] hover:bg-[var(--error-bg)] transition-colors disabled:opacity-50\"\r\n title={t('admin:userRoles.removeRole', 'Retirer le rôle')}\r\n >\r\n {isRemoving ? (\r\n <Loader2 className=\"w-4 h-4 animate-spin\" />\r\n ) : (\r\n <Trash2 className=\"w-4 h-4\" />\r\n )}\r\n </button>\r\n )}\r\n </td>\r\n </tr>\r\n );\r\n })\r\n )}\r\n </tbody>\r\n </table>\r\n {assignedRoles.length > 0 && (\r\n <div className=\"px-4 py-2 text-xs text-[var(--text-muted)] bg-[var(--bg-tertiary)] border-t border-[var(--border-color)]\">\r\n {filteredAssignedRoles.length !== assignedRoles.length\r\n ? t('admin:userRoles.totalFiltered', '{{filtered}} / {{count}} rôle(s) affiché(s)', { filtered: filteredAssignedRoles.length, count: assignedRoles.length })\r\n : t('admin:userRoles.totalAssigned', '{{count}} rôle(s) assigné(s)', { count: assignedRoles.length })}\r\n </div>\r\n )}\r\n </div>\r\n )}\r\n\r\n {/* Assign Role Modal */}\r\n {modalOpen && (\r\n <UserAssignRoleModal\r\n userId={userId}\r\n roles={roles}\r\n assignedRoles={assignedRoles}\r\n globalRoleIds={globalRoleIds}\r\n onGlobalRolesUpdate={onGlobalRolesUpdate}\r\n initialTenantId={tenantId}\r\n initialIsGlobalScope={isGlobalScope}\r\n adminTenants={adminTenants}\r\n tenantMemberships={tenantMemberships}\r\n onAssigned={handleAssigned}\r\n onClose={handleCloseModal}\r\n />\r\n )}\r\n </div>\r\n );\r\n}\r\n\r\n// --- Assign Role Modal ---\r\n\r\ninterface UserAssignRoleModalProps {\r\n readonly userId: string;\r\n readonly roles: RoleListDto[];\r\n readonly assignedRoles: UserConsolidatedRoleDto[];\r\n readonly globalRoleIds: string[];\r\n readonly onGlobalRolesUpdate: (roleIds: string[]) => Promise<void>;\r\n readonly initialTenantId?: string;\r\n readonly initialIsGlobalScope: boolean;\r\n readonly adminTenants: AdminTenantInfo[];\r\n readonly tenantMemberships: TenantMembership[];\r\n readonly onAssigned: () => Promise<void>;\r\n readonly onClose: () => void;\r\n}\r\n\r\nfunction UserAssignRoleModal({\r\n userId: _userId,\r\n roles,\r\n assignedRoles,\r\n globalRoleIds,\r\n onGlobalRolesUpdate,\r\n initialTenantId,\r\n initialIsGlobalScope,\r\n adminTenants,\r\n tenantMemberships,\r\n onAssigned,\r\n onClose,\r\n}: UserAssignRoleModalProps) {\r\n const { t } = useTranslation(['admin', 'groups']);\r\n const [searchQuery, setSearchQuery] = useState('');\r\n const [filterCategory, setFilterCategory] = useState<string>('all');\r\n const [filterContext, setFilterContext] = useState<string>('all');\r\n const [filterApplication, setFilterApplication] = useState<string>('all');\r\n const [saving, setSaving] = useState<string | null>(null);\r\n const [error, setError] = useState<string | null>(null);\r\n const savingRef = useRef(false);\r\n\r\n // Only show tenants the user is a member of\r\n const modalTenants = useMemo(() => {\r\n const memberTenantIds = new Set(tenantMemberships.map(m => m.tenantId));\r\n return adminTenants.filter(at => memberTenantIds.has(at.tenantId));\r\n }, [adminTenants, tenantMemberships]);\r\n\r\n // Local scope state for the modal (initialized from parent)\r\n const [modalScope, setModalScope] = useState<ScopeValue>(() => {\r\n if (initialIsGlobalScope || !initialTenantId) return 'global';\r\n const tenant = adminTenants.find(at => at.tenantId === initialTenantId);\r\n if (!tenant) return 'global';\r\n return {\r\n tenantId: tenant.tenantId,\r\n tenantSlug: tenant.tenantSlug,\r\n tenantUserId: '',\r\n tenantName: tenant.tenantName,\r\n };\r\n });\r\n\r\n const modalIsGlobal = modalScope === 'global';\r\n const modalTenantId = !modalIsGlobal ? modalScope.tenantId : undefined;\r\n\r\n // Roles already assigned for the modal's current scope (Direct only - group roles can coexist)\r\n const currentScopeRoleIds = useMemo(() => {\r\n const ids = new Set<string>();\r\n for (const ar of assignedRoles) {\r\n if (ar.source !== 'Direct') continue;\r\n if (modalIsGlobal && !ar.tenantId) ids.add(ar.roleId);\r\n else if (!modalIsGlobal && ar.tenantId === modalTenantId) ids.add(ar.roleId);\r\n }\r\n return ids;\r\n }, [assignedRoles, modalIsGlobal, modalTenantId]);\r\n\r\n // Load tenant's accessible application IDs when a tenant is selected\r\n const [tenantAppIds, setTenantAppIds] = useState<Set<string> | null>(null);\r\n\r\n useEffect(() => {\r\n if (modalIsGlobal || !modalTenantId) {\r\n setTenantAppIds(null);\r\n return;\r\n }\r\n let cancelled = false;\r\n adminApi.tenants.getApplications(modalTenantId).then(apps => {\r\n if (!cancelled) {\r\n setTenantAppIds(new Set(apps.map(a => a.applicationId)));\r\n }\r\n }).catch(() => {\r\n if (!cancelled) setTenantAppIds(null);\r\n });\r\n return () => { cancelled = true; };\r\n }, [modalIsGlobal, modalTenantId]);\r\n\r\n // Roles available for the current scope (filtered by tenant's accessible apps)\r\n const scopedRoles = useMemo(() => {\r\n if (modalIsGlobal || !tenantAppIds) return roles;\r\n return roles.filter(r => !r.applicationId || tenantAppIds.has(r.applicationId));\r\n }, [roles, modalIsGlobal, tenantAppIds]);\r\n\r\n // Build unique contexts from scoped roles\r\n const contexts = useMemo(() => {\r\n const ctxMap = new Map<string, string>();\r\n for (const r of scopedRoles) {\r\n if (r.contextId && r.contextName && !ctxMap.has(r.contextId)) {\r\n ctxMap.set(r.contextId, r.contextName);\r\n }\r\n }\r\n return Array.from(ctxMap.entries()).map(([id, name]) => ({ id, name }));\r\n }, [scopedRoles]);\r\n\r\n // Build unique applications from scoped roles, filtered by selected context\r\n const applications = useMemo(() => {\r\n const appMap = new Map<string, string>();\r\n for (const r of scopedRoles) {\r\n if (!r.applicationId || !r.applicationName) continue;\r\n if (filterContext !== 'all' && r.contextId !== filterContext) continue;\r\n if (!appMap.has(r.applicationId)) {\r\n appMap.set(r.applicationId, r.applicationName);\r\n }\r\n }\r\n return Array.from(appMap.entries())\r\n .map(([id, name]) => ({ id, name }))\r\n .sort((a, b) => a.name.localeCompare(b.name));\r\n }, [scopedRoles, filterContext]);\r\n\r\n // Reset application filter when context changes\r\n const handleContextChange = useCallback((value: string) => {\r\n setFilterContext(value);\r\n setFilterApplication('all');\r\n }, []);\r\n\r\n const categories = useMemo(() => {\r\n const cats = new Set(scopedRoles.map(r => r.category || 'Custom'));\r\n return ['all', ...Array.from(cats).sort((a, b) => a.localeCompare(b))];\r\n }, [scopedRoles]);\r\n\r\n const filteredRoles = useMemo(() => {\r\n let filtered = scopedRoles;\r\n\r\n // Context filter\r\n if (filterContext !== 'all') {\r\n filtered = filtered.filter(r => r.contextId === filterContext);\r\n }\r\n\r\n // Application filter\r\n if (filterApplication !== 'all') {\r\n filtered = filtered.filter(r => r.applicationId === filterApplication);\r\n }\r\n\r\n // Category filter\r\n if (filterCategory !== 'all') {\r\n filtered = filtered.filter(r => (r.category || 'Custom') === filterCategory);\r\n }\r\n\r\n if (searchQuery.trim()) {\r\n const query = searchQuery.toLowerCase().trim();\r\n filtered = filtered.filter(r =>\r\n r.name.toLowerCase().includes(query) ||\r\n r.shortName?.toLowerCase().includes(query) ||\r\n r.description?.toLowerCase().includes(query)\r\n );\r\n }\r\n\r\n return filtered;\r\n }, [scopedRoles, filterContext, filterApplication, filterCategory, searchQuery]);\r\n\r\n const handleAssignRole = useCallback(async (roleId: string) => {\r\n if (savingRef.current) return;\r\n savingRef.current = true;\r\n setSaving(roleId);\r\n setError(null);\r\n\r\n try {\r\n if (modalIsGlobal) {\r\n // Global scope: add to global role IDs via callback\r\n const newRoleIds = [...globalRoleIds, roleId];\r\n await onGlobalRolesUpdate(newRoleIds);\r\n } else if (modalTenantId) {\r\n // Tenant scope: use individual assign endpoint\r\n const membership = tenantMemberships.find(m => m.tenantId === modalTenantId);\r\n if (membership) {\r\n await adminApi.tenants.assignRole(modalTenantId, membership.tenantUserId, roleId);\r\n } else {\r\n throw new Error(t('admin:userRoles.errors.notMember', 'L\\'utilisateur n\\'est pas membre de ce tenant'));\r\n }\r\n }\r\n await onAssigned();\r\n } catch (err) {\r\n console.error('Failed to assign role:', err);\r\n setError(t('admin:userRoles.errors.assignFailed', 'Erreur lors de l\\'assignation du rôle'));\r\n } finally {\r\n setSaving(null);\r\n savingRef.current = false;\r\n }\r\n }, [modalIsGlobal, modalTenantId, globalRoleIds, onGlobalRolesUpdate, tenantMemberships, onAssigned, t]);\r\n\r\n return (\r\n <div className=\"fixed inset-0 z-[100] flex items-center justify-center p-4 bg-black/60 backdrop-blur-sm\">\r\n <div className=\"relative w-full max-w-2xl h-[80vh] bg-[var(--bg-card)] rounded-[var(--radius-card)] shadow-2xl border border-[var(--border-color)] overflow-hidden flex flex-col animate-in fade-in zoom-in duration-200\">\r\n {/* Header */}\r\n <div className=\"flex items-center justify-between px-6 py-4 border-b border-[var(--border-color)]\">\r\n <div className=\"flex items-center gap-4\">\r\n <div>\r\n <h2 className=\"text-lg font-semibold text-[var(--text-primary)]\">\r\n {t('admin:userRoles.assignRole', 'Assigner un rôle')}\r\n </h2>\r\n </div>\r\n <TenantScopeSelector\r\n value={modalScope}\r\n onChange={setModalScope}\r\n adminTenants={modalTenants}\r\n />\r\n </div>\r\n <button\r\n onClick={onClose}\r\n className=\"p-1.5 rounded-[var(--radius-button)] text-[var(--text-tertiary)] hover:text-[var(--text-primary)] hover:bg-[var(--bg-hover)] transition-colors\"\r\n >\r\n <X className=\"w-5 h-5\" />\r\n </button>\r\n </div>\r\n\r\n {/* Error alert */}\r\n {error && (\r\n <div className=\"mx-6 mt-3 p-3 rounded-[var(--radius-card)] bg-[var(--error-bg)] border border-[var(--error-border)] flex items-center gap-3\">\r\n <AlertCircle className=\"w-4 h-4 text-[var(--error-text)] flex-shrink-0\" />\r\n <p className=\"flex-1 text-sm text-[var(--error-text)]\">{error}</p>\r\n <button onClick={() => setError(null)}>\r\n <X className=\"w-3.5 h-3.5 text-[var(--error-text)]\" />\r\n </button>\r\n </div>\r\n )}\r\n\r\n {/* Filters */}\r\n <div className=\"px-6 py-3 border-b border-[var(--border-color)] flex flex-col gap-3\">\r\n <div className=\"relative\">\r\n <Search className=\"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-[var(--text-muted)]\" />\r\n <input\r\n type=\"text\"\r\n value={searchQuery}\r\n onChange={(e) => setSearchQuery(e.target.value)}\r\n placeholder={t('admin:userRoles.search', 'Rechercher un rôle...')}\r\n className=\"w-full pl-10 pr-4 py-2 text-sm bg-[var(--bg-secondary)] border border-[var(--border-color)] rounded-[var(--radius-input)] text-[var(--text-primary)] placeholder-[var(--text-muted)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n autoFocus\r\n />\r\n </div>\r\n <div className=\"flex items-center gap-2\">\r\n <Filter className=\"w-4 h-4 text-[var(--text-secondary)] shrink-0\" />\r\n <select\r\n value={filterContext}\r\n onChange={(e) => handleContextChange(e.target.value)}\r\n className=\"flex-1 min-w-0 px-3 py-2 text-sm bg-[var(--bg-secondary)] border border-[var(--border-color)] rounded-[var(--radius-input)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n >\r\n <option value=\"all\">{t('admin:userRoles.filterByContext', 'Tous les contextes')}</option>\r\n {contexts.map(ctx => (\r\n <option key={ctx.id} value={ctx.id}>{ctx.name}</option>\r\n ))}\r\n </select>\r\n <select\r\n value={filterApplication}\r\n onChange={(e) => setFilterApplication(e.target.value)}\r\n disabled={filterContext === 'all' || applications.length === 0}\r\n className=\"flex-1 min-w-0 px-3 py-2 text-sm bg-[var(--bg-secondary)] border border-[var(--border-color)] rounded-[var(--radius-input)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)] disabled:opacity-50\"\r\n >\r\n <option value=\"all\">{t('admin:userRoles.filterByApplication', 'Toutes les applications')}</option>\r\n {applications.map(app => (\r\n <option key={app.id} value={app.id}>{app.name}</option>\r\n ))}\r\n </select>\r\n <select\r\n value={filterCategory}\r\n onChange={(e) => setFilterCategory(e.target.value)}\r\n className=\"flex-1 min-w-0 px-3 py-2 text-sm bg-[var(--bg-secondary)] border border-[var(--border-color)] rounded-[var(--radius-input)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n >\r\n <option value=\"all\">{t('admin:userRoles.filterByCategory', 'Toutes les catégories')}</option>\r\n {categories.filter(c => c !== 'all').map(cat => (\r\n <option key={cat} value={cat}>{cat}</option>\r\n ))}\r\n </select>\r\n </div>\r\n </div>\r\n\r\n {/* Role list */}\r\n <div className=\"flex-1 overflow-y-auto\">\r\n <table className=\"w-full\">\r\n <thead className=\"bg-[var(--bg-tertiary)] sticky top-0 z-10\">\r\n <tr>\r\n <th className=\"text-left px-6 py-2.5 text-sm font-medium text-[var(--text-secondary)]\">\r\n {t('admin:roles.name', 'Rôle')}\r\n </th>\r\n <th className=\"text-left px-4 py-2.5 text-sm font-medium text-[var(--text-secondary)]\">\r\n {t('admin:roles.category', 'Catégorie')}\r\n </th>\r\n <th className=\"text-right px-6 py-2.5 text-sm font-medium text-[var(--text-secondary)] w-32\">\r\n {t('admin:roles.actions', 'Actions')}\r\n </th>\r\n </tr>\r\n </thead>\r\n <tbody className=\"divide-y divide-[var(--border-color)]\">\r\n {filteredRoles.length === 0 ? (\r\n <tr>\r\n <td colSpan={3} className=\"px-6 py-12 text-center\">\r\n <Search className=\"w-8 h-8 mx-auto mb-2 text-[var(--text-tertiary)]\" />\r\n <p className=\"text-[var(--text-muted)]\">\r\n {t('admin:userRoles.noRoles', 'Aucun rôle trouvé')}\r\n </p>\r\n </td>\r\n </tr>\r\n ) : (\r\n filteredRoles.map((role) => {\r\n const isAlreadyAssigned = currentScopeRoleIds.has(role.id);\r\n const catStyle = CATEGORY_STYLES[role.category || 'Custom'] || DEFAULT_CATEGORY_STYLE;\r\n const customIcon = getCustomRoleIcon(role.code);\r\n const isAssigning = saving === role.id;\r\n\r\n return (\r\n <tr\r\n key={role.id}\r\n className={`transition-colors ${isAlreadyAssigned ? 'bg-[var(--accent-bg)] opacity-60' : 'hover:bg-[var(--bg-hover)]'}`}\r\n >\r\n <td className=\"px-6 py-3\">\r\n <div className=\"flex items-center gap-2\">\r\n {customIcon && <span>{customIcon}</span>}\r\n <div>\r\n <span className=\"font-medium text-[var(--text-primary)]\">{role.name}</span>\r\n {role.description && (\r\n <p className=\"text-xs text-[var(--text-tertiary)] mt-0.5 max-w-sm truncate\">{role.description}</p>\r\n )}\r\n </div>\r\n </div>\r\n </td>\r\n <td className=\"px-4 py-3\">\r\n <span className={`px-2 py-1 text-xs rounded-full ${catStyle.bg} ${catStyle.text}`}>\r\n {role.category || 'Custom'}\r\n </span>\r\n </td>\r\n <td className=\"px-6 py-3 text-right\">\r\n {isAlreadyAssigned ? (\r\n <span className=\"text-xs text-[var(--text-muted)]\">\r\n {t('admin:userRoles.alreadyAssigned', 'Déjà assigné')}\r\n </span>\r\n ) : (\r\n <button\r\n onClick={() => handleAssignRole(role.id)}\r\n disabled={isAssigning}\r\n className=\"inline-flex items-center gap-1.5 px-3 py-1.5 rounded-[var(--radius-button)] bg-[var(--color-accent-600)] text-white text-xs font-medium hover:bg-[var(--color-accent-700)] transition-colors disabled:opacity-50\"\r\n >\r\n {isAssigning ? (\r\n <Loader2 className=\"w-3.5 h-3.5 animate-spin\" />\r\n ) : (\r\n <Plus className=\"w-3.5 h-3.5\" />\r\n )}\r\n {t('admin:userRoles.assign', 'Assigner')}\r\n </button>\r\n )}\r\n </td>\r\n </tr>\r\n );\r\n })\r\n )}\r\n </tbody>\r\n </table>\r\n </div>\r\n\r\n {/* Footer */}\r\n <div className=\"px-6 py-3 border-t border-[var(--border-color)] bg-[var(--bg-tertiary)] flex justify-end\">\r\n <button\r\n onClick={onClose}\r\n className=\"px-4 py-2 rounded-[var(--radius-button)] bg-[var(--bg-secondary)] text-[var(--text-secondary)] hover:bg-[var(--bg-hover)] transition-colors text-sm font-medium\"\r\n >\r\n {t('common:close', 'Fermer')}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n}\r\n","import type { ReactElement } from 'react';\r\nimport React, { useState, useMemo, useCallback, createRef } from 'react';\r\nimport { useTranslation } from 'react-i18next';\r\nimport { useNavigate } from 'react-router-dom';\r\nimport {\r\n Check,\r\n Star,\r\n Eye,\r\n Ban,\r\n ChevronRight,\r\n ChevronDown,\r\n FolderOpen,\r\n Box,\r\n FileText,\r\n Shield,\r\n Info,\r\n Loader2,\r\n AlertCircle,\r\n Plus,\r\n Edit,\r\n Trash2,\r\n UserPlus,\r\n Play,\r\n Database,\r\n UserCheck,\r\n Users,\r\n User,\r\n} from 'lucide-react';\r\nimport { useUserPermissions } from '@/hooks/useUserPermissions';\r\nimport { useCollapsibleState } from '@/hooks/useCollapsibleState';\r\nimport { groupByApplicationWithSections, calculatePermissionStatus, calculateModuleWithSectionsStatus, getPermissionCellBackground } from '@/utils/permissionUtils';\r\nimport { PermissionStatusIndicator } from './PermissionStatusIndicator';\r\nimport { PermissionPopover } from '../PermissionPopover';\r\nimport type { ResourceNode, PermissionStatus, PermissionInheritanceInfo, ModuleWithSections, SectionWithResources } from './types';\r\nimport type { RoleDto, MatrixRoleDto, UserConsolidatedRoleDto } from '@/services/api/adminApi';\r\nimport { adminApi } from '@/services/api/adminApi';\r\n\r\n/** Helper: Get unique tenant names from consolidated roles map for source roles */\r\nfunction getTenantNamesFromSourceRoles(\r\n sourceRoles: RoleDto[],\r\n consolidatedRolesMap: Map<string, UserConsolidatedRoleDto>,\r\n globalLabel: string\r\n): string[] {\r\n const tenantNames = new Set<string>();\r\n sourceRoles.forEach(role => {\r\n const cr = consolidatedRolesMap.get(role.id);\r\n if (cr) {\r\n tenantNames.add(cr.tenantName || globalLabel);\r\n }\r\n });\r\n return Array.from(tenantNames);\r\n}\r\n\r\n/** Helper: Get unique source types from consolidated roles */\r\nfunction getSourceTypesFromConsolidatedRoles(\r\n sourceRoles: RoleDto[],\r\n consolidatedRolesMap: Map<string, UserConsolidatedRoleDto>\r\n): Array<{ type: 'Direct' | 'Group' | 'Custom'; groupName?: string }> {\r\n const sources: Array<{ type: 'Direct' | 'Group' | 'Custom'; groupName?: string }> = [];\r\n sourceRoles.forEach(role => {\r\n const cr = consolidatedRolesMap.get(role.id);\r\n if (cr) {\r\n const existing = sources.find(s =>\r\n s.type === cr.source &&\r\n (s.type === 'Direct' || s.type === 'Custom' || s.groupName === cr.sourceGroupName)\r\n );\r\n if (!existing) {\r\n sources.push({\r\n type: cr.source,\r\n groupName: cr.sourceGroupName || undefined,\r\n });\r\n }\r\n }\r\n });\r\n return sources;\r\n}\r\n\r\nconst ACTION_ICONS: Record<string, React.ReactNode> = {\r\n '*': <Shield className=\"h-3.5 w-3.5\" />,\r\n read: <Eye className=\"h-3.5 w-3.5\" />,\r\n create: <Plus className=\"h-3.5 w-3.5\" />,\r\n update: <Edit className=\"h-3.5 w-3.5\" />,\r\n delete: <Trash2 className=\"h-3.5 w-3.5\" />,\r\n assign: <UserPlus className=\"h-3.5 w-3.5\" />,\r\n execute: <Play className=\"h-3.5 w-3.5\" />,\r\n};\r\n\r\ntype ActionColor = 'bg-[var(--accent-bg)] text-[var(--accent-text)] border-[var(--accent-border)]'\r\n | 'bg-[var(--info-bg)] text-[var(--info-text)] border-[var(--info-border)]'\r\n | 'bg-[var(--success-bg)] text-[var(--success-text)] border-[var(--success-border)]'\r\n | 'bg-[var(--warning-bg)] text-[var(--warning-text)] border-[var(--warning-border)]'\r\n | 'bg-[var(--error-bg)] text-[var(--error-text)] border-[var(--error-border)]';\r\n\r\nconst ACTION_COLORS: Record<string, ActionColor> = {\r\n '*': 'bg-[var(--accent-bg)] text-[var(--accent-text)] border-[var(--accent-border)]',\r\n read: 'bg-[var(--info-bg)] text-[var(--info-text)] border-[var(--info-border)]',\r\n create: 'bg-[var(--success-bg)] text-[var(--success-text)] border-[var(--success-border)]',\r\n update: 'bg-[var(--warning-bg)] text-[var(--warning-text)] border-[var(--warning-border)]',\r\n delete: 'bg-[var(--error-bg)] text-[var(--error-text)] border-[var(--error-border)]',\r\n assign: 'bg-[var(--accent-bg)] text-[var(--accent-text)] border-[var(--accent-border)]',\r\n execute: 'bg-[var(--warning-bg)] text-[var(--warning-text)] border-[var(--warning-border)]',\r\n};\r\n\r\ninterface UserPermissionMatrixProps {\r\n readonly userId: string;\r\n readonly compact?: boolean;\r\n /** Optional tenant ID for tenant-scoped permissions */\r\n readonly tenantId?: string;\r\n}\r\n\r\nexport function UserPermissionMatrix({ userId, compact = false, tenantId }: UserPermissionMatrixProps): ReactElement {\r\n const { t } = useTranslation('admin');\r\n const navigate = useNavigate();\r\n const {\r\n loading,\r\n error,\r\n user,\r\n userRoles,\r\n filteredResources,\r\n effectivePermissions,\r\n filters,\r\n applications,\r\n modules,\r\n updateFilters,\r\n getPermissionSources,\r\n reloadData,\r\n isTenantMode,\r\n tenantMember,\r\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\r\n assignTenantRoles: _assignTenantRoles,\r\n consolidatedRoles,\r\n } = useUserPermissions({ userId, tenantId });\r\n\r\n // Create a map for quick lookup of consolidated role info by roleId\r\n const consolidatedRolesMap = useMemo(() => {\r\n const map = new Map<string, UserConsolidatedRoleDto>();\r\n consolidatedRoles.forEach(cr => map.set(cr.roleId, cr));\r\n return map;\r\n }, [consolidatedRoles]);\r\n\r\n const { collapsedApps, toggleApp } = useCollapsibleState();\r\n const [collapsedModules, setCollapsedModules] = useState<Set<string>>(new Set());\r\n const [collapsedSections, setCollapsedSections] = useState<Set<string>>(new Set());\r\n const [statusFilters, setStatusFilters] = useState<Set<PermissionStatus>>(new Set());\r\n const [openPopover, setOpenPopover] = useState<string | null>(null);\r\n const [customRoleId, setCustomRoleId] = useState<string | null>(null);\r\n const [customRolePermissions, setCustomRolePermissions] = useState<Set<string>>(new Set());\r\n const [togglingPermission, setTogglingPermission] = useState<string | null>(null);\r\n const [loadingCustomRole, setLoadingCustomRole] = useState(false);\r\n\r\n React.useEffect(() => {\r\n const loadCustomRole = async () => {\r\n try {\r\n setLoadingCustomRole(true);\r\n\r\n // In tenant mode, load tenant-scoped custom role\r\n if (isTenantMode && tenantId && tenantMember) {\r\n const role = await adminApi.tenants.getMemberCustomRole(tenantId, tenantMember.userId);\r\n if (role) {\r\n setCustomRoleId(role.id);\r\n setCustomRolePermissions(new Set((role.permissions ?? []).map(p => p.id)));\r\n } else {\r\n setCustomRoleId(null);\r\n setCustomRolePermissions(new Set());\r\n }\r\n } else {\r\n // Global mode: load global custom role\r\n const role = await adminApi.users.getCustomRole(userId);\r\n if (role) {\r\n setCustomRoleId(role.id);\r\n setCustomRolePermissions(new Set((role.permissions ?? []).map(p => p.id)));\r\n } else {\r\n setCustomRoleId(null);\r\n setCustomRolePermissions(new Set());\r\n }\r\n }\r\n } catch (err) {\r\n if (!(err instanceof Error && err.message.includes('404'))) {\r\n console.error('Failed to load custom role:', err);\r\n }\r\n setCustomRoleId(null);\r\n setCustomRolePermissions(new Set());\r\n } finally {\r\n setLoadingCustomRole(false);\r\n }\r\n };\r\n loadCustomRole();\r\n }, [userId, tenantId, isTenantMode, tenantMember]);\r\n\r\n const handleTogglePermission = async (permissionId: string) => {\r\n try {\r\n setTogglingPermission(permissionId);\r\n let roleId = customRoleId;\r\n let currentPermissions = new Set(customRolePermissions);\r\n\r\n // In tenant mode, use tenant-scoped custom role\r\n if (isTenantMode && tenantId && tenantMember) {\r\n if (!roleId) {\r\n const newRole = await adminApi.tenants.createMemberCustomRole(tenantId, tenantMember.userId);\r\n roleId = newRole.id;\r\n setCustomRoleId(roleId);\r\n currentPermissions = new Set();\r\n }\r\n\r\n const newPermissions = new Set(currentPermissions);\r\n if (newPermissions.has(permissionId)) {\r\n newPermissions.delete(permissionId);\r\n } else {\r\n newPermissions.add(permissionId);\r\n }\r\n\r\n // Update role permissions\r\n const role = await adminApi.roles.getById(roleId);\r\n await adminApi.roles.update(roleId, {\r\n name: role.name,\r\n shortName: role.shortName || undefined,\r\n category: role.category || undefined,\r\n description: role.description || undefined,\r\n permissionIds: Array.from(newPermissions),\r\n });\r\n\r\n setCustomRolePermissions(newPermissions);\r\n } else {\r\n // Global mode: use global custom role\r\n if (!roleId) {\r\n const newRole = await adminApi.users.createCustomRole(userId);\r\n roleId = newRole.id;\r\n setCustomRoleId(roleId);\r\n currentPermissions = new Set();\r\n }\r\n\r\n const newPermissions = new Set(currentPermissions);\r\n if (newPermissions.has(permissionId)) {\r\n newPermissions.delete(permissionId);\r\n } else {\r\n newPermissions.add(permissionId);\r\n }\r\n\r\n const role = await adminApi.roles.getById(roleId);\r\n await adminApi.roles.update(roleId, {\r\n name: role.name,\r\n shortName: role.shortName || undefined,\r\n category: role.category || undefined,\r\n description: role.description || undefined,\r\n permissionIds: Array.from(newPermissions),\r\n });\r\n\r\n setCustomRolePermissions(newPermissions);\r\n }\r\n\r\n // Refresh data without full page reload\r\n await reloadData();\r\n } catch (err) {\r\n console.error('Failed to toggle permission:', err);\r\n } finally {\r\n setTogglingPermission(null);\r\n }\r\n };\r\n\r\n const handleCellClick = (resourceId: string) => {\r\n if (openPopover === resourceId) {\r\n setOpenPopover(null);\r\n } else {\r\n setOpenPopover(resourceId);\r\n }\r\n };\r\n\r\n const toggleStatusFilter = (status: PermissionStatus) => {\r\n setStatusFilters(prev => {\r\n const next = new Set(prev);\r\n if (next.has(status)) {\r\n next.delete(status);\r\n } else {\r\n next.add(status);\r\n }\r\n return next;\r\n });\r\n };\r\n\r\n const toggleModule = (moduleId: string) => {\r\n setCollapsedModules(prev => {\r\n const next = new Set(prev);\r\n if (next.has(moduleId)) {\r\n next.delete(moduleId);\r\n } else {\r\n next.add(moduleId);\r\n }\r\n return next;\r\n });\r\n };\r\n\r\n const toggleSection = (sectionId: string) => {\r\n setCollapsedSections(prev => {\r\n const next = new Set(prev);\r\n if (next.has(sectionId)) {\r\n next.delete(sectionId);\r\n } else {\r\n next.add(sectionId);\r\n }\r\n return next;\r\n });\r\n };\r\n\r\n const getAllPermissionsForResource = useCallback((resource: ResourceNode) => {\r\n const allPermissions = [...resource.permissions];\r\n\r\n if (resource.childSections) {\r\n resource.childSections.forEach(section => {\r\n allPermissions.push(...section.permissions);\r\n });\r\n }\r\n\r\n return allPermissions;\r\n }, []);\r\n\r\n const getPermissionStatusForUser = useCallback((resource: ResourceNode, isSection: boolean = false): { status: PermissionStatus; grantedCount: number } => {\r\n if (isSection) {\r\n return calculatePermissionStatus(resource, (permId) => effectivePermissions.has(permId));\r\n }\r\n\r\n const allPermissions = getAllPermissionsForResource(resource);\r\n const grantedCount = allPermissions.filter(p => effectivePermissions.has(p.id)).length;\r\n const totalCount = allPermissions.length;\r\n\r\n let status: PermissionStatus;\r\n if (grantedCount === 0) {\r\n status = 'none';\r\n } else if (grantedCount === totalCount) {\r\n status = 'all';\r\n } else {\r\n const hasOnlyRead = allPermissions.every(p =>\r\n !effectivePermissions.has(p.id) || p.action === 'read'\r\n ) && allPermissions.some(p => p.action === 'read' && effectivePermissions.has(p.id));\r\n status = hasOnlyRead ? 'read-only' : 'some';\r\n }\r\n\r\n return { status, grantedCount };\r\n }, [effectivePermissions, getAllPermissionsForResource]);\r\n\r\n const filterModulesByStatus = (modules: ModuleWithSections[]) => {\r\n return modules.filter(m => {\r\n const { status } = calculateModuleWithSectionsStatus(m.module, m.sections, (permId) => effectivePermissions.has(permId));\r\n return statusFilters.has(status);\r\n });\r\n };\r\n\r\n const filterApplicationsByModules = (applications: { application: string; modules: ModuleWithSections[] }[]) => {\r\n return applications.map(app => ({\r\n ...app,\r\n modules: filterModulesByStatus(app.modules)\r\n })).filter(app => app.modules.length > 0);\r\n };\r\n\r\n const applyUserStatusFilters = (grouped: ReturnType<typeof groupByApplicationWithSections>) => {\r\n if (statusFilters.size === 0) return grouped;\r\n return filterApplicationsByModules(grouped);\r\n };\r\n\r\n const groupedResources = useMemo(() => {\r\n let grouped = groupByApplicationWithSections(filteredResources);\r\n return applyUserStatusFilters(grouped);\r\n }, [filteredResources, statusFilters, effectivePermissions]);\r\n\r\n // Count total modules\r\n const totalModuleCount = useMemo(() => {\r\n return groupedResources.reduce((sum, app) =>\r\n sum + app.modules.length, 0);\r\n }, [groupedResources]);\r\n\r\n const addSourceRolesFromPermission = (permId: string, sourceRoles: RoleDto[]) => {\r\n const roles = getPermissionSources(permId);\r\n roles.forEach(role => {\r\n if (!sourceRoles.find(r => r.id === role.id)) {\r\n sourceRoles.push(role);\r\n }\r\n });\r\n };\r\n\r\n const getSourceRolesForResource = (resource: ResourceNode): RoleDto[] => {\r\n const sourceRoles: RoleDto[] = [];\r\n // Get permissions for this level only (module or section)\r\n resource.permissions.forEach(perm => {\r\n if (effectivePermissions.has(perm.id)) {\r\n addSourceRolesFromPermission(perm.id, sourceRoles);\r\n }\r\n });\r\n return sourceRoles;\r\n };\r\n\r\n const isCustomRole = (roleName: string): boolean => {\r\n return roleName.startsWith('user_') && roleName.endsWith('_custom');\r\n };\r\n\r\n const getDisplayName = (role: RoleDto): string => {\r\n return isCustomRole(role.name) ? t('userPermissions.customBadge', 'Custom') : (role.shortName || role.name);\r\n };\r\n\r\n // Create a \"virtual role\" representing the user for the permission popover\r\n const userAsRole: MatrixRoleDto | null = useMemo(() => {\r\n if (!user) return null;\r\n return {\r\n id: customRoleId || `user_${userId}_custom`,\r\n name: user.fullName,\r\n shortName: user.fullName,\r\n category: 'Custom' as const,\r\n description: null,\r\n isSystem: false,\r\n permissions: [],\r\n permissionIds: [],\r\n };\r\n }, [user, customRoleId, userId]);\r\n\r\n // Adapter function to provide inheritance info for permissions\r\n const getUserPermissionInheritance = useCallback((_roleId: string, permissionId: string): PermissionInheritanceInfo => {\r\n const isGranted = effectivePermissions.has(permissionId);\r\n const isFromCustomRole = customRolePermissions.has(permissionId);\r\n const sourceRoles = isGranted ? getPermissionSources(permissionId) : [];\r\n const inheritedRole = sourceRoles.find(r => !isCustomRole(r.name));\r\n\r\n return {\r\n isDirect: isFromCustomRole,\r\n isInherited: isGranted && !isFromCustomRole && sourceRoles.length > 0,\r\n inheritedFromPath: inheritedRole ? inheritedRole.name : undefined,\r\n inheritedFromId: inheritedRole?.id,\r\n };\r\n }, [effectivePermissions, customRolePermissions, getPermissionSources]);\r\n\r\n if (loading) {\r\n return (\r\n <div className=\"flex items-center justify-center py-12\">\r\n <Loader2 className=\"h-8 w-8 animate-spin text-[var(--color-accent-500)]\" />\r\n <span className=\"ml-3 text-[var(--text-secondary)]\">{t('userPermissions.loading')}</span>\r\n </div>\r\n );\r\n }\r\n\r\n if (error) {\r\n return (\r\n <div className=\"rounded-[var(--radius-card)] bg-[var(--error-bg)] p-4 border border-[var(--error-border)]\">\r\n <div className=\"flex items-center\">\r\n <AlertCircle className=\"h-5 w-5 text-[var(--error-text)]\" />\r\n <p className=\"ml-2 text-sm text-[var(--error-text)]\">{error}</p>\r\n </div>\r\n </div>\r\n );\r\n }\r\n\r\n if (!user) {\r\n return (\r\n <div className=\"text-center py-12 text-[var(--text-secondary)]\">\r\n <Shield className=\"h-12 w-12 mx-auto mb-4 text-[var(--text-muted)]\" />\r\n <p>{t('userPermissions.noUser')}</p>\r\n </div>\r\n );\r\n }\r\n\r\n const getUserResourceIcon = (level: 'module' | 'section' | 'resource') => {\r\n if (level === 'resource') return <Database className=\"h-3.5 w-3.5 text-[var(--text-muted)]\" />;\r\n if (level === 'section') return <FileText className=\"h-3.5 w-3.5 text-[var(--text-muted)]\" />;\r\n return <Box className=\"h-3.5 w-3.5 text-[var(--text-secondary)]\" />;\r\n };\r\n\r\n const getUserResourceLabelClass = (level: 'module' | 'section' | 'resource'): string => {\r\n if (level === 'resource') return 'text-[var(--text-muted)] italic';\r\n if (level === 'section') return 'text-[var(--text-secondary)]';\r\n return 'font-medium text-[var(--text-primary)]';\r\n };\r\n\r\n const getUserPaddingClass = (level: 'module' | 'section' | 'resource'): string => {\r\n if (level === 'resource') return 'pl-28';\r\n if (level === 'section') return 'pl-22';\r\n return 'pl-16';\r\n };\r\n\r\n const getSourceTypeLabelClass = (type: 'Direct' | 'Group' | 'Custom'): string => {\r\n if (type === 'Direct') {\r\n return 'bg-[var(--success-bg)] text-[var(--success-text)] border border-[var(--success-border)]';\r\n }\r\n if (type === 'Custom') {\r\n return 'bg-[var(--color-accent-100)] text-[var(--color-accent-700)] dark:bg-[var(--color-accent-900)] dark:text-[var(--color-accent-300)] border border-[var(--color-accent-300)] dark:border-[var(--color-accent-700)]';\r\n }\r\n return 'bg-[var(--warning-bg)] text-[var(--warning-text)] border border-[var(--warning-border)]';\r\n };\r\n\r\n const getTenantTagClass = (tenantName: string, t: Function): string => {\r\n const globalLabel = t('userPermissions.globalScope', 'Global');\r\n return tenantName === globalLabel\r\n ? 'bg-[var(--info-bg)] text-[var(--info-text)] border border-[var(--info-border)]'\r\n : 'bg-[var(--bg-tertiary)] text-[var(--text-secondary)] border border-[var(--border-color)]';\r\n };\r\n\r\n const renderSectionWithResources = (sectionWithResources: SectionWithResources, moduleIndex: number, sectionIndex: number) => {\r\n const { section, resources } = sectionWithResources;\r\n const hasResources = resources.length > 0;\r\n const isSectionCollapsed = collapsedSections.has(section.id);\r\n\r\n return (\r\n <React.Fragment key={section.id}>\r\n {renderResourceRow(section, moduleIndex + sectionIndex + 1, 'section', hasResources, isSectionCollapsed)}\r\n {hasResources && !isSectionCollapsed && resources.map((resource: ResourceNode, resourceIndex: number) =>\r\n renderResourceRow(resource, moduleIndex + sectionIndex + resourceIndex + 2, 'resource', false, false)\r\n )}\r\n </React.Fragment>\r\n );\r\n };\r\n\r\n const renderModuleWithSections = (moduleWithSections: ModuleWithSections, moduleIndex: number) => {\r\n const { module, sections } = moduleWithSections;\r\n const hasSections = sections.length > 0;\r\n const isModuleCollapsed = collapsedModules.has(module.id);\r\n\r\n return (\r\n <React.Fragment key={module.id}>\r\n {renderResourceRow(module, moduleIndex, 'module', hasSections, isModuleCollapsed)}\r\n {hasSections && !isModuleCollapsed && sections.map((sectionWithResources: SectionWithResources, sectionIndex: number) =>\r\n renderSectionWithResources(sectionWithResources, moduleIndex, sectionIndex)\r\n )}\r\n </React.Fragment>\r\n );\r\n };\r\n\r\n const renderResourceRow = (\r\n resource: ResourceNode,\r\n rowIndex: number,\r\n level: 'module' | 'section' | 'resource',\r\n hasChildren: boolean = false,\r\n isCollapsed: boolean = false\r\n ) => {\r\n const isSection = level === 'section';\r\n const { status, grantedCount} = getPermissionStatusForUser(resource, isSection);\r\n const totalCount = isSection ? resource.permissions.length : getAllPermissionsForResource(resource).length;\r\n const cellBg = getPermissionCellBackground(status);\r\n const sourceRoles = getSourceRolesForResource(resource);\r\n const isPopoverOpen = openPopover === resource.id;\r\n const buttonRef = createRef<HTMLButtonElement>();\r\n const paddingLeft = getUserPaddingClass(level);\r\n\r\n return (\r\n <tr\r\n key={resource.id}\r\n className={`hover:bg-[var(--bg-hover)] ${rowIndex % 2 === 0 ? 'item-light' : 'item-medium'}`}\r\n >\r\n {/* Sticky Resource Name Column */}\r\n <td\r\n className={`sticky left-0 z-10 ${rowIndex % 2 === 0 ? 'item-light' : 'item-medium'} px-3 py-2 ${paddingLeft}`}\r\n style={{ width: '280px', minWidth: '280px', maxWidth: '280px' }}\r\n >\r\n <div className=\"flex items-center gap-2\">\r\n {/* Toggle button for items with children */}\r\n {hasChildren && (\r\n <button\r\n onClick={() => level === 'module' ? toggleModule(resource.id) : toggleSection(resource.id)}\r\n className=\"p-0.5 hover:bg-[var(--bg-hover)] rounded\"\r\n >\r\n {isCollapsed ? (\r\n <ChevronRight className=\"h-3 w-3 text-[var(--text-muted)]\" />\r\n ) : (\r\n <ChevronDown className=\"h-3 w-3 text-[var(--text-muted)]\" />\r\n )}\r\n </button>\r\n )}\r\n {getUserResourceIcon(level)}\r\n <span className={`text-sm ${getUserResourceLabelClass(level)}`}>\r\n {resource.label}\r\n </span>\r\n <span className=\"text-xs text-[var(--text-muted)]\">\r\n ({totalCount})\r\n </span>\r\n </div>\r\n </td>\r\n\r\n {/* Status Cell - Clickable to open popover */}\r\n <td\r\n className={`px-0 py-1 text-center relative ${cellBg}`}\r\n style={{ width: '60px', minWidth: '60px', maxWidth: '60px' }}\r\n >\r\n <button\r\n ref={buttonRef}\r\n type=\"button\"\r\n onClick={() => handleCellClick(resource.id)}\r\n className={`w-full h-full min-h-[36px] flex items-center justify-center rounded transition-colors hover:opacity-80 ${\r\n isPopoverOpen ? 'ring-2 ring-[var(--color-accent-500)]' : ''\r\n }`}\r\n title={`${resource.label}: ${grantedCount}/${totalCount}`}\r\n >\r\n <PermissionStatusIndicator\r\n status={status}\r\n grantedCount={grantedCount}\r\n totalCount={totalCount}\r\n />\r\n </button>\r\n {isPopoverOpen && user && userAsRole && (\r\n <PermissionPopover\r\n mode=\"editable\"\r\n role={userAsRole}\r\n resource={resource}\r\n onClose={() => setOpenPopover(null)}\r\n onTogglePermission={handleTogglePermission}\r\n getPermissionInheritance={getUserPermissionInheritance}\r\n />\r\n )}\r\n </td>\r\n\r\n {/* Source Roles */}\r\n <td className=\"px-3 py-2\">\r\n <div className=\"flex flex-wrap gap-1\">\r\n {sourceRoles.length > 0 ? (\r\n sourceRoles.map(role => {\r\n const isCustom = isCustomRole(role.name);\r\n const displayName = getDisplayName(role);\r\n return (\r\n <button\r\n key={role.id}\r\n onClick={() => !isCustom && navigate(`/administration/permissions/roles/${role.id}`)}\r\n className={`inline-flex items-center gap-1 px-2 py-0.5 text-xs rounded-full transition-all ${\r\n isCustom\r\n ? 'bg-[var(--color-accent-100)] text-[var(--color-accent-700)] dark:bg-[var(--color-accent-900)] dark:text-[var(--color-accent-300)] border border-[var(--color-accent-300)] dark:border-[var(--color-accent-700)] cursor-default'\r\n : 'bg-[var(--bg-tertiary)] text-[var(--text-secondary)] border border-[var(--border-color)] cursor-pointer hover:ring-1 hover:ring-[var(--color-accent-500)] hover:shadow-sm'\r\n }`}\r\n title={isCustom ? t('userPermissions.customRoleTooltip', 'Rôle personnalisé') : t('userPermissions.clickToViewRole', 'Cliquer pour voir le rôle')}\r\n >\r\n {displayName}\r\n {isCustom && <Star className=\"h-3 w-3\" />}\r\n </button>\r\n );\r\n })\r\n ) : (\r\n <span className=\"text-xs text-[var(--text-muted)]\">-</span>\r\n )}\r\n </div>\r\n </td>\r\n\r\n {/* Tenant Column */}\r\n <td className=\"px-3 py-2\">\r\n <div className=\"flex flex-wrap gap-1\">\r\n {sourceRoles.length > 0 ? (\r\n getTenantNamesFromSourceRoles(sourceRoles, consolidatedRolesMap, t('userPermissions.globalScope', 'Global')).map((tenantName, idx) => (\r\n <span\r\n key={`tenant-${tenantName}-${idx}`}\r\n className={`inline-flex items-center px-2 py-0.5 text-xs rounded-full ${getTenantTagClass(tenantName, t)}`}\r\n >\r\n {tenantName}\r\n </span>\r\n ))\r\n ) : (\r\n <span className=\"text-xs text-[var(--text-muted)]\">-</span>\r\n )}\r\n </div>\r\n </td>\r\n\r\n {/* Source Column (Direct/Group/Custom) */}\r\n <td className=\"px-3 py-2\">\r\n <div className=\"flex flex-wrap gap-1\">\r\n {sourceRoles.length > 0 ? (\r\n getSourceTypesFromConsolidatedRoles(sourceRoles, consolidatedRolesMap).map((source, idx) => (\r\n <span\r\n key={`source-${source.type}-${idx}`}\r\n className={`inline-flex items-center gap-1 px-2 py-0.5 text-xs rounded-full ${getSourceTypeLabelClass(source.type)}`}\r\n title={source.type === 'Group' && source.groupName\r\n ? t('userPermissions.viaGroup', 'Via groupe: {{group}}', { group: source.groupName })\r\n : source.type === 'Custom'\r\n ? t('userPermissions.customPermissions', 'Permissions personnalisées')\r\n : t('userPermissions.directAssignmentTooltip', 'Rôle assigné directement à l\\'utilisateur')}\r\n >\r\n {source.type === 'Direct' && <UserCheck className=\"h-3 w-3\" />}\r\n {source.type === 'Group' && <Users className=\"h-3 w-3\" />}\r\n {source.type === 'Custom' && <User className=\"h-3 w-3\" />}\r\n {source.type === 'Direct'\r\n ? t('userPermissions.directAssignment', 'Direct')\r\n : source.type === 'Custom'\r\n ? t('userPermissions.customSource', 'Custom')\r\n : source.groupName || t('userPermissions.viaGroupShort', 'Groupe')}\r\n </span>\r\n ))\r\n ) : (\r\n <span className=\"text-xs text-[var(--text-muted)]\">-</span>\r\n )}\r\n </div>\r\n </td>\r\n\r\n {/* Permissions - Only show granted permissions for this level (module or section) */}\r\n <td className=\"px-3 py-2\">\r\n <div className=\"flex flex-wrap gap-1.5 items-center relative\">\r\n {resource.permissions\r\n .filter(perm => effectivePermissions.has(perm.id))\r\n .map(perm => {\r\n const isFromCustomRole = customRolePermissions.has(perm.id);\r\n const isToggling = togglingPermission === perm.id;\r\n const actionColor = ACTION_COLORS[perm.action] || 'bg-[var(--bg-secondary)] text-[var(--text-secondary)] border-[var(--border-color)]';\r\n const icon = ACTION_ICONS[perm.action] || <Eye className=\"h-3.5 w-3.5\" />;\r\n\r\n return (\r\n <button\r\n key={perm.id}\r\n onClick={() => handleTogglePermission(perm.id)}\r\n disabled={isToggling || loadingCustomRole || !isFromCustomRole}\r\n className={`inline-flex items-center gap-1.5 px-2 py-1 rounded-[var(--radius-badge)] border text-xs font-medium transition-all ${actionColor} ${\r\n isFromCustomRole ? 'ring-2 ring-[var(--color-accent-600)] dark:ring-[var(--color-accent-400)] hover:opacity-80 cursor-pointer' : 'opacity-60 cursor-not-allowed'\r\n } disabled:opacity-50`}\r\n title={isFromCustomRole ? t('userPermissions.clickToRemove', 'Cliquer pour retirer') : t('userPermissions.grantedByRole', 'Accordé par un rôle')}\r\n >\r\n {isToggling ? (\r\n <Loader2 className=\"h-3.5 w-3.5 animate-spin\" />\r\n ) : (\r\n icon\r\n )}\r\n <span className=\"capitalize\">\r\n {t(`assignments.actions.${perm.action === '*' ? 'all' : perm.action}.label`)}\r\n </span>\r\n {isFromCustomRole && <Star className=\"h-3 w-3\" />}\r\n </button>\r\n );\r\n })}\r\n\r\n </div>\r\n </td>\r\n </tr>\r\n );\r\n };\r\n\r\n return (\r\n <div className=\"space-y-4\">\r\n {!compact && (\r\n <>\r\n {/* Two-column responsive layout: filters sidebar | permissions table */}\r\n <div className=\"flex flex-col lg:flex-row lg:gap-6\">\r\n {/* Left Sidebar - Filters (sticky on large screens) */}\r\n <div className=\"w-full lg:w-72 lg:flex-shrink-0 mb-4 lg:mb-0 lg:sticky lg:top-4 lg:self-start\">\r\n {/* Filter Card */}\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--bg-secondary)] border border-[var(--border-color)]\">\r\n <h4 className=\"text-sm font-semibold text-[var(--text-primary)] mb-3\">\r\n {t('userPermissions.filters.title', 'Filtres')}\r\n </h4>\r\n\r\n {/* Filter Dropdowns - vertical layout in sidebar */}\r\n <div className=\"space-y-3\">\r\n <div className=\"space-y-1\">\r\n <label className=\"text-xs text-[var(--text-secondary)]\">\r\n {t('userPermissions.filters.application')}\r\n </label>\r\n <select\r\n value={filters.applicationFilter}\r\n onChange={(e) => updateFilters({ applicationFilter: e.target.value, moduleFilter: 'all' })}\r\n className=\"w-full px-3 py-1.5 text-sm bg-[var(--bg-primary)] border border-[var(--border-color)] rounded-[var(--radius-input)] text-[var(--text-primary)] focus:outline-none focus:ring-1 focus:ring-[var(--color-accent-500)]\"\r\n >\r\n <option value=\"all\">{t('userPermissions.filters.allApplications')}</option>\r\n {applications\r\n .map(app => (\r\n <option key={app.app} value={app.app}>{app.label}</option>\r\n ))}\r\n </select>\r\n </div>\r\n\r\n <div className=\"space-y-1\">\r\n <label className=\"text-xs text-[var(--text-secondary)]\">\r\n {t('userPermissions.filters.module')}\r\n </label>\r\n <select\r\n value={filters.moduleFilter}\r\n onChange={(e) => updateFilters({ moduleFilter: e.target.value })}\r\n className=\"w-full px-3 py-1.5 text-sm bg-[var(--bg-primary)] border border-[var(--border-color)] rounded-[var(--radius-input)] text-[var(--text-primary)] focus:outline-none focus:ring-1 focus:ring-[var(--color-accent-500)]\"\r\n >\r\n <option value=\"all\">{t('userPermissions.filters.allModules')}</option>\r\n {modules\r\n .filter(mod =>\r\n (filters.applicationFilter === 'all' || mod.app === filters.applicationFilter)\r\n )\r\n .map(mod => (\r\n <option key={`${mod.app}:${mod.module}`} value={mod.module}>{mod.label}</option>\r\n ))}\r\n </select>\r\n </div>\r\n </div>\r\n\r\n {/* Status Filter Buttons */}\r\n <div className=\"mt-4 pt-4 border-t border-[var(--border-color)]\">\r\n <span className=\"text-xs font-medium text-[var(--text-secondary)] block mb-2\">\r\n {t('userPermissions.filterByStatus')}\r\n </span>\r\n <div className=\"flex flex-wrap gap-1.5\">\r\n <button\r\n onClick={() => toggleStatusFilter('all')}\r\n className={`inline-flex items-center gap-1 px-2 py-1 text-xs rounded-full border transition-colors ${\r\n statusFilters.has('all')\r\n ? 'bg-[var(--success-bg)] border-[var(--success-border)] text-[var(--success-text)]'\r\n : 'bg-[var(--bg-tertiary)] border-[var(--border-color)] text-[var(--text-secondary)] hover:border-[var(--success-border)]'\r\n }`}\r\n >\r\n <Check className={`h-3 w-3 ${statusFilters.has('all') ? '' : 'text-[var(--success-dot)]'}`} />\r\n {t('assignments.complete')}\r\n </button>\r\n <button\r\n onClick={() => toggleStatusFilter('some')}\r\n className={`inline-flex items-center gap-1 px-2 py-1 text-xs rounded-full border transition-colors ${\r\n statusFilters.has('some')\r\n ? 'bg-[var(--warning-bg)] border-[var(--warning-border)] text-[var(--warning-text)]'\r\n : 'bg-[var(--bg-tertiary)] border-[var(--border-color)] text-[var(--text-secondary)] hover:border-[var(--warning-border)]'\r\n }`}\r\n >\r\n <Star className={`h-3 w-3 ${statusFilters.has('some') ? '' : 'text-[var(--warning-dot)]'}`} />\r\n {t('assignments.partial')}\r\n </button>\r\n <button\r\n onClick={() => toggleStatusFilter('read-only')}\r\n className={`inline-flex items-center gap-1 px-2 py-1 text-xs rounded-full border transition-colors ${\r\n statusFilters.has('read-only')\r\n ? 'bg-[var(--info-bg)] border-[var(--info-border)] text-[var(--info-text)]'\r\n : 'bg-[var(--bg-tertiary)] border-[var(--border-color)] text-[var(--text-secondary)] hover:border-[var(--info-border)]'\r\n }`}\r\n >\r\n <Eye className={`h-3 w-3 ${statusFilters.has('read-only') ? '' : 'text-[var(--info-dot)]'}`} />\r\n {t('assignments.readOnly')}\r\n </button>\r\n <button\r\n onClick={() => toggleStatusFilter('none')}\r\n className={`inline-flex items-center gap-1 px-2 py-1 text-xs rounded-full border transition-colors ${\r\n statusFilters.has('none')\r\n ? 'bg-[var(--error-bg)] border-[var(--error-border)] text-[var(--error-text)]'\r\n : 'bg-[var(--bg-tertiary)] border-[var(--border-color)] text-[var(--text-secondary)] hover:border-[var(--error-border)]'\r\n }`}\r\n >\r\n <Ban className={`h-3 w-3 ${statusFilters.has('none') ? '' : 'text-[var(--text-muted)]'}`} />\r\n {t('assignments.none')}\r\n </button>\r\n </div>\r\n {statusFilters.size > 0 && (\r\n <button\r\n onClick={() => setStatusFilters(new Set())}\r\n className=\"mt-2 text-xs text-[var(--color-accent-500)] hover:text-[var(--color-accent-600)] underline\"\r\n >\r\n {t('assignments.clearFilters')}\r\n </button>\r\n )}\r\n </div>\r\n\r\n {/* Stats */}\r\n <div className=\"mt-4 pt-4 border-t border-[var(--border-color)]\">\r\n <span className=\"px-2.5 py-1 text-xs font-semibold rounded-full bg-[var(--bg-tertiary)] text-[var(--text-secondary)]\">\r\n {totalModuleCount} {t('assignments.modules')}\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n {/* Right Content - Permissions Table */}\r\n <div className=\"flex-1 min-w-0 space-y-4\">\r\n {/* Tenant Mode Indicator */}\r\n {isTenantMode && tenantMember && (\r\n <div className=\"w-fit flex items-center gap-2 p-3 rounded-[var(--radius-card)] bg-[var(--accent-bg)] border border-[var(--accent-border)]\">\r\n <Shield className=\"h-4 w-4 text-[var(--accent-text)]\" />\r\n <span className=\"text-sm text-[var(--accent-text)]\">\r\n {t('userPermissions.tenantModeInfo', 'Affichage des permissions dans le contexte du tenant. Les rôles ci-dessous sont spécifiques à ce tenant.')}\r\n </span>\r\n </div>\r\n )}\r\n\r\n {/* Tenant Mode - User not member of current tenant */}\r\n {isTenantMode && !tenantMember && (\r\n <div className=\"w-fit flex items-center gap-2 p-3 rounded-[var(--radius-card)] bg-[var(--warning-bg)] border border-[var(--warning-border)]\">\r\n <AlertCircle className=\"h-4 w-4 text-[var(--warning-text)]\" />\r\n <span className=\"text-sm text-[var(--warning-text)]\">\r\n {t('userPermissions.notMemberOfTenant', 'Cet utilisateur n\\'est pas membre du tenant actuel. Aucune permission tenant disponible.')}\r\n </span>\r\n </div>\r\n )}\r\n\r\n {/* User Roles Badges */}\r\n {userRoles.length > 0 ? (\r\n <div className=\"flex flex-wrap gap-2\">\r\n {userRoles.map(role => {\r\n const isCustom = isCustomRole(role.name);\r\n return (\r\n <button\r\n key={role.id}\r\n onClick={() => !isCustom && navigate(`/administration/permissions/roles/${role.id}`)}\r\n className={`inline-flex items-center gap-1.5 px-3 py-1.5 text-sm rounded-full bg-[var(--color-accent-100)] text-[var(--color-accent-700)] dark:bg-[var(--color-accent-900)] dark:text-[var(--color-accent-300)] transition-all ${\r\n isCustom ? 'cursor-default' : 'cursor-pointer hover:ring-2 hover:ring-[var(--color-accent-500)] hover:shadow-md'\r\n }`}\r\n title={isCustom ? t('userPermissions.customRoleTooltip', 'Rôle personnalisé') : t('userPermissions.clickToViewRole', 'Cliquer pour voir le rôle')}\r\n >\r\n <Shield className=\"h-3.5 w-3.5\" />\r\n {role.shortName || role.name}\r\n </button>\r\n );\r\n })}\r\n </div>\r\n ) : !isTenantMode ? (\r\n <div className=\"w-fit flex items-center gap-2 p-3 rounded-[var(--radius-card)] bg-[var(--info-bg)] border border-[var(--info-border)]\">\r\n <Info className=\"h-4 w-4 text-[var(--info-text)]\" />\r\n <span className=\"text-sm text-[var(--info-text)]\">\r\n {t('userPermissions.noRolesInfo', 'Cet utilisateur n\\'a aucun rôle. Vous pouvez lui attribuer des permissions personnalisées ci-dessous.')}\r\n </span>\r\n </div>\r\n ) : null}\r\n\r\n {/* Permission Matrix Table */}\r\n <div className=\"overflow-x-auto overflow-y-visible\">\r\n <table className=\"border-collapse\" style={{ width: 'auto' }}>\r\n <thead className=\"item-medium border-b border-[var(--item-color-border)]\">\r\n <tr>\r\n <th\r\n scope=\"col\"\r\n className=\"sticky left-0 z-20 item-medium px-3 text-left text-xs font-medium text-[var(--text-secondary)] uppercase tracking-wider\"\r\n style={{ width: '280px', minWidth: '280px', maxWidth: '280px', height: '48px', verticalAlign: 'middle' }}\r\n >\r\n {t('assignments.resource')}\r\n </th>\r\n <th\r\n scope=\"col\"\r\n className=\"px-2 text-center text-xs font-medium text-[var(--text-secondary)] uppercase tracking-wider\"\r\n style={{ width: '60px', minWidth: '60px', maxWidth: '60px', height: '48px', verticalAlign: 'middle' }}\r\n >\r\n {t('userPermissions.status')}\r\n </th>\r\n <th\r\n scope=\"col\"\r\n className=\"px-3 text-left text-xs font-medium text-[var(--text-secondary)] uppercase tracking-wider\"\r\n style={{ height: '48px', verticalAlign: 'middle' }}\r\n >\r\n {t('userPermissions.sourceRoles')}\r\n </th>\r\n <th\r\n scope=\"col\"\r\n className=\"px-3 text-left text-xs font-medium text-[var(--text-secondary)] uppercase tracking-wider\"\r\n style={{ height: '48px', verticalAlign: 'middle', minWidth: '120px' }}\r\n >\r\n {t('userPermissions.tenant', 'Tenant')}\r\n </th>\r\n <th\r\n scope=\"col\"\r\n className=\"px-3 text-left text-xs font-medium text-[var(--text-secondary)] uppercase tracking-wider\"\r\n style={{ height: '48px', verticalAlign: 'middle', minWidth: '120px' }}\r\n >\r\n {t('userPermissions.source', 'Source')}\r\n </th>\r\n <th\r\n scope=\"col\"\r\n className=\"px-3 text-left text-xs font-medium text-[var(--text-secondary)] uppercase tracking-wider\"\r\n style={{ height: '48px', verticalAlign: 'middle' }}\r\n >\r\n {t('assignments.permissions')}\r\n </th>\r\n </tr>\r\n </thead>\r\n <tbody className=\"divide-y divide-[var(--item-color-border)]\">\r\n {groupedResources.map(appGroup => {\r\n const appKey = appGroup.application;\r\n const isAppCollapsed = collapsedApps.has(appKey);\r\n\r\n return (\r\n <React.Fragment key={appKey}>\r\n {/* Application Header Row */}\r\n <tr className=\"bg-[var(--bg-tertiary)]\">\r\n <td\r\n className=\"sticky left-0 z-10 px-3 py-2 bg-[var(--bg-tertiary)]\"\r\n style={{ width: '280px', minWidth: '280px', maxWidth: '280px' }}\r\n >\r\n <button\r\n onClick={() => toggleApp(appKey)}\r\n className=\"flex items-center gap-3 w-full text-left hover:opacity-80\"\r\n >\r\n {isAppCollapsed ? (\r\n <ChevronRight className=\"h-4 w-4 text-[var(--text-secondary)]\" />\r\n ) : (\r\n <ChevronDown className=\"h-4 w-4 text-[var(--text-secondary)]\" />\r\n )}\r\n <FolderOpen className=\"h-4 w-4 text-[var(--text-secondary)]\" />\r\n <span className=\"text-sm font-semibold text-[var(--text-primary)]\">\r\n {appGroup.application}\r\n </span>\r\n <span className=\"text-xs text-[var(--text-muted)] ml-auto\">\r\n {appGroup.modules.length} module{appGroup.modules.length > 1 ? 's' : ''}\r\n </span>\r\n </button>\r\n </td>\r\n <td colSpan={5} className=\"px-0 py-2\" />\r\n </tr>\r\n\r\n {/* Module, Section and Resource Rows */}\r\n {!isAppCollapsed && appGroup.modules.map((moduleWithSections: ModuleWithSections, moduleIndex: number) => renderModuleWithSections(moduleWithSections, moduleIndex))}\r\n </React.Fragment>\r\n );\r\n })}\r\n </tbody>\r\n </table>\r\n </div>\r\n\r\n {totalModuleCount === 0 && (\r\n <div className=\"text-center py-12 text-[var(--text-secondary)]\">\r\n {t('assignments.noResources')}\r\n </div>\r\n )}\r\n </div>\r\n </div>\r\n </>\r\n )}\r\n\r\n {compact && (\r\n <div className=\"overflow-x-auto overflow-y-visible\">\r\n <table className=\"border-collapse\" style={{ width: 'auto' }}>\r\n <thead className=\"item-medium border-b border-[var(--item-color-border)]\">\r\n <tr>\r\n <th scope=\"col\" className=\"sticky left-0 z-20 item-medium px-3 text-left text-xs font-medium text-[var(--text-secondary)] uppercase tracking-wider\" style={{ width: '280px', minWidth: '280px', maxWidth: '280px', height: '48px', verticalAlign: 'middle' }}>\r\n {t('assignments.resource')}\r\n </th>\r\n <th scope=\"col\" className=\"px-2 text-center text-xs font-medium text-[var(--text-secondary)] uppercase tracking-wider\" style={{ width: '60px', minWidth: '60px', maxWidth: '60px', height: '48px', verticalAlign: 'middle' }}>\r\n {t('userPermissions.status')}\r\n </th>\r\n <th scope=\"col\" className=\"px-3 text-left text-xs font-medium text-[var(--text-secondary)] uppercase tracking-wider\" style={{ height: '48px', verticalAlign: 'middle' }}>\r\n {t('userPermissions.sourceRoles')}\r\n </th>\r\n <th scope=\"col\" className=\"px-3 text-left text-xs font-medium text-[var(--text-secondary)] uppercase tracking-wider\" style={{ height: '48px', verticalAlign: 'middle' }}>\r\n {t('assignments.permissions')}\r\n </th>\r\n </tr>\r\n </thead>\r\n <tbody className=\"divide-y divide-[var(--item-color-border)]\">\r\n {groupedResources.map(appGroup => (\r\n <React.Fragment key={appGroup.application}>\r\n {appGroup.modules.map((moduleWithSections: ModuleWithSections, moduleIndex: number) => (\r\n <React.Fragment key={moduleWithSections.module.id}>\r\n {renderResourceRow(moduleWithSections.module, moduleIndex, 'module', false, false)}\r\n </React.Fragment>\r\n ))}\r\n </React.Fragment>\r\n ))}\r\n </tbody>\r\n </table>\r\n </div>\r\n )}\r\n </div>\r\n );\r\n}\r\n","import type { ReactElement } from 'react';\r\nimport { useTranslation } from 'react-i18next';\r\nimport { LayoutGrid, Table2 } from 'lucide-react';\r\n\r\nexport type ViewMode = 'cards' | 'table';\r\n\r\ninterface ViewModeToggleProps {\r\n readonly viewMode: ViewMode;\r\n readonly onChange: (mode: ViewMode) => void;\r\n}\r\n\r\nexport function ViewModeToggle({ viewMode, onChange }: ViewModeToggleProps): ReactElement {\r\n const { t } = useTranslation();\r\n\r\n return (\r\n <div className=\"flex items-center rounded-[var(--radius-button)] border border-[var(--border-color)] bg-[var(--bg-primary)] p-0.5 h-[34px]\">\r\n <button\r\n onClick={() => onChange('cards')}\r\n className={`flex items-center justify-center gap-1 px-2.5 h-full rounded text-sm transition-colors ${\r\n viewMode === 'cards'\r\n ? 'bg-[var(--color-accent-500)] text-white'\r\n : 'text-[var(--text-secondary)] hover:bg-[var(--bg-hover)]'\r\n }`}\r\n title={t('common.cardView', 'Vue cartes')}\r\n >\r\n <LayoutGrid className=\"w-4 h-4\" />\r\n </button>\r\n <button\r\n onClick={() => onChange('table')}\r\n className={`flex items-center justify-center gap-1 px-2.5 h-full rounded text-sm transition-colors ${\r\n viewMode === 'table'\r\n ? 'bg-[var(--color-accent-500)] text-white'\r\n : 'text-[var(--text-secondary)] hover:bg-[var(--bg-hover)]'\r\n }`}\r\n title={t('common.tableView', 'Vue tableau')}\r\n >\r\n <Table2 className=\"w-4 h-4\" />\r\n </button>\r\n </div>\r\n );\r\n}\r\n\r\nexport default ViewModeToggle;\r\n","import { useState, useEffect, useCallback } from 'react';\r\nimport type { ReactElement } from 'react';\r\nimport { useTranslation } from 'react-i18next';\r\nimport { useNavigate } from 'react-router-dom';\r\nimport { Users, Loader2, Plus, RefreshCw, Search, X, Trash2, AlertTriangle, CheckCircle, Info, Shield, Cloud, Check, Filter } from 'lucide-react';\r\nimport { groupsApi, type GroupListDto } from '@/services/api/groupsApi';\r\nimport { adminApi, type UserGroupDto } from '@/services/api/adminApi';\r\nimport { DataTable, type DataTableColumn } from '@/components/ui/DataTable';\r\nimport { ViewModeToggle, type ViewMode } from '@/components/ui/ViewModeToggle';\r\nimport { getCustomRoleIcon } from '@/utils/roleUtils';\r\n\r\ntype GroupTypeFilter = 'all' | 'security' | 'standard' | 'entra';\r\n\r\ninterface UserGroupsTabProps {\r\n readonly userId: string;\r\n readonly userName: string;\r\n}\r\n\r\nexport function UserGroupsTab({ userId, userName }: UserGroupsTabProps): ReactElement {\r\n const { t } = useTranslation(['admin', 'groups']);\r\n const navigate = useNavigate();\r\n\r\n const [userGroups, setUserGroups] = useState<UserGroupDto[]>([] as UserGroupDto[]);\r\n const [allGroups, setAllGroups] = useState<GroupListDto[] | null>(null);\r\n const [loading, setLoading] = useState(true);\r\n const [showAddModal, setShowAddModal] = useState(false);\r\n const [searchQuery, setSearchQuery] = useState('');\r\n const [groupTypeFilter, setGroupTypeFilter] = useState<GroupTypeFilter>('all');\r\n const [selectedGroupIds, setSelectedGroupIds] = useState<Set<string>>(new Set());\r\n const [isAddingMultiple, setIsAddingMultiple] = useState(false);\r\n const [removingGroupId, setRemovingGroupId] = useState<string | null>(null);\r\n const [error, setError] = useState<string | null>(null);\r\n const [success, setSuccess] = useState<string | null>(null);\r\n const [viewMode, setViewMode] = useState<ViewMode>('cards');\r\n\r\n const loadUserGroups = useCallback(async () => {\r\n try {\r\n setLoading(true);\r\n const data = await adminApi.users.getGroups(userId);\r\n setUserGroups(data);\r\n } catch (err) {\r\n console.error('Failed to load user groups:', err);\r\n setError(t('admin:userDetail.groups.loadError', 'Erreur lors du chargement des groupes'));\r\n } finally {\r\n setLoading(false);\r\n }\r\n }, [userId, t]);\r\n\r\n const loadAllGroups = async () => {\r\n try {\r\n const data = await groupsApi.getAll(undefined, true);\r\n setAllGroups(data);\r\n } catch (err) {\r\n console.error('Failed to load all groups:', err);\r\n }\r\n };\r\n\r\n useEffect(() => {\r\n loadUserGroups();\r\n loadAllGroups();\r\n }, [loadUserGroups]);\r\n\r\n const handleRemoveFromGroup = async (groupId: string) => {\r\n const group = userGroups?.find((g) => g.id === groupId);\r\n if (!confirm(t('admin:userDetail.groups.confirmRemove', { userName, groupName: group?.name }))) {\r\n return;\r\n }\r\n\r\n try {\r\n setRemovingGroupId(groupId);\r\n setError(null);\r\n await groupsApi.removeMember(groupId, userId);\r\n await loadUserGroups();\r\n setSuccess(t('admin:userDetail.groups.removeSuccess', 'Utilisateur retiré du groupe'));\r\n setTimeout(() => setSuccess(null), 3000);\r\n } catch (err: any) {\r\n console.error('Failed to remove from group:', err);\r\n const errorMessage = err?.response?.data?.message || t('admin:userDetail.groups.removeError', 'Erreur lors du retrait du groupe');\r\n setError(errorMessage);\r\n } finally {\r\n setRemovingGroupId(null);\r\n }\r\n };\r\n\r\n const availableGroups = allGroups?.filter(\r\n (g) => !userGroups?.some((ug) => ug.id === g.id)\r\n );\r\n\r\n const filteredAvailableGroups = availableGroups?.filter((g) => {\r\n // Type filter\r\n if (groupTypeFilter === 'security' && !g.isSecurityGroup) return false;\r\n if (groupTypeFilter === 'standard' && g.isSecurityGroup) return false;\r\n if (groupTypeFilter === 'entra' && !g.isSyncedFromEntra) return false;\r\n\r\n // Search filter\r\n if (!searchQuery.trim()) return true;\r\n const query = searchQuery.toLowerCase().trim();\r\n return (\r\n g.name.toLowerCase().includes(query) ||\r\n (g.description?.toLowerCase().includes(query) ?? false)\r\n );\r\n });\r\n\r\n const toggleGroupSelection = (groupId: string) => {\r\n setSelectedGroupIds((prev) => {\r\n const newSet = new Set(prev);\r\n if (newSet.has(groupId)) {\r\n newSet.delete(groupId);\r\n } else {\r\n newSet.add(groupId);\r\n }\r\n return newSet;\r\n });\r\n };\r\n\r\n const getGroupTypeFilterClass = (filter: GroupTypeFilter, currentFilter: GroupTypeFilter): string => {\r\n return currentFilter === filter\r\n ? 'px-3 py-1 rounded-full text-xs font-medium transition-colors bg-[var(--color-accent-500)] text-white'\r\n : 'px-3 py-1 rounded-full text-xs font-medium transition-colors bg-[var(--bg-secondary)] text-[var(--text-secondary)] hover:bg-[var(--bg-hover)]';\r\n };\r\n\r\n const getGroupCheckboxClass = (isSelected: boolean): string => {\r\n return isSelected\r\n ? 'w-5 h-5 rounded border-2 flex items-center justify-center flex-shrink-0 transition-colors bg-[var(--color-accent-500)] border-[var(--color-accent-500)]'\r\n : 'w-5 h-5 rounded border-2 flex items-center justify-center flex-shrink-0 transition-colors border-[var(--border-color)]';\r\n };\r\n\r\n const selectAllFiltered = () => {\r\n if (filteredAvailableGroups) {\r\n setSelectedGroupIds(new Set(filteredAvailableGroups.map((g) => g.id)));\r\n }\r\n };\r\n\r\n const clearSelection = () => {\r\n setSelectedGroupIds(new Set());\r\n };\r\n\r\n const handleAddMultipleGroups = async () => {\r\n if (selectedGroupIds.size === 0) return;\r\n\r\n try {\r\n setIsAddingMultiple(true);\r\n setError(null);\r\n\r\n const groupIdsArray = Array.from(selectedGroupIds);\r\n for (const groupId of groupIdsArray) {\r\n await groupsApi.addMember(groupId, { userId });\r\n }\r\n\r\n await loadUserGroups();\r\n setShowAddModal(false);\r\n setSearchQuery('');\r\n setGroupTypeFilter('all');\r\n setSelectedGroupIds(new Set());\r\n setSuccess(t('admin:userDetail.groups.addMultipleSuccess', { count: groupIdsArray.length, defaultValue: `${groupIdsArray.length} groupe(s) ajouté(s)` }));\r\n setTimeout(() => setSuccess(null), 3000);\r\n } catch (err: any) {\r\n console.error('Failed to add groups:', err);\r\n const errorMessage = err?.response?.data?.message || t('admin:userDetail.groups.addError', 'Erreur lors de l\\'ajout au groupe');\r\n setError(errorMessage);\r\n } finally {\r\n setIsAddingMultiple(false);\r\n }\r\n };\r\n\r\n const closeModal = () => {\r\n setShowAddModal(false);\r\n setSearchQuery('');\r\n setGroupTypeFilter('all');\r\n setSelectedGroupIds(new Set());\r\n };\r\n\r\n return (\r\n <div className=\"space-y-6\">\r\n {/* Header */}\r\n <div className=\"flex items-center justify-between\">\r\n <h3 className=\"text-lg font-semibold text-[var(--text-primary)] flex items-center gap-2\">\r\n <Users className=\"w-5 h-5\" />\r\n {t('admin:userDetail.groups.title', 'Groupes de l\\'utilisateur')}\r\n {userGroups && (\r\n <span className=\"ml-2 px-2 py-0.5 text-xs rounded-full bg-[var(--bg-secondary)] text-[var(--text-secondary)]\">\r\n {userGroups.length}\r\n </span>\r\n )}\r\n </h3>\r\n <div className=\"flex items-center gap-2\">\r\n <button\r\n onClick={() => setShowAddModal(true)}\r\n className=\"flex items-center gap-2 px-3 py-1.5 rounded-[var(--radius-button)] bg-[var(--color-accent-600)] text-white hover:bg-[var(--color-accent-700)] transition-colors\"\r\n >\r\n <Plus className=\"w-4 h-4\" />\r\n {t('admin:userDetail.groups.add', 'Ajouter à un groupe')}\r\n </button>\r\n <button\r\n onClick={loadUserGroups}\r\n className=\"flex items-center gap-2 px-3 py-1.5 rounded-[var(--radius-button)] bg-[var(--bg-primary)] border border-[var(--border-color)] text-[var(--text-secondary)] hover:bg-[var(--bg-hover)] transition-colors\"\r\n >\r\n <RefreshCw className=\"w-4 h-4\" />\r\n {t('common.refresh', 'Actualiser')}\r\n </button>\r\n <ViewModeToggle viewMode={viewMode} onChange={setViewMode} />\r\n </div>\r\n </div>\r\n\r\n {/* Alerts */}\r\n {error && (\r\n <div className=\"p-4 rounded-lg bg-red-500/10 border border-red-500/20 flex items-center gap-3\">\r\n <AlertTriangle className=\"w-5 h-5 text-red-500 flex-shrink-0\" />\r\n <p className=\"text-red-500\">{error}</p>\r\n <button onClick={() => setError(null)} className=\"ml-auto\">\r\n <X className=\"w-4 h-4 text-red-500\" />\r\n </button>\r\n </div>\r\n )}\r\n\r\n {success && (\r\n <div className=\"p-4 rounded-lg bg-green-500/10 border border-green-500/20 flex items-center gap-3\">\r\n <CheckCircle className=\"w-5 h-5 text-green-500 flex-shrink-0\" />\r\n <p className=\"text-green-500\">{success}</p>\r\n </div>\r\n )}\r\n\r\n {/* Info banner */}\r\n <div className=\"p-4 rounded-lg bg-blue-500/10 border border-blue-500/20\">\r\n <p className=\"text-sm text-blue-500\">\r\n {t('admin:userDetail.groups.info', 'L\\'utilisateur hérite automatiquement des rôles et permissions des groupes auxquels il appartient.')}\r\n </p>\r\n </div>\r\n\r\n {/* Content */}\r\n {loading && (\r\n <div className=\"flex items-center justify-center py-12\">\r\n <Loader2 className=\"w-6 h-6 animate-spin text-[var(--color-accent-500)]\" />\r\n </div>\r\n )}\r\n {!loading && (!userGroups || userGroups.length === 0) && (\r\n <div className=\"text-center py-12\">\r\n <Users className=\"w-12 h-12 mx-auto mb-4 text-[var(--text-tertiary)]\" />\r\n <p className=\"text-[var(--text-secondary)] mb-4\">\r\n {t('admin:userDetail.groups.noGroups', 'Cet utilisateur n\\'appartient à aucun groupe')}\r\n </p>\r\n <button\r\n onClick={() => setShowAddModal(true)}\r\n className=\"inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-[var(--color-accent-600)] text-white hover:bg-[var(--color-accent-700)] transition-colors\"\r\n >\r\n <Plus className=\"w-4 h-4\" />\r\n {t('admin:userDetail.groups.addFirst', 'Ajouter à un premier groupe')}\r\n </button>\r\n </div>\r\n )}\r\n {!loading && (userGroups?.length ?? 0) > 0 && viewMode === 'table' && (\r\n <DataTable\r\n data={userGroups}\r\n columns={[\r\n {\r\n key: 'name',\r\n label: t('admin:userDetail.groups.table.name', 'Nom'),\r\n sortable: true,\r\n render: (group) => (\r\n <div className=\"flex items-center gap-2\">\r\n <div className={`p-1.5 rounded flex-shrink-0 ${\r\n group.isSecurityGroup\r\n ? 'bg-blue-500/10 text-blue-500'\r\n : 'bg-[var(--color-accent-500)]/10 text-[var(--color-accent-500)]'\r\n }`}>\r\n {group.isSecurityGroup ? <Shield className=\"w-4 h-4\" /> : <Users className=\"w-4 h-4\" />}\r\n </div>\r\n <div className=\"min-w-0\">\r\n <span className=\"font-medium text-[var(--text-primary)] flex items-center gap-1\">\r\n {group.name}\r\n {group.isSyncedFromEntra && <Cloud className=\"w-3.5 h-3.5 text-[var(--color-accent-500)]\" />}\r\n </span>\r\n </div>\r\n </div>\r\n ),\r\n },\r\n {\r\n key: 'description',\r\n label: t('admin:userDetail.groups.table.description', 'Description'),\r\n render: (group) => (\r\n <span className=\"text-[var(--text-secondary)] truncate max-w-[200px] block\">\r\n {group.description || '-'}\r\n </span>\r\n ),\r\n hideOnMobile: true,\r\n },\r\n {\r\n key: 'roles',\r\n label: t('admin:userDetail.groups.table.roles', 'Rôles'),\r\n render: (group) => (\r\n <div className=\"flex flex-wrap gap-1\">\r\n {group.roles.slice(0, 2).map((role) => {\r\n const customIcon = getCustomRoleIcon(role.code);\r\n return (\r\n <span\r\n key={role.name}\r\n className=\"inline-flex items-center gap-1 px-1.5 py-0.5 rounded-full text-xs bg-[var(--color-accent-500)]/10 text-[var(--color-accent-500)]\"\r\n >\r\n {customIcon ? (\r\n <span>{customIcon}</span>\r\n ) : (\r\n <Shield className=\"w-3 h-3\" />\r\n )}\r\n {role.name}\r\n </span>\r\n );\r\n })}\r\n {group.roles.length > 2 && (\r\n <span className=\"text-xs text-[var(--text-tertiary)]\">+{group.roles.length - 2}</span>\r\n )}\r\n {group.roles.length === 0 && <span className=\"text-[var(--text-tertiary)]\">-</span>}\r\n </div>\r\n ),\r\n hideOnMobile: true,\r\n },\r\n {\r\n key: 'addedAt',\r\n label: t('admin:userDetail.groups.table.addedAt', 'Ajouté le'),\r\n sortable: true,\r\n render: (group) => (\r\n <span className=\"text-[var(--text-secondary)] text-sm\">\r\n {new Date(group.addedAt).toLocaleDateString()}\r\n </span>\r\n ),\r\n hideOnMobile: true,\r\n },\r\n {\r\n key: 'actions',\r\n label: '',\r\n width: '80px',\r\n align: 'right',\r\n render: (group) => (\r\n <div className=\"flex items-center justify-end gap-1\">\r\n {group.isSyncedFromEntra ? (\r\n <span className=\"text-xs text-amber-500 flex items-center gap-1\">\r\n <Info className=\"w-3 h-3\" />\r\n Entra\r\n </span>\r\n ) : (\r\n <button\r\n onClick={(e) => {\r\n e.stopPropagation();\r\n handleRemoveFromGroup(group.id);\r\n }}\r\n disabled={removingGroupId === group.id}\r\n className=\"flex items-center gap-1 px-2 py-1 rounded text-xs text-red-500 hover:bg-red-500/10 transition-colors disabled:opacity-50\"\r\n >\r\n {removingGroupId === group.id ? (\r\n <Loader2 className=\"w-3 h-3 animate-spin\" />\r\n ) : (\r\n <Trash2 className=\"w-3 h-3\" />\r\n )}\r\n </button>\r\n )}\r\n </div>\r\n ),\r\n },\r\n ] as DataTableColumn<UserGroupDto>[]}\r\n getRowKey={(group) => group.id}\r\n onRowClick={(group) => navigate(`/administration/users/groups/${group.id}`)}\r\n compact\r\n emptyMessage={t('admin:userDetail.groups.noGroups', 'Cet utilisateur n\\'appartient à aucun groupe')}\r\n emptyIcon={<Users className=\"w-8 h-8 text-[var(--text-tertiary)]\" />}\r\n />\r\n )}\r\n {!loading && (userGroups?.length ?? 0) > 0 && viewMode !== 'table' && (\r\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4\">\r\n {userGroups?.map((group) => (\r\n <div\r\n key={group.id}\r\n className=\"p-4 rounded-[var(--radius-card)] bg-[var(--bg-primary)] border border-[var(--border-color)] hover:border-[var(--color-accent-500)] transition-colors\"\r\n >\r\n <div className=\"flex items-start justify-between gap-3\">\r\n <button\r\n type=\"button\"\r\n className=\"flex items-start gap-3 min-w-0 cursor-pointer text-left\"\r\n onClick={() => navigate(`/administration/users/groups/${group.id}`)}\r\n >\r\n <div className={`p-2 rounded-lg flex-shrink-0 ${\r\n group.isSecurityGroup\r\n ? 'bg-blue-500/10 text-blue-500'\r\n : 'bg-[var(--color-accent-500)]/10 text-[var(--color-accent-500)]'\r\n }`}>\r\n {group.isSecurityGroup ? <Shield className=\"w-5 h-5\" /> : <Users className=\"w-5 h-5\" />}\r\n </div>\r\n <div className=\"min-w-0\">\r\n <h4 className=\"text-sm font-semibold text-[var(--text-primary)] truncate flex items-center gap-2\">\r\n {group.name}\r\n {group.isSyncedFromEntra && (\r\n <Cloud className=\"w-3.5 h-3.5 text-[var(--color-accent-500)]\" />\r\n )}\r\n </h4>\r\n {group.description && (\r\n <p className=\"text-xs text-[var(--text-tertiary)] truncate\">{group.description}</p>\r\n )}\r\n </div>\r\n </button>\r\n </div>\r\n\r\n {group.roles.length > 0 && (\r\n <div className=\"mt-3 flex flex-wrap gap-1\">\r\n {group.roles.slice(0, 3).map((role) => {\r\n const customIcon = getCustomRoleIcon(role.code);\r\n return (\r\n <span\r\n key={role.name}\r\n className=\"inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-xs bg-[var(--color-accent-500)]/10 text-[var(--color-accent-500)]\"\r\n >\r\n {customIcon ? (\r\n <span>{customIcon}</span>\r\n ) : (\r\n <Shield className=\"w-3 h-3\" />\r\n )}\r\n {role.name}\r\n </span>\r\n );\r\n })}\r\n {group.roles.length > 3 && (\r\n <span className=\"text-xs text-[var(--text-tertiary)]\">\r\n +{group.roles.length - 3}\r\n </span>\r\n )}\r\n </div>\r\n )}\r\n\r\n <div className=\"mt-3 pt-3 border-t border-[var(--border-color)] space-y-1\">\r\n <p className=\"text-xs text-[var(--text-tertiary)]\">\r\n {t('admin:userDetail.groups.addedAt', 'Ajouté le')}: {new Date(group.addedAt).toLocaleDateString()}\r\n </p>\r\n {group.addedBy && (\r\n <p className=\"text-xs text-[var(--text-tertiary)]\">\r\n {t('admin:userDetail.groups.addedBy', 'Par')}: {group.addedBy}\r\n </p>\r\n )}\r\n </div>\r\n\r\n {!group.isSyncedFromEntra && (\r\n <div className=\"mt-3 flex justify-end\">\r\n <button\r\n onClick={() => handleRemoveFromGroup(group.id)}\r\n disabled={removingGroupId === group.id}\r\n className=\"flex items-center gap-1 px-2 py-1 rounded text-xs text-red-500 hover:bg-red-500/10 transition-colors disabled:opacity-50\"\r\n >\r\n {removingGroupId === group.id ? (\r\n <Loader2 className=\"w-3 h-3 animate-spin\" />\r\n ) : (\r\n <Trash2 className=\"w-3 h-3\" />\r\n )}\r\n {t('common.remove', 'Retirer')}\r\n </button>\r\n </div>\r\n )}\r\n\r\n {group.isSyncedFromEntra && (\r\n <div className=\"mt-3 flex items-center gap-1 text-xs text-amber-500\">\r\n <Info className=\"w-3 h-3\" />\r\n {t('admin:userDetail.groups.syncedFromEntra', 'Synchronisé depuis Entra ID')}\r\n </div>\r\n )}\r\n </div>\r\n ))}\r\n </div>\r\n )}\r\n\r\n {/* Add to Group Modal */}\r\n {showAddModal && (\r\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50\">\r\n <div className=\"w-full max-w-2xl mx-4 bg-[var(--bg-primary)] rounded-[var(--radius-card)] shadow-xl\">\r\n <div className=\"flex items-center justify-between p-4 border-b border-[var(--border-color)]\">\r\n <h3 className=\"text-lg font-semibold text-[var(--text-primary)]\">\r\n {t('admin:userDetail.groups.addModalTitle', 'Ajouter à un groupe')}\r\n </h3>\r\n <button\r\n onClick={closeModal}\r\n className=\"p-1 rounded hover:bg-[var(--bg-hover)] transition-colors\"\r\n >\r\n <X className=\"w-5 h-5 text-[var(--text-secondary)]\" />\r\n </button>\r\n </div>\r\n\r\n <div className=\"p-4 space-y-4\">\r\n {/* Search and Filters */}\r\n <div className=\"space-y-3\">\r\n <div className=\"relative\">\r\n <Search className=\"absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 text-[var(--text-tertiary)]\" />\r\n <input\r\n type=\"text\"\r\n placeholder={t('admin:userDetail.groups.searchPlaceholder', 'Rechercher un groupe...')}\r\n value={searchQuery}\r\n onChange={(e) => setSearchQuery(e.target.value)}\r\n className=\"w-full pl-10 pr-4 py-2 rounded-lg border border-[var(--border-color)] bg-[var(--bg-primary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n autoFocus\r\n />\r\n </div>\r\n\r\n {/* Type Filters */}\r\n <div className=\"flex items-center gap-2 flex-wrap\">\r\n <Filter className=\"w-4 h-4 text-[var(--text-tertiary)]\" />\r\n {(['all', 'security', 'standard', 'entra'] as const).map((filter) => (\r\n <button\r\n key={filter}\r\n onClick={() => setGroupTypeFilter(filter)}\r\n className={getGroupTypeFilterClass(filter, groupTypeFilter)}\r\n >\r\n {filter === 'all' && t('admin:userDetail.groups.filterAll', 'Tous')}\r\n {filter === 'security' && (\r\n <span className=\"flex items-center gap-1\">\r\n <Shield className=\"w-3 h-3\" />\r\n {t('admin:userDetail.groups.filterSecurity', 'Sécurité')}\r\n </span>\r\n )}\r\n {filter === 'standard' && (\r\n <span className=\"flex items-center gap-1\">\r\n <Users className=\"w-3 h-3\" />\r\n {t('admin:userDetail.groups.filterStandard', 'Standard')}\r\n </span>\r\n )}\r\n {filter === 'entra' && (\r\n <span className=\"flex items-center gap-1\">\r\n <Cloud className=\"w-3 h-3\" />\r\n {t('admin:userDetail.groups.filterEntra', 'Entra ID')}\r\n </span>\r\n )}\r\n </button>\r\n ))}\r\n </div>\r\n\r\n {/* Selection Actions */}\r\n {(filteredAvailableGroups?.length ?? 0) > 0 && (\r\n <div className=\"flex items-center justify-between text-xs\">\r\n <span className=\"text-[var(--text-secondary)]\">\r\n {selectedGroupIds.size > 0\r\n ? t('admin:userDetail.groups.selectedCount', { count: selectedGroupIds.size, defaultValue: `${selectedGroupIds.size} sélectionné(s)` })\r\n : t('admin:userDetail.groups.availableCount', { count: filteredAvailableGroups?.length ?? 0, defaultValue: `${filteredAvailableGroups?.length ?? 0} groupe(s) disponible(s)` })}\r\n </span>\r\n <div className=\"flex items-center gap-2\">\r\n <button\r\n onClick={selectAllFiltered}\r\n className=\"text-[var(--color-accent-500)] hover:underline\"\r\n >\r\n {t('admin:userDetail.groups.selectAll', 'Tout sélectionner')}\r\n </button>\r\n {selectedGroupIds.size > 0 && (\r\n <button\r\n onClick={clearSelection}\r\n className=\"text-[var(--text-tertiary)] hover:underline\"\r\n >\r\n {t('admin:userDetail.groups.clearSelection', 'Effacer')}\r\n </button>\r\n )}\r\n </div>\r\n </div>\r\n )}\r\n </div>\r\n\r\n {/* Group List */}\r\n <div className=\"max-h-[350px] overflow-y-auto space-y-2\">\r\n {!filteredAvailableGroups || filteredAvailableGroups.length === 0 ? (\r\n <div className=\"text-center py-8\">\r\n <Users className=\"w-8 h-8 mx-auto mb-2 text-[var(--text-tertiary)]\" />\r\n <p className=\"text-sm text-[var(--text-secondary)]\">\r\n {t('admin:userDetail.groups.noAvailableGroups', 'Aucun groupe disponible')}\r\n </p>\r\n </div>\r\n ) : (\r\n filteredAvailableGroups.map((group) => {\r\n const isSelected = selectedGroupIds.has(group.id);\r\n return (\r\n <button\r\n type=\"button\"\r\n key={group.id}\r\n onClick={() => toggleGroupSelection(group.id)}\r\n className={`w-full flex items-center gap-3 p-3 rounded-lg border cursor-pointer transition-colors text-left ${\r\n isSelected\r\n ? 'border-[var(--color-accent-500)] bg-[var(--color-accent-500)]/5'\r\n : 'border-[var(--border-color)] hover:border-[var(--color-accent-500)] hover:bg-[var(--bg-hover)]'\r\n }`}\r\n >\r\n {/* Checkbox */}\r\n <div className={getGroupCheckboxClass(isSelected)}>\r\n {isSelected && <Check className=\"w-3 h-3 text-white\" />}\r\n </div>\r\n\r\n {/* Icon */}\r\n <div className={`p-2 rounded-lg flex-shrink-0 ${\r\n group.isSecurityGroup\r\n ? 'bg-blue-500/10 text-blue-500'\r\n : 'bg-[var(--color-accent-500)]/10 text-[var(--color-accent-500)]'\r\n }`}>\r\n {group.isSecurityGroup ? <Shield className=\"w-5 h-5\" /> : <Users className=\"w-5 h-5\" />}\r\n </div>\r\n\r\n {/* Content */}\r\n <div className=\"flex-1 min-w-0\">\r\n <p className=\"text-sm font-medium text-[var(--text-primary)] truncate flex items-center gap-2\">\r\n {group.name}\r\n {group.isSyncedFromEntra && (\r\n <Cloud className=\"w-3.5 h-3.5 text-[var(--color-accent-500)]\" />\r\n )}\r\n </p>\r\n {group.description && (\r\n <p className=\"text-xs text-[var(--text-tertiary)] truncate\">{group.description}</p>\r\n )}\r\n </div>\r\n\r\n {/* Member count */}\r\n <span className=\"text-xs text-[var(--text-tertiary)] flex-shrink-0\">\r\n {group.memberCount} {t('admin:userDetail.groups.members', 'membres')}\r\n </span>\r\n </button>\r\n );\r\n })\r\n )}\r\n </div>\r\n </div>\r\n\r\n <div className=\"flex items-center justify-between p-4 border-t border-[var(--border-color)]\">\r\n <div className=\"text-sm text-[var(--text-secondary)]\">\r\n {selectedGroupIds.size > 0 && (\r\n <span className=\"flex items-center gap-2\">\r\n <span className=\"w-6 h-6 rounded-full bg-[var(--color-accent-500)] text-white text-xs flex items-center justify-center font-medium\">\r\n {selectedGroupIds.size}\r\n </span>\r\n {t('admin:userDetail.groups.groupsSelected', 'groupe(s) sélectionné(s)')}\r\n </span>\r\n )}\r\n </div>\r\n <div className=\"flex items-center gap-2\">\r\n <button\r\n onClick={closeModal}\r\n className=\"px-4 py-2 rounded-lg bg-[var(--bg-secondary)] text-[var(--text-secondary)] hover:bg-[var(--bg-hover)] transition-colors\"\r\n >\r\n {t('common.cancel', 'Annuler')}\r\n </button>\r\n <button\r\n onClick={handleAddMultipleGroups}\r\n disabled={selectedGroupIds.size === 0 || isAddingMultiple}\r\n className=\"px-4 py-2 rounded-lg bg-[var(--color-accent-600)] text-white hover:bg-[var(--color-accent-700)] transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2\"\r\n >\r\n {isAddingMultiple ? (\r\n <>\r\n <Loader2 className=\"w-4 h-4 animate-spin\" />\r\n {t('admin:userDetail.groups.adding', 'Ajout en cours...')}\r\n </>\r\n ) : (\r\n <>\r\n <Plus className=\"w-4 h-4\" />\r\n {t('admin:userDetail.groups.addSelected', 'Ajouter')}\r\n {selectedGroupIds.size > 0 && ` (${selectedGroupIds.size})`}\r\n </>\r\n )}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n )}\r\n </div>\r\n );\r\n}\r\n","import { useState, useEffect } from 'react';\r\nimport type { ReactElement } from 'react';\r\nimport { useTranslation } from 'react-i18next';\r\nimport { Plus } from 'lucide-react';\r\n\r\nexport interface SelectOption {\r\n id: string;\r\n name: string;\r\n}\r\n\r\nexport interface SelectWithOtherValue {\r\n id: string;\r\n customValue?: string;\r\n}\r\n\r\ninterface SelectWithOtherProps {\r\n readonly label: string;\r\n readonly options: SelectOption[];\r\n readonly value: SelectWithOtherValue;\r\n readonly onChange: (value: SelectWithOtherValue) => void;\r\n readonly placeholder?: string;\r\n readonly disabled?: boolean;\r\n readonly className?: string;\r\n /** Allow \"Other...\" option to create new values. Default: true */\r\n readonly allowOther?: boolean;\r\n}\r\n\r\nconst OTHER_VALUE = '__OTHER__';\r\n\r\nexport function SelectWithOther({\r\n label,\r\n options,\r\n value,\r\n onChange,\r\n placeholder,\r\n disabled = false,\r\n className = '',\r\n allowOther = true,\r\n}: SelectWithOtherProps): ReactElement {\r\n const { t } = useTranslation();\r\n const [isOther, setIsOther] = useState(false);\r\n const [customInput, setCustomInput] = useState('');\r\n\r\n // Detect if current value is \"other\" mode\r\n useEffect(() => {\r\n if (value.customValue !== undefined) {\r\n setIsOther(true);\r\n setCustomInput(value.customValue);\r\n } else {\r\n setIsOther(false);\r\n setCustomInput('');\r\n }\r\n }, [value]);\r\n\r\n const handleSelectChange = (e: React.ChangeEvent<HTMLSelectElement>) => {\r\n const selectedValue = e.target.value;\r\n\r\n if (selectedValue === OTHER_VALUE) {\r\n setIsOther(true);\r\n setCustomInput('');\r\n onChange({ id: '', customValue: '' });\r\n } else {\r\n setIsOther(false);\r\n setCustomInput('');\r\n onChange({ id: selectedValue, customValue: undefined });\r\n }\r\n };\r\n\r\n const handleCustomInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\r\n const newValue = e.target.value;\r\n setCustomInput(newValue);\r\n onChange({ id: '', customValue: newValue });\r\n };\r\n\r\n const handleCancelOther = () => {\r\n setIsOther(false);\r\n setCustomInput('');\r\n onChange({ id: '', customValue: undefined });\r\n };\r\n\r\n const selectValue = isOther ? OTHER_VALUE : value.id;\r\n\r\n return (\r\n <div className={className}>\r\n <label className=\"block text-sm font-medium text-[var(--text-secondary)] mb-1\">\r\n {label}\r\n </label>\r\n <div className=\"flex gap-2\">\r\n <select\r\n value={selectValue}\r\n onChange={handleSelectChange}\r\n disabled={disabled}\r\n className={`flex-1 px-4 py-2 rounded-[var(--radius-input)] border border-[var(--border-color)] bg-[var(--bg-primary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)] ${isOther ? 'w-1/3 flex-none' : ''}`}\r\n >\r\n <option value=\"\">{placeholder || t('common.none', '-- Aucun --')}</option>\r\n {options.map(opt => (\r\n <option key={opt.id} value={opt.id}>{opt.name}</option>\r\n ))}\r\n {allowOther && (\r\n <option value={OTHER_VALUE} className=\"font-medium text-[var(--color-accent-600)]\">\r\n {t('common.other', '+ Autre...')}\r\n </option>\r\n )}\r\n </select>\r\n\r\n {isOther && (\r\n <>\r\n <input\r\n type=\"text\"\r\n value={customInput}\r\n onChange={handleCustomInputChange}\r\n placeholder={t('common.enterValue', 'Saisir une valeur...')}\r\n disabled={disabled}\r\n autoFocus\r\n className=\"flex-1 px-4 py-2 rounded-[var(--radius-input)] border border-[var(--color-accent-500)] bg-[var(--bg-primary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n />\r\n <button\r\n type=\"button\"\r\n onClick={handleCancelOther}\r\n disabled={disabled}\r\n className=\"px-3 py-2 rounded-[var(--radius-button)] text-[var(--text-secondary)] hover:bg-[var(--bg-hover)] transition-colors\"\r\n title={t('common.cancel', 'Annuler')}\r\n >\r\n ✕\r\n </button>\r\n </>\r\n )}\r\n </div>\r\n {isOther && customInput && (\r\n <p className=\"mt-1 text-xs text-[var(--color-accent-600)] flex items-center gap-1\">\r\n <Plus className=\"w-3 h-3\" />\r\n {t('common.willBeCreated', 'Cette valeur sera créée automatiquement')}\r\n </p>\r\n )}\r\n </div>\r\n );\r\n}\r\n","import type { ReactElement } from 'react';\nimport { useTranslation } from 'react-i18next';\r\nimport {\r\n User,\r\n Save,\r\n Loader2,\r\n Building2,\r\n Briefcase,\r\n Phone,\r\n MapPin as MapPinIcon,\r\n AtSign,\r\n Cloud,\r\n Shield,\r\n Edit3,\r\n CheckCircle,\r\n XCircle,\r\n Mail,\r\n Key\r\n} from 'lucide-react';\r\nimport { formatPhoneNumber } from '@/utils/formatPhone';\r\nimport { SelectWithOther } from '@/components/ui/SelectWithOther';\r\nimport type { UserDetailDto, OrganizationReferencesDto } from '@/services/api/adminApi';\r\nimport type { UserFormData } from '@/hooks/useUserDetail';\r\nimport type { SectionData, SectionType } from '@/hooks/useUserSections';\r\n\r\ninterface UserInfoTabProps {\r\n readonly user: UserDetailDto;\r\n readonly formData: UserFormData;\r\n readonly setFormData: React.Dispatch<React.SetStateAction<UserFormData>>;\r\n readonly handleSaveInfo: (e: React.FormEvent) => Promise<void>;\r\n readonly saving: boolean;\r\n readonly canUpdate: boolean;\r\n\r\n // Section editing\r\n readonly editingSection: string | null;\r\n readonly sectionData: SectionData;\r\n readonly setSectionData: React.Dispatch<React.SetStateAction<SectionData>>;\r\n readonly startEditingSection: (section: SectionType) => void;\r\n readonly cancelEditing: () => void;\r\n readonly handleSaveSection: (section: SectionType) => Promise<void>;\r\n\r\n // References\r\n readonly orgReferences: OrganizationReferencesDto | null;\r\n}\r\n\r\nconst formatDate = (date: string | null) => {\r\n if (!date) return '-';\r\n return new Date(date).toLocaleString();\r\n};\r\n\r\nexport function UserInfoTab({\r\n user,\r\n formData,\r\n setFormData,\r\n handleSaveInfo,\r\n saving,\r\n canUpdate,\r\n editingSection,\r\n sectionData,\r\n setSectionData,\r\n startEditingSection,\r\n cancelEditing,\r\n handleSaveSection,\r\n orgReferences\r\n}: UserInfoTabProps): ReactElement {\r\n const { t } = useTranslation('admin');\r\n\r\n return (\r\n <div className=\"space-y-6\">\r\n {/* Editable Profile Form */}\r\n <form onSubmit={handleSaveInfo} className=\"space-y-6 p-4 rounded-[var(--radius-card)] bg-[var(--bg-primary)] border border-[var(--border-color)]\">\r\n <h3 className=\"text-lg font-semibold text-[var(--text-primary)] flex items-center gap-2\">\r\n <User className=\"w-5 h-5\" />\r\n {t('userDetail.info.profile', 'Profil')}\r\n </h3>\r\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-4\">\r\n <div>\r\n <label className=\"block text-sm font-medium text-[var(--text-secondary)] mb-1\">\r\n {t('users.form.firstName')}\r\n </label>\r\n <input\r\n type=\"text\"\r\n required\r\n value={formData.firstName}\r\n onChange={e => setFormData(prev => ({ ...prev, firstName: e.target.value }))}\r\n className=\"w-full px-4 py-2 rounded-[var(--radius-input)] border border-[var(--border-color)] bg-[var(--bg-primary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n />\r\n </div>\r\n <div>\r\n <label className=\"block text-sm font-medium text-[var(--text-secondary)] mb-1\">\r\n {t('users.form.lastName')}\r\n </label>\r\n <input\r\n type=\"text\"\r\n required\r\n value={formData.lastName}\r\n onChange={e => setFormData(prev => ({ ...prev, lastName: e.target.value }))}\r\n className=\"w-full px-4 py-2 rounded-[var(--radius-input)] border border-[var(--border-color)] bg-[var(--bg-primary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <div>\r\n <label className=\"block text-sm font-medium text-[var(--text-secondary)] mb-1\">\r\n {t('users.columns.email')}\r\n </label>\r\n <input\r\n type=\"email\"\r\n required\r\n value={formData.email}\r\n onChange={e => setFormData(prev => ({ ...prev, email: e.target.value }))}\r\n className=\"w-full px-4 py-2 rounded-[var(--radius-input)] border border-[var(--border-color)] bg-[var(--bg-primary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n />\r\n </div>\r\n\r\n <div className=\"flex justify-end\">\r\n <button\r\n type=\"submit\"\r\n disabled={saving || !canUpdate}\r\n className={`flex items-center gap-2 px-4 py-2 rounded-[var(--radius-button)] font-medium transition-colors disabled:opacity-50 ${!canUpdate ? 'bg-[var(--bg-secondary)] text-[var(--text-tertiary)] cursor-not-allowed' : 'bg-[var(--color-accent-600)] hover:bg-[var(--color-accent-700)] text-white'}`}\r\n title={!canUpdate ? t('common.noPermission', 'Permission insuffisante') : undefined}\r\n >\r\n {saving ? <Loader2 className=\"w-4 h-4 animate-spin\" /> : <Save className=\"w-4 h-4\" />}\r\n {t('common.save')}\r\n </button>\r\n </div>\r\n </form>\r\n\r\n {/* Organization Info */}\r\n <EditableSection\r\n title={t('userDetail.info.organization', 'Organisation')}\r\n icon={<Building2 className=\"w-5 h-5\" />}\r\n sectionKey=\"organization\"\r\n editingSection={editingSection}\r\n saving={saving}\r\n canUpdate={canUpdate}\r\n onStartEdit={() => startEditingSection('organization')}\r\n onCancel={cancelEditing}\r\n onSave={() => handleSaveSection('organization')}\r\n >\r\n {editingSection === 'organization' ? (\r\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4\">\r\n <SelectWithOther\r\n label={t('userDetail.info.company', 'Société')}\r\n options={orgReferences?.companies.map(c => ({ id: c.id, name: c.name })) || []}\r\n value={sectionData.organization.company}\r\n onChange={val => setSectionData(prev => ({ ...prev, organization: { ...prev.organization, company: val } }))}\r\n />\r\n <SelectWithOther\r\n label={t('userDetail.info.department', 'Département')}\r\n options={orgReferences?.departments.map(d => ({ id: d.id, name: d.name })) || []}\r\n value={sectionData.organization.department}\r\n onChange={val => setSectionData(prev => ({ ...prev, organization: { ...prev.organization, department: val } }))}\r\n />\r\n <SelectWithOther\r\n label={t('userDetail.info.jobTitle', 'Fonction')}\r\n options={orgReferences?.jobTitles.map(j => ({ id: j.id, name: j.name })) || []}\r\n value={sectionData.organization.jobTitle}\r\n onChange={val => setSectionData(prev => ({ ...prev, organization: { ...prev.organization, jobTitle: val } }))}\r\n />\r\n <SelectWithOther\r\n label={t('userDetail.info.office', 'Bureau')}\r\n options={orgReferences?.offices.map(o => ({ id: o.id, name: o.name })) || []}\r\n value={sectionData.organization.office}\r\n onChange={val => setSectionData(prev => ({ ...prev, organization: { ...prev.organization, office: val } }))}\r\n />\r\n <div>\r\n <label className=\"block text-sm font-medium text-[var(--text-secondary)] mb-1\">{t('userDetail.info.manager', 'Manager')}</label>\r\n <select\r\n value={sectionData.organization.managerId}\r\n onChange={e => setSectionData(prev => ({ ...prev, organization: { ...prev.organization, managerId: e.target.value } }))}\r\n className=\"w-full px-4 py-2 rounded-[var(--radius-input)] border border-[var(--border-color)] bg-[var(--bg-primary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n >\r\n <option value=\"\">{t('common.none', '-- Aucun --')}</option>\r\n {orgReferences?.managers.map(m => (\r\n <option key={m.id} value={m.id}>{m.name}</option>\r\n ))}\r\n </select>\r\n </div>\r\n </div>\r\n ) : (\r\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4\">\r\n <InfoField label={t('userDetail.info.company', 'Société')} value={user.companyName} />\r\n <InfoField label={t('userDetail.info.department', 'Département')} value={user.departmentName} />\r\n <InfoField label={t('userDetail.info.jobTitle', 'Fonction')} value={user.jobTitleName} />\r\n <InfoField label={t('userDetail.info.office', 'Bureau')} value={user.officeName} />\r\n <InfoField label={t('userDetail.info.manager', 'Manager')} value={user.managerName} />\r\n </div>\r\n )}\r\n </EditableSection>\r\n\r\n {/* Job Information */}\r\n <EditableSection\r\n title={t('userDetail.info.jobInfo', 'Informations emploi')}\r\n icon={<Briefcase className=\"w-5 h-5\" />}\r\n sectionKey=\"jobInfo\"\r\n editingSection={editingSection}\r\n saving={saving}\r\n canUpdate={canUpdate}\r\n onStartEdit={() => startEditingSection('jobInfo')}\r\n onCancel={cancelEditing}\r\n onSave={() => handleSaveSection('jobInfo')}\r\n >\r\n {editingSection === 'jobInfo' ? (\r\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-4\">\r\n <div>\r\n <label className=\"block text-sm font-medium text-[var(--text-secondary)] mb-1\">{t('userDetail.info.employeeId', 'ID Employé')}</label>\r\n <input\r\n type=\"text\"\r\n value={sectionData.jobInfo.employeeId}\r\n onChange={e => setSectionData(prev => ({ ...prev, jobInfo: { ...prev.jobInfo, employeeId: e.target.value } }))}\r\n className=\"w-full px-4 py-2 rounded-[var(--radius-input)] border border-[var(--border-color)] bg-[var(--bg-primary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n />\r\n </div>\r\n <div>\r\n <label className=\"block text-sm font-medium text-[var(--text-secondary)] mb-1\">{t('userDetail.info.employeeType', 'Type employé')}</label>\r\n <input\r\n type=\"text\"\r\n value={sectionData.jobInfo.employeeType}\r\n onChange={e => setSectionData(prev => ({ ...prev, jobInfo: { ...prev.jobInfo, employeeType: e.target.value } }))}\r\n className=\"w-full px-4 py-2 rounded-[var(--radius-input)] border border-[var(--border-color)] bg-[var(--bg-primary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n />\r\n </div>\r\n <div>\r\n <label className=\"block text-sm font-medium text-[var(--text-secondary)] mb-1\">{t('userDetail.info.employeeHireDate', 'Date d\\'embauche')}</label>\r\n <input\r\n type=\"date\"\r\n value={sectionData.jobInfo.employeeHireDate}\r\n onChange={e => setSectionData(prev => ({ ...prev, jobInfo: { ...prev.jobInfo, employeeHireDate: e.target.value } }))}\r\n className=\"w-full px-4 py-2 rounded-[var(--radius-input)] border border-[var(--border-color)] bg-[var(--bg-primary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n />\r\n </div>\r\n </div>\r\n ) : (\r\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4\">\r\n <InfoField label={t('userDetail.info.employeeId', 'ID Employé')} value={user.employeeId} />\r\n <InfoField label={t('userDetail.info.employeeType', 'Type employé')} value={user.employeeType} />\r\n <InfoField label={t('userDetail.info.employeeHireDate', 'Date d\\'embauche')} value={user.employeeHireDate ? new Date(user.employeeHireDate).toLocaleDateString() : null} />\r\n <InfoField label={t('userDetail.info.sponsors', 'Sponsors')} value={user.sponsors} />\r\n </div>\r\n )}\r\n </EditableSection>\r\n\r\n {/* Phone Numbers */}\r\n <EditableSection\r\n title={t('userDetail.info.phones', 'Téléphones')}\r\n icon={<Phone className=\"w-5 h-5\" />}\r\n sectionKey=\"phones\"\r\n editingSection={editingSection}\r\n saving={saving}\r\n canUpdate={canUpdate}\r\n onStartEdit={() => startEditingSection('phones')}\r\n onCancel={cancelEditing}\r\n onSave={() => handleSaveSection('phones')}\r\n >\r\n {editingSection === 'phones' ? (\r\n <div className=\"grid grid-cols-1 sm:grid-cols-3 gap-4\">\r\n <div>\r\n <label className=\"block text-sm font-medium text-[var(--text-secondary)] mb-1\">{t('userDetail.info.phone', 'Téléphone')}</label>\r\n <input\r\n type=\"tel\"\r\n value={sectionData.phones.phoneNumber}\r\n onChange={e => setSectionData(prev => ({ ...prev, phones: { ...prev.phones, phoneNumber: e.target.value } }))}\r\n className=\"w-full px-4 py-2 rounded-[var(--radius-input)] border border-[var(--border-color)] bg-[var(--bg-primary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n />\r\n </div>\r\n <div>\r\n <label className=\"block text-sm font-medium text-[var(--text-secondary)] mb-1\">{t('userDetail.info.mobile', 'Mobile')}</label>\r\n <input\r\n type=\"tel\"\r\n value={sectionData.phones.mobilePhone}\r\n onChange={e => setSectionData(prev => ({ ...prev, phones: { ...prev.phones, mobilePhone: e.target.value } }))}\r\n className=\"w-full px-4 py-2 rounded-[var(--radius-input)] border border-[var(--border-color)] bg-[var(--bg-primary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n />\r\n </div>\r\n <div>\r\n <label className=\"block text-sm font-medium text-[var(--text-secondary)] mb-1\">{t('userDetail.info.fax', 'Fax')}</label>\r\n <input\r\n type=\"tel\"\r\n value={sectionData.phones.faxNumber}\r\n onChange={e => setSectionData(prev => ({ ...prev, phones: { ...prev.phones, faxNumber: e.target.value } }))}\r\n className=\"w-full px-4 py-2 rounded-[var(--radius-input)] border border-[var(--border-color)] bg-[var(--bg-primary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n />\r\n </div>\r\n </div>\r\n ) : (\r\n <div className=\"grid grid-cols-1 sm:grid-cols-3 gap-4\">\r\n <InfoField label={t('userDetail.info.phone', 'Téléphone')} value={formatPhoneNumber(user.phoneNumber, 'CH', 'international')} />\r\n <InfoField label={t('userDetail.info.mobile', 'Mobile')} value={formatPhoneNumber(user.mobilePhone, 'CH', 'international')} />\r\n <InfoField label={t('userDetail.info.fax', 'Fax')} value={formatPhoneNumber(user.faxNumber, 'CH', 'international')} />\r\n </div>\r\n )}\r\n </EditableSection>\r\n\r\n {/* Address */}\r\n <EditableSection\r\n title={t('userDetail.info.address', 'Adresse')}\r\n icon={<MapPinIcon className=\"w-5 h-5\" />}\r\n sectionKey=\"address\"\r\n editingSection={editingSection}\r\n saving={saving}\r\n canUpdate={canUpdate}\r\n onStartEdit={() => startEditingSection('address')}\r\n onCancel={cancelEditing}\r\n onSave={() => handleSaveSection('address')}\r\n >\r\n {editingSection === 'address' ? (\r\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-4\">\r\n <div className=\"sm:col-span-2\">\r\n <label className=\"block text-sm font-medium text-[var(--text-secondary)] mb-1\">{t('userDetail.info.streetAddress', 'Adresse')}</label>\r\n <input\r\n type=\"text\"\r\n value={sectionData.address.streetAddress}\r\n onChange={e => setSectionData(prev => ({ ...prev, address: { ...prev.address, streetAddress: e.target.value } }))}\r\n className=\"w-full px-4 py-2 rounded-[var(--radius-input)] border border-[var(--border-color)] bg-[var(--bg-primary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n />\r\n </div>\r\n <div>\r\n <label className=\"block text-sm font-medium text-[var(--text-secondary)] mb-1\">{t('userDetail.info.city', 'Ville')}</label>\r\n <input\r\n type=\"text\"\r\n value={sectionData.address.city}\r\n onChange={e => setSectionData(prev => ({ ...prev, address: { ...prev.address, city: e.target.value } }))}\r\n className=\"w-full px-4 py-2 rounded-[var(--radius-input)] border border-[var(--border-color)] bg-[var(--bg-primary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n />\r\n </div>\r\n <div>\r\n <label className=\"block text-sm font-medium text-[var(--text-secondary)] mb-1\">{t('userDetail.info.state', 'Région')}</label>\r\n <input\r\n type=\"text\"\r\n value={sectionData.address.state}\r\n onChange={e => setSectionData(prev => ({ ...prev, address: { ...prev.address, state: e.target.value } }))}\r\n className=\"w-full px-4 py-2 rounded-[var(--radius-input)] border border-[var(--border-color)] bg-[var(--bg-primary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n />\r\n </div>\r\n <div>\r\n <label className=\"block text-sm font-medium text-[var(--text-secondary)] mb-1\">{t('userDetail.info.postalCode', 'Code postal')}</label>\r\n <input\r\n type=\"text\"\r\n value={sectionData.address.postalCode}\r\n onChange={e => setSectionData(prev => ({ ...prev, address: { ...prev.address, postalCode: e.target.value } }))}\r\n className=\"w-full px-4 py-2 rounded-[var(--radius-input)] border border-[var(--border-color)] bg-[var(--bg-primary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n />\r\n </div>\r\n <div>\r\n <label className=\"block text-sm font-medium text-[var(--text-secondary)] mb-1\">{t('userDetail.info.country', 'Pays')}</label>\r\n <input\r\n type=\"text\"\r\n value={sectionData.address.country}\r\n onChange={e => setSectionData(prev => ({ ...prev, address: { ...prev.address, country: e.target.value } }))}\r\n className=\"w-full px-4 py-2 rounded-[var(--radius-input)] border border-[var(--border-color)] bg-[var(--bg-primary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n />\r\n </div>\r\n </div>\r\n ) : (\r\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4\">\r\n <InfoField label={t('userDetail.info.streetAddress', 'Adresse')} value={user.streetAddress} className=\"sm:col-span-2 lg:col-span-3\" />\r\n <InfoField label={t('userDetail.info.city', 'Ville')} value={user.city} />\r\n <InfoField label={t('userDetail.info.state', 'Région')} value={user.state} />\r\n <InfoField label={t('userDetail.info.postalCode', 'Code postal')} value={user.postalCode} />\r\n <InfoField label={t('userDetail.info.country', 'Pays')} value={user.country} />\r\n </div>\r\n )}\r\n </EditableSection>\r\n\r\n {/* Other Contact Info (Read-only) */}\r\n {(user.otherEmails || user.mailNickname || user.imAddresses) && (\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--bg-primary)] border border-[var(--border-color)]\">\r\n <h3 className=\"text-lg font-semibold text-[var(--text-primary)] flex items-center gap-2 mb-4\">\r\n <AtSign className=\"w-5 h-5\" />\r\n {t('userDetail.info.otherContact', 'Autres coordonnées')}\r\n </h3>\r\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4\">\r\n {user.mailNickname && <InfoField label={t('userDetail.info.mailNickname', 'Alias mail')} value={user.mailNickname} />}\r\n {user.otherEmails && <InfoField label={t('userDetail.info.otherEmails', 'Autres emails')} value={user.otherEmails} breakAll />}\r\n {user.imAddresses && <InfoField label={t('userDetail.info.imAddresses', 'Messagerie instantanée')} value={user.imAddresses} breakAll />}\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* Entra / AAD Sync Status */}\r\n {user.entraObjectId && (\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800\">\r\n <h3 className=\"text-lg font-semibold text-blue-800 dark:text-blue-300 flex items-center gap-2 mb-4\">\r\n <Cloud className=\"w-5 h-5\" />\r\n {t('userDetail.info.entraSync', 'Synchronisation Microsoft Entra ID')}\r\n </h3>\r\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4\">\r\n <div className=\"p-3 rounded-lg bg-white/50 dark:bg-black/20\">\r\n <p className=\"text-xs text-blue-600 dark:text-blue-400 uppercase tracking-wider mb-1\">{t('userDetail.info.entraObjectId', 'Object ID')}</p>\r\n <p className=\"text-sm text-blue-900 dark:text-blue-200 font-mono break-all\">{user.entraObjectId}</p>\r\n </div>\r\n <div className=\"p-3 rounded-lg bg-white/50 dark:bg-black/20\">\r\n <p className=\"text-xs text-blue-600 dark:text-blue-400 uppercase tracking-wider mb-1\">{t('userDetail.info.authProvider', 'Fournisseur')}</p>\r\n <p className=\"text-sm text-blue-900 dark:text-blue-200 font-medium capitalize\">{user.authProvider || 'microsoft'}</p>\r\n </div>\r\n <div className=\"p-3 rounded-lg bg-white/50 dark:bg-black/20\">\r\n <p className=\"text-xs text-blue-600 dark:text-blue-400 uppercase tracking-wider mb-1\">{t('userDetail.info.lastEntraSync', 'Dernière sync')}</p>\r\n <p className=\"text-sm text-blue-900 dark:text-blue-200 font-medium\">{formatDate(user.lastEntraSyncAt)}</p>\r\n </div>\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* Account Status Badges & Dates */}\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--bg-primary)] border border-[var(--border-color)]\">\r\n <h3 className=\"text-lg font-semibold text-[var(--text-primary)] flex items-center gap-2 mb-4\">\r\n <Shield className=\"w-5 h-5\" />\r\n {t('userDetail.info.accountStatus', 'Statut du compte')}\r\n </h3>\r\n\r\n {/* Status Badges */}\r\n <div className=\"flex flex-wrap gap-2 mb-4\">\r\n <StatusBadge\r\n active={user.isActive}\r\n activeLabel={t('users.status.active')}\r\n inactiveLabel={t('users.status.inactive')}\r\n type=\"active\"\r\n />\r\n <StatusBadge\r\n active={user.emailConfirmed}\r\n activeLabel={t('userDetail.info.emailConfirmed', 'Email confirmé')}\r\n inactiveLabel={t('userDetail.info.emailNotConfirmed', 'Email non confirmé')}\r\n type=\"email\"\r\n />\r\n <StatusBadge\r\n active={user.hasCompletedOnboarding}\r\n activeLabel={t('userDetail.info.onboardingComplete', 'Onboarding terminé')}\r\n inactiveLabel={t('userDetail.info.onboardingPending', 'Onboarding en attente')}\r\n type=\"onboarding\"\r\n />\r\n {user.mustChangePassword && (\r\n <span className=\"inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-sm font-medium bg-amber-100 dark:bg-amber-900/30 text-amber-700 dark:text-amber-400\">\r\n <Key className=\"w-4 h-4\" />\r\n {t('userDetail.info.mustChangePassword', 'Changement de mot de passe requis')}\r\n </span>\r\n )}\r\n {user.entraObjectId && (\r\n <span className=\"inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-sm font-medium bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-400\">\r\n <Cloud className=\"w-4 h-4\" />\r\n {t('userDetail.info.syncedWithAad', 'Synchronisé AAD')}\r\n </span>\r\n )}\r\n </div>\r\n\r\n {/* Dates */}\r\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 pt-4 border-t border-[var(--border-color)]\">\r\n <div>\r\n <p className=\"text-xs text-[var(--text-tertiary)] uppercase tracking-wider mb-1\">{t('userDetail.createdAt')}</p>\r\n <p className=\"text-sm text-[var(--text-primary)] font-medium\">{formatDate(user.createdAt)}</p>\r\n </div>\r\n <div>\r\n <p className=\"text-xs text-[var(--text-tertiary)] uppercase tracking-wider mb-1\">{t('userDetail.updatedAt', 'Modifié le')}</p>\r\n <p className=\"text-sm text-[var(--text-primary)] font-medium\">{formatDate(user.updatedAt)}</p>\r\n </div>\r\n <div>\r\n <p className=\"text-xs text-[var(--text-tertiary)] uppercase tracking-wider mb-1\">{t('userDetail.lastLogin')}</p>\r\n <p className=\"text-sm text-[var(--text-primary)] font-medium\">{formatDate(user.lastLoginAt)}</p>\r\n </div>\r\n <div>\r\n <p className=\"text-xs text-[var(--text-tertiary)] uppercase tracking-wider mb-1\">{t('userDetail.info.userType', 'Type')}</p>\r\n <p className=\"text-sm text-[var(--text-primary)] font-medium\">{user.userType}</p>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n}\r\n\r\n// Helper Components\r\n\r\ninterface InfoFieldProps {\r\n readonly label: string;\r\n readonly value: string | null | undefined;\r\n readonly className?: string;\r\n readonly breakAll?: boolean;\r\n}\r\n\r\nfunction InfoField({ label, value, className, breakAll }: InfoFieldProps) {\r\n return (\r\n <div className={`p-3 rounded-lg bg-[var(--bg-secondary)] ${className || ''}`}>\r\n <p className=\"text-xs text-[var(--text-tertiary)] uppercase tracking-wider mb-1\">{label}</p>\r\n <p className={`text-sm text-[var(--text-primary)] font-medium ${breakAll ? 'break-all' : ''}`}>{value || '-'}</p>\r\n </div>\r\n );\r\n}\r\n\r\ninterface EditableSectionProps {\r\n readonly title: string;\r\n readonly icon: React.ReactNode;\r\n readonly sectionKey: SectionType;\r\n readonly editingSection: string | null;\r\n readonly saving: boolean;\r\n readonly canUpdate: boolean;\r\n readonly onStartEdit: () => void;\r\n readonly onCancel: () => void;\r\n readonly onSave: () => void;\r\n readonly children: React.ReactNode;\r\n}\r\n\r\nfunction EditableSection({\r\n title,\r\n icon,\r\n sectionKey,\r\n editingSection,\r\n saving,\r\n canUpdate,\r\n onStartEdit,\r\n onCancel,\r\n onSave,\r\n children\r\n}: EditableSectionProps) {\r\n const { t } = useTranslation('admin');\r\n const isEditing = editingSection === sectionKey;\r\n\r\n return (\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--bg-primary)] border border-[var(--border-color)]\">\r\n <div className=\"flex items-center justify-between mb-4\">\r\n <h3 className=\"text-lg font-semibold text-[var(--text-primary)] flex items-center gap-2\">\r\n {icon}\r\n {title}\r\n </h3>\r\n {!isEditing ? (\r\n <button\r\n onClick={onStartEdit}\r\n disabled={!canUpdate}\r\n className={`flex items-center gap-1 px-3 py-1.5 rounded-[var(--radius-button)] transition-colors ${!canUpdate ? 'opacity-50 cursor-not-allowed bg-[var(--bg-secondary)] text-[var(--text-tertiary)]' : 'bg-[var(--bg-secondary)] text-[var(--text-secondary)] hover:bg-[var(--bg-hover)]'}`}\r\n title={!canUpdate ? t('common.noPermission', 'Permission insuffisante') : undefined}\r\n >\r\n <Edit3 className=\"w-4 h-4\" />\r\n {t('common.edit', 'Modifier')}\r\n </button>\r\n ) : (\r\n <div className=\"flex items-center gap-2\">\r\n <button\r\n onClick={onCancel}\r\n className=\"px-3 py-1.5 rounded-[var(--radius-button)] bg-[var(--bg-secondary)] text-[var(--text-secondary)] hover:bg-[var(--bg-hover)] transition-colors\"\r\n >\r\n {t('common.cancel', 'Annuler')}\r\n </button>\r\n <button\r\n onClick={onSave}\r\n disabled={saving || !canUpdate}\r\n className={`flex items-center gap-1 px-3 py-1.5 rounded-[var(--radius-button)] transition-colors disabled:opacity-50 ${!canUpdate ? 'bg-[var(--bg-secondary)] text-[var(--text-tertiary)] cursor-not-allowed' : 'bg-[var(--color-accent-600)] text-white hover:bg-[var(--color-accent-700)]'}`}\r\n title={!canUpdate ? t('common.noPermission', 'Permission insuffisante') : undefined}\r\n >\r\n {saving ? <Loader2 className=\"w-4 h-4 animate-spin\" /> : <Save className=\"w-4 h-4\" />}\r\n {t('common.save', 'Enregistrer')}\r\n </button>\r\n </div>\r\n )}\r\n </div>\r\n {children}\r\n </div>\r\n );\r\n}\r\n\r\ninterface StatusBadgeProps {\r\n readonly active: boolean;\r\n readonly activeLabel: string;\r\n readonly inactiveLabel: string;\r\n readonly type: 'active' | 'email' | 'onboarding';\r\n}\r\n\r\nfunction StatusBadge({ active, activeLabel, inactiveLabel, type }: StatusBadgeProps) {\r\n const getIcon = () => {\r\n if (type === 'email') return <Mail className=\"w-4 h-4\" />;\r\n if (type === 'onboarding') return <User className=\"w-4 h-4\" />;\r\n return active ? <CheckCircle className=\"w-4 h-4\" /> : <XCircle className=\"w-4 h-4\" />;\r\n };\r\n\r\n const getColors = () => {\r\n if (active) return 'bg-green-100 dark:bg-green-900/30 text-green-700 dark:text-green-400';\r\n if (type === 'active') return 'bg-red-100 dark:bg-red-900/30 text-red-700 dark:text-red-400';\r\n return 'bg-amber-100 dark:bg-amber-900/30 text-amber-700 dark:text-amber-400';\r\n };\r\n\r\n return (\r\n <span className={`inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-sm font-medium ${getColors()}`}>\r\n {getIcon()}\r\n {active ? activeLabel : inactiveLabel}\r\n </span>\r\n );\r\n}\r\n","import { useState } from 'react';\r\nimport type { ReactElement } from 'react';\r\nimport { useTranslation } from 'react-i18next';\r\nimport { X, Bug } from 'lucide-react';\r\nimport { UnlockReason } from '@/services/api/adminApi';\r\n\r\ninterface UnlockAccountModalProps {\r\n readonly isOpen: boolean;\r\n readonly onClose: () => void;\r\n readonly onConfirm: (reason: UnlockReason, mustChangePassword: boolean) => void;\r\n readonly userName: string;\r\n}\r\n\r\nexport function UnlockAccountModal({\r\n isOpen,\r\n onClose,\r\n onConfirm,\r\n userName,\r\n}: UnlockAccountModalProps): ReactElement | null {\r\n const { t } = useTranslation(['admin', 'common']);\r\n const [selectedReason, setSelectedReason] = useState<UnlockReason | ''>('');\r\n const [mustChangePassword, setMustChangePassword] = useState(false);\r\n\r\n const handleConfirm = () => {\r\n if (selectedReason === '') return;\r\n onConfirm(selectedReason as UnlockReason, mustChangePassword);\r\n onClose();\r\n // Reset state\r\n setSelectedReason('');\r\n setMustChangePassword(false);\r\n };\r\n\r\n const handleClose = () => {\r\n onClose();\r\n // Reset state\r\n setSelectedReason('');\r\n setMustChangePassword(false);\r\n };\r\n\r\n if (!isOpen) return null;\r\n\r\n return (\r\n <div className=\"fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/50 backdrop-blur-sm\">\r\n <div className=\"relative w-full max-w-md bg-[var(--bg-card)] rounded-2xl shadow-2xl border border-[var(--border-color)] overflow-hidden\">\r\n {/* Header */}\r\n <div className=\"flex items-center justify-between p-6 border-b border-[var(--border-color)]\">\r\n <div>\r\n <h2 className=\"text-xl font-semibold text-[var(--text-primary)]\">\r\n {t('userDetail.security.unlockAccount')}\r\n </h2>\r\n <p className=\"text-sm text-[var(--text-secondary)] mt-1\">{userName}</p>\r\n </div>\r\n <div className=\"flex items-center gap-1\">\r\n <button\r\n onClick={() => {\r\n const bugInfo = {\r\n component: 'UnlockAccountModal',\r\n user: userName,\r\n url: window.location.href,\r\n };\r\n const issueUrl = `https://github.com/anthropics/claude-code/issues/new?title=${encodeURIComponent('[Bug] Unlock Account Modal')}&body=${encodeURIComponent(`## Context\\n- Component: ${bugInfo.component}\\n- URL: ${bugInfo.url}\\n\\n## Description\\n\\n<!-- Describe the bug here -->\\n\\n## Steps to Reproduce\\n\\n1. \\n2. \\n3. \\n\\n## Expected Behavior\\n\\n## Actual Behavior\\n`)}`;\r\n window.open(issueUrl, '_blank');\r\n }}\r\n className=\"p-2 rounded-lg hover:bg-[var(--bg-hover)] transition-colors\"\r\n title={t('common:buttons.reportBug')}\r\n >\r\n <Bug className=\"w-5 h-5 text-[var(--text-secondary)]\" />\r\n </button>\r\n <button\r\n onClick={handleClose}\r\n className=\"p-2 rounded-lg hover:bg-[var(--bg-hover)] transition-colors\"\r\n aria-label=\"Close\"\r\n >\r\n <X className=\"w-5 h-5 text-[var(--text-secondary)]\" />\r\n </button>\r\n </div>\r\n </div>\r\n\r\n {/* Content */}\r\n <div className=\"p-6 space-y-6\">\r\n {/* Reason Selection */}\r\n <div>\r\n <label className=\"block text-sm font-medium text-[var(--text-primary)] mb-2\">\r\n {t('userDetail.security.unlockReason')}\r\n <span className=\"text-red-500 ml-1\">*</span>\r\n </label>\r\n <select\r\n value={selectedReason}\r\n onChange={(e) => setSelectedReason(e.target.value as UnlockReason | '')}\r\n className=\"w-full px-4 py-3 rounded-xl border border-[var(--border-color)] bg-[var(--bg-tertiary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-primary-500 transition-all\"\r\n >\r\n <option value=\"\">{t('userDetail.security.selectReason')}</option>\r\n <option value={UnlockReason.PasswordResetMalfunction}>\r\n {t('userDetail.security.unlockReasons.1')}\r\n </option>\r\n <option value={UnlockReason.FalsePositive}>\r\n {t('userDetail.security.unlockReasons.2')}\r\n </option>\r\n <option value={UnlockReason.UrgentBusinessNeed}>\r\n {t('userDetail.security.unlockReasons.3')}\r\n </option>\r\n <option value={UnlockReason.TechnicalSystemError}>\r\n {t('userDetail.security.unlockReasons.4')}\r\n </option>\r\n <option value={UnlockReason.SupportTicketVerified}>\r\n {t('userDetail.security.unlockReasons.5')}\r\n </option>\r\n </select>\r\n </div>\r\n\r\n {/* Password Change Checkbox */}\r\n <div className=\"flex items-start space-x-3 p-4 rounded-xl bg-[var(--bg-secondary)] border border-[var(--border-subtle)]\">\r\n <input\r\n type=\"checkbox\"\r\n id=\"mustChangePassword\"\r\n checked={mustChangePassword}\r\n onChange={(e) => setMustChangePassword(e.target.checked)}\r\n className=\"mt-1 w-4 h-4 rounded border-[var(--border-color)] text-primary-600 focus:ring-2 focus:ring-primary-500 bg-[var(--bg-tertiary)]\"\r\n />\r\n <label\r\n htmlFor=\"mustChangePassword\"\r\n className=\"text-sm text-[var(--text-secondary)] cursor-pointer select-none\"\r\n >\r\n {t('userDetail.security.mustChangePassword')}\r\n </label>\r\n </div>\r\n </div>\r\n\r\n {/* Footer */}\r\n <div className=\"flex items-center justify-end gap-3 p-6 border-t border-[var(--border-color)] bg-[var(--bg-secondary)]\">\r\n <button\r\n onClick={handleClose}\r\n className=\"px-6 py-2.5 rounded-xl border border-[var(--border-color)] text-[var(--text-secondary)] hover:bg-[var(--bg-hover)] transition-all font-medium\"\r\n >\r\n {t('common.cancel')}\r\n </button>\r\n <button\r\n onClick={handleConfirm}\r\n disabled={selectedReason === ''}\r\n className={`px-6 py-2.5 rounded-xl font-medium transition-all ${\r\n selectedReason === ''\r\n ? 'bg-gray-400 text-gray-200 cursor-not-allowed'\r\n : 'bg-gradient-to-r from-green-600 to-emerald-600 text-white hover:from-green-700 hover:to-emerald-700 shadow-lg shadow-green-500/30'\r\n }`}\r\n >\r\n {t('userDetail.security.unlock')}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n}\r\n","import type { ReactElement } from 'react';\nimport { useNavigate } from 'react-router-dom';\r\nimport { useTranslation } from 'react-i18next';\r\nimport {\r\n Loader2,\r\n Mail,\r\n RefreshCw,\r\n Eye,\r\n EyeOff,\r\n Copy,\r\n UserCheck,\r\n UserX,\r\n LogOut,\r\n Unlock,\r\n Trash2\r\n} from 'lucide-react';\r\nimport { adminApi, type UserDetailDto, UnlockReason } from '@/services/api/adminApi';\r\nimport { UnlockAccountModal } from '@/components/ui/UnlockAccountModal';\r\n\r\ninterface UserSecurityTabProps {\r\n readonly user: UserDetailDto;\r\n readonly userId: string;\r\n\r\n // Permissions\r\n readonly canUpdate: boolean;\r\n readonly canDelete: boolean;\r\n readonly canExecute: boolean;\r\n\r\n // Password state\r\n readonly newPassword: string;\r\n readonly setNewPassword: (password: string) => void;\r\n readonly temporaryPassword: string | null;\r\n readonly showTemporaryPassword: boolean;\r\n readonly setShowTemporaryPassword: (show: boolean) => void;\r\n readonly saving: boolean;\r\n\r\n // Modal state\r\n readonly showUnlockModal: boolean;\r\n readonly setShowUnlockModal: (show: boolean) => void;\r\n\r\n // Actions\r\n readonly handleSendResetLink: () => Promise<void>;\r\n readonly handleResetPasswordDirect: () => Promise<void>;\r\n readonly handleToggleStatus: (isActive: boolean) => Promise<void>;\r\n readonly handleEndAllSessions: () => Promise<void>;\r\n readonly handleUnlock: (reason: UnlockReason, mustChangePassword: boolean) => Promise<void>;\r\n readonly handleClearFailedAttempts: () => Promise<void>;\r\n readonly copyToClipboard: (text: string) => Promise<void>;\r\n\r\n // Error handling\r\n readonly setError: (error: string | null) => void;\r\n}\r\n\r\nconst getButtonClasses = (hasPermission: boolean, colorClass: string): string => {\r\n if (!hasPermission) {\r\n return 'opacity-50 cursor-not-allowed bg-[var(--bg-secondary)] text-[var(--text-tertiary)]';\r\n }\r\n return colorClass;\r\n};\r\n\r\nconst getPrimaryButtonClasses = (hasPermission: boolean): string => {\r\n return getButtonClasses(hasPermission, 'bg-[var(--color-accent-600)] hover:bg-[var(--color-accent-700)] text-white');\r\n};\r\n\r\nconst getWarningButtonClasses = (hasPermission: boolean): string => {\r\n return getButtonClasses(hasPermission, 'bg-amber-600 hover:bg-amber-700 text-white');\r\n};\r\n\r\nconst getRedButtonClasses = (hasPermission: boolean): string => {\r\n return getButtonClasses(hasPermission, 'bg-red-600 hover:bg-red-700 text-white');\r\n};\r\n\r\nconst getGreenButtonClasses = (isActive: boolean, hasPermission: boolean): string => {\r\n const activeClass = isActive ? 'bg-red-600 hover:bg-red-700 text-white' : 'bg-green-600 hover:bg-green-700 text-white';\r\n return getButtonClasses(hasPermission, activeClass);\r\n};\r\n\r\nexport function UserSecurityTab({\r\n user,\r\n userId,\r\n canUpdate,\r\n canDelete,\r\n canExecute,\r\n newPassword,\r\n setNewPassword,\r\n temporaryPassword,\r\n showTemporaryPassword,\r\n setShowTemporaryPassword,\r\n saving,\r\n showUnlockModal,\r\n setShowUnlockModal,\r\n handleSendResetLink,\r\n handleResetPasswordDirect,\r\n handleToggleStatus,\r\n handleEndAllSessions,\r\n handleUnlock,\r\n handleClearFailedAttempts,\r\n copyToClipboard,\r\n setError\r\n}: UserSecurityTabProps): ReactElement {\r\n const { t } = useTranslation('admin');\r\n const navigate = useNavigate();\r\n\r\n const getAccountStatusText = (): string => {\r\n if (user.isLocked) return 'Verrouillé (manuel)';\r\n if (user.isTemporarilyLocked) return 'Verrouillé (temporaire)';\r\n if (user.isActive) return t('userDetail.security.accountActive');\r\n return t('userDetail.security.accountInactive');\r\n };\r\n\r\n const getAccountStatusHint = (): string => {\r\n if (user.isLocked) return 'Verrouillé par un administrateur - nécessite un déverrouillage manuel';\r\n if (user.isTemporarilyLocked) return 'Verrouillé suite à plusieurs tentatives échouées - déblocage automatique dans quelques minutes';\r\n if (user.isActive) return t('userDetail.security.deactivateHint');\r\n return t('userDetail.security.activateHint');\r\n };\r\n\r\n const handleDelete = async () => {\r\n if (!confirm(t('users.confirmDelete', { name: user.fullName }))) return;\r\n try {\r\n await adminApi.users.delete(userId);\r\n navigate('/administration/users');\r\n } catch {\r\n setError(t('userDetail.errors.deleteFailed'));\r\n }\r\n };\r\n\r\n return (\r\n <div className=\"space-y-6\">\r\n {/* Send Reset Link (Admin) */}\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--bg-primary)] border border-[var(--border-color)]\">\r\n <h3 className=\"text-lg font-semibold text-[var(--text-primary)] mb-2\">\r\n {t('userDetail.security.sendResetLink', 'Envoyer un lien de réinitialisation')}\r\n </h3>\r\n <p className=\"text-sm text-[var(--text-secondary)] mb-4\">\r\n {t('userDetail.security.sendResetLinkHint', 'L\\'utilisateur recevra un email avec un lien pour définir son nouveau mot de passe.')}\r\n </p>\r\n <button\r\n onClick={handleSendResetLink}\r\n disabled={saving || !canUpdate}\r\n className={`flex items-center gap-2 px-4 py-2 rounded-[var(--radius-button)] font-medium transition-colors disabled:opacity-50 ${getPrimaryButtonClasses(canUpdate)}`}\r\n title={!canUpdate ? t('common.noPermission', 'Permission insuffisante') : undefined}\r\n >\r\n {saving ? <Loader2 className=\"w-4 h-4 animate-spin\" /> : <Mail className=\"w-4 h-4\" />}\r\n {t('userDetail.security.sendLink', 'Envoyer le lien')}\r\n </button>\r\n </div>\r\n\r\n {/* Direct Reset (SuperAdmin) */}\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--warning-bg)] border border-[var(--warning-border)]\">\r\n <h3 className=\"text-lg font-semibold text-[var(--warning-text)] mb-2\">\r\n {t('userDetail.security.directReset', 'Réinitialisation directe (SuperAdmin)')}\r\n </h3>\r\n <p className=\"text-sm text-[var(--warning-text)] opacity-80 mb-4\">\r\n {t('userDetail.security.directResetHint', 'Génère un mot de passe temporaire que vous devez communiquer à l\\'utilisateur. Il devra le changer à sa prochaine connexion.')}\r\n </p>\r\n <div className=\"flex gap-4 mb-4\">\r\n <input\r\n type=\"text\"\r\n placeholder={t('userDetail.security.customPassword', 'Mot de passe personnalisé (optionnel)')}\r\n value={newPassword}\r\n onChange={e => setNewPassword(e.target.value)}\r\n autoComplete=\"off\"\r\n className=\"flex-1 px-4 py-2 rounded-[var(--radius-input)] border border-[var(--warning-border)] bg-[var(--bg-primary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--warning-dot)]\"\r\n />\r\n <button\r\n onClick={handleResetPasswordDirect}\r\n disabled={saving || !canExecute}\r\n className={`flex items-center gap-2 px-4 py-2 rounded-[var(--radius-button)] font-medium transition-colors disabled:opacity-50 ${getWarningButtonClasses(canExecute)}`}\r\n title={!canExecute ? t('common.noPermission', 'Permission insuffisante') : undefined}\r\n >\r\n {saving ? <Loader2 className=\"w-4 h-4 animate-spin\" /> : <RefreshCw className=\"w-4 h-4\" />}\r\n {t('userDetail.security.resetDirect', 'Réinitialiser')}\r\n </button>\r\n </div>\r\n\r\n {/* Show temporary password after direct reset */}\r\n {temporaryPassword && (\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--success-bg)] border border-[var(--success-border)]\">\r\n <p className=\"text-sm font-medium text-[var(--success-text)] mb-2\">\r\n {t('userDetail.security.temporaryPasswordLabel', 'Mot de passe temporaire généré:')}\r\n </p>\r\n <div className=\"flex items-center gap-2\">\r\n <code className=\"flex-1 px-3 py-2 rounded-[var(--radius-input)] bg-[var(--bg-primary)] text-[var(--text-primary)] font-mono text-lg\">\r\n {showTemporaryPassword ? temporaryPassword : '••••••••••••••••'}\r\n </code>\r\n <button\r\n onClick={() => setShowTemporaryPassword(!showTemporaryPassword)}\r\n className=\"p-2 rounded-[var(--radius-button)] hover:bg-[var(--bg-hover)] text-[var(--success-text)] transition-colors\"\r\n title={showTemporaryPassword ? 'Masquer' : 'Afficher'}\r\n >\r\n {showTemporaryPassword ? <EyeOff className=\"w-5 h-5\" /> : <Eye className=\"w-5 h-5\" />}\r\n </button>\r\n <button\r\n onClick={() => copyToClipboard(temporaryPassword)}\r\n className=\"p-2 rounded-[var(--radius-button)] hover:bg-[var(--bg-hover)] text-[var(--success-text)] transition-colors\"\r\n title=\"Copier\"\r\n >\r\n <Copy className=\"w-5 h-5\" />\r\n </button>\r\n </div>\r\n <p className=\"text-xs text-[var(--success-text)] opacity-80 mt-2\">\r\n {t('userDetail.security.temporaryPasswordWarning', 'Ce mot de passe ne sera plus affiché. Communiquez-le immédiatement à l\\'utilisateur.')}\r\n </p>\r\n </div>\r\n )}\r\n </div>\r\n\r\n {/* Account Status */}\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--bg-primary)] border border-[var(--border-color)]\">\r\n <h3 className=\"text-lg font-semibold text-[var(--text-primary)] mb-4\">\r\n {t('userDetail.security.accountStatus')}\r\n </h3>\r\n <div className=\"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4\">\r\n <div>\r\n <p className=\"text-[var(--text-primary)]\">\r\n {getAccountStatusText()}\r\n </p>\r\n <p className=\"text-sm text-[var(--text-secondary)]\">\r\n {getAccountStatusHint()}\r\n </p>\r\n </div>\r\n <button\r\n onClick={() => handleToggleStatus(user.isActive)}\r\n disabled={!canUpdate}\r\n className={`flex items-center gap-2 px-4 py-2 rounded-[var(--radius-button)] font-medium transition-colors ${getGreenButtonClasses(user.isActive, canUpdate)}`}\r\n title={!canUpdate ? t('common.noPermission', 'Permission insuffisante') : undefined}\r\n >\r\n {user.isActive ? <UserX className=\"w-4 h-4\" /> : <UserCheck className=\"w-4 h-4\" />}\r\n {user.isActive ? t('users.deactivate') : t('users.activate')}\r\n </button>\r\n </div>\r\n </div>\r\n\r\n {/* Force Logout */}\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--bg-primary)] border border-[var(--border-color)]\">\r\n <h3 className=\"text-lg font-semibold text-[var(--text-primary)] mb-4\">\r\n {t('userDetail.security.forceLogout')}\r\n </h3>\r\n <div className=\"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4\">\r\n <div>\r\n <p className=\"text-[var(--text-primary)]\">{t('userDetail.security.endAllSessionsLabel')}</p>\r\n <p className=\"text-sm text-[var(--text-secondary)]\">{t('userDetail.security.endAllSessionsHint')}</p>\r\n </div>\r\n <button\r\n onClick={handleEndAllSessions}\r\n disabled={!canUpdate}\r\n className={`flex items-center gap-2 px-4 py-2 rounded-[var(--radius-button)] font-medium transition-colors ${getWarningButtonClasses(canUpdate)}`}\r\n title={!canUpdate ? t('common.noPermission', 'Permission insuffisante') : undefined}\r\n >\r\n <LogOut className=\"w-4 h-4\" />\r\n {t('userDetail.security.endAllSessions')}\r\n </button>\r\n </div>\r\n </div>\r\n\r\n {/* Unlock Account - Manual Lock */}\r\n {user.isLocked && (\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--warning-bg)] border border-[var(--warning-border)]\">\r\n <h3 className=\"text-lg font-semibold text-[var(--warning-text)] mb-4\">\r\n {t('userDetail.security.unlockAccount')}\r\n </h3>\r\n <div className=\"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4\">\r\n <div>\r\n <p className=\"text-[var(--warning-text)]\">Compte verrouillé manuellement par un administrateur</p>\r\n <p className=\"text-sm text-[var(--warning-text)] opacity-80\">{t('userDetail.security.unlockHint')}</p>\r\n </div>\r\n <button\r\n onClick={() => setShowUnlockModal(true)}\r\n disabled={!canUpdate}\r\n className={`flex items-center gap-2 px-4 py-2 rounded-[var(--radius-button)] font-medium transition-colors ${getWarningButtonClasses(canUpdate)}`}\r\n title={!canUpdate ? t('common.noPermission', 'Permission insuffisante') : undefined}\r\n >\r\n <Unlock className=\"w-4 h-4\" />\r\n {t('userDetail.security.unlock')}\r\n </button>\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* Unlock Account - Temporary Lock (Failed Attempts) */}\r\n {!user.isLocked && user.isTemporarilyLocked && (\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--warning-bg)] border border-[var(--warning-border)]\">\r\n <h3 className=\"text-lg font-semibold text-[var(--warning-text)] mb-4\">\r\n Verrouillage temporaire\r\n </h3>\r\n <div className=\"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4\">\r\n <div>\r\n <p className=\"text-[var(--warning-text)]\">\r\n Compte temporairement verrouillé suite à trop de tentatives échouées\r\n </p>\r\n <p className=\"text-sm text-[var(--warning-text)] opacity-80\">\r\n {user.temporaryLockoutEnd && (\r\n <>Déverrouillage automatique prévu à {new Date(user.temporaryLockoutEnd).toLocaleTimeString('fr-FR')}</>\r\n )}\r\n </p>\r\n </div>\r\n <button\r\n onClick={handleClearFailedAttempts}\r\n disabled={!canUpdate}\r\n className={`flex items-center gap-2 px-4 py-2 rounded-[var(--radius-button)] font-medium transition-colors ${getWarningButtonClasses(canUpdate)}`}\r\n title={!canUpdate ? t('common.noPermission', 'Permission insuffisante') : undefined}\r\n >\r\n <Unlock className=\"w-4 h-4\" />\r\n Débloquer maintenant\r\n </button>\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* Delete Account */}\r\n {user.userType !== 'System' && user.userType !== 'LocalAdmin' && (\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--error-bg)] border border-[var(--error-border)]\">\r\n <h3 className=\"text-lg font-semibold text-[var(--error-text)] mb-4\">\r\n {t('userDetail.security.dangerZone')}\r\n </h3>\r\n <div className=\"flex items-center justify-between\">\r\n <div>\r\n <p className=\"text-[var(--error-text)]\">{t('userDetail.security.deleteAccount')}</p>\r\n <p className=\"text-sm text-[var(--error-text)] opacity-80\">{t('userDetail.security.deleteHint')}</p>\r\n </div>\r\n <button\r\n onClick={handleDelete}\r\n disabled={!canDelete}\r\n className={`flex items-center gap-2 px-4 py-2 rounded-[var(--radius-button)] font-medium transition-colors ${getRedButtonClasses(canDelete)}`}\r\n title={!canDelete ? t('common.noPermission', 'Permission insuffisante') : undefined}\r\n >\r\n <Trash2 className=\"w-4 h-4\" />\r\n {t('common.delete')}\r\n </button>\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* Unlock Account Modal */}\r\n <UnlockAccountModal\r\n isOpen={showUnlockModal}\r\n onClose={() => setShowUnlockModal(false)}\r\n onConfirm={handleUnlock}\r\n userName={user.fullName}\r\n />\r\n </div>\r\n );\r\n}\r\n","import type { ReactElement } from 'react';\r\nimport { useTranslation } from 'react-i18next';\r\nimport {\r\n Loader2,\r\n Activity,\r\n Smartphone,\r\n MapPin,\r\n Calendar,\r\n Monitor,\r\n CheckCircle,\r\n XCircle,\r\n LogOut\r\n} from 'lucide-react';\r\nimport type { UserSessionsDto, UserActivityDto, SessionDto } from '@/services/api/adminApi';\r\nimport { parseUserAgent } from '@/utils/deviceDetection';\r\n\r\ninterface UserActivitySessionsTabProps {\r\n readonly sessions: UserSessionsDto | null;\r\n readonly activity: UserActivityDto | null;\r\n readonly isCreateMode: boolean;\r\n readonly canUpdate: boolean;\r\n readonly handleEndSession: (sessionId: string) => Promise<void>;\r\n readonly handleEndAllSessions: () => Promise<void>;\r\n}\r\n\r\nconst formatDate = (date: string | null) => {\r\n if (!date) return '-';\r\n return new Date(date).toLocaleString();\r\n};\r\n\r\nconst formatDuration = (duration: string | null) => {\r\n if (!duration) return '-';\r\n const parts = duration.split(':');\r\n if (parts.length >= 2) {\r\n const hours = parseInt(parts[0]);\r\n const minutes = parseInt(parts[1]);\r\n if (hours > 0) return `${hours}h ${minutes}m`;\r\n return `${minutes}m`;\r\n }\r\n return duration;\r\n};\r\n\r\nconst getStatCardColorClass = (color?: 'green' | 'red'): string => {\r\n if (color === 'green') {\r\n return 'text-green-600';\r\n }\r\n if (color === 'red') {\r\n return 'text-red-600';\r\n }\r\n return 'text-[var(--text-primary)]';\r\n};\r\n\r\nexport function UserActivitySessionsTab({\r\n sessions,\r\n activity,\r\n isCreateMode,\r\n canUpdate,\r\n handleEndSession,\r\n handleEndAllSessions\r\n}: UserActivitySessionsTabProps): ReactElement {\r\n const { t } = useTranslation('admin');\r\n\r\n if (isCreateMode) {\r\n return (\r\n <div className=\"text-center py-12\">\r\n <Activity className=\"w-12 h-12 mx-auto mb-4 text-[var(--text-tertiary)]\" />\r\n <p className=\"text-[var(--text-secondary)]\">\r\n {t('userDetail.activity.notAvailableForNewUser', 'Les statistiques d\\'activité ne sont pas disponibles pour un nouvel utilisateur')}\r\n </p>\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div className=\"space-y-8\">\r\n {/* Activity Statistics Section */}\r\n <ActivitySection activity={activity} />\r\n\r\n {/* Sessions Section */}\r\n <SessionsSection\r\n sessions={sessions}\r\n canUpdate={canUpdate}\r\n handleEndSession={handleEndSession}\r\n handleEndAllSessions={handleEndAllSessions}\r\n />\r\n </div>\r\n );\r\n}\r\n\r\n// Activity Statistics Section\r\ninterface ActivitySectionProps {\r\n readonly activity: UserActivityDto | null;\r\n}\r\n\r\nfunction ActivitySection({ activity }: ActivitySectionProps) {\r\n const { t } = useTranslation('admin');\r\n if (!activity) {\r\n return (\r\n <div className=\"space-y-6\">\r\n <h3 className=\"text-lg font-semibold text-[var(--text-primary)] flex items-center gap-2 pb-2 border-b border-[var(--border-color)]\">\r\n <Activity className=\"w-5 h-5\" />\r\n {t('userDetail.activity.statsTitle', 'Statistiques de connexion')}\r\n </h3>\r\n <div className=\"flex items-center justify-center py-8\">\r\n <Loader2 className=\"w-6 h-6 animate-spin text-[var(--color-accent-500)]\" />\r\n </div>\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div className=\"space-y-6\">\r\n <h3 className=\"text-lg font-semibold text-[var(--text-primary)] flex items-center gap-2 pb-2 border-b border-[var(--border-color)]\">\r\n <Activity className=\"w-5 h-5\" />\r\n {t('userDetail.activity.statsTitle', 'Statistiques de connexion')}\r\n </h3>\r\n\r\n {/* Stats Cards */}\r\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4\">\r\n <StatCard value={activity.totalSuccessfulLogins} label={t('userDetail.activity.successfulLogins')} color=\"green\" />\r\n <StatCard value={activity.totalFailedLogins} label={t('userDetail.activity.failedLogins')} color=\"red\" />\r\n <StatCard value={formatDate(activity.lastSuccessfulLoginAt)} label={t('userDetail.activity.lastSuccess')} isText />\r\n <StatCard value={activity.lastSuccessfulLoginIp || '-'} label={t('userDetail.activity.lastIp')} isText />\r\n </div>\r\n\r\n {/* Device & Location Stats */}\r\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-4\">\r\n {(activity.deviceStats?.length ?? 0) > 0 && (\r\n <StatsCard\r\n icon={<Smartphone className=\"w-4 h-4\" />}\r\n title={t('userDetail.activity.devices')}\r\n items={activity.deviceStats ?? []}\r\n labelKey=\"device\"\r\n countSuffix={t('userDetail.activity.logins')}\r\n />\r\n )}\r\n {(activity.locationStats?.length ?? 0) > 0 && (\r\n <StatsCard\r\n icon={<MapPin className=\"w-4 h-4\" />}\r\n title={t('userDetail.activity.locations')}\r\n items={activity.locationStats ?? []}\r\n labelKey=\"location\"\r\n countSuffix={t('userDetail.activity.logins')}\r\n />\r\n )}\r\n </div>\r\n\r\n {/* Login History */}\r\n {(activity.loginsByDay?.length ?? 0) > 0 && (\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--bg-primary)] border border-[var(--border-color)]\">\r\n <h4 className=\"text-base font-semibold text-[var(--text-primary)] mb-3 flex items-center gap-2\">\r\n <Calendar className=\"w-4 h-4\" />\r\n {t('userDetail.activity.loginHistory')}\r\n </h4>\r\n <div className=\"space-y-2\">\r\n {(activity.loginsByDay ?? []).slice(0, 7).map((day) => (\r\n <div key={day.date} className=\"flex items-center gap-4 py-2 border-b border-[var(--border-color)] last:border-0\">\r\n <span className=\"w-24 text-[var(--text-secondary)]\">\r\n {new Date(day.date).toLocaleDateString()}\r\n </span>\r\n <div className=\"flex-1 flex items-center gap-2\">\r\n <div className=\"flex items-center gap-1 text-green-600\">\r\n <CheckCircle className=\"w-4 h-4\" />\r\n {day.successful}\r\n </div>\r\n <div className=\"flex items-center gap-1 text-red-600\">\r\n <XCircle className=\"w-4 h-4\" />\r\n {day.failed}\r\n </div>\r\n </div>\r\n </div>\r\n ))}\r\n </div>\r\n </div>\r\n )}\r\n </div>\r\n );\r\n}\r\n\r\n// Sessions Section\r\ninterface SessionsSectionProps {\r\n readonly sessions: UserSessionsDto | null;\r\n readonly canUpdate: boolean;\r\n readonly handleEndSession: (sessionId: string) => Promise<void>;\r\n readonly handleEndAllSessions: () => Promise<void>;\r\n}\r\n\r\nfunction SessionsSection({ sessions, canUpdate, handleEndSession, handleEndAllSessions }: SessionsSectionProps) {\r\n const { t } = useTranslation('admin');\r\n if (!sessions) {\r\n return (\r\n <div className=\"space-y-6\">\r\n <h3 className=\"text-lg font-semibold text-[var(--text-primary)] flex items-center gap-2 pb-2 border-b border-[var(--border-color)]\">\r\n <Monitor className=\"w-5 h-5\" />\r\n {t('userDetail.sessions.title', 'Sessions')}\r\n </h3>\r\n <div className=\"flex items-center justify-center py-8\">\r\n <Loader2 className=\"w-6 h-6 animate-spin text-[var(--color-accent-500)]\" />\r\n </div>\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div className=\"space-y-6\">\r\n <h3 className=\"text-lg font-semibold text-[var(--text-primary)] flex items-center gap-2 pb-2 border-b border-[var(--border-color)]\">\r\n <Monitor className=\"w-5 h-5\" />\r\n {t('userDetail.sessions.title', 'Sessions')}\r\n </h3>\r\n\r\n {/* Active Sessions */}\r\n <ActiveSessionsList\r\n sessions={sessions.activeSessions ?? []}\r\n canUpdate={canUpdate}\r\n handleEndSession={handleEndSession}\r\n handleEndAllSessions={handleEndAllSessions}\r\n />\r\n\r\n {/* Session History */}\r\n <SessionHistory sessions={sessions.history ?? []} />\r\n </div>\r\n );\r\n}\r\n\r\n// Active Sessions List\r\ninterface ActiveSessionsListProps {\r\n readonly sessions: SessionDto[];\r\n readonly canUpdate: boolean;\r\n readonly handleEndSession: (sessionId: string) => Promise<void>;\r\n readonly handleEndAllSessions: () => Promise<void>;\r\n}\r\n\r\nfunction ActiveSessionsList({ sessions, canUpdate, handleEndSession, handleEndAllSessions }: ActiveSessionsListProps) {\r\n const { t } = useTranslation('admin');\r\n return (\r\n <div>\r\n <div className=\"flex items-center justify-between mb-4\">\r\n <h4 className=\"text-base font-semibold text-[var(--text-primary)]\">\r\n {t('userDetail.sessions.active')} ({sessions.length})\r\n </h4>\r\n {sessions.length > 0 && (\r\n <button\r\n onClick={handleEndAllSessions}\r\n disabled={!canUpdate}\r\n className={`flex items-center gap-2 px-3 py-1.5 rounded-[var(--radius-button)] border transition-colors ${!canUpdate ? 'opacity-50 cursor-not-allowed bg-[var(--bg-secondary)] text-[var(--text-tertiary)] border-[var(--border-color)]' : 'bg-[var(--error-bg)] border-[var(--error-border)] text-[var(--error-text)] hover:opacity-80'}`}\r\n title={!canUpdate ? t('common.noPermission', 'Permission insuffisante') : undefined}\r\n >\r\n <LogOut className=\"w-4 h-4\" />\r\n {t('userDetail.sessions.endAll')}\r\n </button>\r\n )}\r\n </div>\r\n\r\n {sessions.length === 0 ? (\r\n <p className=\"text-[var(--text-secondary)] py-4\">{t('userDetail.sessions.noActive')}</p>\r\n ) : (\r\n <div className=\"space-y-3\">\r\n {sessions.map((session) => (\r\n <SessionCard\r\n key={session.id}\r\n session={session}\r\n canUpdate={canUpdate}\r\n handleEndSession={handleEndSession}\r\n />\r\n ))}\r\n </div>\r\n )}\r\n </div>\r\n );\r\n}\r\n\r\n// Session Card\r\ninterface SessionCardProps {\r\n readonly session: SessionDto;\r\n readonly canUpdate: boolean;\r\n readonly handleEndSession: (sessionId: string) => Promise<void>;\r\n}\r\n\r\nfunction SessionCard({ session, canUpdate, handleEndSession }: SessionCardProps) {\r\n const { t } = useTranslation('admin');\r\n return (\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--bg-primary)] border border-[var(--success-border)]\">\r\n <div className=\"flex items-start justify-between\">\r\n <div className=\"space-y-1\">\r\n <div className=\"flex items-center gap-2\">\r\n {session.deviceType === 'Mobile' ? (\r\n <Smartphone className=\"w-4 h-4 text-green-600\" />\r\n ) : (\r\n <Monitor className=\"w-4 h-4 text-green-600\" />\r\n )}\r\n <span className=\"font-medium text-[var(--text-primary)]\">\r\n {parseUserAgent(session.userAgent).formatted}\r\n </span>\r\n <span className=\"px-2 py-0.5 text-xs rounded-[var(--radius-badge)] bg-[var(--info-bg)] text-[var(--info-text)] border border-[var(--info-border)]\">\r\n {session.deviceType}\r\n </span>\r\n </div>\r\n <div className=\"text-sm text-[var(--text-secondary)] flex items-center gap-4\">\r\n <span>{session.ipAddress}</span>\r\n {session.city && session.country && (\r\n <span className=\"flex items-center gap-1\">\r\n <MapPin className=\"w-3 h-3\" />\r\n {session.city}, {session.country}\r\n </span>\r\n )}\r\n </div>\r\n <div className=\"text-sm text-[var(--text-secondary)]\">\r\n {t('userDetail.sessions.startedAt')}: {formatDate(session.loginAt)}\r\n </div>\r\n </div>\r\n <button\r\n onClick={() => handleEndSession(session.id)}\r\n disabled={!canUpdate}\r\n className={`p-2 rounded-[var(--radius-button)] transition-colors ${!canUpdate ? 'opacity-50 cursor-not-allowed text-[var(--text-tertiary)]' : 'text-[var(--error-text)] hover:bg-[var(--error-bg)]'}`}\r\n title={!canUpdate ? t('common.noPermission', 'Permission insuffisante') : t('userDetail.sessions.end')}\r\n >\r\n <LogOut className=\"w-4 h-4\" />\r\n </button>\r\n </div>\r\n </div>\r\n );\r\n}\r\n\r\n// Session History Table\r\ninterface SessionHistoryProps {\r\n readonly sessions: SessionDto[];\r\n}\r\n\r\nfunction SessionHistory({ sessions }: SessionHistoryProps) {\r\n const { t } = useTranslation('admin');\r\n if (sessions.length === 0) {\r\n return (\r\n <div>\r\n <h4 className=\"text-base font-semibold text-[var(--text-primary)] mb-4\">\r\n {t('userDetail.sessions.history')}\r\n </h4>\r\n <p className=\"text-[var(--text-secondary)] py-4\">{t('userDetail.sessions.noHistory')}</p>\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div>\r\n <h4 className=\"text-base font-semibold text-[var(--text-primary)] mb-4\">\r\n {t('userDetail.sessions.history')}\r\n </h4>\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 py-3 px-4 text-sm font-medium text-[var(--text-secondary)]\">\r\n {t('userDetail.sessions.device')}\r\n </th>\r\n <th className=\"hidden sm:table-cell text-left py-3 px-4 text-sm font-medium text-[var(--text-secondary)]\">\r\n Type\r\n </th>\r\n <th className=\"hidden md:table-cell text-left py-3 px-4 text-sm font-medium text-[var(--text-secondary)]\">\r\n {t('userDetail.sessions.ip')}\r\n </th>\r\n <th className=\"hidden md:table-cell text-left py-3 px-4 text-sm font-medium text-[var(--text-secondary)]\">\r\n {t('userDetail.sessions.location')}\r\n </th>\r\n <th className=\"text-left py-3 px-4 text-sm font-medium text-[var(--text-secondary)]\">\r\n {t('userDetail.sessions.login')}\r\n </th>\r\n <th className=\"hidden lg:table-cell text-left py-3 px-4 text-sm font-medium text-[var(--text-secondary)]\">\r\n {t('userDetail.sessions.logout')}\r\n </th>\r\n <th className=\"hidden lg:table-cell text-left py-3 px-4 text-sm font-medium text-[var(--text-secondary)]\">\r\n {t('userDetail.sessions.duration')}\r\n </th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n {sessions.slice(0, 20).map((session) => (\r\n <tr key={session.id} className=\"border-b border-[var(--border-color)]\">\r\n <td className=\"py-3 px-4 text-[var(--text-primary)]\">\r\n <div className=\"flex items-center gap-2\">\r\n {session.deviceType === 'Mobile' ? (\r\n <Smartphone className=\"w-4 h-4 text-[var(--text-tertiary)]\" />\r\n ) : (\r\n <Monitor className=\"w-4 h-4 text-[var(--text-tertiary)]\" />\r\n )}\r\n <span>{parseUserAgent(session.userAgent).formatted}</span>\r\n </div>\r\n </td>\r\n <td className=\"hidden sm:table-cell py-3 px-4\">\r\n <span className=\"px-2 py-0.5 text-xs rounded-[var(--radius-badge)] bg-[var(--info-bg)] text-[var(--info-text)] border border-[var(--info-border)]\">\r\n {session.deviceType}\r\n </span>\r\n </td>\r\n <td className=\"hidden md:table-cell py-3 px-4 text-[var(--text-secondary)]\">{session.ipAddress || '-'}</td>\r\n <td className=\"hidden md:table-cell py-3 px-4 text-[var(--text-secondary)]\">\r\n {session.city && session.country ? `${session.city}, ${session.country}` : '-'}\r\n </td>\r\n <td className=\"py-3 px-4 text-[var(--text-secondary)]\">{formatDate(session.loginAt)}</td>\r\n <td className=\"hidden lg:table-cell py-3 px-4 text-[var(--text-secondary)]\">{formatDate(session.logoutAt)}</td>\r\n <td className=\"hidden lg:table-cell py-3 px-4 text-[var(--text-secondary)]\">{formatDuration(session.duration)}</td>\r\n </tr>\r\n ))}\r\n </tbody>\r\n </table>\r\n </div>\r\n </div>\r\n );\r\n}\r\n\r\n// Helper Components\r\ninterface StatCardProps {\r\n readonly value: number | string;\r\n readonly label: string;\r\n readonly color?: 'green' | 'red';\r\n readonly isText?: boolean;\r\n}\r\n\r\nfunction StatCard({ value, label, color, isText }: StatCardProps) {\r\n const colorClass = getStatCardColorClass(color);\r\n const sizeClass = isText ? 'text-sm font-medium' : 'text-2xl font-bold';\r\n\r\n return (\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--bg-primary)] border border-[var(--border-color)]\">\r\n <div className={`${sizeClass} ${colorClass}`}>{value}</div>\r\n <div className=\"text-sm text-[var(--text-secondary)]\">{label}</div>\r\n </div>\r\n );\r\n}\r\n\r\ninterface StatsCardProps {\r\n readonly icon: React.ReactNode;\r\n readonly title: string;\r\n readonly items: Array<{ device?: string; location?: string; count: number }>;\r\n readonly labelKey: 'device' | 'location';\r\n readonly countSuffix: string;\r\n}\r\n\r\nfunction StatsCard({ icon, title, items, labelKey, countSuffix }: StatsCardProps) {\r\n return (\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--bg-primary)] border border-[var(--border-color)]\">\r\n <h4 className=\"text-base font-semibold text-[var(--text-primary)] mb-3 flex items-center gap-2\">\r\n {icon}\r\n {title}\r\n </h4>\r\n <div className=\"space-y-2\">\r\n {items.map((item, i) => (\r\n <div key={`item-${item[labelKey]}-${i}`} className=\"flex items-center justify-between py-2 border-b border-[var(--border-color)] last:border-0\">\r\n <span className=\"text-[var(--text-primary)]\">{item[labelKey]}</span>\r\n <span className=\"text-[var(--text-secondary)]\">{item.count} {countSuffix}</span>\r\n </div>\r\n ))}\r\n </div>\r\n </div>\r\n );\r\n}\r\n","import type { ReactElement } from 'react';\r\nimport { useNavigate, Link } from 'react-router-dom';\r\nimport { useTranslation } from 'react-i18next';\r\n\r\ntype TFunction = ReturnType<typeof useTranslation>['t'];\r\nimport {\r\n Loader2,\r\n Building2,\r\n User,\r\n Plus,\r\n RefreshCw,\r\n Trash2,\r\n UserCheck,\r\n Users,\r\n Link2,\r\n Crown,\r\n Star,\r\n X,\r\n Search,\r\n Check\r\n} from 'lucide-react';\r\nimport type { UserTenantDto, TenantListDto } from '@/services/api/adminApi';\r\nimport { TenantCard } from '@/components/tenants/TenantCard';\r\nimport { DataTable, type DataTableColumn } from '@/components/ui/DataTable';\r\nimport { ViewModeToggle, type ViewMode } from '@/components/ui/ViewModeToggle';\r\n\r\ninterface UserTenantsTabProps {\r\n // Data\r\n readonly userTenants: UserTenantDto[] | null;\r\n readonly allTenants: TenantListDto[] | null;\r\n readonly currentTenant: UserTenantDto | null;\r\n readonly hasGlobalRoles: boolean;\r\n\r\n // UI state\r\n readonly showAddTenantModal: boolean;\r\n readonly tenantSearch: string;\r\n readonly tenantsViewMode: ViewMode;\r\n readonly selectedTenantIds: Set<string>;\r\n readonly isAddingMultipleTenants: boolean;\r\n\r\n // Setters\r\n readonly setShowAddTenantModal: (show: boolean) => void;\r\n readonly setTenantSearch: (search: string) => void;\r\n readonly setTenantsViewMode: (mode: ViewMode) => void;\r\n readonly setUserTenants: React.Dispatch<React.SetStateAction<UserTenantDto[] | null>>;\r\n\r\n // Actions\r\n readonly loadTenants: () => Promise<void>;\r\n readonly toggleTenantSelection: (tenantId: string) => void;\r\n readonly selectAllTenants: (availableTenantIds: string[]) => void;\r\n readonly clearTenantSelection: () => void;\r\n readonly closeAddTenantModal: () => void;\r\n readonly handleAddMultipleTenants: () => Promise<void>;\r\n readonly handleRemoveTenant: (tenantId: string) => Promise<void>;\r\n}\r\n\r\nconst renderTenantsContent = (\r\n filteredTenants: UserTenantDto[] | null | undefined,\r\n hasGlobalRoles: boolean,\r\n tenantsViewMode: ViewMode,\r\n currentTenant: UserTenantDto | null,\r\n handleRemoveTenant: (id: string) => Promise<void>,\r\n navigate: any,\r\n setShowAddTenantModal: (show: boolean) => void\r\n) => {\r\n if (!filteredTenants) {\r\n return <LoadingState />;\r\n }\r\n if (filteredTenants.length === 0) {\r\n return <EmptyState hasGlobalRoles={hasGlobalRoles} onAddClick={() => setShowAddTenantModal(true)} />;\r\n }\r\n if (tenantsViewMode === 'table') {\r\n return (\r\n <TenantTableView\r\n tenants={filteredTenants}\r\n hasGlobalRoles={hasGlobalRoles}\r\n currentTenant={currentTenant}\r\n onRemove={handleRemoveTenant}\r\n onNavigate={(id) => navigate(`/administration/tenants/${id}`)}\r\n />\r\n );\r\n }\r\n return (\r\n <TenantCardsView\r\n tenants={filteredTenants}\r\n hasGlobalRoles={hasGlobalRoles}\r\n currentTenant={currentTenant}\r\n onRemove={handleRemoveTenant}\r\n />\r\n );\r\n};\r\n\r\nconst renderTenantList = (\r\n allTenants: TenantListDto[] | null,\r\n availableTenants: TenantListDto[],\r\n selectedTenantIds: Set<string>,\r\n toggleTenantSelection: (id: string) => void,\r\n t: TFunction\r\n) => {\r\n if (!allTenants) {\r\n return (\r\n <div className=\"flex items-center justify-center py-8\">\r\n <Loader2 className=\"w-6 h-6 animate-spin text-[var(--color-accent-500)]\" />\r\n </div>\r\n );\r\n }\r\n if (availableTenants.length === 0) {\r\n return (\r\n <div className=\"text-center py-8 text-[var(--text-secondary)]\">\r\n <Building2 className=\"w-8 h-8 mx-auto mb-2 opacity-50\" />\r\n <p>{t('userDetail.tenants.addModal.noAvailable', 'Aucun tenant disponible')}</p>\r\n </div>\r\n );\r\n }\r\n return availableTenants.map((tenant) => (\r\n <TenantSelectItem\r\n key={tenant.id}\r\n tenant={tenant}\r\n isSelected={selectedTenantIds.has(tenant.id)}\r\n onToggle={() => toggleTenantSelection(tenant.id)}\r\n />\r\n ));\r\n};\r\n\r\nexport function UserTenantsTab({\r\n userTenants,\r\n allTenants,\r\n currentTenant,\r\n hasGlobalRoles,\r\n showAddTenantModal,\r\n tenantSearch,\r\n tenantsViewMode,\r\n selectedTenantIds,\r\n isAddingMultipleTenants,\r\n setShowAddTenantModal,\r\n setTenantSearch,\r\n setTenantsViewMode,\r\n setUserTenants,\r\n loadTenants,\r\n toggleTenantSelection,\r\n selectAllTenants,\r\n clearTenantSelection,\r\n closeAddTenantModal,\r\n handleAddMultipleTenants,\r\n handleRemoveTenant\r\n}: UserTenantsTabProps): ReactElement {\r\n const { t } = useTranslation('admin');\r\n const navigate = useNavigate();\r\n\r\n // Filter tenants based on current user's access\r\n const filteredTenants = hasGlobalRoles\r\n ? userTenants\r\n : userTenants?.filter(tenant => currentTenant?.id === tenant.id);\r\n\r\n const handleRefresh = () => {\r\n setUserTenants(null);\r\n loadTenants();\r\n };\r\n\r\n return (\r\n <div className=\"space-y-6\">\r\n <div className=\"flex items-center justify-between\">\r\n <h3 className=\"text-lg font-semibold text-[var(--text-primary)] flex items-center gap-2\">\r\n <Building2 className=\"w-5 h-5\" />\r\n {t('userDetail.tenants.title', 'Tenants de l\\'utilisateur')}\r\n {hasGlobalRoles && (\r\n <span className=\"ml-2 px-2 py-0.5 text-xs font-medium rounded-full bg-amber-500/10 text-amber-600\">\r\n {t('userDetail.tenants.globalView', 'Vue globale')}\r\n </span>\r\n )}\r\n </h3>\r\n <div className=\"flex items-center gap-2\">\r\n <ViewModeToggle viewMode={tenantsViewMode} onChange={setTenantsViewMode} />\r\n <button\r\n onClick={() => setShowAddTenantModal(true)}\r\n className=\"flex items-center gap-2 px-3 py-1.5 rounded-[var(--radius-button)] bg-[var(--color-accent-600)] text-white hover:bg-[var(--color-accent-700)] transition-colors\"\r\n >\r\n <Plus className=\"w-4 h-4\" />\r\n {t('userDetail.tenants.add', 'Ajouter un tenant')}\r\n </button>\r\n <button\r\n onClick={handleRefresh}\r\n className=\"flex items-center gap-2 px-3 py-1.5 rounded-[var(--radius-button)] bg-[var(--bg-primary)] border border-[var(--border-color)] text-[var(--text-secondary)] hover:bg-[var(--bg-hover)] transition-colors\"\r\n >\r\n <RefreshCw className=\"w-4 h-4\" />\r\n {t('common.refresh', 'Actualiser')}\r\n </button>\r\n </div>\r\n </div>\r\n\r\n {/* Content */}\r\n {renderTenantsContent(\r\n filteredTenants,\r\n hasGlobalRoles,\r\n tenantsViewMode,\r\n currentTenant,\r\n handleRemoveTenant,\r\n navigate,\r\n setShowAddTenantModal\r\n )}\r\n\r\n {/* Add Tenant Modal */}\r\n {showAddTenantModal && (\r\n <AddTenantModal\r\n userTenants={userTenants}\r\n allTenants={allTenants}\r\n tenantSearch={tenantSearch}\r\n setTenantSearch={setTenantSearch}\r\n selectedTenantIds={selectedTenantIds}\r\n isAddingMultipleTenants={isAddingMultipleTenants}\r\n toggleTenantSelection={toggleTenantSelection}\r\n selectAllTenants={selectAllTenants}\r\n clearTenantSelection={clearTenantSelection}\r\n closeAddTenantModal={closeAddTenantModal}\r\n handleAddMultipleTenants={handleAddMultipleTenants}\r\n />\r\n )}\r\n </div>\r\n );\r\n}\r\n\r\n// Loading State\r\nfunction LoadingState() {\r\n return (\r\n <div className=\"flex items-center justify-center h-32\">\r\n <Loader2 className=\"w-6 h-6 animate-spin text-[var(--color-accent-500)]\" />\r\n </div>\r\n );\r\n}\r\n\r\n// Empty State\r\ninterface EmptyStateProps {\r\n readonly hasGlobalRoles: boolean;\r\n readonly onAddClick: () => void;\r\n}\r\n\r\nfunction EmptyState({ hasGlobalRoles, onAddClick }: EmptyStateProps) {\r\n const { t } = useTranslation('admin');\r\n return (\r\n <div className=\"flex flex-col items-center justify-center h-32 text-[var(--text-secondary)]\">\r\n <Building2 className=\"w-8 h-8 mb-2 opacity-50\" />\r\n <p>{t('userDetail.tenants.noTenants', 'Cet utilisateur n\\'appartient à aucun tenant')}</p>\r\n {hasGlobalRoles && (\r\n <button\r\n onClick={onAddClick}\r\n className=\"mt-3 flex items-center gap-2 px-3 py-1.5 rounded-[var(--radius-button)] bg-[var(--color-accent-600)] text-white hover:bg-[var(--color-accent-700)] transition-colors text-sm\"\r\n >\r\n <Plus className=\"w-4 h-4\" />\r\n {t('userDetail.tenants.addFirst', 'Ajouter un premier tenant')}\r\n </button>\r\n )}\r\n </div>\r\n );\r\n}\r\n\r\n// Table View\r\ninterface TenantTableViewProps {\r\n readonly tenants: UserTenantDto[];\r\n readonly hasGlobalRoles: boolean;\r\n readonly currentTenant: UserTenantDto | null;\r\n readonly onRemove: (id: string) => Promise<void>;\r\n readonly onNavigate: (id: string) => void;\r\n}\r\n\r\nfunction TenantTableView({ tenants, hasGlobalRoles, currentTenant, onRemove, onNavigate }: TenantTableViewProps) {\r\n const { t } = useTranslation('admin');\r\n const columns: DataTableColumn<UserTenantDto>[] = [\r\n {\r\n key: 'name',\r\n label: t('userDetail.tenants.table.name', 'Nom'),\r\n sortable: true,\r\n render: (tenant) => (\r\n <div className=\"flex items-center gap-2\">\r\n <div className={`p-1.5 rounded flex-shrink-0 ${\r\n tenant.type === 'Business'\r\n ? 'bg-blue-500/10 text-blue-500'\r\n : 'bg-violet-500/10 text-violet-500'\r\n }`}>\r\n {tenant.type === 'Business' ? <Building2 className=\"w-4 h-4\" /> : <User className=\"w-4 h-4\" />}\r\n </div>\r\n <div className=\"min-w-0\">\r\n <Link\r\n to={`/administration/tenants/${tenant.id}`}\r\n className=\"font-medium text-[var(--text-primary)] hover:text-[var(--color-accent-600)] hover:underline transition-colors\"\r\n onClick={(e) => e.stopPropagation()}\r\n >\r\n {tenant.name}\r\n </Link>\r\n <span className=\"text-xs text-[var(--text-tertiary)] ml-2\">{tenant.slug}</span>\r\n </div>\r\n </div>\r\n ),\r\n },\r\n {\r\n key: 'type',\r\n label: t('userDetail.tenants.table.type', 'Type'),\r\n sortable: true,\r\n render: (tenant) => (\r\n <span className={`inline-flex items-center px-2 py-0.5 rounded-full text-xs ${\r\n tenant.type === 'Business'\r\n ? 'bg-blue-500/10 text-blue-500'\r\n : 'bg-violet-500/10 text-violet-500'\r\n }`}>\r\n {tenant.type === 'Business' ? t('tenants.type.business', 'Entreprise') : t('tenants.type.personal', 'Personnel')}\r\n </span>\r\n ),\r\n hideOnMobile: true,\r\n },\r\n {\r\n key: 'status',\r\n label: t('userDetail.tenants.table.status', 'Statut'),\r\n sortable: true,\r\n render: (tenant) => {\r\n const statusColors: Record<string, string> = {\r\n Active: 'bg-green-500/10 text-green-600',\r\n Pending: 'bg-blue-500/10 text-blue-500',\r\n Suspended: 'bg-amber-500/10 text-amber-600',\r\n Archived: 'bg-red-500/10 text-red-500',\r\n };\r\n const getStatusDotColor = (status: string): string => {\r\n switch (status) {\r\n case 'Active': return 'bg-green-500';\r\n case 'Pending': return 'bg-blue-500';\r\n case 'Suspended': return 'bg-amber-500';\r\n default: return 'bg-red-500';\r\n }\r\n };\r\n return (\r\n <span className={`inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-xs ${statusColors[tenant.status] || ''}`}>\r\n <span className={`w-1.5 h-1.5 rounded-full ${getStatusDotColor(tenant.status)}`} />\r\n {t(`tenants.status.${tenant.status.toLowerCase()}`, { defaultValue: tenant.status })}\r\n </span>\r\n );\r\n },\r\n hideOnMobile: true,\r\n },\r\n {\r\n key: 'membershipSource',\r\n label: t('userDetail.tenants.table.source', 'Source'),\r\n render: (tenant) => (\r\n <div className=\"flex items-center gap-1 text-xs\">\r\n {tenant.membershipSource === 'Direct' && (\r\n <span className=\"inline-flex items-center gap-1 text-green-600\">\r\n <UserCheck className=\"w-3 h-3\" />\r\n {t('tenants.directMember', 'Direct')}\r\n </span>\r\n )}\r\n {tenant.membershipSource === 'Group' && (\r\n <span className=\"inline-flex items-center gap-1 text-blue-500\">\r\n <Users className=\"w-3 h-3\" />\r\n {t('tenants.viaGroup', 'Groupe')}\r\n </span>\r\n )}\r\n {tenant.membershipSource === 'Both' && (\r\n <span className=\"inline-flex items-center gap-1 text-violet-500\">\r\n <Link2 className=\"w-3 h-3\" />\r\n {t('tenants.directAndGroup', 'Direct + Groupe')}\r\n </span>\r\n )}\r\n </div>\r\n ),\r\n hideOnMobile: true,\r\n },\r\n {\r\n key: 'badges',\r\n label: '',\r\n width: '100px',\r\n render: (tenant) => (\r\n <div className=\"flex items-center gap-1\">\r\n {tenant.isOwner && (\r\n <span className=\"inline-flex items-center gap-1 px-1.5 py-0.5 rounded-full text-xs bg-amber-500/10 text-amber-600\" title={t('tenants.owner', 'Owner')}>\r\n <Crown className=\"w-3 h-3\" />\r\n </span>\r\n )}\r\n {tenant.isDefault && (\r\n <span className=\"inline-flex items-center gap-1 px-1.5 py-0.5 rounded-full text-xs bg-[var(--color-accent-500)]/10 text-[var(--color-accent-600)]\" title={t('tenants.default', 'Default')}>\r\n <Star className=\"w-3 h-3 fill-current\" />\r\n </span>\r\n )}\r\n </div>\r\n ),\r\n },\r\n {\r\n key: 'actions',\r\n label: '',\r\n width: '60px',\r\n align: 'right',\r\n render: (tenant) => {\r\n const canManage = hasGlobalRoles || currentTenant?.id === tenant.id;\r\n if (!canManage) return null;\r\n return (\r\n <button\r\n onClick={(e) => {\r\n e.stopPropagation();\r\n onRemove(tenant.id);\r\n }}\r\n className=\"flex items-center gap-1 px-2 py-1 rounded text-xs text-red-500 hover:bg-red-500/10 transition-colors\"\r\n >\r\n <Trash2 className=\"w-3 h-3\" />\r\n </button>\r\n );\r\n },\r\n },\r\n ];\r\n\r\n return (\r\n <DataTable\r\n data={tenants}\r\n columns={columns}\r\n getRowKey={(tenant) => tenant.id}\r\n onRowClick={(tenant) => onNavigate(tenant.id)}\r\n compact\r\n emptyMessage={t('userDetail.tenants.noTenants', 'Cet utilisateur n\\'appartient à aucun tenant')}\r\n emptyIcon={<Building2 className=\"w-8 h-8 text-[var(--text-tertiary)]\" />}\r\n />\r\n );\r\n}\r\n\r\n// Cards View\r\ninterface TenantCardsViewProps {\r\n readonly tenants: UserTenantDto[];\r\n readonly hasGlobalRoles: boolean;\r\n readonly currentTenant: UserTenantDto | null;\r\n readonly onRemove: (id: string) => Promise<void>;\r\n}\r\n\r\nfunction TenantCardsView({ tenants, hasGlobalRoles, currentTenant, onRemove }: TenantCardsViewProps) {\r\n const { t } = useTranslation('admin');\r\n const primaryTenant = currentTenant\r\n ? tenants.find(tenant => tenant.id === currentTenant.id)\r\n : tenants.find(tenant => tenant.isDefault);\r\n const otherTenants = tenants.filter(tenant => tenant.id !== primaryTenant?.id);\r\n\r\n return (\r\n <div className=\"space-y-6\">\r\n {/* Primary Tenant */}\r\n {primaryTenant && (\r\n <div>\r\n <div className=\"flex items-center gap-2 mb-3\">\r\n <div className=\"w-2 h-2 rounded-full bg-[var(--success-dot)]\" />\r\n <span className=\"text-sm font-medium text-[var(--text-secondary)]\">\r\n {currentTenant?.id === primaryTenant.id\r\n ? t('userDetail.tenants.activeTenant', 'Tenant actif')\r\n : t('userDetail.tenants.defaultTenant', 'Tenant par défaut')}\r\n </span>\r\n </div>\r\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4\">\r\n <TenantCard\r\n tenant={primaryTenant}\r\n showActions={true}\r\n isSelected={true}\r\n navigateTo={`/administration/tenants/${primaryTenant.id}`}\r\n onRemove={hasGlobalRoles || currentTenant?.id === primaryTenant.id ? () => onRemove(primaryTenant.id) : undefined}\r\n />\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* Separator */}\r\n {primaryTenant && otherTenants.length > 0 && (\r\n <div className=\"flex items-center gap-4\">\r\n <div className=\"flex-1 h-px bg-[var(--border-color)]\" />\r\n <span className=\"text-xs text-[var(--text-tertiary)] uppercase tracking-wider\">\r\n {t('userDetail.tenants.otherTenants', 'Autres tenants')}\r\n </span>\r\n <div className=\"flex-1 h-px bg-[var(--border-color)]\" />\r\n </div>\r\n )}\r\n\r\n {/* Other Tenants */}\r\n {primaryTenant && otherTenants.length > 0 && (\r\n <div className={`grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 ${!hasGlobalRoles ? 'opacity-60' : ''}`}>\r\n {otherTenants.map((tenant) => {\r\n const canManage = hasGlobalRoles || currentTenant?.id === tenant.id;\r\n return (\r\n <TenantCard\r\n key={tenant.id}\r\n tenant={tenant}\r\n showActions={true}\r\n isDisabled={!canManage}\r\n navigateTo={`/administration/tenants/${tenant.id}`}\r\n disabledReason={!canManage ? t('userDetail.tenants.notCurrentTenant', 'Changez de tenant pour gérer ce membre') : undefined}\r\n onRemove={canManage ? () => onRemove(tenant.id) : undefined}\r\n />\r\n );\r\n })}\r\n </div>\r\n )}\r\n\r\n {/* No primary tenant - show all */}\r\n {!primaryTenant && tenants.length > 0 && (\r\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4\">\r\n {tenants.map((tenant) => {\r\n const canManage = hasGlobalRoles || currentTenant?.id === tenant.id;\r\n return (\r\n <TenantCard\r\n key={tenant.id}\r\n tenant={tenant}\r\n showActions={true}\r\n isDisabled={!canManage}\r\n navigateTo={`/administration/tenants/${tenant.id}`}\r\n disabledReason={!canManage ? t('userDetail.tenants.notCurrentTenant', 'Changez de tenant pour gérer ce membre') : undefined}\r\n onRemove={canManage ? () => onRemove(tenant.id) : undefined}\r\n />\r\n );\r\n })}\r\n </div>\r\n )}\r\n </div>\r\n );\r\n}\r\n\r\n// Add Tenant Modal\r\ninterface AddTenantModalProps {\r\n readonly userTenants: UserTenantDto[] | null;\r\n readonly allTenants: TenantListDto[] | null;\r\n readonly tenantSearch: string;\r\n readonly setTenantSearch: (search: string) => void;\r\n readonly selectedTenantIds: Set<string>;\r\n readonly isAddingMultipleTenants: boolean;\r\n readonly toggleTenantSelection: (tenantId: string) => void;\r\n readonly selectAllTenants: (availableTenantIds: string[]) => void;\r\n readonly clearTenantSelection: () => void;\r\n readonly closeAddTenantModal: () => void;\r\n readonly handleAddMultipleTenants: () => Promise<void>;\r\n}\r\n\r\nfunction AddTenantModal({\r\n userTenants,\r\n allTenants,\r\n tenantSearch,\r\n setTenantSearch,\r\n selectedTenantIds,\r\n isAddingMultipleTenants,\r\n toggleTenantSelection,\r\n selectAllTenants,\r\n clearTenantSelection,\r\n closeAddTenantModal,\r\n handleAddMultipleTenants\r\n}: AddTenantModalProps) {\r\n const { t } = useTranslation('admin');\r\n const userTenantIds = new Set(userTenants?.map(tenant => tenant.id) || []);\r\n const availableTenants = allTenants\r\n ?.filter(tenant => !userTenantIds.has(tenant.id))\r\n .filter(tenant =>\r\n !tenantSearch.trim() ||\r\n tenant.name.toLowerCase().includes(tenantSearch.toLowerCase()) ||\r\n tenant.slug.toLowerCase().includes(tenantSearch.toLowerCase())\r\n ) ?? [];\r\n\r\n return (\r\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50\">\r\n <div className=\"bg-[var(--bg-card)] rounded-[var(--radius-modal)] shadow-xl w-full max-w-2xl mx-4 max-h-[80vh] flex flex-col\">\r\n {/* Header */}\r\n <div className=\"flex items-center justify-between p-4 border-b border-[var(--border-color)]\">\r\n <h3 className=\"text-lg font-semibold text-[var(--text-primary)]\">\r\n {t('userDetail.tenants.addModal.title', 'Ajouter des tenants')}\r\n </h3>\r\n <button\r\n onClick={closeAddTenantModal}\r\n className=\"p-1 rounded-[var(--radius-button)] hover:bg-[var(--bg-hover)] text-[var(--text-secondary)]\"\r\n >\r\n <X className=\"w-5 h-5\" />\r\n </button>\r\n </div>\r\n\r\n {/* Search and Selection Actions */}\r\n <div className=\"p-4 space-y-3 border-b border-[var(--border-color)]\">\r\n <div className=\"relative\">\r\n <Search className=\"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-[var(--text-tertiary)]\" />\r\n <input\r\n type=\"text\"\r\n value={tenantSearch}\r\n onChange={(e) => setTenantSearch(e.target.value)}\r\n placeholder={t('userDetail.tenants.addModal.search', 'Rechercher un tenant...')}\r\n className=\"w-full pl-10 pr-4 py-2 rounded-[var(--radius-input)] bg-[var(--bg-secondary)] border border-[var(--border-color)] text-[var(--text-primary)] placeholder-[var(--text-tertiary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n autoFocus\r\n />\r\n </div>\r\n\r\n {availableTenants.length > 0 && (\r\n <div className=\"flex items-center justify-between text-xs\">\r\n <span className=\"text-[var(--text-secondary)]\">\r\n {selectedTenantIds.size > 0\r\n ? t('userDetail.tenants.addModal.selectedCount', { count: selectedTenantIds.size, defaultValue: `${selectedTenantIds.size} sélectionné(s)` })\r\n : t('userDetail.tenants.addModal.availableCount', { count: availableTenants.length, defaultValue: `${availableTenants.length} tenant(s) disponible(s)` })}\r\n </span>\r\n <div className=\"flex items-center gap-2\">\r\n <button\r\n onClick={() => selectAllTenants(availableTenants.map(tenant => tenant.id))}\r\n className=\"text-[var(--color-accent-500)] hover:underline\"\r\n >\r\n {t('userDetail.tenants.addModal.selectAll', 'Tout sélectionner')}\r\n </button>\r\n {selectedTenantIds.size > 0 && (\r\n <button\r\n onClick={clearTenantSelection}\r\n className=\"text-[var(--text-tertiary)] hover:underline\"\r\n >\r\n {t('userDetail.tenants.addModal.clearSelection', 'Effacer')}\r\n </button>\r\n )}\r\n </div>\r\n </div>\r\n )}\r\n </div>\r\n\r\n {/* Tenant List */}\r\n <div className=\"flex-1 overflow-y-auto p-4 space-y-2\">\r\n {renderTenantList(allTenants, availableTenants, selectedTenantIds, toggleTenantSelection, t)}\r\n </div>\r\n\r\n {/* Footer */}\r\n <div className=\"flex items-center justify-between p-4 border-t border-[var(--border-color)]\">\r\n <div className=\"text-sm text-[var(--text-secondary)]\">\r\n {selectedTenantIds.size > 0 && (\r\n <span className=\"flex items-center gap-2\">\r\n <span className=\"w-6 h-6 rounded-full bg-[var(--color-accent-500)] text-white text-xs flex items-center justify-center font-medium\">\r\n {selectedTenantIds.size}\r\n </span>\r\n {t('userDetail.tenants.addModal.tenantsSelected', 'tenant(s) sélectionné(s)')}\r\n </span>\r\n )}\r\n </div>\r\n <div className=\"flex items-center gap-2\">\r\n <button\r\n onClick={closeAddTenantModal}\r\n className=\"px-4 py-2 rounded-[var(--radius-button)] bg-[var(--bg-secondary)] text-[var(--text-secondary)] hover:bg-[var(--bg-hover)] transition-colors\"\r\n >\r\n {t('common.cancel', 'Annuler')}\r\n </button>\r\n <button\r\n onClick={handleAddMultipleTenants}\r\n disabled={selectedTenantIds.size === 0 || isAddingMultipleTenants}\r\n className=\"px-4 py-2 rounded-[var(--radius-button)] bg-[var(--color-accent-600)] text-white hover:bg-[var(--color-accent-700)] transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2\"\r\n >\r\n {isAddingMultipleTenants ? (\r\n <>\r\n <Loader2 className=\"w-4 h-4 animate-spin\" />\r\n {t('userDetail.tenants.addModal.adding', 'Ajout en cours...')}\r\n </>\r\n ) : (\r\n <>\r\n <Plus className=\"w-4 h-4\" />\r\n {t('userDetail.tenants.addModal.add', 'Ajouter')}\r\n {selectedTenantIds.size > 0 && ` (${selectedTenantIds.size})`}\r\n </>\r\n )}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n}\r\n\r\n// Tenant Select Item\r\ninterface TenantSelectItemProps {\r\n readonly tenant: TenantListDto;\r\n readonly isSelected: boolean;\r\n readonly onToggle: () => void;\r\n}\r\n\r\nfunction TenantSelectItem({ tenant, isSelected, onToggle }: TenantSelectItemProps) {\r\n const { t } = useTranslation('admin');\r\n return (\r\n <button\r\n type=\"button\"\r\n onClick={onToggle}\r\n className={`w-full flex items-center gap-3 p-3 rounded-[var(--radius-card)] border cursor-pointer transition-colors text-left ${\r\n isSelected\r\n ? 'border-[var(--color-accent-500)] bg-[var(--color-accent-500)]/5'\r\n : 'border-[var(--border-color)] bg-[var(--bg-secondary)] hover:border-[var(--color-accent-500)] hover:bg-[var(--bg-hover)]'\r\n }`}\r\n >\r\n {/* Checkbox */}\r\n <div\r\n className={`w-5 h-5 rounded border-2 flex items-center justify-center flex-shrink-0 transition-colors ${\r\n isSelected\r\n ? 'bg-[var(--color-accent-500)] border-[var(--color-accent-500)]'\r\n : 'border-[var(--border-color)]'\r\n }`}\r\n >\r\n {isSelected && <Check className=\"w-3 h-3 text-white\" />}\r\n </div>\r\n\r\n {/* Icon */}\r\n <div className={`flex-shrink-0 w-10 h-10 flex items-center justify-center rounded-[var(--radius-button)] ${\r\n tenant.type === 'Business' ? 'bg-blue-500/10' : 'bg-violet-500/10'\r\n }`}>\r\n {tenant.type === 'Business' ? (\r\n <Building2 className=\"w-5 h-5 text-blue-500\" />\r\n ) : (\r\n <User className=\"w-5 h-5 text-violet-500\" />\r\n )}\r\n </div>\r\n\r\n {/* Content */}\r\n <div className=\"flex-1 min-w-0\">\r\n <p className=\"font-medium text-[var(--text-primary)] truncate\">{tenant.name}</p>\r\n <p className=\"text-sm text-[var(--text-secondary)] truncate\">{tenant.slug}</p>\r\n </div>\r\n\r\n {/* Member count */}\r\n {tenant.memberCount !== undefined && (\r\n <span className=\"text-xs text-[var(--text-tertiary)] flex-shrink-0\">\r\n {tenant.memberCount} {t('userDetail.tenants.members', 'membres')}\r\n </span>\r\n )}\r\n </button>\r\n );\r\n}\r\n","import type { ReactElement } from 'react';\r\nimport { useTranslation } from 'react-i18next';\r\nimport {\r\n Loader2,\r\n RefreshCw,\r\n History,\r\n Shield,\r\n ShieldX,\r\n Key,\r\n User,\r\n LogOut,\r\n Cloud,\r\n Phone,\r\n MapPin as MapPinIcon,\r\n Briefcase,\r\n Edit3,\r\n RotateCcw\r\n} from 'lucide-react';\r\nimport type { UserHistoryDto } from '@/services/api/adminApi';\r\n\r\ninterface UserHistoryTabProps {\r\n readonly history: UserHistoryDto[] | null;\r\n readonly loadHistory: () => void;\r\n readonly handleRestoreField: (historyId: string) => Promise<void>;\r\n readonly restoringHistoryId: string | null;\r\n readonly canUpdate: boolean;\r\n}\r\n\r\nconst formatDate = (date: string | null) => {\r\n if (!date) return '-';\r\n return new Date(date).toLocaleString();\r\n};\r\n\r\nexport function UserHistoryTab({\r\n history,\r\n loadHistory,\r\n handleRestoreField,\r\n restoringHistoryId,\r\n canUpdate\r\n}: UserHistoryTabProps): ReactElement {\r\n const { t } = useTranslation('admin');\r\n\r\n const getActionLabel = (actionName: string): string => {\r\n const labels: Record<string, string> = {\r\n ProfileUpdated: t('userDetail.history.actions.profileUpdated', 'Profil mis à jour'),\r\n JobInfoUpdated: t('userDetail.history.actions.jobInfoUpdated', 'Info emploi mise à jour'),\r\n AddressUpdated: t('userDetail.history.actions.addressUpdated', 'Adresse mise à jour'),\r\n PhoneUpdated: t('userDetail.history.actions.phoneUpdated', 'Téléphone mis à jour'),\r\n ContactUpdated: t('userDetail.history.actions.contactUpdated', 'Contact mis à jour'),\r\n OrganizationUpdated: t('userDetail.history.actions.organizationUpdated', 'Organisation mise à jour'),\r\n RoleAssigned: t('userDetail.history.actions.roleAssigned', 'Rôle assigné'),\r\n RoleRemoved: t('userDetail.history.actions.roleRemoved', 'Rôle retiré'),\r\n StatusActivated: t('userDetail.history.actions.statusActivated', 'Compte activé'),\r\n StatusDeactivated: t('userDetail.history.actions.statusDeactivated', 'Compte désactivé'),\r\n PasswordReset: t('userDetail.history.actions.passwordReset', 'Mot de passe réinitialisé'),\r\n PasswordResetLinkSent: t('userDetail.history.actions.passwordResetLinkSent', 'Lien de réinitialisation envoyé'),\r\n AccountLocked: t('userDetail.history.actions.accountLocked', 'Compte verrouillé'),\r\n AccountUnlocked: t('userDetail.history.actions.accountUnlocked', 'Compte déverrouillé'),\r\n FailedAttemptCleared: t('userDetail.history.actions.failedAttemptCleared', 'Tentatives échouées effacées'),\r\n SessionEnded: t('userDetail.history.actions.sessionEnded', 'Session terminée'),\r\n AllSessionsEnded: t('userDetail.history.actions.allSessionsEnded', 'Toutes les sessions terminées'),\r\n EntraSynced: t('userDetail.history.actions.entraSynced', 'Synchronisé avec Entra'),\r\n Created: t('userDetail.history.actions.created', 'Compte créé'),\r\n Deleted: t('userDetail.history.actions.deleted', 'Compte supprimé'),\r\n EntraFieldUpdated: t('userDetail.history.actions.entraFieldUpdated', 'Champ modifié par Entra'),\r\n FieldRestored: t('userDetail.history.actions.fieldRestored', 'Champ restauré'),\r\n PermissionAssigned: t('userDetail.history.actions.permissionAssigned', 'Permission assignée'),\r\n PermissionRemoved: t('userDetail.history.actions.permissionRemoved', 'Permission retirée'),\r\n TenantAdded: t('userDetail.history.actions.tenantAdded', 'Ajouté au tenant'),\r\n TenantRemoved: t('userDetail.history.actions.tenantRemoved', 'Retiré du tenant'),\r\n GroupAdded: t('userDetail.history.actions.groupAdded', 'Ajouté au groupe'),\r\n GroupRemoved: t('userDetail.history.actions.groupRemoved', 'Retiré du groupe'),\r\n AccessDenied: t('userDetail.history.actions.accessDenied', 'Accès refusé')\r\n };\r\n return labels[actionName] || actionName;\r\n };\r\n\r\n const isRestorable = (entry: UserHistoryDto): boolean => {\r\n const restorableActions = [\r\n 'ProfileUpdated',\r\n 'PhoneUpdated',\r\n 'JobInfoUpdated',\r\n 'AddressUpdated',\r\n 'OrganizationUpdated',\r\n 'ContactUpdated',\r\n 'EntraFieldUpdated'\r\n ];\r\n return (\r\n restorableActions.includes(entry.actionName) &&\r\n !!entry.fieldChanged &&\r\n entry.oldValue !== null &&\r\n entry.oldValue !== undefined\r\n );\r\n };\r\n\r\n const getActionIcon = (actionName: string) => {\r\n if (actionName === 'AccessDenied') return <ShieldX className=\"w-4 h-4\" />;\r\n if (actionName === 'FieldRestored') return <RotateCcw className=\"w-4 h-4\" />;\r\n if (actionName.includes('Role')) return <Shield className=\"w-4 h-4\" />;\r\n if (actionName.includes('Password')) return <Key className=\"w-4 h-4\" />;\r\n if (actionName.includes('Status') || actionName.includes('Lock')) return <User className=\"w-4 h-4\" />;\r\n if (actionName.includes('Session')) return <LogOut className=\"w-4 h-4\" />;\r\n if (actionName.includes('Entra')) return <Cloud className=\"w-4 h-4\" />;\r\n if (actionName.includes('Phone')) return <Phone className=\"w-4 h-4\" />;\r\n if (actionName.includes('Address')) return <MapPinIcon className=\"w-4 h-4\" />;\r\n if (actionName.includes('Job') || actionName.includes('Organization')) return <Briefcase className=\"w-4 h-4\" />;\r\n return <Edit3 className=\"w-4 h-4\" />;\r\n };\r\n\r\n const handleRefresh = () => {\r\n loadHistory();\r\n };\r\n\r\n return (\r\n <div className=\"space-y-6\">\r\n <div className=\"flex items-center justify-between\">\r\n <h3 className=\"text-lg font-semibold text-[var(--text-primary)] flex items-center gap-2\">\r\n <History className=\"w-5 h-5\" />\r\n {t('userDetail.history.title', 'Historique des modifications')}\r\n </h3>\r\n <button\r\n onClick={handleRefresh}\r\n className=\"flex items-center gap-2 px-3 py-1.5 rounded-[var(--radius-button)] bg-[var(--bg-primary)] border border-[var(--border-color)] text-[var(--text-secondary)] hover:bg-[var(--bg-hover)] transition-colors\"\r\n >\r\n <RefreshCw className=\"w-4 h-4\" />\r\n {t('common.refresh', 'Actualiser')}\r\n </button>\r\n </div>\r\n\r\n {!history && (\r\n <div className=\"flex items-center justify-center py-12\">\r\n <Loader2 className=\"w-6 h-6 animate-spin text-[var(--color-accent-500)]\" />\r\n </div>\r\n )}\r\n {history && (!Array.isArray(history) || history.length === 0) && (\r\n <div className=\"text-center py-12\">\r\n <History className=\"w-12 h-12 mx-auto mb-4 text-[var(--text-tertiary)]\" />\r\n <p className=\"text-[var(--text-secondary)]\">\r\n {t('userDetail.history.noHistory', 'Aucun historique de modification')}\r\n </p>\r\n </div>\r\n )}\r\n {history && Array.isArray(history) && history.length > 0 && (\r\n <div className=\"relative\">\r\n {/* Timeline line */}\r\n <div className=\"absolute left-4 top-0 bottom-0 w-0.5 bg-[var(--border-color)]\" />\r\n\r\n {/* Timeline entries */}\r\n <div className=\"space-y-4\">\r\n {history.map((entry) => (\r\n <div key={entry.id} className=\"relative pl-10\">\r\n {/* Timeline dot */}\r\n <div className=\"absolute left-2 top-2 w-5 h-5 rounded-full bg-[var(--bg-secondary)] border-2 border-[var(--color-accent-500)] flex items-center justify-center\">\r\n {getActionIcon(entry.actionName)}\r\n </div>\r\n\r\n {/* Entry card */}\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--bg-primary)] border border-[var(--border-color)]\">\r\n <div className=\"flex items-start justify-between gap-4\">\r\n <div className=\"flex-1\">\r\n <div className=\"flex items-center gap-2 mb-1\">\r\n <span className=\"font-medium text-[var(--text-primary)]\">\r\n {getActionLabel(entry.actionName)}\r\n </span>\r\n {entry.fieldChanged && (\r\n <span className=\"px-2 py-0.5 rounded-[var(--radius-badge)] text-xs bg-[var(--bg-tertiary)] text-[var(--text-secondary)]\">\r\n {entry.fieldChanged}\r\n </span>\r\n )}\r\n </div>\r\n\r\n {(entry.oldValue || entry.newValue) && (\r\n <div className=\"text-sm text-[var(--text-secondary)] mt-2\">\r\n {entry.oldValue && (\r\n <span className=\"inline-flex items-center gap-1\">\r\n <span className=\"text-red-500 line-through\">{entry.oldValue}</span>\r\n </span>\r\n )}\r\n {entry.oldValue && entry.newValue && (\r\n <span className=\"mx-2\">→</span>\r\n )}\r\n {entry.newValue && (\r\n <span className=\"text-green-500\">{entry.newValue}</span>\r\n )}\r\n </div>\r\n )}\r\n\r\n <div className=\"flex items-center gap-4 mt-2 text-xs text-[var(--text-tertiary)]\">\r\n <span>{formatDate(entry.createdAt)}</span>\r\n {entry.changedByUserName && (\r\n <span className=\"flex items-center gap-1\">\r\n <User className=\"w-3 h-3\" />\r\n {entry.changedByUserName}\r\n </span>\r\n )}\r\n </div>\r\n </div>\r\n\r\n {/* Restore button */}\r\n {isRestorable(entry) && (\r\n <button\r\n onClick={() => handleRestoreField(entry.id)}\r\n disabled={restoringHistoryId === entry.id || !canUpdate}\r\n className={`flex items-center gap-1.5 px-3 py-1.5 rounded-[var(--radius-button)] text-xs font-medium transition-colors disabled:opacity-50 ${!canUpdate ? 'bg-[var(--bg-secondary)] text-[var(--text-tertiary)] cursor-not-allowed' : 'bg-[var(--bg-secondary)] text-[var(--text-secondary)] hover:bg-[var(--color-accent-500)]/10 hover:text-[var(--color-accent-600)]'}`}\r\n title={!canUpdate ? t('common.noPermission', 'Permission insuffisante') : t('userDetail.history.restore', 'Restaurer cette valeur')}\r\n >\r\n {restoringHistoryId === entry.id ? (\r\n <Loader2 className=\"w-3.5 h-3.5 animate-spin\" />\r\n ) : (\r\n <RotateCcw className=\"w-3.5 h-3.5\" />\r\n )}\r\n {t('userDetail.history.restore', 'Restaurer')}\r\n </button>\r\n )}\r\n </div>\r\n </div>\r\n </div>\r\n ))}\r\n </div>\r\n </div>\r\n )}\r\n </div>\r\n );\r\n}\r\n","import { useState, useEffect, useCallback, useMemo } from 'react';\r\nimport type { ReactElement } from 'react';\r\nimport { useTranslation } from 'react-i18next';\r\nimport * as LucideIcons from 'lucide-react';\r\nimport {\r\n Boxes,\r\n Loader2,\r\n ChevronDown,\r\n ChevronRight,\r\n Shield,\r\n Key,\r\n Layers,\r\n RefreshCw,\r\n Building2,\r\n Filter,\r\n} from 'lucide-react';\r\nimport type { LucideIcon } from 'lucide-react';\r\nimport { adminApi, type UserApplicationAccessDto, type UserTenantDto } from '@/services/api/adminApi';\r\n\r\ninterface UserApplicationsTabProps {\r\n readonly userId: string;\r\n}\r\n\r\nexport function UserApplicationsTab({ userId }: UserApplicationsTabProps): ReactElement {\r\n const { t } = useTranslation('admin');\r\n const [applications, setApplications] = useState<UserApplicationAccessDto[]>([]);\r\n const [tenants, setTenants] = useState<UserTenantDto[]>([]);\r\n const [selectedTenantId, setSelectedTenantId] = useState<string | undefined>(undefined);\r\n const [loading, setLoading] = useState(true);\r\n const [tenantsLoading, setTenantsLoading] = useState(true);\r\n const [error, setError] = useState<string | null>(null);\r\n const [expandedApps, setExpandedApps] = useState<Set<string>>(new Set());\r\n\r\n const loadTenants = useCallback(async () => {\r\n setTenantsLoading(true);\r\n try {\r\n const data = await adminApi.users.getTenants(userId);\r\n setTenants(data);\r\n } catch {\r\n setTenants([]);\r\n } finally {\r\n setTenantsLoading(false);\r\n }\r\n }, [userId]);\r\n\r\n const loadApplicationAccess = useCallback(async () => {\r\n setLoading(true);\r\n setError(null);\r\n try {\r\n const data = await adminApi.users.getApplicationAccess(userId, selectedTenantId);\r\n setApplications(data);\r\n } catch (err) {\r\n setApplications([]);\r\n setError(err instanceof Error ? err.message : t('userDetail.applications.loadError'));\r\n } finally {\r\n setLoading(false);\r\n }\r\n }, [userId, selectedTenantId, t]);\r\n\r\n useEffect(() => {\r\n loadTenants();\r\n }, [loadTenants]);\r\n\r\n useEffect(() => {\r\n loadApplicationAccess();\r\n }, [loadApplicationAccess]);\r\n\r\n const toggleExpand = (appId: string) => {\r\n setExpandedApps(prev => {\r\n const next = new Set(prev);\r\n if (next.has(appId)) next.delete(appId);\r\n else next.add(appId);\r\n return next;\r\n });\r\n };\r\n\r\n const selectedTenantName = useMemo(() => {\r\n if (!selectedTenantId) return null;\r\n return tenants.find(t => t.id === selectedTenantId)?.name ?? null;\r\n }, [selectedTenantId, tenants]);\r\n\r\n return (\r\n <div className=\"space-y-6\">\r\n {/* Header with tenant filter */}\r\n <div className=\"flex items-center justify-between gap-4\">\r\n <h3 className=\"text-lg font-semibold text-[var(--text-primary)]\">\r\n {t('userDetail.applications.title')}\r\n </h3>\r\n <div className=\"flex items-center gap-2\">\r\n {/* Tenant filter */}\r\n {!tenantsLoading && tenants.length > 0 && (\r\n <div className=\"flex items-center gap-2\">\r\n <Filter className=\"w-4 h-4 text-[var(--text-muted)]\" />\r\n <select\r\n value={selectedTenantId ?? ''}\r\n onChange={(e) => setSelectedTenantId(e.target.value || undefined)}\r\n className=\"text-sm border border-[var(--border-color)] rounded-[var(--radius-button)] bg-[var(--bg-card)] text-[var(--text-primary)] px-3 py-1.5 focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]/30\"\r\n >\r\n <option value=\"\">{t('userDetail.applications.allTenants')}</option>\r\n {tenants.map(tenant => (\r\n <option key={tenant.id} value={tenant.id}>\r\n {tenant.name}\r\n </option>\r\n ))}\r\n </select>\r\n </div>\r\n )}\r\n <button\r\n onClick={() => void loadApplicationAccess()}\r\n className=\"p-2 rounded-[var(--radius-button)] text-[var(--text-secondary)] hover:bg-[var(--bg-hover)]\"\r\n title={t('common:refresh', 'Refresh')}\r\n >\r\n <RefreshCw className=\"w-4 h-4\" />\r\n </button>\r\n </div>\r\n </div>\r\n\r\n {/* Active filter indicator */}\r\n {selectedTenantName && (\r\n <div className=\"flex items-center gap-2 px-3 py-2 rounded-[var(--radius-button)] bg-[var(--color-accent-500)]/5 border border-[var(--color-accent-500)]/20 text-sm text-[var(--color-accent-600)]\">\r\n <Building2 className=\"w-4 h-4\" />\r\n {t('userDetail.applications.filteredByTenant', { tenant: selectedTenantName })}\r\n </div>\r\n )}\r\n\r\n {/* Loading state */}\r\n {loading ? (\r\n <div className=\"flex items-center justify-center py-12\">\r\n <Loader2 className=\"w-8 h-8 animate-spin text-[var(--color-accent-500)]\" />\r\n </div>\r\n ) : error ? (\r\n <div className=\"text-center py-12 text-[var(--error-text)]\">\r\n <Boxes className=\"w-12 h-12 mx-auto mb-4 text-[var(--error-text)] opacity-50\" />\r\n <p>{error}</p>\r\n </div>\r\n ) : applications.length === 0 ? (\r\n <div className=\"text-center py-12 text-[var(--text-secondary)]\">\r\n <Boxes className=\"w-12 h-12 mx-auto mb-4 text-[var(--text-tertiary)]\" />\r\n <p>{t('userDetail.applications.noAccess')}</p>\r\n </div>\r\n ) : (\r\n /* Application list */\r\n <div className=\"space-y-2\">\r\n {applications.map(app => (\r\n <ApplicationCard\r\n key={app.applicationId}\r\n app={app}\r\n isExpanded={expandedApps.has(app.applicationId)}\r\n onToggle={() => toggleExpand(app.applicationId)}\r\n />\r\n ))}\r\n </div>\r\n )}\r\n </div>\r\n );\r\n}\r\n\r\nfunction ApplicationCard({\r\n app,\r\n isExpanded,\r\n onToggle,\r\n}: {\r\n app: UserApplicationAccessDto;\r\n isExpanded: boolean;\r\n onToggle: () => void;\r\n}) {\r\n const { t } = useTranslation('admin');\r\n const icons = LucideIcons as unknown as Record<string, LucideIcon>;\r\n const AppIcon = app.icon ? icons[app.icon] : null;\r\n\r\n // Group permissions by module\r\n const permissionsByModule = useMemo(() => {\r\n const groups: Record<string, { moduleName: string; permissions: typeof app.permissions }> = {};\r\n for (const perm of app.permissions) {\r\n const key = perm.moduleName || '_global';\r\n if (!groups[key]) {\r\n groups[key] = { moduleName: perm.moduleName || t('userDetail.applications.globalPermissions'), permissions: [] };\r\n }\r\n groups[key].permissions.push(perm);\r\n }\r\n return Object.values(groups);\r\n }, [app.permissions, t]);\r\n\r\n return (\r\n <div className=\"border border-[var(--border-color)] rounded-[var(--radius-card)] bg-[var(--bg-card)] overflow-hidden\">\r\n {/* Card header - clickable */}\r\n <button\r\n onClick={onToggle}\r\n className=\"w-full flex items-center gap-3 p-4 text-left hover:bg-[var(--bg-hover)] transition-colors\"\r\n >\r\n {isExpanded ? (\r\n <ChevronDown className=\"w-4 h-4 text-[var(--text-muted)] flex-shrink-0\" />\r\n ) : (\r\n <ChevronRight className=\"w-4 h-4 text-[var(--text-muted)] flex-shrink-0\" />\r\n )}\r\n\r\n {/* App icon */}\r\n <div className=\"w-9 h-9 rounded-[var(--radius-button)] bg-[var(--color-accent-500)]/10 flex items-center justify-center flex-shrink-0\">\r\n {AppIcon ? (\r\n <AppIcon className=\"w-5 h-5 text-[var(--color-accent-600)]\" />\r\n ) : (\r\n <Layers className=\"w-5 h-5 text-[var(--color-accent-600)]\" />\r\n )}\r\n </div>\r\n\r\n {/* App info */}\r\n <div className=\"flex-1 min-w-0\">\r\n <p className=\"font-medium text-[var(--text-primary)] truncate\">{app.applicationLabel}</p>\r\n <p className=\"text-xs text-[var(--text-muted)] truncate\">{app.applicationCode}</p>\r\n </div>\r\n\r\n {/* Access badge */}\r\n {app.hasFullAccess ? (\r\n <span className=\"px-2.5 py-1 text-xs font-medium rounded-full bg-green-500/10 text-green-600 border border-green-500/20 flex-shrink-0\">\r\n {t('userDetail.applications.fullAccess')}\r\n </span>\r\n ) : (\r\n <span className=\"px-2.5 py-1 text-xs font-medium rounded-full bg-[var(--color-accent-500)]/10 text-[var(--color-accent-600)] border border-[var(--color-accent-500)]/20 flex-shrink-0\">\r\n {t('userDetail.applications.permissionCount', { count: app.permissions.length })}\r\n </span>\r\n )}\r\n\r\n {/* Roles count */}\r\n <span className=\"text-xs text-[var(--text-muted)] flex items-center gap-1 flex-shrink-0\">\r\n <Shield className=\"w-3.5 h-3.5\" />\r\n {app.roles.length}\r\n </span>\r\n </button>\r\n\r\n {/* Expanded content */}\r\n {isExpanded && (\r\n <div className=\"border-t border-[var(--border-color)] p-4 space-y-4 bg-[var(--bg-secondary)]\">\r\n {/* Roles section */}\r\n <div>\r\n <h5 className=\"text-xs font-medium text-[var(--text-muted)] uppercase tracking-wider mb-2\">\r\n {t('userDetail.applications.rolesGrantingAccess')}\r\n </h5>\r\n <div className=\"flex flex-wrap gap-2\">\r\n {app.roles.map(role => (\r\n <span\r\n key={role.roleId}\r\n className=\"inline-flex items-center gap-1.5 px-2.5 py-1 text-xs rounded-full bg-[var(--bg-card)] border border-[var(--border-color)] text-[var(--text-primary)]\"\r\n >\r\n <Shield className=\"w-3 h-3 text-[var(--color-accent-500)]\" />\r\n {role.roleName}\r\n {role.source === 'Group' && (\r\n <span className=\"text-[var(--text-tertiary)]\">\r\n ({t('userDetail.applications.viaGroup')})\r\n </span>\r\n )}\r\n </span>\r\n ))}\r\n </div>\r\n </div>\r\n\r\n {/* Permissions section */}\r\n {!app.hasFullAccess && app.permissions.length > 0 && (\r\n <div>\r\n <h5 className=\"text-xs font-medium text-[var(--text-muted)] uppercase tracking-wider mb-2\">\r\n {t('userDetail.applications.permissionsDetail')}\r\n </h5>\r\n <div className=\"space-y-3\">\r\n {permissionsByModule.map(group => (\r\n <div key={group.moduleName}>\r\n <p className=\"text-xs font-medium text-[var(--text-secondary)] mb-1\">{group.moduleName}</p>\r\n <div className=\"flex flex-wrap gap-1.5\">\r\n {group.permissions.map(perm => (\r\n <span\r\n key={perm.path}\r\n className=\"inline-flex items-center gap-1 px-2 py-0.5 text-xs rounded bg-[var(--bg-card)] border border-[var(--border-color)] text-[var(--text-secondary)]\"\r\n >\r\n <Key className=\"w-2.5 h-2.5 text-[var(--text-tertiary)]\" />\r\n {perm.action || extractActionFromPath(perm.path)}\r\n </span>\r\n ))}\r\n </div>\r\n </div>\r\n ))}\r\n </div>\r\n </div>\r\n )}\r\n\r\n {app.hasFullAccess && (\r\n <p className=\"text-xs text-green-600 italic\">\r\n {t('userDetail.applications.fullAccessDescription')}\r\n </p>\r\n )}\r\n </div>\r\n )}\r\n </div>\r\n );\r\n}\r\n\r\n/** Extract the last segment of a permission path as the action name */\r\nfunction extractActionFromPath(path: string): string {\r\n const parts = path.split('.');\r\n return parts.at(-1)!;\r\n}\r\n","import { useState, useCallback, useEffect, useMemo } from 'react';\r\nimport { useTranslation } from 'react-i18next';\r\nimport {\r\n adminApi,\r\n createAdminApi,\r\n type UserDetailDto,\r\n type RoleListDto,\r\n type UpdateUserRequest,\r\n type UserSessionsDto,\r\n type UserActivityDto,\r\n type UserHistoryDto,\r\n type OrganizationReferencesDto,\r\n type UserTenantDto,\r\n type TenantListDto\r\n} from '@/services/api/adminApi';\r\n\r\nconst isValidGuid = (value: string | undefined): boolean => {\r\n if (!value) return false;\r\n const guidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\r\n return guidRegex.test(value);\r\n};\r\n\r\nexport interface UseUserDetailOptions {\r\n userId: string | undefined;\r\n tenantSlug?: string | null;\r\n}\r\n\r\nexport interface UserFormData {\r\n firstName: string;\r\n lastName: string;\r\n email: string;\r\n roleIds: string[];\r\n}\r\n\r\nexport interface UseUserDetailReturn {\r\n // Core state\r\n user: UserDetailDto | null;\r\n formData: UserFormData;\r\n setFormData: React.Dispatch<React.SetStateAction<UserFormData>>;\r\n isCreateMode: boolean;\r\n loading: boolean;\r\n error: string | null;\r\n success: string | null;\r\n setError: (error: string | null) => void;\r\n setSuccess: (success: string | null) => void;\r\n\r\n // Data loading states\r\n roles: RoleListDto[] | null;\r\n rolesLoading: boolean;\r\n sessions: UserSessionsDto | null;\r\n activity: UserActivityDto | null;\r\n history: UserHistoryDto[] | null;\r\n orgReferences: OrganizationReferencesDto | null;\r\n userTenants: UserTenantDto[] | null;\r\n allTenants: TenantListDto[] | null;\r\n\r\n // Load functions\r\n loadUser: (silent?: boolean) => Promise<void>;\r\n loadRoles: () => Promise<void>;\r\n loadOrgReferences: () => Promise<void>;\r\n loadSessions: () => Promise<void>;\r\n loadActivity: () => Promise<void>;\r\n loadHistory: () => Promise<void>;\r\n loadTenants: () => Promise<void>;\r\n loadAllTenants: () => Promise<void>;\r\n\r\n // State setters for external updates\r\n setHistory: React.Dispatch<React.SetStateAction<UserHistoryDto[] | null>>;\r\n setUserTenants: React.Dispatch<React.SetStateAction<UserTenantDto[] | null>>;\r\n\r\n // Actions\r\n handleSaveInfo: (e: React.FormEvent) => Promise<void>;\r\n saving: boolean;\r\n}\r\n\r\nexport function useUserDetail({ userId, tenantSlug }: UseUserDetailOptions): UseUserDetailReturn {\r\n const { t } = useTranslation('admin');\r\n const isCreateMode = !isValidGuid(userId);\r\n\r\n // Create tenant-aware API instance for sessions/activity\r\n const tenantApi = useMemo(\r\n () => tenantSlug ? createAdminApi(tenantSlug) : adminApi,\r\n [tenantSlug]\r\n );\r\n\r\n // Core state\r\n const [user, setUser] = useState<UserDetailDto | null>(null);\r\n const [loading, setLoading] = useState(true);\r\n const [saving, setSaving] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n const [success, setSuccess] = useState<string | null>(null);\r\n\r\n // Form state\r\n const [formData, setFormData] = useState<UserFormData>({\r\n firstName: '',\r\n lastName: '',\r\n email: '',\r\n roleIds: []\r\n });\r\n\r\n // Related data states\r\n const [roles, setRoles] = useState<RoleListDto[] | null>(null);\r\n const [rolesLoading, setRolesLoading] = useState(false);\r\n const [sessions, setSessions] = useState<UserSessionsDto | null>(null);\r\n const [activity, setActivity] = useState<UserActivityDto | null>(null);\r\n const [history, setHistory] = useState<UserHistoryDto[] | null>(null);\r\n const [orgReferences, setOrgReferences] = useState<OrganizationReferencesDto | null>(null);\r\n const [userTenants, setUserTenants] = useState<UserTenantDto[] | null>(null);\r\n const [allTenants, setAllTenants] = useState<TenantListDto[] | null>(null);\r\n\r\n // Load user data\r\n const loadUser = useCallback(async (silent = false) => {\r\n if (!userId || isCreateMode) return;\r\n try {\r\n if (!silent) setLoading(true);\r\n const userData = await adminApi.users.getById(userId);\r\n setUser(userData);\r\n setFormData({\r\n firstName: userData.firstName,\r\n lastName: userData.lastName,\r\n email: userData.email,\r\n roleIds: userData.roles.map(r => r.id)\r\n });\r\n } catch (err) {\r\n console.error('Failed to load user:', err);\r\n setError(t('userDetail.errors.loadFailed'));\r\n } finally {\r\n if (!silent) setLoading(false);\r\n }\r\n }, [userId, isCreateMode, t]);\r\n\r\n // Load roles\r\n const loadRoles = useCallback(async () => {\r\n try {\r\n setRolesLoading(true);\r\n const result = await adminApi.roles.getAssignable();\r\n setRoles(Array.isArray(result) ? result : []);\r\n } catch (err) {\r\n console.error('Failed to load roles:', err);\r\n setRoles([]);\r\n } finally {\r\n setRolesLoading(false);\r\n }\r\n }, []);\r\n\r\n // Load organization references\r\n const loadOrgReferences = useCallback(async () => {\r\n try {\r\n const data = await adminApi.users.getOrganizationReferences();\r\n setOrgReferences(data);\r\n } catch (err) {\r\n console.error('Failed to load organization references:', err);\r\n }\r\n }, []);\r\n\r\n // Load sessions (tenant-filtered when tenant context is active)\r\n const loadSessions = useCallback(async () => {\r\n if (!userId || isCreateMode) return;\r\n try {\r\n const data = await tenantApi.users.getSessions(userId);\r\n setSessions(data);\r\n } catch (err) {\r\n console.error('Failed to load sessions:', err);\r\n }\r\n }, [userId, isCreateMode, tenantApi]);\r\n\r\n // Load activity (tenant-filtered when tenant context is active)\r\n const loadActivity = useCallback(async () => {\r\n if (!userId || isCreateMode) return;\r\n try {\r\n const data = await tenantApi.users.getActivity(userId);\r\n setActivity(data);\r\n } catch (err) {\r\n console.error('Failed to load activity:', err);\r\n }\r\n }, [userId, isCreateMode, tenantApi]);\r\n\r\n // Load history\r\n const loadHistory = useCallback(async () => {\r\n if (!userId || isCreateMode) return;\r\n try {\r\n const data = await adminApi.users.getHistory(userId, 100);\r\n setHistory(data);\r\n } catch (err) {\r\n console.error('Failed to load history:', err);\r\n setHistory([]);\r\n }\r\n }, [userId, isCreateMode]);\r\n\r\n // Load tenants\r\n const loadTenants = useCallback(async () => {\r\n if (!userId || isCreateMode) return;\r\n try {\r\n const data = await adminApi.users.getTenants(userId);\r\n setUserTenants(data);\r\n } catch (err) {\r\n console.error('Failed to load tenants:', err);\r\n setUserTenants([]);\r\n }\r\n }, [userId, isCreateMode]);\r\n\r\n // Load all tenants for adding\r\n const loadAllTenants = useCallback(async () => {\r\n try {\r\n const result = await adminApi.tenants.getAll({ status: 'Active' });\r\n setAllTenants(result.items);\r\n } catch (err) {\r\n console.error('Failed to load all tenants:', err);\r\n setAllTenants([]);\r\n }\r\n }, []);\r\n\r\n // Handle save info\r\n const handleSaveInfo = useCallback(async (e: React.FormEvent) => {\r\n e.preventDefault();\r\n if (!userId) return;\r\n\r\n setSaving(true);\r\n setError(null);\r\n setSuccess(null);\r\n\r\n try {\r\n const updateData: UpdateUserRequest = {\r\n firstName: formData.firstName,\r\n lastName: formData.lastName,\r\n email: formData.email !== user?.email ? formData.email : undefined,\r\n roleIds: formData.roleIds\r\n };\r\n await adminApi.users.update(userId, updateData);\r\n setSuccess(t('userDetail.success.infoSaved'));\r\n await loadUser();\r\n } catch (err: unknown) {\r\n setError(err instanceof Error ? err.message : t('userDetail.errors.saveFailed'));\r\n } finally {\r\n setSaving(false);\r\n }\r\n }, [userId, formData, user?.email, t, loadUser]);\r\n\r\n // Initial load\r\n useEffect(() => {\r\n loadUser();\r\n }, [loadUser]);\r\n\r\n return {\r\n user,\r\n formData,\r\n setFormData,\r\n isCreateMode,\r\n loading,\r\n error,\r\n success,\r\n setError,\r\n setSuccess,\r\n roles,\r\n rolesLoading,\r\n sessions,\r\n activity,\r\n history,\r\n orgReferences,\r\n userTenants,\r\n allTenants,\r\n loadUser,\r\n loadRoles,\r\n loadOrgReferences,\r\n loadSessions,\r\n loadActivity,\r\n loadHistory,\r\n loadTenants,\r\n loadAllTenants,\r\n setHistory,\r\n setUserTenants,\r\n handleSaveInfo,\r\n saving\r\n };\r\n}\r\n","import { useState, useCallback } from 'react';\r\nimport { useTranslation } from 'react-i18next';\r\nimport { adminApi, UnlockReason } from '@/services/api/adminApi';\r\n\r\nexport interface UseUserSecurityOptions {\r\n userId: string | undefined;\r\n onUserReload: () => Promise<void>;\r\n onSessionsReload: () => Promise<void>;\r\n setError: (error: string | null) => void;\r\n setSuccess: (success: string | null) => void;\r\n}\r\n\r\nexport interface UseUserSecurityReturn {\r\n // Password state\r\n newPassword: string;\r\n setNewPassword: (password: string) => void;\r\n temporaryPassword: string | null;\r\n showTemporaryPassword: boolean;\r\n setShowTemporaryPassword: (show: boolean) => void;\r\n\r\n // Modal state\r\n showUnlockModal: boolean;\r\n setShowUnlockModal: (show: boolean) => void;\r\n\r\n // Actions\r\n handleSendResetLink: () => Promise<void>;\r\n handleResetPasswordDirect: () => Promise<void>;\r\n handleToggleStatus: (isActive: boolean) => Promise<void>;\r\n handleEndSession: (sessionId: string) => Promise<void>;\r\n handleEndAllSessions: () => Promise<void>;\r\n handleUnlock: (reason: UnlockReason, mustChangePassword: boolean) => Promise<void>;\r\n handleClearFailedAttempts: () => Promise<void>;\r\n copyToClipboard: (text: string) => Promise<void>;\r\n\r\n // Loading state\r\n saving: boolean;\r\n}\r\n\r\nexport function useUserSecurity({\r\n userId,\r\n onUserReload,\r\n onSessionsReload,\r\n setError,\r\n setSuccess\r\n}: UseUserSecurityOptions): UseUserSecurityReturn {\r\n const { t } = useTranslation('admin');\r\n\r\n // Password state\r\n const [newPassword, setNewPassword] = useState('');\r\n const [temporaryPassword, setTemporaryPassword] = useState<string | null>(null);\r\n const [showTemporaryPassword, setShowTemporaryPassword] = useState(false);\r\n const [saving, setSaving] = useState(false);\r\n\r\n // Modal state\r\n const [showUnlockModal, setShowUnlockModal] = useState(false);\r\n\r\n // Send reset link\r\n const handleSendResetLink = useCallback(async () => {\r\n if (!userId) return;\r\n\r\n setSaving(true);\r\n setError(null);\r\n setSuccess(null);\r\n setTemporaryPassword(null);\r\n\r\n try {\r\n await adminApi.users.sendPasswordResetLink(userId);\r\n setSuccess(t('userDetail.success.resetLinkSent', 'Lien de réinitialisation envoyé par email'));\r\n } catch (err: unknown) {\r\n setError(err instanceof Error ? err.message : t('userDetail.errors.sendResetLinkFailed', 'Échec de l\\'envoi du lien'));\r\n } finally {\r\n setSaving(false);\r\n }\r\n }, [userId, setError, setSuccess, t]);\r\n\r\n // Direct password reset\r\n const handleResetPasswordDirect = useCallback(async () => {\r\n if (!userId) return;\r\n\r\n setSaving(true);\r\n setError(null);\r\n setSuccess(null);\r\n\r\n try {\r\n const customPassword = newPassword.trim() || undefined;\r\n const result = await adminApi.users.resetPasswordDirect(userId, customPassword);\r\n setTemporaryPassword(result.temporaryPassword);\r\n setNewPassword('');\r\n setShowTemporaryPassword(true);\r\n setSuccess(t('userDetail.success.passwordResetDirect', 'Mot de passe réinitialisé. Communiquez le mot de passe temporaire à l\\'utilisateur.'));\r\n } catch (err: unknown) {\r\n setError(err instanceof Error ? err.message : t('userDetail.errors.passwordResetFailed'));\r\n } finally {\r\n setSaving(false);\r\n }\r\n }, [userId, newPassword, setError, setSuccess, t]);\r\n\r\n // Toggle user active status\r\n const handleToggleStatus = useCallback(async (isActive: boolean) => {\r\n if (!userId) return;\r\n\r\n try {\r\n if (isActive) {\r\n await adminApi.users.deactivate(userId);\r\n } else {\r\n await adminApi.users.activate(userId);\r\n }\r\n await onUserReload();\r\n setSuccess(isActive ? t('userDetail.success.deactivated') : t('userDetail.success.activated'));\r\n } catch {\r\n setError(t('userDetail.errors.statusChangeFailed'));\r\n }\r\n }, [userId, onUserReload, setError, setSuccess, t]);\r\n\r\n // End single session\r\n const handleEndSession = useCallback(async (sessionId: string) => {\r\n if (!userId) return;\r\n\r\n try {\r\n await adminApi.users.endSession(userId, sessionId);\r\n await onSessionsReload();\r\n setSuccess(t('userDetail.success.sessionEnded'));\r\n } catch {\r\n setError(t('userDetail.errors.endSessionFailed'));\r\n }\r\n }, [userId, onSessionsReload, setError, setSuccess, t]);\r\n\r\n // End all sessions\r\n const handleEndAllSessions = useCallback(async () => {\r\n if (!userId) return;\r\n if (!confirm(t('userDetail.confirmEndAllSessions'))) return;\r\n\r\n try {\r\n await adminApi.users.endAllSessions(userId);\r\n await onSessionsReload();\r\n setSuccess(t('userDetail.success.allSessionsEnded'));\r\n } catch {\r\n setError(t('userDetail.errors.endAllSessionsFailed'));\r\n }\r\n }, [userId, onSessionsReload, setError, setSuccess, t]);\r\n\r\n // Unlock account\r\n const handleUnlock = useCallback(async (reason: UnlockReason, mustChangePassword: boolean) => {\r\n if (!userId) return;\r\n\r\n try {\r\n await adminApi.users.unlock(userId, { reason, mustChangePassword });\r\n await onUserReload();\r\n setSuccess(t('userDetail.success.unlocked'));\r\n } catch {\r\n setError(t('userDetail.errors.unlockFailed'));\r\n }\r\n }, [userId, onUserReload, setError, setSuccess, t]);\r\n\r\n // Clear failed attempts\r\n const handleClearFailedAttempts = useCallback(async () => {\r\n if (!userId) return;\r\n\r\n try {\r\n await adminApi.users.clearFailedAttempts(userId);\r\n await onUserReload();\r\n setSuccess('Tentatives échouées réinitialisées avec succès');\r\n } catch {\r\n setError('Échec de la réinitialisation des tentatives échouées');\r\n }\r\n }, [userId, onUserReload, setError, setSuccess]);\r\n\r\n // Copy to clipboard\r\n const copyToClipboard = useCallback(async (text: string) => {\r\n try {\r\n await navigator.clipboard.writeText(text);\r\n setSuccess(t('userDetail.success.copied', 'Mot de passe copié dans le presse-papiers'));\r\n } catch {\r\n setError(t('userDetail.errors.copyFailed', 'Échec de la copie'));\r\n }\r\n }, [setError, setSuccess, t]);\r\n\r\n return {\r\n newPassword,\r\n setNewPassword,\r\n temporaryPassword,\r\n showTemporaryPassword,\r\n setShowTemporaryPassword,\r\n showUnlockModal,\r\n setShowUnlockModal,\r\n handleSendResetLink,\r\n handleResetPasswordDirect,\r\n handleToggleStatus,\r\n handleEndSession,\r\n handleEndAllSessions,\r\n handleUnlock,\r\n handleClearFailedAttempts,\r\n copyToClipboard,\r\n saving\r\n };\r\n}\r\n","import { useState, useCallback } from 'react';\r\nimport { useTranslation } from 'react-i18next';\r\nimport { adminApi, type UserDetailDto } from '@/services/api/adminApi';\r\nimport type { SelectWithOtherValue } from '@/components/ui/SelectWithOther';\r\n\r\nexport type SectionType = 'phones' | 'address' | 'jobInfo' | 'organization';\r\n\r\nexport interface PhonesSectionData {\r\n phoneNumber: string;\r\n mobilePhone: string;\r\n faxNumber: string;\r\n}\r\n\r\nexport interface AddressSectionData {\r\n streetAddress: string;\r\n city: string;\r\n state: string;\r\n postalCode: string;\r\n country: string;\r\n}\r\n\r\nexport interface JobInfoSectionData {\r\n employeeId: string;\r\n employeeType: string;\r\n employeeHireDate: string;\r\n employeeOrgData: string;\r\n}\r\n\r\nexport interface OrganizationSectionData {\r\n company: SelectWithOtherValue;\r\n department: SelectWithOtherValue;\r\n jobTitle: SelectWithOtherValue;\r\n office: SelectWithOtherValue;\r\n managerId: string;\r\n}\r\n\r\nexport interface SectionData {\r\n phones: PhonesSectionData;\r\n address: AddressSectionData;\r\n jobInfo: JobInfoSectionData;\r\n organization: OrganizationSectionData;\r\n}\r\n\r\nexport interface UseUserSectionsOptions {\r\n userId: string | undefined;\r\n user: UserDetailDto | null;\r\n onUserReload: () => Promise<void>;\r\n onHistoryReload: () => void;\r\n setError: (error: string | null) => void;\r\n setSuccess: (success: string | null) => void;\r\n}\r\n\r\nexport interface UseUserSectionsReturn {\r\n editingSection: string | null;\r\n sectionData: SectionData;\r\n setSectionData: React.Dispatch<React.SetStateAction<SectionData>>;\r\n startEditingSection: (section: SectionType) => void;\r\n cancelEditing: () => void;\r\n handleSaveSection: (section: SectionType) => Promise<void>;\r\n saving: boolean;\r\n}\r\n\r\nconst createInitialSectionData = (): SectionData => ({\r\n phones: { phoneNumber: '', mobilePhone: '', faxNumber: '' },\r\n address: { streetAddress: '', city: '', state: '', postalCode: '', country: '' },\r\n jobInfo: { employeeId: '', employeeType: '', employeeHireDate: '', employeeOrgData: '' },\r\n organization: {\r\n company: { id: '', customValue: undefined },\r\n department: { id: '', customValue: undefined },\r\n jobTitle: { id: '', customValue: undefined },\r\n office: { id: '', customValue: undefined },\r\n managerId: ''\r\n }\r\n});\r\n\r\nexport function useUserSections({\r\n userId,\r\n user,\r\n onUserReload,\r\n onHistoryReload,\r\n setError,\r\n setSuccess\r\n}: UseUserSectionsOptions): UseUserSectionsReturn {\r\n const { t } = useTranslation('admin');\r\n\r\n const [editingSection, setEditingSection] = useState<string | null>(null);\r\n const [sectionData, setSectionData] = useState<SectionData>(createInitialSectionData);\r\n const [saving, setSaving] = useState(false);\r\n\r\n // Start editing a section\r\n const startEditingSection = useCallback((section: SectionType) => {\r\n if (!user) return;\r\n setEditingSection(section);\r\n\r\n setSectionData(prev => {\r\n switch (section) {\r\n case 'phones':\r\n return {\r\n ...prev,\r\n phones: {\r\n phoneNumber: user.phoneNumber || '',\r\n mobilePhone: user.mobilePhone || '',\r\n faxNumber: user.faxNumber || ''\r\n }\r\n };\r\n case 'address':\r\n return {\r\n ...prev,\r\n address: {\r\n streetAddress: user.streetAddress || '',\r\n city: user.city || '',\r\n state: user.state || '',\r\n postalCode: user.postalCode || '',\r\n country: user.country || ''\r\n }\r\n };\r\n case 'jobInfo':\r\n return {\r\n ...prev,\r\n jobInfo: {\r\n employeeId: user.employeeId || '',\r\n employeeType: user.employeeType || '',\r\n employeeHireDate: user.employeeHireDate?.split('T')[0] || '',\r\n employeeOrgData: user.employeeOrgData || ''\r\n }\r\n };\r\n case 'organization':\r\n return {\r\n ...prev,\r\n organization: {\r\n company: { id: user.companyId || '', customValue: undefined },\r\n department: { id: user.departmentId || '', customValue: undefined },\r\n jobTitle: { id: user.jobTitleId || '', customValue: undefined },\r\n office: { id: user.officeId || '', customValue: undefined },\r\n managerId: user.managerId || ''\r\n }\r\n };\r\n default:\r\n return prev;\r\n }\r\n });\r\n }, [user]);\r\n\r\n // Cancel editing\r\n const cancelEditing = useCallback(() => {\r\n setEditingSection(null);\r\n }, []);\r\n\r\n // Save section data\r\n const handleSaveSection = useCallback(async (section: SectionType) => {\r\n if (!userId) return;\r\n\r\n setSaving(true);\r\n setError(null);\r\n setSuccess(null);\r\n\r\n try {\r\n switch (section) {\r\n case 'phones':\r\n await adminApi.users.updatePhones(userId, {\r\n phoneNumber: sectionData.phones.phoneNumber || null,\r\n mobilePhone: sectionData.phones.mobilePhone || null,\r\n faxNumber: sectionData.phones.faxNumber || null\r\n });\r\n break;\r\n\r\n case 'address':\r\n await adminApi.users.updateAddress(userId, {\r\n streetAddress: sectionData.address.streetAddress || null,\r\n city: sectionData.address.city || null,\r\n state: sectionData.address.state || null,\r\n postalCode: sectionData.address.postalCode || null,\r\n country: sectionData.address.country || null\r\n });\r\n break;\r\n\r\n case 'jobInfo':\r\n await adminApi.users.updateJobInfo(userId, {\r\n employeeId: sectionData.jobInfo.employeeId || null,\r\n employeeType: sectionData.jobInfo.employeeType || null,\r\n employeeHireDate: sectionData.jobInfo.employeeHireDate || null,\r\n employeeOrgData: sectionData.jobInfo.employeeOrgData || null\r\n });\r\n break;\r\n\r\n case 'organization': {\r\n const org = sectionData.organization;\r\n await adminApi.users.updateOrganization(userId, {\r\n companyId: org.company.customValue ? null : (org.company.id || null),\r\n companyName: org.company.customValue || null,\r\n departmentId: org.department.customValue ? null : (org.department.id || null),\r\n departmentName: org.department.customValue || null,\r\n jobTitleId: org.jobTitle.customValue ? null : (org.jobTitle.id || null),\r\n jobTitleName: org.jobTitle.customValue || null,\r\n officeId: org.office.customValue ? null : (org.office.id || null),\r\n officeName: org.office.customValue || null,\r\n managerId: org.managerId || null\r\n });\r\n break;\r\n }\r\n }\r\n\r\n setEditingSection(null);\r\n setSuccess(t('userDetail.success.sectionSaved', 'Section mise à jour avec succès'));\r\n await onUserReload();\r\n onHistoryReload();\r\n } catch (err: unknown) {\r\n setError(err instanceof Error ? err.message : t('userDetail.errors.saveFailed'));\r\n } finally {\r\n setSaving(false);\r\n }\r\n }, [userId, sectionData, onUserReload, onHistoryReload, setError, setSuccess, t]);\r\n\r\n return {\r\n editingSection,\r\n sectionData,\r\n setSectionData,\r\n startEditingSection,\r\n cancelEditing,\r\n handleSaveSection,\r\n saving\r\n };\r\n}\r\n","import { useState, useCallback, useEffect } from 'react';\r\nimport { useTranslation } from 'react-i18next';\r\nimport { adminApi, type UserTenantDto, type TenantListDto } from '@/services/api/adminApi';\r\nimport type { ViewMode } from '@/components/ui/ViewModeToggle';\r\n\r\nexport interface UseUserTenantsOptions {\r\n userId: string | undefined;\r\n isCreateMode: boolean;\r\n setError: (error: string | null) => void;\r\n setSuccess: (success: string | null) => void;\r\n}\r\n\r\nexport interface UseUserTenantsReturn {\r\n // Data\r\n userTenants: UserTenantDto[] | null;\r\n allTenants: TenantListDto[] | null;\r\n\r\n // UI state\r\n showAddTenantModal: boolean;\r\n tenantSearch: string;\r\n tenantsViewMode: ViewMode;\r\n selectedTenantIds: Set<string>;\r\n isAddingMultipleTenants: boolean;\r\n\r\n // Setters\r\n setShowAddTenantModal: (show: boolean) => void;\r\n setTenantSearch: (search: string) => void;\r\n setTenantsViewMode: (mode: ViewMode) => void;\r\n setUserTenants: React.Dispatch<React.SetStateAction<UserTenantDto[] | null>>;\r\n\r\n // Actions\r\n loadTenants: () => Promise<void>;\r\n loadAllTenants: () => Promise<void>;\r\n toggleTenantSelection: (tenantId: string) => void;\r\n selectAllTenants: (availableTenantIds: string[]) => void;\r\n clearTenantSelection: () => void;\r\n closeAddTenantModal: () => void;\r\n handleAddMultipleTenants: () => Promise<void>;\r\n handleRemoveTenant: (tenantId: string) => Promise<void>;\r\n}\r\n\r\nexport function useUserTenants({\r\n userId,\r\n isCreateMode,\r\n setError,\r\n setSuccess\r\n}: UseUserTenantsOptions): UseUserTenantsReturn {\r\n const { t } = useTranslation('admin');\r\n\r\n // Data state\r\n const [userTenants, setUserTenants] = useState<UserTenantDto[] | null>(null);\r\n const [allTenants, setAllTenants] = useState<TenantListDto[] | null>(null);\r\n\r\n // UI state\r\n const [showAddTenantModal, setShowAddTenantModal] = useState(false);\r\n const [tenantSearch, setTenantSearch] = useState('');\r\n const [tenantsViewMode, setTenantsViewMode] = useState<ViewMode>('cards');\r\n const [selectedTenantIds, setSelectedTenantIds] = useState<Set<string>>(new Set());\r\n const [isAddingMultipleTenants, setIsAddingMultipleTenants] = useState(false);\r\n\r\n // Load user tenants\r\n const loadTenants = useCallback(async () => {\r\n if (!userId || isCreateMode) return;\r\n try {\r\n const data = await adminApi.users.getTenants(userId);\r\n setUserTenants(data);\r\n } catch (err) {\r\n console.error('Failed to load tenants:', err);\r\n setUserTenants([]);\r\n }\r\n }, [userId, isCreateMode]);\r\n\r\n // Load all tenants for adding\r\n const loadAllTenants = useCallback(async () => {\r\n try {\r\n const result = await adminApi.tenants.getAll({ status: 'Active' });\r\n setAllTenants(result.items);\r\n } catch (err) {\r\n console.error('Failed to load all tenants:', err);\r\n setAllTenants([]);\r\n }\r\n }, []);\r\n\r\n // Toggle tenant selection\r\n const toggleTenantSelection = useCallback((tenantId: string) => {\r\n setSelectedTenantIds((prev) => {\r\n const newSet = new Set(prev);\r\n if (newSet.has(tenantId)) {\r\n newSet.delete(tenantId);\r\n } else {\r\n newSet.add(tenantId);\r\n }\r\n return newSet;\r\n });\r\n }, []);\r\n\r\n // Select all tenants\r\n const selectAllTenants = useCallback((availableTenantIds: string[]) => {\r\n setSelectedTenantIds(new Set(availableTenantIds));\r\n }, []);\r\n\r\n // Clear selection\r\n const clearTenantSelection = useCallback(() => {\r\n setSelectedTenantIds(new Set());\r\n }, []);\r\n\r\n // Close modal\r\n const closeAddTenantModal = useCallback(() => {\r\n setShowAddTenantModal(false);\r\n setTenantSearch('');\r\n setSelectedTenantIds(new Set());\r\n }, []);\r\n\r\n // Add multiple tenants\r\n const handleAddMultipleTenants = useCallback(async () => {\r\n if (!userId || selectedTenantIds.size === 0) return;\r\n\r\n try {\r\n setIsAddingMultipleTenants(true);\r\n setError(null);\r\n\r\n const tenantIdsArray = Array.from(selectedTenantIds);\r\n for (const tenantId of tenantIdsArray) {\r\n await adminApi.tenants.addMember(tenantId, { userId });\r\n }\r\n\r\n closeAddTenantModal();\r\n await loadTenants();\r\n setSuccess(t('userDetail.tenants.addMultipleSuccess', { count: tenantIdsArray.length, defaultValue: `${tenantIdsArray.length} tenant(s) ajouté(s) avec succès` }));\r\n setTimeout(() => setSuccess(null), 3000);\r\n } catch (err) {\r\n console.error('Failed to add tenants:', err);\r\n setError(t('userDetail.tenants.addError', 'Erreur lors de l\\'ajout du tenant'));\r\n setTimeout(() => setError(null), 3000);\r\n } finally {\r\n setIsAddingMultipleTenants(false);\r\n }\r\n }, [userId, selectedTenantIds, closeAddTenantModal, loadTenants, setError, setSuccess, t]);\r\n\r\n // Remove tenant\r\n const handleRemoveTenant = useCallback(async (tenantId: string) => {\r\n if (!userId) return;\r\n try {\r\n await adminApi.tenants.removeMember(tenantId, userId);\r\n await loadTenants();\r\n setSuccess(t('userDetail.tenants.removeSuccess', 'Tenant retiré avec succès'));\r\n setTimeout(() => setSuccess(null), 3000);\r\n } catch (err) {\r\n console.error('Failed to remove tenant:', err);\r\n setError(t('userDetail.tenants.removeError', 'Erreur lors du retrait du tenant'));\r\n setTimeout(() => setError(null), 3000);\r\n }\r\n }, [userId, loadTenants, setError, setSuccess, t]);\r\n\r\n // Load all tenants when modal opens\r\n useEffect(() => {\r\n if (showAddTenantModal && !allTenants) {\r\n loadAllTenants();\r\n }\r\n }, [showAddTenantModal, allTenants, loadAllTenants]);\r\n\r\n return {\r\n userTenants,\r\n allTenants,\r\n showAddTenantModal,\r\n tenantSearch,\r\n tenantsViewMode,\r\n selectedTenantIds,\r\n isAddingMultipleTenants,\r\n setShowAddTenantModal,\r\n setTenantSearch,\r\n setTenantsViewMode,\r\n setUserTenants,\r\n loadTenants,\r\n loadAllTenants,\r\n toggleTenantSelection,\r\n selectAllTenants,\r\n clearTenantSelection,\r\n closeAddTenantModal,\r\n handleAddMultipleTenants,\r\n handleRemoveTenant\r\n };\r\n}\r\n","import { useState, useEffect, useCallback } from 'react';\r\nimport type { ReactElement } from 'react';\r\nimport { useParams, useNavigate, useSearchParams } from 'react-router-dom';\r\nimport { useTranslation } from 'react-i18next';\r\nimport {\r\n ArrowLeft,\r\n User,\r\n Shield,\r\n Activity,\r\n Key,\r\n Loader2,\r\n AlertTriangle,\r\n CheckCircle,\r\n Users,\r\n Building2,\r\n History,\r\n AppWindow,\r\n} from 'lucide-react';\r\nimport { adminApi, type UpdateUserRequest, type UserConsolidatedRoleDto } from '@/services/api/adminApi';\r\nimport { Breadcrumb } from '@/components/ui/Breadcrumb';\r\nimport { Slot } from '@/extensions';\r\nimport { useTenant } from '@/contexts/TenantContext';\r\nimport { useAuth } from '@/contexts/AuthContext';\r\nimport { useAdminTenants } from '@/hooks/useAdminTenants';\r\nimport { type ScopeValue } from '@/components/ui/TenantScopeFilter';\r\nimport { UserRoleAssignment } from '@/components/platform/administration/UserRoleAssignment';\r\nimport { UserPermissionMatrix } from '@/components/platform/administration/permissions/UserPermissionMatrix';\r\nimport { UserGroupsTab } from '@/components/platform/administration/UserGroupsTab';\r\nimport {\r\n UserInfoTab,\r\n UserSecurityTab,\r\n UserActivitySessionsTab,\r\n UserTenantsTab,\r\n UserHistoryTab,\r\n UserApplicationsTab,\r\n} from '@/components/platform/administration/users';\r\nimport { useUserDetail } from '@/hooks/useUserDetail';\r\nimport { useUserSecurity } from '@/hooks/useUserSecurity';\r\nimport { useUserSections } from '@/hooks/useUserSections';\r\nimport { useUserTenants } from '@/hooks/useUserTenants';\r\n\r\ntype TabId = 'info' | 'security' | 'activitySessions' | 'roles' | 'permissions' | 'applications' | 'tenants' | 'groups' | 'history';\r\n\r\nconst VALID_TABS: TabId[] = ['info', 'security', 'activitySessions', 'roles', 'permissions', 'applications', 'tenants', 'groups', 'history'];\r\n\r\nexport function UserDetailPage(): ReactElement {\r\n const { t } = useTranslation('admin');\r\n const { id: userId } = useParams<{ id: string }>();\r\n const navigate = useNavigate();\r\n const [searchParams, setSearchParams] = useSearchParams();\r\n\r\n // Tenant context\r\n const { currentTenant, hasGlobalRoles } = useTenant();\r\n const { tenants: adminTenantsList } = useAdminTenants();\r\n const { hasPermission } = useAuth();\r\n\r\n // Permission checks\r\n const canUpdate = hasPermission('administration.users.update');\r\n const canDelete = hasPermission('administration.users.delete');\r\n const canExecute = hasPermission('administration.users.execute');\r\n\r\n // Tab state\r\n const getInitialTab = (): TabId => {\r\n const tabParam = searchParams.get('tab');\r\n if (tabParam && VALID_TABS.includes(tabParam as TabId)) {\r\n return tabParam as TabId;\r\n }\r\n return 'info';\r\n };\r\n const [activeTab, setActiveTab] = useState<TabId>(getInitialTab);\r\n\r\n // Use custom hooks for data management\r\n const userDetail = useUserDetail({ userId, tenantSlug: currentTenant?.slug ?? null });\r\n const {\r\n user,\r\n formData,\r\n setFormData,\r\n isCreateMode,\r\n loading,\r\n error,\r\n success,\r\n setError,\r\n setSuccess,\r\n roles,\r\n rolesLoading,\r\n sessions,\r\n activity,\r\n history,\r\n orgReferences,\r\n loadUser,\r\n loadRoles,\r\n loadOrgReferences,\r\n loadSessions,\r\n loadActivity,\r\n loadHistory,\r\n setHistory,\r\n handleSaveInfo,\r\n saving: infoSaving\r\n } = userDetail;\r\n\r\n // Security hook\r\n const security = useUserSecurity({\r\n userId,\r\n onUserReload: loadUser,\r\n onSessionsReload: loadSessions,\r\n setError,\r\n setSuccess\r\n });\r\n\r\n // Sections hook\r\n const sections = useUserSections({\r\n userId,\r\n user,\r\n onUserReload: loadUser,\r\n onHistoryReload: () => setHistory(null),\r\n setError,\r\n setSuccess\r\n });\r\n\r\n // Tenants hook\r\n const tenants = useUserTenants({\r\n userId,\r\n isCreateMode,\r\n setError,\r\n setSuccess\r\n });\r\n\r\n // History restore state\r\n const [restoringHistoryId, setRestoringHistoryId] = useState<string | null>(null);\r\n\r\n // Scope selection for roles/permissions tabs\r\n const [selectedScope, setSelectedScope] = useState<ScopeValue>('global');\r\n const [tenantMemberships, setTenantMemberships] = useState<Array<{\r\n tenantId: string;\r\n tenantSlug: string;\r\n tenantUserId: string;\r\n tenantName: string;\r\n tenantType?: string;\r\n }> | null>(null);\r\n const [membershipLoadError, setMembershipLoadError] = useState<string | null>(null);\r\n const [, setUserNotMemberOfCurrentTenant] = useState(false);\r\n\r\n // Consolidated roles state (all roles across all tenants with source info)\r\n const [consolidatedRoles, setConsolidatedRoles] = useState<UserConsolidatedRoleDto[] | null>(null);\r\n const [consolidatedRolesLoading, setConsolidatedRolesLoading] = useState(false);\r\n\r\n // Load tenant memberships\r\n const loadTenantMemberships = useCallback(async () => {\r\n if (!userId || isCreateMode) return;\r\n setMembershipLoadError(null);\r\n try {\r\n const userTenantsList = await adminApi.users.getTenants(userId);\r\n const memberships = userTenantsList.map((tenant) => ({\r\n tenantId: tenant.id,\r\n tenantSlug: tenant.slug,\r\n tenantUserId: userId,\r\n tenantName: tenant.name,\r\n tenantType: tenant.type,\r\n }));\r\n setTenantMemberships(memberships);\r\n } catch (err) {\r\n console.error('Failed to load tenant memberships:', err);\r\n setMembershipLoadError(t('userRoles.scope.loadError', 'Erreur lors du chargement des tenants'));\r\n setTenantMemberships([]);\r\n }\r\n }, [userId, isCreateMode, t]);\r\n\r\n // Load consolidated roles (all roles across all tenants with source info)\r\n const loadConsolidatedRoles = useCallback(async () => {\r\n if (!userId) return;\r\n setConsolidatedRolesLoading(true);\r\n try {\r\n const data = await adminApi.users.getConsolidatedRoles(userId);\r\n setConsolidatedRoles(data);\r\n } catch (err) {\r\n console.error('Failed to load consolidated roles:', err);\r\n setConsolidatedRoles([]);\r\n } finally {\r\n setConsolidatedRolesLoading(false);\r\n }\r\n }, [userId]);\r\n\r\n // Handle history restore\r\n const handleRestoreField = async (historyId: string) => {\r\n if (!userId) return;\r\n\r\n setRestoringHistoryId(historyId);\r\n setError(null);\r\n\r\n try {\r\n await adminApi.users.restoreFromHistory(userId, historyId);\r\n setSuccess(t('userDetail.history.restoreSuccess', 'Champ restauré avec succès'));\r\n loadHistory();\r\n loadUser();\r\n } catch (err) {\r\n console.error('Failed to restore field:', err);\r\n setError(t('userDetail.history.restoreError', 'Erreur lors de la restauration'));\r\n } finally {\r\n setRestoringHistoryId(null);\r\n }\r\n };\r\n\r\n // Reset scope when user changes\r\n useEffect(() => {\r\n setSelectedScope('global');\r\n setTenantMemberships(null);\r\n setConsolidatedRoles(null);\r\n }, [userId]);\r\n\r\n // Destructure stable references from tenants hook (avoid unstable object in deps)\r\n const tenantsUserData = tenants.userTenants;\r\n const loadUserTenants = tenants.loadTenants;\r\n\r\n const loadTabData = useCallback(() => {\r\n if (isCreateMode) return;\r\n if ((activeTab === 'info' || activeTab === 'roles') && !roles) loadRoles();\r\n if (activeTab === 'info' && !orgReferences) loadOrgReferences();\r\n if (activeTab === 'roles' && !consolidatedRoles) loadConsolidatedRoles();\r\n if (activeTab === 'activitySessions') {\r\n if (!sessions) loadSessions();\r\n if (!activity) loadActivity();\r\n }\r\n if (activeTab === 'tenants' && !tenantsUserData) loadUserTenants();\r\n if (activeTab === 'history' && !history) loadHistory();\r\n if ((activeTab === 'roles' || activeTab === 'permissions') && !tenantMemberships) {\r\n loadTenantMemberships();\r\n }\r\n }, [activeTab, isCreateMode, roles, orgReferences, sessions, activity, tenantsUserData, tenantMemberships, consolidatedRoles, history, loadRoles, loadOrgReferences, loadConsolidatedRoles, loadSessions, loadActivity, loadHistory, loadTenantMemberships, loadUserTenants]);\r\n\r\n useEffect(() => {\r\n loadTabData();\r\n }, [loadTabData]);\r\n\r\n // Sync selectedScope with currentTenant context\r\n useEffect(() => {\r\n if (!tenantMemberships) {\r\n setUserNotMemberOfCurrentTenant(false);\r\n return;\r\n }\r\n\r\n if (currentTenant) {\r\n const membership = tenantMemberships.find(m => m.tenantId === currentTenant.id);\r\n if (membership) {\r\n setSelectedScope({\r\n tenantId: membership.tenantId,\r\n tenantSlug: membership.tenantSlug,\r\n tenantUserId: membership.tenantUserId,\r\n tenantName: membership.tenantName,\r\n });\r\n setUserNotMemberOfCurrentTenant(false);\r\n } else {\r\n setSelectedScope('global');\r\n setUserNotMemberOfCurrentTenant(true);\r\n }\r\n } else {\r\n setSelectedScope('global');\r\n setUserNotMemberOfCurrentTenant(false);\r\n }\r\n }, [currentTenant, tenantMemberships]);\r\n\r\n // Sync URL with active tab\r\n useEffect(() => {\r\n const currentTab = searchParams.get('tab');\r\n if (currentTab !== activeTab) {\r\n setSearchParams({ tab: activeTab }, { replace: true });\r\n }\r\n }, [activeTab, searchParams, setSearchParams]);\r\n\r\n const tabs: { id: TabId; label: string; icon: React.ReactNode }[] = [\r\n { id: 'info', label: t('userDetail.tabs.info'), icon: <User className=\"w-4 h-4\" /> },\r\n { id: 'security', label: t('userDetail.tabs.security'), icon: <Key className=\"w-4 h-4\" /> },\r\n { id: 'activitySessions', label: t('userDetail.tabs.activitySessions', 'Activité'), icon: <Activity className=\"w-4 h-4\" /> },\r\n { id: 'roles', label: t('userDetail.tabs.roles'), icon: <Shield className=\"w-4 h-4\" /> },\r\n { id: 'permissions', label: t('userDetail.tabs.permissions'), icon: <Key className=\"w-4 h-4\" /> },\r\n { id: 'applications', label: t('userDetail.tabs.applications', 'Applications'), icon: <AppWindow className=\"w-4 h-4\" /> },\r\n { id: 'tenants', label: t('userDetail.tabs.tenants', 'Tenants'), icon: <Building2 className=\"w-4 h-4\" /> },\r\n { id: 'groups', label: t('userDetail.tabs.groups', 'Groupes'), icon: <Users className=\"w-4 h-4\" /> },\r\n { id: 'history', label: t('userDetail.tabs.history', 'Historique'), icon: <History className=\"w-4 h-4\" /> }\r\n ];\r\n\r\n if (loading) {\r\n return (\r\n <div className=\"flex items-center justify-center h-64\">\r\n <Loader2 className=\"w-8 h-8 animate-spin text-[var(--color-accent-500)]\" />\r\n </div>\r\n );\r\n }\r\n\r\n if (!user) {\r\n return (\r\n <div className=\"text-center py-12\">\r\n <p className=\"text-[var(--text-secondary)]\">{t('userDetail.notFound')}</p>\r\n <button\r\n onClick={() => navigate('/administration/users')}\r\n className=\"mt-4 px-4 py-2 rounded-[var(--radius-button)] bg-[var(--color-accent-600)] text-white\"\r\n >\r\n {t('userDetail.backToList')}\r\n </button>\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'), href: '/administration' },\r\n { label: t('users.title'), href: '/administration/users' },\r\n { label: user.fullName }\r\n ]}\r\n />\r\n\r\n {/* Header */}\r\n <div className=\"flex items-center gap-4\">\r\n <button\r\n onClick={() => navigate('/administration/users')}\r\n className=\"p-2 rounded-[var(--radius-button)] hover:bg-[var(--bg-hover)] transition-colors\"\r\n >\r\n <ArrowLeft className=\"w-5 h-5 text-[var(--text-secondary)]\" />\r\n </button>\r\n <div className=\"flex-1\">\r\n <h1 className=\"text-xl sm:text-2xl font-bold text-[var(--text-primary)]\">{user.fullName}</h1>\r\n <p className=\"text-sm sm:text-base text-[var(--text-secondary)]\">{user.email}</p>\r\n </div>\r\n <div className=\"flex items-center gap-2\">\r\n <span className={`px-3 py-1 rounded-[var(--radius-badge)] text-sm ${\r\n user.isActive\r\n ? 'bg-[var(--success-bg)] text-[var(--success-text)] border border-[var(--success-border)]'\r\n : 'bg-[var(--error-bg)] text-[var(--error-text)] border border-[var(--error-border)]'\r\n }`}>\r\n {user.isActive ? t('users.status.active') : t('users.status.inactive')}\r\n </span>\r\n <span className=\"px-3 py-1 rounded-[var(--radius-badge)] text-sm bg-[var(--bg-tertiary)] text-[var(--text-secondary)]\">\r\n {user.userType}\r\n </span>\r\n <Slot name=\"users.detail.header.actions\" context={{ user, reload: loadUser }} />\r\n </div>\r\n </div>\r\n\r\n {/* Alerts */}\r\n {error && (\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--error-bg)] border border-[var(--error-border)] text-[var(--error-text)] flex items-center gap-2\">\r\n <AlertTriangle className=\"w-5 h-5\" />\r\n {error}\r\n </div>\r\n )}\r\n {success && (\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--success-bg)] border border-[var(--success-border)] text-[var(--success-text)] flex items-center gap-2\">\r\n <CheckCircle className=\"w-5 h-5\" />\r\n {success}\r\n </div>\r\n )}\r\n\r\n {/* Tabs */}\r\n <div className=\"flex gap-1 p-1 overflow-x-auto bg-[var(--bg-secondary)] rounded-[var(--radius-card)] border border-[var(--border-color)]\">\r\n {tabs.map(tab => (\r\n <button\r\n key={tab.id}\r\n onClick={() => setActiveTab(tab.id)}\r\n className={`flex items-center gap-2 px-4 py-2 whitespace-nowrap rounded-[var(--radius-button)] font-medium transition-colors ${\r\n activeTab === tab.id\r\n ? 'bg-[var(--color-accent-600)] text-white'\r\n : 'text-[var(--text-secondary)] hover:bg-[var(--bg-hover)]'\r\n }`}\r\n >\r\n {tab.icon}\r\n {tab.label}\r\n </button>\r\n ))}\r\n <Slot name=\"users.detail.tabs\" context={{ user, activeTab, setActiveTab }} />\r\n </div>\r\n\r\n {/* Tab Content */}\r\n <div className=\"bg-[var(--bg-secondary)] rounded-[var(--radius-card)] border border-[var(--border-color)] p-4 sm:p-6\">\r\n {/* Info Tab */}\r\n {activeTab === 'info' && (\r\n <UserInfoTab\r\n user={user}\r\n formData={formData}\r\n setFormData={setFormData}\r\n handleSaveInfo={handleSaveInfo}\r\n saving={infoSaving || sections.saving}\r\n canUpdate={canUpdate}\r\n editingSection={sections.editingSection}\r\n sectionData={sections.sectionData}\r\n setSectionData={sections.setSectionData}\r\n startEditingSection={sections.startEditingSection}\r\n cancelEditing={sections.cancelEditing}\r\n handleSaveSection={sections.handleSaveSection}\r\n orgReferences={orgReferences}\r\n />\r\n )}\r\n\r\n {/* Security Tab */}\r\n {activeTab === 'security' && userId && (\r\n <UserSecurityTab\r\n user={user}\r\n userId={userId}\r\n canUpdate={canUpdate}\r\n canDelete={canDelete}\r\n canExecute={canExecute}\r\n newPassword={security.newPassword}\r\n setNewPassword={security.setNewPassword}\r\n temporaryPassword={security.temporaryPassword}\r\n showTemporaryPassword={security.showTemporaryPassword}\r\n setShowTemporaryPassword={security.setShowTemporaryPassword}\r\n saving={security.saving}\r\n showUnlockModal={security.showUnlockModal}\r\n setShowUnlockModal={security.setShowUnlockModal}\r\n handleSendResetLink={security.handleSendResetLink}\r\n handleResetPasswordDirect={security.handleResetPasswordDirect}\r\n handleToggleStatus={security.handleToggleStatus}\r\n handleEndAllSessions={security.handleEndAllSessions}\r\n handleUnlock={security.handleUnlock}\r\n handleClearFailedAttempts={security.handleClearFailedAttempts}\r\n copyToClipboard={security.copyToClipboard}\r\n setError={setError}\r\n />\r\n )}\r\n\r\n {/* Activity & Sessions Tab */}\r\n {activeTab === 'activitySessions' && (\r\n <UserActivitySessionsTab\r\n sessions={sessions}\r\n activity={activity}\r\n isCreateMode={isCreateMode}\r\n canUpdate={canUpdate}\r\n handleEndSession={security.handleEndSession}\r\n handleEndAllSessions={security.handleEndAllSessions}\r\n />\r\n )}\r\n\r\n {/* Membership load error */}\r\n {(activeTab === 'roles' || activeTab === 'permissions') && userId && membershipLoadError && (\r\n <div className=\"mb-4 flex items-center gap-2 p-3 rounded-lg bg-amber-500/10 border border-amber-500/30 text-amber-700\">\r\n <AlertTriangle className=\"w-4 h-4\" />\r\n <span className=\"text-sm\">{membershipLoadError}</span>\r\n </div>\r\n )}\r\n\r\n {/* Roles Tab */}\r\n {activeTab === 'roles' && userId && (\r\n <UserRoleAssignment\r\n userId={userId}\r\n assignedRoles={consolidatedRoles ?? []}\r\n onSave={async () => {\r\n await Promise.all([loadUser(true), loadConsolidatedRoles()]);\r\n }}\r\n onGlobalRolesUpdate={async (roleIds) => {\r\n const updateData: UpdateUserRequest = {\r\n firstName: formData.firstName,\r\n lastName: formData.lastName,\r\n roleIds,\r\n };\r\n await adminApi.users.update(userId, updateData);\r\n }}\r\n roles={roles ?? []}\r\n loading={rolesLoading || consolidatedRolesLoading}\r\n globalRoleIds={formData.roleIds}\r\n tenantId={selectedScope !== 'global' ? (selectedScope as Exclude<ScopeValue, 'global'>).tenantId : undefined}\r\n isGlobalScope={selectedScope === 'global'}\r\n adminTenants={adminTenantsList.map(tenant => ({\r\n tenantId: tenant.id,\r\n tenantSlug: tenant.slug,\r\n tenantName: tenant.name,\r\n tenantType: tenant.type,\r\n }))}\r\n tenantMemberships={(tenantMemberships ?? []).map(m => ({\r\n tenantId: m.tenantId,\r\n tenantSlug: m.tenantSlug,\r\n tenantUserId: m.tenantUserId,\r\n tenantName: m.tenantName,\r\n }))}\r\n />\r\n )}\r\n\r\n {/* Permissions Tab */}\r\n {activeTab === 'permissions' && userId && (\r\n <UserPermissionMatrix\r\n userId={userId}\r\n tenantId={selectedScope !== 'global' ? (selectedScope as Exclude<ScopeValue, 'global'>).tenantId : undefined}\r\n />\r\n )}\r\n\r\n {/* Applications Tab */}\r\n {activeTab === 'applications' && userId && (\r\n <UserApplicationsTab\r\n userId={userId}\r\n />\r\n )}\r\n\r\n {/* Groups Tab */}\r\n {activeTab === 'groups' && user && userId && (\r\n <UserGroupsTab\r\n userId={userId}\r\n userName={user.fullName}\r\n />\r\n )}\r\n\r\n {/* Tenants Tab */}\r\n {activeTab === 'tenants' && (\r\n <UserTenantsTab\r\n userTenants={tenants.userTenants}\r\n allTenants={tenants.allTenants}\r\n currentTenant={currentTenant}\r\n hasGlobalRoles={hasGlobalRoles}\r\n showAddTenantModal={tenants.showAddTenantModal}\r\n tenantSearch={tenants.tenantSearch}\r\n tenantsViewMode={tenants.tenantsViewMode}\r\n selectedTenantIds={tenants.selectedTenantIds}\r\n isAddingMultipleTenants={tenants.isAddingMultipleTenants}\r\n setShowAddTenantModal={tenants.setShowAddTenantModal}\r\n setTenantSearch={tenants.setTenantSearch}\r\n setTenantsViewMode={tenants.setTenantsViewMode}\r\n setUserTenants={tenants.setUserTenants}\r\n loadTenants={tenants.loadTenants}\r\n toggleTenantSelection={tenants.toggleTenantSelection}\r\n selectAllTenants={tenants.selectAllTenants}\r\n clearTenantSelection={tenants.clearTenantSelection}\r\n closeAddTenantModal={tenants.closeAddTenantModal}\r\n handleAddMultipleTenants={tenants.handleAddMultipleTenants}\r\n handleRemoveTenant={tenants.handleRemoveTenant}\r\n />\r\n )}\r\n\r\n {/* History Tab */}\r\n {activeTab === 'history' && (\r\n <UserHistoryTab\r\n history={history}\r\n loadHistory={loadHistory}\r\n handleRestoreField={handleRestoreField}\r\n restoringHistoryId={restoringHistoryId}\r\n canUpdate={canUpdate}\r\n />\r\n )}\r\n\r\n {/* Extension tab content */}\r\n <Slot name=\"users.detail.tabs.content\" context={{ user, activeTab, reload: loadUser }} />\r\n </div>\r\n </div>\r\n );\r\n}\r\n"],"names":["CATEGORY_STYLES","DEFAULT_CATEGORY_STYLE","SOURCE_STYLES","Globe","Users","Lock","UserRoleAssignment","userId","assignedRoles","onSave","onGlobalRolesUpdate","rolesProp","loading","globalRoleIds","tenantId","isGlobalScope","adminTenants","tenantMemberships","t","useTranslation","roles","searchQuery","setSearchQuery","useState","scopeFilter","setScopeFilter","removing","setRemoving","modalOpen","setModalOpen","error","setError","removingRef","useRef","tenantOptions","useMemo","m","a","b","filteredAssignedRoles","scoped","ar","query","roleMap","map","r","handleRemoveRole","useCallback","roleId","roleTenantId","membership","adminApi","newRoleIds","id","err","handleOpenModal","handleCloseModal","handleAssigned","jsxs","jsx","AlertCircle","X","Search","e","to","ChevronDown","Plus","Loader2","roleDetail","category","catStyle","customIcon","getCustomRoleIcon","isGlobal","isGroupSourced","sourceStyle","SourceIcon","removingKey","isRemoving","Link","Building2","Trash2","UserAssignRoleModal","_userId","initialTenantId","initialIsGlobalScope","onAssigned","onClose","filterCategory","setFilterCategory","filterContext","setFilterContext","filterApplication","setFilterApplication","saving","setSaving","savingRef","modalTenants","memberTenantIds","at","modalScope","setModalScope","tenant","modalIsGlobal","modalTenantId","currentScopeRoleIds","ids","tenantAppIds","setTenantAppIds","useEffect","cancelled","apps","scopedRoles","contexts","ctxMap","name","applications","appMap","handleContextChange","value","categories","cats","filteredRoles","filtered","handleAssignRole","TenantScopeSelector","Filter","ctx","app","c","cat","role","isAlreadyAssigned","isAssigning","getTenantNamesFromSourceRoles","sourceRoles","consolidatedRolesMap","globalLabel","tenantNames","cr","getSourceTypesFromConsolidatedRoles","sources","s","ACTION_ICONS","Shield","Eye","Edit","UserPlus","Play","ACTION_COLORS","UserPermissionMatrix","compact","navigate","useNavigate","user","userRoles","filteredResources","effectivePermissions","filters","modules","updateFilters","getPermissionSources","reloadData","isTenantMode","tenantMember","_assignTenantRoles","consolidatedRoles","useUserPermissions","collapsedApps","toggleApp","useCollapsibleState","collapsedModules","setCollapsedModules","collapsedSections","setCollapsedSections","statusFilters","setStatusFilters","openPopover","setOpenPopover","customRoleId","setCustomRoleId","customRolePermissions","setCustomRolePermissions","togglingPermission","setTogglingPermission","loadingCustomRole","setLoadingCustomRole","React","p","handleTogglePermission","permissionId","currentPermissions","newPermissions","handleCellClick","resourceId","toggleStatusFilter","status","prev","next","toggleModule","moduleId","toggleSection","sectionId","getAllPermissionsForResource","resource","allPermissions","section","getPermissionStatusForUser","isSection","calculatePermissionStatus","permId","grantedCount","totalCount","filterModulesByStatus","calculateModuleWithSectionsStatus","filterApplicationsByModules","applyUserStatusFilters","grouped","groupedResources","groupByApplicationWithSections","totalModuleCount","sum","addSourceRolesFromPermission","getSourceRolesForResource","perm","isCustomRole","roleName","getDisplayName","userAsRole","getUserPermissionInheritance","_roleId","isGranted","isFromCustomRole","inheritedRole","getUserResourceIcon","level","Database","FileText","Box","getUserResourceLabelClass","getUserPaddingClass","getSourceTypeLabelClass","type","getTenantTagClass","tenantName","renderSectionWithResources","sectionWithResources","moduleIndex","sectionIndex","resources","hasResources","isSectionCollapsed","renderResourceRow","resourceIndex","renderModuleWithSections","moduleWithSections","module","sections","hasSections","isModuleCollapsed","rowIndex","hasChildren","isCollapsed","cellBg","getPermissionCellBackground","isPopoverOpen","buttonRef","createRef","paddingLeft","ChevronRight","PermissionStatusIndicator","PermissionPopover","isCustom","displayName","Star","idx","source","UserCheck","User","isToggling","actionColor","icon","Fragment","mod","Check","Ban","Info","appGroup","appKey","isAppCollapsed","FolderOpen","ViewModeToggle","viewMode","onChange","LayoutGrid","Table2","UserGroupsTab","userName","userGroups","setUserGroups","allGroups","setAllGroups","setLoading","showAddModal","setShowAddModal","groupTypeFilter","setGroupTypeFilter","selectedGroupIds","setSelectedGroupIds","isAddingMultiple","setIsAddingMultiple","removingGroupId","setRemovingGroupId","success","setSuccess","setViewMode","loadUserGroups","data","loadAllGroups","groupsApi","handleRemoveFromGroup","groupId","group","g","errorMessage","filteredAvailableGroups","ug","toggleGroupSelection","newSet","getGroupTypeFilterClass","filter","currentFilter","getGroupCheckboxClass","isSelected","selectAllFiltered","clearSelection","handleAddMultipleGroups","groupIdsArray","closeModal","RefreshCw","AlertTriangle","CheckCircle","DataTable","Cloud","OTHER_VALUE","SelectWithOther","label","options","placeholder","disabled","className","allowOther","isOther","setIsOther","customInput","setCustomInput","handleSelectChange","selectedValue","handleCustomInputChange","newValue","handleCancelOther","selectValue","opt","formatDate","date","UserInfoTab","formData","setFormData","handleSaveInfo","canUpdate","editingSection","sectionData","setSectionData","startEditingSection","cancelEditing","handleSaveSection","orgReferences","Save","EditableSection","val","d","j","o","InfoField","Briefcase","Phone","formatPhoneNumber","MapPinIcon","AtSign","StatusBadge","Key","breakAll","title","sectionKey","onStartEdit","onCancel","children","Edit3","active","activeLabel","inactiveLabel","Mail","XCircle","UnlockAccountModal","isOpen","onConfirm","selectedReason","setSelectedReason","mustChangePassword","setMustChangePassword","handleConfirm","handleClose","bugInfo","issueUrl","Bug","UnlockReason","getButtonClasses","hasPermission","colorClass","getPrimaryButtonClasses","getWarningButtonClasses","getRedButtonClasses","getGreenButtonClasses","isActive","UserSecurityTab","canDelete","canExecute","newPassword","setNewPassword","temporaryPassword","showTemporaryPassword","setShowTemporaryPassword","showUnlockModal","setShowUnlockModal","handleSendResetLink","handleResetPasswordDirect","handleToggleStatus","handleEndAllSessions","handleUnlock","handleClearFailedAttempts","copyToClipboard","getAccountStatusText","getAccountStatusHint","handleDelete","EyeOff","Copy","UserX","LogOut","Unlock","formatDuration","duration","parts","hours","minutes","getStatCardColorClass","color","UserActivitySessionsTab","sessions","activity","isCreateMode","handleEndSession","Activity","ActivitySection","SessionsSection","StatCard","StatsCard","Smartphone","MapPin","Calendar","day","Monitor","ActiveSessionsList","SessionHistory","session","SessionCard","parseUserAgent","isText","items","labelKey","countSuffix","item","i","renderTenantsContent","filteredTenants","hasGlobalRoles","tenantsViewMode","currentTenant","handleRemoveTenant","setShowAddTenantModal","EmptyState","TenantTableView","TenantCardsView","LoadingState","renderTenantList","allTenants","availableTenants","selectedTenantIds","toggleTenantSelection","TenantSelectItem","UserTenantsTab","userTenants","showAddTenantModal","tenantSearch","isAddingMultipleTenants","setTenantSearch","setTenantsViewMode","setUserTenants","loadTenants","selectAllTenants","clearTenantSelection","closeAddTenantModal","handleAddMultipleTenants","handleRefresh","AddTenantModal","onAddClick","tenants","onRemove","onNavigate","columns","statusColors","getStatusDotColor","Link2","Crown","primaryTenant","otherTenants","TenantCard","canManage","userTenantIds","onToggle","UserHistoryTab","history","loadHistory","handleRestoreField","restoringHistoryId","getActionLabel","actionName","isRestorable","entry","getActionIcon","ShieldX","RotateCcw","History","UserApplicationsTab","setApplications","setTenants","selectedTenantId","setSelectedTenantId","tenantsLoading","setTenantsLoading","expandedApps","setExpandedApps","loadApplicationAccess","toggleExpand","appId","selectedTenantName","Boxes","ApplicationCard","isExpanded","icons","LucideIcons","AppIcon","permissionsByModule","groups","key","Layers","extractActionFromPath","path","isValidGuid","useUserDetail","tenantSlug","tenantApi","createAdminApi","setUser","setRoles","rolesLoading","setRolesLoading","setSessions","setActivity","setHistory","setOrgReferences","setAllTenants","loadUser","silent","userData","loadRoles","result","loadOrgReferences","loadSessions","loadActivity","loadAllTenants","updateData","useUserSecurity","onUserReload","onSessionsReload","setTemporaryPassword","customPassword","sessionId","reason","text","createInitialSectionData","useUserSections","onHistoryReload","setEditingSection","org","useUserTenants","setSelectedTenantIds","setIsAddingMultipleTenants","availableTenantIds","tenantIdsArray","VALID_TABS","UserDetailPage","useParams","searchParams","setSearchParams","useSearchParams","useTenant","adminTenantsList","useAdminTenants","useAuth","getInitialTab","tabParam","activeTab","setActiveTab","userDetail","infoSaving","security","setRestoringHistoryId","selectedScope","setSelectedScope","setTenantMemberships","membershipLoadError","setMembershipLoadError","setUserNotMemberOfCurrentTenant","setConsolidatedRoles","consolidatedRolesLoading","setConsolidatedRolesLoading","loadTenantMemberships","memberships","loadConsolidatedRoles","historyId","tenantsUserData","loadUserTenants","loadTabData","tabs","AppWindow","Breadcrumb","ArrowLeft","Slot","tab","roleIds"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"UserDetailPage-U7smBQoF.js","sources":["../../src/components/platform/administration/UserRoleAssignment.tsx","../../src/components/platform/administration/permissions/UserPermissionMatrix.tsx","../../src/components/ui/ViewModeToggle.tsx","../../src/components/platform/administration/UserGroupsTab.tsx","../../src/components/ui/SelectWithOther.tsx","../../src/components/platform/administration/users/UserInfoTab.tsx","../../src/components/ui/UnlockAccountModal.tsx","../../src/components/platform/administration/users/UserSecurityTab.tsx","../../src/components/platform/administration/users/UserActivitySessionsTab.tsx","../../src/components/platform/administration/users/UserTenantsTab.tsx","../../src/components/platform/administration/users/UserHistoryTab.tsx","../../src/components/platform/administration/users/UserApplicationsTab.tsx","../../src/hooks/useUserDetail.ts","../../src/hooks/useUserSecurity.ts","../../src/hooks/useUserSections.ts","../../src/hooks/useUserTenants.ts","../../src/pages/platform/administration/users/UserDetailPage.tsx"],"sourcesContent":["import { useState, useMemo, useRef, useCallback, useEffect } from 'react';\r\nimport type { ReactElement } from 'react';\r\nimport { useTranslation } from 'react-i18next';\r\nimport { Link } from 'react-router-dom';\r\nimport { Plus, Trash2, Loader2, Search, Building2, Globe, X, ChevronDown, Filter, AlertCircle, Users, Lock } from 'lucide-react';\r\nimport { adminApi, type RoleListDto, type UserConsolidatedRoleDto } from '@/services/api/adminApi';\r\nimport { getCustomRoleIcon } from '@/utils/roleUtils';\r\nimport { TenantScopeSelector, type ScopeValue } from '@/components/ui/TenantScopeSelector';\r\n\r\ninterface AdminTenantInfo {\r\n tenantId: string;\r\n tenantSlug: string;\r\n tenantName: string;\r\n tenantType: string;\r\n}\r\n\r\ninterface TenantMembership {\r\n tenantId: string;\r\n tenantSlug: string;\r\n tenantUserId: string;\r\n tenantName: string;\r\n}\r\n\r\ninterface UserRoleAssignmentProps {\r\n readonly userId: string;\r\n readonly assignedRoles: UserConsolidatedRoleDto[];\r\n readonly onSave: () => Promise<void>;\r\n readonly onGlobalRolesUpdate: (roleIds: string[]) => Promise<void>;\r\n readonly roles: RoleListDto[];\r\n readonly loading?: boolean;\r\n readonly globalRoleIds: string[];\r\n readonly tenantId?: string;\r\n readonly isGlobalScope?: boolean;\r\n readonly adminTenants?: AdminTenantInfo[];\r\n readonly tenantMemberships?: TenantMembership[];\r\n}\r\n\r\nconst CATEGORY_STYLES: Record<string, { bg: string; text: string }> = {\r\n Global: { bg: 'bg-[var(--accent-bg)]', text: 'text-[var(--color-accent-500)]' },\r\n Admin: { bg: 'bg-[var(--error-bg)]', text: 'text-[var(--error-text)]' },\r\n Manager: { bg: 'bg-[var(--warning-bg)]', text: 'text-[var(--warning-text)]' },\r\n Contributor: { bg: 'bg-[var(--success-bg)]', text: 'text-[var(--success-text)]' },\r\n Viewer: { bg: 'bg-[var(--info-bg)]', text: 'text-[var(--info-text)]' },\r\n Custom: { bg: 'bg-[var(--accent-bg)]', text: 'text-[var(--color-accent-700)]' },\r\n};\r\n\r\nconst DEFAULT_CATEGORY_STYLE = { bg: 'bg-[var(--bg-secondary)]', text: 'text-[var(--text-secondary)]' };\r\n\r\nconst SOURCE_STYLES: Record<string, { bg: string; text: string; icon: React.ElementType }> = {\r\n Direct: { bg: 'bg-[var(--success-bg)]', text: 'text-[var(--success-text)]', icon: Globe },\r\n Group: { bg: 'bg-[var(--accent-bg)]', text: 'text-[var(--color-accent-700)]', icon: Users },\r\n Custom: { bg: 'bg-[var(--warning-bg)]', text: 'text-[var(--warning-text)]', icon: Lock },\r\n};\r\n\r\nexport function UserRoleAssignment({\r\n userId,\r\n assignedRoles = [],\r\n onSave,\r\n onGlobalRolesUpdate,\r\n roles: rolesProp,\r\n loading = false,\r\n globalRoleIds,\r\n tenantId,\r\n isGlobalScope = true,\r\n adminTenants = [],\r\n tenantMemberships = [],\r\n}: UserRoleAssignmentProps): ReactElement {\r\n const { t } = useTranslation(['admin', 'groups']);\r\n const roles = Array.isArray(rolesProp) ? rolesProp : [];\r\n\r\n const [searchQuery, setSearchQuery] = useState('');\r\n const [scopeFilter, setScopeFilter] = useState<string>('all');\r\n const [removing, setRemoving] = useState<string | null>(null);\r\n const [modalOpen, setModalOpen] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n const removingRef = useRef(false);\r\n\r\n // Build tenant options from user's memberships only\r\n const tenantOptions = useMemo(() => {\r\n return tenantMemberships\r\n .map(m => ({ id: m.tenantId, name: m.tenantName }))\r\n .sort((a, b) => a.name.localeCompare(b.name));\r\n }, [tenantMemberships]);\r\n\r\n // --- Overview table: filtered by scope + search ---\r\n\r\n const filteredAssignedRoles = useMemo(() => {\r\n // First: scope filter\r\n let scoped = assignedRoles;\r\n if (scopeFilter === 'global') {\r\n scoped = scoped.filter(ar => !ar.tenantId);\r\n } else if (scopeFilter !== 'all') {\r\n scoped = scoped.filter(ar => !ar.tenantId || ar.tenantId === scopeFilter);\r\n }\r\n\r\n // Then: text search\r\n if (!searchQuery.trim()) return scoped;\r\n const query = searchQuery.toLowerCase().trim();\r\n return scoped.filter(ar =>\r\n ar.roleName.toLowerCase().includes(query) ||\r\n ar.tenantName?.toLowerCase().includes(query) ||\r\n ar.sourceGroupName?.toLowerCase().includes(query)\r\n );\r\n }, [assignedRoles, searchQuery, scopeFilter]);\r\n\r\n // Build a map of roleId -> RoleListDto for category lookup\r\n const roleMap = useMemo(() => {\r\n const map = new Map<string, RoleListDto>();\r\n for (const r of roles) map.set(r.id, r);\r\n return map;\r\n }, [roles]);\r\n\r\n const handleRemoveRole = useCallback(async (roleId: string, roleTenantId: string | null) => {\r\n if (removingRef.current) return;\r\n removingRef.current = true;\r\n setRemoving(roleId + (roleTenantId || 'global'));\r\n setError(null);\r\n\r\n try {\r\n if (!roleTenantId) {\r\n // Global scope: remove from global role IDs via callback\r\n const newRoleIds = globalRoleIds.filter(id => id !== roleId);\r\n await onGlobalRolesUpdate(newRoleIds);\r\n } else {\r\n // Tenant scope: use individual remove endpoint\r\n const membership = tenantMemberships.find(m => m.tenantId === roleTenantId);\r\n if (membership) {\r\n await adminApi.tenants.removeRole(roleTenantId, membership.tenantUserId, roleId);\r\n }\r\n }\r\n await onSave();\r\n } catch (err) {\r\n console.error('Failed to remove role assignment:', err);\r\n setError(t('admin:userRoles.errors.removeFailed', 'Erreur lors du retrait du rôle'));\r\n } finally {\r\n setRemoving(null);\r\n removingRef.current = false;\r\n }\r\n }, [globalRoleIds, tenantMemberships, onGlobalRolesUpdate, onSave, t]);\r\n\r\n const handleOpenModal = useCallback(() => setModalOpen(true), []);\r\n const handleCloseModal = useCallback(() => setModalOpen(false), []);\r\n\r\n const handleAssigned = useCallback(async () => {\r\n await onSave();\r\n }, [onSave]);\r\n\r\n return (\r\n <div className=\"space-y-4\">\r\n {/* Error alert */}\r\n {error && (\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--error-bg)] border border-[var(--error-border)] flex items-center gap-3\">\r\n <AlertCircle className=\"w-5 h-5 text-[var(--error-text)] flex-shrink-0\" />\r\n <p className=\"flex-1 text-[var(--error-text)]\">{error}</p>\r\n <button onClick={() => setError(null)} className=\"ml-auto\">\r\n <X className=\"w-4 h-4 text-[var(--error-text)]\" />\r\n </button>\r\n </div>\r\n )}\r\n\r\n {/* Header: search + scope filter + assign button */}\r\n <div className=\"flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3\">\r\n <div className=\"flex items-center gap-3 flex-1\">\r\n <div className=\"relative flex-1 max-w-md\">\r\n <Search className=\"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-[var(--text-muted)]\" />\r\n <input\r\n type=\"text\"\r\n value={searchQuery}\r\n onChange={(e) => setSearchQuery(e.target.value)}\r\n placeholder={t('admin:userRoles.search', 'Rechercher un rôle...')}\r\n className=\"w-full pl-10 pr-4 py-2 text-sm bg-[var(--bg-secondary)] border border-[var(--border-color)] rounded-[var(--radius-input)] text-[var(--text-primary)] placeholder-[var(--text-muted)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n />\r\n </div>\r\n <div className=\"relative\">\r\n <select\r\n value={scopeFilter}\r\n onChange={(e) => setScopeFilter(e.target.value)}\r\n className=\"px-3 py-2 pr-8 text-sm bg-[var(--bg-secondary)] border border-[var(--border-color)] rounded-[var(--radius-input)] text-[var(--text-primary)] appearance-none focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n >\r\n <option value=\"all\">{t('admin:userRoles.scopeAll', 'Tous les tenants')}</option>\r\n <option value=\"global\">{t('admin:roles.global', 'Global')}</option>\r\n {tenantOptions.map(to => (\r\n <option key={to.id} value={to.id}>{to.name}</option>\r\n ))}\r\n </select>\r\n <ChevronDown className=\"absolute right-2.5 top-1/2 -translate-y-1/2 w-4 h-4 pointer-events-none text-[var(--text-tertiary)]\" />\r\n </div>\r\n </div>\r\n <button\r\n onClick={handleOpenModal}\r\n className=\"flex items-center gap-2 px-4 py-2 rounded-[var(--radius-button)] bg-[var(--color-accent-600)] text-white hover:bg-[var(--color-accent-700)] transition-colors text-sm font-medium\"\r\n >\r\n <Plus className=\"w-4 h-4\" />\r\n {t('admin:userRoles.assignRole', 'Assigner un rôle')}\r\n </button>\r\n </div>\r\n\r\n {/* Overview table */}\r\n {loading ? (\r\n <div className=\"flex items-center justify-center py-12\">\r\n <Loader2 className=\"w-6 h-6 animate-spin text-[var(--color-accent-500)]\" />\r\n </div>\r\n ) : (\r\n <div className=\"overflow-x-auto\">\r\n <table className=\"w-full border border-[var(--border-color)] rounded-[var(--radius-card)] overflow-hidden\">\r\n <thead className=\"bg-[var(--bg-tertiary)]\">\r\n <tr>\r\n <th className=\"text-left px-4 py-3 text-sm font-medium text-[var(--text-secondary)]\">\r\n {t('admin:roles.name', 'Rôle')}\r\n </th>\r\n <th className=\"text-left px-4 py-3 text-sm font-medium text-[var(--text-secondary)]\">\r\n {t('admin:roles.category', 'Catégorie')}\r\n </th>\r\n <th className=\"text-left px-4 py-3 text-sm font-medium text-[var(--text-secondary)]\">\r\n {t('admin:roles.tenant', 'Tenant')}\r\n </th>\r\n <th className=\"text-left px-4 py-3 text-sm font-medium text-[var(--text-secondary)]\">\r\n {t('admin:userRoles.source', 'Source')}\r\n </th>\r\n <th className=\"text-left px-4 py-3 text-sm font-medium text-[var(--text-secondary)] w-24\">\r\n {t('admin:roles.actions', 'Actions')}\r\n </th>\r\n </tr>\r\n </thead>\r\n <tbody className=\"divide-y divide-[var(--border-color)]\">\r\n {filteredAssignedRoles.length === 0 ? (\r\n <tr>\r\n <td colSpan={5} className=\"px-4 py-8 text-center text-[var(--text-muted)]\">\r\n {assignedRoles.length === 0\r\n ? t('admin:userRoles.noAssignedRoles', 'Aucun rôle assigné à cet utilisateur')\r\n : t('admin:userRoles.noRoles', 'Aucun rôle trouvé')}\r\n </td>\r\n </tr>\r\n ) : (\r\n filteredAssignedRoles.map((ar) => {\r\n const roleDetail = roleMap.get(ar.roleId);\r\n const category = roleDetail?.category || 'Custom';\r\n const catStyle = CATEGORY_STYLES[category] || DEFAULT_CATEGORY_STYLE;\r\n const customIcon = roleDetail ? getCustomRoleIcon(roleDetail.code) : null;\r\n const isGlobal = !ar.tenantId;\r\n const isGroupSourced = ar.source === 'Group';\r\n const sourceStyle = SOURCE_STYLES[ar.source] || SOURCE_STYLES.Direct;\r\n const SourceIcon = sourceStyle.icon;\r\n const removingKey = ar.roleId + (ar.tenantId || 'global');\r\n const isRemoving = removing === removingKey;\r\n\r\n return (\r\n <tr key={`${ar.roleId}-${ar.tenantId || 'global'}-${ar.source}`} className=\"hover:bg-[var(--bg-hover)] transition-colors\">\r\n <td className=\"px-4 py-3\">\r\n <div className=\"flex items-center gap-2\">\r\n {customIcon && <span>{customIcon}</span>}\r\n <Link\r\n to={`/administration/permissions/roles/${ar.roleId}`}\r\n className=\"font-medium text-[var(--text-primary)] hover:text-[var(--color-accent-600)] hover:underline transition-colors\"\r\n >\r\n {ar.roleName}\r\n </Link>\r\n </div>\r\n {ar.roleShortName && (\r\n <p className=\"text-xs text-[var(--text-tertiary)] mt-0.5\">{ar.roleShortName}</p>\r\n )}\r\n </td>\r\n <td className=\"px-4 py-3\">\r\n <span className={`px-2 py-1 text-xs rounded-full ${catStyle.bg} ${catStyle.text}`}>\r\n {category}\r\n </span>\r\n </td>\r\n <td className=\"px-4 py-3\">\r\n {isGlobal ? (\r\n <span className=\"inline-flex items-center gap-1 px-2 py-1 text-xs rounded-full bg-[var(--info-bg)] text-[var(--info-text)]\">\r\n <Globe className=\"w-3 h-3\" />\r\n {t('admin:roles.global', 'Global')}\r\n </span>\r\n ) : (\r\n <span className=\"inline-flex items-center gap-1 px-2 py-1 text-xs rounded-full bg-[var(--accent-bg)] text-[var(--color-accent-700)]\">\r\n <Building2 className=\"w-3 h-3\" />\r\n {ar.tenantName || t('admin:roles.unknownTenant', 'Tenant')}\r\n </span>\r\n )}\r\n </td>\r\n <td className=\"px-4 py-3\">\r\n <span className={`inline-flex items-center gap-1 px-2 py-1 text-xs rounded-full ${sourceStyle.bg} ${sourceStyle.text}`}>\r\n <SourceIcon className=\"w-3 h-3\" />\r\n {ar.source === 'Direct'\r\n ? t('admin:userRoles.sourceDirect', 'Direct')\r\n : ar.source === 'Group'\r\n ? ar.sourceGroupName || t('admin:userRoles.sourceGroup', 'Groupe')\r\n : t('admin:userRoles.sourceCustom', 'Personnel')}\r\n </span>\r\n </td>\r\n <td className=\"px-4 py-3\">\r\n {isGroupSourced ? (\r\n <span title={t('admin:userRoles.groupRoleLocked', 'Rôle hérité du groupe, non supprimable')}>\r\n <Lock className=\"w-4 h-4 text-[var(--text-muted)]\" />\r\n </span>\r\n ) : (\r\n <button\r\n onClick={() => handleRemoveRole(ar.roleId, ar.tenantId)}\r\n disabled={isRemoving}\r\n className=\"p-1.5 rounded-[var(--radius-button)] text-[var(--error-text)] hover:bg-[var(--error-bg)] transition-colors disabled:opacity-50\"\r\n title={t('admin:userRoles.removeRole', 'Retirer le rôle')}\r\n >\r\n {isRemoving ? (\r\n <Loader2 className=\"w-4 h-4 animate-spin\" />\r\n ) : (\r\n <Trash2 className=\"w-4 h-4\" />\r\n )}\r\n </button>\r\n )}\r\n </td>\r\n </tr>\r\n );\r\n })\r\n )}\r\n </tbody>\r\n </table>\r\n {assignedRoles.length > 0 && (\r\n <div className=\"px-4 py-2 text-xs text-[var(--text-muted)] bg-[var(--bg-tertiary)] border-t border-[var(--border-color)]\">\r\n {filteredAssignedRoles.length !== assignedRoles.length\r\n ? t('admin:userRoles.totalFiltered', '{{filtered}} / {{count}} rôle(s) affiché(s)', { filtered: filteredAssignedRoles.length, count: assignedRoles.length })\r\n : t('admin:userRoles.totalAssigned', '{{count}} rôle(s) assigné(s)', { count: assignedRoles.length })}\r\n </div>\r\n )}\r\n </div>\r\n )}\r\n\r\n {/* Assign Role Modal */}\r\n {modalOpen && (\r\n <UserAssignRoleModal\r\n userId={userId}\r\n roles={roles}\r\n assignedRoles={assignedRoles}\r\n globalRoleIds={globalRoleIds}\r\n onGlobalRolesUpdate={onGlobalRolesUpdate}\r\n initialTenantId={tenantId}\r\n initialIsGlobalScope={isGlobalScope}\r\n adminTenants={adminTenants}\r\n tenantMemberships={tenantMemberships}\r\n onAssigned={handleAssigned}\r\n onClose={handleCloseModal}\r\n />\r\n )}\r\n </div>\r\n );\r\n}\r\n\r\n// --- Assign Role Modal ---\r\n\r\ninterface UserAssignRoleModalProps {\r\n readonly userId: string;\r\n readonly roles: RoleListDto[];\r\n readonly assignedRoles: UserConsolidatedRoleDto[];\r\n readonly globalRoleIds: string[];\r\n readonly onGlobalRolesUpdate: (roleIds: string[]) => Promise<void>;\r\n readonly initialTenantId?: string;\r\n readonly initialIsGlobalScope: boolean;\r\n readonly adminTenants: AdminTenantInfo[];\r\n readonly tenantMemberships: TenantMembership[];\r\n readonly onAssigned: () => Promise<void>;\r\n readonly onClose: () => void;\r\n}\r\n\r\nfunction UserAssignRoleModal({\r\n userId: _userId,\r\n roles,\r\n assignedRoles,\r\n globalRoleIds,\r\n onGlobalRolesUpdate,\r\n initialTenantId,\r\n initialIsGlobalScope,\r\n adminTenants,\r\n tenantMemberships,\r\n onAssigned,\r\n onClose,\r\n}: UserAssignRoleModalProps) {\r\n const { t } = useTranslation(['admin', 'groups']);\r\n const [searchQuery, setSearchQuery] = useState('');\r\n const [filterCategory, setFilterCategory] = useState<string>('all');\r\n const [filterContext, setFilterContext] = useState<string>('all');\r\n const [filterApplication, setFilterApplication] = useState<string>('all');\r\n const [saving, setSaving] = useState<string | null>(null);\r\n const [error, setError] = useState<string | null>(null);\r\n const savingRef = useRef(false);\r\n\r\n // Only show tenants the user is a member of\r\n const modalTenants = useMemo(() => {\r\n const memberTenantIds = new Set(tenantMemberships.map(m => m.tenantId));\r\n return adminTenants.filter(at => memberTenantIds.has(at.tenantId));\r\n }, [adminTenants, tenantMemberships]);\r\n\r\n // Local scope state for the modal (initialized from parent)\r\n const [modalScope, setModalScope] = useState<ScopeValue>(() => {\r\n if (initialIsGlobalScope || !initialTenantId) return 'global';\r\n const tenant = adminTenants.find(at => at.tenantId === initialTenantId);\r\n if (!tenant) return 'global';\r\n return {\r\n tenantId: tenant.tenantId,\r\n tenantSlug: tenant.tenantSlug,\r\n tenantUserId: '',\r\n tenantName: tenant.tenantName,\r\n };\r\n });\r\n\r\n const modalIsGlobal = modalScope === 'global';\r\n const modalTenantId = !modalIsGlobal ? modalScope.tenantId : undefined;\r\n\r\n // Roles already assigned for the modal's current scope (Direct only - group roles can coexist)\r\n const currentScopeRoleIds = useMemo(() => {\r\n const ids = new Set<string>();\r\n for (const ar of assignedRoles) {\r\n if (ar.source !== 'Direct') continue;\r\n if (modalIsGlobal && !ar.tenantId) ids.add(ar.roleId);\r\n else if (!modalIsGlobal && ar.tenantId === modalTenantId) ids.add(ar.roleId);\r\n }\r\n return ids;\r\n }, [assignedRoles, modalIsGlobal, modalTenantId]);\r\n\r\n // Load tenant's accessible application IDs when a tenant is selected\r\n const [tenantAppIds, setTenantAppIds] = useState<Set<string> | null>(null);\r\n\r\n useEffect(() => {\r\n if (modalIsGlobal || !modalTenantId) {\r\n setTenantAppIds(null);\r\n return;\r\n }\r\n let cancelled = false;\r\n adminApi.tenants.getApplications(modalTenantId).then(apps => {\r\n if (!cancelled) {\r\n setTenantAppIds(new Set(apps.map(a => a.applicationId)));\r\n }\r\n }).catch(() => {\r\n if (!cancelled) setTenantAppIds(null);\r\n });\r\n return () => { cancelled = true; };\r\n }, [modalIsGlobal, modalTenantId]);\r\n\r\n // Roles available for the current scope (filtered by tenant's accessible apps)\r\n const scopedRoles = useMemo(() => {\r\n if (modalIsGlobal || !tenantAppIds) return roles;\r\n return roles.filter(r => !r.applicationId || tenantAppIds.has(r.applicationId));\r\n }, [roles, modalIsGlobal, tenantAppIds]);\r\n\r\n // Build unique contexts from scoped roles\r\n const contexts = useMemo(() => {\r\n const ctxMap = new Map<string, string>();\r\n for (const r of scopedRoles) {\r\n if (r.contextId && r.contextName && !ctxMap.has(r.contextId)) {\r\n ctxMap.set(r.contextId, r.contextName);\r\n }\r\n }\r\n return Array.from(ctxMap.entries()).map(([id, name]) => ({ id, name }));\r\n }, [scopedRoles]);\r\n\r\n // Build unique applications from scoped roles, filtered by selected context\r\n const applications = useMemo(() => {\r\n const appMap = new Map<string, string>();\r\n for (const r of scopedRoles) {\r\n if (!r.applicationId || !r.applicationName) continue;\r\n if (filterContext !== 'all' && r.contextId !== filterContext) continue;\r\n if (!appMap.has(r.applicationId)) {\r\n appMap.set(r.applicationId, r.applicationName);\r\n }\r\n }\r\n return Array.from(appMap.entries())\r\n .map(([id, name]) => ({ id, name }))\r\n .sort((a, b) => a.name.localeCompare(b.name));\r\n }, [scopedRoles, filterContext]);\r\n\r\n // Reset application filter when context changes\r\n const handleContextChange = useCallback((value: string) => {\r\n setFilterContext(value);\r\n setFilterApplication('all');\r\n }, []);\r\n\r\n const categories = useMemo(() => {\r\n const cats = new Set(scopedRoles.map(r => r.category || 'Custom'));\r\n return ['all', ...Array.from(cats).sort((a, b) => a.localeCompare(b))];\r\n }, [scopedRoles]);\r\n\r\n const filteredRoles = useMemo(() => {\r\n let filtered = scopedRoles;\r\n\r\n // Context filter\r\n if (filterContext !== 'all') {\r\n filtered = filtered.filter(r => r.contextId === filterContext);\r\n }\r\n\r\n // Application filter\r\n if (filterApplication !== 'all') {\r\n filtered = filtered.filter(r => r.applicationId === filterApplication);\r\n }\r\n\r\n // Category filter\r\n if (filterCategory !== 'all') {\r\n filtered = filtered.filter(r => (r.category || 'Custom') === filterCategory);\r\n }\r\n\r\n if (searchQuery.trim()) {\r\n const query = searchQuery.toLowerCase().trim();\r\n filtered = filtered.filter(r =>\r\n r.name.toLowerCase().includes(query) ||\r\n r.shortName?.toLowerCase().includes(query) ||\r\n r.description?.toLowerCase().includes(query)\r\n );\r\n }\r\n\r\n return filtered;\r\n }, [scopedRoles, filterContext, filterApplication, filterCategory, searchQuery]);\r\n\r\n const handleAssignRole = useCallback(async (roleId: string) => {\r\n if (savingRef.current) return;\r\n savingRef.current = true;\r\n setSaving(roleId);\r\n setError(null);\r\n\r\n try {\r\n if (modalIsGlobal) {\r\n // Global scope: add to global role IDs via callback\r\n const newRoleIds = [...globalRoleIds, roleId];\r\n await onGlobalRolesUpdate(newRoleIds);\r\n } else if (modalTenantId) {\r\n // Tenant scope: use individual assign endpoint\r\n const membership = tenantMemberships.find(m => m.tenantId === modalTenantId);\r\n if (membership) {\r\n await adminApi.tenants.assignRole(modalTenantId, membership.tenantUserId, roleId);\r\n } else {\r\n throw new Error(t('admin:userRoles.errors.notMember', 'L\\'utilisateur n\\'est pas membre de ce tenant'));\r\n }\r\n }\r\n await onAssigned();\r\n } catch (err) {\r\n console.error('Failed to assign role:', err);\r\n setError(t('admin:userRoles.errors.assignFailed', 'Erreur lors de l\\'assignation du rôle'));\r\n } finally {\r\n setSaving(null);\r\n savingRef.current = false;\r\n }\r\n }, [modalIsGlobal, modalTenantId, globalRoleIds, onGlobalRolesUpdate, tenantMemberships, onAssigned, t]);\r\n\r\n return (\r\n <div className=\"fixed inset-0 z-[100] flex items-center justify-center p-4 bg-black/60 backdrop-blur-sm\">\r\n <div className=\"relative w-full max-w-2xl h-[80vh] bg-[var(--bg-card)] rounded-[var(--radius-card)] shadow-2xl border border-[var(--border-color)] overflow-hidden flex flex-col animate-in fade-in zoom-in duration-200\">\r\n {/* Header */}\r\n <div className=\"flex items-center justify-between px-6 py-4 border-b border-[var(--border-color)]\">\r\n <div className=\"flex items-center gap-4\">\r\n <div>\r\n <h2 className=\"text-lg font-semibold text-[var(--text-primary)]\">\r\n {t('admin:userRoles.assignRole', 'Assigner un rôle')}\r\n </h2>\r\n </div>\r\n <TenantScopeSelector\r\n value={modalScope}\r\n onChange={setModalScope}\r\n adminTenants={modalTenants}\r\n />\r\n </div>\r\n <button\r\n onClick={onClose}\r\n className=\"p-1.5 rounded-[var(--radius-button)] text-[var(--text-tertiary)] hover:text-[var(--text-primary)] hover:bg-[var(--bg-hover)] transition-colors\"\r\n >\r\n <X className=\"w-5 h-5\" />\r\n </button>\r\n </div>\r\n\r\n {/* Error alert */}\r\n {error && (\r\n <div className=\"mx-6 mt-3 p-3 rounded-[var(--radius-card)] bg-[var(--error-bg)] border border-[var(--error-border)] flex items-center gap-3\">\r\n <AlertCircle className=\"w-4 h-4 text-[var(--error-text)] flex-shrink-0\" />\r\n <p className=\"flex-1 text-sm text-[var(--error-text)]\">{error}</p>\r\n <button onClick={() => setError(null)}>\r\n <X className=\"w-3.5 h-3.5 text-[var(--error-text)]\" />\r\n </button>\r\n </div>\r\n )}\r\n\r\n {/* Filters */}\r\n <div className=\"px-6 py-3 border-b border-[var(--border-color)] flex flex-col gap-3\">\r\n <div className=\"relative\">\r\n <Search className=\"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-[var(--text-muted)]\" />\r\n <input\r\n type=\"text\"\r\n value={searchQuery}\r\n onChange={(e) => setSearchQuery(e.target.value)}\r\n placeholder={t('admin:userRoles.search', 'Rechercher un rôle...')}\r\n className=\"w-full pl-10 pr-4 py-2 text-sm bg-[var(--bg-secondary)] border border-[var(--border-color)] rounded-[var(--radius-input)] text-[var(--text-primary)] placeholder-[var(--text-muted)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n autoFocus\r\n />\r\n </div>\r\n <div className=\"flex items-center gap-2\">\r\n <Filter className=\"w-4 h-4 text-[var(--text-secondary)] shrink-0\" />\r\n <select\r\n value={filterContext}\r\n onChange={(e) => handleContextChange(e.target.value)}\r\n className=\"flex-1 min-w-0 px-3 py-2 text-sm bg-[var(--bg-secondary)] border border-[var(--border-color)] rounded-[var(--radius-input)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n >\r\n <option value=\"all\">{t('admin:userRoles.filterByContext', 'Tous les contextes')}</option>\r\n {contexts.map(ctx => (\r\n <option key={ctx.id} value={ctx.id}>{ctx.name}</option>\r\n ))}\r\n </select>\r\n <select\r\n value={filterApplication}\r\n onChange={(e) => setFilterApplication(e.target.value)}\r\n disabled={filterContext === 'all' || applications.length === 0}\r\n className=\"flex-1 min-w-0 px-3 py-2 text-sm bg-[var(--bg-secondary)] border border-[var(--border-color)] rounded-[var(--radius-input)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)] disabled:opacity-50\"\r\n >\r\n <option value=\"all\">{t('admin:userRoles.filterByApplication', 'Toutes les applications')}</option>\r\n {applications.map(app => (\r\n <option key={app.id} value={app.id}>{app.name}</option>\r\n ))}\r\n </select>\r\n <select\r\n value={filterCategory}\r\n onChange={(e) => setFilterCategory(e.target.value)}\r\n className=\"flex-1 min-w-0 px-3 py-2 text-sm bg-[var(--bg-secondary)] border border-[var(--border-color)] rounded-[var(--radius-input)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n >\r\n <option value=\"all\">{t('admin:userRoles.filterByCategory', 'Toutes les catégories')}</option>\r\n {categories.filter(c => c !== 'all').map(cat => (\r\n <option key={cat} value={cat}>{cat}</option>\r\n ))}\r\n </select>\r\n </div>\r\n </div>\r\n\r\n {/* Role list */}\r\n <div className=\"flex-1 overflow-y-auto\">\r\n <table className=\"w-full\">\r\n <thead className=\"bg-[var(--bg-tertiary)] sticky top-0 z-10\">\r\n <tr>\r\n <th className=\"text-left px-6 py-2.5 text-sm font-medium text-[var(--text-secondary)]\">\r\n {t('admin:roles.name', 'Rôle')}\r\n </th>\r\n <th className=\"text-left px-4 py-2.5 text-sm font-medium text-[var(--text-secondary)]\">\r\n {t('admin:roles.category', 'Catégorie')}\r\n </th>\r\n <th className=\"text-right px-6 py-2.5 text-sm font-medium text-[var(--text-secondary)] w-32\">\r\n {t('admin:roles.actions', 'Actions')}\r\n </th>\r\n </tr>\r\n </thead>\r\n <tbody className=\"divide-y divide-[var(--border-color)]\">\r\n {filteredRoles.length === 0 ? (\r\n <tr>\r\n <td colSpan={3} className=\"px-6 py-12 text-center\">\r\n <Search className=\"w-8 h-8 mx-auto mb-2 text-[var(--text-tertiary)]\" />\r\n <p className=\"text-[var(--text-muted)]\">\r\n {t('admin:userRoles.noRoles', 'Aucun rôle trouvé')}\r\n </p>\r\n </td>\r\n </tr>\r\n ) : (\r\n filteredRoles.map((role) => {\r\n const isAlreadyAssigned = currentScopeRoleIds.has(role.id);\r\n const catStyle = CATEGORY_STYLES[role.category || 'Custom'] || DEFAULT_CATEGORY_STYLE;\r\n const customIcon = getCustomRoleIcon(role.code);\r\n const isAssigning = saving === role.id;\r\n\r\n return (\r\n <tr\r\n key={role.id}\r\n className={`transition-colors ${isAlreadyAssigned ? 'bg-[var(--accent-bg)] opacity-60' : 'hover:bg-[var(--bg-hover)]'}`}\r\n >\r\n <td className=\"px-6 py-3\">\r\n <div className=\"flex items-center gap-2\">\r\n {customIcon && <span>{customIcon}</span>}\r\n <div>\r\n <span className=\"font-medium text-[var(--text-primary)]\">{role.name}</span>\r\n {role.description && (\r\n <p className=\"text-xs text-[var(--text-tertiary)] mt-0.5 max-w-sm truncate\">{role.description}</p>\r\n )}\r\n </div>\r\n </div>\r\n </td>\r\n <td className=\"px-4 py-3\">\r\n <span className={`px-2 py-1 text-xs rounded-full ${catStyle.bg} ${catStyle.text}`}>\r\n {role.category || 'Custom'}\r\n </span>\r\n </td>\r\n <td className=\"px-6 py-3 text-right\">\r\n {isAlreadyAssigned ? (\r\n <span className=\"text-xs text-[var(--text-muted)]\">\r\n {t('admin:userRoles.alreadyAssigned', 'Déjà assigné')}\r\n </span>\r\n ) : (\r\n <button\r\n onClick={() => handleAssignRole(role.id)}\r\n disabled={isAssigning}\r\n className=\"inline-flex items-center gap-1.5 px-3 py-1.5 rounded-[var(--radius-button)] bg-[var(--color-accent-600)] text-white text-xs font-medium hover:bg-[var(--color-accent-700)] transition-colors disabled:opacity-50\"\r\n >\r\n {isAssigning ? (\r\n <Loader2 className=\"w-3.5 h-3.5 animate-spin\" />\r\n ) : (\r\n <Plus className=\"w-3.5 h-3.5\" />\r\n )}\r\n {t('admin:userRoles.assign', 'Assigner')}\r\n </button>\r\n )}\r\n </td>\r\n </tr>\r\n );\r\n })\r\n )}\r\n </tbody>\r\n </table>\r\n </div>\r\n\r\n {/* Footer */}\r\n <div className=\"px-6 py-3 border-t border-[var(--border-color)] bg-[var(--bg-tertiary)] flex justify-end\">\r\n <button\r\n onClick={onClose}\r\n className=\"px-4 py-2 rounded-[var(--radius-button)] bg-[var(--bg-secondary)] text-[var(--text-secondary)] hover:bg-[var(--bg-hover)] transition-colors text-sm font-medium\"\r\n >\r\n {t('common:close', 'Fermer')}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n}\r\n","import type { ReactElement } from 'react';\r\nimport React, { useState, useMemo, useCallback, createRef } from 'react';\r\nimport { useTranslation } from 'react-i18next';\r\nimport { useNavigate } from 'react-router-dom';\r\nimport {\r\n Check,\r\n Star,\r\n Eye,\r\n Ban,\r\n ChevronRight,\r\n ChevronDown,\r\n FolderOpen,\r\n Box,\r\n FileText,\r\n Shield,\r\n Info,\r\n Loader2,\r\n AlertCircle,\r\n Plus,\r\n Edit,\r\n Trash2,\r\n UserPlus,\r\n Play,\r\n Database,\r\n UserCheck,\r\n Users,\r\n User,\r\n} from 'lucide-react';\r\nimport { useUserPermissions } from '@/hooks/useUserPermissions';\r\nimport { useCollapsibleState } from '@/hooks/useCollapsibleState';\r\nimport { groupByApplicationWithSections, calculatePermissionStatus, calculateModuleWithSectionsStatus, getPermissionCellBackground } from '@/utils/permissionUtils';\r\nimport { PermissionStatusIndicator } from './PermissionStatusIndicator';\r\nimport { PermissionPopover } from '../PermissionPopover';\r\nimport type { ResourceNode, PermissionStatus, PermissionInheritanceInfo, ModuleWithSections, SectionWithResources } from './types';\r\nimport type { RoleDto, MatrixRoleDto, UserConsolidatedRoleDto } from '@/services/api/adminApi';\r\nimport { adminApi } from '@/services/api/adminApi';\r\n\r\n/** Helper: Get unique tenant names from consolidated roles map for source roles */\r\nfunction getTenantNamesFromSourceRoles(\r\n sourceRoles: RoleDto[],\r\n consolidatedRolesMap: Map<string, UserConsolidatedRoleDto>,\r\n globalLabel: string\r\n): string[] {\r\n const tenantNames = new Set<string>();\r\n sourceRoles.forEach(role => {\r\n const cr = consolidatedRolesMap.get(role.id);\r\n if (cr) {\r\n tenantNames.add(cr.tenantName || globalLabel);\r\n }\r\n });\r\n return Array.from(tenantNames);\r\n}\r\n\r\n/** Helper: Get unique source types from consolidated roles */\r\nfunction getSourceTypesFromConsolidatedRoles(\r\n sourceRoles: RoleDto[],\r\n consolidatedRolesMap: Map<string, UserConsolidatedRoleDto>\r\n): Array<{ type: 'Direct' | 'Group' | 'Custom'; groupName?: string }> {\r\n const sources: Array<{ type: 'Direct' | 'Group' | 'Custom'; groupName?: string }> = [];\r\n sourceRoles.forEach(role => {\r\n const cr = consolidatedRolesMap.get(role.id);\r\n if (cr) {\r\n const existing = sources.find(s =>\r\n s.type === cr.source &&\r\n (s.type === 'Direct' || s.type === 'Custom' || s.groupName === cr.sourceGroupName)\r\n );\r\n if (!existing) {\r\n sources.push({\r\n type: cr.source,\r\n groupName: cr.sourceGroupName || undefined,\r\n });\r\n }\r\n }\r\n });\r\n return sources;\r\n}\r\n\r\nconst ACTION_ICONS: Record<string, React.ReactNode> = {\r\n '*': <Shield className=\"h-3.5 w-3.5\" />,\r\n read: <Eye className=\"h-3.5 w-3.5\" />,\r\n create: <Plus className=\"h-3.5 w-3.5\" />,\r\n update: <Edit className=\"h-3.5 w-3.5\" />,\r\n delete: <Trash2 className=\"h-3.5 w-3.5\" />,\r\n assign: <UserPlus className=\"h-3.5 w-3.5\" />,\r\n execute: <Play className=\"h-3.5 w-3.5\" />,\r\n};\r\n\r\ntype ActionColor = 'bg-[var(--accent-bg)] text-[var(--accent-text)] border-[var(--accent-border)]'\r\n | 'bg-[var(--info-bg)] text-[var(--info-text)] border-[var(--info-border)]'\r\n | 'bg-[var(--success-bg)] text-[var(--success-text)] border-[var(--success-border)]'\r\n | 'bg-[var(--warning-bg)] text-[var(--warning-text)] border-[var(--warning-border)]'\r\n | 'bg-[var(--error-bg)] text-[var(--error-text)] border-[var(--error-border)]';\r\n\r\nconst ACTION_COLORS: Record<string, ActionColor> = {\r\n '*': 'bg-[var(--accent-bg)] text-[var(--accent-text)] border-[var(--accent-border)]',\r\n read: 'bg-[var(--info-bg)] text-[var(--info-text)] border-[var(--info-border)]',\r\n create: 'bg-[var(--success-bg)] text-[var(--success-text)] border-[var(--success-border)]',\r\n update: 'bg-[var(--warning-bg)] text-[var(--warning-text)] border-[var(--warning-border)]',\r\n delete: 'bg-[var(--error-bg)] text-[var(--error-text)] border-[var(--error-border)]',\r\n assign: 'bg-[var(--accent-bg)] text-[var(--accent-text)] border-[var(--accent-border)]',\r\n execute: 'bg-[var(--warning-bg)] text-[var(--warning-text)] border-[var(--warning-border)]',\r\n};\r\n\r\ninterface UserPermissionMatrixProps {\r\n readonly userId: string;\r\n readonly compact?: boolean;\r\n /** Optional tenant ID for tenant-scoped permissions */\r\n readonly tenantId?: string;\r\n}\r\n\r\nexport function UserPermissionMatrix({ userId, compact = false, tenantId }: UserPermissionMatrixProps): ReactElement {\r\n const { t } = useTranslation('admin');\r\n const navigate = useNavigate();\r\n const {\r\n loading,\r\n error,\r\n user,\r\n userRoles,\r\n filteredResources,\r\n effectivePermissions,\r\n filters,\r\n applications,\r\n modules,\r\n updateFilters,\r\n getPermissionSources,\r\n reloadData,\r\n isTenantMode,\r\n tenantMember,\r\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\r\n assignTenantRoles: _assignTenantRoles,\r\n consolidatedRoles,\r\n } = useUserPermissions({ userId, tenantId });\r\n\r\n // Create a map for quick lookup of consolidated role info by roleId\r\n const consolidatedRolesMap = useMemo(() => {\r\n const map = new Map<string, UserConsolidatedRoleDto>();\r\n consolidatedRoles.forEach(cr => map.set(cr.roleId, cr));\r\n return map;\r\n }, [consolidatedRoles]);\r\n\r\n const { collapsedApps, toggleApp } = useCollapsibleState();\r\n const [collapsedModules, setCollapsedModules] = useState<Set<string>>(new Set());\r\n const [collapsedSections, setCollapsedSections] = useState<Set<string>>(new Set());\r\n const [statusFilters, setStatusFilters] = useState<Set<PermissionStatus>>(new Set());\r\n const [openPopover, setOpenPopover] = useState<string | null>(null);\r\n const [customRoleId, setCustomRoleId] = useState<string | null>(null);\r\n const [customRolePermissions, setCustomRolePermissions] = useState<Set<string>>(new Set());\r\n const [togglingPermission, setTogglingPermission] = useState<string | null>(null);\r\n const [loadingCustomRole, setLoadingCustomRole] = useState(false);\r\n\r\n React.useEffect(() => {\r\n const loadCustomRole = async () => {\r\n try {\r\n setLoadingCustomRole(true);\r\n\r\n // In tenant mode, load tenant-scoped custom role\r\n if (isTenantMode && tenantId && tenantMember) {\r\n const role = await adminApi.tenants.getMemberCustomRole(tenantId, tenantMember.userId);\r\n if (role) {\r\n setCustomRoleId(role.id);\r\n setCustomRolePermissions(new Set((role.permissions ?? []).map(p => p.id)));\r\n } else {\r\n setCustomRoleId(null);\r\n setCustomRolePermissions(new Set());\r\n }\r\n } else {\r\n // Global mode: load global custom role\r\n const role = await adminApi.users.getCustomRole(userId);\r\n if (role) {\r\n setCustomRoleId(role.id);\r\n setCustomRolePermissions(new Set((role.permissions ?? []).map(p => p.id)));\r\n } else {\r\n setCustomRoleId(null);\r\n setCustomRolePermissions(new Set());\r\n }\r\n }\r\n } catch (err) {\r\n if (!(err instanceof Error && err.message.includes('404'))) {\r\n console.error('Failed to load custom role:', err);\r\n }\r\n setCustomRoleId(null);\r\n setCustomRolePermissions(new Set());\r\n } finally {\r\n setLoadingCustomRole(false);\r\n }\r\n };\r\n loadCustomRole();\r\n }, [userId, tenantId, isTenantMode, tenantMember]);\r\n\r\n const handleTogglePermission = async (permissionId: string) => {\r\n try {\r\n setTogglingPermission(permissionId);\r\n let roleId = customRoleId;\r\n let currentPermissions = new Set(customRolePermissions);\r\n\r\n // In tenant mode, use tenant-scoped custom role\r\n if (isTenantMode && tenantId && tenantMember) {\r\n if (!roleId) {\r\n const newRole = await adminApi.tenants.createMemberCustomRole(tenantId, tenantMember.userId);\r\n roleId = newRole.id;\r\n setCustomRoleId(roleId);\r\n currentPermissions = new Set();\r\n }\r\n\r\n const newPermissions = new Set(currentPermissions);\r\n if (newPermissions.has(permissionId)) {\r\n newPermissions.delete(permissionId);\r\n } else {\r\n newPermissions.add(permissionId);\r\n }\r\n\r\n // Update role permissions\r\n const role = await adminApi.roles.getById(roleId);\r\n await adminApi.roles.update(roleId, {\r\n name: role.name,\r\n shortName: role.shortName || undefined,\r\n category: role.category || undefined,\r\n description: role.description || undefined,\r\n permissionIds: Array.from(newPermissions),\r\n });\r\n\r\n setCustomRolePermissions(newPermissions);\r\n } else {\r\n // Global mode: use global custom role\r\n if (!roleId) {\r\n const newRole = await adminApi.users.createCustomRole(userId);\r\n roleId = newRole.id;\r\n setCustomRoleId(roleId);\r\n currentPermissions = new Set();\r\n }\r\n\r\n const newPermissions = new Set(currentPermissions);\r\n if (newPermissions.has(permissionId)) {\r\n newPermissions.delete(permissionId);\r\n } else {\r\n newPermissions.add(permissionId);\r\n }\r\n\r\n const role = await adminApi.roles.getById(roleId);\r\n await adminApi.roles.update(roleId, {\r\n name: role.name,\r\n shortName: role.shortName || undefined,\r\n category: role.category || undefined,\r\n description: role.description || undefined,\r\n permissionIds: Array.from(newPermissions),\r\n });\r\n\r\n setCustomRolePermissions(newPermissions);\r\n }\r\n\r\n // Refresh data without full page reload\r\n await reloadData();\r\n } catch (err) {\r\n console.error('Failed to toggle permission:', err);\r\n } finally {\r\n setTogglingPermission(null);\r\n }\r\n };\r\n\r\n const handleCellClick = (resourceId: string) => {\r\n if (openPopover === resourceId) {\r\n setOpenPopover(null);\r\n } else {\r\n setOpenPopover(resourceId);\r\n }\r\n };\r\n\r\n const toggleStatusFilter = (status: PermissionStatus) => {\r\n setStatusFilters(prev => {\r\n const next = new Set(prev);\r\n if (next.has(status)) {\r\n next.delete(status);\r\n } else {\r\n next.add(status);\r\n }\r\n return next;\r\n });\r\n };\r\n\r\n const toggleModule = (moduleId: string) => {\r\n setCollapsedModules(prev => {\r\n const next = new Set(prev);\r\n if (next.has(moduleId)) {\r\n next.delete(moduleId);\r\n } else {\r\n next.add(moduleId);\r\n }\r\n return next;\r\n });\r\n };\r\n\r\n const toggleSection = (sectionId: string) => {\r\n setCollapsedSections(prev => {\r\n const next = new Set(prev);\r\n if (next.has(sectionId)) {\r\n next.delete(sectionId);\r\n } else {\r\n next.add(sectionId);\r\n }\r\n return next;\r\n });\r\n };\r\n\r\n const getAllPermissionsForResource = useCallback((resource: ResourceNode) => {\r\n const allPermissions = [...resource.permissions];\r\n\r\n if (resource.childSections) {\r\n resource.childSections.forEach(section => {\r\n allPermissions.push(...section.permissions);\r\n });\r\n }\r\n\r\n return allPermissions;\r\n }, []);\r\n\r\n const getPermissionStatusForUser = useCallback((resource: ResourceNode, isSection: boolean = false): { status: PermissionStatus; grantedCount: number } => {\r\n if (isSection) {\r\n return calculatePermissionStatus(resource, (permId) => effectivePermissions.has(permId));\r\n }\r\n\r\n const allPermissions = getAllPermissionsForResource(resource);\r\n const grantedCount = allPermissions.filter(p => effectivePermissions.has(p.id)).length;\r\n const totalCount = allPermissions.length;\r\n\r\n let status: PermissionStatus;\r\n if (grantedCount === 0) {\r\n status = 'none';\r\n } else if (grantedCount === totalCount) {\r\n status = 'all';\r\n } else {\r\n const hasOnlyRead = allPermissions.every(p =>\r\n !effectivePermissions.has(p.id) || p.action === 'read'\r\n ) && allPermissions.some(p => p.action === 'read' && effectivePermissions.has(p.id));\r\n status = hasOnlyRead ? 'read-only' : 'some';\r\n }\r\n\r\n return { status, grantedCount };\r\n }, [effectivePermissions, getAllPermissionsForResource]);\r\n\r\n const filterModulesByStatus = (modules: ModuleWithSections[]) => {\r\n return modules.filter(m => {\r\n const { status } = calculateModuleWithSectionsStatus(m.module, m.sections, (permId) => effectivePermissions.has(permId));\r\n return statusFilters.has(status);\r\n });\r\n };\r\n\r\n const filterApplicationsByModules = (applications: { application: string; modules: ModuleWithSections[] }[]) => {\r\n return applications.map(app => ({\r\n ...app,\r\n modules: filterModulesByStatus(app.modules)\r\n })).filter(app => app.modules.length > 0);\r\n };\r\n\r\n const applyUserStatusFilters = (grouped: ReturnType<typeof groupByApplicationWithSections>) => {\r\n if (statusFilters.size === 0) return grouped;\r\n return filterApplicationsByModules(grouped);\r\n };\r\n\r\n const groupedResources = useMemo(() => {\r\n let grouped = groupByApplicationWithSections(filteredResources);\r\n return applyUserStatusFilters(grouped);\r\n }, [filteredResources, statusFilters, effectivePermissions]);\r\n\r\n // Count total modules\r\n const totalModuleCount = useMemo(() => {\r\n return groupedResources.reduce((sum, app) =>\r\n sum + app.modules.length, 0);\r\n }, [groupedResources]);\r\n\r\n const addSourceRolesFromPermission = (permId: string, sourceRoles: RoleDto[]) => {\r\n const roles = getPermissionSources(permId);\r\n roles.forEach(role => {\r\n if (!sourceRoles.find(r => r.id === role.id)) {\r\n sourceRoles.push(role);\r\n }\r\n });\r\n };\r\n\r\n const getSourceRolesForResource = (resource: ResourceNode): RoleDto[] => {\r\n const sourceRoles: RoleDto[] = [];\r\n // Get permissions for this level only (module or section)\r\n resource.permissions.forEach(perm => {\r\n if (effectivePermissions.has(perm.id)) {\r\n addSourceRolesFromPermission(perm.id, sourceRoles);\r\n }\r\n });\r\n return sourceRoles;\r\n };\r\n\r\n const isCustomRole = (roleName: string): boolean => {\r\n return roleName.startsWith('user_') && roleName.endsWith('_custom');\r\n };\r\n\r\n const getDisplayName = (role: RoleDto): string => {\r\n return isCustomRole(role.name) ? t('userPermissions.customBadge', 'Custom') : (role.shortName || role.name);\r\n };\r\n\r\n // Create a \"virtual role\" representing the user for the permission popover\r\n const userAsRole: MatrixRoleDto | null = useMemo(() => {\r\n if (!user) return null;\r\n return {\r\n id: customRoleId || `user_${userId}_custom`,\r\n name: user.fullName,\r\n shortName: user.fullName,\r\n category: 'Custom' as const,\r\n description: null,\r\n isSystem: false,\r\n permissions: [],\r\n permissionIds: [],\r\n };\r\n }, [user, customRoleId, userId]);\r\n\r\n // Adapter function to provide inheritance info for permissions\r\n const getUserPermissionInheritance = useCallback((_roleId: string, permissionId: string): PermissionInheritanceInfo => {\r\n const isGranted = effectivePermissions.has(permissionId);\r\n const isFromCustomRole = customRolePermissions.has(permissionId);\r\n const sourceRoles = isGranted ? getPermissionSources(permissionId) : [];\r\n const inheritedRole = sourceRoles.find(r => !isCustomRole(r.name));\r\n\r\n return {\r\n isDirect: isFromCustomRole,\r\n isInherited: isGranted && !isFromCustomRole && sourceRoles.length > 0,\r\n inheritedFromPath: inheritedRole ? inheritedRole.name : undefined,\r\n inheritedFromId: inheritedRole?.id,\r\n };\r\n }, [effectivePermissions, customRolePermissions, getPermissionSources]);\r\n\r\n if (loading) {\r\n return (\r\n <div className=\"flex items-center justify-center py-12\">\r\n <Loader2 className=\"h-8 w-8 animate-spin text-[var(--color-accent-500)]\" />\r\n <span className=\"ml-3 text-[var(--text-secondary)]\">{t('userPermissions.loading')}</span>\r\n </div>\r\n );\r\n }\r\n\r\n if (error) {\r\n return (\r\n <div className=\"rounded-[var(--radius-card)] bg-[var(--error-bg)] p-4 border border-[var(--error-border)]\">\r\n <div className=\"flex items-center\">\r\n <AlertCircle className=\"h-5 w-5 text-[var(--error-text)]\" />\r\n <p className=\"ml-2 text-sm text-[var(--error-text)]\">{error}</p>\r\n </div>\r\n </div>\r\n );\r\n }\r\n\r\n if (!user) {\r\n return (\r\n <div className=\"text-center py-12 text-[var(--text-secondary)]\">\r\n <Shield className=\"h-12 w-12 mx-auto mb-4 text-[var(--text-muted)]\" />\r\n <p>{t('userPermissions.noUser')}</p>\r\n </div>\r\n );\r\n }\r\n\r\n const getUserResourceIcon = (level: 'module' | 'section' | 'resource') => {\r\n if (level === 'resource') return <Database className=\"h-3.5 w-3.5 text-[var(--text-muted)]\" />;\r\n if (level === 'section') return <FileText className=\"h-3.5 w-3.5 text-[var(--text-muted)]\" />;\r\n return <Box className=\"h-3.5 w-3.5 text-[var(--text-secondary)]\" />;\r\n };\r\n\r\n const getUserResourceLabelClass = (level: 'module' | 'section' | 'resource'): string => {\r\n if (level === 'resource') return 'text-[var(--text-muted)] italic';\r\n if (level === 'section') return 'text-[var(--text-secondary)]';\r\n return 'font-medium text-[var(--text-primary)]';\r\n };\r\n\r\n const getUserPaddingClass = (level: 'module' | 'section' | 'resource'): string => {\r\n if (level === 'resource') return 'pl-28';\r\n if (level === 'section') return 'pl-22';\r\n return 'pl-16';\r\n };\r\n\r\n const getSourceTypeLabelClass = (type: 'Direct' | 'Group' | 'Custom'): string => {\r\n if (type === 'Direct') {\r\n return 'bg-[var(--success-bg)] text-[var(--success-text)] border border-[var(--success-border)]';\r\n }\r\n if (type === 'Custom') {\r\n return 'bg-[var(--color-accent-100)] text-[var(--color-accent-700)] dark:bg-[var(--color-accent-900)] dark:text-[var(--color-accent-300)] border border-[var(--color-accent-300)] dark:border-[var(--color-accent-700)]';\r\n }\r\n return 'bg-[var(--warning-bg)] text-[var(--warning-text)] border border-[var(--warning-border)]';\r\n };\r\n\r\n const getTenantTagClass = (tenantName: string, t: Function): string => {\r\n const globalLabel = t('userPermissions.globalScope', 'Global');\r\n return tenantName === globalLabel\r\n ? 'bg-[var(--info-bg)] text-[var(--info-text)] border border-[var(--info-border)]'\r\n : 'bg-[var(--bg-tertiary)] text-[var(--text-secondary)] border border-[var(--border-color)]';\r\n };\r\n\r\n const renderSectionWithResources = (sectionWithResources: SectionWithResources, moduleIndex: number, sectionIndex: number) => {\r\n const { section, resources } = sectionWithResources;\r\n const hasResources = resources.length > 0;\r\n const isSectionCollapsed = collapsedSections.has(section.id);\r\n\r\n return (\r\n <React.Fragment key={section.id}>\r\n {renderResourceRow(section, moduleIndex + sectionIndex + 1, 'section', hasResources, isSectionCollapsed)}\r\n {hasResources && !isSectionCollapsed && resources.map((resource: ResourceNode, resourceIndex: number) =>\r\n renderResourceRow(resource, moduleIndex + sectionIndex + resourceIndex + 2, 'resource', false, false)\r\n )}\r\n </React.Fragment>\r\n );\r\n };\r\n\r\n const renderModuleWithSections = (moduleWithSections: ModuleWithSections, moduleIndex: number) => {\r\n const { module, sections } = moduleWithSections;\r\n const hasSections = sections.length > 0;\r\n const isModuleCollapsed = collapsedModules.has(module.id);\r\n\r\n return (\r\n <React.Fragment key={module.id}>\r\n {renderResourceRow(module, moduleIndex, 'module', hasSections, isModuleCollapsed)}\r\n {hasSections && !isModuleCollapsed && sections.map((sectionWithResources: SectionWithResources, sectionIndex: number) =>\r\n renderSectionWithResources(sectionWithResources, moduleIndex, sectionIndex)\r\n )}\r\n </React.Fragment>\r\n );\r\n };\r\n\r\n const renderResourceRow = (\r\n resource: ResourceNode,\r\n rowIndex: number,\r\n level: 'module' | 'section' | 'resource',\r\n hasChildren: boolean = false,\r\n isCollapsed: boolean = false\r\n ) => {\r\n const isSection = level === 'section';\r\n const { status, grantedCount} = getPermissionStatusForUser(resource, isSection);\r\n const totalCount = isSection ? resource.permissions.length : getAllPermissionsForResource(resource).length;\r\n const cellBg = getPermissionCellBackground(status);\r\n const sourceRoles = getSourceRolesForResource(resource);\r\n const isPopoverOpen = openPopover === resource.id;\r\n const buttonRef = createRef<HTMLButtonElement>();\r\n const paddingLeft = getUserPaddingClass(level);\r\n\r\n return (\r\n <tr\r\n key={resource.id}\r\n className={`hover:bg-[var(--bg-hover)] ${rowIndex % 2 === 0 ? 'item-light' : 'item-medium'}`}\r\n >\r\n {/* Sticky Resource Name Column */}\r\n <td\r\n className={`sticky left-0 z-10 ${rowIndex % 2 === 0 ? 'item-light' : 'item-medium'} px-3 py-2 ${paddingLeft}`}\r\n style={{ width: '280px', minWidth: '280px', maxWidth: '280px' }}\r\n >\r\n <div className=\"flex items-center gap-2\">\r\n {/* Toggle button for items with children */}\r\n {hasChildren && (\r\n <button\r\n onClick={() => level === 'module' ? toggleModule(resource.id) : toggleSection(resource.id)}\r\n className=\"p-0.5 hover:bg-[var(--bg-hover)] rounded\"\r\n >\r\n {isCollapsed ? (\r\n <ChevronRight className=\"h-3 w-3 text-[var(--text-muted)]\" />\r\n ) : (\r\n <ChevronDown className=\"h-3 w-3 text-[var(--text-muted)]\" />\r\n )}\r\n </button>\r\n )}\r\n {getUserResourceIcon(level)}\r\n <span className={`text-sm ${getUserResourceLabelClass(level)}`}>\r\n {resource.label}\r\n </span>\r\n <span className=\"text-xs text-[var(--text-muted)]\">\r\n ({totalCount})\r\n </span>\r\n </div>\r\n </td>\r\n\r\n {/* Status Cell - Clickable to open popover */}\r\n <td\r\n className={`px-0 py-1 text-center relative ${cellBg}`}\r\n style={{ width: '60px', minWidth: '60px', maxWidth: '60px' }}\r\n >\r\n <button\r\n ref={buttonRef}\r\n type=\"button\"\r\n onClick={() => handleCellClick(resource.id)}\r\n className={`w-full h-full min-h-[36px] flex items-center justify-center rounded transition-colors hover:opacity-80 ${\r\n isPopoverOpen ? 'ring-2 ring-[var(--color-accent-500)]' : ''\r\n }`}\r\n title={`${resource.label}: ${grantedCount}/${totalCount}`}\r\n >\r\n <PermissionStatusIndicator\r\n status={status}\r\n grantedCount={grantedCount}\r\n totalCount={totalCount}\r\n />\r\n </button>\r\n {isPopoverOpen && user && userAsRole && (\r\n <PermissionPopover\r\n mode=\"editable\"\r\n role={userAsRole}\r\n resource={resource}\r\n onClose={() => setOpenPopover(null)}\r\n onTogglePermission={handleTogglePermission}\r\n getPermissionInheritance={getUserPermissionInheritance}\r\n />\r\n )}\r\n </td>\r\n\r\n {/* Source Roles */}\r\n <td className=\"px-3 py-2\">\r\n <div className=\"flex flex-wrap gap-1\">\r\n {sourceRoles.length > 0 ? (\r\n sourceRoles.map(role => {\r\n const isCustom = isCustomRole(role.name);\r\n const displayName = getDisplayName(role);\r\n return (\r\n <button\r\n key={role.id}\r\n onClick={() => !isCustom && navigate(`/administration/permissions/roles/${role.id}`)}\r\n className={`inline-flex items-center gap-1 px-2 py-0.5 text-xs rounded-full transition-all ${\r\n isCustom\r\n ? 'bg-[var(--color-accent-100)] text-[var(--color-accent-700)] dark:bg-[var(--color-accent-900)] dark:text-[var(--color-accent-300)] border border-[var(--color-accent-300)] dark:border-[var(--color-accent-700)] cursor-default'\r\n : 'bg-[var(--bg-tertiary)] text-[var(--text-secondary)] border border-[var(--border-color)] cursor-pointer hover:ring-1 hover:ring-[var(--color-accent-500)] hover:shadow-sm'\r\n }`}\r\n title={isCustom ? t('userPermissions.customRoleTooltip', 'Rôle personnalisé') : t('userPermissions.clickToViewRole', 'Cliquer pour voir le rôle')}\r\n >\r\n {displayName}\r\n {isCustom && <Star className=\"h-3 w-3\" />}\r\n </button>\r\n );\r\n })\r\n ) : (\r\n <span className=\"text-xs text-[var(--text-muted)]\">-</span>\r\n )}\r\n </div>\r\n </td>\r\n\r\n {/* Tenant Column */}\r\n <td className=\"px-3 py-2\">\r\n <div className=\"flex flex-wrap gap-1\">\r\n {sourceRoles.length > 0 ? (\r\n getTenantNamesFromSourceRoles(sourceRoles, consolidatedRolesMap, t('userPermissions.globalScope', 'Global')).map((tenantName, idx) => (\r\n <span\r\n key={`tenant-${tenantName}-${idx}`}\r\n className={`inline-flex items-center px-2 py-0.5 text-xs rounded-full ${getTenantTagClass(tenantName, t)}`}\r\n >\r\n {tenantName}\r\n </span>\r\n ))\r\n ) : (\r\n <span className=\"text-xs text-[var(--text-muted)]\">-</span>\r\n )}\r\n </div>\r\n </td>\r\n\r\n {/* Source Column (Direct/Group/Custom) */}\r\n <td className=\"px-3 py-2\">\r\n <div className=\"flex flex-wrap gap-1\">\r\n {sourceRoles.length > 0 ? (\r\n getSourceTypesFromConsolidatedRoles(sourceRoles, consolidatedRolesMap).map((source, idx) => (\r\n <span\r\n key={`source-${source.type}-${idx}`}\r\n className={`inline-flex items-center gap-1 px-2 py-0.5 text-xs rounded-full ${getSourceTypeLabelClass(source.type)}`}\r\n title={source.type === 'Group' && source.groupName\r\n ? t('userPermissions.viaGroup', 'Via groupe: {{group}}', { group: source.groupName })\r\n : source.type === 'Custom'\r\n ? t('userPermissions.customPermissions', 'Permissions personnalisées')\r\n : t('userPermissions.directAssignmentTooltip', 'Rôle assigné directement à l\\'utilisateur')}\r\n >\r\n {source.type === 'Direct' && <UserCheck className=\"h-3 w-3\" />}\r\n {source.type === 'Group' && <Users className=\"h-3 w-3\" />}\r\n {source.type === 'Custom' && <User className=\"h-3 w-3\" />}\r\n {source.type === 'Direct'\r\n ? t('userPermissions.directAssignment', 'Direct')\r\n : source.type === 'Custom'\r\n ? t('userPermissions.customSource', 'Custom')\r\n : source.groupName || t('userPermissions.viaGroupShort', 'Groupe')}\r\n </span>\r\n ))\r\n ) : (\r\n <span className=\"text-xs text-[var(--text-muted)]\">-</span>\r\n )}\r\n </div>\r\n </td>\r\n\r\n {/* Permissions - Only show granted permissions for this level (module or section) */}\r\n <td className=\"px-3 py-2\">\r\n <div className=\"flex flex-wrap gap-1.5 items-center relative\">\r\n {resource.permissions\r\n .filter(perm => effectivePermissions.has(perm.id))\r\n .map(perm => {\r\n const isFromCustomRole = customRolePermissions.has(perm.id);\r\n const isToggling = togglingPermission === perm.id;\r\n const actionColor = ACTION_COLORS[perm.action] || 'bg-[var(--bg-secondary)] text-[var(--text-secondary)] border-[var(--border-color)]';\r\n const icon = ACTION_ICONS[perm.action] || <Eye className=\"h-3.5 w-3.5\" />;\r\n\r\n return (\r\n <button\r\n key={perm.id}\r\n onClick={() => handleTogglePermission(perm.id)}\r\n disabled={isToggling || loadingCustomRole || !isFromCustomRole}\r\n className={`inline-flex items-center gap-1.5 px-2 py-1 rounded-[var(--radius-badge)] border text-xs font-medium transition-all ${actionColor} ${\r\n isFromCustomRole ? 'ring-2 ring-[var(--color-accent-600)] dark:ring-[var(--color-accent-400)] hover:opacity-80 cursor-pointer' : 'opacity-60 cursor-not-allowed'\r\n } disabled:opacity-50`}\r\n title={isFromCustomRole ? t('userPermissions.clickToRemove', 'Cliquer pour retirer') : t('userPermissions.grantedByRole', 'Accordé par un rôle')}\r\n >\r\n {isToggling ? (\r\n <Loader2 className=\"h-3.5 w-3.5 animate-spin\" />\r\n ) : (\r\n icon\r\n )}\r\n <span className=\"capitalize\">\r\n {t(`assignments.actions.${perm.action === '*' ? 'all' : perm.action}.label`)}\r\n </span>\r\n {isFromCustomRole && <Star className=\"h-3 w-3\" />}\r\n </button>\r\n );\r\n })}\r\n\r\n </div>\r\n </td>\r\n </tr>\r\n );\r\n };\r\n\r\n return (\r\n <div className=\"space-y-4\">\r\n {!compact && (\r\n <>\r\n {/* Two-column responsive layout: filters sidebar | permissions table */}\r\n <div className=\"flex flex-col lg:flex-row lg:gap-6\">\r\n {/* Left Sidebar - Filters (sticky on large screens) */}\r\n <div className=\"w-full lg:w-72 lg:flex-shrink-0 mb-4 lg:mb-0 lg:sticky lg:top-4 lg:self-start\">\r\n {/* Filter Card */}\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--bg-secondary)] border border-[var(--border-color)]\">\r\n <h4 className=\"text-sm font-semibold text-[var(--text-primary)] mb-3\">\r\n {t('userPermissions.filters.title', 'Filtres')}\r\n </h4>\r\n\r\n {/* Filter Dropdowns - vertical layout in sidebar */}\r\n <div className=\"space-y-3\">\r\n <div className=\"space-y-1\">\r\n <label className=\"text-xs text-[var(--text-secondary)]\">\r\n {t('userPermissions.filters.application')}\r\n </label>\r\n <select\r\n value={filters.applicationFilter}\r\n onChange={(e) => updateFilters({ applicationFilter: e.target.value, moduleFilter: 'all' })}\r\n className=\"w-full px-3 py-1.5 text-sm bg-[var(--bg-primary)] border border-[var(--border-color)] rounded-[var(--radius-input)] text-[var(--text-primary)] focus:outline-none focus:ring-1 focus:ring-[var(--color-accent-500)]\"\r\n >\r\n <option value=\"all\">{t('userPermissions.filters.allApplications')}</option>\r\n {applications\r\n .map(app => (\r\n <option key={app.app} value={app.app}>{app.label}</option>\r\n ))}\r\n </select>\r\n </div>\r\n\r\n <div className=\"space-y-1\">\r\n <label className=\"text-xs text-[var(--text-secondary)]\">\r\n {t('userPermissions.filters.module')}\r\n </label>\r\n <select\r\n value={filters.moduleFilter}\r\n onChange={(e) => updateFilters({ moduleFilter: e.target.value })}\r\n className=\"w-full px-3 py-1.5 text-sm bg-[var(--bg-primary)] border border-[var(--border-color)] rounded-[var(--radius-input)] text-[var(--text-primary)] focus:outline-none focus:ring-1 focus:ring-[var(--color-accent-500)]\"\r\n >\r\n <option value=\"all\">{t('userPermissions.filters.allModules')}</option>\r\n {modules\r\n .filter(mod =>\r\n (filters.applicationFilter === 'all' || mod.app === filters.applicationFilter)\r\n )\r\n .map(mod => (\r\n <option key={`${mod.app}:${mod.module}`} value={mod.module}>{mod.label}</option>\r\n ))}\r\n </select>\r\n </div>\r\n </div>\r\n\r\n {/* Status Filter Buttons */}\r\n <div className=\"mt-4 pt-4 border-t border-[var(--border-color)]\">\r\n <span className=\"text-xs font-medium text-[var(--text-secondary)] block mb-2\">\r\n {t('userPermissions.filterByStatus')}\r\n </span>\r\n <div className=\"flex flex-wrap gap-1.5\">\r\n <button\r\n onClick={() => toggleStatusFilter('all')}\r\n className={`inline-flex items-center gap-1 px-2 py-1 text-xs rounded-full border transition-colors ${\r\n statusFilters.has('all')\r\n ? 'bg-[var(--success-bg)] border-[var(--success-border)] text-[var(--success-text)]'\r\n : 'bg-[var(--bg-tertiary)] border-[var(--border-color)] text-[var(--text-secondary)] hover:border-[var(--success-border)]'\r\n }`}\r\n >\r\n <Check className={`h-3 w-3 ${statusFilters.has('all') ? '' : 'text-[var(--success-dot)]'}`} />\r\n {t('assignments.complete')}\r\n </button>\r\n <button\r\n onClick={() => toggleStatusFilter('some')}\r\n className={`inline-flex items-center gap-1 px-2 py-1 text-xs rounded-full border transition-colors ${\r\n statusFilters.has('some')\r\n ? 'bg-[var(--warning-bg)] border-[var(--warning-border)] text-[var(--warning-text)]'\r\n : 'bg-[var(--bg-tertiary)] border-[var(--border-color)] text-[var(--text-secondary)] hover:border-[var(--warning-border)]'\r\n }`}\r\n >\r\n <Star className={`h-3 w-3 ${statusFilters.has('some') ? '' : 'text-[var(--warning-dot)]'}`} />\r\n {t('assignments.partial')}\r\n </button>\r\n <button\r\n onClick={() => toggleStatusFilter('read-only')}\r\n className={`inline-flex items-center gap-1 px-2 py-1 text-xs rounded-full border transition-colors ${\r\n statusFilters.has('read-only')\r\n ? 'bg-[var(--info-bg)] border-[var(--info-border)] text-[var(--info-text)]'\r\n : 'bg-[var(--bg-tertiary)] border-[var(--border-color)] text-[var(--text-secondary)] hover:border-[var(--info-border)]'\r\n }`}\r\n >\r\n <Eye className={`h-3 w-3 ${statusFilters.has('read-only') ? '' : 'text-[var(--info-dot)]'}`} />\r\n {t('assignments.readOnly')}\r\n </button>\r\n <button\r\n onClick={() => toggleStatusFilter('none')}\r\n className={`inline-flex items-center gap-1 px-2 py-1 text-xs rounded-full border transition-colors ${\r\n statusFilters.has('none')\r\n ? 'bg-[var(--error-bg)] border-[var(--error-border)] text-[var(--error-text)]'\r\n : 'bg-[var(--bg-tertiary)] border-[var(--border-color)] text-[var(--text-secondary)] hover:border-[var(--error-border)]'\r\n }`}\r\n >\r\n <Ban className={`h-3 w-3 ${statusFilters.has('none') ? '' : 'text-[var(--text-muted)]'}`} />\r\n {t('assignments.none')}\r\n </button>\r\n </div>\r\n {statusFilters.size > 0 && (\r\n <button\r\n onClick={() => setStatusFilters(new Set())}\r\n className=\"mt-2 text-xs text-[var(--color-accent-500)] hover:text-[var(--color-accent-600)] underline\"\r\n >\r\n {t('assignments.clearFilters')}\r\n </button>\r\n )}\r\n </div>\r\n\r\n {/* Stats */}\r\n <div className=\"mt-4 pt-4 border-t border-[var(--border-color)]\">\r\n <span className=\"px-2.5 py-1 text-xs font-semibold rounded-full bg-[var(--bg-tertiary)] text-[var(--text-secondary)]\">\r\n {totalModuleCount} {t('assignments.modules')}\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n {/* Right Content - Permissions Table */}\r\n <div className=\"flex-1 min-w-0 space-y-4\">\r\n {/* Tenant Mode Indicator */}\r\n {isTenantMode && tenantMember && (\r\n <div className=\"w-fit flex items-center gap-2 p-3 rounded-[var(--radius-card)] bg-[var(--accent-bg)] border border-[var(--accent-border)]\">\r\n <Shield className=\"h-4 w-4 text-[var(--accent-text)]\" />\r\n <span className=\"text-sm text-[var(--accent-text)]\">\r\n {t('userPermissions.tenantModeInfo', 'Affichage des permissions dans le contexte du tenant. Les rôles ci-dessous sont spécifiques à ce tenant.')}\r\n </span>\r\n </div>\r\n )}\r\n\r\n {/* Tenant Mode - User not member of current tenant */}\r\n {isTenantMode && !tenantMember && (\r\n <div className=\"w-fit flex items-center gap-2 p-3 rounded-[var(--radius-card)] bg-[var(--warning-bg)] border border-[var(--warning-border)]\">\r\n <AlertCircle className=\"h-4 w-4 text-[var(--warning-text)]\" />\r\n <span className=\"text-sm text-[var(--warning-text)]\">\r\n {t('userPermissions.notMemberOfTenant', 'Cet utilisateur n\\'est pas membre du tenant actuel. Aucune permission tenant disponible.')}\r\n </span>\r\n </div>\r\n )}\r\n\r\n {/* User Roles Badges */}\r\n {userRoles.length > 0 ? (\r\n <div className=\"flex flex-wrap gap-2\">\r\n {userRoles.map(role => {\r\n const isCustom = isCustomRole(role.name);\r\n return (\r\n <button\r\n key={role.id}\r\n onClick={() => !isCustom && navigate(`/administration/permissions/roles/${role.id}`)}\r\n className={`inline-flex items-center gap-1.5 px-3 py-1.5 text-sm rounded-full bg-[var(--color-accent-100)] text-[var(--color-accent-700)] dark:bg-[var(--color-accent-900)] dark:text-[var(--color-accent-300)] transition-all ${\r\n isCustom ? 'cursor-default' : 'cursor-pointer hover:ring-2 hover:ring-[var(--color-accent-500)] hover:shadow-md'\r\n }`}\r\n title={isCustom ? t('userPermissions.customRoleTooltip', 'Rôle personnalisé') : t('userPermissions.clickToViewRole', 'Cliquer pour voir le rôle')}\r\n >\r\n <Shield className=\"h-3.5 w-3.5\" />\r\n {role.shortName || role.name}\r\n </button>\r\n );\r\n })}\r\n </div>\r\n ) : !isTenantMode ? (\r\n <div className=\"w-fit flex items-center gap-2 p-3 rounded-[var(--radius-card)] bg-[var(--info-bg)] border border-[var(--info-border)]\">\r\n <Info className=\"h-4 w-4 text-[var(--info-text)]\" />\r\n <span className=\"text-sm text-[var(--info-text)]\">\r\n {t('userPermissions.noRolesInfo', 'Cet utilisateur n\\'a aucun rôle. Vous pouvez lui attribuer des permissions personnalisées ci-dessous.')}\r\n </span>\r\n </div>\r\n ) : null}\r\n\r\n {/* Permission Matrix Table */}\r\n <div className=\"overflow-x-auto overflow-y-visible\">\r\n <table className=\"border-collapse\" style={{ width: 'auto' }}>\r\n <thead className=\"item-medium border-b border-[var(--item-color-border)]\">\r\n <tr>\r\n <th\r\n scope=\"col\"\r\n className=\"sticky left-0 z-20 item-medium px-3 text-left text-xs font-medium text-[var(--text-secondary)] uppercase tracking-wider\"\r\n style={{ width: '280px', minWidth: '280px', maxWidth: '280px', height: '48px', verticalAlign: 'middle' }}\r\n >\r\n {t('assignments.resource')}\r\n </th>\r\n <th\r\n scope=\"col\"\r\n className=\"px-2 text-center text-xs font-medium text-[var(--text-secondary)] uppercase tracking-wider\"\r\n style={{ width: '60px', minWidth: '60px', maxWidth: '60px', height: '48px', verticalAlign: 'middle' }}\r\n >\r\n {t('userPermissions.status')}\r\n </th>\r\n <th\r\n scope=\"col\"\r\n className=\"px-3 text-left text-xs font-medium text-[var(--text-secondary)] uppercase tracking-wider\"\r\n style={{ height: '48px', verticalAlign: 'middle' }}\r\n >\r\n {t('userPermissions.sourceRoles')}\r\n </th>\r\n <th\r\n scope=\"col\"\r\n className=\"px-3 text-left text-xs font-medium text-[var(--text-secondary)] uppercase tracking-wider\"\r\n style={{ height: '48px', verticalAlign: 'middle', minWidth: '120px' }}\r\n >\r\n {t('userPermissions.tenant', 'Tenant')}\r\n </th>\r\n <th\r\n scope=\"col\"\r\n className=\"px-3 text-left text-xs font-medium text-[var(--text-secondary)] uppercase tracking-wider\"\r\n style={{ height: '48px', verticalAlign: 'middle', minWidth: '120px' }}\r\n >\r\n {t('userPermissions.source', 'Source')}\r\n </th>\r\n <th\r\n scope=\"col\"\r\n className=\"px-3 text-left text-xs font-medium text-[var(--text-secondary)] uppercase tracking-wider\"\r\n style={{ height: '48px', verticalAlign: 'middle' }}\r\n >\r\n {t('assignments.permissions')}\r\n </th>\r\n </tr>\r\n </thead>\r\n <tbody className=\"divide-y divide-[var(--item-color-border)]\">\r\n {groupedResources.map(appGroup => {\r\n const appKey = appGroup.application;\r\n const isAppCollapsed = collapsedApps.has(appKey);\r\n\r\n return (\r\n <React.Fragment key={appKey}>\r\n {/* Application Header Row */}\r\n <tr className=\"bg-[var(--bg-tertiary)]\">\r\n <td\r\n className=\"sticky left-0 z-10 px-3 py-2 bg-[var(--bg-tertiary)]\"\r\n style={{ width: '280px', minWidth: '280px', maxWidth: '280px' }}\r\n >\r\n <button\r\n onClick={() => toggleApp(appKey)}\r\n className=\"flex items-center gap-3 w-full text-left hover:opacity-80\"\r\n >\r\n {isAppCollapsed ? (\r\n <ChevronRight className=\"h-4 w-4 text-[var(--text-secondary)]\" />\r\n ) : (\r\n <ChevronDown className=\"h-4 w-4 text-[var(--text-secondary)]\" />\r\n )}\r\n <FolderOpen className=\"h-4 w-4 text-[var(--text-secondary)]\" />\r\n <span className=\"text-sm font-semibold text-[var(--text-primary)]\">\r\n {appGroup.application}\r\n </span>\r\n <span className=\"text-xs text-[var(--text-muted)] ml-auto\">\r\n {appGroup.modules.length} module{appGroup.modules.length > 1 ? 's' : ''}\r\n </span>\r\n </button>\r\n </td>\r\n <td colSpan={5} className=\"px-0 py-2\" />\r\n </tr>\r\n\r\n {/* Module, Section and Resource Rows */}\r\n {!isAppCollapsed && appGroup.modules.map((moduleWithSections: ModuleWithSections, moduleIndex: number) => renderModuleWithSections(moduleWithSections, moduleIndex))}\r\n </React.Fragment>\r\n );\r\n })}\r\n </tbody>\r\n </table>\r\n </div>\r\n\r\n {totalModuleCount === 0 && (\r\n <div className=\"text-center py-12 text-[var(--text-secondary)]\">\r\n {t('assignments.noResources')}\r\n </div>\r\n )}\r\n </div>\r\n </div>\r\n </>\r\n )}\r\n\r\n {compact && (\r\n <div className=\"overflow-x-auto overflow-y-visible\">\r\n <table className=\"border-collapse\" style={{ width: 'auto' }}>\r\n <thead className=\"item-medium border-b border-[var(--item-color-border)]\">\r\n <tr>\r\n <th scope=\"col\" className=\"sticky left-0 z-20 item-medium px-3 text-left text-xs font-medium text-[var(--text-secondary)] uppercase tracking-wider\" style={{ width: '280px', minWidth: '280px', maxWidth: '280px', height: '48px', verticalAlign: 'middle' }}>\r\n {t('assignments.resource')}\r\n </th>\r\n <th scope=\"col\" className=\"px-2 text-center text-xs font-medium text-[var(--text-secondary)] uppercase tracking-wider\" style={{ width: '60px', minWidth: '60px', maxWidth: '60px', height: '48px', verticalAlign: 'middle' }}>\r\n {t('userPermissions.status')}\r\n </th>\r\n <th scope=\"col\" className=\"px-3 text-left text-xs font-medium text-[var(--text-secondary)] uppercase tracking-wider\" style={{ height: '48px', verticalAlign: 'middle' }}>\r\n {t('userPermissions.sourceRoles')}\r\n </th>\r\n <th scope=\"col\" className=\"px-3 text-left text-xs font-medium text-[var(--text-secondary)] uppercase tracking-wider\" style={{ height: '48px', verticalAlign: 'middle' }}>\r\n {t('assignments.permissions')}\r\n </th>\r\n </tr>\r\n </thead>\r\n <tbody className=\"divide-y divide-[var(--item-color-border)]\">\r\n {groupedResources.map(appGroup => (\r\n <React.Fragment key={appGroup.application}>\r\n {appGroup.modules.map((moduleWithSections: ModuleWithSections, moduleIndex: number) => (\r\n <React.Fragment key={moduleWithSections.module.id}>\r\n {renderResourceRow(moduleWithSections.module, moduleIndex, 'module', false, false)}\r\n </React.Fragment>\r\n ))}\r\n </React.Fragment>\r\n ))}\r\n </tbody>\r\n </table>\r\n </div>\r\n )}\r\n </div>\r\n );\r\n}\r\n","import type { ReactElement } from 'react';\r\nimport { useTranslation } from 'react-i18next';\r\nimport { LayoutGrid, Table2 } from 'lucide-react';\r\n\r\nexport type ViewMode = 'cards' | 'table';\r\n\r\ninterface ViewModeToggleProps {\r\n readonly viewMode: ViewMode;\r\n readonly onChange: (mode: ViewMode) => void;\r\n}\r\n\r\nexport function ViewModeToggle({ viewMode, onChange }: ViewModeToggleProps): ReactElement {\r\n const { t } = useTranslation();\r\n\r\n return (\r\n <div className=\"flex items-center rounded-[var(--radius-button)] border border-[var(--border-color)] bg-[var(--bg-primary)] p-0.5 h-[34px]\">\r\n <button\r\n onClick={() => onChange('cards')}\r\n className={`flex items-center justify-center gap-1 px-2.5 h-full rounded text-sm transition-colors ${\r\n viewMode === 'cards'\r\n ? 'bg-[var(--color-accent-500)] text-white'\r\n : 'text-[var(--text-secondary)] hover:bg-[var(--bg-hover)]'\r\n }`}\r\n title={t('common.cardView', 'Vue cartes')}\r\n >\r\n <LayoutGrid className=\"w-4 h-4\" />\r\n </button>\r\n <button\r\n onClick={() => onChange('table')}\r\n className={`flex items-center justify-center gap-1 px-2.5 h-full rounded text-sm transition-colors ${\r\n viewMode === 'table'\r\n ? 'bg-[var(--color-accent-500)] text-white'\r\n : 'text-[var(--text-secondary)] hover:bg-[var(--bg-hover)]'\r\n }`}\r\n title={t('common.tableView', 'Vue tableau')}\r\n >\r\n <Table2 className=\"w-4 h-4\" />\r\n </button>\r\n </div>\r\n );\r\n}\r\n\r\nexport default ViewModeToggle;\r\n","import { useState, useEffect, useCallback } from 'react';\r\nimport type { ReactElement } from 'react';\r\nimport { useTranslation } from 'react-i18next';\r\nimport { useNavigate } from 'react-router-dom';\r\nimport { Users, Loader2, Plus, RefreshCw, Search, X, Trash2, AlertTriangle, CheckCircle, Info, Shield, Cloud, Check, Filter } from 'lucide-react';\r\nimport { groupsApi, type GroupListDto } from '@/services/api/groupsApi';\r\nimport { adminApi, type UserGroupDto } from '@/services/api/adminApi';\r\nimport { DataTable, type DataTableColumn } from '@/components/ui/DataTable';\r\nimport { ViewModeToggle, type ViewMode } from '@/components/ui/ViewModeToggle';\r\nimport { getCustomRoleIcon } from '@/utils/roleUtils';\r\n\r\ntype GroupTypeFilter = 'all' | 'security' | 'standard' | 'entra';\r\n\r\ninterface UserGroupsTabProps {\r\n readonly userId: string;\r\n readonly userName: string;\r\n}\r\n\r\nexport function UserGroupsTab({ userId, userName }: UserGroupsTabProps): ReactElement {\r\n const { t } = useTranslation(['admin', 'groups']);\r\n const navigate = useNavigate();\r\n\r\n const [userGroups, setUserGroups] = useState<UserGroupDto[]>([] as UserGroupDto[]);\r\n const [allGroups, setAllGroups] = useState<GroupListDto[] | null>(null);\r\n const [loading, setLoading] = useState(true);\r\n const [showAddModal, setShowAddModal] = useState(false);\r\n const [searchQuery, setSearchQuery] = useState('');\r\n const [groupTypeFilter, setGroupTypeFilter] = useState<GroupTypeFilter>('all');\r\n const [selectedGroupIds, setSelectedGroupIds] = useState<Set<string>>(new Set());\r\n const [isAddingMultiple, setIsAddingMultiple] = useState(false);\r\n const [removingGroupId, setRemovingGroupId] = useState<string | null>(null);\r\n const [error, setError] = useState<string | null>(null);\r\n const [success, setSuccess] = useState<string | null>(null);\r\n const [viewMode, setViewMode] = useState<ViewMode>('cards');\r\n\r\n const loadUserGroups = useCallback(async () => {\r\n try {\r\n setLoading(true);\r\n const data = await adminApi.users.getGroups(userId);\r\n setUserGroups(data);\r\n } catch (err) {\r\n console.error('Failed to load user groups:', err);\r\n setError(t('admin:userDetail.groups.loadError', 'Erreur lors du chargement des groupes'));\r\n } finally {\r\n setLoading(false);\r\n }\r\n }, [userId, t]);\r\n\r\n const loadAllGroups = async () => {\r\n try {\r\n const data = await groupsApi.getAll(undefined, true);\r\n setAllGroups(data);\r\n } catch (err) {\r\n console.error('Failed to load all groups:', err);\r\n }\r\n };\r\n\r\n useEffect(() => {\r\n loadUserGroups();\r\n loadAllGroups();\r\n }, [loadUserGroups]);\r\n\r\n const handleRemoveFromGroup = async (groupId: string) => {\r\n const group = userGroups?.find((g) => g.id === groupId);\r\n if (!confirm(t('admin:userDetail.groups.confirmRemove', { userName, groupName: group?.name }))) {\r\n return;\r\n }\r\n\r\n try {\r\n setRemovingGroupId(groupId);\r\n setError(null);\r\n await groupsApi.removeMember(groupId, userId);\r\n await loadUserGroups();\r\n setSuccess(t('admin:userDetail.groups.removeSuccess', 'Utilisateur retiré du groupe'));\r\n setTimeout(() => setSuccess(null), 3000);\r\n } catch (err: any) {\r\n console.error('Failed to remove from group:', err);\r\n const errorMessage = err?.response?.data?.message || t('admin:userDetail.groups.removeError', 'Erreur lors du retrait du groupe');\r\n setError(errorMessage);\r\n } finally {\r\n setRemovingGroupId(null);\r\n }\r\n };\r\n\r\n const availableGroups = allGroups?.filter(\r\n (g) => !userGroups?.some((ug) => ug.id === g.id)\r\n );\r\n\r\n const filteredAvailableGroups = availableGroups?.filter((g) => {\r\n // Type filter\r\n if (groupTypeFilter === 'security' && !g.isSecurityGroup) return false;\r\n if (groupTypeFilter === 'standard' && g.isSecurityGroup) return false;\r\n if (groupTypeFilter === 'entra' && !g.isSyncedFromEntra) return false;\r\n\r\n // Search filter\r\n if (!searchQuery.trim()) return true;\r\n const query = searchQuery.toLowerCase().trim();\r\n return (\r\n g.name.toLowerCase().includes(query) ||\r\n (g.description?.toLowerCase().includes(query) ?? false)\r\n );\r\n });\r\n\r\n const toggleGroupSelection = (groupId: string) => {\r\n setSelectedGroupIds((prev) => {\r\n const newSet = new Set(prev);\r\n if (newSet.has(groupId)) {\r\n newSet.delete(groupId);\r\n } else {\r\n newSet.add(groupId);\r\n }\r\n return newSet;\r\n });\r\n };\r\n\r\n const getGroupTypeFilterClass = (filter: GroupTypeFilter, currentFilter: GroupTypeFilter): string => {\r\n return currentFilter === filter\r\n ? 'px-3 py-1 rounded-full text-xs font-medium transition-colors bg-[var(--color-accent-500)] text-white'\r\n : 'px-3 py-1 rounded-full text-xs font-medium transition-colors bg-[var(--bg-secondary)] text-[var(--text-secondary)] hover:bg-[var(--bg-hover)]';\r\n };\r\n\r\n const getGroupCheckboxClass = (isSelected: boolean): string => {\r\n return isSelected\r\n ? 'w-5 h-5 rounded border-2 flex items-center justify-center flex-shrink-0 transition-colors bg-[var(--color-accent-500)] border-[var(--color-accent-500)]'\r\n : 'w-5 h-5 rounded border-2 flex items-center justify-center flex-shrink-0 transition-colors border-[var(--border-color)]';\r\n };\r\n\r\n const selectAllFiltered = () => {\r\n if (filteredAvailableGroups) {\r\n setSelectedGroupIds(new Set(filteredAvailableGroups.map((g) => g.id)));\r\n }\r\n };\r\n\r\n const clearSelection = () => {\r\n setSelectedGroupIds(new Set());\r\n };\r\n\r\n const handleAddMultipleGroups = async () => {\r\n if (selectedGroupIds.size === 0) return;\r\n\r\n try {\r\n setIsAddingMultiple(true);\r\n setError(null);\r\n\r\n const groupIdsArray = Array.from(selectedGroupIds);\r\n for (const groupId of groupIdsArray) {\r\n await groupsApi.addMember(groupId, { userId });\r\n }\r\n\r\n await loadUserGroups();\r\n setShowAddModal(false);\r\n setSearchQuery('');\r\n setGroupTypeFilter('all');\r\n setSelectedGroupIds(new Set());\r\n setSuccess(t('admin:userDetail.groups.addMultipleSuccess', { count: groupIdsArray.length, defaultValue: `${groupIdsArray.length} groupe(s) ajouté(s)` }));\r\n setTimeout(() => setSuccess(null), 3000);\r\n } catch (err: any) {\r\n console.error('Failed to add groups:', err);\r\n const errorMessage = err?.response?.data?.message || t('admin:userDetail.groups.addError', 'Erreur lors de l\\'ajout au groupe');\r\n setError(errorMessage);\r\n } finally {\r\n setIsAddingMultiple(false);\r\n }\r\n };\r\n\r\n const closeModal = () => {\r\n setShowAddModal(false);\r\n setSearchQuery('');\r\n setGroupTypeFilter('all');\r\n setSelectedGroupIds(new Set());\r\n };\r\n\r\n return (\r\n <div className=\"space-y-6\">\r\n {/* Header */}\r\n <div className=\"flex items-center justify-between\">\r\n <h3 className=\"text-lg font-semibold text-[var(--text-primary)] flex items-center gap-2\">\r\n <Users className=\"w-5 h-5\" />\r\n {t('admin:userDetail.groups.title', 'Groupes de l\\'utilisateur')}\r\n {userGroups && (\r\n <span className=\"ml-2 px-2 py-0.5 text-xs rounded-full bg-[var(--bg-secondary)] text-[var(--text-secondary)]\">\r\n {userGroups.length}\r\n </span>\r\n )}\r\n </h3>\r\n <div className=\"flex items-center gap-2\">\r\n <button\r\n onClick={() => setShowAddModal(true)}\r\n className=\"flex items-center gap-2 px-3 py-1.5 rounded-[var(--radius-button)] bg-[var(--color-accent-600)] text-white hover:bg-[var(--color-accent-700)] transition-colors\"\r\n >\r\n <Plus className=\"w-4 h-4\" />\r\n {t('admin:userDetail.groups.add', 'Ajouter à un groupe')}\r\n </button>\r\n <button\r\n onClick={loadUserGroups}\r\n className=\"flex items-center gap-2 px-3 py-1.5 rounded-[var(--radius-button)] bg-[var(--bg-primary)] border border-[var(--border-color)] text-[var(--text-secondary)] hover:bg-[var(--bg-hover)] transition-colors\"\r\n >\r\n <RefreshCw className=\"w-4 h-4\" />\r\n {t('common.refresh', 'Actualiser')}\r\n </button>\r\n <ViewModeToggle viewMode={viewMode} onChange={setViewMode} />\r\n </div>\r\n </div>\r\n\r\n {/* Alerts */}\r\n {error && (\r\n <div className=\"p-4 rounded-lg bg-red-500/10 border border-red-500/20 flex items-center gap-3\">\r\n <AlertTriangle className=\"w-5 h-5 text-red-500 flex-shrink-0\" />\r\n <p className=\"text-red-500\">{error}</p>\r\n <button onClick={() => setError(null)} className=\"ml-auto\">\r\n <X className=\"w-4 h-4 text-red-500\" />\r\n </button>\r\n </div>\r\n )}\r\n\r\n {success && (\r\n <div className=\"p-4 rounded-lg bg-green-500/10 border border-green-500/20 flex items-center gap-3\">\r\n <CheckCircle className=\"w-5 h-5 text-green-500 flex-shrink-0\" />\r\n <p className=\"text-green-500\">{success}</p>\r\n </div>\r\n )}\r\n\r\n {/* Info banner */}\r\n <div className=\"p-4 rounded-lg bg-blue-500/10 border border-blue-500/20\">\r\n <p className=\"text-sm text-blue-500\">\r\n {t('admin:userDetail.groups.info', 'L\\'utilisateur hérite automatiquement des rôles et permissions des groupes auxquels il appartient.')}\r\n </p>\r\n </div>\r\n\r\n {/* Content */}\r\n {loading && (\r\n <div className=\"flex items-center justify-center py-12\">\r\n <Loader2 className=\"w-6 h-6 animate-spin text-[var(--color-accent-500)]\" />\r\n </div>\r\n )}\r\n {!loading && (!userGroups || userGroups.length === 0) && (\r\n <div className=\"text-center py-12\">\r\n <Users className=\"w-12 h-12 mx-auto mb-4 text-[var(--text-tertiary)]\" />\r\n <p className=\"text-[var(--text-secondary)] mb-4\">\r\n {t('admin:userDetail.groups.noGroups', 'Cet utilisateur n\\'appartient à aucun groupe')}\r\n </p>\r\n <button\r\n onClick={() => setShowAddModal(true)}\r\n className=\"inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-[var(--color-accent-600)] text-white hover:bg-[var(--color-accent-700)] transition-colors\"\r\n >\r\n <Plus className=\"w-4 h-4\" />\r\n {t('admin:userDetail.groups.addFirst', 'Ajouter à un premier groupe')}\r\n </button>\r\n </div>\r\n )}\r\n {!loading && (userGroups?.length ?? 0) > 0 && viewMode === 'table' && (\r\n <DataTable\r\n data={userGroups}\r\n columns={[\r\n {\r\n key: 'name',\r\n label: t('admin:userDetail.groups.table.name', 'Nom'),\r\n sortable: true,\r\n render: (group) => (\r\n <div className=\"flex items-center gap-2\">\r\n <div className={`p-1.5 rounded flex-shrink-0 ${\r\n group.isSecurityGroup\r\n ? 'bg-blue-500/10 text-blue-500'\r\n : 'bg-[var(--color-accent-500)]/10 text-[var(--color-accent-500)]'\r\n }`}>\r\n {group.isSecurityGroup ? <Shield className=\"w-4 h-4\" /> : <Users className=\"w-4 h-4\" />}\r\n </div>\r\n <div className=\"min-w-0\">\r\n <span className=\"font-medium text-[var(--text-primary)] flex items-center gap-1\">\r\n {group.name}\r\n {group.isSyncedFromEntra && <Cloud className=\"w-3.5 h-3.5 text-[var(--color-accent-500)]\" />}\r\n </span>\r\n </div>\r\n </div>\r\n ),\r\n },\r\n {\r\n key: 'description',\r\n label: t('admin:userDetail.groups.table.description', 'Description'),\r\n render: (group) => (\r\n <span className=\"text-[var(--text-secondary)] truncate max-w-[200px] block\">\r\n {group.description || '-'}\r\n </span>\r\n ),\r\n hideOnMobile: true,\r\n },\r\n {\r\n key: 'roles',\r\n label: t('admin:userDetail.groups.table.roles', 'Rôles'),\r\n render: (group) => (\r\n <div className=\"flex flex-wrap gap-1\">\r\n {group.roles.slice(0, 2).map((role) => {\r\n const customIcon = getCustomRoleIcon(role.code);\r\n return (\r\n <span\r\n key={role.name}\r\n className=\"inline-flex items-center gap-1 px-1.5 py-0.5 rounded-full text-xs bg-[var(--color-accent-500)]/10 text-[var(--color-accent-500)]\"\r\n >\r\n {customIcon ? (\r\n <span>{customIcon}</span>\r\n ) : (\r\n <Shield className=\"w-3 h-3\" />\r\n )}\r\n {role.name}\r\n </span>\r\n );\r\n })}\r\n {group.roles.length > 2 && (\r\n <span className=\"text-xs text-[var(--text-tertiary)]\">+{group.roles.length - 2}</span>\r\n )}\r\n {group.roles.length === 0 && <span className=\"text-[var(--text-tertiary)]\">-</span>}\r\n </div>\r\n ),\r\n hideOnMobile: true,\r\n },\r\n {\r\n key: 'addedAt',\r\n label: t('admin:userDetail.groups.table.addedAt', 'Ajouté le'),\r\n sortable: true,\r\n render: (group) => (\r\n <span className=\"text-[var(--text-secondary)] text-sm\">\r\n {new Date(group.addedAt).toLocaleDateString()}\r\n </span>\r\n ),\r\n hideOnMobile: true,\r\n },\r\n {\r\n key: 'actions',\r\n label: '',\r\n width: '80px',\r\n align: 'right',\r\n render: (group) => (\r\n <div className=\"flex items-center justify-end gap-1\">\r\n {group.isSyncedFromEntra ? (\r\n <span className=\"text-xs text-amber-500 flex items-center gap-1\">\r\n <Info className=\"w-3 h-3\" />\r\n Entra\r\n </span>\r\n ) : (\r\n <button\r\n onClick={(e) => {\r\n e.stopPropagation();\r\n handleRemoveFromGroup(group.id);\r\n }}\r\n disabled={removingGroupId === group.id}\r\n className=\"flex items-center gap-1 px-2 py-1 rounded text-xs text-red-500 hover:bg-red-500/10 transition-colors disabled:opacity-50\"\r\n >\r\n {removingGroupId === group.id ? (\r\n <Loader2 className=\"w-3 h-3 animate-spin\" />\r\n ) : (\r\n <Trash2 className=\"w-3 h-3\" />\r\n )}\r\n </button>\r\n )}\r\n </div>\r\n ),\r\n },\r\n ] as DataTableColumn<UserGroupDto>[]}\r\n getRowKey={(group) => group.id}\r\n onRowClick={(group) => navigate(`/administration/users/groups/${group.id}`)}\r\n compact\r\n emptyMessage={t('admin:userDetail.groups.noGroups', 'Cet utilisateur n\\'appartient à aucun groupe')}\r\n emptyIcon={<Users className=\"w-8 h-8 text-[var(--text-tertiary)]\" />}\r\n />\r\n )}\r\n {!loading && (userGroups?.length ?? 0) > 0 && viewMode !== 'table' && (\r\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4\">\r\n {userGroups?.map((group) => (\r\n <div\r\n key={group.id}\r\n className=\"p-4 rounded-[var(--radius-card)] bg-[var(--bg-primary)] border border-[var(--border-color)] hover:border-[var(--color-accent-500)] transition-colors\"\r\n >\r\n <div className=\"flex items-start justify-between gap-3\">\r\n <button\r\n type=\"button\"\r\n className=\"flex items-start gap-3 min-w-0 cursor-pointer text-left\"\r\n onClick={() => navigate(`/administration/users/groups/${group.id}`)}\r\n >\r\n <div className={`p-2 rounded-lg flex-shrink-0 ${\r\n group.isSecurityGroup\r\n ? 'bg-blue-500/10 text-blue-500'\r\n : 'bg-[var(--color-accent-500)]/10 text-[var(--color-accent-500)]'\r\n }`}>\r\n {group.isSecurityGroup ? <Shield className=\"w-5 h-5\" /> : <Users className=\"w-5 h-5\" />}\r\n </div>\r\n <div className=\"min-w-0\">\r\n <h4 className=\"text-sm font-semibold text-[var(--text-primary)] truncate flex items-center gap-2\">\r\n {group.name}\r\n {group.isSyncedFromEntra && (\r\n <Cloud className=\"w-3.5 h-3.5 text-[var(--color-accent-500)]\" />\r\n )}\r\n </h4>\r\n {group.description && (\r\n <p className=\"text-xs text-[var(--text-tertiary)] truncate\">{group.description}</p>\r\n )}\r\n </div>\r\n </button>\r\n </div>\r\n\r\n {group.roles.length > 0 && (\r\n <div className=\"mt-3 flex flex-wrap gap-1\">\r\n {group.roles.slice(0, 3).map((role) => {\r\n const customIcon = getCustomRoleIcon(role.code);\r\n return (\r\n <span\r\n key={role.name}\r\n className=\"inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-xs bg-[var(--color-accent-500)]/10 text-[var(--color-accent-500)]\"\r\n >\r\n {customIcon ? (\r\n <span>{customIcon}</span>\r\n ) : (\r\n <Shield className=\"w-3 h-3\" />\r\n )}\r\n {role.name}\r\n </span>\r\n );\r\n })}\r\n {group.roles.length > 3 && (\r\n <span className=\"text-xs text-[var(--text-tertiary)]\">\r\n +{group.roles.length - 3}\r\n </span>\r\n )}\r\n </div>\r\n )}\r\n\r\n <div className=\"mt-3 pt-3 border-t border-[var(--border-color)] space-y-1\">\r\n <p className=\"text-xs text-[var(--text-tertiary)]\">\r\n {t('admin:userDetail.groups.addedAt', 'Ajouté le')}: {new Date(group.addedAt).toLocaleDateString()}\r\n </p>\r\n {group.addedBy && (\r\n <p className=\"text-xs text-[var(--text-tertiary)]\">\r\n {t('admin:userDetail.groups.addedBy', 'Par')}: {group.addedBy}\r\n </p>\r\n )}\r\n </div>\r\n\r\n {!group.isSyncedFromEntra && (\r\n <div className=\"mt-3 flex justify-end\">\r\n <button\r\n onClick={() => handleRemoveFromGroup(group.id)}\r\n disabled={removingGroupId === group.id}\r\n className=\"flex items-center gap-1 px-2 py-1 rounded text-xs text-red-500 hover:bg-red-500/10 transition-colors disabled:opacity-50\"\r\n >\r\n {removingGroupId === group.id ? (\r\n <Loader2 className=\"w-3 h-3 animate-spin\" />\r\n ) : (\r\n <Trash2 className=\"w-3 h-3\" />\r\n )}\r\n {t('common.remove', 'Retirer')}\r\n </button>\r\n </div>\r\n )}\r\n\r\n {group.isSyncedFromEntra && (\r\n <div className=\"mt-3 flex items-center gap-1 text-xs text-amber-500\">\r\n <Info className=\"w-3 h-3\" />\r\n {t('admin:userDetail.groups.syncedFromEntra', 'Synchronisé depuis Entra ID')}\r\n </div>\r\n )}\r\n </div>\r\n ))}\r\n </div>\r\n )}\r\n\r\n {/* Add to Group Modal */}\r\n {showAddModal && (\r\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50\">\r\n <div className=\"w-full max-w-2xl mx-4 bg-[var(--bg-primary)] rounded-[var(--radius-card)] shadow-xl\">\r\n <div className=\"flex items-center justify-between p-4 border-b border-[var(--border-color)]\">\r\n <h3 className=\"text-lg font-semibold text-[var(--text-primary)]\">\r\n {t('admin:userDetail.groups.addModalTitle', 'Ajouter à un groupe')}\r\n </h3>\r\n <button\r\n onClick={closeModal}\r\n className=\"p-1 rounded hover:bg-[var(--bg-hover)] transition-colors\"\r\n >\r\n <X className=\"w-5 h-5 text-[var(--text-secondary)]\" />\r\n </button>\r\n </div>\r\n\r\n <div className=\"p-4 space-y-4\">\r\n {/* Search and Filters */}\r\n <div className=\"space-y-3\">\r\n <div className=\"relative\">\r\n <Search className=\"absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 text-[var(--text-tertiary)]\" />\r\n <input\r\n type=\"text\"\r\n placeholder={t('admin:userDetail.groups.searchPlaceholder', 'Rechercher un groupe...')}\r\n value={searchQuery}\r\n onChange={(e) => setSearchQuery(e.target.value)}\r\n className=\"w-full pl-10 pr-4 py-2 rounded-lg border border-[var(--border-color)] bg-[var(--bg-primary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n autoFocus\r\n />\r\n </div>\r\n\r\n {/* Type Filters */}\r\n <div className=\"flex items-center gap-2 flex-wrap\">\r\n <Filter className=\"w-4 h-4 text-[var(--text-tertiary)]\" />\r\n {(['all', 'security', 'standard', 'entra'] as const).map((filter) => (\r\n <button\r\n key={filter}\r\n onClick={() => setGroupTypeFilter(filter)}\r\n className={getGroupTypeFilterClass(filter, groupTypeFilter)}\r\n >\r\n {filter === 'all' && t('admin:userDetail.groups.filterAll', 'Tous')}\r\n {filter === 'security' && (\r\n <span className=\"flex items-center gap-1\">\r\n <Shield className=\"w-3 h-3\" />\r\n {t('admin:userDetail.groups.filterSecurity', 'Sécurité')}\r\n </span>\r\n )}\r\n {filter === 'standard' && (\r\n <span className=\"flex items-center gap-1\">\r\n <Users className=\"w-3 h-3\" />\r\n {t('admin:userDetail.groups.filterStandard', 'Standard')}\r\n </span>\r\n )}\r\n {filter === 'entra' && (\r\n <span className=\"flex items-center gap-1\">\r\n <Cloud className=\"w-3 h-3\" />\r\n {t('admin:userDetail.groups.filterEntra', 'Entra ID')}\r\n </span>\r\n )}\r\n </button>\r\n ))}\r\n </div>\r\n\r\n {/* Selection Actions */}\r\n {(filteredAvailableGroups?.length ?? 0) > 0 && (\r\n <div className=\"flex items-center justify-between text-xs\">\r\n <span className=\"text-[var(--text-secondary)]\">\r\n {selectedGroupIds.size > 0\r\n ? t('admin:userDetail.groups.selectedCount', { count: selectedGroupIds.size, defaultValue: `${selectedGroupIds.size} sélectionné(s)` })\r\n : t('admin:userDetail.groups.availableCount', { count: filteredAvailableGroups?.length ?? 0, defaultValue: `${filteredAvailableGroups?.length ?? 0} groupe(s) disponible(s)` })}\r\n </span>\r\n <div className=\"flex items-center gap-2\">\r\n <button\r\n onClick={selectAllFiltered}\r\n className=\"text-[var(--color-accent-500)] hover:underline\"\r\n >\r\n {t('admin:userDetail.groups.selectAll', 'Tout sélectionner')}\r\n </button>\r\n {selectedGroupIds.size > 0 && (\r\n <button\r\n onClick={clearSelection}\r\n className=\"text-[var(--text-tertiary)] hover:underline\"\r\n >\r\n {t('admin:userDetail.groups.clearSelection', 'Effacer')}\r\n </button>\r\n )}\r\n </div>\r\n </div>\r\n )}\r\n </div>\r\n\r\n {/* Group List */}\r\n <div className=\"max-h-[350px] overflow-y-auto space-y-2\">\r\n {!filteredAvailableGroups || filteredAvailableGroups.length === 0 ? (\r\n <div className=\"text-center py-8\">\r\n <Users className=\"w-8 h-8 mx-auto mb-2 text-[var(--text-tertiary)]\" />\r\n <p className=\"text-sm text-[var(--text-secondary)]\">\r\n {t('admin:userDetail.groups.noAvailableGroups', 'Aucun groupe disponible')}\r\n </p>\r\n </div>\r\n ) : (\r\n filteredAvailableGroups.map((group) => {\r\n const isSelected = selectedGroupIds.has(group.id);\r\n return (\r\n <button\r\n type=\"button\"\r\n key={group.id}\r\n onClick={() => toggleGroupSelection(group.id)}\r\n className={`w-full flex items-center gap-3 p-3 rounded-lg border cursor-pointer transition-colors text-left ${\r\n isSelected\r\n ? 'border-[var(--color-accent-500)] bg-[var(--color-accent-500)]/5'\r\n : 'border-[var(--border-color)] hover:border-[var(--color-accent-500)] hover:bg-[var(--bg-hover)]'\r\n }`}\r\n >\r\n {/* Checkbox */}\r\n <div className={getGroupCheckboxClass(isSelected)}>\r\n {isSelected && <Check className=\"w-3 h-3 text-white\" />}\r\n </div>\r\n\r\n {/* Icon */}\r\n <div className={`p-2 rounded-lg flex-shrink-0 ${\r\n group.isSecurityGroup\r\n ? 'bg-blue-500/10 text-blue-500'\r\n : 'bg-[var(--color-accent-500)]/10 text-[var(--color-accent-500)]'\r\n }`}>\r\n {group.isSecurityGroup ? <Shield className=\"w-5 h-5\" /> : <Users className=\"w-5 h-5\" />}\r\n </div>\r\n\r\n {/* Content */}\r\n <div className=\"flex-1 min-w-0\">\r\n <p className=\"text-sm font-medium text-[var(--text-primary)] truncate flex items-center gap-2\">\r\n {group.name}\r\n {group.isSyncedFromEntra && (\r\n <Cloud className=\"w-3.5 h-3.5 text-[var(--color-accent-500)]\" />\r\n )}\r\n </p>\r\n {group.description && (\r\n <p className=\"text-xs text-[var(--text-tertiary)] truncate\">{group.description}</p>\r\n )}\r\n </div>\r\n\r\n {/* Member count */}\r\n <span className=\"text-xs text-[var(--text-tertiary)] flex-shrink-0\">\r\n {group.memberCount} {t('admin:userDetail.groups.members', 'membres')}\r\n </span>\r\n </button>\r\n );\r\n })\r\n )}\r\n </div>\r\n </div>\r\n\r\n <div className=\"flex items-center justify-between p-4 border-t border-[var(--border-color)]\">\r\n <div className=\"text-sm text-[var(--text-secondary)]\">\r\n {selectedGroupIds.size > 0 && (\r\n <span className=\"flex items-center gap-2\">\r\n <span className=\"w-6 h-6 rounded-full bg-[var(--color-accent-500)] text-white text-xs flex items-center justify-center font-medium\">\r\n {selectedGroupIds.size}\r\n </span>\r\n {t('admin:userDetail.groups.groupsSelected', 'groupe(s) sélectionné(s)')}\r\n </span>\r\n )}\r\n </div>\r\n <div className=\"flex items-center gap-2\">\r\n <button\r\n onClick={closeModal}\r\n className=\"px-4 py-2 rounded-lg bg-[var(--bg-secondary)] text-[var(--text-secondary)] hover:bg-[var(--bg-hover)] transition-colors\"\r\n >\r\n {t('common.cancel', 'Annuler')}\r\n </button>\r\n <button\r\n onClick={handleAddMultipleGroups}\r\n disabled={selectedGroupIds.size === 0 || isAddingMultiple}\r\n className=\"px-4 py-2 rounded-lg bg-[var(--color-accent-600)] text-white hover:bg-[var(--color-accent-700)] transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2\"\r\n >\r\n {isAddingMultiple ? (\r\n <>\r\n <Loader2 className=\"w-4 h-4 animate-spin\" />\r\n {t('admin:userDetail.groups.adding', 'Ajout en cours...')}\r\n </>\r\n ) : (\r\n <>\r\n <Plus className=\"w-4 h-4\" />\r\n {t('admin:userDetail.groups.addSelected', 'Ajouter')}\r\n {selectedGroupIds.size > 0 && ` (${selectedGroupIds.size})`}\r\n </>\r\n )}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n )}\r\n </div>\r\n );\r\n}\r\n","import { useState, useEffect } from 'react';\r\nimport type { ReactElement } from 'react';\r\nimport { useTranslation } from 'react-i18next';\r\nimport { Plus } from 'lucide-react';\r\n\r\nexport interface SelectOption {\r\n id: string;\r\n name: string;\r\n}\r\n\r\nexport interface SelectWithOtherValue {\r\n id: string;\r\n customValue?: string;\r\n}\r\n\r\ninterface SelectWithOtherProps {\r\n readonly label: string;\r\n readonly options: SelectOption[];\r\n readonly value: SelectWithOtherValue;\r\n readonly onChange: (value: SelectWithOtherValue) => void;\r\n readonly placeholder?: string;\r\n readonly disabled?: boolean;\r\n readonly className?: string;\r\n /** Allow \"Other...\" option to create new values. Default: true */\r\n readonly allowOther?: boolean;\r\n}\r\n\r\nconst OTHER_VALUE = '__OTHER__';\r\n\r\nexport function SelectWithOther({\r\n label,\r\n options,\r\n value,\r\n onChange,\r\n placeholder,\r\n disabled = false,\r\n className = '',\r\n allowOther = true,\r\n}: SelectWithOtherProps): ReactElement {\r\n const { t } = useTranslation();\r\n const [isOther, setIsOther] = useState(false);\r\n const [customInput, setCustomInput] = useState('');\r\n\r\n // Detect if current value is \"other\" mode\r\n useEffect(() => {\r\n if (value.customValue !== undefined) {\r\n setIsOther(true);\r\n setCustomInput(value.customValue);\r\n } else {\r\n setIsOther(false);\r\n setCustomInput('');\r\n }\r\n }, [value]);\r\n\r\n const handleSelectChange = (e: React.ChangeEvent<HTMLSelectElement>) => {\r\n const selectedValue = e.target.value;\r\n\r\n if (selectedValue === OTHER_VALUE) {\r\n setIsOther(true);\r\n setCustomInput('');\r\n onChange({ id: '', customValue: '' });\r\n } else {\r\n setIsOther(false);\r\n setCustomInput('');\r\n onChange({ id: selectedValue, customValue: undefined });\r\n }\r\n };\r\n\r\n const handleCustomInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\r\n const newValue = e.target.value;\r\n setCustomInput(newValue);\r\n onChange({ id: '', customValue: newValue });\r\n };\r\n\r\n const handleCancelOther = () => {\r\n setIsOther(false);\r\n setCustomInput('');\r\n onChange({ id: '', customValue: undefined });\r\n };\r\n\r\n const selectValue = isOther ? OTHER_VALUE : value.id;\r\n\r\n return (\r\n <div className={className}>\r\n <label className=\"block text-sm font-medium text-[var(--text-secondary)] mb-1\">\r\n {label}\r\n </label>\r\n <div className=\"flex gap-2\">\r\n <select\r\n value={selectValue}\r\n onChange={handleSelectChange}\r\n disabled={disabled}\r\n className={`flex-1 px-4 py-2 rounded-[var(--radius-input)] border border-[var(--border-color)] bg-[var(--bg-primary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)] ${isOther ? 'w-1/3 flex-none' : ''}`}\r\n >\r\n <option value=\"\">{placeholder || t('common.none', '-- Aucun --')}</option>\r\n {options.map(opt => (\r\n <option key={opt.id} value={opt.id}>{opt.name}</option>\r\n ))}\r\n {allowOther && (\r\n <option value={OTHER_VALUE} className=\"font-medium text-[var(--color-accent-600)]\">\r\n {t('common.other', '+ Autre...')}\r\n </option>\r\n )}\r\n </select>\r\n\r\n {isOther && (\r\n <>\r\n <input\r\n type=\"text\"\r\n value={customInput}\r\n onChange={handleCustomInputChange}\r\n placeholder={t('common.enterValue', 'Saisir une valeur...')}\r\n disabled={disabled}\r\n autoFocus\r\n className=\"flex-1 px-4 py-2 rounded-[var(--radius-input)] border border-[var(--color-accent-500)] bg-[var(--bg-primary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n />\r\n <button\r\n type=\"button\"\r\n onClick={handleCancelOther}\r\n disabled={disabled}\r\n className=\"px-3 py-2 rounded-[var(--radius-button)] text-[var(--text-secondary)] hover:bg-[var(--bg-hover)] transition-colors\"\r\n title={t('common.cancel', 'Annuler')}\r\n >\r\n ✕\r\n </button>\r\n </>\r\n )}\r\n </div>\r\n {isOther && customInput && (\r\n <p className=\"mt-1 text-xs text-[var(--color-accent-600)] flex items-center gap-1\">\r\n <Plus className=\"w-3 h-3\" />\r\n {t('common.willBeCreated', 'Cette valeur sera créée automatiquement')}\r\n </p>\r\n )}\r\n </div>\r\n );\r\n}\r\n","import type { ReactElement } from 'react';\nimport { useTranslation } from 'react-i18next';\r\nimport {\r\n User,\r\n Save,\r\n Loader2,\r\n Building2,\r\n Briefcase,\r\n Phone,\r\n MapPin as MapPinIcon,\r\n AtSign,\r\n Cloud,\r\n Shield,\r\n Edit3,\r\n CheckCircle,\r\n XCircle,\r\n Mail,\r\n Key\r\n} from 'lucide-react';\r\nimport { formatPhoneNumber } from '@/utils/formatPhone';\r\nimport { SelectWithOther } from '@/components/ui/SelectWithOther';\r\nimport type { UserDetailDto, OrganizationReferencesDto } from '@/services/api/adminApi';\r\nimport type { UserFormData } from '@/hooks/useUserDetail';\r\nimport type { SectionData, SectionType } from '@/hooks/useUserSections';\r\n\r\ninterface UserInfoTabProps {\r\n readonly user: UserDetailDto;\r\n readonly formData: UserFormData;\r\n readonly setFormData: React.Dispatch<React.SetStateAction<UserFormData>>;\r\n readonly handleSaveInfo: (e: React.FormEvent) => Promise<void>;\r\n readonly saving: boolean;\r\n readonly canUpdate: boolean;\r\n\r\n // Section editing\r\n readonly editingSection: string | null;\r\n readonly sectionData: SectionData;\r\n readonly setSectionData: React.Dispatch<React.SetStateAction<SectionData>>;\r\n readonly startEditingSection: (section: SectionType) => void;\r\n readonly cancelEditing: () => void;\r\n readonly handleSaveSection: (section: SectionType) => Promise<void>;\r\n\r\n // References\r\n readonly orgReferences: OrganizationReferencesDto | null;\r\n}\r\n\r\nconst formatDate = (date: string | null) => {\r\n if (!date) return '-';\r\n return new Date(date).toLocaleString();\r\n};\r\n\r\nexport function UserInfoTab({\r\n user,\r\n formData,\r\n setFormData,\r\n handleSaveInfo,\r\n saving,\r\n canUpdate,\r\n editingSection,\r\n sectionData,\r\n setSectionData,\r\n startEditingSection,\r\n cancelEditing,\r\n handleSaveSection,\r\n orgReferences\r\n}: UserInfoTabProps): ReactElement {\r\n const { t } = useTranslation('admin');\r\n\r\n return (\r\n <div className=\"space-y-6\">\r\n {/* Editable Profile Form */}\r\n <form onSubmit={handleSaveInfo} className=\"space-y-6 p-4 rounded-[var(--radius-card)] bg-[var(--bg-primary)] border border-[var(--border-color)]\">\r\n <h3 className=\"text-lg font-semibold text-[var(--text-primary)] flex items-center gap-2\">\r\n <User className=\"w-5 h-5\" />\r\n {t('userDetail.info.profile', 'Profil')}\r\n </h3>\r\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-4\">\r\n <div>\r\n <label className=\"block text-sm font-medium text-[var(--text-secondary)] mb-1\">\r\n {t('users.form.firstName')}\r\n </label>\r\n <input\r\n type=\"text\"\r\n required\r\n value={formData.firstName}\r\n onChange={e => setFormData(prev => ({ ...prev, firstName: e.target.value }))}\r\n className=\"w-full px-4 py-2 rounded-[var(--radius-input)] border border-[var(--border-color)] bg-[var(--bg-primary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n />\r\n </div>\r\n <div>\r\n <label className=\"block text-sm font-medium text-[var(--text-secondary)] mb-1\">\r\n {t('users.form.lastName')}\r\n </label>\r\n <input\r\n type=\"text\"\r\n required\r\n value={formData.lastName}\r\n onChange={e => setFormData(prev => ({ ...prev, lastName: e.target.value }))}\r\n className=\"w-full px-4 py-2 rounded-[var(--radius-input)] border border-[var(--border-color)] bg-[var(--bg-primary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <div>\r\n <label className=\"block text-sm font-medium text-[var(--text-secondary)] mb-1\">\r\n {t('users.columns.email')}\r\n </label>\r\n <input\r\n type=\"email\"\r\n required\r\n value={formData.email}\r\n onChange={e => setFormData(prev => ({ ...prev, email: e.target.value }))}\r\n className=\"w-full px-4 py-2 rounded-[var(--radius-input)] border border-[var(--border-color)] bg-[var(--bg-primary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n />\r\n </div>\r\n\r\n <div className=\"flex justify-end\">\r\n <button\r\n type=\"submit\"\r\n disabled={saving || !canUpdate}\r\n className={`flex items-center gap-2 px-4 py-2 rounded-[var(--radius-button)] font-medium transition-colors disabled:opacity-50 ${!canUpdate ? 'bg-[var(--bg-secondary)] text-[var(--text-tertiary)] cursor-not-allowed' : 'bg-[var(--color-accent-600)] hover:bg-[var(--color-accent-700)] text-white'}`}\r\n title={!canUpdate ? t('common.noPermission', 'Permission insuffisante') : undefined}\r\n >\r\n {saving ? <Loader2 className=\"w-4 h-4 animate-spin\" /> : <Save className=\"w-4 h-4\" />}\r\n {t('common.save')}\r\n </button>\r\n </div>\r\n </form>\r\n\r\n {/* Organization Info */}\r\n <EditableSection\r\n title={t('userDetail.info.organization', 'Organisation')}\r\n icon={<Building2 className=\"w-5 h-5\" />}\r\n sectionKey=\"organization\"\r\n editingSection={editingSection}\r\n saving={saving}\r\n canUpdate={canUpdate}\r\n onStartEdit={() => startEditingSection('organization')}\r\n onCancel={cancelEditing}\r\n onSave={() => handleSaveSection('organization')}\r\n >\r\n {editingSection === 'organization' ? (\r\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4\">\r\n <SelectWithOther\r\n label={t('userDetail.info.company', 'Société')}\r\n options={orgReferences?.companies.map(c => ({ id: c.id, name: c.name })) || []}\r\n value={sectionData.organization.company}\r\n onChange={val => setSectionData(prev => ({ ...prev, organization: { ...prev.organization, company: val } }))}\r\n />\r\n <SelectWithOther\r\n label={t('userDetail.info.department', 'Département')}\r\n options={orgReferences?.departments.map(d => ({ id: d.id, name: d.name })) || []}\r\n value={sectionData.organization.department}\r\n onChange={val => setSectionData(prev => ({ ...prev, organization: { ...prev.organization, department: val } }))}\r\n />\r\n <SelectWithOther\r\n label={t('userDetail.info.jobTitle', 'Fonction')}\r\n options={orgReferences?.jobTitles.map(j => ({ id: j.id, name: j.name })) || []}\r\n value={sectionData.organization.jobTitle}\r\n onChange={val => setSectionData(prev => ({ ...prev, organization: { ...prev.organization, jobTitle: val } }))}\r\n />\r\n <SelectWithOther\r\n label={t('userDetail.info.office', 'Bureau')}\r\n options={orgReferences?.offices.map(o => ({ id: o.id, name: o.name })) || []}\r\n value={sectionData.organization.office}\r\n onChange={val => setSectionData(prev => ({ ...prev, organization: { ...prev.organization, office: val } }))}\r\n />\r\n <div>\r\n <label className=\"block text-sm font-medium text-[var(--text-secondary)] mb-1\">{t('userDetail.info.manager', 'Manager')}</label>\r\n <select\r\n value={sectionData.organization.managerId}\r\n onChange={e => setSectionData(prev => ({ ...prev, organization: { ...prev.organization, managerId: e.target.value } }))}\r\n className=\"w-full px-4 py-2 rounded-[var(--radius-input)] border border-[var(--border-color)] bg-[var(--bg-primary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n >\r\n <option value=\"\">{t('common.none', '-- Aucun --')}</option>\r\n {orgReferences?.managers.map(m => (\r\n <option key={m.id} value={m.id}>{m.name}</option>\r\n ))}\r\n </select>\r\n </div>\r\n </div>\r\n ) : (\r\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4\">\r\n <InfoField label={t('userDetail.info.company', 'Société')} value={user.companyName} />\r\n <InfoField label={t('userDetail.info.department', 'Département')} value={user.departmentName} />\r\n <InfoField label={t('userDetail.info.jobTitle', 'Fonction')} value={user.jobTitleName} />\r\n <InfoField label={t('userDetail.info.office', 'Bureau')} value={user.officeName} />\r\n <InfoField label={t('userDetail.info.manager', 'Manager')} value={user.managerName} />\r\n </div>\r\n )}\r\n </EditableSection>\r\n\r\n {/* Job Information */}\r\n <EditableSection\r\n title={t('userDetail.info.jobInfo', 'Informations emploi')}\r\n icon={<Briefcase className=\"w-5 h-5\" />}\r\n sectionKey=\"jobInfo\"\r\n editingSection={editingSection}\r\n saving={saving}\r\n canUpdate={canUpdate}\r\n onStartEdit={() => startEditingSection('jobInfo')}\r\n onCancel={cancelEditing}\r\n onSave={() => handleSaveSection('jobInfo')}\r\n >\r\n {editingSection === 'jobInfo' ? (\r\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-4\">\r\n <div>\r\n <label className=\"block text-sm font-medium text-[var(--text-secondary)] mb-1\">{t('userDetail.info.employeeId', 'ID Employé')}</label>\r\n <input\r\n type=\"text\"\r\n value={sectionData.jobInfo.employeeId}\r\n onChange={e => setSectionData(prev => ({ ...prev, jobInfo: { ...prev.jobInfo, employeeId: e.target.value } }))}\r\n className=\"w-full px-4 py-2 rounded-[var(--radius-input)] border border-[var(--border-color)] bg-[var(--bg-primary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n />\r\n </div>\r\n <div>\r\n <label className=\"block text-sm font-medium text-[var(--text-secondary)] mb-1\">{t('userDetail.info.employeeType', 'Type employé')}</label>\r\n <input\r\n type=\"text\"\r\n value={sectionData.jobInfo.employeeType}\r\n onChange={e => setSectionData(prev => ({ ...prev, jobInfo: { ...prev.jobInfo, employeeType: e.target.value } }))}\r\n className=\"w-full px-4 py-2 rounded-[var(--radius-input)] border border-[var(--border-color)] bg-[var(--bg-primary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n />\r\n </div>\r\n <div>\r\n <label className=\"block text-sm font-medium text-[var(--text-secondary)] mb-1\">{t('userDetail.info.employeeHireDate', 'Date d\\'embauche')}</label>\r\n <input\r\n type=\"date\"\r\n value={sectionData.jobInfo.employeeHireDate}\r\n onChange={e => setSectionData(prev => ({ ...prev, jobInfo: { ...prev.jobInfo, employeeHireDate: e.target.value } }))}\r\n className=\"w-full px-4 py-2 rounded-[var(--radius-input)] border border-[var(--border-color)] bg-[var(--bg-primary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n />\r\n </div>\r\n </div>\r\n ) : (\r\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4\">\r\n <InfoField label={t('userDetail.info.employeeId', 'ID Employé')} value={user.employeeId} />\r\n <InfoField label={t('userDetail.info.employeeType', 'Type employé')} value={user.employeeType} />\r\n <InfoField label={t('userDetail.info.employeeHireDate', 'Date d\\'embauche')} value={user.employeeHireDate ? new Date(user.employeeHireDate).toLocaleDateString() : null} />\r\n <InfoField label={t('userDetail.info.sponsors', 'Sponsors')} value={user.sponsors} />\r\n </div>\r\n )}\r\n </EditableSection>\r\n\r\n {/* Phone Numbers */}\r\n <EditableSection\r\n title={t('userDetail.info.phones', 'Téléphones')}\r\n icon={<Phone className=\"w-5 h-5\" />}\r\n sectionKey=\"phones\"\r\n editingSection={editingSection}\r\n saving={saving}\r\n canUpdate={canUpdate}\r\n onStartEdit={() => startEditingSection('phones')}\r\n onCancel={cancelEditing}\r\n onSave={() => handleSaveSection('phones')}\r\n >\r\n {editingSection === 'phones' ? (\r\n <div className=\"grid grid-cols-1 sm:grid-cols-3 gap-4\">\r\n <div>\r\n <label className=\"block text-sm font-medium text-[var(--text-secondary)] mb-1\">{t('userDetail.info.phone', 'Téléphone')}</label>\r\n <input\r\n type=\"tel\"\r\n value={sectionData.phones.phoneNumber}\r\n onChange={e => setSectionData(prev => ({ ...prev, phones: { ...prev.phones, phoneNumber: e.target.value } }))}\r\n className=\"w-full px-4 py-2 rounded-[var(--radius-input)] border border-[var(--border-color)] bg-[var(--bg-primary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n />\r\n </div>\r\n <div>\r\n <label className=\"block text-sm font-medium text-[var(--text-secondary)] mb-1\">{t('userDetail.info.mobile', 'Mobile')}</label>\r\n <input\r\n type=\"tel\"\r\n value={sectionData.phones.mobilePhone}\r\n onChange={e => setSectionData(prev => ({ ...prev, phones: { ...prev.phones, mobilePhone: e.target.value } }))}\r\n className=\"w-full px-4 py-2 rounded-[var(--radius-input)] border border-[var(--border-color)] bg-[var(--bg-primary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n />\r\n </div>\r\n <div>\r\n <label className=\"block text-sm font-medium text-[var(--text-secondary)] mb-1\">{t('userDetail.info.fax', 'Fax')}</label>\r\n <input\r\n type=\"tel\"\r\n value={sectionData.phones.faxNumber}\r\n onChange={e => setSectionData(prev => ({ ...prev, phones: { ...prev.phones, faxNumber: e.target.value } }))}\r\n className=\"w-full px-4 py-2 rounded-[var(--radius-input)] border border-[var(--border-color)] bg-[var(--bg-primary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n />\r\n </div>\r\n </div>\r\n ) : (\r\n <div className=\"grid grid-cols-1 sm:grid-cols-3 gap-4\">\r\n <InfoField label={t('userDetail.info.phone', 'Téléphone')} value={formatPhoneNumber(user.phoneNumber, 'CH', 'international')} />\r\n <InfoField label={t('userDetail.info.mobile', 'Mobile')} value={formatPhoneNumber(user.mobilePhone, 'CH', 'international')} />\r\n <InfoField label={t('userDetail.info.fax', 'Fax')} value={formatPhoneNumber(user.faxNumber, 'CH', 'international')} />\r\n </div>\r\n )}\r\n </EditableSection>\r\n\r\n {/* Address */}\r\n <EditableSection\r\n title={t('userDetail.info.address', 'Adresse')}\r\n icon={<MapPinIcon className=\"w-5 h-5\" />}\r\n sectionKey=\"address\"\r\n editingSection={editingSection}\r\n saving={saving}\r\n canUpdate={canUpdate}\r\n onStartEdit={() => startEditingSection('address')}\r\n onCancel={cancelEditing}\r\n onSave={() => handleSaveSection('address')}\r\n >\r\n {editingSection === 'address' ? (\r\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-4\">\r\n <div className=\"sm:col-span-2\">\r\n <label className=\"block text-sm font-medium text-[var(--text-secondary)] mb-1\">{t('userDetail.info.streetAddress', 'Adresse')}</label>\r\n <input\r\n type=\"text\"\r\n value={sectionData.address.streetAddress}\r\n onChange={e => setSectionData(prev => ({ ...prev, address: { ...prev.address, streetAddress: e.target.value } }))}\r\n className=\"w-full px-4 py-2 rounded-[var(--radius-input)] border border-[var(--border-color)] bg-[var(--bg-primary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n />\r\n </div>\r\n <div>\r\n <label className=\"block text-sm font-medium text-[var(--text-secondary)] mb-1\">{t('userDetail.info.city', 'Ville')}</label>\r\n <input\r\n type=\"text\"\r\n value={sectionData.address.city}\r\n onChange={e => setSectionData(prev => ({ ...prev, address: { ...prev.address, city: e.target.value } }))}\r\n className=\"w-full px-4 py-2 rounded-[var(--radius-input)] border border-[var(--border-color)] bg-[var(--bg-primary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n />\r\n </div>\r\n <div>\r\n <label className=\"block text-sm font-medium text-[var(--text-secondary)] mb-1\">{t('userDetail.info.state', 'Région')}</label>\r\n <input\r\n type=\"text\"\r\n value={sectionData.address.state}\r\n onChange={e => setSectionData(prev => ({ ...prev, address: { ...prev.address, state: e.target.value } }))}\r\n className=\"w-full px-4 py-2 rounded-[var(--radius-input)] border border-[var(--border-color)] bg-[var(--bg-primary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n />\r\n </div>\r\n <div>\r\n <label className=\"block text-sm font-medium text-[var(--text-secondary)] mb-1\">{t('userDetail.info.postalCode', 'Code postal')}</label>\r\n <input\r\n type=\"text\"\r\n value={sectionData.address.postalCode}\r\n onChange={e => setSectionData(prev => ({ ...prev, address: { ...prev.address, postalCode: e.target.value } }))}\r\n className=\"w-full px-4 py-2 rounded-[var(--radius-input)] border border-[var(--border-color)] bg-[var(--bg-primary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n />\r\n </div>\r\n <div>\r\n <label className=\"block text-sm font-medium text-[var(--text-secondary)] mb-1\">{t('userDetail.info.country', 'Pays')}</label>\r\n <input\r\n type=\"text\"\r\n value={sectionData.address.country}\r\n onChange={e => setSectionData(prev => ({ ...prev, address: { ...prev.address, country: e.target.value } }))}\r\n className=\"w-full px-4 py-2 rounded-[var(--radius-input)] border border-[var(--border-color)] bg-[var(--bg-primary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n />\r\n </div>\r\n </div>\r\n ) : (\r\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4\">\r\n <InfoField label={t('userDetail.info.streetAddress', 'Adresse')} value={user.streetAddress} className=\"sm:col-span-2 lg:col-span-3\" />\r\n <InfoField label={t('userDetail.info.city', 'Ville')} value={user.city} />\r\n <InfoField label={t('userDetail.info.state', 'Région')} value={user.state} />\r\n <InfoField label={t('userDetail.info.postalCode', 'Code postal')} value={user.postalCode} />\r\n <InfoField label={t('userDetail.info.country', 'Pays')} value={user.country} />\r\n </div>\r\n )}\r\n </EditableSection>\r\n\r\n {/* Other Contact Info (Read-only) */}\r\n {(user.otherEmails || user.mailNickname || user.imAddresses) && (\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--bg-primary)] border border-[var(--border-color)]\">\r\n <h3 className=\"text-lg font-semibold text-[var(--text-primary)] flex items-center gap-2 mb-4\">\r\n <AtSign className=\"w-5 h-5\" />\r\n {t('userDetail.info.otherContact', 'Autres coordonnées')}\r\n </h3>\r\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4\">\r\n {user.mailNickname && <InfoField label={t('userDetail.info.mailNickname', 'Alias mail')} value={user.mailNickname} />}\r\n {user.otherEmails && <InfoField label={t('userDetail.info.otherEmails', 'Autres emails')} value={user.otherEmails} breakAll />}\r\n {user.imAddresses && <InfoField label={t('userDetail.info.imAddresses', 'Messagerie instantanée')} value={user.imAddresses} breakAll />}\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* Entra / AAD Sync Status */}\r\n {user.entraObjectId && (\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800\">\r\n <h3 className=\"text-lg font-semibold text-blue-800 dark:text-blue-300 flex items-center gap-2 mb-4\">\r\n <Cloud className=\"w-5 h-5\" />\r\n {t('userDetail.info.entraSync', 'Synchronisation Microsoft Entra ID')}\r\n </h3>\r\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4\">\r\n <div className=\"p-3 rounded-lg bg-white/50 dark:bg-black/20\">\r\n <p className=\"text-xs text-blue-600 dark:text-blue-400 uppercase tracking-wider mb-1\">{t('userDetail.info.entraObjectId', 'Object ID')}</p>\r\n <p className=\"text-sm text-blue-900 dark:text-blue-200 font-mono break-all\">{user.entraObjectId}</p>\r\n </div>\r\n <div className=\"p-3 rounded-lg bg-white/50 dark:bg-black/20\">\r\n <p className=\"text-xs text-blue-600 dark:text-blue-400 uppercase tracking-wider mb-1\">{t('userDetail.info.authProvider', 'Fournisseur')}</p>\r\n <p className=\"text-sm text-blue-900 dark:text-blue-200 font-medium capitalize\">{user.authProvider || 'microsoft'}</p>\r\n </div>\r\n <div className=\"p-3 rounded-lg bg-white/50 dark:bg-black/20\">\r\n <p className=\"text-xs text-blue-600 dark:text-blue-400 uppercase tracking-wider mb-1\">{t('userDetail.info.lastEntraSync', 'Dernière sync')}</p>\r\n <p className=\"text-sm text-blue-900 dark:text-blue-200 font-medium\">{formatDate(user.lastEntraSyncAt)}</p>\r\n </div>\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* Account Status Badges & Dates */}\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--bg-primary)] border border-[var(--border-color)]\">\r\n <h3 className=\"text-lg font-semibold text-[var(--text-primary)] flex items-center gap-2 mb-4\">\r\n <Shield className=\"w-5 h-5\" />\r\n {t('userDetail.info.accountStatus', 'Statut du compte')}\r\n </h3>\r\n\r\n {/* Status Badges */}\r\n <div className=\"flex flex-wrap gap-2 mb-4\">\r\n <StatusBadge\r\n active={user.isActive}\r\n activeLabel={t('users.status.active')}\r\n inactiveLabel={t('users.status.inactive')}\r\n type=\"active\"\r\n />\r\n <StatusBadge\r\n active={user.emailConfirmed}\r\n activeLabel={t('userDetail.info.emailConfirmed', 'Email confirmé')}\r\n inactiveLabel={t('userDetail.info.emailNotConfirmed', 'Email non confirmé')}\r\n type=\"email\"\r\n />\r\n <StatusBadge\r\n active={user.hasCompletedOnboarding}\r\n activeLabel={t('userDetail.info.onboardingComplete', 'Onboarding terminé')}\r\n inactiveLabel={t('userDetail.info.onboardingPending', 'Onboarding en attente')}\r\n type=\"onboarding\"\r\n />\r\n {user.mustChangePassword && (\r\n <span className=\"inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-sm font-medium bg-amber-100 dark:bg-amber-900/30 text-amber-700 dark:text-amber-400\">\r\n <Key className=\"w-4 h-4\" />\r\n {t('userDetail.info.mustChangePassword', 'Changement de mot de passe requis')}\r\n </span>\r\n )}\r\n {user.entraObjectId && (\r\n <span className=\"inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-sm font-medium bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-400\">\r\n <Cloud className=\"w-4 h-4\" />\r\n {t('userDetail.info.syncedWithAad', 'Synchronisé AAD')}\r\n </span>\r\n )}\r\n </div>\r\n\r\n {/* Dates */}\r\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 pt-4 border-t border-[var(--border-color)]\">\r\n <div>\r\n <p className=\"text-xs text-[var(--text-tertiary)] uppercase tracking-wider mb-1\">{t('userDetail.createdAt')}</p>\r\n <p className=\"text-sm text-[var(--text-primary)] font-medium\">{formatDate(user.createdAt)}</p>\r\n </div>\r\n <div>\r\n <p className=\"text-xs text-[var(--text-tertiary)] uppercase tracking-wider mb-1\">{t('userDetail.updatedAt', 'Modifié le')}</p>\r\n <p className=\"text-sm text-[var(--text-primary)] font-medium\">{formatDate(user.updatedAt)}</p>\r\n </div>\r\n <div>\r\n <p className=\"text-xs text-[var(--text-tertiary)] uppercase tracking-wider mb-1\">{t('userDetail.lastLogin')}</p>\r\n <p className=\"text-sm text-[var(--text-primary)] font-medium\">{formatDate(user.lastLoginAt)}</p>\r\n </div>\r\n <div>\r\n <p className=\"text-xs text-[var(--text-tertiary)] uppercase tracking-wider mb-1\">{t('userDetail.info.userType', 'Type')}</p>\r\n <p className=\"text-sm text-[var(--text-primary)] font-medium\">{user.userType}</p>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n}\r\n\r\n// Helper Components\r\n\r\ninterface InfoFieldProps {\r\n readonly label: string;\r\n readonly value: string | null | undefined;\r\n readonly className?: string;\r\n readonly breakAll?: boolean;\r\n}\r\n\r\nfunction InfoField({ label, value, className, breakAll }: InfoFieldProps) {\r\n return (\r\n <div className={`p-3 rounded-lg bg-[var(--bg-secondary)] ${className || ''}`}>\r\n <p className=\"text-xs text-[var(--text-tertiary)] uppercase tracking-wider mb-1\">{label}</p>\r\n <p className={`text-sm text-[var(--text-primary)] font-medium ${breakAll ? 'break-all' : ''}`}>{value || '-'}</p>\r\n </div>\r\n );\r\n}\r\n\r\ninterface EditableSectionProps {\r\n readonly title: string;\r\n readonly icon: React.ReactNode;\r\n readonly sectionKey: SectionType;\r\n readonly editingSection: string | null;\r\n readonly saving: boolean;\r\n readonly canUpdate: boolean;\r\n readonly onStartEdit: () => void;\r\n readonly onCancel: () => void;\r\n readonly onSave: () => void;\r\n readonly children: React.ReactNode;\r\n}\r\n\r\nfunction EditableSection({\r\n title,\r\n icon,\r\n sectionKey,\r\n editingSection,\r\n saving,\r\n canUpdate,\r\n onStartEdit,\r\n onCancel,\r\n onSave,\r\n children\r\n}: EditableSectionProps) {\r\n const { t } = useTranslation('admin');\r\n const isEditing = editingSection === sectionKey;\r\n\r\n return (\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--bg-primary)] border border-[var(--border-color)]\">\r\n <div className=\"flex items-center justify-between mb-4\">\r\n <h3 className=\"text-lg font-semibold text-[var(--text-primary)] flex items-center gap-2\">\r\n {icon}\r\n {title}\r\n </h3>\r\n {!isEditing ? (\r\n <button\r\n onClick={onStartEdit}\r\n disabled={!canUpdate}\r\n className={`flex items-center gap-1 px-3 py-1.5 rounded-[var(--radius-button)] transition-colors ${!canUpdate ? 'opacity-50 cursor-not-allowed bg-[var(--bg-secondary)] text-[var(--text-tertiary)]' : 'bg-[var(--bg-secondary)] text-[var(--text-secondary)] hover:bg-[var(--bg-hover)]'}`}\r\n title={!canUpdate ? t('common.noPermission', 'Permission insuffisante') : undefined}\r\n >\r\n <Edit3 className=\"w-4 h-4\" />\r\n {t('common.edit', 'Modifier')}\r\n </button>\r\n ) : (\r\n <div className=\"flex items-center gap-2\">\r\n <button\r\n onClick={onCancel}\r\n className=\"px-3 py-1.5 rounded-[var(--radius-button)] bg-[var(--bg-secondary)] text-[var(--text-secondary)] hover:bg-[var(--bg-hover)] transition-colors\"\r\n >\r\n {t('common.cancel', 'Annuler')}\r\n </button>\r\n <button\r\n onClick={onSave}\r\n disabled={saving || !canUpdate}\r\n className={`flex items-center gap-1 px-3 py-1.5 rounded-[var(--radius-button)] transition-colors disabled:opacity-50 ${!canUpdate ? 'bg-[var(--bg-secondary)] text-[var(--text-tertiary)] cursor-not-allowed' : 'bg-[var(--color-accent-600)] text-white hover:bg-[var(--color-accent-700)]'}`}\r\n title={!canUpdate ? t('common.noPermission', 'Permission insuffisante') : undefined}\r\n >\r\n {saving ? <Loader2 className=\"w-4 h-4 animate-spin\" /> : <Save className=\"w-4 h-4\" />}\r\n {t('common.save', 'Enregistrer')}\r\n </button>\r\n </div>\r\n )}\r\n </div>\r\n {children}\r\n </div>\r\n );\r\n}\r\n\r\ninterface StatusBadgeProps {\r\n readonly active: boolean;\r\n readonly activeLabel: string;\r\n readonly inactiveLabel: string;\r\n readonly type: 'active' | 'email' | 'onboarding';\r\n}\r\n\r\nfunction StatusBadge({ active, activeLabel, inactiveLabel, type }: StatusBadgeProps) {\r\n const getIcon = () => {\r\n if (type === 'email') return <Mail className=\"w-4 h-4\" />;\r\n if (type === 'onboarding') return <User className=\"w-4 h-4\" />;\r\n return active ? <CheckCircle className=\"w-4 h-4\" /> : <XCircle className=\"w-4 h-4\" />;\r\n };\r\n\r\n const getColors = () => {\r\n if (active) return 'bg-green-100 dark:bg-green-900/30 text-green-700 dark:text-green-400';\r\n if (type === 'active') return 'bg-red-100 dark:bg-red-900/30 text-red-700 dark:text-red-400';\r\n return 'bg-amber-100 dark:bg-amber-900/30 text-amber-700 dark:text-amber-400';\r\n };\r\n\r\n return (\r\n <span className={`inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-sm font-medium ${getColors()}`}>\r\n {getIcon()}\r\n {active ? activeLabel : inactiveLabel}\r\n </span>\r\n );\r\n}\r\n","import { useState } from 'react';\r\nimport type { ReactElement } from 'react';\r\nimport { useTranslation } from 'react-i18next';\r\nimport { X, Bug } from 'lucide-react';\r\nimport { UnlockReason } from '@/services/api/adminApi';\r\n\r\ninterface UnlockAccountModalProps {\r\n readonly isOpen: boolean;\r\n readonly onClose: () => void;\r\n readonly onConfirm: (reason: UnlockReason, mustChangePassword: boolean) => void;\r\n readonly userName: string;\r\n}\r\n\r\nexport function UnlockAccountModal({\r\n isOpen,\r\n onClose,\r\n onConfirm,\r\n userName,\r\n}: UnlockAccountModalProps): ReactElement | null {\r\n const { t } = useTranslation(['admin', 'common']);\r\n const [selectedReason, setSelectedReason] = useState<UnlockReason | ''>('');\r\n const [mustChangePassword, setMustChangePassword] = useState(false);\r\n\r\n const handleConfirm = () => {\r\n if (selectedReason === '') return;\r\n onConfirm(selectedReason as UnlockReason, mustChangePassword);\r\n onClose();\r\n // Reset state\r\n setSelectedReason('');\r\n setMustChangePassword(false);\r\n };\r\n\r\n const handleClose = () => {\r\n onClose();\r\n // Reset state\r\n setSelectedReason('');\r\n setMustChangePassword(false);\r\n };\r\n\r\n if (!isOpen) return null;\r\n\r\n return (\r\n <div className=\"fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/50 backdrop-blur-sm\">\r\n <div className=\"relative w-full max-w-md bg-[var(--bg-card)] rounded-2xl shadow-2xl border border-[var(--border-color)] overflow-hidden\">\r\n {/* Header */}\r\n <div className=\"flex items-center justify-between p-6 border-b border-[var(--border-color)]\">\r\n <div>\r\n <h2 className=\"text-xl font-semibold text-[var(--text-primary)]\">\r\n {t('userDetail.security.unlockAccount')}\r\n </h2>\r\n <p className=\"text-sm text-[var(--text-secondary)] mt-1\">{userName}</p>\r\n </div>\r\n <div className=\"flex items-center gap-1\">\r\n <button\r\n onClick={() => {\r\n const bugInfo = {\r\n component: 'UnlockAccountModal',\r\n user: userName,\r\n url: window.location.href,\r\n };\r\n const issueUrl = `https://github.com/anthropics/claude-code/issues/new?title=${encodeURIComponent('[Bug] Unlock Account Modal')}&body=${encodeURIComponent(`## Context\\n- Component: ${bugInfo.component}\\n- URL: ${bugInfo.url}\\n\\n## Description\\n\\n<!-- Describe the bug here -->\\n\\n## Steps to Reproduce\\n\\n1. \\n2. \\n3. \\n\\n## Expected Behavior\\n\\n## Actual Behavior\\n`)}`;\r\n window.open(issueUrl, '_blank');\r\n }}\r\n className=\"p-2 rounded-lg hover:bg-[var(--bg-hover)] transition-colors\"\r\n title={t('common:buttons.reportBug')}\r\n >\r\n <Bug className=\"w-5 h-5 text-[var(--text-secondary)]\" />\r\n </button>\r\n <button\r\n onClick={handleClose}\r\n className=\"p-2 rounded-lg hover:bg-[var(--bg-hover)] transition-colors\"\r\n aria-label=\"Close\"\r\n >\r\n <X className=\"w-5 h-5 text-[var(--text-secondary)]\" />\r\n </button>\r\n </div>\r\n </div>\r\n\r\n {/* Content */}\r\n <div className=\"p-6 space-y-6\">\r\n {/* Reason Selection */}\r\n <div>\r\n <label className=\"block text-sm font-medium text-[var(--text-primary)] mb-2\">\r\n {t('userDetail.security.unlockReason')}\r\n <span className=\"text-red-500 ml-1\">*</span>\r\n </label>\r\n <select\r\n value={selectedReason}\r\n onChange={(e) => setSelectedReason(e.target.value as UnlockReason | '')}\r\n className=\"w-full px-4 py-3 rounded-xl border border-[var(--border-color)] bg-[var(--bg-tertiary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-primary-500 transition-all\"\r\n >\r\n <option value=\"\">{t('userDetail.security.selectReason')}</option>\r\n <option value={UnlockReason.PasswordResetMalfunction}>\r\n {t('userDetail.security.unlockReasons.1')}\r\n </option>\r\n <option value={UnlockReason.FalsePositive}>\r\n {t('userDetail.security.unlockReasons.2')}\r\n </option>\r\n <option value={UnlockReason.UrgentBusinessNeed}>\r\n {t('userDetail.security.unlockReasons.3')}\r\n </option>\r\n <option value={UnlockReason.TechnicalSystemError}>\r\n {t('userDetail.security.unlockReasons.4')}\r\n </option>\r\n <option value={UnlockReason.SupportTicketVerified}>\r\n {t('userDetail.security.unlockReasons.5')}\r\n </option>\r\n </select>\r\n </div>\r\n\r\n {/* Password Change Checkbox */}\r\n <div className=\"flex items-start space-x-3 p-4 rounded-xl bg-[var(--bg-secondary)] border border-[var(--border-subtle)]\">\r\n <input\r\n type=\"checkbox\"\r\n id=\"mustChangePassword\"\r\n checked={mustChangePassword}\r\n onChange={(e) => setMustChangePassword(e.target.checked)}\r\n className=\"mt-1 w-4 h-4 rounded border-[var(--border-color)] text-primary-600 focus:ring-2 focus:ring-primary-500 bg-[var(--bg-tertiary)]\"\r\n />\r\n <label\r\n htmlFor=\"mustChangePassword\"\r\n className=\"text-sm text-[var(--text-secondary)] cursor-pointer select-none\"\r\n >\r\n {t('userDetail.security.mustChangePassword')}\r\n </label>\r\n </div>\r\n </div>\r\n\r\n {/* Footer */}\r\n <div className=\"flex items-center justify-end gap-3 p-6 border-t border-[var(--border-color)] bg-[var(--bg-secondary)]\">\r\n <button\r\n onClick={handleClose}\r\n className=\"px-6 py-2.5 rounded-xl border border-[var(--border-color)] text-[var(--text-secondary)] hover:bg-[var(--bg-hover)] transition-all font-medium\"\r\n >\r\n {t('common.cancel')}\r\n </button>\r\n <button\r\n onClick={handleConfirm}\r\n disabled={selectedReason === ''}\r\n className={`px-6 py-2.5 rounded-xl font-medium transition-all ${\r\n selectedReason === ''\r\n ? 'bg-gray-400 text-gray-200 cursor-not-allowed'\r\n : 'bg-gradient-to-r from-green-600 to-emerald-600 text-white hover:from-green-700 hover:to-emerald-700 shadow-lg shadow-green-500/30'\r\n }`}\r\n >\r\n {t('userDetail.security.unlock')}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n}\r\n","import type { ReactElement } from 'react';\nimport { useNavigate } from 'react-router-dom';\r\nimport { useTranslation } from 'react-i18next';\r\nimport {\r\n Loader2,\r\n Mail,\r\n RefreshCw,\r\n Eye,\r\n EyeOff,\r\n Copy,\r\n UserCheck,\r\n UserX,\r\n LogOut,\r\n Unlock,\r\n Trash2\r\n} from 'lucide-react';\r\nimport { adminApi, type UserDetailDto, UnlockReason } from '@/services/api/adminApi';\r\nimport { UnlockAccountModal } from '@/components/ui/UnlockAccountModal';\r\n\r\ninterface UserSecurityTabProps {\r\n readonly user: UserDetailDto;\r\n readonly userId: string;\r\n\r\n // Permissions\r\n readonly canUpdate: boolean;\r\n readonly canDelete: boolean;\r\n readonly canExecute: boolean;\r\n\r\n // Password state\r\n readonly newPassword: string;\r\n readonly setNewPassword: (password: string) => void;\r\n readonly temporaryPassword: string | null;\r\n readonly showTemporaryPassword: boolean;\r\n readonly setShowTemporaryPassword: (show: boolean) => void;\r\n readonly saving: boolean;\r\n\r\n // Modal state\r\n readonly showUnlockModal: boolean;\r\n readonly setShowUnlockModal: (show: boolean) => void;\r\n\r\n // Actions\r\n readonly handleSendResetLink: () => Promise<void>;\r\n readonly handleResetPasswordDirect: () => Promise<void>;\r\n readonly handleToggleStatus: (isActive: boolean) => Promise<void>;\r\n readonly handleEndAllSessions: () => Promise<void>;\r\n readonly handleUnlock: (reason: UnlockReason, mustChangePassword: boolean) => Promise<void>;\r\n readonly handleClearFailedAttempts: () => Promise<void>;\r\n readonly copyToClipboard: (text: string) => Promise<void>;\r\n\r\n // Error handling\r\n readonly setError: (error: string | null) => void;\r\n}\r\n\r\nconst getButtonClasses = (hasPermission: boolean, colorClass: string): string => {\r\n if (!hasPermission) {\r\n return 'opacity-50 cursor-not-allowed bg-[var(--bg-secondary)] text-[var(--text-tertiary)]';\r\n }\r\n return colorClass;\r\n};\r\n\r\nconst getPrimaryButtonClasses = (hasPermission: boolean): string => {\r\n return getButtonClasses(hasPermission, 'bg-[var(--color-accent-600)] hover:bg-[var(--color-accent-700)] text-white');\r\n};\r\n\r\nconst getWarningButtonClasses = (hasPermission: boolean): string => {\r\n return getButtonClasses(hasPermission, 'bg-amber-600 hover:bg-amber-700 text-white');\r\n};\r\n\r\nconst getRedButtonClasses = (hasPermission: boolean): string => {\r\n return getButtonClasses(hasPermission, 'bg-red-600 hover:bg-red-700 text-white');\r\n};\r\n\r\nconst getGreenButtonClasses = (isActive: boolean, hasPermission: boolean): string => {\r\n const activeClass = isActive ? 'bg-red-600 hover:bg-red-700 text-white' : 'bg-green-600 hover:bg-green-700 text-white';\r\n return getButtonClasses(hasPermission, activeClass);\r\n};\r\n\r\nexport function UserSecurityTab({\r\n user,\r\n userId,\r\n canUpdate,\r\n canDelete,\r\n canExecute,\r\n newPassword,\r\n setNewPassword,\r\n temporaryPassword,\r\n showTemporaryPassword,\r\n setShowTemporaryPassword,\r\n saving,\r\n showUnlockModal,\r\n setShowUnlockModal,\r\n handleSendResetLink,\r\n handleResetPasswordDirect,\r\n handleToggleStatus,\r\n handleEndAllSessions,\r\n handleUnlock,\r\n handleClearFailedAttempts,\r\n copyToClipboard,\r\n setError\r\n}: UserSecurityTabProps): ReactElement {\r\n const { t } = useTranslation('admin');\r\n const navigate = useNavigate();\r\n\r\n const getAccountStatusText = (): string => {\r\n if (user.isLocked) return 'Verrouillé (manuel)';\r\n if (user.isTemporarilyLocked) return 'Verrouillé (temporaire)';\r\n if (user.isActive) return t('userDetail.security.accountActive');\r\n return t('userDetail.security.accountInactive');\r\n };\r\n\r\n const getAccountStatusHint = (): string => {\r\n if (user.isLocked) return 'Verrouillé par un administrateur - nécessite un déverrouillage manuel';\r\n if (user.isTemporarilyLocked) return 'Verrouillé suite à plusieurs tentatives échouées - déblocage automatique dans quelques minutes';\r\n if (user.isActive) return t('userDetail.security.deactivateHint');\r\n return t('userDetail.security.activateHint');\r\n };\r\n\r\n const handleDelete = async () => {\r\n if (!confirm(t('users.confirmDelete', { name: user.fullName }))) return;\r\n try {\r\n await adminApi.users.delete(userId);\r\n navigate('/administration/users');\r\n } catch {\r\n setError(t('userDetail.errors.deleteFailed'));\r\n }\r\n };\r\n\r\n return (\r\n <div className=\"space-y-6\">\r\n {/* Send Reset Link (Admin) */}\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--bg-primary)] border border-[var(--border-color)]\">\r\n <h3 className=\"text-lg font-semibold text-[var(--text-primary)] mb-2\">\r\n {t('userDetail.security.sendResetLink', 'Envoyer un lien de réinitialisation')}\r\n </h3>\r\n <p className=\"text-sm text-[var(--text-secondary)] mb-4\">\r\n {t('userDetail.security.sendResetLinkHint', 'L\\'utilisateur recevra un email avec un lien pour définir son nouveau mot de passe.')}\r\n </p>\r\n <button\r\n onClick={handleSendResetLink}\r\n disabled={saving || !canUpdate}\r\n className={`flex items-center gap-2 px-4 py-2 rounded-[var(--radius-button)] font-medium transition-colors disabled:opacity-50 ${getPrimaryButtonClasses(canUpdate)}`}\r\n title={!canUpdate ? t('common.noPermission', 'Permission insuffisante') : undefined}\r\n >\r\n {saving ? <Loader2 className=\"w-4 h-4 animate-spin\" /> : <Mail className=\"w-4 h-4\" />}\r\n {t('userDetail.security.sendLink', 'Envoyer le lien')}\r\n </button>\r\n </div>\r\n\r\n {/* Direct Reset (SuperAdmin) */}\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--warning-bg)] border border-[var(--warning-border)]\">\r\n <h3 className=\"text-lg font-semibold text-[var(--warning-text)] mb-2\">\r\n {t('userDetail.security.directReset', 'Réinitialisation directe (SuperAdmin)')}\r\n </h3>\r\n <p className=\"text-sm text-[var(--warning-text)] opacity-80 mb-4\">\r\n {t('userDetail.security.directResetHint', 'Génère un mot de passe temporaire que vous devez communiquer à l\\'utilisateur. Il devra le changer à sa prochaine connexion.')}\r\n </p>\r\n <div className=\"flex gap-4 mb-4\">\r\n <input\r\n type=\"text\"\r\n placeholder={t('userDetail.security.customPassword', 'Mot de passe personnalisé (optionnel)')}\r\n value={newPassword}\r\n onChange={e => setNewPassword(e.target.value)}\r\n autoComplete=\"off\"\r\n className=\"flex-1 px-4 py-2 rounded-[var(--radius-input)] border border-[var(--warning-border)] bg-[var(--bg-primary)] text-[var(--text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--warning-dot)]\"\r\n />\r\n <button\r\n onClick={handleResetPasswordDirect}\r\n disabled={saving || !canExecute}\r\n className={`flex items-center gap-2 px-4 py-2 rounded-[var(--radius-button)] font-medium transition-colors disabled:opacity-50 ${getWarningButtonClasses(canExecute)}`}\r\n title={!canExecute ? t('common.noPermission', 'Permission insuffisante') : undefined}\r\n >\r\n {saving ? <Loader2 className=\"w-4 h-4 animate-spin\" /> : <RefreshCw className=\"w-4 h-4\" />}\r\n {t('userDetail.security.resetDirect', 'Réinitialiser')}\r\n </button>\r\n </div>\r\n\r\n {/* Show temporary password after direct reset */}\r\n {temporaryPassword && (\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--success-bg)] border border-[var(--success-border)]\">\r\n <p className=\"text-sm font-medium text-[var(--success-text)] mb-2\">\r\n {t('userDetail.security.temporaryPasswordLabel', 'Mot de passe temporaire généré:')}\r\n </p>\r\n <div className=\"flex items-center gap-2\">\r\n <code className=\"flex-1 px-3 py-2 rounded-[var(--radius-input)] bg-[var(--bg-primary)] text-[var(--text-primary)] font-mono text-lg\">\r\n {showTemporaryPassword ? temporaryPassword : '••••••••••••••••'}\r\n </code>\r\n <button\r\n onClick={() => setShowTemporaryPassword(!showTemporaryPassword)}\r\n className=\"p-2 rounded-[var(--radius-button)] hover:bg-[var(--bg-hover)] text-[var(--success-text)] transition-colors\"\r\n title={showTemporaryPassword ? 'Masquer' : 'Afficher'}\r\n >\r\n {showTemporaryPassword ? <EyeOff className=\"w-5 h-5\" /> : <Eye className=\"w-5 h-5\" />}\r\n </button>\r\n <button\r\n onClick={() => copyToClipboard(temporaryPassword)}\r\n className=\"p-2 rounded-[var(--radius-button)] hover:bg-[var(--bg-hover)] text-[var(--success-text)] transition-colors\"\r\n title=\"Copier\"\r\n >\r\n <Copy className=\"w-5 h-5\" />\r\n </button>\r\n </div>\r\n <p className=\"text-xs text-[var(--success-text)] opacity-80 mt-2\">\r\n {t('userDetail.security.temporaryPasswordWarning', 'Ce mot de passe ne sera plus affiché. Communiquez-le immédiatement à l\\'utilisateur.')}\r\n </p>\r\n </div>\r\n )}\r\n </div>\r\n\r\n {/* Account Status */}\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--bg-primary)] border border-[var(--border-color)]\">\r\n <h3 className=\"text-lg font-semibold text-[var(--text-primary)] mb-4\">\r\n {t('userDetail.security.accountStatus')}\r\n </h3>\r\n <div className=\"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4\">\r\n <div>\r\n <p className=\"text-[var(--text-primary)]\">\r\n {getAccountStatusText()}\r\n </p>\r\n <p className=\"text-sm text-[var(--text-secondary)]\">\r\n {getAccountStatusHint()}\r\n </p>\r\n </div>\r\n <button\r\n onClick={() => handleToggleStatus(user.isActive)}\r\n disabled={!canUpdate}\r\n className={`flex items-center gap-2 px-4 py-2 rounded-[var(--radius-button)] font-medium transition-colors ${getGreenButtonClasses(user.isActive, canUpdate)}`}\r\n title={!canUpdate ? t('common.noPermission', 'Permission insuffisante') : undefined}\r\n >\r\n {user.isActive ? <UserX className=\"w-4 h-4\" /> : <UserCheck className=\"w-4 h-4\" />}\r\n {user.isActive ? t('users.deactivate') : t('users.activate')}\r\n </button>\r\n </div>\r\n </div>\r\n\r\n {/* Force Logout */}\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--bg-primary)] border border-[var(--border-color)]\">\r\n <h3 className=\"text-lg font-semibold text-[var(--text-primary)] mb-4\">\r\n {t('userDetail.security.forceLogout')}\r\n </h3>\r\n <div className=\"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4\">\r\n <div>\r\n <p className=\"text-[var(--text-primary)]\">{t('userDetail.security.endAllSessionsLabel')}</p>\r\n <p className=\"text-sm text-[var(--text-secondary)]\">{t('userDetail.security.endAllSessionsHint')}</p>\r\n </div>\r\n <button\r\n onClick={handleEndAllSessions}\r\n disabled={!canUpdate}\r\n className={`flex items-center gap-2 px-4 py-2 rounded-[var(--radius-button)] font-medium transition-colors ${getWarningButtonClasses(canUpdate)}`}\r\n title={!canUpdate ? t('common.noPermission', 'Permission insuffisante') : undefined}\r\n >\r\n <LogOut className=\"w-4 h-4\" />\r\n {t('userDetail.security.endAllSessions')}\r\n </button>\r\n </div>\r\n </div>\r\n\r\n {/* Unlock Account - Manual Lock */}\r\n {user.isLocked && (\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--warning-bg)] border border-[var(--warning-border)]\">\r\n <h3 className=\"text-lg font-semibold text-[var(--warning-text)] mb-4\">\r\n {t('userDetail.security.unlockAccount')}\r\n </h3>\r\n <div className=\"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4\">\r\n <div>\r\n <p className=\"text-[var(--warning-text)]\">Compte verrouillé manuellement par un administrateur</p>\r\n <p className=\"text-sm text-[var(--warning-text)] opacity-80\">{t('userDetail.security.unlockHint')}</p>\r\n </div>\r\n <button\r\n onClick={() => setShowUnlockModal(true)}\r\n disabled={!canUpdate}\r\n className={`flex items-center gap-2 px-4 py-2 rounded-[var(--radius-button)] font-medium transition-colors ${getWarningButtonClasses(canUpdate)}`}\r\n title={!canUpdate ? t('common.noPermission', 'Permission insuffisante') : undefined}\r\n >\r\n <Unlock className=\"w-4 h-4\" />\r\n {t('userDetail.security.unlock')}\r\n </button>\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* Unlock Account - Temporary Lock (Failed Attempts) */}\r\n {!user.isLocked && user.isTemporarilyLocked && (\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--warning-bg)] border border-[var(--warning-border)]\">\r\n <h3 className=\"text-lg font-semibold text-[var(--warning-text)] mb-4\">\r\n Verrouillage temporaire\r\n </h3>\r\n <div className=\"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4\">\r\n <div>\r\n <p className=\"text-[var(--warning-text)]\">\r\n Compte temporairement verrouillé suite à trop de tentatives échouées\r\n </p>\r\n <p className=\"text-sm text-[var(--warning-text)] opacity-80\">\r\n {user.temporaryLockoutEnd && (\r\n <>Déverrouillage automatique prévu à {new Date(user.temporaryLockoutEnd).toLocaleTimeString('fr-FR')}</>\r\n )}\r\n </p>\r\n </div>\r\n <button\r\n onClick={handleClearFailedAttempts}\r\n disabled={!canUpdate}\r\n className={`flex items-center gap-2 px-4 py-2 rounded-[var(--radius-button)] font-medium transition-colors ${getWarningButtonClasses(canUpdate)}`}\r\n title={!canUpdate ? t('common.noPermission', 'Permission insuffisante') : undefined}\r\n >\r\n <Unlock className=\"w-4 h-4\" />\r\n Débloquer maintenant\r\n </button>\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* Delete Account */}\r\n {user.userType !== 'System' && user.userType !== 'LocalAdmin' && (\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--error-bg)] border border-[var(--error-border)]\">\r\n <h3 className=\"text-lg font-semibold text-[var(--error-text)] mb-4\">\r\n {t('userDetail.security.dangerZone')}\r\n </h3>\r\n <div className=\"flex items-center justify-between\">\r\n <div>\r\n <p className=\"text-[var(--error-text)]\">{t('userDetail.security.deleteAccount')}</p>\r\n <p className=\"text-sm text-[var(--error-text)] opacity-80\">{t('userDetail.security.deleteHint')}</p>\r\n </div>\r\n <button\r\n onClick={handleDelete}\r\n disabled={!canDelete}\r\n className={`flex items-center gap-2 px-4 py-2 rounded-[var(--radius-button)] font-medium transition-colors ${getRedButtonClasses(canDelete)}`}\r\n title={!canDelete ? t('common.noPermission', 'Permission insuffisante') : undefined}\r\n >\r\n <Trash2 className=\"w-4 h-4\" />\r\n {t('common.delete')}\r\n </button>\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* Unlock Account Modal */}\r\n <UnlockAccountModal\r\n isOpen={showUnlockModal}\r\n onClose={() => setShowUnlockModal(false)}\r\n onConfirm={handleUnlock}\r\n userName={user.fullName}\r\n />\r\n </div>\r\n );\r\n}\r\n","import type { ReactElement } from 'react';\r\nimport { useTranslation } from 'react-i18next';\r\nimport {\r\n Loader2,\r\n Activity,\r\n Smartphone,\r\n MapPin,\r\n Calendar,\r\n Monitor,\r\n CheckCircle,\r\n XCircle,\r\n LogOut\r\n} from 'lucide-react';\r\nimport type { UserSessionsDto, UserActivityDto, SessionDto } from '@/services/api/adminApi';\r\nimport { parseUserAgent } from '@/utils/deviceDetection';\r\n\r\ninterface UserActivitySessionsTabProps {\r\n readonly sessions: UserSessionsDto | null;\r\n readonly activity: UserActivityDto | null;\r\n readonly isCreateMode: boolean;\r\n readonly canUpdate: boolean;\r\n readonly handleEndSession: (sessionId: string) => Promise<void>;\r\n readonly handleEndAllSessions: () => Promise<void>;\r\n}\r\n\r\nconst formatDate = (date: string | null) => {\r\n if (!date) return '-';\r\n return new Date(date).toLocaleString();\r\n};\r\n\r\nconst formatDuration = (duration: string | null) => {\r\n if (!duration) return '-';\r\n const parts = duration.split(':');\r\n if (parts.length >= 2) {\r\n const hours = parseInt(parts[0]);\r\n const minutes = parseInt(parts[1]);\r\n if (hours > 0) return `${hours}h ${minutes}m`;\r\n return `${minutes}m`;\r\n }\r\n return duration;\r\n};\r\n\r\nconst getStatCardColorClass = (color?: 'green' | 'red'): string => {\r\n if (color === 'green') {\r\n return 'text-green-600';\r\n }\r\n if (color === 'red') {\r\n return 'text-red-600';\r\n }\r\n return 'text-[var(--text-primary)]';\r\n};\r\n\r\nexport function UserActivitySessionsTab({\r\n sessions,\r\n activity,\r\n isCreateMode,\r\n canUpdate,\r\n handleEndSession,\r\n handleEndAllSessions\r\n}: UserActivitySessionsTabProps): ReactElement {\r\n const { t } = useTranslation('admin');\r\n\r\n if (isCreateMode) {\r\n return (\r\n <div className=\"text-center py-12\">\r\n <Activity className=\"w-12 h-12 mx-auto mb-4 text-[var(--text-tertiary)]\" />\r\n <p className=\"text-[var(--text-secondary)]\">\r\n {t('userDetail.activity.notAvailableForNewUser', 'Les statistiques d\\'activité ne sont pas disponibles pour un nouvel utilisateur')}\r\n </p>\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div className=\"space-y-8\">\r\n {/* Activity Statistics Section */}\r\n <ActivitySection activity={activity} />\r\n\r\n {/* Sessions Section */}\r\n <SessionsSection\r\n sessions={sessions}\r\n canUpdate={canUpdate}\r\n handleEndSession={handleEndSession}\r\n handleEndAllSessions={handleEndAllSessions}\r\n />\r\n </div>\r\n );\r\n}\r\n\r\n// Activity Statistics Section\r\ninterface ActivitySectionProps {\r\n readonly activity: UserActivityDto | null;\r\n}\r\n\r\nfunction ActivitySection({ activity }: ActivitySectionProps) {\r\n const { t } = useTranslation('admin');\r\n if (!activity) {\r\n return (\r\n <div className=\"space-y-6\">\r\n <h3 className=\"text-lg font-semibold text-[var(--text-primary)] flex items-center gap-2 pb-2 border-b border-[var(--border-color)]\">\r\n <Activity className=\"w-5 h-5\" />\r\n {t('userDetail.activity.statsTitle', 'Statistiques de connexion')}\r\n </h3>\r\n <div className=\"flex items-center justify-center py-8\">\r\n <Loader2 className=\"w-6 h-6 animate-spin text-[var(--color-accent-500)]\" />\r\n </div>\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div className=\"space-y-6\">\r\n <h3 className=\"text-lg font-semibold text-[var(--text-primary)] flex items-center gap-2 pb-2 border-b border-[var(--border-color)]\">\r\n <Activity className=\"w-5 h-5\" />\r\n {t('userDetail.activity.statsTitle', 'Statistiques de connexion')}\r\n </h3>\r\n\r\n {/* Stats Cards */}\r\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4\">\r\n <StatCard value={activity.totalSuccessfulLogins} label={t('userDetail.activity.successfulLogins')} color=\"green\" />\r\n <StatCard value={activity.totalFailedLogins} label={t('userDetail.activity.failedLogins')} color=\"red\" />\r\n <StatCard value={formatDate(activity.lastSuccessfulLoginAt)} label={t('userDetail.activity.lastSuccess')} isText />\r\n <StatCard value={activity.lastSuccessfulLoginIp || '-'} label={t('userDetail.activity.lastIp')} isText />\r\n </div>\r\n\r\n {/* Device & Location Stats */}\r\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-4\">\r\n {(activity.deviceStats?.length ?? 0) > 0 && (\r\n <StatsCard\r\n icon={<Smartphone className=\"w-4 h-4\" />}\r\n title={t('userDetail.activity.devices')}\r\n items={activity.deviceStats ?? []}\r\n labelKey=\"device\"\r\n countSuffix={t('userDetail.activity.logins')}\r\n />\r\n )}\r\n {(activity.locationStats?.length ?? 0) > 0 && (\r\n <StatsCard\r\n icon={<MapPin className=\"w-4 h-4\" />}\r\n title={t('userDetail.activity.locations')}\r\n items={activity.locationStats ?? []}\r\n labelKey=\"location\"\r\n countSuffix={t('userDetail.activity.logins')}\r\n />\r\n )}\r\n </div>\r\n\r\n {/* Login History */}\r\n {(activity.loginsByDay?.length ?? 0) > 0 && (\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--bg-primary)] border border-[var(--border-color)]\">\r\n <h4 className=\"text-base font-semibold text-[var(--text-primary)] mb-3 flex items-center gap-2\">\r\n <Calendar className=\"w-4 h-4\" />\r\n {t('userDetail.activity.loginHistory')}\r\n </h4>\r\n <div className=\"space-y-2\">\r\n {(activity.loginsByDay ?? []).slice(0, 7).map((day) => (\r\n <div key={day.date} className=\"flex items-center gap-4 py-2 border-b border-[var(--border-color)] last:border-0\">\r\n <span className=\"w-24 text-[var(--text-secondary)]\">\r\n {new Date(day.date).toLocaleDateString()}\r\n </span>\r\n <div className=\"flex-1 flex items-center gap-2\">\r\n <div className=\"flex items-center gap-1 text-green-600\">\r\n <CheckCircle className=\"w-4 h-4\" />\r\n {day.successful}\r\n </div>\r\n <div className=\"flex items-center gap-1 text-red-600\">\r\n <XCircle className=\"w-4 h-4\" />\r\n {day.failed}\r\n </div>\r\n </div>\r\n </div>\r\n ))}\r\n </div>\r\n </div>\r\n )}\r\n </div>\r\n );\r\n}\r\n\r\n// Sessions Section\r\ninterface SessionsSectionProps {\r\n readonly sessions: UserSessionsDto | null;\r\n readonly canUpdate: boolean;\r\n readonly handleEndSession: (sessionId: string) => Promise<void>;\r\n readonly handleEndAllSessions: () => Promise<void>;\r\n}\r\n\r\nfunction SessionsSection({ sessions, canUpdate, handleEndSession, handleEndAllSessions }: SessionsSectionProps) {\r\n const { t } = useTranslation('admin');\r\n if (!sessions) {\r\n return (\r\n <div className=\"space-y-6\">\r\n <h3 className=\"text-lg font-semibold text-[var(--text-primary)] flex items-center gap-2 pb-2 border-b border-[var(--border-color)]\">\r\n <Monitor className=\"w-5 h-5\" />\r\n {t('userDetail.sessions.title', 'Sessions')}\r\n </h3>\r\n <div className=\"flex items-center justify-center py-8\">\r\n <Loader2 className=\"w-6 h-6 animate-spin text-[var(--color-accent-500)]\" />\r\n </div>\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div className=\"space-y-6\">\r\n <h3 className=\"text-lg font-semibold text-[var(--text-primary)] flex items-center gap-2 pb-2 border-b border-[var(--border-color)]\">\r\n <Monitor className=\"w-5 h-5\" />\r\n {t('userDetail.sessions.title', 'Sessions')}\r\n </h3>\r\n\r\n {/* Active Sessions */}\r\n <ActiveSessionsList\r\n sessions={sessions.activeSessions ?? []}\r\n canUpdate={canUpdate}\r\n handleEndSession={handleEndSession}\r\n handleEndAllSessions={handleEndAllSessions}\r\n />\r\n\r\n {/* Session History */}\r\n <SessionHistory sessions={sessions.history ?? []} />\r\n </div>\r\n );\r\n}\r\n\r\n// Active Sessions List\r\ninterface ActiveSessionsListProps {\r\n readonly sessions: SessionDto[];\r\n readonly canUpdate: boolean;\r\n readonly handleEndSession: (sessionId: string) => Promise<void>;\r\n readonly handleEndAllSessions: () => Promise<void>;\r\n}\r\n\r\nfunction ActiveSessionsList({ sessions, canUpdate, handleEndSession, handleEndAllSessions }: ActiveSessionsListProps) {\r\n const { t } = useTranslation('admin');\r\n return (\r\n <div>\r\n <div className=\"flex items-center justify-between mb-4\">\r\n <h4 className=\"text-base font-semibold text-[var(--text-primary)]\">\r\n {t('userDetail.sessions.active')} ({sessions.length})\r\n </h4>\r\n {sessions.length > 0 && (\r\n <button\r\n onClick={handleEndAllSessions}\r\n disabled={!canUpdate}\r\n className={`flex items-center gap-2 px-3 py-1.5 rounded-[var(--radius-button)] border transition-colors ${!canUpdate ? 'opacity-50 cursor-not-allowed bg-[var(--bg-secondary)] text-[var(--text-tertiary)] border-[var(--border-color)]' : 'bg-[var(--error-bg)] border-[var(--error-border)] text-[var(--error-text)] hover:opacity-80'}`}\r\n title={!canUpdate ? t('common.noPermission', 'Permission insuffisante') : undefined}\r\n >\r\n <LogOut className=\"w-4 h-4\" />\r\n {t('userDetail.sessions.endAll')}\r\n </button>\r\n )}\r\n </div>\r\n\r\n {sessions.length === 0 ? (\r\n <p className=\"text-[var(--text-secondary)] py-4\">{t('userDetail.sessions.noActive')}</p>\r\n ) : (\r\n <div className=\"space-y-3\">\r\n {sessions.map((session) => (\r\n <SessionCard\r\n key={session.id}\r\n session={session}\r\n canUpdate={canUpdate}\r\n handleEndSession={handleEndSession}\r\n />\r\n ))}\r\n </div>\r\n )}\r\n </div>\r\n );\r\n}\r\n\r\n// Session Card\r\ninterface SessionCardProps {\r\n readonly session: SessionDto;\r\n readonly canUpdate: boolean;\r\n readonly handleEndSession: (sessionId: string) => Promise<void>;\r\n}\r\n\r\nfunction SessionCard({ session, canUpdate, handleEndSession }: SessionCardProps) {\r\n const { t } = useTranslation('admin');\r\n return (\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--bg-primary)] border border-[var(--success-border)]\">\r\n <div className=\"flex items-start justify-between\">\r\n <div className=\"space-y-1\">\r\n <div className=\"flex items-center gap-2\">\r\n {session.deviceType === 'Mobile' ? (\r\n <Smartphone className=\"w-4 h-4 text-green-600\" />\r\n ) : (\r\n <Monitor className=\"w-4 h-4 text-green-600\" />\r\n )}\r\n <span className=\"font-medium text-[var(--text-primary)]\">\r\n {parseUserAgent(session.userAgent).formatted}\r\n </span>\r\n <span className=\"px-2 py-0.5 text-xs rounded-[var(--radius-badge)] bg-[var(--info-bg)] text-[var(--info-text)] border border-[var(--info-border)]\">\r\n {session.deviceType}\r\n </span>\r\n </div>\r\n <div className=\"text-sm text-[var(--text-secondary)] flex items-center gap-4\">\r\n <span>{session.ipAddress}</span>\r\n {session.city && session.country && (\r\n <span className=\"flex items-center gap-1\">\r\n <MapPin className=\"w-3 h-3\" />\r\n {session.city}, {session.country}\r\n </span>\r\n )}\r\n </div>\r\n <div className=\"text-sm text-[var(--text-secondary)]\">\r\n {t('userDetail.sessions.startedAt')}: {formatDate(session.loginAt)}\r\n </div>\r\n </div>\r\n <button\r\n onClick={() => handleEndSession(session.id)}\r\n disabled={!canUpdate}\r\n className={`p-2 rounded-[var(--radius-button)] transition-colors ${!canUpdate ? 'opacity-50 cursor-not-allowed text-[var(--text-tertiary)]' : 'text-[var(--error-text)] hover:bg-[var(--error-bg)]'}`}\r\n title={!canUpdate ? t('common.noPermission', 'Permission insuffisante') : t('userDetail.sessions.end')}\r\n >\r\n <LogOut className=\"w-4 h-4\" />\r\n </button>\r\n </div>\r\n </div>\r\n );\r\n}\r\n\r\n// Session History Table\r\ninterface SessionHistoryProps {\r\n readonly sessions: SessionDto[];\r\n}\r\n\r\nfunction SessionHistory({ sessions }: SessionHistoryProps) {\r\n const { t } = useTranslation('admin');\r\n if (sessions.length === 0) {\r\n return (\r\n <div>\r\n <h4 className=\"text-base font-semibold text-[var(--text-primary)] mb-4\">\r\n {t('userDetail.sessions.history')}\r\n </h4>\r\n <p className=\"text-[var(--text-secondary)] py-4\">{t('userDetail.sessions.noHistory')}</p>\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div>\r\n <h4 className=\"text-base font-semibold text-[var(--text-primary)] mb-4\">\r\n {t('userDetail.sessions.history')}\r\n </h4>\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 py-3 px-4 text-sm font-medium text-[var(--text-secondary)]\">\r\n {t('userDetail.sessions.device')}\r\n </th>\r\n <th className=\"hidden sm:table-cell text-left py-3 px-4 text-sm font-medium text-[var(--text-secondary)]\">\r\n Type\r\n </th>\r\n <th className=\"hidden md:table-cell text-left py-3 px-4 text-sm font-medium text-[var(--text-secondary)]\">\r\n {t('userDetail.sessions.ip')}\r\n </th>\r\n <th className=\"hidden md:table-cell text-left py-3 px-4 text-sm font-medium text-[var(--text-secondary)]\">\r\n {t('userDetail.sessions.location')}\r\n </th>\r\n <th className=\"text-left py-3 px-4 text-sm font-medium text-[var(--text-secondary)]\">\r\n {t('userDetail.sessions.login')}\r\n </th>\r\n <th className=\"hidden lg:table-cell text-left py-3 px-4 text-sm font-medium text-[var(--text-secondary)]\">\r\n {t('userDetail.sessions.logout')}\r\n </th>\r\n <th className=\"hidden lg:table-cell text-left py-3 px-4 text-sm font-medium text-[var(--text-secondary)]\">\r\n {t('userDetail.sessions.duration')}\r\n </th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n {sessions.slice(0, 20).map((session) => (\r\n <tr key={session.id} className=\"border-b border-[var(--border-color)]\">\r\n <td className=\"py-3 px-4 text-[var(--text-primary)]\">\r\n <div className=\"flex items-center gap-2\">\r\n {session.deviceType === 'Mobile' ? (\r\n <Smartphone className=\"w-4 h-4 text-[var(--text-tertiary)]\" />\r\n ) : (\r\n <Monitor className=\"w-4 h-4 text-[var(--text-tertiary)]\" />\r\n )}\r\n <span>{parseUserAgent(session.userAgent).formatted}</span>\r\n </div>\r\n </td>\r\n <td className=\"hidden sm:table-cell py-3 px-4\">\r\n <span className=\"px-2 py-0.5 text-xs rounded-[var(--radius-badge)] bg-[var(--info-bg)] text-[var(--info-text)] border border-[var(--info-border)]\">\r\n {session.deviceType}\r\n </span>\r\n </td>\r\n <td className=\"hidden md:table-cell py-3 px-4 text-[var(--text-secondary)]\">{session.ipAddress || '-'}</td>\r\n <td className=\"hidden md:table-cell py-3 px-4 text-[var(--text-secondary)]\">\r\n {session.city && session.country ? `${session.city}, ${session.country}` : '-'}\r\n </td>\r\n <td className=\"py-3 px-4 text-[var(--text-secondary)]\">{formatDate(session.loginAt)}</td>\r\n <td className=\"hidden lg:table-cell py-3 px-4 text-[var(--text-secondary)]\">{formatDate(session.logoutAt)}</td>\r\n <td className=\"hidden lg:table-cell py-3 px-4 text-[var(--text-secondary)]\">{formatDuration(session.duration)}</td>\r\n </tr>\r\n ))}\r\n </tbody>\r\n </table>\r\n </div>\r\n </div>\r\n );\r\n}\r\n\r\n// Helper Components\r\ninterface StatCardProps {\r\n readonly value: number | string;\r\n readonly label: string;\r\n readonly color?: 'green' | 'red';\r\n readonly isText?: boolean;\r\n}\r\n\r\nfunction StatCard({ value, label, color, isText }: StatCardProps) {\r\n const colorClass = getStatCardColorClass(color);\r\n const sizeClass = isText ? 'text-sm font-medium' : 'text-2xl font-bold';\r\n\r\n return (\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--bg-primary)] border border-[var(--border-color)]\">\r\n <div className={`${sizeClass} ${colorClass}`}>{value}</div>\r\n <div className=\"text-sm text-[var(--text-secondary)]\">{label}</div>\r\n </div>\r\n );\r\n}\r\n\r\ninterface StatsCardProps {\r\n readonly icon: React.ReactNode;\r\n readonly title: string;\r\n readonly items: Array<{ device?: string; location?: string; count: number }>;\r\n readonly labelKey: 'device' | 'location';\r\n readonly countSuffix: string;\r\n}\r\n\r\nfunction StatsCard({ icon, title, items, labelKey, countSuffix }: StatsCardProps) {\r\n return (\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--bg-primary)] border border-[var(--border-color)]\">\r\n <h4 className=\"text-base font-semibold text-[var(--text-primary)] mb-3 flex items-center gap-2\">\r\n {icon}\r\n {title}\r\n </h4>\r\n <div className=\"space-y-2\">\r\n {items.map((item, i) => (\r\n <div key={`item-${item[labelKey]}-${i}`} className=\"flex items-center justify-between py-2 border-b border-[var(--border-color)] last:border-0\">\r\n <span className=\"text-[var(--text-primary)]\">{item[labelKey]}</span>\r\n <span className=\"text-[var(--text-secondary)]\">{item.count} {countSuffix}</span>\r\n </div>\r\n ))}\r\n </div>\r\n </div>\r\n );\r\n}\r\n","import type { ReactElement } from 'react';\r\nimport { useNavigate, Link } from 'react-router-dom';\r\nimport { useTranslation } from 'react-i18next';\r\n\r\ntype TFunction = ReturnType<typeof useTranslation>['t'];\r\nimport {\r\n Loader2,\r\n Building2,\r\n User,\r\n Plus,\r\n RefreshCw,\r\n Trash2,\r\n UserCheck,\r\n Users,\r\n Link2,\r\n Crown,\r\n Star,\r\n X,\r\n Search,\r\n Check\r\n} from 'lucide-react';\r\nimport type { UserTenantDto, TenantListDto } from '@/services/api/adminApi';\r\nimport { TenantCard } from '@/components/tenants/TenantCard';\r\nimport { DataTable, type DataTableColumn } from '@/components/ui/DataTable';\r\nimport { ViewModeToggle, type ViewMode } from '@/components/ui/ViewModeToggle';\r\n\r\ninterface UserTenantsTabProps {\r\n // Data\r\n readonly userTenants: UserTenantDto[] | null;\r\n readonly allTenants: TenantListDto[] | null;\r\n readonly currentTenant: UserTenantDto | null;\r\n readonly hasGlobalRoles: boolean;\r\n\r\n // UI state\r\n readonly showAddTenantModal: boolean;\r\n readonly tenantSearch: string;\r\n readonly tenantsViewMode: ViewMode;\r\n readonly selectedTenantIds: Set<string>;\r\n readonly isAddingMultipleTenants: boolean;\r\n\r\n // Setters\r\n readonly setShowAddTenantModal: (show: boolean) => void;\r\n readonly setTenantSearch: (search: string) => void;\r\n readonly setTenantsViewMode: (mode: ViewMode) => void;\r\n readonly setUserTenants: React.Dispatch<React.SetStateAction<UserTenantDto[] | null>>;\r\n\r\n // Actions\r\n readonly loadTenants: () => Promise<void>;\r\n readonly toggleTenantSelection: (tenantId: string) => void;\r\n readonly selectAllTenants: (availableTenantIds: string[]) => void;\r\n readonly clearTenantSelection: () => void;\r\n readonly closeAddTenantModal: () => void;\r\n readonly handleAddMultipleTenants: () => Promise<void>;\r\n readonly handleRemoveTenant: (tenantId: string) => Promise<void>;\r\n}\r\n\r\nconst renderTenantsContent = (\r\n filteredTenants: UserTenantDto[] | null | undefined,\r\n hasGlobalRoles: boolean,\r\n tenantsViewMode: ViewMode,\r\n currentTenant: UserTenantDto | null,\r\n handleRemoveTenant: (id: string) => Promise<void>,\r\n navigate: any,\r\n setShowAddTenantModal: (show: boolean) => void\r\n) => {\r\n if (!filteredTenants) {\r\n return <LoadingState />;\r\n }\r\n if (filteredTenants.length === 0) {\r\n return <EmptyState hasGlobalRoles={hasGlobalRoles} onAddClick={() => setShowAddTenantModal(true)} />;\r\n }\r\n if (tenantsViewMode === 'table') {\r\n return (\r\n <TenantTableView\r\n tenants={filteredTenants}\r\n hasGlobalRoles={hasGlobalRoles}\r\n currentTenant={currentTenant}\r\n onRemove={handleRemoveTenant}\r\n onNavigate={(id) => navigate(`/administration/tenants/${id}`)}\r\n />\r\n );\r\n }\r\n return (\r\n <TenantCardsView\r\n tenants={filteredTenants}\r\n hasGlobalRoles={hasGlobalRoles}\r\n currentTenant={currentTenant}\r\n onRemove={handleRemoveTenant}\r\n />\r\n );\r\n};\r\n\r\nconst renderTenantList = (\r\n allTenants: TenantListDto[] | null,\r\n availableTenants: TenantListDto[],\r\n selectedTenantIds: Set<string>,\r\n toggleTenantSelection: (id: string) => void,\r\n t: TFunction\r\n) => {\r\n if (!allTenants) {\r\n return (\r\n <div className=\"flex items-center justify-center py-8\">\r\n <Loader2 className=\"w-6 h-6 animate-spin text-[var(--color-accent-500)]\" />\r\n </div>\r\n );\r\n }\r\n if (availableTenants.length === 0) {\r\n return (\r\n <div className=\"text-center py-8 text-[var(--text-secondary)]\">\r\n <Building2 className=\"w-8 h-8 mx-auto mb-2 opacity-50\" />\r\n <p>{t('userDetail.tenants.addModal.noAvailable', 'Aucun tenant disponible')}</p>\r\n </div>\r\n );\r\n }\r\n return availableTenants.map((tenant) => (\r\n <TenantSelectItem\r\n key={tenant.id}\r\n tenant={tenant}\r\n isSelected={selectedTenantIds.has(tenant.id)}\r\n onToggle={() => toggleTenantSelection(tenant.id)}\r\n />\r\n ));\r\n};\r\n\r\nexport function UserTenantsTab({\r\n userTenants,\r\n allTenants,\r\n currentTenant,\r\n hasGlobalRoles,\r\n showAddTenantModal,\r\n tenantSearch,\r\n tenantsViewMode,\r\n selectedTenantIds,\r\n isAddingMultipleTenants,\r\n setShowAddTenantModal,\r\n setTenantSearch,\r\n setTenantsViewMode,\r\n setUserTenants,\r\n loadTenants,\r\n toggleTenantSelection,\r\n selectAllTenants,\r\n clearTenantSelection,\r\n closeAddTenantModal,\r\n handleAddMultipleTenants,\r\n handleRemoveTenant\r\n}: UserTenantsTabProps): ReactElement {\r\n const { t } = useTranslation('admin');\r\n const navigate = useNavigate();\r\n\r\n // Filter tenants based on current user's access\r\n const filteredTenants = hasGlobalRoles\r\n ? userTenants\r\n : userTenants?.filter(tenant => currentTenant?.id === tenant.id);\r\n\r\n const handleRefresh = () => {\r\n setUserTenants(null);\r\n loadTenants();\r\n };\r\n\r\n return (\r\n <div className=\"space-y-6\">\r\n <div className=\"flex items-center justify-between\">\r\n <h3 className=\"text-lg font-semibold text-[var(--text-primary)] flex items-center gap-2\">\r\n <Building2 className=\"w-5 h-5\" />\r\n {t('userDetail.tenants.title', 'Tenants de l\\'utilisateur')}\r\n {hasGlobalRoles && (\r\n <span className=\"ml-2 px-2 py-0.5 text-xs font-medium rounded-full bg-amber-500/10 text-amber-600\">\r\n {t('userDetail.tenants.globalView', 'Vue globale')}\r\n </span>\r\n )}\r\n </h3>\r\n <div className=\"flex items-center gap-2\">\r\n <ViewModeToggle viewMode={tenantsViewMode} onChange={setTenantsViewMode} />\r\n <button\r\n onClick={() => setShowAddTenantModal(true)}\r\n className=\"flex items-center gap-2 px-3 py-1.5 rounded-[var(--radius-button)] bg-[var(--color-accent-600)] text-white hover:bg-[var(--color-accent-700)] transition-colors\"\r\n >\r\n <Plus className=\"w-4 h-4\" />\r\n {t('userDetail.tenants.add', 'Ajouter un tenant')}\r\n </button>\r\n <button\r\n onClick={handleRefresh}\r\n className=\"flex items-center gap-2 px-3 py-1.5 rounded-[var(--radius-button)] bg-[var(--bg-primary)] border border-[var(--border-color)] text-[var(--text-secondary)] hover:bg-[var(--bg-hover)] transition-colors\"\r\n >\r\n <RefreshCw className=\"w-4 h-4\" />\r\n {t('common.refresh', 'Actualiser')}\r\n </button>\r\n </div>\r\n </div>\r\n\r\n {/* Content */}\r\n {renderTenantsContent(\r\n filteredTenants,\r\n hasGlobalRoles,\r\n tenantsViewMode,\r\n currentTenant,\r\n handleRemoveTenant,\r\n navigate,\r\n setShowAddTenantModal\r\n )}\r\n\r\n {/* Add Tenant Modal */}\r\n {showAddTenantModal && (\r\n <AddTenantModal\r\n userTenants={userTenants}\r\n allTenants={allTenants}\r\n tenantSearch={tenantSearch}\r\n setTenantSearch={setTenantSearch}\r\n selectedTenantIds={selectedTenantIds}\r\n isAddingMultipleTenants={isAddingMultipleTenants}\r\n toggleTenantSelection={toggleTenantSelection}\r\n selectAllTenants={selectAllTenants}\r\n clearTenantSelection={clearTenantSelection}\r\n closeAddTenantModal={closeAddTenantModal}\r\n handleAddMultipleTenants={handleAddMultipleTenants}\r\n />\r\n )}\r\n </div>\r\n );\r\n}\r\n\r\n// Loading State\r\nfunction LoadingState() {\r\n return (\r\n <div className=\"flex items-center justify-center h-32\">\r\n <Loader2 className=\"w-6 h-6 animate-spin text-[var(--color-accent-500)]\" />\r\n </div>\r\n );\r\n}\r\n\r\n// Empty State\r\ninterface EmptyStateProps {\r\n readonly hasGlobalRoles: boolean;\r\n readonly onAddClick: () => void;\r\n}\r\n\r\nfunction EmptyState({ hasGlobalRoles, onAddClick }: EmptyStateProps) {\r\n const { t } = useTranslation('admin');\r\n return (\r\n <div className=\"flex flex-col items-center justify-center h-32 text-[var(--text-secondary)]\">\r\n <Building2 className=\"w-8 h-8 mb-2 opacity-50\" />\r\n <p>{t('userDetail.tenants.noTenants', 'Cet utilisateur n\\'appartient à aucun tenant')}</p>\r\n {hasGlobalRoles && (\r\n <button\r\n onClick={onAddClick}\r\n className=\"mt-3 flex items-center gap-2 px-3 py-1.5 rounded-[var(--radius-button)] bg-[var(--color-accent-600)] text-white hover:bg-[var(--color-accent-700)] transition-colors text-sm\"\r\n >\r\n <Plus className=\"w-4 h-4\" />\r\n {t('userDetail.tenants.addFirst', 'Ajouter un premier tenant')}\r\n </button>\r\n )}\r\n </div>\r\n );\r\n}\r\n\r\n// Table View\r\ninterface TenantTableViewProps {\r\n readonly tenants: UserTenantDto[];\r\n readonly hasGlobalRoles: boolean;\r\n readonly currentTenant: UserTenantDto | null;\r\n readonly onRemove: (id: string) => Promise<void>;\r\n readonly onNavigate: (id: string) => void;\r\n}\r\n\r\nfunction TenantTableView({ tenants, hasGlobalRoles, currentTenant, onRemove, onNavigate }: TenantTableViewProps) {\r\n const { t } = useTranslation('admin');\r\n const columns: DataTableColumn<UserTenantDto>[] = [\r\n {\r\n key: 'name',\r\n label: t('userDetail.tenants.table.name', 'Nom'),\r\n sortable: true,\r\n render: (tenant) => (\r\n <div className=\"flex items-center gap-2\">\r\n <div className={`p-1.5 rounded flex-shrink-0 ${\r\n tenant.type === 'Business'\r\n ? 'bg-blue-500/10 text-blue-500'\r\n : 'bg-violet-500/10 text-violet-500'\r\n }`}>\r\n {tenant.type === 'Business' ? <Building2 className=\"w-4 h-4\" /> : <User className=\"w-4 h-4\" />}\r\n </div>\r\n <div className=\"min-w-0\">\r\n <Link\r\n to={`/administration/tenants/${tenant.id}`}\r\n className=\"font-medium text-[var(--text-primary)] hover:text-[var(--color-accent-600)] hover:underline transition-colors\"\r\n onClick={(e) => e.stopPropagation()}\r\n >\r\n {tenant.name}\r\n </Link>\r\n <span className=\"text-xs text-[var(--text-tertiary)] ml-2\">{tenant.slug}</span>\r\n </div>\r\n </div>\r\n ),\r\n },\r\n {\r\n key: 'type',\r\n label: t('userDetail.tenants.table.type', 'Type'),\r\n sortable: true,\r\n render: (tenant) => (\r\n <span className={`inline-flex items-center px-2 py-0.5 rounded-full text-xs ${\r\n tenant.type === 'Business'\r\n ? 'bg-blue-500/10 text-blue-500'\r\n : 'bg-violet-500/10 text-violet-500'\r\n }`}>\r\n {tenant.type === 'Business' ? t('tenants.type.business', 'Entreprise') : t('tenants.type.personal', 'Personnel')}\r\n </span>\r\n ),\r\n hideOnMobile: true,\r\n },\r\n {\r\n key: 'status',\r\n label: t('userDetail.tenants.table.status', 'Statut'),\r\n sortable: true,\r\n render: (tenant) => {\r\n const statusColors: Record<string, string> = {\r\n Active: 'bg-green-500/10 text-green-600',\r\n Pending: 'bg-blue-500/10 text-blue-500',\r\n Suspended: 'bg-amber-500/10 text-amber-600',\r\n Archived: 'bg-red-500/10 text-red-500',\r\n };\r\n const getStatusDotColor = (status: string): string => {\r\n switch (status) {\r\n case 'Active': return 'bg-green-500';\r\n case 'Pending': return 'bg-blue-500';\r\n case 'Suspended': return 'bg-amber-500';\r\n default: return 'bg-red-500';\r\n }\r\n };\r\n return (\r\n <span className={`inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-xs ${statusColors[tenant.status] || ''}`}>\r\n <span className={`w-1.5 h-1.5 rounded-full ${getStatusDotColor(tenant.status)}`} />\r\n {t(`tenants.status.${tenant.status.toLowerCase()}`, { defaultValue: tenant.status })}\r\n </span>\r\n );\r\n },\r\n hideOnMobile: true,\r\n },\r\n {\r\n key: 'membershipSource',\r\n label: t('userDetail.tenants.table.source', 'Source'),\r\n render: (tenant) => (\r\n <div className=\"flex items-center gap-1 text-xs\">\r\n {tenant.membershipSource === 'Direct' && (\r\n <span className=\"inline-flex items-center gap-1 text-green-600\">\r\n <UserCheck className=\"w-3 h-3\" />\r\n {t('tenants.directMember', 'Direct')}\r\n </span>\r\n )}\r\n {tenant.membershipSource === 'Group' && (\r\n <span className=\"inline-flex items-center gap-1 text-blue-500\">\r\n <Users className=\"w-3 h-3\" />\r\n {t('tenants.viaGroup', 'Groupe')}\r\n </span>\r\n )}\r\n {tenant.membershipSource === 'Both' && (\r\n <span className=\"inline-flex items-center gap-1 text-violet-500\">\r\n <Link2 className=\"w-3 h-3\" />\r\n {t('tenants.directAndGroup', 'Direct + Groupe')}\r\n </span>\r\n )}\r\n </div>\r\n ),\r\n hideOnMobile: true,\r\n },\r\n {\r\n key: 'badges',\r\n label: '',\r\n width: '100px',\r\n render: (tenant) => (\r\n <div className=\"flex items-center gap-1\">\r\n {tenant.isOwner && (\r\n <span className=\"inline-flex items-center gap-1 px-1.5 py-0.5 rounded-full text-xs bg-amber-500/10 text-amber-600\" title={t('tenants.owner', 'Owner')}>\r\n <Crown className=\"w-3 h-3\" />\r\n </span>\r\n )}\r\n {tenant.isDefault && (\r\n <span className=\"inline-flex items-center gap-1 px-1.5 py-0.5 rounded-full text-xs bg-[var(--color-accent-500)]/10 text-[var(--color-accent-600)]\" title={t('tenants.default', 'Default')}>\r\n <Star className=\"w-3 h-3 fill-current\" />\r\n </span>\r\n )}\r\n </div>\r\n ),\r\n },\r\n {\r\n key: 'actions',\r\n label: '',\r\n width: '60px',\r\n align: 'right',\r\n render: (tenant) => {\r\n const canManage = hasGlobalRoles || currentTenant?.id === tenant.id;\r\n if (!canManage) return null;\r\n return (\r\n <button\r\n onClick={(e) => {\r\n e.stopPropagation();\r\n onRemove(tenant.id);\r\n }}\r\n className=\"flex items-center gap-1 px-2 py-1 rounded text-xs text-red-500 hover:bg-red-500/10 transition-colors\"\r\n >\r\n <Trash2 className=\"w-3 h-3\" />\r\n </button>\r\n );\r\n },\r\n },\r\n ];\r\n\r\n return (\r\n <DataTable\r\n data={tenants}\r\n columns={columns}\r\n getRowKey={(tenant) => tenant.id}\r\n onRowClick={(tenant) => onNavigate(tenant.id)}\r\n compact\r\n emptyMessage={t('userDetail.tenants.noTenants', 'Cet utilisateur n\\'appartient à aucun tenant')}\r\n emptyIcon={<Building2 className=\"w-8 h-8 text-[var(--text-tertiary)]\" />}\r\n />\r\n );\r\n}\r\n\r\n// Cards View\r\ninterface TenantCardsViewProps {\r\n readonly tenants: UserTenantDto[];\r\n readonly hasGlobalRoles: boolean;\r\n readonly currentTenant: UserTenantDto | null;\r\n readonly onRemove: (id: string) => Promise<void>;\r\n}\r\n\r\nfunction TenantCardsView({ tenants, hasGlobalRoles, currentTenant, onRemove }: TenantCardsViewProps) {\r\n const { t } = useTranslation('admin');\r\n const primaryTenant = currentTenant\r\n ? tenants.find(tenant => tenant.id === currentTenant.id)\r\n : tenants.find(tenant => tenant.isDefault);\r\n const otherTenants = tenants.filter(tenant => tenant.id !== primaryTenant?.id);\r\n\r\n return (\r\n <div className=\"space-y-6\">\r\n {/* Primary Tenant */}\r\n {primaryTenant && (\r\n <div>\r\n <div className=\"flex items-center gap-2 mb-3\">\r\n <div className=\"w-2 h-2 rounded-full bg-[var(--success-dot)]\" />\r\n <span className=\"text-sm font-medium text-[var(--text-secondary)]\">\r\n {currentTenant?.id === primaryTenant.id\r\n ? t('userDetail.tenants.activeTenant', 'Tenant actif')\r\n : t('userDetail.tenants.defaultTenant', 'Tenant par défaut')}\r\n </span>\r\n </div>\r\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4\">\r\n <TenantCard\r\n tenant={primaryTenant}\r\n showActions={true}\r\n isSelected={true}\r\n navigateTo={`/administration/tenants/${primaryTenant.id}`}\r\n onRemove={hasGlobalRoles || currentTenant?.id === primaryTenant.id ? () => onRemove(primaryTenant.id) : undefined}\r\n />\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* Separator */}\r\n {primaryTenant && otherTenants.length > 0 && (\r\n <div className=\"flex items-center gap-4\">\r\n <div className=\"flex-1 h-px bg-[var(--border-color)]\" />\r\n <span className=\"text-xs text-[var(--text-tertiary)] uppercase tracking-wider\">\r\n {t('userDetail.tenants.otherTenants', 'Autres tenants')}\r\n </span>\r\n <div className=\"flex-1 h-px bg-[var(--border-color)]\" />\r\n </div>\r\n )}\r\n\r\n {/* Other Tenants */}\r\n {primaryTenant && otherTenants.length > 0 && (\r\n <div className={`grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 ${!hasGlobalRoles ? 'opacity-60' : ''}`}>\r\n {otherTenants.map((tenant) => {\r\n const canManage = hasGlobalRoles || currentTenant?.id === tenant.id;\r\n return (\r\n <TenantCard\r\n key={tenant.id}\r\n tenant={tenant}\r\n showActions={true}\r\n isDisabled={!canManage}\r\n navigateTo={`/administration/tenants/${tenant.id}`}\r\n disabledReason={!canManage ? t('userDetail.tenants.notCurrentTenant', 'Changez de tenant pour gérer ce membre') : undefined}\r\n onRemove={canManage ? () => onRemove(tenant.id) : undefined}\r\n />\r\n );\r\n })}\r\n </div>\r\n )}\r\n\r\n {/* No primary tenant - show all */}\r\n {!primaryTenant && tenants.length > 0 && (\r\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4\">\r\n {tenants.map((tenant) => {\r\n const canManage = hasGlobalRoles || currentTenant?.id === tenant.id;\r\n return (\r\n <TenantCard\r\n key={tenant.id}\r\n tenant={tenant}\r\n showActions={true}\r\n isDisabled={!canManage}\r\n navigateTo={`/administration/tenants/${tenant.id}`}\r\n disabledReason={!canManage ? t('userDetail.tenants.notCurrentTenant', 'Changez de tenant pour gérer ce membre') : undefined}\r\n onRemove={canManage ? () => onRemove(tenant.id) : undefined}\r\n />\r\n );\r\n })}\r\n </div>\r\n )}\r\n </div>\r\n );\r\n}\r\n\r\n// Add Tenant Modal\r\ninterface AddTenantModalProps {\r\n readonly userTenants: UserTenantDto[] | null;\r\n readonly allTenants: TenantListDto[] | null;\r\n readonly tenantSearch: string;\r\n readonly setTenantSearch: (search: string) => void;\r\n readonly selectedTenantIds: Set<string>;\r\n readonly isAddingMultipleTenants: boolean;\r\n readonly toggleTenantSelection: (tenantId: string) => void;\r\n readonly selectAllTenants: (availableTenantIds: string[]) => void;\r\n readonly clearTenantSelection: () => void;\r\n readonly closeAddTenantModal: () => void;\r\n readonly handleAddMultipleTenants: () => Promise<void>;\r\n}\r\n\r\nfunction AddTenantModal({\r\n userTenants,\r\n allTenants,\r\n tenantSearch,\r\n setTenantSearch,\r\n selectedTenantIds,\r\n isAddingMultipleTenants,\r\n toggleTenantSelection,\r\n selectAllTenants,\r\n clearTenantSelection,\r\n closeAddTenantModal,\r\n handleAddMultipleTenants\r\n}: AddTenantModalProps) {\r\n const { t } = useTranslation('admin');\r\n const userTenantIds = new Set(userTenants?.map(tenant => tenant.id) || []);\r\n const availableTenants = allTenants\r\n ?.filter(tenant => !userTenantIds.has(tenant.id))\r\n .filter(tenant =>\r\n !tenantSearch.trim() ||\r\n tenant.name.toLowerCase().includes(tenantSearch.toLowerCase()) ||\r\n tenant.slug.toLowerCase().includes(tenantSearch.toLowerCase())\r\n ) ?? [];\r\n\r\n return (\r\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50\">\r\n <div className=\"bg-[var(--bg-card)] rounded-[var(--radius-modal)] shadow-xl w-full max-w-2xl mx-4 max-h-[80vh] flex flex-col\">\r\n {/* Header */}\r\n <div className=\"flex items-center justify-between p-4 border-b border-[var(--border-color)]\">\r\n <h3 className=\"text-lg font-semibold text-[var(--text-primary)]\">\r\n {t('userDetail.tenants.addModal.title', 'Ajouter des tenants')}\r\n </h3>\r\n <button\r\n onClick={closeAddTenantModal}\r\n className=\"p-1 rounded-[var(--radius-button)] hover:bg-[var(--bg-hover)] text-[var(--text-secondary)]\"\r\n >\r\n <X className=\"w-5 h-5\" />\r\n </button>\r\n </div>\r\n\r\n {/* Search and Selection Actions */}\r\n <div className=\"p-4 space-y-3 border-b border-[var(--border-color)]\">\r\n <div className=\"relative\">\r\n <Search className=\"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-[var(--text-tertiary)]\" />\r\n <input\r\n type=\"text\"\r\n value={tenantSearch}\r\n onChange={(e) => setTenantSearch(e.target.value)}\r\n placeholder={t('userDetail.tenants.addModal.search', 'Rechercher un tenant...')}\r\n className=\"w-full pl-10 pr-4 py-2 rounded-[var(--radius-input)] bg-[var(--bg-secondary)] border border-[var(--border-color)] text-[var(--text-primary)] placeholder-[var(--text-tertiary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]\"\r\n autoFocus\r\n />\r\n </div>\r\n\r\n {availableTenants.length > 0 && (\r\n <div className=\"flex items-center justify-between text-xs\">\r\n <span className=\"text-[var(--text-secondary)]\">\r\n {selectedTenantIds.size > 0\r\n ? t('userDetail.tenants.addModal.selectedCount', { count: selectedTenantIds.size, defaultValue: `${selectedTenantIds.size} sélectionné(s)` })\r\n : t('userDetail.tenants.addModal.availableCount', { count: availableTenants.length, defaultValue: `${availableTenants.length} tenant(s) disponible(s)` })}\r\n </span>\r\n <div className=\"flex items-center gap-2\">\r\n <button\r\n onClick={() => selectAllTenants(availableTenants.map(tenant => tenant.id))}\r\n className=\"text-[var(--color-accent-500)] hover:underline\"\r\n >\r\n {t('userDetail.tenants.addModal.selectAll', 'Tout sélectionner')}\r\n </button>\r\n {selectedTenantIds.size > 0 && (\r\n <button\r\n onClick={clearTenantSelection}\r\n className=\"text-[var(--text-tertiary)] hover:underline\"\r\n >\r\n {t('userDetail.tenants.addModal.clearSelection', 'Effacer')}\r\n </button>\r\n )}\r\n </div>\r\n </div>\r\n )}\r\n </div>\r\n\r\n {/* Tenant List */}\r\n <div className=\"flex-1 overflow-y-auto p-4 space-y-2\">\r\n {renderTenantList(allTenants, availableTenants, selectedTenantIds, toggleTenantSelection, t)}\r\n </div>\r\n\r\n {/* Footer */}\r\n <div className=\"flex items-center justify-between p-4 border-t border-[var(--border-color)]\">\r\n <div className=\"text-sm text-[var(--text-secondary)]\">\r\n {selectedTenantIds.size > 0 && (\r\n <span className=\"flex items-center gap-2\">\r\n <span className=\"w-6 h-6 rounded-full bg-[var(--color-accent-500)] text-white text-xs flex items-center justify-center font-medium\">\r\n {selectedTenantIds.size}\r\n </span>\r\n {t('userDetail.tenants.addModal.tenantsSelected', 'tenant(s) sélectionné(s)')}\r\n </span>\r\n )}\r\n </div>\r\n <div className=\"flex items-center gap-2\">\r\n <button\r\n onClick={closeAddTenantModal}\r\n className=\"px-4 py-2 rounded-[var(--radius-button)] bg-[var(--bg-secondary)] text-[var(--text-secondary)] hover:bg-[var(--bg-hover)] transition-colors\"\r\n >\r\n {t('common.cancel', 'Annuler')}\r\n </button>\r\n <button\r\n onClick={handleAddMultipleTenants}\r\n disabled={selectedTenantIds.size === 0 || isAddingMultipleTenants}\r\n className=\"px-4 py-2 rounded-[var(--radius-button)] bg-[var(--color-accent-600)] text-white hover:bg-[var(--color-accent-700)] transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2\"\r\n >\r\n {isAddingMultipleTenants ? (\r\n <>\r\n <Loader2 className=\"w-4 h-4 animate-spin\" />\r\n {t('userDetail.tenants.addModal.adding', 'Ajout en cours...')}\r\n </>\r\n ) : (\r\n <>\r\n <Plus className=\"w-4 h-4\" />\r\n {t('userDetail.tenants.addModal.add', 'Ajouter')}\r\n {selectedTenantIds.size > 0 && ` (${selectedTenantIds.size})`}\r\n </>\r\n )}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n}\r\n\r\n// Tenant Select Item\r\ninterface TenantSelectItemProps {\r\n readonly tenant: TenantListDto;\r\n readonly isSelected: boolean;\r\n readonly onToggle: () => void;\r\n}\r\n\r\nfunction TenantSelectItem({ tenant, isSelected, onToggle }: TenantSelectItemProps) {\r\n const { t } = useTranslation('admin');\r\n return (\r\n <button\r\n type=\"button\"\r\n onClick={onToggle}\r\n className={`w-full flex items-center gap-3 p-3 rounded-[var(--radius-card)] border cursor-pointer transition-colors text-left ${\r\n isSelected\r\n ? 'border-[var(--color-accent-500)] bg-[var(--color-accent-500)]/5'\r\n : 'border-[var(--border-color)] bg-[var(--bg-secondary)] hover:border-[var(--color-accent-500)] hover:bg-[var(--bg-hover)]'\r\n }`}\r\n >\r\n {/* Checkbox */}\r\n <div\r\n className={`w-5 h-5 rounded border-2 flex items-center justify-center flex-shrink-0 transition-colors ${\r\n isSelected\r\n ? 'bg-[var(--color-accent-500)] border-[var(--color-accent-500)]'\r\n : 'border-[var(--border-color)]'\r\n }`}\r\n >\r\n {isSelected && <Check className=\"w-3 h-3 text-white\" />}\r\n </div>\r\n\r\n {/* Icon */}\r\n <div className={`flex-shrink-0 w-10 h-10 flex items-center justify-center rounded-[var(--radius-button)] ${\r\n tenant.type === 'Business' ? 'bg-blue-500/10' : 'bg-violet-500/10'\r\n }`}>\r\n {tenant.type === 'Business' ? (\r\n <Building2 className=\"w-5 h-5 text-blue-500\" />\r\n ) : (\r\n <User className=\"w-5 h-5 text-violet-500\" />\r\n )}\r\n </div>\r\n\r\n {/* Content */}\r\n <div className=\"flex-1 min-w-0\">\r\n <p className=\"font-medium text-[var(--text-primary)] truncate\">{tenant.name}</p>\r\n <p className=\"text-sm text-[var(--text-secondary)] truncate\">{tenant.slug}</p>\r\n </div>\r\n\r\n {/* Member count */}\r\n {tenant.memberCount !== undefined && (\r\n <span className=\"text-xs text-[var(--text-tertiary)] flex-shrink-0\">\r\n {tenant.memberCount} {t('userDetail.tenants.members', 'membres')}\r\n </span>\r\n )}\r\n </button>\r\n );\r\n}\r\n","import type { ReactElement } from 'react';\r\nimport { useTranslation } from 'react-i18next';\r\nimport {\r\n Loader2,\r\n RefreshCw,\r\n History,\r\n Shield,\r\n ShieldX,\r\n Key,\r\n User,\r\n LogOut,\r\n Cloud,\r\n Phone,\r\n MapPin as MapPinIcon,\r\n Briefcase,\r\n Edit3,\r\n RotateCcw\r\n} from 'lucide-react';\r\nimport type { UserHistoryDto } from '@/services/api/adminApi';\r\n\r\ninterface UserHistoryTabProps {\r\n readonly history: UserHistoryDto[] | null;\r\n readonly loadHistory: () => void;\r\n readonly handleRestoreField: (historyId: string) => Promise<void>;\r\n readonly restoringHistoryId: string | null;\r\n readonly canUpdate: boolean;\r\n}\r\n\r\nconst formatDate = (date: string | null) => {\r\n if (!date) return '-';\r\n return new Date(date).toLocaleString();\r\n};\r\n\r\nexport function UserHistoryTab({\r\n history,\r\n loadHistory,\r\n handleRestoreField,\r\n restoringHistoryId,\r\n canUpdate\r\n}: UserHistoryTabProps): ReactElement {\r\n const { t } = useTranslation('admin');\r\n\r\n const getActionLabel = (actionName: string): string => {\r\n const labels: Record<string, string> = {\r\n ProfileUpdated: t('userDetail.history.actions.profileUpdated', 'Profil mis à jour'),\r\n JobInfoUpdated: t('userDetail.history.actions.jobInfoUpdated', 'Info emploi mise à jour'),\r\n AddressUpdated: t('userDetail.history.actions.addressUpdated', 'Adresse mise à jour'),\r\n PhoneUpdated: t('userDetail.history.actions.phoneUpdated', 'Téléphone mis à jour'),\r\n ContactUpdated: t('userDetail.history.actions.contactUpdated', 'Contact mis à jour'),\r\n OrganizationUpdated: t('userDetail.history.actions.organizationUpdated', 'Organisation mise à jour'),\r\n RoleAssigned: t('userDetail.history.actions.roleAssigned', 'Rôle assigné'),\r\n RoleRemoved: t('userDetail.history.actions.roleRemoved', 'Rôle retiré'),\r\n StatusActivated: t('userDetail.history.actions.statusActivated', 'Compte activé'),\r\n StatusDeactivated: t('userDetail.history.actions.statusDeactivated', 'Compte désactivé'),\r\n PasswordReset: t('userDetail.history.actions.passwordReset', 'Mot de passe réinitialisé'),\r\n PasswordResetLinkSent: t('userDetail.history.actions.passwordResetLinkSent', 'Lien de réinitialisation envoyé'),\r\n AccountLocked: t('userDetail.history.actions.accountLocked', 'Compte verrouillé'),\r\n AccountUnlocked: t('userDetail.history.actions.accountUnlocked', 'Compte déverrouillé'),\r\n FailedAttemptCleared: t('userDetail.history.actions.failedAttemptCleared', 'Tentatives échouées effacées'),\r\n SessionEnded: t('userDetail.history.actions.sessionEnded', 'Session terminée'),\r\n AllSessionsEnded: t('userDetail.history.actions.allSessionsEnded', 'Toutes les sessions terminées'),\r\n EntraSynced: t('userDetail.history.actions.entraSynced', 'Synchronisé avec Entra'),\r\n Created: t('userDetail.history.actions.created', 'Compte créé'),\r\n Deleted: t('userDetail.history.actions.deleted', 'Compte supprimé'),\r\n EntraFieldUpdated: t('userDetail.history.actions.entraFieldUpdated', 'Champ modifié par Entra'),\r\n FieldRestored: t('userDetail.history.actions.fieldRestored', 'Champ restauré'),\r\n PermissionAssigned: t('userDetail.history.actions.permissionAssigned', 'Permission assignée'),\r\n PermissionRemoved: t('userDetail.history.actions.permissionRemoved', 'Permission retirée'),\r\n TenantAdded: t('userDetail.history.actions.tenantAdded', 'Ajouté au tenant'),\r\n TenantRemoved: t('userDetail.history.actions.tenantRemoved', 'Retiré du tenant'),\r\n GroupAdded: t('userDetail.history.actions.groupAdded', 'Ajouté au groupe'),\r\n GroupRemoved: t('userDetail.history.actions.groupRemoved', 'Retiré du groupe'),\r\n AccessDenied: t('userDetail.history.actions.accessDenied', 'Accès refusé')\r\n };\r\n return labels[actionName] || actionName;\r\n };\r\n\r\n const isRestorable = (entry: UserHistoryDto): boolean => {\r\n const restorableActions = [\r\n 'ProfileUpdated',\r\n 'PhoneUpdated',\r\n 'JobInfoUpdated',\r\n 'AddressUpdated',\r\n 'OrganizationUpdated',\r\n 'ContactUpdated',\r\n 'EntraFieldUpdated'\r\n ];\r\n return (\r\n restorableActions.includes(entry.actionName) &&\r\n !!entry.fieldChanged &&\r\n entry.oldValue !== null &&\r\n entry.oldValue !== undefined\r\n );\r\n };\r\n\r\n const getActionIcon = (actionName: string) => {\r\n if (actionName === 'AccessDenied') return <ShieldX className=\"w-4 h-4\" />;\r\n if (actionName === 'FieldRestored') return <RotateCcw className=\"w-4 h-4\" />;\r\n if (actionName.includes('Role')) return <Shield className=\"w-4 h-4\" />;\r\n if (actionName.includes('Password')) return <Key className=\"w-4 h-4\" />;\r\n if (actionName.includes('Status') || actionName.includes('Lock')) return <User className=\"w-4 h-4\" />;\r\n if (actionName.includes('Session')) return <LogOut className=\"w-4 h-4\" />;\r\n if (actionName.includes('Entra')) return <Cloud className=\"w-4 h-4\" />;\r\n if (actionName.includes('Phone')) return <Phone className=\"w-4 h-4\" />;\r\n if (actionName.includes('Address')) return <MapPinIcon className=\"w-4 h-4\" />;\r\n if (actionName.includes('Job') || actionName.includes('Organization')) return <Briefcase className=\"w-4 h-4\" />;\r\n return <Edit3 className=\"w-4 h-4\" />;\r\n };\r\n\r\n const handleRefresh = () => {\r\n loadHistory();\r\n };\r\n\r\n return (\r\n <div className=\"space-y-6\">\r\n <div className=\"flex items-center justify-between\">\r\n <h3 className=\"text-lg font-semibold text-[var(--text-primary)] flex items-center gap-2\">\r\n <History className=\"w-5 h-5\" />\r\n {t('userDetail.history.title', 'Historique des modifications')}\r\n </h3>\r\n <button\r\n onClick={handleRefresh}\r\n className=\"flex items-center gap-2 px-3 py-1.5 rounded-[var(--radius-button)] bg-[var(--bg-primary)] border border-[var(--border-color)] text-[var(--text-secondary)] hover:bg-[var(--bg-hover)] transition-colors\"\r\n >\r\n <RefreshCw className=\"w-4 h-4\" />\r\n {t('common.refresh', 'Actualiser')}\r\n </button>\r\n </div>\r\n\r\n {!history && (\r\n <div className=\"flex items-center justify-center py-12\">\r\n <Loader2 className=\"w-6 h-6 animate-spin text-[var(--color-accent-500)]\" />\r\n </div>\r\n )}\r\n {history && (!Array.isArray(history) || history.length === 0) && (\r\n <div className=\"text-center py-12\">\r\n <History className=\"w-12 h-12 mx-auto mb-4 text-[var(--text-tertiary)]\" />\r\n <p className=\"text-[var(--text-secondary)]\">\r\n {t('userDetail.history.noHistory', 'Aucun historique de modification')}\r\n </p>\r\n </div>\r\n )}\r\n {history && Array.isArray(history) && history.length > 0 && (\r\n <div className=\"relative\">\r\n {/* Timeline line */}\r\n <div className=\"absolute left-4 top-0 bottom-0 w-0.5 bg-[var(--border-color)]\" />\r\n\r\n {/* Timeline entries */}\r\n <div className=\"space-y-4\">\r\n {history.map((entry) => (\r\n <div key={entry.id} className=\"relative pl-10\">\r\n {/* Timeline dot */}\r\n <div className=\"absolute left-2 top-2 w-5 h-5 rounded-full bg-[var(--bg-secondary)] border-2 border-[var(--color-accent-500)] flex items-center justify-center\">\r\n {getActionIcon(entry.actionName)}\r\n </div>\r\n\r\n {/* Entry card */}\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--bg-primary)] border border-[var(--border-color)]\">\r\n <div className=\"flex items-start justify-between gap-4\">\r\n <div className=\"flex-1\">\r\n <div className=\"flex items-center gap-2 mb-1\">\r\n <span className=\"font-medium text-[var(--text-primary)]\">\r\n {getActionLabel(entry.actionName)}\r\n </span>\r\n {entry.fieldChanged && (\r\n <span className=\"px-2 py-0.5 rounded-[var(--radius-badge)] text-xs bg-[var(--bg-tertiary)] text-[var(--text-secondary)]\">\r\n {entry.fieldChanged}\r\n </span>\r\n )}\r\n </div>\r\n\r\n {(entry.oldValue || entry.newValue) && (\r\n <div className=\"text-sm text-[var(--text-secondary)] mt-2\">\r\n {entry.oldValue && (\r\n <span className=\"inline-flex items-center gap-1\">\r\n <span className=\"text-red-500 line-through\">{entry.oldValue}</span>\r\n </span>\r\n )}\r\n {entry.oldValue && entry.newValue && (\r\n <span className=\"mx-2\">→</span>\r\n )}\r\n {entry.newValue && (\r\n <span className=\"text-green-500\">{entry.newValue}</span>\r\n )}\r\n </div>\r\n )}\r\n\r\n <div className=\"flex items-center gap-4 mt-2 text-xs text-[var(--text-tertiary)]\">\r\n <span>{formatDate(entry.createdAt)}</span>\r\n {entry.changedByUserName && (\r\n <span className=\"flex items-center gap-1\">\r\n <User className=\"w-3 h-3\" />\r\n {entry.changedByUserName}\r\n </span>\r\n )}\r\n </div>\r\n </div>\r\n\r\n {/* Restore button */}\r\n {isRestorable(entry) && (\r\n <button\r\n onClick={() => handleRestoreField(entry.id)}\r\n disabled={restoringHistoryId === entry.id || !canUpdate}\r\n className={`flex items-center gap-1.5 px-3 py-1.5 rounded-[var(--radius-button)] text-xs font-medium transition-colors disabled:opacity-50 ${!canUpdate ? 'bg-[var(--bg-secondary)] text-[var(--text-tertiary)] cursor-not-allowed' : 'bg-[var(--bg-secondary)] text-[var(--text-secondary)] hover:bg-[var(--color-accent-500)]/10 hover:text-[var(--color-accent-600)]'}`}\r\n title={!canUpdate ? t('common.noPermission', 'Permission insuffisante') : t('userDetail.history.restore', 'Restaurer cette valeur')}\r\n >\r\n {restoringHistoryId === entry.id ? (\r\n <Loader2 className=\"w-3.5 h-3.5 animate-spin\" />\r\n ) : (\r\n <RotateCcw className=\"w-3.5 h-3.5\" />\r\n )}\r\n {t('userDetail.history.restore', 'Restaurer')}\r\n </button>\r\n )}\r\n </div>\r\n </div>\r\n </div>\r\n ))}\r\n </div>\r\n </div>\r\n )}\r\n </div>\r\n );\r\n}\r\n","import { useState, useEffect, useCallback, useMemo } from 'react';\r\nimport type { ReactElement } from 'react';\r\nimport { useTranslation } from 'react-i18next';\r\nimport * as LucideIcons from 'lucide-react';\r\nimport {\r\n Boxes,\r\n Loader2,\r\n ChevronDown,\r\n ChevronRight,\r\n Shield,\r\n Key,\r\n Layers,\r\n RefreshCw,\r\n Building2,\r\n Filter,\r\n} from 'lucide-react';\r\nimport type { LucideIcon } from 'lucide-react';\r\nimport { adminApi, type UserApplicationAccessDto, type UserTenantDto } from '@/services/api/adminApi';\r\n\r\ninterface UserApplicationsTabProps {\r\n readonly userId: string;\r\n}\r\n\r\nexport function UserApplicationsTab({ userId }: UserApplicationsTabProps): ReactElement {\r\n const { t } = useTranslation('admin');\r\n const [applications, setApplications] = useState<UserApplicationAccessDto[]>([]);\r\n const [tenants, setTenants] = useState<UserTenantDto[]>([]);\r\n const [selectedTenantId, setSelectedTenantId] = useState<string | undefined>(undefined);\r\n const [loading, setLoading] = useState(true);\r\n const [tenantsLoading, setTenantsLoading] = useState(true);\r\n const [error, setError] = useState<string | null>(null);\r\n const [expandedApps, setExpandedApps] = useState<Set<string>>(new Set());\r\n\r\n const loadTenants = useCallback(async () => {\r\n setTenantsLoading(true);\r\n try {\r\n const data = await adminApi.users.getTenants(userId);\r\n setTenants(data);\r\n } catch {\r\n setTenants([]);\r\n } finally {\r\n setTenantsLoading(false);\r\n }\r\n }, [userId]);\r\n\r\n const loadApplicationAccess = useCallback(async () => {\r\n setLoading(true);\r\n setError(null);\r\n try {\r\n const data = await adminApi.users.getApplicationAccess(userId, selectedTenantId);\r\n setApplications(data);\r\n } catch (err) {\r\n setApplications([]);\r\n setError(err instanceof Error ? err.message : t('userDetail.applications.loadError'));\r\n } finally {\r\n setLoading(false);\r\n }\r\n }, [userId, selectedTenantId, t]);\r\n\r\n useEffect(() => {\r\n loadTenants();\r\n }, [loadTenants]);\r\n\r\n useEffect(() => {\r\n loadApplicationAccess();\r\n }, [loadApplicationAccess]);\r\n\r\n const toggleExpand = (appId: string) => {\r\n setExpandedApps(prev => {\r\n const next = new Set(prev);\r\n if (next.has(appId)) next.delete(appId);\r\n else next.add(appId);\r\n return next;\r\n });\r\n };\r\n\r\n const selectedTenantName = useMemo(() => {\r\n if (!selectedTenantId) return null;\r\n return tenants.find(t => t.id === selectedTenantId)?.name ?? null;\r\n }, [selectedTenantId, tenants]);\r\n\r\n return (\r\n <div className=\"space-y-6\">\r\n {/* Header with tenant filter */}\r\n <div className=\"flex items-center justify-between gap-4\">\r\n <h3 className=\"text-lg font-semibold text-[var(--text-primary)]\">\r\n {t('userDetail.applications.title')}\r\n </h3>\r\n <div className=\"flex items-center gap-2\">\r\n {/* Tenant filter */}\r\n {!tenantsLoading && tenants.length > 0 && (\r\n <div className=\"flex items-center gap-2\">\r\n <Filter className=\"w-4 h-4 text-[var(--text-muted)]\" />\r\n <select\r\n value={selectedTenantId ?? ''}\r\n onChange={(e) => setSelectedTenantId(e.target.value || undefined)}\r\n className=\"text-sm border border-[var(--border-color)] rounded-[var(--radius-button)] bg-[var(--bg-card)] text-[var(--text-primary)] px-3 py-1.5 focus:outline-none focus:ring-2 focus:ring-[var(--color-accent-500)]/30\"\r\n >\r\n <option value=\"\">{t('userDetail.applications.allTenants')}</option>\r\n {tenants.map(tenant => (\r\n <option key={tenant.id} value={tenant.id}>\r\n {tenant.name}\r\n </option>\r\n ))}\r\n </select>\r\n </div>\r\n )}\r\n <button\r\n onClick={() => void loadApplicationAccess()}\r\n className=\"p-2 rounded-[var(--radius-button)] text-[var(--text-secondary)] hover:bg-[var(--bg-hover)]\"\r\n title={t('common:refresh', 'Refresh')}\r\n >\r\n <RefreshCw className=\"w-4 h-4\" />\r\n </button>\r\n </div>\r\n </div>\r\n\r\n {/* Active filter indicator */}\r\n {selectedTenantName && (\r\n <div className=\"flex items-center gap-2 px-3 py-2 rounded-[var(--radius-button)] bg-[var(--color-accent-500)]/5 border border-[var(--color-accent-500)]/20 text-sm text-[var(--color-accent-600)]\">\r\n <Building2 className=\"w-4 h-4\" />\r\n {t('userDetail.applications.filteredByTenant', { tenant: selectedTenantName })}\r\n </div>\r\n )}\r\n\r\n {/* Loading state */}\r\n {loading ? (\r\n <div className=\"flex items-center justify-center py-12\">\r\n <Loader2 className=\"w-8 h-8 animate-spin text-[var(--color-accent-500)]\" />\r\n </div>\r\n ) : error ? (\r\n <div className=\"text-center py-12 text-[var(--error-text)]\">\r\n <Boxes className=\"w-12 h-12 mx-auto mb-4 text-[var(--error-text)] opacity-50\" />\r\n <p>{error}</p>\r\n </div>\r\n ) : applications.length === 0 ? (\r\n <div className=\"text-center py-12 text-[var(--text-secondary)]\">\r\n <Boxes className=\"w-12 h-12 mx-auto mb-4 text-[var(--text-tertiary)]\" />\r\n <p>{t('userDetail.applications.noAccess')}</p>\r\n </div>\r\n ) : (\r\n /* Application list */\r\n <div className=\"space-y-2\">\r\n {applications.map(app => (\r\n <ApplicationCard\r\n key={app.applicationId}\r\n app={app}\r\n isExpanded={expandedApps.has(app.applicationId)}\r\n onToggle={() => toggleExpand(app.applicationId)}\r\n />\r\n ))}\r\n </div>\r\n )}\r\n </div>\r\n );\r\n}\r\n\r\nfunction ApplicationCard({\r\n app,\r\n isExpanded,\r\n onToggle,\r\n}: {\r\n app: UserApplicationAccessDto;\r\n isExpanded: boolean;\r\n onToggle: () => void;\r\n}) {\r\n const { t } = useTranslation('admin');\r\n const icons = LucideIcons as unknown as Record<string, LucideIcon>;\r\n const AppIcon = app.icon ? icons[app.icon] : null;\r\n\r\n // Group permissions by module\r\n const permissionsByModule = useMemo(() => {\r\n const groups: Record<string, { moduleName: string; permissions: typeof app.permissions }> = {};\r\n for (const perm of app.permissions) {\r\n const key = perm.moduleName || '_global';\r\n if (!groups[key]) {\r\n groups[key] = { moduleName: perm.moduleName || t('userDetail.applications.globalPermissions'), permissions: [] };\r\n }\r\n groups[key].permissions.push(perm);\r\n }\r\n return Object.values(groups);\r\n }, [app.permissions, t]);\r\n\r\n return (\r\n <div className=\"border border-[var(--border-color)] rounded-[var(--radius-card)] bg-[var(--bg-card)] overflow-hidden\">\r\n {/* Card header - clickable */}\r\n <button\r\n onClick={onToggle}\r\n className=\"w-full flex items-center gap-3 p-4 text-left hover:bg-[var(--bg-hover)] transition-colors\"\r\n >\r\n {isExpanded ? (\r\n <ChevronDown className=\"w-4 h-4 text-[var(--text-muted)] flex-shrink-0\" />\r\n ) : (\r\n <ChevronRight className=\"w-4 h-4 text-[var(--text-muted)] flex-shrink-0\" />\r\n )}\r\n\r\n {/* App icon */}\r\n <div className=\"w-9 h-9 rounded-[var(--radius-button)] bg-[var(--color-accent-500)]/10 flex items-center justify-center flex-shrink-0\">\r\n {AppIcon ? (\r\n <AppIcon className=\"w-5 h-5 text-[var(--color-accent-600)]\" />\r\n ) : (\r\n <Layers className=\"w-5 h-5 text-[var(--color-accent-600)]\" />\r\n )}\r\n </div>\r\n\r\n {/* App info */}\r\n <div className=\"flex-1 min-w-0\">\r\n <p className=\"font-medium text-[var(--text-primary)] truncate\">{app.applicationLabel}</p>\r\n <p className=\"text-xs text-[var(--text-muted)] truncate\">{app.applicationCode}</p>\r\n </div>\r\n\r\n {/* Access badge */}\r\n {app.hasFullAccess ? (\r\n <span className=\"px-2.5 py-1 text-xs font-medium rounded-full bg-green-500/10 text-green-600 border border-green-500/20 flex-shrink-0\">\r\n {t('userDetail.applications.fullAccess')}\r\n </span>\r\n ) : (\r\n <span className=\"px-2.5 py-1 text-xs font-medium rounded-full bg-[var(--color-accent-500)]/10 text-[var(--color-accent-600)] border border-[var(--color-accent-500)]/20 flex-shrink-0\">\r\n {t('userDetail.applications.permissionCount', { count: app.permissions.length })}\r\n </span>\r\n )}\r\n\r\n {/* Roles count */}\r\n <span className=\"text-xs text-[var(--text-muted)] flex items-center gap-1 flex-shrink-0\">\r\n <Shield className=\"w-3.5 h-3.5\" />\r\n {app.roles.length}\r\n </span>\r\n </button>\r\n\r\n {/* Expanded content */}\r\n {isExpanded && (\r\n <div className=\"border-t border-[var(--border-color)] p-4 space-y-4 bg-[var(--bg-secondary)]\">\r\n {/* Roles section */}\r\n <div>\r\n <h5 className=\"text-xs font-medium text-[var(--text-muted)] uppercase tracking-wider mb-2\">\r\n {t('userDetail.applications.rolesGrantingAccess')}\r\n </h5>\r\n <div className=\"flex flex-wrap gap-2\">\r\n {app.roles.map(role => (\r\n <span\r\n key={role.roleId}\r\n className=\"inline-flex items-center gap-1.5 px-2.5 py-1 text-xs rounded-full bg-[var(--bg-card)] border border-[var(--border-color)] text-[var(--text-primary)]\"\r\n >\r\n <Shield className=\"w-3 h-3 text-[var(--color-accent-500)]\" />\r\n {role.roleName}\r\n {role.source === 'Group' && (\r\n <span className=\"text-[var(--text-tertiary)]\">\r\n ({t('userDetail.applications.viaGroup')})\r\n </span>\r\n )}\r\n </span>\r\n ))}\r\n </div>\r\n </div>\r\n\r\n {/* Permissions section */}\r\n {!app.hasFullAccess && app.permissions.length > 0 && (\r\n <div>\r\n <h5 className=\"text-xs font-medium text-[var(--text-muted)] uppercase tracking-wider mb-2\">\r\n {t('userDetail.applications.permissionsDetail')}\r\n </h5>\r\n <div className=\"space-y-3\">\r\n {permissionsByModule.map(group => (\r\n <div key={group.moduleName}>\r\n <p className=\"text-xs font-medium text-[var(--text-secondary)] mb-1\">{group.moduleName}</p>\r\n <div className=\"flex flex-wrap gap-1.5\">\r\n {group.permissions.map(perm => (\r\n <span\r\n key={perm.path}\r\n className=\"inline-flex items-center gap-1 px-2 py-0.5 text-xs rounded bg-[var(--bg-card)] border border-[var(--border-color)] text-[var(--text-secondary)]\"\r\n >\r\n <Key className=\"w-2.5 h-2.5 text-[var(--text-tertiary)]\" />\r\n {perm.action || extractActionFromPath(perm.path)}\r\n </span>\r\n ))}\r\n </div>\r\n </div>\r\n ))}\r\n </div>\r\n </div>\r\n )}\r\n\r\n {app.hasFullAccess && (\r\n <p className=\"text-xs text-green-600 italic\">\r\n {t('userDetail.applications.fullAccessDescription')}\r\n </p>\r\n )}\r\n </div>\r\n )}\r\n </div>\r\n );\r\n}\r\n\r\n/** Extract the last segment of a permission path as the action name */\r\nfunction extractActionFromPath(path: string): string {\r\n const parts = path.split('.');\r\n return parts.at(-1)!;\r\n}\r\n","import { useState, useCallback, useEffect, useMemo } from 'react';\r\nimport { useTranslation } from 'react-i18next';\r\nimport {\r\n adminApi,\r\n createAdminApi,\r\n type UserDetailDto,\r\n type RoleListDto,\r\n type UpdateUserRequest,\r\n type UserSessionsDto,\r\n type UserActivityDto,\r\n type UserHistoryDto,\r\n type OrganizationReferencesDto,\r\n type UserTenantDto,\r\n type TenantListDto\r\n} from '@/services/api/adminApi';\r\n\r\nconst isValidGuid = (value: string | undefined): boolean => {\r\n if (!value) return false;\r\n const guidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\r\n return guidRegex.test(value);\r\n};\r\n\r\nexport interface UseUserDetailOptions {\r\n userId: string | undefined;\r\n tenantSlug?: string | null;\r\n}\r\n\r\nexport interface UserFormData {\r\n firstName: string;\r\n lastName: string;\r\n email: string;\r\n roleIds: string[];\r\n}\r\n\r\nexport interface UseUserDetailReturn {\r\n // Core state\r\n user: UserDetailDto | null;\r\n formData: UserFormData;\r\n setFormData: React.Dispatch<React.SetStateAction<UserFormData>>;\r\n isCreateMode: boolean;\r\n loading: boolean;\r\n error: string | null;\r\n success: string | null;\r\n setError: (error: string | null) => void;\r\n setSuccess: (success: string | null) => void;\r\n\r\n // Data loading states\r\n roles: RoleListDto[] | null;\r\n rolesLoading: boolean;\r\n sessions: UserSessionsDto | null;\r\n activity: UserActivityDto | null;\r\n history: UserHistoryDto[] | null;\r\n orgReferences: OrganizationReferencesDto | null;\r\n userTenants: UserTenantDto[] | null;\r\n allTenants: TenantListDto[] | null;\r\n\r\n // Load functions\r\n loadUser: (silent?: boolean) => Promise<void>;\r\n loadRoles: () => Promise<void>;\r\n loadOrgReferences: () => Promise<void>;\r\n loadSessions: () => Promise<void>;\r\n loadActivity: () => Promise<void>;\r\n loadHistory: () => Promise<void>;\r\n loadTenants: () => Promise<void>;\r\n loadAllTenants: () => Promise<void>;\r\n\r\n // State setters for external updates\r\n setHistory: React.Dispatch<React.SetStateAction<UserHistoryDto[] | null>>;\r\n setUserTenants: React.Dispatch<React.SetStateAction<UserTenantDto[] | null>>;\r\n\r\n // Actions\r\n handleSaveInfo: (e: React.FormEvent) => Promise<void>;\r\n saving: boolean;\r\n}\r\n\r\nexport function useUserDetail({ userId, tenantSlug }: UseUserDetailOptions): UseUserDetailReturn {\r\n const { t } = useTranslation('admin');\r\n const isCreateMode = !isValidGuid(userId);\r\n\r\n // Create tenant-aware API instance for sessions/activity\r\n const tenantApi = useMemo(\r\n () => tenantSlug ? createAdminApi(tenantSlug) : adminApi,\r\n [tenantSlug]\r\n );\r\n\r\n // Core state\r\n const [user, setUser] = useState<UserDetailDto | null>(null);\r\n const [loading, setLoading] = useState(true);\r\n const [saving, setSaving] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n const [success, setSuccess] = useState<string | null>(null);\r\n\r\n // Form state\r\n const [formData, setFormData] = useState<UserFormData>({\r\n firstName: '',\r\n lastName: '',\r\n email: '',\r\n roleIds: []\r\n });\r\n\r\n // Related data states\r\n const [roles, setRoles] = useState<RoleListDto[] | null>(null);\r\n const [rolesLoading, setRolesLoading] = useState(false);\r\n const [sessions, setSessions] = useState<UserSessionsDto | null>(null);\r\n const [activity, setActivity] = useState<UserActivityDto | null>(null);\r\n const [history, setHistory] = useState<UserHistoryDto[] | null>(null);\r\n const [orgReferences, setOrgReferences] = useState<OrganizationReferencesDto | null>(null);\r\n const [userTenants, setUserTenants] = useState<UserTenantDto[] | null>(null);\r\n const [allTenants, setAllTenants] = useState<TenantListDto[] | null>(null);\r\n\r\n // Load user data\r\n const loadUser = useCallback(async (silent = false) => {\r\n if (!userId || isCreateMode) return;\r\n try {\r\n if (!silent) setLoading(true);\r\n const userData = await adminApi.users.getById(userId);\r\n setUser(userData);\r\n setFormData({\r\n firstName: userData.firstName,\r\n lastName: userData.lastName,\r\n email: userData.email,\r\n roleIds: userData.roles.map(r => r.id)\r\n });\r\n } catch (err) {\r\n console.error('Failed to load user:', err);\r\n setError(t('userDetail.errors.loadFailed'));\r\n } finally {\r\n if (!silent) setLoading(false);\r\n }\r\n }, [userId, isCreateMode, t]);\r\n\r\n // Load roles\r\n const loadRoles = useCallback(async () => {\r\n try {\r\n setRolesLoading(true);\r\n const result = await adminApi.roles.getAssignable();\r\n setRoles(Array.isArray(result) ? result : []);\r\n } catch (err) {\r\n console.error('Failed to load roles:', err);\r\n setRoles([]);\r\n } finally {\r\n setRolesLoading(false);\r\n }\r\n }, []);\r\n\r\n // Load organization references\r\n const loadOrgReferences = useCallback(async () => {\r\n try {\r\n const data = await adminApi.users.getOrganizationReferences();\r\n setOrgReferences(data);\r\n } catch (err) {\r\n console.error('Failed to load organization references:', err);\r\n }\r\n }, []);\r\n\r\n // Load sessions (tenant-filtered when tenant context is active)\r\n const loadSessions = useCallback(async () => {\r\n if (!userId || isCreateMode) return;\r\n try {\r\n const data = await tenantApi.users.getSessions(userId);\r\n setSessions(data);\r\n } catch (err) {\r\n console.error('Failed to load sessions:', err);\r\n }\r\n }, [userId, isCreateMode, tenantApi]);\r\n\r\n // Load activity (tenant-filtered when tenant context is active)\r\n const loadActivity = useCallback(async () => {\r\n if (!userId || isCreateMode) return;\r\n try {\r\n const data = await tenantApi.users.getActivity(userId);\r\n setActivity(data);\r\n } catch (err) {\r\n console.error('Failed to load activity:', err);\r\n }\r\n }, [userId, isCreateMode, tenantApi]);\r\n\r\n // Load history\r\n const loadHistory = useCallback(async () => {\r\n if (!userId || isCreateMode) return;\r\n try {\r\n const data = await adminApi.users.getHistory(userId, 100);\r\n setHistory(data);\r\n } catch (err) {\r\n console.error('Failed to load history:', err);\r\n setHistory([]);\r\n }\r\n }, [userId, isCreateMode]);\r\n\r\n // Load tenants\r\n const loadTenants = useCallback(async () => {\r\n if (!userId || isCreateMode) return;\r\n try {\r\n const data = await adminApi.users.getTenants(userId);\r\n setUserTenants(data);\r\n } catch (err) {\r\n console.error('Failed to load tenants:', err);\r\n setUserTenants([]);\r\n }\r\n }, [userId, isCreateMode]);\r\n\r\n // Load all tenants for adding\r\n const loadAllTenants = useCallback(async () => {\r\n try {\r\n const result = await adminApi.tenants.getAll({ status: 'Active' });\r\n setAllTenants(result.items);\r\n } catch (err) {\r\n console.error('Failed to load all tenants:', err);\r\n setAllTenants([]);\r\n }\r\n }, []);\r\n\r\n // Handle save info\r\n const handleSaveInfo = useCallback(async (e: React.FormEvent) => {\r\n e.preventDefault();\r\n if (!userId) return;\r\n\r\n setSaving(true);\r\n setError(null);\r\n setSuccess(null);\r\n\r\n try {\r\n const updateData: UpdateUserRequest = {\r\n firstName: formData.firstName,\r\n lastName: formData.lastName,\r\n email: formData.email !== user?.email ? formData.email : undefined,\r\n roleIds: formData.roleIds\r\n };\r\n await adminApi.users.update(userId, updateData);\r\n setSuccess(t('userDetail.success.infoSaved'));\r\n await loadUser();\r\n } catch (err: unknown) {\r\n setError(err instanceof Error ? err.message : t('userDetail.errors.saveFailed'));\r\n } finally {\r\n setSaving(false);\r\n }\r\n }, [userId, formData, user?.email, t, loadUser]);\r\n\r\n // Initial load\r\n useEffect(() => {\r\n loadUser();\r\n }, [loadUser]);\r\n\r\n return {\r\n user,\r\n formData,\r\n setFormData,\r\n isCreateMode,\r\n loading,\r\n error,\r\n success,\r\n setError,\r\n setSuccess,\r\n roles,\r\n rolesLoading,\r\n sessions,\r\n activity,\r\n history,\r\n orgReferences,\r\n userTenants,\r\n allTenants,\r\n loadUser,\r\n loadRoles,\r\n loadOrgReferences,\r\n loadSessions,\r\n loadActivity,\r\n loadHistory,\r\n loadTenants,\r\n loadAllTenants,\r\n setHistory,\r\n setUserTenants,\r\n handleSaveInfo,\r\n saving\r\n };\r\n}\r\n","import { useState, useCallback } from 'react';\r\nimport { useTranslation } from 'react-i18next';\r\nimport { adminApi, UnlockReason } from '@/services/api/adminApi';\r\n\r\nexport interface UseUserSecurityOptions {\r\n userId: string | undefined;\r\n onUserReload: () => Promise<void>;\r\n onSessionsReload: () => Promise<void>;\r\n setError: (error: string | null) => void;\r\n setSuccess: (success: string | null) => void;\r\n}\r\n\r\nexport interface UseUserSecurityReturn {\r\n // Password state\r\n newPassword: string;\r\n setNewPassword: (password: string) => void;\r\n temporaryPassword: string | null;\r\n showTemporaryPassword: boolean;\r\n setShowTemporaryPassword: (show: boolean) => void;\r\n\r\n // Modal state\r\n showUnlockModal: boolean;\r\n setShowUnlockModal: (show: boolean) => void;\r\n\r\n // Actions\r\n handleSendResetLink: () => Promise<void>;\r\n handleResetPasswordDirect: () => Promise<void>;\r\n handleToggleStatus: (isActive: boolean) => Promise<void>;\r\n handleEndSession: (sessionId: string) => Promise<void>;\r\n handleEndAllSessions: () => Promise<void>;\r\n handleUnlock: (reason: UnlockReason, mustChangePassword: boolean) => Promise<void>;\r\n handleClearFailedAttempts: () => Promise<void>;\r\n copyToClipboard: (text: string) => Promise<void>;\r\n\r\n // Loading state\r\n saving: boolean;\r\n}\r\n\r\nexport function useUserSecurity({\r\n userId,\r\n onUserReload,\r\n onSessionsReload,\r\n setError,\r\n setSuccess\r\n}: UseUserSecurityOptions): UseUserSecurityReturn {\r\n const { t } = useTranslation('admin');\r\n\r\n // Password state\r\n const [newPassword, setNewPassword] = useState('');\r\n const [temporaryPassword, setTemporaryPassword] = useState<string | null>(null);\r\n const [showTemporaryPassword, setShowTemporaryPassword] = useState(false);\r\n const [saving, setSaving] = useState(false);\r\n\r\n // Modal state\r\n const [showUnlockModal, setShowUnlockModal] = useState(false);\r\n\r\n // Send reset link\r\n const handleSendResetLink = useCallback(async () => {\r\n if (!userId) return;\r\n\r\n setSaving(true);\r\n setError(null);\r\n setSuccess(null);\r\n setTemporaryPassword(null);\r\n\r\n try {\r\n await adminApi.users.sendPasswordResetLink(userId);\r\n setSuccess(t('userDetail.success.resetLinkSent', 'Lien de réinitialisation envoyé par email'));\r\n } catch (err: unknown) {\r\n setError(err instanceof Error ? err.message : t('userDetail.errors.sendResetLinkFailed', 'Échec de l\\'envoi du lien'));\r\n } finally {\r\n setSaving(false);\r\n }\r\n }, [userId, setError, setSuccess, t]);\r\n\r\n // Direct password reset\r\n const handleResetPasswordDirect = useCallback(async () => {\r\n if (!userId) return;\r\n\r\n setSaving(true);\r\n setError(null);\r\n setSuccess(null);\r\n\r\n try {\r\n const customPassword = newPassword.trim() || undefined;\r\n const result = await adminApi.users.resetPasswordDirect(userId, customPassword);\r\n setTemporaryPassword(result.temporaryPassword);\r\n setNewPassword('');\r\n setShowTemporaryPassword(true);\r\n setSuccess(t('userDetail.success.passwordResetDirect', 'Mot de passe réinitialisé. Communiquez le mot de passe temporaire à l\\'utilisateur.'));\r\n } catch (err: unknown) {\r\n setError(err instanceof Error ? err.message : t('userDetail.errors.passwordResetFailed'));\r\n } finally {\r\n setSaving(false);\r\n }\r\n }, [userId, newPassword, setError, setSuccess, t]);\r\n\r\n // Toggle user active status\r\n const handleToggleStatus = useCallback(async (isActive: boolean) => {\r\n if (!userId) return;\r\n\r\n try {\r\n if (isActive) {\r\n await adminApi.users.deactivate(userId);\r\n } else {\r\n await adminApi.users.activate(userId);\r\n }\r\n await onUserReload();\r\n setSuccess(isActive ? t('userDetail.success.deactivated') : t('userDetail.success.activated'));\r\n } catch {\r\n setError(t('userDetail.errors.statusChangeFailed'));\r\n }\r\n }, [userId, onUserReload, setError, setSuccess, t]);\r\n\r\n // End single session\r\n const handleEndSession = useCallback(async (sessionId: string) => {\r\n if (!userId) return;\r\n\r\n try {\r\n await adminApi.users.endSession(userId, sessionId);\r\n await onSessionsReload();\r\n setSuccess(t('userDetail.success.sessionEnded'));\r\n } catch {\r\n setError(t('userDetail.errors.endSessionFailed'));\r\n }\r\n }, [userId, onSessionsReload, setError, setSuccess, t]);\r\n\r\n // End all sessions\r\n const handleEndAllSessions = useCallback(async () => {\r\n if (!userId) return;\r\n if (!confirm(t('userDetail.confirmEndAllSessions'))) return;\r\n\r\n try {\r\n await adminApi.users.endAllSessions(userId);\r\n await onSessionsReload();\r\n setSuccess(t('userDetail.success.allSessionsEnded'));\r\n } catch {\r\n setError(t('userDetail.errors.endAllSessionsFailed'));\r\n }\r\n }, [userId, onSessionsReload, setError, setSuccess, t]);\r\n\r\n // Unlock account\r\n const handleUnlock = useCallback(async (reason: UnlockReason, mustChangePassword: boolean) => {\r\n if (!userId) return;\r\n\r\n try {\r\n await adminApi.users.unlock(userId, { reason, mustChangePassword });\r\n await onUserReload();\r\n setSuccess(t('userDetail.success.unlocked'));\r\n } catch {\r\n setError(t('userDetail.errors.unlockFailed'));\r\n }\r\n }, [userId, onUserReload, setError, setSuccess, t]);\r\n\r\n // Clear failed attempts\r\n const handleClearFailedAttempts = useCallback(async () => {\r\n if (!userId) return;\r\n\r\n try {\r\n await adminApi.users.clearFailedAttempts(userId);\r\n await onUserReload();\r\n setSuccess('Tentatives échouées réinitialisées avec succès');\r\n } catch {\r\n setError('Échec de la réinitialisation des tentatives échouées');\r\n }\r\n }, [userId, onUserReload, setError, setSuccess]);\r\n\r\n // Copy to clipboard\r\n const copyToClipboard = useCallback(async (text: string) => {\r\n try {\r\n await navigator.clipboard.writeText(text);\r\n setSuccess(t('userDetail.success.copied', 'Mot de passe copié dans le presse-papiers'));\r\n } catch {\r\n setError(t('userDetail.errors.copyFailed', 'Échec de la copie'));\r\n }\r\n }, [setError, setSuccess, t]);\r\n\r\n return {\r\n newPassword,\r\n setNewPassword,\r\n temporaryPassword,\r\n showTemporaryPassword,\r\n setShowTemporaryPassword,\r\n showUnlockModal,\r\n setShowUnlockModal,\r\n handleSendResetLink,\r\n handleResetPasswordDirect,\r\n handleToggleStatus,\r\n handleEndSession,\r\n handleEndAllSessions,\r\n handleUnlock,\r\n handleClearFailedAttempts,\r\n copyToClipboard,\r\n saving\r\n };\r\n}\r\n","import { useState, useCallback } from 'react';\r\nimport { useTranslation } from 'react-i18next';\r\nimport { adminApi, type UserDetailDto } from '@/services/api/adminApi';\r\nimport type { SelectWithOtherValue } from '@/components/ui/SelectWithOther';\r\n\r\nexport type SectionType = 'phones' | 'address' | 'jobInfo' | 'organization';\r\n\r\nexport interface PhonesSectionData {\r\n phoneNumber: string;\r\n mobilePhone: string;\r\n faxNumber: string;\r\n}\r\n\r\nexport interface AddressSectionData {\r\n streetAddress: string;\r\n city: string;\r\n state: string;\r\n postalCode: string;\r\n country: string;\r\n}\r\n\r\nexport interface JobInfoSectionData {\r\n employeeId: string;\r\n employeeType: string;\r\n employeeHireDate: string;\r\n employeeOrgData: string;\r\n}\r\n\r\nexport interface OrganizationSectionData {\r\n company: SelectWithOtherValue;\r\n department: SelectWithOtherValue;\r\n jobTitle: SelectWithOtherValue;\r\n office: SelectWithOtherValue;\r\n managerId: string;\r\n}\r\n\r\nexport interface SectionData {\r\n phones: PhonesSectionData;\r\n address: AddressSectionData;\r\n jobInfo: JobInfoSectionData;\r\n organization: OrganizationSectionData;\r\n}\r\n\r\nexport interface UseUserSectionsOptions {\r\n userId: string | undefined;\r\n user: UserDetailDto | null;\r\n onUserReload: () => Promise<void>;\r\n onHistoryReload: () => void;\r\n setError: (error: string | null) => void;\r\n setSuccess: (success: string | null) => void;\r\n}\r\n\r\nexport interface UseUserSectionsReturn {\r\n editingSection: string | null;\r\n sectionData: SectionData;\r\n setSectionData: React.Dispatch<React.SetStateAction<SectionData>>;\r\n startEditingSection: (section: SectionType) => void;\r\n cancelEditing: () => void;\r\n handleSaveSection: (section: SectionType) => Promise<void>;\r\n saving: boolean;\r\n}\r\n\r\nconst createInitialSectionData = (): SectionData => ({\r\n phones: { phoneNumber: '', mobilePhone: '', faxNumber: '' },\r\n address: { streetAddress: '', city: '', state: '', postalCode: '', country: '' },\r\n jobInfo: { employeeId: '', employeeType: '', employeeHireDate: '', employeeOrgData: '' },\r\n organization: {\r\n company: { id: '', customValue: undefined },\r\n department: { id: '', customValue: undefined },\r\n jobTitle: { id: '', customValue: undefined },\r\n office: { id: '', customValue: undefined },\r\n managerId: ''\r\n }\r\n});\r\n\r\nexport function useUserSections({\r\n userId,\r\n user,\r\n onUserReload,\r\n onHistoryReload,\r\n setError,\r\n setSuccess\r\n}: UseUserSectionsOptions): UseUserSectionsReturn {\r\n const { t } = useTranslation('admin');\r\n\r\n const [editingSection, setEditingSection] = useState<string | null>(null);\r\n const [sectionData, setSectionData] = useState<SectionData>(createInitialSectionData);\r\n const [saving, setSaving] = useState(false);\r\n\r\n // Start editing a section\r\n const startEditingSection = useCallback((section: SectionType) => {\r\n if (!user) return;\r\n setEditingSection(section);\r\n\r\n setSectionData(prev => {\r\n switch (section) {\r\n case 'phones':\r\n return {\r\n ...prev,\r\n phones: {\r\n phoneNumber: user.phoneNumber || '',\r\n mobilePhone: user.mobilePhone || '',\r\n faxNumber: user.faxNumber || ''\r\n }\r\n };\r\n case 'address':\r\n return {\r\n ...prev,\r\n address: {\r\n streetAddress: user.streetAddress || '',\r\n city: user.city || '',\r\n state: user.state || '',\r\n postalCode: user.postalCode || '',\r\n country: user.country || ''\r\n }\r\n };\r\n case 'jobInfo':\r\n return {\r\n ...prev,\r\n jobInfo: {\r\n employeeId: user.employeeId || '',\r\n employeeType: user.employeeType || '',\r\n employeeHireDate: user.employeeHireDate?.split('T')[0] || '',\r\n employeeOrgData: user.employeeOrgData || ''\r\n }\r\n };\r\n case 'organization':\r\n return {\r\n ...prev,\r\n organization: {\r\n company: { id: user.companyId || '', customValue: undefined },\r\n department: { id: user.departmentId || '', customValue: undefined },\r\n jobTitle: { id: user.jobTitleId || '', customValue: undefined },\r\n office: { id: user.officeId || '', customValue: undefined },\r\n managerId: user.managerId || ''\r\n }\r\n };\r\n default:\r\n return prev;\r\n }\r\n });\r\n }, [user]);\r\n\r\n // Cancel editing\r\n const cancelEditing = useCallback(() => {\r\n setEditingSection(null);\r\n }, []);\r\n\r\n // Save section data\r\n const handleSaveSection = useCallback(async (section: SectionType) => {\r\n if (!userId) return;\r\n\r\n setSaving(true);\r\n setError(null);\r\n setSuccess(null);\r\n\r\n try {\r\n switch (section) {\r\n case 'phones':\r\n await adminApi.users.updatePhones(userId, {\r\n phoneNumber: sectionData.phones.phoneNumber || null,\r\n mobilePhone: sectionData.phones.mobilePhone || null,\r\n faxNumber: sectionData.phones.faxNumber || null\r\n });\r\n break;\r\n\r\n case 'address':\r\n await adminApi.users.updateAddress(userId, {\r\n streetAddress: sectionData.address.streetAddress || null,\r\n city: sectionData.address.city || null,\r\n state: sectionData.address.state || null,\r\n postalCode: sectionData.address.postalCode || null,\r\n country: sectionData.address.country || null\r\n });\r\n break;\r\n\r\n case 'jobInfo':\r\n await adminApi.users.updateJobInfo(userId, {\r\n employeeId: sectionData.jobInfo.employeeId || null,\r\n employeeType: sectionData.jobInfo.employeeType || null,\r\n employeeHireDate: sectionData.jobInfo.employeeHireDate || null,\r\n employeeOrgData: sectionData.jobInfo.employeeOrgData || null\r\n });\r\n break;\r\n\r\n case 'organization': {\r\n const org = sectionData.organization;\r\n await adminApi.users.updateOrganization(userId, {\r\n companyId: org.company.customValue ? null : (org.company.id || null),\r\n companyName: org.company.customValue || null,\r\n departmentId: org.department.customValue ? null : (org.department.id || null),\r\n departmentName: org.department.customValue || null,\r\n jobTitleId: org.jobTitle.customValue ? null : (org.jobTitle.id || null),\r\n jobTitleName: org.jobTitle.customValue || null,\r\n officeId: org.office.customValue ? null : (org.office.id || null),\r\n officeName: org.office.customValue || null,\r\n managerId: org.managerId || null\r\n });\r\n break;\r\n }\r\n }\r\n\r\n setEditingSection(null);\r\n setSuccess(t('userDetail.success.sectionSaved', 'Section mise à jour avec succès'));\r\n await onUserReload();\r\n onHistoryReload();\r\n } catch (err: unknown) {\r\n setError(err instanceof Error ? err.message : t('userDetail.errors.saveFailed'));\r\n } finally {\r\n setSaving(false);\r\n }\r\n }, [userId, sectionData, onUserReload, onHistoryReload, setError, setSuccess, t]);\r\n\r\n return {\r\n editingSection,\r\n sectionData,\r\n setSectionData,\r\n startEditingSection,\r\n cancelEditing,\r\n handleSaveSection,\r\n saving\r\n };\r\n}\r\n","import { useState, useCallback, useEffect } from 'react';\r\nimport { useTranslation } from 'react-i18next';\r\nimport { adminApi, type UserTenantDto, type TenantListDto } from '@/services/api/adminApi';\r\nimport type { ViewMode } from '@/components/ui/ViewModeToggle';\r\n\r\nexport interface UseUserTenantsOptions {\r\n userId: string | undefined;\r\n isCreateMode: boolean;\r\n setError: (error: string | null) => void;\r\n setSuccess: (success: string | null) => void;\r\n}\r\n\r\nexport interface UseUserTenantsReturn {\r\n // Data\r\n userTenants: UserTenantDto[] | null;\r\n allTenants: TenantListDto[] | null;\r\n\r\n // UI state\r\n showAddTenantModal: boolean;\r\n tenantSearch: string;\r\n tenantsViewMode: ViewMode;\r\n selectedTenantIds: Set<string>;\r\n isAddingMultipleTenants: boolean;\r\n\r\n // Setters\r\n setShowAddTenantModal: (show: boolean) => void;\r\n setTenantSearch: (search: string) => void;\r\n setTenantsViewMode: (mode: ViewMode) => void;\r\n setUserTenants: React.Dispatch<React.SetStateAction<UserTenantDto[] | null>>;\r\n\r\n // Actions\r\n loadTenants: () => Promise<void>;\r\n loadAllTenants: () => Promise<void>;\r\n toggleTenantSelection: (tenantId: string) => void;\r\n selectAllTenants: (availableTenantIds: string[]) => void;\r\n clearTenantSelection: () => void;\r\n closeAddTenantModal: () => void;\r\n handleAddMultipleTenants: () => Promise<void>;\r\n handleRemoveTenant: (tenantId: string) => Promise<void>;\r\n}\r\n\r\nexport function useUserTenants({\r\n userId,\r\n isCreateMode,\r\n setError,\r\n setSuccess\r\n}: UseUserTenantsOptions): UseUserTenantsReturn {\r\n const { t } = useTranslation('admin');\r\n\r\n // Data state\r\n const [userTenants, setUserTenants] = useState<UserTenantDto[] | null>(null);\r\n const [allTenants, setAllTenants] = useState<TenantListDto[] | null>(null);\r\n\r\n // UI state\r\n const [showAddTenantModal, setShowAddTenantModal] = useState(false);\r\n const [tenantSearch, setTenantSearch] = useState('');\r\n const [tenantsViewMode, setTenantsViewMode] = useState<ViewMode>('cards');\r\n const [selectedTenantIds, setSelectedTenantIds] = useState<Set<string>>(new Set());\r\n const [isAddingMultipleTenants, setIsAddingMultipleTenants] = useState(false);\r\n\r\n // Load user tenants\r\n const loadTenants = useCallback(async () => {\r\n if (!userId || isCreateMode) return;\r\n try {\r\n const data = await adminApi.users.getTenants(userId);\r\n setUserTenants(data);\r\n } catch (err) {\r\n console.error('Failed to load tenants:', err);\r\n setUserTenants([]);\r\n }\r\n }, [userId, isCreateMode]);\r\n\r\n // Load all tenants for adding\r\n const loadAllTenants = useCallback(async () => {\r\n try {\r\n const result = await adminApi.tenants.getAll({ status: 'Active' });\r\n setAllTenants(result.items);\r\n } catch (err) {\r\n console.error('Failed to load all tenants:', err);\r\n setAllTenants([]);\r\n }\r\n }, []);\r\n\r\n // Toggle tenant selection\r\n const toggleTenantSelection = useCallback((tenantId: string) => {\r\n setSelectedTenantIds((prev) => {\r\n const newSet = new Set(prev);\r\n if (newSet.has(tenantId)) {\r\n newSet.delete(tenantId);\r\n } else {\r\n newSet.add(tenantId);\r\n }\r\n return newSet;\r\n });\r\n }, []);\r\n\r\n // Select all tenants\r\n const selectAllTenants = useCallback((availableTenantIds: string[]) => {\r\n setSelectedTenantIds(new Set(availableTenantIds));\r\n }, []);\r\n\r\n // Clear selection\r\n const clearTenantSelection = useCallback(() => {\r\n setSelectedTenantIds(new Set());\r\n }, []);\r\n\r\n // Close modal\r\n const closeAddTenantModal = useCallback(() => {\r\n setShowAddTenantModal(false);\r\n setTenantSearch('');\r\n setSelectedTenantIds(new Set());\r\n }, []);\r\n\r\n // Add multiple tenants\r\n const handleAddMultipleTenants = useCallback(async () => {\r\n if (!userId || selectedTenantIds.size === 0) return;\r\n\r\n try {\r\n setIsAddingMultipleTenants(true);\r\n setError(null);\r\n\r\n const tenantIdsArray = Array.from(selectedTenantIds);\r\n for (const tenantId of tenantIdsArray) {\r\n await adminApi.tenants.addMember(tenantId, { userId });\r\n }\r\n\r\n closeAddTenantModal();\r\n await loadTenants();\r\n setSuccess(t('userDetail.tenants.addMultipleSuccess', { count: tenantIdsArray.length, defaultValue: `${tenantIdsArray.length} tenant(s) ajouté(s) avec succès` }));\r\n setTimeout(() => setSuccess(null), 3000);\r\n } catch (err) {\r\n console.error('Failed to add tenants:', err);\r\n setError(t('userDetail.tenants.addError', 'Erreur lors de l\\'ajout du tenant'));\r\n setTimeout(() => setError(null), 3000);\r\n } finally {\r\n setIsAddingMultipleTenants(false);\r\n }\r\n }, [userId, selectedTenantIds, closeAddTenantModal, loadTenants, setError, setSuccess, t]);\r\n\r\n // Remove tenant\r\n const handleRemoveTenant = useCallback(async (tenantId: string) => {\r\n if (!userId) return;\r\n try {\r\n await adminApi.tenants.removeMember(tenantId, userId);\r\n await loadTenants();\r\n setSuccess(t('userDetail.tenants.removeSuccess', 'Tenant retiré avec succès'));\r\n setTimeout(() => setSuccess(null), 3000);\r\n } catch (err) {\r\n console.error('Failed to remove tenant:', err);\r\n setError(t('userDetail.tenants.removeError', 'Erreur lors du retrait du tenant'));\r\n setTimeout(() => setError(null), 3000);\r\n }\r\n }, [userId, loadTenants, setError, setSuccess, t]);\r\n\r\n // Load all tenants when modal opens\r\n useEffect(() => {\r\n if (showAddTenantModal && !allTenants) {\r\n loadAllTenants();\r\n }\r\n }, [showAddTenantModal, allTenants, loadAllTenants]);\r\n\r\n return {\r\n userTenants,\r\n allTenants,\r\n showAddTenantModal,\r\n tenantSearch,\r\n tenantsViewMode,\r\n selectedTenantIds,\r\n isAddingMultipleTenants,\r\n setShowAddTenantModal,\r\n setTenantSearch,\r\n setTenantsViewMode,\r\n setUserTenants,\r\n loadTenants,\r\n loadAllTenants,\r\n toggleTenantSelection,\r\n selectAllTenants,\r\n clearTenantSelection,\r\n closeAddTenantModal,\r\n handleAddMultipleTenants,\r\n handleRemoveTenant\r\n };\r\n}\r\n","import { useState, useEffect, useCallback } from 'react';\r\nimport type { ReactElement } from 'react';\r\nimport { useParams, useNavigate, useSearchParams } from 'react-router-dom';\r\nimport { useTranslation } from 'react-i18next';\r\nimport {\r\n ArrowLeft,\r\n User,\r\n Shield,\r\n Activity,\r\n Key,\r\n Loader2,\r\n AlertTriangle,\r\n CheckCircle,\r\n Users,\r\n Building2,\r\n History,\r\n AppWindow,\r\n} from 'lucide-react';\r\nimport { adminApi, type UpdateUserRequest, type UserConsolidatedRoleDto } from '@/services/api/adminApi';\r\nimport { Breadcrumb } from '@/components/ui/Breadcrumb';\r\nimport { Slot } from '@/extensions';\r\nimport { useTenant } from '@/contexts/TenantContext';\r\nimport { useAuth } from '@/contexts/AuthContext';\r\nimport { useAdminTenants } from '@/hooks/useAdminTenants';\r\nimport { type ScopeValue } from '@/components/ui/TenantScopeFilter';\r\nimport { UserRoleAssignment } from '@/components/platform/administration/UserRoleAssignment';\r\nimport { UserPermissionMatrix } from '@/components/platform/administration/permissions/UserPermissionMatrix';\r\nimport { UserGroupsTab } from '@/components/platform/administration/UserGroupsTab';\r\nimport {\r\n UserInfoTab,\r\n UserSecurityTab,\r\n UserActivitySessionsTab,\r\n UserTenantsTab,\r\n UserHistoryTab,\r\n UserApplicationsTab,\r\n} from '@/components/platform/administration/users';\r\nimport { useUserDetail } from '@/hooks/useUserDetail';\r\nimport { useUserSecurity } from '@/hooks/useUserSecurity';\r\nimport { useUserSections } from '@/hooks/useUserSections';\r\nimport { useUserTenants } from '@/hooks/useUserTenants';\r\n\r\ntype TabId = 'info' | 'security' | 'activitySessions' | 'roles' | 'permissions' | 'applications' | 'tenants' | 'groups' | 'history';\r\n\r\nconst VALID_TABS: TabId[] = ['info', 'security', 'activitySessions', 'roles', 'permissions', 'applications', 'tenants', 'groups', 'history'];\r\n\r\nexport function UserDetailPage(): ReactElement {\r\n const { t } = useTranslation('admin');\r\n const { id: userId } = useParams<{ id: string }>();\r\n const navigate = useNavigate();\r\n const [searchParams, setSearchParams] = useSearchParams();\r\n\r\n // Tenant context\r\n const { currentTenant, hasGlobalRoles } = useTenant();\r\n const { tenants: adminTenantsList } = useAdminTenants();\r\n const { hasPermission } = useAuth();\r\n\r\n // Permission checks\r\n const canUpdate = hasPermission('administration.users.update');\r\n const canDelete = hasPermission('administration.users.delete');\r\n const canExecute = hasPermission('administration.users.execute');\r\n\r\n // Tab state\r\n const getInitialTab = (): TabId => {\r\n const tabParam = searchParams.get('tab');\r\n if (tabParam && VALID_TABS.includes(tabParam as TabId)) {\r\n return tabParam as TabId;\r\n }\r\n return 'info';\r\n };\r\n const [activeTab, setActiveTab] = useState<TabId>(getInitialTab);\r\n\r\n // Use custom hooks for data management\r\n const userDetail = useUserDetail({ userId, tenantSlug: currentTenant?.slug ?? null });\r\n const {\r\n user,\r\n formData,\r\n setFormData,\r\n isCreateMode,\r\n loading,\r\n error,\r\n success,\r\n setError,\r\n setSuccess,\r\n roles,\r\n rolesLoading,\r\n sessions,\r\n activity,\r\n history,\r\n orgReferences,\r\n loadUser,\r\n loadRoles,\r\n loadOrgReferences,\r\n loadSessions,\r\n loadActivity,\r\n loadHistory,\r\n setHistory,\r\n handleSaveInfo,\r\n saving: infoSaving\r\n } = userDetail;\r\n\r\n // Security hook\r\n const security = useUserSecurity({\r\n userId,\r\n onUserReload: loadUser,\r\n onSessionsReload: loadSessions,\r\n setError,\r\n setSuccess\r\n });\r\n\r\n // Sections hook\r\n const sections = useUserSections({\r\n userId,\r\n user,\r\n onUserReload: loadUser,\r\n onHistoryReload: () => setHistory(null),\r\n setError,\r\n setSuccess\r\n });\r\n\r\n // Tenants hook\r\n const tenants = useUserTenants({\r\n userId,\r\n isCreateMode,\r\n setError,\r\n setSuccess\r\n });\r\n\r\n // History restore state\r\n const [restoringHistoryId, setRestoringHistoryId] = useState<string | null>(null);\r\n\r\n // Scope selection for roles/permissions tabs\r\n const [selectedScope, setSelectedScope] = useState<ScopeValue>('global');\r\n const [tenantMemberships, setTenantMemberships] = useState<Array<{\r\n tenantId: string;\r\n tenantSlug: string;\r\n tenantUserId: string;\r\n tenantName: string;\r\n tenantType?: string;\r\n }> | null>(null);\r\n const [membershipLoadError, setMembershipLoadError] = useState<string | null>(null);\r\n const [, setUserNotMemberOfCurrentTenant] = useState(false);\r\n\r\n // Consolidated roles state (all roles across all tenants with source info)\r\n const [consolidatedRoles, setConsolidatedRoles] = useState<UserConsolidatedRoleDto[] | null>(null);\r\n const [consolidatedRolesLoading, setConsolidatedRolesLoading] = useState(false);\r\n\r\n // Load tenant memberships\r\n const loadTenantMemberships = useCallback(async () => {\r\n if (!userId || isCreateMode) return;\r\n setMembershipLoadError(null);\r\n try {\r\n const userTenantsList = await adminApi.users.getTenants(userId);\r\n const memberships = userTenantsList.map((tenant) => ({\r\n tenantId: tenant.id,\r\n tenantSlug: tenant.slug,\r\n tenantUserId: userId,\r\n tenantName: tenant.name,\r\n tenantType: tenant.type,\r\n }));\r\n setTenantMemberships(memberships);\r\n } catch (err) {\r\n console.error('Failed to load tenant memberships:', err);\r\n setMembershipLoadError(t('userRoles.scope.loadError', 'Erreur lors du chargement des tenants'));\r\n setTenantMemberships([]);\r\n }\r\n }, [userId, isCreateMode, t]);\r\n\r\n // Load consolidated roles (all roles across all tenants with source info)\r\n const loadConsolidatedRoles = useCallback(async () => {\r\n if (!userId) return;\r\n setConsolidatedRolesLoading(true);\r\n try {\r\n const data = await adminApi.users.getConsolidatedRoles(userId);\r\n setConsolidatedRoles(data);\r\n } catch (err) {\r\n console.error('Failed to load consolidated roles:', err);\r\n setConsolidatedRoles([]);\r\n } finally {\r\n setConsolidatedRolesLoading(false);\r\n }\r\n }, [userId]);\r\n\r\n // Handle history restore\r\n const handleRestoreField = async (historyId: string) => {\r\n if (!userId) return;\r\n\r\n setRestoringHistoryId(historyId);\r\n setError(null);\r\n\r\n try {\r\n await adminApi.users.restoreFromHistory(userId, historyId);\r\n setSuccess(t('userDetail.history.restoreSuccess', 'Champ restauré avec succès'));\r\n loadHistory();\r\n loadUser();\r\n } catch (err) {\r\n console.error('Failed to restore field:', err);\r\n setError(t('userDetail.history.restoreError', 'Erreur lors de la restauration'));\r\n } finally {\r\n setRestoringHistoryId(null);\r\n }\r\n };\r\n\r\n // Reset scope when user changes\r\n useEffect(() => {\r\n setSelectedScope('global');\r\n setTenantMemberships(null);\r\n setConsolidatedRoles(null);\r\n }, [userId]);\r\n\r\n // Destructure stable references from tenants hook (avoid unstable object in deps)\r\n const tenantsUserData = tenants.userTenants;\r\n const loadUserTenants = tenants.loadTenants;\r\n\r\n const loadTabData = useCallback(() => {\r\n if (isCreateMode) return;\r\n if ((activeTab === 'info' || activeTab === 'roles') && !roles) loadRoles();\r\n if (activeTab === 'info' && !orgReferences) loadOrgReferences();\r\n if (activeTab === 'roles' && !consolidatedRoles) loadConsolidatedRoles();\r\n if (activeTab === 'activitySessions') {\r\n if (!sessions) loadSessions();\r\n if (!activity) loadActivity();\r\n }\r\n if (activeTab === 'tenants' && !tenantsUserData) loadUserTenants();\r\n if (activeTab === 'history' && !history) loadHistory();\r\n if ((activeTab === 'roles' || activeTab === 'permissions') && !tenantMemberships) {\r\n loadTenantMemberships();\r\n }\r\n }, [activeTab, isCreateMode, roles, orgReferences, sessions, activity, tenantsUserData, tenantMemberships, consolidatedRoles, history, loadRoles, loadOrgReferences, loadConsolidatedRoles, loadSessions, loadActivity, loadHistory, loadTenantMemberships, loadUserTenants]);\r\n\r\n useEffect(() => {\r\n loadTabData();\r\n }, [loadTabData]);\r\n\r\n // Sync selectedScope with currentTenant context\r\n useEffect(() => {\r\n if (!tenantMemberships) {\r\n setUserNotMemberOfCurrentTenant(false);\r\n return;\r\n }\r\n\r\n if (currentTenant) {\r\n const membership = tenantMemberships.find(m => m.tenantId === currentTenant.id);\r\n if (membership) {\r\n setSelectedScope({\r\n tenantId: membership.tenantId,\r\n tenantSlug: membership.tenantSlug,\r\n tenantUserId: membership.tenantUserId,\r\n tenantName: membership.tenantName,\r\n });\r\n setUserNotMemberOfCurrentTenant(false);\r\n } else {\r\n setSelectedScope('global');\r\n setUserNotMemberOfCurrentTenant(true);\r\n }\r\n } else {\r\n setSelectedScope('global');\r\n setUserNotMemberOfCurrentTenant(false);\r\n }\r\n }, [currentTenant, tenantMemberships]);\r\n\r\n // Sync URL with active tab\r\n useEffect(() => {\r\n const currentTab = searchParams.get('tab');\r\n if (currentTab !== activeTab) {\r\n setSearchParams({ tab: activeTab }, { replace: true });\r\n }\r\n }, [activeTab, searchParams, setSearchParams]);\r\n\r\n const tabs: { id: TabId; label: string; icon: React.ReactNode }[] = [\r\n { id: 'info', label: t('userDetail.tabs.info'), icon: <User className=\"w-4 h-4\" /> },\r\n { id: 'security', label: t('userDetail.tabs.security'), icon: <Key className=\"w-4 h-4\" /> },\r\n { id: 'activitySessions', label: t('userDetail.tabs.activitySessions', 'Activité'), icon: <Activity className=\"w-4 h-4\" /> },\r\n { id: 'roles', label: t('userDetail.tabs.roles'), icon: <Shield className=\"w-4 h-4\" /> },\r\n { id: 'permissions', label: t('userDetail.tabs.permissions'), icon: <Key className=\"w-4 h-4\" /> },\r\n { id: 'applications', label: t('userDetail.tabs.applications', 'Applications'), icon: <AppWindow className=\"w-4 h-4\" /> },\r\n { id: 'tenants', label: t('userDetail.tabs.tenants', 'Tenants'), icon: <Building2 className=\"w-4 h-4\" /> },\r\n { id: 'groups', label: t('userDetail.tabs.groups', 'Groupes'), icon: <Users className=\"w-4 h-4\" /> },\r\n { id: 'history', label: t('userDetail.tabs.history', 'Historique'), icon: <History className=\"w-4 h-4\" /> }\r\n ];\r\n\r\n if (loading) {\r\n return (\r\n <div className=\"flex items-center justify-center h-64\">\r\n <Loader2 className=\"w-8 h-8 animate-spin text-[var(--color-accent-500)]\" />\r\n </div>\r\n );\r\n }\r\n\r\n if (!user) {\r\n return (\r\n <div className=\"text-center py-12\">\r\n <p className=\"text-[var(--text-secondary)]\">{t('userDetail.notFound')}</p>\r\n <button\r\n onClick={() => navigate('/administration/users')}\r\n className=\"mt-4 px-4 py-2 rounded-[var(--radius-button)] bg-[var(--color-accent-600)] text-white\"\r\n >\r\n {t('userDetail.backToList')}\r\n </button>\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'), href: '/administration' },\r\n { label: t('users.title'), href: '/administration/users' },\r\n { label: user.fullName }\r\n ]}\r\n />\r\n\r\n {/* Header */}\r\n <div className=\"flex items-center gap-4\">\r\n <button\r\n onClick={() => navigate('/administration/users')}\r\n className=\"p-2 rounded-[var(--radius-button)] hover:bg-[var(--bg-hover)] transition-colors\"\r\n >\r\n <ArrowLeft className=\"w-5 h-5 text-[var(--text-secondary)]\" />\r\n </button>\r\n <div className=\"flex-1\">\r\n <h1 className=\"text-xl sm:text-2xl font-bold text-[var(--text-primary)]\">{user.fullName}</h1>\r\n <p className=\"text-sm sm:text-base text-[var(--text-secondary)]\">{user.email}</p>\r\n </div>\r\n <div className=\"flex items-center gap-2\">\r\n <span className={`px-3 py-1 rounded-[var(--radius-badge)] text-sm ${\r\n user.isActive\r\n ? 'bg-[var(--success-bg)] text-[var(--success-text)] border border-[var(--success-border)]'\r\n : 'bg-[var(--error-bg)] text-[var(--error-text)] border border-[var(--error-border)]'\r\n }`}>\r\n {user.isActive ? t('users.status.active') : t('users.status.inactive')}\r\n </span>\r\n <span className=\"px-3 py-1 rounded-[var(--radius-badge)] text-sm bg-[var(--bg-tertiary)] text-[var(--text-secondary)]\">\r\n {user.userType}\r\n </span>\r\n <Slot name=\"users.detail.header.actions\" context={{ user, reload: loadUser }} />\r\n </div>\r\n </div>\r\n\r\n {/* Alerts */}\r\n {error && (\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--error-bg)] border border-[var(--error-border)] text-[var(--error-text)] flex items-center gap-2\">\r\n <AlertTriangle className=\"w-5 h-5\" />\r\n {error}\r\n </div>\r\n )}\r\n {success && (\r\n <div className=\"p-4 rounded-[var(--radius-card)] bg-[var(--success-bg)] border border-[var(--success-border)] text-[var(--success-text)] flex items-center gap-2\">\r\n <CheckCircle className=\"w-5 h-5\" />\r\n {success}\r\n </div>\r\n )}\r\n\r\n {/* Tabs */}\r\n <div className=\"flex gap-1 p-1 overflow-x-auto bg-[var(--bg-secondary)] rounded-[var(--radius-card)] border border-[var(--border-color)]\">\r\n {tabs.map(tab => (\r\n <button\r\n key={tab.id}\r\n onClick={() => setActiveTab(tab.id)}\r\n className={`flex items-center gap-2 px-4 py-2 whitespace-nowrap rounded-[var(--radius-button)] font-medium transition-colors ${\r\n activeTab === tab.id\r\n ? 'bg-[var(--color-accent-600)] text-white'\r\n : 'text-[var(--text-secondary)] hover:bg-[var(--bg-hover)]'\r\n }`}\r\n >\r\n {tab.icon}\r\n {tab.label}\r\n </button>\r\n ))}\r\n <Slot name=\"users.detail.tabs\" context={{ user, activeTab, setActiveTab }} />\r\n </div>\r\n\r\n {/* Tab Content */}\r\n <div className=\"bg-[var(--bg-secondary)] rounded-[var(--radius-card)] border border-[var(--border-color)] p-4 sm:p-6\">\r\n {/* Info Tab */}\r\n {activeTab === 'info' && (\r\n <UserInfoTab\r\n user={user}\r\n formData={formData}\r\n setFormData={setFormData}\r\n handleSaveInfo={handleSaveInfo}\r\n saving={infoSaving || sections.saving}\r\n canUpdate={canUpdate}\r\n editingSection={sections.editingSection}\r\n sectionData={sections.sectionData}\r\n setSectionData={sections.setSectionData}\r\n startEditingSection={sections.startEditingSection}\r\n cancelEditing={sections.cancelEditing}\r\n handleSaveSection={sections.handleSaveSection}\r\n orgReferences={orgReferences}\r\n />\r\n )}\r\n\r\n {/* Security Tab */}\r\n {activeTab === 'security' && userId && (\r\n <UserSecurityTab\r\n user={user}\r\n userId={userId}\r\n canUpdate={canUpdate}\r\n canDelete={canDelete}\r\n canExecute={canExecute}\r\n newPassword={security.newPassword}\r\n setNewPassword={security.setNewPassword}\r\n temporaryPassword={security.temporaryPassword}\r\n showTemporaryPassword={security.showTemporaryPassword}\r\n setShowTemporaryPassword={security.setShowTemporaryPassword}\r\n saving={security.saving}\r\n showUnlockModal={security.showUnlockModal}\r\n setShowUnlockModal={security.setShowUnlockModal}\r\n handleSendResetLink={security.handleSendResetLink}\r\n handleResetPasswordDirect={security.handleResetPasswordDirect}\r\n handleToggleStatus={security.handleToggleStatus}\r\n handleEndAllSessions={security.handleEndAllSessions}\r\n handleUnlock={security.handleUnlock}\r\n handleClearFailedAttempts={security.handleClearFailedAttempts}\r\n copyToClipboard={security.copyToClipboard}\r\n setError={setError}\r\n />\r\n )}\r\n\r\n {/* Activity & Sessions Tab */}\r\n {activeTab === 'activitySessions' && (\r\n <UserActivitySessionsTab\r\n sessions={sessions}\r\n activity={activity}\r\n isCreateMode={isCreateMode}\r\n canUpdate={canUpdate}\r\n handleEndSession={security.handleEndSession}\r\n handleEndAllSessions={security.handleEndAllSessions}\r\n />\r\n )}\r\n\r\n {/* Membership load error */}\r\n {(activeTab === 'roles' || activeTab === 'permissions') && userId && membershipLoadError && (\r\n <div className=\"mb-4 flex items-center gap-2 p-3 rounded-lg bg-amber-500/10 border border-amber-500/30 text-amber-700\">\r\n <AlertTriangle className=\"w-4 h-4\" />\r\n <span className=\"text-sm\">{membershipLoadError}</span>\r\n </div>\r\n )}\r\n\r\n {/* Roles Tab */}\r\n {activeTab === 'roles' && userId && (\r\n <UserRoleAssignment\r\n userId={userId}\r\n assignedRoles={consolidatedRoles ?? []}\r\n onSave={async () => {\r\n await Promise.all([loadUser(true), loadConsolidatedRoles()]);\r\n }}\r\n onGlobalRolesUpdate={async (roleIds) => {\r\n const updateData: UpdateUserRequest = {\r\n firstName: formData.firstName,\r\n lastName: formData.lastName,\r\n roleIds,\r\n };\r\n await adminApi.users.update(userId, updateData);\r\n }}\r\n roles={roles ?? []}\r\n loading={rolesLoading || consolidatedRolesLoading}\r\n globalRoleIds={formData.roleIds}\r\n tenantId={selectedScope !== 'global' ? (selectedScope as Exclude<ScopeValue, 'global'>).tenantId : undefined}\r\n isGlobalScope={selectedScope === 'global'}\r\n adminTenants={adminTenantsList.map(tenant => ({\r\n tenantId: tenant.id,\r\n tenantSlug: tenant.slug,\r\n tenantName: tenant.name,\r\n tenantType: tenant.type,\r\n }))}\r\n tenantMemberships={(tenantMemberships ?? []).map(m => ({\r\n tenantId: m.tenantId,\r\n tenantSlug: m.tenantSlug,\r\n tenantUserId: m.tenantUserId,\r\n tenantName: m.tenantName,\r\n }))}\r\n />\r\n )}\r\n\r\n {/* Permissions Tab */}\r\n {activeTab === 'permissions' && userId && (\r\n <UserPermissionMatrix\r\n userId={userId}\r\n tenantId={selectedScope !== 'global' ? (selectedScope as Exclude<ScopeValue, 'global'>).tenantId : undefined}\r\n />\r\n )}\r\n\r\n {/* Applications Tab */}\r\n {activeTab === 'applications' && userId && (\r\n <UserApplicationsTab\r\n userId={userId}\r\n />\r\n )}\r\n\r\n {/* Groups Tab */}\r\n {activeTab === 'groups' && user && userId && (\r\n <UserGroupsTab\r\n userId={userId}\r\n userName={user.fullName}\r\n />\r\n )}\r\n\r\n {/* Tenants Tab */}\r\n {activeTab === 'tenants' && (\r\n <UserTenantsTab\r\n userTenants={tenants.userTenants}\r\n allTenants={tenants.allTenants}\r\n currentTenant={currentTenant}\r\n hasGlobalRoles={hasGlobalRoles}\r\n showAddTenantModal={tenants.showAddTenantModal}\r\n tenantSearch={tenants.tenantSearch}\r\n tenantsViewMode={tenants.tenantsViewMode}\r\n selectedTenantIds={tenants.selectedTenantIds}\r\n isAddingMultipleTenants={tenants.isAddingMultipleTenants}\r\n setShowAddTenantModal={tenants.setShowAddTenantModal}\r\n setTenantSearch={tenants.setTenantSearch}\r\n setTenantsViewMode={tenants.setTenantsViewMode}\r\n setUserTenants={tenants.setUserTenants}\r\n loadTenants={tenants.loadTenants}\r\n toggleTenantSelection={tenants.toggleTenantSelection}\r\n selectAllTenants={tenants.selectAllTenants}\r\n clearTenantSelection={tenants.clearTenantSelection}\r\n closeAddTenantModal={tenants.closeAddTenantModal}\r\n handleAddMultipleTenants={tenants.handleAddMultipleTenants}\r\n handleRemoveTenant={tenants.handleRemoveTenant}\r\n />\r\n )}\r\n\r\n {/* History Tab */}\r\n {activeTab === 'history' && (\r\n <UserHistoryTab\r\n history={history}\r\n loadHistory={loadHistory}\r\n handleRestoreField={handleRestoreField}\r\n restoringHistoryId={restoringHistoryId}\r\n canUpdate={canUpdate}\r\n />\r\n )}\r\n\r\n {/* Extension tab content */}\r\n <Slot name=\"users.detail.tabs.content\" context={{ user, activeTab, reload: loadUser }} />\r\n </div>\r\n </div>\r\n );\r\n}\r\n"],"names":["CATEGORY_STYLES","DEFAULT_CATEGORY_STYLE","SOURCE_STYLES","Globe","Users","Lock","UserRoleAssignment","userId","assignedRoles","onSave","onGlobalRolesUpdate","rolesProp","loading","globalRoleIds","tenantId","isGlobalScope","adminTenants","tenantMemberships","t","useTranslation","roles","searchQuery","setSearchQuery","useState","scopeFilter","setScopeFilter","removing","setRemoving","modalOpen","setModalOpen","error","setError","removingRef","useRef","tenantOptions","useMemo","m","a","b","filteredAssignedRoles","scoped","ar","query","roleMap","map","r","handleRemoveRole","useCallback","roleId","roleTenantId","membership","adminApi","newRoleIds","id","err","handleOpenModal","handleCloseModal","handleAssigned","jsxs","jsx","AlertCircle","X","Search","e","to","ChevronDown","Plus","Loader2","roleDetail","category","catStyle","customIcon","getCustomRoleIcon","isGlobal","isGroupSourced","sourceStyle","SourceIcon","removingKey","isRemoving","Link","Building2","Trash2","UserAssignRoleModal","_userId","initialTenantId","initialIsGlobalScope","onAssigned","onClose","filterCategory","setFilterCategory","filterContext","setFilterContext","filterApplication","setFilterApplication","saving","setSaving","savingRef","modalTenants","memberTenantIds","at","modalScope","setModalScope","tenant","modalIsGlobal","modalTenantId","currentScopeRoleIds","ids","tenantAppIds","setTenantAppIds","useEffect","cancelled","apps","scopedRoles","contexts","ctxMap","name","applications","appMap","handleContextChange","value","categories","cats","filteredRoles","filtered","handleAssignRole","TenantScopeSelector","Filter","ctx","app","c","cat","role","isAlreadyAssigned","isAssigning","getTenantNamesFromSourceRoles","sourceRoles","consolidatedRolesMap","globalLabel","tenantNames","cr","getSourceTypesFromConsolidatedRoles","sources","s","ACTION_ICONS","Shield","Eye","Edit","UserPlus","Play","ACTION_COLORS","UserPermissionMatrix","compact","navigate","useNavigate","user","userRoles","filteredResources","effectivePermissions","filters","modules","updateFilters","getPermissionSources","reloadData","isTenantMode","tenantMember","_assignTenantRoles","consolidatedRoles","useUserPermissions","collapsedApps","toggleApp","useCollapsibleState","collapsedModules","setCollapsedModules","collapsedSections","setCollapsedSections","statusFilters","setStatusFilters","openPopover","setOpenPopover","customRoleId","setCustomRoleId","customRolePermissions","setCustomRolePermissions","togglingPermission","setTogglingPermission","loadingCustomRole","setLoadingCustomRole","React","p","handleTogglePermission","permissionId","currentPermissions","newPermissions","handleCellClick","resourceId","toggleStatusFilter","status","prev","next","toggleModule","moduleId","toggleSection","sectionId","getAllPermissionsForResource","resource","allPermissions","section","getPermissionStatusForUser","isSection","calculatePermissionStatus","permId","grantedCount","totalCount","filterModulesByStatus","calculateModuleWithSectionsStatus","filterApplicationsByModules","applyUserStatusFilters","grouped","groupedResources","groupByApplicationWithSections","totalModuleCount","sum","addSourceRolesFromPermission","getSourceRolesForResource","perm","isCustomRole","roleName","getDisplayName","userAsRole","getUserPermissionInheritance","_roleId","isGranted","isFromCustomRole","inheritedRole","getUserResourceIcon","level","Database","FileText","Box","getUserResourceLabelClass","getUserPaddingClass","getSourceTypeLabelClass","type","getTenantTagClass","tenantName","renderSectionWithResources","sectionWithResources","moduleIndex","sectionIndex","resources","hasResources","isSectionCollapsed","renderResourceRow","resourceIndex","renderModuleWithSections","moduleWithSections","module","sections","hasSections","isModuleCollapsed","rowIndex","hasChildren","isCollapsed","cellBg","getPermissionCellBackground","isPopoverOpen","buttonRef","createRef","paddingLeft","ChevronRight","PermissionStatusIndicator","PermissionPopover","isCustom","displayName","Star","idx","source","UserCheck","User","isToggling","actionColor","icon","Fragment","mod","Check","Ban","Info","appGroup","appKey","isAppCollapsed","FolderOpen","ViewModeToggle","viewMode","onChange","LayoutGrid","Table2","UserGroupsTab","userName","userGroups","setUserGroups","allGroups","setAllGroups","setLoading","showAddModal","setShowAddModal","groupTypeFilter","setGroupTypeFilter","selectedGroupIds","setSelectedGroupIds","isAddingMultiple","setIsAddingMultiple","removingGroupId","setRemovingGroupId","success","setSuccess","setViewMode","loadUserGroups","data","loadAllGroups","groupsApi","handleRemoveFromGroup","groupId","group","g","errorMessage","filteredAvailableGroups","ug","toggleGroupSelection","newSet","getGroupTypeFilterClass","filter","currentFilter","getGroupCheckboxClass","isSelected","selectAllFiltered","clearSelection","handleAddMultipleGroups","groupIdsArray","closeModal","RefreshCw","AlertTriangle","CheckCircle","DataTable","Cloud","OTHER_VALUE","SelectWithOther","label","options","placeholder","disabled","className","allowOther","isOther","setIsOther","customInput","setCustomInput","handleSelectChange","selectedValue","handleCustomInputChange","newValue","handleCancelOther","selectValue","opt","formatDate","date","UserInfoTab","formData","setFormData","handleSaveInfo","canUpdate","editingSection","sectionData","setSectionData","startEditingSection","cancelEditing","handleSaveSection","orgReferences","Save","EditableSection","val","d","j","o","InfoField","Briefcase","Phone","formatPhoneNumber","MapPinIcon","AtSign","StatusBadge","Key","breakAll","title","sectionKey","onStartEdit","onCancel","children","Edit3","active","activeLabel","inactiveLabel","Mail","XCircle","UnlockAccountModal","isOpen","onConfirm","selectedReason","setSelectedReason","mustChangePassword","setMustChangePassword","handleConfirm","handleClose","bugInfo","issueUrl","Bug","UnlockReason","getButtonClasses","hasPermission","colorClass","getPrimaryButtonClasses","getWarningButtonClasses","getRedButtonClasses","getGreenButtonClasses","isActive","UserSecurityTab","canDelete","canExecute","newPassword","setNewPassword","temporaryPassword","showTemporaryPassword","setShowTemporaryPassword","showUnlockModal","setShowUnlockModal","handleSendResetLink","handleResetPasswordDirect","handleToggleStatus","handleEndAllSessions","handleUnlock","handleClearFailedAttempts","copyToClipboard","getAccountStatusText","getAccountStatusHint","handleDelete","EyeOff","Copy","UserX","LogOut","Unlock","formatDuration","duration","parts","hours","minutes","getStatCardColorClass","color","UserActivitySessionsTab","sessions","activity","isCreateMode","handleEndSession","Activity","ActivitySection","SessionsSection","StatCard","StatsCard","Smartphone","MapPin","Calendar","day","Monitor","ActiveSessionsList","SessionHistory","session","SessionCard","parseUserAgent","isText","items","labelKey","countSuffix","item","i","renderTenantsContent","filteredTenants","hasGlobalRoles","tenantsViewMode","currentTenant","handleRemoveTenant","setShowAddTenantModal","EmptyState","TenantTableView","TenantCardsView","LoadingState","renderTenantList","allTenants","availableTenants","selectedTenantIds","toggleTenantSelection","TenantSelectItem","UserTenantsTab","userTenants","showAddTenantModal","tenantSearch","isAddingMultipleTenants","setTenantSearch","setTenantsViewMode","setUserTenants","loadTenants","selectAllTenants","clearTenantSelection","closeAddTenantModal","handleAddMultipleTenants","handleRefresh","AddTenantModal","onAddClick","tenants","onRemove","onNavigate","columns","statusColors","getStatusDotColor","Link2","Crown","primaryTenant","otherTenants","TenantCard","canManage","userTenantIds","onToggle","UserHistoryTab","history","loadHistory","handleRestoreField","restoringHistoryId","getActionLabel","actionName","isRestorable","entry","getActionIcon","ShieldX","RotateCcw","History","UserApplicationsTab","setApplications","setTenants","selectedTenantId","setSelectedTenantId","tenantsLoading","setTenantsLoading","expandedApps","setExpandedApps","loadApplicationAccess","toggleExpand","appId","selectedTenantName","Boxes","ApplicationCard","isExpanded","icons","LucideIcons","AppIcon","permissionsByModule","groups","key","Layers","extractActionFromPath","path","isValidGuid","useUserDetail","tenantSlug","tenantApi","createAdminApi","setUser","setRoles","rolesLoading","setRolesLoading","setSessions","setActivity","setHistory","setOrgReferences","setAllTenants","loadUser","silent","userData","loadRoles","result","loadOrgReferences","loadSessions","loadActivity","loadAllTenants","updateData","useUserSecurity","onUserReload","onSessionsReload","setTemporaryPassword","customPassword","sessionId","reason","text","createInitialSectionData","useUserSections","onHistoryReload","setEditingSection","org","useUserTenants","setSelectedTenantIds","setIsAddingMultipleTenants","availableTenantIds","tenantIdsArray","VALID_TABS","UserDetailPage","useParams","searchParams","setSearchParams","useSearchParams","useTenant","adminTenantsList","useAdminTenants","useAuth","getInitialTab","tabParam","activeTab","setActiveTab","userDetail","infoSaving","security","setRestoringHistoryId","selectedScope","setSelectedScope","setTenantMemberships","membershipLoadError","setMembershipLoadError","setUserNotMemberOfCurrentTenant","setConsolidatedRoles","consolidatedRolesLoading","setConsolidatedRolesLoading","loadTenantMemberships","memberships","loadConsolidatedRoles","historyId","tenantsUserData","loadUserTenants","loadTabData","tabs","AppWindow","Breadcrumb","ArrowLeft","Slot","tab","roleIds"],"mappings":"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"}
|