Skip to content

Commit 751f1e9

Browse files
committed
photo reset token save + save photo in logs
1 parent 22879d3 commit 751f1e9

3 files changed

Lines changed: 72 additions & 21 deletions

File tree

frontend/src/App.jsx

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,14 @@ function App() {
2828
const [isPasswordRecovery, setIsPasswordRecovery] = useState(() => {
2929
// Check for recovery hash on initial render (before Supabase processes it)
3030
const hashParams = new URLSearchParams(window.location.hash.substring(1));
31-
return hashParams.get('type') === 'recovery';
31+
const isRecovery = hashParams.get('type') === 'recovery';
32+
// Clear the hash immediately after reading to prevent loops on page reload
33+
if (isRecovery) {
34+
window.history.replaceState(null, '', window.location.pathname + window.location.search);
35+
// Set flag for auth listener to check (since hash is now cleared)
36+
sessionStorage.setItem('password_recovery_active', 'true');
37+
}
38+
return isRecovery;
3239
});
3340

3441
useEffect(() => {
@@ -49,20 +56,22 @@ function App() {
4956
// Handle password recovery event - set recovery mode and don't set session
5057
if (event === 'PASSWORD_RECOVERY') {
5158
console.log('PASSWORD_RECOVERY event - enabling recovery mode');
59+
sessionStorage.setItem('password_recovery_active', 'true');
5260
setIsPasswordRecovery(true);
5361
setSession(null);
5462
return;
5563
}
5664

57-
// Check if we should skip setting session due to recovery
58-
const hashParams = new URLSearchParams(window.location.hash.substring(1));
59-
const isRecoveryHash = hashParams.get('type') === 'recovery';
60-
61-
if (isRecoveryHash && event === 'SIGNED_IN') {
62-
console.log('Recovery hash present - ignoring SIGNED_IN event');
63-
setIsPasswordRecovery(true);
64-
setSession(null);
65-
return;
65+
// Skip setting session if we're already in recovery mode
66+
// Note: Hash is cleared on initial load, so we rely on isPasswordRecovery state
67+
if (event === 'SIGNED_IN') {
68+
// Check current recovery state - use a ref or check localStorage for persistence
69+
const recoveryActive = sessionStorage.getItem('password_recovery_active') === 'true';
70+
if (recoveryActive) {
71+
console.log('Recovery mode active - ignoring SIGNED_IN event');
72+
setSession(null);
73+
return;
74+
}
6675
}
6776

6877
// IMPORTANT: Don't set session immediately - wait for OAuth checks to complete

frontend/src/components/PhotoMealUpload.jsx

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export default function PhotoMealUpload({ onMealAdded }) {
2525
const [customMealName, setCustomMealName] = useState('');
2626
const [isNameManuallyEdited, setIsNameManuallyEdited] = useState(false);
2727
const [dietaryRestrictions, setDietaryRestrictions] = useState([]);
28+
const [showPhotoModal, setShowPhotoModal] = useState(false);
2829

2930
// Fetch user dietary restrictions on mount
3031
useEffect(() => {
@@ -716,7 +717,13 @@ export default function PhotoMealUpload({ onMealAdded }) {
716717
{preview && !result && (
717718
<div>
718719
<div className="relative">
719-
<img src={preview} alt="Preview" className="w-full mb-4 max-h-64 object-cover" />
720+
<img
721+
src={preview}
722+
alt="Preview"
723+
className="w-full mb-4 max-h-64 object-cover cursor-pointer hover:opacity-90 transition"
724+
onClick={() => setShowPhotoModal(true)}
725+
title="Click to view full size"
726+
/>
720727
<button
721728
onClick={() => {
722729
setSelectedFile(null);
@@ -790,7 +797,13 @@ export default function PhotoMealUpload({ onMealAdded }) {
790797
{editableResult && (
791798
<div className="space-y-4">
792799
<div className="relative">
793-
<img src={preview} alt="Analyzed" className="w-full max-h-48 object-cover" />
800+
<img
801+
src={preview}
802+
alt="Analyzed"
803+
className="w-full max-h-48 object-cover cursor-pointer hover:opacity-90 transition"
804+
onClick={() => setShowPhotoModal(true)}
805+
title="Click to view full size"
806+
/>
794807
<button
795808
onClick={() => {
796809
setResult(null);
@@ -1125,6 +1138,30 @@ export default function PhotoMealUpload({ onMealAdded }) {
11251138
</div>
11261139
</div>
11271140
)}
1141+
1142+
{/* Photo Preview Modal */}
1143+
{showPhotoModal && preview && (
1144+
<div
1145+
className="fixed inset-0 z-50 flex items-center justify-center bg-black/90 p-4"
1146+
onClick={() => setShowPhotoModal(false)}
1147+
>
1148+
<div className="relative max-w-4xl max-h-[90vh] w-full">
1149+
<button
1150+
onClick={() => setShowPhotoModal(false)}
1151+
className="absolute -top-10 right-0 text-white/70 hover:text-white transition text-sm flex items-center gap-2"
1152+
>
1153+
<span>Close</span>
1154+
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
1155+
</button>
1156+
<img
1157+
src={preview}
1158+
alt="Full size preview"
1159+
className="w-full h-full object-contain max-h-[85vh]"
1160+
onClick={(e) => e.stopPropagation()}
1161+
/>
1162+
</div>
1163+
</div>
1164+
)}
11281165
</div>
11291166
);
11301167
}

frontend/src/pages/ResetPassword.jsx

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,31 @@ export default function ResetPassword() {
1010
const [error, setError] = useState(null);
1111
const [success, setSuccess] = useState(false);
1212
const [isOAuthAccount, setIsOAuthAccount] = useState(false);
13+
const [isRecoverySession, setIsRecoverySession] = useState(false);
1314
const [showPassword, setShowPassword] = useState(false);
1415
const [showConfirmPassword, setShowConfirmPassword] = useState(false);
1516
const navigate = useNavigate();
1617

1718
useEffect(() => {
1819
// Check if this is an OAuth-only account (no password set yet)
1920
const checkAuthProvider = async () => {
20-
// Parse URL hash for Supabase auth parameters
21+
// Check sessionStorage for recovery flag (set by App.jsx when hash was detected)
22+
const recoveryActive = sessionStorage.getItem('password_recovery_active') === 'true';
23+
24+
// Also check URL hash as fallback (in case user navigated directly)
2125
const hashParams = new URLSearchParams(window.location.hash.substring(1));
2226
const tokenType = hashParams.get('type');
2327
const accessToken = hashParams.get('access_token');
2428

29+
console.log('Recovery active from sessionStorage:', recoveryActive);
2530
console.log('URL hash type:', tokenType);
2631
console.log('Has access token:', !!accessToken);
2732

28-
// If coming from password reset email (has type=recovery in hash)
33+
// If coming from password reset email (recovery flag set or hash present)
2934
// ALWAYS show password reset form, never redirect
30-
if (tokenType === 'recovery' || accessToken) {
35+
if (recoveryActive || tokenType === 'recovery' || accessToken) {
3136
console.log('Password reset link detected - showing reset form');
37+
setIsRecoverySession(true);
3238
setIsOAuthAccount(false);
3339
return;
3440
}
@@ -79,17 +85,16 @@ export default function ResetPassword() {
7985
setError(updateError.message);
8086
setLoading(false);
8187
} else {
82-
// Check again if this was a password reset (recovery) session
83-
const hashParams = new URLSearchParams(window.location.hash.substring(1));
84-
const wasRecoverySession = hashParams.get('type') === 'recovery';
85-
8688
console.log('Password updated successfully');
87-
console.log('Was recovery session:', wasRecoverySession);
89+
console.log('Was recovery session:', isRecoverySession);
8890
console.log('Is OAuth account:', isOAuthAccount);
8991

9092
// If they came from a password reset link, sign them out regardless of OAuth
91-
if (wasRecoverySession) {
93+
if (isRecoverySession) {
9294
console.log('Recovery session - signing out user');
95+
// Clear the URL hash and recovery flag to prevent recovery loop
96+
window.history.replaceState(null, '', window.location.pathname);
97+
sessionStorage.removeItem('password_recovery_active');
9398
await supabase.auth.signOut();
9499
setSuccess(true);
95100
} else if (isOAuthAccount) {

0 commit comments

Comments
 (0)