import React from 'react'; import { Location, useLocation, useNavigate } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { ArrowRight, Loader2 } from 'lucide-react'; import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'; import { Button } from '@/components/ui/button'; import AppLogoIcon from '@/components/app-logo-icon'; import { useAuth } from '../auth/context'; import { ADMIN_DEFAULT_AFTER_LOGIN_PATH } from '../constants'; import { buildAdminOAuthStartPath, buildMarketingLoginUrl, encodeReturnTo, resolveReturnTarget, storeLastDestination } from '../lib/returnTo'; interface LocationState { from?: Location; } export default function LoginPage(): JSX.Element { const { status, login } = useAuth(); const { t } = useTranslation('auth'); const location = useLocation(); const navigate = useNavigate(); const searchParams = React.useMemo(() => new URLSearchParams(location.search), [location.search]); const oauthError = searchParams.get('error'); const oauthErrorDescription = searchParams.get('error_description'); const rawReturnTo = searchParams.get('return_to'); const { finalTarget, encodedFinal } = React.useMemo( () => resolveReturnTarget(rawReturnTo, ADMIN_DEFAULT_AFTER_LOGIN_PATH), [rawReturnTo] ); const resolvedErrorMessage = React.useMemo(() => { if (!oauthError) { return null; } const errorMap: Record = { login_required: t('login.oauth_errors.login_required'), invalid_request: t('login.oauth_errors.invalid_request'), invalid_client: t('login.oauth_errors.invalid_client'), invalid_redirect: t('login.oauth_errors.invalid_redirect'), invalid_scope: t('login.oauth_errors.invalid_scope'), tenant_mismatch: t('login.oauth_errors.tenant_mismatch'), google_failed: t('login.oauth_errors.google_failed'), google_no_match: t('login.oauth_errors.google_no_match'), }; return errorMap[oauthError] ?? oauthErrorDescription ?? oauthError; }, [oauthError, oauthErrorDescription, t]); React.useEffect(() => { if (status === 'authenticated') { navigate(finalTarget, { replace: true }); } }, [finalTarget, navigate, status]); const redirectTarget = React.useMemo(() => { if (finalTarget) { return finalTarget; } const state = location.state as LocationState | null; if (state?.from) { const from = state.from; const search = from.search ?? ''; const hash = from.hash ?? ''; const path = `${from.pathname}${search}${hash}`; return path.startsWith('/') ? path : `/${path}`; } return ADMIN_DEFAULT_AFTER_LOGIN_PATH; }, [finalTarget, location.state]); const shouldOpenAccountLogin = oauthError === 'login_required'; const isLoading = status === 'loading'; const hasAutoStartedRef = React.useRef(false); const oauthStartPath = React.useMemo( () => buildAdminOAuthStartPath(redirectTarget, encodedFinal), [encodedFinal, redirectTarget] ); const marketingLoginUrl = React.useMemo(() => buildMarketingLoginUrl(oauthStartPath), [oauthStartPath]); const hasRedirectedRef = React.useRef(false); React.useEffect(() => { if (!shouldOpenAccountLogin || hasRedirectedRef.current) { return; } hasRedirectedRef.current = true; window.location.replace(marketingLoginUrl); }, [marketingLoginUrl, shouldOpenAccountLogin]); React.useEffect(() => { if (status !== 'unauthenticated' || oauthError || hasAutoStartedRef.current) { return; } hasAutoStartedRef.current = true; storeLastDestination(redirectTarget); login(redirectTarget); }, [login, oauthError, redirectTarget, status]); const googleHref = React.useMemo(() => { const target = new URL('/event-admin/auth/google', window.location.origin); target.searchParams.set('return_to', encodeReturnTo(oauthStartPath)); return target.toString(); }, [oauthStartPath]); return (

{t('login.panel_title', t('login.title', 'Event Admin'))}

{t('login.panel_copy', 'Sign in with your Fotospiel admin access. OAuth 2.1 and clear role permissions keep your account protected.')}

{resolvedErrorMessage ? ( {t('login.oauth_error_title')} {resolvedErrorMessage} ) : null}

{t('login.actions_title', 'Choose your sign-in method')}

{t('login.actions_copy', 'Access the tenant dashboard securely with OAuth or your Google account.')}

{t('login.support', "Need access? Contact your event team or email support@fotospiel.de — we're happy to help.")}

{redirectTarget !== ADMIN_DEFAULT_AFTER_LOGIN_PATH ? (

{t('login.return_hint')}

) : null}
); } function GoogleIcon({ className }: { className?: string }): JSX.Element { return ( ); }