Add citas module: scheduling, calendar, blocked schedules
This commit is contained in:
293
resources/views/admin/citas/create.blade.php
Normal file
293
resources/views/admin/citas/create.blade.php
Normal file
@@ -0,0 +1,293 @@
|
||||
@extends('admin.layouts.master')
|
||||
|
||||
@section('title', 'Crear Cita - Lash Vanshy')
|
||||
|
||||
@section('page-title', 'Nueva Cita')
|
||||
|
||||
@section('content')
|
||||
<!-- Breadcrumb -->
|
||||
<nav aria-label="breadcrumb" class="mb-4">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="{{ route('admin.dashboard') }}">Dashboard</a></li>
|
||||
<li class="breadcrumb-item"><a href="{{ route('admin.citas.index') }}">Citas</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Nueva Cita</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-8">
|
||||
<div class="card-admin">
|
||||
<div class="card-header">
|
||||
<i class="fas fa-calendar-plus me-2"></i>Agendar Nueva Cita
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="POST" action="{{ route('admin.citas.store') }}" id="citaForm">
|
||||
@csrf
|
||||
|
||||
@if($mensaje)
|
||||
<input type="hidden" name="mensaje_id" value="{{ $mensaje->id }}">
|
||||
<div class="alert alert-info mb-4">
|
||||
<i class="fas fa-info-circle me-2"></i>
|
||||
<strong>Nota:</strong> Esta cita se creará a partir del mensaje de
|
||||
<strong>{{ $mensaje->nombre }}</strong>
|
||||
<a href="{{ route('admin.mensajes.show', $mensaje) }}" class="text-decoration-underline ms-1">
|
||||
(Ver mensaje)
|
||||
</a>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="row">
|
||||
<!-- Cliente Nombre -->
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="cliente_nombre" class="form-label">
|
||||
Nombre del Cliente <span class="text-danger">*</span>
|
||||
</label>
|
||||
<input type="text"
|
||||
class="form-control @error('cliente_nombre') is-invalid @enderror"
|
||||
id="cliente_nombre"
|
||||
name="cliente_nombre"
|
||||
value="{{ $mensaje->nombre ?? old('cliente_nombre') }}"
|
||||
required>
|
||||
@error('cliente_nombre')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<!-- Cliente Email -->
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="cliente_email" class="form-label">
|
||||
Email <span class="text-danger">*</span>
|
||||
</label>
|
||||
<input type="email"
|
||||
class="form-control @error('cliente_email') is-invalid @enderror"
|
||||
id="cliente_email"
|
||||
name="cliente_email"
|
||||
value="{{ $mensaje->email ?? old('cliente_email') }}"
|
||||
required>
|
||||
@error('cliente_email')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<!-- Cliente Teléfono -->
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="cliente_telefono" class="form-label">
|
||||
Teléfono
|
||||
</label>
|
||||
<input type="tel"
|
||||
class="form-control @error('cliente_telefono') is-invalid @enderror"
|
||||
id="cliente_telefono"
|
||||
name="cliente_telefono"
|
||||
value="{{ $mensaje->telefono ?? old('cliente_telefono') }}">
|
||||
@error('cliente_telefono')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<!-- Servicio -->
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="servicio" class="form-label">
|
||||
Servicio
|
||||
</label>
|
||||
<select class="form-select @error('servicio') is-invalid @enderror"
|
||||
id="servicio"
|
||||
name="servicio">
|
||||
<option value="Lash Extensions" selected>Lash Extensions</option>
|
||||
<option value="Lash Lift">Lash Lift</option>
|
||||
<option value="Lash Removal">Lash Removal</option>
|
||||
<option value="Relleno">Relleno</option>
|
||||
<option value="Otro">Otro</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="my-4">
|
||||
|
||||
<div class="row">
|
||||
<!-- Fecha -->
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="fecha" class="form-label">
|
||||
Fecha <span class="text-danger">*</span>
|
||||
</label>
|
||||
<input type="date"
|
||||
class="form-control @error('fecha') is-invalid @enderror"
|
||||
id="fecha"
|
||||
name="fecha"
|
||||
value="{{ old('fecha') }}"
|
||||
min="{{ date('Y-m-d') }}"
|
||||
required>
|
||||
@error('fecha')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@else
|
||||
<small class="text-muted">
|
||||
<i class="fas fa-info-circle me-1"></i>
|
||||
Horario: 9:00 AM - 7:00 PM (Lun-Sáb)
|
||||
</small>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<!-- Hora Inicio -->
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="hora_inicio" class="form-label">
|
||||
Hora <span class="text-danger">*</span>
|
||||
</label>
|
||||
<select class="form-select @error('hora_inicio') is-invalid @enderror"
|
||||
id="hora_inicio"
|
||||
name="hora_inicio"
|
||||
required
|
||||
{{ old('fecha') ? '' : 'disabled' }}>
|
||||
<option value="">Seleccione fecha primero</option>
|
||||
@if(old('fecha'))
|
||||
@php
|
||||
$oldFecha = old('fecha');
|
||||
$oldHora = old('hora_inicio');
|
||||
@endphp
|
||||
@foreach($horariosDisponibles ?? [] as $hora)
|
||||
<option value="{{ $hora['hora'] }}"
|
||||
{{ $oldHora == $hora['hora'] ? 'selected' : '' }}>
|
||||
{{ $hora['label'] }}
|
||||
</option>
|
||||
@endforeach
|
||||
@endif
|
||||
</select>
|
||||
@error('hora_inicio')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@else
|
||||
<small class="text-muted" id="horaHelp">
|
||||
Duración: 60 minutos
|
||||
</small>
|
||||
@enderror
|
||||
<div class="loading-spinner d-none" id="horaLoading">
|
||||
<div class="spinner"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Notas -->
|
||||
<div class="mb-3">
|
||||
<label for="notas" class="form-label">Notas</label>
|
||||
<textarea class="form-control @error('notas') is-invalid @enderror"
|
||||
id="notas"
|
||||
name="notas"
|
||||
rows="3"
|
||||
placeholder="Notas adicionales sobre la cita...">{{ old('notas') }}</textarea>
|
||||
@error('notas')
|
||||
<div class="invalid-feedback">{{ $message }}</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-between mt-4">
|
||||
<a href="{{ route('admin.citas.index') }}" class="btn btn-secondary-admin">
|
||||
<i class="fas fa-arrow-left me-2"></i>Volver
|
||||
</a>
|
||||
<button type="submit" class="btn btn-primary-admin" id="submitBtn">
|
||||
<i class="fas fa-calendar-check me-2"></i>Agendar Cita
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sidebar -->
|
||||
<div class="col-lg-4">
|
||||
<div class="card-admin mb-3">
|
||||
<div class="card-header">
|
||||
<i class="fas fa-info-circle me-2"></i>Información
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ul class="text-muted">
|
||||
<li class="mb-2">Duración de cada cita: <strong>60 minutos</strong></li>
|
||||
<li class="mb-2">Horario de atención: <strong>9:00 AM - 7:00 PM</strong></li>
|
||||
<li class="mb-2">Días laborables: <strong>Lunes a Sábado</strong></li>
|
||||
<li class="mb-2">Último turno: <strong>6:00 PM</strong></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-admin">
|
||||
<div class="card-header">
|
||||
<i class="fas fa-calendar-alt me-2"></i>Calendario
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<a href="{{ route('admin.citas.calendario') }}" class="btn btn-secondary-admin w-100 mb-2">
|
||||
<i class="fas fa-calendar-alt me-2"></i>Ver Calendario
|
||||
</a>
|
||||
<a href="{{ route('admin.horarios.index') }}" class="btn btn-secondary-admin w-100">
|
||||
<i class="fas fa-clock me-2"></i>Horarios Bloqueados
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const fechaInput = document.getElementById('fecha');
|
||||
const horaSelect = document.getElementById('hora_inicio');
|
||||
const horaLoading = document.getElementById('horaLoading');
|
||||
const horaHelp = document.getElementById('horaHelp');
|
||||
const hoy = new Date().toISOString().split('T')[0];
|
||||
fechaInput.setAttribute('min', hoy);
|
||||
|
||||
// Sundays disabled
|
||||
fechaInput.addEventListener('change', function() {
|
||||
const fecha = new Date(this.value + 'T00:00:00');
|
||||
const diaSemana = fecha.getDay();
|
||||
|
||||
if (diaSemana === 0) {
|
||||
alert('Los domingos no hay atención.');
|
||||
this.value = '';
|
||||
horaSelect.innerHTML = '<option value="">Seleccione fecha primero</option>';
|
||||
horaSelect.disabled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
cargarHorariosDisponibles(this.value);
|
||||
});
|
||||
|
||||
function cargarHorariosDisponibles(fecha) {
|
||||
if (!fecha) return;
|
||||
|
||||
horaSelect.disabled = true;
|
||||
horaLoading.classList.remove('d-none');
|
||||
horaHelp.classList.add('d-none');
|
||||
|
||||
fetch(`/admin/citas/disponibles?fecha=${fecha}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
horaSelect.innerHTML = '<option value="">Seleccione un horario</option>';
|
||||
|
||||
if (data.length === 0) {
|
||||
horaSelect.innerHTML = '<option value="">No hay horarios disponibles</option>';
|
||||
} else {
|
||||
data.forEach(hora => {
|
||||
const option = document.createElement('option');
|
||||
option.value = hora.hora;
|
||||
option.textContent = hora.label;
|
||||
horaSelect.appendChild(option);
|
||||
});
|
||||
}
|
||||
|
||||
horaSelect.disabled = false;
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
horaSelect.innerHTML = '<option value="">Error al cargar horarios</option>';
|
||||
horaSelect.disabled = false;
|
||||
})
|
||||
.finally(() => {
|
||||
horaLoading.classList.add('d-none');
|
||||
horaHelp.classList.remove('d-none');
|
||||
});
|
||||
}
|
||||
|
||||
// Trigger on page load if fecha has value
|
||||
if (fechaInput.value) {
|
||||
cargarHorariosDisponibles(fechaInput.value);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
Reference in New Issue
Block a user