diff --git a/api/URLs.ts b/api/URLs.ts
index e90b9bc..93ce264 100644
--- a/api/URLs.ts
+++ b/api/URLs.ts
@@ -28,7 +28,7 @@ export const API_URLS = {
User_Update: 'auth/user-update/',
Employee_List: 'api/employee/',
My_Ads: 'api/my-ads/',
- My_Ads_Detail: (id: number) => `api/my-ads/${id}`,
+ Ads_Detail: (id: number) => `api/my-ads/${id}/`,
My_Bonuses: 'api/cashback/',
My_Refferals: 'api/referral/',
Goverment_Service: '/api/goverment-service/',
diff --git a/app/_layout.tsx b/app/_layout.tsx
index a50eb1f..9fe881e 100644
--- a/app/_layout.tsx
+++ b/app/_layout.tsx
@@ -10,6 +10,7 @@ import { I18nextProvider } from 'react-i18next';
import { View } from 'react-native';
import 'react-native-reanimated';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
+import ToastManager from "toastify-react-native";
function AppContent() {
useNotifications();
@@ -43,6 +44,7 @@ export default function RootLayout() {
+
diff --git a/app/profile/categories.tsx b/app/profile/categories.tsx
index c011c6a..ce6635f 100644
--- a/app/profile/categories.tsx
+++ b/app/profile/categories.tsx
@@ -14,10 +14,10 @@ import {
ScrollView,
StyleSheet,
Text,
- ToastAndroid,
TouchableOpacity,
View,
} from 'react-native';
+import { Toast } from 'toastify-react-native';
export default function PersonalInfoScreen() {
const router = useRouter();
@@ -76,7 +76,7 @@ export default function PersonalInfoScreen() {
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['get_me'] });
router.push('/profile/personal-info');
- ToastAndroid.show(t("Ma'lumotlar yangilandi"), ToastAndroid.TOP);
+ Toast.success(t("Ma'lumotlar yangilandi"));
},
onError: () => {
Alert.alert(t('Xatolik yzu berdi'), t("Ma'lumotlarni yangilashda xatolik yuz berdi"));
diff --git a/app/profile/personal-info.tsx b/app/profile/personal-info.tsx
index d3e78b5..3978731 100644
--- a/app/profile/personal-info.tsx
+++ b/app/profile/personal-info.tsx
@@ -9,17 +9,16 @@ import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import {
ActivityIndicator,
- Alert,
Image,
Pressable,
ScrollView,
StyleSheet,
Text,
TextInput,
- ToastAndroid,
TouchableOpacity,
- View,
+ View
} from 'react-native';
+import { Toast } from 'toastify-react-native';
export default function PersonalInfoScreen() {
const router = useRouter();
@@ -71,10 +70,10 @@ export default function PersonalInfoScreen() {
queryClient.invalidateQueries({ queryKey: ['get_me'] });
setIsEditing(false);
setShowCategories(false);
- ToastAndroid.show(t("Ma'lumotlar yangilandi"), ToastAndroid.TOP);
+ Toast.success(t("Ma'lumotlar yangilandi"));
},
onError: () => {
- Alert.alert(t('Xatolik yuz berdi'), t('Yangilashda xatolik yuz berdi'));
+ Toast.error(t('Yangilashda xatolik yuz berdi'));
},
});
diff --git a/assets/announcements-video/video_en.mp4 b/assets/announcements-video/video_en.mp4
new file mode 100644
index 0000000..7cf44d9
Binary files /dev/null and b/assets/announcements-video/video_en.mp4 differ
diff --git a/assets/announcements-video/video_en.webm b/assets/announcements-video/video_en.webm
deleted file mode 100644
index dd38173..0000000
Binary files a/assets/announcements-video/video_en.webm and /dev/null differ
diff --git a/assets/announcements-video/video_ru.mp4 b/assets/announcements-video/video_ru.mp4
new file mode 100644
index 0000000..e152f94
Binary files /dev/null and b/assets/announcements-video/video_ru.mp4 differ
diff --git a/assets/announcements-video/video_ru.webm b/assets/announcements-video/video_ru.webm
deleted file mode 100644
index 558baf5..0000000
Binary files a/assets/announcements-video/video_ru.webm and /dev/null differ
diff --git a/assets/announcements-video/video_uz.mp4 b/assets/announcements-video/video_uz.mp4
new file mode 100644
index 0000000..b6dd522
Binary files /dev/null and b/assets/announcements-video/video_uz.mp4 differ
diff --git a/assets/announcements-video/video_uz.webm b/assets/announcements-video/video_uz.webm
deleted file mode 100644
index 5244549..0000000
Binary files a/assets/announcements-video/video_uz.webm and /dev/null differ
diff --git a/assets/goverment/video_ru.mp4 b/assets/goverment/video_ru.mp4
new file mode 100644
index 0000000..5976e2f
Binary files /dev/null and b/assets/goverment/video_ru.mp4 differ
diff --git a/assets/goverment/video_ru.webm b/assets/goverment/video_ru.webm
deleted file mode 100644
index b5a62fb..0000000
Binary files a/assets/goverment/video_ru.webm and /dev/null differ
diff --git a/assets/manual/manual_video_en.mp4 b/assets/manual/manual_video_en.mp4
new file mode 100644
index 0000000..ec03703
Binary files /dev/null and b/assets/manual/manual_video_en.mp4 differ
diff --git a/assets/manual/manual_video_en.webm b/assets/manual/manual_video_en.webm
deleted file mode 100644
index 4015cf7..0000000
Binary files a/assets/manual/manual_video_en.webm and /dev/null differ
diff --git a/assets/manual/manual_video_ru.mp4 b/assets/manual/manual_video_ru.mp4
new file mode 100644
index 0000000..4e1fce5
Binary files /dev/null and b/assets/manual/manual_video_ru.mp4 differ
diff --git a/assets/manual/manual_video_ru.webm b/assets/manual/manual_video_ru.webm
deleted file mode 100644
index e710499..0000000
Binary files a/assets/manual/manual_video_ru.webm and /dev/null differ
diff --git a/assets/manual/manual_video_uz.mp4 b/assets/manual/manual_video_uz.mp4
new file mode 100644
index 0000000..83e3b56
Binary files /dev/null and b/assets/manual/manual_video_uz.mp4 differ
diff --git a/assets/manual/manual_video_uz.webm b/assets/manual/manual_video_uz.webm
deleted file mode 100644
index d35c99d..0000000
Binary files a/assets/manual/manual_video_uz.webm and /dev/null differ
diff --git a/components/ui/ProductList.tsx b/components/ui/ProductList.tsx
index b52d98a..bb0338d 100644
--- a/components/ui/ProductList.tsx
+++ b/components/ui/ProductList.tsx
@@ -1,8 +1,9 @@
import { useTheme } from '@/components/ThemeContext';
import { products_api } from '@/screens/home/lib/api';
import { ProductResponse } from '@/screens/home/lib/types';
+import { user_api } from '@/screens/profile/lib/api';
import { BottomSheetBackdrop, BottomSheetModal, BottomSheetScrollView } from '@gorhom/bottom-sheet';
-import { useInfiniteQuery } from '@tanstack/react-query';
+import { useInfiniteQuery, useQuery } from '@tanstack/react-query';
import { ResizeMode, Video } from 'expo-av';
import { Info, Package, PlayCircle } from 'lucide-react-native';
import React, { useCallback, useRef, useState } from 'react';
@@ -50,6 +51,17 @@ export default function ProductList({ query }: Props) {
const allProducts = data?.pages.flatMap((p) => p.results) ?? [];
+ const {
+ data: detail,
+ isLoading: loadingDetail,
+ isError: detailError,
+ } = useQuery({
+ queryKey: ['my_ads_id', selectedProduct],
+ queryFn: () => user_api.detail_service(Number(selectedProduct?.id)),
+ select: (res) => res.data.data,
+ enabled: !!selectedProduct,
+ });
+
const handlePresentModalPress = useCallback((product: ProductResponse) => {
setSelectedProduct(product);
setCurrentImageIndex(0);
@@ -181,12 +193,29 @@ export default function ProductList({ query }: Props) {
style={styles.sheetContent}
contentContainerStyle={styles.sheetContentContainer}
>
- {selectedProduct && (
+ {/* Loading holati */}
+ {loadingDetail && (
+
+
+
+ )}
+
+ {/* Error holati */}
+ {detailError && (
+
+
+ {t('Xatolik yuz berdi')}
+
+
+ )}
+
+ {/* Detail mavjud bo‘lsa */}
+ {detail && (
<>
item.id.toString()}
horizontal
@@ -197,9 +226,9 @@ export default function ProductList({ query }: Props) {
setCurrentImageIndex(index);
}}
/>
- {selectedProduct.files.length > 1 && (
+ {detail.files.length > 1 && (
- {selectedProduct.files.map((_, i) => (
+ {detail.files.map((_, i) => (
- {selectedProduct.title}
+ {detail.title}
- {selectedProduct.company}
+ {detail.company}
@@ -230,10 +259,8 @@ export default function ProductList({ query }: Props) {
{t("Batafsil ma'lumot")}
-
- {selectedProduct.description || "Ma'lumot mavjud emas."}
+
+ {detail.description || "Ma'lumot mavjud emas."}
>
diff --git a/i18n/locales/en.json b/i18n/locales/en.json
index 6c3a461..848cb0a 100644
--- a/i18n/locales/en.json
+++ b/i18n/locales/en.json
@@ -139,7 +139,7 @@
"Keyingi": "Next",
"Xizmat sarlavhasi": "Service title",
"Yangilashda xato yuz berdi": "Error occurred while updating",
- "Xizmatni tahrirlash (1/2)": "Edit service (1/2)",
+ "Xizmatni tahrirlash": "Edit service",
"Xizmatni tahrirlash (2/2)": "Edit service (2/2)",
"Tilni tanlang": "Select language",
"Rejimni tanlang": "Select mode",
@@ -226,5 +226,6 @@
"INN kiriting (9 raqam)": "Enter INN (9 digits)",
"Referal kodi": "Referral code",
"Direktor JSHSHR": "Director JSHSHR",
- "Direktor JSHSHR (14 raqam)": "Director JSHSHR (number 14)"
+ "Direktor JSHSHR (14 raqam)": "Director JSHSHR (number 14)",
+ "Hozircha bildirishnomalar yo'q": "No notifications yet"
}
\ No newline at end of file
diff --git a/i18n/locales/ru.json b/i18n/locales/ru.json
index 4decdd8..23d6ca1 100644
--- a/i18n/locales/ru.json
+++ b/i18n/locales/ru.json
@@ -139,7 +139,7 @@
"Keyingi": "Далее",
"Xizmat sarlavhasi": "Заголовок услуги",
"Yangilashda xato yuz berdi": "Произошла ошибка при обновлении",
- "Xizmatni tahrirlash (1/2)": "Редактирование услуги (1/2)",
+ "Xizmatni tahrirlash": "Редактирование услуги",
"Xizmatni tahrirlash (2/2)": "Редактирование услуги (2/2)",
"Tilni tanlang": "Выберите язык",
"Rejimni tanlang": "Выберите режим",
@@ -225,5 +225,6 @@
"INN kiriting (9 raqam)": "Введите ИНН (9 цифр)",
"Referal kodi": "Реферальный код",
"Direktor JSHSHR": "Директор ПИНФЛ",
- "Direktor JSHSHR kiriting (14 raqam)": "Введите ПИНФЛ директора (14 цифр)"
+ "Direktor JSHSHR kiriting (14 raqam)": "Введите ПИНФЛ директора (14 цифр)",
+ "Hozircha bildirishnomalar yo'q": "Пока нет уведомлений"
}
\ No newline at end of file
diff --git a/i18n/locales/uz.json b/i18n/locales/uz.json
index e11f95a..8e4214f 100644
--- a/i18n/locales/uz.json
+++ b/i18n/locales/uz.json
@@ -139,7 +139,7 @@
"Yangi xizmat (2/2)": "Yangi xizmat (2/2)",
"Keyingi": "Keyingi",
"Xizmat sarlavhasi": "Xizmat sarlavhasi",
- "Xizmatni tahrirlash (1/2)": "Xizmatni tahrirlash (1/2)",
+ "Xizmatni tahrirlash": "Xizmatni tahrirlash",
"Xizmatni tahrirlash (2/2)": "Xizmatni tahrirlash (2/2)",
"Tilni tanlang": "Tilni tanlang",
"Rejimni tanlang": "Rejimni tanlang",
@@ -177,6 +177,7 @@
"Faqat tasdiqlangan profillarga ishonch bilan murojaat qiling.": "Faqat tasdiqlangan profillarga ishonch bilan murojaat qiling.",
"Qo'llanma video": "Qo'llanma video",
"Bildirishnomalar": "Bildirishnomalar",
+ "Hozircha bildirishnomalar yo'q": "Hozircha bildirishnomalar yo'q",
"Bildirishnomalarni yuklashda muammo bo'ldi": "Bildirishnomalarni yuklashda muammo bo'ldi",
"Hozir": "Hozir",
"daqiqa oldin": "daqiqa oldin",
diff --git a/package-lock.json b/package-lock.json
index a28d5b6..50946c9 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -71,6 +71,7 @@
"react-native-worklets": "^0.5.1",
"react-stately": "^3.39.0",
"tailwind-variants": "^0.1.20",
+ "toastify-react-native": "^7.2.3",
"zustand": "^5.0.10"
},
"devDependencies": {
@@ -15396,6 +15397,73 @@
"react-native-pager-view": ">= 6.0.0"
}
},
+ "node_modules/react-native-vector-icons": {
+ "version": "10.3.0",
+ "resolved": "https://registry.npmjs.org/react-native-vector-icons/-/react-native-vector-icons-10.3.0.tgz",
+ "integrity": "sha512-IFQ0RE57819hOUdFvgK4FowM5aMXg7C7XKsuGLevqXkkIJatc3QopN0wYrb2IrzUgmdpfP+QVIbI3S6h7M0btw==",
+ "deprecated": "react-native-vector-icons package has moved to a new model of per-icon-family packages. See the https://github.com/oblador/react-native-vector-icons/blob/master/MIGRATION.md on how to migrate",
+ "license": "MIT",
+ "dependencies": {
+ "prop-types": "^15.7.2",
+ "yargs": "^16.1.1"
+ },
+ "bin": {
+ "fa-upgrade.sh": "bin/fa-upgrade.sh",
+ "fa5-upgrade": "bin/fa5-upgrade.sh",
+ "fa6-upgrade": "bin/fa6-upgrade.sh",
+ "generate-icon": "bin/generate-icon.js"
+ }
+ },
+ "node_modules/react-native-vector-icons/node_modules/cliui": {
+ "version": "7.0.4",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
+ "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
+ "license": "ISC",
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.0",
+ "wrap-ansi": "^7.0.0"
+ }
+ },
+ "node_modules/react-native-vector-icons/node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/react-native-vector-icons/node_modules/yargs": {
+ "version": "16.2.0",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
+ "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
+ "license": "MIT",
+ "dependencies": {
+ "cliui": "^7.0.2",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.0",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^20.2.2"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/react-native-vector-icons/node_modules/yargs-parser": {
+ "version": "20.2.9",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
+ "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/react-native-web": {
"version": "0.21.2",
"resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.21.2.tgz",
@@ -17202,6 +17270,19 @@
"node": ">=8.0"
}
},
+ "node_modules/toastify-react-native": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/toastify-react-native/-/toastify-react-native-7.2.3.tgz",
+ "integrity": "sha512-ngmpTKlTo0IRddwSsNWK+YKbB2veqotHy7Zpil4eksoLAlq0RPSgdVOk5QDEDUONJQ4r7ljGYeRW68KBztirsg==",
+ "license": "MIT",
+ "dependencies": {
+ "react-native-vector-icons": "*"
+ },
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*"
+ }
+ },
"node_modules/toidentifier": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
diff --git a/package.json b/package.json
index 0baf5a3..d411c01 100644
--- a/package.json
+++ b/package.json
@@ -76,6 +76,7 @@
"react-native-worklets": "^0.5.1",
"react-stately": "^3.39.0",
"tailwind-variants": "^0.1.20",
+ "toastify-react-native": "^7.2.3",
"zustand": "^5.0.10"
},
"devDependencies": {
diff --git a/screens/announcements/ui/AnnouncementsList.tsx b/screens/announcements/ui/AnnouncementsList.tsx
index 61524f0..db23f88 100644
--- a/screens/announcements/ui/AnnouncementsList.tsx
+++ b/screens/announcements/ui/AnnouncementsList.tsx
@@ -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> = {
- ru: require('@/assets/goverment/video_ru.webm'),
+ ru: require('@/assets/goverment/video_ru.mp4'),
};
// Update selected language
diff --git a/screens/auth/confirm/ConfirmScreen.tsx b/screens/auth/confirm/ConfirmScreen.tsx
index 976ed65..d825a81 100644
--- a/screens/auth/confirm/ConfirmScreen.tsx
+++ b/screens/auth/confirm/ConfirmScreen.tsx
@@ -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'));
},
});
diff --git a/screens/auth/register-confirm/ConfirmScreen.tsx b/screens/auth/register-confirm/ConfirmScreen.tsx
index 50c7779..97918fd 100644
--- a/screens/auth/register-confirm/ConfirmScreen.tsx
+++ b/screens/auth/register-confirm/ConfirmScreen.tsx
@@ -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: () => {
diff --git a/screens/auth/register/RegisterForm.tsx b/screens/auth/register/RegisterForm.tsx
index 32bd0af..db7167a 100644
--- a/screens/auth/register/RegisterForm.tsx
+++ b/screens/auth/register/RegisterForm.tsx
@@ -360,7 +360,10 @@ export default function RegisterFormScreen() {
};
return (
-
+
-
+
);
}
diff --git a/screens/create-ads/ui/CreateAdsScreens.tsx b/screens/create-ads/ui/CreateAdsScreens.tsx
index 2c3b6ec..58b311c 100644
--- a/screens/create-ads/ui/CreateAdsScreens.tsx
+++ b/screens/create-ads/ui/CreateAdsScreens.tsx
@@ -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);
},
});
diff --git a/screens/create-ads/ui/StepTwo.tsx b/screens/create-ads/ui/StepTwo.tsx
index 6c348ff..415b289 100644
--- a/screens/create-ads/ui/StepTwo.tsx
+++ b/screens/create-ads/ui/StepTwo.tsx
@@ -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;
diff --git a/screens/e-services/ui/EServicesCategoryScreen.tsx b/screens/e-services/ui/EServicesCategoryScreen.tsx
index 8b888f5..9edb7b0 100644
--- a/screens/e-services/ui/EServicesCategoryScreen.tsx
+++ b/screens/e-services/ui/EServicesCategoryScreen.tsx
@@ -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"));
}
};
diff --git a/screens/e-services/ui/EServicesScreen.tsx b/screens/e-services/ui/EServicesScreen.tsx
index 66cd54b..9b40cab 100644
--- a/screens/e-services/ui/EServicesScreen.tsx
+++ b/screens/e-services/ui/EServicesScreen.tsx
@@ -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"));
}
};
diff --git a/screens/profile/lib/api.ts b/screens/profile/lib/api.ts
index 5618afe..a3e9448 100644
--- a/screens/profile/lib/api.ts
+++ b/screens/profile/lib/api.ts
@@ -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> {
- 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> {
+ 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;
diff --git a/screens/profile/ui/AddEmployee.tsx b/screens/profile/ui/AddEmployee.tsx
index 3e862d2..ea89b7c 100644
--- a/screens/profile/ui/AddEmployee.tsx
+++ b/screens/profile/ui/AddEmployee.tsx
@@ -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() {
router.push('/profile/employees')}>
- {t("Yangi xodim qo'shish")}
+ {t("Xodim qo'shish")}
{isPending ? (
) : (
- {t('Saqlash')}
+
)}
diff --git a/screens/profile/ui/AnnouncementsTab.tsx b/screens/profile/ui/AnnouncementsTab.tsx
index 93dd0ab..bfc6ceb 100644
--- a/screens/profile/ui/AnnouncementsTab.tsx
+++ b/screens/profile/ui/AnnouncementsTab.tsx
@@ -52,7 +52,7 @@ export function AnnouncementsTab() {
};
const [refreshing, setRefreshing] = useState(false);
- const [selectedAnnouncement, setSelectedAnnouncement] = useState(null);
+ const [selectedAnnouncement, setSelectedAnnouncement] = useState(null);
const [sheetOpen, setSheetOpen] = useState(false); const bottomSheetModalRef = useRef(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 (
- {t('Xatolik yuz berdi')}
+ {t('Xatolik yuz berdi')}
);
}
@@ -196,7 +196,7 @@ export function AnnouncementsTab() {
item.id.toString()}
- contentContainerStyle={styles.list}
+ contentContainerStyle={[styles.list, { flexGrow: 1 }]}
refreshControl={
}
@@ -204,7 +204,7 @@ export function AnnouncementsTab() {
renderItem={({ item }) => (
openSheet(item)}
+ onPress={() => { openSheet(item); setSelectedAnnouncement(item.id) }}
>
{item.files?.[0]?.file && (
@@ -243,6 +243,14 @@ export function AnnouncementsTab() {
)}
+ ListEmptyComponent={() => (
+
+
+
+ {t('Hozircha hech qanday eʼlon mavjud emas')}
+
+
+ )}
/>
{
- setSheetOpen(false);
- setSelectedAnnouncement(null);
+ setSelectedAnnouncement(null); // shu yetarli
}}
>
{loadingDetail && }
{detailError && (
- {t('Xatolik yuz berdi')}
+ {t('Xatolik yuz berdi')}
)}
{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' })}
>
@@ -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' })}
>
{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',
+ },
});
diff --git a/screens/profile/ui/BonusesScreen.tsx b/screens/profile/ui/BonusesScreen.tsx
index 0e21cac..526701f 100644
--- a/screens/profile/ui/BonusesScreen.tsx
+++ b/screens/profile/ui/BonusesScreen.tsx
@@ -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,
diff --git a/screens/profile/ui/CreateReferrals.tsx b/screens/profile/ui/CreateReferrals.tsx
index 0fc1cde..94a6f7d 100644
--- a/screens/profile/ui/CreateReferrals.tsx
+++ b/screens/profile/ui/CreateReferrals.tsx
@@ -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'));
},
});
diff --git a/screens/profile/ui/EditServices.tsx b/screens/profile/ui/EditServices.tsx
index fa53d94..e57c0e5 100644
--- a/screens/profile/ui/EditServices.tsx
+++ b/screens/profile/ui/EditServices.tsx
@@ -151,7 +151,7 @@ export default function EditService() {
- {step === 1 ? t('Xizmatni tahrirlash (1/2)') : t('Xizmatni tahrirlash (2/2)')}
+ {t('Xizmatni tahrirlash')}
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',
diff --git a/screens/profile/ui/ManualTab.tsx b/screens/profile/ui/ManualTab.tsx
index 10f1801..10261f7 100644
--- a/screens/profile/ui/ManualTab.tsx
+++ b/screens/profile/ui/ManualTab.tsx
@@ -68,9 +68,9 @@ export function ManualTab() {
/** 🔹 Video manbalari (SELECT ga bog‘liq) */
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 },
diff --git a/screens/profile/ui/MyServices.tsx b/screens/profile/ui/MyServices.tsx
index 78c7256..b79f3b3 100644
--- a/screens/profile/ui/MyServices.tsx
+++ b/screens/profile/ui/MyServices.tsx
@@ -116,7 +116,7 @@ export default function MyServicesScreen() {
item.id.toString()}
- contentContainerStyle={styles.list}
+ contentContainerStyle={[styles.list, { flexGrow: 1 }]}
onEndReached={() => hasNextPage && fetchNextPage()}
refreshControl={
{t('Bildirishnomalar')}
-
- {notifications.some((n) => !n.is_read) && (
- markAllAsRead()}
- disabled={isMarkingAllRead}
- >
- {isMarkingAllRead ? (
-
- ) : (
-
- {t("Barchasi o'qildi")}
-
- )}
-
- )}
item.id.toString()}
contentContainerStyle={styles.listContent}
showsVerticalScrollIndicator={false}
- renderItem={({ item, index }) => }
+ ListHeaderComponent={() => {
+ if (notifications.length === 0) {
+ return (
+
+
+ {t("Hozircha bildirishnomalar yo'q")}
+
+
+
+ {t("Yangi xabarlar shu yerda paydo bo‘ladi")}
+
+
+ );
+ }
+
+ if (notifications.some((n) => !n.is_read)) {
+ return (
+
+ markAllAsRead()}
+ disabled={isMarkingAllRead}
+ >
+ {isMarkingAllRead ? (
+
+ ) : (
+
+ {t("Barchasi o'qildi")}
+
+ )}
+
+
+ );
+ }
+
+ return (
+
+
+ {t("Barcha bildirishnomalar o‘qilgan")}
+
+
+ );
+ }}
+ renderItem={({ item }) => }
onEndReached={() => {
if (hasNextPage && !isFetchingNextPage) {
fetchNextPage();
@@ -130,6 +175,15 @@ export function NotificationTab() {
}
refreshing={isLoading}
onRefresh={refetch}
+ ListEmptyComponent={() =>
+ !isLoading && (
+
+
+ {t("Hozircha bildirishnomalar yo'q")}
+
+
+ )
+ }
/>
);
@@ -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,
+ },
});
diff --git a/screens/profile/ui/ProductServicesTab.tsx b/screens/profile/ui/ProductServicesTab.tsx
index 76d228d..a280629 100644
--- a/screens/profile/ui/ProductServicesTab.tsx
+++ b/screens/profile/ui/ProductServicesTab.tsx
@@ -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,
diff --git a/screens/profile/ui/RefferallsTab.tsx b/screens/profile/ui/RefferallsTab.tsx
index 0f71d57..72661a2 100644
--- a/screens/profile/ui/RefferallsTab.tsx
+++ b/screens/profile/ui/RefferallsTab.tsx
@@ -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() {
)}
- ListEmptyComponent={
-
- {t('Refferallar topilmadi')}
-
- }
+ ListEmptyComponent={() => (
+
+
+
+
+
+
+ {t("Refferallar mavjud emas")}
+
+
+ )}
/>
);
@@ -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,
+ },
});