// This module is only meant to be used in Server Components in the app/ directory // It cannot be imported in Client Components or pages/ directory import { redirect } from 'next/navigation'; import { CustomerResponse, CustomerStats } from './api-client'; // Dynamically import cookies to prevent build errors let cookiesModule: any; try { // This will only work in server components cookiesModule = require('next/headers'); } catch (error) { console.warn('Warning: next/headers only works in Server Components in the app/ directory'); } /** * Constructs a server-side API URL for backend requests * Used in Server Components and API routes to directly access the backend API * * @param endpoint The API endpoint path * @returns A complete URL to the backend API */ function getServerApiUrl(endpoint: string): string { const apiUrl = process.env.SERVER_API_URL || 'https://internal-api.inboxi.ng/api'; const cleanEndpoint = endpoint.startsWith('/') ? endpoint.substring(1) : endpoint; return apiUrl.endsWith('/') ? `${apiUrl}${cleanEndpoint}` : `${apiUrl}/${cleanEndpoint}`; } /** * Server-side fetch wrapper with authentication. * Used in Server Components to make authenticated API requests to the backend. * This uses the SERVER_API_URL environment variable and is different from client-side fetching. * * @throws Error if used outside of a Server Component in the app/ directory */ export async function fetchServer( endpoint: string, options: RequestInit = {} ): Promise { // Check if we're in a server component context if (!cookiesModule?.cookies) { throw new Error( "fetchServer can only be used in Server Components in the app/ directory. " + "For client components, use clientFetch or fetchClient instead." ); } // Get auth token from cookies const cookieStore = await cookiesModule.cookies(); const authToken = cookieStore.get('Authorization')?.value; // Redirect to login if not authenticated if (!authToken) redirect('/login'); try { // Get the complete backend URL using the utility function const url = getServerApiUrl(endpoint); // Make the request with proper auth headers const res = await fetch(url, { ...options, headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${authToken}`, ...options.headers, }, cache: 'no-store', // Always fetch fresh data }); // Handle auth failures if (res.status === 401) redirect('/login'); // Handle other errors if (!res.ok) { const errorData = await res.json().catch(() => ({})); const errorMessage = errorData.message || errorData.error || `Request failed: ${res.status} ${res.statusText}`; throw new Error(errorMessage); } // Handle 204 No Content responses if (res.status === 204) { return {} as T; } return await res.json(); } catch (error) { console.error(`Server request to ${endpoint} failed:`, error); throw error; } } /** * Get a paginated list of customers (server-side) * @param page Page number (starting from 1) * @param limit Number of items per page * @returns Promise with customers data and total count */ export const getCustomersServer = async (page: number = 1, limit: number = 25): Promise => { return fetchServer(`/customers?page=${page}&limit=${limit}`); }; /** * Get detailed stats for a specific customer (server-side) * @param userId The customer's user ID * @returns Promise with detailed customer stats */ export const getCustomerDetailsServer = async (userId: string): Promise => { return fetchServer(`/customers/${userId}`); }; // Server-side platform stats function export async function getPlatformStatsServer() { try { const url = getServerApiUrl('/stats/platform'); // Make direct request without auth const res = await fetch(url, { cache: 'no-store', // Always fetch fresh data headers: { 'Content-Type': 'application/json' } }); const data = await res.json(); // If we have real data, use it if (data && Object.keys(data).length > 0) { return data; } // If API returned empty data, use sample data console.info('Using sample stats data for demo'); return { orders: { completed: 1289 }, vendors: { total: 15 }, transactions: { volume: 38450, averageOrderValue: 29.83 } }; } catch (error) { console.error('Error fetching platform stats (server):', error); // Return default stats to prevent UI breakage return { orders: { completed: 0 }, vendors: { total: 0 }, transactions: { volume: 0, averageOrderValue: 0 } }; } } // Analytics Types for server-side export interface AnalyticsOverview { orders: { total: number; completed: number; pending: number; completionRate: string; }; revenue: { total: number; monthly: number; weekly: number; averageOrderValue: number; }; products: { total: number; }; customers: { unique: number; }; userType?: 'vendor' | 'staff'; } export interface RevenueData { _id: { year: number; month: number; day: number; }; revenue: number; orders: number; } export interface ProductPerformance { productId: string; name: string; image: string; unitType: string; currentStock: number; stockStatus: string; totalSold: number; totalRevenue: number; orderCount: number; averagePrice: number; } export interface CustomerInsights { totalCustomers: number; segments: { new: number; returning: number; loyal: number; vip: number; }; topCustomers: Array<{ _id: string; orderCount: number; totalSpent: number; averageOrderValue: number; firstOrder: string; lastOrder: string; }>; averageOrdersPerCustomer: string; } export interface OrderAnalytics { statusDistribution: Array<{ _id: string; count: number; }>; dailyOrders: Array<{ _id: { year: number; month: number; day: number; }; orders: number; revenue: number; }>; averageProcessingDays: number; } // Server-side analytics functions export const getAnalyticsOverviewServer = async (storeId?: string): Promise => { const url = storeId ? `/analytics/overview?storeId=${storeId}` : '/analytics/overview'; return fetchServer(url); }; export const getRevenueTrendsServer = async (period: string = '30', storeId?: string): Promise => { const params = new URLSearchParams({ period }); if (storeId) params.append('storeId', storeId); const url = `/analytics/revenue-trends?${params.toString()}`; return fetchServer(url); }; export const getProductPerformanceServer = async (storeId?: string): Promise => { const url = storeId ? `/analytics/product-performance?storeId=${storeId}` : '/analytics/product-performance'; return fetchServer(url); }; export const getCustomerInsightsServer = async (storeId?: string): Promise => { const url = storeId ? `/analytics/customer-insights?storeId=${storeId}` : '/analytics/customer-insights'; return fetchServer(url); }; export const getOrderAnalyticsServer = async (period: string = '30', storeId?: string): Promise => { const params = new URLSearchParams({ period }); if (storeId) params.append('storeId', storeId); const url = `/analytics/order-analytics?${params.toString()}`; return fetchServer(url); };