139 lines
4.7 KiB
Plaintext
139 lines
4.7 KiB
Plaintext
@page "/"
|
|
@using NimbusFlow.Frontend.Services
|
|
@using NimbusFlow.Frontend.Models
|
|
@inject IApiService ApiService
|
|
|
|
<PageTitle>NimbusFlow Dashboard</PageTitle>
|
|
|
|
<h1>NimbusFlow Dashboard</h1>
|
|
|
|
<div class="row">
|
|
<div class="col-md-3">
|
|
<div class="card text-white bg-primary mb-3">
|
|
<div class="card-header">Active Members</div>
|
|
<div class="card-body">
|
|
<h4 class="card-title">@activeMemberCount</h4>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-3">
|
|
<div class="card text-white bg-success mb-3">
|
|
<div class="card-header">Pending Schedules</div>
|
|
<div class="card-body">
|
|
<h4 class="card-title">@pendingScheduleCount</h4>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-3">
|
|
<div class="card text-white bg-warning mb-3">
|
|
<div class="card-header">Upcoming Services</div>
|
|
<div class="card-body">
|
|
<h4 class="card-title">@upcomingServiceCount</h4>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-3">
|
|
<div class="card text-white bg-info mb-3">
|
|
<div class="card-header">Total Classifications</div>
|
|
<div class="card-body">
|
|
<h4 class="card-title">@classificationCount</h4>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row mt-4">
|
|
<div class="col-md-6">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5>Recent Schedules</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
@if (recentSchedules.Any())
|
|
{
|
|
<div class="list-group">
|
|
@foreach (var schedule in recentSchedules.Take(5))
|
|
{
|
|
<div class="list-group-item">
|
|
<div class="d-flex w-100 justify-content-between">
|
|
<h6 class="mb-1">@($"{schedule.Member?.FullName}")</h6>
|
|
<small class="badge @GetStatusBadgeClass(schedule.Status)">@schedule.Status</small>
|
|
</div>
|
|
<p class="mb-1">Service: @schedule.Service?.ServiceDate.ToString("MMM dd, yyyy")</p>
|
|
<small>Scheduled: @schedule.ScheduledAt.ToString("MMM dd, yyyy HH:mm")</small>
|
|
</div>
|
|
}
|
|
</div>
|
|
}
|
|
else
|
|
{
|
|
<p class="text-muted">No recent schedules found.</p>
|
|
}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-6">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5>Quick Actions</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="d-grid gap-2">
|
|
<a href="/schedules/create" class="btn btn-primary">Schedule Next Member</a>
|
|
<a href="/members/create" class="btn btn-success">Add New Member</a>
|
|
<a href="/services/create" class="btn btn-warning">Create New Service</a>
|
|
<a href="/schedules" class="btn btn-info">View All Schedules</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
@code {
|
|
private int activeMemberCount = 0;
|
|
private int pendingScheduleCount = 0;
|
|
private int upcomingServiceCount = 0;
|
|
private int classificationCount = 0;
|
|
private List<Schedule> recentSchedules = new();
|
|
|
|
protected override async Task OnInitializedAsync()
|
|
{
|
|
try
|
|
{
|
|
// Load dashboard data
|
|
var members = await ApiService.GetMembersAsync();
|
|
activeMemberCount = members.Count(m => m.IsActive == 1);
|
|
|
|
var schedules = await ApiService.GetSchedulesAsync();
|
|
recentSchedules = schedules.OrderByDescending(s => s.ScheduledAt).ToList();
|
|
pendingScheduleCount = schedules.Count(s => s.Status == "pending");
|
|
|
|
var services = await ApiService.GetServicesAsync();
|
|
upcomingServiceCount = services.Count(s => s.ServiceDate >= DateTime.Today);
|
|
|
|
var classifications = await ApiService.GetClassificationsAsync();
|
|
classificationCount = classifications.Count;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// Handle API errors gracefully
|
|
Console.WriteLine($"Error loading dashboard data: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
private string GetStatusBadgeClass(string status)
|
|
{
|
|
return status switch
|
|
{
|
|
"pending" => "bg-warning",
|
|
"accepted" => "bg-success",
|
|
"declined" => "bg-danger",
|
|
_ => "bg-secondary"
|
|
};
|
|
}
|
|
}
|