diff --git a/frontend/src/component/personalDashboard/MyProjects.tsx b/frontend/src/component/personalDashboard/MyProjects.tsx index 06e9fd898c88..ec8b73cd22d2 100644 --- a/frontend/src/component/personalDashboard/MyProjects.tsx +++ b/frontend/src/component/personalDashboard/MyProjects.tsx @@ -1,9 +1,11 @@ +import type { RemoteData } from './RemoteData'; import { Box, IconButton, ListItem, ListItemButton, Typography, + styled, } from '@mui/material'; import { ProjectIcon } from '../common/ProjectIcon/ProjectIcon'; import LinkIcon from '@mui/icons-material/ArrowForward'; @@ -33,8 +35,7 @@ import { ContactAdmins, DataError } from './ProjectDetailsError'; import { usePlausibleTracker } from 'hooks/usePlausibleTracker'; import { Link } from 'react-router-dom'; import { ActionBox } from './ActionBox'; -import { NoProjectsContactAdmin } from './NoProjectsContactAdmin'; -import { AskOwnerToAddYouToTheirProject } from './AskOwnerToAddYouToTheirProject'; +import useLoading from 'hooks/useLoading'; const ActiveProjectDetails: FC<{ project: PersonalDashboardSchemaProjectsItem; @@ -69,6 +70,10 @@ const ActiveProjectDetails: FC<{ ); }; +const SkeletonDiv = styled('div')({ + height: '80%', +}); + const ProjectListItem: FC<{ project: PersonalDashboardSchemaProjectsItem; selected: boolean; @@ -122,16 +127,11 @@ const ProjectListItem: FC<{ ); }; -type MyProjectsState = - | 'no projects' - | 'projects' - | 'projects with error or loading'; - export const MyProjects = forwardRef< HTMLDivElement, { projects: PersonalDashboardSchemaProjectsItem[]; - personalDashboardProjectDetails?: PersonalDashboardProjectDetailsSchema; + personalDashboardProjectDetails: RemoteData; activeProject: string; setActiveProject: (project: string) => void; admins: PersonalDashboardSchemaAdminsItem[]; @@ -147,149 +147,103 @@ export const MyProjects = forwardRef< admins, owners, }, - ref, + // ref, ) => { - const state: MyProjectsState = projects.length - ? personalDashboardProjectDetails - ? 'projects' - : 'projects with error or loading' - : 'no projects'; + const ref = useLoading( + personalDashboardProjectDetails.state === 'loading', + ); - const activeProjectStage = - personalDashboardProjectDetails?.onboardingStatus.status ?? - 'loading'; - const setupIncomplete = - activeProjectStage === 'onboarding-started' || - activeProjectStage === 'first-flag-created'; + // const state: MyProjectsState = projects.length + // ? personalDashboardProjectDetails + // ? 'projects' + // : 'projects with error or loading' + // : 'no projects'; const getGridContents = (): { list: ReactNode; box1: ReactNode; box2: ReactNode; } => { - switch (state) { - case 'no projects': - return { - list: ( - - - You don't currently have access to any - projects in the system. - - - To get started, you can{' '} - - create your own project - - . Alternatively, you can review the - available projects in the system and ask the - owner for access. - - - ), - box1: , - box2: ( - - ), - }; + const list = projects.length ? ( + + {projects.map((project) => ( + setActiveProject(project.id)} + /> + ))} + + ) : ( + + + You don't currently have access to any projects in the + system. + + + To get started, you can{' '} + + create your own project + + . Alternatively, you can review the available projects + in the system and ask the owner for access. + + + ); - case 'projects with error or loading': - return { - list: ( - - {projects.map((project) => ( - - setActiveProject(project.id) - } - /> - ))} - - ), - box1: ( -
- -
- ), - box2: ( -
- -
- ), - }; + const [box1, box2] = (() => { + switch (personalDashboardProjectDetails.state) { + case 'success': { + const activeProjectStage = + personalDashboardProjectDetails.data + .onboardingStatus.status ?? 'loading'; + const setupIncomplete = + activeProjectStage === 'onboarding-started' || + activeProjectStage === 'first-flag-created'; - case 'projects': { - const box1 = (() => { - if ( - activeProjectStage === 'onboarded' && - personalDashboardProjectDetails - ) { - return ( + if (activeProjectStage === 'onboarded') { + return [ - ); - } else if ( - activeProjectStage === 'onboarding-started' || - activeProjectStage === 'loading' - ) { - return ; - } else if ( - activeProjectStage === 'first-flag-created' - ) { - return ; - } - })(); - - const box2 = (() => { - if ( - activeProjectStage === 'onboarded' && - personalDashboardProjectDetails - ) { - return ( + />, - ); - } else if ( - setupIncomplete || - activeProjectStage === 'loading' - ) { - return ; + />, + ]; + } else if (setupIncomplete) { + return [ + , + , + ]; + } else { + return [ + , + , + ]; } - })(); - - return { - list: ( - - {projects.map((project) => ( - - setActiveProject(project.id) - } - /> - ))} - - ), - box1, - box2, - }; + } + case 'error': + return [ + , + , + ]; + default: // loading + return [ + , + , + ]; } - } + })(); + + return { list, box1, box2 }; }; const { list, box1, box2 } = getGridContents(); @@ -303,14 +257,19 @@ export const MyProjects = forwardRef< role.name, - ) ?? [] + personalDashboardProjectDetails.state === + 'success' + ? personalDashboardProjectDetails.data.roles.map( + (role) => role.name, + ) + : [] } owners={ - personalDashboardProjectDetails?.owners ?? [ - { ownerType: 'user', name: '?' }, - ] + personalDashboardProjectDetails.state === + 'success' + ? personalDashboardProjectDetails.data + .owners + : [{ ownerType: 'user', name: '?' }] } /> diff --git a/frontend/src/component/personalDashboard/PersonalDashboard.tsx b/frontend/src/component/personalDashboard/PersonalDashboard.tsx index a90bd95987e2..6de3aa0f19d7 100644 --- a/frontend/src/component/personalDashboard/PersonalDashboard.tsx +++ b/frontend/src/component/personalDashboard/PersonalDashboard.tsx @@ -20,6 +20,7 @@ import { useAuthSplash } from 'hooks/api/getters/useAuth/useAuthSplash'; import { useDashboardState } from './useDashboardState'; import { MyFlags } from './MyFlags'; import { usePageTitle } from 'hooks/usePageTitle'; +import { fromPersonalDashboardProjectDetailsOutput } from './RemoteData'; const WelcomeSection = styled('div')(({ theme }) => ({ display: 'flex', @@ -130,10 +131,14 @@ export const PersonalDashboard = () => { splash?.personalDashboardKeyConcepts ? 'closed' : 'open', ); - const { personalDashboardProjectDetails, loading: detailsLoading } = - usePersonalDashboardProjectDetails(activeProject); + const personalDashboardProjectDetails = + fromPersonalDashboardProjectDetailsOutput( + usePersonalDashboardProjectDetails(activeProject), + ); - const loadingProjectDetailsRef = useLoading(detailsLoading); + const loadingProjectDetailsRef = useLoading( + personalDashboardProjectDetails.state === 'loading', + ); return ( diff --git a/frontend/src/component/personalDashboard/RemoteData.ts b/frontend/src/component/personalDashboard/RemoteData.ts new file mode 100644 index 000000000000..1f79b0c778b5 --- /dev/null +++ b/frontend/src/component/personalDashboard/RemoteData.ts @@ -0,0 +1,29 @@ +import type { IPersonalDashboardProjectDetailsOutput } from 'hooks/api/getters/usePersonalDashboard/usePersonalDashboardProjectDetails'; +import type { PersonalDashboardProjectDetailsSchema } from 'openapi'; + +type RemoteData = { refetch: () => void } & ( + | { state: 'error'; error: Error } + | { state: 'loading' } + | { state: 'success'; data: T } +); + +export const fromPersonalDashboardProjectDetailsOutput = ({ + personalDashboardProjectDetails, + error, +}: IPersonalDashboardProjectDetailsOutput): RemoteData => { + const converted = error + ? { + state: 'error', + error, + } + : personalDashboardProjectDetails + ? { + state: 'success', + data: personalDashboardProjectDetails, + } + : { + state: 'loading' as const, + }; + + return converted as RemoteData; +};