diff --git a/frontend/src/component/personalDashboard/Grid.tsx b/frontend/src/component/personalDashboard/Grid.tsx new file mode 100644 index 000000000000..de1ce152ecc9 --- /dev/null +++ b/frontend/src/component/personalDashboard/Grid.tsx @@ -0,0 +1,31 @@ +import { Box, Grid, styled } from '@mui/material'; +import type { Theme } from '@mui/material/styles/createTheme'; + +export const ContentGrid = styled(Grid)(({ theme }) => ({ + backgroundColor: theme.palette.background.paper, + borderRadius: `${theme.shape.borderRadiusLarge}px`, +})); + +export const SpacedGridItem = styled(Grid)(({ theme }) => ({ + padding: theme.spacing(4), + border: `0.5px solid ${theme.palette.divider}`, +})); + +export const ListItemBox = styled(Box)(({ theme }) => ({ + display: 'flex', + gap: theme.spacing(2), + alignItems: 'center', + width: '100%', +})); + +export const listItemStyle = (theme: Theme) => ({ + borderRadius: theme.spacing(0.5), + borderLeft: `${theme.spacing(0.5)} solid transparent`, + '&.Mui-selected': { + borderLeft: `${theme.spacing(0.5)} solid ${theme.palette.primary.main}`, + }, + display: 'flex', + flexDirection: 'column', + alignItems: 'flex-start', + gap: theme.spacing(1), +}); diff --git a/frontend/src/component/personalDashboard/MyProjects.tsx b/frontend/src/component/personalDashboard/MyProjects.tsx new file mode 100644 index 000000000000..629ebe4941a7 --- /dev/null +++ b/frontend/src/component/personalDashboard/MyProjects.tsx @@ -0,0 +1,175 @@ +import { + Box, + IconButton, + Link, + List, + ListItem, + ListItemButton, + Typography, +} from '@mui/material'; +import { Badge } from '../common/Badge/Badge'; +import { ProjectIcon } from '../common/ProjectIcon/ProjectIcon'; +import LinkIcon from '@mui/icons-material/Link'; +import { ProjectSetupComplete } from './ProjectSetupComplete'; +import { ConnectSDK, CreateFlag, ExistingFlag } from './ConnectSDK'; +import { LatestProjectEvents } from './LatestProjectEvents'; +import { RoleAndOwnerInfo } from './RoleAndOwnerInfo'; +import type { FC } from 'react'; +import { StyledCardTitle } from './PersonalDashboard'; +import type { + PersonalDashboardProjectDetailsSchema, + PersonalDashboardSchemaProjectsItem, +} from '../../openapi'; +import { + ContentGrid, + ListItemBox, + listItemStyle, + SpacedGridItem, +} from './Grid'; + +const ActiveProjectDetails: FC<{ + project: PersonalDashboardSchemaProjectsItem; +}> = ({ project }) => { + return ( + + + + {project.featureCount} + + + flags + + + + + {project.memberCount} + + + members + + + + + {project.health}% + + + health + + + + ); +}; + +export const MyProjects: FC<{ + projects: PersonalDashboardSchemaProjectsItem[]; + personalDashboardProjectDetails?: PersonalDashboardProjectDetailsSchema; + activeProject: string; + setActiveProject: (project: string) => void; +}> = ({ + projects, + personalDashboardProjectDetails, + setActiveProject, + activeProject, +}) => { + const activeProjectStage = + personalDashboardProjectDetails?.onboardingStatus.status ?? 'loading'; + const setupIncomplete = + activeProjectStage === 'onboarding-started' || + activeProjectStage === 'first-flag-created'; + + return ( + + + My projects + + + {setupIncomplete ? ( + Setup incomplete + ) : null} + + + + {projects.map((project) => { + return ( + + setActiveProject(project.id)} + > + + + + {project.name} + + + + + + {project.id === activeProject ? ( + + ) : null} + + + ); + })} + + + + {activeProjectStage === 'onboarded' ? ( + + ) : null} + {activeProjectStage === 'onboarding-started' || + activeProjectStage === 'loading' ? ( + + ) : null} + {activeProjectStage === 'first-flag-created' ? ( + + ) : null} + + + {activeProjectStage === 'onboarded' && + personalDashboardProjectDetails ? ( + + ) : null} + {setupIncomplete || activeProjectStage === 'loading' ? ( + + ) : null} + + + + {activeProject ? ( + + ) : null} + + + ); +}; diff --git a/frontend/src/component/personalDashboard/PersonalDashboard.tsx b/frontend/src/component/personalDashboard/PersonalDashboard.tsx index 2989672b22a3..f3d8416a52fd 100644 --- a/frontend/src/component/personalDashboard/PersonalDashboard.tsx +++ b/frontend/src/component/personalDashboard/PersonalDashboard.tsx @@ -1,7 +1,5 @@ import { useAuthUser } from 'hooks/api/getters/useAuth/useAuthUser'; import { - Box, - Grid, IconButton, Link, List, @@ -10,15 +8,10 @@ import { styled, Typography, } from '@mui/material'; -import type { Theme } from '@mui/material/styles/createTheme'; -import { ProjectIcon } from 'component/common/ProjectIcon/ProjectIcon'; import React, { type FC, useEffect, useState } from 'react'; import LinkIcon from '@mui/icons-material/Link'; -import { Badge } from '../common/Badge/Badge'; -import { ConnectSDK, CreateFlag, ExistingFlag } from './ConnectSDK'; import { WelcomeDialog } from './WelcomeDialog'; import { useLocalStorageState } from 'hooks/useLocalStorageState'; -import { ProjectSetupComplete } from './ProjectSetupComplete'; import { usePersonalDashboard } from 'hooks/api/getters/usePersonalDashboard/usePersonalDashboard'; import { getFeatureTypeIcons } from 'utils/getFeatureTypeIcons'; import type { @@ -26,12 +19,17 @@ import type { PersonalDashboardSchemaProjectsItem, } from '../../openapi'; import { FlagExposure } from 'component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FlagExposure'; -import { RoleAndOwnerInfo } from './RoleAndOwnerInfo'; -import { ContentGridNoProjects } from './ContentGridNoProjects'; -import { LatestProjectEvents } from './LatestProjectEvents'; import { usePersonalDashboardProjectDetails } from 'hooks/api/getters/usePersonalDashboard/usePersonalDashboardProjectDetails'; import HelpOutline from '@mui/icons-material/HelpOutline'; import useLoading from '../../hooks/useLoading'; +import { MyProjects } from './MyProjects'; +import { + ContentGrid, + ListItemBox, + listItemStyle, + SpacedGridItem, +} from './Grid'; +import { ContentGridNoProjects } from './ContentGridNoProjects'; const ScreenExplanation = styled('div')(({ theme }) => ({ marginBottom: theme.spacing(4), @@ -39,30 +37,6 @@ const ScreenExplanation = styled('div')(({ theme }) => ({ alignItems: 'center', })); -const ContentGrid = styled(Grid)(({ theme }) => ({ - backgroundColor: theme.palette.background.paper, - borderRadius: `${theme.shape.borderRadiusLarge}px`, -})); - -const ProjectBox = styled(Box)(({ theme }) => ({ - display: 'flex', - gap: theme.spacing(2), - alignItems: 'center', - width: '100%', -})); - -const projectStyle = (theme: Theme) => ({ - borderRadius: theme.spacing(0.5), - borderLeft: `${theme.spacing(0.5)} solid transparent`, - '&.Mui-selected': { - borderLeft: `${theme.spacing(0.5)} solid ${theme.palette.primary.main}`, - }, - display: 'flex', - flexDirection: 'column', - alignItems: 'flex-start', - gap: theme.spacing(1), -}); - export const StyledCardTitle = styled('div')<{ lines?: number }>( ({ theme, lines = 2 }) => ({ fontWeight: theme.typography.fontWeightRegular, @@ -80,56 +54,6 @@ export const StyledCardTitle = styled('div')<{ lines?: number }>( }), ); -const ActiveProjectDetails: FC<{ - project: PersonalDashboardSchemaProjectsItem; -}> = ({ project }) => { - return ( - - - - {project.featureCount} - - - flags - - - - - {project.memberCount} - - - members - - - - - {project.health}% - - - health - - - - ); -}; - -const SpacedGridItem = styled(Grid)(({ theme }) => ({ - padding: theme.spacing(4), - border: `0.5px solid ${theme.palette.divider}`, -})); - -const useProjects = (projects: PersonalDashboardSchemaProjectsItem[]) => { - const [activeProject, setActiveProject] = useState(projects[0]?.id); - - useEffect(() => { - if (!activeProject && projects.length > 0) { - setActiveProject(projects[0].id); - } - }, [JSON.stringify(projects)]); - - return { projects, activeProject, setActiveProject }; -}; - const FlagListItem: FC<{ flag: { name: string; project: string; type: string }; selected: boolean; @@ -139,11 +63,11 @@ const FlagListItem: FC<{ return ( - + {flag.name} - + ); }; +const useActiveProject = (projects: PersonalDashboardSchemaProjectsItem[]) => { + const [activeProject, setActiveProject] = useState(projects[0]?.id); + + useEffect(() => { + if (!activeProject && projects.length > 0) { + setActiveProject(projects[0].id); + } + }, [JSON.stringify(projects)]); + + return [activeProject, setActiveProject] as const; +}; + export const PersonalDashboard = () => { const { user } = useAuthUser(); @@ -181,32 +117,25 @@ export const PersonalDashboard = () => { } }, [JSON.stringify(personalDashboard?.flags)]); - const { projects, activeProject, setActiveProject } = useProjects( - personalDashboard?.projects || [], - ); + const [welcomeDialog, setWelcomeDialog] = useLocalStorageState< + 'open' | 'closed' + >('welcome-dialog:v1', 'open'); + + const projects = personalDashboard?.projects || []; + const [activeProject, setActiveProject] = useActiveProject(projects); const { personalDashboardProjectDetails, loading: loadingDetails } = usePersonalDashboardProjectDetails(activeProject); - const stage = + const activeProjectStage = personalDashboardProjectDetails?.onboardingStatus.status ?? 'loading'; - - const [welcomeDialog, setWelcomeDialog] = useLocalStorageState< - 'open' | 'closed' - >('welcome-dialog:v1', 'open'); + const setupIncomplete = + activeProjectStage === 'onboarding-started' || + activeProjectStage === 'first-flag-created'; const noProjects = projects.length === 0; - const setupIncomplete = - personalDashboardProjectDetails?.onboardingStatus.status === - 'onboarding-started' || - personalDashboardProjectDetails?.onboardingStatus.status === - 'first-flag-created'; - const onboarded = - personalDashboardProjectDetails?.onboardingStatus.status === - 'onboarded'; - - const projectStageRef = useLoading(stage === 'loading'); + const projectStageRef = useLoading(activeProjectStage === 'loading'); return (
@@ -215,13 +144,13 @@ export const PersonalDashboard = () => {

- {onboarded + {activeProjectStage === 'onboarded' ? 'We have gathered projects and flags you have favorited or owned' : null} {setupIncomplete ? 'Here are some tasks we think would be useful in order to get the most out of Unleash' : null} - {stage === 'loading' + {activeProjectStage === 'loading' ? 'We have gathered projects and flags you have favorited or owned' : null}

@@ -241,104 +170,16 @@ export const PersonalDashboard = () => { admins={personalDashboard.admins} /> ) : ( - - - My projects - - - {setupIncomplete ? ( - Setup incomplete - ) : null} - - - - {projects.map((project) => { - return ( - - - setActiveProject(project.id) - } - > - - - - {project.name} - - - - - - {project.id === activeProject ? ( - - ) : null} - - - ); - })} - - - - {stage === 'onboarded' ? ( - - ) : null} - {stage === 'onboarding-started' || - stage === 'loading' ? ( - - ) : null} - {stage === 'first-flag-created' ? ( - - ) : null} - - - {stage === 'onboarded' && - personalDashboardProjectDetails ? ( - - ) : null} - {setupIncomplete || stage === 'loading' ? ( - - ) : null} - - - - {activeProject ? ( - - ) : null} - - + )} + My feature flags