Skip to content
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.
3 changes: 2 additions & 1 deletion web/src/components/DisputeView/PeriodBanner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,14 @@ const StyledLabel = styled.label<{ frontColor: string; withDot?: boolean; isCard
`
: null}
`;

export interface IPeriodBanner {
id: number;
period: Periods;
isCard?: boolean;
}

const getPeriodColors = (period: Periods, theme: Theme): [string, string] => {
export const getPeriodColors = (period: Periods, theme: Theme): [string, string] => {
switch (period) {
case Periods.appeal:
return [theme.tint, theme.tintMedium];
Expand Down
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/1?address=${sender}`;

const transactionExplorerLink = useMemo(() => {
return getTxnExplorerLink(transactionHash ?? "");
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -36,26 +40,34 @@ export const ReStyledArrowLink = styled(StyledArrowLink)`
}
`;

interface IJurorTitle {
interface IJurorLink {
address: string;
isInternalLink?: boolean;
}

const JurorTitle: React.FC<IJurorTitle> = ({ address }) => {
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/1?address=${address}`;
const addressExplorerLink = useMemo(() => {
return `${getChain(DEFAULT_CHAIN)?.blockExplorers?.default.url}/address/${address}`;
}, [address]);

return (
<Container>
<IdenticonOrAvatar address={address} />
<ReStyledArrowLink to={profileLink}>
<ReStyledArrowLink
to={isInternalLink ? profileLink : addressExplorerLink}
rel={`${isInternalLink ? "" : "noopener noreferrer"}`}
target={`${isInternalLink ? "" : "_blank"}`}
>
<AddressOrName address={address} />
<ArrowIcon />
{isInternalLink ? <ArrowIcon /> : <NewTabIcon />}
</ReStyledArrowLink>
</Container>
);
};

export default JurorTitle;
export default JurorLink;
7 changes: 5 additions & 2 deletions web/src/components/NumberDisplay.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import React from "react";

import { Tooltip } from "@kleros/ui-components-library";

import { commify } from "utils/commify";

interface INumberDisplay {
value: string | number;
unit?: string;
Expand All @@ -19,7 +22,7 @@ const getFormattedValue = (value: number, decimals: number) => {
return `> -0.${"0".repeat(decimals - 1)}1`;
}
}
return withFixedDecimals;
return commify(withFixedDecimals);
};

const NumberDisplay: React.FC<INumberDisplay> = ({
Expand All @@ -32,7 +35,7 @@ const NumberDisplay: React.FC<INumberDisplay> = ({
}) => {
const parsedValue = Number(value);
const formattedValue = getFormattedValue(parsedValue, decimals);
const tooltipValue = isCurrency ? `${unit} ${value}` : `${value} ${unit}`;
const tooltipValue = isCurrency ? `${unit} ${commify(value)}` : `${commify(value)} ${unit}`;
const displayUnit = showUnitInDisplay ? unit : "";
const displayValue = isCurrency ? `${displayUnit} ${formattedValue}` : `${formattedValue} ${displayUnit}`;
return (
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/Coherence";
import PixelArt from "pages/Profile/JurorInfo/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
62 changes: 62 additions & 0 deletions web/src/hooks/queries/useStakingHistory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { useQuery } from "@tanstack/react-query";

// dynamic atlasUri would go here
const atlasUri = "https://url.example/graphql";

const AUTH_TOKEN = "Bearer tokenExampleGoesHere";

export const useStakingHistory = (take: number, lastCursorId?: number) => {
const variables = {
pagination: { take, lastCursorId: lastCursorId ?? null },
};

return useQuery({
queryKey: ["stakingHistoryQuery", take, lastCursorId],
enabled: true,
staleTime: 60000,
queryFn: async () => {
console.log("Fetching with variables:", variables);

try {
const response = await fetch(atlasUri, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: AUTH_TOKEN,
},
body: JSON.stringify({
query: `
query GetStakingEvents($pagination: PaginationArgs) {
userStakingEvents(pagination: $pagination) {
edges {
node {
name
args
blockTimestamp
transactionHash
}
cursor
}
count
hasNextPage
}
}
`,
variables,
}),
});

const result = await response.json();

if (!response.ok) {
throw new Error(`GraphQL error: ${JSON.stringify(result)}`);
}

return result;
} catch (error) {
console.error("GraphQL Fetch Error:", error);
throw error;
}
},
});
};
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/stakes/1"} onClick={toggleIsSettingsOpen}>
My Profile <ArrowIcon />
</ReStyledArrowLink>
</Container>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -86,13 +86,13 @@ 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/1?address=${juror}`;

return (
<TitleContainer>
<AddressContainer>
<StyledInternalLink to={profileLink}>
<JurorTitle address={juror} />
<JurorLink address={juror} />
</StyledInternalLink>
</AddressContainer>
<VoteStatus {...{ choice, period, answers, isActiveRound, commited, hiddenVotes }} />
Expand Down
4 changes: 2 additions & 2 deletions web/src/pages/Home/TopJurors/JurorCard/DesktopCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down Expand Up @@ -57,7 +57,7 @@ const DesktopCard: React.FC<IDesktopCard> = ({
return (
<Container renderRank={renderRank}>
{renderRank && <Rank rank={rank} />}
<JurorTitle address={address} />
<JurorLink address={address} />
<Rewards address={address} />
<Coherence {...{ totalCoherentVotes, totalResolvedVotes }} />
<JurorLevel {...{ totalCoherentVotes, totalResolvedVotes, totalResolvedDisputes }} />
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/PixelArt";
import PixelArt from "pages/Profile/JurorCard/BottomContent/PixelArt";

const Container = styled.div`
display: flex;
Expand Down
4 changes: 2 additions & 2 deletions web/src/pages/Home/TopJurors/JurorCard/MobileCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down Expand Up @@ -97,7 +97,7 @@ const MobileCard: React.FC<IMobileCard> = ({
<TopSide>
<RankAndTitle>
{rank ? <Rank rank={rank} /> : null}
<JurorTitle address={address} />
<JurorLink address={address} />
</RankAndTitle>
<JurorLevel {...{ totalCoherentVotes, totalResolvedVotes, totalResolvedDisputes }} />
</TopSide>
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/stakes/1">
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 {
searchParamAddress: `0x${string}`;
}

const Cases: React.FC<ICases> = ({ searchParamAddress }) => {
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(
searchParamAddress,
disputeSkip,
decodedFilter,
order === "asc" ? OrderDirection.Asc : OrderDirection.Desc
);

const { data: userData } = useUserQuery(searchParamAddress, 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;
Loading