|
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"; |
2 | 4 | import { cn } from "@gitcoin/ui/lib"; |
3 | | -import { StakeProjectCardProps } from "@gitcoin/ui/project"; |
4 | | - |
5 | 5 | 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"; |
6 | 18 |
|
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 |
25 | 23 |
|
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)); |
52 | 28 |
|
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 | + } |
83 | 37 |
|
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 | + }; |
110 | 41 |
|
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 | + }; |
125 | 45 |
|
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); |
135 | 48 |
|
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 | + }; |
145 | 60 |
|
146 | | -export const ClaimRewards = () => { |
147 | 61 | return ( |
148 | 62 | <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"> |
150 | 64 | <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"> |
152 | 66 | Total claimable rewards |
153 | 67 | </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)}`} |
156 | 70 | </div> |
157 | 71 | </div> |
158 | 72 | <div> |
159 | 73 | <Button |
160 | 74 | value="Claim all rewards" |
161 | 75 | variant="ghost" |
162 | 76 | 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", |
165 | 79 | )} |
| 80 | + onClick={handleToggleConfirmationDialog} |
| 81 | + disabled={claimablePools.length === 0 || isClaimLoading} |
166 | 82 | /> |
167 | 83 | </div> |
168 | 84 | </div> |
| 85 | + |
169 | 86 | <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"> |
171 | 88 | {`Ready to claim (${claimablePools.length})`} |
172 | 89 | </span> |
173 | 90 | <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 | + )} |
177 | 98 | </div> |
178 | 99 | </div> |
| 100 | + |
179 | 101 | <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"> |
181 | 103 | {`Pending (${pendingPools.length})`} |
182 | 104 | </span> |
183 | 105 | <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 | + )} |
187 | 113 | </div> |
188 | 114 | </div> |
| 115 | + |
189 | 116 | <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"> |
191 | 118 | {`Claimed (${claimedPools.length})`} |
192 | 119 | </span> |
193 | 120 | <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 | + )} |
197 | 128 | </div> |
198 | 129 | </div> |
| 130 | + <ProgressModal isOpen={isClaimLoading} steps={steps} /> |
| 131 | + <ClaimConfirmationDialog |
| 132 | + isOpen={isConfirmationDialogOpen} |
| 133 | + onOpenChange={handleToggleConfirmationDialog} |
| 134 | + onClaim={() => handleClaimAll(false)} |
| 135 | + onGiveBack={() => handleClaimAll(true)} |
| 136 | + /> |
199 | 137 | </div> |
200 | 138 | ); |
201 | 139 | }; |
0 commit comments