Skip to content

Feat(web)/case verdict component #1022

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jul 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
3 changes: 3 additions & 0 deletions web/src/assets/svgs/icons/close-circle.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
137 changes: 137 additions & 0 deletions web/src/components/Verdict/DisputeTimeline.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
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 { 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";

const Container = styled.div`
display: flex;
position: relative;
margin-left: 8px;
`;

const StyledTimeline = styled(CustomTimeline)`
width: 100%;
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;
`;

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;
};

type TimelineItems = [_TimelineItem1, ..._TimelineItem1[]];

const useItems = (disputeDetails?: DisputeDetailsQuery) => {
const { data: disputeTemplate } = useDisputeTemplate();
const { id } = useParams();
const { data: votingHistory } = useVotingHistory(id);
const localRounds = votingHistory?.dispute?.disputeKitDispute?.localRounds;
const theme = useTheme();

return useMemo<TimelineItems | undefined>(() => {
const dispute = disputeDetails?.dispute;
if (dispute) {
const currentPeriodIndex = Periods[dispute.period];
const lastPeriodChange = dispute.lastPeriodChange;
const courtTimePeriods = dispute.court.timesPerPeriod;
return localRounds?.reduce<TimelineItems>(
(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 DisputeTimeline: React.FC = () => {
const { id } = useParams();
const { data: disputeDetails } = useDisputeDetailsQuery(id);
const items = useItems(disputeDetails);

return (
<Container>
{items && <StyledTimeline {...{ items }} />}
{disputeDetails?.dispute?.ruled && items && (
<EnforcementContainer>
<StyledCalendarIcon />
<small>Enforcement: {items.at(-1)?.subtitle}</small>
</EnforcementContainer>
)}
</Container>
);
};
export default DisputeTimeline;
106 changes: 48 additions & 58 deletions web/src/components/Verdict/FinalDecision.tsx
Original file line number Diff line number Diff line change
@@ -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;
}
Expand All @@ -40,7 +29,7 @@ const JuryDecisionTag = styled.small`
`;

const Divider = styled.hr`
color: ${({ theme }) => theme.secondaryText};
color: ${({ theme }) => theme.stroke};
`;

const UserContainer = styled.div`
Expand All @@ -66,71 +55,72 @@ const StyledIdenticon = styled(Identicon)`
`;

const Header = styled.h1`
margin: 20px 0px 48px;
margin: 20px 0px 32px 0px;
`;

const Title = styled.small`
color: ${({ theme }) => theme.secondaryText};
`;

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<IDecisionText> = ({ 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<IFinalDecision> = ({ 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]);
console.log("🚀 ~ file: FinalDecision.tsx:90 ~ currentRuling:", currentRuling);
console.log("disputeTemplate", disputeTemplate);
const answer = disputeTemplate?.answers?.[currentRuling! - 1];
console.log("🚀 ~ file: FinalDecision.tsx:92 ~ answer:", answer);

const handleClick = () => {
navigate(`/cases/${id.toString()}/voting`);
};

return (
<Container>
<VerdictBanner ruled={ruled} />
<Header>
<DecisionText ruled={ruled} />
</Header>
<JuryContanier>
<Header> {ruled ? "Final Decision" : "Current Ruling"} </Header>
<JuryContainer>
<JuryDecisionTag>The jury decided in favor of:</JuryDecisionTag>
{answer ? <h3>{`${answer.title}. ${answer.description}`}</h3> : <h3>Refuse to Arbitrate</h3>}
</JuryContanier>
<Divider />
<UserContainer>
<StyledIdenticon size="24" />
<AliasTag>
{disputeTemplate?.aliases?.challenger && <small>Alice.eth</small>}
<Title>Claimant</Title>
</AliasTag>
</UserContainer>
{answer ? (
<div>
<AnswerTitle>{answer.title}</AnswerTitle>
<small>{answer.description}</small>
</div>
) : (
<h3>Refuse to Arbitrate</h3>
)}
</JuryContainer>
<Divider />
{disputeTemplate?.aliases && (
<>
<UserContainer>
<StyledIdenticon size="24" />
<AliasTag>
{disputeTemplate?.aliases?.challenger && <small>Alice.eth</small>}
<Title>Claimant</Title>
</AliasTag>
</UserContainer>
<Divider />
</>
)}
<StyledButton
onClick={handleClick}
onClick={() => navigate(`/cases/${id?.toString()}/voting`)}
text={"Check how the jury voted"}
Icon={ArrowIcon}
className="reverse-button"
/>
</Container>
);
};

export default FinalDecision;
43 changes: 0 additions & 43 deletions web/src/components/Verdict/Timeline.tsx

This file was deleted.

1 change: 0 additions & 1 deletion web/src/components/Verdict/VerdictBanner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ interface IVerdictBanner {
}

const VerdictBanner: React.FC<IVerdictBanner> = ({ ruled }) => {
console.log("ruledinside verdict banner", ruled);
return (
<BannerContainer>
<VerdictIcon ruled={ruled} />
Expand Down
18 changes: 7 additions & 11 deletions web/src/components/Verdict/index.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,21 @@
import React from "react";
import styled from "styled-components";
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;
`;

interface IVerdict {
id: string;
disputeTemplate: any;
ruled: boolean;
}

const Verdict: React.FC<IVerdict> = ({ id, disputeTemplate, ruled }) => {
const Verdict: React.FC = () => {
return (
<Container>
<FinalDecision id={id} disputeTemplate={disputeTemplate} ruled={ruled} />
{/* <DisputeTimeline id={id} disputeTemplate={disputeTemplate} /> */}
<FinalDecision />
<DisputeTimeline />
</Container>
);
};

export default Verdict;
Loading