Skip to content

Commit 9e1422a

Browse files
authored
fix(mobile): couldn’t properly scroll in sheet (#5025)
When the list of safes was big one was not able to scroll inside of it.
1 parent d8ecec7 commit 9e1422a

File tree

6 files changed

+98
-57
lines changed

6 files changed

+98
-57
lines changed

apps/mobile/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@
113113
"@babel/preset-env": "^7.26.0",
114114
"@babel/preset-react": "^7.26.3",
115115
"@eslint/js": "^9.18.0",
116-
"@gorhom/bottom-sheet": "^5.0.6",
116+
"@gorhom/bottom-sheet": "^5.1.1",
117117
"@react-native-async-storage/async-storage": "1.23.1",
118118
"@react-native-community/datetimepicker": "8.2.0",
119119
"@react-native-community/slider": "4.5.5",

apps/mobile/src/components/SafeBottomSheet/SafeBottomSheet.tsx

Lines changed: 58 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
import { BackdropComponent, BackgroundComponent } from '@/src/components/Dropdown/sheetComponents'
22
import { getTokenValue, H5, View } from 'tamagui'
3-
import React, { useCallback } from 'react'
3+
import React, { useCallback, useEffect, useRef } from 'react'
44
import BottomSheet, {
55
BottomSheetFooterProps,
66
BottomSheetModalProps,
77
BottomSheetView,
88
BottomSheetScrollView,
9+
BottomSheetFooter,
910
} from '@gorhom/bottom-sheet'
1011
import DraggableFlatList, { DragEndParams, RenderItemParams, ScaleDecorator } from 'react-native-draggable-flatlist'
1112
import { StyleSheet } from 'react-native'
1213
import { useRouter } from 'expo-router'
14+
import { useSafeAreaInsets } from 'react-native-safe-area-context'
1315

1416
interface SafeBottomSheetProps<T> {
1517
children?: React.ReactNode
@@ -19,7 +21,7 @@ interface SafeBottomSheetProps<T> {
1921
items?: T[]
2022
snapPoints?: BottomSheetModalProps['snapPoints']
2123
actions?: React.ReactNode
22-
footerComponent?: React.FC<BottomSheetFooterProps>
24+
FooterComponent?: React.FC
2325
renderItem?: React.FC<{ item: T; isDragging?: boolean; drag?: () => void; onClose: () => void }>
2426
keyExtractor?: ({ item, index }: { item: T; index: number }) => string
2527
}
@@ -29,14 +31,17 @@ export function SafeBottomSheet<T>({
2931
title,
3032
sortable,
3133
items,
32-
snapPoints = [600, '90%'],
34+
snapPoints = [600, '100%'],
3335
keyExtractor,
3436
actions,
3537
renderItem: Render,
36-
footerComponent,
38+
FooterComponent,
3739
onDragEnd,
3840
}: SafeBottomSheetProps<T>) {
41+
const ref = useRef<BottomSheet>(null)
3942
const router = useRouter()
43+
const insets = useSafeAreaInsets()
44+
const [footerHeight, setFooterHeight] = React.useState(0)
4045
const hasCustomItems = items && Render
4146
const isSortable = items && sortable
4247

@@ -77,8 +82,34 @@ export function SafeBottomSheet<T>({
7782
}
7883
}, [])
7984

85+
// Auto-expand when sorting is enabled
86+
useEffect(() => {
87+
if (sortable && ref.current) {
88+
ref.current.expand()
89+
}
90+
}, [sortable])
91+
92+
// Wrapping the footer component with a function to get the height of the footer
93+
const renderFooter: React.FC<BottomSheetFooterProps> = useCallback(
94+
(props) => {
95+
return (
96+
<BottomSheetFooter animatedFooterPosition={props.animatedFooterPosition}>
97+
<View
98+
onLayout={(e) => {
99+
setFooterHeight(e.nativeEvent.layout.height)
100+
}}
101+
>
102+
{FooterComponent && <FooterComponent />}
103+
</View>
104+
</BottomSheetFooter>
105+
)
106+
},
107+
[FooterComponent, setFooterHeight],
108+
)
109+
80110
return (
81111
<BottomSheet
112+
ref={ref}
82113
enableOverDrag={false}
83114
snapPoints={snapPoints}
84115
enableDynamicSizing={true}
@@ -87,21 +118,35 @@ export function SafeBottomSheet<T>({
87118
overDragResistanceFactor={10}
88119
backgroundComponent={BackgroundComponent}
89120
backdropComponent={BackdropComponent}
90-
footerComponent={footerComponent}
121+
footerComponent={isSortable ? undefined : renderFooter}
122+
topInset={insets.top}
91123
>
92-
{!isSortable && !!title && <TitleHeader />}
93-
<BottomSheetView style={[styles.contentContainer, !isSortable ? { flex: 1 } : undefined]}>
124+
<BottomSheetView
125+
style={[
126+
styles.contentContainer,
127+
{
128+
paddingBottom: insets.bottom,
129+
},
130+
]}
131+
>
132+
<TitleHeader />
94133
{isSortable ? (
95134
<DraggableFlatList<T>
96135
data={items}
97-
containerStyle={{ height: '90%' }}
98-
ListHeaderComponent={title ? <TitleHeader /> : undefined}
136+
style={{ marginBottom: insets.bottom }}
137+
containerStyle={{ height: '100%' }}
138+
contentContainerStyle={{ paddingBottom: 50 }}
99139
onDragEnd={onDragEnd}
100140
keyExtractor={(item, index) => (keyExtractor ? keyExtractor({ item, index }) : index.toString())}
101141
renderItem={renderItem}
102142
/>
103143
) : (
104-
<BottomSheetScrollView contentContainerStyle={styles.scrollInnerContainer}>
144+
<BottomSheetScrollView
145+
style={{
146+
marginBottom: (!sortable && FooterComponent ? footerHeight : 0) + 12,
147+
}}
148+
contentContainerStyle={[styles.scrollInnerContainer]}
149+
>
105150
<View minHeight={200} alignItems="center" paddingVertical="$3">
106151
<View alignItems="flex-start" paddingBottom="$4" width="100%">
107152
{hasCustomItems
@@ -126,5 +171,7 @@ const styles = StyleSheet.create({
126171
contentContainer: {
127172
justifyContent: 'space-around',
128173
},
129-
scrollInnerContainer: { paddingHorizontal: getTokenValue('$3'), paddingBottom: getTokenValue('$5') },
174+
scrollInnerContainer: {
175+
paddingHorizontal: getTokenValue('$3'),
176+
},
130177
})

apps/mobile/src/features/AccountsSheet/AccountsSheet.container.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export const AccountsSheetContainer = () => {
2121
title="My accounts"
2222
items={safes}
2323
keyExtractor={({ item }) => item.SafeInfo.address.value}
24-
footerComponent={MyAccountsFooter}
24+
FooterComponent={MyAccountsFooter}
2525
renderItem={MyAccountsContainer}
2626
sortable={isEdit}
2727
onDragEnd={onDragEnd}

apps/mobile/src/features/AccountsSheet/MyAccounts/MyAccountsFooter.test.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
import { render } from '@/src/tests/test-utils'
22
import { MyAccountsFooter } from './MyAccountsFooter'
3-
import { SharedValue } from 'react-native-reanimated'
43

54
describe('MyAccountsFooter', () => {
65
it('should render the defualt template', () => {
7-
const container = render(<MyAccountsFooter animatedFooterPosition={2 as unknown as SharedValue<number>} />)
6+
const container = render(<MyAccountsFooter />)
87

98
expect(container.getByText('Add Existing Account')).toBeDefined()
109
expect(container.getByText('Join New Account')).toBeDefined()
Lines changed: 32 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { Badge } from '@/src/components/Badge'
22
import { SafeFontIcon } from '@/src/components/SafeFontIcon'
3-
import { BottomSheetFooter, BottomSheetFooterProps } from '@gorhom/bottom-sheet'
43
import React from 'react'
54
import { TouchableOpacity } from 'react-native'
65
import { styled, Text, View } from 'tamagui'
@@ -9,53 +8,49 @@ import { Link } from 'expo-router'
98
const MyAccountsFooterContainer = styled(View, {
109
borderTopWidth: 1,
1110
borderTopColor: '$colorSecondary',
12-
paddingVertical: '$7',
13-
paddingHorizontal: '$5',
11+
paddingVertical: '$4',
12+
paddingHorizontal: '$4',
1413
backgroundColor: '$backgroundPaper',
1514
})
1615

1716
const MyAccountsButton = styled(View, {
1817
columnGap: '$2',
1918
alignItems: 'center',
2019
flexDirection: 'row',
21-
marginBottom: '$4',
20+
padding: '$2',
2221
})
2322

24-
interface CustomFooterProps extends BottomSheetFooterProps {}
25-
26-
export function MyAccountsFooter({ animatedFooterPosition }: CustomFooterProps) {
27-
const onAddAccountClick = () => null
23+
export function MyAccountsFooter() {
2824
const onJoinAccountClick = () => null
29-
3025
return (
31-
<BottomSheetFooter animatedFooterPosition={animatedFooterPosition}>
32-
<MyAccountsFooterContainer>
33-
<TouchableOpacity onPress={onAddAccountClick}>
34-
<Link href={'/(import-accounts)'} asChild>
35-
<MyAccountsButton testID="add-existing-account">
36-
<Badge
37-
themeName="badge_background"
38-
circleSize="$10"
39-
content={<SafeFontIcon size={20} name="plus-filled" />}
40-
/>
41-
42-
<Text fontSize="$4" fontWeight={600}>
43-
Add Existing Account
44-
</Text>
45-
</MyAccountsButton>
46-
</Link>
47-
</TouchableOpacity>
48-
49-
<TouchableOpacity onPress={onJoinAccountClick}>
50-
<MyAccountsButton testID="join-new-account">
26+
<MyAccountsFooterContainer paddingBottom={'$7'}>
27+
<Link href={'/(import-accounts)'} asChild>
28+
<MyAccountsButton testID="add-existing-account">
29+
<View paddingLeft="$2">
30+
<Badge
31+
themeName="badge_background"
32+
circleSize="$10"
33+
content={<SafeFontIcon size={20} name="plus-filled" />}
34+
/>
35+
</View>
36+
37+
<Text fontSize="$4" fontWeight={600}>
38+
Add Existing Account
39+
</Text>
40+
</MyAccountsButton>
41+
</Link>
42+
43+
<TouchableOpacity onPress={onJoinAccountClick}>
44+
<MyAccountsButton testID="join-new-account">
45+
<View paddingLeft="$2">
5146
<Badge themeName="badge_background" circleSize="$10" content={<SafeFontIcon size={20} name="owners" />} />
52-
53-
<Text fontSize="$4" fontWeight={600}>
54-
Join New Account
55-
</Text>
56-
</MyAccountsButton>
57-
</TouchableOpacity>
58-
</MyAccountsFooterContainer>
59-
</BottomSheetFooter>
47+
</View>
48+
49+
<Text fontSize="$4" fontWeight={600}>
50+
Join New Account
51+
</Text>
52+
</MyAccountsButton>
53+
</TouchableOpacity>
54+
</MyAccountsFooterContainer>
6055
)
6156
}

yarn.lock

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5345,9 +5345,9 @@ __metadata:
53455345
languageName: node
53465346
linkType: hard
53475347

5348-
"@gorhom/bottom-sheet@npm:^5.0.6":
5349-
version: 5.0.6
5350-
resolution: "@gorhom/bottom-sheet@npm:5.0.6"
5348+
"@gorhom/bottom-sheet@npm:^5.1.1":
5349+
version: 5.1.1
5350+
resolution: "@gorhom/bottom-sheet@npm:5.1.1"
53515351
dependencies:
53525352
"@gorhom/portal": "npm:1.0.14"
53535353
invariant: "npm:^2.2.4"
@@ -5363,7 +5363,7 @@ __metadata:
53635363
optional: true
53645364
"@types/react-native":
53655365
optional: true
5366-
checksum: 10/b8beb6bb4d80828deed5c74c8b19926cbb4887d530d07c19eaaa1d8faae6c79f942f83baad076c84d065f357f6666cbc257799fe8fc58cb375e6cbebf52b6227
5366+
checksum: 10/6da29c3927f6a0b6d2a459e2a1cae48ce7c0fce41663b46b0aba98490af15199e31248f83ca18753eeb439faf2c1dd957f26e4eacc9796b4962df44170b1a2d3
53675367
languageName: node
53685368
linkType: hard
53695369

@@ -8190,7 +8190,7 @@ __metadata:
81908190
"@ethersproject/shims": "npm:^5.7.0"
81918191
"@expo/config-plugins": "npm:^9.0.10"
81928192
"@expo/vector-icons": "npm:^14.0.2"
8193-
"@gorhom/bottom-sheet": "npm:^5.0.6"
8193+
"@gorhom/bottom-sheet": "npm:^5.1.1"
81948194
"@notifee/react-native": "npm:^9.1.8"
81958195
"@react-native-async-storage/async-storage": "npm:1.23.1"
81968196
"@react-native-clipboard/clipboard": "npm:^1.15.0"

0 commit comments

Comments
 (0)