Skip to content

Commit

Permalink
feat: swap slippage and singleTxOnly options in settings (#38)
Browse files Browse the repository at this point in the history
* feat: added swap slippage option in the settings modal

* refactor: settings modal & sort preference components

* feat: singleTxOnly option in settings

* chores: removed css flex gap

* feat: refetch the active quote on slippage change [major change]

* chores: UX fixes

* update: sdk version

* fix: refetching btn loading state

* chores: added singleTX info to main screen, redesigned settings modal and minor fixes

* removed console logs

* minor fix

* chores: added tooltip and minor text edits

* fix: refetch and update support for pending transactions

* fix: review modal button state on route update

* chores: added tooltips for setting items

* fix: setting activeRoute to null on txModal unmount

* chores: edited the low slippage error message
  • Loading branch information
salil-naik authored Oct 14, 2022
1 parent b217f34 commit 020fed2
Show file tree
Hide file tree
Showing 41 changed files with 1,483 additions and 379 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ yarn-error.log*
*.zip
/storybook-static
build-storybook.log
/src/lib

# Dev Notes
*.txt
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"types": "dist/index.d.ts",
"repository": "https://github.com/SocketDotTech/widget",
"license": "MIT",
"keywords": ["library", "plugin", "web3", "bridge", "cross-chain", "swap", "cross-chain-swap", "blockchain", "interoperability"],
"scripts": {
"storybook": "start-storybook -p 6006",
"build:storybook": "build-storybook",
Expand All @@ -16,7 +17,7 @@
"@react-spring/web": "^9.5.0",
"@reduxjs/toolkit": "^1.8.2",
"@socket.tech/ll-core": "^0.1.10",
"@socket.tech/socket-v2-sdk": "^1.20.0",
"@socket.tech/socket-v2-sdk": "^1.21.0",
"ethers": "^5.6.9",
"react-feather": "^2.0.10",
"react-redux": "^8.0.2",
Expand Down
4 changes: 2 additions & 2 deletions src/components/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -287,8 +287,8 @@ export const Input = ({
return (
<div className="skt-w mt-3.5">
<div className="skt-w flex items-center justify-between">
<div className="skt-w flex items-center gap-1.5">
<span className="skt-w text-widget-secondary text-sm">From</span>
<div className="skt-w flex items-center">
<span className="skt-w text-widget-secondary text-sm mr-1.5">From</span>
<ChainSelect
networks={supportedNetworks}
activeNetworkId={sourceChainId}
Expand Down
4 changes: 2 additions & 2 deletions src/components/Output.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -225,8 +225,8 @@ export const Output = ({
return (
<div className="skt-w mt-6">
<div className="skt-w flex items-center justify-between">
<div className="skt-w flex items-center gap-x-1.5">
<span className="skt-w text-widget-secondary text-sm">To</span>
<div className="skt-w flex items-center">
<span className="skt-w text-widget-secondary text-sm mr-1.5">To</span>
<ChainSelect
networks={supportedNetworksSubset}
activeNetworkId={destChainId}
Expand Down
4 changes: 2 additions & 2 deletions src/components/PendingTransactions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { Modal } from "./common/Modal";
// actions
import { setActiveRoute, setIsTxModalOpen } from "../state/modals";

import { useActiveRoutes } from "../hooks/apis";
import { usePendingRoutes } from "../hooks/apis";
import { useTransition } from "@react-spring/web";
import { TokenDetailsRow } from "./common/TokenDetailsRow";

Expand All @@ -32,7 +32,7 @@ export const PendingTransactions = () => {
});

// Hook that fetches the routes that are active (routes that have started but have not been completed yet.)
const { data: activeRoutesData } = useActiveRoutes();
const { data: activeRoutesData } = usePendingRoutes();

useEffect(() => {
if (activeRoutesData) {
Expand Down
4 changes: 2 additions & 2 deletions src/components/Refuel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ export const Refuel = () => {

return (
<div
className="skt-w flex gap-1 bg-widget-secondary py-3 pl-4 pr-3 justify-between mt-6 items-center relative"
className="skt-w flex bg-widget-secondary py-3 pl-4 pr-3 justify-between mt-6 items-center relative"
style={{ borderRadius: `calc(0.5rem * ${borderRadius})` }}
>
<div>
<div className="mr-1">
<div className="skt-w text-sm text-widget-primary font-medium flex items-center">
Enable Refuel
<Popover
Expand Down
43 changes: 34 additions & 9 deletions src/components/RouteDetails/ReviewModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import { BRIDGE_DISPLAY_NAMES, UserTxType } from "../../consts/";
// components
import { Button } from "../common/Button";
import { Modal } from "../common/Modal";
import { ChevronUp } from "react-feather";
import { ChevronUp, Edit } from "react-feather";
import { InnerCard } from "../common/InnerCard";

// actions
import { setIsTxModalOpen } from "../../state/modals";
import { setIsSettingsModalOpen, setIsTxModalOpen } from "../../state/modals";
import { setSelectedRoute } from "../../state/selectedRouteSlice";
import { TxStepDetails } from "../TxModal/TxStepDetails";
import { TokenDetailsRow } from "../common/TokenDetailsRow";
Expand Down Expand Up @@ -103,6 +103,10 @@ export const ReviewModal = ({
fundMovrData?.steps &&
fundMovrData?.steps.filter((step) => step.type === "bridge")[0];

const swapStepInFundMovr =
fundMovrData?.steps &&
fundMovrData?.steps.filter((step) => step.type === "middleware")[0];

// Extracting the Swap step from userTxs
const swapData = selectedRoute?.route?.userTxs.filter(
(item) => item.userTxType === UserTxType.DEX_SWAP
Expand All @@ -124,6 +128,10 @@ export const ReviewModal = ({
);
}, [selectedRoute]);

const openSettingsModal = () => {
dispatch(setIsSettingsModalOpen(true));
};

return (
<Modal
title="Review Quote"
Expand All @@ -133,7 +141,10 @@ export const ReviewModal = ({
style={style}
>
<div className="skt-w flex flex-col justify-between flex-1 relative">
<div className="skt-w w-full">
<div
className="skt-w w-full overflow-y-auto"
style={{ height: "calc(100% - 7rem)" }}
>
<TokenDetailsRow
srcDetails={{
token: selectedRoute?.path?.fromToken,
Expand All @@ -147,7 +158,7 @@ export const ReviewModal = ({
destRefuel={refuelDestToken}
/>

<div className="skt-w p-3 flex flex-col gap-3 mt-1">
<div className="skt-w px-3 py-1.5 flex flex-col mt-1">
{!isSameChainSwap ? (
<>
<RouteDetailRow
Expand Down Expand Up @@ -198,21 +209,34 @@ export const ReviewModal = ({
/>
</>
)}
{(!!swapStepInFundMovr || !!swapData) && (
<RouteDetailRow label="Swap Slippage">
<div className="flex items-center">
{swapData?.swapSlippage ?? swapStepInFundMovr?.swapSlippage}%{" "}
<button
className="skt-w skt-w-input skt-w-button flex"
onClick={openSettingsModal}
>
<Edit className="ml-2 w-4 h-4 text-widget-accent" />
</button>
</div>
</RouteDetailRow>
)}
</div>
</div>

<InnerCard
classNames={`absolute w-full flex bottom-0 flex-col justify-between transition-all ${
classNames={`absolute w-full flex bottom-0 flex-col justify-between transition-all ${
showTxDetails ? `h-full max-h-full` : "h-auto max-h-min"
}`}
>
<div className="skt-w flex-1 flex flex-col overflow-auto">
<button
className="skt-w skt-w-button skt-w-input flex items-center gap-1.5 text-sm text-widget-secondary mb-3"
className="skt-w skt-w-button skt-w-input flex items-center text-sm text-widget-secondary mb-3"
onClick={() => setShowTxDetails(!showTxDetails)}
>
<ChevronUp
className={`skt-w w-4 h-4 text-widget-secondary transition-all ${
className={`skt-w w-4 h-4 text-widget-secondary transition-all mr-1.5 ${
showTxDetails ? "rotate-180" : "rotate-0"
}`}
/>{" "}
Expand Down Expand Up @@ -240,13 +264,14 @@ export const ReviewModal = ({
>
{quoteUpdated && (
<span className="skt-w whitespace-nowrap w-full text-widget-secondary text-sm text-left">
Quote updated
{!bestRoute ? 'Quote updating...' : 'Quote updated'}
</span>
)}

<Button
onClick={quoteUpdated ? updateSelectedRoute : openTxModal}
classNames={`${quoteUpdated ? "h-12" : ""}`}
disabled={!bestRoute}
>
{quoteUpdated
? "Accept"
Expand All @@ -269,7 +294,7 @@ const RouteDetailRow = ({
children?: ReactNode;
}) => {
return (
<div className="skt-w w-full flex justify-between text-sm text-widget-secondary">
<div className="skt-w w-full flex justify-between text-sm text-widget-secondary my-1.5">
<span>{label}</span>
<span>{value}</span>
{children}
Expand Down
16 changes: 11 additions & 5 deletions src/components/RouteDetails/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ export const RouteDetails = () => {
);
const web3Context = useContext(Web3Context);
const { userAddress } = web3Context.web3Provider;
const singleTxOnly = useSelector((state: any) => state.quotes.singleTxOnly);
const swapSlippage = useSelector((state: any) => state.quotes.swapSlippage);

// Hook to fetch the quotes for given params.
const { data, isQuotesLoading } = useRoutes(
Expand All @@ -55,7 +57,9 @@ export const RouteDetails = () => {
userAddress,
refuelEnabled,
includeBridges,
excludeBridges
excludeBridges,
singleTxOnly,
swapSlippage
);

// Boolean variable to fill all condition before the api call is made to fetch quotes.
Expand Down Expand Up @@ -199,14 +203,16 @@ export const RouteDetails = () => {

return (
<InnerCard>
<div className="skt-w text-widget-secondary mb-3 text-sm flex items-center gap-1">
<div className="skt-w text-widget-secondary mb-3 text-sm flex items-center">
{sourceAmount && sourceAmount !== "0" && isQuotesLoading ? (
<Spinner size={4} />
<span className="mr-1">
<Spinner size={4} />
</span>
) : !!bestRoute?.refuel && !isNativeTokenEnough ? (
<Info className="w-4 h-4" />
<Info className="w-4 h-4 mr-1" />
) : (
""
)}{" "}
)}
{quotesStatus()}
</div>
<Button
Expand Down
56 changes: 56 additions & 0 deletions src/components/Settings/SettingsModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { useTransition } from "@react-spring/web";
import { useDispatch, useSelector } from "react-redux";
import { setIsSettingsModalOpen } from "../../state/modals";

// components
import { Modal } from "../common/Modal";
import { SwapSlippage } from "./SwapSlippage";
import { SortPreference } from "./SortPreference";
import { SingleTx } from "./SingleTx";

export const SettingsModal = () => {
const dispatch = useDispatch();

const isSettingsOpen = useSelector(
(state: any) => state.modals.isSettingsModalOpen
);

const transitions = useTransition(isSettingsOpen, {
from: { y: "100%" },
enter: { y: "0" },
leave: { y: "100%" },
config: { duration: 200 },
onReset: () => toggleSettingsModal(false),
});

const toggleSettingsModal = (value: boolean) => {
dispatch(setIsSettingsModalOpen(value));
};

return (
<>
{transitions(
(style, item) =>
item && (
<Modal
title="Settings"
closeModal={() => toggleSettingsModal(false)}
style={style}
classNames="z-50"
>
<div className="skt-w px-3 pt-3">
{/* Sort options */}
<SortPreference />

{/* Single tx checkbox */}
<SingleTx />

{/* Swap Slippage */}
<SwapSlippage />
</div>
</Modal>
)
)}
</>
);
};
52 changes: 52 additions & 0 deletions src/components/Settings/SingleTx.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { useEffect, useState } from "react";
import { Info } from "react-feather";
import { useDispatch, useSelector } from "react-redux";
import { setSingleTxOnly } from "../../state/quotesSlice";

// components
import { CheckBox } from "../common/CheckBox";
import { Popover } from "../common/Popover";
import { SubTitle } from "./SubTitle";

export const SingleTx = () => {
const dispatch = useDispatch();
const singleTxOnlyFromDev = useSelector(
(state: any) => state.customSettings.singleTxOnly
);
const singleTxOnlyFromUser = useSelector(
(state: any) => state.quotes.singleTxOnly
);

const [singleTx, setSingleTx] = useState(singleTxOnlyFromUser);

// sets the store data and local storage on user input
useEffect(() => {
if (singleTx !== singleTxOnlyFromUser) {
dispatch(setSingleTxOnly(singleTx));
localStorage.setItem("singleTxOnly", singleTx ? "true" : "false");
}
}, [singleTx]);

if (singleTxOnlyFromDev) return null;
return (
<div className="skt-w flex items-center relative mt-6 justify-between">
<div className="skt-w flex items-center mb-1.5">
<SubTitle>Single Transaction Mode</SubTitle>
<Popover
content="Only select routes with one user transaction i.e. direct bridge or source chain swap + bridge."
classNames="bottom-8"
cursor="cursor-help"
>
<Info className="ml-1.5 w-4 h-4 text-widget-secondary" />
</Popover>
</div>
<span className="px-1"></span>
<CheckBox
small
id="singleTx"
isChecked={singleTx}
setIsChecked={setSingleTx}
/>
</div>
);
};
Loading

0 comments on commit 020fed2

Please sign in to comment.