diff --git a/Clases bootstrap b/Clases bootstrap new file mode 100644 index 0000000..e69de29 diff --git a/Explicacion DER.txt b/Explicacion DER.txt index 5f6e99d..5847de2 100644 --- a/Explicacion DER.txt +++ b/Explicacion DER.txt @@ -41,7 +41,8 @@ Formulario -Si Cli_DNI es null, entonces ese formulario lo envió _________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ LogSeguridad -Responsable_ID: Vendría a ser el DNI de la persona que ejecutó esa accion. _________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ - +HorariosAtenciones -TIPO = Corresponde a AM o PM +_________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ diff --git a/admincreate.php b/admincreate.php new file mode 100644 index 0000000..b668da7 --- /dev/null +++ b/admincreate.php @@ -0,0 +1,73 @@ +make(Kernel::class)->bootstrap(); + +$usuario = env('ADMIN_USUARIO', 'admin'); +$passwordPlano = env('ADMIN_PASSWORD', 'admin1234'); +$correo = env('ADMIN_CORREO', 'admin@abogadaslitoral.com'); +$dni = env('ADMIN_DNI', '30000000'); +$nombre = env('ADMIN_NOMBRE', 'Usuario'); +$apellido = env('ADMIN_APELLIDO', 'Administrador'); +$cuil = env('ADMIN_CUIL', '20-30000000-0'); +$fechaNac = env('ADMIN_FECHANAC', '2026-01-01'); + +try { + DB::transaction(function () use ($usuario, $passwordPlano, $correo, $dni, $nombre, $apellido, $cuil, $fechaNac): void { + $foto = Foto::firstOrCreate( + ['ruta' => 'avatars/admin-default.png'], + [ + 'extension' => 'png', + 'nombre' => 'admin-default', + 'mime_type' => 'image/png', + 'tamanio_bytes' => 0, + ] + ); + + $persona = Persona::updateOrCreate( + ['dni' => $dni], + [ + 'nombre' => $nombre, + 'apellido' => $apellido, + 'cuil' => $cuil, + 'fechanac' => $fechaNac, + 'foto_id' => $foto->id, + ] + ); + + $credencial = CredencialProfesional::updateOrCreate( + ['usuario' => $usuario], + [ + 'contra' => Hash::make($passwordPlano), + 'rol' => 'ADMIN', + ] + ); + + Administrador::updateOrCreate( + ['dni' => $dni, 'correo' => $correo], + [ + 'persona_id' => $persona->id, + 'credencialprofesional_id' => $credencial->id, + ] + ); + }); + + echo "Administrador creado/actualizado correctamente." . PHP_EOL; + echo "Usuario: {$usuario}" . PHP_EOL; + echo "Correo: {$correo}" . PHP_EOL; +} catch (Throwable $e) { + fwrite(STDERR, 'Error al crear administrador: ' . $e->getMessage() . PHP_EOL); + exit(1); +} diff --git a/app/Http/Controllers/AgendaController.php b/app/Http/Controllers/AgendaController.php index 9f15a46..1f6c470 100644 --- a/app/Http/Controllers/AgendaController.php +++ b/app/Http/Controllers/AgendaController.php @@ -76,4 +76,5 @@ class AgendaController extends Controller 'message' => 'Registro eliminado correctamente', ], 200); } + } \ No newline at end of file diff --git a/app/Http/Controllers/AuthController.php b/app/Http/Controllers/AuthController.php new file mode 100644 index 0000000..888fa52 --- /dev/null +++ b/app/Http/Controllers/AuthController.php @@ -0,0 +1,237 @@ +validate([ + 'correo' => ['required', 'string'], + 'contra' => ['required', 'string'], + ]); + + $correo = trim((string) $request->input('correo')); + $contra = (string) $request->input('contra'); + + $credencial = CredencialCliente::where('correo', $correo)->first(); + if (!$credencial || !$this->credencialValida($contra, (string) $credencial->contra)) { + return back() + ->withInput($request->except('contra')) + ->with('login_error', 'Usuario o contraseña incorrectos.'); + } + + $token = Str::random(64); + $credencial->token = $token; + $credencial->fecha_hora = now(); + $credencial->save(); + + return back()->with('login_success', 'Login exitoso.'); + } + + public function loginPersonalWeb(Request $request): RedirectResponse + { + $request->validate([ + 'usuario' => ['required', 'string'], + 'contra' => ['required', 'string'], + ]); + + $usuario = trim((string) $request->input('usuario')); + $contra = (string) $request->input('contra'); + + $credencial = CredencialProfesional::where('usuario', $usuario)->first(); + if (!$credencial || !$this->credencialValida($contra, (string) $credencial->contra)) { + return back() + ->withInput($request->except('contra')) + ->with('login_error', 'Usuario o contraseña incorrectos.'); + } + + $token = Str::random(64); + $credencial->token = $token; + $credencial->fecha_hora = now(); + $credencial->save(); + + return back()->with('login_success', 'Login exitoso.'); + } + + public function loginCliente(Request $request): JsonResponse + { + $request->validate([ + 'correo' => ['required', 'string'], + 'contra' => ['required', 'string'], + ]); + + $correo = trim((string) $request->input('correo')); + $contra = (string) $request->input('contra'); + + $credencial = CredencialCliente::where('correo', $correo)->first(); + if (!$credencial || !$this->credencialValida($contra, (string) $credencial->contra)) { + return response()->json([ + 'success' => false, + 'message' => 'Credenciales invalidas', + ], 401); + } + + $token = Str::random(64); + $credencial->token = $token; + $credencial->fecha_hora = now(); + $credencial->save(); + + return response()->json([ + 'success' => true, + 'data' => [ + 'tipo' => 'cliente', + 'id_credencial' => $credencial->id, + 'token' => $token, + ], + 'message' => 'Login de cliente exitoso', + ], 200); + } + + public function loginPersonal(Request $request): JsonResponse + { + $request->validate([ + 'usuario' => ['required', 'string'], + 'contra' => ['required', 'string'], + ]); + + $usuario = trim((string) $request->input('usuario')); + $contra = (string) $request->input('contra'); + + $credencial = CredencialProfesional::where('usuario', $usuario)->first(); + if (!$credencial || !$this->credencialValida($contra, (string) $credencial->contra)) { + return response()->json([ + 'success' => false, + 'message' => 'Credenciales invalidas', + ], 401); + } + + $token = Str::random(64); + $credencial->token = $token; + $credencial->fecha_hora = now(); + $credencial->save(); + + return response()->json([ + 'success' => true, + 'data' => [ + 'tipo' => 'personal', + 'rol' => $credencial->rol, + 'id_credencial' => $credencial->id, + 'token' => $token, + ], + 'message' => 'Login de personal exitoso', + ], 200); + } + + public function login(Request $request): JsonResponse + { + $request->validate([ + 'identificador' => ['required', 'string'], + 'contra' => ['required', 'string'], + 'tipo' => ['nullable', 'in:cliente,profesional'], + ]); + + $identificador = trim((string) $request->input('identificador')); + $contra = (string) $request->input('contra'); + $tipo = $request->input('tipo'); + + $credencial = null; + $tipoDetectado = null; + + if ($tipo === 'cliente') { + $credencial = CredencialCliente::where('correo', $identificador)->first(); + $tipoDetectado = 'cliente'; + } elseif ($tipo === 'profesional') { + $credencial = CredencialProfesional::where('usuario', $identificador)->first(); + $tipoDetectado = 'personal'; + } else { + $credencial = CredencialCliente::where('correo', $identificador)->first(); + $tipoDetectado = $credencial ? 'cliente' : null; + + if (!$credencial) { + $credencial = CredencialProfesional::where('usuario', $identificador)->first(); + $tipoDetectado = $credencial ? 'personal' : null; + } + } + + if (!$credencial || !$this->credencialValida($contra, (string) $credencial->contra)) { + return response()->json([ + 'success' => false, + 'message' => 'Credenciales invalidas', + ], 401); + } + + $token = Str::random(64); + $credencial->token = $token; + $credencial->fecha_hora = now(); + $credencial->save(); + + return response()->json([ + 'success' => true, + 'data' => [ + 'tipo' => $tipoDetectado, + 'rol' => $credencial instanceof CredencialProfesional ? $credencial->rol : null, + 'id_credencial' => $credencial->id, + 'token' => $token, + ], + 'message' => 'Login exitoso', + ], 200); + } + + public function logout(Request $request): JsonResponse + { + $token = (string) $request->input('token', ''); + if ($token === '') { + return response()->json([ + 'success' => false, + 'message' => 'Token requerido', + ], 422); + } + + $credencialCliente = CredencialCliente::where('token', $token)->first(); + if ($credencialCliente) { + $credencialCliente->token = null; + $credencialCliente->fecha_hora = now(); + $credencialCliente->save(); + + return response()->json([ + 'success' => true, + 'message' => 'Logout exitoso', + ], 200); + } + + $credencialProfesional = CredencialProfesional::where('token', $token)->first(); + if ($credencialProfesional) { + $credencialProfesional->token = null; + $credencialProfesional->fecha_hora = now(); + $credencialProfesional->save(); + + return response()->json([ + 'success' => true, + 'message' => 'Logout exitoso', + ], 200); + } + + return response()->json([ + 'success' => false, + 'message' => 'Token invalido', + ], 401); + } + + private function credencialValida(string $contraIngresada, string $contraGuardada): bool + { + if ($contraIngresada === $contraGuardada) { + return true; + } + + return Hash::check($contraIngresada, $contraGuardada); + } +} diff --git a/app/Http/Controllers/EstadoTurnoController.php b/app/Http/Controllers/EstadoTurnoController.php index 6ab54e8..bc8fc5c 100644 --- a/app/Http/Controllers/EstadoTurnoController.php +++ b/app/Http/Controllers/EstadoTurnoController.php @@ -3,7 +3,6 @@ namespace App\Http\Controllers; use App\Models\EstadoTurno; -use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; class EstadoTurnoController extends Controller @@ -11,41 +10,43 @@ class EstadoTurnoController extends Controller /** * Display a listing of the resource. */ - public function index(): JsonResponse + public function index() : JsonResponse { - $items = EstadoTurno::all(); - + $estadoTurnos = EstadoTurno::all(); return response()->json([ 'success' => true, - 'data' => $items, - 'message' => 'Registros obtenidos correctamente', + 'data' => $estadoTurnos, + 'message' => 'Estados de turno obtenidos correctamente' ], 200); } /** * Store a newly created resource in storage. */ - public function store(Request $request): JsonResponse + public function store(Request $request) : JsonResponse { - $payload = $request->only((new EstadoTurno())->getFillable()); - $estadoTurno = EstadoTurno::create($payload); + $validated = $request->validate([ + 'descripcion' => 'required|string|max:255|unique:estado_turnos,descripcion', + ]); + + $estadoTurno = EstadoTurno::create($validated); return response()->json([ 'success' => true, 'data' => $estadoTurno, - 'message' => 'Registro creado correctamente', + 'message' => 'Estado de turno creado correctamente' ], 201); } /** * Display the specified resource. */ - public function show(EstadoTurno $estadoTurno): JsonResponse + public function show(EstadoTurno $estadoTurno) : JsonResponse { return response()->json([ 'success' => true, 'data' => $estadoTurno, - 'message' => 'Registro obtenido correctamente', + 'message' => 'Estado de turno obtenido correctamente' ], 200); } @@ -54,26 +55,28 @@ class EstadoTurnoController extends Controller */ public function update(Request $request, EstadoTurno $estadoTurno): JsonResponse { - $payload = $request->only((new EstadoTurno())->getFillable()); - $estadoTurno->update($payload); + $validated = $request->validate([ + 'descripcion' => 'required|string|max:255|unique:estado_turnos,descripcion,' . $estadoTurno->id, + ]); + + $estadoTurno->update($validated); return response()->json([ 'success' => true, 'data' => $estadoTurno, - 'message' => 'Registro actualizado correctamente', - ], 200); + 'message' => 'Estado de turno actualizado correctamente' + ], 200); } /** * Remove the specified resource from storage. */ - public function destroy(EstadoTurno $estadoTurno): JsonResponse + public function destroy(EstadoTurno $estadoTurno) : JsonResponse { $estadoTurno->delete(); return response()->json([ 'success' => true, - 'message' => 'Registro eliminado correctamente', - ], 200); + 'message' => 'Estado de turno eliminado correctamente' } -} \ No newline at end of file +} diff --git a/app/Http/Controllers/ProfesionalController.php b/app/Http/Controllers/ProfesionalController.php index 7e68931..a908b96 100644 --- a/app/Http/Controllers/ProfesionalController.php +++ b/app/Http/Controllers/ProfesionalController.php @@ -6,6 +6,8 @@ use App\Models\Profesional; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; +use App\Http\Controllers\LogSeguridadController; + class ProfesionalController extends Controller { /** @@ -22,21 +24,54 @@ class ProfesionalController extends Controller ], 200); } + + /** * Store a newly created resource in storage. */ - public function store(Request $request): JsonResponse - { - $payload = $request->only((new Profesional())->getFillable()); - $profesional = Profesional::create($payload); +public function store(Request $request): JsonResponse +{ + // 1. Validamos los datos de entrada + $validated = $request->validate([ + 'inicio' => 'required|date_format:Y-m-d H:i:s', + 'correo' => 'nullable|email|max:255', + 'nombrecompleto' => 'nullable|string|max:255', + 'descripcion' => 'required|string', + 'cliente_id' => 'nullable|exists:clientes,id', + 'estadoturno_id' => 'required|exists:estadosturnos,id', + 'agenda_id' => 'required|exists:agendas,id', + 'profesional_id' => 'required|exists:profesionales,id', + 'servicio_id' => 'required|exists:servicios,id', + 'modalidad_id' => 'required|exists:modalidades,id', + ]); + // 2. Verificamos si el profesional ya tiene un turno en ese "inicio" + $existeTurno = Turno::where('profesional_id', $validated['profesional_id']) + ->where('inicio', $validated['inicio']) + ->whereIn('estadoturno_id', [1, 2]) // 1: Pendiente, 2: Confirmado + ->exists(); + if ($existeTurno) { return response()->json([ - 'success' => true, - 'data' => $profesional, - 'message' => 'Registro creado correctamente', - ], 201); + 'success' => false, + 'message' => 'Horario no disponible.', + ], 422); // Error de validación lógica } + + $turno = Turno::create($validated); + // 3. Registramos el evento en el log de seguridad + $personaId = auth()->check() ? auth()->user()->persona->id : null; + LogSeguridadController::registrarAccion('Creacion de turno ID: ' . $turno->id, 'Profesional', 17, $personaId); + + + + return response()->json([ + 'success' => true, + 'data' => $turno, + 'message' => 'Turno agendado correctamente para el ' . $turno->inicio->format('d/m/Y H:i'), + ], 201); + +} /** * Display the specified resource. */ @@ -76,4 +111,14 @@ class ProfesionalController extends Controller 'message' => 'Registro eliminado correctamente', ], 200); } + + public function aceptarFormulario(Formulario $formulario): JsonResponse + { + $turno->update(['estadoturno_id' => 2]); + + return response()->json([ + 'success' => true, + 'message' => 'Turno aceptado correctamente', + ], 200); + } } \ No newline at end of file diff --git a/app/Http/Controllers/TurnoController.php b/app/Http/Controllers/TurnoController.php index 2211f92..bc09bcf 100644 --- a/app/Http/Controllers/TurnoController.php +++ b/app/Http/Controllers/TurnoController.php @@ -76,4 +76,59 @@ class TurnoController extends Controller 'message' => 'Registro eliminado correctamente', ], 200); } + + public function confirmar(Turno $turno): JsonResponse + { + $turno->confirmar(); + + return response()->json([ + 'success' => true, + 'data' => $turno, + 'message' => 'Turno confirmado correctamente', + ], 200); + } + + public function cancelar(Turno $turno): JsonResponse + { + $turno->cancelar(); + + return response()->json([ + 'success' => true, + 'data' => $turno, + 'message' => 'Turno cancelado correctamente', + ], 200); + } + + public function reprogramar(Turno $turno): JsonResponse + { + $turno->reprogramar(); + + return response()->json([ + 'success' => true, + 'data' => $turno, + 'message' => 'Turno reprogramado correctamente', + ], 200); + } + + public function clienteAusente(Turno $turno): JsonResponse + { + $turno->clienteAusente(); + + return response()->json([ + 'success' => true, + 'data' => $turno, + 'message' => 'Turno marcado como cliente ausente', + ], 200); + } + + public function clientePresente(Turno $turno): JsonResponse + { + $turno->clientePresente(); + + return response()->json([ + 'success' => true, + 'data' => $turno, + 'message' => 'Turno marcado como cliente presente', + ], 200); + } } \ No newline at end of file diff --git a/app/Models/Agenda.php b/app/Models/Agenda.php index a009469..2b378ec 100644 --- a/app/Models/Agenda.php +++ b/app/Models/Agenda.php @@ -4,6 +4,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Support\Facades\DB; class Agenda extends Model { @@ -40,4 +41,509 @@ class Agenda extends Model { return $this->hasMany(ModoVacaciones::class, 'agenda_id', 'id'); } + + public function formularios() +{ + return $this->belongsToMany( + \App\Models\Formulario::class, + 'profesionales_formularios', + 'profesional_id', + 'formulario_id', + 'profesional_id', + 'id' + )->withPivot('estadoformulario')->withTimestamps(); +} + + public function estaDisponible($fecha, $hora, $agendaId = null) // Verificar si la agenda está disponible para una fecha y hora específicas + { + $agenda = $agendaId ? self::find($agendaId) : $this; + if (!$agenda) { + return false; + } + + // Verificar si la fecha es un feriado + if ($agenda->feriado()->where('fecha', $fecha)->exists()) { + return false; + } + + // Verificar si la fecha está dentro de un período de vacaciones + if ($agenda->modoVacaciones()->where('inicio', '<=', $fecha)->where('fin', '>=', $fecha)->exists()) { + return false; + } + + // Verificar si el día de atención corresponde al día de la semana de la fecha + $diaSemana = date('N', strtotime($fecha)); // 1 (lunes) a 7 (domingo) + $diaAtencion = $agenda->diaDeAtencion()->where('dia_id', $diaSemana)->first(); + if (!$diaAtencion) { + return false; + } + + // Verificar si la hora está dentro del horario de atención + if (!$diaAtencion->horariosAtenciones()->where('horariocomienzo', '<=', $hora)->where('horariofin', '>=', $hora)->exists()) { + return false; + } + + // Verificar si la hora no está dentro de un horario de receso + if ($diaAtencion->horariosRecesos()->where('comienzo', '<=', $hora)->where('fin', '>=', $hora)->exists()) { + return false; + } + + // Verificar si ya existe un turno para esa fecha y hora + if ($agenda->turno()->where('inicio', $fecha . ' ' . $hora)->exists()) { + return false; + } + + return true; + } + + public function obtenerTurnoDisponible($idProfesional, $tipopreferencia = 'INDISTINTO', $diasPreferencia = []) //Devuelve el turno disponible más cercano según preferencias + { + // Inicializa estructuras de salida con valores por defecto. + $DiasDeAtenciones = array_fill(0, 7, array_fill(0, 5, null)); + $tipo = null; + $recesos = []; + $vacaciones = []; + $feriados = []; + $turnoMasCercano = null; + + // Busca la agenda asociada al profesional recibido por parámetro. + $agendaId = self::where('profesional_id', $idProfesional)->value('id'); + + // Si no existe agenda para ese profesional, devuelve la estructura vacía. + if (!$agendaId) { + return null; + } + + // Obtiene días de atención y sus horarios AM/PM para la agenda encontrada. + // [fila][0]=dia_id, [fila][1]=inicio AM, [fila][2]=fin AM, [fila][3]=inicio PM, [fila][4]=fin PM + + $filasAtencion = DB::table('diasdeatenciones as d') + ->leftJoin('horariosatenciones as h', 'h.diadeatencion_id', '=', 'd.id') + ->where('d.agenda_id', $agendaId) + ->select('d.dia_id', 'h.horariocomienzo', 'h.horariofin', 'h.tipo') + ->orderBy('d.dia_id') + ->get(); + + // Recorre cada fila y la ubica en la matriz de 7x5 según día y tipo de horario. + foreach ($filasAtencion as $filaAtencion) { + $fila = (int) $filaAtencion->dia_id - 1; + + // Ignora valores fuera del rango esperado de días (1 a 7). + if ($fila < 0 || $fila > 6) { + continue; + } + + // Guarda el identificador del día en la primera columna. + $DiasDeAtenciones[$fila][0] = $filaAtencion->dia_id; + + // Si no hay tipo de horario, salta al siguiente registro. + if ($filaAtencion->tipo === null) { + continue; + } + + // Normaliza y guarda el tipo actual (AM o PM). + $tipoActual = strtoupper(trim((string) $filaAtencion->tipo)); + $tipo = $tipoActual; + + // Completa columnas de mañana (inicio y fin). + if ($tipoActual === 'AM') { + $DiasDeAtenciones[$fila][1] = $filaAtencion->horariocomienzo; + $DiasDeAtenciones[$fila][2] = $filaAtencion->horariofin; + } + + // Completa columnas de tarde (inicio y fin). + if ($tipoActual === 'PM') { + $DiasDeAtenciones[$fila][3] = $filaAtencion->horariocomienzo; + $DiasDeAtenciones[$fila][4] = $filaAtencion->horariofin; + } + } + + // Trae los recesos de la agenda y los transforma a una matriz [dia_id, comienzo, fin]. + $recesos = DB::table('horariosrecesos as r') + ->join('diasdeatenciones as d', 'd.id', '=', 'r.diadeatencion_id') + ->where('d.agenda_id', $agendaId) + ->select('d.dia_id', 'r.comienzo', 'r.fin') + ->orderBy('d.dia_id') + ->get() + ->map(function ($receso) { + return [ + $receso->dia_id, + $receso->comienzo, + $receso->fin, + ]; + }) + ->values() + ->all(); + + // Trae períodos de vacaciones y los transforma a una matriz [inicio, fin]. + $vacaciones = DB::table('modosvacaciones') + ->where('agenda_id', $agendaId) + ->select('inicio', 'fin') + ->orderBy('inicio') + ->get() + ->map(function ($vacacion) { + return [ + $vacacion->inicio, + $vacacion->fin, + ]; + }) + ->values() + ->all(); + + // Trae todos los feriados de la agenda y los transforma en una matriz de fechas. + $feriados = DB::table('feriados') + ->where('agenda_id', $agendaId) + ->select('fecha') + ->orderBy('fecha') + ->pluck('fecha') + ->values() + ->all(); + + // Normaliza preferencia horaria (AM, PM o INDISTINTO). + $tipopreferencia = strtoupper(trim((string) $tipopreferencia)); + if (!in_array($tipopreferencia, ['AM', 'PM', 'INDISTINTO'], true)) { + $tipopreferencia = 'INDISTINTO'; + } + + // Convierte los días preferidos en texto a ids de 1 (lunes) a 7 (domingo). + $mapaDias = [ + 'lunes' => 1, + 'martes' => 2, + 'miercoles' => 3, + 'jueves' => 4, + 'viernes' => 5, + 'sabado' => 6, + 'domingo' => 7, + ]; + $diasPreferidosIds = []; + foreach ((array) $diasPreferencia as $diaPreferido) { + $diaNormalizado = strtolower(trim((string) $diaPreferido)); + $diaNormalizado = strtr($diaNormalizado, [ + 'á' => 'a', + 'é' => 'e', + 'í' => 'i', + 'ó' => 'o', + 'ú' => 'u', + ]); + + if (isset($mapaDias[$diaNormalizado])) { + $diasPreferidosIds[] = $mapaDias[$diaNormalizado]; + } + } + $diasPreferidosIds = array_values(array_unique($diasPreferidosIds)); + + // Toma la duración de turno de la agenda; si no existe, usa 40 minutos. + $duracionTurno = (int) (self::where('id', $agendaId)->value('duracionturno') ?? 40); + if ($duracionTurno <= 0) { + $duracionTurno = 40; + } + + // Define el punto de inicio de la búsqueda desde el día siguiente (para evitar asignar turnos inmediatos del día actual). + $baseTimestamp = strtotime('tomorrow'); + + // Crea índices rápidos para validar fechas bloqueadas y horarios ocupados. + $feriadosLookup = array_flip($feriados); + $recesosPorDia = []; + foreach ($recesos as $receso) { + $diaId = (int) $receso[0]; + if (!isset($recesosPorDia[$diaId])) { + $recesosPorDia[$diaId] = []; + } + $recesosPorDia[$diaId][] = [$receso[1], $receso[2]]; + } + + $turnosOcupadosLookup = []; + $turnosOcupados = DB::table('turnos') + ->where('agenda_id', $agendaId) + ->where('inicio', '>=', date('Y-m-d', $baseTimestamp)) + ->select('inicio') + ->get(); + + foreach ($turnosOcupados as $turnoOcupado) { + $tsTurno = strtotime((string) $turnoOcupado->inicio); + if ($tsTurno === false) { + continue; + } + + $turnosOcupadosLookup[date('Y-m-d H:i:s', $tsTurno)] = true; + } + + // Busca el primer turno disponible respetando tipo, días preferidos y reglas de agenda. + for ($offsetDias = 0; $offsetDias <= 120; $offsetDias++) { + $tsDia = strtotime(date('Y-m-d', $baseTimestamp) . ' +' . $offsetDias . ' day'); + if ($tsDia === false) { + continue; + } + + $fechaIterada = date('Y-m-d', $tsDia); + $diaId = (int) date('N', $tsDia); + + if (!empty($diasPreferidosIds) && !in_array($diaId, $diasPreferidosIds, true)) { + continue; + } + + if (isset($feriadosLookup[$fechaIterada])) { + continue; + } + + $enVacaciones = false; + foreach ($vacaciones as $vacacion) { + if ($fechaIterada >= $vacacion[0] && $fechaIterada <= $vacacion[1]) { + $enVacaciones = true; + break; + } + } + if ($enVacaciones) { + continue; + } + + $filaDia = $DiasDeAtenciones[$diaId - 1] ?? null; + if (!$filaDia || $filaDia[0] === null) { + continue; + } + + $ventanas = []; + if (($tipopreferencia === 'AM' || $tipopreferencia === 'INDISTINTO') && $filaDia[1] !== null && $filaDia[2] !== null) { + $ventanas[] = ['tipo' => 'AM', 'inicio' => $filaDia[1], 'fin' => $filaDia[2]]; + } + if (($tipopreferencia === 'PM' || $tipopreferencia === 'INDISTINTO') && $filaDia[3] !== null && $filaDia[4] !== null) { + $ventanas[] = ['tipo' => 'PM', 'inicio' => $filaDia[3], 'fin' => $filaDia[4]]; + } + + foreach ($ventanas as $ventana) { + $inicioVentanaTs = strtotime($fechaIterada . ' ' . $ventana['inicio']); + $finVentanaTs = strtotime($fechaIterada . ' ' . $ventana['fin']); + if ($inicioVentanaTs === false || $finVentanaTs === false || $inicioVentanaTs >= $finVentanaTs) { + continue; + } + + for ($slotTs = $inicioVentanaTs; ($slotTs + ($duracionTurno * 60)) <= $finVentanaTs; $slotTs += ($duracionTurno * 60)) { + $slotFecha = date('Y-m-d', $slotTs); + $slotHora = date('H:i:s', $slotTs); + $slotDateTime = $slotFecha . ' ' . $slotHora; + $slotFinTs = $slotTs + ($duracionTurno * 60); + + if (isset($turnosOcupadosLookup[$slotDateTime])) { + continue; + } + + $solapaReceso = false; + foreach ($recesosPorDia[$diaId] ?? [] as $recesoDia) { + $recesoInicioTs = strtotime($slotFecha . ' ' . $recesoDia[0]); + $recesoFinTs = strtotime($slotFecha . ' ' . $recesoDia[1]); + if ($recesoInicioTs === false || $recesoFinTs === false) { + continue; + } + + if ($slotTs < $recesoFinTs && $slotFinTs > $recesoInicioTs) { + $solapaReceso = true; + break; + } + } + + if ($solapaReceso) { + continue; + } + + if (!$this->estaDisponible($slotFecha, $slotHora, $agendaId)) { + continue; + } + + $turnoMasCercano = [ + 'fecha' => $slotFecha, + 'hora' => $slotHora, + 'fechaHora' => $slotDateTime, + 'tipo' => $ventana['tipo'], + 'duracionMinutos' => $duracionTurno, + ]; + break 3; + } + } + } + + // Devuelve solo la fecha/hora del turno más cercano o null si no hay disponibilidad. + return $turnoMasCercano['fechaHora'] ?? null; + } + + public function crearDiaDeAtencion($diaId, $horarioComienzo, $horarioFin, $tipo) + { + $tipoNormalizado = strtoupper(trim((string) $tipo)); + if (!in_array($tipoNormalizado, ['AM', 'PM'], true)) { + throw new \InvalidArgumentException('El tipo debe ser AM o PM.'); + } + + $horarioComienzoNormalizado = $this->normalizarHora($horarioComienzo, 'horarioComienzo'); + $horarioFinNormalizado = $this->normalizarHora($horarioFin, 'horarioFin'); + + if (strtotime('1970-01-01 ' . $horarioComienzoNormalizado) >= strtotime('1970-01-01 ' . $horarioFinNormalizado)) { + throw new \InvalidArgumentException('horarioComienzo debe ser menor que horarioFin.'); + } + + return DB::transaction(function () use ($diaId, $tipoNormalizado, $horarioComienzoNormalizado, $horarioFinNormalizado) { + $diaAtencion = DiaDeAtencion::firstOrCreate( + ['agenda_id' => $this->id, 'dia_id' => $diaId], + ['descripcion' => 'Dia de atencion'] + ); + + HorarioDeAtencion::updateOrCreate( + [ + 'diadeatencion_id' => $diaAtencion->id, + 'tipo' => $tipoNormalizado, + ], + [ + 'horariocomienzo' => $horarioComienzoNormalizado, + 'horariofin' => $horarioFinNormalizado, + ] + ); + + return $diaAtencion; + }); + } + + public function eliminarDiaDeAtencion($diaId) + { + return DB::transaction(function () use ($diaId) { + $diaAtencion = DiaDeAtencion::where('agenda_id', $this->id)->where('dia_id', $diaId)->first(); + if ($diaAtencion) { + HorarioDeAtencion::where('diadeatencion_id', $diaAtencion->id)->delete(); + HorarioReceso::where('diadeatencion_id', $diaAtencion->id)->delete(); + $diaAtencion->delete(); + } + }); + } + + public function crearModoVacaciones($inicio, $fin, $descripcion = null) + { + return ModoVacaciones::create([ + 'agenda_id' => $this->id, + 'inicio' => $inicio, + 'fin' => $fin, + 'descripcion' => $descripcion, + ]); + + } + + public function eliminarModoVacaciones($id) + { + $modoVacaciones = ModoVacaciones::where('agenda_id', $this->id)->where('id', $id)->first(); + if ($modoVacaciones) { + $modoVacaciones->delete(); + } + } + + public function crearFeriado($fecha, $descripcion = null) + { + return Feriado::create([ + 'agenda_id' => $this->id, + 'fecha' => $fecha, + 'descripcion' => $descripcion, + ]); + } + + public function eliminarFeriado($id) + { + $feriado = Feriado::where('agenda_id', $this->id)->where('id', $id)->first(); + if ($feriado) { + $feriado->delete(); + } + } + + public function guardarTurno($inicio, $correo = null, $nombrecompleto = null, $descripcion = null, $clienteId = null, $estadoturnoId = null, $profesionalId = null, $servicioId = null, $modalidadId = null, $agendaId = null) + { + $inicioNormalizado = $this->normalizarDatetime($inicio, 'inicio'); + + $turno = Turno::create([ + 'agenda_id' => $agendaId ?? $this->id, + 'correo' => $correo, + 'nombrecompleto' => $nombrecompleto, + 'descripcion' => $descripcion, + 'cliente_id' => $clienteId, + 'estadoturno_id' => $estadoturnoId, + 'profesional_id' => $profesionalId, + 'servicio_id' => $servicioId, + 'modalidad_id' => $modalidadId, + 'inicio' => $inicioNormalizado, + ]); + + return $turno; + } + + private function normalizarHora($valor, $campo) + { + if ($valor instanceof \DateTimeInterface) { + return $valor->format('H:i:s'); + } + + $timestamp = strtotime(trim((string) $valor)); + if ($timestamp === false) { + throw new \InvalidArgumentException('El campo ' . $campo . ' debe ser una hora valida.'); + } + + return date('H:i:s', $timestamp); + } + + private function normalizarDatetime($valor, $campo) + { + if ($valor instanceof \DateTimeInterface) { + return $valor->format('Y-m-d H:i:s'); + } + + $timestamp = strtotime(trim((string) $valor)); + if ($timestamp === false) { + throw new \InvalidArgumentException('El campo ' . $campo . ' debe ser una fecha y hora valida.'); + } + + return date('Y-m-d H:i:s', $timestamp); + } + + public function confirmarTurno($id) + { + $turno = $this->turno()->find($id); + if (!$turno) { + return null; + } + + return $turno->confirmar(); + } + + public function cancelarTurno($id) + { + $turno = $this->turno()->find($id); + if (!$turno) { + return null; + } + + return $turno->cancelar(); + } + + public function reprogramarTurno($id) + { + $turno = $this->turno()->find($id); + if (!$turno) { + return null; + } + + return $turno->reprogramar(); + } + + public function marcarClienteAusente($id) + { + $turno = $this->turno()->find($id); + if (!$turno) { + return null; + } + + return $turno->clienteAusente(); + } + + public function marcarClientePresente($id) + { + $turno = $this->turno()->find($id); + if (!$turno) { + return null; + } + + return $turno->clientePresente(); + } + } diff --git a/app/Models/DiaDeAtencion.php b/app/Models/DiaDeAtencion.php index 477d016..0970568 100644 --- a/app/Models/DiaDeAtencion.php +++ b/app/Models/DiaDeAtencion.php @@ -33,7 +33,7 @@ use HasFactory; } public function horariosAtenciones() { - return $this->hasMany(HorarioAtencion::class, 'diadeatencion_id', 'id'); + return $this->hasMany(HorarioDeAtencion::class, 'diadeatencion_id', 'id'); } diff --git a/app/Models/Formulario.php b/app/Models/Formulario.php index c4757a8..f695399 100644 --- a/app/Models/Formulario.php +++ b/app/Models/Formulario.php @@ -56,7 +56,7 @@ class Formulario extends Model return $this->belongsToMany(DiaPreferencia::class, 'formularios_diaspreferidos', 'formulario_id', 'diapreferencia_id'); } - public function horariopreferido() + public function horariosPreferidos() { return $this->belongsToMany(HorarioPreferencia::class, 'formularios_horariospreferidos', 'formulario_id', 'horariopreferencia_id'); } diff --git a/app/Models/HorarioDeAtencion.php b/app/Models/HorarioDeAtencion.php index 1727540..23c296f 100644 --- a/app/Models/HorarioDeAtencion.php +++ b/app/Models/HorarioDeAtencion.php @@ -13,6 +13,7 @@ class HorarioDeAtencion extends Model protected $fillable = [ 'horariocomienzo', 'horariofin', + 'tipo', 'diadeatencion_id', ]; diff --git a/app/Models/Modalidad.php b/app/Models/Modalidad.php index f7c5358..3c465f2 100644 --- a/app/Models/Modalidad.php +++ b/app/Models/Modalidad.php @@ -19,4 +19,9 @@ class Modalidad extends Model return $this->hasMany(Formulario::class, 'modalidad_id', 'id'); } + public function turnos() + { + return $this->hasMany(Turno::class, 'modalidad_id', 'id'); + } + } diff --git a/app/Models/Turno.php b/app/Models/Turno.php index 6f693b4..51a81c0 100644 --- a/app/Models/Turno.php +++ b/app/Models/Turno.php @@ -20,6 +20,11 @@ class Turno extends Model 'agenda_id', 'profesional_id', 'servicio_id', + 'modalidad_id', + ]; + + protected $casts = [ + 'inicio' => 'datetime', ]; public function estadoTurno() @@ -45,4 +50,45 @@ class Turno extends Model { return $this->belongsTo(Servicio::class, 'servicio_id', 'id'); } + + public function modalidad() + { + return $this->belongsTo(Modalidad::class, 'modalidad_id', 'id'); + } + + public function confirmar() + { + $this->estadoturno_id = 1; // ID del estado Confirmado (dato maestro) + $this->save(); + return $this; + } + + public function cancelar() + { + $this->estadoturno_id = 2; // ID del estado Cancelado (dato maestro) + $this->save(); + return $this; + } + + public function reprogramar() + { + $this->estadoturno_id = 3; // ID del estado Reprogramado (dato maestro) + $this->save(); + return $this; + } + + public function clienteAusente() + { + $this->estadoturno_id = 4; // ID del estado Cliente Ausente (dato maestro) + $this->save(); + return $this; + } + + public function clientePresente() + { + $this->estadoturno_id = 5; // ID del estado Cliente Presente (dato maestro) + $this->save(); + return $this; + } + } diff --git a/database/migrations/2026_03_05_194208_create_horariosatenciones_table.php b/database/migrations/2026_03_05_194208_create_horariosatenciones_table.php index c0b4c0c..bed9684 100644 --- a/database/migrations/2026_03_05_194208_create_horariosatenciones_table.php +++ b/database/migrations/2026_03_05_194208_create_horariosatenciones_table.php @@ -16,6 +16,7 @@ return new class extends Migration $table->timestamps(); $table->time('horariocomienzo'); $table->time('horariofin'); + $table->string('tipo'); // AM o PM $table->foreignId('diadeatencion_id') ->constrained('diasdeatenciones'); }); diff --git a/database/migrations/2026_03_06_113148_create_turnos_table.php b/database/migrations/2026_03_06_113148_create_turnos_table.php index a19b117..3699887 100644 --- a/database/migrations/2026_03_06_113148_create_turnos_table.php +++ b/database/migrations/2026_03_06_113148_create_turnos_table.php @@ -38,6 +38,10 @@ return new class extends Migration $table->foreignId('servicio_id') ->constrained('servicios') ->onDelete('cascade'); + + $table->foreignId('modalidad_id') + ->constrained('modalidades') + ->onDelete('cascade'); }); } diff --git a/database/seeders/EstadoTurnoSeeder.php b/database/seeders/EstadoTurnoSeeder.php index 712ae27..1d12afb 100644 --- a/database/seeders/EstadoTurnoSeeder.php +++ b/database/seeders/EstadoTurnoSeeder.php @@ -14,11 +14,11 @@ class EstadoTurnoSeeder extends Seeder public function run(): void { $estados = [ - ['descripcion' => 'Pendiente'], ['descripcion' => 'Confirmado'], - ['descripcion' => 'Rechazado'], ['descripcion' => 'Cancelado'], - ['descripcion' => 'Reprogramado'] + ['descripcion' => 'Reprogramado'], + ['descripcion' => 'Cliente Ausente'], + ['descripcion' => 'Cliente Presente'] ]; foreach ($estados as $estado){ diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..82278ee --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1836 @@ +{ + "name": "abogadaslitoral", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "@popperjs/core": "^2.11.8", + "bootstrap": "^5.3.8" + }, + "devDependencies": { + "axios": "^1.11.0", + "concurrently": "^9.0.1", + "laravel-vite-plugin": "^2.0.0", + "vite": "^7.0.7" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.4.tgz", + "integrity": "sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.4.tgz", + "integrity": "sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.4.tgz", + "integrity": "sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.4.tgz", + "integrity": "sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.4.tgz", + "integrity": "sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.4.tgz", + "integrity": "sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.4.tgz", + "integrity": "sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.4.tgz", + "integrity": "sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.4.tgz", + "integrity": "sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.4.tgz", + "integrity": "sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.4.tgz", + "integrity": "sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.4.tgz", + "integrity": "sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.4.tgz", + "integrity": "sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.4.tgz", + "integrity": "sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.4.tgz", + "integrity": "sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.4.tgz", + "integrity": "sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.4.tgz", + "integrity": "sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.4.tgz", + "integrity": "sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.4.tgz", + "integrity": "sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.4.tgz", + "integrity": "sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.4.tgz", + "integrity": "sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.4.tgz", + "integrity": "sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.4.tgz", + "integrity": "sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.4.tgz", + "integrity": "sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.4.tgz", + "integrity": "sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.4.tgz", + "integrity": "sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.0.tgz", + "integrity": "sha512-WOhNW9K8bR3kf4zLxbfg6Pxu2ybOUbB2AjMDHSQx86LIF4rH4Ft7vmMwNt0loO0eonglSNy4cpD3MKXXKQu0/A==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.0.tgz", + "integrity": "sha512-u6JHLll5QKRvjciE78bQXDmqRqNs5M/3GVqZeMwvmjaNODJih/WIrJlFVEihvV0MiYFmd+ZyPr9wxOVbPAG2Iw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.0.tgz", + "integrity": "sha512-qEF7CsKKzSRc20Ciu2Zw1wRrBz4g56F7r/vRwY430UPp/nt1x21Q/fpJ9N5l47WWvJlkNCPJz3QRVw008fi7yA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.0.tgz", + "integrity": "sha512-WADYozJ4QCnXCH4wPB+3FuGmDPoFseVCUrANmA5LWwGmC6FL14BWC7pcq+FstOZv3baGX65tZ378uT6WG8ynTw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.0.tgz", + "integrity": "sha512-6b8wGHJlDrGeSE3aH5mGNHBjA0TTkxdoNHik5EkvPHCt351XnigA4pS7Wsj/Eo9Y8RBU6f35cjN9SYmCFBtzxw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.0.tgz", + "integrity": "sha512-h25Ga0t4jaylMB8M/JKAyrvvfxGRjnPQIR8lnCayyzEjEOx2EJIlIiMbhpWxDRKGKF8jbNH01NnN663dH638mA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.0.tgz", + "integrity": "sha512-RzeBwv0B3qtVBWtcuABtSuCzToo2IEAIQrcyB/b2zMvBWVbjo8bZDjACUpnaafaxhTw2W+imQbP2BD1usasK4g==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.0.tgz", + "integrity": "sha512-Sf7zusNI2CIU1HLzuu9Tc5YGAHEZs5Lu7N1ssJG4Tkw6e0MEsN7NdjUDDfGNHy2IU+ENyWT+L2obgWiguWibWQ==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.0.tgz", + "integrity": "sha512-DX2x7CMcrJzsE91q7/O02IJQ5/aLkVtYFryqCjduJhUfGKG6yJV8hxaw8pZa93lLEpPTP/ohdN4wFz7yp/ry9A==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.0.tgz", + "integrity": "sha512-09EL+yFVbJZlhcQfShpswwRZ0Rg+z/CsSELFCnPt3iK+iqwGsI4zht3secj5vLEs957QvFFXnzAT0FFPIxSrkQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.0.tgz", + "integrity": "sha512-i9IcCMPr3EXm8EQg5jnja0Zyc1iFxJjZWlb4wr7U2Wx/GrddOuEafxRdMPRYVaXjgbhvqalp6np07hN1w9kAKw==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.0.tgz", + "integrity": "sha512-DGzdJK9kyJ+B78MCkWeGnpXJ91tK/iKA6HwHxF4TAlPIY7GXEvMe8hBFRgdrR9Ly4qebR/7gfUs9y2IoaVEyog==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.0.tgz", + "integrity": "sha512-RwpnLsqC8qbS8z1H1AxBA1H6qknR4YpPR9w2XX0vo2Sz10miu57PkNcnHVaZkbqyw/kUWfKMI73jhmfi9BRMUQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.0.tgz", + "integrity": "sha512-Z8pPf54Ly3aqtdWC3G4rFigZgNvd+qJlOE52fmko3KST9SoGfAdSRCwyoyG05q1HrrAblLbk1/PSIV+80/pxLg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.0.tgz", + "integrity": "sha512-3a3qQustp3COCGvnP4SvrMHnPQ9d1vzCakQVRTliaz8cIp/wULGjiGpbcqrkv0WrHTEp8bQD/B3HBjzujVWLOA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.0.tgz", + "integrity": "sha512-pjZDsVH/1VsghMJ2/kAaxt6dL0psT6ZexQVrijczOf+PeP2BUqTHYejk3l6TlPRydggINOeNRhvpLa0AYpCWSQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.0.tgz", + "integrity": "sha512-3ObQs0BhvPgiUVZrN7gqCSvmFuMWvWvsjG5ayJ3Lraqv+2KhOsp+pUbigqbeWqueGIsnn+09HBw27rJ+gYK4VQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.0.tgz", + "integrity": "sha512-EtylprDtQPdS5rXvAayrNDYoJhIz1/vzN2fEubo3yLE7tfAw+948dO0g4M0vkTVFhKojnF+n6C8bDNe+gDRdTg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.0.tgz", + "integrity": "sha512-k09oiRCi/bHU9UVFqD17r3eJR9bn03TyKraCrlz5ULFJGdJGi7VOmm9jl44vOJvRJ6P7WuBi/s2A97LxxHGIdw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.0.tgz", + "integrity": "sha512-1o/0/pIhozoSaDJoDcec+IVLbnRtQmHwPV730+AOD29lHEEo4F5BEUB24H0OBdhbBBDwIOSuf7vgg0Ywxdfiiw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.0.tgz", + "integrity": "sha512-pESDkos/PDzYwtyzB5p/UoNU/8fJo68vcXM9ZW2V0kjYayj1KaaUfi1NmTUTUpMn4UhU4gTuK8gIaFO4UGuMbA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.0.tgz", + "integrity": "sha512-hj1wFStD7B1YBeYmvY+lWXZ7ey73YGPcViMShYikqKT1GtstIKQAtfUI6yrzPjAy/O7pO0VLXGmUVWXQMaYgTQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.0.tgz", + "integrity": "sha512-SyaIPFoxmUPlNDq5EHkTbiKzmSEmq/gOYFI/3HHJ8iS/v1mbugVa7dXUzcJGQfoytp9DJFLhHH4U3/eTy2Bq4w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.0.tgz", + "integrity": "sha512-RdcryEfzZr+lAr5kRm2ucN9aVlCCa2QNq4hXelZxb8GG0NJSazq44Z3PCCc8wISRuCVnGs0lQJVX5Vp6fKA+IA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.0.tgz", + "integrity": "sha512-PrsWNQ8BuE00O3Xsx3ALh2Df8fAj9+cvvX9AIA6o4KpATR98c9mud4XtDWVvsEuyia5U4tVSTKygawyJkjm60w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.6.tgz", + "integrity": "sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.11", + "form-data": "^4.0.5", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/bootstrap": { + "version": "5.3.8", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.8.tgz", + "integrity": "sha512-HP1SZDqaLDPwsNiqRqi5NcP0SSXciX2s9E+RyqJIIqGo+vJeN5AJVM98CXmW/Wux0nQ5L7jeWUdplCEf0Ee+tg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/twbs" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/bootstrap" + } + ], + "license": "MIT", + "peerDependencies": { + "@popperjs/core": "^2.11.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/concurrently": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.1.tgz", + "integrity": "sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "4.1.2", + "rxjs": "7.8.2", + "shell-quote": "1.8.3", + "supports-color": "8.1.1", + "tree-kill": "1.2.2", + "yargs": "17.7.2" + }, + "bin": { + "conc": "dist/bin/concurrently.js", + "concurrently": "dist/bin/concurrently.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.4.tgz", + "integrity": "sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.4", + "@esbuild/android-arm": "0.27.4", + "@esbuild/android-arm64": "0.27.4", + "@esbuild/android-x64": "0.27.4", + "@esbuild/darwin-arm64": "0.27.4", + "@esbuild/darwin-x64": "0.27.4", + "@esbuild/freebsd-arm64": "0.27.4", + "@esbuild/freebsd-x64": "0.27.4", + "@esbuild/linux-arm": "0.27.4", + "@esbuild/linux-arm64": "0.27.4", + "@esbuild/linux-ia32": "0.27.4", + "@esbuild/linux-loong64": "0.27.4", + "@esbuild/linux-mips64el": "0.27.4", + "@esbuild/linux-ppc64": "0.27.4", + "@esbuild/linux-riscv64": "0.27.4", + "@esbuild/linux-s390x": "0.27.4", + "@esbuild/linux-x64": "0.27.4", + "@esbuild/netbsd-arm64": "0.27.4", + "@esbuild/netbsd-x64": "0.27.4", + "@esbuild/openbsd-arm64": "0.27.4", + "@esbuild/openbsd-x64": "0.27.4", + "@esbuild/openharmony-arm64": "0.27.4", + "@esbuild/sunos-x64": "0.27.4", + "@esbuild/win32-arm64": "0.27.4", + "@esbuild/win32-ia32": "0.27.4", + "@esbuild/win32-x64": "0.27.4" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/laravel-vite-plugin": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-2.1.0.tgz", + "integrity": "sha512-z+ck2BSV6KWtYcoIzk9Y5+p4NEjqM+Y4i8/H+VZRLq0OgNjW2DqyADquwYu5j8qRvaXwzNmfCWl1KrMlV1zpsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "picocolors": "^1.0.0", + "vite-plugin-full-reload": "^1.1.0" + }, + "bin": { + "clean-orphaned-assets": "bin/clean.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^7.0.0" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", + "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true, + "license": "MIT" + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.0.tgz", + "integrity": "sha512-yqjxruMGBQJ2gG4HtjZtAfXArHomazDHoFwFFmZZl0r7Pdo7qCIXKqKHZc8yeoMgzJJ+pO6pEEHa+V7uzWlrAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.60.0", + "@rollup/rollup-android-arm64": "4.60.0", + "@rollup/rollup-darwin-arm64": "4.60.0", + "@rollup/rollup-darwin-x64": "4.60.0", + "@rollup/rollup-freebsd-arm64": "4.60.0", + "@rollup/rollup-freebsd-x64": "4.60.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.60.0", + "@rollup/rollup-linux-arm-musleabihf": "4.60.0", + "@rollup/rollup-linux-arm64-gnu": "4.60.0", + "@rollup/rollup-linux-arm64-musl": "4.60.0", + "@rollup/rollup-linux-loong64-gnu": "4.60.0", + "@rollup/rollup-linux-loong64-musl": "4.60.0", + "@rollup/rollup-linux-ppc64-gnu": "4.60.0", + "@rollup/rollup-linux-ppc64-musl": "4.60.0", + "@rollup/rollup-linux-riscv64-gnu": "4.60.0", + "@rollup/rollup-linux-riscv64-musl": "4.60.0", + "@rollup/rollup-linux-s390x-gnu": "4.60.0", + "@rollup/rollup-linux-x64-gnu": "4.60.0", + "@rollup/rollup-linux-x64-musl": "4.60.0", + "@rollup/rollup-openbsd-x64": "4.60.0", + "@rollup/rollup-openharmony-arm64": "4.60.0", + "@rollup/rollup-win32-arm64-msvc": "4.60.0", + "@rollup/rollup-win32-ia32-msvc": "4.60.0", + "@rollup/rollup-win32-x64-gnu": "4.60.0", + "@rollup/rollup-win32-x64-msvc": "4.60.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/shell-quote": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "license": "MIT", + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, + "node_modules/vite": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", + "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-plugin-full-reload": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/vite-plugin-full-reload/-/vite-plugin-full-reload-1.2.0.tgz", + "integrity": "sha512-kz18NW79x0IHbxRSHm0jttP4zoO9P9gXh+n6UTwlNKnviTTEpOlum6oS9SmecrTtSr+muHEn5TUuC75UovQzcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picocolors": "^1.0.0", + "picomatch": "^2.3.1" + } + }, + "node_modules/vite-plugin-full-reload/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + } + } +} diff --git a/package.json b/package.json index 7686b29..6fe117d 100644 --- a/package.json +++ b/package.json @@ -7,11 +7,13 @@ "dev": "vite" }, "devDependencies": { - "@tailwindcss/vite": "^4.0.0", "axios": "^1.11.0", "concurrently": "^9.0.1", "laravel-vite-plugin": "^2.0.0", - "tailwindcss": "^4.0.0", "vite": "^7.0.7" + }, + "dependencies": { + "@popperjs/core": "^2.11.8", + "bootstrap": "^5.3.8" } } diff --git a/profesionalcreate.php b/profesionalcreate.php new file mode 100644 index 0000000..fe7b902 --- /dev/null +++ b/profesionalcreate.php @@ -0,0 +1,73 @@ +make(Kernel::class)->bootstrap(); + +$usuario = env('PROFESIONAL_USUARIO', 'profesional'); +$passwordPlano = env('PROFESIONAL_PASSWORD', 'profesional1234'); +$correo = env('PROFESIONAL_CORREO', 'profesional@abogadaslitoral.com'); +$dni = env('PROFESIONAL_DNI', '40000000'); +$nombre = env('PROFESIONAL_NOMBRE', 'Usuario'); +$apellido = env('PROFESIONAL_APELLIDO', 'Profesional'); +$cuil = env('PROFESIONAL_CUIL', '20-40000000-0'); +$fechaNac = env('PROFESIONAL_FECHANAC', '2026-01-01'); + +try { + DB::transaction(function () use ($usuario, $passwordPlano, $correo, $dni, $nombre, $apellido, $cuil, $fechaNac): void { + $foto = Foto::firstOrCreate( + ['ruta' => 'avatars/profesional-default.png'], + [ + 'extension' => 'png', + 'nombre' => 'profesional-default', + 'mime_type' => 'image/png', + 'tamanio_bytes' => 0, + ] + ); + + $persona = Persona::updateOrCreate( + ['dni' => $dni], + [ + 'nombre' => $nombre, + 'apellido' => $apellido, + 'cuil' => $cuil, + 'fechanac' => $fechaNac, + 'foto_id' => $foto->id, + ] + ); + + $credencial = CredencialProfesional::updateOrCreate( + ['usuario' => $usuario], + [ + 'contra' => Hash::make($passwordPlano), + 'rol' => 'PROFESIONAL', + ] + ); + + Profesional::updateOrCreate( + ['dni' => $dni, 'correo' => $correo], + [ + 'persona_id' => $persona->id, + 'credencialprofesional_id' => $credencial->id, + ] + ); + }); + + echo "Profesional creado correctamente." . PHP_EOL; + echo "Usuario: {$usuario}" . PHP_EOL; + echo "Correo: {$correo}" . PHP_EOL; +} catch (Throwable $e) { + fwrite(STDERR, 'Error al crear profesional: ' . $e->getMessage() . PHP_EOL); + exit(1); +} \ No newline at end of file diff --git a/resources/css/app.css b/resources/css/app.css index 3e6abea..f51f054 100644 --- a/resources/css/app.css +++ b/resources/css/app.css @@ -1,11 +1 @@ -@import 'tailwindcss'; - -@source '../../vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php'; -@source '../../storage/framework/views/*.php'; -@source '../**/*.blade.php'; -@source '../**/*.js'; - -@theme { - --font-sans: 'Instrument Sans', ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', - 'Segoe UI Symbol', 'Noto Color Emoji'; -} +@import 'bootstrap/dist/css/bootstrap.min.css'; diff --git a/resources/js/app.js b/resources/js/app.js index e59d6a0..a491cf4 100644 --- a/resources/js/app.js +++ b/resources/js/app.js @@ -1 +1,2 @@ import './bootstrap'; +import 'bootstrap'; diff --git a/resources/views/auth/login-cliente.blade.php b/resources/views/auth/login-cliente.blade.php new file mode 100644 index 0000000..d0d5b71 --- /dev/null +++ b/resources/views/auth/login-cliente.blade.php @@ -0,0 +1,57 @@ + + + + + + Login Cliente + @vite(['resources/css/app.css', 'resources/js/app.js']) + + +
+
+
+
+
+

Login de Cliente

+

Ingresa con tu correo y contraseña

+ + @if (session('login_error')) + + @endif + + @if (session('login_success')) + + @endif + +
+ @csrf +
+ + +
+ +
+ + +
+ + +
+ +
+

+ ¿Sos profesional o administrador? + Ir a login de personal +

+ +
+
+
+
+
+ + diff --git a/resources/views/auth/login-personal.blade.php b/resources/views/auth/login-personal.blade.php new file mode 100644 index 0000000..e2d6b6f --- /dev/null +++ b/resources/views/auth/login-personal.blade.php @@ -0,0 +1,62 @@ + + + + + + Login Personal + @vite(['resources/css/app.css', 'resources/js/app.js']) + + +
+
+
+
+
+

Login de Personal

+

Acceso para profesionales y administradores.

+ + @if (session('login_error')) + + @endif + + @if (session('login_success')) + + @endif + +
+ @csrf +
+ + +
+ +
+ + +
+ + +
+ +
+

+ ¿Sos cliente? + Ir a login de cliente +

+
+
+
+
+
+ Agregar Administrador +
+
+ Agregar Profesional +
+
+ + diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php new file mode 100644 index 0000000..c7c0a15 --- /dev/null +++ b/resources/views/layouts/app.blade.php @@ -0,0 +1,85 @@ + + + + + + @yield('title', 'Abogadas Litoral') + @vite(['resources/css/app.css', 'resources/js/app.js']) + + + +
+ +
+ + @yield('content') + + + + diff --git a/resources/views/welcome.blade.php b/resources/views/welcome.blade.php index b7355d7..25014c1 100644 --- a/resources/views/welcome.blade.php +++ b/resources/views/welcome.blade.php @@ -1,277 +1,50 @@ - - - - - +@extends('layouts.app') - {{ config('app.name', 'Laravel') }} +@section('title', 'Pagina Principal') - - - +@section('content') +
+
+

Servicios

+

Espacio para describir servicios.

+
+
- - @if (file_exists(public_path('build/manifest.json')) || file_exists(public_path('hot'))) - @vite(['resources/css/app.css', 'resources/js/app.js']) - @else - - @endif - - -
- @if (Route::has('login')) - - @endif -
-
-
-
-

Let's get started

-

Laravel has an incredibly rich ecosystem.
We suggest starting with the following.

- - +
+

Equipo

+
+ ... +
+

Some quick example text to build on the card title and make up the bulk of the card’s content.

-
- {{-- Laravel Logo --}} - - - - - - - - - +
+
+
- {{-- Light Mode 12 SVG --}} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
+

Ubicacion

+

Pasteur 141

+
+ +
+
+
- {{-- Dark Mode 12 SVG --}} - -
-
-
-
- - @if (Route::has('login')) - - @endif - - +
+

Formulario

+

Espacio para formulario de contacto.

+
+
+@endsection diff --git a/routes/api.php b/routes/api.php new file mode 100644 index 0000000..042dd12 --- /dev/null +++ b/routes/api.php @@ -0,0 +1,87 @@ +group(function () { + Route::post('auth/login/cliente', [AuthController::class, 'loginCliente']); + Route::post('auth/login/personal', [AuthController::class, 'loginPersonal']); + Route::post('auth/login', [AuthController::class, 'login']); + Route::post('auth/logout', [AuthController::class, 'logout']); + + // Rutas API Resource estándar + Route::apiResource('accioneslogs', AccionLogController::class); + Route::apiResource('administradores', AdministradorController::class); + Route::apiResource('agendas', AgendaController::class); + Route::apiResource('bajas', BajaController::class); + Route::apiResource('bugs', BugController::class); + Route::apiResource('clientes', ClienteController::class); + Route::apiResource('contenidosweb', ContenidoWebController::class); + Route::apiResource('credencialesclientes', CredencialClienteController::class); + Route::apiResource('credencialesprofesionales', CredencialProfesionalController::class); + Route::apiResource('dias', DiaController::class); + Route::apiResource('diasdeatenciones', DiaDeAtencionController::class); + Route::apiResource('diaspreferencias', DiaPreferenciaController::class); + Route::apiResource('documentacionesclientes', DocumentacionClienteController::class); + Route::apiResource('errores', ErrorController::class); + Route::apiResource('estadosprofesionales', EstadoProfesionalController::class); + Route::apiResource('estadosturnos', EstadoTurnoController::class); + Route::apiResource('feriados', FeriadoController::class); + Route::apiResource('formularios', FormularioController::class); + Route::apiResource('fotosbugs', FotoBugController::class); + Route::apiResource('fotos', FotoController::class); + Route::apiResource('horariosatenciones', HorarioDeAtencionController::class); + Route::apiResource('horariospreferencias', HorarioPreferenciaController::class); + Route::apiResource('horariosrecesos', HorarioRecesoController::class); + Route::apiResource('logseguridades', LogSeguridadController::class); + Route::apiResource('modalidades', ModalidadController::class); + Route::apiResource('modosvacaciones', ModoVacacionesController::class); + Route::apiResource('personas', PersonaController::class); + Route::apiResource('profesiones', ProfesionController::class); + Route::apiResource('profesionales', ProfesionalController::class); + Route::apiResource('servicios', ServicioController::class); + Route::apiResource('telefonos', TelefonoController::class); + Route::apiResource('turnos', TurnoController::class); + Route::post('turnos/{turno}/confirmar', [TurnoController::class, 'confirmar']); + Route::post('turnos/{turno}/cancelar', [TurnoController::class, 'cancelar']); + Route::post('turnos/{turno}/reprogramar', [TurnoController::class, 'reprogramar']); + Route::post('turnos/{turno}/cliente-ausente', [TurnoController::class, 'clienteAusente']); + Route::post('turnos/{turno}/cliente-presente', [TurnoController::class, 'clientePresente']); + Route::apiResource('ubicaciones', UbicacionController::class); + Route::apiResource('users', UserController::class); +}); diff --git a/routes/web.php b/routes/web.php index 86a06c5..1f8aed5 100644 --- a/routes/web.php +++ b/routes/web.php @@ -1,7 +1,13 @@