feat: add backoffice API client with NEXT_PUBLIC_BACKOFFICE_URL env var
This commit is contained in:
parent
b7987dead9
commit
35d3032d52
2 changed files with 89 additions and 2 deletions
|
|
@ -10,11 +10,18 @@
|
||||||
|
|
||||||
NEXT_PUBLIC_API_URL=http://localhost:8521
|
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)
|
# 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)
|
# 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)
|
# Vercel Analytics (optional)
|
||||||
NEXT_PUBLIC_VERCEL_ANALYTICS=false
|
NEXT_PUBLIC_VERCEL_ANALYTICS=false
|
||||||
|
|
|
||||||
|
|
@ -462,3 +462,83 @@ export const profileApi = {
|
||||||
return res.json();
|
return res.json();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// BACKOFFICE API (Stripe, Admin Dashboard, etc.)
|
||||||
|
// =============================================================================
|
||||||
|
const BACKOFFICE_URL = process.env.NEXT_PUBLIC_BACKOFFICE_URL || "";
|
||||||
|
|
||||||
|
async function backofficeRequest<T>(endpoint: string, options: RequestInit = {}): Promise<T> {
|
||||||
|
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<DashboardStats>("/admin/stats"),
|
||||||
|
getRevenue: () => backofficeRequest<RevenueByMonth[]>("/admin/revenue"),
|
||||||
|
getSubscriptionsByPlan: () => backofficeRequest<SubscriptionsByPlan[]>("/admin/subscriptions-by-plan"),
|
||||||
|
},
|
||||||
|
// Stripe
|
||||||
|
stripe: {
|
||||||
|
createCheckoutSession: (data: CheckoutSessionRequest) =>
|
||||||
|
backofficeRequest<CheckoutSessionResponse>("/stripe/checkout", {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
}),
|
||||||
|
createBillingPortal: (returnUrl: string) =>
|
||||||
|
backofficeRequest<{ url: string }>("/stripe/portal", {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify({ returnUrl }),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue