Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: add new tabs and proper filtering #5176

Draft
wants to merge 2 commits into
base: limit-ui-improvement-2
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions apps/cowswap-frontend/src/modules/ordersTable/const/tabs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,21 @@ export interface OrderTab {
isActive?: boolean
}

export const ALL_ORDERS_TAB: OrderTab = {
id: 'all',
title: 'All orders',
count: 0,
}

export const UNFILLABLE_TAB: OrderTab = {
id: 'unfillable',
title: 'Unfillable',
count: 0,
}

export const OPEN_TAB: OrderTab = {
id: 'open',
title: 'Open orders',
title: 'Open',
count: 0,
}

Expand All @@ -17,7 +29,7 @@ export const HISTORY_TAB: OrderTab = {
count: 0,
}

export const ORDERS_TABLE_TABS: OrderTab[] = [OPEN_TAB, HISTORY_TAB]
export const ORDERS_TABLE_TABS: OrderTab[] = [ALL_ORDERS_TAB, UNFILLABLE_TAB, OPEN_TAB, HISTORY_TAB]

export const ORDERS_TABLE_PAGE_SIZE = 10

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@ import { getIsComposableCowOrder } from 'utils/orderUtils/getIsComposableCowOrde
import { getIsNotComposableCowOrder } from 'utils/orderUtils/getIsNotComposableCowOrder'

import { TabOrderTypes } from '../../../types'
import { getOrderParams } from '../../../utils/getOrderParams'
import { groupOrdersTable } from '../../../utils/groupOrdersTable'
import { getParsedOrderFromTableItem, isParsedOrder, OrderTableItem } from '../../../utils/orderTableGroupUtils'

export interface OrdersTableList {
pending: OrderTableItem[]
history: OrderTableItem[]
unfillable: OrderTableItem[]
all: OrderTableItem[]
}

const ordersSorter = (a: OrderTableItem, b: OrderTableItem) => {
Expand All @@ -23,13 +26,18 @@ const ordersSorter = (a: OrderTableItem, b: OrderTableItem) => {

const ORDERS_LIMIT = 100

export function useOrdersTableList(allOrders: Order[], orderType: TabOrderTypes): OrdersTableList {
export function useOrdersTableList(
allOrders: Order[],
orderType: TabOrderTypes,
chainId: number,
balancesAndAllowances: any,
): OrdersTableList {
const allSortedOrders = useMemo(() => {
return groupOrdersTable(allOrders).sort(ordersSorter)
}, [allOrders])

return useMemo(() => {
const { pending, history } = allSortedOrders.reduce(
const { pending, history, unfillable, all } = allSortedOrders.reduce(
(acc, item) => {
const order = isParsedOrder(item) ? item : item.parent

Expand All @@ -41,17 +49,37 @@ export function useOrdersTableList(allOrders: Order[], orderType: TabOrderTypes)
return acc
}

if (PENDING_STATES.includes(order.status)) {
// Add to 'all' list regardless of status
acc.all.push(item)

const isPending = PENDING_STATES.includes(order.status)

// Check if order is unfillable (insufficient balance or allowance)
const params = getOrderParams(chainId, balancesAndAllowances, order)
const isUnfillable = params.hasEnoughBalance === false || params.hasEnoughAllowance === false

// Only add to unfillable if the order is both pending and unfillable
if (isPending && isUnfillable) {
acc.unfillable.push(item)
}

// Add to pending or history based on status
if (isPending) {
acc.pending.push(item)
} else {
acc.history.push(item)
}

return acc
},
{ pending: [], history: [] } as OrdersTableList,
{ pending: [], history: [], unfillable: [], all: [] } as OrdersTableList,
)

return { pending: pending.slice(0, ORDERS_LIMIT), history: history.slice(0, ORDERS_LIMIT) }
}, [allSortedOrders, orderType])
return {
pending: pending.slice(0, ORDERS_LIMIT),
history: history.slice(0, ORDERS_LIMIT),
unfillable: unfillable.slice(0, ORDERS_LIMIT),
all: all.slice(0, ORDERS_LIMIT),
}
}, [allSortedOrders, orderType, chainId, balancesAndAllowances])
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { useAtomValue, useSetAtom } from 'jotai'
import { useCallback, useEffect, useMemo, useState } from 'react'


import { useTokensAllowances, useTokensBalances } from '@cowprotocol/balances-and-allowances'
import { useIsSafeViaWc, useWalletDetails, useWalletInfo } from '@cowprotocol/wallet'

Expand Down Expand Up @@ -74,7 +73,18 @@ const SearchInput = styled.input`
`

function getOrdersListByIndex(ordersList: OrdersTableList, id: string): OrderTableItem[] {
return id === OPEN_TAB.id ? ordersList.pending : ordersList.history
switch (id) {
case 'all':
return ordersList.all
case 'unfillable':
return ordersList.unfillable
case 'open':
return ordersList.pending
case 'history':
return ordersList.history
default:
return ordersList.pending
}
}

function toggleOrderInCancellationList(state: CancellableOrder[], order: CancellableOrder): CancellableOrder[] {
Expand Down Expand Up @@ -102,7 +112,6 @@ export function OrdersTableWidget({
const location = useLocation()
const navigate = useNavigate()
const cancelOrder = useCancelOrder()
const ordersList = useOrdersTableList(allOrders, orderType)
const { allowsOffchainSigning } = useWalletDetails()
const pendingOrdersPrices = useAtomValue(pendingOrdersPricesAtom)
const ordersToCancel = useAtomValue(ordersToCancelAtom)
Expand All @@ -114,6 +123,21 @@ export function OrdersTableWidget({
const injectedWidgetParams = useInjectedWidgetParams()
const [searchTerm, setSearchTerm] = useState('')

const balancesState = useTokensBalances()
const allowancesState = useTokensAllowances()

const balancesAndAllowances: BalancesAndAllowances = useMemo(() => {
const { isLoading: balancesLoading, values: balances } = balancesState
const { isLoading: allowancesLoading, values: allowances } = allowancesState
return {
isLoading: balancesLoading || allowancesLoading,
balances,
allowances,
}
}, [balancesState, allowancesState])

const ordersList = useOrdersTableList(allOrders, orderType, chainId, balancesAndAllowances)

const { currentTabId, currentPageNumber } = useMemo(() => {
const params = parseOrdersTableUrl(location.search)

Expand All @@ -133,21 +157,6 @@ export function OrdersTableWidget({
})
}, [currentTabId, ordersList])

const isOpenOrdersTab = useMemo(() => OPEN_TAB.id === currentTabId, [currentTabId])

const balancesState = useTokensBalances()
const allowancesState = useTokensAllowances()

const balancesAndAllowances: BalancesAndAllowances = useMemo(() => {
const { isLoading: balancesLoading, values: balances } = balancesState
const { isLoading: allowancesLoading, values: allowances } = allowancesState
return {
isLoading: balancesLoading || allowancesLoading,
balances,
allowances,
}
}, [balancesState, allowancesState])

const { pendingActivity } = useCategorizeRecentActivity()

const toggleOrdersForCancellation = useCallback(
Expand Down Expand Up @@ -244,7 +253,6 @@ export function OrdersTableWidget({
orders={filteredOrders}
displayOrdersOnlyForSafeApp={displayOrdersOnlyForSafeApp}
isSafeViaWc={isSafeViaWc}
isOpenOrdersTab={isOpenOrdersTab}
currentPageNumber={currentPageNumber}
pendingOrdersPrices={pendingOrdersPrices}
balancesAndAllowances={balancesAndAllowances}
Expand All @@ -258,7 +266,9 @@ export function OrdersTableWidget({
ordersPermitStatus={ordersPermitStatus}
injectedWidgetParams={injectedWidgetParams}
>
{isOpenOrdersTab && orders.length && <MultipleCancellationMenu pendingOrders={tableItemsToOrders(orders)} />}
{currentTabId === OPEN_TAB.id && orders.length > 0 && (
<MultipleCancellationMenu pendingOrders={tableItemsToOrders(orders)} />
)}

<SearchInputContainer>
<SearchIcon />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { isOrderCancellable } from 'common/utils/isOrderCancellable'
import { calculatePercentageInRelationToReference } from 'utils/orderUtils/calculatePercentageInRelationToReference'
import { calculatePriceDifference, PriceDifference } from 'utils/orderUtils/calculatePriceDifference'
import { getIsComposableCowParentOrder } from 'utils/orderUtils/getIsComposableCowParentOrder'
import { getIsFinalizedOrder } from 'utils/orderUtils/getIsFinalizedOrder'
import { getSellAmountWithFee } from 'utils/orderUtils/getSellAmountWithFee'
import { getUiOrderType } from 'utils/orderUtils/getUiOrderType'
import { ParsedOrder } from 'utils/orderUtils/parseOrder'
Expand Down Expand Up @@ -195,7 +196,8 @@ export function OrderRow({
[order, orderActions],
)

const withAllowanceWarning = hasEnoughAllowance === false && hasValidPendingPermit === false
const withAllowanceWarning =
hasEnoughAllowance === false && (hasValidPendingPermit === false || hasValidPendingPermit === undefined)
const withWarning =
(hasEnoughBalance === false || withAllowanceWarning) &&
// show the warning only for pending and scheduled orders
Expand Down Expand Up @@ -286,7 +288,9 @@ export function OrderRow({
</styledEl.RateValue>
) : (
<>
{prices && estimatedExecutionPrice ? (
{getIsFinalizedOrder(order) ? (
'-'
) : prices && estimatedExecutionPrice ? (
<styledEl.ExecuteCellWrapper>
<EstimatedExecutionPrice
amount={executionPriceInverted}
Expand Down Expand Up @@ -316,7 +320,7 @@ export function OrderRow({
<styledEl.PriceElement>
{priceDiffs?.percentage && Number(priceDiffs.percentage.toFixed(4)) >= MIN_PERCENTAGE_TO_DISPLAY ? (
<styledEl.DistanceToMarket $color={getDistanceColor(Number(priceDiffs.percentage.toFixed(4)))}>
{priceDiffs.percentage.toSignificant(4)}%
{priceDiffs.percentage.toFixed(2)}%
</styledEl.DistanceToMarket>
) : (
'-'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { TableGroup } from './TableGroup'
import { createTableHeaders } from './tableHeaders'
import { OrderActions } from './types'

import { ORDERS_TABLE_PAGE_SIZE } from '../../const/tabs'
import { ALL_ORDERS_TAB, HISTORY_TAB, OPEN_TAB, UNFILLABLE_TAB, ORDERS_TABLE_PAGE_SIZE } from '../../const/tabs'
import { useGetBuildOrdersTableUrl } from '../../hooks/useGetBuildOrdersTableUrl'
import { getOrderParams } from '../../utils/getOrderParams'
import {
Expand Down Expand Up @@ -96,7 +96,7 @@ const Rows = styled.div`
`

export interface OrdersTableProps {
isOpenOrdersTab: boolean
currentTab: string
allowsOffchainSigning: boolean
currentPageNumber: number
chainId: SupportedChainId
Expand All @@ -110,7 +110,7 @@ export interface OrdersTableProps {
}

export function OrdersTable({
isOpenOrdersTab,
currentTab,
selectedOrders,
allowsOffchainSigning,
chainId,
Expand Down Expand Up @@ -143,7 +143,6 @@ export function OrdersTable({
return selectedOrders.reduce(
(acc, val) => {
acc[val.id] = true

return acc
},
{} as { [key: string]: true },
Expand Down Expand Up @@ -178,20 +177,20 @@ export function OrdersTable({

const visibleHeaders = useMemo(() => {
return tableHeaders.filter((header) => {
if (isOpenOrdersTab) {
if (currentTab === OPEN_TAB.id || currentTab === UNFILLABLE_TAB.id || currentTab === ALL_ORDERS_TAB.id) {
return header.showInOpenOrders
}
return header.showInClosedOrders
})
}, [tableHeaders, isOpenOrdersTab])
}, [tableHeaders, currentTab])

return (
<>
<TableBox>
<TableInner onScroll={onScroll}>
<TableHeader isOpenOrdersTab={isOpenOrdersTab} isRowSelectable={isRowSelectable}>
<TableHeader isOpenOrdersTab={currentTab !== HISTORY_TAB.id} isRowSelectable={isRowSelectable}>
{visibleHeaders.map((header) => {
if (header.id === 'checkbox' && (!isRowSelectable || !isOpenOrdersTab)) {
if (header.id === 'checkbox' && (!isRowSelectable || currentTab === HISTORY_TAB.id)) {
return null
}

Expand Down Expand Up @@ -245,7 +244,7 @@ export function OrdersTable({
key={order.id}
isRowSelectable={isRowSelectable}
isRowSelected={!!selectedOrdersMap[order.id]}
isOpenOrdersTab={isOpenOrdersTab}
isOpenOrdersTab={currentTab !== HISTORY_TAB.id}
order={order}
spotPrice={spotPrice}
prices={pendingOrdersPrices[order.id]}
Expand All @@ -266,7 +265,7 @@ export function OrdersTable({
key={item.parent.id}
isRowSelectable={isRowSelectable}
isRowSelected={!!selectedOrdersMap[item.parent.id]}
isOpenOrdersTab={isOpenOrdersTab}
isOpenOrdersTab={currentTab !== HISTORY_TAB.id}
spotPrice={spotPrice}
prices={pendingOrdersPrices[item.parent.id]}
isRateInverted={false}
Expand Down
Loading
Loading