274 lines
15 KiB
Plaintext
274 lines
15 KiB
Plaintext
@model PowderCoating.Application.DTOs.Appointment.UpdateAppointmentDto
|
|
|
|
@{
|
|
ViewData["Title"] = "Edit Appointment";
|
|
ViewData["PageIcon"] = "bi-pencil";
|
|
ViewData["PageHelpTitle"] = "Edit Appointment";
|
|
ViewData["PageHelpContent"] = "Update appointment details, change status, record actual arrival/completion times, or adjust the reminder. Use Actual Times to track punctuality vs scheduled time.";
|
|
}
|
|
|
|
<div class="d-flex justify-content-end align-items-center mb-4">
|
|
<a asp-action="Details" asp-route-id="@Model.Id" class="btn btn-outline-secondary">
|
|
<i class="bi bi-arrow-left"></i> Back to Details
|
|
</a>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-lg-8">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<form asp-action="Edit" method="post">
|
|
<input type="hidden" asp-for="Id" />
|
|
<partial name="_ValidationSummary" />
|
|
|
|
<!-- Title -->
|
|
<div class="mb-3">
|
|
<label asp-for="Title" class="form-label">Title <span class="text-danger">*</span></label>
|
|
<input asp-for="Title" class="form-control" />
|
|
<span asp-validation-for="Title" class="text-danger"></span>
|
|
</div>
|
|
|
|
<!-- Description -->
|
|
<div class="mb-3">
|
|
<label asp-for="Description" class="form-label">Description</label>
|
|
<textarea asp-for="Description" class="form-control" rows="3"></textarea>
|
|
<span asp-validation-for="Description" class="text-danger"></span>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<!-- Customer -->
|
|
<div class="col-md-6 mb-3">
|
|
<label asp-for="CustomerId" class="form-label">Customer</label>
|
|
<select asp-for="CustomerId" class="form-select" asp-items="ViewBag.Customers">
|
|
<option value="">-- Select Customer (Optional) --</option>
|
|
</select>
|
|
<span asp-validation-for="CustomerId" class="text-danger"></span>
|
|
</div>
|
|
|
|
<!-- Appointment Type -->
|
|
<div class="col-md-6 mb-3">
|
|
<label asp-for="AppointmentTypeId" class="form-label">Type <span class="text-danger">*</span></label>
|
|
<select asp-for="AppointmentTypeId" class="form-select" asp-items="ViewBag.AppointmentTypes" id="appointmentType">
|
|
<option value="">-- Select Type --</option>
|
|
</select>
|
|
<span asp-validation-for="AppointmentTypeId" class="text-danger"></span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<!-- Status -->
|
|
<div class="col-md-6 mb-3">
|
|
<div class="d-flex align-items-center gap-1 mb-1">
|
|
<label asp-for="AppointmentStatusId" class="form-label mb-0">Status <span class="text-danger">*</span></label>
|
|
<a tabindex="0" class="help-icon" role="button"
|
|
data-bs-toggle="popover" data-bs-placement="right" data-bs-trigger="focus"
|
|
data-bs-title="Appointment Status"
|
|
data-bs-content="Scheduled → Confirmed (customer acknowledged) → In Progress (currently happening) → Completed. Use Cancelled for cancellations, No Show if the customer didn't arrive, and Rescheduled when moved to a new time.">
|
|
<i class="bi bi-question-circle"></i>
|
|
</a>
|
|
</div>
|
|
<select asp-for="AppointmentStatusId" class="form-select" asp-items="ViewBag.AppointmentStatuses">
|
|
<option value="">-- Select Status --</option>
|
|
</select>
|
|
<span asp-validation-for="AppointmentStatusId" class="text-danger"></span>
|
|
</div>
|
|
|
|
<!-- Job (conditional) -->
|
|
<div class="col-md-6 mb-3">
|
|
<label asp-for="JobId" class="form-label">Linked Job</label>
|
|
<select asp-for="JobId" class="form-select" asp-items="ViewBag.Jobs">
|
|
<option value="">-- Select Job (Optional) --</option>
|
|
</select>
|
|
<span asp-validation-for="JobId" class="text-danger"></span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- All Day Checkbox -->
|
|
<div class="mb-3 form-check">
|
|
<input asp-for="IsAllDay" class="form-check-input" id="isAllDay" />
|
|
<label asp-for="IsAllDay" class="form-check-label">
|
|
All Day Event
|
|
</label>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<!-- Start Date/Time -->
|
|
<div class="col-md-6 mb-3">
|
|
<label asp-for="ScheduledStartTime" class="form-label">Start <span class="text-danger">*</span></label>
|
|
<input asp-for="ScheduledStartTime" type="datetime-local" class="form-control" id="startTime" />
|
|
<span asp-validation-for="ScheduledStartTime" class="text-danger"></span>
|
|
</div>
|
|
|
|
<!-- End Date/Time -->
|
|
<div class="col-md-6 mb-3">
|
|
<label asp-for="ScheduledEndTime" class="form-label">End <span class="text-danger">*</span></label>
|
|
<input asp-for="ScheduledEndTime" type="datetime-local" class="form-control" id="endTime" />
|
|
<span asp-validation-for="ScheduledEndTime" class="text-danger"></span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Actual Times -->
|
|
<div class="card mb-3 bg-light">
|
|
<div class="card-header">
|
|
<div class="d-flex align-items-center gap-2">
|
|
<h6 class="mb-0"><i class="bi bi-clock-history me-2"></i>Actual Times</h6>
|
|
<a tabindex="0" class="help-icon" role="button"
|
|
data-bs-toggle="popover" data-bs-placement="right" data-bs-trigger="focus"
|
|
data-bs-title="Actual Times"
|
|
data-bs-content="Record when the customer actually arrived and when the appointment finished. These are optional and separate from the scheduled times — useful for tracking punctuality and measuring how accurately appointments are estimated.">
|
|
<i class="bi bi-question-circle"></i>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-6 mb-3 mb-md-0">
|
|
<label asp-for="ActualStartTime" class="form-label">Actual Start</label>
|
|
<input asp-for="ActualStartTime" type="datetime-local" class="form-control" />
|
|
<span asp-validation-for="ActualStartTime" class="text-danger"></span>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label asp-for="ActualEndTime" class="form-label">Actual End</label>
|
|
<input asp-for="ActualEndTime" type="datetime-local" class="form-control" />
|
|
<span asp-validation-for="ActualEndTime" class="text-danger"></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<!-- Assigned Worker -->
|
|
<div class="col-md-6 mb-3">
|
|
<label asp-for="AssignedUserId" class="form-label">Assign To Worker</label>
|
|
<select asp-for="AssignedUserId" class="form-select" asp-items="ViewBag.Workers">
|
|
<option value="">-- No Assignment --</option>
|
|
</select>
|
|
<span asp-validation-for="AssignedUserId" class="text-danger"></span>
|
|
</div>
|
|
|
|
<!-- Location -->
|
|
<div class="col-md-6 mb-3">
|
|
<label asp-for="Location" class="form-label">Location</label>
|
|
<input asp-for="Location" class="form-control" />
|
|
<span asp-validation-for="Location" class="text-danger"></span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Internal Notes -->
|
|
<div class="mb-3">
|
|
<label asp-for="Notes" class="form-label">Internal Notes</label>
|
|
<textarea asp-for="Notes" class="form-control" rows="2"></textarea>
|
|
<span asp-validation-for="Notes" class="text-danger"></span>
|
|
</div>
|
|
|
|
<!-- Reminder Settings -->
|
|
<div class="card mb-3">
|
|
<div class="card-header">
|
|
<div class="d-flex align-items-center gap-2">
|
|
<h6 class="mb-0"><i class="bi bi-bell me-2"></i>Reminder Settings</h6>
|
|
<a tabindex="0" class="help-icon" role="button"
|
|
data-bs-toggle="popover" data-bs-placement="right" data-bs-trigger="focus"
|
|
data-bs-title="Reminder Settings"
|
|
data-bs-content="Enable a reminder to receive an in-app notification before the appointment. Set how many minutes in advance — e.g., 30 for a brief heads-up, 1440 for a full day before. Reminders are per-appointment and do not send external emails or SMS.">
|
|
<i class="bi bi-question-circle"></i>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="mb-3 form-check">
|
|
<input asp-for="IsReminderEnabled" class="form-check-input" id="reminderEnabled" />
|
|
<label asp-for="IsReminderEnabled" class="form-check-label">
|
|
Send reminder notification
|
|
</label>
|
|
</div>
|
|
<div class="mb-0" id="reminderTime" style="display: @(Model.IsReminderEnabled ? "block" : "none")">
|
|
<label asp-for="ReminderMinutesBefore" class="form-label">Remind me</label>
|
|
<div class="input-group">
|
|
<input asp-for="ReminderMinutesBefore" type="number" class="form-control" min="5" max="1440" />
|
|
<span class="input-group-text">minutes before</span>
|
|
</div>
|
|
<span asp-validation-for="ReminderMinutesBefore" class="text-danger"></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Actions -->
|
|
<div class="d-flex justify-content-between">
|
|
<button type="submit" class="btn btn-primary">
|
|
<i class="bi bi-check-circle"></i> Save Changes
|
|
</button>
|
|
<a asp-action="Details" asp-route-id="@Model.Id" class="btn btn-outline-secondary">Cancel</a>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Sidebar - Status Guide -->
|
|
<div class="col-lg-4">
|
|
<div class="card">
|
|
<div class="card-header bg-info text-white">
|
|
<h6 class="mb-0"><i class="bi bi-info-circle me-2"></i>Status Guide</h6>
|
|
</div>
|
|
<div class="card-body">
|
|
<h6>Status Meanings:</h6>
|
|
<ul class="small mb-3">
|
|
<li><strong>Scheduled:</strong> Initial appointment booking</li>
|
|
<li><strong>Confirmed:</strong> Customer has confirmed attendance</li>
|
|
<li><strong>In Progress:</strong> Appointment is currently happening</li>
|
|
<li><strong>Completed:</strong> Appointment finished successfully</li>
|
|
<li><strong>Cancelled:</strong> Appointment was cancelled</li>
|
|
<li><strong>No Show:</strong> Customer didn't arrive</li>
|
|
<li><strong>Rescheduled:</strong> Moved to a different time</li>
|
|
</ul>
|
|
<h6>Actual Times:</h6>
|
|
<p class="small mb-0">Record when the customer actually arrived and when the appointment was completed. Useful for tracking punctuality and duration accuracy.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
@section Scripts {
|
|
<partial name="_ValidationScriptsPartial" />
|
|
<script>
|
|
// Toggle reminder time visibility
|
|
document.getElementById('reminderEnabled').addEventListener('change', function() {
|
|
const reminderTime = document.getElementById('reminderTime');
|
|
reminderTime.style.display = this.checked ? 'block' : 'none';
|
|
});
|
|
|
|
// Hide time inputs when "All Day" is checked
|
|
const isAllDayCheckbox = document.getElementById('isAllDay');
|
|
const startTimeInput = document.getElementById('startTime');
|
|
const endTimeInput = document.getElementById('endTime');
|
|
|
|
function toggleTimeInputs() {
|
|
if (isAllDayCheckbox.checked) {
|
|
startTimeInput.type = 'date';
|
|
endTimeInput.type = 'date';
|
|
} else {
|
|
startTimeInput.type = 'datetime-local';
|
|
endTimeInput.type = 'datetime-local';
|
|
}
|
|
}
|
|
|
|
// Initialize on load
|
|
toggleTimeInputs();
|
|
|
|
isAllDayCheckbox.addEventListener('change', toggleTimeInputs);
|
|
|
|
// Auto-update end time when start time changes
|
|
startTimeInput.addEventListener('change', function() {
|
|
if (isAllDayCheckbox.checked) {
|
|
// For all-day events, set end date to same as start date
|
|
endTimeInput.value = this.value;
|
|
} else {
|
|
// For timed events, set end time to 1 hour after start time
|
|
const newEndTime = new Date(this.value);
|
|
newEndTime.setHours(newEndTime.getHours() + 1);
|
|
endTimeInput.value = newEndTime.toISOString().slice(0, 16);
|
|
}
|
|
});
|
|
</script>
|
|
}
|