Fix proxy endpoints and demo data mapping for live cross-service data

- rVote proxy: use space-scoped /api/s/{slug}/api/proposals instead of top-level
- rNotes proxy: fetch all notebooks and filter by slug server-side
- rCart demo: map carts array directly (each cart = one gear item)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jeff Emmett 2026-02-15 09:25:15 -07:00
parent 0d3d636751
commit e5f4c7040e
3 changed files with 39 additions and 31 deletions

View File

@ -12,27 +12,34 @@ export async function GET(req: NextRequest) {
return NextResponse.json({ error: 'Missing endpoint param' }, { status: 400 }); return NextResponse.json({ error: 'Missing endpoint param' }, { status: 400 });
} }
let targetUrl: string;
if (endpoint === 'notebook' && slug) {
// Get notebook by slug — use search with slug filter
targetUrl = `${RNOTES_BASE}/api/notebooks?slug=${encodeURIComponent(slug)}`;
} else if (endpoint === 'notes' && notebookId) {
targetUrl = `${RNOTES_BASE}/api/notebooks/${encodeURIComponent(notebookId)}/notes`;
} else {
return NextResponse.json({ error: 'Invalid endpoint or missing params' }, { status: 400 });
}
try { try {
const res = await fetch(targetUrl, { next: { revalidate: 30 } }); if (endpoint === 'notebook' && slug) {
if (!res.ok) { // Fetch all notebooks and filter by slug (rNotes API doesn't support slug filter)
return NextResponse.json( const res = await fetch(`${RNOTES_BASE}/api/notebooks`, { next: { revalidate: 30 } });
{ error: `Upstream error: ${res.status}` }, if (!res.ok) {
{ status: res.status } return NextResponse.json({ error: `Upstream error: ${res.status}` }, { status: res.status });
}
const notebooks = await res.json();
const notebook = Array.isArray(notebooks)
? notebooks.find((nb: { slug: string }) => nb.slug === slug)
: null;
if (!notebook) {
return NextResponse.json({ error: 'Notebook not found' }, { status: 404 });
}
return NextResponse.json(notebook);
} else if (endpoint === 'notes' && notebookId) {
const res = await fetch(
`${RNOTES_BASE}/api/notebooks/${encodeURIComponent(notebookId)}/notes`,
{ next: { revalidate: 30 } }
); );
if (!res.ok) {
return NextResponse.json({ error: `Upstream error: ${res.status}` }, { status: res.status });
}
const data = await res.json();
return NextResponse.json(data);
} else {
return NextResponse.json({ error: 'Invalid endpoint or missing params' }, { status: 400 });
} }
const data = await res.json();
return NextResponse.json(data);
} catch (e) { } catch (e) {
return NextResponse.json( return NextResponse.json(
{ error: e instanceof Error ? e.message : 'Fetch failed' }, { error: e instanceof Error ? e.message : 'Fetch failed' },

View File

@ -17,7 +17,7 @@ export async function GET(req: NextRequest) {
targetUrl = `${RVOTE_BASE}/api/spaces/${encodeURIComponent(slug)}`; targetUrl = `${RVOTE_BASE}/api/spaces/${encodeURIComponent(slug)}`;
} else if (endpoint === 'proposals') { } else if (endpoint === 'proposals') {
const status = searchParams.get('status') || 'RANKING'; const status = searchParams.get('status') || 'RANKING';
targetUrl = `${RVOTE_BASE}/api/proposals?spaceSlug=${encodeURIComponent(slug)}&status=${status}&limit=10`; targetUrl = `${RVOTE_BASE}/api/s/${encodeURIComponent(slug)}/api/proposals?status=${status}&limit=10`;
} else { } else {
return NextResponse.json({ error: 'Invalid endpoint' }, { status: 400 }); return NextResponse.json({ error: 'Invalid endpoint' }, { status: 400 });
} }

View File

@ -676,18 +676,19 @@ export default function DemoContent() {
}) })
.then((data) => { .then((data) => {
if (Array.isArray(data) && data.length > 0) { if (Array.isArray(data) && data.length > 0) {
const cart = data[0] setCartData(
if (cart.items?.length > 0) { data.map((cart: Record<string, unknown>) => {
setCartData( const target = Number(cart.targetAmount) || 100
cart.items.map((item: Record<string, unknown>) => ({ const funded = Number(cart.fundedAmount) || 0
item: item.name as string, return {
target: (item.targetAmount as number) || 100, item: cart.name as string,
funded: (item.fundedAmount as number) || 0, target,
status: ((item.fundedAmount as number) || 0) >= ((item.targetAmount as number) || 100) ? 'Purchased' : 'Funding', funded,
})) status: (funded >= target ? 'Purchased' : 'Funding') as 'Purchased' | 'Funding',
) }
setLiveFlags((f) => ({ ...f, cart: true })) })
} )
setLiveFlags((f) => ({ ...f, cart: true }))
} }
}) })
.catch(() => { .catch(() => {