import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import React from "react";
import { useToken } from "..";
import { getReviewSubmission, postReviewEvaluation } from "@/shared/api/review";
import { Loading } from "@/components/ui/loading";
import {
Review,
ReviewCriteria,
ReviewEvaluation,
} from "@/shared/types/review";
import dayjs from "dayjs";
import { Button } from "@/components/ui/button";
import { cn } from "@/shared/lib/utils";
import { ofetch } from "ofetch";
import { File } from "lucide-react";
interface ReviewDialogProps {
reviewId: string;
children: React.ReactNode;
}
export const ReviewDialog = ({ reviewId, children }: ReviewDialogProps) => {
return (
);
};
const ReviewScreen = ({ reviewId }: { reviewId: string }) => {
const queryClient = useQueryClient();
const token = useToken();
const { data: review, isLoading } = useQuery({
queryKey: ["review", reviewId],
queryFn: async () => getReviewSubmission(token, reviewId),
});
const [evaluation, setEvaluation] = React.useState<{
[key: string]: ReviewEvaluation;
}>({});
React.useEffect(() => {
if (review?.evaluation) {
setEvaluation(
review.evaluation.reduce(
(acc, e) => {
acc[e.slug] = e;
return acc;
},
{} as { [key: string]: ReviewEvaluation },
),
);
}
}, [review?.evaluation]);
const onSubmit = React.useCallback(async () => {
const e: ReviewEvaluation[] | undefined = review?.criteries?.map((c) => {
return (
evaluation[c.slug] ?? {
slug: c.slug,
mark: 0,
}
);
});
if (!e) {
return;
}
await postReviewEvaluation(token, reviewId, e);
queryClient.invalidateQueries({
queryKey: ["submissions", token],
});
}, [review?.criteries, evaluation, token, queryClient]);
if (isLoading) {
return ;
}
if (!review) {
queryClient.invalidateQueries({
queryKey: ["submissions", token],
});
return;
}
return (
);
};
const ReviewHeader = ({ review }: { review: Review }) => {
const id = review.id.split("-").at(-1)?.slice(0, 6);
return (
{review.competition_name}
{review.task_title}
{id}
•
{dayjs(review.submitted_at).format("D MMMM, HH:mm")}
);
};
const ReviewDescription = ({ review }: { review: Review }) => {
if (!review.description) {
return;
}
return (
Условие
{review.description}
);
};
const ReviewContent = ({ review }: { review: Review }) => {
const extension = review.content.split(".").at(-1);
const filename = review.content.split("/").at(-1);
const { data: content, isLoading } = useQuery({
queryKey: ["review-file", review.id],
queryFn: async () => await ofetch(review.content),
});
if (isLoading) {
return null;
}
return (
Ответ
{extension === "txt" ? (
content
) : (
{filename}
)}
);
};
const ReviewCriteriesList = ({
review,
evaluation,
setEvaluation,
}: {
review: Review;
evaluation: { [key: string]: ReviewEvaluation };
setEvaluation: React.Dispatch<
React.SetStateAction<{
[key: string]: ReviewEvaluation;
}>
>;
}) => {
const onChange = React.useCallback(
(slug: string, value?: number) => {
if (!value || isNaN(value)) {
setEvaluation((prev) => ({ ...prev, [slug]: { slug, mark: 0 } }));
return;
}
if (
value < 0 ||
value >
(review.criteries?.filter((c) => c.slug === slug).at(0)?.max_value ??
0)
) {
return setEvaluation((prev) => ({
...prev,
[slug]: { slug, mark: 0 },
}));
}
setEvaluation((prev) => ({ ...prev, [slug]: { slug, mark: value } }));
},
[evaluation],
);
return (
Критерии
{review.criteries?.map((c) => {
const value = evaluation[c.slug]?.mark;
return (
);
})}
);
};
const Criteria = ({
criteria,
value,
onChange,
}: {
criteria: ReviewCriteria;
value?: number;
onChange?: (slug: string, value: number) => void;
}) => {
return (
);
};
const ReviewFooter = ({
evaluation,
criteries,
onSubmit,
}: {
evaluation: { [key: string]: ReviewEvaluation };
criteries?: ReviewCriteria[];
onSubmit: () => Promise;
}) => {
const score = Object.values(evaluation).reduce((acc, e) => acc + e.mark, 0);
const maxScore = criteries?.reduce((acc, c) => acc + c.max_value, 0);
return (
button]:bg-correct-foreground [&>button]:hover:bg-correct-foreground/80 [&>button]:text-correct":
score === maxScore,
"bg-partial *:text-partial-foreground [&>button]:bg-partial-foreground [&>button]:hover:bg-partial-foreground/80 [&>button]:text-partial":
score > 0 && score < (maxScore ?? 0),
"bg-wrong *:text-wrong-foreground [&>button]:bg-wrong-foreground [&>button]:hover:bg-wrong-foreground/80 [&>button]:text-wrong":
score === 0,
})}
>
Итого
{score <= 0 ? "Неверный ответ" : `Зачтено ${score}/${maxScore}`}
);
};