Skip to content
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
45bc1fb
feat: setup new profile page structure, new juror card style, add tab…
kemuru Jan 31, 2025
c3213ca
feat: url path tab logic, refactors, add voted ballot svg, add icons …
kemuru Feb 1, 2025
f701d8f
feat: add support for sharing your own profile, variable renaming
kemuru Feb 1, 2025
6197733
feat: add total stake info in stakes tab
kemuru Feb 7, 2025
c0c8158
Merge branch 'dev' into feat(web)/profile-page-new-design
kemuru Feb 7, 2025
59b50e9
fix: commify fails when string contains < or >, responsiveness issues…
kemuru Feb 7, 2025
6908af8
feat: test in staging atlas, votes tab setup, pagination setup, styli…
kemuru Feb 11, 2025
4172322
feat: build vote cards and stylings
kemuru Feb 12, 2025
91b35fb
Merge branch 'dev' into feat(web)/profile-page-new-design
kemuru Aug 20, 2025
d374caf
Merge branch 'dev' into feat(web)/profile-page-new-design
kemuru Aug 20, 2025
89fa758
fix: smalldisplay fix on the jurorlinks
kemuru Aug 20, 2025
3342328
feat: merge conflicts
kemuru Nov 9, 2025
574f8c9
feat: add new section latest stakes in this court, substitute the pro…
kemuru Nov 10, 2025
e6b8207
chore: change naming to staking history
kemuru Nov 10, 2025
e67c533
chore: fix table a bit
kemuru Nov 12, 2025
46de145
Merge branch 'dev' into feat(web)/profile-page-new-design
kemuru Dec 10, 2025
c843eba
Merge branch 'dev' into feat(web)/profile-page-new-design
kemuru Dec 14, 2025
01234cb
feat: remove hardcoded values in vote cards, stylings, etc
kemuru Dec 17, 2025
927cede
fix: few code smells
kemuru Dec 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions contracts/audit/METRICS.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,6 @@ Total: 15
</ul>
</div>


#### <span id=t-out-of-scope>Out of Scope</span>

##### <span id=t-out-of-scope-excluded-source-units>Excluded Source Units</span>
Expand Down Expand Up @@ -288,7 +287,6 @@ This section lists functions that are explicitly declared public or payable. Ple

<div id="surya-mdreport" style="display:none">


Files Description Table

| File Name | SHA-1 Hash |
Expand Down
2 changes: 1 addition & 1 deletion web/src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,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
7 changes: 3 additions & 4 deletions web/src/components/EvidenceCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,9 @@ import { hoverShortTransitionTiming } from "styles/commonStyles";
import { landscapeStyle } from "styles/landscapeStyle";
import { responsiveSize } from "styles/responsiveSize";

import JurorTitle from "pages/Home/TopJurors/JurorCard/JurorTitle";

import { ExternalLink } from "./ExternalLink";
import { InternalLink } from "./InternalLink";
import JurorLink from "components/JurorLink";
import MarkdownRenderer from "./MarkdownRenderer";

const StyledCard = styled(Card)`
Expand Down Expand Up @@ -201,8 +200,8 @@ const EvidenceCard: React.FC<IEvidenceCard> = ({
description,
fileURI,
}) => {
const profileLink = `/profile/1/desc/all?address=${sender}`;
const { id } = useParams();
const profileLink = `/profile/stakes/1?address=${sender}`;

const transactionExplorerLink = useMemo(() => {
return getTxnExplorerLink(transactionHash ?? "");
Expand All @@ -228,7 +227,7 @@ const EvidenceCard: React.FC<IEvidenceCard> = ({
<BottomShade>
<BottomLeftContent>
<StyledJurorInternalLink to={profileLink}>
<JurorTitle address={sender} />
<JurorLink address={sender} />
</StyledJurorInternalLink>
<StyledExternalLink to={transactionExplorerLink} rel="noopener noreferrer" target="_blank">
<label>{formatDate(Number(timestamp), true)}</label>
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 ArrowSvg from "svgs/icons/arrow.svg";
import { useAccount } from "wagmi";

import ArrowIcon from "svgs/icons/arrow.svg";
import NewTabIcon from "svgs/icons/new-tab.svg";

import { DEFAULT_CHAIN, getChain } from "consts/chains";

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 @@ -45,27 +49,36 @@ export const ReStyledArrowLink = styled(StyledArrowLink)<{ smallDisplay?: boolea
`}
`;

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

const JurorTitle: React.FC<IJurorTitle> = ({ address, smallDisplay }) => {
const JurorLink: React.FC<IJurorLink> = ({ address, isInternalLink = true, smallDisplay }) => {
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 }} />
<ReStyledArrowLink to={profileLink} {...{ smallDisplay }}>
<IdenticonOrAvatar address={address} />
<ReStyledArrowLink
{...{ smallDisplay }}
to={isInternalLink ? profileLink : addressExplorerLink}
rel={`${isInternalLink ? "" : "noopener noreferrer"}`}
target={`${isInternalLink ? "" : "_blank"}`}
>
<AddressOrName {...{ address, smallDisplay }} />
<ArrowSvg />
{isInternalLink ? <ArrowIcon /> : <NewTabIcon />}
</ReStyledArrowLink>
</Container>
);
};

export default JurorTitle;
export default JurorLink;
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;
}
},
});
};
74 changes: 74 additions & 0 deletions web/src/hooks/useStakingEventsByCourt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { useQuery } from "@tanstack/react-query";
import { request } from "graphql-request";

import { isUndefined } from "src/utils";

export type StakingEventItem = {
id: string;
blockHash: string;
transactionHash: string;
blockTimestamp: string;
network: {
chainId: number;
};
args: {
_address: string;
_courtID: string;
_amount: string;
};
};

type StakingEventsResponse = {
userStakingEvents: {
items: Array<{ item: StakingEventItem }>;
count: number;
};
};

const atlasUri = import.meta.env.REACT_APP_ATLAS_URI;

export const useStakingEventsByCourt = (courtIds: number[], skip: number, take: number, partialAddress?: string) => {
const addressParam = partialAddress ?? "";
// Allow empty courtIds array for "all courts" query
const isEnabled = !isUndefined(atlasUri);

const query = `
query GetStakingEvents($partialAddress: String!, $courtIDs: [Int!], $pagination: PaginationArgs) {
userStakingEvents(partialAddress: $partialAddress, courtIDs: $courtIDs, pagination: $pagination) {
items {
item {
id
blockHash
transactionHash
blockTimestamp
network {
chainId
}
args {
_address
_courtID
_amount
}
}
}
count
}
}
`;

const variables = {
partialAddress: addressParam,
// If courtIds is empty, pass null to query all courts
courtIDs: courtIds.length > 0 ? courtIds : null,
pagination: { skip, take },
};

return useQuery<StakingEventsResponse>({
queryKey: ["stakingEventsByCourt", courtIds, skip, take, partialAddress],
enabled: isEnabled,
staleTime: 60000,
queryFn: async () => {
return await request<StakingEventsResponse>(`${atlasUri}/graphql`, query, variables);
},
});
};
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
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const Container = styled.div`
border: 1px solid ${({ theme }) => theme.stroke};
border-top-left-radius: 3px;
border-top-right-radius: 3px;
padding: 18px 24px;
padding: 16px 20px;
justify-content: space-between;
margin-top: ${responsiveSize(12, 16)};
`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import styled from "styled-components";

import { hoverShortTransitionTiming } from "styles/commonStyles";

import JurorTitle from "pages/Home/TopJurors/JurorCard/JurorTitle";
import JurorLink from "components/JurorLink";

import Stake from "./Stake";

const Container = styled.div`
Expand All @@ -15,7 +16,7 @@ const Container = styled.div`
border: 1px solid ${({ theme }) => theme.stroke};
border-top: none;
align-items: center;
padding: 18px 24px;
padding: 16px 20px;

:hover {
background-color: ${({ theme }) => theme.lightGrey}BB;
Expand All @@ -30,7 +31,7 @@ interface IJurorCard {
const JurorCard: React.FC<IJurorCard> = ({ address, effectiveStake }) => {
return (
<Container>
<JurorTitle {...{ address }} smallDisplay />
<JurorLink {...{ address }} smallDisplay />
<Stake {...{ effectiveStake }} />
</Container>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import React from "react";
import styled from "styled-components";

import { responsiveSize } from "styles/responsiveSize";

import { getDescriptiveCourtName } from "utils/getDescriptiveCourtName";

import Search from "./Search";
import { responsiveSize } from "styles/responsiveSize";

import DisplayJurors from "./DisplayJurors";
import Search from "./Search";

const Container = styled.div`
margin-top: ${responsiveSize(28, 48)};
max-width: 578px;
`;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from "react";

import { DesktopHeader } from "./Header/DesktopHeader";

const Header: React.FC = () => {
return <DesktopHeader />;
};

export default Header;
Loading
Loading