145 lines
5.7 KiB
TypeScript
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>
|
|
);
|
|
}
|