From d101459115c5120e4bbeb1e5619a8ff5ea6e2535 Mon Sep 17 00:00:00 2001 From: lebaudantoine Date: Sun, 25 Jan 2026 16:25:43 +0100 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8(frontend)=20add=20configurable=20exte?= =?UTF-8?q?rnal=20redirect=20for=20unauthenticated=20users?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Offer a way to redirect unauthenticated users to an external home page when they visit the app, allowing a more marketing-focused entry point with a clearer value proposition. In many self-hosted deployments, the default unauthenticated home page is not accessible or already redirects elsewhere. To ensure resilience, the client briefly checks that the target page is reachable and falls back to the default page if not. --- CHANGELOG.md | 4 +++ src/backend/meet/settings.py | 3 ++ src/frontend/src/api/useConfig.ts | 1 + .../src/features/home/routes/Home.tsx | 28 ++++++++++++++++++- 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1204c587..44425507 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ and this project adheres to ## [Unreleased] +### Added + +- ✨(frontend) add configurable redirect for unauthenticated users #904 + ### Changed - ♿️(frontend) add accessible back button in side panel #881 diff --git a/src/backend/meet/settings.py b/src/backend/meet/settings.py index dd6cca0f..b5044620 100755 --- a/src/backend/meet/settings.py +++ b/src/backend/meet/settings.py @@ -336,6 +336,9 @@ class Base(Configuration): "feedback": values.DictValue( {}, environ_name="FRONTEND_FEEDBACK", environ_prefix=None ), + "external_home_url": values.Value( + None, environ_name="FRONTEND_EXTERNAL_HOME_URL", environ_prefix=None + ), "use_french_gov_footer": values.BooleanValue( False, environ_name="FRONTEND_USE_FRENCH_GOV_FOOTER", environ_prefix=None ), diff --git a/src/frontend/src/api/useConfig.ts b/src/frontend/src/api/useConfig.ts index f936023c..67a67738 100644 --- a/src/frontend/src/api/useConfig.ts +++ b/src/frontend/src/api/useConfig.ts @@ -17,6 +17,7 @@ export interface ApiConfig { feedback: { url: string } + external_home_url?: string silence_livekit_debug_logs?: boolean is_silent_login_enabled?: boolean custom_css_url?: string diff --git a/src/frontend/src/features/home/routes/Home.tsx b/src/frontend/src/features/home/routes/Home.tsx index aa18afda..be81e49f 100644 --- a/src/frontend/src/features/home/routes/Home.tsx +++ b/src/frontend/src/features/home/routes/Home.tsx @@ -11,7 +11,7 @@ import { RiAddLine, RiLink } from '@remixicon/react' import { LaterMeetingDialog } from '@/features/home/components/LaterMeetingDialog' import { IntroSlider } from '@/features/home/components/IntroSlider' import { MoreLink } from '@/features/home/components/MoreLink' -import { ReactNode, useState } from 'react' +import { ReactNode, useEffect, useState } from 'react' import { css } from '@/styled-system/css' import { menuRecipe } from '@/primitives/menuRecipe.ts' @@ -19,6 +19,7 @@ import { usePersistentUserChoices } from '@/features/rooms/livekit/hooks/usePers import { useConfig } from '@/api/useConfig' import { LoginButton } from '@/components/LoginButton' import { ApiRoom } from '@/features/rooms/api/ApiRoom' +import { LoadingScreen } from '@/components/LoadingScreen' const Columns = ({ children }: { children?: ReactNode }) => { return ( @@ -155,9 +156,34 @@ export const Home = () => { const { mutateAsync: createRoom } = useCreateRoom() const [laterRoom, setLaterRoom] = useState(null) + const [redirectFailed, setRedirectFailed] = useState(false) const { data } = useConfig() + useEffect(() => { + const checkSiteAndRedirect = async () => { + if (!data?.external_home_url) return + if (isLoggedIn === false) { + try { + await fetch(data.external_home_url, { + method: 'HEAD', // Use HEAD to avoid downloading the full page + mode: 'no-cors', // Needed for cross-origin requests + }) + window.location.replace(data.external_home_url) + } catch (error) { + setRedirectFailed(true) + console.error('Site is not reachable:', error) + } + } + } + + checkSiteAndRedirect() + }, [isLoggedIn, data]) + + if (data?.external_home_url && isLoggedIn == false && !redirectFailed) { + return + } + return (