From 45bc1fb8658e48914b28e2c94822f8fd9e629f46 Mon Sep 17 00:00:00 2001 From: kemuru <102478601+kemuru@users.noreply.github.com> Date: Fri, 31 Jan 2025 19:29:54 +0100 Subject: [PATCH 1/3] feat: setup new profile page structure, new juror card style, add tabs, style tweaks, refactors --- .../JurorLink.tsx} | 26 +++++-- .../Popup/MiniGuides/JurorLevels.tsx | 4 +- .../Voting/VotesDetails/AccordionTitle.tsx | 4 +- .../Home/TopJurors/JurorCard/DesktopCard.tsx | 4 +- .../Home/TopJurors/JurorCard/JurorLevel.tsx | 2 +- .../Home/TopJurors/JurorCard/MobileCard.tsx | 4 +- .../{ => BottomContent}/Coherence.tsx | 9 ++- .../{ => BottomContent}/JurorRewards.tsx | 31 ++++++--- .../{ => BottomContent}/PixelArt.tsx | 9 ++- .../Profile/JurorInfo/BottomContent/index.tsx | 69 +++++++++++++++++++ web/src/pages/Profile/JurorInfo/Header.tsx | 25 +------ .../Profile/JurorInfo/StakingRewards.tsx | 29 +++++--- .../Profile/JurorInfo/TopContent/index.tsx | 35 ++++++++++ web/src/pages/Profile/JurorInfo/index.tsx | 25 +++---- .../CourtCard/CourtName.tsx | 0 .../{Courts => Stakes}/CourtCard/Stake.tsx | 0 .../{Courts => Stakes}/CourtCard/index.tsx | 0 .../Profile/{Courts => Stakes}/Header.tsx | 5 +- .../Profile/{Courts => Stakes}/index.tsx | 15 ++-- web/src/pages/Profile/index.tsx | 50 +++++++++----- web/src/utils/userLevelCalculation.ts | 2 +- 21 files changed, 235 insertions(+), 113 deletions(-) rename web/src/{pages/Home/TopJurors/JurorCard/JurorTitle.tsx => components/JurorLink.tsx} (61%) rename web/src/pages/Profile/JurorInfo/{ => BottomContent}/Coherence.tsx (94%) rename web/src/pages/Profile/JurorInfo/{ => BottomContent}/JurorRewards.tsx (67%) rename web/src/pages/Profile/JurorInfo/{ => BottomContent}/PixelArt.tsx (93%) create mode 100644 web/src/pages/Profile/JurorInfo/BottomContent/index.tsx create mode 100644 web/src/pages/Profile/JurorInfo/TopContent/index.tsx rename web/src/pages/Profile/{Courts => Stakes}/CourtCard/CourtName.tsx (100%) rename web/src/pages/Profile/{Courts => Stakes}/CourtCard/Stake.tsx (100%) rename web/src/pages/Profile/{Courts => Stakes}/CourtCard/index.tsx (100%) rename web/src/pages/Profile/{Courts => Stakes}/Header.tsx (86%) rename web/src/pages/Profile/{Courts => Stakes}/index.tsx (78%) diff --git a/web/src/pages/Home/TopJurors/JurorCard/JurorTitle.tsx b/web/src/components/JurorLink.tsx similarity index 61% rename from web/src/pages/Home/TopJurors/JurorCard/JurorTitle.tsx rename to web/src/components/JurorLink.tsx index 437aea26a..212c5605b 100644 --- a/web/src/pages/Home/TopJurors/JurorCard/JurorTitle.tsx +++ b/web/src/components/JurorLink.tsx @@ -1,11 +1,15 @@ -import React from "react"; +import React, { useMemo } from "react"; import styled from "styled-components"; +import { useAccount } from "wagmi"; + +import { DEFAULT_CHAIN, getChain } from "consts/chains"; + import ArrowIcon from "svgs/icons/arrow.svg"; +import NewTabIcon from "svgs/icons/new-tab.svg"; import { IdenticonOrAvatar, AddressOrName } from "components/ConnectWallet/AccountDisplay"; import { StyledArrowLink } from "components/StyledArrowLink"; -import { useAccount } from "wagmi"; const Container = styled.div` display: flex; @@ -36,26 +40,34 @@ export const ReStyledArrowLink = styled(StyledArrowLink)` } `; -interface IJurorTitle { +interface IJurorLink { address: string; + isInternalLink?: boolean; } -const JurorTitle: React.FC = ({ address }) => { +const JurorLink: React.FC = ({ 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}`; + const addressExplorerLink = useMemo(() => { + return `${getChain(DEFAULT_CHAIN)?.blockExplorers?.default.url}/address/${address}`; + }, [address]); return ( - + - + {isInternalLink ? : } ); }; -export default JurorTitle; +export default JurorLink; diff --git a/web/src/components/Popup/MiniGuides/JurorLevels.tsx b/web/src/components/Popup/MiniGuides/JurorLevels.tsx index b8043e26f..8dc0b0ede 100644 --- a/web/src/components/Popup/MiniGuides/JurorLevels.tsx +++ b/web/src/components/Popup/MiniGuides/JurorLevels.tsx @@ -5,8 +5,8 @@ import { Card as _Card } from "@kleros/ui-components-library"; import { landscapeStyle } from "styles/landscapeStyle"; -import Coherence from "pages/Profile/JurorInfo/Coherence"; -import PixelArt from "pages/Profile/JurorInfo/PixelArt"; +import Coherence from "pages/Profile/JurorInfo/BottomContent/Coherence"; +import PixelArt from "pages/Profile/JurorInfo/BottomContent/PixelArt"; import Template from "./MainStructureTemplate"; import { Title, ParagraphsContainer, LeftContentContainer } from "./PageContentsTemplate"; diff --git a/web/src/pages/Cases/CaseDetails/Voting/VotesDetails/AccordionTitle.tsx b/web/src/pages/Cases/CaseDetails/Voting/VotesDetails/AccordionTitle.tsx index 6c208351c..bc48524c8 100644 --- a/web/src/pages/Cases/CaseDetails/Voting/VotesDetails/AccordionTitle.tsx +++ b/web/src/pages/Cases/CaseDetails/Voting/VotesDetails/AccordionTitle.tsx @@ -8,7 +8,7 @@ import { getVoteChoice } from "utils/getVoteChoice"; import { isUndefined } from "utils/index"; import { InternalLink } from "components/InternalLink"; -import JurorTitle from "pages/Home/TopJurors/JurorCard/JurorTitle"; +import JurorLink from "components/JurorLink"; const TitleContainer = styled.div` display: flex; @@ -92,7 +92,7 @@ const AccordionTitle: React.FC<{ - + diff --git a/web/src/pages/Home/TopJurors/JurorCard/DesktopCard.tsx b/web/src/pages/Home/TopJurors/JurorCard/DesktopCard.tsx index 1538dcd67..e6a843201 100644 --- a/web/src/pages/Home/TopJurors/JurorCard/DesktopCard.tsx +++ b/web/src/pages/Home/TopJurors/JurorCard/DesktopCard.tsx @@ -7,9 +7,9 @@ import { hoverShortTransitionTiming } from "styles/commonStyles"; import Coherence from "./Coherence"; import JurorLevel from "./JurorLevel"; -import JurorTitle from "./JurorTitle"; import Rank from "./Rank"; import Rewards from "./Rewards"; +import JurorLink from "components/JurorLink"; const Container = styled.div<{ renderRank?: boolean }>` ${hoverShortTransitionTiming} @@ -57,7 +57,7 @@ const DesktopCard: React.FC = ({ return ( {renderRank && } - + diff --git a/web/src/pages/Home/TopJurors/JurorCard/JurorLevel.tsx b/web/src/pages/Home/TopJurors/JurorCard/JurorLevel.tsx index eba34f350..3a0b114fb 100644 --- a/web/src/pages/Home/TopJurors/JurorCard/JurorLevel.tsx +++ b/web/src/pages/Home/TopJurors/JurorCard/JurorLevel.tsx @@ -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/PixelArt"; +import PixelArt from "pages/Profile/JurorInfo/BottomContent/PixelArt"; const Container = styled.div` display: flex; diff --git a/web/src/pages/Home/TopJurors/JurorCard/MobileCard.tsx b/web/src/pages/Home/TopJurors/JurorCard/MobileCard.tsx index faffb821a..5118670a6 100644 --- a/web/src/pages/Home/TopJurors/JurorCard/MobileCard.tsx +++ b/web/src/pages/Home/TopJurors/JurorCard/MobileCard.tsx @@ -9,9 +9,9 @@ import HeaderRewards from "../Header/Rewards"; import Coherence from "./Coherence"; import JurorLevel from "./JurorLevel"; -import JurorTitle from "./JurorTitle"; import Rank from "./Rank"; import Rewards from "./Rewards"; +import JurorLink from "components/JurorLink"; const Container = styled.div` ${hoverShortTransitionTiming} @@ -97,7 +97,7 @@ const MobileCard: React.FC = ({ {rank ? : null} - + diff --git a/web/src/pages/Profile/JurorInfo/Coherence.tsx b/web/src/pages/Profile/JurorInfo/BottomContent/Coherence.tsx similarity index 94% rename from web/src/pages/Profile/JurorInfo/Coherence.tsx rename to web/src/pages/Profile/JurorInfo/BottomContent/Coherence.tsx index 712884d22..44e1f9786 100644 --- a/web/src/pages/Profile/JurorInfo/Coherence.tsx +++ b/web/src/pages/Profile/JurorInfo/BottomContent/Coherence.tsx @@ -1,9 +1,11 @@ import React from "react"; import styled, { css } from "styled-components"; +import { landscapeStyle } from "styles/landscapeStyle"; + import { CircularProgress } from "@kleros/ui-components-library"; -import { landscapeStyle } from "styles/landscapeStyle"; +import { ILevelCriteria } from "utils/userLevelCalculation"; import WithHelpTooltip from "components/WithHelpTooltip"; @@ -26,10 +28,7 @@ const tooltipMsg = " the majority of jurors it's considered a Coherent Vote."; interface ICoherence { - userLevelData: { - level: number; - title: string; - }; + userLevelData: ILevelCriteria; totalCoherentVotes: number; totalResolvedVotes: number; isMiniGuide: boolean; diff --git a/web/src/pages/Profile/JurorInfo/JurorRewards.tsx b/web/src/pages/Profile/JurorInfo/BottomContent/JurorRewards.tsx similarity index 67% rename from web/src/pages/Profile/JurorInfo/JurorRewards.tsx rename to web/src/pages/Profile/JurorInfo/BottomContent/JurorRewards.tsx index 0a4471252..96ee2f4a7 100644 --- a/web/src/pages/Profile/JurorInfo/JurorRewards.tsx +++ b/web/src/pages/Profile/JurorInfo/BottomContent/JurorRewards.tsx @@ -1,7 +1,7 @@ import React from "react"; -import styled from "styled-components"; +import styled, { css } from "styled-components"; -import { useAccount } from "wagmi"; +import { landscapeStyle } from "styles/landscapeStyle"; import { CoinIds } from "consts/coingecko"; import { useCoinPrice } from "hooks/useCoinPrice"; @@ -10,14 +10,27 @@ import { getFormattedRewards } from "utils/jurorRewardConfig"; import { useUserQuery } from "queries/useUser"; import WithHelpTooltip from "components/WithHelpTooltip"; - -import TokenRewards from "./TokenRewards"; +import TokenRewards from "../TokenRewards"; const Container = styled.div` display: flex; flex-direction: column; - align-items: flex-start; + align-items: center; width: auto; + gap: 24px; + + ${landscapeStyle( + () => css` + align-items: flex-start; + ` + )} +`; + +const TokenRewardsContainer = styled.div` + display: flex; + flex-direction: column; + align-items: start; + gap: 16px; `; const tooltipMsg = @@ -42,9 +55,11 @@ const JurorRewards: React.FC = ({ addressToQuery }) => { - {formattedRewards.map(({ token, amount, value }) => ( - - ))} + + {formattedRewards.map(({ token, amount, value }) => ( + + ))} + ); }; diff --git a/web/src/pages/Profile/JurorInfo/PixelArt.tsx b/web/src/pages/Profile/JurorInfo/BottomContent/PixelArt.tsx similarity index 93% rename from web/src/pages/Profile/JurorInfo/PixelArt.tsx rename to web/src/pages/Profile/JurorInfo/BottomContent/PixelArt.tsx index 48e15dd93..59a909a82 100644 --- a/web/src/pages/Profile/JurorInfo/PixelArt.tsx +++ b/web/src/pages/Profile/JurorInfo/BottomContent/PixelArt.tsx @@ -9,6 +9,11 @@ import platoImage from "assets/pngs/dashboard/plato.png"; import pythagorasImage from "assets/pngs/dashboard/pythagoras.png"; import socratesImage from "assets/pngs/dashboard/socrates.png"; +const Container = styled.div` + display: flex; + justify-content: center; +`; + interface IStyledImage { show: boolean; width: number | string; @@ -42,7 +47,7 @@ interface IPixelArt { const PixelArt: React.FC = ({ level, width, height }) => { const [imageLoaded, setImageLoaded] = useState(false); return ( -
+ {!imageLoaded && } = ({ level, width, height }) => { width={width} height={height} /> -
+ ); }; diff --git a/web/src/pages/Profile/JurorInfo/BottomContent/index.tsx b/web/src/pages/Profile/JurorInfo/BottomContent/index.tsx new file mode 100644 index 000000000..4d49c13e9 --- /dev/null +++ b/web/src/pages/Profile/JurorInfo/BottomContent/index.tsx @@ -0,0 +1,69 @@ +import React from "react"; +import styled, { css } from "styled-components"; + +import { landscapeStyle } from "styles/landscapeStyle"; + +import { ILevelCriteria } from "utils/userLevelCalculation"; + +import PixelArt from "./PixelArt"; +import Coherence from "./Coherence"; +import JurorRewards from "./JurorRewards"; +import StakingRewards from "../StakingRewards"; + +const Container = styled.div` + display: flex; + flex-direction: column; + flex-wrap: wrap; + justify-content: space-between; + align-items: center; + + gap: 32px; + width: 100%; + height: auto; + + ${landscapeStyle( + () => css` + flex-direction: row; + align-items: flex-start; + ` + )} +`; + +const LeftContent = styled.div` + display: flex; + flex-direction: row; + gap: 48px; + flex-direction: column; + + ${landscapeStyle( + () => css` + flex-direction: row; + ` + )} +`; + +interface IBottomContent { + userLevelData: ILevelCriteria; + totalCoherentVotes: number; + totalResolvedVotes: number; + addressToQuery: `0x${string}`; +} + +const BottomContent: React.FC = ({ + userLevelData, + totalCoherentVotes, + totalResolvedVotes, + addressToQuery, +}) => { + return ( + + + + + + + + + ); +}; +export default BottomContent; diff --git a/web/src/pages/Profile/JurorInfo/Header.tsx b/web/src/pages/Profile/JurorInfo/Header.tsx index 8e90df5b6..13c4e88be 100644 --- a/web/src/pages/Profile/JurorInfo/Header.tsx +++ b/web/src/pages/Profile/JurorInfo/Header.tsx @@ -1,17 +1,13 @@ -import React, { useMemo } from "react"; +import React from "react"; import styled from "styled-components"; import { responsiveSize } from "styles/responsiveSize"; import { useToggle } from "react-use"; import { useSearchParams } from "react-router-dom"; -import { Copiable } from "@kleros/ui-components-library"; import XIcon from "svgs/socialmedia/x.svg"; -import { DEFAULT_CHAIN, getChain } from "consts/chains"; -import { shortenAddress } from "utils/shortenAddress"; - import HowItWorks from "components/HowItWorks"; import JurorLevels from "components/Popup/MiniGuides/JurorLevels"; import { ExternalLink } from "components/ExternalLink"; @@ -51,12 +47,6 @@ const StyledLink = styled(ExternalLink)` gap: 8px; `; -const StyledExternalLink = styled(ExternalLink)` - font-size: ${responsiveSize(18, 22)}; - margin-left: ${responsiveSize(4, 8)}; - font-weight: 600; -`; - interface IHeader { levelTitle: string; levelNumber: number; @@ -81,20 +71,9 @@ const Header: React.FC = ({ const xShareUrl = `https://twitter.com/intent/tweet?text=${encodeURIComponent(xPostText)}`; const searchParamAddress = searchParams.get("address")?.toLowerCase(); - const addressExplorerLink = useMemo(() => { - return `${getChain(DEFAULT_CHAIN)?.blockExplorers?.default.url}/address/${addressToQuery}`; - }, [addressToQuery]); - return ( - - Juror Profile - - - - {shortenAddress(addressToQuery)} - - - + Juror Profile { const tooltipMsg = "Staking Rewards are the rewards won by staking your PNK on a court during " + - "the Kleros' Jurors incentive program."; + "the Kleros' Jurors incentive program. This will start as soon as the " + + "corresponding KIP (Kleros Improvement Proposal) goes into effect."; -const Coherence: React.FC = () => { +const StakingRewards: React.FC = () => { return ( + // + // + // + // Coming soon + // + // + // + // - + - - + ); }; -export default Coherence; +export default StakingRewards; diff --git a/web/src/pages/Profile/JurorInfo/TopContent/index.tsx b/web/src/pages/Profile/JurorInfo/TopContent/index.tsx new file mode 100644 index 000000000..d917ff537 --- /dev/null +++ b/web/src/pages/Profile/JurorInfo/TopContent/index.tsx @@ -0,0 +1,35 @@ +import React from "react"; +import styled from "styled-components"; + +import JurorLink from "components/JurorLink"; + +const Container = styled.div` + display: flex; + flex-direction: row + align-items: center; + gap: 16px 24px; + flex-wrap: wrap; +`; + +const StyledLabel = styled.label` + font-size: 14px; +`; + +interface ITopContent { + address: `0x${string}`; + totalResolvedDisputes: number; +} + +const TopContent: React.FC = ({ address, totalResolvedDisputes }) => { + return ( + + + {totalResolvedDisputes > 0 ? ( + + Juror in {totalResolvedDisputes} {totalResolvedDisputes === 1 ? "case" : "cases"} + + ) : null} + + ); +}; +export default TopContent; diff --git a/web/src/pages/Profile/JurorInfo/index.tsx b/web/src/pages/Profile/JurorInfo/index.tsx index f85122738..193d61d8c 100644 --- a/web/src/pages/Profile/JurorInfo/index.tsx +++ b/web/src/pages/Profile/JurorInfo/index.tsx @@ -11,31 +11,22 @@ import { useUserQuery } from "queries/useUser"; import { landscapeStyle } from "styles/landscapeStyle"; import { responsiveSize } from "styles/responsiveSize"; -import Coherence from "./Coherence"; import Header from "./Header"; -import JurorRewards from "./JurorRewards"; -import PixelArt from "./PixelArt"; +import BottomContent from "./BottomContent"; +import { Divider } from "components/Divider"; +import TopContent from "./TopContent"; const Container = styled.div``; const Card = styled(_Card)` display: flex; flex-direction: column; - align-items: center; justify-content: center; - gap: 40px; + gap: 24px; width: 100%; height: auto; - padding: 24px 0; - - ${landscapeStyle( - () => css` - flex-direction: row; - gap: ${responsiveSize(24, 64)}; - height: 236px; - ` - )} + padding: 24px; `; interface IJurorInfo { @@ -58,9 +49,9 @@ const JurorInfo: React.FC = ({ addressToQuery }) => { {...{ totalCoherentVotes, totalResolvedVotes, addressToQuery }} /> - - - + + + ); diff --git a/web/src/pages/Profile/Courts/CourtCard/CourtName.tsx b/web/src/pages/Profile/Stakes/CourtCard/CourtName.tsx similarity index 100% rename from web/src/pages/Profile/Courts/CourtCard/CourtName.tsx rename to web/src/pages/Profile/Stakes/CourtCard/CourtName.tsx diff --git a/web/src/pages/Profile/Courts/CourtCard/Stake.tsx b/web/src/pages/Profile/Stakes/CourtCard/Stake.tsx similarity index 100% rename from web/src/pages/Profile/Courts/CourtCard/Stake.tsx rename to web/src/pages/Profile/Stakes/CourtCard/Stake.tsx diff --git a/web/src/pages/Profile/Courts/CourtCard/index.tsx b/web/src/pages/Profile/Stakes/CourtCard/index.tsx similarity index 100% rename from web/src/pages/Profile/Courts/CourtCard/index.tsx rename to web/src/pages/Profile/Stakes/CourtCard/index.tsx diff --git a/web/src/pages/Profile/Courts/Header.tsx b/web/src/pages/Profile/Stakes/Header.tsx similarity index 86% rename from web/src/pages/Profile/Courts/Header.tsx rename to web/src/pages/Profile/Stakes/Header.tsx index 07f61e11c..93c7f3dd9 100644 --- a/web/src/pages/Profile/Courts/Header.tsx +++ b/web/src/pages/Profile/Stakes/Header.tsx @@ -2,7 +2,6 @@ import React from "react"; import styled, { css } from "styled-components"; import { formatUnits } from "viem"; -import { useSearchParams } from "react-router-dom"; import LockerIcon from "svgs/icons/locker.svg"; @@ -58,12 +57,10 @@ interface IHeader { const Header: React.FC = ({ lockedStake }) => { const formattedLockedStake = !isUndefined(lockedStake) && formatUnits(lockedStake, 18); - const [searchParams] = useSearchParams(); - const searchParamAddress = searchParams.get("address")?.toLowerCase(); return ( - {searchParamAddress ? "Their" : "My"} Courts + Stakes {!isUndefined(lockedStake) ? ( diff --git a/web/src/pages/Profile/Courts/index.tsx b/web/src/pages/Profile/Stakes/index.tsx similarity index 78% rename from web/src/pages/Profile/Courts/index.tsx rename to web/src/pages/Profile/Stakes/index.tsx index 512478b1d..858d1cabf 100644 --- a/web/src/pages/Profile/Courts/index.tsx +++ b/web/src/pages/Profile/Stakes/index.tsx @@ -2,7 +2,6 @@ import React from "react"; import styled, { css } from "styled-components"; import Skeleton from "react-loading-skeleton"; -import { useSearchParams } from "react-router-dom"; import { useReadSortitionModuleGetJurorBalance } from "hooks/contracts/generated"; @@ -15,7 +14,7 @@ import CourtCard from "./CourtCard"; import Header from "./Header"; const Container = styled.div` - margin-top: ${responsiveSize(24, 48)}; + margin-top: ${responsiveSize(24, 32)}; `; const CourtCardsContainer = styled.div` @@ -35,17 +34,15 @@ const StyledLabel = styled.label` font-size: ${responsiveSize(14, 16)}; `; -interface ICourts { +interface IStakes { addressToQuery: `0x${string}`; } -const Courts: React.FC = ({ addressToQuery }) => { +const Stakes: React.FC = ({ addressToQuery }) => { const { data: stakeData, isLoading } = useJurorStakeDetailsQuery(addressToQuery); const { data: jurorBalance } = useReadSortitionModuleGetJurorBalance({ args: [addressToQuery, BigInt(1)], }); - const [searchParams] = useSearchParams(); - const searchParamAddress = searchParams.get("address")?.toLowerCase(); const stakedCourts = stakeData?.jurorTokensPerCourts?.filter(({ staked }) => staked > 0); const isStaked = stakedCourts && stakedCourts.length > 0; const lockedStake = jurorBalance?.[1]; @@ -54,9 +51,7 @@ const Courts: React.FC = ({ addressToQuery }) => {
{isLoading ? : null} - {!isStaked && !isLoading ? ( - {searchParamAddress ? "They" : "You"} are not staked in any court - ) : null} + {!isStaked && !isLoading ? No stakes found : null} {isStaked && !isLoading ? ( {stakeData?.jurorTokensPerCourts @@ -70,4 +65,4 @@ const Courts: React.FC = ({ addressToQuery }) => { ); }; -export default Courts; +export default Stakes; diff --git a/web/src/pages/Profile/index.tsx b/web/src/pages/Profile/index.tsx index 8a329a719..4a554684c 100644 --- a/web/src/pages/Profile/index.tsx +++ b/web/src/pages/Profile/index.tsx @@ -1,4 +1,4 @@ -import React, { useMemo } from "react"; +import React, { useState, useMemo } from "react"; import styled, { css } from "styled-components"; import { MAX_WIDTH_LANDSCAPE, landscapeStyle } from "styles/landscapeStyle"; @@ -6,19 +6,19 @@ 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 ConnectWallet from "components/ConnectWallet"; import FavoriteCases from "components/FavoriteCases"; import ScrollTop from "components/ScrollTop"; -import Courts from "./Courts"; import JurorInfo from "./JurorInfo"; +import Stakes from "./Stakes"; const Container = styled.div` width: 100%; @@ -35,13 +35,18 @@ const Container = styled.div` `; const StyledCasesDisplay = styled(CasesDisplay)` - margin-top: ${responsiveSize(24, 48)}; + margin-top: ${responsiveSize(24, 32)}; .title { margin-bottom: ${responsiveSize(12, 24)}; } `; +const StyledTabs = styled(TabsComponent)` + width: 100%; + margin-top: ${responsiveSize(16, 32)}; +`; + const ConnectWalletContainer = styled.div` display: flex; flex-direction: column; @@ -50,6 +55,12 @@ const ConnectWalletContainer = styled.div` color: ${({ theme }) => theme.primaryText}; `; +const TABS = [ + { text: "Stakes", value: 0 }, + { text: "Cases", value: 1 }, + { text: "Votes", value: 2 }, +]; + const Profile: React.FC = () => { const { isConnected, address: connectedAddress } = useAccount(); const { page, order, filter } = useParams(); @@ -75,25 +86,30 @@ const Profile: React.FC = () => { () => (!isUndefined(totalCases) ? Math.ceil(totalCases / casesPerPage) : 1), [totalCases, casesPerPage] ); + const [currentTab, setCurrentTab] = useState(0); return ( {isConnected || searchParamAddress ? ( <> - - - navigate(`${location}/${newPage}/${order}/${filter}?${searchParams.toString()}`) - } - {...{ casesPerPage }} - /> + setCurrentTab(n)} /> + {currentTab === 0 && } + {currentTab === 1 && ( + + navigate(`${location}/${newPage}/${order}/${filter}?${searchParams.toString()}`) + } + {...{ casesPerPage }} + /> + )} + {currentTab === 2 && null} ) : ( diff --git a/web/src/utils/userLevelCalculation.ts b/web/src/utils/userLevelCalculation.ts index 52d504256..60dc56b02 100644 --- a/web/src/utils/userLevelCalculation.ts +++ b/web/src/utils/userLevelCalculation.ts @@ -1,4 +1,4 @@ -interface ILevelCriteria { +export interface ILevelCriteria { level: number; title: string; minDisputes: number; From c3213ca635f27f9f2fbc270937a6990bd26f58c6 Mon Sep 17 00:00:00 2001 From: kemuru <102478601+kemuru@users.noreply.github.com> Date: Sat, 1 Feb 2025 02:44:17 +0100 Subject: [PATCH 2/3] feat: url path tab logic, refactors, add voted ballot svg, add icons to tabs --- web/src/app.tsx | 2 +- web/src/assets/svgs/icons/voted-ballot.svg | 5 + web/src/components/EvidenceCard.tsx | 2 +- web/src/components/JurorLink.tsx | 4 +- .../Popup/MiniGuides/JurorLevels.tsx | 4 +- .../Settings/General/WalletAndProfile.tsx | 2 +- .../Voting/VotesDetails/AccordionTitle.tsx | 2 +- .../Home/TopJurors/JurorCard/JurorLevel.tsx | 2 +- web/src/pages/Jurors/index.tsx | 2 +- web/src/pages/Profile/Cases/index.tsx | 68 +++++++++++ .../BottomContent/Coherence.tsx | 0 .../BottomContent/JurorRewards.tsx | 3 +- .../BottomContent/PixelArt.tsx | 0 .../BottomContent/index.tsx | 0 .../{JurorInfo => JurorCard}/Header.tsx | 0 .../StakingRewards.tsx | 0 .../{JurorInfo => JurorCard}/TokenRewards.tsx | 0 .../TopContent/index.tsx | 0 .../{JurorInfo => JurorCard}/index.tsx | 11 +- web/src/pages/Profile/Stakes/index.tsx | 2 +- web/src/pages/Profile/Votes/index.tsx | 8 ++ web/src/pages/Profile/index.tsx | 107 ++++++++---------- 22 files changed, 146 insertions(+), 78 deletions(-) create mode 100644 web/src/assets/svgs/icons/voted-ballot.svg create mode 100644 web/src/pages/Profile/Cases/index.tsx rename web/src/pages/Profile/{JurorInfo => JurorCard}/BottomContent/Coherence.tsx (100%) rename web/src/pages/Profile/{JurorInfo => JurorCard}/BottomContent/JurorRewards.tsx (98%) rename web/src/pages/Profile/{JurorInfo => JurorCard}/BottomContent/PixelArt.tsx (100%) rename web/src/pages/Profile/{JurorInfo => JurorCard}/BottomContent/index.tsx (100%) rename web/src/pages/Profile/{JurorInfo => JurorCard}/Header.tsx (100%) rename web/src/pages/Profile/{JurorInfo => JurorCard}/StakingRewards.tsx (100%) rename web/src/pages/Profile/{JurorInfo => JurorCard}/TokenRewards.tsx (100%) rename web/src/pages/Profile/{JurorInfo => JurorCard}/TopContent/index.tsx (100%) rename web/src/pages/Profile/{JurorInfo => JurorCard}/index.tsx (85%) create mode 100644 web/src/pages/Profile/Votes/index.tsx diff --git a/web/src/app.tsx b/web/src/app.tsx index 7fc3b8af8..b3f29e38d 100644 --- a/web/src/app.tsx +++ b/web/src/app.tsx @@ -73,7 +73,7 @@ const App: React.FC = () => { } /> }> diff --git a/web/src/assets/svgs/icons/voted-ballot.svg b/web/src/assets/svgs/icons/voted-ballot.svg new file mode 100644 index 000000000..3b9bb7c04 --- /dev/null +++ b/web/src/assets/svgs/icons/voted-ballot.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/web/src/components/EvidenceCard.tsx b/web/src/components/EvidenceCard.tsx index 07c4bb955..43e0e1d4b 100644 --- a/web/src/components/EvidenceCard.tsx +++ b/web/src/components/EvidenceCard.tsx @@ -223,7 +223,7 @@ const EvidenceCard: React.FC = ({ description, fileURI, }) => { - const profileLink = `/profile/1/desc/all?address=${sender}`; + const profileLink = `/profile/stakes?address=${sender}`; const transactionExplorerLink = useMemo(() => { return getTxnExplorerLink(transactionHash ?? ""); diff --git a/web/src/components/JurorLink.tsx b/web/src/components/JurorLink.tsx index 212c5605b..cbb5e192a 100644 --- a/web/src/components/JurorLink.tsx +++ b/web/src/components/JurorLink.tsx @@ -49,8 +49,8 @@ const JurorLink: React.FC = ({ 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]); diff --git a/web/src/components/Popup/MiniGuides/JurorLevels.tsx b/web/src/components/Popup/MiniGuides/JurorLevels.tsx index 8dc0b0ede..c28de3cb1 100644 --- a/web/src/components/Popup/MiniGuides/JurorLevels.tsx +++ b/web/src/components/Popup/MiniGuides/JurorLevels.tsx @@ -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"; diff --git a/web/src/layout/Header/navbar/Menu/Settings/General/WalletAndProfile.tsx b/web/src/layout/Header/navbar/Menu/Settings/General/WalletAndProfile.tsx index 57931035c..16d9fe1f6 100644 --- a/web/src/layout/Header/navbar/Menu/Settings/General/WalletAndProfile.tsx +++ b/web/src/layout/Header/navbar/Menu/Settings/General/WalletAndProfile.tsx @@ -52,7 +52,7 @@ const WalletAndProfile: React.FC = ({ toggleIsSettingsOpen }) => { - + My Profile diff --git a/web/src/pages/Cases/CaseDetails/Voting/VotesDetails/AccordionTitle.tsx b/web/src/pages/Cases/CaseDetails/Voting/VotesDetails/AccordionTitle.tsx index bc48524c8..185e87e33 100644 --- a/web/src/pages/Cases/CaseDetails/Voting/VotesDetails/AccordionTitle.tsx +++ b/web/src/pages/Cases/CaseDetails/Voting/VotesDetails/AccordionTitle.tsx @@ -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 ( diff --git a/web/src/pages/Home/TopJurors/JurorCard/JurorLevel.tsx b/web/src/pages/Home/TopJurors/JurorCard/JurorLevel.tsx index 3a0b114fb..4dd0d9b9f 100644 --- a/web/src/pages/Home/TopJurors/JurorCard/JurorLevel.tsx +++ b/web/src/pages/Home/TopJurors/JurorCard/JurorLevel.tsx @@ -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; diff --git a/web/src/pages/Jurors/index.tsx b/web/src/pages/Jurors/index.tsx index 2d7666521..ff021af90 100644 --- a/web/src/pages/Jurors/index.tsx +++ b/web/src/pages/Jurors/index.tsx @@ -55,7 +55,7 @@ const Jurors: React.FC = () => {
Jurors Leaderboard {isConnected ? ( - + My Profile ) : null} diff --git a/web/src/pages/Profile/Cases/index.tsx b/web/src/pages/Profile/Cases/index.tsx new file mode 100644 index 000000000..296d47c19 --- /dev/null +++ b/web/src/pages/Profile/Cases/index.tsx @@ -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 = ({ 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 ( + + navigate(`${location}/${newPage}/${order}/${filter}?${searchParams.toString()}`) + } + {...{ casesPerPage }} + /> + ); +}; + +export default Cases; diff --git a/web/src/pages/Profile/JurorInfo/BottomContent/Coherence.tsx b/web/src/pages/Profile/JurorCard/BottomContent/Coherence.tsx similarity index 100% rename from web/src/pages/Profile/JurorInfo/BottomContent/Coherence.tsx rename to web/src/pages/Profile/JurorCard/BottomContent/Coherence.tsx diff --git a/web/src/pages/Profile/JurorInfo/BottomContent/JurorRewards.tsx b/web/src/pages/Profile/JurorCard/BottomContent/JurorRewards.tsx similarity index 98% rename from web/src/pages/Profile/JurorInfo/BottomContent/JurorRewards.tsx rename to web/src/pages/Profile/JurorCard/BottomContent/JurorRewards.tsx index 96ee2f4a7..23261df92 100644 --- a/web/src/pages/Profile/JurorInfo/BottomContent/JurorRewards.tsx +++ b/web/src/pages/Profile/JurorCard/BottomContent/JurorRewards.tsx @@ -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; ` )} `; diff --git a/web/src/pages/Profile/JurorInfo/BottomContent/PixelArt.tsx b/web/src/pages/Profile/JurorCard/BottomContent/PixelArt.tsx similarity index 100% rename from web/src/pages/Profile/JurorInfo/BottomContent/PixelArt.tsx rename to web/src/pages/Profile/JurorCard/BottomContent/PixelArt.tsx diff --git a/web/src/pages/Profile/JurorInfo/BottomContent/index.tsx b/web/src/pages/Profile/JurorCard/BottomContent/index.tsx similarity index 100% rename from web/src/pages/Profile/JurorInfo/BottomContent/index.tsx rename to web/src/pages/Profile/JurorCard/BottomContent/index.tsx diff --git a/web/src/pages/Profile/JurorInfo/Header.tsx b/web/src/pages/Profile/JurorCard/Header.tsx similarity index 100% rename from web/src/pages/Profile/JurorInfo/Header.tsx rename to web/src/pages/Profile/JurorCard/Header.tsx diff --git a/web/src/pages/Profile/JurorInfo/StakingRewards.tsx b/web/src/pages/Profile/JurorCard/StakingRewards.tsx similarity index 100% rename from web/src/pages/Profile/JurorInfo/StakingRewards.tsx rename to web/src/pages/Profile/JurorCard/StakingRewards.tsx diff --git a/web/src/pages/Profile/JurorInfo/TokenRewards.tsx b/web/src/pages/Profile/JurorCard/TokenRewards.tsx similarity index 100% rename from web/src/pages/Profile/JurorInfo/TokenRewards.tsx rename to web/src/pages/Profile/JurorCard/TokenRewards.tsx diff --git a/web/src/pages/Profile/JurorInfo/TopContent/index.tsx b/web/src/pages/Profile/JurorCard/TopContent/index.tsx similarity index 100% rename from web/src/pages/Profile/JurorInfo/TopContent/index.tsx rename to web/src/pages/Profile/JurorCard/TopContent/index.tsx diff --git a/web/src/pages/Profile/JurorInfo/index.tsx b/web/src/pages/Profile/JurorCard/index.tsx similarity index 85% rename from web/src/pages/Profile/JurorInfo/index.tsx rename to web/src/pages/Profile/JurorCard/index.tsx index 193d61d8c..7ba721bad 100644 --- a/web/src/pages/Profile/JurorInfo/index.tsx +++ b/web/src/pages/Profile/JurorCard/index.tsx @@ -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"; @@ -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"; @@ -29,11 +26,11 @@ const Card = styled(_Card)` padding: 24px; `; -interface IJurorInfo { +interface IJurorCard { addressToQuery: `0x${string}`; } -const JurorInfo: React.FC = ({ addressToQuery }) => { +const JurorCard: React.FC = ({ addressToQuery }) => { const { data } = useUserQuery(addressToQuery); const totalCoherentVotes = data?.user ? parseInt(data?.user?.totalCoherentVotes) : 0; const totalResolvedVotes = data?.user ? parseInt(data?.user?.totalResolvedVotes) : 0; @@ -57,4 +54,4 @@ const JurorInfo: React.FC = ({ addressToQuery }) => { ); }; -export default JurorInfo; +export default JurorCard; diff --git a/web/src/pages/Profile/Stakes/index.tsx b/web/src/pages/Profile/Stakes/index.tsx index 858d1cabf..5be1921f7 100644 --- a/web/src/pages/Profile/Stakes/index.tsx +++ b/web/src/pages/Profile/Stakes/index.tsx @@ -25,7 +25,7 @@ const CourtCardsContainer = styled.div` ${landscapeStyle( () => css` - gap: 16px; + gap: 8px; ` )} `; diff --git a/web/src/pages/Profile/Votes/index.tsx b/web/src/pages/Profile/Votes/index.tsx new file mode 100644 index 000000000..a93433eb2 --- /dev/null +++ b/web/src/pages/Profile/Votes/index.tsx @@ -0,0 +1,8 @@ +import React from "react"; + +interface IVotes {} + +const Votes: React.FC = () => { + return
; +}; +export default Votes; diff --git a/web/src/pages/Profile/index.tsx b/web/src/pages/Profile/index.tsx index 4a554684c..8e7fc37b7 100644 --- a/web/src/pages/Profile/index.tsx +++ b/web/src/pages/Profile/index.tsx @@ -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%; @@ -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` @@ -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 ( {isConnected || searchParamAddress ? ( <> - - setCurrentTab(n)} /> - {currentTab === 0 && } - {currentTab === 1 && ( - - navigate(`${location}/${newPage}/${order}/${filter}?${searchParams.toString()}`) + + handleTabChange(tabIndex)} + /> + + } /> + } /> + } /> + } - {...{ casesPerPage }} /> - )} - {currentTab === 2 && null} + ) : ( From f701d8fda9d796d2c0199c2b17691122f5ade91c Mon Sep 17 00:00:00 2001 From: kemuru <102478601+kemuru@users.noreply.github.com> Date: Sat, 1 Feb 2025 03:17:24 +0100 Subject: [PATCH 3/3] feat: add support for sharing your own profile, variable renaming --- web/src/pages/Profile/Cases/index.tsx | 8 +++---- .../JurorCard/BottomContent/JurorRewards.tsx | 6 +++--- .../Profile/JurorCard/BottomContent/index.tsx | 6 +++--- web/src/pages/Profile/JurorCard/Header.tsx | 8 ++----- web/src/pages/Profile/JurorCard/index.tsx | 12 +++++------ web/src/pages/Profile/Stakes/index.tsx | 8 +++---- web/src/pages/Profile/index.tsx | 21 ++++++++++++------- 7 files changed, 35 insertions(+), 34 deletions(-) diff --git a/web/src/pages/Profile/Cases/index.tsx b/web/src/pages/Profile/Cases/index.tsx index 296d47c19..52e40d495 100644 --- a/web/src/pages/Profile/Cases/index.tsx +++ b/web/src/pages/Profile/Cases/index.tsx @@ -21,10 +21,10 @@ const StyledCasesDisplay = styled(CasesDisplay)` `; interface ICases { - addressToQuery: `0x${string}`; + searchParamAddress: `0x${string}`; } -const Cases: React.FC = ({ addressToQuery }) => { +const Cases: React.FC = ({ searchParamAddress }) => { const { page, order, filter } = useParams(); const [searchParams] = useSearchParams(); const location = useRootPath(); @@ -35,13 +35,13 @@ const Cases: React.FC = ({ addressToQuery }) => { const disputeSkip = casesPerPage * (pageNumber - 1); const decodedFilter = decodeURIFilter(filter ?? "all"); const { data: disputesData } = useMyCasesQuery( - addressToQuery, + searchParamAddress, disputeSkip, decodedFilter, order === "asc" ? OrderDirection.Asc : OrderDirection.Desc ); - const { data: userData } = useUserQuery(addressToQuery, decodedFilter); + const { data: userData } = useUserQuery(searchParamAddress, decodedFilter); const totalCases = userData?.user?.disputes.length; const totalResolvedCases = parseInt(userData?.user?.totalResolvedDisputes); const totalPages = useMemo( diff --git a/web/src/pages/Profile/JurorCard/BottomContent/JurorRewards.tsx b/web/src/pages/Profile/JurorCard/BottomContent/JurorRewards.tsx index 23261df92..96adeab1f 100644 --- a/web/src/pages/Profile/JurorCard/BottomContent/JurorRewards.tsx +++ b/web/src/pages/Profile/JurorCard/BottomContent/JurorRewards.tsx @@ -41,11 +41,11 @@ const tooltipMsg = "arbitration fees (ETH) + PNK redistribution between jurors."; interface IJurorRewards { - addressToQuery: `0x${string}`; + searchParamAddress: `0x${string}`; } -const JurorRewards: React.FC = ({ addressToQuery }) => { - const { data } = useUserQuery(addressToQuery); +const JurorRewards: React.FC = ({ searchParamAddress }) => { + const { data } = useUserQuery(searchParamAddress); const coinIds = [CoinIds.PNK, CoinIds.ETH]; const { prices: pricesData } = useCoinPrice(coinIds); diff --git a/web/src/pages/Profile/JurorCard/BottomContent/index.tsx b/web/src/pages/Profile/JurorCard/BottomContent/index.tsx index 4d49c13e9..34749232b 100644 --- a/web/src/pages/Profile/JurorCard/BottomContent/index.tsx +++ b/web/src/pages/Profile/JurorCard/BottomContent/index.tsx @@ -46,21 +46,21 @@ interface IBottomContent { userLevelData: ILevelCriteria; totalCoherentVotes: number; totalResolvedVotes: number; - addressToQuery: `0x${string}`; + searchParamAddress: `0x${string}`; } const BottomContent: React.FC = ({ userLevelData, totalCoherentVotes, totalResolvedVotes, - addressToQuery, + searchParamAddress, }) => { return ( - + diff --git a/web/src/pages/Profile/JurorCard/Header.tsx b/web/src/pages/Profile/JurorCard/Header.tsx index 13c4e88be..fed750f01 100644 --- a/web/src/pages/Profile/JurorCard/Header.tsx +++ b/web/src/pages/Profile/JurorCard/Header.tsx @@ -4,7 +4,6 @@ import styled from "styled-components"; import { responsiveSize } from "styles/responsiveSize"; import { useToggle } from "react-use"; -import { useSearchParams } from "react-router-dom"; import XIcon from "svgs/socialmedia/x.svg"; @@ -52,7 +51,7 @@ interface IHeader { levelNumber: number; totalCoherentVotes: number; totalResolvedVotes: number; - addressToQuery: `0x${string}`; + searchParamAddress: `0x${string}`; } const Header: React.FC = ({ @@ -60,16 +59,13 @@ const Header: React.FC = ({ levelNumber, totalCoherentVotes, totalResolvedVotes, - addressToQuery, + searchParamAddress, }) => { const [isJurorLevelsMiniGuideOpen, toggleJurorLevelsMiniGuide] = useToggle(false); - const [searchParams] = useSearchParams(); - const coherencePercentage = parseFloat(((totalCoherentVotes / Math.max(totalResolvedVotes, 1)) * 100).toFixed(2)); const courtUrl = window.location.origin; 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: ${totalCoherentVotes}/${totalResolvedVotes}\n\nBe a juror with me! ➡️ ${courtUrl}`; const xShareUrl = `https://twitter.com/intent/tweet?text=${encodeURIComponent(xPostText)}`; - const searchParamAddress = searchParams.get("address")?.toLowerCase(); return ( diff --git a/web/src/pages/Profile/JurorCard/index.tsx b/web/src/pages/Profile/JurorCard/index.tsx index 7ba721bad..2533fc09c 100644 --- a/web/src/pages/Profile/JurorCard/index.tsx +++ b/web/src/pages/Profile/JurorCard/index.tsx @@ -27,11 +27,11 @@ const Card = styled(_Card)` `; interface IJurorCard { - addressToQuery: `0x${string}`; + searchParamAddress: `0x${string}`; } -const JurorCard: React.FC = ({ addressToQuery }) => { - const { data } = useUserQuery(addressToQuery); +const JurorCard: React.FC = ({ searchParamAddress }) => { + const { data } = useUserQuery(searchParamAddress); const totalCoherentVotes = data?.user ? parseInt(data?.user?.totalCoherentVotes) : 0; const totalResolvedVotes = data?.user ? parseInt(data?.user?.totalResolvedVotes) : 0; const totalResolvedDisputes = data?.user ? parseInt(data?.user?.totalResolvedDisputes) : 0; @@ -43,12 +43,12 @@ const JurorCard: React.FC = ({ addressToQuery }) => {
- + - + ); diff --git a/web/src/pages/Profile/Stakes/index.tsx b/web/src/pages/Profile/Stakes/index.tsx index 5be1921f7..0ace54253 100644 --- a/web/src/pages/Profile/Stakes/index.tsx +++ b/web/src/pages/Profile/Stakes/index.tsx @@ -35,13 +35,13 @@ const StyledLabel = styled.label` `; interface IStakes { - addressToQuery: `0x${string}`; + searchParamAddress: `0x${string}`; } -const Stakes: React.FC = ({ addressToQuery }) => { - const { data: stakeData, isLoading } = useJurorStakeDetailsQuery(addressToQuery); +const Stakes: React.FC = ({ searchParamAddress }) => { + const { data: stakeData, isLoading } = useJurorStakeDetailsQuery(searchParamAddress); const { data: jurorBalance } = useReadSortitionModuleGetJurorBalance({ - args: [addressToQuery, BigInt(1)], + args: [searchParamAddress, BigInt(1)], }); const stakedCourts = stakeData?.jurorTokensPerCourts?.filter(({ staked }) => staked > 0); const isStaked = stakedCourts && stakedCourts.length > 0; diff --git a/web/src/pages/Profile/index.tsx b/web/src/pages/Profile/index.tsx index 8e7fc37b7..bc82ee79d 100644 --- a/web/src/pages/Profile/index.tsx +++ b/web/src/pages/Profile/index.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useEffect } from "react"; import { Routes, Route, useNavigate, useSearchParams, useLocation, Navigate } from "react-router-dom"; import { useAccount } from "wagmi"; import styled, { css } from "styled-components"; @@ -69,7 +69,12 @@ const Profile: React.FC = () => { const { pathname } = useLocation(); const navigate = useNavigate(); const searchParamAddress = searchParams.get("address")?.toLowerCase(); - const addressToQuery = searchParamAddress || connectedAddress?.toLowerCase(); + + useEffect(() => { + if (isConnected && !searchParamAddress && connectedAddress) { + navigate(`${pathname}?address=${connectedAddress.toLowerCase()}`, { replace: true }); + } + }, [isConnected, searchParamAddress, connectedAddress, pathname, navigate]); const handleTabChange = (tabIndex: number) => { const selectedTab = TABS[tabIndex]; @@ -80,17 +85,17 @@ const Profile: React.FC = () => { return ( - {isConnected || searchParamAddress ? ( + {searchParamAddress ? ( <> - + handleTabChange(tabIndex)} /> - } /> - } /> + } /> + } /> } /> { /> - ) : ( + ) : !isConnected ? ( To see your profile, connect first
- )} + ) : null}