Skip to content

Commit

Permalink
Niloofar Sadeghi / Bug - Getting "Sorry for interruption" error messa…
Browse files Browse the repository at this point in the history
…ge while trying to open P2P page on responsive (#8467)

* fix: data-list issue

* fix: circle/ci issue

* fix: onscroll issue

* fix: circle/ci

* fix: Trading Experience Assessment modal clicks

---------

Co-authored-by: niloofar sadeghi <niloofar.sadeghi@re-work.dev>
  • Loading branch information
niloofar-deriv and niloofar sadeghi committed May 8, 2023
1 parent 3c4cefc commit e7df8d2
Show file tree
Hide file tree
Showing 2 changed files with 186 additions and 186 deletions.
359 changes: 173 additions & 186 deletions packages/components/src/components/data-list/data-list.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import classNames from 'classnames';
import React from 'react';
import classNames from 'classnames';
import { TransitionGroup } from 'react-transition-group';
import {
List as _List,
Expand All @@ -8,7 +8,6 @@ import {
CellMeasurerProps,
AutoSizer as _AutoSizer,
type AutoSizerProps,
ScrollParams,
ListProps,
ListRowProps,
} from 'react-virtualized';
Expand All @@ -26,15 +25,16 @@ export type TPassThrough = { isTopUp: (item: TRow) => boolean };
export type TRow = {
[key: string]: string;
};
type DataListProps = {

type TDataList = {
className?: string;
data_source: TRow[];
footer?: React.ReactNode;
getRowAction?: (row: TRow) => string;
getRowSize?: (params: { index: number }) => number;
keyMapper?: (row: TRow) => number | string;
onRowsRendered?: () => void;
onScroll?: (ev: ScrollParams) => void;
onScroll?: React.UIEventHandler<HTMLDivElement>;
passthrough?: TPassThrough;
row_gap?: number;
setListRef?: (ref: MeasuredCellParent) => void;
Expand All @@ -44,196 +44,183 @@ type DataListProps = {
};
type GetContentType = { measure?: () => void | undefined };

const DataList = ({
children,
className,
data_source,
footer,
getRowSize,
keyMapper,
onRowsRendered,
onScroll,
setListRef,
overscanRowCount,
rowRenderer: rowRendererProp,
row_gap,
getRowAction,
passthrough,
}: DataListProps) => {
const [is_loading, setLoading] = React.useState(true);
const [is_scrolling, setIsScrolling] = React.useState(false);
const [scroll_top, setScrollTop] = React.useState(0);

const cache = React.useRef<CellMeasurerCache>();
const list_ref = React.useRef<MeasuredCellParent | null>(null);
const items_transition_map_ref = React.useRef<{ [key: string]: boolean }>({});
const data_source_ref = React.useRef<TRow[] | null>(null);
data_source_ref.current = data_source;

const is_dynamic_height = !getRowSize;

const trackItemsForTransition = React.useCallback(() => {
data_source.forEach((item: TRow, index: number) => {
const row_key: string | number = keyMapper?.(item) || `${index}-0`;
items_transition_map_ref.current[row_key] = true;
});
}, [data_source, keyMapper]);

React.useEffect(() => {
if (is_dynamic_height) {
cache.current = new CellMeasurerCache({
fixedWidth: true,
keyMapper: row_index => {
if (data_source_ref?.current && row_index < data_source_ref?.current.length)
return keyMapper?.(data_source_ref.current[row_index]) || row_index;
return row_index;
},
const DataList = React.memo(
({
children,
className,
data_source,
footer,
getRowSize,
keyMapper,
onRowsRendered,
onScroll,
setListRef,
overscanRowCount,
...other_props
}: TDataList) => {
const [is_loading, setLoading] = React.useState(true);
const [is_scrolling, setIsScrolling] = React.useState(false);
const [scroll_top, setScrollTop] = React.useState(0);

const cache = React.useRef<CellMeasurerCache>();
const list_ref = React.useRef<MeasuredCellParent | null>(null);
const items_transition_map_ref = React.useRef<{ [key: string]: boolean }>({});
const data_source_ref = React.useRef<TRow[] | null>(null);
data_source_ref.current = data_source;

const is_dynamic_height = !getRowSize;

const trackItemsForTransition = React.useCallback(() => {
data_source.forEach((item: TRow, index: number) => {
const row_key: string | number = keyMapper?.(item) || `${index}-0`;
items_transition_map_ref.current[row_key] = true;
});
}
trackItemsForTransition();
setLoading(false);
}, []); // eslint-disable-line react-hooks/exhaustive-deps

React.useEffect(() => {
if (is_dynamic_height) {
list_ref.current?.recomputeGridSize?.({ columnIndex: 0, rowIndex: 0 });
}
trackItemsForTransition();
}, [data_source, is_dynamic_height, trackItemsForTransition]);

const footerRowRenderer = () => {
return <React.Fragment>{rowRendererProp({ row: footer, is_footer: true })}</React.Fragment>;
};

const rowRenderer = ({ style, index, key, parent }: ListRowProps) => {
const row = data_source[index];
const action = getRowAction && getRowAction(row);
const destination_link = typeof action === 'string' ? action : undefined;
const action_desc = typeof action === 'object' ? action : undefined;
const row_key = keyMapper?.(row) || key;

const getContent = ({ measure }: GetContentType = {}) => (
<DataListRow
action_desc={action_desc}
destination_link={destination_link}
is_new_row={!items_transition_map_ref.current[row_key]}
is_scrolling={is_scrolling}
measure={measure}
passthrough={passthrough}
row_gap={row_gap}
row_key={row_key}
row={row}
rowRenderer={rowRendererProp}
is_dynamic_height={is_dynamic_height}
/>
);
}, [data_source, keyMapper]);

React.useEffect(() => {
if (is_dynamic_height) {
cache.current = new CellMeasurerCache({
fixedWidth: true,
keyMapper: row_index => {
if (data_source_ref?.current && row_index < data_source_ref?.current.length)
return keyMapper?.(data_source_ref.current[row_index]) || row_index;
return row_index;
},
});
}
trackItemsForTransition();
setLoading(false);
}, []); // eslint-disable-line react-hooks/exhaustive-deps

return is_dynamic_height && cache.current ? (
<CellMeasurer cache={cache?.current} columnIndex={0} key={row_key} rowIndex={index} parent={parent}>
{({ measure }) => <div style={style}>{getContent({ measure })}</div>}
</CellMeasurer>
) : (
<div key={row_key} style={style}>
{getContent()}
</div>
);
};
let timeout: ReturnType<typeof setTimeout>;
const handleScroll = (e: ScrollParams): void => {
const { scrollTop } = e;

clearTimeout(timeout);
if (!is_scrolling) {
setIsScrolling(true);
}
timeout = setTimeout(() => {
if (!is_loading) {
setIsScrolling(false);
React.useEffect(() => {
if (is_dynamic_height) {
list_ref.current?.recomputeGridSize?.({ columnIndex: 0, rowIndex: 0 });
}
}, 200);
trackItemsForTransition();
}, [data_source, is_dynamic_height, trackItemsForTransition]);

const footerRowRenderer = () => {
return <React.Fragment>{other_props.rowRenderer({ row: footer, is_footer: true })}</React.Fragment>;
};

const rowRenderer = ({ style, index, key, parent }: ListRowProps) => {
const { getRowAction, passthrough, row_gap } = other_props;
const row = data_source[index];
const action = getRowAction && getRowAction(row);
const destination_link = typeof action === 'string' ? action : undefined;
const action_desc = typeof action === 'object' ? action : undefined;
const row_key = keyMapper?.(row) || key;

const getContent = ({ measure }: GetContentType = {}) => (
<DataListRow
action_desc={action_desc}
destination_link={destination_link}
is_new_row={!items_transition_map_ref.current[row_key]}
is_scrolling={is_scrolling}
measure={measure}
passthrough={passthrough}
row_gap={row_gap}
row_key={row_key}
row={row}
rowRenderer={other_props.rowRenderer}
is_dynamic_height={is_dynamic_height}
/>
);

return is_dynamic_height && cache.current ? (
<CellMeasurer cache={cache.current} columnIndex={0} key={row_key} rowIndex={index} parent={parent}>
{({ measure }) => <div style={style}>{getContent({ measure })}</div>}
</CellMeasurer>
) : (
<div key={row_key} style={style}>
{getContent()}
</div>
);
};

setScrollTop(scrollTop);
onScroll?.(e);
};
const handleScroll: React.UIEventHandler<HTMLDivElement> = ev => {
let timeout;

const setRef = (ref: MeasuredCellParent) => {
list_ref.current = ref;
setListRef?.(ref);
};
clearTimeout(timeout);
if (!is_scrolling) {
setIsScrolling(true);
}
timeout = setTimeout(() => {
if (!is_loading) {
setIsScrolling(false);
}
}, 200);

setScrollTop((ev.target as HTMLElement).scrollTop);
if (typeof onScroll === 'function') {
onScroll(ev);
}
};

if (is_loading) {
return <div />;
}
return (
<div
data-testid='dt_data_list'
className={classNames(className, 'data-list', {
[`${className}__data-list`]: className,
})}
>
<div className='data-list__body-wrapper'>
<div className={classNames('data-list__body', { [`${className}__data-list-body`]: className })}>
<AutoSizer>
{({ width, height }) => (
// Don't remove `TransitionGroup`. When `TransitionGroup` is removed, transition life cycle events like `onEntered` won't be fired sometimes on it's `CSSTransition` children
<TransitionGroup style={{ height, width }}>
<ThemedScrollbars
onScroll={e => {
const event = {
clientHeight: e.currentTarget.clientHeight,
clientWidth: e.currentTarget.clientWidth,
scrollHeight: e.currentTarget.scrollHeight,
scrollLeft: e.currentTarget.scrollLeft,
scrollTop: e.currentTarget.scrollTop,
scrollWidth: e.currentTarget.scrollWidth,
};
handleScroll(event);
}}
autohide
is_bypassed={isMobile()}
>
<List
className={className}
deferredMeasurementCache={cache?.current}
height={height}
onRowsRendered={onRowsRendered}
overscanRowCount={overscanRowCount || 1}
ref={(ref: MeasuredCellParent) => setRef(ref)}
rowCount={data_source.length}
rowHeight={
is_dynamic_height && cache?.current?.rowHeight
? cache?.current?.rowHeight
: getRowSize || 0
}
rowRenderer={rowRenderer}
scrollingResetTimeInterval={0}
width={width}
{...(isDesktop()
? { scrollTop: scroll_top, autoHeight: true }
: { onScroll: target => handleScroll(target) })}
/>
</ThemedScrollbars>
</TransitionGroup>
)}
</AutoSizer>
const setRef = (ref: MeasuredCellParent) => {
list_ref.current = ref;
setListRef?.(ref);
};

if (is_loading) {
return <div />;
}
return (
<div
data-testid='dt_data_list'
className={classNames(className, 'data-list', {
[`${className}__data-list`]: className,
})}
>
<div className='data-list__body-wrapper'>
<div className={classNames('data-list__body', { [`${className}__data-list-body`]: className })}>
<AutoSizer>
{({ width, height }) => (
// Don't remove `TransitionGroup`. When `TransitionGroup` is removed, transition life cycle events like `onEntered` won't be fired sometimes on it's `CSSTransition` children
<TransitionGroup style={{ height, width }}>
<ThemedScrollbars onScroll={handleScroll} autohide is_bypassed={isMobile()}>
<List
className={className}
deferredMeasurementCache={cache?.current}
height={height}
onRowsRendered={onRowsRendered}
overscanRowCount={overscanRowCount || 1}
ref={(ref: MeasuredCellParent) => setRef(ref)}
rowCount={data_source.length}
rowHeight={
is_dynamic_height && cache?.current?.rowHeight
? cache?.current?.rowHeight
: getRowSize || 0
}
rowRenderer={rowRenderer}
scrollingResetTimeInterval={0}
width={width}
{...(isDesktop()
? { scrollTop: scroll_top, autoHeight: true }
: { onScroll: target => handleScroll({ target } as any) })}
/>
</ThemedScrollbars>
</TransitionGroup>
)}
</AutoSizer>
</div>
{children}
</div>
{children}
{footer && (
<div
className={classNames('data-list__footer', {
[`${className}__data-list-footer`]: className,
})}
>
{footerRowRenderer()}
</div>
)}
</div>
{footer && (
<div
className={classNames('data-list__footer', {
[`${className}__data-list-footer`]: className,
})}
>
{footerRowRenderer()}
</div>
)}
</div>
);
};
);
}
);

DataList.displayName = 'DataList';
(DataList as any).Cell = DataListCell;

DataList.Cell = DataListCell;
const genericMemo: <T>(component: T) => T = React.memo;
export default genericMemo(DataList);
export default DataList;
Loading

1 comment on commit e7df8d2

@vercel
Copy link

@vercel vercel bot commented on e7df8d2 May 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

deriv-app – ./

binary.sx
deriv-app.binary.sx
deriv-app.vercel.app
deriv-app-git-master.binary.sx

Please sign in to comment.