Files
info-target-mobile/app/(auth)/select-category.tsx
2026-02-24 11:28:06 +05:00

279 lines
7.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import AuthHeader from '@/components/ui/AuthHeader';
import { auth_api } from '@/screens/auth/login/lib/api';
import { products_api } from '@/screens/home/lib/api';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { useMutation, useQuery } from '@tanstack/react-query';
import { AxiosError } from 'axios';
import { LinearGradient } from 'expo-linear-gradient';
import { Stack, useLocalSearchParams, useRouter } from 'expo-router';
import { ChevronLeft } from 'lucide-react-native';
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import {
ActivityIndicator,
Alert,
ScrollView,
StyleSheet,
Text,
TouchableOpacity,
View,
} from 'react-native';
interface Category {
id: number;
name: string;
is_leaf: boolean;
}
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<{
phone: string;
stir: string;
person_type: 'band' | 'ytt';
referal: string;
director_full_name: string;
first_name: string;
last_name: string;
middle_name: string;
}>();
const [selected, setSelected] = useState<number | null>(null);
const [categories, setCategories] = useState<Category[]>([]);
const [history, setHistory] = useState<Category[][]>([]);
/** ROOT categories */
const { isLoading } = useQuery({
queryKey: ['categories-root'],
queryFn: () => products_api.getCategorys(),
select: (res) => {
setCategories(res.data.data);
},
});
/** CHILD categories */
const childMutation = useMutation({
mutationFn: (id: number) => products_api.getCategorys({ parent: id }),
onSuccess: (res) => {
setHistory((prev) => [...prev, categories]);
setCategories(res.data.data);
},
});
/** REGISTER */
const registerMutation = useMutation({
mutationFn: (body: {
phone: string;
stir: string;
person_type: string;
activate_types: number[];
director_full_name: string;
referal: string;
first_name: string;
last_name: string;
}) => 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 errrAlert = errMessage ? errMessage : errMessageDetail;
Alert.alert(t('Xatolik yuz berdi'), errMessage || errrAlert || t('erroXatolik yuz berdi'));
},
});
const onCategoryPress = (cat: Category) => {
if (cat.is_leaf) {
setSelected(cat.id);
} else {
childMutation.mutate(cat.id);
}
};
const goBack = () => {
if (history.length === 0) return;
const prev = history[history.length - 1];
setCategories(prev);
setHistory((h) => h.slice(0, -1));
setSelected(null);
};
const full_name = first_name.length > 0 ? first_name + ' ' + last_name + ' ' + middle_name : director_full_name;
return (
<View style={styles.safeArea}>
<AuthHeader />
<Stack.Screen options={{ title: t('Yonalishni tanlang') }} />
<LinearGradient colors={['#0f172a', '#1e293b']} style={StyleSheet.absoluteFill} />
<ScrollView contentContainerStyle={styles.container}>
{history.length > 0 && (
<TouchableOpacity onPress={goBack} style={styles.backBtn}>
<ChevronLeft size={20} color="#3b82f6" />
<Text style={styles.backText}>{t('Orqaga')}</Text>
</TouchableOpacity>
)}
<Text style={styles.title}>{t("Yo'nalishni tanlang")}</Text>
{isLoading || childMutation.isPending ? (
<ActivityIndicator color="#3b82f6" />
) : (
categories.map((c) => {
const active = selected === c.id;
return (
<TouchableOpacity
key={c.id}
style={[styles.item, active && styles.itemActive]}
onPress={() => onCategoryPress(c)}
>
<Text style={[styles.text, active && styles.textActive]}>{c.name}</Text>
</TouchableOpacity>
);
})
)}
</ScrollView>
<TouchableOpacity
disabled={!selected || registerMutation.isPending}
style={[styles.bottom, (!selected || registerMutation.isPending) && styles.bottomDisabled]}
onPress={() => {
if (!selected) return;
registerMutation.mutate({
activate_types: [selected],
person_type,
phone: `998${phone}`,
stir,
referal: referal,
director_full_name: director_full_name,
first_name: full_name,
last_name: last_name,
});
}}
>
<Text style={styles.bottomText} disabled={registerMutation.isPending}>
{t('Tadiqlash')}
</Text>
</TouchableOpacity>
</View>
);
}
const styles = StyleSheet.create({
title: {
fontSize: 18,
fontWeight: '700',
color: '#ffffff',
marginBottom: 12,
},
safeArea: {
flex: 1,
backgroundColor: '#0f172a',
},
container: {
paddingHorizontal: 20,
paddingTop: 16,
paddingBottom: 70,
gap: 12,
},
backBtn: {
flexDirection: 'row',
alignItems: 'center',
gap: 6,
marginBottom: 12,
},
backText: {
fontSize: 14,
color: '#3b82f6',
fontWeight: '600',
},
item: {
paddingVertical: 18,
paddingHorizontal: 18,
borderRadius: 16,
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
backgroundColor: 'rgba(255,255,255,0.06)',
borderWidth: 1,
borderColor: 'rgba(255,255,255,0.12)',
},
itemActive: {
backgroundColor: 'rgba(59,130,246,0.15)',
borderColor: 'rgba(59,130,246,0.6)',
},
text: {
fontSize: 15,
fontWeight: '600',
color: '#cbd5f5',
},
textActive: {
color: '#ffffff',
fontWeight: '800',
},
arrow: {
fontSize: 18,
color: '#94a3b8',
},
bottom: {
position: 'absolute',
bottom: 20,
left: 16,
right: 16,
height: 54,
borderRadius: 16,
backgroundColor: '#3b82f6',
alignItems: 'center',
justifyContent: 'center',
shadowColor: '#3b82f6',
shadowOffset: { width: 0, height: 8 },
shadowOpacity: 0.35,
shadowRadius: 12,
elevation: 10,
},
bottomDisabled: {
backgroundColor: '#64748b',
},
bottomText: {
color: '#ffffff',
fontWeight: '800',
fontSize: 16,
},
decorCircle1: {
position: 'absolute',
top: -120,
right: -80,
width: 300,
height: 300,
borderRadius: 150,
backgroundColor: 'rgba(59,130,246,0.12)',
},
decorCircle2: {
position: 'absolute',
bottom: -120,
left: -100,
width: 280,
height: 280,
borderRadius: 140,
backgroundColor: 'rgba(16,185,129,0.1)',
},
});