Skip to content

Commit fe1be15

Browse files
authored
Merge 9154327 into 5ac2de0
2 parents 5ac2de0 + 9154327 commit fe1be15

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+1659
-1094
lines changed

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,7 @@
342342
"@types/qs": "6.9.7",
343343
"@types/react": "18.2.65",
344344
"@types/react-native-extra-dimensions-android": "1.2.3",
345+
"@types/react-native-indicators": "0.16.6",
345346
"@types/react-test-renderer": "18.3.0",
346347
"@types/styled-components": "5.1.7",
347348
"@types/url-parse": "1.4.3",

src/__swaps__/types/refraction.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { ZerionAsset } from '@/__swaps__/types/assets';
22
import { ChainId, ChainName } from '@/chains/types';
3-
import { PaginatedTransactionsApiResponse } from '@/resources/transactions/types';
3+
import { PaginatedTransactionsApiResponse } from '@/entities';
44

55
/**
66
* Metadata for a message from the Zerion API.

src/components/ActivityIndicator.js src/components/ActivityIndicator.tsx

+8-2
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,15 @@ import { Centered } from './layout';
55
import styled from '@/styled-thing';
66
import { position } from '@/styles';
77

8-
const Container = styled(Centered)(({ size }) => position.sizeAsObject(Number(size)));
8+
const Container = styled(Centered)(({ size }: { size: number }) => position.sizeAsObject(Number(size)));
99

10-
export default function ActivityIndicator({ color, isInteraction = false, size = 25, ...props }) {
10+
type ActivityIndicatorProps = {
11+
color?: string;
12+
isInteraction?: boolean;
13+
size?: number;
14+
};
15+
16+
export default function ActivityIndicator({ color, isInteraction = false, size = 25, ...props }: ActivityIndicatorProps) {
1117
const { colors } = useTheme();
1218
return (
1319
<Container size={size} {...props}>

src/components/Divider.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import React from 'react';
33
import { magicMemo } from '../utils';
44
import styled from '@/styled-thing';
55
import { borders, position } from '@/styles';
6-
import { StyleProp, View, ViewProps, ViewStyle } from 'react-native';
6+
import { View } from 'react-native';
77
import { ThemeContextProps, useTheme } from '@/theme';
88

99
export const DividerSize = 2;

src/components/activity-list/ActivityList.js

-145
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
import React, { useCallback, useEffect, useState } from 'react';
2+
import { SectionList, StyleSheet, View } from 'react-native';
3+
import sectionListGetItemLayout from 'react-native-section-list-get-item-layout';
4+
import ActivityIndicator from '../ActivityIndicator';
5+
import Spinner from '../Spinner';
6+
import { ButtonPressAnimation } from '../animations';
7+
import { CoinRowHeight } from '../coin-row/CoinRow';
8+
import Text from '../text/Text';
9+
import ActivityListEmptyState from './ActivityListEmptyState';
10+
import ActivityListHeader from './ActivityListHeader';
11+
import styled from '@/styled-thing';
12+
import { ThemeContextProps, useTheme } from '@/theme';
13+
import { useSectionListScrollToTopContext } from '@/navigation/SectionListScrollToTopContext';
14+
import { safeAreaInsetValues } from '@/utils';
15+
import { useAccountSettings, useAccountTransactions } from '@/hooks';
16+
import { usePendingTransactionsStore } from '@/state/pendingTransactions';
17+
import { TransactionSections, TransactionItemForSectionList } from '@/helpers/buildTransactionsSectionsSelector';
18+
19+
const sx = StyleSheet.create({
20+
sectionHeader: {
21+
paddingVertical: 18,
22+
},
23+
});
24+
25+
const ActivityListHeaderHeight = 42;
26+
const TRANSACTION_COIN_ROW_VERTICAL_PADDING = 7;
27+
28+
const getItemLayout = sectionListGetItemLayout({
29+
getItemHeight: () => CoinRowHeight + TRANSACTION_COIN_ROW_VERTICAL_PADDING * 2,
30+
getSectionHeaderHeight: () => ActivityListHeaderHeight,
31+
});
32+
33+
const keyExtractor = (data: TransactionSections['data'][number]) => {
34+
if ('hash' in data) {
35+
return (data.hash || data.timestamp ? data.timestamp?.toString() : performance.now().toString()) ?? performance.now().toString();
36+
}
37+
return (
38+
(data.displayDetails?.timestampInMs ? data.displayDetails.timestampInMs.toString() : performance.now().toString()) ??
39+
performance.now().toString()
40+
);
41+
};
42+
43+
const renderSectionHeader = ({ section, colors }: { section: TransactionSections; colors: ThemeContextProps['colors'] }) => {
44+
return (
45+
<View style={[sx.sectionHeader, { backgroundColor: colors.white }]}>
46+
<ActivityListHeader {...section} />
47+
</View>
48+
);
49+
};
50+
51+
const LoadingSpinner = android ? Spinner : ActivityIndicator;
52+
53+
const FooterWrapper = styled(ButtonPressAnimation)({
54+
alignItems: 'center',
55+
height: 40,
56+
justifyContent: 'center',
57+
paddingBottom: 10,
58+
width: '100%',
59+
});
60+
61+
function ListFooterComponent({ label, onPress }: { label: string; onPress: () => void }) {
62+
const [isLoading, setIsLoading] = useState(false);
63+
const { colors } = useTheme();
64+
65+
useEffect(() => {
66+
if (isLoading) {
67+
onPress();
68+
setIsLoading(false);
69+
}
70+
}, [isLoading, setIsLoading, onPress]);
71+
const onPressWrapper = () => {
72+
setIsLoading(true);
73+
};
74+
return (
75+
<FooterWrapper onPress={onPressWrapper}>
76+
{isLoading ? (
77+
<LoadingSpinner />
78+
) : (
79+
<Text align="center" color={colors.alpha(colors.blueGreyDark, 0.3)} lineHeight="loose" size="smedium" weight="bold">
80+
{label}
81+
</Text>
82+
)}
83+
</FooterWrapper>
84+
);
85+
}
86+
87+
const ActivityList = () => {
88+
const { accountAddress, nativeCurrency } = useAccountSettings();
89+
90+
const { setScrollToTopRef } = useSectionListScrollToTopContext();
91+
const { sections, nextPage, transactionsCount, remainingItemsLabel } = useAccountTransactions();
92+
const pendingTransactions = usePendingTransactionsStore(state => state.pendingTransactions[accountAddress] || []);
93+
94+
const { colors } = useTheme();
95+
const renderSectionHeaderWithTheme = useCallback(
96+
({ section }: { section: TransactionSections }) => renderSectionHeader({ colors, section }),
97+
[colors]
98+
);
99+
100+
const handleScrollToTopRef = (ref: SectionList<TransactionItemForSectionList, TransactionSections> | null) => {
101+
if (!ref) return;
102+
// @ts-expect-error - no idea why this is not working
103+
setScrollToTopRef(ref);
104+
};
105+
106+
return (
107+
<SectionList<TransactionItemForSectionList, TransactionSections>
108+
ListFooterComponent={() => remainingItemsLabel && <ListFooterComponent label={remainingItemsLabel} onPress={nextPage} />}
109+
ref={handleScrollToTopRef}
110+
alwaysBounceVertical={false}
111+
contentContainerStyle={{ paddingBottom: !transactionsCount ? 0 : 90 }}
112+
extraData={{
113+
hasPendingTransaction: pendingTransactions.length > 0,
114+
nativeCurrency,
115+
pendingTransactionsCount: pendingTransactions.length,
116+
}}
117+
testID={'wallet-activity-list'}
118+
ListEmptyComponent={<ActivityListEmptyState />}
119+
// @ts-expect-error - mismatch between react-native-section-list-get-item-layout and SectionList
120+
getItemLayout={getItemLayout}
121+
initialNumToRender={12}
122+
keyExtractor={keyExtractor}
123+
removeClippedSubviews
124+
renderSectionHeader={renderSectionHeaderWithTheme}
125+
scrollIndicatorInsets={{
126+
bottom: safeAreaInsetValues.bottom + 14,
127+
}}
128+
sections={sections}
129+
/>
130+
);
131+
};
132+
133+
export default ActivityList;

src/components/activity-list/ActivityListEmptyState.js src/components/activity-list/ActivityListEmptyState.tsx

+7-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,13 @@ const Container = styled(Column)({
1616
width: 200,
1717
});
1818

19-
const ActivityListEmptyState = ({ children, emoji, label }) => {
19+
type ActivityListEmptyStateProps = {
20+
children?: React.ReactNode;
21+
emoji: string;
22+
label: string;
23+
};
24+
25+
const ActivityListEmptyState = ({ children, emoji, label }: ActivityListEmptyStateProps) => {
2026
const { top: topInset } = useSafeAreaInsets();
2127
const { colors, isDarkMode } = useTheme();
2228

src/components/activity-list/LoadingState.js src/components/activity-list/LoadingState.tsx

+5-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@ import { AssetListItemSkeleton } from '../asset-list';
33
import { Column } from '../layout';
44
import { times } from '@/helpers/utilities';
55

6-
const LoadingState = ({ children }) => (
6+
type LoadingStateProps = {
7+
children: React.ReactNode;
8+
};
9+
10+
const LoadingState = ({ children }: LoadingStateProps) => (
711
<Column flex={1}>
812
{children}
913
<Column flex={1}>
File renamed without changes.

src/components/cards/GasCard.tsx

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// @ts-expect-error
21
import AnimateNumber from '@bankify/react-native-animate-number';
32
import { useIsFocused } from '@react-navigation/native';
43
import * as i18n from '@/languages';
@@ -60,8 +59,7 @@ export const GasCard = () => {
6059
const isCurrentGweiLoaded = currentGwei && Number(currentGwei) > 0;
6160

6261
const renderGweiText = useCallback(
63-
// @ts-expect-error passed to an untyped JS component
64-
animatedNumber => {
62+
(animatedNumber: number) => {
6563
const priceText =
6664
animatedNumber === 0
6765
? isCurrentGweiLoaded

0 commit comments

Comments
 (0)