236 lines
10 KiB
Plaintext
236 lines
10 KiB
Plaintext
@page "/services"
|
|
@using NimbusFlow.Frontend.Services
|
|
@using NimbusFlow.Frontend.Models
|
|
@inject IApiService ApiService
|
|
|
|
<PageTitle>Services</PageTitle>
|
|
|
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
|
<h1 class="nimbus-page-title">
|
|
<i class="bi bi-gear-fill me-3"></i>Services
|
|
</h1>
|
|
<a href="/services/create" class="btn btn-nimbus-primary">
|
|
<i class="bi bi-gear-wide-connected me-2"></i>Create Service
|
|
</a>
|
|
</div>
|
|
|
|
@if (loading)
|
|
{
|
|
<div class="text-center">
|
|
<div class="spinner-border" role="status">
|
|
<span class="visually-hidden">Loading...</span>
|
|
</div>
|
|
</div>
|
|
}
|
|
else if (services.Any())
|
|
{
|
|
<!-- Filter Controls -->
|
|
<div class="row mb-3">
|
|
<div class="col-md-4">
|
|
<select class="form-select" @bind="selectedServiceType">
|
|
<option value="">All Service Types</option>
|
|
@foreach (var serviceType in serviceTypes)
|
|
{
|
|
<option value="@serviceType.ServiceTypeId">@serviceType.TypeName</option>
|
|
}
|
|
</select>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<input type="date" class="form-control" @bind="filterDate" />
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" @bind="showPastServices" id="showPast">
|
|
<label class="form-check-label" for="showPast">
|
|
Show past services
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-12">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<div class="table-responsive">
|
|
<table class="table table-striped table-hover">
|
|
<thead>
|
|
<tr>
|
|
<th>Date</th>
|
|
<th>Service Type</th>
|
|
<th>Scheduled Members</th>
|
|
<th>Status</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@foreach (var service in filteredServices.OrderBy(s => s.ServiceDate))
|
|
{
|
|
<tr class="@(service.ServiceDate < DateTime.Today ? "text-muted" : "")">
|
|
<td>
|
|
<strong>@service.ServiceDate.ToString("MMM dd, yyyy (dddd)")</strong>
|
|
</td>
|
|
<td>
|
|
<span class="badge" style="background-color: var(--nimbus-gold); color: var(--nimbus-navy);">
|
|
@service.ServiceTypeName
|
|
</span>
|
|
</td>
|
|
<td>
|
|
@{
|
|
var serviceSchedules = schedules.Where(s => s.ServiceId == service.ServiceId).ToList();
|
|
var acceptedCount = serviceSchedules.Count(s => s.Status == "accepted");
|
|
var pendingCount = serviceSchedules.Count(s => s.Status == "pending");
|
|
var declinedCount = serviceSchedules.Count(s => s.Status == "declined");
|
|
}
|
|
<div class="d-flex gap-1">
|
|
@if (acceptedCount > 0)
|
|
{
|
|
<span class="badge bg-success">@acceptedCount accepted</span>
|
|
}
|
|
@if (pendingCount > 0)
|
|
{
|
|
<span class="badge bg-warning text-dark">@pendingCount pending</span>
|
|
}
|
|
@if (declinedCount > 0)
|
|
{
|
|
<span class="badge bg-danger">@declinedCount declined</span>
|
|
}
|
|
@if (serviceSchedules.Count == 0)
|
|
{
|
|
<span class="text-muted">No schedules</span>
|
|
}
|
|
</div>
|
|
</td>
|
|
<td>
|
|
@if (service.ServiceDate < DateTime.Today)
|
|
{
|
|
<span class="badge bg-secondary">Past</span>
|
|
}
|
|
else if (service.ServiceDate == DateTime.Today)
|
|
{
|
|
<span class="badge bg-primary">Today</span>
|
|
}
|
|
else
|
|
{
|
|
<span class="badge bg-success">Upcoming</span>
|
|
}
|
|
</td>
|
|
<td>
|
|
<div class="btn-group" role="group">
|
|
<a href="/services/@service.ServiceId" class="btn btn-sm btn-nimbus-secondary me-1">
|
|
<i class="bi bi-eye-fill me-1"></i>View
|
|
</a>
|
|
@if (service.ServiceDate >= DateTime.Today)
|
|
{
|
|
<a href="/schedules/create?serviceId=@service.ServiceId" class="btn btn-sm btn-success me-1">
|
|
<i class="bi bi-calendar-plus-fill me-1"></i>Schedule
|
|
</a>
|
|
<a href="/services/@service.ServiceId/edit" class="btn btn-sm btn-outline-warning">
|
|
<i class="bi bi-pencil-fill me-1"></i>Edit
|
|
</a>
|
|
}
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row mt-3">
|
|
<div class="col-md-12">
|
|
<small class="text-muted">
|
|
Showing @filteredServices.Count() of @services.Count services
|
|
</small>
|
|
</div>
|
|
</div>
|
|
}
|
|
else
|
|
{
|
|
<div class="text-center">
|
|
<div class="alert alert-info">
|
|
<h4>No Services Found</h4>
|
|
<p>There are currently no services in the system.</p>
|
|
<a href="/services/create" class="btn btn-primary">Create Your First Service</a>
|
|
</div>
|
|
</div>
|
|
}
|
|
|
|
@code {
|
|
private List<Service> services = new();
|
|
private List<ServiceType> serviceTypes = new();
|
|
private List<Schedule> schedules = new();
|
|
private bool loading = true;
|
|
private string selectedServiceType = "";
|
|
private DateTime? filterDate;
|
|
private bool showPastServices = false;
|
|
|
|
private IEnumerable<Service> filteredServices
|
|
{
|
|
get
|
|
{
|
|
var filtered = services.AsEnumerable();
|
|
|
|
if (!showPastServices)
|
|
{
|
|
filtered = filtered.Where(s => s.ServiceDate >= DateTime.Today);
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(selectedServiceType) && int.TryParse(selectedServiceType, out int typeId))
|
|
{
|
|
filtered = filtered.Where(s => s.ServiceTypeId == typeId);
|
|
}
|
|
|
|
if (filterDate.HasValue)
|
|
{
|
|
filtered = filtered.Where(s => s.ServiceDate.Date == filterDate.Value.Date);
|
|
}
|
|
|
|
return filtered;
|
|
}
|
|
}
|
|
|
|
protected override async Task OnInitializedAsync()
|
|
{
|
|
await LoadData();
|
|
}
|
|
|
|
private async Task LoadData()
|
|
{
|
|
try
|
|
{
|
|
loading = true;
|
|
|
|
// Load all data in parallel
|
|
var servicesTask = ApiService.GetServicesAsync();
|
|
var serviceTypesTask = ApiService.GetServiceTypesAsync();
|
|
var schedulesTask = ApiService.GetSchedulesAsync();
|
|
|
|
await Task.WhenAll(servicesTask, serviceTypesTask, schedulesTask);
|
|
|
|
services = servicesTask.Result;
|
|
serviceTypes = serviceTypesTask.Result;
|
|
schedules = schedulesTask.Result;
|
|
|
|
// Map service type names to services
|
|
foreach (var service in services)
|
|
{
|
|
var serviceType = serviceTypes.FirstOrDefault(st => st.ServiceTypeId == service.ServiceTypeId);
|
|
service.ServiceTypeName = serviceType?.TypeName ?? "Unknown";
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"Error loading services data: {ex.Message}");
|
|
}
|
|
finally
|
|
{
|
|
loading = false;
|
|
}
|
|
}
|
|
|
|
} |