refactor(problems): consolidate judge status toast

- Migrate status toast from shared hooks to problems feature
- Remove deprecated show-status-toast.tsx and status.ts
- Implement self-contained JudgeToast component with built-in status mapping
This commit is contained in:
cfngc4594 2025-05-14 16:09:13 +08:00
parent 9003e4b5a4
commit 4ca6840bbd
3 changed files with 95 additions and 115 deletions

View File

@ -0,0 +1,95 @@
import {
AlertTriangleIcon,
BanIcon,
CircleCheckIcon,
XIcon,
} from "lucide-react";
import { toast } from "sonner";
import { cn } from "@/lib/utils";
import { useTranslations } from "next-intl";
import { Status } from "@/generated/client";
import { Button } from "@/components/ui/button";
interface JudgeToastProps {
t: number | string;
status: Status;
}
const getIconForStatus = (status: Status) => {
switch (status) {
case Status.PD:
case Status.QD:
case Status.CP:
case Status.CE:
case Status.RU:
case Status.TLE:
case Status.MLE:
case Status.RE:
case Status.WA:
return AlertTriangleIcon;
case Status.CS:
case Status.AC:
return CircleCheckIcon;
case Status.SE:
return BanIcon;
}
};
const getColorClassForStatus = (status: Status) => {
switch (status) {
case Status.PD:
case Status.QD:
return "text-gray-500";
case Status.CP:
case Status.CE:
return "text-yellow-500";
case Status.CS:
case Status.AC:
return "text-green-500";
case Status.RU:
case Status.TLE:
return "text-blue-500";
case Status.MLE:
return "text-purple-500";
case Status.RE:
return "text-orange-500";
case Status.WA:
case Status.SE:
return "text-red-500";
}
};
export const JudgeToast = ({ t, status }: JudgeToastProps) => {
const s = useTranslations("StatusMessage");
const Icon = getIconForStatus(status);
const colorClass = getColorClassForStatus(status);
return (
<div className="bg-background text-foreground w-full rounded-md border px-4 py-1 shadow-lg h-10 flex items-center">
<div className="flex gap-2">
<div className="flex grow gap-3">
<Icon
className={cn("mt-0.5 shrink-0", colorClass)}
size={16}
aria-hidden="true"
/>
<div className="flex grow justify-between gap-12">
<p className="text-sm">{s(status)}</p>
</div>
</div>
<Button
variant="ghost"
className="group -my-1.5 -me-2 size-8 shrink-0 p-0 hover:bg-transparent"
onClick={() => toast.dismiss(t)}
aria-label="Close toast"
>
<XIcon
size={16}
className="opacity-60 transition-opacity group-hover:opacity-100"
aria-hidden="true"
/>
</Button>
</div>
</div>
);
};

View File

@ -1,75 +0,0 @@
import {
LucideIcon,
XIcon,
} from "lucide-react";
import { toast } from "sonner";
import { useTranslations } from "next-intl";
import { Button } from "@/components/ui/button";
import type { Status } from "@/generated/client";
import { getStatusColorClass, statusMap } from "@/lib/status";
const StatusToast = ({
t,
Icon,
message,
colorClass,
}: {
t: string | number;
Icon: LucideIcon;
message: string;
colorClass: string;
}) => {
const s = useTranslations("StatusMessage");
return (
<div className="bg-background text-foreground w-full rounded-md border px-4 py-1 shadow-lg h-10 flex items-center">
<div className="flex gap-2">
<div className="flex grow gap-3">
<Icon
className={`mt-0.5 shrink-0 ${colorClass}`}
size={16}
aria-hidden="true"
/>
<div className="flex grow justify-between gap-12">
<p className="text-sm">{s(`${message}`)}</p>
</div>
</div>
<Button
variant="ghost"
className="group -my-1.5 -me-2 size-8 shrink-0 p-0 hover:bg-transparent"
onClick={() => toast.dismiss(t)}
aria-label="Close sonner"
>
<XIcon
size={16}
className="opacity-60 transition-opacity group-hover:opacity-100"
aria-hidden="true"
/>
</Button>
</div>
</div>
)
};
interface ShowStatusToastProps {
status: Status;
}
export function showStatusToast({
status,
}: ShowStatusToastProps) {
const { icon: Icon, message } = statusMap.get(status) || {
icon: XIcon,
message: "Unknown Error",
};
const colorClass = getStatusColorClass(status);
toast.custom((t) => (
<StatusToast
t={t}
Icon={Icon}
message={message}
colorClass={colorClass}
/>
));
}

View File

@ -1,40 +0,0 @@
import {
AlertTriangleIcon,
BanIcon,
CircleCheckIcon,
} from "lucide-react";
import { LucideIcon } from "lucide-react";
import { Status } from "@/generated/client";
export const getStatusColorClass = (status: Status) => {
const colorMap: Record<Status, string> = {
PD: "text-gray-500",
QD: "text-gray-500",
CP: "text-yellow-500",
CE: "text-yellow-500",
CS: "text-green-500",
RU: "text-blue-500",
TLE: "text-blue-500",
MLE: "text-purple-500",
RE: "text-orange-500",
AC: "text-green-500",
WA: "text-red-500",
SE: "text-red-500",
};
return colorMap[status] || "text-gray-500";
};
export const statusMap = new Map<Status, { icon: LucideIcon; message: string }>([
["PD", { icon: AlertTriangleIcon, message: "PD" }],
["QD", { icon: AlertTriangleIcon, message: "QD" }],
["CP", { icon: AlertTriangleIcon, message: "CP" }],
["CE", { icon: AlertTriangleIcon, message: "CE" }],
["CS", { icon: CircleCheckIcon, message: "CS" }],
["RU", { icon: AlertTriangleIcon, message: "RU" }],
["TLE", { icon: AlertTriangleIcon, message: "TLE" }],
["MLE", { icon: AlertTriangleIcon, message: "MLE" }],
["RE", { icon: AlertTriangleIcon, message: "RE" }],
["AC", { icon: CircleCheckIcon, message: "AC" }],
["WA", { icon: AlertTriangleIcon, message: "WA" }],
["SE", { icon: BanIcon, message: "SE" }],
]);