Skip to content

Commit ed63810

Browse files
committedJan 20, 2025··
feat: initial jurors page setup, jurors explore navlink, small styling tweak, dashboard to profile
1 parent 3110e46 commit ed63810

File tree

26 files changed

+222
-20
lines changed

26 files changed

+222
-20
lines changed
 

‎web/src/app.tsx

+12-3
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@ import QueryClientProvider from "context/QueryClientProvider";
1414
import StyledComponentsProvider from "context/StyledComponentsProvider";
1515
const Home = lazy(() => import("./pages/Home"));
1616
const Cases = lazy(() => import("./pages/Cases"));
17-
const Dashboard = lazy(() => import("./pages/Dashboard"));
17+
const Profile = lazy(() => import("./pages/Profile"));
1818
const Courts = lazy(() => import("./pages/Courts"));
19+
const Jurors = lazy(() => import("./pages/Jurors"));
1920
const DisputeResolver = lazy(() => import("./pages/Resolver"));
2021
const GetPnk = lazy(() => import("./pages/GetPnk"));
2122
const Settings = lazy(() => import("./pages/Settings"));
@@ -64,10 +65,18 @@ const App: React.FC = () => {
6465
}
6566
/>
6667
<Route
67-
path="dashboard/:page/:order/:filter"
68+
path="jurors/*"
6869
element={
6970
<Suspense fallback={<Loader width={"48px"} height={"48px"} />}>
70-
<Dashboard />
71+
<Jurors />
72+
</Suspense>
73+
}
74+
/>
75+
<Route
76+
path="profile/:page/:order/:filter"
77+
element={
78+
<Suspense fallback={<Loader width={"48px"} height={"48px"} />}>
79+
<Profile />
7180
</Suspense>
7281
}
7382
/>

‎web/src/components/EvidenceCard.tsx

+2-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import { Card } from "@kleros/ui-components-library";
88

99
import AttachmentIcon from "svgs/icons/attachment.svg";
1010

11-
import { DEFAULT_CHAIN, getChain } from "consts/chains";
1211
import { formatDate } from "utils/date";
1312
import { getIpfsUrl } from "utils/getIpfsUrl";
1413
import { shortenAddress } from "utils/shortenAddress";
@@ -224,7 +223,7 @@ const EvidenceCard: React.FC<IEvidenceCard> = ({
224223
description,
225224
fileURI,
226225
}) => {
227-
const dashboardLink = `/dashboard/1/desc/all?address=${sender}`;
226+
const profileLink = `/profile/1/desc/all?address=${sender}`;
228227

229228
const transactionExplorerLink = useMemo(() => {
230229
return getTxnExplorerLink(transactionHash ?? "");
@@ -249,7 +248,7 @@ const EvidenceCard: React.FC<IEvidenceCard> = ({
249248
<BottomLeftContent>
250249
<AccountContainer>
251250
<Identicon size="24" string={sender} />
252-
<InternalLink to={dashboardLink}>
251+
<InternalLink to={profileLink}>
253252
<Address>{shortenAddress(sender)}</Address>
254253
</InternalLink>
255254
</AccountContainer>

‎web/src/components/Popup/MiniGuides/JurorLevels.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import { Card as _Card } from "@kleros/ui-components-library";
55

66
import { landscapeStyle } from "styles/landscapeStyle";
77

8-
import Coherence from "pages/Dashboard/JurorInfo/Coherence";
9-
import PixelArt from "pages/Dashboard/JurorInfo/PixelArt";
8+
import Coherence from "pages/Profile/JurorInfo/Coherence";
9+
import PixelArt from "pages/Profile/JurorInfo/PixelArt";
1010

1111
import Template from "./MainStructureTemplate";
1212
import { Title, ParagraphsContainer, LeftContentContainer } from "./PageContentsTemplate";

‎web/src/layout/Header/navbar/Explore.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ const links = [
5454
{ to: "/", text: "Home" },
5555
{ to: "/cases/display/1/desc/all", text: "Cases" },
5656
{ to: "/courts", text: "Courts" },
57-
{ to: "/dashboard/1/desc/all", text: "Dashboard" },
57+
{ to: "/jurors", text: "Jurors" },
5858
{ to: "/get-pnk", text: "Get PNK" },
5959
];
6060

‎web/src/pages/Cases/CaseDetails/Voting/VotesDetails/AccordionTitle.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -88,13 +88,13 @@ const AccordionTitle: React.FC<{
8888
commited: boolean;
8989
hiddenVotes: boolean;
9090
}> = ({ juror, choice, voteCount, period, answers, isActiveRound, commited, hiddenVotes }) => {
91-
const dashboardLink = `/dashboard/1/desc/all?address=${juror}`;
91+
const profileLink = `/profile/1/desc/all?address=${juror}`;
9292

9393
return (
9494
<TitleContainer>
9595
<AddressContainer>
9696
<Identicon size="20" string={juror} />
97-
<StyledInternalLink to={dashboardLink}>
97+
<StyledInternalLink to={profileLink}>
9898
<StyledLabel variant="secondaryText">{shortenAddress(juror)}</StyledLabel>
9999
</StyledInternalLink>
100100
</AddressContainer>

‎web/src/pages/Courts/CourtDetails/TopSearch.tsx

+3
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ const SearchResultsContainer = styled(OverlayScrollbarsComponent)`
6868
overflow-y: auto;
6969
z-index: 1;
7070
background-color: ${({ theme }) => theme.whiteBackground};
71+
border-top-left-radius: 0;
72+
border-top-right-radius: 0;
7173
`;
7274

7375
const StyledCard = styled(Card)<{ selected: boolean }>`
@@ -79,6 +81,7 @@ const StyledCard = styled(Card)<{ selected: boolean }>`
7981
border: none;
8082
border-left: ${({ selected, theme }) => (selected ? `3px solid ${theme.primaryBlue}` : "none")};
8183
background-color: ${({ selected, theme }) => (selected ? theme.mediumBlue : "transparent")};
84+
border-radius: 0;
8285
8386
:hover {
8487
background-color: ${({ theme }) => theme.mediumBlue};

‎web/src/pages/Home/TopJurors/JurorCard/JurorLevel.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { getUserLevelData } from "utils/userLevelCalculation";
55

66
import { landscapeStyle } from "styles/landscapeStyle";
77

8-
import PixelArt from "pages/Dashboard/JurorInfo/PixelArt";
8+
import PixelArt from "pages/Profile/JurorInfo/PixelArt";
99

1010
const Container = styled.div`
1111
display: flex;

‎web/src/pages/Home/TopJurors/JurorCard/JurorTitle.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,12 @@ interface IJurorTitle {
3434
}
3535

3636
const JurorTitle: React.FC<IJurorTitle> = ({ address }) => {
37-
const dashboardLink = `/dashboard/1/desc/all?address=${address}`;
37+
const profileLink = `/profile/1/desc/all?address=${address}`;
3838

3939
return (
4040
<Container>
4141
<IdenticonOrAvatar address={address} />
42-
<StyledInternalLink to={dashboardLink}>
42+
<StyledInternalLink to={profileLink}>
4343
<AddressOrName address={address} />
4444
</StyledInternalLink>
4545
</Container>

‎web/src/pages/Home/TopJurors/index.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ const Title = styled.h1`
2222
font-size: ${responsiveSize(20, 24)};
2323
`;
2424

25-
const ListContainer = styled.div`
25+
export const ListContainer = styled.div`
2626
display: flex;
2727
flex-direction: column;
2828
justify-content: center;
@@ -35,7 +35,7 @@ const ListContainer = styled.div`
3535
)}
3636
`;
3737

38-
const StyledLabel = styled.label`
38+
export const StyledLabel = styled.label`
3939
font-size: 16px;
4040
`;
4141

‎web/src/pages/Jurors/Search.tsx

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import React, { useRef, useState } from "react";
2+
import styled, { css } from "styled-components";
3+
4+
import { useNavigate, useParams, useSearchParams } from "react-router-dom";
5+
import { useDebounce } from "react-use";
6+
import { Searchbar } from "@kleros/ui-components-library";
7+
8+
import { isEmpty } from "utils/index";
9+
import { decodeURIFilter, encodeURIFilter, useRootPath } from "utils/uri";
10+
11+
import { landscapeStyle } from "styles/landscapeStyle";
12+
import { responsiveSize } from "styles/responsiveSize";
13+
14+
const Container = styled.div`
15+
display: flex;
16+
flex-direction: column;
17+
gap: ${responsiveSize(8, 16)};
18+
19+
${landscapeStyle(
20+
() => css`
21+
flex-direction: row;
22+
`
23+
)}
24+
`;
25+
26+
const StyledSearchbar = styled(Searchbar)`
27+
flex: 1;
28+
flex-basis: 310px;
29+
30+
input {
31+
font-size: 16px;
32+
height: 45px;
33+
padding-top: 0px;
34+
padding-bottom: 0px;
35+
}
36+
`;
37+
38+
const Search: React.FC = () => {
39+
const { page, order, filter } = useParams();
40+
const location = useRootPath();
41+
const decodedFilter = decodeURIFilter(filter ?? "all");
42+
const { id: searchValue, ...filterObject } = decodedFilter;
43+
const [search, setSearch] = useState(searchValue ?? "");
44+
const initialRenderRef = useRef(true);
45+
const navigate = useNavigate();
46+
const [searchParams] = useSearchParams();
47+
48+
useDebounce(
49+
() => {
50+
if (initialRenderRef.current && isEmpty(search)) {
51+
initialRenderRef.current = false;
52+
return;
53+
}
54+
initialRenderRef.current = false;
55+
const newFilters = isEmpty(search) ? { ...filterObject } : { ...filterObject, id: search };
56+
const encodedFilter = encodeURIFilter(newFilters);
57+
navigate(`${location}/${page}/${order}/${encodedFilter}?${searchParams.toString()}`);
58+
},
59+
500,
60+
[search]
61+
);
62+
63+
return (
64+
<Container>
65+
<StyledSearchbar
66+
dir="auto"
67+
type="text"
68+
placeholder="Search"
69+
value={search}
70+
onChange={(e) => setSearch(e.target.value)}
71+
/>
72+
</Container>
73+
);
74+
};
75+
76+
export default Search;

‎web/src/pages/Jurors/Stats.tsx

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import React from "react";
2+
import styled from "styled-components";
3+
4+
const FieldWrapper = styled.div`
5+
display: inline-flex;
6+
gap: 8px;
7+
`;
8+
9+
const StyledLabel = styled.label`
10+
color: ${({ theme }) => theme.primaryText};
11+
`;
12+
13+
const Field: React.FC<{ label: string; value: string }> = ({ label, value }) => (
14+
<FieldWrapper>
15+
<StyledLabel>{label}</StyledLabel>
16+
<small>{value}</small>
17+
</FieldWrapper>
18+
);
19+
20+
export interface IStats {
21+
totalJurors: number;
22+
}
23+
24+
const Stats: React.FC<IStats> = ({ totalJurors }) => {
25+
return <Field label="Total" value={`${totalJurors} Jurors`} />;
26+
};
27+
28+
export default Stats;
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import React from "react";
2+
import styled from "styled-components";
3+
4+
import { responsiveSize } from "styles/responsiveSize";
5+
import Stats, { IStats } from "./Stats";
6+
7+
const Container = styled.div`
8+
display: flex;
9+
flex-wrap: wrap;
10+
gap: 8px;
11+
margin-top: ${responsiveSize(4, 8)};
12+
margin-bottom: ${responsiveSize(16, 32)};
13+
justify-content: space-between;
14+
`;
15+
16+
const StatsAndFilters: React.FC<IStats> = ({ totalJurors }) => (
17+
<Container>
18+
<Stats {...{ totalJurors }} />
19+
</Container>
20+
);
21+
22+
export default StatsAndFilters;

‎web/src/pages/Jurors/index.tsx

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import React from "react";
2+
import styled, { css } from "styled-components";
3+
4+
import { MAX_WIDTH_LANDSCAPE, landscapeStyle } from "styles/landscapeStyle";
5+
import { responsiveSize } from "styles/responsiveSize";
6+
7+
import { isUndefined } from "utils/index";
8+
9+
import { useTopUsersByCoherenceScore } from "queries/useTopUsersByCoherenceScore";
10+
11+
import { SkeletonDisputeListItem } from "components/StyledSkeleton";
12+
import Search from "./Search";
13+
import StatsAndFilters from "./StatsAndFilters";
14+
import JurorCard from "../Home/TopJurors/JurorCard";
15+
import { ListContainer, StyledLabel } from "../Home/TopJurors";
16+
import Header from "../Home/TopJurors/Header";
17+
18+
const Container = styled.div`
19+
width: 100%;
20+
background-color: ${({ theme }) => theme.lightBackground};
21+
padding: 32px 16px 40px;
22+
max-width: ${MAX_WIDTH_LANDSCAPE};
23+
margin: 0 auto;
24+
25+
${landscapeStyle(
26+
() => css`
27+
padding: 48px ${responsiveSize(0, 132)} 60px;
28+
`
29+
)}
30+
`;
31+
32+
const StyledTitle = styled.h1`
33+
margin: 0px;
34+
font-size: ${responsiveSize(20, 24)};
35+
`;
36+
37+
const Jurors: React.FC = () => {
38+
const { data: queryJurors } = useTopUsersByCoherenceScore(1000);
39+
40+
const topJurors = queryJurors?.users?.map((juror, index) => ({
41+
...juror,
42+
rank: index + 1,
43+
}));
44+
45+
return (
46+
<Container>
47+
<StyledTitle>Jurors Leaderboard</StyledTitle>
48+
<Search />
49+
<StatsAndFilters totalJurors={0} />
50+
51+
{!isUndefined(topJurors) && topJurors.length === 0 ? (
52+
<StyledLabel>There are no jurors staked yet.</StyledLabel>
53+
) : (
54+
<ListContainer>
55+
<Header />
56+
{!isUndefined(topJurors)
57+
? topJurors.map((juror) => <JurorCard key={juror.rank} address={juror.id} {...juror} />)
58+
: [...Array(5)].map((_, i) => <SkeletonDisputeListItem key={i} />)}
59+
</ListContainer>
60+
)}
61+
</Container>
62+
);
63+
};
64+
65+
export default Jurors;

‎web/src/pages/Dashboard/JurorInfo/Header.tsx ‎web/src/pages/Profile/JurorInfo/Header.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ const Header: React.FC<IHeader> = ({
8787
return (
8888
<Container>
8989
<StyledTitle>
90-
Juror Dashboard -
90+
Juror Profile -
9191
<Copiable copiableContent={addressToQuery} info="Copy Address">
9292
<StyledExternalLink to={addressExplorerLink} target="_blank" rel="noopener noreferrer">
9393
{shortenAddress(addressToQuery)}

‎web/src/pages/Dashboard/index.tsx ‎web/src/pages/Profile/index.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ const ConnectWalletContainer = styled.div`
5050
color: ${({ theme }) => theme.primaryText};
5151
`;
5252

53-
const Dashboard: React.FC = () => {
53+
const Profile: React.FC = () => {
5454
const { isConnected, address: connectedAddress } = useAccount();
5555
const { page, order, filter } = useParams();
5656
const [searchParams] = useSearchParams();
@@ -97,7 +97,7 @@ const Dashboard: React.FC = () => {
9797
</>
9898
) : (
9999
<ConnectWalletContainer>
100-
To see your dashboard, connect first
100+
To see your profile, connect first
101101
<hr />
102102
<ConnectWallet />
103103
</ConnectWalletContainer>
@@ -108,4 +108,4 @@ const Dashboard: React.FC = () => {
108108
);
109109
};
110110

111-
export default Dashboard;
111+
export default Profile;

0 commit comments

Comments
 (0)
Please sign in to comment.