bug fixed

This commit is contained in:
Samandar Turgunboyev
2026-03-02 13:22:55 +05:00
parent bdc205b538
commit ab363ca3b9
44 changed files with 424 additions and 130 deletions

View File

@@ -101,14 +101,14 @@ export default function DashboardScreen() {
// Announcement videos
const videos = {
uz: require('@/assets/announcements-video/video_uz.webm'),
ru: require('@/assets/announcements-video/video_ru.webm'),
en: require('@/assets/announcements-video/video_en.webm'),
uz: require('@/assets/announcements-video/video_uz.mp4'),
ru: require('@/assets/announcements-video/video_ru.mp4'),
en: require('@/assets/announcements-video/video_en.mp4'),
};
// Government videos: faqat RU mavjud
const govermentVideos: Partial<Record<'uz' | 'ru' | 'en', any>> = {
ru: require('@/assets/goverment/video_ru.webm'),
ru: require('@/assets/goverment/video_ru.mp4'),
};
// Update selected language

View File

@@ -16,12 +16,12 @@ import {
Platform,
StyleSheet,
Text,
ToastAndroid,
TouchableOpacity,
View,
View
} from 'react-native';
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view';
import { SafeAreaView } from 'react-native-safe-area-context';
import { Toast } from 'toastify-react-native';
import { auth_api } from '../login/lib/api';
import useTokenStore from '../login/lib/hook';
import ConfirmForm from './ConfirmForm';
@@ -98,11 +98,11 @@ const ConfirmScreen = () => {
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
setResendTimer(60);
if (Platform.OS === 'android') {
ToastAndroid.show(t('Kod qayta yuborildi'), ToastAndroid.SHORT);
Toast.info(t('Kod qayta yuborildi'));
}
},
onError: () => {
Alert.alert(t('Xatolik yuz berdi'), t('Kodni qayta yuborishda xatolik yuz berdi'));
Toast.error(t('Kodni qayta yuborishda xatolik yuz berdi'));
},
});

View File

@@ -16,12 +16,12 @@ import {
Platform,
StyleSheet,
Text,
ToastAndroid,
TouchableOpacity,
View,
View
} from 'react-native';
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view';
import { SafeAreaView } from 'react-native-safe-area-context';
import { Toast } from 'toastify-react-native';
import { auth_api } from '../login/lib/api';
import useTokenStore from '../login/lib/hook';
import ConfirmForm from './ConfirmForm';
@@ -93,7 +93,7 @@ const RegisterConfirmScreen = () => {
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
setResendTimer(60);
if (Platform.OS === 'android') {
ToastAndroid.show(t('Kod qayta yuborildi'), ToastAndroid.SHORT);
Toast.info(t('Kod qayta yuborildi'));
}
},
onError: () => {

View File

@@ -360,7 +360,10 @@ export default function RegisterFormScreen() {
};
return (
<View style={{ flex: 1 }}>
<KeyboardAvoidingView
behavior="padding"
style={{ flex: 1 }}
>
<View style={styles.container}>
<LinearGradient
colors={['#0f172a', '#1e293b', '#334155']}
@@ -727,7 +730,7 @@ export default function RegisterFormScreen() {
/>
</BottomSheet>
</View>
</View>
</KeyboardAvoidingView>
);
}

View File

@@ -190,8 +190,9 @@ export default function CreateAdsScreens() {
router.push('/(dashboard)/announcements');
}
},
onError: (err) => {
Alert.alert('Xatolik yuz berdi', err.message);
onError: (err: AxiosError) => {
const errMessage = (err.response?.data as { referral_amount: string }).referral_amount
Alert.alert(t('Xatolik yuz berdi'), errMessage || err.message);
},
});

View File

@@ -3,7 +3,8 @@ import CategorySelection from '@/components/ui/IndustrySelection';
import { XIcon } from 'lucide-react-native';
import React, { forwardRef, useEffect, useImperativeHandle, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { FlatList, StyleSheet, Text, ToastAndroid, TouchableOpacity, View } from 'react-native';
import { FlatList, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import { Toast } from 'toastify-react-native';
type StepProps = {
formData: any;
@@ -36,7 +37,7 @@ const StepTwo = forwardRef(({ formData, updateForm }: StepProps, ref) => {
const validate = () => {
if (selectedCategories.length === 0) {
setError('Iltimos, kompaniyalarni tanlang');
ToastAndroid.show(t('Iltimos, kompaniyalarni tanlang'), ToastAndroid.TOP);
Toast.info(t('Iltimos, kompaniyalarni tanlang'));
return false;
}
return true;

View File

@@ -3,19 +3,19 @@ import { useTheme } from "@/components/ThemeContext";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { Image } from "expo-image";
import { router } from "expo-router";
import * as WebBrowser from "expo-web-browser";
import { useState } from "react";
import { useTranslation } from "react-i18next";
import {
ActivityIndicator,
FlatList,
Text,
ToastAndroid,
TouchableOpacity,
View,
View
} from "react-native";
import { RefreshControl } from "react-native-gesture-handler";
import * as WebBrowser from "expo-web-browser";
import { Toast } from "toastify-react-native";
import { eservices_api } from "../lib/api";
import { useTranslation } from "react-i18next";
const dark = {
bg: "#0f172a",
@@ -41,7 +41,7 @@ export default function EServicesCategoryScreen() {
try {
await WebBrowser.openBrowserAsync(fileUrl);
} catch (error) {
ToastAndroid.show(t("Xatolik yuz berdi"), ToastAndroid.TOP);
Toast.error(t("Xatolik yuz berdi"));
}
};

View File

@@ -2,6 +2,7 @@ import { useTheme } from "@/components/ThemeContext";
import { useInfiniteQuery, useQueryClient } from "@tanstack/react-query";
import { Image } from "expo-image";
import { router, useLocalSearchParams } from "expo-router";
import * as WebBrowser from "expo-web-browser";
import { ChevronLeft } from "lucide-react-native";
import { useCallback, useState } from "react";
import {
@@ -10,14 +11,13 @@ import {
FlatList,
StyleSheet,
Text,
ToastAndroid,
TouchableOpacity,
View,
View
} from "react-native";
import * as WebBrowser from "expo-web-browser";
import { useTranslation } from "react-i18next";
import { RefreshControl } from "react-native-gesture-handler";
import { Toast } from "toastify-react-native";
import { eservices_api } from "../lib/api";
const { width: SCREEN_WIDTH } = Dimensions.get("window");
@@ -74,11 +74,10 @@ export default function EServicesScreen() {
};
const handleOpenBrowser = async (fileUrl: string) => {
ToastAndroid.show(t("Xatolik yuz berdi"), ToastAndroid.TOP);
try {
await WebBrowser.openBrowserAsync(fileUrl);
} catch (error) {
ToastAndroid.show(t("Xatolik yuz berdi"), ToastAndroid.TOP);
Toast.error(t("Xatolik yuz berdi"));
}
};

View File

@@ -3,12 +3,12 @@ import { API_URLS } from '@/api/URLs';
import { ProductBody, ProductResponse } from '@/screens/home/lib/types';
import { AxiosResponse } from 'axios';
import {
ExployeesResponse,
MyAdsData,
MyAdsDataRes,
MyBonusesData,
NotificationListRes,
UserInfoResponseData,
ExployeesResponse,
MyAdsData,
MyAdsDataRes,
MyBonusesData,
NotificationListRes,
UserInfoResponseData,
} from './type';
export const user_api = {
@@ -61,10 +61,6 @@ export const user_api = {
return res;
},
async my_ads_detail(id: number): Promise<AxiosResponse<{ status: boolean; data: MyAdsDataRes }>> {
const res = await httpClient.get(API_URLS.My_Ads_Detail(id));
return res;
},
async my_bonuses(params: {
page: number;
@@ -109,6 +105,11 @@ export const user_api = {
return res;
},
async ads_detail(id: number): Promise<AxiosResponse<{ status: boolean; data: MyAdsDataRes }>> {
const res = await httpClient.get(API_URLS.Ads_Detail(id));
return res;
},
async my_referrals(params: { page: number; page_size: number }) {
const res = await httpClient.get(API_URLS.My_Refferals, { params });
return res;

View File

@@ -3,7 +3,7 @@ import { formatPhone, normalizeDigits } from '@/constants/formatPhone';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { AxiosError } from 'axios';
import { useRouter } from 'expo-router';
import { ArrowLeft } from 'lucide-react-native';
import { ArrowLeft, Check } from 'lucide-react-native';
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import {
@@ -14,9 +14,9 @@ import {
StyleSheet,
Text,
TextInput,
ToastAndroid,
View,
View
} from 'react-native';
import { Toast } from 'toastify-react-native';
import { user_api } from '../lib/api';
export default function AddEmployee() {
@@ -60,14 +60,14 @@ export default function AddEmployee() {
const handleSave = () => {
if (!firstName.trim() || !lastName.trim() || !phoneNumber.trim()) {
ToastAndroid.show(t("Barcha maydonlarni to'ldiring"), ToastAndroid.SHORT);
Toast.info(t("Barcha maydonlarni to'ldiring"));
return;
}
mutate({
first_name: firstName.trim(),
last_name: lastName.trim(),
phone: phoneNumber.trim(),
phone: `998${phoneNumber.trim()}`,
});
};
@@ -77,12 +77,12 @@ export default function AddEmployee() {
<Pressable onPress={() => router.push('/profile/employees')}>
<ArrowLeft color={theme.text} />
</Pressable>
<Text style={[styles.headerTitle, { color: theme.text }]}>{t("Yangi xodim qo'shish")}</Text>
<Text style={[styles.headerTitle, { color: theme.text }]}>{t("Xodim qo'shish")}</Text>
<Pressable onPress={handleSave} disabled={isPending}>
{isPending ? (
<ActivityIndicator size={'small'} />
) : (
<Text style={[styles.saveButton, { color: theme.primary }]}>{t('Saqlash')}</Text>
<Check size={26} color={theme.primary} />
)}
</Pressable>
</View>

View File

@@ -52,7 +52,7 @@ export function AnnouncementsTab() {
};
const [refreshing, setRefreshing] = useState(false);
const [selectedAnnouncement, setSelectedAnnouncement] = useState<MyAdsDataRes | null>(null);
const [selectedAnnouncement, setSelectedAnnouncement] = useState<number | null>(null);
const [sheetOpen, setSheetOpen] = useState(false); const bottomSheetModalRef = useRef<BottomSheetModal>(null);
const { data, isLoading, isError, fetchNextPage, hasNextPage, refetch } = useInfiniteQuery({
@@ -82,14 +82,14 @@ export function AnnouncementsTab() {
isLoading: loadingDetail,
isError: detailError,
} = useQuery({
queryKey: ['my_ads_id', selectedAnnouncement?.id],
queryFn: () => user_api.my_ads_detail(selectedAnnouncement?.id!),
queryKey: ['my_ads_id', selectedAnnouncement],
queryFn: () => user_api.ads_detail(Number(selectedAnnouncement)),
select: (res) => res.data.data,
enabled: !!selectedAnnouncement && sheetOpen,
enabled: !!selectedAnnouncement,
});
const openSheet = (item: MyAdsDataRes) => {
setSelectedAnnouncement(item);
setSelectedAnnouncement(item.id);
setSheetOpen(true);
requestAnimationFrame(() => bottomSheetRef.current?.present());
};
@@ -176,7 +176,7 @@ export function AnnouncementsTab() {
if (isError) {
return (
<View style={[styles.center, { backgroundColor: theme.background }]}>
<Text style={[styles.error, { color: theme.error }]}>{t('Xatolik yuz berdi')}</Text>
<Text style={[{ color: theme.error }]}>{t('Xatolik yuz berdi')}</Text>
</View>
);
}
@@ -196,7 +196,7 @@ export function AnnouncementsTab() {
<FlatList
data={allAds}
keyExtractor={(item) => item.id.toString()}
contentContainerStyle={styles.list}
contentContainerStyle={[styles.list, { flexGrow: 1 }]}
refreshControl={
<RefreshControl refreshing={refreshing} onRefresh={onRefresh} tintColor={theme.primary} />
}
@@ -204,7 +204,7 @@ export function AnnouncementsTab() {
renderItem={({ item }) => (
<Pressable
style={[styles.card, { backgroundColor: theme.cardBg }]}
onPress={() => openSheet(item)}
onPress={() => { openSheet(item); setSelectedAnnouncement(item.id) }}
>
{item.files?.[0]?.file && (
<Image source={{ uri: item.files[0].file }} style={styles.cardImage} />
@@ -243,6 +243,14 @@ export function AnnouncementsTab() {
</View>
</Pressable>
)}
ListEmptyComponent={() => (
<View style={styles.emptyContainer}>
<Megaphone size={48} color={theme.textSecondary} />
<Text style={[styles.emptyTitle, { color: theme.text }]}>
{t('Hozircha hech qanday eʼlon mavjud emas')}
</Text>
</View>
)}
/>
<BottomSheetModal
@@ -253,14 +261,13 @@ export function AnnouncementsTab() {
backgroundStyle={{ backgroundColor: theme.sheetBg }}
handleIndicatorStyle={{ backgroundColor: theme.indicator }}
onDismiss={() => {
setSheetOpen(false);
setSelectedAnnouncement(null);
setSelectedAnnouncement(null); // shu yetarli
}}
>
<BottomSheetScrollView contentContainerStyle={styles.sheet}>
{loadingDetail && <ActivityIndicator size={'large'} />}
{detailError && (
<Text style={[styles.error, { color: theme.error }]}>{t('Xatolik yuz berdi')}</Text>
<Text style={[{ color: theme.error }]}>{t('Xatolik yuz berdi')}</Text>
)}
{detail && (
@@ -374,7 +381,7 @@ export function AnnouncementsTab() {
isDark ? styles.darkPaymentItem : styles.lightPaymentItem,
{ flexDirection: 'row', justifyContent: 'flex-start', alignItems: 'center' },
]}
onPress={() => sendPayment({ id: selectedAnnouncement?.id!, type: 'payme' })}
onPress={() => sendPayment({ id: selectedAnnouncement!, type: 'payme' })}
>
<Image source={PAYME} style={{ width: 80, height: 80 }} />
</TouchableOpacity>
@@ -384,7 +391,7 @@ export function AnnouncementsTab() {
styles.paymentItem,
isDark ? styles.darkPaymentItem : styles.lightPaymentItem,
]}
onPress={() => sendPayment({ id: selectedAnnouncement?.id!, type: 'referral' })}
onPress={() => sendPayment({ id: selectedAnnouncement!, type: 'referral' })}
>
<Text style={[styles.paymentText, isDark ? styles.darkText : styles.lightText]}>
{t('Referal orqali')}
@@ -498,6 +505,22 @@ const styles = StyleSheet.create({
fontWeight: '700',
},
loading: {},
error: {},
emptyContainer: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
paddingVertical: 60,
},
emptyTitle: {
fontSize: 18,
fontWeight: '600',
marginTop: 12,
},
emptyDesc: {
fontSize: 14,
marginTop: 6,
textAlign: 'center',
},
});

View File

@@ -164,6 +164,7 @@ const styles = StyleSheet.create({
padding: 16,
gap: 16,
paddingBottom: 30,
flexGrow: 1
},
card: {
borderRadius: 20,
@@ -236,6 +237,7 @@ const styles = StyleSheet.create({
fontWeight: '600' as const,
},
emptyContainer: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
paddingVertical: 80,

View File

@@ -12,9 +12,9 @@ import {
Switch,
Text,
TextInput,
ToastAndroid,
View,
View
} from 'react-native';
import { Toast } from 'toastify-react-native';
import { user_api } from '../lib/api';
type FormType = {
@@ -44,12 +44,12 @@ export default function CreateReferrals() {
is_agent: boolean;
}) => user_api.create_referral(body),
onSuccess: () => {
ToastAndroid.show(t('Referral yaratildi'), ToastAndroid.SHORT);
Toast.success(t('Referral yaratildi'));
queryClient.refetchQueries({ queryKey: ['my_referrals'] });
router.back();
},
onError: () => {
ToastAndroid.show(t('Xatolik yuz berdi'), ToastAndroid.SHORT);
Toast.error(t('Xatolik yuz berdi'));
},
});

View File

@@ -151,7 +151,7 @@ export default function EditService() {
<ArrowLeft color={isDark ? '#fff' : '#0f172a'} />
</Pressable>
<Text style={[styles.headerTitle, { color: isDark ? '#fff' : '#0f172a' }]}>
{step === 1 ? t('Xizmatni tahrirlash (1/2)') : t('Xizmatni tahrirlash (2/2)')}
{t('Xizmatni tahrirlash')}
</Text>
</View>
<Pressable

View File

@@ -124,7 +124,7 @@ export function EmployeesTab() {
data={allEmployees}
keyExtractor={(item) => item.phone}
renderItem={renderItem}
contentContainerStyle={styles.list}
contentContainerStyle={[styles.list, { flexGrow: 1 }]}
onEndReached={() => {
if (hasNextPage && !isFetchingNextPage) {
fetchNextPage();
@@ -176,7 +176,12 @@ const styles = StyleSheet.create({
infoContainer: { flex: 1, gap: 4 },
name: { fontSize: 17, fontWeight: '700' },
phone: { fontSize: 15, fontWeight: '500' },
emptyContainer: { alignItems: 'center', justifyContent: 'center', paddingVertical: 80, gap: 16 },
emptyContainer: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
paddingVertical: 60,
},
emptyText: { fontSize: 17, fontWeight: '600' },
emptyButton: {
flexDirection: 'row',

View File

@@ -68,9 +68,9 @@ export function ManualTab() {
/** 🔹 Video manbalari (SELECT ga bogliq) */
const videos = {
uz: require('@/assets/manual/manual_video_uz.webm'),
ru: require('@/assets/manual/manual_video_ru.webm'),
en: require('@/assets/manual/manual_video_en.webm'),
uz: require('@/assets/manual/manual_video_uz.mp4'),
ru: require('@/assets/manual/manual_video_ru.mp4'),
en: require('@/assets/manual/manual_video_en.mp4'),
};
const player = useVideoPlayer(videos[selectedLang], (player) => {
@@ -158,8 +158,6 @@ export function ManualTab() {
[imageLang]
);
const selectedLanguage = languages.find((l) => l.code === selectedLang);
useEffect(() => {
// listener qo'shish
const subscription = player.addListener('playingChange', (state) => {
@@ -350,7 +348,7 @@ const styles = StyleSheet.create({
container: { flex: 1 },
hero: { padding: 20 },
topHeader: { flexDirection: 'row', alignItems: 'center', gap: 12 },
headerTitle: { fontSize: 22, fontWeight: '700', marginHorizontal: 16 },
headerTitle: { fontSize: 18, fontWeight: '700', marginHorizontal: 16 },
subtitle: { fontSize: 16, marginTop: 5, fontWeight: '500', marginHorizontal: 16 },
section: { marginBottom: 28 },

View File

@@ -116,7 +116,7 @@ export default function MyServicesScreen() {
<FlatList
data={allServices}
keyExtractor={(item) => item.id.toString()}
contentContainerStyle={styles.list}
contentContainerStyle={[styles.list, { flexGrow: 1 }]}
onEndReached={() => hasNextPage && fetchNextPage()}
refreshControl={
<RefreshControl
@@ -269,7 +269,7 @@ const styles = StyleSheet.create({
borderRadius: 12,
},
categoryText: { fontSize: 13, fontWeight: '500' as const },
emptyContainer: { alignItems: 'center', justifyContent: 'center', paddingVertical: 80, gap: 16 },
emptyContainer: { alignItems: 'center', justifyContent: 'center', paddingVertical: 80, gap: 16, flex: 1 },
emptyText: { fontSize: 17, fontWeight: '600' as const },
emptyButton: {
flexDirection: 'row',

View File

@@ -91,32 +91,77 @@ export function NotificationTab() {
<Text style={[styles.headerTitle, { color: isDark ? '#f1f5f9' : '#0f172a' }]}>
{t('Bildirishnomalar')}
</Text>
{notifications.some((n) => !n.is_read) && (
<TouchableOpacity
style={[
styles.markAllButton,
{ backgroundColor: isDark ? '#1e293b' : '#e0f2fe', borderColor: '#3b82f6' },
]}
onPress={() => markAllAsRead()}
disabled={isMarkingAllRead}
>
{isMarkingAllRead ? (
<ActivityIndicator size="small" color="#3b82f6" />
) : (
<Text style={[styles.markAllText, { color: '#3b82f6' }]}>
{t("Barchasi o'qildi")}
</Text>
)}
</TouchableOpacity>
)}
</View>
<FlatList
data={notifications}
keyExtractor={(item) => item.id.toString()}
contentContainerStyle={styles.listContent}
showsVerticalScrollIndicator={false}
renderItem={({ item, index }) => <NotificationCard item={item} />}
ListHeaderComponent={() => {
if (notifications.length === 0) {
return (
<View style={styles.emptyHeader}>
<Text
style={[
styles.emptyTitle,
{ color: isDark ? '#f1f5f9' : '#0f172a' },
]}
>
{t("Hozircha bildirishnomalar yo'q")}
</Text>
<Text
style={[
styles.emptyDesc,
{ color: isDark ? '#94a3b8' : '#64748b' },
]}
>
{t("Yangi xabarlar shu yerda paydo boladi")}
</Text>
</View>
);
}
if (notifications.some((n) => !n.is_read)) {
return (
<View style={styles.headerActions}>
<TouchableOpacity
style={[
styles.markAllButton,
{
backgroundColor: isDark ? '#1e293b' : '#e0f2fe',
borderColor: '#3b82f6',
},
]}
onPress={() => markAllAsRead()}
disabled={isMarkingAllRead}
>
{isMarkingAllRead ? (
<ActivityIndicator size="small" color="#3b82f6" />
) : (
<Text style={[styles.markAllText, { color: '#3b82f6' }]}>
{t("Barchasi o'qildi")}
</Text>
)}
</TouchableOpacity>
</View>
);
}
return (
<View style={styles.allReadContainer}>
<Text
style={[
styles.allReadText,
{ color: isDark ? '#94a3b8' : '#64748b' },
]}
>
{t("Barcha bildirishnomalar oqilgan")}
</Text>
</View>
);
}}
renderItem={({ item }) => <NotificationCard item={item} />}
onEndReached={() => {
if (hasNextPage && !isFetchingNextPage) {
fetchNextPage();
@@ -130,6 +175,15 @@ export function NotificationTab() {
}
refreshing={isLoading}
onRefresh={refetch}
ListEmptyComponent={() =>
!isLoading && (
<View style={styles.emptyContainer}>
<Text style={[styles.emptyTitle, { color: isDark ? '#f1f5f9' : '#0f172a' }]}>
{t("Hozircha bildirishnomalar yo'q")}
</Text>
</View>
)
}
/>
</View>
);
@@ -266,6 +320,7 @@ const styles = StyleSheet.create({
listContent: {
padding: 16,
paddingBottom: 32,
flexGrow: 1
},
/* Card Styles */
@@ -292,6 +347,38 @@ const styles = StyleSheet.create({
flex: 1,
justifyContent: 'center',
},
headerActions: {
marginBottom: 16,
alignItems: 'flex-end',
},
emptyHeader: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
paddingVertical: 60,
},
allReadContainer: {
marginBottom: 16,
alignItems: 'center',
},
allReadText: {
fontSize: 14,
},
emptyTitle: {
fontSize: 18,
fontWeight: '700',
marginBottom: 8,
textAlign: 'center',
},
emptyDesc: {
fontSize: 14,
textAlign: 'center',
},
cardHeader: {
flexDirection: 'row',
alignItems: 'center',
@@ -407,7 +494,7 @@ const styles = StyleSheet.create({
paddingVertical: 8,
borderRadius: 8,
borderWidth: 1,
minWidth: 80,
width: "auto",
alignItems: 'center',
justifyContent: 'center',
},
@@ -415,4 +502,10 @@ const styles = StyleSheet.create({
fontSize: 13,
fontWeight: '600',
},
emptyContainer: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
paddingHorizontal: 30,
},
});

View File

@@ -260,7 +260,7 @@ export function ProductServicesTab() {
style={[
styles.categoryOptionText,
selectedCategories.includes(category) &&
styles.categoryOptionTextSelected,
styles.categoryOptionTextSelected,
]}
>
{category}
@@ -313,6 +313,7 @@ const styles = StyleSheet.create({
},
list: {
gap: 16,
flexGrow: 1
},
card: {
backgroundColor: '#1e293b',
@@ -372,6 +373,7 @@ const styles = StyleSheet.create({
fontWeight: '500' as const,
},
emptyContainer: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
paddingVertical: 80,

View File

@@ -2,7 +2,7 @@ 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 { ArrowLeft, CopyIcon, Gift, HandCoins, Plus, Users } from 'lucide-react-native';
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import {
@@ -14,11 +14,11 @@ import {
Share,
StyleSheet,
Text,
ToastAndroid,
TouchableOpacity,
View,
View
} from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
import { Toast } from 'toastify-react-native';
import { user_api } from '../lib/api';
const PAGE_SIZE = 10;
@@ -84,7 +84,7 @@ export function ReferralsTab() {
}
if (Platform.OS === 'android') {
ToastAndroid.show(t('Refferal kopiya qilindi'), ToastAndroid.SHORT);
Toast.success(t('Refferal kopiya qilindi'));
}
};
@@ -153,11 +153,22 @@ export function ReferralsTab() {
</View>
</View>
)}
ListEmptyComponent={
<Text style={{ textAlign: 'center', color: theme.subText }}>
{t('Refferallar topilmadi')}
</Text>
}
ListEmptyComponent={() => (
<View style={styles.emptyContainer}>
<View
style={[
styles.emptyIconWrapper,
{ backgroundColor: theme.cardBg }
]}
>
<Gift size={40} color={theme.primary} />
</View>
<Text style={[styles.emptyTitle, { color: theme.text }]}>
{t("Refferallar mavjud emas")}
</Text>
</View>
)}
/>
</View>
);
@@ -175,7 +186,7 @@ const styles = StyleSheet.create({
},
headerTitle: { fontSize: 18, fontWeight: '700' },
list: { padding: 16, gap: 12, paddingBottom: 30 },
list: { padding: 16, gap: 12, paddingBottom: 30, flexGrow: 1 },
card: {
borderRadius: 16,
@@ -217,4 +228,46 @@ const styles = StyleSheet.create({
amount: {
fontWeight: '700',
},
emptyContainer: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
paddingHorizontal: 30,
},
emptyIconWrapper: {
width: 80,
height: 80,
borderRadius: 40,
alignItems: 'center',
justifyContent: 'center',
marginBottom: 20,
elevation: 4,
},
emptyTitle: {
fontSize: 18,
fontWeight: '700',
marginBottom: 8,
textAlign: 'center',
},
emptyDesc: {
fontSize: 14,
textAlign: 'center',
marginBottom: 20,
lineHeight: 20,
},
emptyButton: {
paddingHorizontal: 24,
paddingVertical: 12,
borderRadius: 12,
},
emptyButtonText: {
color: '#fff',
fontWeight: '600',
fontSize: 15,
},
});