mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	feat: project members widget (#6628)

This commit is contained in:
		
							parent
							
								
									f0e5d075a7
								
							
						
					
					
						commit
						1becfc0202
					
				| @ -13,6 +13,9 @@ interface IProjectMembersWidgetProps { | ||||
|     change?: number; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * @deprecated in favor of ProjectMembers.tsx | ||||
|  */ | ||||
| export const ProjectMembersWidget = ({ | ||||
|     projectId, | ||||
|     memberCount, | ||||
|  | ||||
| @ -7,6 +7,7 @@ import { ProjectInsightsStats } from './ProjectInsightsStats/ProjectInsightsStat | ||||
| import { useRequiredPathParam } from 'hooks/useRequiredPathParam'; | ||||
| import { useProjectInsights } from 'hooks/api/getters/useProjectInsights/useProjectInsights'; | ||||
| import useLoading from 'hooks/useLoading'; | ||||
| import { ProjectMembers } from './ProjectMembers/ProjectMembers'; | ||||
| 
 | ||||
| const Container = styled(Box)(({ theme }) => ({ | ||||
|     backgroundColor: theme.palette.background.paper, | ||||
| @ -56,7 +57,9 @@ export const ProjectInsights = () => { | ||||
|             <NarrowContainer> | ||||
|                 <FlagTypesUsed featureTypeCounts={data.featureTypeCounts} /> | ||||
|             </NarrowContainer> | ||||
|             <NarrowContainer>Project members</NarrowContainer> | ||||
|             <NarrowContainer> | ||||
|                 <ProjectMembers projectId={projectId} members={data.members} /> | ||||
|             </NarrowContainer> | ||||
|             <WideContainer> | ||||
|                 {data.changeRequests && ( | ||||
|                     <ChangeRequests changeRequests={data.changeRequests} /> | ||||
|  | ||||
| @ -0,0 +1,18 @@ | ||||
| import { screen } from '@testing-library/react'; | ||||
| import { render } from 'utils/testRenderer'; | ||||
| import { ProjectMembers } from './ProjectMembers'; | ||||
| 
 | ||||
| test('Show outdated project members', async () => { | ||||
|     const members = { | ||||
|         active: 10, | ||||
|         totalPreviousMonth: 2, | ||||
|         inactive: 5, | ||||
|     }; | ||||
| 
 | ||||
|     render(<ProjectMembers projectId={'default'} members={members} />); | ||||
| 
 | ||||
|     await screen.findByText('15'); | ||||
|     await screen.findByText('+13'); | ||||
|     await screen.findByText('10'); | ||||
|     await screen.findByText('5'); | ||||
| }); | ||||
| @ -0,0 +1,149 @@ | ||||
| import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; | ||||
| import { Box, styled, Typography, useTheme } from '@mui/material'; | ||||
| import { StatusBox } from '../ProjectInsightsStats/StatusBox'; | ||||
| import KeyboardArrowRight from '@mui/icons-material/KeyboardArrowRight'; | ||||
| import { Link } from 'react-router-dom'; | ||||
| import type { ProjectInsightsSchemaMembers } from '../../../../../openapi'; | ||||
| 
 | ||||
| interface IProjectMembersProps { | ||||
|     members: ProjectInsightsSchemaMembers; | ||||
|     projectId: string; | ||||
| } | ||||
| 
 | ||||
| const NavigationBar = styled(Link)(({ theme }) => ({ | ||||
|     display: 'flex', | ||||
|     justifyContent: 'space-between', | ||||
|     textDecoration: 'none', | ||||
|     color: theme.palette.text.primary, | ||||
| })); | ||||
| 
 | ||||
| export const StyledProjectInfoWidgetContainer = styled('div')(({ theme }) => ({ | ||||
|     display: 'flex', | ||||
|     flexDirection: 'column', | ||||
|     gap: theme.spacing(2.5), | ||||
| })); | ||||
| 
 | ||||
| export const BarContainer = styled('div')(({ theme }) => ({ | ||||
|     width: '100%', | ||||
|     height: '20px', | ||||
|     display: 'flex', | ||||
| })); | ||||
| 
 | ||||
| const ActiveBar = styled('span', { | ||||
|     shouldForwardProp: (prop) => prop !== 'percentage', | ||||
| })<{ | ||||
|     percentage: number; | ||||
| }>(({ theme, percentage }) => ({ | ||||
|     width: `${percentage - 1}%`, | ||||
|     backgroundColor: theme.palette.success.border, | ||||
|     borderRadius: theme.shape.borderRadius, | ||||
| })); | ||||
| 
 | ||||
| const InactiveBar = styled('span', { | ||||
|     shouldForwardProp: (prop) => prop !== 'percentage', | ||||
| })<{ | ||||
|     percentage: number; | ||||
| }>(({ theme, percentage }) => ({ | ||||
|     width: `${percentage - 1}%`, | ||||
|     backgroundColor: theme.palette.warning.border, | ||||
|     marginLeft: 'auto', | ||||
|     borderRadius: theme.shape.borderRadius, | ||||
| })); | ||||
| 
 | ||||
| export const CountContainer = styled('div')(({ theme }) => ({ | ||||
|     display: 'flex', | ||||
|     flexDirection: 'column', | ||||
|     gap: theme.spacing(1.5), | ||||
| })); | ||||
| 
 | ||||
| export const CountRow = styled(NavigationBar)(({ theme }) => ({ | ||||
|     display: 'flex', | ||||
|     padding: theme.spacing(0.5, 1, 0, 2), | ||||
|     alignItems: 'center', | ||||
|     gap: theme.spacing(3), | ||||
|     alignSelf: 'stretch', | ||||
|     borderRadius: theme.shape.borderRadiusMedium, | ||||
|     background: '#F7F7FA', | ||||
| })); | ||||
| 
 | ||||
| const StatusWithDot = styled(Box)(({ theme }) => ({ | ||||
|     display: 'flex', | ||||
|     alignItems: 'center', | ||||
|     gap: theme.spacing(1), | ||||
| })); | ||||
| 
 | ||||
| const Dot = styled('span', { | ||||
|     shouldForwardProp: (prop) => prop !== 'color', | ||||
| })<{ | ||||
|     color?: string; | ||||
| }>(({ theme, color }) => ({ | ||||
|     height: '15px', | ||||
|     width: '15px', | ||||
|     borderRadius: '50%', | ||||
|     display: 'inline-block', | ||||
|     backgroundColor: color, | ||||
| })); | ||||
| 
 | ||||
| export const StyledCount = styled('span')(({ theme }) => ({ | ||||
|     fontSize: theme.typography.h1.fontSize, | ||||
|     fontWeight: theme.typography.fontWeightRegular, | ||||
|     color: theme.palette.text.primary, | ||||
| })); | ||||
| 
 | ||||
| export const ProjectMembers = ({ | ||||
|     members, | ||||
|     projectId, | ||||
| }: IProjectMembersProps) => { | ||||
|     const { uiConfig } = useUiConfig(); | ||||
|     const theme = useTheme(); | ||||
| 
 | ||||
|     const link = uiConfig?.versionInfo?.current?.enterprise | ||||
|         ? `/projects/${projectId}/settings/access` | ||||
|         : `/admin/users`; | ||||
| 
 | ||||
|     const { active, totalPreviousMonth, inactive } = members; | ||||
| 
 | ||||
|     const currentMembers = active + inactive; | ||||
|     const change = currentMembers - (totalPreviousMonth || 0); | ||||
| 
 | ||||
|     const activePercentage = (active / currentMembers) * 100; | ||||
|     const inactivePercentage = (inactive / currentMembers) * 100; | ||||
| 
 | ||||
|     return ( | ||||
|         <StyledProjectInfoWidgetContainer> | ||||
|             <NavigationBar to={link}> | ||||
|                 <Typography variant='h3'>Project members</Typography> | ||||
|                 <KeyboardArrowRight /> | ||||
|             </NavigationBar> | ||||
|             <Box | ||||
|                 sx={{ | ||||
|                     display: 'flex', | ||||
|                 }} | ||||
|             > | ||||
|                 <StatusBox boxText={`${currentMembers}`} change={change} /> | ||||
|             </Box> | ||||
|             <BarContainer> | ||||
|                 <ActiveBar percentage={activePercentage} /> | ||||
|                 <InactiveBar percentage={inactivePercentage} /> | ||||
|             </BarContainer> | ||||
|             <CountContainer> | ||||
|                 <CountRow to={link}> | ||||
|                     <StatusWithDot> | ||||
|                         <Dot color={theme.palette.success.border} /> | ||||
|                         <Box>Active</Box> | ||||
|                         <StyledCount>{active}</StyledCount> | ||||
|                     </StatusWithDot> | ||||
|                     <KeyboardArrowRight /> | ||||
|                 </CountRow> | ||||
|                 <CountRow to={link}> | ||||
|                     <StatusWithDot> | ||||
|                         <Dot color={theme.palette.warning.border} /> | ||||
|                         <Box>Inactive</Box> | ||||
|                         <StyledCount>{inactive}</StyledCount> | ||||
|                     </StatusWithDot> | ||||
|                     <KeyboardArrowRight /> | ||||
|                 </CountRow> | ||||
|             </CountContainer> | ||||
|         </StyledProjectInfoWidgetContainer> | ||||
|     ); | ||||
| }; | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user