Skip to content

Commit 3da2ddc

Browse files
committed
chore: ui-improvements
1 parent 2f3d23e commit 3da2ddc

4 files changed

Lines changed: 270 additions & 155 deletions

File tree

Lines changed: 92 additions & 154 deletions
Original file line numberDiff line numberDiff line change
@@ -1,201 +1,139 @@
1-
import { Button } from "@gitcoin/ui";
1+
import { useState } from "react";
2+
import { useNavigate } from "react-router-dom";
3+
import { Button, ProgressModal } from "@gitcoin/ui";
24
import { cn } from "@gitcoin/ui/lib";
3-
import { StakeProjectCardProps } from "@gitcoin/ui/project";
4-
55
import { StakePoolCard } from "@gitcoin/ui/pool";
6+
import { zeroAddress } from "viem";
7+
import { useAccount } from "wagmi";
8+
import { LoadingPage } from "@/components/Loading";
9+
import { useGetStakerOverview } from "@/hooks/backend";
10+
import { useClaim } from "@/hooks/contracts";
11+
import { useGetRewardsAmountInUSD } from "@/hooks/tokens";
12+
import { ClaimConfirmationDialog } from "./components";
13+
import {
14+
getClaimableRewardsInUSDParams,
15+
prepareClaimData,
16+
processRewardsData,
17+
} from "./utils/claimRewards";
618

7-
const simpleRound = {
8-
roundName: "Grants Round Defi",
9-
roundDescription: "Grants Round Defi description text here",
10-
roundId: "90",
11-
chainId: 10,
12-
votingStartDate: new Date("2024-12-09T19:22:56.413Z"),
13-
votingEndDate: new Date("2024-12-10T19:23:30.678Z"),
14-
onClick: (pool?: { chainId: number; roundId: string }) => {
15-
console.log(pool);
16-
},
17-
createdAtBlock: 123456,
18-
matchingPoolAmount: 100000,
19-
stakedAmount: 100000,
20-
totalProjects: 100,
21-
totalStaked: 100000,
22-
lastStakeDate: new Date("2024-12-08T19:22:56.413Z"),
23-
onClaim: () => void 0,
24-
};
19+
export const ClaimRewards = () => {
20+
const { address } = useAccount();
21+
const navigate = useNavigate();
22+
const { batchClaim, isLoading: isClaimLoading, steps } = useClaim(); // Assuming you have this hook
2523

26-
const availableToClaimCardProps: StakeProjectCardProps[] = [
27-
{
28-
name: "Project Name",
29-
description: "Project Description",
30-
image: "https://picsum.photos/200",
31-
variant: "staked",
32-
id: "1",
33-
chainId: 1,
34-
roundId: "1",
35-
amount: 100,
36-
stakedAt: new Date(),
37-
unlockAt: new Date(new Date().getTime() - 1000 * 60 * 60 * 24 * 10),
38-
},
39-
{
40-
name: "Project Name",
41-
description: "Project Description",
42-
image: "https://picsum.photos/200",
43-
variant: "staked",
44-
id: "2",
45-
chainId: 1,
46-
roundId: "1",
47-
amount: 100,
48-
stakedAt: new Date(),
49-
unlockAt: new Date(new Date().getTime() - 1000 * 60 * 60 * 24 * 10),
50-
},
51-
];
24+
const { data: stakeOverview, isLoading, refetch } = useGetStakerOverview(address ?? zeroAddress);
25+
const [isConfirmationDialogOpen, setIsConfirmationDialogOpen] = useState(false);
26+
const { data: rewardsAmountInUSD, isLoading: isRewardsAmountInUSDLoading } =
27+
useGetRewardsAmountInUSD(getClaimableRewardsInUSDParams(stakeOverview));
5228

53-
const claimRewardsCardProps: StakeProjectCardProps[] = [
54-
{
55-
name: "Project Name",
56-
description: "Project Description",
57-
image: "https://picsum.photos/200",
58-
variant: "claimed",
59-
id: "1",
60-
chainId: 1,
61-
roundId: "1",
62-
amount: 100,
63-
stakedAt: new Date(),
64-
unlockAt: new Date(new Date().getTime() + 1000 * 60 * 60 * 24 * 10),
65-
claimedAt: new Date(new Date().getTime() + 1000 * 60 * 60 * 24 * 30),
66-
txHash: "0x123",
67-
},
68-
{
69-
name: "Project Name",
70-
description: "Project Description",
71-
image: "https://picsum.photos/200",
72-
variant: "claimed",
73-
id: "2",
74-
chainId: 1,
75-
roundId: "1",
76-
amount: 100,
77-
stakedAt: new Date(),
78-
unlockAt: new Date(new Date().getTime() + 1000 * 60 * 60 * 24 * 10),
79-
claimedAt: new Date(new Date().getTime() + 1000 * 60 * 60 * 24 * 30),
80-
txHash: "0x123",
81-
},
82-
];
29+
if (
30+
isLoading ||
31+
isRewardsAmountInUSDLoading ||
32+
!stakeOverview ||
33+
rewardsAmountInUSD === undefined
34+
) {
35+
return <LoadingPage />;
36+
}
8337

84-
const upcomingStakeCardProps: StakeProjectCardProps[] = [
85-
{
86-
name: "Project Name",
87-
description: "Project Description",
88-
image: "https://picsum.photos/200",
89-
variant: "staked",
90-
id: "1",
91-
chainId: 1,
92-
roundId: "1",
93-
amount: 100,
94-
stakedAt: new Date(),
95-
unlockAt: new Date(new Date().getTime() + 1000 * 60 * 60 * 24 * 10),
96-
},
97-
{
98-
name: "Project Name",
99-
description: "Project Description",
100-
image: "https://picsum.photos/200",
101-
variant: "staked",
102-
id: "2",
103-
chainId: 1,
104-
roundId: "1",
105-
amount: 100,
106-
stakedAt: new Date(),
107-
unlockAt: new Date(new Date().getTime() + 1000 * 60 * 60 * 24 * 10),
108-
},
109-
];
38+
const handleToggleConfirmationDialog = () => {
39+
setIsConfirmationDialogOpen(!isConfirmationDialogOpen);
40+
};
11041

111-
const claimablePools = [
112-
{
113-
...simpleRound,
114-
roundId: "91",
115-
roundName: "Grants Round Defi",
116-
stakedProjects: availableToClaimCardProps,
117-
},
118-
{
119-
...simpleRound,
120-
roundId: "91",
121-
roundName: "Grants Round Defi 2",
122-
stakedProjects: availableToClaimCardProps,
123-
},
124-
];
42+
const handlePoolClick = (chainId: number, roundId: string) => {
43+
navigate(`/staking-round/${chainId}/${roundId}`);
44+
};
12545

126-
const pendingPools = [
127-
{
128-
...simpleRound,
129-
roundId: "92",
130-
roundName: "Grants Round Defi 3",
131-
votingEndDate: new Date(new Date().getTime() + 1000 * 60 * 60 * 24 * 10),
132-
stakedProjects: upcomingStakeCardProps,
133-
},
134-
];
46+
const { claimablePools, pendingPools, claimedPools, RewardsByPool, totalUnstaked } =
47+
processRewardsData(stakeOverview, handlePoolClick);
13548

136-
const claimedPools = [
137-
{
138-
...simpleRound,
139-
roundId: "93",
140-
roundName: "Grants Round Defi 4",
141-
claimed: true,
142-
stakedProjects: claimRewardsCardProps,
143-
},
144-
];
49+
const handleClaimAll = async (returnToMatchingPool: boolean) => {
50+
handleToggleConfirmationDialog();
51+
const claims = prepareClaimData(
52+
claimablePools,
53+
RewardsByPool,
54+
address ?? zeroAddress,
55+
returnToMatchingPool,
56+
);
57+
await batchClaim(claims, totalUnstaked);
58+
await refetch();
59+
};
14560

146-
export const ClaimRewards = () => {
14761
return (
14862
<div className="flex flex-col gap-8">
149-
<div className="flex justify-between items-center bg-purple-50 rounded-lg py-6 px-[56px]">
63+
<div className="flex items-center justify-between rounded-lg bg-purple-50 px-[56px] py-6">
15064
<div className="flex flex-col items-start gap-2">
151-
<div className="text-grey-900 text-sm font-semibold font-ui-sans leading-7">
65+
<div className="text-grey-900 font-ui-sans text-sm font-semibold leading-7">
15266
Total claimable rewards
15367
</div>
154-
<div className="text-black text-[32px]/[41.66px] font-normal font-ui-mono leading-7">
155-
$100.00
68+
<div className="font-ui-mono text-[32px]/[41.66px] font-normal leading-7 text-black">
69+
{`$${rewardsAmountInUSD.toFixed(2)}`}
15670
</div>
15771
</div>
15872
<div>
15973
<Button
16074
value="Claim all rewards"
16175
variant="ghost"
16276
className={cn(
163-
"text-purple-700 bg-white",
164-
"disabled:text-grey-500 disabled:bg-grey-100"
77+
"bg-white text-purple-700",
78+
"disabled:text-grey-500 disabled:bg-grey-100",
16579
)}
80+
onClick={handleToggleConfirmationDialog}
81+
disabled={claimablePools.length === 0 || isClaimLoading}
16682
/>
16783
</div>
16884
</div>
85+
16986
<div className="flex flex-col gap-6">
170-
<span className=" text-2xl font-medium font-ui-sans leading-7">
87+
<span className="font-ui-sans text-2xl font-medium leading-7">
17188
{`Ready to claim (${claimablePools.length})`}
17289
</span>
17390
<div className="flex flex-col gap-4">
174-
{claimablePools.map((props) => (
175-
<StakePoolCard key={props.roundId} data={props} />
176-
))}
91+
{claimablePools.length > 0 ? (
92+
claimablePools.map((props) => (
93+
<StakePoolCard key={`${props.chainId}-${props.roundId}`} data={props} />
94+
))
95+
) : (
96+
<div className="py-4 text-center text-gray-500">No rewards ready to claim</div>
97+
)}
17798
</div>
17899
</div>
100+
179101
<div className="flex flex-col gap-6">
180-
<span className=" text-2xl font-medium font-ui-sans leading-7">
102+
<span className="font-ui-sans text-2xl font-medium leading-7">
181103
{`Pending (${pendingPools.length})`}
182104
</span>
183105
<div className="flex flex-col gap-4">
184-
{pendingPools.map((props) => (
185-
<StakePoolCard key={props.roundId} data={props} />
186-
))}
106+
{pendingPools.length > 0 ? (
107+
pendingPools.map((props) => (
108+
<StakePoolCard key={`${props.chainId}-${props.roundId}`} data={props} />
109+
))
110+
) : (
111+
<div className="py-4 text-center text-gray-500">No pending stakes</div>
112+
)}
187113
</div>
188114
</div>
115+
189116
<div className="flex flex-col gap-6">
190-
<span className=" text-2xl font-medium font-ui-sans leading-7">
117+
<span className="font-ui-sans text-2xl font-medium leading-7">
191118
{`Claimed (${claimedPools.length})`}
192119
</span>
193120
<div className="flex flex-col gap-4">
194-
{claimedPools.map((props) => (
195-
<StakePoolCard key={props.roundId} data={props} />
196-
))}
121+
{claimedPools.length > 0 ? (
122+
claimedPools.map((props) => (
123+
<StakePoolCard key={`${props.chainId}-${props.roundId}`} data={props} />
124+
))
125+
) : (
126+
<div className="py-4 text-center text-gray-500">No claimed rewards</div>
127+
)}
197128
</div>
198129
</div>
130+
<ProgressModal isOpen={isClaimLoading} steps={steps} />
131+
<ClaimConfirmationDialog
132+
isOpen={isConfirmationDialogOpen}
133+
onOpenChange={handleToggleConfirmationDialog}
134+
onClaim={() => handleClaimAll(false)}
135+
onGiveBack={() => handleClaimAll(true)}
136+
/>
199137
</div>
200138
);
201139
};
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import {
2+
Dialog,
3+
DialogHeader,
4+
DialogTitle,
5+
IconType,
6+
Icon,
7+
DialogDescription,
8+
Modal,
9+
Button,
10+
} from "@gitcoin/ui";
11+
12+
export const ClaimConfirmationDialog = ({
13+
isOpen,
14+
onOpenChange,
15+
onClaim,
16+
onGiveBack,
17+
}: {
18+
isOpen: boolean;
19+
onOpenChange: (open: boolean) => void;
20+
onClaim: () => void;
21+
onGiveBack: () => void;
22+
}) => {
23+
return (
24+
<Dialog open={isOpen} onOpenChange={onOpenChange}>
25+
<Modal className="max-w-[676px] p-6">
26+
<div className="flex flex-col gap-6">
27+
<DialogHeader className="flex flex-col items-start gap-2 text-start">
28+
<div className="flex w-full justify-between">
29+
<DialogTitle className="text-3xl font-semibold">
30+
Ready to claim your rewards?
31+
</DialogTitle>
32+
<button onClick={() => onOpenChange(false)}>
33+
<Icon type={IconType.X} />
34+
</button>
35+
</div>
36+
<DialogDescription className="text-[16px]/[26px]">
37+
You're about to claim your staking rewards and unstake your GTC.
38+
</DialogDescription>
39+
</DialogHeader>
40+
41+
<div className="flex flex-col gap-4">
42+
<h3 className="font-ui-sans text-xl">What to expect:</h3>
43+
44+
<div className="flex flex-col gap-3">
45+
<div className="text-p font-ui-sans">
46+
💸 Rewards Claim: You can claim all rewards for yourself or donate them to Gitcoin’s
47+
matching pool to support future funding rounds 💙 💯
48+
</div>
49+
50+
<div className="text-p font-ui-sans">
51+
👍 Unstaking GTC: Your staked GTC will be withdrawn
52+
</div>
53+
</div>
54+
55+
<p className="text-p font-ui-sans font-normal">
56+
This process requires multiple approvals in your wallet.
57+
</p>
58+
</div>
59+
60+
<div className="mt-2 flex items-center justify-center gap-3">
61+
<Button
62+
value="💙 Give back to the matching pool 💙"
63+
variant="light-blue"
64+
className="w-fit bg-blue-300 hover:bg-blue-400"
65+
onClick={onGiveBack}
66+
/>
67+
<Button
68+
value="🤑 Claim my rewards"
69+
variant="outlined-primary"
70+
className="border-grey-100 w-fit text-purple-500"
71+
onClick={onClaim}
72+
/>
73+
</div>
74+
</div>
75+
</Modal>
76+
</Dialog>
77+
);
78+
};

‎web/src/pages/StakingRound/StakingRound.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import {
3232

3333
export const StakingRound = () => {
3434
const { chainId, roundId } = useParams();
35-
const [searchParams, setSearchParams] = useSearchParams();
35+
const [searchParams] = useSearchParams();
3636

3737
const applicationId = searchParams.get("applicationId");
3838

0 commit comments

Comments
 (0)