Skip to content

Commit

Permalink
[FEQ] / Ameerul / FEQ-1401 Search the adverts list by nickname (deriv…
Browse files Browse the repository at this point in the history
…-com#13569)

* feat: added sort dropdown/button for buy/sell list

* chore: added suggestions

* feat: added search by nickname

* chore: added empty state to Table
  • Loading branch information
ameerul-deriv authored Feb 19, 2024
1 parent 89d0245 commit 213b5c4
Show file tree
Hide file tree
Showing 10 changed files with 122 additions and 47 deletions.
32 changes: 20 additions & 12 deletions packages/p2p-v2/src/components/Search/Search.scss
Original file line number Diff line number Diff line change
@@ -1,21 +1,29 @@
.p2p-v2-search {
border-radius: 4px;
width: 100%;
font-size: 1.4rem;
line-height: 2rem;

.p2p-v2-input {
margin: 0;
justify-content: flex-start;
position: relative;
align-items: center;
.deriv-input {
padding: 6px 8px;
font-size: 1.4rem;

&__container {
width: 100%;
}

&__field {
padding-left: 4.8rem;
margin-left: 0.8rem;

&:not(:placeholder-shown) ~ label,
&:focus ~ label {
display: none;
}
}

&__helper-message {
display: none;
}

@include mobile {
justify-content: center;
align-items: unset;
&__label {
left: 3rem;
}
}
}
10 changes: 7 additions & 3 deletions packages/p2p-v2/src/components/Search/Search.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useCallback } from 'react';
import { Input } from '@/components';
import { LabelPairedSearchMdRegularIcon } from '@deriv/quill-icons';
import { Input } from '@deriv-com/ui';
import './Search.scss';

type TSearchProps = {
Expand All @@ -22,8 +22,12 @@ const Search = ({ name, onSearch, placeholder }: TSearchProps) => {
const debouncedOnSearch = useCallback(debounce(onSearch, 500), [onSearch]);

return (
<form className='p2p-v2-search' onChange={event => debouncedOnSearch((event.target as HTMLInputElement).value)}>
<Input leadingIcon={<LabelPairedSearchMdRegularIcon />} name={name} placeholder={placeholder} />
<form
className='p2p-v2-search'
onChange={event => debouncedOnSearch((event.target as HTMLInputElement).value)}
role='search'
>
<Input label={placeholder} leftPlaceholder={<LabelPairedSearchMdRegularIcon />} name={name} type='search' />
</form>
);
};
Expand Down
21 changes: 16 additions & 5 deletions packages/p2p-v2/src/components/Table/Table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import './Table.scss';
type TProps<T> = {
columns?: ColumnDef<T>[];
data: T[];
emptyDataMessage: string;
groupBy?: GroupingState;
isFetching: boolean;
loadMoreFunction: () => void;
Expand All @@ -19,6 +20,7 @@ type TProps<T> = {
const Table = <T,>({
columns = [],
data,
emptyDataMessage,
isFetching,
loadMoreFunction,
renderHeader = () => <div />,
Expand Down Expand Up @@ -67,11 +69,20 @@ const Table = <T,>({
ref={tableContainerRef}
style={{ height: isDesktop && columns.length > 0 ? `calc(${height}px - 3.6rem)` : '100%' }}
>
{table.getRowModel().rows.map(row => (
<div className='p2p-v2-table__content-row' key={row.id}>
{rowRender(row.original)}
</div>
))}
{data && data.length > 0 ? (
table.getRowModel().rows.map(row => (
<div className='p2p-v2-table__content-row' key={row.id}>
{rowRender(row.original)}
</div>
))
) : (
<Text
className='w-full flex items-center justify-center border-b-[1px] border-solid border-b-[#f2f3f4] p-[1.6rem]'
size='sm'
>
{emptyDataMessage}
</Text>
)}
</div>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
.p2p-v2-sort-dropdown {
.deriv-dropdown__items {
top: 4.4rem;
}

.deriv-input {
&__field {
font-size: 14px;

&:not(:placeholder-shown) ~ label {
transform: translate(-29%, -50%);
}
}

&__helper-message {
display: none;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { TSortByValues } from '@/utils';
import { LabelPairedChevronDownMdRegularIcon } from '@deriv/quill-icons';
import { Button, Dropdown, useDevice } from '@deriv-com/ui';
import SortIcon from '../../../../public/ic-cashier-sort.svg';
import './SortDropdown.scss';

type TSortDropdownProps = {
list: readonly { text: string; value: string }[];
Expand All @@ -26,14 +27,16 @@ const SortDropdown = ({ list, onSelect, setIsFilterModalOpen, value }: TSortDrop
}

return (
<Dropdown
dropdownIcon={<LabelPairedChevronDownMdRegularIcon />}
label='Sort by'
list={list}
name='Sort by'
onSelect={(value: string) => onSelect(value as TSortByValues)}
value={value}
/>
<div className='p2p-v2-sort-dropdown'>
<Dropdown
dropdownIcon={<LabelPairedChevronDownMdRegularIcon />}
label='Sort by'
list={list}
name='Sort by'
onSelect={(value: string) => onSelect(value as TSortByValues)}
value={value}
/>
</div>
);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,19 @@
border: 1px solid #f2f3f4;
}

.deriv-dropdown__items {
top: 4.4rem;
}

.deriv-input {
padding: 6px 8px;
width: 24rem;

&__container {
width: 24rem;
}

&__field {
font-size: 14px;

&:not(:placeholder-shown) ~ label {
transform: translate(-29%, -50%);
}
@include mobile {
height: 3.2rem;
display: flex;
align-items: center;
line-height: 1rem;
}

&__helper-message {
display: none;
&__container {
width: 24rem;
}
}

Expand All @@ -56,6 +48,10 @@
}

&__row {
display: flex;
flex-direction: row;
gap: 1rem;

@include mobile {
width: 100%;
padding: 1.6rem;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import React from 'react';
import { Search } from '@/components';
import { SORT_BY_LIST } from '@/constants';
import { TSortByValues } from '@/utils';
import { Tab, Tabs } from '@deriv-com/ui';
import { Tab, Tabs, useDevice } from '@deriv-com/ui';
import { SortDropdown } from '../../components';
import './BuySellHeader.scss';

type TBuySellHeaderProps = {
activeTab: string;
setActiveTab: (tab: string) => void;
setIsFilterModalOpen: (value: boolean) => void;
setSearchValue: (value: string) => void;
setSortDropdownValue: (value: TSortByValues) => void;
sortDropdownValue: TSortByValues;
};
Expand All @@ -17,9 +19,12 @@ const BuySellHeader = ({
activeTab,
setActiveTab,
setIsFilterModalOpen,
setSearchValue,
setSortDropdownValue,
sortDropdownValue,
}: TBuySellHeaderProps) => {
const { isMobile } = useDevice();

return (
<div className='p2p-v2-buy-sell-header' data-testid='dt_p2p_v2_buy_sell_header'>
<Tabs
Expand All @@ -33,6 +38,11 @@ const BuySellHeader = ({
<Tab title='Sell' />
</Tabs>
<div className='p2p-v2-buy-sell-header__row'>
<Search
name='search-nickname'
onSearch={setSearchValue}
placeholder={isMobile ? 'Search' : 'Search by nickname'}
/>
<SortDropdown
list={SORT_BY_LIST}
onSelect={setSortDropdownValue}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import { TSortByValues } from '@/utils';
import { useDevice } from '@deriv-com/ui';
import { render, screen, within } from '@testing-library/react';
import { act, render, screen, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import BuySellHeader from '../BuySellHeader';

Expand All @@ -19,6 +19,7 @@ const mockProps = {
],
setActiveTab: jest.fn(),
setIsFilterModalOpen: jest.fn(),
setSearchValue: jest.fn(),
setSortDropdownValue: jest.fn(),
sortDropdownValue: 'rate' as TSortByValues,
};
Expand All @@ -32,6 +33,8 @@ jest.mock('@deriv-com/ui', () => ({

const mockUseDevice = useDevice as jest.Mock;

jest.useFakeTimers();

describe('<BuySellHeader />', () => {
it('should render the BuySellHeader', () => {
render(<BuySellHeader {...mockProps} />);
Expand All @@ -40,6 +43,7 @@ describe('<BuySellHeader />', () => {

expect(within(buySellHeader).getByRole('button', { name: 'Buy' })).toBeInTheDocument();
expect(within(buySellHeader).getByRole('button', { name: 'Sell' })).toBeInTheDocument();
expect(screen.getByRole('searchbox')).toBeInTheDocument();
expect(screen.getByRole('combobox', { name: 'Sort by' })).toBeInTheDocument();
});

Expand All @@ -61,6 +65,22 @@ describe('<BuySellHeader />', () => {
expect(mockProps.setActiveTab).toHaveBeenCalledWith('Buy');
});

it('should call setSearchValue when a value is entered in the search input', () => {
render(<BuySellHeader {...mockProps} />);

const searchInput = screen.getByRole('searchbox');

act(() => {
userEvent.type(searchInput, 'John Doe');
});

act(() => {
jest.runAllTimers();
});

expect(mockProps.setSearchValue).toHaveBeenCalledWith('John Doe');
});

it('should call setSortDropdownValue when a value is selected from the dropdown', () => {
render(<BuySellHeader {...mockProps} />);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@ const headerRenderer = (header: string) => <span>{header}</span>;
const BuySellTable = () => {
const [activeTab, setActiveTab] = useState<string>('Buy');
const [sortDropdownValue, setSortDropdownValue] = useState<TSortByValues>('rate');
const [searchValue, setSearchValue] = useState<string>('');
const [isFilterModalOpen, setIsFilterModalOpen] = useState<boolean>(false);
const { data, isFetching, isLoading, loadMoreAdverts } = p2p.advert.useGetList({
advertiser_name: searchValue,
counterparty_type: activeTab === 'Buy' ? BUY_SELL.BUY : BUY_SELL.SELL,
sort_by: sortDropdownValue,
});
Expand All @@ -43,6 +45,7 @@ const BuySellTable = () => {
activeTab={activeTab}
setActiveTab={setActiveTab}
setIsFilterModalOpen={setIsFilterModalOpen}
setSearchValue={setSearchValue}
setSortDropdownValue={setSortDropdownValue}
sortDropdownValue={sortDropdownValue}
/>
Expand All @@ -53,6 +56,7 @@ const BuySellTable = () => {
<Table
columns={columns}
data={data}
emptyDataMessage='There are no matching ads.'
isFetching={isFetching}
loadMoreFunction={loadMoreAdverts}
renderHeader={headerRenderer}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const MyProfileCounterpartiesTableRow = ({ id, isBlocked, nickname }: TMyProfile
<>
<div className='p2p-v2-my-profile-counterparties-table-row'>
<div className='p2p-v2-my-profile-counterparties-table-row__nickname-wrapper'>
<UserAvatar nickname={nickname} />
<UserAvatar className='h-[3rem] w-[3rem]' nickname={nickname} size={65} textSize='sm' />
<Text size={isMobile ? 'md' : 'sm'}>{nickname}</Text>
</div>
{/* TODO: variant to be replaced after available in @deriv-com/ui */}
Expand Down

0 comments on commit 213b5c4

Please sign in to comment.