Skip to content

Commit

Permalink
feat: url path tab logic, refactors, add voted ballot svg, add icons …
Browse files Browse the repository at this point in the history
…to tabs
  • Loading branch information
kemuru committed Feb 1, 2025
1 parent 45bc1fb commit c3213ca
Show file tree
Hide file tree
Showing 22 changed files with 146 additions and 78 deletions.
2 changes: 1 addition & 1 deletion web/src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ const App: React.FC = () => {
}
/>
<Route
path="profile/:page/:order/:filter"
path="profile/*"
element={
<Suspense fallback={<Loader width={"48px"} height={"48px"} />}>
<Profile />
Expand Down
5 changes: 5 additions & 0 deletions web/src/assets/svgs/icons/voted-ballot.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion web/src/components/EvidenceCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ const EvidenceCard: React.FC<IEvidenceCard> = ({
description,
fileURI,
}) => {
const profileLink = `/profile/1/desc/all?address=${sender}`;
const profileLink = `/profile/stakes?address=${sender}`;

const transactionExplorerLink = useMemo(() => {
return getTxnExplorerLink(transactionHash ?? "");
Expand Down
4 changes: 2 additions & 2 deletions web/src/components/JurorLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ const JurorLink: React.FC<IJurorLink> = ({ address, isInternalLink = true }) =>
const { isConnected, address: connectedAddress } = useAccount();
const profileLink =
isConnected && connectedAddress?.toLowerCase() === address.toLowerCase()
? "/profile/1/desc/all"
: `/profile/1/desc/all?address=${address}`;
? "/profile"
: `/profile/stakes?address=${address}`;
const addressExplorerLink = useMemo(() => {
return `${getChain(DEFAULT_CHAIN)?.blockExplorers?.default.url}/address/${address}`;
}, [address]);
Expand Down
4 changes: 2 additions & 2 deletions web/src/components/Popup/MiniGuides/JurorLevels.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import { Card as _Card } from "@kleros/ui-components-library";

import { landscapeStyle } from "styles/landscapeStyle";

import Coherence from "pages/Profile/JurorInfo/BottomContent/Coherence";
import PixelArt from "pages/Profile/JurorInfo/BottomContent/PixelArt";
import Coherence from "pages/Profile/JurorCard/BottomContent/Coherence";
import PixelArt from "pages/Profile/JurorCard/BottomContent/PixelArt";

import Template from "./MainStructureTemplate";
import { Title, ParagraphsContainer, LeftContentContainer } from "./PageContentsTemplate";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ const WalletAndProfile: React.FC<ISettings> = ({ toggleIsSettingsOpen }) => {
<IdenticonOrAvatar />
<AddressOrName />
</AvatarAndAddressContainer>
<ReStyledArrowLink to={"/profile/1/desc/all"} onClick={toggleIsSettingsOpen}>
<ReStyledArrowLink to={"/profile"} onClick={toggleIsSettingsOpen}>
My Profile <ArrowIcon />
</ReStyledArrowLink>
</Container>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ const AccordionTitle: React.FC<{
commited: boolean;
hiddenVotes: boolean;
}> = ({ juror, choice, voteCount, period, answers, isActiveRound, commited, hiddenVotes }) => {
const profileLink = `/profile/1/desc/all?address=${juror}`;
const profileLink = `/profile/stakes?address=${juror}`;

return (
<TitleContainer>
Expand Down
2 changes: 1 addition & 1 deletion web/src/pages/Home/TopJurors/JurorCard/JurorLevel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { landscapeStyle } from "styles/landscapeStyle";
import { getUserLevelData } from "utils/userLevelCalculation";
import { getCoherencePercent } from "utils/getCoherencePercent";

import PixelArt from "pages/Profile/JurorInfo/BottomContent/PixelArt";
import PixelArt from "pages/Profile/JurorCard/BottomContent/PixelArt";

const Container = styled.div`
display: flex;
Expand Down
2 changes: 1 addition & 1 deletion web/src/pages/Jurors/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ const Jurors: React.FC = () => {
<Header>
<StyledTitle>Jurors Leaderboard</StyledTitle>
{isConnected ? (
<StyledArrowLink to="/profile/1/desc/all">
<StyledArrowLink to="/profile">
My Profile <ArrowIcon />
</StyledArrowLink>
) : null}
Expand Down
68 changes: 68 additions & 0 deletions web/src/pages/Profile/Cases/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import React, { useMemo } from "react";
import { useNavigate, useParams, useSearchParams } from "react-router-dom";

import styled from "styled-components";
import { responsiveSize } from "styles/responsiveSize";

import { isUndefined } from "utils/index";
import { decodeURIFilter, useRootPath } from "utils/uri";

import { DisputeDetailsFragment, OrderDirection } from "src/graphql/graphql";
import { useMyCasesQuery } from "queries/useCasesQuery";
import { useUserQuery } from "queries/useUser";
import CasesDisplay from "components/CasesDisplay";

const StyledCasesDisplay = styled(CasesDisplay)`
margin-top: ${responsiveSize(24, 32)};
.title {
margin-bottom: ${responsiveSize(12, 24)};
}
`;

interface ICases {
addressToQuery: `0x${string}`;
}

const Cases: React.FC<ICases> = ({ addressToQuery }) => {
const { page, order, filter } = useParams();
const [searchParams] = useSearchParams();
const location = useRootPath();
const navigate = useNavigate();

const casesPerPage = 3;
const pageNumber = parseInt(page ?? "1");
const disputeSkip = casesPerPage * (pageNumber - 1);
const decodedFilter = decodeURIFilter(filter ?? "all");
const { data: disputesData } = useMyCasesQuery(
addressToQuery,
disputeSkip,
decodedFilter,
order === "asc" ? OrderDirection.Asc : OrderDirection.Desc
);

const { data: userData } = useUserQuery(addressToQuery, decodedFilter);
const totalCases = userData?.user?.disputes.length;
const totalResolvedCases = parseInt(userData?.user?.totalResolvedDisputes);
const totalPages = useMemo(
() => (!isUndefined(totalCases) ? Math.ceil(totalCases / casesPerPage) : 1),
[totalCases, casesPerPage]
);

return (
<StyledCasesDisplay
title="Cases Drawn"
disputes={userData?.user !== null ? (disputesData?.user?.disputes as DisputeDetailsFragment[]) : []}
numberDisputes={totalCases}
numberClosedDisputes={totalResolvedCases}
totalPages={totalPages}
currentPage={pageNumber}
setCurrentPage={(newPage: number) =>
navigate(`${location}/${newPage}/${order}/${filter}?${searchParams.toString()}`)
}
{...{ casesPerPage }}
/>
);
};

export default Cases;
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@ const Container = styled.div`
flex-direction: column;
align-items: center;
width: auto;
gap: 24px;
gap: 12px;
${landscapeStyle(
() => css`
align-items: flex-start;
gap: 24px;
`
)}
`;
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from "react";
import styled, { css } from "styled-components";
import styled from "styled-components";

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

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

import { useUserQuery } from "queries/useUser";

import { landscapeStyle } from "styles/landscapeStyle";
import { responsiveSize } from "styles/responsiveSize";

import Header from "./Header";
import BottomContent from "./BottomContent";
import { Divider } from "components/Divider";
Expand All @@ -29,11 +26,11 @@ const Card = styled(_Card)`
padding: 24px;
`;

interface IJurorInfo {
interface IJurorCard {
addressToQuery: `0x${string}`;
}

const JurorInfo: React.FC<IJurorInfo> = ({ addressToQuery }) => {
const JurorCard: React.FC<IJurorCard> = ({ addressToQuery }) => {
const { data } = useUserQuery(addressToQuery);
const totalCoherentVotes = data?.user ? parseInt(data?.user?.totalCoherentVotes) : 0;
const totalResolvedVotes = data?.user ? parseInt(data?.user?.totalResolvedVotes) : 0;
Expand All @@ -57,4 +54,4 @@ const JurorInfo: React.FC<IJurorInfo> = ({ addressToQuery }) => {
);
};

export default JurorInfo;
export default JurorCard;
2 changes: 1 addition & 1 deletion web/src/pages/Profile/Stakes/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const CourtCardsContainer = styled.div`
${landscapeStyle(
() => css`
gap: 16px;
gap: 8px;
`
)}
`;
Expand Down
8 changes: 8 additions & 0 deletions web/src/pages/Profile/Votes/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import React from "react";

interface IVotes {}

const Votes: React.FC<IVotes> = () => {
return <div></div>;
};
export default Votes;
107 changes: 48 additions & 59 deletions web/src/pages/Profile/index.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,22 @@
import React, { useState, useMemo } from "react";

import React from "react";
import { Routes, Route, useNavigate, useSearchParams, useLocation, Navigate } from "react-router-dom";
import { useAccount } from "wagmi";
import styled, { css } from "styled-components";
import { MAX_WIDTH_LANDSCAPE, landscapeStyle } from "styles/landscapeStyle";
import { responsiveSize } from "styles/responsiveSize";

import { useNavigate, useParams, useSearchParams } from "react-router-dom";
import { useAccount } from "wagmi";
import { Tabs as TabsComponent } from "@kleros/ui-components-library";

import { isUndefined } from "utils/index";
import { decodeURIFilter, useRootPath } from "utils/uri";
import { DisputeDetailsFragment, useMyCasesQuery } from "queries/useCasesQuery";
import { useUserQuery } from "queries/useUser";
import { OrderDirection } from "src/graphql/graphql";
import CasesDisplay from "components/CasesDisplay";
import PnkIcon from "svgs/icons/pnk.svg";
import DocIcon from "svgs/icons/doc.svg";
import VotedIcon from "svgs/icons/voted-ballot.svg";

import ConnectWallet from "components/ConnectWallet";
import FavoriteCases from "components/FavoriteCases";
import ScrollTop from "components/ScrollTop";
import JurorInfo from "./JurorInfo";
import JurorCard from "./JurorCard";
import Stakes from "./Stakes";
import Cases from "./Cases";
import Votes from "./Votes";

const Container = styled.div`
width: 100%;
Expand All @@ -34,17 +32,17 @@ const Container = styled.div`
)}
`;

const StyledCasesDisplay = styled(CasesDisplay)`
margin-top: ${responsiveSize(24, 32)};
.title {
margin-bottom: ${responsiveSize(12, 24)};
}
`;

const StyledTabs = styled(TabsComponent)`
width: 100%;
margin-top: ${responsiveSize(16, 32)};
> * {
display: flex;
flex-wrap: wrap;
font-size: ${responsiveSize(14, 16)};
> svg {
margin-right: 8px !important;
}
}
`;

const ConnectWalletContainer = styled.div`
Expand All @@ -56,60 +54,51 @@ const ConnectWalletContainer = styled.div`
`;

const TABS = [
{ text: "Stakes", value: 0 },
{ text: "Cases", value: 1 },
{ text: "Votes", value: 2 },
{ text: "Stakes", value: 0, Icon: PnkIcon, path: "stakes" },
{ text: "Cases", value: 1, Icon: DocIcon, path: "cases/1/desc/all" },
{ text: "Votes", value: 2, Icon: VotedIcon, path: "votes" },
];

const getTabIndex = (currentPath: string) => {
return TABS.findIndex((tab) => currentPath.includes(tab.path.split("/")[0]));
};

const Profile: React.FC = () => {
const { isConnected, address: connectedAddress } = useAccount();
const { page, order, filter } = useParams();
const [searchParams] = useSearchParams();
const location = useRootPath();
const { pathname } = useLocation();
const navigate = useNavigate();
const searchParamAddress = searchParams.get("address")?.toLowerCase();
const addressToQuery = searchParamAddress || connectedAddress?.toLowerCase();
const casesPerPage = 3;
const pageNumber = parseInt(page ?? "1");
const disputeSkip = casesPerPage * (pageNumber - 1);
const decodedFilter = decodeURIFilter(filter ?? "all");
const { data: disputesData } = useMyCasesQuery(
addressToQuery,
disputeSkip,
decodedFilter,
order === "asc" ? OrderDirection.Asc : OrderDirection.Desc
);
const { data: userData } = useUserQuery(addressToQuery, decodedFilter);
const totalCases = userData?.user?.disputes.length;
const totalResolvedCases = parseInt(userData?.user?.totalResolvedDisputes);
const totalPages = useMemo(
() => (!isUndefined(totalCases) ? Math.ceil(totalCases / casesPerPage) : 1),
[totalCases, casesPerPage]
);
const [currentTab, setCurrentTab] = useState(0);

const handleTabChange = (tabIndex: number) => {
const selectedTab = TABS[tabIndex];
const basePath = `/profile/${selectedTab.path}`;
const queryParam = searchParamAddress ? `?address=${searchParamAddress}` : "";
navigate(`${basePath}${queryParam}`);
};

return (
<Container>
{isConnected || searchParamAddress ? (
<>
<JurorInfo {...{ addressToQuery }} />
<StyledTabs currentValue={currentTab} items={TABS} callback={(n) => setCurrentTab(n)} />
{currentTab === 0 && <Stakes {...{ addressToQuery }} />}
{currentTab === 1 && (
<StyledCasesDisplay
title="Cases Drawn"
disputes={userData?.user !== null ? (disputesData?.user?.disputes as DisputeDetailsFragment[]) : []}
numberDisputes={totalCases}
numberClosedDisputes={totalResolvedCases}
totalPages={totalPages}
currentPage={pageNumber}
setCurrentPage={(newPage: number) =>
navigate(`${location}/${newPage}/${order}/${filter}?${searchParams.toString()}`)
<JurorCard {...{ addressToQuery }} />
<StyledTabs
currentValue={getTabIndex(pathname)}
items={TABS}
callback={(tabIndex: number) => handleTabChange(tabIndex)}
/>
<Routes>
<Route path="stakes" element={<Stakes {...{ addressToQuery }} />} />
<Route path="cases/:page/:order/:filter" element={<Cases {...{ addressToQuery }} />} />
<Route path="votes" element={<Votes />} />
<Route
path="*"
element={
<Navigate to={`${searchParamAddress ? `stakes?address=${searchParamAddress}` : "stakes"}`} replace />
}
{...{ casesPerPage }}
/>
)}
{currentTab === 2 && null}
</Routes>
</>
) : (
<ConnectWalletContainer>
Expand Down

0 comments on commit c3213ca

Please sign in to comment.