Skip to content

Commit

Permalink
feat: add cancel rewards functionality (#2321)
Browse files Browse the repository at this point in the history
* feat: add cancel rewards functionality

* feat: check for rewards status in rewards info as well

* feat: add switchChain fn to cancel rewards

* feat: add toasts and one more messsage in cancel rewards modal
  • Loading branch information
nakedfool authored Sep 10, 2024
1 parent 4b6370b commit 9600d02
Show file tree
Hide file tree
Showing 7 changed files with 284 additions and 47 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import DialogModalV4 from "@components/UI/DialogModalV4";
import Image from "next/image";
import { FC } from "react";

interface CancelRewardsModalProps {
isCancelRewardsModalOpen: boolean;
setIsCancelRewardsModalOpen: (isOpen: boolean) => void;
cancelRewardsHandler: () => void;
}

const CancelRewardsModal: FC<CancelRewardsModalProps> = ({
isCancelRewardsModalOpen,
setIsCancelRewardsModalOpen,
cancelRewardsHandler,
}) => {
return (
<DialogModalV4 isOpen={isCancelRewardsModalOpen} onClose={setIsCancelRewardsModalOpen}>
<div className="flex flex-col gap-8 py-6 md:py-16 pl-8 md:pl-32 pr-4 md:pr-16">
<div className="flex justify-between items-center">
<p className="text-[24px] text-neutral-11 font-bold">cancel rewards?? 😬</p>
<Image
src="/modal/modal_close.svg"
width={39}
height={33}
alt="close"
className="hidden md:block cursor-pointer"
onClick={() => setIsCancelRewardsModalOpen(false)}
/>
</div>
<div className="flex flex-col gap-4 text-neutral-11 text-[16px]">
<p>if you proceed, you will cancel rewards for this contest.</p>
<p className="font-bold">🚨 players will not be able to receive rewards.</p>
<p>🚨 after you cancel rewards, you can withdraw any funds on the rewards page.</p>
<p>🚨 you will not be able to deploy another rewards pool for this contest.</p>
<p>are you really, really, really sure you want to proceed?</p>
</div>
<button
className="mt-4 bg-negative-11 rounded-[40px] w-80 h-10 text-center text-true-black text-[16px] font-bold hover:opacity-80 transition-opacity duration-300 ease-in-out"
onClick={cancelRewardsHandler}
>
cancel rewards 😈
</button>
</div>
</DialogModalV4>
);
};

export default CancelRewardsModal;
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { useCancelRewards } from "@hooks/useCancelRewards";
import { FC, useState } from "react";
import CancelRewardsModal from "./components/Modal";
import { TrashIcon } from "@heroicons/react/24/outline";
import { Abi } from "viem";
import { switchChain } from "@wagmi/core";
import { useAccount } from "wagmi";
import { config } from "@config/wagmi";

interface CancelRewardsProps {
rewardsAddress: `0x${string}`;
abi: Abi;
chainId: number;
version: string;
}

const CancelRewards: FC<CancelRewardsProps> = ({ rewardsAddress, abi, chainId, version }) => {
const { cancelRewards, isLoading } = useCancelRewards({ rewardsAddress, abi, chainId, version });
const [isCancelRewardsModalOpen, setIsCancelRewardsModalOpen] = useState(false);
const { chainId: accountChainId } = useAccount();
const isUserOnCorrectChain = accountChainId === chainId;
const handleOpenModal = () => setIsCancelRewardsModalOpen(true);

const handleCancelRewards = async () => {
if (!isUserOnCorrectChain) {
await switchChain(config, { chainId });
}

cancelRewards();
setIsCancelRewardsModalOpen(false);
};

return (
<>
<button disabled={isLoading} onClick={handleOpenModal}>
<TrashIcon className="w-6 h-6 text-negative-11 hover:text-negative-10 transition-colors duration-300 ease-in-out" />
</button>

<CancelRewardsModal
isCancelRewardsModalOpen={isCancelRewardsModalOpen}
setIsCancelRewardsModalOpen={setIsCancelRewardsModalOpen}
cancelRewardsHandler={handleCancelRewards}
/>
</>
);
};

export default CancelRewards;
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ interface RewardsReleasableProps {
rewardsAbi: Abi;
rankings: number[];
isWithdrawRewardsOpen: boolean;
isCanceled: boolean;
setIsWithdrawRewardsOpen: (isOpen: boolean) => void;
}

Expand All @@ -20,6 +21,7 @@ const RewardsReleasable: FC<RewardsReleasableProps> = ({
rewardsAbi,
rankings,
isWithdrawRewardsOpen,
isCanceled,
setIsWithdrawRewardsOpen,
}) => {
const {
Expand All @@ -45,21 +47,27 @@ const RewardsReleasable: FC<RewardsReleasableProps> = ({

return (
<>
{isReleasableRewardsErc20AddressesError && (
<div className="text-[16px] text-negative-11 font-bold">
Error while loading ERC20 tokens for rewards distribution, please reload the page.
{!isCanceled ? (
<div className="flex flex-col gap-8 border-b border-primary-2 pb-8">
<p className="text-[24px] text-neutral-9 font-bold">rewards to distribute</p>

{isReleasableRewardsErc20AddressesError && (
<div className="text-[16px] text-negative-11 font-bold">
Error while loading ERC20 tokens for rewards distribution, please reload the page.
</div>
)}
{rankings.map((payee, index) => (
<RewardsDistributionTable
key={index}
chainId={chainId}
payee={payee}
releasableRewards={releasableRewards}
contractRewardsModuleAddress={rewardsModuleAddress}
abiRewardsModule={rewardsAbi}
/>
))}
</div>
)}
{rankings.map((payee, index) => (
<RewardsDistributionTable
key={index}
chainId={chainId}
payee={payee}
releasableRewards={releasableRewards}
contractRewardsModuleAddress={rewardsModuleAddress}
abiRewardsModule={rewardsAbi}
/>
))}
) : null}

<DialogWithdrawFundsFromRewardsModule isOpen={isWithdrawRewardsOpen} setIsOpen={setIsWithdrawRewardsOpen}>
<ContestWithdrawRewards
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { FOOTER_LINKS } from "@config/links";
import { ofacAddresses } from "@config/ofac-addresses/ofac-addresses";
import { chains } from "@config/wagmi";
import { extractPathSegments } from "@helpers/extractPath";
import { REWARDS_CANCELED_VERSION, useCancelRewards } from "@hooks/useCancelRewards";
import { useContestStore } from "@hooks/useContest/store";
import useRewardsModule from "@hooks/useRewards";
import { useRewardsStore } from "@hooks/useRewards/store";
Expand All @@ -15,6 +16,9 @@ import CreateRewardsModule from "./components/CreateRewardsModule";
import NoRewardsInfo from "./components/NoRewards";
import RewardsReleasable from "./components/ReleasableRewards";
import RewardsReleased from "./components/ReleasedRewards";
import { compareVersions } from "compare-versions";
import CancelRewards from "./components/CancelRewards";
import { useMediaQuery } from "react-responsive";

const ContestRewards = () => {
const asPath = usePathname();
Expand Down Expand Up @@ -43,6 +47,18 @@ const ContestRewards = () => {
const { address: accountAddress } = useAccount();
const creator = contestAuthorEthereumAddress === accountAddress;
const githubLink = FOOTER_LINKS.find(link => link.label === "Github");
const {
isCanceled,
isLoading: isRewardsCanceledLoading,
isSuccess: isRewardsCanceledSuccess,
} = useCancelRewards({
rewardsAddress: rewardsStore.rewards.contractAddress as `0x${string}`,
abi: rewardsStore.rewards.abi,
chainId,
version,
});
const hasCanceledFunction = compareVersions(version, REWARDS_CANCELED_VERSION) >= 0;
const isMobile = useMediaQuery({ query: "(max-width: 768px)" });

useAccountEffect({
onConnect(data) {
Expand Down Expand Up @@ -80,7 +96,29 @@ const ContestRewards = () => {
{rewardsStore.isSuccess && (
<div className="flex flex-col gap-12">
<div className={`flex flex-col gap-8 border-b border-primary-2 ${creator ? "pb-8" : ""}`}>
<p className="text-[24px] text-neutral-9 font-bold">rewards pool configuration</p>
{isCanceled ? (
<div className="flex">
<div className="inline-block border border-negative-11 py-2 px-4 rounded-lg">
<p className="text-negative-11 text-[16px] md:text-[20px] font-bold text-center">
{isMobile
? "rewards were canceled by the creator"
: "rewards were canceled by the creator and are no longer active"}
</p>
</div>
</div>
) : null}
<div className="flex justify-between items-center">
<p className="text-[24px] text-neutral-9 font-bold">rewards pool configuration</p>
{creator && hasCanceledFunction && !isCanceled && (
<CancelRewards
rewardsAddress={rewardsStore.rewards.contractAddress as `0x${string}`}
abi={rewardsStore.rewards.abi}
chainId={chainId}
version={version}
/>
)}
</div>

<div className="flex flex-col gap-3">
<p className="text-[16px] text-neutral-11 font-bold">rewards pool address:</p>
<a
Expand Down Expand Up @@ -118,40 +156,42 @@ const ContestRewards = () => {
</div>
</div>

{creator ? (
{creator && !isRewardsCanceledLoading && isRewardsCanceledSuccess ? (
<div className="flex gap-8 items-center">
<button
className="bg-transparent text-positive-11 text-[16px] hover:text-positive-9 transition-colors duration-300"
onClick={() => setIsFundRewardsOpen(true)}
>
add funds
</button>
<button
className="bg-transparent text-negative-11 text-[16px] hover:text-negative-10 transition-colors duration-300"
onClick={() => setIsWithdrawRewardsOpen(true)}
>
remove funds
</button>
{!isCanceled && (
<button
className="bg-transparent text-positive-11 text-[16px] hover:text-positive-9 transition-colors duration-300"
onClick={() => setIsFundRewardsOpen(true)}
>
add funds
</button>
)}
{(isCanceled && hasCanceledFunction) || !hasCanceledFunction ? (
<button
className="bg-transparent text-negative-11 text-[16px] hover:text-negative-10 transition-colors duration-300"
onClick={() => setIsWithdrawRewardsOpen(true)}
>
remove funds
</button>
) : null}
</div>
) : null}
</div>
</div>

<div className="flex flex-col gap-8 border-b border-primary-2 pb-8">
<p className="text-[24px] text-neutral-9 font-bold">rewards to distribute</p>
{rewardsStore.rewards.contractAddress &&
rewardsStore.rewards.abi &&
rewardsStore.rewards.payees.length > 0 && (
<RewardsReleasable
rewardsModuleAddress={rewardsStore.rewards.contractAddress}
chainId={chainId}
rewardsAbi={rewardsStore.rewards.abi}
rankings={rewardsStore.rewards.payees}
isWithdrawRewardsOpen={isWithdrawRewardsOpen}
setIsWithdrawRewardsOpen={setIsWithdrawRewardsOpen}
/>
)}
</div>
{rewardsStore.rewards.contractAddress &&
rewardsStore.rewards.abi &&
rewardsStore.rewards.payees.length > 0 && (
<RewardsReleasable
rewardsModuleAddress={rewardsStore.rewards.contractAddress}
chainId={chainId}
rewardsAbi={rewardsStore.rewards.abi}
rankings={rewardsStore.rewards.payees}
isWithdrawRewardsOpen={isWithdrawRewardsOpen}
setIsWithdrawRewardsOpen={setIsWithdrawRewardsOpen}
isCanceled={isCanceled}
/>
)}

<div className="flex flex-col gap-8">
<p className="text-[24px] text-neutral-9 font-bold">previously distributed rewards</p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { chains } from "@config/wagmi";
import { extractPathSegments } from "@helpers/extractPath";
import { formatBalance } from "@helpers/formatBalance";
import { returnOnlySuffix } from "@helpers/ordinalSuffix";
import { useCancelRewards } from "@hooks/useCancelRewards";
import { transform } from "@hooks/useDistributeRewards";
import { useReleasableRewards } from "@hooks/useReleasableRewards";
import { useReleasedRewards } from "@hooks/useReleasedRewards";
Expand All @@ -15,9 +16,10 @@ import { useReadContract } from "wagmi";
interface ContestRewardsInfoProps {
rewardsModuleAddress: string;
rewardsAbi: Abi;
version: string;
}

const ContestRewardsInfo: FC<ContestRewardsInfoProps> = ({ rewardsModuleAddress, rewardsAbi }) => {
const ContestRewardsInfo: FC<ContestRewardsInfoProps> = ({ rewardsModuleAddress, rewardsAbi, version }) => {
const pathname = usePathname();
const { chainName } = extractPathSegments(pathname);
const chainId = chains.filter(
Expand All @@ -35,6 +37,12 @@ const ContestRewardsInfo: FC<ContestRewardsInfoProps> = ({ rewardsModuleAddress,
},
},
});
const { isCanceled } = useCancelRewards({
rewardsAddress: rewardsModuleAddress as `0x${string}`,
chainId,
abi: rewardsAbi,
version,
});

const {
data: releasableRewards,
Expand Down Expand Up @@ -96,7 +104,7 @@ const ContestRewardsInfo: FC<ContestRewardsInfoProps> = ({ rewardsModuleAddress,
);
}

if (!currentReward || isError) return null;
if (!currentReward || isError || isCanceled) return null;

const currentRewardAmount = transform(
currentReward?.amount ?? 0n,
Expand Down
Loading

0 comments on commit 9600d02

Please sign in to comment.