Skip to content

Commit 90fad94

Browse files
committed
fix: scope waitlist already_joined check to current user
Prevent a stale waitlist email in localStorage from showing 'already_joined' to a different user on the same browser. Only mark as already_joined when the stored email matches the authenticated user's email, and re-evaluate when auth state loads. Adds regression test for cross-user stored email scenario.
1 parent 9535739 commit 90fad94

2 files changed

Lines changed: 41 additions & 3 deletions

File tree

src/pages/ProComingSoonPage.jsx

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,14 @@ function ProComingSoonPage() {
6969

7070
const [email, setEmail] = useState(defaultEmail);
7171
const emailEditedRef = useRef(false);
72-
const [submitState, setSubmitState] = useState(() =>
73-
readStoredWaitlistEmail() ? 'already_joined' : 'idle'
74-
);
72+
const [submitState, setSubmitState] = useState(() => {
73+
const storedEmail = readStoredWaitlistEmail();
74+
if (!storedEmail) return 'idle';
75+
const currentUserEmail = profile?.email || user?.email;
76+
return currentUserEmail && storedEmail === currentUserEmail
77+
? 'already_joined'
78+
: 'idle';
79+
});
7580
const [position, setPosition] = useState(null);
7681
const [errorKey, setErrorKey] = useState(null);
7782
const [waitlistCount, setWaitlistCount] = useState(0);
@@ -82,6 +87,17 @@ function ProComingSoonPage() {
8287
}
8388
}, [defaultEmail]);
8489

90+
// Re-evaluate already_joined when auth state loads — a different user may
91+
// have left a stale waitlist email in localStorage.
92+
useEffect(() => {
93+
if (submitState !== 'idle') return;
94+
const storedEmail = readStoredWaitlistEmail();
95+
const currentUserEmail = profile?.email || user?.email;
96+
if (storedEmail && currentUserEmail && storedEmail === currentUserEmail) {
97+
setSubmitState('already_joined');
98+
}
99+
}, [user, profile, submitState]);
100+
85101
useEffect(() => {
86102
window.scrollTo({ top: 0, behavior: 'instant' });
87103
}, []);

src/pages/ProComingSoonPage.test.jsx

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,4 +149,26 @@ describe('ProComingSoonPage', () => {
149149
screen.queryByText(/learners are on the waitlist/i)
150150
).not.toBeInTheDocument();
151151
});
152+
153+
it('does not show already_joined for a different user on same browser', async () => {
154+
const { readStoredWaitlistEmail } =
155+
await import('@/services/waitlistService.js');
156+
vi.mocked(readStoredWaitlistEmail).mockReturnValue('other@example.com');
157+
158+
const { useAuth } = await import('@/hooks/useAuth.js');
159+
useAuth.mockReturnValue({
160+
user: { id: 'u2', email: 'current@example.com' },
161+
profile: { email: 'current@example.com' },
162+
});
163+
164+
renderPage('/pro');
165+
166+
// Form should be idle, not already_joined
167+
expect(
168+
screen.queryByText(/you are already on the waitlist/i)
169+
).not.toBeInTheDocument();
170+
expect(
171+
screen.getByRole('button', { name: /join the waitlist/i })
172+
).toBeInTheDocument();
173+
});
152174
});

0 commit comments

Comments
 (0)