diff --git a/app/admin/import-status/page.tsx b/app/admin/import-status/page.tsx index 00427ef..e25a413 100644 --- a/app/admin/import-status/page.tsx +++ b/app/admin/import-status/page.tsx @@ -46,8 +46,8 @@ export default function ImportStatusPage() { setError(null); const [summaryRes, byMerchantRes] = await Promise.all([ - fetch(`${API_BASE_URL}/api/admin/import-status/summary`), - fetch(`${API_BASE_URL}/api/admin/import-status/by-merchant`), + fetch('/api/admin/import-status/summary', { credentials: 'include' }), + fetch('/api/admin/import-status/by-merchant', { credentials: 'include' }), ]); if (!summaryRes.ok || !byMerchantRes.ok) { @@ -108,9 +108,10 @@ export default function ImportStatusPage() { try { setImportingId(merchantId); const res = await fetch( - `${API_BASE_URL}/api/admin/merchants/${merchantId}/import`, + `/api/admin/merchants/${merchantId}/import`, { method: "POST", + credentials: 'include', } ); diff --git a/app/admin/mapping/page.tsx b/app/admin/mapping/page.tsx index 7117f40..6f8733b 100644 --- a/app/admin/mapping/page.tsx +++ b/app/admin/mapping/page.tsx @@ -198,8 +198,9 @@ export default function MappingAdminPage() { // EXPECTED backend endpoint (new): // GET { merchants: [{id,name}], canonicalCategories: [{id,name,slug}] } - const res = await fetch(`${API_BASE_URL}/api/admin/mapping/options`, { + const res = await fetch('/api/admin/mapping/options', { headers: { Accept: "application/json" }, + credentials: 'include', cache: "no-store", }); @@ -243,8 +244,9 @@ export default function MappingAdminPage() { if (tab === "roles") { // Existing endpoint you already have: // GET /api/admin/mapping/pending-buckets - const res = await fetch(`${API_BASE_URL}/api/admin/mapping/pending-buckets`, { + const res = await fetch('/api/admin/mapping/pending-buckets', { headers: { Accept: "application/json" }, + credentials: 'include', cache: "no-store", }); @@ -277,8 +279,8 @@ export default function MappingAdminPage() { if (q?.trim()) params.set("q", q.trim()); const res = await fetch( - `${API_BASE_URL}/api/admin/mapping/raw-categories?${params.toString()}`, - { headers: { Accept: "application/json" }, cache: "no-store" } + `/api/admin/mapping/raw-categories?${params.toString()}`, + { headers: { Accept: "application/json" }, credentials: 'include', cache: "no-store" } ); if (!res.ok) { @@ -336,9 +338,10 @@ export default function MappingAdminPage() { // Existing endpoint you already have: // POST /api/admin/mapping/apply - const res = await fetch(`${API_BASE_URL}/api/admin/mapping/apply`, { + const res = await fetch('/api/admin/mapping/apply', { method: "POST", headers: { "Content-Type": "application/json" }, + credentials: 'include', body: JSON.stringify({ merchantId: row.merchantId, rawCategoryKey: row.rawCategoryKey, @@ -390,9 +393,10 @@ export default function MappingAdminPage() { // EXPECTED new endpoint: // POST /api/admin/mapping/upsert - const res = await fetch(`${API_BASE_URL}/api/admin/mapping/upsert`, { + const res = await fetch('/api/admin/mapping/upsert', { method: "POST", headers: { "Content-Type": "application/json" }, + credentials: 'include', body: JSON.stringify({ merchantId: row.merchantId, platform: row.platform ?? platform ?? null, diff --git a/app/admin/page.tsx b/app/admin/page.tsx index b9ebe27..05d54c7 100644 --- a/app/admin/page.tsx +++ b/app/admin/page.tsx @@ -24,7 +24,9 @@ export default function AdminLandingPage() { try { setLoading(true); setError(null); - const res = await fetch(`${API_BASE_URL}/api/admin/dashboard/overview`); + const res = await fetch('/api/admin/dashboard/overview', { + credentials: 'include', + }); if (!res.ok) { throw new Error(`Failed to load dashboard (${res.status})`); } diff --git a/app/api/admin/dashboard/overview/route.ts b/app/api/admin/dashboard/overview/route.ts new file mode 100644 index 0000000..5e5607c --- /dev/null +++ b/app/api/admin/dashboard/overview/route.ts @@ -0,0 +1,35 @@ +import { NextResponse } from 'next/server'; +import { cookies } from 'next/headers'; + +const API_BASE_URL = process.env.API_BASE_URL || process.env.NEXT_PUBLIC_API_BASE_URL; + +async function getAuthHeader() { + const token = cookies().get('session_token')?.value; + if (!token) throw new Error('Unauthorized'); + return { Authorization: `Bearer ${token}` }; +} + +export async function GET() { + try { + const headers = await getAuthHeader(); + + const res = await fetch(`${API_BASE_URL}/api/admin/dashboard/overview`, { + headers, + cache: 'no-store', + }); + + if (!res.ok) { + return NextResponse.json( + { error: await res.text() }, + { status: res.status } + ); + } + + return NextResponse.json(await res.json()); + } catch (err: any) { + return NextResponse.json( + { error: err?.message || 'Unauthorized' }, + { status: 401 } + ); + } +} diff --git a/app/api/admin/import-status/by-merchant/route.ts b/app/api/admin/import-status/by-merchant/route.ts new file mode 100644 index 0000000..c25fac7 --- /dev/null +++ b/app/api/admin/import-status/by-merchant/route.ts @@ -0,0 +1,35 @@ +import { NextResponse } from 'next/server'; +import { cookies } from 'next/headers'; + +const API_BASE_URL = process.env.API_BASE_URL || process.env.NEXT_PUBLIC_API_BASE_URL; + +async function getAuthHeader() { + const token = cookies().get('session_token')?.value; + if (!token) throw new Error('Unauthorized'); + return { Authorization: `Bearer ${token}` }; +} + +export async function GET() { + try { + const headers = await getAuthHeader(); + + const res = await fetch(`${API_BASE_URL}/api/admin/import-status/by-merchant`, { + headers, + cache: 'no-store', + }); + + if (!res.ok) { + return NextResponse.json( + { error: await res.text() }, + { status: res.status } + ); + } + + return NextResponse.json(await res.json()); + } catch (err: any) { + return NextResponse.json( + { error: err?.message || 'Unauthorized' }, + { status: 401 } + ); + } +} diff --git a/app/api/admin/import-status/summary/route.ts b/app/api/admin/import-status/summary/route.ts new file mode 100644 index 0000000..2da4586 --- /dev/null +++ b/app/api/admin/import-status/summary/route.ts @@ -0,0 +1,35 @@ +import { NextResponse } from 'next/server'; +import { cookies } from 'next/headers'; + +const API_BASE_URL = process.env.API_BASE_URL || process.env.NEXT_PUBLIC_API_BASE_URL; + +async function getAuthHeader() { + const token = cookies().get('session_token')?.value; + if (!token) throw new Error('Unauthorized'); + return { Authorization: `Bearer ${token}` }; +} + +export async function GET() { + try { + const headers = await getAuthHeader(); + + const res = await fetch(`${API_BASE_URL}/api/admin/import-status/summary`, { + headers, + cache: 'no-store', + }); + + if (!res.ok) { + return NextResponse.json( + { error: await res.text() }, + { status: res.status } + ); + } + + return NextResponse.json(await res.json()); + } catch (err: any) { + return NextResponse.json( + { error: err?.message || 'Unauthorized' }, + { status: 401 } + ); + } +} diff --git a/app/api/admin/mapping/apply/route.ts b/app/api/admin/mapping/apply/route.ts new file mode 100644 index 0000000..87484d4 --- /dev/null +++ b/app/api/admin/mapping/apply/route.ts @@ -0,0 +1,40 @@ +import { NextRequest, NextResponse } from 'next/server'; +import { cookies } from 'next/headers'; + +const API_BASE_URL = process.env.API_BASE_URL || process.env.NEXT_PUBLIC_API_BASE_URL; + +async function getAuthHeader() { + const token = cookies().get('session_token')?.value; + if (!token) throw new Error('Unauthorized'); + return { Authorization: `Bearer ${token}` }; +} + +export async function POST(request: NextRequest) { + try { + const headers = await getAuthHeader(); + const body = await request.json(); + + const res = await fetch(`${API_BASE_URL}/api/admin/mapping/apply`, { + method: 'POST', + headers: { + ...headers, + 'Content-Type': 'application/json', + }, + body: JSON.stringify(body), + }); + + if (!res.ok) { + return NextResponse.json( + { error: await res.text() }, + { status: res.status } + ); + } + + return NextResponse.json(await res.json()); + } catch (err: any) { + return NextResponse.json( + { error: err?.message || 'Unauthorized' }, + { status: 401 } + ); + } +} diff --git a/app/api/admin/mapping/options/route.ts b/app/api/admin/mapping/options/route.ts new file mode 100644 index 0000000..95917c9 --- /dev/null +++ b/app/api/admin/mapping/options/route.ts @@ -0,0 +1,35 @@ +import { NextResponse } from 'next/server'; +import { cookies } from 'next/headers'; + +const API_BASE_URL = process.env.API_BASE_URL || process.env.NEXT_PUBLIC_API_BASE_URL; + +async function getAuthHeader() { + const token = cookies().get('session_token')?.value; + if (!token) throw new Error('Unauthorized'); + return { Authorization: `Bearer ${token}` }; +} + +export async function GET() { + try { + const headers = await getAuthHeader(); + + const res = await fetch(`${API_BASE_URL}/api/admin/mapping/options`, { + headers, + cache: 'no-store', + }); + + if (!res.ok) { + return NextResponse.json( + { error: await res.text() }, + { status: res.status } + ); + } + + return NextResponse.json(await res.json()); + } catch (err: any) { + return NextResponse.json( + { error: err?.message || 'Unauthorized' }, + { status: 401 } + ); + } +} diff --git a/app/api/admin/mapping/pending-buckets/route.ts b/app/api/admin/mapping/pending-buckets/route.ts new file mode 100644 index 0000000..47ec6f9 --- /dev/null +++ b/app/api/admin/mapping/pending-buckets/route.ts @@ -0,0 +1,35 @@ +import { NextResponse } from 'next/server'; +import { cookies } from 'next/headers'; + +const API_BASE_URL = process.env.API_BASE_URL || process.env.NEXT_PUBLIC_API_BASE_URL; + +async function getAuthHeader() { + const token = cookies().get('session_token')?.value; + if (!token) throw new Error('Unauthorized'); + return { Authorization: `Bearer ${token}` }; +} + +export async function GET() { + try { + const headers = await getAuthHeader(); + + const res = await fetch(`${API_BASE_URL}/api/admin/mapping/pending-buckets`, { + headers, + cache: 'no-store', + }); + + if (!res.ok) { + return NextResponse.json( + { error: await res.text() }, + { status: res.status } + ); + } + + return NextResponse.json(await res.json()); + } catch (err: any) { + return NextResponse.json( + { error: err?.message || 'Unauthorized' }, + { status: 401 } + ); + } +} diff --git a/app/api/admin/mapping/raw-categories/route.ts b/app/api/admin/mapping/raw-categories/route.ts new file mode 100644 index 0000000..34bba01 --- /dev/null +++ b/app/api/admin/mapping/raw-categories/route.ts @@ -0,0 +1,39 @@ +import { NextRequest, NextResponse } from 'next/server'; +import { cookies } from 'next/headers'; + +const API_BASE_URL = process.env.API_BASE_URL || process.env.NEXT_PUBLIC_API_BASE_URL; + +async function getAuthHeader() { + const token = cookies().get('session_token')?.value; + if (!token) throw new Error('Unauthorized'); + return { Authorization: `Bearer ${token}` }; +} + +export async function GET(request: NextRequest) { + try { + const headers = await getAuthHeader(); + const { searchParams } = new URL(request.url); + + const res = await fetch( + `${API_BASE_URL}/api/admin/mapping/raw-categories?${searchParams.toString()}`, + { + headers, + cache: 'no-store', + } + ); + + if (!res.ok) { + return NextResponse.json( + { error: await res.text() }, + { status: res.status } + ); + } + + return NextResponse.json(await res.json()); + } catch (err: any) { + return NextResponse.json( + { error: err?.message || 'Unauthorized' }, + { status: 401 } + ); + } +} diff --git a/app/api/admin/mapping/upsert/route.ts b/app/api/admin/mapping/upsert/route.ts new file mode 100644 index 0000000..3496a30 --- /dev/null +++ b/app/api/admin/mapping/upsert/route.ts @@ -0,0 +1,40 @@ +import { NextRequest, NextResponse } from 'next/server'; +import { cookies } from 'next/headers'; + +const API_BASE_URL = process.env.API_BASE_URL || process.env.NEXT_PUBLIC_API_BASE_URL; + +async function getAuthHeader() { + const token = cookies().get('session_token')?.value; + if (!token) throw new Error('Unauthorized'); + return { Authorization: `Bearer ${token}` }; +} + +export async function POST(request: NextRequest) { + try { + const headers = await getAuthHeader(); + const body = await request.json(); + + const res = await fetch(`${API_BASE_URL}/api/admin/mapping/upsert`, { + method: 'POST', + headers: { + ...headers, + 'Content-Type': 'application/json', + }, + body: JSON.stringify(body), + }); + + if (!res.ok) { + return NextResponse.json( + { error: await res.text() }, + { status: res.status } + ); + } + + return NextResponse.json(await res.json()); + } catch (err: any) { + return NextResponse.json( + { error: err?.message || 'Unauthorized' }, + { status: 401 } + ); + } +}