Files
cpost-mobile/src/screens/wallet/paymentMethod/ui/ModalCard.tsx
Samandar Turgunboyev fd95422447 Initial commit
2025-08-26 16:26:59 +05:00

250 lines
6.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { NativeStackNavigationProp } from '@react-navigation/native-stack';
import { useMutation } from '@tanstack/react-query';
import packetsApi from 'api/packets';
import React, { useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import {
ActivityIndicator,
Animated,
Dimensions,
Linking,
StyleSheet,
Text,
TouchableOpacity,
TouchableWithoutFeedback,
View,
} from 'react-native';
import Check from 'svg/Check';
import Click from 'svg/Click';
import Payme from 'svg/Payme';
import { RootStackParamList } from 'types/types';
import { PaymentStyle } from '../../payment/ui/style';
const { height } = Dimensions.get('window');
interface ModalCardViewProps {
isVisible: boolean;
setIsVisible: React.Dispatch<React.SetStateAction<boolean>>;
selectedId: 'click' | 'payme' | null;
packId: number;
setSelectedId: React.Dispatch<React.SetStateAction<'click' | 'payme' | null>>;
}
type NavigationProp = NativeStackNavigationProp<
RootStackParamList,
'PaymentMethod'
>;
const ModalCard = ({
isVisible,
setIsVisible,
packId,
selectedId,
setSelectedId,
}: ModalCardViewProps) => {
const slideAnim = useRef(new Animated.Value(height)).current;
const [load, setLoad] = React.useState(false);
const [pay, setPay] = useState<string>('');
const { t } = useTranslation();
const openLink = async (url: string) => {
try {
const supported = await Linking.canOpenURL(url);
if (supported) {
await Linking.openURL(url);
} else {
// Agar app ocholmasa, default brauzerda ochishga urinadi
await Linking.openURL(url);
}
} catch (err) {
console.error('Link xatolik:', err);
// Xato bolsa ham brauzer orqali ochishga urinish
try {
await Linking.openURL(url);
} catch (err2) {
console.error('Brauzer orqali ham ochilmadi:', err2);
}
}
};
const { mutate, isPending } = useMutation({
mutationFn: ({ id, payType }: { id: number; payType: string }) =>
packetsApi.payPackets(id, { payType }),
onSuccess: res => {
setIsVisible(false);
const url = res.data.paymentUrl;
openLink(url);
},
onError: err => {
console.dir(err);
},
});
const openModal = () => {
Animated.timing(slideAnim, {
toValue: 0,
duration: 100,
useNativeDriver: true,
}).start();
};
const closeModal = () => {
Animated.timing(slideAnim, {
toValue: height,
duration: 200,
useNativeDriver: true,
}).start(() => {
setIsVisible(false);
});
};
const handlePayment = () => {
mutate({ id: packId, payType: pay });
};
useEffect(() => {
if (isVisible) openModal();
}, [isVisible]);
if (!isVisible) return null;
return (
<View style={styles.overlay}>
<TouchableWithoutFeedback onPress={closeModal}>
<View style={styles.backdrop} />
</TouchableWithoutFeedback>
<Animated.View
style={[styles.sheet, { transform: [{ translateY: slideAnim }] }]}
>
<View style={styles.sheetContent}>
{/* CLICK */}
<TouchableOpacity
style={[
styles.paymentOption,
{
backgroundColor:
selectedId === 'click' ? '#28A7E81A' : '#FFFFFF',
},
]}
onPress={() => setSelectedId('click')}
>
<View style={PaymentStyle.paymentCard}>
<Click width={80} height={80} />
</View>
<View
style={[
PaymentStyle.select,
{
backgroundColor:
selectedId === 'click' ? '#28A7E8' : '#FFFFFF',
borderColor: selectedId === 'click' ? '#28A7E8' : '#383838',
},
]}
>
{selectedId === 'click' && (
<Check color="#fff" width={20} height={20} />
)}
</View>
</TouchableOpacity>
{/* PAYME */}
<TouchableOpacity
style={[
styles.paymentOption,
{ backgroundColor: '#FFFFFF', marginBottom: 50 },
]}
onPress={() => {
setPay('PAYME'), setSelectedId('payme');
}}
>
<View style={PaymentStyle.paymentCard}>
<Payme width={80} height={80} />
</View>
<View
style={[
PaymentStyle.select,
{
backgroundColor:
selectedId === 'payme' ? '#28A7E8' : '#FFFFFF',
borderColor: selectedId === 'payme' ? '#28A7E8' : '#383838',
},
]}
>
{selectedId === 'payme' && (
<Check color="#fff" width={20} height={20} />
)}
</View>
</TouchableOpacity>
<TouchableOpacity
style={[
PaymentStyle.modalBtn,
{
margin: 'auto',
right: 0,
bottom: -20,
backgroundColor:
load || selectedId === null ? '#88888840' : '#28A7E8',
},
]}
onPress={handlePayment}
disabled={load}
>
{load || isPending ? (
<ActivityIndicator size="small" color="#fff" />
) : (
<Text
style={[
PaymentStyle.btnText,
{
color: load || selectedId === null ? '#000000b9' : '#FFFF',
},
]}
>
{t("To'lash")}
</Text>
)}
</TouchableOpacity>
</View>
</Animated.View>
</View>
);
};
const styles = StyleSheet.create({
overlay: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
zIndex: 1000,
justifyContent: 'flex-end',
},
backdrop: {
...StyleSheet.absoluteFillObject,
backgroundColor: 'rgba(0,0,0,0.4)',
},
sheet: {
width: '100%',
backgroundColor: '#F3FAFF',
borderTopLeftRadius: 20,
borderTopRightRadius: 20,
padding: 20,
paddingBottom: 30,
},
sheetContent: {
gap: 10,
},
paymentOption: {
flexDirection: 'row',
justifyContent: 'space-between',
borderRadius: 10,
paddingLeft: 20,
paddingRight: 20,
alignItems: 'center',
},
});
export default ModalCard;