Skip to content

Commit

Permalink
Feat/tables redesign (#1541)
Browse files Browse the repository at this point in the history
* feat: tables skeleton

* feat: save table design

* feat: table in listingstable and ownerstable

* feat: trasnaction history table

* feat: rentalHistory table

* feat: last tables remaining

* feat: fix imports

* fix: tests

* feat: fixed actions on collections table

* fix: test on best buying opion

* fix: pr comments

* feat: remove nft server local url
  • Loading branch information
flobarreto authored and juanmahidalgo committed Jun 1, 2023
1 parent abee489 commit 96d7c51
Show file tree
Hide file tree
Showing 38 changed files with 1,376 additions and 891 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,19 @@
margin-left: unset;
}

.BestBuyingOption :global(.ui.loader.active) {
display: flex;
position: unset;
margin-top: 20px;
}

.BestBuyingOption .emptyContainer {
display: flex;
width: 100%;
justify-content: center;
align-items: center;
height: 150px;
}
.BestBuyingOption .buyWithCardClassName {
background-color: white !important;
color: black !important;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ describe('Best Buying Option', () => {
rarity: Rarity.UNIQUE,
price: '10',
available: 2,
isOnSale: false,
isOnSale: true,
creator: '0xcreator',
beneficiary: null,
createdAt: 1671033414000,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import noListings from '../../../images/noListings.png'
import { ManaToFiat } from '../../ManaToFiat'
import { LinkedProfile } from '../../LinkedProfile'
import { BuyNFTButtons } from '../SaleActionBox/BuyNFTButtons'
import { BelowTabs } from '../ListingsTableContainer/ListingsTableContainer.types'
import { BuyOptions, Props } from './BestBuyingOption.types'
import styles from './BestBuyingOption.module.css'

Expand All @@ -43,14 +42,14 @@ const BestBuyingOption = ({ asset, tableRef }: Props) => {
const handleViewOffers = () => {
history.replace({
pathname: location.pathname,
search: `selectedTableTab=${BelowTabs.OWNERS}`
search: `selectedTableTab=owners`
})
tableRef.current?.scrollIntoView({ block: 'center', behavior: 'smooth' })
}

useEffect(() => {
if (asset && !isNFT(asset)) {
if (asset.available > 1) {
if (asset.available > 1 && asset.isOnSale) {
setBuyOption(BuyOptions.MINT)
} else {
setIsLoading(true)
Expand Down Expand Up @@ -103,7 +102,7 @@ const BestBuyingOption = ({ asset, tableRef }: Props) => {
return (
<div className={styles.BestBuyingOption}>
{isLoading ? (
<div className={`${styles.containerColumn} ${styles.fullWitdth}`}>
<div className={styles.emptyContainer}>
<Loader active data-testid="loader" />
</div>
) : buyOption === BuyOptions.MINT && asset && !isNFT(asset) ? (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
padding: 20px !important;
}

.ListingsTable .issuedIdContainer {
.issuedIdContainer {
display: flex;
flex-direction: row;
justify-content: space-between;
Expand All @@ -23,39 +23,56 @@
font-weight: 700;
}

.ListingsTable .row {
.row {
display: flex;
flex-direction: row;
gap: 10px;
justify-content: space-between;
align-items: center;
}

.ListingsTable .badge {
.badgeContainer :global(.dcl.badge) {
color: white;
background-color: var(--background) !important;
background-color: transparent !important;
}

.badgeContainer {
display: flex;
flex-direction: row;
gap: 10px;
}

.ListingsTable .goToNFT {
color: white;
padding-right: 25px;
}

.ListingsTable .emptyTable {
height: 200px;
.emptyTable {
width: 100%;
height: 350px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 10px;
font-size: 20px;
}

.ListingsTable .manaField {
.manaField {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 14px;
}

.ListingsTable :global(.ui.header.dcl.mana) {
margin: 0px;
font-size: 15px;
.manaField :global(.ui.header:last-child) {
font-size: 14px;
}

.viewListingContainer {
display: flex;
flex-direction: row;
justify-content: space-between;
margin-right: 10px;
}

@media (max-width: 768px) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { waitFor } from '@testing-library/react'
import {
ChainId,
Item,
Expand All @@ -7,15 +8,14 @@ import {
Order,
Rarity
} from '@dcl/schemas'
import { waitFor, within } from '@testing-library/react'
import { t } from 'decentraland-dapps/dist/modules/translation/utils'
import { formatDistanceToNow, getDateAndMonthName } from '../../../lib/date'
import { formatWeiMANA } from '../../../lib/mana'
import { OwnersResponse } from '../../../modules/vendor/decentraland'
import * as nftAPI from '../../../modules/vendor/decentraland/nft/api'
import * as orderAPI from '../../../modules/vendor/decentraland/order/api'
import { renderWithProviders } from '../../../utils/tests'
import ListingsTable, { ROWS_PER_PAGE } from './ListingsTable'
import ListingsTable from './ListingsTable'

jest.mock('../../../modules/vendor/decentraland/nft/api')
jest.mock('../../../modules/vendor/decentraland/order/api')
Expand Down Expand Up @@ -139,7 +139,7 @@ describe('Listings Table', () => {
expect(loader).not.toBeInTheDocument()
})

expect(getByTestId('listings-table')).not.toBe(null)
expect(getByTestId('table-content')).not.toBe(null)
})

it('should render the table data correctly', async () => {
Expand All @@ -165,63 +165,4 @@ describe('Listings Table', () => {
expect(getByText(price)).not.toBe(null)
})
})

describe('Pagination', () => {
describe('Should have pagination', () => {
beforeEach(() => {
;(nftAPI.nftAPI.getOwners as jest.Mock).mockResolvedValueOnce({
data: Array(ROWS_PER_PAGE + 1).fill(ownersResponse),
total: 7
})
;(orderAPI.orderAPI.fetchOrders as jest.Mock).mockResolvedValueOnce({
data: Array(ROWS_PER_PAGE + 1).fill(orderResponse),
total: 7
})
})

it('should render the pagination correctly', async () => {
const screen = renderWithProviders(<ListingsTable asset={asset} />)

const { findByTestId, getByRole } = screen

const loader = await findByTestId('loader')

await waitFor(() => {
expect(loader).not.toBeInTheDocument()
})

const navigation = getByRole('navigation')

expect(within(navigation).getByText('1')).toBeInTheDocument()
expect(within(navigation).getByText('2')).toBeInTheDocument()
})
})

describe('Should not have pagination', () => {
beforeEach(() => {
;(nftAPI.nftAPI.getOwners as jest.Mock).mockResolvedValueOnce({
data: Array(ROWS_PER_PAGE - 1).fill(ownersResponse),
total: 5
})
;(orderAPI.orderAPI.fetchOrders as jest.Mock).mockResolvedValueOnce({
data: Array(ROWS_PER_PAGE - 1).fill(orderResponse),
total: 5
})
})

it('should not render pagination as there is no need', async () => {
const screen = renderWithProviders(<ListingsTable asset={asset} />)

const { findByTestId, queryByRole } = screen

const loader = await findByTestId('loader')

await waitFor(() => {
expect(loader).not.toBeInTheDocument()
})

expect(queryByRole('navigation')).not.toBeInTheDocument()
})
})
})
})
116 changes: 18 additions & 98 deletions webapp/src/components/AssetPage/ListingsTable/ListingsTable.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import React, { useState, useEffect } from 'react'
import { Link } from 'react-router-dom'
import { ListingStatus, Network } from '@dcl/schemas'
import { Table, Loader, Row, Pagination, Icon, Mana } from 'decentraland-ui'
import { OrderFilters, OrderSortBy } from '@dcl/schemas/dist/dapps/order'
import { t } from 'decentraland-dapps/dist/modules/translation/utils'
import { Order, OrderFilters, OrderSortBy } from '@dcl/schemas/dist/dapps/order'
import { nftAPI, orderAPI } from '../../../modules/vendor/decentraland'
import { locations } from '../../../modules/routing/locations'
import { formatWeiMANA } from '../../../lib/mana'
import { formatDistanceToNow, getDateAndMonthName } from '../../../lib/date'
import { LinkedProfile } from '../../LinkedProfile'
import noListings from '../../../images/noListings.png'
import { TableContent } from '../../Table/TableContent'
import { DataTableType } from '../../Table/TableContent/TableContent.types'
import { formatDataToTable } from './utils'
import { Props } from './ListingsTable.types'
import styles from './ListingsTable.module.css'

Expand All @@ -18,7 +16,7 @@ const INITIAL_PAGE = 1
const ListingsTable = (props: Props) => {
const { asset, sortBy = OrderSortBy.CHEAPEST } = props

const [orders, setOrders] = useState<Order[]>([])
const [orders, setOrders] = useState<DataTableType[]>([])
const [total, setTotal] = useState(0)
const [page, setPage] = useState(INITIAL_PAGE)
const [totalPages, setTotalPages] = useState<number>(0)
Expand Down Expand Up @@ -61,8 +59,8 @@ const ListingsTable = (props: Props) => {
orderAPI
.fetchOrders(params, sortBy)
.then(response => {
setOrders(response.data)
setTotalPages(Math.ceil(response.total / ROWS_PER_PAGE) || 0)
setOrders(formatDataToTable(response.data))
})
.finally(() => setIsLoading(false))
.catch(error => {
Expand All @@ -72,99 +70,21 @@ const ListingsTable = (props: Props) => {
}, [asset, setIsLoading, setOrders, sortBy, page])

return (
<div className={styles.ListingsTable}>
{isLoading ? (
<div className={styles.emptyTable}>
<Loader active data-testid="loader" />
</div>
) : orders.length === 0 ? (
<TableContent
data={orders}
isLoading={isLoading}
setPage={setPage}
totalPages={totalPages}
empty={() => (
<div className={styles.emptyTable}>
<img src={noListings} alt="empty" />
<span>{t('listings_table.there_are_no_listings')}</span>
</div>
) : (
<>
<Table basic="very" data-testid="listings-table">
<Table.Header>
<Table.Row>
<Table.HeaderCell className={styles.headerMargin}>
{t('listings_table.owner')}
</Table.HeaderCell>
<Table.HeaderCell>
{t('listings_table.published_date')}
</Table.HeaderCell>
<Table.HeaderCell>
{t('listings_table.expiration_date')}
</Table.HeaderCell>
<Table.HeaderCell>
{t('listings_table.issue_number')}
</Table.HeaderCell>
<Table.HeaderCell>{t('listings_table.price')}</Table.HeaderCell>
</Table.Row>
</Table.Header>
<Table.Body className={isLoading ? 'is-loading' : ''}>
{orders?.map(order => (
<Table.Row key={order.id}>
<Table.Cell>
<LinkedProfile
className={styles.linkedProfileRow}
address={order.owner}
/>
</Table.Cell>
<Table.Cell>
{getDateAndMonthName(order.createdAt)}
</Table.Cell>
<Table.Cell>
{formatDistanceToNow(+order.expiresAt, {
addSuffix: true
})}
</Table.Cell>
<Table.Cell>
<div className={styles.issuedIdContainer}>
<div className={styles.row}>
<span>
<span className={styles.issuedId}>
{order.issuedId}
</span>
/ {total}
</span>
</div>
</div>
</Table.Cell>
<Table.Cell>
<div className={styles.manaField}>
<Mana className="manaField" network={asset?.network}>
{formatWeiMANA(order.price)}
</Mana>
{asset?.contractAddress && order.tokenId && (
<Link
to={locations.nft(
asset.contractAddress,
order.tokenId
)}
>
<Icon name="arrow right" className={styles.goToNFT} />
</Link>
)}
</div>
</Table.Cell>
</Table.Row>
))}
</Table.Body>
</Table>
{totalPages && totalPages > 1 ? (
<Row center>
<Pagination
activePage={page}
totalPages={totalPages}
onPageChange={(_event, props) => setPage(+props.activePage!)}
firstItem={null}
lastItem={null}
/>
</Row>
) : null}
</>
)}
</div>
total={total}
rowsPerPage={ROWS_PER_PAGE}
activePage={page}
/>
)
}

Expand Down
Loading

0 comments on commit 96d7c51

Please sign in to comment.