Perfil + onboarding + home reformulado + fixes
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)
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
---
|
||||
import AppLayout from '@/layouts/AppLayout.astro';
|
||||
import PerfilForm from '@/components/profile/PerfilForm.tsx';
|
||||
import Avatar from '@/components/profile/Avatar.tsx';
|
||||
import { avatarInfo } from '@/lib/avatar';
|
||||
|
||||
const user = Astro.locals.user!;
|
||||
const profile = Astro.locals.profile!;
|
||||
|
||||
const googleAvatarUrl =
|
||||
(user.user_metadata as Record<string, unknown> | undefined)?.avatar_url as string | undefined ||
|
||||
(user.user_metadata as Record<string, unknown> | undefined)?.picture as string | undefined ||
|
||||
null;
|
||||
|
||||
const { data: maestrosData } = await Astro.locals.supabase
|
||||
.from('maestros')
|
||||
.select('id, nombre')
|
||||
.eq('activo', true)
|
||||
.order('nombre');
|
||||
const maestros = (maestrosData ?? []) as { id: number; nombre: string }[];
|
||||
|
||||
const info = avatarInfo({
|
||||
email: profile.email,
|
||||
nombre: profile.nombre,
|
||||
fotoPath: profile.foto_path,
|
||||
googleAvatarUrl,
|
||||
});
|
||||
---
|
||||
<AppLayout title="Mi perfil — LabPréstamos">
|
||||
<div class="max-w-md mx-auto">
|
||||
<header class="flex items-center gap-4 mb-6">
|
||||
<Avatar client:load info={info} size={80} />
|
||||
<div class="min-w-0">
|
||||
<h1 class="text-xl md:text-2xl font-semibold uppercase tracking-wide leading-tight truncate">
|
||||
{profile.nombre ?? profile.email.split('@')[0]}
|
||||
</h1>
|
||||
<p class="text-sm truncate" style="color: var(--color-pencil);">{profile.email}</p>
|
||||
<span class="badge mt-2" style={`background: ${profile.rol === 'admin' ? 'var(--color-secondary)' : 'var(--color-chalk)'};`}>
|
||||
{profile.rol}
|
||||
</span>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section class="card-raised">
|
||||
<h2 class="text-sm uppercase tracking-wide font-semibold mb-4">Datos del perfil</h2>
|
||||
<PerfilForm
|
||||
client:load
|
||||
userId={user.id}
|
||||
email={profile.email}
|
||||
nombre={profile.nombre}
|
||||
initialProfile={{
|
||||
matricula: profile.matricula,
|
||||
semestre: profile.semestre,
|
||||
tutor_id: profile.tutor_id,
|
||||
foto_path: profile.foto_path,
|
||||
}}
|
||||
maestros={maestros}
|
||||
googleAvatarUrl={googleAvatarUrl}
|
||||
/>
|
||||
</section>
|
||||
</div>
|
||||
</AppLayout>
|
||||
Reference in New Issue
Block a user