orderBy('fecha', 'desc')->orderBy('hora_inicio', 'desc'); // Filtros if ($request->filled('estado')) { $query->where('estado', $request->estado); } if ($request->filled('fecha')) { $query->whereDate('fecha', $request->fecha); } if ($request->filled('fecha_inicio') && $request->filled('fecha_fin')) { $query->whereBetween('fecha', [$request->fecha_inicio, $request->fecha_fin]); } if ($request->filled('buscar')) { $buscar = $request->buscar; $query->where(function ($q) use ($buscar) { $q->where('nombre_cliente', 'like', "%{$buscar}%") ->orWhere('email_cliente', 'like', "%{$buscar}%") ->orWhere('telefono_cliente', 'like', "%{$buscar}%") ->orWhere('servicio', 'like', "%{$buscar}%"); }); } $citas = $query->paginate(15)->appends($request->query()); return view('admin.citas.index', compact('citas')); } /** * Mostrar formulario de creación */ public function create(): View { $mensajes = Mensaje::orderBy('created_at', 'desc')->get(); return view('admin.citas.create', compact('mensajes')); } /** * Guardar nueva cita */ public function store(CitaRequest $request): RedirectResponse { $data = $request->validated(); // Calcular hora_fin basada en hora_inicio y duracion $horaInicio = Carbon::parse($data['hora_inicio']); $horaFin = $horaInicio->addMinutes($data['duracion']); $data['hora_fin'] = $horaFin->format('H:i:s'); // Verificar disponibilidad antes de crear $conflicto = Cita::whereDate('fecha', $data['fecha']) ->where(function ($query) use ($data) { $query->where(function ($q) use ($data) { $q->whereTime('hora_inicio', '<', $data['hora_fin']) ->whereTime('hora_fin', '>', $data['hora_inicio']); }); }) ->whereIn('estado', ['pendiente', 'confirmada']) ->exists(); if ($conflicto) { return back()->withErrors(['hora_inicio' => 'Ya existe una cita programada en este horario.'])->withInput(); } // Verificar si el horario está bloqueado if (HorarioBloqueado::estaBloqueado($data['fecha'], $data['hora_inicio'])) { return back()->withErrors(['hora_inicio' => 'El horario está bloqueado.'])->withInput(); } Cita::create($data); return redirect()->route('admin.citas.index')->with('success', 'Cita creada correctamente.'); } /** * Mostrar detalles de una cita */ public function show(Cita $cita): View { $cita->load('mensaje'); return view('admin.citas.show', compact('cita')); } /** * Mostrar formulario de edición */ public function edit(Cita $cita): View { $mensajes = Mensaje::orderBy('created_at', 'desc')->get(); return view('admin.citas.edit', compact('cita', 'mensajes')); } /** * Actualizar cita */ public function update(CitaRequest $request, Cita $cita): RedirectResponse { $data = $request->validated(); // Calcular hora_fin si cambió hora_inicio o duracion if ($request->has('hora_inicio') || $request->has('duracion')) { $horaInicio = Carbon::parse($data['hora_inicio'] ?? $cita->hora_inicio); $duracion = $data['duracion'] ?? $cita->duracion; $horaFin = $horaInicio->addMinutes($duracion); $data['hora_fin'] = $horaFin->format('H:i:s'); } // Verificar conflicto si se cambia fecha u hora $conflicto = Cita::where('id', '!=', $cita->id) ->whereDate('fecha', $data['fecha']) ->where(function ($query) use ($data) { $query->where(function ($q) use ($data) { $q->whereTime('hora_inicio', '<', $data['hora_fin']) ->whereTime('hora_fin', '>', $data['hora_inicio']); }); }) ->whereIn('estado', ['pendiente', 'confirmada']) ->exists(); if ($conflicto) { return back()->withErrors(['hora_inicio' => 'Ya existe una cita programada en este horario.'])->withInput(); } $cita->update($data); return redirect()->route('admin.citas.index')->with('success', 'Cita actualizada correctamente.'); } /** * Eliminar cita */ public function destroy(Cita $cita): RedirectResponse { $cita->delete(); return redirect()->route('admin.citas.index')->with('success', 'Cita eliminada correctamente.'); } /** * Cambiar estado de la cita */ public function cambiarEstado(Request $request, Cita $cita): RedirectResponse { $request->validate([ 'estado' => ['required', 'in:pendiente,confirmada,completada,cancelada'], ]); $cita->update(['estado' => $request->estado]); return back()->with('success', 'Estado de la cita actualizado correctamente.'); } /** * Mostrar calendario de citas */ public function calendario(Request $request): View { $fecha = $request->filled('fecha') ? Carbon::parse($request->fecha) : Carbon::now(); $citas = Cita::with('mensaje') ->whereDate('fecha', $fecha) ->whereIn('estado', ['pendiente', 'confirmada']) ->orderBy('hora_inicio') ->get(); return view('admin.citas.calendario', compact('citas', 'fecha')); } /** * Obtener citas para una fecha específica (API) */ public function porFecha(Request $request): JsonResponse { $request->validate([ 'fecha' => ['required', 'date'], ]); $citas = Cita::whereDate('fecha', $request->fecha) ->whereIn('estado', ['pendiente', 'confirmada']) ->orderBy('hora_inicio') ->get(); return response()->json($citas); } }