Initial commit
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,276 @@
|
||||
@using PowderCoating.Application.DTOs.Dashboard
|
||||
@using PowderCoating.Core.Enums
|
||||
@model SuperAdminDashboardViewModel
|
||||
@{
|
||||
ViewData["Title"] = "Platform Dashboard";
|
||||
ViewData["PageIcon"] = "bi-shield-check";
|
||||
|
||||
// Badge color by position in sorted plan distribution (1st=secondary, 2nd=primary, 3rd=info, 4th+=success)
|
||||
var planBadgeColors = Model.PlanDistribution.Keys
|
||||
.Select((k, i) => (k, i))
|
||||
.ToDictionary(x => x.k, x => x.i switch {
|
||||
0 => "bg-secondary",
|
||||
1 => "bg-primary",
|
||||
2 => "bg-info",
|
||||
_ => "bg-success"
|
||||
});
|
||||
string PlanBadge(int plan) => planBadgeColors.TryGetValue(plan, out var c) ? c : "bg-secondary";
|
||||
|
||||
string StatusBadge(SubscriptionStatus status) => status switch {
|
||||
SubscriptionStatus.Active => "bg-success-subtle text-success",
|
||||
SubscriptionStatus.GracePeriod => "bg-warning-subtle text-warning",
|
||||
SubscriptionStatus.Expired => "bg-danger-subtle text-danger",
|
||||
SubscriptionStatus.Canceled => "bg-secondary-subtle text-secondary",
|
||||
_ => "bg-secondary-subtle text-secondary"
|
||||
};
|
||||
}
|
||||
|
||||
<!-- Platform Overview Header -->
|
||||
<div class="d-flex justify-content-end mb-4">
|
||||
<span class="badge bg-warning text-dark fs-6 px-3 py-2">
|
||||
<i class="bi bi-shield-fill me-1"></i>Super Admin Mode
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Platform Stats Row -->
|
||||
<div class="row g-3 mb-4">
|
||||
<div class="col-6 col-md-3">
|
||||
<div class="card border-0 shadow-sm h-100">
|
||||
<div class="card-body d-flex align-items-center gap-3">
|
||||
<div class="rounded-3 p-3" style="background: rgba(79,70,229,0.1);">
|
||||
<i class="bi bi-building fs-4" style="color: #4f46e5;"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div class="fs-2 fw-bold lh-1">@Model.TotalCompanies</div>
|
||||
<div class="small text-muted">Total Companies</div>
|
||||
<div class="small mt-1">
|
||||
<span class="text-success">@Model.ActiveCompanies active</span>
|
||||
@if (Model.InactiveCompanies > 0)
|
||||
{
|
||||
<span class="text-danger ms-1">· @Model.InactiveCompanies inactive</span>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6 col-md-3">
|
||||
<div class="card border-0 shadow-sm h-100">
|
||||
<div class="card-body d-flex align-items-center gap-3">
|
||||
<div class="rounded-3 p-3" style="background: rgba(16,185,129,0.1);">
|
||||
<i class="bi bi-people fs-4" style="color: #10b981;"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div class="fs-2 fw-bold lh-1">@Model.TotalUsers</div>
|
||||
<div class="small text-muted">Total Users</div>
|
||||
<div class="small text-muted mt-1">across all companies</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6 col-md-3">
|
||||
<div class="card border-0 shadow-sm h-100">
|
||||
<div class="card-body d-flex align-items-center gap-3">
|
||||
<div class="rounded-3 p-3" style="background: rgba(245,158,11,0.1);">
|
||||
<i class="bi bi-check-circle fs-4" style="color: #f59e0b;"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div class="fs-2 fw-bold lh-1">@Model.ActiveSubscriptions</div>
|
||||
<div class="small text-muted">Active Subscriptions</div>
|
||||
<div class="small mt-1">
|
||||
@if (Model.GracePeriodCount > 0)
|
||||
{
|
||||
<span class="text-warning">@Model.GracePeriodCount grace period</span>
|
||||
}
|
||||
@if (Model.ExpiredCount > 0)
|
||||
{
|
||||
<span class="text-danger @(Model.GracePeriodCount > 0 ? "ms-1" : "")">@Model.ExpiredCount expired</span>
|
||||
}
|
||||
@if (Model.GracePeriodCount == 0 && Model.ExpiredCount == 0)
|
||||
{
|
||||
<span class="text-success">all healthy</span>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6 col-md-3">
|
||||
<div class="card border-0 shadow-sm h-100">
|
||||
<div class="card-body d-flex align-items-center gap-3">
|
||||
<div class="rounded-3 p-3" style="background: rgba(139,92,246,0.1);">
|
||||
<i class="bi bi-layers fs-4" style="color: #8b5cf6;"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div class="small text-muted mb-2">Plan Distribution</div>
|
||||
<div class="d-flex flex-column gap-1">
|
||||
@foreach (var kv in Model.PlanDistribution)
|
||||
{
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<span class="badge @PlanBadge(kv.Key)" style="min-width:60px;">@kv.Value.DisplayName</span>
|
||||
<span class="fw-semibold">@kv.Value.Count</span>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-4">
|
||||
<!-- Companies Needing Attention -->
|
||||
<div class="col-lg-7">
|
||||
<div class="card border-0 shadow-sm h-100">
|
||||
<div class="card-header d-flex align-items-center gap-2">
|
||||
<i class="bi bi-exclamation-triangle text-warning"></i>
|
||||
<span>Subscriptions Needing Attention</span>
|
||||
@if (Model.CompanyAlerts.Any())
|
||||
{
|
||||
<span class="badge bg-warning text-dark ms-auto">@Model.CompanyAlerts.Count</span>
|
||||
}
|
||||
</div>
|
||||
@if (!Model.CompanyAlerts.Any())
|
||||
{
|
||||
<div class="card-body text-center py-5">
|
||||
<i class="bi bi-check-circle-fill text-success fs-1 mb-3 d-block"></i>
|
||||
<p class="text-muted mb-0">All subscriptions are in good standing.</p>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="card-body p-0">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Company</th>
|
||||
<th>Plan</th>
|
||||
<th>Status</th>
|
||||
<th>Expired</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var alert in Model.CompanyAlerts)
|
||||
{
|
||||
var manageUrl = Url.Action("Manage", "SubscriptionManagement", new { id = alert.Id });
|
||||
<tr style="cursor:pointer" onclick="window.location='@manageUrl'">
|
||||
<td>
|
||||
<div class="fw-semibold">@alert.CompanyName</div>
|
||||
@if (!alert.IsActive)
|
||||
{
|
||||
<small class="badge bg-danger-subtle text-danger">Inactive</small>
|
||||
}
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge @PlanBadge(alert.Plan)">@alert.PlanDisplayName</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge @StatusBadge(alert.Status)">@alert.Status</span>
|
||||
</td>
|
||||
<td>
|
||||
@if (alert.SubscriptionEndDate.HasValue)
|
||||
{
|
||||
<span class="text-danger small">@alert.SubscriptionEndDate.Value.ToString("MMM d, yyyy")</span>
|
||||
<br />
|
||||
<small class="text-muted">@alert.DaysOverdue day@(alert.DaysOverdue == 1 ? "" : "s") ago</small>
|
||||
}
|
||||
</td>
|
||||
<td class="text-end" onclick="event.stopPropagation()">
|
||||
<a asp-controller="SubscriptionManagement" asp-action="Manage" asp-route-id="@alert.Id"
|
||||
class="btn btn-sm btn-outline-secondary">
|
||||
<i class="bi bi-pencil"></i>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Recently Added Companies -->
|
||||
<div class="col-lg-5">
|
||||
<div class="card border-0 shadow-sm h-100">
|
||||
<div class="card-header d-flex align-items-center gap-2">
|
||||
<i class="bi bi-building-add text-primary"></i>
|
||||
<span>Recently Added Companies</span>
|
||||
</div>
|
||||
@if (!Model.RecentCompanies.Any())
|
||||
{
|
||||
<div class="card-body text-center py-5">
|
||||
<p class="text-muted mb-0">No companies yet.</p>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="list-group list-group-flush">
|
||||
@foreach (var company in Model.RecentCompanies)
|
||||
{
|
||||
<a asp-controller="Companies" asp-action="Details" asp-route-id="@company.Id"
|
||||
class="list-group-item list-group-item-action d-flex align-items-center gap-3 py-3 px-4">
|
||||
<div class="rounded-circle d-flex align-items-center justify-content-center flex-shrink-0"
|
||||
style="width:36px;height:36px;background:rgba(79,70,229,0.12);">
|
||||
<i class="bi bi-building text-primary small"></i>
|
||||
</div>
|
||||
<div class="flex-grow-1 overflow-hidden">
|
||||
<div class="fw-semibold text-truncate">@company.CompanyName</div>
|
||||
<div class="small text-muted">@company.CreatedAt.ToString("MMM d, yyyy")</div>
|
||||
</div>
|
||||
<div class="d-flex flex-column align-items-end gap-1">
|
||||
<span class="badge @PlanBadge(company.Plan)">@company.PlanDisplayName</span>
|
||||
@if (!company.IsActive)
|
||||
{
|
||||
<span class="badge bg-danger-subtle text-danger">Inactive</span>
|
||||
}
|
||||
</div>
|
||||
</a>
|
||||
}
|
||||
</div>
|
||||
<div class="card-footer text-center py-2">
|
||||
<a asp-controller="Companies" asp-action="Index" class="small text-muted">
|
||||
View all companies <i class="bi bi-arrow-right ms-1"></i>
|
||||
</a>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quick Links Row -->
|
||||
<div class="row g-3 mt-2">
|
||||
<div class="col-12">
|
||||
<div class="card border-0 shadow-sm">
|
||||
<div class="card-body py-3">
|
||||
<div class="d-flex flex-wrap gap-2 align-items-center">
|
||||
<span class="text-muted small me-2">Quick Actions:</span>
|
||||
<a asp-controller="Companies" asp-action="Create" class="btn btn-sm btn-outline-primary">
|
||||
<i class="bi bi-plus-circle me-1"></i>New Company
|
||||
</a>
|
||||
<a asp-controller="PlatformUsers" asp-action="Index" class="btn btn-sm btn-outline-secondary">
|
||||
<i class="bi bi-people me-1"></i>Platform Users
|
||||
</a>
|
||||
<a asp-controller="PlatformSubscription" asp-action="Index" class="btn btn-sm btn-outline-secondary">
|
||||
<i class="bi bi-layers me-1"></i>Subscription Plans
|
||||
</a>
|
||||
<a asp-controller="SystemInfo" asp-action="Index" class="btn btn-sm btn-outline-secondary">
|
||||
<i class="bi bi-cpu me-1"></i>System Info
|
||||
</a>
|
||||
@if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("WEBSITE_SITE_NAME")))
|
||||
{
|
||||
<a asp-controller="Diagnostics" asp-action="ViewLogs" class="btn btn-sm btn-outline-secondary">
|
||||
<i class="bi bi-file-text me-1"></i>View Logs
|
||||
</a>
|
||||
}
|
||||
<a asp-controller="SeedData" asp-action="Index" class="btn btn-sm btn-outline-secondary">
|
||||
<i class="bi bi-database-fill-gear me-1"></i>Seed Data
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user