diff --git a/src/App.tsx b/src/App.tsx index 65c91e3..de77ea8 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -77,7 +77,6 @@ function App() { - {/* ================================================== */} @@ -94,7 +93,9 @@ function App() { {/* ================================================== */} + + }> {/* Dashboard (Root) */} @@ -190,7 +191,6 @@ function App() { } /> - diff --git a/src/hooks/useInvitations.ts b/src/hooks/useInvitations.ts index e8dbd79..040d95b 100644 --- a/src/hooks/useInvitations.ts +++ b/src/hooks/useInvitations.ts @@ -65,6 +65,7 @@ export interface InvitationValidation { roleIds: string[]; roleLabels?: string[]; targetUsername?: string; + email?: string; } diff --git a/src/pages/InvitePage.tsx b/src/pages/InvitePage.tsx index f5cd0ab..85c83bc 100644 --- a/src/pages/InvitePage.tsx +++ b/src/pages/InvitePage.tsx @@ -24,6 +24,7 @@ import React, { useState, useEffect } from 'react'; import { useParams, useNavigate, Link } from 'react-router-dom'; import { useInvitations, type InvitationValidation } from '../hooks/useInvitations'; +import api from '../api'; import { FaCheckCircle, FaTimesCircle, FaSpinner, FaSignInAlt, FaUserPlus } from 'react-icons/fa'; import styles from './InvitePage.module.css'; @@ -35,7 +36,7 @@ export const InvitePage: React.FC = () => { const navigate = useNavigate(); const { validateInvitation, acceptInvitation } = useInvitations(); - // Check if user has auth token (simplified check) + // Check if user has an active session const isAuthenticated = !!sessionStorage.getItem('auth_authority'); // State @@ -68,12 +69,11 @@ export const InvitePage: React.FC = () => { // Check if the target username already has an account if (result.targetUsername) { try { - const resp = await fetch(`/api/local/available?username=${encodeURIComponent(result.targetUsername)}`); - if (resp.ok) { - const data = await resp.json(); - // available=true means username is free -> user does NOT exist - setUserExists(!data.available); - } + const resp = await api.get(`/api/local/available`, { + params: { username: result.targetUsername } + }); + // available=true means username is free -> user does NOT exist + setUserExists(!resp.data.available); } catch { // On error, default to showing both options setUserExists(null); @@ -104,6 +104,10 @@ export const InvitePage: React.FC = () => { setTimeout(() => { navigate('/'); }, 2000); + } else if (result.error?.includes('401') || result.error?.includes('Not authenticated')) { + // Session expired — clear auth and redirect to login + sessionStorage.removeItem('auth_authority'); + handleLoginRedirect(); } else { setError(result.error || 'Fehler beim Annehmen der Einladung'); } @@ -111,20 +115,28 @@ export const InvitePage: React.FC = () => { setAccepting(false); }; - // Handle redirect to login (stores token first) + // Handle redirect to login (stores token first, passes invitation data for pre-fill) const handleLoginRedirect = () => { if (token) { localStorage.setItem(PENDING_INVITATION_KEY, token); } - navigate('/login', { state: { from: { pathname: `/invite/${token}` } } }); + navigate('/login', { state: { + from: { pathname: `/invite/${token}` }, + invitationUsername: validation?.targetUsername || '', + } }); }; - // Handle redirect to register (stores token first) + // Handle redirect to register (stores token first, passes invitation data for pre-fill) const handleRegisterRedirect = () => { if (token) { localStorage.setItem(PENDING_INVITATION_KEY, token); } - navigate('/register', { state: { from: { pathname: `/invite/${token}` }, pendingInvitation: true } }); + navigate('/register', { state: { + from: { pathname: `/invite/${token}` }, + pendingInvitation: true, + invitationUsername: validation?.targetUsername || '', + invitationEmail: validation?.email || '', + } }); }; // Loading state diff --git a/src/pages/Login.tsx b/src/pages/Login.tsx index 9756d96..d06bca0 100644 --- a/src/pages/Login.tsx +++ b/src/pages/Login.tsx @@ -12,7 +12,9 @@ import styles from './Login.module.css'; function Login() { const navigate = useNavigate(); const location = useLocation(); - const [username, setUsername] = useState(''); + // Pre-fill username from invitation if provided via location.state + const invitationUsername = (location.state as any)?.invitationUsername || ''; + const [username, setUsername] = useState(invitationUsername); const [password, setPassword] = useState(''); const [usernameFocused, setUsernameFocused] = useState(false); const [passwordFocused, setPasswordFocused] = useState(false); diff --git a/src/pages/Register.tsx b/src/pages/Register.tsx index 2602d10..a3c1403 100644 --- a/src/pages/Register.tsx +++ b/src/pages/Register.tsx @@ -19,9 +19,12 @@ function Register() { const { register, error: registerError, isLoading } = useRegister(); const { error: msalError } = useMsalRegister(); const { checkAvailability, isChecking, error: availabilityError } = useUsernameAvailability(); + // Pre-fill from invitation if provided via location.state + const invitationUsername = (location.state as any)?.invitationUsername || ''; + const invitationEmail = (location.state as any)?.invitationEmail || ''; const [formData, setFormData] = useState({ - username: '', - email: '', + username: invitationUsername, + email: invitationEmail, fullName: '' }); const [validationError, setValidationError] = useState(null);