mirror of
https://gitlab.com/megazordpobeda/DataRush.git
synced 2026-05-23 16:47:10 +00:00
Merge branch 'master' of https://gitlab.prodcontest.ru/team-15/project
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
import { Review, ReviewStatus } from "@/shared/types/review";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
interface ReviewCardProps {
|
||||
review: Review;
|
||||
}
|
||||
|
||||
export const ReviewCard = ({ review }: ReviewCardProps) => {
|
||||
const id = review.id.split("-").at(-1)?.slice(0, 6);
|
||||
|
||||
return (
|
||||
<div className="bg-card flex items-center justify-between gap-8 rounded-lg px-8 py-5">
|
||||
<div className="flex flex-col gap-1">
|
||||
<p className="text-muted-foreground font-semibold">
|
||||
{review.competition_name}
|
||||
</p>
|
||||
<h1 className="text-2xl font-semibold">{review.task_title}</h1>
|
||||
</div>
|
||||
<div className="flex flex-col items-end gap-1 text-right">
|
||||
<div className="text-muted-foreground flex gap-1.5 font-semibold">
|
||||
<p>{id}</p>
|
||||
<p>•</p>
|
||||
<p>
|
||||
{review.review_status === ReviewStatus.NOT_CHECKED
|
||||
? `Дата посылки: ${dayjs(review.submitted_at).format("D MMMM, HH:mm")}`
|
||||
: `Дата проверки: ${review.checked_at}`}
|
||||
</p>
|
||||
</div>
|
||||
<h1 className="text-2xl font-semibold">
|
||||
{review.review_status === ReviewStatus.NOT_CHECKED
|
||||
? "Не проверено"
|
||||
: ""}
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -3,7 +3,10 @@ import { getReviewer, getReviewerSubmissions } from "@/shared/api/review";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { useNavigate, useParams } from "react-router";
|
||||
import { ReviewHeader } from "./modules/review-header";
|
||||
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
import { ReviewsList } from "./modules/reviews-list";
|
||||
import React from "react";
|
||||
import { ReviewStatus } from "@/shared/types/review";
|
||||
|
||||
const ReviewPage = () => {
|
||||
const { token } = useParams<{ token: string }>();
|
||||
@@ -20,6 +23,22 @@ const ReviewPage = () => {
|
||||
retry: 0,
|
||||
});
|
||||
|
||||
const availableReviews = React.useMemo(
|
||||
() =>
|
||||
(submissionsQuery.data?.submissions || []).filter(
|
||||
(s) => s.review_status === ReviewStatus.NOT_CHECKED,
|
||||
),
|
||||
[submissionsQuery.data],
|
||||
);
|
||||
|
||||
const checkedReviews = React.useMemo(
|
||||
() =>
|
||||
(submissionsQuery.data?.submissions || []).filter(
|
||||
(s) => s.review_status === ReviewStatus.CHECKED,
|
||||
),
|
||||
[submissionsQuery.data],
|
||||
);
|
||||
|
||||
if (reviewerQuery.isLoading || submissionsQuery.isLoading) {
|
||||
return <Loading />;
|
||||
}
|
||||
@@ -34,14 +53,35 @@ const ReviewPage = () => {
|
||||
<div className="mx-auto max-w-5xl">
|
||||
<ReviewHeader reviewer={reviewerQuery.data} />
|
||||
|
||||
<Tabs defaultValue="available" className="my-3">
|
||||
<Tabs
|
||||
defaultValue="available"
|
||||
className="my-3 flex flex-col items-stretch gap-6"
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<h1 className="text-3xl font-semibold">Посылки</h1>
|
||||
<h1 className="text-3xl font-semibold">Решения</h1>
|
||||
<TabsList>
|
||||
<TabsTrigger value="available">Доступные</TabsTrigger>
|
||||
<TabsTrigger
|
||||
value="available"
|
||||
className="flex items-center gap-2"
|
||||
>
|
||||
<span>Доступные</span>
|
||||
{availableReviews.length > 0 && (
|
||||
<div className="bg-primary min-w-5 rounded-full px-1.5 py-0.5 text-xs">
|
||||
{availableReviews.length}
|
||||
</div>
|
||||
)}
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="checked">Проверенные</TabsTrigger>
|
||||
</TabsList>
|
||||
</div>
|
||||
|
||||
<TabsContent value="available" asChild>
|
||||
<ReviewsList reviews={availableReviews} />
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="checked" asChild>
|
||||
<ReviewsList reviews={checkedReviews} />
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import { Check } from "lucide-react";
|
||||
|
||||
export const NoReviews = () => {
|
||||
return (
|
||||
<div className="flex flex-col items-center gap-4">
|
||||
<Check size={32} />
|
||||
<div className="flex flex-col items-center gap-2">
|
||||
<h2 className="text-2xl font-semibold">Посылок пока нет</h2>
|
||||
<p className="text-muted-foreground text-lg">Можете расслабиться</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
import { Review } from "@/shared/types/review";
|
||||
import { ReviewCard } from "../components/review-card";
|
||||
import { NoReviews } from "./no-reviews";
|
||||
|
||||
interface ReviewsListProp {
|
||||
reviews: Review[];
|
||||
}
|
||||
|
||||
export const ReviewsList = ({ reviews }: ReviewsListProp) => {
|
||||
if (reviews.length === 0) {
|
||||
return <NoReviews />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col items-stretch gap-5">
|
||||
{reviews.map((review) => (
|
||||
<ReviewCard key={review.id} review={review} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user