Aplicación web para encontrar y reservar plazas de estacionamiento en tiempo real.
- Ve a la pestaña Projects en GitHub.
- Busca tu issue asignada.
- Crea tu rama a partir del nombre de la issue:
git checkout -b feature/nombre-de-la-tarea
npm install
npm run dev
Abre http://localhost:5173
en el navegador para ver la app en desarrollo.
src/
├── app/ # Configuración de rutas y estado global (router.tsx, store.ts)
├── features/ # Módulos principales (auth, parkings, bookings, map)
│ └── [modulo]/
│ ├── pages/ # Vistas completas que se mapean con rutas
│ ├── components/ # Componentes reutilizables solo dentro del módulo
│ └── services/ # Llamadas a API, React Query hooks
├── layouts/ # Layouts generales como PublicLayout (Header/Footer persistentes)
├── shared/
│ ├── ui/ # Componentes reutilizables globales (Botón, Input, Header, Footer)
│ ├── hooks/ # Custom hooks genéricos (useToggle, useDebounce...)
│ ├── types/ # Tipos TypeScript globales (User, Parking, etc.)
│ └── utils/ # Funciones auxiliares (validaciones, formateo de fechas...)
- Cada funcionalidad va dentro de su carpeta en
features/
- Usa los archivos de ejemplo ya creados para
HomePage
- Los componentes comunes van en
shared/ui/
- Si creas lógica compartida, usa
shared/hooks
oshared/utils
🚀 Notificaciones con Toast El proyecto utiliza react-toastify para mostrar notificaciones visuales al usuario. Ya está configurado globalmente y listo para usarse desde cualquier parte de la aplicación.
✅ Cómo usar los toast Importa los helpers desde shared/ui/toast.ts:
import { showSuccess, showError, showInfo, showWarning } from '@/shared/ui/toast';
import { showSuccess, showError } from '@/shared/ui/toast';
const handleSubmit = async () => {
try {
await registerUser();
showSuccess('Registro completado');
} catch (err) {
showError('Hubo un error al registrar el usuario');
}
};
📦 Modal Global con Zustand + MUI Este proyecto incluye un modal global reutilizable utilizando Zustand para manejar el estado y Material UI (@mui/material) para el diseño. ✅ ¿Cómo funciona? El componente GlobalModal se monta una sola vez en el App.tsx.
Desde cualquier parte de la app se puede abrir el modal usando el hook useModalStore.
El modal se cierra al hacer clic fuera del contenido o al presionar Escape. 💡 Ejemplo de uso
import { useModalStore } from '../../store/modal.store';
const { openModal } = useModalStore();
<Button onClick={() => openModal(<div>¿Estás segura de eliminar?</div>)}>
Eliminar
</Button>
✨ Comportamiento ✅ Se cierra tocando fuera o presionando Esc.
❌ No tiene botón "X" para cerrar.
🔄 El contenido del modal es dinámico: podés pasarle cualquier JSX.
🧩 1. Importar el hook de Zustand Al principio de tu componente (donde estás desarrollando el panel de control), importa el hook useParkingStore:
import { useParkingStore } from '@/features/parking/store/useParkingStore' 🧩 2. Acceder a la función setAvailability Dentro de tu componente (fuera del return), crea esta constante:
const setAvailability = useParkingStore((state) => state.setAvailability) Esto te permitirá actualizar el número de plazas en toda la app.
🧩 3. Llamar a setAvailability al guardar cambios Cuando el usuario haga clic en "Guardar cambios", llama a esta función pasando:
el id del parking
la cantidad de plazas disponibles que haya elegido
Así:
setAvailability(parkingId, newAvailableSlots) Ejemplo real en tu botón:
<Button onClick={() => setAvailability(parking.id, slots)}> Guardar cambios ✅ parking.id: es el identificador del parking actual (deberías tenerlo en el componente). ✅ slots: es el número actualizado (lo que ve en el input o el contador).
🧩 4. Cómo probar que funciona El proyecto tiene activo un mock (useMockAvailabilityUpdates) que actualiza automáticamente un parking cada 5 segundos.
Mientras tanto, tu cambio manual usando setAvailability debe actualizar inmediatamente el número de plazas en:
Tu panel de control (contador)
El perfil del parking (ParkingProfile) donde se usa AvailabilityStatus.
✅ No hace falta recargar la página. ✅ No hace falta tocar ParkingProfile. ✅ Todo se actualiza solo.
🧪 ¿Cómo saber si todo funciona bien? Cambia el número de plazas disponibles en el control.
Haz clic en "Guardar cambios".
Ve al perfil del parking → Deberías ver que el número de plazas cambia en vivo.
⚙️ Info extra Mientras desarrollamos, dejamos el mock activo para facilitar las pruebas (useMockAvailabilityUpdates() está activado en App.tsx).
Cuando conectemos el WebSocket real del backend, no tendrás que cambiar nada en tu componente.
import { useParkingStore } from '@/features/parking/store/useParkingStore'
const ParkingAvailabilityControl = ({ parkingId }: { parkingId: string }) => { const [slots, setSlots] = useState(0) const setAvailability = useParkingStore((state) => state.setAvailability)
const handleSave = () => { setAvailability(parkingId, slots) }
return (