From 1ed08df198fca7a3f9cc3d355d192c0daf5f35ba Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Thu, 24 Jul 2025 07:20:43 +0200 Subject: [PATCH] refactor: extract project info data to hook --- apps/client/src/AppRouter.tsx | 1 + .../src/views/project-info/ProjectInfo.tsx | 61 ++++++++++--------- .../views/project-info/useProjectInfoData.ts | 26 ++++++++ 3 files changed, 58 insertions(+), 30 deletions(-) create mode 100644 apps/client/src/views/project-info/useProjectInfoData.ts diff --git a/apps/client/src/AppRouter.tsx b/apps/client/src/AppRouter.tsx index 16f28f510..a2e39d87b 100644 --- a/apps/client/src/AppRouter.tsx +++ b/apps/client/src/AppRouter.tsx @@ -87,6 +87,7 @@ export default function AppRouter() { path='info' element={ + } diff --git a/apps/client/src/views/project-info/ProjectInfo.tsx b/apps/client/src/views/project-info/ProjectInfo.tsx index bdedb7429..0ceab40c6 100644 --- a/apps/client/src/views/project-info/ProjectInfo.tsx +++ b/apps/client/src/views/project-info/ProjectInfo.tsx @@ -1,44 +1,46 @@ import { IoOpenOutline } from 'react-icons/io5'; import { OntimeView } from 'ontime-types'; -import ViewNavigationMenu from '../../common/components/navigation-menu/ViewNavigationMenu'; import EmptyPage from '../../common/components/state/EmptyPage'; import ViewLogo from '../../common/components/view-logo/ViewLogo'; import ViewParamsEditor from '../../common/components/view-params-editor/ViewParamsEditor'; import { useWindowTitle } from '../../common/hooks/useWindowTitle'; -import useProjectData from '../../common/hooks-query/useProjectData'; -import { useViewOptionsStore } from '../../common/stores/viewOptions'; import { useTranslation } from '../../translation/TranslationProvider'; +import Loader from '../common/loader/Loader'; + +import { ProjectInfoData, useProjectInfoData } from './useProjectInfoData'; import './ProjectInfo.scss'; -export default function ProjectInfo() { - // persisted app state - const isMirrored = useViewOptionsStore((state) => state.mirror); - const { data, status } = useProjectData(); - const { getLocalizedString } = useTranslation(); +export default function ProjectInfoLoader() { + const { data, status } = useProjectInfoData(); useWindowTitle('Project info'); - if (status === 'pending' || !data) { - return ( - <> - - - ; - - ); + if (status === 'pending') { + return ; } + if (status === 'error') { + return ; + } + + return ; +} + +function ProjectInfo({ projectData, isMirrored }: ProjectInfoData) { + const { getLocalizedString } = useTranslation(); + /** * Check if there is data to show at all * We need a special check for the project fields which can be an empty array */ - const isEmpty = Object.values(data).every((value) => !value || (value && Array.isArray(value) && value.length === 0)); + const isEmpty = + !projectData || + Object.values(projectData).every((value) => !value || (value && Array.isArray(value) && value.length === 0)); if (isEmpty) { return ( <> - ; @@ -47,37 +49,36 @@ export default function ProjectInfo() { return (
- - {data.logo && } + {projectData.logo && }
- {data.title && ( + {projectData.title && (
{getLocalizedString('project.title')}
-
{data.title}
+
{projectData.title}
)} - {data.description && ( + {projectData.description && (
{getLocalizedString('project.description')}
-
{data.description}
+
{projectData.description}
)} - {data.info && ( + {projectData.info && (
{getLocalizedString('project.info')}
-
{data.info}
+
{projectData.info}
)} - {data.url && ( + {projectData.url && (
{getLocalizedString('project.url')}
- - {data.url} + + {projectData.url}
)} - {data.custom.map((info, idx) => { + {projectData.custom.map((info, idx) => { const hasUrl = Boolean(info.url); return (
diff --git a/apps/client/src/views/project-info/useProjectInfoData.ts b/apps/client/src/views/project-info/useProjectInfoData.ts new file mode 100644 index 000000000..74596324c --- /dev/null +++ b/apps/client/src/views/project-info/useProjectInfoData.ts @@ -0,0 +1,26 @@ +import { ProjectData } from 'ontime-types'; + +import useProjectData from '../../common/hooks-query/useProjectData'; +import { useViewOptionsStore } from '../../common/stores/viewOptions'; +import { ViewData } from '../utils/viewLoader.utils'; + +export interface ProjectInfoData { + projectData: ProjectData; + isMirrored: boolean; +} + +export function useProjectInfoData(): ViewData { + // persisted app state + const isMirrored = useViewOptionsStore((state) => state.mirror); + + // HTTP API data + const { data: projectData, status: projectDataStatus } = useProjectData(); + + return { + data: { + projectData, + isMirrored, + }, + status: projectDataStatus, + }; +}