Skip to content

Commit 5a72ba1

Browse files
authored
Merge pull request #1304 from kleros/feat(web)/mini-guides-levels
feat(web): create mini guides structure, create level miniguides, sty…
2 parents 7016cc7 + f5495c9 commit 5a72ba1

File tree

10 files changed

+310
-12
lines changed

10 files changed

+310
-12
lines changed
-46.4 KB
Loading
-48.5 KB
Loading
-46.4 KB
Loading
-47.9 KB
Loading
-48.7 KB
Loading
Lines changed: 124 additions & 0 deletions
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;
Lines changed: 155 additions & 0 deletions
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

Lines changed: 19 additions & 11 deletions
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
};

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ const JurorInfo: React.FC = () => {
5454
userLevelData={userLevelData}
5555
totalCoherent={totalCoherent}
5656
totalResolvedDisputes={totalResolvedDisputes}
57+
isMiniGuide={false}
5758
/>
5859
<JurorRewards />
5960
</Card>

web/src/pages/Home/TopJurors/TopJurorsHeader.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import React from "react";
22
import styled, { css } from "styled-components";
3+
import { useToggle } from "react-use";
34
import { landscapeStyle } from "styles/landscapeStyle";
45
import WithHelpTooltip from "pages/Dashboard/WithHelpTooltip";
56
import BookOpenIcon from "tsx:assets/svgs/icons/book-open.svg";
7+
import Level from "components/Popup/MiniGuides/Level";
68

79
const Container = styled.div`
810
display: flex;
@@ -101,6 +103,11 @@ const HowItWorks = styled.div`
101103
align-items: center;
102104
gap: 8px;
103105
106+
&,
107+
& * {
108+
cursor: pointer;
109+
}
110+
104111
label {
105112
color: ${({ theme }) => theme.primaryBlue};
106113
}
@@ -125,6 +132,8 @@ const coherentVotesTooltipMsg =
125132
"the juror voted";
126133

127134
const TopJurorsHeader: React.FC = () => {
135+
const [isLevelMiniGuidesOpen, toggleIsLevelMiniGuidesOpen] = useToggle(false);
136+
128137
return (
129138
<Container>
130139
<PlaceAndTitleAndRewardsAndCoherency>
@@ -145,10 +154,11 @@ const TopJurorsHeader: React.FC = () => {
145154
</WithHelpTooltip>
146155
</Coherency>
147156
</PlaceAndTitleAndRewardsAndCoherency>
148-
<HowItWorks>
157+
<HowItWorks onClick={() => toggleIsLevelMiniGuidesOpen()}>
149158
<BookOpenIcon />
150159
<label> How it works </label>
151160
</HowItWorks>
161+
{isLevelMiniGuidesOpen && <Level {...{ toggleIsLevelMiniGuidesOpen }} />}
152162
</Container>
153163
);
154164
};

0 commit comments

Comments
 (0)