Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
59 changes: 31 additions & 28 deletions apps/frontend/app/(tabs)/(profile)/(pay-methods)/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ const PayMethods = () => {
const isEmpty = payMethods.length === 0;
const listStyle = !isEmpty
? Platform.select({
ios: 'pb-60 px-2 pt-4',
android: 'pb-24 px-2 pt-4',
ios: 'pb-60',
android: 'pb-24',
})
: 'flex-1 items-center justify-center pb-48';

Expand All @@ -31,40 +31,43 @@ const PayMethods = () => {
right={
<HeaderActionIcon
icon={isDark ? icons.dark.addSquare : icons.light.addSquare}
onPress={() => setModalVisible(true)} // πŸ‘ˆ opens modal
onPress={() => setModalVisible(true)}
/>
}
/>
),
});
});
}, []);

return (
<SafeAreaView className='screen-wrapper' edges={['bottom']}>
<View className='content-wrapper mt-2'>
<FlatList
data={payMethods}
keyExtractor={(item) => item.id}
showsVerticalScrollIndicator={false}
contentContainerClassName={listStyle}
renderItem={({ item, index }) => <PayMethodCard index={index} payMethod={item} />}
ItemSeparatorComponent={() => <DividerX style={cn('mt-px mb-2', isDark ? 'opacity-40' : 'opacity-25')} />}
ListFooterComponent={() => !isEmpty && <DividerX style={cn('mt-px', isDark ? 'opacity-40' : 'opacity-25')} />}
ListEmptyComponent={
<ListEmptyState
title='No Pay Methods Available'
ctaLabel='Add'
ctaStyle='py-4 px-8 rounded-lg'
ctaOnPresss={() => {
setModalVisible(true);
}}
/>
}
/>
</View>

<>
<SafeAreaView className='screen-wrapper' edges={['bottom']}>
<View className='content-wrapper mt-2'>
<FlatList
data={payMethods}
keyExtractor={(item) => item.id}
showsVerticalScrollIndicator={false}
contentContainerClassName={listStyle}
renderItem={({ item, index }) => <PayMethodCard index={index} payMethod={item} />}
ItemSeparatorComponent={() => <DividerX style={cn('mt-px mb-2', isDark ? 'opacity-40' : 'opacity-25')} />}
ListFooterComponent={() =>
!isEmpty && <DividerX style={cn('mt-px', isDark ? 'opacity-40' : 'opacity-25')} />
}
ListEmptyComponent={
<ListEmptyState
title='No Pay Methods Available'
ctaLabel='Add'
ctaStyle='py-4 px-8 rounded-lg'
ctaOnPresss={() => {
setModalVisible(true);
}}
/>
}
/>
</View>
</SafeAreaView>
<NewPayMethodModal visible={modalVisible} onClose={() => setModalVisible(false)} />
</SafeAreaView>
</>
);
};

Expand Down
5 changes: 3 additions & 2 deletions apps/frontend/app/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import toastConfig from '@/components/toasts';
import { useCustomFonts } from '@/hooks';
import { Stack } from 'expo-router';
import { useColorScheme } from 'react-native';
import { Host } from 'react-native-portalize';
import Toast from 'react-native-toast-message';
import './globals.css';

Expand All @@ -11,7 +12,7 @@ const RootLayout = () => {
if (!fontsLoaded) return null;

return (
<>
<Host>
<Stack
screenOptions={{
animation: 'simple_push',
Expand All @@ -22,7 +23,7 @@ const RootLayout = () => {
}}
/>
<Toast config={toastConfig} />
</>
</Host>
);
};

Expand Down
4 changes: 2 additions & 2 deletions apps/frontend/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -505,7 +505,7 @@
}

.deposit-form-icon-wrapper {
@apply w-14 items-center justify-center rounded-r-lg bg-base dark:bg-base-dark;
@apply w-14 items-center justify-center rounded-r-lg bg-base-white dark:bg-base-dark;
}

.deposit-form-footer {
Expand Down Expand Up @@ -565,7 +565,7 @@
}

.dropdown-icon-wrapper {
@apply w-14 items-center justify-center rounded-r-lg bg-base dark:bg-base-dark;
@apply w-14 items-center justify-center rounded-r-lg bg-base-white dark:bg-base-dark;
}

.dropdown-error {
Expand Down
2 changes: 1 addition & 1 deletion apps/frontend/app/verify/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const Verify = () => {
/>
</View>

<View className='flex-1 gap-y-4 bg-base px-4 py-8 dark:bg-base-dark'>
<View className='flex-1 gap-y-4 bg-base-white px-4 py-8 dark:bg-base-dark'>
<Text className='font-clashDisplay-medium text-2xl text-title dark:text-title-dark'>
{Strings.verify.SCREEN_TITLE}
</Text>
Expand Down
2 changes: 1 addition & 1 deletion apps/frontend/components/cards/PayMethodCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const PayMethodCard = (props: PayMethodCardProps) => {
};

return (
<View className='gap-y-3 rounded px-2 pb-4 pt-2'>
<View className='gap-y-3 rounded pb-4 pt-2'>
<View className='flex-row items-center justify-between'>
<Text className='font-clashDisplay-medium text-sm text-label dark:text-label-dark'>{payMethodType?.name}</Text>
<Image source={payMethodTypeLogoUrl} className='size-12' resizeMode='contain' />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import cn from 'clsx';
import { useState } from 'react';
import { Platform, Text, TextInput, View } from 'react-native';

const FormInputField = (props: FormInputFieldProps) => {
const SecondaryInputField = (props: SecondaryInputFieldProps) => {
const isIOS = Platform.OS === 'ios';
const value = props.value ?? '';

Expand Down Expand Up @@ -49,7 +49,7 @@ const FormInputField = (props: FormInputFieldProps) => {
<View
className={cn(
'justify-center rounded-r-lg px-4 py-3',
isFocused ? 'bg-primary' : 'bg-base dark:bg-base-dark',
isFocused ? 'bg-primary' : 'bg-base-white dark:bg-base-dark',
props.disabled && 'opacity-45',
)}
>
Expand All @@ -63,4 +63,4 @@ const FormInputField = (props: FormInputFieldProps) => {
);
};

export default FormInputField;
export default SecondaryInputField;
66 changes: 0 additions & 66 deletions apps/frontend/components/form/formInputField.tsx

This file was deleted.

2 changes: 1 addition & 1 deletion apps/frontend/components/form/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export { default as FileUplaod } from './FileUpload';
export { default as FormInputField } from './FormInputField';
export { default as InputField } from './InputField';
export { default as SecondaryInputField } from './SecondaryInputField';
export { default as StepperInput } from './StepperInput';
30 changes: 14 additions & 16 deletions apps/frontend/components/modals/ModalView.tsx
Original file line number Diff line number Diff line change
@@ -1,43 +1,41 @@
import React from 'react';
import { Dimensions, Pressable, Text } from 'react-native';
import { Dimensions, Pressable, Text, View } from 'react-native';
import Animated, { Easing, FadeIn, FadeOut, SlideInDown, SlideOutDown } from 'react-native-reanimated';
import { useSafeAreaInsets } from 'react-native-safe-area-context';

const screenHeight = Dimensions.get('window').height;

const ModalView = ({ visible, onClose, title, children, maxHeight = '80%' }: ModalViewProps) => {
const insets = useSafeAreaInsets();

const ModalView = ({ visible, onClose, title, children, maxHeight = 0.55 }: ModalViewProps) => {
if (!visible) return null;

return (
<Animated.View
className='z-100 absolute inset-0 justify-end'
className='absolute inset-0 justify-end'
entering={FadeIn.duration(250).easing(Easing.out(Easing.cubic))}
exiting={FadeOut.duration(200).easing(Easing.in(Easing.cubic))}
>
{/* Backdrop pressable covering entire screen */}
<Pressable onPress={onClose} className='absolute inset-0 z-[1] bg-black/50' />
<Pressable onPress={onClose} className='absolute inset-0 bg-backdrop dark:bg-backdrop-dark' />

{/* Bottom sheet content above backdrop */}
<Animated.View
className='flex-1 rounded-t-[20px] bg-base dark:bg-base-dark'
className='flex-1 gap-y-6 rounded-t-[20px] bg-base-white py-2 dark:bg-base-dark'
style={{
maxHeight: typeof maxHeight === 'string' ? (parseFloat(maxHeight) / 100) * screenHeight : maxHeight,
zIndex: 2,
maxHeight: Dimensions.get('screen').height * maxHeight,
}}
entering={SlideInDown.duration(250).easing(Easing.out(Easing.ease))}
exiting={SlideOutDown.duration(200).easing(Easing.in(Easing.ease))}
>
<Text className='self-center pb-2 pt-4 font-clashDisplay-medium text-lg text-title dark:text-title-dark'>
{title}
</Text>
<View className='items-center'>
<View className='h-1 w-10 rounded-md bg-stroke dark:bg-stroke-dark' />
</View>

<View className='items-center'>
<Text className='font-clashDisplay-medium text-lg text-title dark:text-title-dark'>{title}</Text>
</View>

{React.cloneElement(children as any, {
style: [{ flex: 1 }, (children as any).props.style],
contentContainerStyle: [
(children as any).props.contentContainerStyle,
{ paddingBottom: 200 }, // optional extra space
{ paddingBottom: 16 }, // optional extra space
],
})}
</Animated.View>
Expand Down
70 changes: 44 additions & 26 deletions apps/frontend/components/modals/NewPayMethodModal.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { usePayMethodType } from '@/hooks';
import { FlatList, Image, Text, TouchableHighlight, useColorScheme, View } from 'react-native';
import { router } from 'expo-router';
import { Dimensions, FlatList, Image, Text, TouchableHighlight, useColorScheme, View } from 'react-native';
import { Portal } from 'react-native-portalize';
import { DividerX } from '../dividers';
import ModalView from './ModalView';

Expand All @@ -12,33 +14,49 @@ const NewPayMethodModal = (props: NewPayMethodModalProps) => {
const isDark = useColorScheme() === 'dark';
const { payMethodTypes, getPayMethodTypeById, getPayMethodTypeLogoUrlById } = usePayMethodType();

const modalMaxHeight = 0.55;
const listMaxHeight = modalMaxHeight * 0.7;

return (
<ModalView title='New Pay Method' visible={props.visible} onClose={props.onClose}>
<FlatList
data={payMethodTypes}
keyExtractor={(item) => item.id}
showsVerticalScrollIndicator={false}
contentContainerClassName='mt-4'
renderItem={({ item, index }) => {
const payMethodType = getPayMethodTypeById(item.id);
const payMethodTypeLogoUrl = getPayMethodTypeLogoUrlById(item.id);
<Portal>
<ModalView title='New Pay Method' visible={props.visible} onClose={props.onClose} maxHeight={modalMaxHeight}>
<FlatList
data={payMethodTypes}
keyExtractor={(item, index) => item.id}
showsVerticalScrollIndicator={false}
style={{ maxHeight: Dimensions.get('screen').height * listMaxHeight }}
renderItem={({ item, index }) => {
const payMethodType = getPayMethodTypeById(item.id);
const payMethodTypeLogoUrl = getPayMethodTypeLogoUrlById(item.id);

return (
<TouchableHighlight
className='flex-1'
underlayColor={isDark ? '#1C1C1C' : '#F1F1F1'}
onPress={() => console.log('Pressed', payMethodType?.name)}
>
<View className='flex-row items-center justify-between px-6 py-6'>
<Text className='font-satoshi text-sm text-title dark:text-title-dark'>{payMethodType?.name}</Text>
<Image source={payMethodTypeLogoUrl} className='h-6 w-12' resizeMode='contain' />
</View>
</TouchableHighlight>
);
}}
ItemSeparatorComponent={() => <DividerX style={isDark ? 'opacity-40' : 'opacity-25'} />}
/>
</ModalView>
return (
<TouchableHighlight
className='flex-1'
underlayColor={isDark ? '#1C1C1C' : '#F1F1F1'}
onPress={() => {
props.onClose();
router.push({
pathname: '/details',
params: {
payMethodTypeId: item.id,
payMethodTypeName: item.name,
payMethodTypeCategory: item.category,
},
});
}}
>
<View className='flex-row items-center justify-between px-6 py-6'>
<Text className='font-satoshi text-sm text-title dark:text-title-dark'>{payMethodType?.name}</Text>
<Image source={payMethodTypeLogoUrl} className='h-6 w-12' resizeMode='contain' />
</View>
</TouchableHighlight>
);
}}
ItemSeparatorComponent={() => <DividerX style={isDark ? 'opacity-40' : 'opacity-25'} />}
ListFooterComponent={() => <DividerX style={isDark ? 'opacity-40' : 'opacity-25'} />}
/>
</ModalView>
</Portal>
);
};

Expand Down
4 changes: 2 additions & 2 deletions apps/frontend/components/sections/VerifyEmail.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Strings } from '@/constants';
import { useKyc } from '@/hooks';
import { FormInputField } from '../form';
import { SecondaryInputField } from '../form';

const VerifyEmail = () => {
const { kyc } = useKyc();

return (
<FormInputField
<SecondaryInputField
label={Strings.info.EMAIL_LABEL}
placeholder={Strings.info.EMAIL_HINT}
value={kyc?.email}
Expand Down
Loading