fix(disputed): add admin role + contact info in discussion modal
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled

- request-discussion endpoint: add 'admin' to allowed roles
- Return rejector_email and rejector_role in the response
- Modal success state shows contact card with username, role, email link
  so the approving lead can immediately reach out to the rejecting lead
This commit is contained in:
kitos
2026-06-03 13:02:57 +02:00
parent 4e20bfa835
commit 02ff89401c
3 changed files with 52 additions and 17 deletions

View File

@@ -313,6 +313,8 @@ export async function requestDiscussion(testId: string): Promise<{
status: string;
message: string;
rejector_username: string;
rejector_email: string | null;
rejector_role: string;
}> {
const { data } = await client.post(`/tests/${testId}/request-discussion`);
return data;

View File

@@ -87,11 +87,17 @@ export default function TestDetailHeader({
const role = user?.role ?? "";
const currentIdx = STATE_INDEX[test.state];
const [showDiscussModal, setShowDiscussModal] = useState(false);
const [discussResult, setDiscussResult] = useState<string | null>(null);
const [discussResult, setDiscussResult] = useState<{
username: string; email: string | null; role: string;
} | null>(null);
const discussMutation = useMutation({
mutationFn: () => requestDiscussion(test.id),
onSuccess: (data) => setDiscussResult(data.rejector_username),
onSuccess: (data) => setDiscussResult({
username: data.rejector_username,
email: data.rejector_email,
role: data.rejector_role,
}),
});
const formatDate = (d: string | null) => {
@@ -544,16 +550,40 @@ export default function TestDetailHeader({
)}
</div>
) : (
/* Success state */
<div className="px-6 py-8 text-center space-y-3">
<CheckCircle className="mx-auto h-12 w-12 text-green-400" />
<p className="text-lg font-semibold text-white">Discussion request sent</p>
<p className="text-sm text-gray-400">
<strong className="text-white">{discussResult}</strong> has been notified
that you are standing by your approval and want to discuss their rejection.
</p>
<p className="text-xs text-gray-500">
Reach out directly via your team's communication channels to resolve this.
/* Success state with contact info */
<div className="px-6 py-6 space-y-4">
<div className="flex items-center gap-3">
<CheckCircle className="h-8 w-8 shrink-0 text-green-400" />
<div>
<p className="text-base font-semibold text-white">Discussion request sent</p>
<p className="text-xs text-gray-400">
{discussResult?.role} has been notified that you want to discuss.
</p>
</div>
</div>
{/* Contact card */}
<div className="rounded-lg border border-amber-500/20 bg-amber-500/5 p-4 space-y-2">
<p className="text-xs font-semibold uppercase tracking-wider text-amber-400">Contact details</p>
<div className="flex items-center gap-2">
<span className="text-sm font-medium text-white">{discussResult?.username}</span>
<span className="rounded-full border border-gray-600 bg-gray-800 px-2 py-0.5 text-[10px] text-gray-400">
{discussResult?.role}
</span>
</div>
{discussResult?.email && (
<a
href={`mailto:${discussResult.email}`}
className="flex items-center gap-1.5 text-xs text-cyan-400 hover:underline"
>
{discussResult.email}
</a>
)}
</div>
<p className="text-xs text-gray-500 leading-relaxed">
Reach out directly via the contact above or your team's communication channels (Slack, Teams, etc.) to resolve the disagreement.
The test will remain in <strong className="text-amber-400">Disputed</strong> state until one lead changes their vote.
</p>
</div>
)}