From 67a82ac701d8096503041b23439f6e086071066c Mon Sep 17 00:00:00 2001 From: Nick Lionis Date: Fri, 29 Nov 2024 23:53:26 +0700 Subject: [PATCH] fix : add approve/reject list in main checker page (#68) fix : add approve/reject list in main checker page + ui fixes + invalidate queries --- .../ProjectEvaluationList.tsx | 2 +- .../ProjectReviewList/ProjectReviewList.tsx | 37 ++++++--- .../ApplicationEvaluationOverviewPage.tsx | 8 +- .../ReviewApplicationsPage.tsx | 79 ++++++++++++++++--- .../SubmitApplicationEvaluationPage.tsx | 19 +++-- .../SubmitFinalEvaluationPage.tsx | 12 ++- .../utils/mapApplicationsForOverviewPage.ts | 64 ++++++++------- .../Indicators/CircleStat/CircleStat.tsx | 4 +- 8 files changed, 159 insertions(+), 66 deletions(-) diff --git a/src/features/checker/components/ProjectEvaluationList/ProjectEvaluationList.tsx b/src/features/checker/components/ProjectEvaluationList/ProjectEvaluationList.tsx index e3f2aa9..2a31097 100644 --- a/src/features/checker/components/ProjectEvaluationList/ProjectEvaluationList.tsx +++ b/src/features/checker/components/ProjectEvaluationList/ProjectEvaluationList.tsx @@ -67,7 +67,7 @@ export const ProjectEvaluationList = ({ position: "center", render: (item) => (
- +
), }, diff --git a/src/features/checker/components/ProjectReviewList/ProjectReviewList.tsx b/src/features/checker/components/ProjectReviewList/ProjectReviewList.tsx index 4ef671d..a07e033 100644 --- a/src/features/checker/components/ProjectReviewList/ProjectReviewList.tsx +++ b/src/features/checker/components/ProjectReviewList/ProjectReviewList.tsx @@ -1,3 +1,5 @@ +import { Address } from "viem"; + import { DefaultLogo } from "@/assets"; import { IconLabel } from "@/components/IconLabel"; import { Button } from "@/primitives/Button"; @@ -10,12 +12,21 @@ import { getReviewsCount } from "~checker/utils/getReviewsCount"; import { ReviewsCounterLabel } from "../ReviewsCounterLabel"; export interface ProjectReviewListProps { - reviewer: `0x${string}`; projects: ProjectReview[]; + + reviewer?: Address; action?: (projectId: string) => void; + actionLabel?: string; + keepAction?: boolean; } -export const ProjectReviewList = ({ reviewer, projects, action }: ProjectReviewListProps) => { +export const ProjectReviewList = ({ + reviewer, + projects, + action, + actionLabel, + keepAction, +}: ProjectReviewListProps) => { const columns: ListGridColumn[] = [ { header: "Project", @@ -38,7 +49,7 @@ export const ProjectReviewList = ({ reviewer, projects, action }: ProjectReviewL { header: "Date Submitted", key: "date", - width: "1fr", + width: "1.3fr", render: (item) => , }, { @@ -53,17 +64,23 @@ export const ProjectReviewList = ({ reviewer, projects, action }: ProjectReviewL { header: "AI Suggestion", key: "aiSuggestion", - width: "1fr", - render: (item) => , + width: "0.9fr", + render: (item) => { + return item.aiSuggestion !== 0 ? ( + + ) : ( + + ); + }, }, { header: "Score Average", key: "scoreAverage", - width: "1fr", + width: "0.8fr", position: "center", render: (item) => (
- +
), }, @@ -73,13 +90,13 @@ export const ProjectReviewList = ({ reviewer, projects, action }: ProjectReviewL width: "1fr", position: "center", render: (item) => { - const isReviewed = item.reviews.some((review) => review.reviewer === reviewer); + const isReviewed = item.reviews.some((review) => review.reviewer === reviewer) || !reviewer; return (
@@ -87,7 +96,7 @@ export const ReviewApplicationsPage = () => { ) : ( @@ -111,13 +120,65 @@ export const ReviewApplicationsPage = () => { ) : ( )} +
+
+
+
+ {`Approved applications (${ApprovedApplications.length})`} +
+
+
+
+ +
+ {ApprovedApplications.length === 0 ? ( +
+ No approved applications. +
+ ) : ( + + )} +
+
+
+
+
+
+ {`Rejected applications (${RejectedApplications.length})`} +
+
+
+
+ +
+ {RejectedApplications.length === 0 ? ( +
+ No rejected applications. +
+ ) : ( + + )} +
+
diff --git a/src/features/checker/pages/SubmitApplicationEvaluationPage/SubmitApplicationEvaluationPage.tsx b/src/features/checker/pages/SubmitApplicationEvaluationPage/SubmitApplicationEvaluationPage.tsx index 0a23b6b..24c5ad1 100644 --- a/src/features/checker/pages/SubmitApplicationEvaluationPage/SubmitApplicationEvaluationPage.tsx +++ b/src/features/checker/pages/SubmitApplicationEvaluationPage/SubmitApplicationEvaluationPage.tsx @@ -1,6 +1,7 @@ // src/components/SubmitApplicationEvaluation/SubmitApplicationEvaluationPage.tsx import { useEffect, useState } from "react"; +import { useQueryClient } from "@tanstack/react-query"; import { Hex } from "viem"; import { ApplicationBadge, ApplicationBadgeStatus } from "@/components/Badges"; @@ -65,10 +66,10 @@ export const SubmitApplicationEvaluationPage = ({ const { application, evaluationQuestions } = useApplicationOverviewEvaluations({ applicationId }) || {}; - const [toastShowed, setToastShowed] = useState(false); const dispatch = useCheckerDispatchContext(); const { data: pastApplications } = useGetPastApplications(chainId, poolId, applicationId); const { toast } = useToast(); + const queryClient = useQueryClient(); const showToast = () => { toast({ @@ -89,13 +90,15 @@ export const SubmitApplicationEvaluationPage = ({ }; useEffect(() => { - if ((isSuccess || isError) && !toastShowed) { - setToastShowed(true); + if ((isSuccess || isError) && isModalOpen) { setIsModalOpen(false); showToast(); goToSubmitFinalEvaluation(); + if (isSuccess) { + queryClient.invalidateQueries({ queryKey: ["poolData", chainId, poolId] }); // Invalidate the query + } } - }, [isSuccess, isError, toastShowed]); + }, [isSuccess, isError]); if (!application || !evaluationQuestions) return null; @@ -191,10 +194,10 @@ export const SubmitApplicationEvaluationPage = ({ poolId={poolId} strategyName={application.round.strategyName} name={application.round.roundMetadata.name} - registerStartDate={new Date()} - registerEndDate={new Date()} - allocationStartDate={new Date()} - allocationEndDate={new Date()} + registerStartDate={new Date(application.round.applicationsStartTime)} + registerEndDate={new Date(application.round.applicationsEndTime)} + allocationStartDate={new Date(application.round.donationsStartTime)} + allocationEndDate={new Date(application.round.donationsEndTime)} />
{ if (success && isModalOpen) { setReviewBody(null); + queryClient.invalidateQueries({ queryKey: ["poolData", chainId, poolId] }); // Invalidate the query setIsModalOpen(false); toast({ status: "success", description: "Your evaluations have been submitted" }); dispatch(goToReviewApplicationsAction()); @@ -109,10 +113,10 @@ export const SubmitFinalEvaluationPage = ({ poolId={poolId ?? "1"} strategyName={application?.round.strategyName ?? ""} name={application?.round.roundMetadata.name ?? ""} - registerStartDate={new Date()} - registerEndDate={new Date()} - allocationStartDate={new Date()} - allocationEndDate={new Date()} + registerStartDate={new Date(application?.round.applicationsStartTime ?? new Date())} + registerEndDate={new Date(application?.round.applicationsEndTime ?? new Date())} + allocationStartDate={new Date(application?.round.donationsStartTime ?? new Date())} + allocationEndDate={new Date(application?.round.donationsEndTime ?? new Date())} />
diff --git a/src/features/checker/utils/mapApplicationsForOverviewPage.ts b/src/features/checker/utils/mapApplicationsForOverviewPage.ts index 431f008..c47fd4d 100644 --- a/src/features/checker/utils/mapApplicationsForOverviewPage.ts +++ b/src/features/checker/utils/mapApplicationsForOverviewPage.ts @@ -6,7 +6,10 @@ import { ProjectReview, Review } from "../types"; // Define the structure of the function's return type interface ProjectReviewsResultByCategory { - categorizedReviews: Record<"INREVIEW" | "READY_TO_REVIEW", ProjectReview[]>; + categorizedReviews: Record< + "INREVIEW" | "READY_TO_REVIEW" | "APPROVED" | "REJECTED", + ProjectReview[] + >; statCardsProps: StatCardProps[]; application: CheckerApplication; } @@ -21,9 +24,14 @@ export function categorizeProjectReviews( const applicationsArray = Object.values(applications); // Initialize the categorized reviews record - const categorizedReviews: Record<"INREVIEW" | "READY_TO_REVIEW", ProjectReview[]> = { + const categorizedReviews: Record< + "INREVIEW" | "READY_TO_REVIEW" | "APPROVED" | "REJECTED", + ProjectReview[] + > = { INREVIEW: [], READY_TO_REVIEW: [], + APPROVED: [], + REJECTED: [], }; // Initialize application counts @@ -35,25 +43,23 @@ export function categorizeProjectReviews( }; for (const application of applicationsArray) { + const reviewedApplicationStatus = application.status !== "PENDING"; + // Only consider applications that are PENDING - if (application.status !== "PENDING") { - // Update application counts based on status - switch (application.status) { - case "APPROVED": - applicationCounts.approved += 1; - break; - case "REJECTED": - applicationCounts.rejected += 1; - break; - default: - break; - } - applicationCounts.total += 1; - continue; // Skip non-PENDING applications + // Update application counts based on status + switch (application.status) { + case "APPROVED": + applicationCounts.approved += 1; + break; + case "REJECTED": + applicationCounts.rejected += 1; + break; + case "PENDING": + applicationCounts.pending += 1; + break; + default: + continue; } - - // Update application counts for PENDING - applicationCounts.pending += 1; applicationCounts.total += 1; if (!application.evaluations) { @@ -73,16 +79,19 @@ export function categorizeProjectReviews( // Determine the category based on the number of human evaluations const isReadyForReview = humanEvaluations.length >= 2; - const category: "INREVIEW" | "READY_TO_REVIEW" = isReadyForReview - ? "READY_TO_REVIEW" - : "INREVIEW"; + const category: "INREVIEW" | "READY_TO_REVIEW" | "APPROVED" | "REJECTED" | "IGNORE" = + !reviewedApplicationStatus && isReadyForReview + ? "READY_TO_REVIEW" + : !reviewedApplicationStatus + ? "INREVIEW" + : application.status !== "PENDING" + ? application.status + : "IGNORE"; // Map human evaluations to reviews const reviews: Review[] = humanEvaluations?.map((evaluation) => { - const isApproved = evaluation.evaluatorScore >= 50; // Assuming 50 as the approval threshold - const reviewerAddress: `0x${string}` = evaluation.evaluator.startsWith("0x") - ? (evaluation.evaluator as `0x${string}`) - : (`0x${evaluation.evaluator}` as `0x${string}`); + const isApproved = evaluation.evaluationStatus === "APPROVED"; // Assuming 50 as the approval threshold + const reviewerAddress = evaluation.evaluator as `0x${string}`; return { reviewer: reviewerAddress, approved: isApproved, @@ -115,8 +124,7 @@ export function categorizeProjectReviews( scoreAverage, // Average score from all evaluations }; - // Add the ProjectReview to the appropriate category - categorizedReviews[category].push(projectReview); + if (category !== "IGNORE") categorizedReviews[category].push(projectReview); } const statCardsProps: StatCardProps[] = [ diff --git a/src/primitives/Indicators/CircleStat/CircleStat.tsx b/src/primitives/Indicators/CircleStat/CircleStat.tsx index ed5a213..80f315d 100644 --- a/src/primitives/Indicators/CircleStat/CircleStat.tsx +++ b/src/primitives/Indicators/CircleStat/CircleStat.tsx @@ -35,13 +35,13 @@ export const CircleStat: React.FC = ({ value, size = "medium", showPercentageSymbol = true, - thresholds = { low: 30, mid: 60 }, + thresholds = { low: 40, mid: 60 }, colors, className, }) => { const getColorVariant = () => { const _value = typeof value === "string" ? parseFloat(value) : value; - if (isNaN(_value) || _value <= thresholds.low) return "low"; + if (isNaN(_value) || _value < thresholds.low) return "low"; else if (_value < thresholds.mid) return "mid"; else return "high"; };