All checks were successful
Build and Deploy / build-and-push (push) Successful in 2m3s
- Implemented real JWT authentication and persistent user sessions - Replaced all hardcoded mock data with dynamic MySQL-backed API calls - Created new 'Times' (Teams) dashboard with performance metrics - Renamed 'Equipe' to 'Membros' and centralized team management - Added Role-Based Access Control (RBAC) for Admin/Manager/Agent roles - Implemented secure invite-only member creation and password setup flow - Enhanced Login with password visibility and real-time validation - Added safe delete confirmation modal and custom Toast notifications
172 lines
5.0 KiB
TypeScript
172 lines
5.0 KiB
TypeScript
|
|
import { Attendance, FunnelStage, Tenant, User } from './types';
|
|
|
|
export const TENANTS: Tenant[] = [
|
|
{
|
|
id: 'tenant_123',
|
|
name: 'Fasto Corp',
|
|
slug: 'fasto',
|
|
admin_email: 'admin@fasto.com',
|
|
status: 'active',
|
|
user_count: 12,
|
|
attendance_count: 1450,
|
|
created_at: '2023-01-15T10:00:00Z'
|
|
},
|
|
{
|
|
id: 'tenant_456',
|
|
name: 'Acme Inc',
|
|
slug: 'acme-inc',
|
|
admin_email: 'contact@acme.com',
|
|
status: 'trial',
|
|
user_count: 5,
|
|
attendance_count: 320,
|
|
created_at: '2023-06-20T14:30:00Z'
|
|
},
|
|
{
|
|
id: 'tenant_789',
|
|
name: 'Globex Utils',
|
|
slug: 'globex',
|
|
admin_email: 'sysadmin@globex.com',
|
|
status: 'inactive',
|
|
user_count: 2,
|
|
attendance_count: 45,
|
|
created_at: '2022-11-05T09:15:00Z'
|
|
},
|
|
{
|
|
id: 'tenant_101',
|
|
name: 'Soylent Green',
|
|
slug: 'soylent',
|
|
admin_email: 'admin@soylent.com',
|
|
status: 'active',
|
|
user_count: 25,
|
|
attendance_count: 5600,
|
|
created_at: '2023-02-10T11:20:00Z'
|
|
},
|
|
];
|
|
|
|
export const USERS: User[] = [
|
|
{
|
|
id: 'sa1',
|
|
tenant_id: 'system',
|
|
name: 'Super Administrator',
|
|
email: 'root@system.com',
|
|
role: 'super_admin',
|
|
team_id: '',
|
|
avatar_url: 'https://ui-avatars.com/api/?name=Super+Admin&background=0f172a&color=fff',
|
|
bio: 'Administrador do Sistema Global',
|
|
status: 'active'
|
|
},
|
|
{
|
|
id: 'u1',
|
|
tenant_id: 'tenant_123',
|
|
name: 'Lidya Chan',
|
|
email: 'lidya@fasto.com',
|
|
role: 'manager',
|
|
team_id: 'sales_1',
|
|
avatar_url: 'https://picsum.photos/id/1011/200/200',
|
|
bio: 'Gerente de Vendas com mais de 10 anos de experiência em SaaS. Apaixonada por construção de equipes e crescimento de receita.',
|
|
status: 'active'
|
|
},
|
|
{
|
|
id: 'u2',
|
|
tenant_id: 'tenant_123',
|
|
name: 'Alex Noer',
|
|
email: 'alex@fasto.com',
|
|
role: 'agent',
|
|
team_id: 'sales_1',
|
|
avatar_url: 'https://picsum.photos/id/1012/200/200',
|
|
bio: 'Melhor desempenho no Q3. Focado em clientes corporativos e relacionamentos de longo prazo.',
|
|
status: 'active'
|
|
},
|
|
{
|
|
id: 'u3',
|
|
tenant_id: 'tenant_123',
|
|
name: 'Angela Moss',
|
|
email: 'angela@fasto.com',
|
|
role: 'agent',
|
|
team_id: 'sales_1',
|
|
avatar_url: 'https://picsum.photos/id/1013/200/200',
|
|
status: 'inactive'
|
|
},
|
|
{
|
|
id: 'u4',
|
|
tenant_id: 'tenant_123',
|
|
name: 'Brian Samuel',
|
|
email: 'brian@fasto.com',
|
|
role: 'agent',
|
|
team_id: 'sales_2',
|
|
avatar_url: 'https://picsum.photos/id/1014/200/200',
|
|
status: 'active'
|
|
},
|
|
{
|
|
id: 'u5',
|
|
tenant_id: 'tenant_123',
|
|
name: 'Benny Chagur',
|
|
email: 'benny@fasto.com',
|
|
role: 'agent',
|
|
team_id: 'sales_2',
|
|
avatar_url: 'https://picsum.photos/id/1025/200/200',
|
|
status: 'active'
|
|
},
|
|
];
|
|
|
|
const generateMockAttendances = (count: number): Attendance[] => {
|
|
const origins = ['WhatsApp', 'Instagram', 'Website', 'LinkedIn', 'Referral'] as const;
|
|
const stages = Object.values(FunnelStage);
|
|
const products = ['Plano Premium', 'Plano Básico', 'Suíte Enterprise', 'Consultoria'];
|
|
|
|
return Array.from({ length: count }).map((_, i) => {
|
|
const user = USERS.slice(1)[Math.floor(Math.random() * (USERS.length - 1))]; // Skip super admin
|
|
const rand = Math.random();
|
|
// Weighted stages for realism
|
|
let stage = FunnelStage.IDENTIFICATION;
|
|
let isConverted = false;
|
|
|
|
if (rand > 0.85) {
|
|
stage = FunnelStage.WON;
|
|
isConverted = true;
|
|
} else if (rand > 0.7) {
|
|
stage = FunnelStage.LOST;
|
|
} else if (rand > 0.5) {
|
|
stage = FunnelStage.NEGOTIATION;
|
|
} else if (rand > 0.2) {
|
|
stage = FunnelStage.IDENTIFICATION;
|
|
} else {
|
|
stage = FunnelStage.NO_CONTACT;
|
|
}
|
|
|
|
// Force won/lost logic consistency
|
|
if (stage === FunnelStage.WON) isConverted = true;
|
|
|
|
return {
|
|
id: `att_${i}`,
|
|
tenant_id: 'tenant_123',
|
|
user_id: user.id,
|
|
created_at: new Date(Date.now() - Math.floor(Math.random() * 60 * 24 * 60 * 60 * 1000)).toISOString(),
|
|
summary: "Cliente perguntou sobre detalhes do produto e níveis de preços.",
|
|
attention_points: Math.random() > 0.8 ? ["Resposta demorada", "Verificar tom de voz"] : [],
|
|
improvement_points: ["Sugerir plano anual", "Fazer follow-up mais cedo"],
|
|
score: Math.floor(Math.random() * (100 - 50) + 50),
|
|
first_response_time_min: Math.floor(Math.random() * 120),
|
|
handling_time_min: Math.floor(Math.random() * 45),
|
|
funnel_stage: stage,
|
|
origin: origins[Math.floor(Math.random() * origins.length)],
|
|
product_requested: products[Math.floor(Math.random() * products.length)],
|
|
product_sold: isConverted ? products[Math.floor(Math.random() * products.length)] : undefined,
|
|
converted: isConverted,
|
|
};
|
|
});
|
|
};
|
|
|
|
export const MOCK_ATTENDANCES = generateMockAttendances(300);
|
|
|
|
// Visual Constants
|
|
export const COLORS = {
|
|
primary: '#facc15', // Yellow-400
|
|
secondary: '#1e293b', // Slate-800
|
|
success: '#22c55e',
|
|
warning: '#f59e0b',
|
|
danger: '#ef4444',
|
|
charts: ['#3b82f6', '#10b981', '#6366f1', '#f59e0b', '#ec4899', '#8b5cf6'],
|
|
};
|