- conexion supabase
- autenticacion solo correos glm
- pantalla gestor empleados
This commit is contained in:
2026-09-05 12:42:29 -04:00
parent bb6757b492
commit c45182012c
27 changed files with 803 additions and 143 deletions
@@ -0,0 +1,21 @@
export interface Employee {
id: string;
employee_code: string;
nombre: string;
usuario: string | null;
email: string | null;
perfil: string | null;
pais: string | null;
regional: string | null;
latitud: number;
longitud: number;
horas_por_dia: number;
dias_por_semana: number;
jornada_codigo: string;
horas_descanso_por_dia: number;
dias_descanso: string[];
visitas_maximas_por_dia: number;
activo: boolean;
}
export type EmployeeInput = Omit<Employee, 'id'>;
@@ -0,0 +1,17 @@
export interface WorkSchedule {
code: 'LUN_DOM_44' | 'LUN_SAB_40' | 'LUN_SAB_44' | 'LUN_VIE_40';
label: string;
weeklyHours: number;
days: string[];
}
export const WORK_SCHEDULES: WorkSchedule[] = [
{ code: 'LUN_DOM_44', label: 'Lun a Dom - 44h', weeklyHours: 44, days: ['Lunes', 'Martes', 'Miercoles', 'Jueves', 'Viernes', 'Sabado', 'Domingo'] },
{ code: 'LUN_SAB_40', label: 'Lun a Sáb - 40h', weeklyHours: 40, days: ['Lunes', 'Martes', 'Miercoles', 'Jueves', 'Viernes', 'Sabado'] },
{ code: 'LUN_SAB_44', label: 'Lun a Sáb - 44h', weeklyHours: 44, days: ['Lunes', 'Martes', 'Miercoles', 'Jueves', 'Viernes', 'Sabado'] },
{ code: 'LUN_VIE_40', label: 'Lun a Vie - 40h', weeklyHours: 40, days: ['Lunes', 'Martes', 'Miercoles', 'Jueves', 'Viernes'] }
];
export function workSchedule(code: string): WorkSchedule {
return WORK_SCHEDULES.find(schedule => schedule.code === code) ?? WORK_SCHEDULES[3];
}
@@ -0,0 +1,9 @@
import { inject } from '@angular/core';
import { CanActivateFn, Router } from '@angular/router';
import { AuthService } from './auth.service';
export const authGuard: CanActivateFn = async () => {
const auth = inject(AuthService);
const router = inject(Router);
return await auth.getSession() ? true : router.parseUrl('/login');
};
@@ -0,0 +1,37 @@
import { Injectable } from '@angular/core';
import { Session } from '@supabase/supabase-js';
import { supabaseClient } from './supabase.client';
const CORPORATE_DOMAIN = '@gomezleemarketing.com';
@Injectable({ providedIn: 'root' })
export class AuthService {
private readonly client = supabaseClient;
async signIn(email: string, password: string): Promise<string | null> {
const normalizedEmail = email.trim().toLowerCase();
if (!normalizedEmail.endsWith(CORPORATE_DOMAIN)) {
return `Solo se permiten correos ${CORPORATE_DOMAIN}.`;
}
const { error } = await this.client.auth.signInWithPassword({ email: normalizedEmail, password });
return error?.message ?? null;
}
async signInWithGoogle(): Promise<string | null> {
const { error } = await this.client.auth.signInWithOAuth({
provider: 'google',
options: { redirectTo: `${window.location.origin}/home` }
});
return error?.message ?? null;
}
async getSession(): Promise<Session | null> {
const { data } = await this.client.auth.getSession();
const email = data.session?.user.email?.toLowerCase() ?? '';
return email.endsWith(CORPORATE_DOMAIN) ? data.session : null;
}
async signOut(): Promise<void> {
await this.client.auth.signOut();
}
}
@@ -0,0 +1,66 @@
import { Injectable } from '@angular/core';
import { Employee, EmployeeInput } from '../models/employee.model';
import { workSchedule } from '../models/work-schedule.model';
import * as XLSX from 'xlsx';
import { supabaseClient } from './supabase.client';
@Injectable({ providedIn: 'root' })
export class EmployeeService {
private readonly client = supabaseClient;
private readonly table = 'rutero_empleados';
async list(): Promise<Employee[]> {
const { data: sessionData, error: sessionError } = await this.client.auth.getSession();
if (sessionError) throw sessionError;
if (!sessionData.session) throw new Error('No hay una sesión Supabase activa. Cierra sesión e inicia sesión nuevamente.');
const { data, error } = await this.client.from(this.table).select('*').order('nombre');
if (error) throw new Error(`Supabase ${error.code ?? 'error'}: ${error.message}`);
return (data ?? []).map(row => ({
...row,
jornada_codigo: row.jornada_codigo ?? 'LUN_VIE_40',
horas_descanso_por_dia: Number(row.horas_descanso_por_dia ?? 1),
dias_descanso: Array.isArray(row.dias_descanso) ? row.dias_descanso : []
})) as Employee[];
}
async create(employee: EmployeeInput): Promise<void> {
const { error } = await this.client.from(this.table).insert(employee);
if (error) throw error;
}
async upsert(employees: EmployeeInput[]): Promise<void> {
const { error } = await this.client.from(this.table).upsert(employees, { onConflict: 'employee_code' });
if (error) throw error;
}
async update(id: string, employee: EmployeeInput): Promise<void> {
const { error } = await this.client.from(this.table).update(employee).eq('id', id);
if (error) throw error;
}
async remove(id: string): Promise<void> {
const { error } = await this.client.from(this.table).delete().eq('id', id);
if (error) throw error;
}
async activeEmployeesFile(): Promise<File> {
const employees = (await this.list()).filter(employee => employee.activo);
const rows = employees.map(employee => ({
ID: employee.employee_code,
'Nombre del empleado': employee.nombre,
Latitud: employee.latitud,
Longitud: employee.longitud,
'Horas por día usuario': employee.horas_por_dia,
'Horas por semana usuario': workSchedule(employee.jornada_codigo).weeklyHours,
'Visitas maximas por dia': employee.visitas_maximas_por_dia,
Jornada: employee.jornada_codigo,
'Horas descanso por día': employee.horas_descanso_por_dia,
'Días descanso': (employee.dias_descanso ?? []).join(', '),
'Usuario activo': 'Sí'
}));
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, XLSX.utils.json_to_sheet(rows), 'Usuarios');
const data = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' });
return new File([data], 'empleados_activos.xlsx', { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
}
}
@@ -0,0 +1,6 @@
import { createClient } from '@supabase/supabase-js';
import { environment } from '../../../environments/environment';
export const supabaseClient = createClient(environment.supabaseUrl, environment.supabaseAnonKey, {
auth: { persistSession: true, autoRefreshToken: true, detectSessionInUrl: true }
});