Files
dare/client/App.js
2026-05-14 14:14:07 +02:00

300 lines
10 KiB
JavaScript

// App.js
import { $, watch, h, when } from "sigpro";
import {
Navbar,
Drawer,
DrawerToggle,
DrawerContent,
DrawerSide,
DrawerOverlay,
Menu,
MenuTitle,
MenuItem,
Tabs,
Tab,
Swap,
SwapToggle,
SwapOn,
SwapOff,
Icon,
Avatar,
Dropdown,
DropdownButton,
DropdownContent,
Modal,
ModalBox,
ModalClose,
ModalAction,
ModalBackdrop,
Fieldset,
Input,
LabelFloating,
Button,
Loading
} from "sigpro-ui";
import 'sigpro-ui/css';
import { Desktop } from "./tabs/Desktop.js";
import { ModalSearch } from "./components/ModalSearch.js";
export const isDark = $(false, "theme-mode");
export const App = () => {
const showSearchModal = $(false);
// Tema oscuro/claro
watch(isDark, (dark) => {
document.documentElement.setAttribute("data-theme", dark ? "dark" : "light");
});
document.documentElement.setAttribute("data-theme", isDark() ? "dark" : "light");
// Estado de login persistente
const logged = $(false, "logged");
const showLoginModal = $(false);
const loginForm = {
username: $(""),
password: $("")
};
// Pestañas: la primera (Escritorio) no es cerrable
const tabs = $([
{
label: "Escritorio",
content: () => Desktop,
closable: false
}
]);
const activeTab = $(0);
const openDrawer = $(false);
// Elementos del menú en el drawer
const menuItems = [
{
label: "Clientes",
children: [
{ label: "Buscar Cliente", onclick: () => openTab("Clientes") },
]
},
{
label: "Recibos",
children: [
{ label: "Buscar Recibo" },
{ label: "Pendientes" },
{ label: "Extornos" },
],
},
{
label: "Polizas",
children: [
{ label: "Buscar Póliza", onclick: () => openTab("Polizas") },
{ label: "Nueva producción", onclick: () => openTab("Polizas") },
{ label: "Anulaciones", onclick: () => openTab("Polizas") },
{ label: "Renovación Cartera", onclick: () => openTab("Polizas") }
]
},
{
label: "Comercial",
children: [
{ label: "Oportunidades" },
],
},
{
label: "Siniestros",
children: [
{ label: "Nuevo Siniestro" },
{ label: "Buscar Siniestro" },
]
},
{
label: "Soporte",
children: [
{ label: "Tickets" },
{ label: "Reportes" },
]
}
];
let tabsContainerRef = null;
let drawerToggleRef = null;
const openTab = (label) => {
const currentTabs = tabs();
if (currentTabs.length >= 15) return;
const newTab = {
label,
content: () => `¡Bienvenido a ${label}!`,
closable: true
};
tabs([...currentTabs, newTab]);
activeTab(tabs().length - 1);
closeDrawer();
};
const closeDrawer = () => {
openDrawer(false);
if (drawerToggleRef) drawerToggleRef.checked = false;
};
const handleLogin = () => {
if (!loginForm.username() || !loginForm.password()) {
alert('Por favor, complete todos los campos');
return;
}
logged(true);
showLoginModal(false);
loginForm.username("");
loginForm.password("");
};
const handleLogout = () => {
logged(false);
};
return [
Drawer({}, [
DrawerToggle({
id: "app-drawer",
ref: (el) => drawerToggleRef = el,
checked: openDrawer,
onchange: (e) => openDrawer(e.target.checked)
}),
DrawerContent({}, [
Navbar({ class: "bg-base-100 shadow-lg align-center" }, [
div({ class: "flex-none" }, [
label({ for: "app-drawer", class: "btn btn-ghost btn-square" }, [
Icon({}, "icon-[lucide--menu]")
])
]),
Button({ class: "icon-[lucide--search] btn-ghost", onclick: () => showSearchModal(true) }),
div({ class: "flex-1" }),
Swap({ class: "text-xl" }, [
SwapToggle({ value: isDark, class: "swap-rotate" }),
SwapOn({}, h('span', { class: "icon-[lucide--moon]" })),
SwapOff({}, h('span', { class: "icon-[lucide--sun]" })),
]),
when(logged,
() => Dropdown({ class: "flex-none ml-2 dropdown-bottom dropdown-end" }, [
DropdownButton({ class: "btn-circle btn btn-ghost", tabindex: "0", role: "button" }, [
Avatar({ class: "placeholder" }, [
div({ class: "bg-neutral text-neutral-content w-10 rounded-full" }, [
h('span', { class: "text-xl" }, "U")
])
])
]),
DropdownContent(
{ class: "menu bg-base-100 rounded-box w-52 p-2 shadow" },
[
Menu({ class: "bg-base-100 max-w-xs w-full" },
[
MenuItem({ label: "Mi Perfil", onclick: () => openTab("Mi Perfil") }),
MenuItem({ label: "Configuración", onclick: () => openTab("Configuración") }),
MenuItem({ label: "Cerrar Sesión", onclick: handleLogout }),
]
),
],
),
]),
() => Button({
class: "flex-none ml-2 btn btn-ghost btn-circle relative",
onclick: () => showLoginModal(true)
}, [
Icon({}, "icon-[lucide--user] text-xl"),
])
)
]),
// Área principal con pestañas
div({
class: "p-4",
ref: (el) => tabsContainerRef = el
}, [
h('div', { class: 'tabs tabs-box' },
() => tabs().map((item, idx) =>
Tab({
name: "app-tabs",
"aria-label": item.label,
checked: activeTab() === idx,
onchange: () => activeTab(idx),
content: item.content,
closable: item.closable,
tabs,
index: idx
})
)
)
])
]),
DrawerSide({ class: "z-50" }, [
DrawerOverlay({ for: "app-drawer" }),
div({
class: "menu bg-base-200 text-base-content min-h-full w-80 p-4"
}, [
h('h2', { class: "text-lg font-bold mb-4" }, "Menú"),
Menu({ class: "bg-base-200 max-w-xs w-full" },
menuItems.flatMap(item => [
MenuTitle({}, item.label),
...item.children.map(child =>
MenuItem({ label: child.label, onclick: child.onclick })
)
])
)
])
])
]),
ModalSearch({
open: showSearchModal,
onSelect: (item) => {
console.log("Item seleccionado:", item);
showSearchModal(false);
}
}),
// Modal de Login adaptado
when(showLoginModal, () =>
Modal({ open: true, class: '' }, [
ModalBox({}, [
ModalClose({ onclick: () => showLoginModal(false) }),
h('h3', { class: "text-lg font-bold" }, "Iniciar Sesión"),
Fieldset({
class: "bg-base-200 border-base-300 rounded-box border gap-3 p-4"
}, [
LabelFloating({ class: "w-full" }, [
Input({
class: "w-full",
type: "text",
placeholder: "Nombre de usuario",
value: loginForm.username,
oninput: (e) => loginForm.username(e.target.value)
}),
h('span', {}, "Usuario")
]),
LabelFloating({ class: "w-full" }, [
Input({
class: "w-full",
type: "password",
placeholder: "Contraseña",
value: loginForm.password,
oninput: (e) => loginForm.password(e.target.value)
}),
h('span', {}, "Contraseña")
])
]),
ModalAction({}, [
Button({
class: "btn btn-ghost",
onclick: () => showLoginModal(false)
}, "Cancelar"),
Button({
class: "btn btn-primary",
onclick: handleLogin
}, "Entrar")
])
]),
ModalBackdrop({ onclick: () => showLoginModal(false) })
])
)
];
};