Add DEMO feature to the project

This commit is contained in:
Urtzi Alfaro
2025-10-03 14:09:34 +02:00
parent 1243c2ca6d
commit dc8221bd2f
77 changed files with 6251 additions and 1074 deletions

View File

@@ -45,6 +45,7 @@ class ApiClient {
private baseURL: string;
private authToken: string | null = null;
private tenantId: string | null = null;
private demoSessionId: string | null = null;
private refreshToken: string | null = null;
private isRefreshing: boolean = false;
private refreshAttempts: number = 0;
@@ -74,14 +75,31 @@ class ApiClient {
// Request interceptor to add auth headers
this.client.interceptors.request.use(
(config) => {
if (this.authToken) {
// Public endpoints that don't require authentication
const publicEndpoints = [
'/demo/accounts',
'/demo/session/create',
];
const isPublicEndpoint = publicEndpoints.some(endpoint =>
config.url?.includes(endpoint)
);
// Only add auth token for non-public endpoints
if (this.authToken && !isPublicEndpoint) {
config.headers.Authorization = `Bearer ${this.authToken}`;
}
if (this.tenantId) {
if (this.tenantId && !isPublicEndpoint) {
config.headers['X-Tenant-ID'] = this.tenantId;
}
// Check demo session ID from memory OR localStorage
const demoSessionId = this.demoSessionId || localStorage.getItem('demo_session_id');
if (demoSessionId) {
config.headers['X-Demo-Session-Id'] = demoSessionId;
}
return config;
},
(error) => {
@@ -317,6 +335,19 @@ class ApiClient {
this.tenantId = tenantId;
}
setDemoSessionId(sessionId: string | null) {
this.demoSessionId = sessionId;
if (sessionId) {
localStorage.setItem('demo_session_id', sessionId);
} else {
localStorage.removeItem('demo_session_id');
}
}
getDemoSessionId(): string | null {
return this.demoSessionId || localStorage.getItem('demo_session_id');
}
getAuthToken(): string | null {
return this.authToken;
}

View File

@@ -111,6 +111,9 @@ export const useSubscription = () => {
const analyticsLevel = subscriptionService.getAnalyticsLevelForPlan(planKey);
return { hasAccess: true, level: analyticsLevel };
}
// Default fallback when plan is not recognized
return { hasAccess: false, level: 'none', reason: 'Unknown plan' };
}, [subscriptionInfo.plan]);
// Check if user can access specific analytics features

View File

@@ -0,0 +1,83 @@
/**
* Demo Session API Service
* Manages demo session creation, extension, and cleanup
*/
import { apiClient } from '../client';
export interface DemoAccount {
account_type: string;
email: string;
name: string;
password: string;
description?: string;
features?: string[];
business_model?: string;
}
export interface DemoSession {
session_id: string;
virtual_tenant_id: string;
base_demo_tenant_id: string;
demo_account_type: string;
status: 'active' | 'expired' | 'destroyed';
created_at: string;
expires_at: string;
remaining_extensions: number;
}
export interface CreateSessionRequest {
demo_account_type: 'individual_bakery' | 'central_baker';
}
export interface ExtendSessionRequest {
session_id: string;
}
export interface DestroySessionRequest {
session_id: string;
}
/**
* Get available demo accounts
*/
export const getDemoAccounts = async (): Promise<DemoAccount[]> => {
return await apiClient.get<DemoAccount[]>('/demo/accounts');
};
/**
* Create a new demo session
*/
export const createDemoSession = async (
request: CreateSessionRequest
): Promise<DemoSession> => {
return await apiClient.post<DemoSession>('/demo/session/create', request);
};
/**
* Extend an existing demo session
*/
export const extendDemoSession = async (
request: ExtendSessionRequest
): Promise<DemoSession> => {
return await apiClient.post<DemoSession>('/demo/session/extend', request);
};
/**
* Destroy a demo session
*/
export const destroyDemoSession = async (
request: DestroySessionRequest
): Promise<{ message: string }> => {
return await apiClient.post<{ message: string }>(
'/demo/session/destroy',
request
);
};
/**
* Get demo session statistics
*/
export const getDemoStats = async (): Promise<any> => {
return await apiClient.get('/demo/stats');
};