From 5bf8a84f2d3b4c1c6c53ea4a821d67f0d671633f Mon Sep 17 00:00:00 2001 From: aphex Date: Tue, 7 Jan 2025 19:57:45 +0000 Subject: [PATCH 1/3] fix create market page crashing on visit --- apps/dapp/src/pages/create-auction-page.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/dapp/src/pages/create-auction-page.tsx b/apps/dapp/src/pages/create-auction-page.tsx index 15abfe73..83cd1203 100644 --- a/apps/dapp/src/pages/create-auction-page.tsx +++ b/apps/dapp/src/pages/create-auction-page.tsx @@ -1579,6 +1579,7 @@ export default function CreateAuctionPage() { // Define the options listed in the callback select dropdown const callbackOptions = React.useMemo(() => { form.resetField("callbacksType"); + const existingCallbacks = getExistingCallbacks(chainId); // Define the Baseline callback options @@ -1615,7 +1616,7 @@ export default function CreateAuctionPage() { }); return existingCallbacks; - }, [chainId, form]); + }, [chainId]); const handlePreview = () => { form.trigger(); From dff4daebb73898f4cccd180ceb1d5af5ed25b90c Mon Sep 17 00:00:00 2001 From: aphex Date: Thu, 19 Dec 2024 16:57:10 +0000 Subject: [PATCH 2/3] first pass at redesigning sealed bid ui --- .../src/modules/auction/auction-bid-input.tsx | 145 +++++++++++------- .../modules/auction/auction-sealed-bid.tsx | 23 +++ .../dapp/src/modules/auction/price-slider.tsx | 116 ++++++++++++++ .../src/modules/token/token-amount-input.tsx | 8 +- packages/ui/src/components/number-input.tsx | 4 +- packages/ui/src/style.css | 13 ++ 6 files changed, 249 insertions(+), 60 deletions(-) create mode 100644 apps/dapp/src/modules/auction/auction-sealed-bid.tsx create mode 100644 apps/dapp/src/modules/auction/price-slider.tsx diff --git a/apps/dapp/src/modules/auction/auction-bid-input.tsx b/apps/dapp/src/modules/auction/auction-bid-input.tsx index e19443af..b9941959 100644 --- a/apps/dapp/src/modules/auction/auction-bid-input.tsx +++ b/apps/dapp/src/modules/auction/auction-bid-input.tsx @@ -1,4 +1,4 @@ -import { FormField, FormItemWrapperSlim } from "@repo/ui"; +import { Text, FormField, FormItemWrapperSlim, UsdToggle } from "@repo/ui"; import { useFormContext } from "react-hook-form"; import { PropsWithAuction } from "@axis-finance/types"; import { TokenAmountInput } from "modules/token/token-amount-input"; @@ -6,6 +6,7 @@ import { trimCurrency } from "utils/currency"; import { useState } from "react"; import { formatUnits, parseUnits } from "viem"; import { BidForm } from "./auction-purchase"; +import { PriceSlider } from "./price-slider"; export function AuctionBidInput({ auction, @@ -18,6 +19,7 @@ export function AuctionBidInput({ disabled?: boolean; } & PropsWithAuction) { const form = useFormContext(); + const empData = auction.encryptedMarginalPrice!; const [formAmount] = form.watch(["quoteTokenAmount"]); @@ -49,62 +51,23 @@ export function AuctionBidInput({ setMinAmountOutFormatted(trimCurrency(minAmountOutDecimal)); }; + function handleSliderChange(values: number[]) { + const [amount] = values; + form.setValue("bidPrice", amount.toString()); + } + return (
-
-
- ( - - { - field.onChange(e); - - // Display USD value of input amount - const rawAmountIn = e as string; - // Update amount out value - handleAmountOutChange( - parseUnits(rawAmountIn, auction.quoteToken.decimals), - ); - }} - onClickMaxButton={() => { - // Take the minimum of the balance and the limit - let maxSpend = balance; - if (limit) { - maxSpend = balance < limit ? balance : limit; - } - - const maxSpendStr = formatUnits( - maxSpend, - auction.quoteToken.decimals, - ); - - form.setValue("quoteTokenAmount", maxSpendStr); - // Force re-validation - form.trigger("quoteTokenAmount"); - - // Update amount out value - handleAmountOutChange(maxSpend); - }} - /> - - )} - /> -
+
e.preventDefault()} + > + + {" "} + How much should {auction.baseToken.name} cost? + + +
@@ -159,6 +122,78 @@ export function AuctionBidInput({ />
+
+ +
+ +
+ ( + + { + field.onChange(e); + + // Display USD value of input amount + const rawAmountIn = e as string; + // Update amount out value + handleAmountOutChange( + parseUnits(rawAmountIn, auction.quoteToken.decimals), + ); + }} + onClickMaxButton={() => { + // Take the minimum of the balance and the limit + let maxSpend = balance; + if (limit) { + maxSpend = balance < limit ? balance : limit; + } + + const maxSpendStr = formatUnits( + maxSpend, + auction.quoteToken.decimals, + ); + + form.setValue("quoteTokenAmount", maxSpendStr); + // Force re-validation + form.trigger("quoteTokenAmount"); + + // Update amount out value + handleAmountOutChange(maxSpend); + }} + /> + + )} + /> +
+ + {showAmountOut && ( +
+ + If successful, you will receive at least: {minAmountOutFormatted} + {auction.baseToken.symbol} + +
+ )}
); } diff --git a/apps/dapp/src/modules/auction/auction-sealed-bid.tsx b/apps/dapp/src/modules/auction/auction-sealed-bid.tsx new file mode 100644 index 00000000..2a583271 --- /dev/null +++ b/apps/dapp/src/modules/auction/auction-sealed-bid.tsx @@ -0,0 +1,23 @@ +import { PriceSlider } from "./price-slider"; +import { TokenAmountInput } from "modules/token/token-amount-input"; +import { PropsWithAuction } from "@axis-finance/types"; + +export function AuctionSealedBid({ auction }: PropsWithAuction) { + const quoteSymbol = auction.quoteToken.symbol; + const label = `${quoteSymbol} for ${auction.baseToken.symbol}`; + + return ( +
+ {" "} +
+ + +
+ +
+ ); +} diff --git a/apps/dapp/src/modules/auction/price-slider.tsx b/apps/dapp/src/modules/auction/price-slider.tsx new file mode 100644 index 00000000..b2b73df0 --- /dev/null +++ b/apps/dapp/src/modules/auction/price-slider.tsx @@ -0,0 +1,116 @@ +import * as React from "react"; +import * as SliderPrimitive from "@radix-ui/react-slider"; +import { useFormContext } from "react-hook-form"; + +import { cn } from "@/utils"; +import { BidForm } from "./auction-purchase"; + +type PriceSliderProps = { + minAmountDisplay?: string; + maxAmountDisplay?: string; +}; + +const PriceSlider = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & PriceSliderProps +>(({ className, ...props }, ref) => { + const [price, setPrice] = React.useState(); + const [sliderValue, setSliderValue] = React.useState(); + + const { watch } = useFormContext(); + const [formPrice] = watch(["bidPrice", "baseTokenAmount"]); + + //Updates slider position and value when the price is typed in + React.useEffect(() => { + if (formPrice && formPrice !== price) { + setPrice(formPrice); + setSliderValue([+formPrice]); + } + }, [formPrice]); + + function handleChange(value: number[]) { + const [price] = value; + if (!props.min || price >= props.min) { + setPrice(price.toString()); + setSliderValue(value); + } + } + + const fadeLeft = price && isBelowLowerBound(+price, props.min, props.max); + const fadeRight = price && isAboveUpperBound(+price, props.min, props.max); + + return ( +
+
+
+
+ | +
+
+ {props.minAmountDisplay} +
+
+ + + + {" "} + + + + +
+ + +
+
+
|
+
+ {props.maxAmountDisplay} +
+
+
+ ); +}); + +const TOLERANCE = 0.04; //4% + +function isBelowLowerBound(value?: number, min = 0, max = 0): boolean { + if (!value) return false; + const lowerThreshold = min + (max - min) * TOLERANCE; + return value <= lowerThreshold; +} + +function isAboveUpperBound(value?: number, min = 0, max = 0): boolean { + if (!value) return false; + const upperThreshold = max - (max - min) * TOLERANCE; + return value >= upperThreshold; +} + +PriceSlider.displayName = SliderPrimitive.Root.displayName; +export { PriceSlider }; diff --git a/apps/dapp/src/modules/token/token-amount-input.tsx b/apps/dapp/src/modules/token/token-amount-input.tsx index d4f96290..e081f4b5 100644 --- a/apps/dapp/src/modules/token/token-amount-input.tsx +++ b/apps/dapp/src/modules/token/token-amount-input.tsx @@ -6,7 +6,7 @@ import { Format } from "./format"; type TokenAmountInputProps = React.HTMLProps & { /** the input's label */ - label: string; + label?: string; /** the input's token label, defaults to the token's symbol */ tokenLabel?: string; /** the input's token type */ @@ -32,7 +32,7 @@ type TokenAmountInputProps = React.HTMLProps & { /** the prefix to add to the amount */ amountPrefix?: string; - onChange: NumberInputProps["onChange"]; + onChange?: NumberInputProps["onChange"]; }; export const TokenAmountInput = React.forwardRef< @@ -54,6 +54,7 @@ export const TokenAmountInput = React.forwardRef< disableMaxButton, onClickMaxButton, amountPrefix, + className, ...props }, ref, @@ -61,9 +62,10 @@ export const TokenAmountInput = React.forwardRef< return (
diff --git a/packages/ui/src/components/number-input.tsx b/packages/ui/src/components/number-input.tsx index c9e8a81b..a6589213 100644 --- a/packages/ui/src/components/number-input.tsx +++ b/packages/ui/src/components/number-input.tsx @@ -3,7 +3,7 @@ import { Input, InputProps } from "./primitives/input"; export type NumberInputProps = { value: string; - onChange: (value: string) => void; + onChange?: (value: string) => void; } & Omit; const formatNumber = (value: string) => { @@ -22,7 +22,7 @@ export const NumberInput = React.forwardRef( } if ((newValue.match(/\./g) || []).length <= 1) { - onChange(newValue); + onChange?.(newValue); } }; diff --git a/packages/ui/src/style.css b/packages/ui/src/style.css index 08638eae..c1e3cd88 100644 --- a/packages/ui/src/style.css +++ b/packages/ui/src/style.css @@ -352,4 +352,17 @@ -moz-box-shadow: -2px 10px 78px 1px rgba(0, 0, 0, 0.57); box-shadow: -2px 10px 78px 1px rgba(0, 0, 0, 0.57); } + + .price-slider-gradient { + width: 100%; + height: 20px; /* Adjust height as needed */ + background: linear-gradient( + to right, + #ff4d4d 0%, + #ffa64d 20%, + #ffff99 50%, + #c2ff99 80%, + #66ff66 100% + ); + } } From 9d66755560bf5c3a22ceb6fa0a9940a4e57d5ca0 Mon Sep 17 00:00:00 2001 From: aphex Date: Fri, 10 Jan 2025 16:04:28 +0000 Subject: [PATCH 3/3] update sealed bid input card size --- apps/dapp/src/modules/auction/auction-purchase.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/dapp/src/modules/auction/auction-purchase.tsx b/apps/dapp/src/modules/auction/auction-purchase.tsx index e7819c33..e946ca08 100644 --- a/apps/dapp/src/modules/auction/auction-purchase.tsx +++ b/apps/dapp/src/modules/auction/auction-purchase.tsx @@ -297,7 +297,7 @@ export function AuctionPurchase({ auction, ...props }: AuctionPurchaseProps) { // TODO display "waiting" in modal when the tx is waiting to be signed by the user return ( -
+
{canBid ? (
e.preventDefault()}>