- Copy admin-dashboard-web → dashboards/admin-web - Copy tracker-dashboard-web → dashboards/tracker-web - Update pnpm-workspace.yaml to include dashboards/* - Replace file: refs with workspace:* for @bytelyst/* packages - Replace all hardcoded LysnrAI/lysnn.com branding with generic platform refs - Make telemetry use NEXT_PUBLIC_PRODUCT_ID / PRODUCT_ID env vars - Update mock credentials, seed data, invitation codes, placeholders - Update READMEs, e2e tests, unit tests for product-agnostic content - Both dashboards pass tsc --noEmit clean
73 lines
1.8 KiB
TypeScript
73 lines
1.8 KiB
TypeScript
'use client';
|
|
|
|
import { createAuthProvider, type LoginResult } from '@bytelyst/react-auth';
|
|
|
|
export interface AdminUser {
|
|
email: string;
|
|
name: string;
|
|
role: 'super_admin' | 'admin' | 'viewer';
|
|
avatarUrl?: string;
|
|
[key: string]: unknown;
|
|
}
|
|
|
|
// Mock credentials — used as fallback when Cosmos DB is not configured
|
|
const MOCK_ADMINS: Record<string, { password: string; user: AdminUser }> = {
|
|
'admin@example.com': {
|
|
password: 'Admin123!',
|
|
user: {
|
|
email: 'admin@example.com',
|
|
name: 'Admin User',
|
|
role: 'super_admin',
|
|
},
|
|
},
|
|
'viewer@example.com': {
|
|
password: 'viewer123',
|
|
user: {
|
|
email: 'viewer@example.com',
|
|
name: 'Viewer User',
|
|
role: 'viewer',
|
|
},
|
|
},
|
|
};
|
|
|
|
const { AuthProvider, useAuth } = createAuthProvider<AdminUser>({
|
|
storagePrefix: 'admin',
|
|
loginEndpoint: '/auth/login',
|
|
mapLoginResponse: (data: unknown) => {
|
|
const d = data as {
|
|
user: { email: string; name: string; role: string };
|
|
accessToken: string;
|
|
refreshToken: string;
|
|
};
|
|
return {
|
|
user: {
|
|
email: d.user.email,
|
|
name: d.user.name,
|
|
role: d.user.role as AdminUser['role'],
|
|
},
|
|
accessToken: d.accessToken,
|
|
refreshToken: d.refreshToken,
|
|
};
|
|
},
|
|
onLoginFallback: async (
|
|
email: string,
|
|
password: string,
|
|
error: string
|
|
): Promise<LoginResult<AdminUser> | null> => {
|
|
if (error === 'API unavailable' || error === 'Internal server error') {
|
|
await new Promise(r => setTimeout(r, 400));
|
|
const entry = MOCK_ADMINS[email.toLowerCase()];
|
|
if (entry && entry.password === password) {
|
|
return {
|
|
user: entry.user,
|
|
accessToken: 'mock-token',
|
|
refreshToken: 'mock-refresh',
|
|
};
|
|
}
|
|
}
|
|
return null;
|
|
},
|
|
});
|
|
|
|
export { AuthProvider, useAuth };
|