mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
fix(companies): honest status errors and per-role suspension visibility
A suspended customer trying to create a contract was told their account was "awaiting approval" - the guards collapsed every non-active status into the pending message. Contract and booking creation now go through a shared assertCompanyActiveFor that names the real company status, and the per-role guard names the role's actual state (suspended, blacklisted, rejected - with the reviewer note) so a customer suspended for one operation knows the others still work. Portal: the operation dropdown gets a Suspended badge, the block modal a suspended branch quoting the staff message, and the wizard a suspended/blacklisted gate instead of falling through to a submit error. EDRFREIGHT-234
This commit is contained in:
@@ -124,6 +124,30 @@ export default function NewContractPage({
|
||||
);
|
||||
}
|
||||
|
||||
// A suspended/blacklisted account must be told its real status — falling
|
||||
// through to the wizard here only to fail at submit read as "pending" before.
|
||||
if (
|
||||
!auth.isPending &&
|
||||
(auth.companyStatus === "suspended" || auth.companyStatus === "blacklisted")
|
||||
) {
|
||||
return (
|
||||
<GateNotice
|
||||
title={
|
||||
auth.companyStatus === "suspended"
|
||||
? "Account Suspended"
|
||||
: "Account Blacklisted"
|
||||
}
|
||||
body={
|
||||
auth.companyStatus === "suspended"
|
||||
? "Your company account has been suspended by EDR staff, so new contracts are disabled. Please contact EDR support for details."
|
||||
: "Your company account has been blacklisted, so new contracts are disabled. Please contact EDR support."
|
||||
}
|
||||
actionLabel="Back to Contracts"
|
||||
onAction={() => navigate("/contracts")}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
// Profile changes pending review lock out new contract creation too.
|
||||
if (!auth.isPending && auth.isUnderReview) {
|
||||
return (
|
||||
@@ -349,13 +373,19 @@ export default function NewContractPage({
|
||||
// badges. Intercity rides any customer profile, so always "approved".
|
||||
const operationStatus = useMemo(
|
||||
() =>
|
||||
(op: OperationType): "approved" | "pending" | "rejected" | "missing" => {
|
||||
(
|
||||
op: OperationType,
|
||||
): "approved" | "pending" | "rejected" | "suspended" | "missing" => {
|
||||
if (op === "intercity") return "approved";
|
||||
const target = operationToProfileType(op, profileTypes);
|
||||
const status = profileStatusByType.get(target);
|
||||
if (!status) return "missing";
|
||||
if (status === "active") return "approved";
|
||||
if (status === "rejected") return "rejected";
|
||||
// Suspension is per-role: the customer keeps working under their other
|
||||
// roles, so this operation must say "suspended", not "pending".
|
||||
if (status === "suspended" || status === "blacklisted")
|
||||
return "suspended";
|
||||
return "pending";
|
||||
},
|
||||
[profileStatusByType, profileTypes],
|
||||
@@ -1171,6 +1201,8 @@ export default function NewContractPage({
|
||||
? profileByType.get(pendingApprovalProfile)
|
||||
: undefined;
|
||||
const isRejected = target?.status === "rejected";
|
||||
const isSuspended =
|
||||
target?.status === "suspended" || target?.status === "blacklisted";
|
||||
const label = pendingApprovalProfile
|
||||
? (PROFILE_TYPE_LABELS[pendingApprovalProfile] ??
|
||||
pendingApprovalProfile)
|
||||
@@ -1179,12 +1211,42 @@ export default function NewContractPage({
|
||||
<Modal
|
||||
opened={pendingApprovalProfile !== null}
|
||||
onClose={() => setPendingApprovalProfile(null)}
|
||||
title={isRejected ? "Profile not approved" : "Awaiting approval"}
|
||||
title={
|
||||
isRejected
|
||||
? "Profile not approved"
|
||||
: isSuspended
|
||||
? "Role suspended"
|
||||
: "Awaiting approval"
|
||||
}
|
||||
centered
|
||||
radius="lg"
|
||||
>
|
||||
<Stack gap="md">
|
||||
{isRejected ? (
|
||||
{isSuspended ? (
|
||||
<>
|
||||
<Text size="sm" c="dimmed">
|
||||
Your {label} role has been suspended by EDR staff, so you
|
||||
can't start a contract under it. Your other roles are
|
||||
unaffected. Contact EDR support to resolve this.
|
||||
</Text>
|
||||
{target?.reviewNote && (
|
||||
<Alert color="orange" variant="light" radius="md">
|
||||
<Text size="sm">
|
||||
<strong>Message from EDR staff:</strong>{" "}
|
||||
{target.reviewNote}
|
||||
</Text>
|
||||
</Alert>
|
||||
)}
|
||||
<Group justify="flex-end" gap="sm">
|
||||
<Button
|
||||
color="edr-green"
|
||||
onClick={() => setPendingApprovalProfile(null)}
|
||||
>
|
||||
OK
|
||||
</Button>
|
||||
</Group>
|
||||
</>
|
||||
) : isRejected ? (
|
||||
<>
|
||||
<Text size="sm" c="dimmed">
|
||||
Your {label} profile was not approved. Fix the issue below
|
||||
|
||||
@@ -45,7 +45,7 @@ export function Step1ContractType({
|
||||
/** Approval state of the profile each operation maps to (for the badges). */
|
||||
operationStatus?: (
|
||||
op: OperationType,
|
||||
) => "approved" | "pending" | "rejected" | "missing";
|
||||
) => "approved" | "pending" | "rejected" | "suspended" | "missing";
|
||||
}) {
|
||||
const contractType = form.watch("contractType");
|
||||
|
||||
@@ -229,6 +229,11 @@ export function Step1ContractType({
|
||||
Rejected
|
||||
</Badge>
|
||||
)}
|
||||
{status === "suspended" && (
|
||||
<Badge size="xs" color="orange" variant="light" radius="sm">
|
||||
Suspended
|
||||
</Badge>
|
||||
)}
|
||||
{status === "missing" && (
|
||||
<Badge size="xs" color="gray" variant="light" radius="sm">
|
||||
Add license
|
||||
|
||||
Reference in New Issue
Block a user