Skip to content

Commit 6908af8

Browse files
committed
feat: test in staging atlas, votes tab setup, pagination setup, stylings, staking history
1 parent 59b50e9 commit 6908af8

File tree

19 files changed

+513
-100
lines changed

19 files changed

+513
-100
lines changed

web/src/components/EvidenceCard.tsx

Lines changed: 1 addition & 1 deletion
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/stakes?address=${sender}`;
226+
const profileLink = `/profile/stakes/1?address=${sender}`;
227227

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

web/src/components/JurorLink.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ const JurorLink: React.FC<IJurorLink> = ({ address, isInternalLink = true }) =>
5050
const profileLink =
5151
isConnected && connectedAddress?.toLowerCase() === address.toLowerCase()
5252
? "/profile"
53-
: `/profile/stakes?address=${address}`;
53+
: `/profile/stakes/1?address=${address}`;
5454
const addressExplorerLink = useMemo(() => {
5555
return `${getChain(DEFAULT_CHAIN)?.blockExplorers?.default.url}/address/${address}`;
5656
}, [address]);
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { useQuery } from "@tanstack/react-query";
2+
3+
// dynamic atlasUri would go here
4+
const atlasUri = "https://url.example/graphql";
5+
6+
const AUTH_TOKEN = "Bearer tokenExampleGoesHere";
7+
8+
export const useStakingHistory = (take: number, lastCursorId?: number) => {
9+
const variables = {
10+
pagination: { take, lastCursorId: lastCursorId ?? null },
11+
};
12+
13+
return useQuery({
14+
queryKey: ["stakingHistoryQuery", take, lastCursorId],
15+
enabled: true,
16+
staleTime: 60000,
17+
queryFn: async () => {
18+
console.log("Fetching with variables:", variables);
19+
20+
try {
21+
const response = await fetch(atlasUri, {
22+
method: "POST",
23+
headers: {
24+
"Content-Type": "application/json",
25+
Authorization: AUTH_TOKEN,
26+
},
27+
body: JSON.stringify({
28+
query: `
29+
query GetStakingEvents($pagination: PaginationArgs) {
30+
userStakingEvents(pagination: $pagination) {
31+
edges {
32+
node {
33+
name
34+
args
35+
blockTimestamp
36+
transactionHash
37+
}
38+
cursor
39+
}
40+
count
41+
hasNextPage
42+
}
43+
}
44+
`,
45+
variables,
46+
}),
47+
});
48+
49+
const result = await response.json();
50+
51+
if (!response.ok) {
52+
throw new Error(`GraphQL error: ${JSON.stringify(result)}`);
53+
}
54+
55+
return result;
56+
} catch (error) {
57+
console.error("GraphQL Fetch Error:", error);
58+
throw error;
59+
}
60+
},
61+
});
62+
};

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

Lines changed: 1 addition & 1 deletion
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"} onClick={toggleIsSettingsOpen}>
55+
<ReStyledArrowLink to={"/profile/stakes/1"} onClick={toggleIsSettingsOpen}>
5656
My Profile <ArrowIcon />
5757
</ReStyledArrowLink>
5858
</Container>

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

Lines changed: 1 addition & 1 deletion
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/stakes?address=${juror}`;
89+
const profileLink = `/profile/stakes/1?address=${juror}`;
9090

9191
return (
9292
<TitleContainer>

web/src/pages/Jurors/index.tsx

Lines changed: 1 addition & 1 deletion
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">
58+
<StyledArrowLink to="/profile/stakes/1">
5959
My Profile <ArrowIcon />
6060
</StyledArrowLink>
6161
) : null}

web/src/pages/Profile/Stakes/CourtCard/CourtName.tsx

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,6 @@ import styled, { css } from "styled-components";
33

44
import { landscapeStyle } from "styles/landscapeStyle";
55

6-
import ArrowIcon from "svgs/icons/arrow.svg";
7-
8-
import { StyledArrowLink } from "components/StyledArrowLink";
9-
106
const Container = styled.div`
117
display: flex;
128
width: 100%;
@@ -29,15 +25,6 @@ const Container = styled.div`
2925
)}
3026
`;
3127

32-
const ReStyledArrowLink = styled(StyledArrowLink)`
33-
font-size: 14px;
34-
35-
> svg {
36-
height: 15px;
37-
width: 15px;
38-
}
39-
`;
40-
4128
interface ICourtName {
4229
name: string;
4330
id: string;
@@ -47,9 +34,6 @@ const CourtName: React.FC<ICourtName> = ({ name, id }) => {
4734
return (
4835
<Container>
4936
<small>{name}</small>
50-
<ReStyledArrowLink to={`/courts/${id?.toString()}`}>
51-
Open Court <ArrowIcon />
52-
</ReStyledArrowLink>
5337
</Container>
5438
);
5539
};
Lines changed: 4 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,10 @@
11
import React from "react";
2-
import styled, { css } from "styled-components";
2+
import styled from "styled-components";
33

44
import { formatUnits } from "viem";
55

6-
import { landscapeStyle } from "styles/landscapeStyle";
7-
86
import NumberDisplay from "components/NumberDisplay";
97

10-
import PnkIcon from "svgs/icons/pnk.svg";
11-
12-
const Container = styled.div`
13-
display: flex;
14-
flex-direction: row;
15-
gap: 8px;
16-
width: 100%;
17-
justify-content: flex-start;
18-
align-items: center;
19-
20-
${landscapeStyle(
21-
() => css`
22-
width: auto;
23-
gap: 12px;
24-
`
25-
)}
26-
`;
27-
288
const StyledLabel = styled.label`
299
display: flex;
3010
font-weight: 600;
@@ -34,13 +14,6 @@ const StyledLabel = styled.label`
3414
gap: 4px;
3515
`;
3616

37-
const StyledPnkIcon = styled(PnkIcon)`
38-
display: inline-block;
39-
width: 16px;
40-
height: 16px;
41-
fill: ${({ theme }) => theme.secondaryPurple};
42-
`;
43-
4417
interface IStake {
4518
stake: string;
4619
}
@@ -49,12 +22,9 @@ const Stake: React.FC<IStake> = ({ stake }) => {
4922
const formattedStake = formatUnits(stake, 18);
5023

5124
return (
52-
<Container>
53-
<StyledPnkIcon />
54-
<StyledLabel>
55-
<NumberDisplay value={formattedStake} unit="PNK" />
56-
</StyledLabel>
57-
</Container>
25+
<StyledLabel>
26+
<NumberDisplay value={formattedStake} unit="PNK" />
27+
</StyledLabel>
5828
);
5929
};
6030
export default Stake;

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

Lines changed: 70 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,30 @@
11
import React from "react";
22
import styled, { css } from "styled-components";
33

4+
import { landscapeStyle } from "styles/landscapeStyle";
5+
46
import { Card as _Card } from "@kleros/ui-components-library";
57

6-
import { landscapeStyle } from "styles/landscapeStyle";
8+
import ArrowIcon from "svgs/icons/arrow.svg";
9+
import NewTabIcon from "svgs/icons/new-tab.svg";
710

11+
import { formatDate } from "utils/date";
12+
import { getTxnExplorerLink } from "utils/index";
13+
14+
import { StyledArrowLink } from "components/StyledArrowLink";
815
import CourtName from "./CourtName";
916
import Stake from "./Stake";
1017

11-
const Container = styled(_Card)`
18+
const Container = styled(_Card)<{ isCurrentStakeCard?: boolean }>`
1219
display: flex;
1320
flex-direction: row;
1421
align-items: center;
1522
justify-content: space-between;
1623
height: auto;
1724
width: 100%;
1825
padding: 20px 16px 24px;
19-
border-left: 5px solid ${({ theme }) => theme.secondaryPurple};
26+
border-left: 5px solid
27+
${({ theme, isCurrentStakeCard }) => (isCurrentStakeCard ? theme.secondaryPurple : theme.secondaryText)};
2028
flex-wrap: wrap;
2129
gap: 16px;
2230
@@ -28,22 +36,76 @@ const Container = styled(_Card)`
2836
2937
${landscapeStyle(
3038
() => css`
31-
padding: 21.5px 32px;
39+
padding: 21.5px 28px;
3240
`
3341
)}
3442
`;
3543

44+
const LeftContent = styled.div`
45+
display: flex;
46+
flex-direction: row;
47+
flex-wrap: wrap;
48+
gap: 16px 24px;
49+
`;
50+
51+
const StakeAndLinkAndDateContainer = styled.div`
52+
display: flex;
53+
flex-direction: row;
54+
flex-wrap: wrap;
55+
gap: 16px;
56+
`;
57+
58+
const StakeAndLink = styled.div`
59+
display: flex;
60+
flex-direction: row;
61+
gap: 8px;
62+
`;
63+
64+
const ReStyledArrowLink = styled(StyledArrowLink)`
65+
font-size: 14px;
66+
67+
> svg {
68+
height: 15px;
69+
width: 15px;
70+
}
71+
`;
72+
3673
interface ICourtCard {
3774
name: string;
3875
stake: string;
3976
id: string;
77+
timestamp?: number;
78+
transactionHash?: string;
79+
isCurrentStakeCard?: boolean;
4080
}
4181

42-
const CourtCard: React.FC<ICourtCard> = ({ name, stake, id }) => {
82+
const CourtCard: React.FC<ICourtCard> = ({
83+
name,
84+
stake,
85+
id,
86+
timestamp,
87+
transactionHash,
88+
isCurrentStakeCard = true,
89+
}) => {
4390
return (
44-
<Container hover>
45-
<CourtName {...{ name, id }} />
46-
<Stake {...{ stake }} />
91+
<Container hover {...{ isCurrentStakeCard }}>
92+
<LeftContent>
93+
<CourtName {...{ name, id }} />
94+
<StakeAndLinkAndDateContainer>
95+
<StakeAndLink>
96+
<Stake {...{ stake }} />
97+
{transactionHash ? (
98+
<ReStyledArrowLink to={getTxnExplorerLink(transactionHash)} target="_blank" rel="noopener noreferrer">
99+
<NewTabIcon />
100+
</ReStyledArrowLink>
101+
) : null}
102+
</StakeAndLink>
103+
{timestamp ? <label>{formatDate(timestamp)}</label> : null}
104+
</StakeAndLinkAndDateContainer>
105+
</LeftContent>
106+
<ReStyledArrowLink to={`/courts/${id?.toString()}`}>
107+
Open Court <ArrowIcon />
108+
</ReStyledArrowLink>
47109
</Container>
48110
);
49111
};

web/src/pages/Profile/Stakes/Header.tsx renamed to web/src/pages/Profile/Stakes/CurrentStakes/Header.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const Container = styled.div`
2020
width: 100%;
2121
gap: 4px 16px;
2222
align-items: center;
23-
margin-bottom: ${responsiveSize(16, 24)};
23+
margin-bottom: 20px;
2424
2525
${landscapeStyle(
2626
() => css`
@@ -74,7 +74,7 @@ const Header: React.FC<IHeader> = ({ totalStake, lockedStake }) => {
7474

7575
return (
7676
<Container>
77-
<StyledTitle>Stakes</StyledTitle>
77+
<StyledTitle>Current Stakes</StyledTitle>
7878
<TotalStakeAndLockedPnk>
7979
{!isUndefined(totalStake) ? (
8080
<StakedPnk>
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import React from "react";
2+
import styled from "styled-components";
3+
4+
import { responsiveSize } from "styles/responsiveSize";
5+
6+
import Skeleton from "react-loading-skeleton";
7+
8+
import { JurorStakeDetailsQuery } from "src/graphql/graphql";
9+
10+
import Header from "./Header";
11+
import CourtCard from "../CourtCard";
12+
import { CourtCardsContainer } from "../index";
13+
14+
const Container = styled.div`
15+
display: flex;
16+
flex-direction: column;
17+
flex-wrap: wrap;
18+
`;
19+
20+
const NoCurrentStakesLabel = styled.label`
21+
font-size: ${responsiveSize(14, 16)};
22+
margin-bottom: 12px;
23+
`;
24+
25+
interface ICurrentStakes {
26+
totalStake: string;
27+
lockedStake: string;
28+
currentStakeData: JurorStakeDetailsQuery | undefined;
29+
isLoading: boolean;
30+
}
31+
32+
const CurrentStakes: React.FC<ICurrentStakes> = ({ totalStake, lockedStake, currentStakeData, isLoading }) => {
33+
const stakedCourts = currentStakeData?.jurorTokensPerCourts?.filter(({ staked }) => staked > 0);
34+
const isStaked = stakedCourts && stakedCourts.length > 0;
35+
36+
return (
37+
<Container>
38+
<Header {...{ totalStake, lockedStake }} />
39+
{!isStaked && !isLoading ? (
40+
<NoCurrentStakesLabel>No stakes found</NoCurrentStakesLabel>
41+
) : isLoading ? (
42+
<Skeleton />
43+
) : null}
44+
{isStaked && !isLoading ? (
45+
<CourtCardsContainer>
46+
{currentStakeData?.jurorTokensPerCourts
47+
?.filter(({ staked }) => staked > 0)
48+
.map(({ court: { id, name }, staked }) => (
49+
<CourtCard key={id} name={name ?? ""} stake={staked} {...{ id }} />
50+
))}
51+
</CourtCardsContainer>
52+
) : null}
53+
</Container>
54+
);
55+
};
56+
export default CurrentStakes;

0 commit comments

Comments
 (0)