feat(freight-portal): show account-status banner on every login

Ticket #422 — surface Pending/Suspended/Approved company status as a
banner, branching AccountReviewBanner on companyStatus instead of only
per-profile review state.
This commit is contained in:
Nathnael
2026-07-31 11:43:07 +00:00
parent 93163ac575
commit 83d3fc3b78

View File

@@ -1,6 +1,6 @@
import { useQuery } from "@tanstack/react-query";
import { Link } from "react-router-dom";
import { AlertTriangle, ArrowRight, Clock } from "lucide-react";
import { AlertTriangle, ArrowRight, CheckCircle2, Clock } from "lucide-react";
import { api } from "@/services/api";
import useAuth from "@/hooks/useAuth";
import type { OnboardingRequirements } from "@/services/companies.service";
@@ -157,11 +157,34 @@ export default function OnboardingResumeBanner({
* Self-hides when there's nothing outstanding.
*/
export function AccountReviewBanner() {
const { company, reviewStatus, reviewNote } = useAuth();
const { company, companyStatus, reviewStatus, reviewNote } = useAuth();
const profiles = company?.company?.companyProfiles ?? [];
const pending = profiles.filter((p) => p.status === "pending");
const approved = profiles.filter((p) => p.status === "active");
// 0. Account suspended/blacklisted — the hardest lock, takes priority over
// everything else since nothing below matters if the account is shut down.
if (companyStatus === "suspended" || companyStatus === "blacklisted") {
return (
<div className="border-b border-red-200 bg-red-50 px-6 py-3">
<div className="mx-auto flex max-w-6xl items-center gap-3">
<span className="flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-red-100 text-red-700">
<AlertTriangle size={18} />
</span>
<span className="flex flex-col gap-0.5">
<span className="text-sm font-semibold text-red-900">
Your account has been suspended
</span>
<span className="text-xs text-red-800">
Contact EDR support to resolve this before you can continue
working.
</span>
</span>
</div>
</div>
);
}
// 1. Profile-edit review pending — the account-wide lock.
if (reviewStatus === "pending") {
return (
@@ -216,8 +239,45 @@ export function AccountReviewBanner() {
);
}
// 3. Per-operational-profile approval (existing behaviour).
if (profiles.length === 0 || pending.length === 0) return null;
// 3. Company approved and awaiting its first operational profile — nothing
// profile-specific to report yet, but the account itself is pending.
if (profiles.length === 0) {
if (companyStatus === "pending") {
return (
<div className="border-b border-amber-200 bg-amber-50 px-6 py-3">
<div className="mx-auto flex max-w-6xl items-center gap-3">
<span className="flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-amber-100 text-amber-700">
<Clock size={18} />
</span>
<span className="text-sm font-semibold text-amber-900">
Your account is pending approval
</span>
</div>
</div>
);
}
return null;
}
// 4. Per-operational-profile approval (existing behaviour).
if (pending.length === 0) {
// Nothing outstanding — a quiet confirmation that the account is live.
if (companyStatus === "active") {
return (
<div className="border-b border-emerald-200 bg-emerald-50 px-6 py-3">
<div className="mx-auto flex max-w-6xl items-center gap-3">
<span className="flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-emerald-100 text-emerald-700">
<CheckCircle2 size={18} />
</span>
<span className="text-sm font-semibold text-emerald-900">
Your account is approved
</span>
</div>
</div>
);
}
return null;
}
const pendingLabel = pending
.map((p) => p.type.replace(/_/g, " "))