diff --git a/frontend/.env.example b/frontend/.env.example index 613bd7f..c361475 100644 --- a/frontend/.env.example +++ b/frontend/.env.example @@ -10,11 +10,18 @@ NEXT_PUBLIC_API_URL=http://localhost:8521 +# Backoffice API URL (NestJS backend for Stripe, admin dashboard) +# Examples: +# Local: http://localhost:3001 +# Production: https://backoffice.gohorsejobs.com + +NEXT_PUBLIC_BACKOFFICE_URL=http://localhost:3001 + # Seeder API URL (for admin operations) -NEXT_PUBLIC_SEEDER_API_URL=http://localhost:3001 +NEXT_PUBLIC_SEEDER_API_URL=http://localhost:3002 # Scraper API URL (for importing scraped jobs) -NEXT_PUBLIC_SCRAPER_API_URL=http://localhost:3002 +NEXT_PUBLIC_SCRAPER_API_URL=http://localhost:3003 # Vercel Analytics (optional) NEXT_PUBLIC_VERCEL_ANALYTICS=false diff --git a/frontend/src/lib/api.ts b/frontend/src/lib/api.ts index 2c7d7ad..9da576f 100644 --- a/frontend/src/lib/api.ts +++ b/frontend/src/lib/api.ts @@ -462,3 +462,83 @@ export const profileApi = { return res.json(); } }; + +// ============================================================================= +// BACKOFFICE API (Stripe, Admin Dashboard, etc.) +// ============================================================================= +const BACKOFFICE_URL = process.env.NEXT_PUBLIC_BACKOFFICE_URL || ""; + +async function backofficeRequest(endpoint: string, options: RequestInit = {}): Promise { + const token = localStorage.getItem("token"); + const headers = { + "Content-Type": "application/json", + ...(token ? { Authorization: `Bearer ${token}` } : {}), + ...options.headers, + }; + + const response = await fetch(`${BACKOFFICE_URL}${endpoint}`, { + ...options, + headers, + }); + + if (!response.ok) { + const errorData = await response.json().catch(() => ({})); + throw new Error(errorData.message || `Request failed with status ${response.status}`); + } + + if (response.status === 204) { + return {} as T; + } + + return response.json(); +} + +export interface DashboardStats { + totalCompanies: number; + activeSubscriptions: number; + monthlyRevenue: number; + newCompaniesThisMonth: number; +} + +export interface RevenueByMonth { + month: string; + revenue: number; +} + +export interface SubscriptionsByPlan { + plan: string; + count: number; +} + +export interface CheckoutSessionRequest { + priceId: string; + successUrl: string; + cancelUrl: string; +} + +export interface CheckoutSessionResponse { + url: string; + sessionId: string; +} + +export const backofficeApi = { + // Admin Dashboard + admin: { + getStats: () => backofficeRequest("/admin/stats"), + getRevenue: () => backofficeRequest("/admin/revenue"), + getSubscriptionsByPlan: () => backofficeRequest("/admin/subscriptions-by-plan"), + }, + // Stripe + stripe: { + createCheckoutSession: (data: CheckoutSessionRequest) => + backofficeRequest("/stripe/checkout", { + method: "POST", + body: JSON.stringify(data), + }), + createBillingPortal: (returnUrl: string) => + backofficeRequest<{ url: string }>("/stripe/portal", { + method: "POST", + body: JSON.stringify({ returnUrl }), + }), + }, +};