Skip to content

Commit

Permalink
Provide start over button for steps 1-5
Browse files Browse the repository at this point in the history
  • Loading branch information
MattPereira committed Aug 10, 2024
1 parent 4d75bbe commit 363c739
Show file tree
Hide file tree
Showing 13 changed files with 140 additions and 65 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,6 @@ node_modules

# cli
dist

# env
.env
7 changes: 7 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
-include .env

fork: fork-sepolia fork-mainnet fork-gnosis

fork-%:
@echo "Forking the $* network..."
anvil --fork-url $($(shell echo $* | tr a-z A-Z)_RPC_URL) --chain-id 31337
4 changes: 2 additions & 2 deletions packages/nextjs/app/cow/_components/PoolConfiguration.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export const PoolConfiguration = () => {
return (
<>
<div className="bg-base-200 p-7 rounded-xl w-full sm:w-[555px] flex flex-grow shadow-lg">
<div className="flex flex-col items-center gap-4 w-full">
<div className="flex flex-col items-center gap-3 w-full">
<h5 className="text-xl md:text-2xl font-bold">Configure your pool</h5>

<div className="w-full">
Expand Down Expand Up @@ -147,7 +147,7 @@ export const PoolConfiguration = () => {
</Link>
</Alert>
) : (
<Alert type="warning">
<Alert type="warning" showIcon={false}>
<div className="form-control">
<label className="label cursor-pointer flex gap-4 m-0 p-0">
<input
Expand Down
60 changes: 32 additions & 28 deletions packages/nextjs/app/cow/_components/PoolCreation.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import { useEffect, useState } from "react";
import { StepsDisplay } from "./StepsDisplay";
import { PoolResetModal, StepsDisplay } from "./";
import { Address, parseUnits } from "viem";
import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
import { Alert, ExternalLinkButton, TextField, TokenField, TransactionButton } from "~~/components/common/";
import {
type PoolCreationState,
getPoolUrl,
useBindPool,
useCreatePool,
useFinalizePool,
useNewPoolEvents,
usePoolCreationPersistedState,
useReadPool,
useSetSwapFee,
} from "~~/hooks/cow/";
import { getPoolUrl } from "~~/hooks/cow/getPoolUrl";
import { PoolCreationState } from "~~/hooks/cow/usePoolCreationState";
import { usePoolCreationPersistedState } from "~~/hooks/cow/usePoolCreationState";
import { useTargetNetwork } from "~~/hooks/scaffold-eth/useTargetNetwork";
import { useApproveToken, useReadToken } from "~~/hooks/token";
import { getBlockExplorerAddressLink } from "~~/utils/scaffold-eth";
Expand All @@ -28,6 +28,7 @@ export const PoolCreation = ({ state, clearState }: ManagePoolCreationProps) =>
const token2RawAmount = parseUnits(state.token2Amount, state.token2.decimals);

const [userPoolAddress, setUserPoolAddress] = useState<Address>();
const [isResetModalOpen, setIsResetModalOpen] = useState(false);

useNewPoolEvents(setUserPoolAddress);
const { targetNetwork } = useTargetNetwork();
Expand Down Expand Up @@ -131,6 +132,7 @@ export const PoolCreation = ({ state, clearState }: ManagePoolCreationProps) =>
};

useEffect(() => {
if (state.step === 1) return;
if (pool && pool.numTokens < 2n) {
if (allowance1 < token1RawAmount || allowance2 < token2RawAmount) {
setPersistedState({ ...state, step: 2 });
Expand All @@ -145,15 +147,16 @@ export const PoolCreation = ({ state, clearState }: ManagePoolCreationProps) =>
setPersistedState({ ...state, step: 5 });
}
}
if (pool && pool.isFinalized && state.step !== 1) setPersistedState({ ...state, step: 6 });
if (pool && pool.isFinalized) setPersistedState({ ...state, step: 6 });
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [pool, allowance1, allowance2, token1RawAmount, token2RawAmount]);

return (
<>
<div className="bg-base-200 p-7 rounded-xl w-full sm:w-[555px] flex flex-grow shadow-lg">
<div className="flex flex-col items-center gap-4 w-full">
<h5 className="text-xl md:text-2xl font-bold">Pool preview</h5>
<div className="flex flex-col items-center gap-3 w-full">
<h5 className="text-xl md:text-2xl font-bold text-center">Preview your pool</h5>

<div className="w-full">
<div className="ml-1 mb-1">Selected pool tokens:</div>
<div className="w-full flex flex-col gap-3">
Expand All @@ -168,17 +171,12 @@ export const PoolCreation = ({ state, clearState }: ManagePoolCreationProps) =>
{state.step < 6 && <StepsDisplay currentStep={state.step} />}

{pool && state.step === 6 && (
<>
<div className="bg-base-100 w-full py-4 rounded-xl shadow-md flex justify-center">
<div className="font-semibold sm:text-lg overflow-hidden text-transparent bg-clip-text bg-gradient-to-r from-violet-500 via-violet-300 via-40% to-orange-400">
{pool.address}
</div>
</div>
<div className="bg-base-200 w-full p-5 rounded-xl flex flex-col gap-5">
<Alert type="success">Your CoW AMM pool was successfully created!</Alert>

<Alert type="success">
Your CoW AMM pool was successfully created! Because of caching, it may take a few minutes for the pool to
appear in the Balancer app
</Alert>
<div className="text-center">
<div className=" sm:text-xl overflow-hidden ">{pool.address}</div>
</div>

<div className="grid grid-cols-1 sm:grid-cols-2 gap-4 w-full">
<ExternalLinkButton href={getPoolUrl(state.chainId, pool.address)} text="View on Balancer" />
Expand All @@ -187,11 +185,22 @@ export const PoolCreation = ({ state, clearState }: ManagePoolCreationProps) =>
text="View on Etherscan"
/>
</div>
</>

<Alert type="warning">It may take a few minutes to appear in the Balancer app</Alert>
</div>
)}

{isWrongNetwork && <Alert type="error">You&apos;re connected to the wrong network</Alert>}

{txError && (
<Alert type="error">
<div className="flex items-center gap-2">
<ExclamationTriangleIcon className="w-5 h-5" /> Error:{" "}
{(txError as { shortMessage?: string }).shortMessage || txError.message}
</div>
</Alert>
)}

{(() => {
switch (state.step) {
case 1:
Expand All @@ -203,9 +212,6 @@ export const PoolCreation = ({ state, clearState }: ManagePoolCreationProps) =>
isDisabled={isCreatePending || isWrongNetwork}
onClick={handleCreatePool}
/>
<div className="link flex items-center gap-2" onClick={clearState}>
Back to Configure
</div>
</>
);
case 2:
Expand Down Expand Up @@ -258,14 +264,12 @@ export const PoolCreation = ({ state, clearState }: ManagePoolCreationProps) =>
}
})()}

{txError && (
<Alert type="error">
<div className="flex items-center gap-2">
<ExclamationTriangleIcon className="w-5 h-5" /> Error:{" "}
{(txError as { shortMessage?: string }).shortMessage || txError.message}
</div>
</Alert>
{state.step < 6 && (
<div className=" link flex items-center gap-2" onClick={() => setIsResetModalOpen(true)}>
Start Over
</div>
)}
{isResetModalOpen && <PoolResetModal setIsModalOpen={setIsResetModalOpen} clearState={() => clearState()} />}
</>
);
};
37 changes: 37 additions & 0 deletions packages/nextjs/app/cow/_components/PoolResetModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { XMarkIcon } from "@heroicons/react/24/outline";

interface PoolResetModalModalProps {
setIsModalOpen: (isOpen: boolean) => void;
clearState: () => void;
}

export const PoolResetModal = ({ setIsModalOpen, clearState }: PoolResetModalModalProps) => {
return (
<div className="fixed inset-0 bg-black bg-opacity-75 flex justify-center items-center z-50">
<div className="absolute w-full h-full" onClick={() => setIsModalOpen(false)} />
<div className="w-[500px] relative bg-base-300 border border-base-200 rounded-lg p-6">
<div className="flex items-center justify-between mb-5">
<h5 className="font-bold text-xl mb-0">Are you sure?</h5>

<XMarkIcon className="w-6 h-6 hover:cursor-pointer " onClick={() => setIsModalOpen(false)} />
</div>

<div className="text-lg my-10">Resetting the pool creation progress cannot be undone.</div>
<div className="flex gap-3 justify-end">
<button
className="w-24 border border-base-content px-5 py-3 rounded-xl"
onClick={() => setIsModalOpen(false)}
>
Cancel
</button>
<button
onClick={clearState}
className="text-error bg-error-tint px-5 py-3 border border-error rounded-xl w-24"
>
Reset
</button>
</div>
</div>
</div>
);
};
1 change: 1 addition & 0 deletions packages/nextjs/app/cow/_components/index.tsx
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from "./StepsDisplay";
export * from "./PoolCreation";
export * from "./PoolResetModal";
34 changes: 22 additions & 12 deletions packages/nextjs/components/common/Alert.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,38 @@
import { CheckCircleIcon, ExclamationCircleIcon, ExclamationTriangleIcon } from "@heroicons/react/24/outline";

interface AlertProps {
type: "error" | "warning" | "success"; // `type` is required
showIcon?: boolean;
children?: React.ReactNode; // `children` can be optional
}

export const Alert: React.FC<AlertProps> = ({ children, type }) => {
export const Alert: React.FC<AlertProps> = ({ children, type, showIcon = true }) => {
let bgColor;
let borderColor;
// let textColor;
let textColor;
let icon;

if (type === "error") {
bgColor = "bg-[#d64e4e2b]";
borderColor = "border-red-500";
// textColor = "text-red-500";
bgColor = "bg-error-tint";
borderColor = "border-error";
textColor = "text-error";
icon = <ExclamationCircleIcon className="w-6 h-6" />;
} else if (type === "warning") {
bgColor = "bg-[#fb923c40]";
borderColor = "border-orange-400";
// textColor = "text-orange-400";
bgColor = "bg-warning-tint";
borderColor = "border-warning";
textColor = "text-warning";
icon = <ExclamationTriangleIcon className="w-6 h-6" />;
} else if (type === "success") {
bgColor = "bg-[#15803d33]";
borderColor = "border-green-500";
// textColor = "text-green-400";
bgColor = "bg-success-tint";
borderColor = "border-success";
textColor = "text-success";
icon = <CheckCircleIcon className="w-6 h-6" />;
}
return (
<div className={`${bgColor} border ${borderColor} rounded-lg p-3 overflow-auto w-full`}>
<div
className={`${textColor} ${bgColor} border ${borderColor} flex items-center gap-2 rounded-lg p-3 overflow-auto w-full`}
>
{showIcon && <div>{icon}</div>}
<div>{children}</div>
</div>
);
Expand Down
10 changes: 5 additions & 5 deletions packages/nextjs/components/common/ExternalLinkButton.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import Link from "next/link";
import { useTheme } from "next-themes";
// import { useTheme } from "next-themes";
import { ArrowTopRightOnSquareIcon } from "@heroicons/react/24/outline";

export const ExternalLinkButton = ({ href, text }: { href: string; text: string }) => {
const { resolvedTheme } = useTheme();
const textColor = resolvedTheme === "dark" ? "text-violet-300" : "text-violet-700";
// const { resolvedTheme } = useTheme();
// const textColor = resolvedTheme === "dark" ? "text-violet-300" : "text-violet-700";
return (
<div className="w-full">
<Link
className={`flex items-center justify-center gap-3 text-lg w-full rounded-xl h-[50px] border font-semibold ${textColor} border-violet-400 bg-[#8b5cf650] hover:bg-[#6d28d950]`}
// className={`flex items-center justify-center gap-3 text-lg w-full rounded-xl h-[50px] font-semibold ${textColor} bg-gradient-to-b from-custom-beige-start to-custom-beige-end to-100%">
// className={`flex items-center justify-center gap-3 text-lg w-full rounded-xl h-[50px] border font-semibold border-base-content`}
className={`flex items-center justify-center gap-3 text-lg w-full rounded-xl h-[50px] font-semibold text-neutral-700 bg-gradient-to-b from-custom-beige-start to-custom-beige-end to-100%"`}
rel="noopener noreferrer"
target="_blank"
href={href}
Expand Down
9 changes: 7 additions & 2 deletions packages/nextjs/components/common/TokenField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,10 @@ export const TokenField: React.FC<TokenFieldProps> = ({
min="0"
placeholder="0.0"
value={value}
className={`${sufficientAmount !== undefined && (amountGreaterThanBalance || !sufficientAmount) && "ring-1 ring-red-400"} border-0 h-[77px] pb-5 text-right text-2xl w-full input rounded-xl bg-base-300 disabled:bg-base-300 disabled:text-base-content`}
className={`border-0 h-[77px] pb-5 text-right text-2xl w-full input rounded-xl bg-base-300 disabled:bg-base-300 disabled:text-base-content
${
sufficientAmount !== undefined && (amountGreaterThanBalance || !sufficientAmount) && "ring-1 ring-red-400"
} `}
/>
<div className="absolute top-0 left-0 ">
<div className="p-2.5">
Expand All @@ -65,7 +68,7 @@ export const TokenField: React.FC<TokenFieldProps> = ({
{!isDisabled && <ChevronDownIcon className="w-4 h-4 mt-0.5" />}
</button>

{selectedToken && balance !== undefined && (
{selectedToken && balance !== undefined ? (
<div className={`flex items-center gap-2 text-neutral-400`}>
<div className="flex items-center gap-1">
<WalletIcon className="h-4 w-4 mt-0.5" /> {formatToHuman(balance, selectedToken?.decimals || 0)}
Expand All @@ -82,6 +85,8 @@ export const TokenField: React.FC<TokenFieldProps> = ({
</div>
)}
</div>
) : (
<div className="text-neutral-400 ml-1">{selectedToken?.name}</div>
)}
</div>
</div>
Expand Down
15 changes: 8 additions & 7 deletions packages/nextjs/components/common/TokenSelectModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,24 @@ export const TokenSelectModal: React.FC<ModalProps> = ({ tokenOptions, setIsModa
<div className="relative w-[500px]">
<div className="relative bg-base-300 border border-base-200 rounded-lg">
<div className="p-4 mb-2">
<XMarkIcon
className="absolute top-4 right-4 w-7 h-7 hover:cursor-pointer"
onClick={() => setIsModalOpen(false)}
/>
<div className="flex items-center justify-between mb-5">
<h5 className="ml-3 font-bold text-xl mb-0">Select a Token:</h5>

<XMarkIcon className="w-6 h-6 hover:cursor-pointer " onClick={() => setIsModalOpen(false)} />
</div>

<h5 className="font-bold text-xl mb-3">Select Token</h5>
<input
type="text"
placeholder="Search by symbol..."
value={searchText}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setSearchText(e.target.value)}
className="w-full input input-bordered rounded-xl bg-base-200 disabled:bg-base-300 px-5 h-[52px] text-lg"
className="w-full input rounded-xl bg-base-200 disabled:bg-base-200 px-5 h-[52px] text-lg"
/>
</div>

<div>
<VirtualList
className="flex flex-col gap-0 border-t border-neutral-500"
className="flex flex-col gap-0"
width="100%"
height={500}
itemCount={filteredTokenOptions.length}
Expand Down
4 changes: 3 additions & 1 deletion packages/nextjs/components/common/TransactionButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ export const TransactionButton = ({
<button
disabled={isDisabled}
onClick={onClick}
className={`shadow-lg flex flex-col items-center justify-center text-lg w-full sm:w-80 rounded-xl h-[50px] font-bold text-neutral-700 ${isDisabled ? "bg-neutral-500" : gradient}`}
className={`shadow-lg flex flex-col items-center justify-center text-lg w-full sm:w-80 rounded-xl h-[50px] font-bold text-neutral-700 ${
isDisabled ? "bg-neutral-500" : gradient
}`}
>
{isPending ? <span className="loading loading-bars loading-sm"></span> : title}
</button>
Expand Down
2 changes: 2 additions & 0 deletions packages/nextjs/hooks/cow/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ export * from "./useCreatePool";
export * from "./useFinalizePool";
export * from "./useBindPool";
export * from "./useSetSwapFee";
export * from "./getPoolUrl";
export * from "./usePoolCreationState";
Loading

0 comments on commit 363c739

Please sign in to comment.