Skip to content

Commit f2803cb

Browse files
committed
Merge branch 'dev' into feat(web)/mobile-view-top-jurors-and-some-refactors
2 parents 62e6a91 + 74235df commit f2803cb

File tree

12 files changed

+392
-24
lines changed

12 files changed

+392
-24
lines changed
-46.4 KB
Loading
-48.5 KB
Loading
-46.4 KB
Loading
-47.9 KB
Loading
-48.7 KB
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import React, { useState } from "react";
2+
import styled, { css } from "styled-components";
3+
import { landscapeStyle } from "styles/landscapeStyle";
4+
import { Card as _Card } from "@kleros/ui-components-library";
5+
import PixelArt from "pages/Dashboard/JurorInfo/PixelArt";
6+
import Coherency from "pages/Dashboard/JurorInfo/Coherency";
7+
import Template from "./Template";
8+
9+
const Card = styled(_Card)`
10+
display: flex;
11+
flex-direction: column;
12+
align-items: center;
13+
width: 234px;
14+
height: 100%;
15+
gap: 28px;
16+
17+
padding: 24px;
18+
19+
${landscapeStyle(
20+
() => css`
21+
flex-direction: row;
22+
width: 100%;
23+
height: 236px;
24+
`
25+
)}
26+
`;
27+
28+
const Title = styled.h1`
29+
margin-bottom: 0;
30+
`;
31+
32+
const LeftContentContainer = styled.div`
33+
display: flex;
34+
gap: 18px;
35+
flex-direction: column;
36+
`;
37+
38+
const userLevelData = [
39+
{
40+
level: 1,
41+
title: "Pythagoras",
42+
totalCoherent: 6,
43+
totalResolvedDisputes: 10,
44+
firstParagraph: "Jurors are classified into distinct levels according to their performance starting from Level 1.",
45+
secondParagraph:
46+
"Level 1: Jurors with 0 cases arbitrated, OR Jurors with ≥ 1 case arbitrated with 0-70% of coherent votes.",
47+
},
48+
{
49+
level: 2,
50+
title: "Socrates",
51+
totalCoherent: 7,
52+
totalResolvedDisputes: 10,
53+
firstParagraph: "Level 2: Jurors with ≥ 3 cases arbitrated with 70%-80% of coherent votes.",
54+
},
55+
{
56+
level: 3,
57+
title: "Plato",
58+
totalCoherent: 8,
59+
totalResolvedDisputes: 10,
60+
firstParagraph: "Level 3: Jurors with ≥ 7 cases arbitrated with 80%-90% of coherent votes.",
61+
},
62+
{
63+
level: 4,
64+
title: "Aristoteles",
65+
totalCoherent: 9,
66+
totalResolvedDisputes: 10,
67+
firstParagraph: "Level 4: Jurors with ≥ 10 cases arbitrated with more than 90% of coherent votes.",
68+
},
69+
{
70+
level: 0,
71+
title: "Diogenes",
72+
totalCoherent: 3,
73+
totalResolvedDisputes: 10,
74+
firstParagraph:
75+
"There's a level for the low-performance/lazy jurors. Level 0: Jurors with ≥ 3 cases arbitrated with less than 50% of coherent votes.",
76+
},
77+
];
78+
79+
const LeftContent: React.FC<{ currentPage: number }> = ({ currentPage }) => {
80+
return (
81+
<LeftContentContainer>
82+
<Title>
83+
Juror Level {userLevelData[currentPage - 1].level}: {userLevelData[currentPage - 1].title}
84+
</Title>
85+
<label>{userLevelData[currentPage - 1].firstParagraph}</label>
86+
<label>{userLevelData[currentPage - 1].secondParagraph}</label>
87+
</LeftContentContainer>
88+
);
89+
};
90+
91+
const RightContent: React.FC<{ currentPage: number }> = ({ currentPage }) => {
92+
return (
93+
<Card>
94+
<PixelArt level={userLevelData[currentPage - 1].level} width="189px" height="189px" />
95+
<Coherency
96+
userLevelData={userLevelData[currentPage - 1]}
97+
totalCoherent={userLevelData[currentPage - 1].totalCoherent}
98+
totalResolvedDisputes={userLevelData[currentPage - 1].totalResolvedDisputes}
99+
isMiniGuide={true}
100+
/>
101+
</Card>
102+
);
103+
};
104+
105+
interface ILevel {
106+
toggleIsLevelMiniGuidesOpen: () => void;
107+
}
108+
109+
const Level: React.FC<ILevel> = ({ toggleIsLevelMiniGuidesOpen }) => {
110+
const [currentPage, setCurrentPage] = useState(1);
111+
112+
return (
113+
<Template
114+
LeftContent={<LeftContent currentPage={currentPage} />}
115+
RightContent={<RightContent currentPage={currentPage} />}
116+
onClose={toggleIsLevelMiniGuidesOpen}
117+
currentPage={currentPage}
118+
setCurrentPage={setCurrentPage}
119+
numPages={userLevelData.length}
120+
/>
121+
);
122+
};
123+
124+
export default Level;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
import React, { Dispatch, SetStateAction, useRef } from "react";
2+
import styled, { css } from "styled-components";
3+
import { landscapeStyle } from "styles/landscapeStyle";
4+
import { CompactPagination } from "@kleros/ui-components-library";
5+
import { Overlay } from "components/Overlay";
6+
import BookOpenIcon from "tsx:assets/svgs/icons/book-open.svg";
7+
import { useFocusOutside } from "hooks/useFocusOutside";
8+
9+
const Container = styled.div`
10+
display: flex;
11+
margin: 0 auto;
12+
width: auto;
13+
z-index: 10;
14+
position: fixed;
15+
width: 82vw;
16+
flex-direction: column;
17+
18+
top: 50%;
19+
left: 50%;
20+
transform: translate(-50%, -50%);
21+
max-height: 80vh;
22+
overflow-y: auto;
23+
24+
${landscapeStyle(
25+
() => css`
26+
overflow-y: hidden;
27+
width: calc(700px + (900 - 700) * (min(max(100vw, 375px), 1250px) - 375px) / 875);
28+
flex-direction: row;
29+
height: 500px;
30+
`
31+
)}
32+
`;
33+
34+
const LeftContainer = styled.div`
35+
display: grid;
36+
grid-template-rows: auto 1fr auto;
37+
width: 82vw;
38+
min-height: 356px;
39+
padding: calc(24px + (32 - 24) * (min(max(100vw, 375px), 1250px) - 375px) / 875);
40+
background-color: ${({ theme }) => theme.whiteBackground};
41+
border-top-left-radius: 3px;
42+
border-bottom-left-radius: 3px;
43+
44+
${landscapeStyle(
45+
() => css`
46+
overflow-y: hidden;
47+
width: calc(350px + (450 - 350) * (min(max(100vw, 375px), 1250px) - 375px) / 875);
48+
height: 500px;
49+
min-height: auto;
50+
`
51+
)}
52+
`;
53+
54+
const HowItWorks = styled.div`
55+
display: flex;
56+
align-items: center;
57+
gap: 8px;
58+
margin-bottom: calc(32px + (64 - 32) * (min(max(100vw, 375px), 1250px) - 375px) / 875);
59+
60+
label {
61+
color: ${({ theme }) => theme.secondaryPurple};
62+
}
63+
`;
64+
65+
const StyledCompactPagination = styled(CompactPagination)`
66+
align-self: end;
67+
justify-self: end;
68+
`;
69+
70+
const Close = styled.label`
71+
position: absolute;
72+
top: calc(24px + (32 - 24) * (min(max(100vw, 375px), 1250px) - 375px) / 875);
73+
right: 17px;
74+
display: flex;
75+
align-items: flex-end;
76+
justify-content: flex-end;
77+
cursor: pointer;
78+
79+
color: ${({ theme }) => theme.primaryBlue};
80+
81+
${landscapeStyle(
82+
() => css`
83+
z-index: 11;
84+
`
85+
)}
86+
`;
87+
88+
const RightContainer = styled.div`
89+
width: 82vw;
90+
position: relative;
91+
display: flex;
92+
flex-direction: column;
93+
align-items: center;
94+
justify-content: center;
95+
padding: calc(24px + (32 - 24) * (min(max(100vw, 375px), 1250px) - 375px) / 875) 17px;
96+
background-color: ${({ theme }) => theme.mediumBlue};
97+
border-top-right-radius: 3px;
98+
border-bottom-right-radius: 3px;
99+
height: 800px;
100+
101+
${landscapeStyle(
102+
() => css`
103+
overflow-y: hidden;
104+
width: calc(350px + (450 - 350) * (min(max(100vw, 375px), 1250px) - 375px) / 875);
105+
height: 500px;
106+
`
107+
)}
108+
`;
109+
110+
interface ITemplate {
111+
onClose: () => void;
112+
LeftContent: React.ReactNode;
113+
RightContent: React.ReactNode;
114+
currentPage: number;
115+
setCurrentPage: Dispatch<SetStateAction<number>>;
116+
numPages: number;
117+
}
118+
119+
const Template: React.FC<ITemplate> = ({
120+
onClose,
121+
LeftContent,
122+
RightContent,
123+
currentPage,
124+
setCurrentPage,
125+
numPages,
126+
}) => {
127+
const containerRef = useRef(null);
128+
useFocusOutside(containerRef, () => {
129+
onClose();
130+
});
131+
return (
132+
<>
133+
<Overlay />
134+
<Container ref={containerRef}>
135+
<LeftContainer>
136+
<HowItWorks>
137+
<BookOpenIcon />
138+
<label> How it works </label>
139+
</HowItWorks>
140+
<Close onClick={onClose}>Close</Close>
141+
{LeftContent}
142+
<StyledCompactPagination
143+
currentPage={currentPage}
144+
callback={setCurrentPage}
145+
numPages={numPages}
146+
label={`${currentPage}/${numPages}`}
147+
/>
148+
</LeftContainer>
149+
<RightContainer>{RightContent}</RightContainer>
150+
</Container>
151+
</>
152+
);
153+
};
154+
155+
export default Template;

web/src/pages/Dashboard/JurorInfo/Coherency.tsx

+19-11
Original file line numberDiff line numberDiff line change
@@ -24,31 +24,39 @@ const tooltipMsg =
2424

2525
interface ICoherency {
2626
userLevelData: {
27-
scoreRange: number[];
2827
level: number;
2928
title: string;
3029
};
3130
totalCoherent: number;
3231
totalResolvedDisputes: number;
32+
isMiniGuide: boolean;
3333
}
3434

35-
const Coherency: React.FC<ICoherency> = ({ userLevelData, totalCoherent, totalResolvedDisputes }) => {
35+
const Coherency: React.FC<ICoherency> = ({ userLevelData, totalCoherent, totalResolvedDisputes, isMiniGuide }) => {
36+
const votesContent = (
37+
<label>
38+
Coherent Votes:
39+
<small>
40+
{" "}
41+
{totalCoherent}/{totalResolvedDisputes}{" "}
42+
</small>
43+
</label>
44+
);
45+
3646
return (
3747
<Container>
3848
<small>{userLevelData.title}</small>
3949
<label>Level {userLevelData.level}</label>
4050
<CircularProgress
4151
progress={parseFloat(((totalCoherent / Math.max(totalResolvedDisputes, 1)) * 100).toFixed(2))}
4252
/>
43-
<WithHelpTooltip place="left" {...{ tooltipMsg }}>
44-
<label>
45-
Coherent Votes:
46-
<small>
47-
{" "}
48-
{totalCoherent}/{totalResolvedDisputes}{" "}
49-
</small>
50-
</label>
51-
</WithHelpTooltip>
53+
{!isMiniGuide ? (
54+
<WithHelpTooltip place="left" {...{ tooltipMsg }}>
55+
{votesContent}
56+
</WithHelpTooltip>
57+
) : (
58+
votesContent
59+
)}
5260
</Container>
5361
);
5462
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import React from "react";
2+
import styled from "styled-components";
3+
import XIcon from "svgs/socialmedia/x.svg";
4+
5+
const Container = styled.div`
6+
display: flex;
7+
flex-direction: row;
8+
align-items: center;
9+
justify-content: space-between;
10+
`;
11+
12+
const StyledTitle = styled.h1`
13+
margin-bottom: calc(16px + (48 - 16) * (min(max(100vw, 375px), 1250px) - 375px) / 875);
14+
`;
15+
16+
const XLinkContainer = styled.div`
17+
display: flex;
18+
color: ${({ theme }) => theme.primaryBlue};
19+
margin-bottom: calc(16px + (48 - 16) * (min(max(100vw, 375px), 1250px) - 375px) / 875);
20+
`;
21+
22+
const StyledXIcon = styled(XIcon)`
23+
fill: ${({ theme }) => theme.primaryBlue};
24+
width: 16px;
25+
height: 16px;
26+
`;
27+
28+
const StyledLink = styled.a`
29+
display: flex;
30+
border: 0px;
31+
align-items: center;
32+
gap: 8px;
33+
34+
&:hover {
35+
text-decoration: underline;
36+
}
37+
`;
38+
39+
interface IHeader {
40+
levelTitle: string;
41+
levelNumber: number;
42+
totalCoherent: number;
43+
totalResolvedDisputes: number;
44+
}
45+
46+
const Header: React.FC<IHeader> = ({ levelTitle, levelNumber, totalCoherent, totalResolvedDisputes }) => {
47+
const coherencePercentage = parseFloat(((totalCoherent / Math.max(totalResolvedDisputes, 1)) * 100).toFixed(2));
48+
const courtUrl = window.location.origin;
49+
const xPostText = `Hey I've been busy as a Juror on the Kleros court, check out my score: \n\nLevel: ${levelNumber} (${levelTitle})\nCoherence Percentage: ${coherencePercentage}%\nCoherent Votes: ${totalCoherent}/${totalResolvedDisputes}\n\nBe a juror with me! ➡️ ${courtUrl}`;
50+
const xShareUrl = `https://twitter.com/intent/tweet?text=${encodeURIComponent(xPostText)}`;
51+
52+
return (
53+
<Container>
54+
<StyledTitle>Juror Dashboard</StyledTitle>
55+
<XLinkContainer>
56+
<StyledLink href={xShareUrl} target="_blank" rel="noreferrer">
57+
<StyledXIcon /> <span>Share your juror score</span>
58+
</StyledLink>
59+
</XLinkContainer>
60+
</Container>
61+
);
62+
};
63+
64+
export default Header;

0 commit comments

Comments
 (0)