Tech4biz-channel/Channel-Frontend/src/lib/api-client.ts
2026-07-09 09:31:15 +05:30

345 lines
11 KiB
TypeScript

import type { User, Asset, Category, BlogPost, Announcement } from '../types';
import { initializeStorage } from './mock-data';
// Ensure data is seeded in localStorage
initializeStorage();
// Helper delay function to simulate network response
const delay = (ms: number = 300) => new Promise(resolve => setTimeout(resolve, ms));
const getStored = <T>(key: string): T => {
const data = localStorage.getItem(key);
return data ? JSON.parse(data) : [] as unknown as T;
};
const setStored = <T>(key: string, data: T): void => {
localStorage.setItem(key, JSON.stringify(data));
};
export interface ApiResponse<T> {
data: T;
status: number;
}
// Custom mock API client resembling Axios
export const apiClient = {
get: async <T>(url: string, config?: { params?: any }): Promise<ApiResponse<T>> => {
await delay();
// Clean up url by removing query string if any
const cleanUrl = url.split('?')[0];
// Auth endpoints
if (cleanUrl === '/auth/session') {
const activeUserEmail = sessionStorage.getItem('t4b_session_email');
if (!activeUserEmail) {
throw { status: 401, message: 'Unauthorized' };
}
const users = getStored<User[]>('t4b_users');
const user = users.find(u => u.email === activeUserEmail);
if (!user) {
throw { status: 401, message: 'User not found' };
}
return { data: user as unknown as T, status: 200 };
}
// Asset endpoints
if (cleanUrl === '/assets') {
const assets = getStored<Asset[]>('t4b_assets');
const params = config?.params || {};
let filtered = [...assets];
if (params.categoryId && params.categoryId !== 'all') {
filtered = filtered.filter(a => a.categoryId === params.categoryId);
}
if (params.subcategory && params.subcategory !== 'all') {
filtered = filtered.filter(a => a.subcategory === params.subcategory);
}
if (params.search) {
const q = params.search.toLowerCase();
filtered = filtered.filter(a =>
a.title.toLowerCase().includes(q) ||
a.description.toLowerCase().includes(q) ||
a.tags.some(t => t.toLowerCase().includes(q))
);
}
// If client is logged in and not admin, only show published assets
const activeUserEmail = sessionStorage.getItem('t4b_session_email');
const users = getStored<User[]>('t4b_users');
const activeUser = users.find(u => u.email === activeUserEmail);
if (!activeUser || activeUser.role !== 'ADMIN') {
filtered = filtered.filter(a => a.status === 'published');
}
return { data: filtered as unknown as T, status: 200 };
}
if (cleanUrl.startsWith('/assets/')) {
const id = cleanUrl.split('/assets/')[1];
const assets = getStored<Asset[]>('t4b_assets');
const asset = assets.find(a => a.id === id);
if (!asset) {
throw { status: 404, message: 'Asset not found' };
}
return { data: asset as unknown as T, status: 200 };
}
// Categories
if (cleanUrl === '/categories') {
const categories = getStored<Category[]>('t4b_categories');
return { data: categories as unknown as T, status: 200 };
}
// Blog posts
if (cleanUrl === '/blog') {
const posts = getStored<BlogPost[]>('t4b_blog_posts');
// Filter out drafts for client roles
const activeUserEmail = sessionStorage.getItem('t4b_session_email');
const users = getStored<User[]>('t4b_users');
const activeUser = users.find(u => u.email === activeUserEmail);
let filtered = [...posts];
if (!activeUser || activeUser.role !== 'ADMIN') {
filtered = filtered.filter(p => p.status === 'published');
}
return { data: filtered as unknown as T, status: 200 };
}
// Announcements
if (cleanUrl === '/announcements') {
const announcements = getStored<Announcement[]>('t4b_announcements');
return { data: announcements as unknown as T, status: 200 };
}
// Admin Client Queue
if (cleanUrl === '/admin/clients') {
const users = getStored<User[]>('t4b_users');
// Filter out admins, return only clients
const clients = users.filter(u => u.role === 'CLIENT');
return { data: clients as unknown as T, status: 200 };
}
throw { status: 404, message: 'Route not found' };
},
post: async <T>(url: string, payload: any): Promise<ApiResponse<T>> => {
await delay();
if (url === '/auth/login') {
const { email, password } = payload;
const users = getStored<User[]>('t4b_users');
const user = users.find(u => u.email === email);
if (!user || password !== 'password') {
throw { status: 400, message: 'Invalid email or password' };
}
// Login success, return user (MFA verification will occur if required)
return { data: user as unknown as T, status: 200 };
}
if (url === '/auth/register') {
const { email, companyName, website, sector, companySize } = payload;
const users = getStored<User[]>('t4b_users');
if (users.some(u => u.email === email)) {
throw { status: 400, message: 'Email already registered' };
}
const newUser: User = {
id: `user-${Date.now()}`,
email,
role: 'CLIENT',
companyName: companyName || '',
website: website || '',
sector: sector || 'Technology',
companySize: companySize || '1-10',
onboardingStatus: 'NOT_STARTED',
mfaVerified: false,
createdAt: new Date().toISOString()
};
users.push(newUser);
setStored('t4b_users', users);
return { data: newUser as unknown as T, status: 201 };
}
if (url === '/auth/mfa-verify') {
const { email, code } = payload;
const users = getStored<User[]>('t4b_users');
const index = users.findIndex(u => u.email === email);
if (index === -1) {
throw { status: 404, message: 'User not found' };
}
if (code !== '123456') {
throw { status: 400, message: 'Invalid OTP code. Try "123456"' };
}
users[index].mfaVerified = true;
setStored('t4b_users', users);
sessionStorage.setItem('t4b_session_email', email);
return { data: users[index] as unknown as T, status: 200 };
}
if (url === '/client/onboarding') {
const activeUserEmail = sessionStorage.getItem('t4b_session_email');
const users = getStored<User[]>('t4b_users');
const index = users.findIndex(u => u.email === activeUserEmail);
if (index === -1) {
throw { status: 401, message: 'Unauthorized' };
}
users[index] = {
...users[index],
...payload,
onboardingStatus: 'FORM_COMPLETED'
};
setStored('t4b_users', users);
return { data: users[index] as unknown as T, status: 200 };
}
if (url === '/client/nda') {
const activeUserEmail = sessionStorage.getItem('t4b_session_email');
const users = getStored<User[]>('t4b_users');
const index = users.findIndex(u => u.email === activeUserEmail);
if (index === -1) {
throw { status: 401, message: 'Unauthorized' };
}
users[index].ndaSignature = {
type: payload.type,
dataUrl: payload.dataUrl,
date: new Date().toISOString()
};
users[index].onboardingStatus = 'NDA_SIGNED';
setStored('t4b_users', users);
return { data: users[index] as unknown as T, status: 200 };
}
if (url === '/client/msa') {
const activeUserEmail = sessionStorage.getItem('t4b_session_email');
const users = getStored<User[]>('t4b_users');
const index = users.findIndex(u => u.email === activeUserEmail);
if (index === -1) {
throw { status: 401, message: 'Unauthorized' };
}
users[index].msaSignature = {
type: payload.type,
dataUrl: payload.dataUrl,
date: new Date().toISOString()
};
users[index].onboardingStatus = 'PENDING_APPROVAL';
setStored('t4b_users', users);
return { data: users[index] as unknown as T, status: 200 };
}
if (url === '/assets/new') {
const assets = getStored<Asset[]>('t4b_assets');
const newAsset: Asset = {
id: `asset-${Date.now()}`,
title: payload.title,
description: payload.description,
categoryId: payload.categoryId,
subcategory: payload.subcategory,
tags: payload.tags || [],
author: payload.author || 'Admin Staff',
publishDate: new Date().toISOString().split('T')[0],
thumbnailUrl: payload.thumbnailUrl || 'https://images.unsplash.com/photo-1488590528505-98d2b5aba04b?w=500&auto=format&fit=crop&q=60',
downloadUrl: payload.downloadUrl || '#',
githubUrl: payload.githubUrl,
status: payload.status || 'draft',
downloadsCount: 0
};
assets.push(newAsset);
setStored('t4b_assets', assets);
return { data: newAsset as unknown as T, status: 201 };
}
if (url === '/blog/new') {
const posts = getStored<BlogPost[]>('t4b_blog_posts');
const newPost: BlogPost = {
id: `blog-${Date.now()}`,
title: payload.title,
content: payload.content,
author: payload.author || 'Admin Staff',
publishDate: new Date().toISOString().split('T')[0],
thumbnailUrl: payload.thumbnailUrl || 'https://images.unsplash.com/photo-1555066931-4365d14bab8c?w=500&auto=format&fit=crop&q=60',
readTime: `${Math.ceil(payload.content.split(' ').length / 200)} min read`,
tags: payload.tags || [],
status: payload.status || 'draft'
};
posts.push(newPost);
setStored('t4b_blog_posts', posts);
return { data: newPost as unknown as T, status: 201 };
}
throw { status: 404, message: 'Route not found' };
},
put: async <T>(url: string, payload: any): Promise<ApiResponse<T>> => {
await delay();
if (url.startsWith('/admin/clients/')) {
const clientId = url.split('/admin/clients/')[1];
const users = getStored<User[]>('t4b_users');
const index = users.findIndex(u => u.id === clientId);
if (index === -1) {
throw { status: 404, message: 'Client not found' };
}
users[index].onboardingStatus = payload.status; // 'APPROVED' or 'REJECTED'
setStored('t4b_users', users);
return { data: users[index] as unknown as T, status: 200 };
}
if (url.startsWith('/assets/')) {
const id = url.split('/assets/')[1];
const assets = getStored<Asset[]>('t4b_assets');
const index = assets.findIndex(a => a.id === id);
if (index === -1) {
throw { status: 404, message: 'Asset not found' };
}
assets[index] = {
...assets[index],
...payload
};
setStored('t4b_assets', assets);
return { data: assets[index] as unknown as T, status: 200 };
}
throw { status: 404, message: 'Route not found' };
},
delete: async <T>(url: string): Promise<ApiResponse<T>> => {
await delay();
if (url.startsWith('/assets/')) {
const id = url.split('/assets/')[1];
let assets = getStored<Asset[]>('t4b_assets');
const exists = assets.some(a => a.id === id);
if (!exists) {
throw { status: 404, message: 'Asset not found' };
}
assets = assets.filter(a => a.id !== id);
setStored('t4b_assets', assets);
return { data: { success: true } as unknown as T, status: 200 };
}
throw { status: 404, message: 'Route not found' };
}
};