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

feat: 7702 FE #1245

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
24 changes: 24 additions & 0 deletions examples/ui-demo/src/components/icons/key.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
export const Key = ({ className }: { className?: string }) => (
<svg
width="94"
height="94"
viewBox="0 0 94 94"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className={className}
>
<path
opacity="0.4"
fill-rule="evenodd"
clip-rule="evenodd"
d="M79.9001 34.4667C79.9001 43.9844 72.1844 51.7001 62.6667 51.7001C60.4556 51.7001 58.3418 51.2837 56.3993 50.525L53.2667 50.1334L50.1334 50.9167L47.7834 62.6667L33.6834 65.0167L32.9001 73.6334L17.2334 75.9834V72.0667L47.6664 42.9569C46.245 40.4509 45.4334 37.5536 45.4334 34.4667C45.4334 24.949 53.149 17.2334 62.6667 17.2334C72.1844 17.2334 79.9001 24.949 79.9001 34.4667ZM70.5001 28.2001C70.5001 31.661 67.6944 34.4667 64.2334 34.4667C60.7724 34.4667 57.9667 31.661 57.9667 28.2001C57.9667 24.7391 60.7724 21.9334 64.2334 21.9334C67.6944 21.9334 70.5001 24.7391 70.5001 28.2001Z"
fill="#363FF9"
/>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M44.893 17.2863C53.164 9.01525 66.574 9.01525 74.845 17.2863C83.116 25.5573 83.116 38.9672 74.845 47.2383C68.48 53.6033 59.0747 55.068 51.3105 51.641L49.5929 62.2535C49.3405 63.8133 48.0549 64.9987 46.4798 65.124L35.2172 66.0204C35.0658 66.0324 34.9482 66.157 34.9449 66.3088L34.8061 72.6164C34.7673 74.3802 33.3966 75.8268 31.6375 75.9604L18.2405 76.978C16.2582 77.1285 14.5637 75.5674 14.5516 73.5795L14.502 65.4329C14.4974 64.6822 14.7936 63.9609 15.3245 63.43L39.7777 38.9768C37.3217 31.6101 39.0239 23.1554 44.893 17.2863ZM72.6294 19.5019C65.582 12.4545 54.156 12.4545 47.1086 19.5019C42.0769 24.5336 40.6355 31.7995 42.7934 38.1135C43.1338 39.1096 42.9203 40.2654 42.1237 41.062L17.6361 65.5496L17.6849 73.5604C17.6859 73.7319 17.8321 73.8666 18.0031 73.8536L31.4002 72.836C31.5519 72.8245 31.6702 72.6997 31.6735 72.5475L31.8123 66.2399C31.851 64.4808 33.2147 63.0365 34.9686 62.8969L46.2312 62.0006C46.3672 61.9898 46.4781 61.8875 46.4998 61.7529L48.2724 50.8006C48.5931 48.8192 50.7216 47.9277 52.3547 48.6751C59.0164 51.7239 67.1487 50.5034 72.6294 45.0227C79.6768 37.9753 79.6768 26.5492 72.6294 19.5019ZM59.3913 22.9591C62.092 20.2584 66.4707 20.2584 69.1714 22.9591C71.8721 25.6598 71.8721 30.0385 69.1714 32.7392C66.4707 35.4399 62.092 35.4399 59.3913 32.7392C56.6906 30.0385 56.6906 25.6598 59.3913 22.9591ZM66.9558 25.1747C65.4787 23.6977 63.084 23.6977 61.6069 25.1747C60.1299 26.6518 60.1299 29.0466 61.6069 30.5236C63.084 32.0007 65.4787 32.0007 66.9558 30.5236C68.4328 29.0466 68.4328 26.6518 66.9558 25.1747Z"
fill="#020617"
/>
</svg>
);
3 changes: 2 additions & 1 deletion examples/ui-demo/src/components/icons/loading.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useTheme } from "@/state/useTheme";
export const LoadingIcon = () => {
export const LoadingIcon = ({ className }: { className?: string }) => {
const theme = useTheme();
const animationClass =
theme === "dark" ? "animate-ui-loading-dark" : "animate-ui-loading-light";
Expand All @@ -11,6 +11,7 @@ export const LoadingIcon = () => {
viewBox="0 0 48 48"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className={className}
>
<circle
className={animationClass}
Expand Down
6 changes: 3 additions & 3 deletions examples/ui-demo/src/components/preview/AuthCardWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { cn } from "@/lib/utils";
import { useTheme } from "@/state/useTheme";
import { AuthCard, useUser } from "@account-kit/react";
import { EOAPostLogin } from "../shared/eoa-post-login/EOAPostLogin";
import { MintCard } from "../shared/mint-card/MintCard";
import { Wrapper7702 } from "../shared/7702/Wrapper";

export function AuthCardWrapper({ className }: { className?: string }) {
const theme = useTheme();
Expand Down Expand Up @@ -53,6 +53,6 @@ const RenderContent = () => {
</div>
);
}

return <MintCard />;
return <Wrapper7702 />;
// return <MintCard />;
};
18 changes: 18 additions & 0 deletions examples/ui-demo/src/components/shared/7702/Button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { PropsWithChildren } from "react";

export const Button = ({
children,
className,
...rest
}: PropsWithChildren<
React.ComponentProps<"button"> & { className?: string }
>) => {
return (
<button
className={`border bg-bg-surface-default text-fg-primary rounded-lg px-3 text-sm font-semibold h-10 flex items-center justify-center text-center disabled:bg-bg-surface-disabled disabled:text-fg-disabled ${className}`}
{...rest}
>
{children}
</button>
);
};
101 changes: 101 additions & 0 deletions examples/ui-demo/src/components/shared/7702/MintCard7702.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import Image from "next/image";
import { LoadingIcon } from "@/components/icons/loading";
import { Button } from "./Button";
import { MintStages } from "./MintStages";

type NFTLoadingState = "initial" | "loading" | "success";
export type MintStatus = {
signing: NFTLoadingState;
gas: NFTLoadingState;
batch: NFTLoadingState;
};

export const MintCard7702 = ({
isLoading,
isDisabled,
status,
nftTransfered,
handleCollectNFT,
uri,
}: {
isLoading: boolean;
isDisabled?: boolean;
status: MintStatus;
nftTransfered: boolean;
handleCollectNFT: () => void;
uri?: string;
}) => {
return (
<div
className="bg-bg-surface-default rounded-lg p-6 w-[278px] h-[430px] flex flex-col"
style={{
boxShadow:
"0px 50px 50px 0px rgba(0, 0, 0, 0.09), 0px 12px 27px 0px rgba(0, 0, 0, 0.10)",
}}
>
{uri ? (
<div className="relative flex flex-col items-center">
<div className="relative w-full h-[170px] overflow-hidden mb-4 rounded-xl">
<Image
src={uri}
alt="An NFT"
layout="fill"
objectFit="cover"
priority
/>
</div>
</div>
) : (
<div className="flex justify-center items-center h-[170px]">
<LoadingIcon />
</div>
)}
<div className="mb-3">
<h3 className="text-fg-primary text-xl font-semibold">
Gasless transactions
</h3>
</div>
{!nftTransfered ? (
<>
<p className="text-fg-primary text-sm">
Sponsor gas and sign in the background for a one-click transaction
experience.
</p>
<div className="flex justify-between items-center">
<p className="text-fg-secondary text-base">Gas Fee</p>
<p>
<span className="line-through mr-1 text-base text-fg-primary align-top">
$0.02
</span>
<span
className="text-base align-top"
style={{
background:
"linear-gradient(132deg, #FF9C27 0%, #FD48CE 100%)",
WebkitBackgroundClip: "text",
backgroundClip: "text",
WebkitTextFillColor: "transparent",
}}
>
Free
</span>
</p>
</div>
</>
) : (
<MintStages status={status} />
)}
<Button
className="w-full mt-auto"
onClick={handleCollectNFT}
disabled={isLoading || isDisabled}
>
{!nftTransfered
? "Collect NFT"
: isLoading
? "Collecting NFT..."
: "Re-collect NFT"}
</Button>
</div>
);
};
52 changes: 52 additions & 0 deletions examples/ui-demo/src/components/shared/7702/MintStages.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { CheckCircleFilledIcon } from "@/components/icons/check-circle-filled";
import { LoadingIcon } from "@/components/icons/loading";
import { MintStatus } from "./MintCard7702";
import { loadingState } from "./Transactions";

export const MintStages = ({ status }: { status: MintStatus }) => {
return (
<div>
<Stage
icon={status.signing}
description="Invisibly signing txs for you..."
/>
<Stage
icon={status.gas}
description="Sponsoring gas behind the scenes..."
/>
<Stage
icon={status.batch}
description="Deploying your smart account..."
/>
</div>
);
};

const Stage = ({
icon,
description,
className,
}: {
icon: loadingState;
description: string | JSX.Element;
className?: string;
}) => {
return (
<div className={`flex ${className}`}>
<div className="w-4 h-4 mr-2">{getMintIcon(icon)}</div>
<p className="text-sm text-fg-secondary">{description}</p>
</div>
);
};

export const getMintIcon = (icon: loadingState) => {
switch (icon) {
case "loading":
case "initial":
return <LoadingIcon className="h-4 w-4" />;
case "success":
return (
<CheckCircleFilledIcon className=" h-4 w-4 fill-demo-surface-success" />
);
}
};
54 changes: 54 additions & 0 deletions examples/ui-demo/src/components/shared/7702/Transactions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { ExternalLinkIcon } from "@/components/icons/external-link";
import { TransactionType } from "./useTransaction";
import { CheckCircleFilledIcon } from "@/components/icons/check-circle-filled";
import { LoadingIcon } from "@/components/icons/loading";

export type loadingState = "loading" | "success" | "initial";

export const Transactions = ({
transactions,
}: {
transactions: TransactionType[];
}) => {
return (
<div>
{transactions.map((transaction, i) => (
<Transaction key={i} {...transaction} />
))}
</div>
);
};

const Transaction = ({
className,
externalLink,
description,
state,
}: TransactionType & { className?: string }) => {
const getText = () => {
if (state === "initial") {
return "...";
}
if (state === "initiating") {
return "Initiating buy...";
}
if (state === "next") {
return "Next buy in 10 seconds...";
}
return description;
};

return (
<div className={`flex ${className}`}>
<div className="w-4 h-4 mr-2">
{state === "complete" ? (
<CheckCircleFilledIcon className=" h-4 w-4 fill-demo-surface-success" />
) : (
<LoadingIcon className="h-4 w-4" />
)}
</div>
<p className="text-sm text-fg-secondary">{getText()}</p>
{externalLink && <ExternalLinkIcon className="w-4 h-4 ml-2" />}
</div>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { Key } from "@/components/icons/key";
import { Button } from "./Button";
import { useState } from "react";
import { Transactions } from "./Transactions";
import { TransactionType } from "./useTransaction";

export const TransactionsCard = ({
isLoading,
isDisabled,
transactions,
handleTransactions,
}: {
isLoading: boolean;
isDisabled?: boolean;
transactions: TransactionType[];
handleTransactions: () => void;
}) => {
const [hasClicked, setHasClicked] = useState(false);
const handleClick = () => {
setHasClicked(true);
handleTransactions();
};
return (
<div
className="bg-bg-surface-default rounded-lg p-6 w-[278px] h-[430px] flex flex-col"
style={{
boxShadow:
"0px 50px 50px 0px rgba(0, 0, 0, 0.09), 0px 12px 27px 0px rgba(0, 0, 0, 0.10)",
}}
>
<div
className="rounded-xl w-full h-[170px] mb-3 flex justify-center items-center"
style={{
background: `rgba(54, 63, 249, 0.05)`,
}}
>
<Key />
</div>
<h3 className="text-fg-primary text-xl font-semibold">
Recurring transactions
</h3>
{!hasClicked ? (
<p className="text-fg-primary text-sm">
Set up a dollar-cost average order by creating a session key with
permission to buy ETH every 10 seconds.
</p>
) : (
<Transactions transactions={transactions} />
)}

<Button
className="mt-auto"
onClick={handleClick}
disabled={isLoading || isDisabled}
>
{!hasClicked
? "Create session key"
: isLoading
? "Creating session key..."
: "Restart session key"}
</Button>
</div>
);
};
37 changes: 37 additions & 0 deletions examples/ui-demo/src/components/shared/7702/Wrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { MintCard7702 } from "./MintCard7702";
import { TransactionsCard } from "./TransactionsCard";
import { useMint } from "./useMint";
import { useTransactions } from "./useTransaction";

export const Wrapper7702 = () => {
const {
isLoading: isLoadingTransactions,
transactions,
handleTransactions,
} = useTransactions();
const {
isLoading: isLoadingMint,
status,
nftTransfered,
handleCollectNFT,
uri,
} = useMint();
return (
<div className="flex gap-6">
<MintCard7702
isLoading={isLoadingMint || isLoadingTransactions}
isDisabled={isLoadingTransactions}
status={status}
nftTransfered={nftTransfered}
handleCollectNFT={handleCollectNFT}
uri={uri}
/>
<TransactionsCard
isDisabled={isLoadingMint}
isLoading={isLoadingTransactions}
transactions={transactions}
handleTransactions={handleTransactions}
/>
</div>
);
};
Loading
Loading