Skip to content

Commit 809d356

Browse files
committed
Integrate getTxInfo reports server API
1 parent 209f6ae commit 809d356

File tree

17 files changed

+683
-45
lines changed

17 files changed

+683
-45
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## Unreleased (develop)
44

55
- added: `ReturnKeyTypeButton` to `FlipInputModal2`
6+
- added: Integrated reports server order status to transaction details.
67

78
## 4.32.0 (staging)
89

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
"@react-navigation/native": "^6.1.3",
8181
"@react-navigation/stack": "^6.3.12",
8282
"@sentry/react-native": "^6.14.0",
83+
"@tanstack/react-query": "^5.83.0",
8384
"@types/jsrsasign": "^10.5.13",
8485
"@unstoppabledomains/resolution": "^9.3.0",
8586
"@walletconnect/react-native-compat": "^2.11.0",

src/components/App.tsx

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import '@ethersproject/shims'
22

33
import { ErrorBoundary, Scope, wrap } from '@sentry/react-native'
4+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
45
import * as React from 'react'
56
import { StyleSheet } from 'react-native'
67
import { GestureHandlerRootView } from 'react-native-gesture-handler'
@@ -12,26 +13,30 @@ import { EdgeCoreManager } from './services/EdgeCoreManager'
1213
import { StatusBarManager } from './services/StatusBarManager'
1314
import { ThemeProvider } from './services/ThemeContext'
1415

16+
const queryClient = new QueryClient()
17+
1518
function MainApp() {
1619
const handleBeforeCapture = useHandler((scope: Scope) => {
1720
scope.setLevel('fatal')
1821
scope.setTag('handled', false)
1922
})
2023

2124
return (
22-
<SafeAreaProvider>
23-
<ThemeProvider>
24-
<GestureHandlerRootView style={StyleSheet.absoluteFill}>
25-
<ErrorBoundary
26-
beforeCapture={handleBeforeCapture}
27-
fallback={<CrashScene />}
28-
>
29-
<StatusBarManager />
30-
<EdgeCoreManager />
31-
</ErrorBoundary>
32-
</GestureHandlerRootView>
33-
</ThemeProvider>
34-
</SafeAreaProvider>
25+
<QueryClientProvider client={queryClient}>
26+
<SafeAreaProvider>
27+
<ThemeProvider>
28+
<GestureHandlerRootView style={StyleSheet.absoluteFill}>
29+
<ErrorBoundary
30+
beforeCapture={handleBeforeCapture}
31+
fallback={<CrashScene />}
32+
>
33+
<StatusBarManager />
34+
<EdgeCoreManager />
35+
</ErrorBoundary>
36+
</GestureHandlerRootView>
37+
</ThemeProvider>
38+
</SafeAreaProvider>
39+
</QueryClientProvider>
3540
)
3641
}
3742

src/components/cards/SwapDetailsCard.tsx

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@ import {
1616
} from '../../selectors/DenominationSelectors'
1717
import { useSelector } from '../../types/reactRedux'
1818
import { getWalletName } from '../../util/CurrencyWalletHelpers'
19+
import { ReportsTxInfo } from '../../util/reportsServer'
1920
import { convertNativeToDisplay, unixToLocaleDateTime } from '../../util/utils'
2021
import { DataSheetModal, DataSheetSection } from '../modals/DataSheetModal'
22+
import { ShimmerText } from '../progress-indicators/ShimmerText'
2123
import { EdgeRow } from '../rows/EdgeRow'
2224
import { Airship, showError } from '../services/AirshipInstance'
2325
import { EdgeText } from '../themed/EdgeText'
@@ -27,12 +29,27 @@ interface Props {
2729
swapData: EdgeTxSwap
2830
transaction: EdgeTransaction
2931
sourceWallet?: EdgeCurrencyWallet
32+
33+
/** The transaction info from the reports server. */
34+
reportsTxInfo?: ReportsTxInfo
35+
36+
/**
37+
* Whether the transaction info from the reports server is loading.
38+
* If not provided, the card will not show the status.
39+
* */
40+
isReportsTxInfoLoading?: boolean
3041
}
3142

3243
const TXID_PLACEHOLDER = '{{TXID}}'
3344

3445
export function SwapDetailsCard(props: Props) {
35-
const { swapData, transaction, sourceWallet } = props
46+
const {
47+
swapData,
48+
transaction,
49+
sourceWallet,
50+
reportsTxInfo,
51+
isReportsTxInfoLoading = false
52+
} = props
3653
const { memos = [], spendTargets = [], tokenId } = transaction
3754

3855
const formattedOrderUri =
@@ -199,7 +216,15 @@ export function SwapDetailsCard(props: Props) {
199216
body: swapData.isEstimate
200217
? lstrings.estimated_quote
201218
: lstrings.fixed_quote
202-
}
219+
},
220+
...(reportsTxInfo == null
221+
? []
222+
: [
223+
{
224+
title: lstrings.transaction_details_exchange_status,
225+
body: reportsTxInfo.swapInfo.status
226+
}
227+
])
203228
]
204229
},
205230
{
@@ -288,6 +313,19 @@ export function SwapDetailsCard(props: Props) {
288313
: lstrings.fixed_quote}
289314
</EdgeText>
290315
</EdgeRow>
316+
{isReportsTxInfoLoading == null ? null : (
317+
<EdgeRow title={lstrings.transaction_details_exchange_status}>
318+
{isReportsTxInfoLoading ? (
319+
<ShimmerText characters={10} />
320+
) : (
321+
<EdgeText>
322+
{reportsTxInfo == null
323+
? lstrings.string_unknown
324+
: reportsTxInfo.swapInfo.status}
325+
</EdgeText>
326+
)}
327+
</EdgeRow>
328+
)}
291329
{swapData.orderUri == null ? null : (
292330
<EdgeRow
293331
rightButtonType="touchable"
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
import * as React from 'react'
2+
import { View } from 'react-native'
3+
import LinearGradient from 'react-native-linear-gradient'
4+
import Animated, {
5+
SharedValue,
6+
useAnimatedStyle,
7+
useSharedValue,
8+
withRepeat,
9+
withSequence,
10+
withTiming
11+
} from 'react-native-reanimated'
12+
13+
import { useHandler } from '../../hooks/useHandler'
14+
import { useLayout } from '../../hooks/useLayout'
15+
import { styled } from '../hoc/styled'
16+
import { useTheme } from '../services/ThemeContext'
17+
18+
interface Props {
19+
/** Whether the component is shown (rendered). Default: true */
20+
isShown?: boolean
21+
22+
/** Number of characters to represent in size for the shimmer. */
23+
characters?: number
24+
25+
/** Number of lines to represent in size for the shimmer. */
26+
lines?: number
27+
}
28+
29+
export const ShimmerText = (props: Props) => {
30+
const { isShown = true, characters, lines = 1 } = props
31+
const theme = useTheme()
32+
33+
const containerHeight = React.useMemo(
34+
() => theme.rem(lines * 1.5),
35+
[lines, theme]
36+
)
37+
const containerWidth = React.useMemo(
38+
() =>
39+
characters
40+
? characters * theme.rem(0.75)
41+
: Math.floor(Math.random() * 80) + 20 + '%',
42+
[characters, theme]
43+
)
44+
45+
const [containerLayout, handleContainerLayout] = useLayout()
46+
const containerLayoutWidth = containerLayout.width
47+
const gradientWidth = containerLayoutWidth * 6
48+
49+
const offset = useSharedValue(0)
50+
51+
const startAnimation = useHandler(() => {
52+
const duration = 2000
53+
const startPosition = -gradientWidth
54+
const endPosition = containerLayoutWidth
55+
offset.value = startPosition
56+
offset.value = withRepeat(
57+
withSequence(
58+
withTiming(startPosition, { duration: duration / 2 }),
59+
withTiming(endPosition, { duration })
60+
),
61+
-1,
62+
false
63+
)
64+
})
65+
66+
React.useEffect(() => {
67+
if (gradientWidth > 0) startAnimation()
68+
}, [startAnimation, gradientWidth])
69+
70+
return isShown ? (
71+
<ContainerView
72+
width={containerWidth}
73+
height={containerHeight}
74+
onLayout={handleContainerLayout}
75+
>
76+
<Shimmer width={gradientWidth} offset={offset}>
77+
<Gradient
78+
start={{ x: 0, y: 0 }}
79+
end={{ x: 1, y: 1 }}
80+
colors={['rgba(0,0,0,0)', theme.shimmerBackgroundHighlight]}
81+
/>
82+
<Gradient
83+
start={{ x: 1, y: 0 }}
84+
end={{ x: 0, y: 1 }}
85+
colors={['rgba(0,0,0,0)', theme.shimmerBackgroundHighlight]}
86+
/>
87+
</Shimmer>
88+
</ContainerView>
89+
) : null
90+
}
91+
92+
/**
93+
* This is the track of the component that contains a gradient that overflows
94+
* in width.
95+
*/
96+
const ContainerView = styled(View)<{
97+
width: string | number
98+
height: string | number
99+
}>(theme => props => ({
100+
width: props.width,
101+
maxWidth: '100%',
102+
height: props.height,
103+
borderRadius: theme.rem(0.25),
104+
backgroundColor: theme.shimmerBackgroundColor,
105+
overflow: 'hidden'
106+
}))
107+
108+
/**
109+
* This is the animated view that within the {@link ContainerView}. It animates
110+
* by an offset value which represents the horizontal position of the shimmer.
111+
*/
112+
const Shimmer = styled(Animated.View)<{
113+
width: string | number
114+
offset: SharedValue<number>
115+
}>(_ => props => [
116+
{
117+
position: 'absolute',
118+
top: 0,
119+
left: 0,
120+
bottom: 0,
121+
display: 'flex',
122+
flexDirection: 'row',
123+
width: props.width
124+
},
125+
useAnimatedStyle(() => ({
126+
transform: [{ translateX: props.offset.value }]
127+
}))
128+
])
129+
130+
/**
131+
* This is gradient nested within the {@link Shimmer}.
132+
*/
133+
const Gradient = styled(LinearGradient)({
134+
flex: 1,
135+
width: '100%',
136+
height: '100%'
137+
})

src/components/rows/EdgeRow.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { lstrings } from '../../locales/strings'
1010
import { triggerHaptic } from '../../util/haptic'
1111
import { fixSides, mapSides, sidesToMargin } from '../../util/sides'
1212
import { EdgeTouchableOpacity } from '../common/EdgeTouchableOpacity'
13+
import { ShimmerText } from '../progress-indicators/ShimmerText'
1314
import { showToast } from '../services/AirshipInstance'
1415
import { cacheStyles, Theme, useTheme } from '../services/ThemeContext'
1516
import { EdgeText } from '../themed/EdgeText'
@@ -34,6 +35,7 @@ interface Props {
3435
error?: boolean
3536
icon?: React.ReactNode
3637
loading?: boolean
38+
shimmer?: boolean
3739
maximumHeight?: 'small' | 'medium' | 'large'
3840
rightButtonType?: RowActionIcon
3941
title?: string
@@ -118,7 +120,9 @@ export const EdgeRow = (props: Props) => {
118120
{title}
119121
</EdgeText>
120122
)}
121-
{loading ? (
123+
{props.shimmer ? (
124+
<ShimmerText characters={title?.length} />
125+
) : loading ? (
122126
<ActivityIndicator
123127
style={styles.loader}
124128
color={theme.primaryText}

0 commit comments

Comments
 (0)