diff --git a/api/URLs.ts b/api/URLs.ts
index 93ce264..d525e40 100644
--- a/api/URLs.ts
+++ b/api/URLs.ts
@@ -37,5 +37,6 @@ export const API_URLS = {
Notification_Ready: (id: number) => `/api/notifications/${id}/read/`,
Notification_Mark_All_Read: '/api/notifications/read-all/',
Info: "/auth/get-person/",
- Get_Director_Info: "/auth/get-director/"
+ Get_Director_Info: "/auth/get-director/",
+ GetTokens: "/api/tokens/",
};
diff --git a/api/httpClient.ts b/api/httpClient.ts
index 1defde2..34395fe 100644
--- a/api/httpClient.ts
+++ b/api/httpClient.ts
@@ -82,7 +82,6 @@ httpClient.interceptors.response.use(
// Original so'rovni qayta yuboramiz
return httpClient(originalRequest);
} catch (refreshError) {
- console.error('Refresh token xatosi:', refreshError);
// Refresh muvaffaqiyatsiz bo'lsa
processQueue(refreshError);
diff --git a/app.json b/app.json
index 8b8ce6e..f1da3c7 100644
--- a/app.json
+++ b/app.json
@@ -2,7 +2,7 @@
"expo": {
"name": "Info target",
"slug": "infotarget",
- "version": "1.0.2",
+ "version": "1.0.3",
"orientation": "portrait",
"icon": "./assets/images/logo.png",
"scheme": "infotarget",
diff --git a/app/(auth)/register.tsx b/app/(auth)/register.tsx
index 70a5c40..4c2ea8d 100644
--- a/app/(auth)/register.tsx
+++ b/app/(auth)/register.tsx
@@ -1,247 +1,8 @@
-import AuthHeader from '@/components/ui/AuthHeader';
-import { PersonType, useRegister } from '@/screens/auth/register/lib/useRegisterStore';
-import { LinearGradient } from 'expo-linear-gradient';
-import { useRouter } from 'expo-router';
-import { Building2, ChevronRight, ShieldCheck, User } from 'lucide-react-native';
+import RegisterFormScreen from '@/screens/auth/register/RegisterForm';
import React from 'react';
-import { useTranslation } from 'react-i18next';
-import {
- Animated,
- ScrollView,
- StyleSheet,
- Text,
- TouchableOpacity,
- View,
-} from 'react-native';
-import { SafeAreaView } from 'react-native-safe-area-context';
-
-const PERSON_TYPES: {
- key: PersonType;
- label: string;
- description: string;
- icon: React.ReactNode;
- gradient: [string, string];
-}[] = [
- {
- key: 'legal_entity',
- label: 'Yuridik shaxs',
- description: "Tashkilot yoki korxona",
- icon: ,
- gradient: ['#f59e0b', '#d97706'],
- },
- {
- key: 'yatt',
- label: 'YATT',
- description: "Yakka tartibdagi tadbirkor",
- icon: ,
- gradient: ['#10b981', '#059669'],
- },
- {
- key: 'band',
- label: "O'zini o'zi band qilgan",
- description: "O'z faoliyatini mustaqil yurituvchi",
- icon: ,
- gradient: ['#3b82f6', '#2563eb'],
- },
- ];
-
-function TypeCard({
- item,
- index,
- onPress,
-}: {
- item: (typeof PERSON_TYPES)[number];
- index: number;
- onPress: () => void;
-}) {
- const scale = React.useRef(new Animated.Value(1)).current;
- const { t } = useTranslation()
-
- const handlePressIn = () => {
- Animated.spring(scale, {
- toValue: 0.96,
- useNativeDriver: true,
- }).start();
- };
-
- const handlePressOut = () => {
- Animated.spring(scale, {
- toValue: 1,
- friction: 4,
- useNativeDriver: true,
- }).start();
- };
+export default function Index() {
return (
-
-
-
- {item.icon}
-
-
- {t(item.label)}
- {t(item.description)}
-
-
-
-
+
);
-}
-
-export default function PersonTypeScreen() {
- const router = useRouter();
- const { t } = useTranslation();
- const { setPersonType, reset } = useRegister();
-
- const handleSelect = (type: PersonType) => {
- setPersonType(type);
- router.push('/(auth)/register-form');
- };
-
- return (
-
-
-
-
-
-
-
- {t("Ro'yxatdan o'tish")}
-
- {t("Faoliyat turingizni tanlang")}
-
-
-
-
- {PERSON_TYPES.map((item, index) => (
- { handleSelect(item.key); reset() }}
- />
- ))}
-
-
-
- router.back()} testID="go-to-login">
-
- {t("Hisobingiz bormi?")} {t("Kirish")}
-
-
-
-
-
- );
-}
-
-const styles = StyleSheet.create({
- container: {
- flex: 1,
- backgroundColor: '#0f172a',
- },
- safeArea: {
- flex: 1,
- paddingHorizontal: 14,
- },
- header: {
- alignItems: 'center',
- marginBottom: 20,
- marginTop: 20,
- },
- title: {
- fontSize: 28,
- fontWeight: '800' as const,
- color: '#ffffff',
- marginBottom: 10,
- letterSpacing: 0.5,
- },
- subtitle: {
- fontSize: 15,
- color: '#94a3b8',
- textAlign: 'center',
- lineHeight: 22,
- },
- cardList: {
- marginBottom: 14,
- },
- card: {
- flexDirection: 'row',
- alignItems: 'center',
- backgroundColor: 'rgba(255, 255, 255, 0.06)',
- borderRadius: 20,
- padding: 18,
- borderWidth: 1,
- borderColor: 'rgba(255, 255, 255, 0.1)',
- gap: 16,
- },
- cardIcon: {
- width: 56,
- height: 56,
- borderRadius: 16,
- alignItems: 'center',
- justifyContent: 'center',
- },
- cardContent: {
- flex: 1,
- },
- cardTitle: {
- fontSize: 17,
- fontWeight: '700' as const,
- color: '#ffffff',
- marginBottom: 4,
- },
- cardDescription: {
- fontSize: 13,
- color: '#94a3b8',
- lineHeight: 18,
- },
- footer: {
- marginTop: 'auto' as const,
- paddingBottom: 20,
- alignItems: 'center',
- },
- footerText: {
- color: '#94a3b8',
- fontSize: 14,
- },
- footerLink: {
- color: '#3b82f6',
- fontWeight: '700' as const,
- },
- decorCircle1: {
- position: 'absolute',
- top: -150,
- right: -100,
- width: 400,
- height: 400,
- borderRadius: 200,
- backgroundColor: 'rgba(59, 130, 246, 0.1)',
- },
- decorCircle2: {
- position: 'absolute',
- bottom: -100,
- left: -150,
- width: 350,
- height: 350,
- borderRadius: 175,
- backgroundColor: 'rgba(16, 185, 129, 0.08)',
- },
-});
+}
\ No newline at end of file
diff --git a/app/(auth)/select-category.tsx b/app/(auth)/select-category.tsx
index 91d95f7..34798b2 100644
--- a/app/(auth)/select-category.tsx
+++ b/app/(auth)/select-category.tsx
@@ -11,13 +11,13 @@ import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import {
ActivityIndicator,
- Alert,
ScrollView,
StyleSheet,
Text,
TouchableOpacity,
- View,
+ View
} from 'react-native';
+import { Toast } from 'toastify-react-native';
interface Category {
id: number;
@@ -28,15 +28,17 @@ interface Category {
export default function CategorySelectScreen() {
const router = useRouter();
const { t } = useTranslation();
- const { phone, stir, person_type, director_full_name, referal, first_name, last_name, middle_name } = useLocalSearchParams<{
+ const { phone, stir, person_type, referal, director_full_name, first_name, last_name, district, company_name, address } = useLocalSearchParams<{
phone: string;
stir: string;
- person_type: 'band' | 'ytt';
+ person_type: 'band' | 'ytt' | "legal_entity";
referal: string;
director_full_name: string;
first_name: string;
last_name: string;
- middle_name: string;
+ district: string
+ address: string;
+ company_name: string;
}>();
const [selected, setSelected] = useState(null);
@@ -69,22 +71,32 @@ export default function CategorySelectScreen() {
person_type: string;
activate_types: number[];
director_full_name: string;
- referal: string;
+ referral: string;
first_name: string;
last_name: string;
+ district: number;
+ company_name: string;
+ address: number;
}) => auth_api.register(body),
onSuccess: async () => {
router.replace('/(auth)/register-confirm');
await AsyncStorage.setItem('phone', phone);
},
onError: (err: AxiosError) => {
- const errMessage = (err.response?.data as { data: { stir: string[] } }).data.stir[0];
- const errMessageDetail = (err.response?.data as { data: { detail: string } }).data.detail;
+ const errMessage = (err.response?.data as any)?.data?.stir?.[0];
+ const errMessageDetail = (err.response?.data as any)?.data?.detail;
+ const errMessageReffral = (err.response?.data as any).data.referral[0];
+ const errMessageDetailData = (err.response?.data as any)?.data;
- const errrAlert = errMessage ? errMessage : errMessageDetail;
+ const message =
+ errMessage ||
+ errMessageReffral ||
+ errMessageDetail ||
+ errMessageDetailData ||
+ t('Xatolik yuz berdi');
- Alert.alert(t('Xatolik yuz berdi'), errMessage || errrAlert || t('erroXatolik yuz berdi'));
- },
+ Toast.error(String(message));
+ }
});
const onCategoryPress = (cat: Category) => {
@@ -103,8 +115,6 @@ export default function CategorySelectScreen() {
setSelected(null);
};
- const full_name = first_name.length > 0 ? first_name + ' ' + last_name + ' ' + middle_name : director_full_name;
-
return (
@@ -149,10 +159,13 @@ export default function CategorySelectScreen() {
person_type,
phone: `998${phone}`,
stir,
- referal: referal,
- director_full_name: director_full_name,
- first_name: full_name,
- last_name: last_name,
+ referral: referal,
+ director_full_name,
+ first_name,
+ last_name,
+ district: Number(district),
+ address: Number(address),
+ company_name
});
}}
>
@@ -179,7 +192,7 @@ const styles = StyleSheet.create({
container: {
paddingHorizontal: 20,
paddingTop: 16,
- paddingBottom: 70,
+ paddingBottom: 90,
gap: 12,
},
diff --git a/app/(dashboard)/_layout.tsx b/app/(dashboard)/_layout.tsx
index 794efbe..d724066 100644
--- a/app/(dashboard)/_layout.tsx
+++ b/app/(dashboard)/_layout.tsx
@@ -27,9 +27,6 @@ export default function TabsLayout() {
};
}, []);
- console.log(keyboard);
-
-
useEffect(() => {
Animated.loop(
Animated.timing(rotateAnim, {
diff --git a/components/NotificationProvider.tsx b/components/NotificationProvider.tsx
index 8c1e811..89416ce 100644
--- a/components/NotificationProvider.tsx
+++ b/components/NotificationProvider.tsx
@@ -34,7 +34,6 @@ export async function registerForPushNotificationsAsync() {
}
if (finalStatus !== 'granted') {
- console.log('Notification uchun ruxsat berilmadi!');
return;
}
@@ -43,10 +42,6 @@ export async function registerForPushNotificationsAsync() {
projectId: '67d5a024-4eb7-44ec-8b18-6c9187bd1862',
})
).data;
-
- console.log('Push Token:', token);
- } else {
- console.log('Push notification faqat real qurilmalarda ishlaydi!');
}
return token;
diff --git a/components/ui/CategorySelect.tsx b/components/ui/CategorySelect.tsx
index 9e81944..458f64d 100644
--- a/components/ui/CategorySelect.tsx
+++ b/components/ui/CategorySelect.tsx
@@ -1,9 +1,9 @@
import { useTheme } from '@/components/ThemeContext';
import { products_api } from '@/screens/home/lib/api';
import { useMutation, useQuery } from '@tanstack/react-query';
-import { AxiosError } from 'axios';
import { ChevronLeft, ChevronRight } from 'lucide-react-native';
import React, { Dispatch, SetStateAction, useState } from 'react';
+import { useTranslation } from 'react-i18next';
import {
ActivityIndicator,
FlatList,
@@ -12,6 +12,7 @@ import {
TouchableOpacity,
View,
} from 'react-native';
+import { Toast } from 'toastify-react-native';
interface Category {
id: number;
@@ -44,6 +45,7 @@ export default function CategorySelect({ selectedCategories, setSelectedCategori
const [currentCategories, setCurrentCategories] = useState([]);
const [currentParentId, setCurrentParentId] = useState(null);
const [history, setHistory] = useState([]);
+ const { t } = useTranslation()
// Root categories
const { isLoading: rootLoading, error: rootError } = useQuery({
@@ -66,8 +68,8 @@ export default function CategorySelect({ selectedCategories, setSelectedCategori
setCurrentCategories(childCategories);
setCurrentParentId(id);
},
- onError: (err: AxiosError) => {
- console.error('Child category loading error:', err);
+ onError: () => {
+ Toast.error(t("Xatolik yuz berdi"))
},
});
diff --git a/components/ui/FilterUI.tsx b/components/ui/FilterUI.tsx
index cd5f6b6..b303442 100644
--- a/components/ui/FilterUI.tsx
+++ b/components/ui/FilterUI.tsx
@@ -6,7 +6,6 @@ import BottomSheet, {
BottomSheetScrollView,
} from '@gorhom/bottom-sheet';
import { useMutation, useQuery } from '@tanstack/react-query';
-import { AxiosError } from 'axios';
import { Image } from 'expo-image';
import { CheckIcon, ChevronRight, XIcon } from 'lucide-react-native';
import React, { Dispatch, SetStateAction, useCallback, useMemo, useRef, useState } from 'react';
@@ -75,7 +74,6 @@ export default function FilterUI({ back, onApply, setStep, setFiltered }: Filter
setStep('items');
setFiltered(data.data.data.results);
},
- onError: (error: AxiosError) => console.log(error),
});
const handleApply = () => {
diff --git a/components/ui/IndustrySelection.tsx b/components/ui/IndustrySelection.tsx
index ce4cb99..c13d9aa 100644
--- a/components/ui/IndustrySelection.tsx
+++ b/components/ui/IndustrySelection.tsx
@@ -1,8 +1,8 @@
import { products_api } from '@/screens/home/lib/api';
import { useMutation, useQuery } from '@tanstack/react-query';
-import { AxiosError } from 'axios';
import { ChevronLeft, ChevronRight } from 'lucide-react-native';
import React, { Dispatch, SetStateAction, useState } from 'react';
+import { useTranslation } from 'react-i18next';
import {
ActivityIndicator,
FlatList,
@@ -11,6 +11,7 @@ import {
TouchableOpacity,
View,
} from 'react-native';
+import { Toast } from 'toastify-react-native';
import { useTheme } from '../ThemeContext';
interface Category {
@@ -39,6 +40,7 @@ export default function CategorySelection({ selectedCategories, setSelectedCateg
const [history, setHistory] = useState<{ parentId: number | null; categories: Category[] }[]>([]);
const [currentParentId, setCurrentParentId] = useState(null);
const { isDark } = useTheme();
+ const { t } = useTranslation()
const theme = {
cardBg: isDark ? '#1e293b' : '#f8fafc',
@@ -75,8 +77,8 @@ export default function CategorySelection({ selectedCategories, setSelectedCateg
setCurrentCategories(childCategories);
setCurrentParentId(id);
},
- onError: (err: AxiosError) => {
- console.error('Child yuklashda xato:', err);
+ onError: () => {
+ Toast.error(t("Xatolik yuz berdi"))
},
});
diff --git a/components/ui/RefreshContext.tsx b/components/ui/RefreshContext.tsx
index 74f71a7..901391c 100644
--- a/components/ui/RefreshContext.tsx
+++ b/components/ui/RefreshContext.tsx
@@ -18,9 +18,7 @@ export function RefreshProvider({ children }: { children: React.ReactNode }) {
setRefreshing(true);
try {
await queryClient.refetchQueries();
- } catch (err) {
- console.error('Global refresh error:', err);
- } finally {
+ } catch (err) { } finally {
setRefreshing(false);
}
}, [queryClient, refreshing]);
diff --git a/components/ui/gluestack-ui-provider/script.ts b/components/ui/gluestack-ui-provider/script.ts
index 732d136..75ea4a6 100644
--- a/components/ui/gluestack-ui-provider/script.ts
+++ b/components/ui/gluestack-ui-provider/script.ts
@@ -13,7 +13,5 @@ export const script = (mode: string) => {
documentElement.classList.remove(theme === 'light' ? 'dark' : 'light');
documentElement.classList.add(theme);
documentElement.style.colorScheme = theme;
- } catch (e) {
- console.error(e);
- }
+ } catch (e) { }
};
diff --git a/constants/crypto.ts b/constants/crypto.ts
new file mode 100644
index 0000000..331009d
--- /dev/null
+++ b/constants/crypto.ts
@@ -0,0 +1,41 @@
+import CryptoJS from 'crypto-js';
+
+/**
+ * Backenddan kelgan shifrlangan tokenni ochish
+ */
+export const decryptToken = (encryptedBase64: string) => {
+ try {
+ // 1. Base64 dan WordArray ga
+ const encryptedData = CryptoJS.enc.Base64.parse(encryptedBase64);
+
+ // 2. IV (dastlabki 16 bayt)
+ const iv = CryptoJS.lib.WordArray.create(encryptedData.words.slice(0, 4));
+
+ // 3. Ciphertext (qolgan qism)
+ const ciphertext = CryptoJS.lib.WordArray.create(
+ encryptedData.words.slice(4),
+ encryptedData.sigBytes - 16
+ );
+
+ // 4. Maxfiy kalit
+ const key = CryptoJS.enc.Utf8.parse("12345678901234567890123456789012");
+
+ // 5. CipherParams yaratish
+ const cipherParams = CryptoJS.lib.CipherParams.create({
+ ciphertext,
+ key,
+ iv
+ });
+
+ // 6. Dekodlash
+ const decrypted = CryptoJS.AES.decrypt(cipherParams, key, {
+ iv,
+ mode: CryptoJS.mode.CBC,
+ padding: CryptoJS.pad.Pkcs7
+ });
+
+ return decrypted.toString(CryptoJS.enc.Utf8);
+ } catch (error) {
+ return null;
+ }
+};
\ No newline at end of file
diff --git a/constants/formatText.ts b/constants/formatText.ts
new file mode 100644
index 0000000..1207ddf
--- /dev/null
+++ b/constants/formatText.ts
@@ -0,0 +1,55 @@
+const latinToCyrillicMap = [
+ ["O'", "Ў"], ["o'", "ў"],
+ ["G'", "Ғ"], ["g'", "ғ"],
+ ["Sh", "Ш"], ["sh", "ш"],
+ ["Ch", "Ч"], ["ch", "ч"],
+ ["A", "А"], ["B", "Б"], ["D", "Д"], ["E", "Е"], ["F", "Ф"],
+ ["G", "Г"], ["H", "Ҳ"], ["I", "И"], ["J", "Ж"], ["K", "К"],
+ ["L", "Л"], ["M", "М"], ["N", "Н"], ["O", "О"], ["P", "П"],
+ ["Q", "Қ"], ["R", "Р"], ["S", "С"], ["T", "Т"], ["U", "У"],
+ ["V", "В"], ["X", "Х"], ["Y", "Й"], ["Z", "З"],
+ ["a", "а"], ["b", "б"], ["d", "д"], ["e", "е"], ["f", "ф"],
+ ["g", "г"], ["h", "ҳ"], ["i", "и"], ["j", "ж"], ["k", "к"],
+ ["l", "л"], ["m", "м"], ["n", "н"], ["o", "о"], ["p", "п"],
+ ["q", "қ"], ["r", "р"], ["s", "с"], ["t", "т"], ["u", "у"],
+ ["v", "в"], ["x", "х"], ["y", "й"], ["z", "з"],
+ ["'", ""] // apostrofni olib tashlaymiz
+];
+
+export function formatText(str: string | null) {
+ if (!str) return null;
+ let result = str;
+ for (let [latin, cyrillic] of latinToCyrillicMap) {
+ const regex = new RegExp(latin, "g");
+ result = result.replace(regex, cyrillic);
+ }
+ return result;
+}
+
+const cyrillicToLatinMap = [
+ ["Ў", "O'"], ["ў", "o'"],
+ ["Ғ", "G'"], ["ғ", "g'"],
+ ["Ш", "Sh"], ["ш", "sh"],
+ ["Ч", "Ch"], ["ч", "ch"],
+ ["ё", "yo"], ["Ё", "YO"],
+ ["А", "A"], ["Б", "B"], ["Д", "D"], ["Е", "E"], ["Ф", "F"],
+ ["Г", "G"], ["Ҳ", "H"], ["И", "I"], ["Ж", "J"], ["К", "K"],
+ ["Л", "L"], ["М", "M"], ["Н", "N"], ["О", "O"], ["П", "P"],
+ ["Қ", "Q"], ["Р", "R"], ["С", "S"], ["Т", "T"], ["У", "U"],
+ ["В", "V"], ["Х", "X"], ["Й", "Y"], ["З", "Z"],
+ ["а", "a"], ["б", "b"], ["д", "d"], ["е", "e"], ["ф", "f"],
+ ["г", "g"], ["ҳ", "h"], ["и", "i"], ["ж", "j"], ["к", "k"],
+ ["л", "l"], ["м", "m"], ["н", "n"], ["о", "o"], ["п", "p"],
+ ["қ", "q"], ["р", "r"], ["с", "s"], ["т", "t"], ["у", "u"],
+ ["в", "v"], ["х", "x"], ["й", "y"], ["з", "z"],
+];
+
+export function formatTextToLatin(str: string | null) {
+ if (!str) return null;
+ let result = str;
+ for (let [cyrillic, latin] of cyrillicToLatinMap) {
+ const regex = new RegExp(cyrillic, "g");
+ result = result.replace(regex, latin);
+ }
+ return result;
+}
\ No newline at end of file
diff --git a/hooks/storage.native.ts b/hooks/storage.native.ts
index 5089c3c..b4ec181 100644
--- a/hooks/storage.native.ts
+++ b/hooks/storage.native.ts
@@ -19,10 +19,7 @@ export const deleteAsyncStorage = async (name: string) => {
export const saveLang = async (lang: string) => {
try {
await AsyncStorage.setItem('lang', lang);
- console.log(`Language saved: ${lang}`);
- } catch (error) {
- console.error('Failed to save language', error);
- }
+ } catch (error) { }
};
/**
@@ -34,7 +31,6 @@ export const getLang = async (): Promise => {
const lang = await AsyncStorage.getItem('lang');
return lang;
} catch (error) {
- console.error('Failed to get language', error);
return null;
}
};
@@ -45,9 +41,7 @@ export const getLang = async (): Promise => {
export const deleteLang = async () => {
try {
await AsyncStorage.removeItem('lang');
- } catch (error) {
- console.error('Failed to delete language', error);
- }
+ } catch (error) { }
};
const ACCESS = 'access_token';
diff --git a/hooks/useNotifications.ts b/hooks/useNotifications.ts
index bb5677d..d3b2a81 100644
--- a/hooks/useNotifications.ts
+++ b/hooks/useNotifications.ts
@@ -45,7 +45,6 @@ export function useNotifications() {
// Foreground listener
notificationListener.current = Notifications.addNotificationReceivedListener((notification) => {
- console.log('Notification received:', notification);
});
// User response listener
diff --git a/i18n/locales/en.json b/i18n/locales/en.json
index 848cb0a..484e2e2 100644
--- a/i18n/locales/en.json
+++ b/i18n/locales/en.json
@@ -227,5 +227,7 @@
"Referal kodi": "Referral code",
"Direktor JSHSHR": "Director JSHSHR",
"Direktor JSHSHR (14 raqam)": "Director JSHSHR (number 14)",
- "Hozircha bildirishnomalar yo'q": "No notifications yet"
+ "Hozircha bildirishnomalar yo'q": "No notifications yet",
+ "Siz o'zini o'zi band qilgan yoki yakka tartibdagi tadbirkorlik bo'lishingiz kerak": "You must be self-employed or an individual entrepreneur",
+ "Sizning shaxsiy ma'lumotlaringiz topilmadi": "Your personal information was not found"
}
\ No newline at end of file
diff --git a/i18n/locales/ru.json b/i18n/locales/ru.json
index 23d6ca1..9dd4946 100644
--- a/i18n/locales/ru.json
+++ b/i18n/locales/ru.json
@@ -226,5 +226,7 @@
"Referal kodi": "Реферальный код",
"Direktor JSHSHR": "Директор ПИНФЛ",
"Direktor JSHSHR kiriting (14 raqam)": "Введите ПИНФЛ директора (14 цифр)",
- "Hozircha bildirishnomalar yo'q": "Пока нет уведомлений"
+ "Hozircha bildirishnomalar yo'q": "Пока нет уведомлений",
+ "Siz o'zini o'zi band qilgan yoki yakka tartibdagi tadbirkorlik bo'lishingiz kerak": "Вы должны быть самозанятым или индивидуальным предпринимателем",
+ "Sizning shaxsiy ma'lumotlaringiz topilmadi": "Ваши личные данные не найдены"
}
\ No newline at end of file
diff --git a/i18n/locales/uz.json b/i18n/locales/uz.json
index 8e4214f..36ea769 100644
--- a/i18n/locales/uz.json
+++ b/i18n/locales/uz.json
@@ -226,5 +226,7 @@
"INN kiriting (9 raqam)": "INN kiriting (9 raqam)",
"Referal kodi": "Referal kodi",
"Direktor JSHSHR": "Direktor JSHSHR",
- "Direktor JSHSHR kiriting (14 raqam)": "Direktor JSHSHR kiriting (14 raqam)"
+ "Direktor JSHSHR kiriting (14 raqam)": "Direktor JSHSHR kiriting (14 raqam)",
+ "Siz o'zini o'zi band qilgan yoki yakka tartibdagi tadbirkorlik bo'lishingiz kerak": "Siz o'zini o'zi band qilgan yoki yakka tartibdagi tadbirkorlik bo'lishingiz kerak",
+ "Sizning shaxsiy ma'lumotlaringiz topilmadi": "Sizning shaxsiy ma'lumotlaringiz topilmadi"
}
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 50946c9..ccdac21 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -23,6 +23,7 @@
"@react-navigation/native": "^7.1.8",
"@tanstack/react-query": "^5.90.17",
"axios": "^1.13.2",
+ "crypto-js": "^4.2.0",
"expo": "~54.0.31",
"expo-av": "~16.0.8",
"expo-blur": "~15.0.8",
@@ -75,6 +76,7 @@
"zustand": "^5.0.10"
},
"devDependencies": {
+ "@types/crypto-js": "^4.2.2",
"@types/react": "~19.1.0",
"babel-plugin-module-resolver": "^5.0.0",
"eslint": "^9.25.0",
@@ -6537,6 +6539,13 @@
"@babel/types": "^7.28.2"
}
},
+ "node_modules/@types/crypto-js": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.2.2.tgz",
+ "integrity": "sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/estree": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
@@ -8569,6 +8578,12 @@
"node": ">= 8"
}
},
+ "node_modules/crypto-js": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
+ "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==",
+ "license": "MIT"
+ },
"node_modules/crypto-random-string": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz",
diff --git a/package.json b/package.json
index d411c01..6773171 100644
--- a/package.json
+++ b/package.json
@@ -28,6 +28,7 @@
"@react-navigation/native": "^7.1.8",
"@tanstack/react-query": "^5.90.17",
"axios": "^1.13.2",
+ "crypto-js": "^4.2.0",
"expo": "~54.0.31",
"expo-av": "~16.0.8",
"expo-blur": "~15.0.8",
@@ -80,6 +81,7 @@
"zustand": "^5.0.10"
},
"devDependencies": {
+ "@types/crypto-js": "^4.2.2",
"@types/react": "~19.1.0",
"babel-plugin-module-resolver": "^5.0.0",
"eslint": "^9.25.0",
diff --git a/screens/auth/confirm/ConfirmScreen.tsx b/screens/auth/confirm/ConfirmScreen.tsx
index 7e3142e..868f32e 100644
--- a/screens/auth/confirm/ConfirmScreen.tsx
+++ b/screens/auth/confirm/ConfirmScreen.tsx
@@ -43,9 +43,7 @@ const ConfirmScreen = () => {
const storedPhone = await AsyncStorage.getItem('phone');
if (storedPhone) setPhone(storedPhone);
else setPhone(null);
- } catch (error) {
- console.log('AsyncStorage error:', error);
- }
+ } catch (error) { }
};
loadPhone();
}, []);
diff --git a/screens/auth/login/lib/api.ts b/screens/auth/login/lib/api.ts
index 66fda1d..23bc0a3 100644
--- a/screens/auth/login/lib/api.ts
+++ b/screens/auth/login/lib/api.ts
@@ -1,6 +1,6 @@
import httpClient from '@/api/httpClient';
import { API_URLS } from '@/api/URLs';
-import { AxiosResponse } from 'axios';
+import axios, { AxiosResponse } from 'axios';
interface ConfirmBody {
status: boolean;
@@ -13,307 +13,70 @@ interface ConfirmBody {
};
}
-export interface CompanyInfo {
- id: number;
- inn: string;
- registration_authority: string;
- registration_date: string;
- registration_number: string;
- name: string;
- short_name: string;
- opf_code: string;
- opf_name: string;
- oked_code: string;
- vat_number: string;
- oked_name: string;
- area: string;
- region: string;
- soogu_code: string;
- soogu_name: string;
- small_businesses: string;
- activity_state: number;
- statutory_fund: string;
-
- activity_state_detail: ActivityStateDetail;
- business_type_detail: BusinessTypeDetail;
-
- director: string;
- email: string;
- village_code: string;
- email_status: number;
- phones: string[];
-
- soato_code: string;
- soato_name: string;
- address: string;
-
- relevance_date: string;
- court_relevance_date: string | null;
- deal_relevance_date: string | null;
-
- tax_mode: number;
- trust: string;
- score: number;
-
- itpark: number;
- leasing_count_all: number | null;
- leasing_count_not_finish: number | null;
- leasing_sum: number | null;
- leasing_is_delay: number | null;
- leasing_debt: number | null;
- leasing_is_partner: number | null;
- leasing_relevance_date: string | null;
-
- is_bankrupt: number;
- is_abuse_vat: number;
- is_large_taxpayer: number;
-
- vendor_rating: number | null;
- developer_rating: number | null;
-
- dishonest_executor: DishonestExecutor;
- village_detail: VillageDetail;
- company_billing_address: BillingAddress;
-
- actual_date: string;
- kfs: Kfs;
-
- uuid: string;
-
- connections: Connections;
- courts: Courts;
-
- director_uuid: string;
- founders: Founder[];
-
- deals: Deals;
- licenses: Licenses;
-
- leasing_guarantor_pinfl: string | null;
- leasing_guarantor_inn: string | null;
-
- buildings: Buildings;
- cadastres: Cadastres;
-
- liquidation_date: string | null;
- liquidation_reason: string | null;
-
- is_suppliers: number;
-}
-export interface ActivityStateDetail {
- id: number;
- group: string;
- name: string;
- name_en: string;
- name_uz: string;
- name_uz_kir: string;
+export interface GetInfo {
+ VATRegCode: null | string
+ VATRegStatus: null | string
+ account: string
+ accountant: null | string
+ address: string
+ bankAccount: string
+ bankCode: string
+ director: string | null
+ directorPinfl: string | null
+ directorTin: null | string
+ fullName: string
+ fullname: string
+ isBudget: number
+ isItd: boolean
+ mfo: string
+ na1Code: null | string
+ na1Name: null | string
+ name: string
+ ns10Code: number
+ ns11Code: number
+ oked: null | string
+ peasantFarm: boolean
+ personalNum: string
+ privateNotary: boolean
+ regDate: null | string
+ selfEmployment: boolean
+ shortName: string
+ shortname: string
+ statusCode: null | string
+ statusName: null | string
+ tin: string
}
-export interface BusinessTypeDetail {
- id: number;
- external_id: number;
- name: string;
- name_uz: string;
- name_en: string;
+export interface GetDistrict {
+ districtId: string,
+ regionId: number,
+ districtCode: number,
+ name: string
}
-export interface DishonestExecutor {
- is_dishonest_executor: number;
- delete_date: string | null;
+export interface GetRegion {
+ regionId: number,
+ name: string
}
-export interface VillageDetail {
- code: number;
- name: string;
-}
-
-export interface BillingAddress {
- country_code: number;
- region_code: number;
- region_name: string;
- region_name_en: string;
- region_name_uz: string;
-
- district_code: number;
- district_name: string;
- district_name_en: string;
- district_name_uz: string;
-
- sector_code: number;
- street_name: string;
- house: string | null;
- flat: string | null;
- postcode: string;
-}
-
-export interface Kfs {
- code: number;
- name: string;
- name_ru: string;
- name_uz_cyr: string;
- name_uz_lat: string;
-}
-
-export interface Connections {
- director: number;
- founders: number;
- entrepreneur: number;
- all: number;
-}
-
-export interface Courts {
- total: number;
- current: number;
- completed: number;
-}
-
-export interface Founder {
- name: string;
- percentage: number;
- is_individual: number;
- person_type: string;
- id: number | null;
- founder_uuid: string;
-}
-
-export interface Deals {
- customer: DealSide;
- provider: DealSide;
- actual_date: string;
-}
-
-export interface DealSide {
- rows: any[];
- total: number;
- summ: number | null;
-}
-
-export interface Licenses {
- total: number;
- relevance_date: string;
- actual_date: string;
-}
-
-export interface Buildings {
- total: number;
-}
-
-export interface Cadastres {
- total: number;
- relevance_date: string | null;
-}
-export interface GetInfoResponse {
- status: boolean;
- data: CompanyInfo | IndividualInfo;
-}
-
-export interface IndividualInfo {
- uuid: string,
- id: number,
- lastname: string,
- firstname: string,
- middlename: string,
- registered_at: string,
- unregistered_at: null | string,
- activities: {
- code: number,
- name_en: string,
- name_uz: string,
- name_ru: string
- }[]
-
-}
-
-export interface GetDirectorInfoResponse {
+export interface GetTokens {
status: boolean,
data: {
- entity: {
- name: {
- rows: {
- id: number,
- inn: string,
- name: string,
- director: string,
- email: string,
- phones: string[],
- founders: {
- name: string,
- percentage: number,
- is_individual: number,
- person_type: string,
- id: number | null,
- founder_uuid: string
- }[],
- activity_state: number,
- registration_date: string,
- oked_code: string,
- oked_name: string,
- statutory_fund: string,
- address: string,
- variant: null
- }[],
- total: number
- },
- inn: {
- rows: [],
- total: 0
- },
- director: {
- rows: [],
- total: 0
- },
- founder: {
- rows: {
- id: number,
- inn: string,
- name: string,
- director: string,
- email: string,
- phones: string[],
- founders:
- {
- name: string,
- percentage: number,
- is_individual: number,
- person_type: string,
- id: number | null,
- founder_uuid: string
- }[],
- activity_state: number,
- registration_date: string,
- oked_code: string,
- oked_name: string,
- statutory_fund: string,
- address: string,
- variant: null
- }[],
- total: number
- },
- email: {
- rows: [],
- total: number
- },
- phone: {
- rows: [],
- total: number
- }
+ links: {
+ previous: null | string,
+ next: null | string
},
- entrepreneur: {
- rows:
- {
- id: number,
- pinfl: string,
- entrepreneur: string,
- email: string,
- phone: string,
- registration_date: string
- }[],
- total: number
- },
- trademark: {
- rows: [],
- total: number
- }
+ total_items: number,
+ total_pages: number,
+ page_size: number,
+ current_page: number,
+ results:
+ {
+ id: number,
+ key: string,
+ value: string,
+ is_active: boolean
+ }[]
}
}
@@ -332,25 +95,60 @@ export const auth_api = {
return res;
},
- async get_info(body: { value: string, type: string, passport_series?: string, passport_number?: string }): Promise> {
- const res = await httpClient.post(API_URLS.Info, body);
- return res;
+ async get_info(body: { value: string, token: string, tokenName: string }): Promise> {
+ try {
+ const res = await axios.get(`https://testapi3.didox.uz/v1/utils/info/${body.value}`, {
+ headers: {
+ "Accept-Language": "uz",
+ [body.tokenName]: body.token
+ }
+ });
+ return res;
+ } catch (error) {
+ throw error;
+ }
},
- async get_director_info(body: { value: string }): Promise> {
- const res = await httpClient.post(API_URLS.Get_Director_Info, body);
- return res;
+ async get_district(): Promise> {
+ try {
+ const res = await axios.get(`https://testapi3.didox.uz/v1/districts/all/`, {
+ headers: {
+ "Accept-Language": "uz",
+ "Partner-Authorization": `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MzYsInN0YXR1cyI6IkFDVElWRSIsIm5hbWUiOiJcIkZFTElYIC0gSVRTXCIgTUNISiIsInJvbGUiOiJQQVJUTkVSIiwidGluIjoiMzA3NTA0MzQ4IiwiaWF0IjoxNzczMzkyMjcwfQ.Q-cIBl4Z784Fq5jdRUEVYF2iaUd7_5RD2sFsJeh-Xno `
+ }
+ });
+ return res;
+ } catch (error) {
+ throw error;
+ }
+ },
+
+ async get_region(): Promise> {
+ try {
+ const res = await axios.get(`https://testapi3.didox.uz/v1/regions/all/`, {
+ headers: {
+ "Accept-Language": "uz",
+ "Partner-Authorization": `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MzYsInN0YXR1cyI6IkFDVElWRSIsIm5hbWUiOiJcIkZFTElYIC0gSVRTXCIgTUNISiIsInJvbGUiOiJQQVJUTkVSIiwidGluIjoiMzA3NTA0MzQ4IiwiaWF0IjoxNzczMzkyMjcwfQ.Q-cIBl4Z784Fq5jdRUEVYF2iaUd7_5RD2sFsJeh-Xno `
+ }
+ });
+ return res;
+ } catch (error) {
+ throw error;
+ }
},
async register(body: {
phone: string;
stir: string;
person_type: string;
- referal: string;
+ referral: string;
activate_types: number[];
director_full_name: string;
first_name: string;
last_name: string;
+ district: number;
+ address: number;
+ company_name: string;
}) {
const res = await httpClient.post(API_URLS.Register, body);
return res;
@@ -365,4 +163,10 @@ export const auth_api = {
const res = await httpClient.post(API_URLS.Register_Resend, body);
return res;
},
+
+ async get_tokens(): Promise> {
+ const res = httpClient.get(API_URLS.GetTokens)
+ return res
+ },
+
};
diff --git a/screens/auth/login/ui/LoginForm.tsx b/screens/auth/login/ui/LoginForm.tsx
index 1f5e4e8..69e9ebc 100644
--- a/screens/auth/login/ui/LoginForm.tsx
+++ b/screens/auth/login/ui/LoginForm.tsx
@@ -19,7 +19,6 @@ export default function LoginForm() {
const [focused, setFocused] = useState(false);
const scaleAnim = useRef(new Animated.Value(1)).current;
const { phone, setPhone, submit, loading, error } = UseLoginForm();
- console.log(error);
const { t } = useTranslation();
const handleChange = useCallback(
diff --git a/screens/auth/register-confirm/ConfirmScreen.tsx b/screens/auth/register-confirm/ConfirmScreen.tsx
index 97918fd..5862ea9 100644
--- a/screens/auth/register-confirm/ConfirmScreen.tsx
+++ b/screens/auth/register-confirm/ConfirmScreen.tsx
@@ -44,9 +44,7 @@ const RegisterConfirmScreen = () => {
const storedPhone = await AsyncStorage.getItem('phone');
if (storedPhone) setPhone(storedPhone);
else setPhone(null);
- } catch (error) {
- console.log('AsyncStorage error:', error);
- }
+ } catch (error) { }
};
loadPhone();
}, []);
@@ -67,6 +65,7 @@ const RegisterConfirmScreen = () => {
savedToken(res.data.data.token.access);
await AsyncStorage.setItem('refresh_token', res.data.data.token.refresh);
await login(res.data.data.token.access);
+
const pushToken = await registerForPushNotificationsAsync();
if (pushToken) {
await commonRequests.registerDevice({
@@ -78,6 +77,8 @@ const RegisterConfirmScreen = () => {
// Notification querylarni refetch
queryClient.refetchQueries({ queryKey: ['notification-list'] });
queryClient.refetchQueries({ queryKey: ['notifications-list'] });
+
+ // Dashboardga yo‘naltirish
router.replace('/(dashboard)');
},
onError: (err: any) => {
diff --git a/screens/auth/register/RegisterCategorySelection.tsx b/screens/auth/register/RegisterCategorySelection.tsx
index 124668c..a506739 100644
--- a/screens/auth/register/RegisterCategorySelection.tsx
+++ b/screens/auth/register/RegisterCategorySelection.tsx
@@ -9,7 +9,7 @@ import { ScrollView, StyleSheet, Text, TouchableOpacity } from 'react-native';
export default function CategorySelectScreen() {
const router = useRouter();
- const { phone, stir, person_type, director_full_name, referal, first_name, last_name } = useLocalSearchParams<{
+ const { phone, stir, person_type, director_full_name, referal, first_name, last_name, address, company_name } = useLocalSearchParams<{
phone: string;
stir: string;
person_type: 'band' | 'ytt';
@@ -17,10 +17,10 @@ export default function CategorySelectScreen() {
director_full_name: string;
first_name: string;
last_name: string;
+ address: string;
+ company_name: string;
}>();
- console.log(referal);
-
const [selected, setSelected] = React.useState(null);
const { data } = useQuery({
@@ -34,10 +34,13 @@ export default function CategorySelectScreen() {
stir: string;
person_type: string;
activate_types: number[];
- referal: string;
+ referral: string;
director_full_name: string;
first_name: string;
last_name: string;
+ district: number;
+ company_name: string;
+ address: number;
}) => auth_api.register(body),
onSuccess: () => router.replace('/'),
});
@@ -68,10 +71,13 @@ export default function CategorySelectScreen() {
person_type: person_type,
phone: `998${phone}`,
stir: stir,
- referal: String(referal),
+ referral: String(referal),
director_full_name: String(director_full_name),
first_name: String(first_name),
last_name: String(last_name),
+ district: Number(address),
+ company_name: String(company_name),
+ address: Number(address),
});
}
}}
diff --git a/screens/auth/register/RegisterForm.tsx b/screens/auth/register/RegisterForm.tsx
index 47a5415..120cfad 100644
--- a/screens/auth/register/RegisterForm.tsx
+++ b/screens/auth/register/RegisterForm.tsx
@@ -1,27 +1,22 @@
import AuthHeader from '@/components/ui/AuthHeader';
+import { decryptToken } from '@/constants/crypto';
import { formatPhone, normalizeDigits } from '@/constants/formatPhone';
+import { formatText, formatTextToLatin } from '@/constants/formatText';
import { products_api } from '@/screens/home/lib/api';
-import BottomSheet, {
- BottomSheetBackdrop,
- BottomSheetFlatList,
- BottomSheetTextInput,
-} from '@gorhom/bottom-sheet';
+import BottomSheet, { BottomSheetBackdrop, BottomSheetFlatList, BottomSheetTextInput } from '@gorhom/bottom-sheet';
import { useMutation, useQuery } from '@tanstack/react-query';
-import { AxiosError } from 'axios';
import { Image } from 'expo-image';
import { LinearGradient } from 'expo-linear-gradient';
import { useRouter } from 'expo-router';
import {
- Building2,
CheckIcon,
+ ChevronDown,
Globe,
Hash,
Search,
- ShieldCheck,
- User,
- UserPlus,
+ UserPlus
} from 'lucide-react-native';
-import React, { useCallback, useMemo, useRef, useState } from 'react';
+import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import {
ActivityIndicator,
@@ -34,72 +29,78 @@ import {
} from 'react-native';
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view';
import { SafeAreaView } from 'react-native-safe-area-context';
-import { auth_api } from '../login/lib/api';
+import { auth_api, GetInfo } from '../login/lib/api';
import PhonePrefix from '../login/ui/PhonePrefix';
-import { useRegister } from './lib/useRegisterStore';
+import { UseLoginForm } from '../login/ui/UseLoginForm';
-function getHeaderInfo(personType: string | null) {
- switch (personType) {
- case 'yatt':
- return {
- label: 'YATT',
- icon: ,
- gradient: ['#10b981', '#059669'] as [string, string],
- };
- case 'band':
- return {
- label: "O'zini o'zi band qilgan",
- icon: ,
- gradient: ['#3b82f6', '#2563eb'] as [string, string],
- };
- case 'legal_entity':
- return {
- label: 'Yuridik shaxs',
- icon: ,
- gradient: ['#f59e0b', '#d97706'] as [string, string],
- };
- default:
- return {
- label: "Ro'yxatdan o'tish",
- icon: ,
- gradient: ['#10b981', '#059669'] as [string, string],
- };
- }
+interface CoordsData {
+ lat: number;
+ lon: number;
+ polygon: [number, number][][];
}
export default function RegisterFormScreen() {
const router = useRouter();
- const {
- personType,
- phone,
- setPhone,
- referal,
- setReferal,
- jshshr,
- setJshshr,
- passportSeries,
- setPassportSeries,
- passportNumber,
- setPassportNumber,
- inn,
- setInn,
- info,
- setInfo,
- directorInfo,
- setDirectorInfo,
- } = useRegister();
const { t } = useTranslation();
-
- const [loading, setLoading] = React.useState(false);
- const [directorJshshr, setDirectorJshshr] = React.useState('');
- const [directorLoading, setDirectorLoading] = React.useState(false);
- const [directorInfoError, setErrorDirectorInfo] = useState(null);
-
- // Country select
- const [selectedCountry, setSelectedCountry] = useState('UZ');
- const [countrySearch, setCountrySearch] = useState('');
+ const { phone, setPhone } = UseLoginForm();
const countrySheetRef = useRef(null);
const snapPoints = useMemo(() => ['60%', '90%'], []);
+ const [selectedCountry, setSelectedCountry] = useState('UZ');
+ const [countrySearch, setCountrySearch] = useState('');
+
+ const [stir, setStir] = useState('');
+ const [info, setInfo] = useState(null);
+ const [loading, setLoading] = useState(false);
+ const [referal, setReferal] = useState('');
+ const [error, setError] = useState(null)
+ const [district, setDistrict] = useState(null)
+ const [region, setRegion] = useState(null)
+ const [token, setTokens] = useState<{ name: string, value: string } | null>(null)
+
+ const [directorTinInput, setDirectorTinInput] = useState('');
+
+ const { data } = useQuery({
+ queryKey: ["tokens"],
+ queryFn: async () => auth_api.get_tokens(),
+ select(data) {
+ return data.data.data.results
+ },
+ })
+
+ useEffect(() => {
+ if (data?.length) {
+ const token = data[0]
+ const tokenValue = decryptToken(token.value)
+ if (tokenValue) {
+ setTokens({ name: token.key, value: tokenValue })
+ }
+ }
+ }, [data])
+
+ const { mutate } = useMutation({
+ mutationFn: (stir: string) => auth_api.get_info({ value: stir, token: token?.value || "", tokenName: token?.name || "" }),
+ onSuccess: (res) => {
+ setInfo(res.data);
+ setLoading(false);
+ setError(null)
+ setDistrict(res.data.address)
+ },
+ onError: () => {
+ setInfo(null);
+ setLoading(false);
+ setError("Foydalanuvchi topilmadi")
+ },
+ });
+
+ const { data: districts } = useQuery({
+ queryKey: ["discrit"],
+ queryFn: async () => auth_api.get_district(),
+ })
+
+ const { data: regions } = useQuery({
+ queryKey: ["regions"],
+ queryFn: async () => auth_api.get_region(),
+ })
const { data: countryResponse, isLoading: countryLoading } = useQuery({
queryKey: ['country-detail'],
@@ -107,6 +108,111 @@ export default function RegisterFormScreen() {
select: (res) => res.data?.data || [],
});
+ const getRegionDistrictFromAddress = async (address: string) => {
+ try {
+ const encoded = encodeURIComponent(address + ", Uzbekistan");
+ const res = await fetch(
+ `https://nominatim.openstreetmap.org/search?q=${encoded}&format=json&addressdetails=1&limit=1`,
+ { headers: { 'Accept-Language': 'uz', 'User-Agent': 'MyApp/1.0 (turgunboyevsamandar4@gamil.com)' } }
+ );
+ const data = await res.json();
+
+ if (data.length > 0) {
+ const addr = data[0].address;
+ return {
+ district: addr.county || addr.district || addr.suburb,
+ region: addr.state,
+ };
+ }
+ } catch (e) { }
+ return null;
+ };
+
+ useEffect(() => {
+ if (district) {
+ const dis = formatText(district)?.split(" ")[0].toLocaleUpperCase()
+ let reg = null
+ if (dis) {
+ reg = districts?.data.find((item) => item.name.includes(dis))
+ };
+
+ if (reg) {
+ const region = regions?.data.find((item) => item.regionId == reg.regionId)
+ setRegion(region?.name || "")
+ }
+ }
+ }, [district])
+
+
+ const [districtId, setDistrictId] = useState(null);
+ const [regionId, setRegionId] = useState(null);
+
+ useEffect(() => {
+ if (!district || !countryResponse?.length) return;
+
+ const resolve = async () => {
+ const geo = await getRegionDistrictFromAddress(district.split(" ")[0]);
+
+ const searchRegion = geo?.region || region;
+ const searchDistrict = geo?.district || district
+
+ for (const country of countryResponse) {
+ const regionName = formatTextToLatin(searchRegion)?.split(" ")[0];
+ let foundRegion = null
+ if (regionName) {
+ foundRegion = country.region.find((r: any) =>
+ formatTextToLatin(r.name)?.includes(regionName)
+ );
+ }
+
+ if (foundRegion) {
+ setRegionId(foundRegion.id);
+ setDistrictId(null);
+ return;
+ }
+
+ for (const reg of country.region || []) {
+ const dis = formatTextToLatin(searchDistrict)?.split(" ")[0].toUpperCase();
+ let foundDistrict = null
+ if (dis) {
+ foundDistrict = reg.districts.find((d: any) => {
+ return formatTextToLatin(d.name)?.toUpperCase().includes(dis.slice(0, 4))
+ }
+ );
+ };
+
+ if (foundDistrict) {
+ setDistrictId(foundDistrict.id);
+ setRegionId(null);
+ return;
+ }
+ }
+ }
+ };
+ resolve();
+ }, [district, countryResponse]);
+
+ useEffect(() => {
+ if (info === null || (stir.length === 9 && info.name && info.fullName)) {
+ setError(null)
+ } else if (info?.name === null || info?.fullName === null) {
+ setError("Sizning shaxsiy ma'lumotlaringiz topilmadi")
+ } else if (!info?.selfEmployment && !info?.isItd) {
+ setError("Siz o'zini o'zi band qilgan yoki yakka tartibdagi tadbirkorlik bo'lishingiz kerak")
+ }
+ }, [info])
+
+ const hasDirectorTin = info?.directorPinfl && String(info.directorPinfl).length > 0;
+
+ const isDirectorTinValid = !hasDirectorTin || directorTinInput === String(info.directorPinfl);
+ const hasValidName = Boolean(info?.name || info?.fullName);
+
+ const filteredCountries = useMemo(() => {
+ if (!countrySearch.trim()) return countryResponse || [];
+ const q = countrySearch.toLowerCase().trim();
+ return (countryResponse || []).filter((c: any) => c.name?.toLowerCase().includes(q));
+ }, [countryResponse, countrySearch]);
+
const openCountrySheet = useCallback(() => {
Keyboard.dismiss();
setTimeout(() => {
@@ -114,10 +220,13 @@ export default function RegisterFormScreen() {
}, 100);
}, []);
- const closeCountrySheet = useCallback(() => {
- countrySheetRef.current?.close();
- setTimeout(() => setCountrySearch(''), 300);
- }, []);
+ const selectedCountryName = useMemo(() => {
+ if (!selectedCountry) return t('Tanlang');
+ return (
+ countryResponse?.find((c: any) => c.flag?.toUpperCase() === selectedCountry)?.name ||
+ t('Tanlang')
+ );
+ }, [selectedCountry, countryResponse, t]);
const renderBackdrop = useCallback(
(props: any) => (
@@ -132,223 +241,20 @@ export default function RegisterFormScreen() {
[]
);
- const selectedCountryName = useMemo(() => {
- if (!selectedCountry) return t('Tanlang');
- return (
- countryResponse?.find((c: any) => c.flag?.toUpperCase() === selectedCountry)?.name ||
- t('Tanlang')
- );
- }, [selectedCountry, countryResponse, t]);
+ const closeCountrySheet = useCallback(() => {
+ countrySheetRef.current?.close();
+ setTimeout(() => setCountrySearch(''), 300);
+ }, []);
- const filteredCountries = useMemo(() => {
- if (!countrySearch.trim()) return countryResponse || [];
- const q = countrySearch.toLowerCase().trim();
- return (countryResponse || []).filter((c: any) => c.name?.toLowerCase().includes(q));
- }, [countryResponse, countrySearch]);
-
- const headerInfo = getHeaderInfo(personType);
-
- const isYattOrBand = personType === 'yatt' || personType === 'band';
- const isLegal = personType === 'legal_entity';
-
- const { mutate: fetchInfo } = useMutation({
- mutationFn: (body: {
- value: string;
- type: string;
- passport_series?: string;
- passport_number?: string;
- }) => auth_api.get_info(body),
- onSuccess: (res) => {
- setInfo(res.data.data);
- setLoading(false);
- setDirectorJshshr('');
- setDirectorInfo(null);
- setErrorDirectorInfo(null);
- },
- onError: () => {
- setInfo(null);
- setLoading(false);
- setDirectorJshshr('');
- setDirectorInfo(null);
- setErrorDirectorInfo(null);
- },
- });
-
- const { mutate: fetchDirectorInfo } = useMutation({
- mutationFn: (body: { value: string }) => auth_api.get_director_info(body),
- onSuccess: (res) => {
- const directorData = res.data;
- const rows: Array<{ inn: string }> = directorData?.data?.entity?.name?.rows ?? [];
- const innMatch = rows.some((row) => row.inn === inn);
-
- if (!innMatch) {
- setDirectorInfo(null);
- setErrorDirectorInfo(t("Bu direktor ko'rsatilgan tashkilotga tegishli emas"));
- setDirectorLoading(false);
- return;
- }
-
- setDirectorInfo(directorData);
- setDirectorLoading(false);
- setErrorDirectorInfo(null);
- },
- onError: (error: AxiosError) => {
- const err = error.response?.data as {
- status: boolean;
- data: {
- detail: string;
- error: { message: string };
- status_code: number;
- };
- };
- setDirectorInfo(null);
- setErrorDirectorInfo(err?.data?.detail ?? t('Xatolik yuz berdi'));
- setDirectorLoading(false);
- },
- });
-
- const handleJshshrChange = useCallback(
- (text: string) => {
- const v = normalizeDigits(text).slice(0, 14);
- setJshshr(v);
- if (v.length === 14) {
- setLoading(true);
- if (personType) {
- fetchInfo({ value: v, type: personType });
- }
- }
- },
- [setJshshr, fetchInfo, personType]
- );
-
- const handleInnChange = useCallback(
- (text: string) => {
- const v = normalizeDigits(text).slice(0, 9);
- setInn(v);
- if (v.length === 9) {
- setLoading(true);
- if (personType) {
- fetchInfo({ value: v, type: personType });
- }
- }
- },
- [setInn, fetchInfo, personType]
- );
-
- const handlePassportSeriesChange = useCallback(
- (text: string) => {
- const v = text
- .toUpperCase()
- .replace(/[^A-Z]/g, '')
- .slice(0, 2);
- setPassportSeries(v);
- if (personType && passportNumber.length === 7 && jshshr.length === 14) {
- setLoading(true);
- fetchInfo({
- type: personType,
- passport_number: passportNumber,
- passport_series: v,
- value: jshshr,
- });
- }
- },
- [setPassportSeries, passportNumber, jshshr, personType, fetchInfo]
- );
-
- const handlePassportNumberChange = useCallback(
- (text: string) => {
- const v = normalizeDigits(text).slice(0, 7);
- setPassportNumber(v);
- if (personType && passportSeries.length === 2 && jshshr.length === 14) {
- setLoading(true);
- fetchInfo({
- type: personType,
- passport_number: v,
- passport_series: passportSeries,
- value: jshshr,
- });
- }
- },
- [setPassportNumber, passportSeries, jshshr, personType, fetchInfo]
- );
-
- const handleDirectorJshshrChange = useCallback(
- (text: string) => {
- const v = normalizeDigits(text).slice(0, 14);
- setDirectorJshshr(v);
- setDirectorInfo(null);
- setErrorDirectorInfo(null);
- if (v.length === 14) {
- setDirectorLoading(true);
- fetchDirectorInfo({ value: v });
- }
- },
- [fetchDirectorInfo]
- );
-
- const hasValidName = Boolean(info?.name || info?.fullName);
- const hasValidInfo = Boolean(info?.lastname || info?.firstname || info?.middlename);
-
- const isValid = (() => {
- const phoneValid = phone.length === 9;
- const referalValid = referal.length > 0;
- const countryValid = Boolean(selectedCountry && selectedCountry !== 'all');
-
- if (isYattOrBand) {
- return (
- phoneValid &&
- referalValid &&
- countryValid &&
- jshshr.length === 14 &&
- passportSeries.length === 2 &&
- passportNumber.length === 7 &&
- info
- );
- }
-
- if (isLegal) {
- return (
- phoneValid &&
- referalValid &&
- countryValid &&
- inn.length === 9 &&
- info &&
- directorJshshr.length === 14 &&
- directorInfo
- );
- }
-
- return false;
- })();
-
- const handleContinue = () => {
- const directorFullName = isLegal
- ? (directorInfo?.data?.entrepreneur?.rows[0]?.entrepreneur ?? '')
- : `${info?.firstname ?? ''} ${info?.lastname ?? ''} ${info?.middlename ?? ''}`.trim();
-
- const countryObj = countryResponse?.find((c: any) => c.flag?.toUpperCase() === selectedCountry);
-
- router.push({
- pathname: '/(auth)/select-category',
- params: {
- phone,
- stir: isLegal ? inn : jshshr,
- person_type: personType ?? '',
- passport_series: passportSeries,
- passport_number: passportNumber,
- director_full_name: directorFullName,
- referal: referal,
- first_name: info?.firstname ?? '',
- last_name: info?.lastname ?? '',
- middle_name: info?.middlename ?? '',
- country: countryObj?.name ?? '',
- country_id: selectedCountry,
- },
- });
- };
+ const valid =
+ phone.length === 9 &&
+ (stir.length === 9 || stir.length === 14) &&
+ info &&
+ hasValidName &&
+ isDirectorTinValid &&
+ error === null;
return (
- // ✅ Fragment — BottomSheet tashqarida bo'lishi uchun
<>
- {/* ✅ TouchableWithoutFeedback yo'q — onStartShouldSetResponder ishlatildi */}
{
Keyboard.dismiss();
- return false; // false — child elementlar (buttonlar) ham ishlaydi
+ return false;
}}
>
- {/* ✅ SafeAreaView va ichki ScrollView yo'q — to'g'ridan View */}
- {headerInfo.icon}
+
- {t(headerInfo.label)}
-
- {isYattOrBand
- ? t("JSHSHR va passport ma'lumotlarini kiriting")
- : t('INN raqamini kiriting')}
-
+ {t('Ro\'yxatdan o\'tish')}
- {/* ---- YATT / BAND ---- */}
- {isYattOrBand && (
- <>
-
- {t('JSHSHR')}
-
-
-
- {loading && jshshr.length >= 14 && (
-
- )}
-
-
-
-
- {t('Passport seriya va raqami')}
-
-
-
-
-
-
-
-
-
- >
- )}
-
- {/* ---- LEGAL ENTITY: INN ---- */}
- {isLegal && (
+
- {t('INN')}
-
-
-
- {loading && inn.length >= 9 && (
-
+ {t('Davlat')}
+
+ {countryLoading ? (
+
+ ) : (
+ <>
+
+
+ {selectedCountryName}
+
+ >
)}
-
+
+
- )}
+
- {/* ---- LEGAL ENTITY: Kompaniya ma'lumoti ---- */}
- {isLegal &&
- info &&
- (hasValidName ? (
-
- {t('Tashkilot')}
- {info.fullName || info.name}
-
- ) : hasValidInfo ? (
-
- {t('Tashkilot')}
- {info.firstname}
- {info.lastname}
- {info.middlename}
-
- ) : (
-
- {t('Tashkilot topilmadi')}
-
- ))}
+
+ {t('STIR')}
+
+
+ {
+ const v = normalizeDigits(text).slice(0, 14);
+ setStir(v);
- {/* ---- LEGAL ENTITY: Direktor JSHSHR ---- */}
- {isLegal && info && (
-
- {t('Direktor JSHSHR')}
-
-
-
- {directorLoading && directorJshshr.length >= 14 && (
-
- )}
-
-
- {directorInfo && (
-
- {t('Direktor')}
-
- {directorInfo?.data?.entrepreneur?.rows[0]?.entrepreneur}
-
-
- )}
-
- {directorInfoError && (
-
- {directorInfoError}
-
- )}
+ if (v.length === 9 || v.length === 14) {
+ setLoading(true);
+ mutate(v);
+ setRegionId(null)
+ setDistrictId(null)
+ setRegion(null)
+ setDistrict(null)
+ }
+ }}
+ />
+ {loading && }
- )}
+
- {/* ---- Referal ---- */}
{t('Referal')}
@@ -553,7 +380,6 @@ export default function RegisterFormScreen() {
- {/* ---- Telefon ---- */}
{t('Telefon raqami')}
@@ -563,38 +389,62 @@ export default function RegisterFormScreen() {
placeholder="90 123 45 67"
placeholderTextColor="#94a3b8"
keyboardType="phone-pad"
- style={styles.textInput}
- onChangeText={(t) => setPhone(normalizeDigits(t).slice(0, 9))}
- testID="phone-input"
+ style={{ flex: 1 }}
+ onChangeText={(t) => setPhone(normalizeDigits(t))}
/>
- {/* ---- YATT/BAND info ---- */}
- {!isLegal &&
- info &&
- (hasValidName ? (
-
- {info.fullName || info.name}
+ {hasDirectorTin && (
+
+ {t('Direktor STIR')}
+
+
+ setDirectorTinInput(normalizeDigits(t))}
+ />
- ) : hasValidInfo ? (
-
- {info.firstname}
- {info.lastname}
- {info.middlename}
-
- ) : (
-
- {t('Foydalanuvchi topilmadi')}
-
- ))}
- {/* ---- Davom etish tugmasi ---- */}
+ {directorTinInput.length === 14 && !isDirectorTinValid && (
+ {t('Direktor STIR noto‘g‘ri')}
+ )}
+
+ )}
+
+ {error !== null ?
+ {t(error)}
+ : info && hasValidName &&
+ {info.fullName || info.name}
+ }
+
{
+ if (error === null) {
+ router.push({
+ pathname: '/(auth)/select-category',
+ params: {
+ phone,
+ first_name: stir.length === 9 ? info?.director : info?.fullName,
+ last_name: stir.length === 9 ? info?.director : info?.fullName,
+ company_name: info?.name,
+ district: districtId !== null ? districtId : regionId,
+ address: districtId !== null ? districtId : regionId,
+ director_full_name: stir.length === 9 ? info?.director : info?.fullName,
+ stir,
+ referal,
+ person_type: stir.length === 9 ? 'legal_entity' : info?.selfEmployment ? 'band' : info?.isItd ? 'ytt' : 'ytt',
+ },
+ })
+ }
+ }}
>
{t('Davom etish')}
@@ -602,10 +452,9 @@ export default function RegisterFormScreen() {
-
-
+
+
- {/* ✅ BottomSheet KeyboardAwareScrollView TASHQARISIDA */}
-
+
>
);
}
const styles = StyleSheet.create({
- // ✅ KeyboardAwareScrollView uchun style
keyboardScroll: {
flex: 1,
backgroundColor: '#0f172a',
@@ -877,6 +725,7 @@ const styles = StyleSheet.create({
infoBox: {
backgroundColor: '#f0fdf4',
padding: 14,
+ marginTop: 10,
borderRadius: 14,
borderWidth: 1,
borderColor: '#bbf7d0',
@@ -948,4 +797,26 @@ const styles = StyleSheet.create({
backgroundColor: '#f1f5f9',
borderColor: '#e2e8f0',
},
+
+ info: {
+ padding: 12,
+ borderRadius: 12,
+ fontWeight: '700',
+ backgroundColor: '#f0fdf4',
+ },
+ error: {
+ color: '#dc2626',
+ fontSize: 12,
+ marginTop: 4,
+ fontWeight: '600',
+ },
+ notFound: {
+ backgroundColor: '#fef2f2',
+ padding: 12,
+ borderRadius: 12,
+ fontWeight: '700',
+ color: '#dc2626',
+ borderWidth: 1,
+ borderColor: '#fecaca',
+ },
});
\ No newline at end of file
diff --git a/screens/auth/register/lib/useRegisterStore.ts b/screens/auth/register/lib/useRegisterStore.ts
index 3927f30..e326f88 100644
--- a/screens/auth/register/lib/useRegisterStore.ts
+++ b/screens/auth/register/lib/useRegisterStore.ts
@@ -1,6 +1,6 @@
import createContextHook from '@nkzw/create-context-hook';
import { useState } from 'react';
-import { GetDirectorInfoResponse } from '../../login/lib/api';
+import { GetInfo } from '../../login/lib/api';
export type PersonType = 'yatt' | 'band' | 'legal_entity' | null;
@@ -19,14 +19,14 @@ interface RegisterState {
setPassportNumber: (number: string) => void;
inn: string;
setInn: (inn: string) => void;
- info: any;
- setInfo: (info: any) => void;
+ info: GetInfo | null;
+ setInfo: (info: GetInfo | null) => void;
reset_full: () => void;
reset: () => void;
directorJshshr: string;
setDirectorJshshr: (directorJshshr: string) => void;
- directorInfo: GetDirectorInfoResponse | null;
- setDirectorInfo: (directorInfo: GetDirectorInfoResponse | null) => void;
+ directorInfo: GetInfo | null;
+ setDirectorInfo: (directorInfo: GetInfo | null) => void;
}
export const [RegisterProvider, useRegister] = createContextHook(() => {
@@ -37,9 +37,9 @@ export const [RegisterProvider, useRegister] = createContextHook(
const [passportSeries, setPassportSeries] = useState('');
const [passportNumber, setPassportNumber] = useState('');
const [inn, setInn] = useState('');
- const [info, setInfo] = useState(null);
+ const [info, setInfo] = useState(null);
const [directorJshshr, setDirectorJshshr] = useState('');
- const [directorInfo, setDirectorInfo] = useState(null);
+ const [directorInfo, setDirectorInfo] = useState(null);
const reset_full = () => {
setPersonType(null);
diff --git a/screens/home/ui/HomeScreen.tsx b/screens/home/ui/HomeScreen.tsx
index b7a3b27..714fb6e 100644
--- a/screens/home/ui/HomeScreen.tsx
+++ b/screens/home/ui/HomeScreen.tsx
@@ -57,7 +57,6 @@ export default function HomeScreen() {
}
await queryClient.refetchQueries();
} catch (err) {
- console.error('Refresh error:', err);
} finally {
setRefreshing(false);
}
diff --git a/screens/profile/ui/EditServices.tsx b/screens/profile/ui/EditServices.tsx
index e57c0e5..f5d357e 100644
--- a/screens/profile/ui/EditServices.tsx
+++ b/screens/profile/ui/EditServices.tsx
@@ -86,13 +86,11 @@ export default function EditService() {
const { mutate, isPending } = useMutation({
mutationFn: (body: FormData) => user_api.update_service({ body, id: Number(id) }),
onSuccess: (res) => {
- console.log(res);
queryClient.invalidateQueries({ queryKey: ['my_services'] });
queryClient.invalidateQueries({ queryKey: ['service_detail'] });
router.back();
},
onError: (err: any) => {
- console.log(err);
Alert.alert(t('Xatolik yuz berdi'), err?.message || t('Yangilashda xato yuz berdi'));
},
});
diff --git a/screens/profile/ui/RefferallsTab.tsx b/screens/profile/ui/RefferallsTab.tsx
index 64c7df2..2c352f8 100644
--- a/screens/profile/ui/RefferallsTab.tsx
+++ b/screens/profile/ui/RefferallsTab.tsx
@@ -80,7 +80,6 @@ export function ReferralsTab() {
title: t('Referal linkni ulashish'),
});
} catch (err) {
- console.log('Share error:', err);
}
if (Platform.OS === 'android') {