From 35d9a62d89546228521f3433c1afecd7269606c5 Mon Sep 17 00:00:00 2001 From: andreas-unleash Date: Wed, 23 Nov 2022 15:58:02 +0200 Subject: [PATCH] Soft landing page on projects or last viewed project (#2499) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: andreas-unleash This PR introduces a soft landing page to the last viewed project or to the project list (if there is more than 1 project) Changes: - Replaced clearing of `storage` with clearing `cache` in logout.ts :: REVERTED - Root redirects to `projects` instead of `features` ## About the changes Closes # ### Important files ## Discussion points Signed-off-by: andreas-unleash --- frontend/src/component/App.tsx | 2 +- .../project/Project/ProjectOverview.tsx | 7 ++++++ .../project/ProjectList/ProjectList.tsx | 6 ++++- frontend/src/component/user/Login/Login.tsx | 9 +++++++- frontend/src/hooks/useLastViewedProject.ts | 23 +++++++++++++++++++ frontend/src/hooks/useThemeMode.ts | 7 ++++-- src/lib/routes/logout.ts | 2 +- 7 files changed, 50 insertions(+), 6 deletions(-) create mode 100644 frontend/src/hooks/useLastViewedProject.ts diff --git a/frontend/src/component/App.tsx b/frontend/src/component/App.tsx index 9ff43b3e8f..0b7ebc4e8e 100644 --- a/frontend/src/component/App.tsx +++ b/frontend/src/component/App.tsx @@ -63,7 +63,7 @@ export const App = () => { path="/" element={ } diff --git a/frontend/src/component/project/Project/ProjectOverview.tsx b/frontend/src/component/project/Project/ProjectOverview.tsx index f81b939449..df0764e06e 100644 --- a/frontend/src/component/project/Project/ProjectOverview.tsx +++ b/frontend/src/component/project/Project/ProjectOverview.tsx @@ -6,6 +6,8 @@ import ProjectInfo from './ProjectInfo/ProjectInfo'; import { useStyles } from './Project.styles'; import { usePageTitle } from 'hooks/usePageTitle'; import { useRequiredPathParam } from 'hooks/useRequiredPathParam'; +import { useLastViewedProject } from '../../../hooks/useLastViewedProject'; +import { useEffect } from 'react'; const refreshInterval = 15 * 1000; @@ -16,6 +18,11 @@ const ProjectOverview = () => { const { members, features, health, description, environments } = project; const { classes: styles } = useStyles(); usePageTitle(`Project overview – ${projectName}`); + const { setLastViewed } = useLastViewedProject(); + + useEffect(() => { + setLastViewed(projectName); + }, [projectName, setLastViewed]); return (
diff --git a/frontend/src/component/project/ProjectList/ProjectList.tsx b/frontend/src/component/project/ProjectList/ProjectList.tsx index 522ec04647..dab56aaf1b 100644 --- a/frontend/src/component/project/ProjectList/ProjectList.tsx +++ b/frontend/src/component/project/ProjectList/ProjectList.tsx @@ -1,5 +1,5 @@ import { useContext, useEffect, useMemo, useState } from 'react'; -import { Link, useNavigate, useSearchParams } from 'react-router-dom'; +import { Link, Navigate, useNavigate, useSearchParams } from 'react-router-dom'; import { mutate } from 'swr'; import { getProjectFetcher } from 'hooks/api/getters/useProject/getProjectFetcher'; import useProjects from 'hooks/api/getters/useProjects/useProjects'; @@ -152,6 +152,10 @@ export const ProjectListNew = () => { ? `${filteredProjects.length} of ${projects.length}` : projects.length; + if (projects?.length === 1) { + return ; + } + return (
{ const { classes: styles } = useStyles(); const { authDetails } = useAuthDetails(); const { user } = useAuthUser(); + const { lastViewed } = useLastViewedProject(); const query = useQueryParams(); const resetPassword = query.get('reset') === 'true'; const invited = query.get('invited') === 'true'; - const redirect = query.get('redirect') || '/'; + + const getRedirect = () => { + return lastViewed == null ? '/projects' : `/projects/${lastViewed}`; + }; + + const redirect = query.get('redirect') || getRedirect(); if (user) { return ; diff --git a/frontend/src/hooks/useLastViewedProject.ts b/frontend/src/hooks/useLastViewedProject.ts new file mode 100644 index 0000000000..12af31da6d --- /dev/null +++ b/frontend/src/hooks/useLastViewedProject.ts @@ -0,0 +1,23 @@ +import { useEffect, useState } from 'react'; +import { setLocalStorageItem, getLocalStorageItem } from '../utils/storage'; +import useUiConfig from './api/getters/useUiConfig/useUiConfig'; + +export const useLastViewedProject = () => { + const { uiConfig } = useUiConfig(); + const key = `${uiConfig.baseUriPath}:unleash-lastViewedProject`; + + const [lastViewed, setLastViewed] = useState(() => { + return getLocalStorageItem(key); + }); + + useEffect(() => { + if (lastViewed) { + setLocalStorageItem(key, lastViewed); + } + }, [lastViewed, key]); + + return { + lastViewed, + setLastViewed, + }; +}; diff --git a/frontend/src/hooks/useThemeMode.ts b/frontend/src/hooks/useThemeMode.ts index 750a0daa33..7a9390f2d9 100644 --- a/frontend/src/hooks/useThemeMode.ts +++ b/frontend/src/hooks/useThemeMode.ts @@ -4,6 +4,7 @@ import { setLocalStorageItem } from 'utils/storage'; import mainTheme from 'themes/theme'; import darkTheme from 'themes/dark-theme'; import { Theme } from '@emotion/react'; +import useUiConfig from './api/getters/useUiConfig/useUiConfig'; interface IUseThemeModeOutput { resolveTheme: () => Theme; @@ -13,6 +14,8 @@ interface IUseThemeModeOutput { export const useThemeMode = (): IUseThemeModeOutput => { const { themeMode, setThemeMode } = useContext(UIContext); + const { uiConfig } = useUiConfig(); + const key = `${uiConfig.baseUriPath}:unleash-theme`; const resolveTheme = () => { if (themeMode === 'light') { @@ -25,10 +28,10 @@ export const useThemeMode = (): IUseThemeModeOutput => { const onSetThemeMode = () => { setThemeMode((prev: themeMode) => { if (prev === 'light') { - setLocalStorageItem('unleash-theme', 'dark'); + setLocalStorageItem(key, 'dark'); return 'dark'; } - setLocalStorageItem('unleash-theme', 'light'); + setLocalStorageItem(key, 'light'); return 'light'; }); }; diff --git a/src/lib/routes/logout.ts b/src/lib/routes/logout.ts index 98a597c9af..c7dfb78feb 100644 --- a/src/lib/routes/logout.ts +++ b/src/lib/routes/logout.ts @@ -1,6 +1,6 @@ import { Response } from 'express'; import { promisify } from 'util'; -import { IUnleashConfig } from '../types/option'; +import { IUnleashConfig } from '../types'; import Controller from './controller'; import { IAuthRequest } from './unleash-types'; import { IUnleashServices } from '../types';