Use this file to discover all available pages before exploring further.
The shared/hooks directory provides a set of custom React hooks that encapsulate the most common data-fetching, UI, and utility patterns used across the panel. Each hook follows the same interface: call it at the top of a component, destructure what you need, and let it handle loading state and error handling internally. This page also covers the guided tour system (useTour + tour constants), the useSpeech accessibility hook, the lib/toast.ts notification helpers, and the lib/date.ts formatting utility.
All hooks marked "use client" must be used inside Client Components. If you need to fetch catalogue data server-side, call the underlying API functions directly instead.
These hooks fetch read-only reference catalogues from the backend. They all share the same pattern: they check an in-memory cache first, then fetch, and they always return { data, loading, error } (with the data key renamed to match the resource).
useMateriales
shared/hooks/useMateriales.tsFetches the list of hull materials (MaterialCatalogo) used to populate vessel registration form selects. Results are cached under the key "materiales" in the shared in-memory cache so repeated renders do not trigger duplicate requests.Signature
import { useMateriales } from "@/shared/hooks/useMateriales";export default function MaterialSelect() { const { materiales, loading, error } = useMateriales(); if (loading) return <p>Cargando materiales...</p>; if (error) return <p className="text-red-500">{error}</p>; return ( <select> {materiales.map((m) => ( <option key={m.id} value={m.id}>{m.nombre}</option> ))} </select> );}
useModalidades
shared/hooks/useModalidades.tsFetches the list of operation modalities (ModalidadCatalogo). Uses a module-level cache variable — once the list has been fetched during the browser session, subsequent calls return it instantly without an API round-trip.Signature
import { useModalidades } from "@/shared/hooks/useModalidades";export default function ModalidadSelect() { const { modalidades, loading, error } = useModalidades(); if (loading) return <p>Cargando modalidades...</p>; if (error) return <p className="text-red-500">{error}</p>; return ( <select> {modalidades.map((m) => ( <option key={m.id} value={m.id}>{m.nombre}</option> ))} </select> );}
useTiposNave
shared/hooks/useTiposNave.tsFetches the list of vessel types (TipoNaveCatalogo). Uses a module-level cache variable identical in behaviour to useModalidades.Signature
import { useTiposNave } from "@/shared/hooks/useTiposNave";export default function TipoNaveSelect() { const { tiposNave, loading, error } = useTiposNave(); if (loading) return <p>Cargando tipos de nave...</p>; if (error) return <p className="text-red-500">{error}</p>; return ( <select> {tiposNave.map((t) => ( <option key={t.id} value={t.id}>{t.nombre}</option> ))} </select> );}
useServiciosNave
shared/hooks/useServiceNave.tsFetches the list of vessel services (ServicioNave). Uses the shared getCache/setCache helpers from shared/cache/cache.ts with the key "servicios_nave".Signature
import { useServiciosNave } from "@/shared/hooks/useServiceNave";export default function ServicioSelect() { const { serviciosNave, loading, error } = useServiciosNave(); if (loading) return <p>Cargando servicios...</p>; if (error) return <p className="text-red-500">{error}</p>; return ( <select> {serviciosNave.map((s) => ( <option key={s.id} value={s.id}>{s.nombre}</option> ))} </select> );}
useUbicaciones
shared/hooks/useUbicaciones.tsFetches the list of geographic locations (UbicacionCatalogo) used in vessel registration. Uses a module-level cache variable.Signature
shared/cache/cache.ts exports three functions used internally by the catalogue hooks. You can use them to add caching to any other hook that fetches static or semi-static data.
// Get a cached value by key. Returns null if the key does not exist.function getCache<T>(key: string): T | null// Store a value under a key. Overwrites any existing value.function setCache<T>(key: string, data: T): void// Clear a single key, or omit the argument to clear everything.function clearCache(key?: string): void
shared/hooks/usePersonaVerification.tsLooks up a person by DNI (8 digits) or RUC (11 digits) and returns the result. It debounces lookups by only firing when the document string is exactly 8 or 11 characters long. The hook re-runs automatically whenever doc changes.Signature
shared/hooks/propietario/useCreatePropietario.tsWraps the createPropietario API call with loading and error state. Errors from Axios responses are unwrapped to their human-readable message before being stored.Signature
The guided tour system is built on driver.js and consists of two parts: the useTour hook that drives the tour engine, and a set of step-constant files that define the tour steps for each major workflow.
useTour
shared/hooks/useTour.tsWraps the driver.js library and exposes a single startTour function. The tour renders with a 50% overlay, animated transitions, and a progress indicator.Signature
type Step = { element: string; // CSS selector for the highlighted element popover: { title: string; description: string; }; stagePadding?: number; // padding around the highlighted element};function useTour(): { startTour: (steps: Step[]) => void;}
Usage
import { useTour } from "@/shared/hooks/useTour";import { EMPADRONAMIENTO_TOURS } from "@/shared/tours/empadronamiento.tour";export default function EmpadronamientoPage() { const { startTour } = useTour(); return ( <Button variant="ghost" size="sm" onClick={() => startTour(EMPADRONAMIENTO_TOURS.completo)} > Ver tutorial </Button> );}
Tour step constants
Tour steps are defined as exported constants in shared/tours/. Import the constant that matches the current page and pass it directly to startTour.EMPADRONAMIENTO_TOURS — shared/tours/empadronamiento.tour.tsAn object with three named step sequences for the vessel registration workflow:
Key
Steps
Purpose
bloques
#bloque-titular, #bloque-nave, #bloque-motor
Tour of the three main form sections
campos
#dni-ruc, #nombre
Tour of key individual fields
completo
#bloque-titular, #Tipo_persona, #dni-ruc
Full onboarding tour from the beginning
import { EMPADRONAMIENTO_TOURS } from "@/shared/tours/empadronamiento.tour";// Start the full onboarding tourstartTour(EMPADRONAMIENTO_TOURS.completo);// Start a focused field tourstartTour(EMPADRONAMIENTO_TOURS.campos);
LOGIN_TOUR — shared/tours/login.tour.tsA flat array of three steps guiding users through the login form: #email, #password, and #btn-login.
import { LOGIN_TOUR } from "@/shared/tours/login.tour";startTour(LOGIN_TOUR);
DASHBOARD_TOUR — shared/tours/dashboard.tour.tsA flat array of two steps: #menu (sidebar navigation) and #cards (KPI summary cards).
import { DASHBOARD_TOUR } from "@/shared/tours/dashboard.tour";startTour(DASHBOARD_TOUR);
Make sure each element selector exists in the DOM when startTour is called. Assign the corresponding id to the target element in your JSX — for example <div id="bloque-titular">.
shared/hooks/useSpeech.tsWraps the Web Speech API (window.speechSynthesis) to provide text-to-speech functionality for accessibility. The hook is configured for Peruvian Spanish (es-PE) at a slightly slowed rate of 0.95.Signature
type UseSpeechReturn = { hablar: (texto: string) => void; // speak the given text; cancels any current speech first detener: () => void; // cancel speech immediately estaHablando: () => boolean; // returns true while speech is active};function useSpeech(): UseSpeechReturn
lib/toast.ts exports three namespaced toast objects built on top of react-hot-toast. Each namespace targets a different toasterId, allowing you to position notification groups independently.
toastEmpadronamiento
Used for vessel registration (empadronamiento) workflow notifications. Toasts appear in the "left" toaster.Methods
lib/date.tsFormats a Date object as a full human-readable date string in Peruvian Spanish locale. Includes weekday, day number, month name, and year.Signature
function formatFullDate(date?: Date): string
The date parameter defaults to new Date() (today) if omitted.Output formatThe format follows es-PE locale conventions:
lunes, 20 de mayo de 2026
Usage
import { formatFullDate } from "@/lib/date";// Current dateconst hoy = formatFullDate();// → "lunes, 20 de mayo de 2026"// Specific dateconst fecha = formatFullDate(new Date("2026-01-15"));// → "jueves, 15 de enero de 2026"
Usage in a component
import { formatFullDate } from "@/lib/date";export default function DashboardHeader() { return ( <p className="text-sm text-slate-500 capitalize"> {formatFullDate()} </p> );}
Wrap the output in a capitalize class (Tailwind capitalize) or call .charAt(0).toUpperCase() + str.slice(1) if you need the weekday capitalized, since toLocaleDateString returns it in lowercase for es-PE.