mirror of
https://github.com/massbug/judge4c.git
synced 2025-05-17 14:56:36 +00:00
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:
parent
9003e4b5a4
commit
4ca6840bbd
95
src/features/problems/components/judge-toast.tsx
Normal file
95
src/features/problems/components/judge-toast.tsx
Normal 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>
|
||||
);
|
||||
};
|
@ -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}
|
||||
/>
|
||||
));
|
||||
}
|
@ -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" }],
|
||||
]);
|
Loading…
Reference in New Issue
Block a user