250 lines
6.4 KiB
TypeScript
250 lines
6.4 KiB
TypeScript
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 bo‘lsa 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;
|