From d779fc62d2a3470b063da91453ce94281265a112 Mon Sep 17 00:00:00 2001 From: Nick Lionis Date: Wed, 16 Oct 2024 18:33:05 +0300 Subject: [PATCH 1/4] mint-attestations-improvements --- .../MintAttestationProgressModal.tsx | 21 +++-- .../attestations/MintProgressModalBody.tsx | 4 +- .../attestations/MintYourImpactComponents.tsx | 6 +- .../components/BalanceDisplay.tsx | 49 +++++++----- .../attestations/utils/formatAmount.ts | 4 +- .../src/features/common/ShareButtons.tsx | 31 +++++--- .../src/features/common/components/Modal.tsx | 78 ++++++++++++------- .../Buttons/MintDonationImpactAction.tsx | 56 ++++++++----- .../src/features/round/ThankYou.tsx | 47 +++++------ .../src/hooks/attestations/config.ts | 1 + .../attestations/useAttestationStatus.ts | 11 ++- .../hooks/attestations/useEASAttestation.ts | 7 +- .../attestations/useGetAttestationData.ts | 4 +- 13 files changed, 199 insertions(+), 120 deletions(-) diff --git a/packages/grant-explorer/src/features/attestations/MintAttestationProgressModal.tsx b/packages/grant-explorer/src/features/attestations/MintAttestationProgressModal.tsx index 87db79dab..e8c2f3e97 100755 --- a/packages/grant-explorer/src/features/attestations/MintAttestationProgressModal.tsx +++ b/packages/grant-explorer/src/features/attestations/MintAttestationProgressModal.tsx @@ -1,6 +1,6 @@ import { Fragment, ReactNode } from "react"; import { Dialog, Transition } from "@headlessui/react"; -import { XMarkIcon } from "@heroicons/react/24/outline"; +import { ReactComponent as CloseIcon } from "../../assets/icons/close.svg"; interface MintAttestationProgressModalProps { isOpen: boolean; @@ -20,6 +20,9 @@ export default function MintAttestationProgressModal({ children, ...props }: MintAttestationProgressModalProps) { + const onAction = + heading !== "Mint your impact!" && heading !== "Your donation impact"; + return ( -
+
+ + {heading} +
- - {heading} -
diff --git a/packages/grant-explorer/src/features/attestations/MintProgressModalBody.tsx b/packages/grant-explorer/src/features/attestations/MintProgressModalBody.tsx index 83731f065..af1118902 100755 --- a/packages/grant-explorer/src/features/attestations/MintProgressModalBody.tsx +++ b/packages/grant-explorer/src/features/attestations/MintProgressModalBody.tsx @@ -99,17 +99,15 @@ export function MintProgressModalBodyHistory( chainId: AttestationChainId, address, }); - const [nextStep, setNextStep] = useState(false); return (
- {!nextStep ? ( + {status === ProgressStatus.SELECTING_COLOR ? (
void} nextStep={() => { toggleStartAction?.(); - setNextStep(true); }} previewBackground={previewBackground as string} selectedColor={selectedColor as string} diff --git a/packages/grant-explorer/src/features/attestations/MintYourImpactComponents.tsx b/packages/grant-explorer/src/features/attestations/MintYourImpactComponents.tsx index c4a5ebd57..4c89cd81f 100755 --- a/packages/grant-explorer/src/features/attestations/MintYourImpactComponents.tsx +++ b/packages/grant-explorer/src/features/attestations/MintYourImpactComponents.tsx @@ -274,7 +274,7 @@ export const PreviewFrameHistoryPage = ({
-
+
Pick your color
@@ -300,11 +300,11 @@ export const PreviewFrameHistoryPage = ({ >
diff --git a/packages/grant-explorer/src/features/attestations/components/BalanceDisplay.tsx b/packages/grant-explorer/src/features/attestations/components/BalanceDisplay.tsx index 1380ff61f..208713d84 100644 --- a/packages/grant-explorer/src/features/attestations/components/BalanceDisplay.tsx +++ b/packages/grant-explorer/src/features/attestations/components/BalanceDisplay.tsx @@ -1,6 +1,7 @@ import warningIcon from "../../../assets/warning.svg"; -import ethereumIcon from "../../../assets/icons/ethereum-icon.svg"; import { formatAmount } from "../utils/formatAmount"; +import { AttestationChainId } from "../utils/constants"; +import { getChainById, stringToBlobUrl } from "common"; export const BalanceDisplay = ({ balance, @@ -8,23 +9,35 @@ export const BalanceDisplay = ({ }: { balance: bigint | undefined; notEnoughFunds: boolean; -}) => ( -
-
- Ethereum -
- Mainnet -
- {notEnoughFunds ? ( -
- errorIcon - Balance: {formatAmount(balance)} ETH -
- ) : ( - Balance: {formatAmount(balance)} ETH - )} +}) => { + const chain = getChainById(AttestationChainId); + + return ( +
+
+ Ethereum +
+ {chain.prettyName} +
+ {notEnoughFunds ? ( +
+ errorIcon + Balance: {formatAmount(balance, 3)} ETH +
+ ) : ( + Balance: {formatAmount(balance, 3)} ETH + )} +
-
-); + ); +}; diff --git a/packages/grant-explorer/src/features/attestations/utils/formatAmount.ts b/packages/grant-explorer/src/features/attestations/utils/formatAmount.ts index ca047c62a..0f2f04af3 100644 --- a/packages/grant-explorer/src/features/attestations/utils/formatAmount.ts +++ b/packages/grant-explorer/src/features/attestations/utils/formatAmount.ts @@ -1,5 +1,5 @@ import { formatEther } from "viem"; -export function formatAmount(amount: bigint | undefined) { - return (amount ? Number(formatEther(amount)) : 0).toFixed(5); +export function formatAmount(amount: bigint | undefined, decimals = 5): string { + return (amount ? Number(formatEther(amount)) : 0).toFixed(decimals); } diff --git a/packages/grant-explorer/src/features/common/ShareButtons.tsx b/packages/grant-explorer/src/features/common/ShareButtons.tsx index c318dfd13..70e07fd5b 100755 --- a/packages/grant-explorer/src/features/common/ShareButtons.tsx +++ b/packages/grant-explorer/src/features/common/ShareButtons.tsx @@ -5,6 +5,9 @@ import shareOnFarcaster from "../../assets/farcaster-logo.svg"; import XTwitter from "../../assets/x-logo.svg"; import Link from "../../assets/link.svg"; import xIcon from "../../assets/x-logo-black.png"; +import { useNavigate } from "react-router-dom"; +import { useAccount } from "wagmi"; +import { useState } from "react"; export const ShareButtons = ({ attestationLink, @@ -17,23 +20,33 @@ export const ShareButtons = ({ const farcasterShareUrl = createFarcasterShareUrl(farcasterShareText, [ attestationLink, ]); + const [tooltipVisible, setTooltipVisible] = useState(false); // Add state for tooltip visibility + + const handleCopy = () => { + navigator.clipboard.writeText(attestationLink); + setTooltipVisible(true); // Show tooltip + setTimeout(() => setTooltipVisible(false), 1000); // Hide tooltip after 1 second + }; return (
-
+
Share Your Impact
-
+
Frame { - navigator.clipboard.writeText(attestationLink); - }} + onClick={handleCopy} // Update onClick to use handleCopy /> + {tooltipVisible && ( // Render tooltip conditionally + + Copied! + + )}
-
+
Frame window.open(twitterShareUrl, "_blank")} />
-
+
Frame window.open(shareUrl, "_blank")} - className="flex items-center justify-center shadow-sm font-mono text-xs rounded-lg border-1 text-black bg-white px-4 sm:px-10 hover:shadow-md border" + className="flex items-center justify-center shadow-md font-mono text-xs rounded-lg border-1 text-black bg-white px-4 sm:px-10 hover:shadow-lg" data-testid="x-button" > X logo @@ -120,8 +133,6 @@ export function TwitterButton(props: TwitterButtonParams) { ); } -import { useNavigate } from "react-router-dom"; -import { useAccount } from "wagmi"; export const ThankYouSectionButtons = ({ roundName, isMrc, diff --git a/packages/grant-explorer/src/features/common/components/Modal.tsx b/packages/grant-explorer/src/features/common/components/Modal.tsx index 970434e60..1e6fdf8ad 100644 --- a/packages/grant-explorer/src/features/common/components/Modal.tsx +++ b/packages/grant-explorer/src/features/common/components/Modal.tsx @@ -1,5 +1,5 @@ -import { ReactNode } from "react"; -import { Dialog } from "@headlessui/react"; +import { ReactNode, Fragment } from "react"; +import { Dialog, Transition } from "@headlessui/react"; import { ReactComponent as CloseIcon } from "../../../assets/icons/close.svg"; interface ModalProps { @@ -18,34 +18,56 @@ export default function Modal({ ...props }: ModalProps) { return ( - - + - {showCloseButton && ( - - )} - {children} - - + {showCloseButton && ( + + )} + {children} + + +
+
); } diff --git a/packages/grant-explorer/src/features/contributors/components/Buttons/MintDonationImpactAction.tsx b/packages/grant-explorer/src/features/contributors/components/Buttons/MintDonationImpactAction.tsx index 28d32f5f4..ccd25c691 100644 --- a/packages/grant-explorer/src/features/contributors/components/Buttons/MintDonationImpactAction.tsx +++ b/packages/grant-explorer/src/features/contributors/components/Buttons/MintDonationImpactAction.tsx @@ -17,12 +17,13 @@ import { useEstimateGas } from "../../../../hooks/attestations/useEstimateGas"; import { AttestationChainId } from "../../../attestations/utils/constants"; import { ethers } from "ethers"; import { useAttestationFee } from "../../hooks/useMintingAttestations"; +import { useMemo } from "react"; interface MintDonationImpactActionProps { toggleModal: () => void; toggleStartAction: (started: boolean) => void; selectBackground: (background: string) => void; - startAction: boolean; + startAction: boolean | undefined; isOpen: boolean; contributions: Contribution[]; transactionHash: string; @@ -72,7 +73,8 @@ export function MintDonationImpactAction({ !isOpen || !startAction || !imagesFetched, - selectedColor + selectedColor, + name as string | undefined ); const { @@ -87,12 +89,14 @@ export function MintDonationImpactAction({ const { data: attestationFee } = useAttestationFee(); - const { handleAttest, handleSwitchChain, status } = useEASAttestation( - AttestationChainId, - () => null, - data?.data, - attestationFee - ); + const { handleAttest, handleSwitchChain, status, updateStatus } = + useEASAttestation( + AttestationChainId, + () => null, + data?.data, + attestationFee, + true + ); const { data: balance, isLoading: isLoadingBalance } = useBalance({ chainId: AttestationChainId, @@ -104,16 +108,24 @@ export function MintDonationImpactAction({ ? false : balance.value < attestationFee + (gasEstimation ?? 0n); - const title = - status !== ProgressStatus.IS_SUCCESS - ? "Mint your impact" - : "Your donation impact"; - - const subheading = - status !== ProgressStatus.IS_SUCCESS - ? "Your unique donation graphic will be generated after you mint." - : "Share with your friends"; - + // Use useMemo to memoize title and subheading + const { title, subheading } = useMemo(() => { + const newTitle = + status === ProgressStatus.SELECTING_COLOR + ? "Mint your impact!" + : status !== ProgressStatus.IS_SUCCESS + ? "Mint your impact" + : "Your donation impact"; + + const newSubheading = + status === ProgressStatus.SELECTING_COLOR + ? "Capture your contribution onchain with an attestation and receive a unique visual representation of your donation. Please note, this is not an NFT, but an onchain attestation that verifies your support." + : status !== ProgressStatus.IS_SUCCESS + ? "Your attestation will be generated after you mint. " + : "Congratulations! Your attestation is now onchain, and here's the unique visual that represents your donation. Share your impact with your community and inspire others to join in!"; + + return { title: newTitle, subheading: newSubheading }; + }, [status]); const loading = isLoading || isLoadingENS || isRefetching || isRefetchingEstimate; @@ -124,6 +136,9 @@ export function MintDonationImpactAction({ onClose={() => { toggleModal(); toggleStartAction(false); + setTimeout(() => { + updateStatus(ProgressStatus.SELECTING_COLOR); + }, 500); }} heading={title} subheading={subheading} @@ -141,7 +156,10 @@ export function MintDonationImpactAction({ previewBackground={previewBackground} selectedColor={selectedColor} isTransactionHistoryPage - toggleStartAction={() => toggleStartAction(true)} + toggleStartAction={() => { + toggleStartAction(true); + updateStatus(ProgressStatus.NOT_STARTED); + }} impactImageCid={data?.impactImageCid} /> } diff --git a/packages/grant-explorer/src/features/round/ThankYou.tsx b/packages/grant-explorer/src/features/round/ThankYou.tsx index 033650061..e09673e85 100755 --- a/packages/grant-explorer/src/features/round/ThankYou.tsx +++ b/packages/grant-explorer/src/features/round/ThankYou.tsx @@ -157,7 +157,8 @@ export default function ThankYou() { !isModalOpen || isLoadingRoundNames || !imagesFetched, - selectedBackground + selectedBackground, + name as string | undefined ); const [impactImageCid, setImpactImageCid] = useState(); @@ -239,32 +240,32 @@ export default function ThankYou() { {/* Right Section */} - {debugModeEnabled && -
-
- {/* Main content */} -
-
-
-

- Mint your Impact -

-

- Create a unique onchain collectible that -

-

- shows off your donations from this round! -

+ {debugModeEnabled && ( +
+
+ {/* Main content */} +
+
+
+

+ Mint your Impact +

+

+ Create a unique onchain collectible that +

+

+ shows off your donations from this round! +

+
+
-
-
- } + )}
) : minted ? (
diff --git a/packages/grant-explorer/src/hooks/attestations/config.ts b/packages/grant-explorer/src/hooks/attestations/config.ts index 1dd1d120b..00330d0a0 100644 --- a/packages/grant-explorer/src/hooks/attestations/config.ts +++ b/packages/grant-explorer/src/hooks/attestations/config.ts @@ -15,6 +15,7 @@ export interface Signature { export enum ProgressStatus { IS_SUCCESS = "IS_SUCCESS", + SELECTING_COLOR = "SELECTING_COLOR", IN_PROGRESS = "IN_PROGRESS", NOT_STARTED = "NOT_STARTED", IS_ERROR = "IS_ERROR", diff --git a/packages/grant-explorer/src/hooks/attestations/useAttestationStatus.ts b/packages/grant-explorer/src/hooks/attestations/useAttestationStatus.ts index 3a656894a..aa9e69e53 100644 --- a/packages/grant-explorer/src/hooks/attestations/useAttestationStatus.ts +++ b/packages/grant-explorer/src/hooks/attestations/useAttestationStatus.ts @@ -5,7 +5,10 @@ import { useAccount } from "wagmi"; /** * Hook to manage attestation status. */ -export const useAttestationStatus = (chainId: number) => { +export const useAttestationStatus = ( + chainId: number, + isHistoryPage?: boolean +) => { const { chainId: userChainID } = useAccount(); const requiresSwitch = chainId !== userChainID; @@ -13,8 +16,10 @@ export const useAttestationStatus = (chainId: number) => { const initialStatus = useMemo(() => { return requiresSwitch ? ProgressStatus.SWITCH_CHAIN - : ProgressStatus.NOT_STARTED; - }, [requiresSwitch]); + : isHistoryPage + ? ProgressStatus.SELECTING_COLOR + : ProgressStatus.NOT_STARTED; + }, [requiresSwitch, isHistoryPage]); const [status, setStatus] = useState(initialStatus); diff --git a/packages/grant-explorer/src/hooks/attestations/useEASAttestation.ts b/packages/grant-explorer/src/hooks/attestations/useEASAttestation.ts index 5d5f099f9..23ea4d0f8 100644 --- a/packages/grant-explorer/src/hooks/attestations/useEASAttestation.ts +++ b/packages/grant-explorer/src/hooks/attestations/useEASAttestation.ts @@ -12,13 +12,14 @@ export const useEASAttestation = ( chainId: number, handleToggleModal: () => void, data: AttestInput | undefined, - attestationFee: bigint + attestationFee: bigint, + isHistoryPage?: boolean ) => { const { data: walletClient } = useWalletClient({ chainId }); const { address } = useAccount(); const publicClient = usePublicClient({ chainId }); - const { status, updateStatus } = useAttestationStatus(chainId); + const { status, updateStatus } = useAttestationStatus(chainId, isHistoryPage); const { easAddress, abi, schema } = useEASConfig(chainId); @@ -62,5 +63,5 @@ export const useEASAttestation = ( } }; - return { status, handleSwitchChain, handleAttest }; + return { status, handleSwitchChain, handleAttest, updateStatus }; }; diff --git a/packages/grant-explorer/src/hooks/attestations/useGetAttestationData.ts b/packages/grant-explorer/src/hooks/attestations/useGetAttestationData.ts index 12e9165de..5cbdc9e40 100644 --- a/packages/grant-explorer/src/hooks/attestations/useGetAttestationData.ts +++ b/packages/grant-explorer/src/hooks/attestations/useGetAttestationData.ts @@ -9,7 +9,8 @@ export const useGetAttestationData = ( transactionHashes: string[], getImpactImageData: (txHash: string) => Promise, isLoading: boolean, - selectedColor: string + selectedColor: string, + donorENS?: string ) => { return useQuery({ queryKey: [ @@ -39,6 +40,7 @@ export const useGetAttestationData = ( transactionHashes, chainId: AttestationChainId, base64Image: image, + donorENS: donorENS, }); try { From 2e00e5aa73a9d25084e6e9fa9818825b314e3424 Mon Sep 17 00:00:00 2001 From: Nick Lionis Date: Wed, 16 Oct 2024 23:55:33 +0300 Subject: [PATCH 2/4] replicates attestation designs --- .../attestations/MintYourImpactComponents.tsx | 4 +- .../src/features/common/ShareButtons.tsx | 64 +++++++------- .../Buttons/RainbowBorderButton.tsx | 2 +- .../ViewAttestationBody.tsx | 33 ------- .../ViewAttestationModal.tsx | 8 +- .../src/features/round/ThankYou.tsx | 85 +++++++++++-------- 6 files changed, 87 insertions(+), 109 deletions(-) delete mode 100644 packages/grant-explorer/src/features/contributors/components/ViewAttestationModal/ViewAttestationBody.tsx diff --git a/packages/grant-explorer/src/features/attestations/MintYourImpactComponents.tsx b/packages/grant-explorer/src/features/attestations/MintYourImpactComponents.tsx index 4c89cd81f..4c48b6b4c 100755 --- a/packages/grant-explorer/src/features/attestations/MintYourImpactComponents.tsx +++ b/packages/grant-explorer/src/features/attestations/MintYourImpactComponents.tsx @@ -384,8 +384,9 @@ export const ImpactMintingSuccess = ({ style={{ backgroundImage: `url(${bgImage})` }} >
+
-
); }; diff --git a/packages/grant-explorer/src/features/common/ShareButtons.tsx b/packages/grant-explorer/src/features/common/ShareButtons.tsx index 70e07fd5b..a9490a298 100755 --- a/packages/grant-explorer/src/features/common/ShareButtons.tsx +++ b/packages/grant-explorer/src/features/common/ShareButtons.tsx @@ -29,39 +29,37 @@ export const ShareButtons = ({ }; return ( -
-
- Share Your Impact -
-
- Frame - {tooltipVisible && ( // Render tooltip conditionally - - Copied! - - )} -
-
- Frame window.open(twitterShareUrl, "_blank")} - /> -
-
- Frame window.open(farcasterShareUrl, "_blank")} - /> -
+
+ Share +
+
+ Frame + {tooltipVisible && ( // Render tooltip conditionally + + Copied! + + )} +
+
+ Frame window.open(twitterShareUrl, "_blank")} + /> +
+
+ Frame window.open(farcasterShareUrl, "_blank")} + />
diff --git a/packages/grant-explorer/src/features/contributors/components/Buttons/RainbowBorderButton.tsx b/packages/grant-explorer/src/features/contributors/components/Buttons/RainbowBorderButton.tsx index 0074ec101..ec6603ded 100644 --- a/packages/grant-explorer/src/features/contributors/components/Buttons/RainbowBorderButton.tsx +++ b/packages/grant-explorer/src/features/contributors/components/Buttons/RainbowBorderButton.tsx @@ -16,7 +16,7 @@ export function RainbowBorderButton({ }: PropsWithChildren) { return (
-
-
-

{subheading}

-
-
{props.body}
- {children} - - -
- {/* Adding invisible button as modal needs to be displayed with a button */} - -
-
-
+
+
Pick your color
+ {Object.keys(colorMapper).map((key, index) => ( +
selectBackground(key)} + className={`w-5 h-5 rounded-full cursor-pointer ${ + selectedColor === key ? "border-1 border-black" : "" + }`} + style={{ + backgroundColor: + selectedColor === key + ? colorMapper[key as unknown as keyof typeof colorMapper] + : defaultColor, + }} + /> + ))} +
+
+
); @@ -358,19 +349,18 @@ export const HiddenAttestationFrame = ({
); }; -import bgImage from "../../assets/mint-your-impact-background.svg"; import { ImageWithLoading } from "../common/components/ImageWithLoading"; export const ImpactMintingSuccess = ({ attestationLink, impactImageCid, - containerSize = "w-[430px] h-[430px]", - imageSize = "w-[400px] h-[400px]", + imageSize = "size-[400px]", + isShareButtonsAbove = true, }: { attestationLink: string; impactImageCid?: string; - containerSize?: string; imageSize?: string; + isShareButtonsAbove?: boolean; }) => { const { data: image, @@ -378,23 +368,23 @@ export const ImpactMintingSuccess = ({ isFetching, } = useGetImages(impactImageCid ? [impactImageCid] : [], !!impactImageCid); - return ( -
-
- -
- -
-
-
+ return isShareButtonsAbove ? ( + <> + + + + ) : ( + <> + + + ); }; diff --git a/packages/grant-explorer/src/features/attestations/components/CostDetails.tsx b/packages/grant-explorer/src/features/attestations/components/CostDetails.tsx index 320fc01bb..8addb6b93 100644 --- a/packages/grant-explorer/src/features/attestations/components/CostDetails.tsx +++ b/packages/grant-explorer/src/features/attestations/components/CostDetails.tsx @@ -17,7 +17,7 @@ export const CostDetails = ({ const estimatedGasFormatted = `${formatAmount(estimatedGas)} ETH`; return ( -
+