Skip to content

Commit

Permalink
feat: added review order modal
Browse files Browse the repository at this point in the history
  • Loading branch information
crnbarr93 committed Jun 6, 2024
1 parent 49ba698 commit 27afcbc
Show file tree
Hide file tree
Showing 4 changed files with 366 additions and 157 deletions.
4 changes: 3 additions & 1 deletion packages/web/components/input/limit-input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { FC, useCallback, useEffect, useMemo, useState } from "react";

import { Icon } from "~/components/assets";
import { DynamicSizeInput } from "~/components/input/dynamic-size-input";
import { useCoinPrice } from "~/hooks/queries/assets/use-coin-price";
import { formatPretty } from "~/utils/formatter";

export interface LimitInputProps {
Expand Down Expand Up @@ -43,6 +44,7 @@ export const LimitInput: FC<LimitInputProps> = ({
}) => {
const [fiatAmount, setFiatAmount] = useState<string>("");
const [focused, setFocused] = useState<FocusedInput>(FocusedInput.FIAT);
const { price: basePrice } = useCoinPrice(baseAsset);

const swapFocus = useCallback(() => {
switch (focused) {
Expand Down Expand Up @@ -99,7 +101,7 @@ export const LimitInput: FC<LimitInputProps> = ({
const tokenValue = new Dec(value)?.quo(price);
setTokenAmountSafe(tokenValue.toString());
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [price, fiatAmount, setTokenAmountSafe]);
}, [price, fiatAmount, setTokenAmountSafe, basePrice]);

const FiatInput = useMemo(() => {
const isFocused = focused === FocusedInput.FIAT;
Expand Down
253 changes: 134 additions & 119 deletions packages/web/components/place-limit-tool/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { Button } from "~/components/ui/button";
import { useTranslation } from "~/hooks";
import { OrderDirection, usePlaceLimit } from "~/hooks/limit-orders";
import { useOrderbookPool } from "~/hooks/limit-orders/use-orderbook-pool";
import { ReviewLimitOrderModal } from "~/modals/review-limit-order";
import { useStore } from "~/stores";
import { formatPretty } from "~/utils/formatter";

Expand All @@ -30,6 +31,7 @@ export const PlaceLimitTool: FunctionComponent<PlaceLimitToolProps> = observer(
({ orderDirection = OrderDirection.Bid }) => {
const { accountStore } = useStore();
const { t } = useTranslation();
const [reviewOpen, setReviewOpen] = useState<boolean>(false);
const [baseDenom, setBaseDenom] = useState<string>("ION");
const quoteDenom = "OSMO";

Expand All @@ -51,135 +53,148 @@ export const PlaceLimitTool: FunctionComponent<PlaceLimitToolProps> = observer(
const isSwapToolLoading = false;

return (
<div className="flex flex-col gap-3">
<TokenSelectLimit
selectableAssets={[swapState.fromAsset, swapState.toAsset]}
baseAsset={swapState.baseAsset}
quoteAsset={swapState.quoteAsset}
baseBalance={swapState.baseTokenBalance}
quoteBalance={swapState.quoteTokenBalance}
onTokenSelect={(newDenom) => setBaseDenom(newDenom)}
disabled={false}
orderDirection={orderDirection}
/>
<div className="px-4 py-[22px] transition-all md:rounded-xl md:py-2.5 md:px-3">
<div className="flex place-content-end items-center transition-opacity">
<div className="flex items-center gap-1.5">
<Tooltip
content={
<div className="text-center">
{t("swap.maxButtonErrorNoBalance")}
</div>
}
disabled={!swapState.inAmountInput.notEnoughBalanceForMax}
>
<Button
variant="outline"
size="sm"
className={classNames(
"text-wosmongton-300",
swapState.inAmountInput.isMaxValue &&
!swapState.inAmountInput
.isLoadingCurrentBalanceNetworkFee &&
!swapState.inAmountInput.hasErrorWithCurrentBalanceQuote
? "bg-wosmongton-100/20"
: "bg-transparent"
)}
disabled={
!swapState.inAmountInput.balance ||
swapState.inAmountInput.balance.toDec().isZero() ||
swapState.inAmountInput.notEnoughBalanceForMax
<>
<div className="flex flex-col gap-3">
<TokenSelectLimit
selectableAssets={[swapState.baseAsset, swapState.quoteAsset]}
baseAsset={swapState.baseAsset}
quoteAsset={swapState.quoteAsset}
baseBalance={swapState.baseTokenBalance}
quoteBalance={swapState.quoteTokenBalance}
onTokenSelect={(newDenom) => setBaseDenom(newDenom)}
disabled={false}
orderDirection={orderDirection}
/>
<div className="px-4 py-[22px] transition-all md:rounded-xl md:py-2.5 md:px-3">
<div className="flex place-content-end items-center transition-opacity">
<div className="flex items-center gap-1.5">
<Tooltip
content={
<div className="text-center">
{t("swap.maxButtonErrorNoBalance")}
</div>
}
isLoading={false}
loadingText={t("swap.MAX")}
classes={{
spinner: "!h-3 !w-3",
spinnerContainer: "!gap-1",
}}
onClick={() => swapState.inAmountInput.toggleMax()}
disabled={!swapState.inAmountInput.notEnoughBalanceForMax}
>
{t("swap.MAX")}
</Button>
</Tooltip>
<Button
variant="outline"
size="sm"
className={classNames(
"text-wosmongton-300",
swapState.inAmountInput.isMaxValue &&
!swapState.inAmountInput
.isLoadingCurrentBalanceNetworkFee &&
!swapState.inAmountInput.hasErrorWithCurrentBalanceQuote
? "bg-wosmongton-100/20"
: "bg-transparent"
)}
disabled={
!swapState.inAmountInput.balance ||
swapState.inAmountInput.balance.toDec().isZero() ||
swapState.inAmountInput.notEnoughBalanceForMax
}
isLoading={false}
loadingText={t("swap.MAX")}
classes={{
spinner: "!h-3 !w-3",
spinnerContainer: "!gap-1",
}}
onClick={() => swapState.inAmountInput.toggleMax()}
>
{t("swap.MAX")}
</Button>
</Tooltip>
</div>
</div>
</div>
<div className="mt-3 flex place-content-between items-center">
<div className="flex w-full flex-col items-center">
<LimitInput
onChange={swapState.inAmountInput.setAmount}
baseAsset={swapState.inAmountInput.balance!}
tokenAmount={swapState.inAmountInput.inputAmount}
price={swapState.priceState.price}
/>
<div className="mt-3 flex place-content-between items-center">
<div className="flex w-full flex-col items-center">
<LimitInput
onChange={swapState.inAmountInput.setAmount}
baseAsset={swapState.inAmountInput.balance!}
tokenAmount={swapState.inAmountInput.inputAmount}
price={swapState.priceState.price}
/>
</div>
</div>
</div>
</div>
<div className="mt-3 flex place-content-between items-center text-body1">
<div className="flex w-full flex-col">
<div>
<span
className={classNames(
"w-full bg-transparent text-white-full focus:outline-none"
)}
>{`When ${swapState.baseDenom} price is at `}</span>
<span
className={classNames(
"w-full bg-transparent text-wosmongton-300 focus:outline-none "
)}
>{`$${formatPretty(swapState.priceState.price)}`}</span>
<div className="mt-3 flex place-content-between items-center text-body1">
<div className="flex w-full flex-col">
<div>
<span
className={classNames(
"w-full bg-transparent text-white-full focus:outline-none"
)}
>{`When ${swapState.baseDenom} price is at `}</span>
<span
className={classNames(
"w-full bg-transparent text-wosmongton-300 focus:outline-none "
)}
>{`$${formatPretty(swapState.priceState.price)}`}</span>
</div>
</div>
</div>
</div>
<div className="flex w-full flex-row place-content-between items-center rounded-xl border border-osmoverse-700 py-3 px-6">
<div className="h-full">
<span>{`${swapState.priceState.percentAdjusted
.mul(new Dec(100))
.round()
.abs()}% `}</span>
<span className="text-osmoverse-400">
{orderDirection === OrderDirection.Bid ? "below" : "above"}{" "}
current price
</span>
<div className="flex w-full flex-row place-content-between items-center rounded-xl border border-osmoverse-700 py-3 px-6">
<div className="h-full">
<span>{`${swapState.priceState.percentAdjusted
.mul(new Dec(100))
.round()
.abs()}% `}</span>
<span className="text-osmoverse-400">
{orderDirection === OrderDirection.Bid ? "below" : "above"}{" "}
current price
</span>
</div>
<div className="grid grid-cols-4 gap-2">
{useMemo(
() =>
percentAdjustmentOptions.map(({ label, value }) => (
<button
className="rounded-xl border border-osmoverse-700 py-1 px-3 text-white-full text-wosmongton-200"
key={`limit-price-adjust-${label}`}
onClick={() =>
swapState.priceState.adjustByPercentage(
orderDirection == OrderDirection.Bid
? value.neg()
: value
)
}
>
{label}
</button>
)),
[swapState.priceState, orderDirection]
)}
</div>
</div>
<div className="grid grid-cols-4 gap-2">
{useMemo(
() =>
percentAdjustmentOptions.map(({ label, value }) => (
<button
className="rounded-xl border border-osmoverse-700 py-1 px-3 text-white-full text-wosmongton-200"
key={`limit-price-adjust-${label}`}
onClick={() =>
swapState.priceState.adjustByPercentage(
orderDirection == OrderDirection.Bid
? value.neg()
: value
)
}
>
{label}
</button>
)),
[swapState.priceState, orderDirection]
<Button
disabled={
swapState.insufficientFunds ||
!swapState.inAmountInput.inputAmount ||
swapState.inAmountInput.inputAmount === "0"
}
isLoading={!swapState.isBalancesFetched}
loadingText={"Loading..."}
onClick={() => setReviewOpen(true)}
>
{account?.walletStatus === WalletStatus.Connected ||
isSwapToolLoading ? (
"Review Order"
) : (
<h6 className="flex items-center gap-3">
<Icon id="wallet" className="h-6 w-6" />
{t("connectWallet")}
</h6>
)}
</div>
</Button>
</div>
<Button
disabled={swapState.insufficientFunds}
isLoading={!swapState.isBalancesFetched}
loadingText={"Loading..."}
onClick={swapState.placeLimit}
>
{account?.walletStatus === WalletStatus.Connected ||
isSwapToolLoading ? (
"Place Order"
) : (
<h6 className="flex items-center gap-3">
<Icon id="wallet" className="h-6 w-6" />
{t("connectWallet")}
</h6>
)}
</Button>
</div>
<ReviewLimitOrderModal
placeLimitState={swapState}
orderDirection={orderDirection}
isOpen={reviewOpen}
onRequestClose={() => setReviewOpen(false)}
orderType="limit"
/>
</>
);
}
);
Loading

0 comments on commit 27afcbc

Please sign in to comment.