Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 8 additions & 10 deletions apps/frontend/src/app/pages/LandingPage.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { useEffect, useState } from 'react';
import { Link } from 'react-router-dom';
import { useAuthStore } from '@/app/store/useAuthStore';
import { WaitlistModal } from '@/features/waitlist/components/WaitlistModal';
import { ThemeSwitcher } from '@/features/landing/components/ThemeSwitcher';
import { useLandingTheme } from '@/features/landing/hooks/useLandingTheme';
import landingReference from '@/assets/landing/landing-reference.svg';
Expand All @@ -25,7 +24,6 @@ export function LandingPage() {
const authenticated = useAuthStore((state) => state.status === 'authenticated');
const [faqIndex, setFaqIndex] = useState<number | null>(null);
const [footerNotice, setFooterNotice] = useState<string | null>(null);
const [waitlistOpen, setWaitlistOpen] = useState(false);
const workspaceHref = authenticated ? '/dashboard' : '/login';
const theme = useLandingTheme();
const dark = theme.resolved === 'dark';
Expand All @@ -36,16 +34,18 @@ export function LandingPage() {
document.documentElement.removeAttribute('data-landing-theme-boot');
}, []);

// Registration is invite-only (#341): an unauthenticated visitor's "analyze
// a repository" intent opens the waitlist instead of navigating to
// /register, which they cannot usefully complete without an invite yet.
// Self-hosted is the only deployment model for the foreseeable future
// (#382): an unauthenticated visitor's "analyze a repository" intent goes
// straight to account creation on this instance, same as it would for
// anyone standing up their own copy of PARTHA. Registration itself still
// enforces the admin-managed email allowlist (#374/#375) or the
// development bypass (#384) exactly as before -- this only changes what
// the landing page's CTA points at, not what registering requires.
const analysisCta = (className: string) =>
authenticated ? (
<Link className={className} to="/upload"><span className="sr-only">Analyze a repository</span></Link>
) : (
<button type="button" className={`${className} border-0 bg-transparent p-0`} onClick={() => setWaitlistOpen(true)}>
<span className="sr-only">Join the waitlist</span>
</button>
<Link className={className} to="/register"><span className="sr-only">Create an account</span></Link>
);

return (
Expand Down Expand Up @@ -124,8 +124,6 @@ export function LandingPage() {
</div>
)}

{waitlistOpen && <WaitlistModal dark={dark} onClose={() => setWaitlistOpen(false)} />}

{footerNotice && (
<div role="status" className="fixed bottom-5 left-1/2 z-50 w-[min(92vw,34rem)] -translate-x-1/2 rounded-2xl border border-primary/35 bg-card px-5 py-4 text-center text-sm font-medium text-foreground shadow-xl">
{footerNotice}
Expand Down
9 changes: 5 additions & 4 deletions apps/frontend/src/app/routes/router.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,12 @@ describe('deep-linked route reachability (#179)', () => {
expect(
await screen.findByRole('heading', { name: 'Reveal the system behind the code.', level: 1 }, { timeout: ROUTE_RENDER_TIMEOUT_MS }),
).toBeInTheDocument();
// Registration is invite-only (#341): an unauthenticated visitor's
// "analyze a repository" intent opens the waitlist rather than linking
// to /register, which they cannot usefully complete without an invite.
// Self-hosted is the only deployment model (#382): an unauthenticated
// visitor's "analyze a repository" intent links straight to account
// creation on this instance, not a waitlist -- registration itself
// still enforces the allowlist (#374/#375) or dev bypass (#384).
expect(screen.queryAllByRole('link', { name: /analyze a repository/i })).toHaveLength(0);
expect(screen.getAllByRole('button', { name: /join the waitlist/i }).length).toBeGreaterThan(0);
expect(screen.getAllByRole('link', { name: /create an account/i }).length).toBeGreaterThan(0);
});

it('renders Dashboard directly at /dashboard instead of 404ing', async () => {
Expand Down
Loading