Files
ember-market-frontend/lib/services/analytics-service.ts
g f17d623570 Revamp growth analytics to show all-time cumulative data
Refactors GrowthAnalyticsChart to display all-time growth since first sale, removes period selection, and introduces tabbed charts for daily, monthly, and customer segment analytics. Updates the GrowthAnalytics interface and service to return cumulative and segmented data, and simplifies API usage to always fetch all-time analytics. Improves customer segment breakdown and chart visualizations.
2026-01-07 12:58:52 +00:00

301 lines
6.9 KiB
TypeScript

"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<AnalyticsOverview> => {
const url = storeId
? `/analytics/overview?storeId=${storeId}`
: "/analytics/overview";
return clientFetch<AnalyticsOverview>(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<RevenueData[]> => {
const params = new URLSearchParams({ period });
if (storeId) params.append("storeId", storeId);
const url = `/analytics/revenue-trends?${params.toString()}`;
return clientFetch<RevenueData[]>(url);
};
/**
* Get product performance data
* @param storeId Optional storeId for staff users
*/
export const getProductPerformance = async (
storeId?: string,
): Promise<ProductPerformance[]> => {
const url = storeId
? `/analytics/product-performance?storeId=${storeId}`
: "/analytics/product-performance";
return clientFetch<ProductPerformance[]>(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<CustomerInsights> => {
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<CustomerInsights>(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<OrderAnalytics> => {
const params = new URLSearchParams({ period });
if (storeId) params.append("storeId", storeId);
const url = `/analytics/order-analytics?${params.toString()}`;
return clientFetch<OrderAnalytics>(url);
};
/**
* Get growth analytics data (since first order)
* @param storeId Optional storeId for staff users
*/
export const getGrowthAnalytics = async (
storeId?: string,
): Promise<GrowthAnalytics> => {
const params = new URLSearchParams();
if (storeId) params.append("storeId", storeId);
const url = params.toString()
? `/analytics/growth?${params.toString()}`
: "/analytics/growth";
return clientFetch<GrowthAnalytics>(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<AnalyticsOverview> => {
const storeId = getStoreIdForUser();
return getAnalyticsOverview(storeId);
};
export const getRevenueTrendsWithStore = async (
period: string = "30",
): Promise<RevenueData[]> => {
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<CustomerInsights> => {
const storeId = getStoreIdForUser();
return getCustomerInsights(storeId, page, limit);
};
export const getOrderAnalyticsWithStore = async (
period: string = "30",
): Promise<OrderAnalytics> => {
const storeId = getStoreIdForUser();
return getOrderAnalytics(period, storeId);
};
export const getGrowthAnalyticsWithStore =
async (): Promise<GrowthAnalytics> => {
const storeId = getStoreIdForUser();
return getGrowthAnalytics(storeId);
};
export function formatGBP(value: number) {
return value.toLocaleString("en-GB", {
style: "currency",
currency: "GBP",
minimumFractionDigits: 2,
maximumFractionDigits: 2,
});
}