diff --git a/src/assets/icons/tableSettings.svg b/src/assets/icons/tableSettings.svg new file mode 100644 index 00000000..1549614d --- /dev/null +++ b/src/assets/icons/tableSettings.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/icons/tablesSize.svg b/src/assets/icons/tablesSize.svg deleted file mode 100644 index 7f6d8134..00000000 --- a/src/assets/icons/tablesSize.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/assets/icons/tablesSizeSelector.svg b/src/assets/icons/tablesSizeSelector.svg new file mode 100644 index 00000000..4ac190cc --- /dev/null +++ b/src/assets/icons/tablesSizeSelector.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/screens/SpotScreen/BottomTables/BaseTable.tsx b/src/screens/SpotScreen/BottomTables/BaseTable.tsx index c60a7dc7..869d592b 100644 --- a/src/screens/SpotScreen/BottomTables/BaseTable.tsx +++ b/src/screens/SpotScreen/BottomTables/BaseTable.tsx @@ -1,22 +1,18 @@ -import React, { useState } from "react"; -import { Config } from "react-popper-tooltip"; +import React from "react"; import styled from "@emotion/styled"; import { observer } from "mobx-react-lite"; import { Row } from "@components/Flex"; -import SizedBox from "@components/SizedBox"; import { SmartFlex } from "@components/SmartFlex"; import Tab from "@components/Tab"; import Text, { TEXT_TYPES } from "@components/Text"; -import Tooltip from "@components/Tooltip"; import { media } from "@themes/breakpoints"; -import tableSizeSelector from "@assets/icons/tablesSize.svg"; - import { useStores } from "@stores"; import { TRADE_TABLE_SIZE } from "@stores/SettingsStore"; -import { MAX_TABLE_HEIGHT, RESIZE_TOOLTIP_CONFIG, TABLE_SIZES_CONFIG } from "./constants"; +import { MAX_TABLE_HEIGHT } from "./constants"; +import { TableActionButtons } from "./TableActionButtons"; interface Props { tabs: { title: string; disabled: boolean; rowCount: number }[]; @@ -28,19 +24,6 @@ interface Props { export const BaseTable: React.FC = observer(({ tabs, activeTab, onTabClick, children }) => { const { settingsStore } = useStores(); - const [isTooltipVisible, setIsTooltipVisible] = useState(false); - - const tooltipConfig: Config = { - ...RESIZE_TOOLTIP_CONFIG, - visible: isTooltipVisible, - onVisibleChange: setIsTooltipVisible, - }; - - const handleTableSize = (size: TRADE_TABLE_SIZE) => { - settingsStore.setTradeTableSize(size); - setIsTooltipVisible(false); - }; - return ( @@ -63,35 +46,7 @@ export const BaseTable: React.FC = observer(({ tabs, activeTab, onTabClic )} ))} - - - {TABLE_SIZES_CONFIG.map(({ size, icon, title }) => ( - handleTableSize(size)} - > - - - - {title.toUpperCase()} - - - ))} - - } - > - setIsTooltipVisible(true)} - /> - - + {children} @@ -134,36 +89,12 @@ const TabContainer = styled(Row)` } `; -const TableSizeSelector = styled.div` - position: absolute; - right: 12px; - top: 4px; - - ${media.mobile} { - display: none; - } -`; - const TableContainer = styled(SmartFlex)` width: 100%; height: 100%; overflow-y: scroll; `; -const TableSize = styled.div<{ active?: boolean }>` - display: flex; - align-items: center; - padding: 4px 12px; - width: 100%; - cursor: pointer; - - ${({ active, theme }) => active && `background: ${theme.colors.borderPrimary}`}; - - :hover { - background: ${({ theme }) => theme.colors.borderSecondary}; - } -`; - const Badge = styled.div` margin-left: 4px; background: ${({ theme }) => theme.colors.borderSecondary}; diff --git a/src/screens/SpotScreen/BottomTables/SpotTable/SpotTableVM.tsx b/src/screens/SpotScreen/BottomTables/SpotTable/SpotTableVM.tsx index 4dcd5ea1..83793968 100644 --- a/src/screens/SpotScreen/BottomTables/SpotTable/SpotTableVM.tsx +++ b/src/screens/SpotScreen/BottomTables/SpotTable/SpotTableVM.tsx @@ -2,6 +2,8 @@ import React, { PropsWithChildren, useMemo } from "react"; import { makeAutoObservable, reaction } from "mobx"; import { Nullable } from "tsdef"; +import { OrderType } from "@compolabs/spark-orderbook-ts-sdk"; + import useVM from "@hooks/useVM"; import { RootStore, useStores } from "@stores"; @@ -42,9 +44,33 @@ class SpotTableVM { isOpenOrdersLoaded = false; isHistoryOrdersLoaded = false; + + // filters offset = 0; limit = 10; + filterIsSellOrderTypeEnabled = true; + filterIsBuyOrderTypeEnabled = true; + toggleFilterOrderType = (orderType: OrderType) => { + if (orderType === OrderType.Sell) { + if (this.filterIsSellOrderTypeEnabled && !this.filterIsBuyOrderTypeEnabled) { + this.filterIsSellOrderTypeEnabled = false; + this.filterIsBuyOrderTypeEnabled = true; + return; + } + this.filterIsSellOrderTypeEnabled = !this.filterIsSellOrderTypeEnabled; + return; + } + + if (this.filterIsBuyOrderTypeEnabled && !this.filterIsSellOrderTypeEnabled) { + // Cannot uncheck 'buy' because 'sell' is already unchecked + this.filterIsBuyOrderTypeEnabled = false; + this.filterIsSellOrderTypeEnabled = true; + return; + } + this.filterIsBuyOrderTypeEnabled = !this.filterIsBuyOrderTypeEnabled; + }; + constructor(rootStore: RootStore) { makeAutoObservable(this); this.rootStore = rootStore; @@ -68,6 +94,21 @@ class SpotTableVM { return this.isOpenOrdersLoaded && this.isHistoryOrdersLoaded; } + get tableFilters() { + const orderType = + this.filterIsSellOrderTypeEnabled && this.filterIsBuyOrderTypeEnabled + ? undefined + : this.filterIsSellOrderTypeEnabled + ? OrderType.Sell + : OrderType.Buy; + + return { + limit: this.limit, + offset: this.offset, + orderType, + }; + } + cancelOrder = async (order: SpotMarketOrder) => { const { notificationStore } = this.rootStore; const bcNetwork = FuelNetwork.getInstance(); @@ -117,8 +158,7 @@ class SpotTableVM { this.subscriptionToOpenOrders = bcNetwork .subscribeSpotOrders({ - limit: this.limit, - offset: this.offset, + ...this.tableFilters, market: tradeStore.market!.contractAddress, asset: tradeStore.market!.baseToken.assetId, user: accountStore.address!, @@ -147,8 +187,7 @@ class SpotTableVM { } this.subscriptionToHistoryOrders = bcNetwork .subscribeSpotOrders({ - limit: this.limit, - offset: this.offset, + ...this.tableFilters, market: tradeStore.market!.contractAddress, asset: tradeStore.market!.baseToken.assetId, user: accountStore.address!, diff --git a/src/screens/SpotScreen/BottomTables/TableActionButtons.tsx b/src/screens/SpotScreen/BottomTables/TableActionButtons.tsx new file mode 100644 index 00000000..f7095b2b --- /dev/null +++ b/src/screens/SpotScreen/BottomTables/TableActionButtons.tsx @@ -0,0 +1,176 @@ +import React, { useState } from "react"; +import { Config } from "react-popper-tooltip"; +import styled from "@emotion/styled"; +import { observer } from "mobx-react-lite"; + +import { OrderType } from "@compolabs/spark-orderbook-ts-sdk"; + +import SizedBox from "@components/SizedBox"; +import { SmartFlex } from "@components/SmartFlex"; +import Text, { TEXT_TYPES } from "@components/Text"; +import Tooltip from "@components/Tooltip"; +import { media } from "@themes/breakpoints"; + +import TableSettingsIcon from "@assets/icons/tableSettings.svg?react"; +import TableSizeSelectorIcon from "@assets/icons/tablesSizeSelector.svg?react"; + +import { useStores } from "@stores"; +import { TRADE_TABLE_SIZE } from "@stores/SettingsStore"; + +import { Checkbox } from "@src/components/Checkbox"; + +import { useSpotTableVMProvider } from "./SpotTable/SpotTableVM"; +import { RESIZE_TOOLTIP_CONFIG, TABLE_SIZES_CONFIG } from "./constants"; + +const useTooltipConfig = (isVisible: boolean, setIsVisible: React.Dispatch>): Config => ({ + ...RESIZE_TOOLTIP_CONFIG, + visible: isVisible, + onVisibleChange: setIsVisible, +}); + +export const TableActionButtons: React.FC = observer(() => { + const vm = useSpotTableVMProvider(); + const { settingsStore } = useStores(); + + const [isResizeTooltipVisible, setIsResizeTooltipVisible] = useState(false); + const [isSettingsTooltipVisible, setIsSettingsTooltipVisible] = useState(false); + + const resizeTooltipConfig = useTooltipConfig(isResizeTooltipVisible, setIsResizeTooltipVisible); + const settingsTooltipConfig = useTooltipConfig(isSettingsTooltipVisible, setIsSettingsTooltipVisible); + + const handleTableSize = (size: TRADE_TABLE_SIZE) => { + settingsStore.setTradeTableSize(size); + setIsResizeTooltipVisible(false); + }; + + const isAnySettingsChanged = false; + + const renderResizeTooltipContent = () => { + return ( + + {TABLE_SIZES_CONFIG.map(({ size, icon, title }) => ( + handleTableSize(size)}> + + + + {title.toUpperCase()} + + + ))} + + ); + }; + + const renderSettingsTooltipContent = () => { + return ( + + {/* + + Type + + + + MARKET + + + + + LIMIT + + + */} + + + Side + + vm.toggleFilterOrderType(OrderType.Buy)}> + + BUY + + + vm.toggleFilterOrderType(OrderType.Sell)}> + + SELL + + + + + ); + }; + + const renderResizeButton = () => { + return ( + + + setIsResizeTooltipVisible(true)} /> + + + ); + }; + + const renderSettingsButton = () => { + return ( + + {isAnySettingsChanged && } + + setIsSettingsTooltipVisible(true)} /> + + + ); + }; + + return ( + + {renderResizeButton()} + {renderSettingsButton()} + + ); +}); + +const ActionContainer = styled(SmartFlex)` + gap: 12px; + position: absolute; + right: 12px; + top: 4px; + + ${media.mobile} { + display: none; + } +`; + +const TableSize = styled.div<{ active?: boolean }>` + display: flex; + align-items: center; + padding: 4px 12px; + width: 100%; + cursor: pointer; + + ${({ active, theme }) => active && `background: ${theme.colors.borderPrimary}`}; + + :hover { + background: ${({ theme }) => theme.colors.borderSecondary}; + } +`; + +const SettingsTooltipContainer = styled(SmartFlex)` + gap: 16px; + padding: 0 16px 16px; + position: relative; +`; + +const GreenDot = styled.div` + position: absolute; + right: -3px; + top: -3px; + width: 8px; + height: 8px; + background-color: ${({ theme }) => theme.colors.greenLight}; + border-radius: 8px; +`; + +const Icon = styled(SmartFlex)<{ isActive: boolean }>` + cursor: pointer; + + transition: color 250ms; + color: ${({ theme, isActive }) => (isActive ? theme.colors.textPrimary : theme.colors.textDisabled)}; +`;