Files
nimbusflow/frontend/Components/Pages/Services.razor

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;
}
}
}