From 59bacd7ece5a571b8acf801fd7a980966ae1f15a Mon Sep 17 00:00:00 2001 From: nhestrompia Date: Thu, 6 Jul 2023 19:45:40 +0300 Subject: [PATCH 1/4] feat: dispute timeline --- web/package.json | 2 +- web/src/assets/svgs/icons/close-circle.svg | 3 + .../components/Verdict/DisputeTimeline.tsx | 141 ++++++++++++++++++ web/src/components/Verdict/FinalDecision.tsx | 9 +- web/src/components/Verdict/Timeline.tsx | 43 ------ web/src/components/Verdict/index.tsx | 17 ++- web/src/pages/Cases/CaseDetails/Overview.tsx | 4 +- yarn.lock | 10 +- 8 files changed, 169 insertions(+), 60 deletions(-) create mode 100644 web/src/assets/svgs/icons/close-circle.svg create mode 100644 web/src/components/Verdict/DisputeTimeline.tsx delete mode 100644 web/src/components/Verdict/Timeline.tsx diff --git a/web/package.json b/web/package.json index 36833b581..4b384a243 100644 --- a/web/package.json +++ b/web/package.json @@ -63,7 +63,7 @@ "dependencies": { "@filebase/client": "^0.0.4", "@kleros/kleros-v2-contracts": "workspace:^", - "@kleros/ui-components-library": "^2.5.2", + "@kleros/ui-components-library": "^2.6.1", "@sentry/react": "^7.55.2", "@sentry/tracing": "^7.55.2", "@types/react-modal": "^3.16.0", diff --git a/web/src/assets/svgs/icons/close-circle.svg b/web/src/assets/svgs/icons/close-circle.svg new file mode 100644 index 000000000..f3d4a2477 --- /dev/null +++ b/web/src/assets/svgs/icons/close-circle.svg @@ -0,0 +1,3 @@ + + + diff --git a/web/src/components/Verdict/DisputeTimeline.tsx b/web/src/components/Verdict/DisputeTimeline.tsx new file mode 100644 index 000000000..200e8fcc7 --- /dev/null +++ b/web/src/components/Verdict/DisputeTimeline.tsx @@ -0,0 +1,141 @@ +import React from "react"; +import styled from "styled-components"; +import { _TimelineItem1, CustomTimeline } from "@kleros/ui-components-library"; +import { Periods } from "consts/periods"; +import { useVotingHistory } from "queries/useVotingHistory"; +import { DisputeDetailsQuery } from "queries/useDisputeDetailsQuery"; +import { useKlerosCoreCurrentRuling } from "hooks/contracts/generated"; +import { lightTheme } from "~src/styles/themes"; +import ClosedCaseIcon from "assets/svgs/icons/check-circle-outline.svg"; +import AppealedCaseIcon from "assets/svgs/icons/close-circle.svg"; +import CalendarIcon from "assets/svgs/icons/calendar.svg"; + +const Container = styled.div` + display: flex; + position: relative; + margin-left: 16px; +`; + +const StyledTimeline = styled(CustomTimeline)` + width: calc(200px + (350 - 200) * (100vw - 375px) / (1250 - 375)); + margin-bottom: 32px; +`; + +const EnforcementContainer = styled.div` + position: absolute; + bottom: 0; + display: flex; + gap: 8px; + margin-bottom: 8px; + fill: ${({ theme }) => theme.secondaryText}; + + small { + font-weight: 400; + line-height: 19px; + color: ${({ theme }) => theme.secondaryText}; + } +`; + +const StyledCalendarIcon = styled(CalendarIcon)` + width: 14px; + height: 14px; +`; + +interface IDisputeTimeline { + id: string; + disputeTemplate: any; + disputeDetails: DisputeDetailsQuery; +} + +const getCaseEventTimes = ( + lastPeriodChange: string, + currentPeriodIndex: number, + timesPerPeriod: string[], + isCreation: boolean +) => { + const options: Intl.DateTimeFormatOptions = { year: "numeric", month: "long", day: "numeric" }; + const durationCurrentPeriod = parseInt(timesPerPeriod[currentPeriodIndex - 1]); + const startingDate = new Date( + (parseInt(lastPeriodChange) + (isCreation ? -durationCurrentPeriod : durationCurrentPeriod)) * 1000 + ); + + const formattedDate = startingDate.toLocaleDateString("en-US", options); + return formattedDate; +}; + +const calculateLocalRoundJuror = (votes) => { + const choiceCount = {}; + let maxVotes = 0; + let winningChoice = null; + + votes.forEach((vote) => { + const { choice } = vote; + + choiceCount[choice] = (choiceCount[choice] || 0) + 1; + + if (choiceCount[choice] > maxVotes) { + maxVotes = choiceCount[choice]; + winningChoice = choice; + } + }); + + return winningChoice; +}; + +const DisputeTimeline: React.FC = ({ id, disputeTemplate, disputeDetails }) => { + const { data: votingHistory } = useVotingHistory(id); + const currentPeriodIndex = Periods[disputeDetails?.dispute?.period!]; + const lastPeriodChange = disputeDetails?.dispute?.lastPeriodChange; + const courtTimePeriods = disputeDetails.dispute?.court.timesPerPeriod!; + const rounds = votingHistory?.dispute?.rounds; + const localRounds = votingHistory?.dispute?.disputeKitDispute?.localRounds; + + const dynamicItems: [_TimelineItem1, ..._TimelineItem1[]] = [ + { + title: "Dispute created", + party: "", + subtitle: getCaseEventTimes(lastPeriodChange, currentPeriodIndex, courtTimePeriods, true), + rightSided: true, + variant: lightTheme.secondaryPurple, + }, + ]; + + if (rounds) { + rounds.forEach((round, index) => { + const localRuling = calculateLocalRoundJuror(localRounds![index].votes); + const eventDate = getCaseEventTimes(lastPeriodChange, currentPeriodIndex, courtTimePeriods, false); + const variant = disputeDetails?.dispute?.ruled && index === rounds.length - 1 ? ClosedCaseIcon : ""; + + dynamicItems.push({ + title: `Jury Decision - Round ${index + 1}`, + party: localRuling ? disputeTemplate?.answers?.[localRuling - 1].title : "Refuse to Arbitrate", + subtitle: eventDate, + rightSided: true, + variant: lightTheme.secondaryPurple, + Icon: variant !== "" ? variant : undefined, + }); + + if (index < rounds.length - 1) { + dynamicItems.push({ + title: "Appealed", + party: "", + subtitle: eventDate, + rightSided: true, + Icon: AppealedCaseIcon, + }); + } + }); + } + return ( + + + {disputeDetails?.dispute?.ruled && ( + + + Enforcement: {dynamicItems[dynamicItems.length - 1].subtitle} + + )} + + ); +}; +export default DisputeTimeline; diff --git a/web/src/components/Verdict/FinalDecision.tsx b/web/src/components/Verdict/FinalDecision.tsx index 15f67e94f..c3ace8634 100644 --- a/web/src/components/Verdict/FinalDecision.tsx +++ b/web/src/components/Verdict/FinalDecision.tsx @@ -40,7 +40,7 @@ const JuryDecisionTag = styled.small` `; const Divider = styled.hr` - color: ${({ theme }) => theme.secondaryText}; + color: ${({ theme }) => theme.stroke}; `; const UserContainer = styled.div` @@ -87,10 +87,7 @@ const FinalDecision: React.FC = ({ id, disputeTemplate }) => { const navigate = useNavigate(); const { data: currentRulingArray } = useKlerosCoreCurrentRuling({ args: [BigInt(id)], watch: true }); const currentRuling = Number(currentRulingArray?.[0]); - console.log("🚀 ~ file: FinalDecision.tsx:90 ~ currentRuling:", currentRuling); - console.log("disputeTemplate", disputeTemplate); - const answer = disputeTemplate?.answers?.[currentRuling!]; - console.log("🚀 ~ file: FinalDecision.tsx:92 ~ answer:", answer); + const answer = disputeTemplate?.answers?.[currentRuling! - 1]; const handleClick = () => { navigate(`/cases/${id.toString()}/voting`); @@ -102,7 +99,7 @@ const FinalDecision: React.FC = ({ id, disputeTemplate }) => {
Final Decision
The jury decided in favor of: - {answer &&

{`${answer.title}. ${answer.description}`}

} + {answer ?

{`${answer.title}. ${answer.description}`}

:

Refuse to Arbitrate

}
diff --git a/web/src/components/Verdict/Timeline.tsx b/web/src/components/Verdict/Timeline.tsx deleted file mode 100644 index 7b8ee9592..000000000 --- a/web/src/components/Verdict/Timeline.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import React from "react"; -import styled from "styled-components"; -import { Timeline } from "@kleros/ui-components-library"; -import { useKlerosCoreCurrentRuling } from "hooks/contracts/generated"; - -const StyledTimeline = styled(Timeline)` - margin: 0px 100px; -`; - -interface IDisputeTimeline { - id: string; - disputeTemplate: any; -} - -const DisputeTimeline: React.FC = ({ id, disputeTemplate }) => { - const { data: currentRulingArray } = useKlerosCoreCurrentRuling({ args: [BigInt(id)], watch: true }); - const currentRuling = Number(currentRulingArray?.[0]); - - const answer = disputeTemplate?.answers?.[currentRuling!]; - return ( -
- -
- ); -}; -export default DisputeTimeline; diff --git a/web/src/components/Verdict/index.tsx b/web/src/components/Verdict/index.tsx index 42f359663..a16d79d67 100644 --- a/web/src/components/Verdict/index.tsx +++ b/web/src/components/Verdict/index.tsx @@ -1,23 +1,32 @@ import React from "react"; import styled from "styled-components"; +import { DisputeDetailsQuery } from "queries/useDisputeDetailsQuery"; import FinalDecision from "./FinalDecision"; -import DisputeTimeline from "./Timeline"; +import DisputeTimeline from "./DisputeTimeline"; const Container = styled.div` display: flex; - gap: 48px; + flex-wrap: wrap; + gap: 24px; +`; + +const VerticalDivider = styled.div` + width: 1px; + background-color: ${({ theme }) => theme.stroke}; `; interface IVerdict { id: string; disputeTemplate: any; + disputeDetails: DisputeDetailsQuery; } -const Verdict: React.FC = ({ id, disputeTemplate }) => { +const Verdict: React.FC = ({ id, disputeTemplate, disputeDetails }) => { return ( - {/* */} + + ); }; diff --git a/web/src/pages/Cases/CaseDetails/Overview.tsx b/web/src/pages/Cases/CaseDetails/Overview.tsx index fc4aed5ce..bf2396bba 100644 --- a/web/src/pages/Cases/CaseDetails/Overview.tsx +++ b/web/src/pages/Cases/CaseDetails/Overview.tsx @@ -112,7 +112,9 @@ const Overview: React.FC<{ arbitrable?: `0x${string}`; courtID?: string }> = ({ ))}
- {disputeDetails?.dispute?.ruled && } + {disputeDetails?.dispute?.ruled && ( + + )}
diff --git a/yarn.lock b/yarn.lock index b6234e820..702155a1f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5243,7 +5243,7 @@ __metadata: "@kleros/kleros-v2-eslint-config": "workspace:^" "@kleros/kleros-v2-prettier-config": "workspace:^" "@kleros/kleros-v2-tsconfig": "workspace:^" - "@kleros/ui-components-library": ^2.5.2 + "@kleros/ui-components-library": ^2.6.1 "@netlify/functions": ^1.6.0 "@parcel/transformer-svg-react": ~2.8.0 "@parcel/watcher": ~2.1.0 @@ -5298,9 +5298,9 @@ __metadata: languageName: unknown linkType: soft -"@kleros/ui-components-library@npm:^2.5.2": - version: 2.5.2 - resolution: "@kleros/ui-components-library@npm:2.5.2" +"@kleros/ui-components-library@npm:^2.6.1": + version: 2.6.1 + resolution: "@kleros/ui-components-library@npm:2.6.1" dependencies: "@datepicker-react/hooks": ^2.8.4 "@swc/helpers": ^0.3.2 @@ -5317,7 +5317,7 @@ __metadata: react-dom: ^18.0.0 react-is: ^18.0.0 styled-components: ^5.3.3 - checksum: 159a999c4e13fb288f1594a677f325002552a06cf3c01e5139a16e2749a795934c3876e7e62eb0401ebeec85dec3ae9c66d9a14ff83de8134c58b0eadbbe6883 + checksum: 776b95e0af1b223ad1b0e8b82819d9a3275a05df51effc40926010977d39dbd162b8eafd0241ad1efd953a96c47bb270e5839cf390e45e9b74c583695a47a37f languageName: node linkType: hard From 4df385f4712fc71306aa6afb5cc982a3f6ae2250 Mon Sep 17 00:00:00 2001 From: nhestrompia Date: Thu, 6 Jul 2023 20:14:36 +0300 Subject: [PATCH 2/4] fix: code smells --- web/src/components/Verdict/DisputeTimeline.tsx | 5 ++--- web/src/components/Verdict/FinalDecision.tsx | 1 - web/src/pages/Cases/CaseDetails/Overview.tsx | 10 +++++----- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/web/src/components/Verdict/DisputeTimeline.tsx b/web/src/components/Verdict/DisputeTimeline.tsx index 200e8fcc7..c9a500fb0 100644 --- a/web/src/components/Verdict/DisputeTimeline.tsx +++ b/web/src/components/Verdict/DisputeTimeline.tsx @@ -4,12 +4,11 @@ import { _TimelineItem1, CustomTimeline } from "@kleros/ui-components-library"; import { Periods } from "consts/periods"; import { useVotingHistory } from "queries/useVotingHistory"; import { DisputeDetailsQuery } from "queries/useDisputeDetailsQuery"; -import { useKlerosCoreCurrentRuling } from "hooks/contracts/generated"; import { lightTheme } from "~src/styles/themes"; import ClosedCaseIcon from "assets/svgs/icons/check-circle-outline.svg"; import AppealedCaseIcon from "assets/svgs/icons/close-circle.svg"; import CalendarIcon from "assets/svgs/icons/calendar.svg"; - +import { isUndefined } from "utils/index"; const Container = styled.div` display: flex; position: relative; @@ -102,7 +101,7 @@ const DisputeTimeline: React.FC = ({ id, disputeTemplate, disp if (rounds) { rounds.forEach((round, index) => { - const localRuling = calculateLocalRoundJuror(localRounds![index].votes); + const localRuling = calculateLocalRoundJuror(!isUndefined(localRounds) && localRounds[index].votes); const eventDate = getCaseEventTimes(lastPeriodChange, currentPeriodIndex, courtTimePeriods, false); const variant = disputeDetails?.dispute?.ruled && index === rounds.length - 1 ? ClosedCaseIcon : ""; diff --git a/web/src/components/Verdict/FinalDecision.tsx b/web/src/components/Verdict/FinalDecision.tsx index 7b13f15ac..a47b1462d 100644 --- a/web/src/components/Verdict/FinalDecision.tsx +++ b/web/src/components/Verdict/FinalDecision.tsx @@ -111,7 +111,6 @@ const FinalDecision: React.FC = ({ id, disputeTemplate, ruled }) The jury decided in favor of: {answer ?

{`${answer.title}. ${answer.description}`}

:

Refuse to Arbitrate

} - {answer ?

{`${answer.title}. ${answer.description}`}

:

Refuse to Arbitrate

}
diff --git a/web/src/pages/Cases/CaseDetails/Overview.tsx b/web/src/pages/Cases/CaseDetails/Overview.tsx index 46b900d1c..3c6438fdf 100644 --- a/web/src/pages/Cases/CaseDetails/Overview.tsx +++ b/web/src/pages/Cases/CaseDetails/Overview.tsx @@ -3,7 +3,7 @@ import styled from "styled-components"; import { useParams } from "react-router-dom"; import { formatEther } from "viem"; import Skeleton from "react-loading-skeleton"; -import { useDisputeDetailsQuery } from "queries/useDisputeDetailsQuery"; +import { DisputeDetailsQuery, useDisputeDetailsQuery } from "queries/useDisputeDetailsQuery"; import { useDisputeTemplate } from "queries/useDisputeTemplate"; import { useCourtPolicy } from "queries/useCourtPolicy"; import { useCourtPolicyURI } from "queries/useCourtPolicyURI"; @@ -121,14 +121,14 @@ const Overview: React.FC = ({ arbitrable, courtID, currentPeriodIndex {currentPeriodIndex !== Periods.evidence && ( <>
- ( + - ) +
)} From fa51e976c8690002cc11f9b94c4c0f1683f0ecea Mon Sep 17 00:00:00 2001 From: alcercu <333aleix333@gmail.com> Date: Fri, 7 Jul 2023 15:31:43 +0200 Subject: [PATCH 3/4] refactor(web): use hooks to avoid drilling props --- .../components/Verdict/DisputeTimeline.tsx | 144 +++++++++--------- web/src/components/Verdict/FinalDecision.tsx | 101 ++++++------ web/src/components/Verdict/index.tsx | 21 +-- web/src/graphql/gql.ts | 6 +- web/src/graphql/graphql.ts | 2 + web/src/hooks/queries/useVotingHistory.ts | 1 + web/src/pages/Cases/CaseDetails/Overview.tsx | 11 +- 7 files changed, 129 insertions(+), 157 deletions(-) diff --git a/web/src/components/Verdict/DisputeTimeline.tsx b/web/src/components/Verdict/DisputeTimeline.tsx index c9a500fb0..0ceade464 100644 --- a/web/src/components/Verdict/DisputeTimeline.tsx +++ b/web/src/components/Verdict/DisputeTimeline.tsx @@ -1,22 +1,23 @@ -import React from "react"; -import styled from "styled-components"; +import React, { useMemo } from "react"; +import { useParams } from "react-router-dom"; +import styled, { useTheme } from "styled-components"; import { _TimelineItem1, CustomTimeline } from "@kleros/ui-components-library"; import { Periods } from "consts/periods"; import { useVotingHistory } from "queries/useVotingHistory"; -import { DisputeDetailsQuery } from "queries/useDisputeDetailsQuery"; -import { lightTheme } from "~src/styles/themes"; +import { useDisputeTemplate } from "queries/useDisputeTemplate"; +import { DisputeDetailsQuery, useDisputeDetailsQuery } from "queries/useDisputeDetailsQuery"; import ClosedCaseIcon from "assets/svgs/icons/check-circle-outline.svg"; import AppealedCaseIcon from "assets/svgs/icons/close-circle.svg"; import CalendarIcon from "assets/svgs/icons/calendar.svg"; -import { isUndefined } from "utils/index"; + const Container = styled.div` display: flex; position: relative; - margin-left: 16px; + margin-left: 8px; `; const StyledTimeline = styled(CustomTimeline)` - width: calc(200px + (350 - 200) * (100vw - 375px) / (1250 - 375)); + width: 100%; margin-bottom: 32px; `; @@ -40,12 +41,6 @@ const StyledCalendarIcon = styled(CalendarIcon)` height: 14px; `; -interface IDisputeTimeline { - id: string; - disputeTemplate: any; - disputeDetails: DisputeDetailsQuery; -} - const getCaseEventTimes = ( lastPeriodChange: string, currentPeriodIndex: number, @@ -62,76 +57,77 @@ const getCaseEventTimes = ( return formattedDate; }; -const calculateLocalRoundJuror = (votes) => { - const choiceCount = {}; - let maxVotes = 0; - let winningChoice = null; - - votes.forEach((vote) => { - const { choice } = vote; - - choiceCount[choice] = (choiceCount[choice] || 0) + 1; +type TimelineItems = [_TimelineItem1, ..._TimelineItem1[]]; - if (choiceCount[choice] > maxVotes) { - maxVotes = choiceCount[choice]; - winningChoice = choice; - } - }); - - return winningChoice; -}; - -const DisputeTimeline: React.FC = ({ id, disputeTemplate, disputeDetails }) => { +const useItems = (disputeDetails?: DisputeDetailsQuery) => { + const { data: disputeTemplate } = useDisputeTemplate(); + const { id } = useParams(); const { data: votingHistory } = useVotingHistory(id); - const currentPeriodIndex = Periods[disputeDetails?.dispute?.period!]; - const lastPeriodChange = disputeDetails?.dispute?.lastPeriodChange; - const courtTimePeriods = disputeDetails.dispute?.court.timesPerPeriod!; - const rounds = votingHistory?.dispute?.rounds; const localRounds = votingHistory?.dispute?.disputeKitDispute?.localRounds; + const theme = useTheme(); + + return useMemo(() => { + if (disputeDetails?.dispute) { + const currentPeriodIndex = disputeDetails?.dispute ? Periods[disputeDetails.dispute.period] : 0; + const lastPeriodChange = disputeDetails?.dispute?.lastPeriodChange; + const courtTimePeriods = disputeDetails.dispute?.court.timesPerPeriod; + return localRounds?.reduce( + (acc, { winningChoice }, index) => { + const parsedWinningChoice = parseInt(winningChoice); + const eventDate = getCaseEventTimes(lastPeriodChange, currentPeriodIndex, courtTimePeriods, false); + const icon = disputeDetails?.dispute?.ruled && index === localRounds.length - 1 ? ClosedCaseIcon : ""; + + acc.push({ + title: `Jury Decision - Round ${index + 1}`, + party: + parsedWinningChoice !== 0 + ? disputeTemplate?.answers?.[parseInt(winningChoice) - 1].title + : "Refuse to Arbitrate", + subtitle: eventDate, + rightSided: true, + variant: theme.secondaryPurple, + Icon: icon !== "" ? icon : undefined, + }); + + if (index < localRounds.length - 1) { + acc.push({ + title: "Appealed", + party: "", + subtitle: eventDate, + rightSided: true, + Icon: AppealedCaseIcon, + }); + } + + return acc; + }, + [ + { + title: "Dispute created", + party: "", + subtitle: getCaseEventTimes(lastPeriodChange, currentPeriodIndex, courtTimePeriods, true), + rightSided: true, + variant: theme.secondaryPurple, + }, + ] + ); + } + return; + }, [disputeDetails, disputeTemplate, localRounds, theme]); +}; - const dynamicItems: [_TimelineItem1, ..._TimelineItem1[]] = [ - { - title: "Dispute created", - party: "", - subtitle: getCaseEventTimes(lastPeriodChange, currentPeriodIndex, courtTimePeriods, true), - rightSided: true, - variant: lightTheme.secondaryPurple, - }, - ]; - - if (rounds) { - rounds.forEach((round, index) => { - const localRuling = calculateLocalRoundJuror(!isUndefined(localRounds) && localRounds[index].votes); - const eventDate = getCaseEventTimes(lastPeriodChange, currentPeriodIndex, courtTimePeriods, false); - const variant = disputeDetails?.dispute?.ruled && index === rounds.length - 1 ? ClosedCaseIcon : ""; - - dynamicItems.push({ - title: `Jury Decision - Round ${index + 1}`, - party: localRuling ? disputeTemplate?.answers?.[localRuling - 1].title : "Refuse to Arbitrate", - subtitle: eventDate, - rightSided: true, - variant: lightTheme.secondaryPurple, - Icon: variant !== "" ? variant : undefined, - }); +const DisputeTimeline: React.FC = () => { + const { id } = useParams(); + const { data: disputeDetails } = useDisputeDetailsQuery(id); + const items = useItems(disputeDetails); - if (index < rounds.length - 1) { - dynamicItems.push({ - title: "Appealed", - party: "", - subtitle: eventDate, - rightSided: true, - Icon: AppealedCaseIcon, - }); - } - }); - } return ( - - {disputeDetails?.dispute?.ruled && ( + {items && } + {disputeDetails?.dispute?.ruled && items && ( - Enforcement: {dynamicItems[dynamicItems.length - 1].subtitle} + Enforcement: {items.at(-1)?.subtitle} )} diff --git a/web/src/components/Verdict/FinalDecision.tsx b/web/src/components/Verdict/FinalDecision.tsx index a47b1462d..eb0393fda 100644 --- a/web/src/components/Verdict/FinalDecision.tsx +++ b/web/src/components/Verdict/FinalDecision.tsx @@ -1,33 +1,22 @@ import React from "react"; +import { useNavigate, useParams } from "react-router-dom"; import styled from "styled-components"; import Identicon from "react-identicons"; -import { useNavigate } from "react-router-dom"; import ArrowIcon from "assets/svgs/icons/arrow.svg"; +import { useDisputeTemplate } from "queries/useDisputeTemplate"; +import { useDisputeDetailsQuery } from "queries/useDisputeDetailsQuery"; +import { useKlerosCoreCurrentRuling } from "hooks/contracts/generated"; import LightButton from "../LightButton"; import VerdictBanner from "./VerdictBanner"; -import { useKlerosCoreCurrentRuling } from "hooks/contracts/generated"; const Container = styled.div` - position: relative; - width: calc(200px + (360 - 200) * (100vw - 375px) / (1250 - 375)); - - height: 400px; - margin-left: 16px; - .reverse-button { - display: flex; - flex-direction: row-reverse; - gap: 8px; - .button-text { - color: ${({ theme }) => theme.primaryBlue}; - } - } + width: 100%; `; -const JuryContanier = styled.div` +const JuryContainer = styled.div` display: flex; flex-direction: column; gap: 8px; - margin-top: 32px; h3 { line-height: 21px; } @@ -66,7 +55,7 @@ const StyledIdenticon = styled(Identicon)` `; const Header = styled.h1` - margin: 20px 0px 48px; + margin: 20px 0px 32px 0px; `; const Title = styled.small` @@ -74,55 +63,58 @@ const Title = styled.small` `; const StyledButton = styled(LightButton)` - position: absolute; - bottom: 0; + display: flex; + flex-direction: row-reverse; + gap: 8px; + > .button-text { + color: ${({ theme }) => theme.primaryBlue}; + } `; -interface IDecisionText { - ruled: boolean; -} - -const DecisionText: React.FC = ({ ruled }) => { - return ruled ? <>Final Decision : <>Current Ruling; -}; - -interface IFinalDecision { - id: string; - disputeTemplate: any; - ruled: boolean; -} +const AnswerTitle = styled.h3` + margin: 0; +`; -const FinalDecision: React.FC = ({ id, disputeTemplate, ruled }) => { +const FinalDecision: React.FC = () => { + const { id } = useParams(); + const { data: disputeTemplate } = useDisputeTemplate(id); + const { data: disputeDetails } = useDisputeDetailsQuery(id); + const ruled = disputeDetails?.dispute?.ruled ?? false; const navigate = useNavigate(); - const { data: currentRulingArray } = useKlerosCoreCurrentRuling({ args: [BigInt(id)], watch: true }); + const { data: currentRulingArray } = useKlerosCoreCurrentRuling({ args: [BigInt(id ?? 0)], watch: true }); const currentRuling = Number(currentRulingArray?.[0]); const answer = disputeTemplate?.answers?.[currentRuling! - 1]; - const handleClick = () => { - navigate(`/cases/${id.toString()}/voting`); - }; - return ( -
- -
- +
{ruled ? "Final Decision" : "Current Ruling"}
+ The jury decided in favor of: - {answer ?

{`${answer.title}. ${answer.description}`}

:

Refuse to Arbitrate

} -
- - - - - {disputeTemplate?.aliases?.challenger && Alice.eth} - Claimant - - + {answer ? ( +
+ {answer.title} + {answer.description} +
+ ) : ( +

Refuse to Arbitrate

+ )} + + {disputeTemplate?.aliases && ( + <> + + + + {disputeTemplate?.aliases?.challenger && Alice.eth} + Claimant + + + + + )} navigate(`/cases/${id?.toString()}/voting`)} text={"Check how the jury voted"} Icon={ArrowIcon} className="reverse-button" @@ -130,4 +122,5 @@ const FinalDecision: React.FC = ({ id, disputeTemplate, ruled })
); }; + export default FinalDecision; diff --git a/web/src/components/Verdict/index.tsx b/web/src/components/Verdict/index.tsx index faf07c79f..76f14bff4 100644 --- a/web/src/components/Verdict/index.tsx +++ b/web/src/components/Verdict/index.tsx @@ -1,6 +1,5 @@ import React from "react"; import styled from "styled-components"; -import { DisputeDetailsQuery } from "queries/useDisputeDetailsQuery"; import FinalDecision from "./FinalDecision"; import DisputeTimeline from "./DisputeTimeline"; @@ -10,25 +9,13 @@ const Container = styled.div` gap: 24px; `; -const VerticalDivider = styled.div` - width: 1px; - background-color: ${({ theme }) => theme.stroke}; -`; - -interface IVerdict { - id: string; - disputeTemplate: any; - disputeDetails: DisputeDetailsQuery; - ruled: boolean; -} - -const Verdict: React.FC = ({ id, disputeTemplate, disputeDetails, ruled }) => { +const Verdict: React.FC = () => { return ( - - - + + ); }; + export default Verdict; diff --git a/web/src/graphql/gql.ts b/web/src/graphql/gql.ts index 81fc515f5..90c809e70 100644 --- a/web/src/graphql/gql.ts +++ b/web/src/graphql/gql.ts @@ -33,7 +33,7 @@ const documents = { types.HomePageDocument, "\n query User($address: ID!) {\n user(id: $address) {\n totalDisputes\n totalResolvedDisputes\n totalCoherent\n tokens {\n court {\n id\n name\n }\n }\n shifts {\n tokenAmount\n ethAmount\n }\n }\n }\n": types.UserDocument, - "\n query VotingHistory($disputeID: ID!) {\n dispute(id: $disputeID) {\n id\n rounds {\n nbVotes\n }\n disputeKitDispute {\n localRounds {\n ... on ClassicRound {\n totalVoted\n votes {\n id\n juror {\n id\n }\n ... on ClassicVote {\n choice\n justification\n }\n }\n }\n }\n }\n }\n }\n": + "\n query VotingHistory($disputeID: ID!) {\n dispute(id: $disputeID) {\n id\n rounds {\n nbVotes\n }\n disputeKitDispute {\n localRounds {\n ... on ClassicRound {\n winningChoice\n totalVoted\n votes {\n id\n juror {\n id\n }\n ... on ClassicVote {\n choice\n justification\n }\n }\n }\n }\n }\n }\n }\n": types.VotingHistoryDocument, }; @@ -115,8 +115,8 @@ export function graphql( * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( - source: "\n query VotingHistory($disputeID: ID!) {\n dispute(id: $disputeID) {\n id\n rounds {\n nbVotes\n }\n disputeKitDispute {\n localRounds {\n ... on ClassicRound {\n totalVoted\n votes {\n id\n juror {\n id\n }\n ... on ClassicVote {\n choice\n justification\n }\n }\n }\n }\n }\n }\n }\n" -): (typeof documents)["\n query VotingHistory($disputeID: ID!) {\n dispute(id: $disputeID) {\n id\n rounds {\n nbVotes\n }\n disputeKitDispute {\n localRounds {\n ... on ClassicRound {\n totalVoted\n votes {\n id\n juror {\n id\n }\n ... on ClassicVote {\n choice\n justification\n }\n }\n }\n }\n }\n }\n }\n"]; + source: "\n query VotingHistory($disputeID: ID!) {\n dispute(id: $disputeID) {\n id\n rounds {\n nbVotes\n }\n disputeKitDispute {\n localRounds {\n ... on ClassicRound {\n winningChoice\n totalVoted\n votes {\n id\n juror {\n id\n }\n ... on ClassicVote {\n choice\n justification\n }\n }\n }\n }\n }\n }\n }\n" +): (typeof documents)["\n query VotingHistory($disputeID: ID!) {\n dispute(id: $disputeID) {\n id\n rounds {\n nbVotes\n }\n disputeKitDispute {\n localRounds {\n ... on ClassicRound {\n winningChoice\n totalVoted\n votes {\n id\n juror {\n id\n }\n ... on ClassicVote {\n choice\n justification\n }\n }\n }\n }\n }\n }\n }\n"]; export function graphql(source: string) { return (documents as any)[source] ?? {}; diff --git a/web/src/graphql/graphql.ts b/web/src/graphql/graphql.ts index 528128ffe..879939a1f 100644 --- a/web/src/graphql/graphql.ts +++ b/web/src/graphql/graphql.ts @@ -3761,6 +3761,7 @@ export type VotingHistoryQuery = { __typename?: "ClassicDispute"; localRounds: Array<{ __typename?: "ClassicRound"; + winningChoice: any; totalVoted: any; votes: Array<{ __typename?: "ClassicVote"; @@ -4523,6 +4524,7 @@ export const VotingHistoryDocument = { selectionSet: { kind: "SelectionSet", selections: [ + { kind: "Field", name: { kind: "Name", value: "winningChoice" } }, { kind: "Field", name: { kind: "Name", value: "totalVoted" } }, { kind: "Field", diff --git a/web/src/hooks/queries/useVotingHistory.ts b/web/src/hooks/queries/useVotingHistory.ts index b428c2ffe..9bf5a6808 100644 --- a/web/src/hooks/queries/useVotingHistory.ts +++ b/web/src/hooks/queries/useVotingHistory.ts @@ -13,6 +13,7 @@ const votingHistoryQuery = graphql(` disputeKitDispute { localRounds { ... on ClassicRound { + winningChoice totalVoted votes { id diff --git a/web/src/pages/Cases/CaseDetails/Overview.tsx b/web/src/pages/Cases/CaseDetails/Overview.tsx index b4c527c70..3935ab568 100644 --- a/web/src/pages/Cases/CaseDetails/Overview.tsx +++ b/web/src/pages/Cases/CaseDetails/Overview.tsx @@ -4,7 +4,7 @@ import { useParams } from "react-router-dom"; import ReactMarkdown from "react-markdown"; import { formatEther } from "viem"; import Skeleton from "react-loading-skeleton"; -import { DisputeDetailsQuery, useDisputeDetailsQuery } from "queries/useDisputeDetailsQuery"; +import { useDisputeDetailsQuery } from "queries/useDisputeDetailsQuery"; import { useDisputeTemplate } from "queries/useDisputeTemplate"; import { useCourtPolicy } from "queries/useCourtPolicy"; import { useCourtPolicyURI } from "queries/useCourtPolicyURI"; @@ -120,14 +120,7 @@ const Overview: React.FC = ({ arbitrable, courtID, currentPeriodIndex {currentPeriodIndex !== Periods.evidence && ( <>
- - - +
)} From 1dbe7bf14393c93fea915c054e751d9e9e99c478 Mon Sep 17 00:00:00 2001 From: alcercu <333aleix333@gmail.com> Date: Mon, 10 Jul 2023 14:35:13 +0200 Subject: [PATCH 4/4] fix(web): verdict pr smells --- web/src/components/Verdict/DisputeTimeline.tsx | 9 +++++---- web/src/components/Verdict/VerdictBanner.tsx | 1 - 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/web/src/components/Verdict/DisputeTimeline.tsx b/web/src/components/Verdict/DisputeTimeline.tsx index 0ceade464..439abd8e2 100644 --- a/web/src/components/Verdict/DisputeTimeline.tsx +++ b/web/src/components/Verdict/DisputeTimeline.tsx @@ -67,10 +67,11 @@ const useItems = (disputeDetails?: DisputeDetailsQuery) => { const theme = useTheme(); return useMemo(() => { - if (disputeDetails?.dispute) { - const currentPeriodIndex = disputeDetails?.dispute ? Periods[disputeDetails.dispute.period] : 0; - const lastPeriodChange = disputeDetails?.dispute?.lastPeriodChange; - const courtTimePeriods = disputeDetails.dispute?.court.timesPerPeriod; + const dispute = disputeDetails?.dispute; + if (dispute) { + const currentPeriodIndex = Periods[dispute.period]; + const lastPeriodChange = dispute.lastPeriodChange; + const courtTimePeriods = dispute.court.timesPerPeriod; return localRounds?.reduce( (acc, { winningChoice }, index) => { const parsedWinningChoice = parseInt(winningChoice); diff --git a/web/src/components/Verdict/VerdictBanner.tsx b/web/src/components/Verdict/VerdictBanner.tsx index 63c5e659e..8cfa591f0 100644 --- a/web/src/components/Verdict/VerdictBanner.tsx +++ b/web/src/components/Verdict/VerdictBanner.tsx @@ -44,7 +44,6 @@ interface IVerdictBanner { } const VerdictBanner: React.FC = ({ ruled }) => { - console.log("ruledinside verdict banner", ruled); return (