feat: global platform v2 update
This commit is contained in:
309
lib/demo/demo-aware-api.ts
Normal file
309
lib/demo/demo-aware-api.ts
Normal file
@@ -0,0 +1,309 @@
|
||||
// ============================================================================
|
||||
// Demo-Aware API Wrapper
|
||||
// ============================================================================
|
||||
// This wrapper checks if the workspace is demo and returns mock data instead
|
||||
|
||||
import { isDemoWorkspace, DEMO_WORKSPACE_ID } from "./constants";
|
||||
import {
|
||||
demoChannels,
|
||||
demoCreatives,
|
||||
demoPlacements,
|
||||
demoPurchasePlanChannels,
|
||||
demoSpendingAnalytics,
|
||||
demoCreativeAnalytics,
|
||||
demoChannelAnalytics,
|
||||
demoProjects,
|
||||
demoWorkspace,
|
||||
demoMember,
|
||||
} from "./mock-data";
|
||||
import type {
|
||||
PaginatedResponse,
|
||||
Channel,
|
||||
Creative,
|
||||
Placement,
|
||||
PurchasePlanChannel,
|
||||
SpendingAnalytics,
|
||||
CreativeAnalyticsItem,
|
||||
ChannelAnalyticsItem,
|
||||
Project,
|
||||
Workspace,
|
||||
WorkspaceMember,
|
||||
DateGrouping,
|
||||
} from "@/lib/types/api";
|
||||
import {
|
||||
workspacesApi,
|
||||
projectsApi,
|
||||
channelsApi,
|
||||
creativesApi,
|
||||
placementsApi,
|
||||
purchasePlanApi,
|
||||
analyticsApi,
|
||||
membersApi,
|
||||
} from "@/lib/api";
|
||||
|
||||
// ============================================================================
|
||||
// Helper
|
||||
// ============================================================================
|
||||
|
||||
const paginate = <T>(items: T[], page = 1, size = 50): PaginatedResponse<T> => ({
|
||||
items: items.slice((page - 1) * size, page * size),
|
||||
total: items.length,
|
||||
page,
|
||||
size,
|
||||
pages: Math.ceil(items.length / size),
|
||||
});
|
||||
|
||||
// ============================================================================
|
||||
// Demo-Aware Workspaces API
|
||||
// ============================================================================
|
||||
|
||||
export const demoAwareWorkspacesApi = {
|
||||
list: async (params?: { page?: number; size?: number }) => {
|
||||
// Always include demo workspace in list for demo mode
|
||||
return workspacesApi.list(params);
|
||||
},
|
||||
get: async (workspaceId: string): Promise<Workspace> => {
|
||||
if (isDemoWorkspace(workspaceId)) {
|
||||
return demoWorkspace;
|
||||
}
|
||||
// Workspaces API doesn't have get method, fetch from list
|
||||
const response = await workspacesApi.list({ size: 100 });
|
||||
const workspace = response.items.find(w => w.id === workspaceId);
|
||||
if (!workspace) throw new Error("Workspace not found");
|
||||
return workspace;
|
||||
},
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// Demo-Aware Projects API
|
||||
// ============================================================================
|
||||
|
||||
export const demoAwareProjectsApi = {
|
||||
list: async (
|
||||
workspaceId: string,
|
||||
params?: { page?: number; size?: number }
|
||||
): Promise<PaginatedResponse<Project>> => {
|
||||
if (isDemoWorkspace(workspaceId)) {
|
||||
return paginate(demoProjects, params?.page, params?.size);
|
||||
}
|
||||
return projectsApi.list(workspaceId, params);
|
||||
},
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// Demo-Aware Members API
|
||||
// ============================================================================
|
||||
|
||||
export const demoAwareMembersApi = {
|
||||
list: async (
|
||||
workspaceId: string,
|
||||
params?: { page?: number; size?: number }
|
||||
): Promise<PaginatedResponse<WorkspaceMember>> => {
|
||||
if (isDemoWorkspace(workspaceId)) {
|
||||
return paginate([demoMember], params?.page, params?.size);
|
||||
}
|
||||
return membersApi.list(workspaceId, params);
|
||||
},
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// Demo-Aware Channels API
|
||||
// ============================================================================
|
||||
|
||||
export const demoAwareChannelsApi = {
|
||||
list: async (params?: {
|
||||
page?: number;
|
||||
size?: number;
|
||||
username?: string;
|
||||
}): Promise<PaginatedResponse<Channel>> => {
|
||||
// Channels are global, check if we're in demo context via some mechanism
|
||||
// For now, always return real data - demo channels are handled per-workspace
|
||||
return channelsApi.list(params);
|
||||
},
|
||||
listForDemo: (): PaginatedResponse<Channel> => {
|
||||
return paginate(demoChannels);
|
||||
},
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// Demo-Aware Creatives API
|
||||
// ============================================================================
|
||||
|
||||
export const demoAwareCreativesApi = {
|
||||
list: async (
|
||||
workspaceId: string,
|
||||
params?: {
|
||||
project_id?: string;
|
||||
include_archived?: boolean;
|
||||
page?: number;
|
||||
size?: number;
|
||||
}
|
||||
): Promise<PaginatedResponse<Creative>> => {
|
||||
if (isDemoWorkspace(workspaceId)) {
|
||||
let items = demoCreatives;
|
||||
if (params?.project_id) {
|
||||
items = items.filter((c) => c.project_id === params.project_id);
|
||||
}
|
||||
if (!params?.include_archived) {
|
||||
items = items.filter((c) => c.status === "active");
|
||||
}
|
||||
return paginate(items, params?.page, params?.size);
|
||||
}
|
||||
return creativesApi.list(workspaceId, params);
|
||||
},
|
||||
get: async (workspaceId: string, creativeId: string): Promise<Creative> => {
|
||||
if (isDemoWorkspace(workspaceId)) {
|
||||
const creative = demoCreatives.find((c) => c.id === creativeId);
|
||||
if (!creative) throw new Error("Creative not found");
|
||||
return creative;
|
||||
}
|
||||
return creativesApi.get(workspaceId, creativeId);
|
||||
},
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// Demo-Aware Placements API
|
||||
// ============================================================================
|
||||
|
||||
export const demoAwarePlacementsApi = {
|
||||
list: async (
|
||||
workspaceId: string,
|
||||
params?: {
|
||||
project_id?: string;
|
||||
placement_channel_id?: string;
|
||||
creative_id?: string;
|
||||
include_archived?: boolean;
|
||||
page?: number;
|
||||
size?: number;
|
||||
}
|
||||
): Promise<PaginatedResponse<Placement>> => {
|
||||
if (isDemoWorkspace(workspaceId)) {
|
||||
let items = demoPlacements;
|
||||
if (params?.project_id) {
|
||||
items = items.filter((p) => p.project_id === params.project_id);
|
||||
}
|
||||
if (params?.placement_channel_id) {
|
||||
items = items.filter(
|
||||
(p) => p.placement_channel_id === params.placement_channel_id
|
||||
);
|
||||
}
|
||||
if (params?.creative_id) {
|
||||
items = items.filter((p) => p.creative_id === params.creative_id);
|
||||
}
|
||||
if (!params?.include_archived) {
|
||||
items = items.filter((p) => p.status === "active");
|
||||
}
|
||||
return paginate(items, params?.page, params?.size);
|
||||
}
|
||||
return placementsApi.list(workspaceId, params);
|
||||
},
|
||||
get: async (workspaceId: string, placementId: string): Promise<Placement> => {
|
||||
if (isDemoWorkspace(workspaceId)) {
|
||||
const placement = demoPlacements.find((p) => p.id === placementId);
|
||||
if (!placement) throw new Error("Placement not found");
|
||||
return placement;
|
||||
}
|
||||
return placementsApi.get(workspaceId, placementId);
|
||||
},
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// Demo-Aware Purchase Plan API
|
||||
// ============================================================================
|
||||
|
||||
export const demoAwarePurchasePlanApi = {
|
||||
list: async (
|
||||
workspaceId: string,
|
||||
projectId: string,
|
||||
params?: { page?: number; size?: number }
|
||||
): Promise<PaginatedResponse<PurchasePlanChannel>> => {
|
||||
if (isDemoWorkspace(workspaceId)) {
|
||||
const items = demoPurchasePlanChannels[projectId] || [];
|
||||
return paginate(items, params?.page, params?.size);
|
||||
}
|
||||
return purchasePlanApi.list(workspaceId, projectId, params);
|
||||
},
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// Demo-Aware Analytics API
|
||||
// ============================================================================
|
||||
|
||||
export const demoAwareAnalyticsApi = {
|
||||
spending: async (
|
||||
workspaceId: string,
|
||||
params?: {
|
||||
project_id?: string;
|
||||
date_from?: string;
|
||||
date_to?: string;
|
||||
grouping?: DateGrouping;
|
||||
}
|
||||
): Promise<SpendingAnalytics> => {
|
||||
if (isDemoWorkspace(workspaceId)) {
|
||||
if (params?.project_id) {
|
||||
const projectPlacements = demoPlacements.filter(
|
||||
(p) => p.project_id === params.project_id && p.status === "active"
|
||||
);
|
||||
const totalCost = projectPlacements.reduce(
|
||||
(sum, p) => sum + (p.cost || 0),
|
||||
0
|
||||
);
|
||||
const totalSubs = projectPlacements.reduce(
|
||||
(sum, p) => sum + (p.subscriptions_count || 0),
|
||||
0
|
||||
);
|
||||
const totalViews = projectPlacements.reduce(
|
||||
(sum, p) => sum + (p.views_count || 0),
|
||||
0
|
||||
);
|
||||
return {
|
||||
total_cost: totalCost,
|
||||
total_subscriptions: totalSubs,
|
||||
total_views: totalViews,
|
||||
avg_cpf: totalSubs > 0 ? totalCost / totalSubs : null,
|
||||
avg_cpm: totalViews > 0 ? (totalCost / totalViews) * 1000 : null,
|
||||
chart_data: demoSpendingAnalytics.chart_data.slice(0, 4),
|
||||
};
|
||||
}
|
||||
return demoSpendingAnalytics;
|
||||
}
|
||||
return analyticsApi.spending(workspaceId, params);
|
||||
},
|
||||
creatives: async (
|
||||
workspaceId: string,
|
||||
params?: { project_id?: string; page?: number; size?: number }
|
||||
): Promise<PaginatedResponse<CreativeAnalyticsItem>> => {
|
||||
if (isDemoWorkspace(workspaceId)) {
|
||||
let items = demoCreativeAnalytics;
|
||||
if (params?.project_id) {
|
||||
const projectCreativeIds = demoCreatives
|
||||
.filter((c) => c.project_id === params.project_id)
|
||||
.map((c) => c.id);
|
||||
items = items.filter((a) => projectCreativeIds.includes(a.id));
|
||||
}
|
||||
return paginate(items, params?.page, params?.size);
|
||||
}
|
||||
return analyticsApi.creatives(workspaceId, params);
|
||||
},
|
||||
channels: async (
|
||||
workspaceId: string,
|
||||
params?: { project_id?: string; page?: number; size?: number }
|
||||
): Promise<PaginatedResponse<ChannelAnalyticsItem>> => {
|
||||
if (isDemoWorkspace(workspaceId)) {
|
||||
let items = demoChannelAnalytics;
|
||||
if (params?.project_id) {
|
||||
const projectPlacementChannelIds = new Set(
|
||||
demoPlacements
|
||||
.filter((p) => p.project_id === params.project_id)
|
||||
.map((p) => p.placement_channel_id)
|
||||
);
|
||||
items = items.filter((a) =>
|
||||
projectPlacementChannelIds.has(a.channel_id)
|
||||
);
|
||||
}
|
||||
return paginate(items, params?.page, params?.size);
|
||||
}
|
||||
return analyticsApi.channels(workspaceId, params);
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user