"use client"; import { clientFetch } from "../api-client"; // Analytics Types 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; displayName?: string; username?: string; }>; averageOrdersPerCustomer: string; pagination?: { currentPage: number; totalPages: number; totalCustomers: number; limit: number; hasNextPage: boolean; hasPrevPage: boolean; startIndex: number; endIndex: number; }; } export interface OrderAnalytics { statusDistribution: Array<{ _id: string; count: number; }>; } export interface GrowthAnalytics { launchDate: string; generatedAt: string; daily: Array<{ date: string; orders: number; revenue: number; customers: number; avgOrderValue: number; }>; monthly: Array<{ month: string; orders: number; revenue: number; customers: number; avgOrderValue: number; newCustomers: number; }>; customers: { total: number; segments: { new: number; returning: number; loyal: number; vip: number; }; segmentDetails: { [key: string]: { count: number; totalRevenue: number; avgOrderCount: number; avgSpent: number; }; }; segmentPercentages: { new: number; returning: number; loyal: number; vip: number; }; }; cumulative: { orders: number; revenue: number; customers: number; products: number; avgOrderValue: number; }; } // Analytics Service Functions /** * Get analytics overview data * @param storeId Optional storeId for staff users */ export const getAnalyticsOverview = async ( storeId?: string, ): Promise => { const url = storeId ? `/analytics/overview?storeId=${storeId}` : "/analytics/overview"; return clientFetch(url); }; /** * Get revenue trends data * @param period Time period in days (7, 30, 90) * @param storeId Optional storeId for staff users */ export const getRevenueTrends = 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 clientFetch(url); }; /** * Get product performance data * @param storeId Optional storeId for staff users */ export const getProductPerformance = async ( storeId?: string, ): Promise => { const url = storeId ? `/analytics/product-performance?storeId=${storeId}` : "/analytics/product-performance"; return clientFetch(url); }; /** * Get customer insights data * @param storeId Optional storeId for staff users * @param page Page number (default: 1) * @param limit Number of customers per page (default: 10) */ export const getCustomerInsights = async ( storeId?: string, page: number = 1, limit: number = 10, ): Promise => { const params = new URLSearchParams({ page: page.toString(), limit: limit.toString(), }); if (storeId) params.append("storeId", storeId); const url = `/analytics/customer-insights?${params.toString()}`; return clientFetch(url); }; /** * Get order analytics data * @param period Time period in days (7, 30, 90) * @param storeId Optional storeId for staff users */ export const getOrderAnalytics = 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 clientFetch(url); }; /** * Get growth analytics data (since first order) * @param storeId Optional storeId for staff users */ export const getGrowthAnalytics = async ( storeId?: string, ): Promise => { const params = new URLSearchParams(); if (storeId) params.append("storeId", storeId); const url = params.toString() ? `/analytics/growth?${params.toString()}` : "/analytics/growth"; return clientFetch(url); }; // Helper function to determine if user is staff and get storeId export const getStoreIdForUser = (): string | undefined => { if (typeof window === "undefined") return undefined; // Check if user is staff (you might need to adjust this based on your auth system) const userType = localStorage.getItem("userType"); const storeId = localStorage.getItem("storeId"); if (userType === "staff" && storeId) { return storeId; } return undefined; }; // Enhanced analytics functions that automatically handle storeId for staff users export const getAnalyticsOverviewWithStore = async (): Promise => { const storeId = getStoreIdForUser(); return getAnalyticsOverview(storeId); }; export const getRevenueTrendsWithStore = async ( period: string = "30", ): Promise => { const storeId = getStoreIdForUser(); return getRevenueTrends(period, storeId); }; export const getProductPerformanceWithStore = async (): Promise< ProductPerformance[] > => { const storeId = getStoreIdForUser(); return getProductPerformance(storeId); }; export const getCustomerInsightsWithStore = async ( page: number = 1, limit: number = 10, ): Promise => { const storeId = getStoreIdForUser(); return getCustomerInsights(storeId, page, limit); }; export const getOrderAnalyticsWithStore = async ( period: string = "30", ): Promise => { const storeId = getStoreIdForUser(); return getOrderAnalytics(period, storeId); }; export const getGrowthAnalyticsWithStore = async (): Promise => { const storeId = getStoreIdForUser(); return getGrowthAnalytics(storeId); }; export function formatGBP(value: number) { return value.toLocaleString("en-GB", { style: "currency", currency: "GBP", minimumFractionDigits: 2, maximumFractionDigits: 2, }); } // Prediction Types export interface SalesPrediction { predicted: number | null; predictedOrders: number | null; dailyPredictions?: Array<{ day: number; predicted: number; date: string; }>; confidence: "very_high" | "high" | "medium" | "low"; method: string; methods?: { aiNeuralNetwork?: number | null; weightedMovingAverage?: number | null; exponentialSmoothing?: number | null; holtWinters?: number | null; weightedLinearRegression?: number | null; trendAdjusted?: number | null; }; aiModel?: { used: boolean; available?: boolean; confidence?: string; modelAccuracy?: number; error?: string | null; }; trend?: { direction: "up" | "down" | "neutral"; strength: number; acceleration: number; slope?: number; }; variance?: number; minPrediction?: number; maxPrediction?: number; confidenceScore?: number; confidenceIntervals?: { lower: number; upper: number; confidenceScore?: number; modelAgreement?: number; avgModelAccuracy?: number; dataConsistency?: number; }; modelPerformance?: { [key: string]: { mae?: number; mape?: number; rmse?: number; accuracy?: number; confidence?: string; }; }; seasonality?: { dayOfWeek: Record; month: Record; confidence: string; }; historicalPeriod: number; predictionPeriod: number; message?: string; } export interface DemandPrediction { predictedDaily: number | null; predictedWeekly: number | null; predictedMonthly: number | null; confidence: "very_high" | "high" | "medium" | "low"; averageDaily?: number; trendFactor?: number; stdDev?: number; confidenceIntervals?: { lower: number; upper: number; confidenceScore?: number; modelAgreement?: number; avgModelAccuracy?: number; dataConsistency?: number; }; historicalPeriod: number; predictionPeriod: number; productId?: string | null; message?: string; } export interface StockPrediction { productId: string; productName: string; currentStock: number; lowStockThreshold: number; unitType: string; prediction: { daysUntilOutOfStock: number | null; estimatedDate: string | null; confidence: "very_high" | "high" | "medium" | "low"; averageDailySales?: number; stdDev?: number; optimisticDays?: number | null; pessimisticDays?: number | null; optimisticDate?: string | null; pessimisticDate?: string | null; message?: string; }; needsRestock: boolean; } export interface StockPredictionsResponse { predictions: StockPrediction[]; historicalPeriod: number; totalProducts: number; productsNeedingRestock: number; } export interface PredictionsOverview { sales: SalesPrediction; demand: DemandPrediction; stock: { totalProducts: number; message?: string; }; historicalPeriod: number; predictionPeriod: number; message?: string; } export interface BatchPredictionsResponse { success: boolean; storeId?: string; historicalPeriod?: number; horizons?: number[]; simulationFactors?: number[]; predictions?: { [horizon: string]: { [simulationFactor: string]: PredictionsOverview; }; }; totalEntries?: number; generatedAt?: string; message?: string; } // Prediction Service Functions /** * Get sales/revenue predictions * @param daysAhead Number of days to predict ahead (default: 7) * @param period Historical period in days (default: 30) * @param storeId Optional storeId for staff users */ export const getSalesPredictions = async ( daysAhead: number = 7, period: number = 30, storeId?: string, ): Promise => { const params = new URLSearchParams({ daysAhead: daysAhead.toString(), period: period.toString(), }); if (storeId) params.append("storeId", storeId); const url = `/analytics/predictions/sales?${params.toString()}`; return clientFetch(url); }; /** * Get product demand predictions * @param productId Optional product ID for specific product prediction * @param daysAhead Number of days to predict ahead (default: 7) * @param period Historical period in days (default: 30) * @param storeId Optional storeId for staff users */ export const getDemandPredictions = async ( productId?: string, daysAhead: number = 7, period: number = 30, storeId?: string, ): Promise => { const params = new URLSearchParams({ daysAhead: daysAhead.toString(), period: period.toString(), }); if (productId) params.append("productId", productId); if (storeId) params.append("storeId", storeId); const url = `/analytics/predictions/demand?${params.toString()}`; return clientFetch(url); }; /** * Get stock depletion predictions * @param period Historical period in days (default: 30) * @param storeId Optional storeId for staff users */ export const getStockPredictions = async ( period: number = 30, storeId?: string, ): Promise => { const params = new URLSearchParams({ period: period.toString(), }); if (storeId) params.append("storeId", storeId); const url = `/analytics/predictions/stock?${params.toString()}`; return clientFetch(url); }; /** * Get comprehensive predictions overview * @param daysAhead Number of days to predict ahead (default: 7) * @param period Historical period in days (default: 30) * @param storeId Optional storeId for staff users * @param simulation Simulation factor (e.g. 0.1 for +10%) */ export const getPredictionsOverview = async ( daysAhead: number = 7, period: number = 30, storeId?: string, simulation: number = 0, ): Promise => { const params = new URLSearchParams({ daysAhead: daysAhead.toString(), period: period.toString(), simulation: simulation.toString(), }); if (storeId) params.append("storeId", storeId); const url = `/analytics/predictions/overview?${params.toString()}`; return clientFetch(url); }; // Helper functions with automatic storeId handling export const getSalesPredictionsWithStore = async ( daysAhead: number = 7, period: number = 30, ): Promise => { const storeId = getStoreIdForUser(); return getSalesPredictions(daysAhead, period, storeId); }; export const getDemandPredictionsWithStore = async ( productId?: string, daysAhead: number = 7, period: number = 30, ): Promise => { const storeId = getStoreIdForUser(); return getDemandPredictions(productId, daysAhead, period, storeId); }; export const getStockPredictionsWithStore = async ( period: number = 30, ): Promise => { const storeId = getStoreIdForUser(); return getStockPredictions(period, storeId); }; export const getPredictionsOverviewWithStore = async ( daysAhead: number = 7, period: number = 30, simulation: number = 0, ): Promise => { const storeId = getStoreIdForUser(); return getPredictionsOverview(daysAhead, period, storeId, simulation); }; /** * Get all cached predictions in one request (for client-side switching) * @param period Historical period in days (default: 90) * @param storeId Optional storeId for staff users */ export const getBatchPredictions = async ( period: number = 90, storeId?: string, ): Promise => { const params = new URLSearchParams({ period: period.toString(), }); if (storeId) params.append("storeId", storeId); const url = `/analytics/predictions/batch?${params.toString()}`; return clientFetch(url); }; export const getBatchPredictionsWithStore = async ( period: number = 90, ): Promise => { const storeId = getStoreIdForUser(); return getBatchPredictions(period, storeId); };