diff --git a/dashboard/app/api/client.ts b/dashboard/app/api/client.ts index f3d9416..1119e91 100644 --- a/dashboard/app/api/client.ts +++ b/dashboard/app/api/client.ts @@ -44,8 +44,8 @@ export type ClientOptions< body: Body extends ComponentSchema ? components['schemas'][Body] : undefined; query: Record; method: 'GET' | 'POST' | 'PATCH' | 'DELETE'; - noRedirect: boolean; - noThrow: boolean; + shouldRedirect: boolean; + shouldThrow: boolean; pathKey: string; }>; @@ -54,8 +54,8 @@ const client = async ( { body, method = 'GET', - noRedirect, - noThrow = false, + shouldRedirect = true, + shouldThrow = true, pathKey, query, }: ClientOptions, @@ -88,15 +88,15 @@ const client = async ( ...(body !== undefined && { body: JSON.stringify(body) }), }); - if (!res.ok && !noThrow) { + if (!res.ok && shouldThrow) { // If the user is not logged in, redirect to the login page - if (res.status === 401 && !noRedirect) { - throw expireSession(noRedirect); + if (res.status === 401 && shouldRedirect) { + throw expireSession(shouldRedirect); } // If it is 401 and noRedirect is true, do not throw anything but expire the invalid session - if (res.status === 401 && noRedirect) { - expireSession(noRedirect); + if (res.status === 401 && !shouldRedirect) { + expireSession(!shouldRedirect); return res; } diff --git a/dashboard/app/api/user.ts b/dashboard/app/api/user.ts index 1fa80a5..9a035b7 100644 --- a/dashboard/app/api/user.ts +++ b/dashboard/app/api/user.ts @@ -1,5 +1,3 @@ -import { hasSession } from '@/utils/cookies'; -import { redirect } from '@remix-run/react'; import { type ClientOptions, type DataResponse, client } from './client'; const userGet = async ( @@ -23,17 +21,4 @@ const userUpdate = async ( return { data: await res.json(), res }; }; -const userLoggedIn = async () => { - // If the user is already logged in, redirect them to the dashboard. - if (hasSession()) { - // Check if session hasn't been revoked. - const res = await client('/user', { method: 'GET' }); - if (res.ok) { - return; - } - } - - throw redirect('/login'); -}; - -export { userGet, userLoggedIn, userUpdate, userUsageGet }; +export { userGet, userUpdate, userUsageGet }; diff --git a/dashboard/app/routes/$hostname.tsx b/dashboard/app/routes/$hostname.tsx index 1e6dec9..152904c 100644 --- a/dashboard/app/routes/$hostname.tsx +++ b/dashboard/app/routes/$hostname.tsx @@ -8,7 +8,6 @@ import { } from '@remix-run/react'; import { useMemo } from 'react'; -import { userLoggedIn } from '@/api/user'; import { websiteList } from '@/api/websites'; import { Chart } from '@/components/stats/Chart'; import { Filters } from '@/components/stats/Filter'; @@ -25,8 +24,6 @@ export const clientLoader = async ({ request, params, }: ClientLoaderFunctionArgs) => { - await userLoggedIn(); - // Check chart param for the chart data to display const searchParams = new URL(request.url).searchParams; const chart = searchParams.get('chart[stat]'); diff --git a/dashboard/app/routes/_index.tsx b/dashboard/app/routes/_index.tsx index ce6f7e9..4247c9b 100644 --- a/dashboard/app/routes/_index.tsx +++ b/dashboard/app/routes/_index.tsx @@ -15,7 +15,6 @@ import * as v from 'valibot'; import isFQDN from 'validator/lib/isFQDN'; import type { components } from '@/api/types'; -import { userLoggedIn } from '@/api/user'; import { websiteCreate, websiteList } from '@/api/websites'; import { Button } from '@/components/Button'; import { TextInput } from '@/components/Input'; @@ -36,8 +35,6 @@ export const meta: MetaFunction = () => { }; export const clientLoader = async () => { - await userLoggedIn(); - const { data, res } = await websiteList({ query: { summary: true } }); if (!res.ok || !data) { diff --git a/dashboard/app/routes/login._index.tsx b/dashboard/app/routes/login._index.tsx index 6e7a92c..14b3f71 100644 --- a/dashboard/app/routes/login._index.tsx +++ b/dashboard/app/routes/login._index.tsx @@ -30,7 +30,7 @@ export const clientLoader = async () => { username: 'admin', password: 'CHANGE_ME_ON_FIRST_LOGIN', }, - noThrow: true, + shouldThrow: false, }); if (!res.ok) { @@ -46,7 +46,7 @@ export const clientLoader = async () => { // If the user is already logged in, redirect them to the dashboard. if (hasSession()) { // Check if session hasn't been revoked - await userGet({ noRedirect: true }); + await userGet({ shouldRedirect: false }); return redirect('/'); } @@ -74,7 +74,7 @@ export const clientAction = async ({ request }: ClientActionFunctionArgs) => { username, password, }, - noThrow: true, + shouldThrow: false, }); if (!res.ok) { @@ -98,6 +98,13 @@ export const clientAction = async ({ request }: ClientActionFunctionArgs) => { // Set logged in cookie document.cookie = LOGGED_IN_COOKIE; + // If user has redirect query param, redirect them to that URL + const url = new URL(request.url); + const redirectPathname = url.searchParams.get('redirect'); + if (redirectPathname) { + return redirect(redirectPathname); + } + return redirect('/'); }; diff --git a/dashboard/app/routes/settings.account.tsx b/dashboard/app/routes/settings.account.tsx index 2765bf9..e025627 100644 --- a/dashboard/app/routes/settings.account.tsx +++ b/dashboard/app/routes/settings.account.tsx @@ -76,7 +76,7 @@ export const clientAction = async ({ request }: ClientActionFunctionArgs) => { language: 'en', }, }, - noThrow: true, + shouldThrow: false, }); res = update.res; break; diff --git a/dashboard/app/routes/settings.tracker.tsx b/dashboard/app/routes/settings.tracker.tsx index 9cb4381..e2e097d 100644 --- a/dashboard/app/routes/settings.tracker.tsx +++ b/dashboard/app/routes/settings.tracker.tsx @@ -74,7 +74,7 @@ export const clientAction = async ({ request }: ClientActionFunctionArgs) => { ) as components['schemas']['UserGet']['settings']['script_type'], }, }, - noThrow: true, + shouldThrow: false, }); res = update.res; break; diff --git a/dashboard/app/routes/settings.tsx b/dashboard/app/routes/settings.tsx index b6e5626..75c85b7 100644 --- a/dashboard/app/routes/settings.tsx +++ b/dashboard/app/routes/settings.tsx @@ -1,14 +1,8 @@ import { Outlet } from '@remix-run/react'; -import { userLoggedIn } from '@/api/user'; import { InnerHeader } from '@/components/layout/InnerHeader'; import { SettingsLayout } from '@/components/settings/Layout'; -export const clientLoader = async () => { - await userLoggedIn(); - return null; -}; - export default function Index() { return ( <> diff --git a/dashboard/app/routes/settings.websites.tsx b/dashboard/app/routes/settings.websites.tsx index 3f79731..5076862 100644 --- a/dashboard/app/routes/settings.websites.tsx +++ b/dashboard/app/routes/settings.websites.tsx @@ -58,7 +58,7 @@ export const clientAction = async ({ request }: ClientActionFunctionArgs) => { case 'delete': { const deleteWebsite = await websiteDelete({ pathKey: getString(body, 'hostname'), - noThrow: true, + shouldThrow: false, }); res = deleteWebsite.res; diff --git a/dashboard/app/utils/cookies.ts b/dashboard/app/utils/cookies.ts index ee9da3c..cdc0ab8 100644 --- a/dashboard/app/utils/cookies.ts +++ b/dashboard/app/utils/cookies.ts @@ -15,9 +15,20 @@ const hasSession = () => .split(';') .some((c) => c.trim().startsWith(`${LOGGED_IN_NAME}=`)); -const expireSession = (noRedirect?: boolean) => { +const expireSession = (shouldRedirect = true) => { + // Expire the logged-in cookie document.cookie = EXPIRE_LOGGED_IN; - if (!noRedirect) redirect('/login'); + + // Check if we should redirect the user to the login page + // and whether to include the current path as a redirect parameter + if (shouldRedirect) { + const currentPath = window.location.pathname; + if (currentPath !== '/' && currentPath !== '/login') { + return redirect(`/login?redirect=${currentPath}`); + } + + return redirect('/login'); + } }; export { EXPIRE_LOGGED_IN, expireSession, hasSession, LOGGED_IN_COOKIE };