Skip to content

Commit c3213ca

Browse files
committed
feat: url path tab logic, refactors, add voted ballot svg, add icons to tabs
1 parent 45bc1fb commit c3213ca

File tree

22 files changed

+146
-78
lines changed

22 files changed

+146
-78
lines changed

web/src/app.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ const App: React.FC = () => {
7373
}
7474
/>
7575
<Route
76-
path="profile/:page/:order/:filter"
76+
path="profile/*"
7777
element={
7878
<Suspense fallback={<Loader width={"48px"} height={"48px"} />}>
7979
<Profile />
Loading

web/src/components/EvidenceCard.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ const EvidenceCard: React.FC<IEvidenceCard> = ({
223223
description,
224224
fileURI,
225225
}) => {
226-
const profileLink = `/profile/1/desc/all?address=${sender}`;
226+
const profileLink = `/profile/stakes?address=${sender}`;
227227

228228
const transactionExplorerLink = useMemo(() => {
229229
return getTxnExplorerLink(transactionHash ?? "");

web/src/components/JurorLink.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ const JurorLink: React.FC<IJurorLink> = ({ address, isInternalLink = true }) =>
4949
const { isConnected, address: connectedAddress } = useAccount();
5050
const profileLink =
5151
isConnected && connectedAddress?.toLowerCase() === address.toLowerCase()
52-
? "/profile/1/desc/all"
53-
: `/profile/1/desc/all?address=${address}`;
52+
? "/profile"
53+
: `/profile/stakes?address=${address}`;
5454
const addressExplorerLink = useMemo(() => {
5555
return `${getChain(DEFAULT_CHAIN)?.blockExplorers?.default.url}/address/${address}`;
5656
}, [address]);

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/Profile/JurorInfo/BottomContent/Coherence";
9-
import PixelArt from "pages/Profile/JurorInfo/BottomContent/PixelArt";
8+
import Coherence from "pages/Profile/JurorCard/BottomContent/Coherence";
9+
import PixelArt from "pages/Profile/JurorCard/BottomContent/PixelArt";
1010

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

web/src/layout/Header/navbar/Menu/Settings/General/WalletAndProfile.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ const WalletAndProfile: React.FC<ISettings> = ({ toggleIsSettingsOpen }) => {
5252
<IdenticonOrAvatar />
5353
<AddressOrName />
5454
</AvatarAndAddressContainer>
55-
<ReStyledArrowLink to={"/profile/1/desc/all"} onClick={toggleIsSettingsOpen}>
55+
<ReStyledArrowLink to={"/profile"} onClick={toggleIsSettingsOpen}>
5656
My Profile <ArrowIcon />
5757
</ReStyledArrowLink>
5858
</Container>

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ const AccordionTitle: React.FC<{
8686
commited: boolean;
8787
hiddenVotes: boolean;
8888
}> = ({ juror, choice, voteCount, period, answers, isActiveRound, commited, hiddenVotes }) => {
89-
const profileLink = `/profile/1/desc/all?address=${juror}`;
89+
const profileLink = `/profile/stakes?address=${juror}`;
9090

9191
return (
9292
<TitleContainer>

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { landscapeStyle } from "styles/landscapeStyle";
66
import { getUserLevelData } from "utils/userLevelCalculation";
77
import { getCoherencePercent } from "utils/getCoherencePercent";
88

9-
import PixelArt from "pages/Profile/JurorInfo/BottomContent/PixelArt";
9+
import PixelArt from "pages/Profile/JurorCard/BottomContent/PixelArt";
1010

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

web/src/pages/Jurors/index.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ const Jurors: React.FC = () => {
5555
<Header>
5656
<StyledTitle>Jurors Leaderboard</StyledTitle>
5757
{isConnected ? (
58-
<StyledArrowLink to="/profile/1/desc/all">
58+
<StyledArrowLink to="/profile">
5959
My Profile <ArrowIcon />
6060
</StyledArrowLink>
6161
) : null}

web/src/pages/Profile/Cases/index.tsx

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import React, { useMemo } from "react";
2+
import { useNavigate, useParams, useSearchParams } from "react-router-dom";
3+
4+
import styled from "styled-components";
5+
import { responsiveSize } from "styles/responsiveSize";
6+
7+
import { isUndefined } from "utils/index";
8+
import { decodeURIFilter, useRootPath } from "utils/uri";
9+
10+
import { DisputeDetailsFragment, OrderDirection } from "src/graphql/graphql";
11+
import { useMyCasesQuery } from "queries/useCasesQuery";
12+
import { useUserQuery } from "queries/useUser";
13+
import CasesDisplay from "components/CasesDisplay";
14+
15+
const StyledCasesDisplay = styled(CasesDisplay)`
16+
margin-top: ${responsiveSize(24, 32)};
17+
18+
.title {
19+
margin-bottom: ${responsiveSize(12, 24)};
20+
}
21+
`;
22+
23+
interface ICases {
24+
addressToQuery: `0x${string}`;
25+
}
26+
27+
const Cases: React.FC<ICases> = ({ addressToQuery }) => {
28+
const { page, order, filter } = useParams();
29+
const [searchParams] = useSearchParams();
30+
const location = useRootPath();
31+
const navigate = useNavigate();
32+
33+
const casesPerPage = 3;
34+
const pageNumber = parseInt(page ?? "1");
35+
const disputeSkip = casesPerPage * (pageNumber - 1);
36+
const decodedFilter = decodeURIFilter(filter ?? "all");
37+
const { data: disputesData } = useMyCasesQuery(
38+
addressToQuery,
39+
disputeSkip,
40+
decodedFilter,
41+
order === "asc" ? OrderDirection.Asc : OrderDirection.Desc
42+
);
43+
44+
const { data: userData } = useUserQuery(addressToQuery, decodedFilter);
45+
const totalCases = userData?.user?.disputes.length;
46+
const totalResolvedCases = parseInt(userData?.user?.totalResolvedDisputes);
47+
const totalPages = useMemo(
48+
() => (!isUndefined(totalCases) ? Math.ceil(totalCases / casesPerPage) : 1),
49+
[totalCases, casesPerPage]
50+
);
51+
52+
return (
53+
<StyledCasesDisplay
54+
title="Cases Drawn"
55+
disputes={userData?.user !== null ? (disputesData?.user?.disputes as DisputeDetailsFragment[]) : []}
56+
numberDisputes={totalCases}
57+
numberClosedDisputes={totalResolvedCases}
58+
totalPages={totalPages}
59+
currentPage={pageNumber}
60+
setCurrentPage={(newPage: number) =>
61+
navigate(`${location}/${newPage}/${order}/${filter}?${searchParams.toString()}`)
62+
}
63+
{...{ casesPerPage }}
64+
/>
65+
);
66+
};
67+
68+
export default Cases;

web/src/pages/Profile/JurorInfo/BottomContent/JurorRewards.tsx web/src/pages/Profile/JurorCard/BottomContent/JurorRewards.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,12 @@ const Container = styled.div`
1717
flex-direction: column;
1818
align-items: center;
1919
width: auto;
20-
gap: 24px;
20+
gap: 12px;
2121
2222
${landscapeStyle(
2323
() => css`
2424
align-items: flex-start;
25+
gap: 24px;
2526
`
2627
)}
2728
`;

web/src/pages/Profile/JurorInfo/index.tsx web/src/pages/Profile/JurorCard/index.tsx

+4-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React from "react";
2-
import styled, { css } from "styled-components";
2+
import styled from "styled-components";
33

44
import { Card as _Card } from "@kleros/ui-components-library";
55

@@ -8,9 +8,6 @@ import { getCoherencePercent } from "utils/getCoherencePercent";
88

99
import { useUserQuery } from "queries/useUser";
1010

11-
import { landscapeStyle } from "styles/landscapeStyle";
12-
import { responsiveSize } from "styles/responsiveSize";
13-
1411
import Header from "./Header";
1512
import BottomContent from "./BottomContent";
1613
import { Divider } from "components/Divider";
@@ -29,11 +26,11 @@ const Card = styled(_Card)`
2926
padding: 24px;
3027
`;
3128

32-
interface IJurorInfo {
29+
interface IJurorCard {
3330
addressToQuery: `0x${string}`;
3431
}
3532

36-
const JurorInfo: React.FC<IJurorInfo> = ({ addressToQuery }) => {
33+
const JurorCard: React.FC<IJurorCard> = ({ addressToQuery }) => {
3734
const { data } = useUserQuery(addressToQuery);
3835
const totalCoherentVotes = data?.user ? parseInt(data?.user?.totalCoherentVotes) : 0;
3936
const totalResolvedVotes = data?.user ? parseInt(data?.user?.totalResolvedVotes) : 0;
@@ -57,4 +54,4 @@ const JurorInfo: React.FC<IJurorInfo> = ({ addressToQuery }) => {
5754
);
5855
};
5956

60-
export default JurorInfo;
57+
export default JurorCard;

web/src/pages/Profile/Stakes/index.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ const CourtCardsContainer = styled.div`
2525
2626
${landscapeStyle(
2727
() => css`
28-
gap: 16px;
28+
gap: 8px;
2929
`
3030
)}
3131
`;

web/src/pages/Profile/Votes/index.tsx

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import React from "react";
2+
3+
interface IVotes {}
4+
5+
const Votes: React.FC<IVotes> = () => {
6+
return <div></div>;
7+
};
8+
export default Votes;

web/src/pages/Profile/index.tsx

+48-59
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,22 @@
1-
import React, { useState, useMemo } from "react";
2-
1+
import React from "react";
2+
import { Routes, Route, useNavigate, useSearchParams, useLocation, Navigate } from "react-router-dom";
3+
import { useAccount } from "wagmi";
34
import styled, { css } from "styled-components";
45
import { MAX_WIDTH_LANDSCAPE, landscapeStyle } from "styles/landscapeStyle";
56
import { responsiveSize } from "styles/responsiveSize";
6-
7-
import { useNavigate, useParams, useSearchParams } from "react-router-dom";
8-
import { useAccount } from "wagmi";
97
import { Tabs as TabsComponent } from "@kleros/ui-components-library";
108

11-
import { isUndefined } from "utils/index";
12-
import { decodeURIFilter, useRootPath } from "utils/uri";
13-
import { DisputeDetailsFragment, useMyCasesQuery } from "queries/useCasesQuery";
14-
import { useUserQuery } from "queries/useUser";
15-
import { OrderDirection } from "src/graphql/graphql";
16-
import CasesDisplay from "components/CasesDisplay";
9+
import PnkIcon from "svgs/icons/pnk.svg";
10+
import DocIcon from "svgs/icons/doc.svg";
11+
import VotedIcon from "svgs/icons/voted-ballot.svg";
12+
1713
import ConnectWallet from "components/ConnectWallet";
1814
import FavoriteCases from "components/FavoriteCases";
1915
import ScrollTop from "components/ScrollTop";
20-
import JurorInfo from "./JurorInfo";
16+
import JurorCard from "./JurorCard";
2117
import Stakes from "./Stakes";
18+
import Cases from "./Cases";
19+
import Votes from "./Votes";
2220

2321
const Container = styled.div`
2422
width: 100%;
@@ -34,17 +32,17 @@ const Container = styled.div`
3432
)}
3533
`;
3634

37-
const StyledCasesDisplay = styled(CasesDisplay)`
38-
margin-top: ${responsiveSize(24, 32)};
39-
40-
.title {
41-
margin-bottom: ${responsiveSize(12, 24)};
42-
}
43-
`;
44-
4535
const StyledTabs = styled(TabsComponent)`
4636
width: 100%;
4737
margin-top: ${responsiveSize(16, 32)};
38+
> * {
39+
display: flex;
40+
flex-wrap: wrap;
41+
font-size: ${responsiveSize(14, 16)};
42+
> svg {
43+
margin-right: 8px !important;
44+
}
45+
}
4846
`;
4947

5048
const ConnectWalletContainer = styled.div`
@@ -56,60 +54,51 @@ const ConnectWalletContainer = styled.div`
5654
`;
5755

5856
const TABS = [
59-
{ text: "Stakes", value: 0 },
60-
{ text: "Cases", value: 1 },
61-
{ text: "Votes", value: 2 },
57+
{ text: "Stakes", value: 0, Icon: PnkIcon, path: "stakes" },
58+
{ text: "Cases", value: 1, Icon: DocIcon, path: "cases/1/desc/all" },
59+
{ text: "Votes", value: 2, Icon: VotedIcon, path: "votes" },
6260
];
6361

62+
const getTabIndex = (currentPath: string) => {
63+
return TABS.findIndex((tab) => currentPath.includes(tab.path.split("/")[0]));
64+
};
65+
6466
const Profile: React.FC = () => {
6567
const { isConnected, address: connectedAddress } = useAccount();
66-
const { page, order, filter } = useParams();
6768
const [searchParams] = useSearchParams();
68-
const location = useRootPath();
69+
const { pathname } = useLocation();
6970
const navigate = useNavigate();
7071
const searchParamAddress = searchParams.get("address")?.toLowerCase();
7172
const addressToQuery = searchParamAddress || connectedAddress?.toLowerCase();
72-
const casesPerPage = 3;
73-
const pageNumber = parseInt(page ?? "1");
74-
const disputeSkip = casesPerPage * (pageNumber - 1);
75-
const decodedFilter = decodeURIFilter(filter ?? "all");
76-
const { data: disputesData } = useMyCasesQuery(
77-
addressToQuery,
78-
disputeSkip,
79-
decodedFilter,
80-
order === "asc" ? OrderDirection.Asc : OrderDirection.Desc
81-
);
82-
const { data: userData } = useUserQuery(addressToQuery, decodedFilter);
83-
const totalCases = userData?.user?.disputes.length;
84-
const totalResolvedCases = parseInt(userData?.user?.totalResolvedDisputes);
85-
const totalPages = useMemo(
86-
() => (!isUndefined(totalCases) ? Math.ceil(totalCases / casesPerPage) : 1),
87-
[totalCases, casesPerPage]
88-
);
89-
const [currentTab, setCurrentTab] = useState(0);
73+
74+
const handleTabChange = (tabIndex: number) => {
75+
const selectedTab = TABS[tabIndex];
76+
const basePath = `/profile/${selectedTab.path}`;
77+
const queryParam = searchParamAddress ? `?address=${searchParamAddress}` : "";
78+
navigate(`${basePath}${queryParam}`);
79+
};
9080

9181
return (
9282
<Container>
9383
{isConnected || searchParamAddress ? (
9484
<>
95-
<JurorInfo {...{ addressToQuery }} />
96-
<StyledTabs currentValue={currentTab} items={TABS} callback={(n) => setCurrentTab(n)} />
97-
{currentTab === 0 && <Stakes {...{ addressToQuery }} />}
98-
{currentTab === 1 && (
99-
<StyledCasesDisplay
100-
title="Cases Drawn"
101-
disputes={userData?.user !== null ? (disputesData?.user?.disputes as DisputeDetailsFragment[]) : []}
102-
numberDisputes={totalCases}
103-
numberClosedDisputes={totalResolvedCases}
104-
totalPages={totalPages}
105-
currentPage={pageNumber}
106-
setCurrentPage={(newPage: number) =>
107-
navigate(`${location}/${newPage}/${order}/${filter}?${searchParams.toString()}`)
85+
<JurorCard {...{ addressToQuery }} />
86+
<StyledTabs
87+
currentValue={getTabIndex(pathname)}
88+
items={TABS}
89+
callback={(tabIndex: number) => handleTabChange(tabIndex)}
90+
/>
91+
<Routes>
92+
<Route path="stakes" element={<Stakes {...{ addressToQuery }} />} />
93+
<Route path="cases/:page/:order/:filter" element={<Cases {...{ addressToQuery }} />} />
94+
<Route path="votes" element={<Votes />} />
95+
<Route
96+
path="*"
97+
element={
98+
<Navigate to={`${searchParamAddress ? `stakes?address=${searchParamAddress}` : "stakes"}`} replace />
10899
}
109-
{...{ casesPerPage }}
110100
/>
111-
)}
112-
{currentTab === 2 && null}
101+
</Routes>
113102
</>
114103
) : (
115104
<ConnectWalletContainer>

0 commit comments

Comments
 (0)