Skip to content
This repository has been archived by the owner on May 13, 2024. It is now read-only.

Feature/new dashboard #313

Open
wants to merge 22 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
c5aace2
feat: new app dashboard and app registration flow
shafin-deriv Mar 18, 2024
4f9d15c
chore: update file names
shafin-deriv Mar 18, 2024
e2328e6
chore: remove lazy loading for server rendering issue
shafin-deriv Mar 18, 2024
dbd310e
chore: fix previous tests
shafin-deriv Mar 18, 2024
c586cc7
fix: test case
shafin-deriv Mar 18, 2024
35274fa
test: add test for CustomRadioButton
shafin-deriv Mar 19, 2024
4c9ff94
Merge pull request #289 from binary-com/master
sandeep-deriv Mar 19, 2024
5bc5b9a
Merge pull request #292 from binary-com/master
sandeep-deriv Mar 19, 2024
b7e648c
test: swipeable bottom sheet test case
shafin-deriv Mar 21, 2024
5e0713c
chore: change radio button to checkbox
shafin-deriv Mar 21, 2024
5c15552
test: improve swipeable bottom sheet test coverage
shafin-deriv Mar 21, 2024
69d3707
test: finalize all tests
shafin-deriv Mar 22, 2024
cd30d63
Merge pull request #286 from shafin-deriv/shafin/DAPI-462/feat--api-r…
sandeep-deriv Apr 4, 2024
0390003
feat: app manager desktop
shafin-deriv Apr 15, 2024
e87d5e3
feat: complete responsive design
shafin-deriv Apr 16, 2024
741faee
fix: fix existing test cases
shafin-deriv Apr 16, 2024
07dffb8
Merge remote-tracking branch 'upstream/master' into feature/new-dashb…
sandeep-deriv Apr 17, 2024
c8153f5
test: test coverage for accordion, tooltip and tabs
shafin-deriv Apr 17, 2024
7c4c2d5
Merge branch 'feature/new-dashboard' into shafin/DAPI-464/feat--api-a…
shafin-deriv Apr 17, 2024
121f3d1
test: test coverage for copy button and reponsive table
shafin-deriv Apr 17, 2024
0da7466
fix: text overflow issue
shafin-deriv Apr 18, 2024
a8cf15c
Merge pull request #315 from shafin-deriv/shafin/DAPI-464/feat--api-a…
sandeep-deriv Apr 22, 2024
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
4 changes: 3 additions & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ module.exports = {
'^.+\\.(j|t)sx?$': 'ts-jest',
'^.+\\.mjs$': 'babel-jest',
},
transformIgnorePatterns: ['node_modules/(?!(@docusaurus|swiper|ssr-window|dom7)|@theme)'],
transformIgnorePatterns: [
'node_modules/(?!(@docusaurus|swiper|ssr-window|dom7)|@theme|@deriv/quill-design)',
],
moduleNameMapper: {
'@theme/(.*)': '@docusaurus/theme-classic/src/theme/$1',

Expand Down
15 changes: 15 additions & 0 deletions jest.setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,18 @@ window.ResizeObserver =
observe: jest.fn(),
unobserve: jest.fn(),
}));

// HINT: we need this mock for the tests with useDevice hook
Object.defineProperty(window, 'matchMedia', {
writable: true,
value: jest.fn().mockImplementation((query) => ({
matches: false,
media: query,
onchange: null,
addListener: jest.fn(),
removeListener: jest.fn(),
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
dispatchEvent: jest.fn(),
})),
});
1,646 changes: 1,406 additions & 240 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
},
"dependencies": {
"@deriv/deriv-api": "^1.0.11",
"@deriv/quill-design": "^1.2.18",
"@deriv/quill-icons": "^1.21.3",
"@deriv/ui": "^0.1.0",
"@docusaurus/core": "^2.4.0",
"@docusaurus/plugin-client-redirects": "^2.4.0",
Expand All @@ -30,9 +32,13 @@
"@easyops-cn/docusaurus-search-local": "^0.35.0",
"@hookform/resolvers": "^2.9.10",
"@mdx-js/react": "^1.6.22",
"@radix-ui/react-accordion": "^1.1.2",
"@radix-ui/react-dropdown-menu": "^2.0.2",
"@radix-ui/react-tabs": "^1.0.2",
"@radix-ui/react-tooltip": "^1.0.7",
"@react-spring/web": "^9.7.3",
"@testing-library/react-hooks": "^8.0.1",
"@use-gesture/react": "^10.3.0",
"babel-plugin-jsx-remove-data-test-id": "^3.0.0",
"clsx": "^1.2.1",
"docusaurus-plugin-sass": "^0.2.2",
Expand Down
31 changes: 31 additions & 0 deletions src/components/CustomAccordion/__tests__/custom-accordion.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React from 'react';
import { cleanup, render, screen } from '@testing-library/react';
import CustomAccordion from '..';
import userEvent from '@testing-library/user-event';

const mock_accordion_items = [
{ header: 'header_1', content: 'content 1' },
{ header: 'header_2', content: 'content 2' },
];

describe('CustomAccordion', () => {
beforeEach(() => {
render(<CustomAccordion items={mock_accordion_items} />);
});

afterEach(() => {
cleanup();
});

it('should render the custom accordion', () => {
const header = screen.getByText('header_1');
expect(header).toBeInTheDocument();
});

it('should open accordion content on click', async () => {
const header = screen.getByText('header_2');
await userEvent.click(header);
const content = screen.getByText('content 2');
expect(content).toBeInTheDocument();
});
});
79 changes: 79 additions & 0 deletions src/components/CustomAccordion/custom-accordion.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
.accordion_root {
margin: 16px;
margin-top: 48px;
display: flex;
flex-direction: column;

&__item {
overflow: hidden;
margin-top: 2px;
border-radius: 24px;
}
}

.accordion_header {
display: flex;
background-color: transparent;

[data-state='open'] {
background-color: var(--opacity-black-75);
}

&__trigger {
font-family: inherit;
padding: 24px;
height: 42px;
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 16px;
line-height: 1;
}

.accordion_chevron {
transition: transform 300ms cubic-bezier(0.87, 0, 0.13, 1);
}

[data-state='open'] > .accordion_chevron {
transform: rotate(180deg);
}
}

.accordion_content {
overflow: hidden;
background-color: var(--opacity-black-75);

&__text {
padding: 16px 18px;
font-size: 14px;
font-weight: 400;
}

&[data-state='open'] {
animation: slideDown 300ms cubic-bezier(0.87, 0, 0.13, 1);
}

&[data-state='closed'] {
animation: slideUp 300ms cubic-bezier(0.87, 0, 0.13, 1);
background-color: transparent;
}
}

@keyframes slideDown {
from {
height: 0;
}
to {
height: var(--radix-accordion-content-height);
}
}

@keyframes slideUp {
from {
height: var(--radix-accordion-content-height);
}
to {
height: 0;
}
}
41 changes: 41 additions & 0 deletions src/components/CustomAccordion/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React from 'react';
import { StandaloneChevronDownRegularIcon } from '@deriv/quill-icons';
import * as Accordion from '@radix-ui/react-accordion';
import './custom-accordion.scss';

type TCustomAccordionProps = {
items: Array<{ header: string; content: React.ReactNode }>;
};

const AccordionTrigger: React.FC = ({ children }) => (
<Accordion.Header className='accordion_header'>
<Accordion.Trigger className='accordion_header__trigger'>
{children}
<StandaloneChevronDownRegularIcon iconSize='md' className='accordion_chevron' />
</Accordion.Trigger>
</Accordion.Header>
);

const AccordionContent: React.FC = ({ children }) => (
<Accordion.Content className='accordion_content'>
<div className='accordion_content__text'>{children}</div>
</Accordion.Content>
);

const CustomAccordion: React.FC<TCustomAccordionProps> = ({ items }) => (
<Accordion.Root
data-testid='dt_accordion_root'
className='accordion_root'
type='single'
collapsible
>
{items.map((item) => (
<Accordion.Item className='accordion_root__item' key={item.header} value={item.header}>
<AccordionTrigger>{item.header}</AccordionTrigger>
<AccordionContent>{item.content}</AccordionContent>
</Accordion.Item>
))}
</Accordion.Root>
);

export default CustomAccordion;
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import React from 'react';
import { cleanup, render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import CustomRadioButton from '..';

const onChange = jest.fn();

describe('CustomRadioButton', () => {
const renderRadioButton = ({ checked }) => {
render(
<CustomRadioButton
id='test_id'
name='test_name'
value='test_value'
checked={checked}
onChange={onChange}
>
<label htmlFor='test_id'>this is a test label</label>
</CustomRadioButton>,
);
};

afterEach(() => {
cleanup();
});

it('should render the radio button', () => {
renderRadioButton({ checked: true });
const label = screen.getByText('this is a test label');
expect(label).toBeInTheDocument();
});

it('should render the radio button with checked icon', () => {
renderRadioButton({ checked: true });
const imgElement = screen.getByRole('img');
expect(imgElement).toBeInTheDocument();
expect(imgElement).toHaveAttribute('src', '/img/circle_dot_caption_fill.svg');
});

it('should render the radio button with unchecked icon', () => {
renderRadioButton({ checked: false });
const imgElement = screen.getByRole('img');
expect(imgElement).toBeInTheDocument();
expect(imgElement).toHaveAttribute('src', '/img/circle_dot_caption_bold.svg');
});

it('should fire the onChange event when clicking the button', async () => {
renderRadioButton({ checked: false });
const radio_button = screen.getByRole<HTMLInputElement>('radio', {
name: 'this is a test label',
});
await userEvent.click(radio_button);
expect(onChange).toBeCalled();
});
});
30 changes: 30 additions & 0 deletions src/components/CustomRadioButton/custom_radio_button.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
.custom_radio {
position: relative;

input {
opacity: 0;
position: absolute;
top: 8px;
}

label {
display: flex;
align-items: baseline;
cursor: pointer;
}

&__icon {
position: relative;
margin-inline-end: 8px;
top: 6px;

img {
width: 24px;
height: 24px;

@media (max-width: 767px) {
width: 48px;
}
}
}
}
38 changes: 38 additions & 0 deletions src/components/CustomRadioButton/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React from 'react';
import './custom_radio_button.scss';

type CustomRadioButtonProps = {
id: string;
name: string;
value: string;
checked: boolean;
onChange: () => void;
};

const CustomRadioButton: React.FC<CustomRadioButtonProps> = ({
id,
name,
value,
checked,
onChange,
children,
...rest
}) => {
return (
<div className='custom_radio'>
<input type='radio' id={id} name={name} value={value} onClick={onChange} {...rest} />
<label htmlFor={id}>
<div className='custom_radio__icon'>
{checked ? (
<img src='/img/circle_dot_caption_fill.svg' />
) : (
<img src='/img/circle_dot_caption_bold.svg' />
)}
</div>
<div>{children}</div>
</label>
</div>
);
};

export default CustomRadioButton;
31 changes: 31 additions & 0 deletions src/components/CustomTabs/__tests__/custom-tabs.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React from 'react';
import { cleanup, render, screen } from '@testing-library/react';
import CustomTabs from '..';
import userEvent from '@testing-library/user-event';

const mock_tabs = [
{ label: 'tab_1', content: 'content 1' },
{ label: 'tab_2', content: 'content 2' },
];

describe('CustomTabs', () => {
beforeEach(() => {
render(<CustomTabs tabs={mock_tabs}></CustomTabs>);
});

afterEach(() => {
cleanup();
});

it('should render the custom tabs', () => {
const tab = screen.getByText('tab_1');
expect(tab).toBeInTheDocument();
});

it('should change tab content on different tab click', async () => {
const tab = screen.getByText('tab_2');
await userEvent.click(tab);
const content = screen.getByText('content 2');
expect(content).toBeInTheDocument();
});
});
30 changes: 30 additions & 0 deletions src/components/CustomTabs/custom-tabs.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
.tabs {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;

&_header {
margin-block: 64px;
background-color: var(--opacity-black-75);
padding: 12px;
border-radius: 24px;
text-align: center;

&__items {
display: flex;
justify-content: space-between;
align-items: center;
}
&__item {
padding: 8px;
min-width: 160px;
cursor: pointer;

&.active {
background-color: var(--solid-slate-50);
border-radius: 12px;
}
}
}
}
Loading
Loading