diff --git a/frontend/src/app/page.tsx b/frontend/src/app/page.tsx index 6936f16a6501240063f90c332fc8108dc1faeaa1_ZnJvbnRlbmQvc3JjL2FwcC9wYWdlLnRzeA==..ff76e62386781f63689a85cfba351307bcf9a848_ZnJvbnRlbmQvc3JjL2FwcC9wYWdlLnRzeA== 100644 --- a/frontend/src/app/page.tsx +++ b/frontend/src/app/page.tsx @@ -19,6 +19,7 @@ deleteProject, updateProjectState, } from "@/api/cubicweb"; +import { useHandleAuthErrors } from "@/hooks/useHandleAuthErrors"; export default function Home() { const { data: projects, loading: projectsLoading } = useGetProjectList(); @@ -31,6 +32,7 @@ eid?: number; type?: "deleteDataService" | "deleteProject" | "toggle"; }>({ visible: false }); + const handleAuthErrors = useHandleAuthErrors(); return ( <Container> @@ -130,9 +132,23 @@ text={modal?.text ?? ""} onClose={() => setModal((prev) => ({ ...prev, visible: false }))} onAccept={async () => { - if (modal.type === "toggle") { - const project = projects?.find((p) => p.eid === modal.eid); - if (project && modal.eid) { - await updateProjectState(modal.eid, !project.activated); - project.activated = !project.activated; + try { + if (modal.type === "toggle") { + const project = projects?.find((p) => p.eid === modal.eid); + if (project && modal.eid) { + await updateProjectState(modal.eid, !project.activated); + project.activated = !project.activated; + } + } else if (modal.type === "deleteProject" && modal.eid) { + await deleteProject(modal.eid); + projects?.splice( + projects?.findIndex((p) => p.eid === modal.eid), + 1, + ); + } else if (modal.type === "deleteDataService" && modal.eid) { + await deleteDataService(modal.eid); + dataServices?.splice( + dataServices?.findIndex((p) => p.eid === modal.eid), + 1, + ); } @@ -138,16 +154,6 @@ } - } else if (modal.type === "deleteProject" && modal.eid) { - await deleteProject(modal.eid); - projects?.splice( - projects?.findIndex((p) => p.eid === modal.eid), - 1, - ); - } else if (modal.type === "deleteDataService" && modal.eid) { - await deleteDataService(modal.eid); - dataServices?.splice( - dataServices?.findIndex((p) => p.eid === modal.eid), - 1, - ); + } catch (e) { + handleAuthErrors(e); } }} /> diff --git a/frontend/src/components/DataServiceForm.tsx b/frontend/src/components/DataServiceForm.tsx index 6936f16a6501240063f90c332fc8108dc1faeaa1_ZnJvbnRlbmQvc3JjL2NvbXBvbmVudHMvRGF0YVNlcnZpY2VGb3JtLnRzeA==..ff76e62386781f63689a85cfba351307bcf9a848_ZnJvbnRlbmQvc3JjL2NvbXBvbmVudHMvRGF0YVNlcnZpY2VGb3JtLnRzeA== 100644 --- a/frontend/src/components/DataServiceForm.tsx +++ b/frontend/src/components/DataServiceForm.tsx @@ -15,6 +15,7 @@ import { useRouter } from "next/navigation"; import { createDataService, updateDataService } from "@/api/cubicweb"; import { LoadingButton } from "@mui/lab"; +import { useHandleAuthErrors } from "@/hooks/useHandleAuthErrors"; export interface DataServiceFormProps { dataService?: DataService; @@ -29,8 +30,9 @@ refresh_period: "weekly", }, }); + const handleAuthErrors = useHandleAuthErrors(); const router = useRouter(); const onSubmit: SubmitHandler<DataService> = async (data) => { setLoading(true); @@ -32,16 +34,20 @@ const router = useRouter(); const onSubmit: SubmitHandler<DataService> = async (data) => { setLoading(true); - if (data.eid === undefined) { - const result = await createDataService(data); - const eid = result[0][0]; - setLoading(false); - router.push(`/data-service/${eid}`); - } else { - await updateDataService(data); - setLoading(false); + try { + if (data.eid === undefined) { + const result = await createDataService(data); + const eid = result[0][0]; + setLoading(false); + router.push(`/data-service/${eid}`); + } else { + await updateDataService(data); + setLoading(false); + } + } catch (e) { + handleAuthErrors(e); } }; diff --git a/frontend/src/components/ProjectForm.tsx b/frontend/src/components/ProjectForm.tsx index 6936f16a6501240063f90c332fc8108dc1faeaa1_ZnJvbnRlbmQvc3JjL2NvbXBvbmVudHMvUHJvamVjdEZvcm0udHN4..ff76e62386781f63689a85cfba351307bcf9a848_ZnJvbnRlbmQvc3JjL2NvbXBvbmVudHMvUHJvamVjdEZvcm0udHN4 100644 --- a/frontend/src/components/ProjectForm.tsx +++ b/frontend/src/components/ProjectForm.tsx @@ -14,6 +14,7 @@ import { useRouter } from "next/navigation"; import { LoadingButton } from "@mui/lab"; import { createProject, updateProject } from "@/api/cubicweb"; +import { useHandleAuthErrors } from "@/hooks/useHandleAuthErrors"; export interface ProjectFormProps { project?: Project; @@ -24,8 +25,9 @@ const { handleSubmit, control } = useForm<Project>({ defaultValues: project, }); + const handleAuthErrors = useHandleAuthErrors(); const router = useRouter(); const onSubmit: SubmitHandler<Project> = async (data) => { setLoading(true); @@ -27,16 +29,20 @@ const router = useRouter(); const onSubmit: SubmitHandler<Project> = async (data) => { setLoading(true); - if (data.eid === undefined) { - const result = await createProject(data); - const eid = result[0][0]; - setLoading(false); - router.push(`/project/${eid}`); - } else { - await updateProject(data); - setLoading(false); + try { + if (data.eid === undefined) { + const result = await createProject(data); + const eid = result[0][0]; + setLoading(false); + router.push(`/project/${eid}`); + } else { + await updateProject(data); + setLoading(false); + } + } catch (e) { + handleAuthErrors(e); } }; diff --git a/frontend/src/hooks/useGetDataService.tsx b/frontend/src/hooks/useGetDataService.tsx index 6936f16a6501240063f90c332fc8108dc1faeaa1_ZnJvbnRlbmQvc3JjL2hvb2tzL3VzZUdldERhdGFTZXJ2aWNlLnRzeA==..ff76e62386781f63689a85cfba351307bcf9a848_ZnJvbnRlbmQvc3JjL2hvb2tzL3VzZUdldERhdGFTZXJ2aWNlLnRzeA== 100644 --- a/frontend/src/hooks/useGetDataService.tsx +++ b/frontend/src/hooks/useGetDataService.tsx @@ -1,8 +1,9 @@ import { UnknownEidError, getDataService } from "@/api/cubicweb"; import { DataService } from "@/types"; import { useState, useEffect } from "react"; +import { useHandleAuthErrors } from "./useHandleAuthErrors"; export function useGetDataService(eid: number) { const [loading, setLoading] = useState(true); const [data, setData] = useState<DataService | undefined>(undefined); const [error, setError] = useState<string | undefined>(); @@ -4,8 +5,9 @@ export function useGetDataService(eid: number) { const [loading, setLoading] = useState(true); const [data, setData] = useState<DataService | undefined>(undefined); const [error, setError] = useState<string | undefined>(); + const handleAuthErrors = useHandleAuthErrors(); useEffect(() => { setLoading(true); @@ -16,6 +18,7 @@ setLoading(false); setData(result); }) + .catch(handleAuthErrors) .catch((e) => { if (e instanceof UnknownEidError) { setError(`Impossible de trouver le data service '${eid}'`); @@ -24,6 +27,6 @@ } }); } - }, [eid]); + }, [eid, handleAuthErrors]); return { loading, data, error }; } diff --git a/frontend/src/hooks/useGetDataServiceList.tsx b/frontend/src/hooks/useGetDataServiceList.tsx index 6936f16a6501240063f90c332fc8108dc1faeaa1_ZnJvbnRlbmQvc3JjL2hvb2tzL3VzZUdldERhdGFTZXJ2aWNlTGlzdC50c3g=..ff76e62386781f63689a85cfba351307bcf9a848_ZnJvbnRlbmQvc3JjL2hvb2tzL3VzZUdldERhdGFTZXJ2aWNlTGlzdC50c3g= 100644 --- a/frontend/src/hooks/useGetDataServiceList.tsx +++ b/frontend/src/hooks/useGetDataServiceList.tsx @@ -1,7 +1,8 @@ import { getDataServiceList } from "@/api/cubicweb"; import { DataService } from "@/types"; import { useEffect, useState } from "react"; +import { useHandleAuthErrors } from "./useHandleAuthErrors"; export function useGetDataServiceList() { const [loading, setLoading] = useState(true); const [data, setData] = useState<Array<DataService> | undefined>(undefined); @@ -4,7 +5,8 @@ export function useGetDataServiceList() { const [loading, setLoading] = useState(true); const [data, setData] = useState<Array<DataService> | undefined>(undefined); + const handleAuthErrors = useHandleAuthErrors(); useEffect(() => { setLoading(true); @@ -8,11 +10,13 @@ useEffect(() => { setLoading(true); - getDataServiceList().then((result) => { - console.log(result); - setLoading(false); - setData(result); - }); - }, []); + getDataServiceList() + .then((result) => { + console.log(result); + setLoading(false); + setData(result); + }) + .catch(handleAuthErrors); + }, [handleAuthErrors]); return { loading, data }; } diff --git a/frontend/src/hooks/useGetProject.tsx b/frontend/src/hooks/useGetProject.tsx index 6936f16a6501240063f90c332fc8108dc1faeaa1_ZnJvbnRlbmQvc3JjL2hvb2tzL3VzZUdldFByb2plY3QudHN4..ff76e62386781f63689a85cfba351307bcf9a848_ZnJvbnRlbmQvc3JjL2hvb2tzL3VzZUdldFByb2plY3QudHN4 100644 --- a/frontend/src/hooks/useGetProject.tsx +++ b/frontend/src/hooks/useGetProject.tsx @@ -1,8 +1,9 @@ import { UnknownEidError, getProject } from "@/api/cubicweb"; import { Project } from "@/types"; import { useState, useEffect } from "react"; +import { useHandleAuthErrors } from "./useHandleAuthErrors"; export function useGetProject(eid: number) { const [loading, setLoading] = useState(true); const [data, setData] = useState<Project | undefined>(); const [error, setError] = useState<string | undefined>(); @@ -4,8 +5,9 @@ export function useGetProject(eid: number) { const [loading, setLoading] = useState(true); const [data, setData] = useState<Project | undefined>(); const [error, setError] = useState<string | undefined>(); + const handleAuthErrors = useHandleAuthErrors(); useEffect(() => { setLoading(true); @@ -16,6 +18,7 @@ setLoading(false); setData(result); }) + .catch(handleAuthErrors) .catch((e) => { if (e instanceof UnknownEidError) { setError(`Impossible de trouver le projet '${eid}'`); @@ -24,6 +27,6 @@ } }); } - }, [eid]); + }, [eid, handleAuthErrors]); return { loading, data, error }; } diff --git a/frontend/src/hooks/useGetProjectList.tsx b/frontend/src/hooks/useGetProjectList.tsx index 6936f16a6501240063f90c332fc8108dc1faeaa1_ZnJvbnRlbmQvc3JjL2hvb2tzL3VzZUdldFByb2plY3RMaXN0LnRzeA==..ff76e62386781f63689a85cfba351307bcf9a848_ZnJvbnRlbmQvc3JjL2hvb2tzL3VzZUdldFByb2plY3RMaXN0LnRzeA== 100644 --- a/frontend/src/hooks/useGetProjectList.tsx +++ b/frontend/src/hooks/useGetProjectList.tsx @@ -1,7 +1,8 @@ import { getProjectList } from "@/api/cubicweb"; import { Project } from "@/types"; import { useState, useEffect } from "react"; +import { useHandleAuthErrors } from "./useHandleAuthErrors"; export function useGetProjectList() { const [loading, setLoading] = useState(true); const [data, setData] = useState<Array<Project> | undefined>(undefined); @@ -4,7 +5,8 @@ export function useGetProjectList() { const [loading, setLoading] = useState(true); const [data, setData] = useState<Array<Project> | undefined>(undefined); + const handleAuthErrors = useHandleAuthErrors(); useEffect(() => { setLoading(true); @@ -8,11 +10,13 @@ useEffect(() => { setLoading(true); - getProjectList().then((result) => { - console.log(result); - setLoading(false); - setData(result); - }); - }, []); + getProjectList() + .then((result) => { + console.log(result); + setLoading(false); + setData(result); + }) + .catch(handleAuthErrors); + }, [handleAuthErrors]); return { loading, data }; } diff --git a/frontend/src/hooks/useHandleAuthErrors.tsx b/frontend/src/hooks/useHandleAuthErrors.tsx new file mode 100644 index 0000000000000000000000000000000000000000..ff76e62386781f63689a85cfba351307bcf9a848_ZnJvbnRlbmQvc3JjL2hvb2tzL3VzZUhhbmRsZUF1dGhFcnJvcnMudHN4 --- /dev/null +++ b/frontend/src/hooks/useHandleAuthErrors.tsx @@ -0,0 +1,24 @@ +import { useLogout } from "@/api/cubicweb"; +import { useMemo } from "react"; + +export function useHandleAuthErrors() { + const logout = useLogout(); + + const handleAuthErrors = useMemo(() => { + return (e: unknown) => { + if ( + e && + typeof e === "object" && + "title" in e && + e.title === "AuthenticationError" + ) { + logout(); + } else { + throw e; + } + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return handleAuthErrors; +}