e159e8d297
Perfil de usuario: - /perfil con avatar, matrícula, semestre, tutor, foto de perfil - /onboarding opcional (skippeable) para primer login - Avatar con prioridad: foto propia > Google OAuth > iniciales sobre color HSL - Endpoint PATCH /api/profile con validación y guard self-only - Middleware carga semestre, tutor_id, foto_path - Sidebar footer con Avatar + link a perfil CRUD admin de maestros: - /admin/maestros con tabla desktop / cards mobile - MaestroForm + EliminarMaestro (mismo patrón que categorias) - Endpoints POST/PATCH/DELETE con guard admin + 23503 traducido - Subnav de inventario ahora incluye tab Maestros Home reformulado: - Alumno: saludo por hora + CTA "¿Qué vas a pedir hoy?" + card de último préstamo activo - Admin: saludo + 2 KPIs de alerta (Pendientes, Vencidos) + últimas 2 pendientes + actividad reciente (tabla desktop, cards mobile — fix del bug 6) - Helper saludoHora() y fmtFechaRelativa() en date.ts con offset MX Checkout con tutor auto: - SolicitudCart: input maestro → textarea con placeholder = nombre del tutor - Guard perfil incompleto: CTA "Completa tu perfil" si !matricula || !tutor_id - RPC crear_solicitud: fallback automático al nombre del tutor si textarea vacío Fixes: - Bug upload imagen: Dockerfile ARG + docker-compose build.args pasan PUBLIC_* al bundle client de Vite - Grid inventario mobile: acciones en grid 2-col con prop compact en botones - UnidadesManager mobile: tabla reemplazada por cards, select estado con min-width 130px - Chart donut: Legend horizontal debajo (sin labels internos cortadas) - Chart barras: YAxis width fijo 100 + tickFormatter que trunca >14 chars - Panel admin mobile: tabla ahora tiene versión cards mobile (parte del rediseño home)
51 lines
1.6 KiB
TypeScript
51 lines
1.6 KiB
TypeScript
import { createServerClient, createBrowserClient, type CookieOptionsWithName } from '@supabase/ssr';
|
|
import { createClient } from '@supabase/supabase-js';
|
|
import type { AstroCookies } from 'astro';
|
|
|
|
const SCHEMA = 'prestamos';
|
|
|
|
const SUPABASE_URL = process.env.PUBLIC_SUPABASE_URL ?? import.meta.env.PUBLIC_SUPABASE_URL;
|
|
const SUPABASE_ANON_KEY = process.env.PUBLIC_SUPABASE_ANON_KEY ?? import.meta.env.PUBLIC_SUPABASE_ANON_KEY;
|
|
const SUPABASE_SERVICE_KEY = process.env.SUPABASE_SERVICE_ROLE_KEY ?? import.meta.env.SUPABASE_SERVICE_ROLE_KEY;
|
|
|
|
// ponytail: solo para preview local sin login. Bypass RLS con service_role.
|
|
// Su uso queda tras un flag de DEV en el middleware.
|
|
export function serviceClient() {
|
|
return createClient(SUPABASE_URL, SUPABASE_SERVICE_KEY, {
|
|
db: { schema: SCHEMA },
|
|
auth: { persistSession: false, autoRefreshToken: false },
|
|
});
|
|
}
|
|
|
|
const cookieOptions: CookieOptionsWithName = {
|
|
name: 'sb',
|
|
path: '/',
|
|
sameSite: 'lax',
|
|
httpOnly: true,
|
|
secure: process.env.NODE_ENV === 'production',
|
|
};
|
|
|
|
export function serverClient(cookies: AstroCookies) {
|
|
return createServerClient(
|
|
SUPABASE_URL,
|
|
SUPABASE_ANON_KEY,
|
|
{
|
|
db: { schema: SCHEMA },
|
|
cookieOptions,
|
|
cookies: {
|
|
get: (name) => cookies.get(name)?.value,
|
|
set: (name, value, options) => cookies.set(name, value, options),
|
|
remove: (name, options) => cookies.delete(name, options),
|
|
},
|
|
},
|
|
);
|
|
}
|
|
|
|
export function browserClient() {
|
|
return createBrowserClient(
|
|
SUPABASE_URL,
|
|
SUPABASE_ANON_KEY,
|
|
{ db: { schema: SCHEMA }, cookieOptions },
|
|
);
|
|
}
|