Initial commit
This commit is contained in:
@@ -0,0 +1,266 @@
|
||||
@model PowderCoating.Application.DTOs.Appointment.CreateAppointmentDto
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "New Appointment";
|
||||
ViewData["PageIcon"] = "bi-calendar-plus";
|
||||
ViewData["PageHelpTitle"] = "New Appointment";
|
||||
ViewData["PageHelpContent"] = "Create an appointment to schedule a customer visit, drop-off, pick-up, or consultation. Select the Type first — the Linked Job field appears once a type is chosen. Reminder notifications fire before the scheduled start time.";
|
||||
}
|
||||
|
||||
<div class="d-flex justify-content-end align-items-center mb-4">
|
||||
<a asp-action="Index" class="btn btn-outline-secondary">
|
||||
<i class="bi bi-arrow-left"></i> Back to List
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-8">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<form asp-action="Create" method="post">
|
||||
@if (!ViewData.ModelState.IsValid)
|
||||
{
|
||||
<div class="alert alert-danger">
|
||||
<h6 class="alert-heading"><i class="bi bi-exclamation-triangle me-2"></i>Please correct the following errors:</h6>
|
||||
<partial name="_ValidationSummary" />
|
||||
</div>
|
||||
}
|
||||
|
||||
<!-- 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" placeholder="e.g., John's Rims - Drop Off" />
|
||||
<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" placeholder="Additional details about the appointment..."></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">
|
||||
<div class="d-flex align-items-center gap-1 mb-1">
|
||||
<label asp-for="AppointmentTypeId" class="form-label mb-0">Type <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 Type"
|
||||
data-bs-content="Drop-Off: customer brings items in. Pick-Up: customer collects completed work. Consultation/Quote: meeting to discuss pricing. Job Work: block time for a specific job. The Linked Job field appears after you select a type.">
|
||||
<i class="bi bi-question-circle"></i>
|
||||
</a>
|
||||
</div>
|
||||
<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>
|
||||
|
||||
<!-- Job (conditional) -->
|
||||
<div class="mb-3" id="jobField" style="display: none;">
|
||||
<div class="d-flex align-items-center gap-1 mb-1">
|
||||
<label asp-for="JobId" class="form-label mb-0">Linked Job <span class="text-danger" id="jobRequired">*</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="Linked Job"
|
||||
data-bs-content="Connect this appointment to an active job so it appears on the job timeline. Useful for Drop-Offs, Pick-Ups, and scheduled job work. Optional for consultations and internal meetings.">
|
||||
<i class="bi bi-question-circle"></i>
|
||||
</a>
|
||||
</div>
|
||||
<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>
|
||||
<small class="text-muted">Link this appointment to an existing job.</small>
|
||||
</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>
|
||||
|
||||
<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" placeholder="e.g., Main Office, Loading Dock" />
|
||||
<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" placeholder="Notes for staff (not visible to customer)..."></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" checked />
|
||||
<label asp-for="IsReminderEnabled" class="form-check-label">
|
||||
Send reminder notification
|
||||
</label>
|
||||
</div>
|
||||
<div class="mb-0" id="reminderTime">
|
||||
<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" value="30" />
|
||||
<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> Create Appointment
|
||||
</button>
|
||||
<a asp-action="Index" class="btn btn-outline-secondary">Cancel</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sidebar - Help -->
|
||||
<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>Tips</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h6>Appointment Types:</h6>
|
||||
<ul class="small mb-3">
|
||||
<li><strong>Customer Drop-Off:</strong> Customer bringing items to the shop</li>
|
||||
<li><strong>Customer Pick-Up:</strong> Customer collecting completed items</li>
|
||||
<li><strong>Consultation/Quote:</strong> Meeting to discuss pricing and requirements</li>
|
||||
<li><strong>Scheduled Job Work:</strong> Blocking time for working on a specific job</li>
|
||||
</ul>
|
||||
<h6>Reminders:</h6>
|
||||
<p class="small mb-0">Set a reminder to receive a notification before the appointment starts. Useful for preparing materials or coordinating with staff.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@section Scripts {
|
||||
<partial name="_ValidationScriptsPartial" />
|
||||
<script>
|
||||
// Show/hide job field based on appointment type
|
||||
document.getElementById('appointmentType').addEventListener('change', function() {
|
||||
const jobField = document.getElementById('jobField');
|
||||
const jobRequired = document.getElementById('jobRequired');
|
||||
// You can add logic here to check if selected type requires job link
|
||||
// For now, we'll show it for all types but mark required only for JOB_WORK
|
||||
if (this.value) {
|
||||
jobField.style.display = 'block';
|
||||
} else {
|
||||
jobField.style.display = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
// Toggle reminder time visibility
|
||||
document.getElementById('reminderEnabled').addEventListener('change', function() {
|
||||
const reminderTime = document.getElementById('reminderTime');
|
||||
reminderTime.style.display = this.checked ? 'block' : 'none';
|
||||
});
|
||||
|
||||
// Set default start time to tomorrow at 9 AM if empty
|
||||
const startTimeInput = document.getElementById('startTime');
|
||||
const endTimeInput = document.getElementById('endTime');
|
||||
|
||||
if (!startTimeInput.value) {
|
||||
const tomorrow = new Date();
|
||||
tomorrow.setDate(tomorrow.getDate() + 1);
|
||||
tomorrow.setHours(9, 0, 0, 0);
|
||||
startTimeInput.value = tomorrow.toISOString().slice(0, 16);
|
||||
|
||||
const endTime = new Date(tomorrow);
|
||||
endTime.setHours(10, 0, 0, 0);
|
||||
endTimeInput.value = endTime.toISOString().slice(0, 16);
|
||||
}
|
||||
|
||||
// Auto-update end time when start time changes
|
||||
startTimeInput.addEventListener('change', function() {
|
||||
const isAllDay = document.getElementById('isAllDay').checked;
|
||||
const newEndTime = new Date(this.value);
|
||||
|
||||
if (isAllDay) {
|
||||
// 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
|
||||
newEndTime.setHours(newEndTime.getHours() + 1);
|
||||
endTimeInput.value = newEndTime.toISOString().slice(0, 16);
|
||||
}
|
||||
});
|
||||
|
||||
// Hide time inputs when "All Day" is checked
|
||||
document.getElementById('isAllDay').addEventListener('change', function() {
|
||||
const timeInputs = document.querySelectorAll('#startTime, #endTime');
|
||||
timeInputs.forEach(input => {
|
||||
if (this.checked) {
|
||||
input.type = 'date';
|
||||
} else {
|
||||
input.type = 'datetime-local';
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
}
|
||||
Reference in New Issue
Block a user