Skip to content

Commit 6cd85a0

Browse files
fix logout client
1 parent aa6a7ae commit 6cd85a0

File tree

4 files changed

+66
-3
lines changed

4 files changed

+66
-3
lines changed

client/src/App.jsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Routes, Route } from 'react-router-dom';
33

44
import LandingPage from './pages/LandingPage';
55
import CallbackPage from './pages/CallbackPage.jsx';
6+
import LogoutPage from './pages/LogoutPage.jsx';
67
import useUpdateLocation from './hooks/useUpdateLocation.js';
78
import RequireAuth from './components/RequireAuth';
89
import useRegisterUser from './hooks/useRegisterUser';
@@ -22,6 +23,7 @@ function App() {
2223
<Routes>
2324
<Route path="/" element={<LandingPage />} />
2425
<Route path="/callback" element={<CallbackPage />} />
26+
<Route path="/logout" element={<LogoutPage />} />
2527
<Route path="/home" element={<Home />} />
2628
<Route path="/signin/" element={<SignInPage />} />
2729
<Route path="/signup/" element={<SignUpPage />} />

client/src/components/Header.jsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import React from 'react';
22
import { useAuth0 } from '@auth0/auth0-react';
3+
import { useNavigate } from 'react-router-dom';
34
import { NavLink } from 'react-router-dom';
45
import '../styles/LandingPage.css';
56

67
const Header = () => {
78
const { isAuthenticated, user, logout, loginWithRedirect } = useAuth0();
9+
const navigate = useNavigate();
810
const authNav = [
911
{ path: '/home', label: 'Home' },
1012
{ path: '/matches', label: 'Matching' },
@@ -65,7 +67,7 @@ const Header = () => {
6567
style={{ width: 32, height: 32, borderRadius: '50%' }}
6668
onClick={() => navigate('/profile')}
6769
/>
68-
)} <button onClick={() => logout({ returnTo: window.location.origin })} className="btn btn-secondary">Log out</button>
70+
)} <button onClick={() => logout({ logoutParams: { returnTo: window.location.origin + '/logout' } })} className="btn btn-secondary">Log out</button>
6971
</div>
7072
) : (
7173
<div className="auth-links">

client/src/pages/LogoutPage.jsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { useEffect } from 'react';
2+
import { useNavigate } from 'react-router-dom';
3+
import LoadingSpinner from '../components/LoadingSpinner';
4+
5+
// Simple page shown after Auth0 redirects back to our app post-logout.
6+
// It briefly shows a spinner and then navigates to the landing page (/).
7+
export default function LogoutPage() {
8+
const navigate = useNavigate();
9+
10+
useEffect(() => {
11+
// Give users brief feedback, then redirect.
12+
const id = setTimeout(() => navigate('/', { replace: true }), 1000);
13+
return () => clearTimeout(id);
14+
}, [navigate]);
15+
16+
return <LoadingSpinner text="Logging out…" />;
17+
}

client/src/pages/MatchingPage.jsx

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,10 +106,52 @@ function MatchingPage() {
106106
const [profile, setProfile] = useState(null);
107107
const [location, setLocation] = useState('');
108108
const [matches, setMatches] = useState([]);
109+
const [loadingHistory, setLoadingHistory] = useState(true);
109110
const [matchingLoading, setMatchingLoading] = useState(false);
110111
const [showExplanationModal, setShowExplanationModal] = useState(false);
111112
const [selectedExplanation, setSelectedExplanation] = useState(null);
112113

114+
// Load previously stored matches on first mount
115+
useEffect(() => {
116+
(async () => {
117+
try {
118+
const token = await getAccessTokenSilently();
119+
const historyRes = await fetch(`${API_URL}/matching/history/${encodeURIComponent(user.sub)}`, {
120+
headers: { Authorization: `Bearer ${token}` },
121+
});
122+
if (historyRes.ok) {
123+
const history = await historyRes.json();
124+
// Fetch user details for each matched user in parallel
125+
const userDetailsArr = await Promise.all(history.map(h =>
126+
fetch(`${API_URL}/user/${encodeURIComponent(h.matchedUserId)}`, {
127+
headers: { Authorization: `Bearer ${token}` },
128+
}).then(res => res.ok ? res.json() : null)
129+
));
130+
const userMap = Object.fromEntries(userDetailsArr.filter(Boolean).map(u => [u.id, u]));
131+
132+
const formatted = history.map(h => {
133+
const u = userMap[h.matchedUserId] || {};
134+
return {
135+
id: h.matchedUserId,
136+
name: u.name || 'Unknown',
137+
distance: 0,
138+
avatar: u.picture || '/images/default-avatar.png',
139+
sports: u.sportInterests || [],
140+
shared: Array.isArray(h.commonPreferences) ? h.commonPreferences.join(', ') : '',
141+
match: h.score ? Math.round(h.score * 100) : 0,
142+
explanation: h.explanation,
143+
};
144+
});
145+
setMatches(formatted);
146+
}
147+
} catch (e) {
148+
console.warn('Failed to load match history', e);
149+
} finally {
150+
setLoadingHistory(false);
151+
}
152+
})();
153+
}, []); // run once on mount
154+
113155
// validation helpers and Match click handler
114156
const hasValidAvailability = (avl) => avl && Object.values(avl).some((arr) => Array.isArray(arr) && arr.length);
115157

@@ -337,7 +379,7 @@ function MatchingPage() {
337379

338380
{/* Matches list */}
339381
{view === 'cards' && (
340-
matchingLoading ? (
382+
(matchingLoading || loadingHistory) ? (
341383
<div className="match-loader">
342384
<div className="spinner" />
343385
<p>Finding your best matches…</p>
@@ -349,7 +391,7 @@ function MatchingPage() {
349391
<button className="btn-link edit">⚙️ Edit Preferences</button>
350392
</div>
351393
<div className="match-grid">
352-
{(matches.length ? matches : mockMatches).map((m) => (
394+
{matches.map((m) => (
353395
<div key={m.id} className="match-card card">
354396
<div className="match-header">
355397
<img src={m.avatar} alt={m.name} className="avatar-sm" />

0 commit comments

Comments
 (0)