- New addressable kinds 35007–35011 with types, label maps and parsers - Shared parseCraftBase helper + parseLabProfile dispatcher in useLabProfiles - Reusable, config-driven CraftProfileForm (polished shared shell, per-craft skill sections + extra fields, entity/collective, CLINK, Pro upgrade) - Five thin Become* pages wired into AppRouter and the Lab "Offer" menu - LabPage: extended ServiceType, accents, scrollable tab strip, filter sections, counts, empty states and ProfileCard to all 10 crafts - CoachDetailPage renders all craft types (map-driven accents/icons/labels) plus craft-specific fields (studio, books-open, credentials, remote, graffiti crew, music links) - NIP.md documents all five new craft schemas Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
161 lines
9.3 KiB
TypeScript
161 lines
9.3 KiB
TypeScript
import { lazy, Suspense } from "react";
|
|
import { HashRouter, Route, Routes } from "react-router-dom";
|
|
import { ScrollToTop } from "./components/ScrollToTop";
|
|
import { DeepLinkHandler } from "./components/DeepLinkHandler";
|
|
|
|
// Eagerly load the map — it's now the homepage
|
|
import MapPage from "./pages/MapPage";
|
|
|
|
// Lazy load everything else — each page becomes its own JS chunk
|
|
const Index = lazy(() => import("./pages/Index"));
|
|
const EventsPage = lazy(() => import("./pages/EventsPage"));
|
|
const LabPage = lazy(() => import("./pages/LabPage"));
|
|
const WalletPage = lazy(() => import("./pages/WalletPage"));
|
|
const SettingsPage = lazy(() => import("./pages/SettingsPage"));
|
|
const CreateSpotPage = lazy(() => import("./pages/CreateSpotPage"));
|
|
const CreateShopPage = lazy(() => import("./pages/CreateShopPage"));
|
|
const CreateEventPage = lazy(() => import("./pages/CreateEventPage"));
|
|
const CreateListingPage = lazy(() => import("./pages/CreateListingPage"));
|
|
const CreateTourPage = lazy(() => import("./pages/CreateTourPage"));
|
|
const EditSpotPage = lazy(() => import("./pages/EditSpotPage"));
|
|
const EditShopPage = lazy(() => import("./pages/EditShopPage"));
|
|
const EditEventPage = lazy(() => import("./pages/EditEventPage"));
|
|
const GearSwapPage = lazy(() => import("./pages/GearSwapPage"));
|
|
const SpotDetailPage = lazy(() => import("./pages/SpotDetailPage"));
|
|
const ShopDetailPage = lazy(() => import("./pages/ShopDetailPage"));
|
|
const EventDetailPage = lazy(() => import("./pages/EventDetailPage"));
|
|
const OnboardingPage = lazy(() => import("./pages/OnboardingPage"));
|
|
const PyramidPage = lazy(() => import("./pages/PyramidPage"));
|
|
const BecomeCoachPage = lazy(() => import("./pages/BecomeCoachPage"));
|
|
const BecomeFilmerPage = lazy(() => import("./pages/BecomeFilmerPage"));
|
|
const BecomeEditorPage = lazy(() => import("./pages/BecomeEditorPage"));
|
|
const BecomePhotographerPage = lazy(() => import("./pages/BecomePhotographerPage"));
|
|
const BecomeBuilderPage = lazy(() => import("./pages/BecomeBuilderPage"));
|
|
const BecomeArtistPage = lazy(() => import("./pages/BecomeArtistPage"));
|
|
const BecomeGraffitiPage = lazy(() => import("./pages/BecomeGraffitiPage"));
|
|
const BecomeTattooPage = lazy(() => import("./pages/BecomeTattooPage"));
|
|
const BecomeTrainerPage = lazy(() => import("./pages/BecomeTrainerPage"));
|
|
const BecomeMusicianPage = lazy(() => import("./pages/BecomeMusicianPage"));
|
|
const CrewsPage = lazy(() => import("./pages/CrewsPage"));
|
|
const CreateCrewPage = lazy(() => import("./pages/CreateCrewPage"));
|
|
const EditCrewPage = lazy(() => import("./pages/EditCrewPage"));
|
|
const CrewDetailPage = lazy(() => import("./pages/CrewDetailPage"));
|
|
const CoachDetailPage = lazy(() => import("./pages/CoachDetailPage"));
|
|
const TourDetailPage = lazy(() => import("./pages/TourDetailPage"));
|
|
const AboutPage = lazy(() => import("./pages/AboutPage"));
|
|
const FAQPage = lazy(() => import("./pages/FAQPage"));
|
|
const FoodPage = lazy(() => import("./pages/FoodPage"));
|
|
const CommunityStatsPage = lazy(() => import("./pages/CommunityStatsPage"));
|
|
const SpotCollectionsPage = lazy(() => import("./pages/SpotCollectionsPage"));
|
|
const CollectionDetailPage = lazy(() => import("./pages/CollectionDetailPage"));
|
|
const DirectMessagesPage = lazy(() => import("./pages/DirectMessagesPage"));
|
|
const ConversationPage = lazy(() => import("./pages/ConversationPage"));
|
|
const ContactsPage = lazy(() => import("./pages/ContactsPage"));
|
|
const BountyLeaderboardPage = lazy(() => import("./pages/BountyLeaderboardPage"));
|
|
const SignersPage = lazy(() => import("./pages/SignersPage"));
|
|
const StashPage = lazy(() => import("./pages/StashPage"));
|
|
const NIP19Page = lazy(() => import("./pages/NIP19Page").then(m => ({ default: m.NIP19Page })));
|
|
const LicensePage = lazy(() => import("./pages/LicensePage"));
|
|
const SupportersPage = lazy(() => import("./pages/SupportersPage"));
|
|
const RiderCardPage = lazy(() => import("./pages/RiderCardPage"));
|
|
const AmberCallbackPage = lazy(() => import("./pages/AmberCallbackPage"));
|
|
const MarketplacePage = lazy(() => import("./pages/MarketplacePage"));
|
|
const NewsletterPage = lazy(() => import("./pages/NewsletterPage"));
|
|
const GlossaryPage = lazy(() => import("./pages/GlossaryPage"));
|
|
const NotFound = lazy(() => import("./pages/NotFound"));
|
|
|
|
// Minimal inline fallback — no extra component needed
|
|
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 function AppRouter() {
|
|
return (
|
|
<HashRouter>
|
|
<DeepLinkHandler />
|
|
<ScrollToTop />
|
|
<Suspense fallback={<PageLoader />}>
|
|
<Routes>
|
|
{/* Map is the homepage */}
|
|
<Route path="/" element={<MapPage />} />
|
|
{/* /map redirects to / */}
|
|
<Route path="/map" element={<MapPage />} />
|
|
{/* Legacy home page still accessible */}
|
|
<Route path="/home" element={<Index />} />
|
|
<Route path="/events" element={<EventsPage />} />
|
|
<Route path="/lab" element={<LabPage />} />
|
|
{/* Legacy route redirect */}
|
|
<Route path="/coaches" element={<LabPage />} />
|
|
<Route path="/become-coach" element={<BecomeCoachPage />} />
|
|
<Route path="/become-filmer" element={<BecomeFilmerPage />} />
|
|
<Route path="/become-editor" element={<BecomeEditorPage />} />
|
|
<Route path="/become-photographer" element={<BecomePhotographerPage />} />
|
|
<Route path="/become-builder" element={<BecomeBuilderPage />} />
|
|
<Route path="/become-artist" element={<BecomeArtistPage />} />
|
|
<Route path="/become-graffiti" element={<BecomeGraffitiPage />} />
|
|
<Route path="/become-tattoo" element={<BecomeTattooPage />} />
|
|
<Route path="/become-trainer" element={<BecomeTrainerPage />} />
|
|
<Route path="/become-musician" element={<BecomeMusicianPage />} />
|
|
<Route path="/crews" element={<CrewsPage />} />
|
|
<Route path="/create-crew" element={<CreateCrewPage />} />
|
|
<Route path="/edit-crew/:pubkey/:identifier" element={<EditCrewPage />} />
|
|
<Route path="/crew/:pubkey/:identifier" element={<CrewDetailPage />} />
|
|
<Route path="/coach/:pubkey/:identifier" element={<CoachDetailPage />} />
|
|
<Route path="/onboarding" element={<OnboardingPage />} />
|
|
<Route path="/pyramid" element={<PyramidPage />} />
|
|
<Route path="/marketplace" element={<GearSwapPage />} />
|
|
<Route path="/stats" element={<CommunityStatsPage />} />
|
|
<Route path="/about" element={<AboutPage />} />
|
|
<Route path="/faq" element={<FAQPage />} />
|
|
<Route path="/food" element={<FoodPage />} />
|
|
<Route path="/wallet" element={<WalletPage />} />
|
|
<Route path="/settings" element={<SettingsPage />} />
|
|
<Route path="/create-spot" element={<CreateSpotPage />} />
|
|
<Route path="/create-shop" element={<CreateShopPage />} />
|
|
<Route path="/create-event" element={<CreateEventPage />} />
|
|
<Route path="/create-listing" element={<CreateListingPage />} />
|
|
<Route path="/create-tour" element={<CreateTourPage />} />
|
|
<Route path="/edit-spot/:pubkey/:identifier" element={<EditSpotPage />} />
|
|
<Route path="/edit-shop/:pubkey/:identifier" element={<EditShopPage />} />
|
|
<Route path="/edit-event/:pubkey/:identifier" element={<EditEventPage />} />
|
|
<Route path="/spot/:pubkey/:identifier" element={<SpotDetailPage />} />
|
|
<Route path="/shop/:pubkey/:identifier" element={<ShopDetailPage />} />
|
|
<Route path="/event/:pubkey/:identifier" element={<EventDetailPage />} />
|
|
<Route path="/tour/:pubkey/:identifier" element={<TourDetailPage />} />
|
|
<Route path="/collections" element={<SpotCollectionsPage />} />
|
|
<Route path="/collections/:pubkey/:identifier" element={<CollectionDetailPage />} />
|
|
<Route path="/messages" element={<DirectMessagesPage />} />
|
|
<Route path="/messages/:npub" element={<ConversationPage />} />
|
|
<Route path="/contacts" element={<ContactsPage />} />
|
|
{/* Bounty System */}
|
|
<Route path="/bounties" element={<BountyLeaderboardPage />} />
|
|
{/* Security & Signers */}
|
|
<Route path="/signers" element={<SignersPage />} />
|
|
{/* Stash - Private Inventory */}
|
|
<Route path="/stash" element={<StashPage />} />
|
|
{/* Info pages */}
|
|
<Route path="/card" element={<RiderCardPage />} />
|
|
<Route path="/license" element={<LicensePage />} />
|
|
<Route path="/supporters" element={<SupportersPage />} />
|
|
{/* Amber NIP-55 callback — Amber redirects here after signing/login */}
|
|
<Route path="/amber-callback" element={<AmberCallbackPage />} />
|
|
{/* Marketplace */}
|
|
<Route path="/marketplace-listings" element={<MarketplacePage />} />
|
|
{/* Newsletter */}
|
|
<Route path="/newsletter" element={<NewsletterPage />} />
|
|
{/* Trick Glossary */}
|
|
<Route path="/glossary" element={<GlossaryPage />} />
|
|
{/* NIP-19 route for npub1, note1, naddr1, nevent1, nprofile1 */}
|
|
<Route path="/:nip19" element={<NIP19Page />} />
|
|
{/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL "*" ROUTE */}
|
|
<Route path="*" element={<NotFound />} />
|
|
</Routes>
|
|
</Suspense>
|
|
</HashRouter>
|
|
);
|
|
}
|
|
export default AppRouter;
|