Move the all-campaigns directory from /campaigns/all to /campaigns
/campaigns was a redirect to / (the curated home), and the actual all-campaigns directory lived at /campaigns/all. Flip the routing so /campaigns IS the directory, the home page stays at /, and /campaigns/all becomes a redirect to /campaigns for any external links and bookmarks that still point there. Rewrite every internal link/navigate target accordingly (TopNav, the Browse-all CTA on the home page, the OnboardingGate donor redirect, NoteCard's kind-33863 nounRoute) and refresh the doc/comment references in NIP.md and the discovery hooks.
This commit is contained in:
@@ -70,7 +70,7 @@ Clients filter both case variants (`agora` and `Agora`) because Nostr `t` tags a
|
||||
|
||||
#### Backward compatibility
|
||||
|
||||
Events published before this marker was adopted do not carry `t:agora` and therefore do not appear in the Agora activity feed. They remain reachable by direct link and via kind-specific directories (e.g. the moderator-curated `/campaigns/all`). Authors who wish to surface a legacy event in the feed can republish it (any edit through the Agora UI will add the marker automatically).
|
||||
Events published before this marker was adopted do not carry `t:agora` and therefore do not appear in the Agora activity feed. They remain reachable by direct link and via kind-specific directories (e.g. the moderator-curated `/campaigns`). Authors who wish to surface a legacy event in the feed can republish it (any edit through the Agora UI will add the marker automatically).
|
||||
|
||||
### Community Chat
|
||||
|
||||
@@ -498,7 +498,7 @@ The `pinnedEvents` array is ordered newest pin first. Pinning an already-pinned
|
||||
|
||||
### Agora Moderation Labels
|
||||
|
||||
Agora curates which kind 33863 campaigns appear on the homepage (`/`) and on the Support directory (`/campaigns/all`), which kind 34550 organizations appear in the Featured shelf on `/communities`, and which kind 36639 pledges appear in the discovery surfaces on `/pledges`, via moderator-signed NIP-32 label events (kind 1985) in a dedicated label namespace. The labeled event itself is never modified — surfacing is purely a client-side rollup of label events.
|
||||
Agora curates which kind 33863 campaigns appear on the homepage (`/`) and on the Support directory (`/campaigns`), which kind 34550 organizations appear in the Featured shelf on `/communities`, and which kind 36639 pledges appear in the discovery surfaces on `/pledges`, via moderator-signed NIP-32 label events (kind 1985) in a dedicated label namespace. The labeled event itself is never modified — surfacing is purely a client-side rollup of label events.
|
||||
|
||||
Campaigns, organizations, and pledges share a single label namespace and a single moderator pack (Team Soapbox); the only thing distinguishing the three streams is the kind prefix on the `a` tag of each label:
|
||||
|
||||
|
||||
+5
-2
@@ -187,9 +187,12 @@ export function AppRouter() {
|
||||
constraints. */}
|
||||
<Route element={<FundraiserLayout narrow={false} />}>
|
||||
<Route path="/" element={<CampaignsPage />} />
|
||||
<Route path="/campaigns" element={<Navigate to="/" replace />} />
|
||||
<Route path="/campaigns" element={<AllCampaignsPage />} />
|
||||
<Route path="/campaigns/new" element={<CreateCampaignPage />} />
|
||||
<Route path="/campaigns/all" element={<AllCampaignsPage />} />
|
||||
{/* Legacy URL: the all-campaigns directory lived at
|
||||
`/campaigns/all` for a while. Keep it as a redirect so
|
||||
external links and bookmarks still resolve. */}
|
||||
<Route path="/campaigns/all" element={<Navigate to="/campaigns" replace />} />
|
||||
<Route path="/groups" element={<CommunitiesPage />} />
|
||||
<Route path="/groups/new" element={<CreateCommunityPage />} />
|
||||
<Route path="/events/new" element={<CreateEventPage />} />
|
||||
|
||||
@@ -1867,7 +1867,7 @@ const KIND_HEADER_MAP: Record<number, KindHeaderConfig> = {
|
||||
icon: HandHeart,
|
||||
action: (event) => publishedAtKey(event, { created: "noteCard.kindHeader.campaignLaunched", updated: "noteCard.kindHeader.campaignUpdated", fallback: "noteCard.kindHeader.campaignFallback" }),
|
||||
noun: "noteCard.kindHeader.campaignNoun",
|
||||
nounRoute: "/campaigns/all",
|
||||
nounRoute: "/campaigns",
|
||||
},
|
||||
8: {
|
||||
icon: Award,
|
||||
|
||||
@@ -132,7 +132,7 @@ function CaptiveOverlay() {
|
||||
// Role pick is the final step. Picking a role both records the choice
|
||||
// (used by the role-pick CTA labels) and navigates to the matching
|
||||
// surface: creator → campaign-creation form, donor → full campaign grid
|
||||
// (`/campaigns/all`, not `/`, so they land on the browse-everything view
|
||||
// (`/campaigns`, not `/`, so they land on the browse-everything view
|
||||
// rather than the curated home with its own marketing hero). No separate
|
||||
// outro / celebration screen.
|
||||
const handleRolePick = useCallback(
|
||||
@@ -142,7 +142,7 @@ function CaptiveOverlay() {
|
||||
if (next === 'creator') {
|
||||
navigate('/campaigns/new');
|
||||
} else {
|
||||
navigate('/campaigns/all');
|
||||
navigate('/campaigns');
|
||||
}
|
||||
},
|
||||
[setContextRole, cancel, navigate],
|
||||
|
||||
@@ -37,7 +37,7 @@ interface NavItem {
|
||||
}
|
||||
|
||||
const NAV_ITEMS: NavItem[] = [
|
||||
{ labelKey: 'nav.campaigns', to: '/campaigns/all', icon: HandHeart },
|
||||
{ labelKey: 'nav.campaigns', to: '/campaigns', icon: HandHeart },
|
||||
{ labelKey: 'nav.activity', to: '/feed', icon: Activity },
|
||||
// Groups and Pledges are intentionally hidden from the main nav for
|
||||
// launch — keep the routes and feature code intact so we can re-add
|
||||
|
||||
@@ -18,7 +18,7 @@ interface CampaignsDiscoverySectionProps {
|
||||
* Where this section's filter state lives:
|
||||
*
|
||||
* • `'url'` — flat URL params (`?q=&sort=&country=`). Used by the
|
||||
* dedicated `/campaigns/all` page so search results are
|
||||
* dedicated `/campaigns` page so search results are
|
||||
* shareable and survive refresh.
|
||||
* • `'local'` — local-only state. Used by `/` where three
|
||||
* discovery sections coexist and can't all own `?q=`.
|
||||
|
||||
@@ -3,7 +3,7 @@ import { createContext, useContext } from 'react';
|
||||
/**
|
||||
* The two top-level roles a new user can pick during onboarding. Drives
|
||||
* downstream copy (creator vs. donor framing) and the role-pick CTA target
|
||||
* (creator → /campaigns/new, donor → /campaigns/all).
|
||||
* (creator → /campaigns/new, donor → /campaigns).
|
||||
*
|
||||
* `null` before the user has answered the role-picker step.
|
||||
*/
|
||||
|
||||
@@ -12,7 +12,7 @@ import type { Nip50Sort } from '@/hooks/useNip50Search';
|
||||
* - Anything else (missing, empty, legacy values) collapses to
|
||||
* `'default'`, the curated featured-first idle state.
|
||||
*
|
||||
* Exported because the dedicated discovery pages (`/campaigns/all`,
|
||||
* Exported because the dedicated discovery pages (`/campaigns`,
|
||||
* `/pledges`) read `?sort=` independently from the section's hook to
|
||||
* thread the value into ancillary derivations (hidden-list cache
|
||||
* lookups, create-X href country prefills). One canonical parser
|
||||
@@ -52,7 +52,7 @@ interface UseDiscoveryFiltersOptions {
|
||||
* state.
|
||||
*
|
||||
* • `''` — flat URL params (`?q=…&sort=…&country=…`). The dedicated
|
||||
* browse pages (`/campaigns/all`, `/groups`, `/pledges`) want
|
||||
* browse pages (`/campaigns`, `/groups`, `/pledges`) want
|
||||
* this so search results are shareable / linkable and survive
|
||||
* refresh.
|
||||
*
|
||||
@@ -84,8 +84,8 @@ interface UseDiscoveryFiltersOptions {
|
||||
* Owns three pieces of state — search input (debounced), sort mode,
|
||||
* country code — and (optionally) mirrors them to URL params so deep
|
||||
* links and browser back/forward work. Defaults are stripped on write
|
||||
* so the canonical URL stays clean (`/campaigns/all`, not
|
||||
* `/campaigns/all?q=&sort=`).
|
||||
* so the canonical URL stays clean (`/campaigns`, not
|
||||
* `/campaigns?q=&sort=`).
|
||||
*
|
||||
* Debouncing lives inside this hook (300ms) so consumers don't have
|
||||
* to thread the debounced value back in — that would create a
|
||||
|
||||
@@ -239,7 +239,7 @@ export function CampaignsPage() {
|
||||
hidden. */}
|
||||
<div className="pt-2 text-center sm:text-left">
|
||||
<Button asChild variant="ghost" size="sm">
|
||||
<Link to="/campaigns/all">{t('campaigns.home.browseAll')}</Link>
|
||||
<Link to="/campaigns">{t('campaigns.home.browseAll')}</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
Reference in New Issue
Block a user