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 });
}
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 {
const res = await fetch(targetUrl, { next: { revalidate: 30 } });
if (!res.ok) {
return NextResponse.json(
{ error: `Upstream error: ${res.status}` },
{ status: res.status }
if (endpoint === 'notebook' && slug) {
// Fetch all notebooks and filter by slug (rNotes API doesn't support slug filter)
const res = await fetch(`${RNOTES_BASE}/api/notebooks`, { next: { revalidate: 30 } });
if (!res.ok) {
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) {
return NextResponse.json(
{ 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)}`;
} else if (endpoint === 'proposals') {
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 {
return NextResponse.json({ error: 'Invalid endpoint' }, { status: 400 });
}

View File

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