Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reusable TriggerModal component in RainbowKitCustomConnectButton and Faucet #507

Closed
wants to merge 6 commits into from
Closed
33 changes: 33 additions & 0 deletions packages/nextjs/components/TriggerWithModal/Modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* A reusable modal component that displays content when triggered.
*/

type ModalProps = {
id: string; // Unique identifier for the modal.
children: React.ReactNode; // Content to be displayed inside the modal.
className?: string; // Optional classNames to be applied to the modal.
closeOnOutsideClick?: boolean; // Option to close the modal on outside click.
};

const Modal: React.FC<ModalProps> = ({ id, children, className, closeOnOutsideClick = true }) => {
return (
<div role="dialog">
{/* Checkbox for toggling the modal. */}
<input type="checkbox" id={`modal-${id}`} className="modal-toggle" />
<div className={`modal ${className || ""}`}>
<div className="modal-box">
{/* Close button for the modal. */}
<label htmlFor={`modal-${id}`} className="btn btn-sm btn-circle btn-ghost absolute right-2 top-2">
</label>
{/* Modal content. */}
{children}
</div>
{/* Transparent backdrop for closing on outside click */}
{closeOnOutsideClick && <label htmlFor={`modal-${id}`} className="modal-backdrop" />}
</div>
</div>
);
};

export default Modal;
22 changes: 22 additions & 0 deletions packages/nextjs/components/TriggerWithModal/Trigger.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* Triggers a modal with the corresponding ID when clicked.
*/

type TriggerProps = {
id: string; // ID of the associated modal.
children: React.ReactNode; // Content inside the trigger element (e.g. button, text).
className?: string; // Optional classNames to be applied to the label.
};

const Trigger: React.FC<TriggerProps> = ({ id, children, className }) => {
const labelClassName = `${className || ""}`; // Include provided classNames

return (
// Label that triggers the modal when clicked
<label htmlFor={`modal-${id}`} className={labelClassName}>
{children}
</label>
);
};

export default Trigger;
73 changes: 35 additions & 38 deletions packages/nextjs/components/scaffold-eth/Faucet.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { useEffect, useState } from "react";
import Modal from "../TriggerWithModal/Modal";
import Trigger from "../TriggerWithModal/Trigger";
import { Address as AddressType, createWalletClient, http, parseEther } from "viem";
import { useNetwork } from "wagmi";
import { hardhat } from "wagmi/chains";
Expand All @@ -10,6 +12,8 @@ import { notification } from "~~/utils/scaffold-eth";
// Account index to use from generated hardhat accounts.
const FAUCET_ACCOUNT_INDEX = 0;

const FAUCET_MODAL_ID = "faucet-modal";

const localWalletClient = createWalletClient({
chain: hardhat,
transport: http(),
Expand Down Expand Up @@ -82,49 +86,42 @@ export const Faucet = () => {

return (
<div>
<label htmlFor="faucet-modal" className="btn btn-primary btn-sm px-2 rounded-full font-normal normal-case">
<Trigger id={FAUCET_MODAL_ID} className="btn btn-primary btn-sm px-2 rounded-full font-normal normal-case">
<BanknotesIcon className="h-4 w-4" />
<span>Faucet</span>
</label>
<input type="checkbox" id="faucet-modal" className="modal-toggle" />
<label htmlFor="faucet-modal" className="modal cursor-pointer">
<label className="modal-box relative">
{/* dummy input to capture event onclick on modal box */}
<input className="h-0 w-0 absolute top-0 left-0" />
<h3 className="text-xl font-bold mb-3">Local Faucet</h3>
<label htmlFor="faucet-modal" className="btn btn-ghost btn-sm btn-circle absolute right-3 top-3">
</label>
<div className="space-y-3">
<div className="flex space-x-4">
<div>
<span className="text-sm font-bold">From:</span>
<Address address={faucetAddress} />
</div>
<div>
<span className="text-sm font-bold pl-3">Available:</span>
<Balance address={faucetAddress} />
</div>
</Trigger>

<Modal id={FAUCET_MODAL_ID}>
<h3 className="text-xl font-bold mb-3">Local Faucet</h3>
<div className="space-y-3">
<div className="flex space-x-4">
<div>
<span className="text-sm font-bold">From:</span>
<Address address={faucetAddress} />
</div>
<div className="flex flex-col space-y-3">
<AddressInput
placeholder="Destination Address"
value={inputAddress ?? ""}
onChange={value => setInputAddress(value)}
/>
<EtherInput placeholder="Amount to send" value={sendValue} onChange={value => setSendValue(value)} />
<button className="h-10 btn btn-primary btn-sm px-2 rounded-full" onClick={sendETH} disabled={loading}>
{!loading ? (
<BanknotesIcon className="h-6 w-6" />
) : (
<span className="loading loading-spinner loading-sm"></span>
)}
<span>Send</span>
</button>
<div>
<span className="text-sm font-bold pl-3">Available:</span>
<Balance address={faucetAddress} />
</div>
</div>
</label>
</label>
<div className="flex flex-col space-y-3">
<AddressInput
placeholder="Destination Address"
value={inputAddress ?? ""}
onChange={value => setInputAddress(value)}
/>
<EtherInput placeholder="Amount to send" value={sendValue} onChange={value => setSendValue(value)} />
<button className="h-10 btn btn-primary btn-sm px-2 rounded-full" onClick={sendETH} disabled={loading}>
{!loading ? (
<BanknotesIcon className="h-6 w-6" />
) : (
<span className="loading loading-spinner loading-sm"></span>
)}
<span>Send</span>
</button>
</div>
</div>
</Modal>
</div>
);
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { useState } from "react";
import Modal from "../TriggerWithModal/Modal";
import Trigger from "../TriggerWithModal/Trigger";
import { ConnectButton } from "@rainbow-me/rainbowkit";
import { QRCodeSVG } from "qrcode.react";
import CopyToClipboard from "react-copy-to-clipboard";
Expand All @@ -16,6 +18,8 @@ import { Address, Balance, BlockieAvatar } from "~~/components/scaffold-eth";
import { useAutoConnect, useNetworkColor } from "~~/hooks/scaffold-eth";
import { getBlockExplorerAddressLink, getTargetNetwork } from "~~/utils/scaffold-eth";

const QR_CODE_MODAL_ID = "qrcode-modal";

/**
* Custom Wagmi Connect Button (watch balance + custom design)
*/
Expand Down Expand Up @@ -134,10 +138,10 @@ export const RainbowKitCustomConnectButton = () => {
)}
</li>
<li>
<label htmlFor="qrcode-modal" className="btn-sm !rounded-xl flex gap-3 py-3">
<Trigger id={QR_CODE_MODAL_ID} className="btn-sm !rounded-xl flex gap-3 py-3">
<QrCodeIcon className="h-6 w-4 ml-2 sm:ml-0" />
<span className="whitespace-nowrap">View QR Code</span>
</label>
</Trigger>
</li>
<li>
<button className="menu-item btn-sm !rounded-xl flex gap-3 py-3" type="button">
Expand All @@ -163,27 +167,14 @@ export const RainbowKitCustomConnectButton = () => {
</li>
</ul>
</div>
<div>
<input type="checkbox" id="qrcode-modal" className="modal-toggle" />
<label htmlFor="qrcode-modal" className="modal cursor-pointer">
<label className="modal-box relative">
{/* dummy input to capture event onclick on modal box */}
<input className="h-0 w-0 absolute top-0 left-0" />
<label
htmlFor="qrcode-modal"
className="btn btn-ghost btn-sm btn-circle absolute right-3 top-3"
>
</label>
<div className="space-y-3 py-6">
<div className="flex space-x-4 flex-col items-center gap-6">
<QRCodeSVG value={account.address} size={256} />
<Address address={account.address} format="long" disableAddressLink />
</div>
</div>
</label>
</label>
</div>
<Modal id={QR_CODE_MODAL_ID}>
<div className="space-y-3 py-6">
<div className="flex space-x-4 flex-col items-center gap-6">
<QRCodeSVG value={account.address} size={256} />
<Address address={account.address} format="long" disableAddressLink />
</div>
</div>
</Modal>
</div>
);
})()}
Expand Down