Empty states (P4 follow-up): - CrewsPage and EventsPage now render the shared <EmptyState> instead of their own local copies, keeping spacing/actions/footer consistent. Become-role routes (P1): - Add src/lib/becomeRoles.tsx: single registry mapping each role slug to either a CraftProfileForm config (artist/graffiti/musician/judge/tattoo/ trainer) or a lazy bespoke page (coach/filmer/editor/photographer/ builder/skater). The 6 craft roles were already thin config wrappers, so their configs move into the registry and the wrapper files are deleted. - Replace 12 hardcoded /become-* routes + 12 imports with one /become/:role route (BecomeRolePage) that renders from the registry. - Legacy /become-<slug> URLs now redirect to /become/<slug> so shared/ bookmarked links keep working. - Update all internal links (LabPage, Index, SkatersPage, SpotDetailPage, NIP19Page, SkaterDirectoryCard) to the canonical /become/<slug> paths. Note: the 5 large bespoke forms were intentionally NOT merged into one config — they carry distinct machinery (SpotPicker, wallet/Pro, geohashing) and forcing them together would increase complexity, not reduce it. Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
57 lines
1.5 KiB
TypeScript
57 lines
1.5 KiB
TypeScript
import { Suspense } from 'react';
|
|
import { useParams } from 'react-router-dom';
|
|
import { useSeoMeta } from '@unhead/react';
|
|
import { CraftProfileForm } from '@/components/CraftProfileForm';
|
|
import { getBecomeRole } from '@/lib/becomeRoles';
|
|
import NotFound from '@/pages/NotFound';
|
|
|
|
/**
|
|
* Single entry point for every "become a <role>" flow (/become/:role).
|
|
*
|
|
* - Craft roles render the shared <CraftProfileForm> from their data config.
|
|
* - Bespoke roles render their own lazy page component.
|
|
* - Unknown roles fall through to the 404 page.
|
|
*
|
|
* This replaces 12 hardcoded routes + 12 component imports in the router.
|
|
*/
|
|
|
|
function PageLoader() {
|
|
return (
|
|
<div className="min-h-screen bg-black flex items-center justify-center">
|
|
<div className="w-8 h-8 border-2 border-[#ff0040] border-t-transparent rounded-full animate-spin" />
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default function BecomeRolePage() {
|
|
const { role: slug } = useParams<{ role: string }>();
|
|
const role = getBecomeRole(slug);
|
|
|
|
if (!role) {
|
|
return <NotFound />;
|
|
}
|
|
|
|
if (role.kind === 'craft') {
|
|
return <CraftRole role={role} />;
|
|
}
|
|
|
|
const Component = role.component;
|
|
return (
|
|
<Suspense fallback={<PageLoader />}>
|
|
<Component />
|
|
</Suspense>
|
|
);
|
|
}
|
|
|
|
function CraftRole({
|
|
role,
|
|
}: {
|
|
role: Extract<ReturnType<typeof getBecomeRole>, { kind: 'craft' }>;
|
|
}) {
|
|
useSeoMeta({
|
|
title: role.seoTitle,
|
|
description: role.seoDescription,
|
|
});
|
|
|
|
return <CraftProfileForm config={role.config} />;
|
|
}
|