11import React , { useMemo } from "react" ;
22import styled , { useTheme } from "styled-components" ;
33
4- import Skeleton from "react-loading-skeleton" ;
54import { useParams } from "react-router-dom" ;
65
76import { _TimelineItem1 , CustomTimeline } from "@kleros/ui-components-library" ;
87
9- import CalendarIcon from "svgs/icons/calendar.svg" ;
108import ClosedCaseIcon from "svgs/icons/check-circle-outline.svg" ;
119import NewTabIcon from "svgs/icons/new-tab.svg" ;
10+ import GavelExecutedIcon from "svgs/icons/gavel-executed.svg" ;
1211
1312import { Periods } from "consts/periods" ;
1413import { usePopulatedDisputeData } from "hooks/queries/usePopulatedDisputeData" ;
@@ -21,8 +20,6 @@ import { useVotingHistory } from "queries/useVotingHistory";
2120import { ClassicRound } from "src/graphql/graphql" ;
2221import { getTxnExplorerLink } from "src/utils" ;
2322
24- import { responsiveSize } from "styles/responsiveSize" ;
25-
2623import { StyledClosedCircle } from "components/StyledIcons/ClosedCircleIcon" ;
2724
2825import { ExternalLink } from "../ExternalLink" ;
@@ -37,24 +34,6 @@ const StyledTimeline = styled(CustomTimeline)`
3734 width: 100%;
3835` ;
3936
40- const EnforcementContainer = styled . div `
41- display: flex;
42- gap: 8px;
43- margin-top: ${ responsiveSize ( 12 , 24 ) } ;
44- fill: ${ ( { theme } ) => theme . secondaryText } ;
45-
46- small {
47- font-weight: 400;
48- line-height: 19px;
49- color: ${ ( { theme } ) => theme . secondaryText } ;
50- }
51- ` ;
52-
53- const StyledCalendarIcon = styled ( CalendarIcon ) `
54- width: 14px;
55- height: 14px;
56- ` ;
57-
5837const StyledNewTabIcon = styled ( NewTabIcon ) `
5938 margin-bottom: 2px;
6039 path {
@@ -84,73 +63,95 @@ const useItems = (disputeDetails?: DisputeDetailsQuery, arbitrable?: `0x${string
8463 const localRounds : ClassicRound [ ] = getLocalRounds ( votingHistory ?. dispute ?. disputeKitDispute ) as ClassicRound [ ] ;
8564 const rounds = votingHistory ?. dispute ?. rounds ;
8665 const theme = useTheme ( ) ;
87- const txnExplorerLink = useMemo ( ( ) => {
66+ const txnDisputeCreatedLink = useMemo ( ( ) => {
8867 return getTxnExplorerLink ( votingHistory ?. dispute ?. transactionHash ?? "" ) ;
8968 } , [ votingHistory ] ) ;
69+ const txnEnforcementLink = useMemo ( ( ) => {
70+ return getTxnExplorerLink ( disputeDetails ?. dispute ?. rulingTransactionHash ?? "" ) ;
71+ } , [ disputeDetails ] ) ;
9072
9173 return useMemo < TimelineItems | undefined > ( ( ) => {
9274 const dispute = disputeDetails ?. dispute ;
93- if ( dispute ) {
94- const rulingOverride = dispute . overridden ;
95- const currentPeriodIndex = Periods [ dispute . period ] ;
96-
97- return localRounds ?. reduce < TimelineItems > (
98- ( acc , { winningChoice } , index ) => {
99- const isOngoing = index === localRounds . length - 1 && currentPeriodIndex < 3 ;
100- const roundTimeline = rounds ?. [ index ] . timeline ;
101-
102- const icon = dispute . ruled && ! rulingOverride && index === localRounds . length - 1 ? ClosedCaseIcon : "" ;
103- const answers = disputeData ?. answers ;
104- acc . push ( {
105- title : `Jury Decision - Round ${ index + 1 } ` ,
106- party : isOngoing ? "Voting is ongoing" : getVoteChoice ( winningChoice , answers ) ,
107- subtitle : isOngoing
108- ? ""
109- : `${ formatDate ( roundTimeline ?. [ Periods . vote ] ) } / ${
110- votingHistory ?. dispute ?. rounds . at ( index ) ?. court . name
111- } `,
112- rightSided : true ,
113- variant : theme . secondaryPurple ,
114- Icon : icon !== "" ? icon : undefined ,
115- } ) ;
116-
117- if ( index < localRounds . length - 1 ) {
118- acc . push ( {
119- title : "Appealed" ,
120- party : "" ,
121- subtitle : formatDate ( roundTimeline ?. [ Periods . appeal ] ) ,
122- rightSided : true ,
123- Icon : StyledClosedCircle ,
124- } ) ;
125- } else if ( rulingOverride && dispute . currentRuling !== winningChoice ) {
126- acc . push ( {
127- title : "Won by Appeal" ,
128- party : getVoteChoice ( dispute . currentRuling , answers ) ,
129- subtitle : formatDate ( roundTimeline ?. [ Periods . appeal ] ) ,
130- rightSided : true ,
131- Icon : ClosedCaseIcon ,
132- } ) ;
133- }
134-
135- return acc ;
136- } ,
137- [
138- {
139- title : "Dispute created" ,
140- party : (
141- < ExternalLink to = { txnExplorerLink } rel = "noopener noreferrer" target = "_blank" >
142- < StyledNewTabIcon />
143- </ ExternalLink >
144- ) ,
145- subtitle : formatDate ( votingHistory ?. dispute ?. createdAt ) ,
146- rightSided : true ,
147- variant : theme . secondaryPurple ,
148- } ,
149- ]
150- ) ;
75+ if ( ! dispute ) return ;
76+
77+ const rulingOverride = dispute . overridden ;
78+ const currentPeriodIndex = Periods [ dispute . period ] ;
79+
80+ const base : TimelineItems = [
81+ {
82+ title : "Dispute created" ,
83+ party : (
84+ < ExternalLink to = { txnDisputeCreatedLink } rel = "noopener noreferrer" target = "_blank" >
85+ < StyledNewTabIcon />
86+ </ ExternalLink >
87+ ) ,
88+ subtitle : formatDate ( votingHistory ?. dispute ?. createdAt ) ,
89+ rightSided : true ,
90+ variant : theme . secondaryPurple ,
91+ } ,
92+ ] ;
93+
94+ const items = localRounds ?. reduce < _TimelineItem1 [ ] > ( ( acc , { winningChoice } , index ) => {
95+ const isOngoing = index === localRounds . length - 1 && currentPeriodIndex < 3 ;
96+ const roundTimeline = rounds ?. [ index ] . timeline ;
97+ const icon = dispute . ruled && ! rulingOverride && index === localRounds . length - 1 ? ClosedCaseIcon : undefined ;
98+ const answers = disputeData ?. answers ;
99+
100+ acc . push ( {
101+ title : `Jury Decision - Round ${ index + 1 } ` ,
102+ party : isOngoing ? "Voting is ongoing" : getVoteChoice ( winningChoice , answers ) ,
103+ subtitle : isOngoing ? "" : `${ formatDate ( roundTimeline ?. [ Periods . vote ] ) } / ${ rounds ?. [ index ] ?. court . name } ` ,
104+ rightSided : true ,
105+ variant : theme . secondaryPurple ,
106+ Icon : icon ,
107+ } ) ;
108+
109+ if ( index < localRounds . length - 1 ) {
110+ acc . push ( {
111+ title : "Appealed" ,
112+ party : "" ,
113+ subtitle : formatDate ( roundTimeline ?. [ Periods . appeal ] ) ,
114+ rightSided : true ,
115+ Icon : StyledClosedCircle ,
116+ } ) ;
117+ } else if ( rulingOverride && dispute . currentRuling !== winningChoice ) {
118+ acc . push ( {
119+ title : "Won by Appeal" ,
120+ party : getVoteChoice ( dispute . currentRuling , answers ) ,
121+ subtitle : formatDate ( roundTimeline ?. [ Periods . appeal ] ) ,
122+ rightSided : true ,
123+ Icon : ClosedCaseIcon ,
124+ } ) ;
125+ }
126+
127+ return acc ;
128+ } , [ ] ) ;
129+
130+ if ( dispute . ruled ) {
131+ items . push ( {
132+ title : "Enforcement" ,
133+ party : (
134+ < ExternalLink to = { txnEnforcementLink } rel = "noopener noreferrer" target = "_blank" >
135+ < StyledNewTabIcon />
136+ </ ExternalLink >
137+ ) ,
138+ subtitle : `${ formatDate ( dispute . rulingTimestamp ) } / ${ rounds ?. at ( - 1 ) ?. court . name } ` ,
139+ rightSided : true ,
140+ Icon : GavelExecutedIcon ,
141+ } ) ;
151142 }
152- return ;
153- } , [ disputeDetails , disputeData , localRounds , theme , rounds , votingHistory , txnExplorerLink ] ) ;
143+
144+ return [ ...base , ...items ] as TimelineItems ;
145+ } , [
146+ disputeDetails ,
147+ disputeData ,
148+ localRounds ,
149+ theme ,
150+ rounds ,
151+ votingHistory ,
152+ txnDisputeCreatedLink ,
153+ txnEnforcementLink ,
154+ ] ) ;
154155} ;
155156
156157interface IDisputeTimeline {
@@ -160,33 +161,8 @@ interface IDisputeTimeline {
160161const DisputeTimeline : React . FC < IDisputeTimeline > = ( { arbitrable } ) => {
161162 const { id } = useParams ( ) ;
162163 const { data : disputeDetails } = useDisputeDetailsQuery ( id ) ;
163- const { data : votingHistory } = useVotingHistory ( id ) ;
164164 const items = useItems ( disputeDetails , arbitrable ) ;
165165
166- const transactionExplorerLink = useMemo ( ( ) => {
167- return getTxnExplorerLink ( disputeDetails ?. dispute ?. rulingTransactionHash ?? "" ) ;
168- } , [ disputeDetails ] ) ;
169-
170- return (
171- < Container >
172- { items && < StyledTimeline { ...{ items } } /> }
173- { disputeDetails ?. dispute ?. ruled && (
174- < EnforcementContainer >
175- < StyledCalendarIcon />
176- < small >
177- Enforcement:{ " " }
178- { disputeDetails . dispute . rulingTimestamp ? (
179- < ExternalLink to = { transactionExplorerLink } rel = "noopener noreferrer" target = "_blank" >
180- { formatDate ( disputeDetails . dispute . rulingTimestamp ) }
181- </ ExternalLink >
182- ) : (
183- < Skeleton height = { 16 } width = { 56 } />
184- ) } { " " }
185- / { votingHistory ?. dispute ?. rounds . at ( - 1 ) ?. court . name }
186- </ small >
187- </ EnforcementContainer >
188- ) }
189- </ Container >
190- ) ;
166+ return < Container > { items && < StyledTimeline { ...{ items } } /> } </ Container > ;
191167} ;
192168export default DisputeTimeline ;
0 commit comments