221 lines
5.9 KiB
TypeScript
221 lines
5.9 KiB
TypeScript
import { useTheme } from '@/components/ThemeContext';
|
|
import { useInfiniteQuery } from '@tanstack/react-query';
|
|
import * as Clipboard from 'expo-clipboard';
|
|
import { useRouter } from 'expo-router';
|
|
import { ArrowLeft, CopyIcon, HandCoins, Plus, Users } from 'lucide-react-native';
|
|
import React, { useState } from 'react';
|
|
import { useTranslation } from 'react-i18next';
|
|
import {
|
|
ActivityIndicator,
|
|
FlatList,
|
|
Platform,
|
|
Pressable,
|
|
RefreshControl,
|
|
Share,
|
|
StyleSheet,
|
|
Text,
|
|
ToastAndroid,
|
|
TouchableOpacity,
|
|
View,
|
|
} from 'react-native';
|
|
import { SafeAreaView } from 'react-native-safe-area-context';
|
|
import { user_api } from '../lib/api';
|
|
|
|
const PAGE_SIZE = 10;
|
|
|
|
export function ReferralsTab() {
|
|
const router = useRouter();
|
|
const { isDark } = useTheme();
|
|
const { t } = useTranslation();
|
|
const [refreshing, setRefreshing] = useState(false);
|
|
|
|
const theme = {
|
|
background: isDark ? '#0f172a' : '#f8fafc',
|
|
cardBg: isDark ? '#1e293b' : '#ffffff',
|
|
text: isDark ? '#ffffff' : '#0f172a',
|
|
subText: isDark ? '#94a3b8' : '#64748b',
|
|
primary: '#3b82f6',
|
|
success: '#10b981',
|
|
};
|
|
|
|
const { data, isLoading, isError, fetchNextPage, hasNextPage, refetch } = useInfiniteQuery({
|
|
queryKey: ['my_referrals'],
|
|
queryFn: async ({ pageParam = 1 }) => {
|
|
const res = await user_api.my_referrals({
|
|
page: pageParam,
|
|
page_size: PAGE_SIZE,
|
|
});
|
|
|
|
const d = res.data.data;
|
|
return {
|
|
results: d.results ?? [],
|
|
current_page: d.current_page,
|
|
total_pages: d.total_pages,
|
|
};
|
|
},
|
|
getNextPageParam: (lastPage) =>
|
|
lastPage.current_page < lastPage.total_pages ? lastPage.current_page + 1 : undefined,
|
|
initialPageParam: 1,
|
|
});
|
|
|
|
const referrals = data?.pages.flatMap((p) => p.results) ?? [];
|
|
|
|
const onRefresh = async () => {
|
|
setRefreshing(true);
|
|
await refetch();
|
|
setRefreshing(false);
|
|
};
|
|
|
|
// Clipboard + Share funksiyasi
|
|
const handleCopyAndShare = async (code: string) => {
|
|
const referralLink = `https://t.me/infotargetbot/join?startapp=${code}`;
|
|
|
|
// Clipboard-ga nusxa olish
|
|
await Clipboard.setStringAsync(referralLink);
|
|
|
|
// Share qilish
|
|
try {
|
|
await Share.share({
|
|
message: referralLink,
|
|
title: t('Referal linkni ulashish'),
|
|
});
|
|
} catch (err) {
|
|
console.log('Share error:', err);
|
|
}
|
|
|
|
if (Platform.OS === 'android') {
|
|
ToastAndroid.show(t('Refferal kopiya qilindi'), ToastAndroid.SHORT);
|
|
}
|
|
};
|
|
|
|
if (isLoading) {
|
|
return (
|
|
<SafeAreaView style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
|
|
<ActivityIndicator size="large" />
|
|
</SafeAreaView>
|
|
);
|
|
}
|
|
|
|
if (isError) {
|
|
return (
|
|
<View style={[styles.center, { backgroundColor: theme.background }]}>
|
|
<Text style={{ color: 'red' }}>{t('Xatolik yuz berdi')}</Text>
|
|
</View>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<View style={[styles.container, { backgroundColor: theme.background }]}>
|
|
{/* Header */}
|
|
<View style={styles.topHeader}>
|
|
<Pressable onPress={() => router.push('/profile')}>
|
|
<ArrowLeft color={theme.text} />
|
|
</Pressable>
|
|
<Text style={[styles.headerTitle, { color: theme.text }]}>{t('Refferallarim')}</Text>
|
|
<Pressable onPress={() => router.push('/profile/added-referalls')}>
|
|
<Plus color={theme.primary} />
|
|
</Pressable>
|
|
</View>
|
|
|
|
<FlatList
|
|
data={referrals}
|
|
keyExtractor={(item) => item.id.toString()}
|
|
contentContainerStyle={styles.list}
|
|
refreshControl={
|
|
<RefreshControl refreshing={refreshing} onRefresh={onRefresh} tintColor={theme.primary} />
|
|
}
|
|
onEndReached={() => hasNextPage && fetchNextPage()}
|
|
renderItem={({ item }) => (
|
|
<View style={[styles.card, { backgroundColor: theme.cardBg }]}>
|
|
<View style={styles.cardRow}>
|
|
<View style={styles.cardHeader}>
|
|
<HandCoins size={20} color={theme.primary} />
|
|
<Text style={[styles.code, { color: theme.text }]}>{item.code}</Text>
|
|
</View>
|
|
<TouchableOpacity onPress={() => handleCopyAndShare(item.code)}>
|
|
<CopyIcon size={20} color={theme.primary} />
|
|
</TouchableOpacity>
|
|
</View>
|
|
|
|
<Text style={{ color: theme.subText }}>{item.description}</Text>
|
|
|
|
<View style={styles.footer}>
|
|
<View style={styles.row}>
|
|
<Users size={16} color={theme.subText} />
|
|
<Text style={[styles.meta, { color: theme.subText }]}>
|
|
{item.referral_registered_count} {t('foydalanuvchi')}
|
|
</Text>
|
|
</View>
|
|
|
|
<Text style={[styles.amount, { color: theme.success }]}>
|
|
{item.referral_income_amount} {t("so'm")}
|
|
</Text>
|
|
</View>
|
|
</View>
|
|
)}
|
|
ListEmptyComponent={
|
|
<Text style={{ textAlign: 'center', color: theme.subText }}>
|
|
{t('Refferallar topilmadi')}
|
|
</Text>
|
|
}
|
|
/>
|
|
</View>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
container: { flex: 1 },
|
|
center: { flex: 1, justifyContent: 'center', alignItems: 'center' },
|
|
|
|
topHeader: {
|
|
flexDirection: 'row',
|
|
justifyContent: 'space-between',
|
|
padding: 16,
|
|
alignItems: 'center',
|
|
},
|
|
headerTitle: { fontSize: 18, fontWeight: '700' },
|
|
|
|
list: { padding: 16, gap: 12, paddingBottom: 30 },
|
|
|
|
card: {
|
|
borderRadius: 16,
|
|
padding: 16,
|
|
gap: 10,
|
|
},
|
|
|
|
cardRow: {
|
|
flexDirection: 'row',
|
|
justifyContent: 'space-between',
|
|
alignContent: 'center',
|
|
alignItems: 'center',
|
|
},
|
|
|
|
cardHeader: {
|
|
flexDirection: 'row',
|
|
gap: 8,
|
|
alignItems: 'center',
|
|
},
|
|
|
|
code: {
|
|
fontSize: 16,
|
|
fontWeight: '700',
|
|
},
|
|
|
|
footer: {
|
|
flexDirection: 'row',
|
|
justifyContent: 'space-between',
|
|
marginTop: 6,
|
|
},
|
|
|
|
row: {
|
|
flexDirection: 'row',
|
|
gap: 6,
|
|
alignItems: 'center',
|
|
},
|
|
|
|
meta: {},
|
|
amount: {
|
|
fontWeight: '700',
|
|
},
|
|
});
|