socios-comerciales.skyballo.../src/routes/perfil.tsx

145 lines
5.7 KiB
TypeScript

import { createFileRoute, useNavigate } from "@tanstack/react-router";
import { Bell, Download, LogOut } from "lucide-react";
import { AppShell } from "@/components/AppShell";
import { cerrarSesion, useAppState } from "@/lib/store";
import { BrandMark } from "@/components/BrandLogo";
import { useInstalarPWA } from "@/lib/pwa-install";
import { notificar, pedirPermisoNotificaciones } from "@/lib/notificaciones";
export const Route = createFileRoute("/perfil")({
head: () => ({
meta: [
{ title: "Perfil y ajustes del socio | Socios Comerciales" },
{
name: "description",
content:
"Consulta los datos fiscales y comerciales de tu cuenta de socio, activa notificaciones e instala la app.",
},
{ property: "og:title", content: "Perfil y ajustes del socio" },
{ property: "og:description", content: "Datos del socio comercial, notificaciones e instalación PWA." },
],
}),
component: PerfilPage,
});
function PerfilPage() {
const { socio } = useAppState();
const navigate = useNavigate();
const { disponible, instalada, instalar } = useInstalarPWA();
const campos: [string, string][] = socio
? [
["Categoría", socio.categoria],
["Empresas asignadas", socio.empresas.join(", ") || "—"],
["Nombre", socio.nombre],
["Razón Social", socio.razonSocial],
["RUC", socio.ruc],
["Contacto Principal", socio.contacto],
["Email", socio.email],
["Teléfono", socio.telefono],
["Sitio Web", socio.sitioWeb],
["Dirección", socio.direccion],
["Notas", socio.notas],
]
: [];
return (
<AppShell title="Perfil y ajustes" subtitle="Datos del socio comercial">
<section className="rounded-3xl bg-card p-5 shadow-soft">
<div className="flex items-center gap-4">
<span className="grid size-14 place-items-center rounded-3xl bg-brand text-xl font-bold text-brand-foreground">
{(socio?.nombre ?? "S").charAt(0).toUpperCase()}
</span>
<div className="min-w-0">
<p className="truncate text-lg font-bold">{socio?.nombre ?? "Socio"}</p>
<p className="truncate text-sm text-muted-foreground">{socio?.email ?? "Sin sesión de registro"}</p>
</div>
</div>
<dl className="mt-6 grid gap-3 sm:grid-cols-2">
{campos.map(([k, v]) => (
<div key={k} className="rounded-2xl bg-muted px-4 py-3">
<dt className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">{k}</dt>
<dd className="mt-1 break-words text-sm font-medium">{v || "—"}</dd>
</div>
))}
{campos.length === 0 && (
<p className="text-sm text-muted-foreground">
Completa el registro de socio para ver aquí tus datos.
</p>
)}
</dl>
</section>
<section className="mt-5 grid gap-3 sm:grid-cols-2">
<button
onClick={async () => {
const estado = await pedirPermisoNotificaciones();
notificar(
"Notificaciones",
estado === "granted" ? "Activadas correctamente." : "Se mostrarán dentro de la app.",
);
}}
className="flex items-center gap-3 rounded-3xl bg-card p-5 text-left shadow-soft"
>
<Bell className="size-5 text-brand" />
<span>
<span className="block text-sm font-semibold">Activar notificaciones</span>
<span className="block text-xs text-muted-foreground">
Reservaciones confirmadas y comisiones acreditadas
</span>
</span>
</button>
<div className="rounded-3xl bg-ink p-5 text-ink-foreground shadow-lift">
<div className="flex items-center gap-3">
<span className="grid size-11 shrink-0 place-items-center rounded-2xl bg-white/10 p-1.5">
<BrandMark className="h-7" />
</span>
<span className="min-w-0">
<span className="block text-sm font-bold">Instalar la app Sky Balloons</span>
<span className="block text-xs opacity-70">
Acceso directo, pantalla completa y avisos de comisiones
</span>
</span>
</div>
<button
type="button"
disabled={instalada}
onClick={async () => {
const ok = await instalar();
if (!ok && !instalada) {
notificar(
"Instalar la app",
"Usa “Agregar a pantalla de inicio” desde el menú de tu navegador.",
);
}
}}
className="mt-4 flex w-full items-center justify-center gap-3 rounded-2xl bg-white px-4 py-3.5 text-ink transition-all hover:-translate-y-0.5 hover:shadow-lift active:scale-[0.99] disabled:opacity-60"
>
<Download className="size-5" />
<span className="text-left leading-tight">
<span className="block text-[10px] font-semibold uppercase tracking-widest opacity-60">
{instalada ? "Ya instalada" : disponible ? "Disponible ahora" : "Instalación web"}
</span>
<span className="block text-sm font-bold">
{instalada ? "App en tu dispositivo" : "Instalar aplicación"}
</span>
</span>
</button>
</div>
</section>
<button
onClick={() => {
cerrarSesion();
navigate({ to: "/" });
}}
className="mt-5 flex w-full items-center justify-center gap-2 rounded-2xl bg-ink px-4 py-3.5 text-sm font-semibold text-ink-foreground"
>
<LogOut className="size-4" /> Cerrar sesión
</button>
</AppShell>
);
}