Files
info-target-mobile/screens/create-ads/ui/StepThree.tsx
Samandar Turgunboyev d747c72c8d complated
2026-02-17 10:46:57 +05:00

365 lines
11 KiB
TypeScript

import { useTheme } from '@/components/ThemeContext';
import { products_api } from '@/screens/home/lib/api';
import { useQuery } from '@tanstack/react-query';
import React, { forwardRef, useEffect, useImperativeHandle, useState } from 'react';
import { useTranslation } from 'react-i18next';
import {
Dimensions,
FlatList,
ListRenderItemInfo,
ScrollView,
StyleSheet,
Text,
TouchableOpacity,
View,
} from 'react-native';
import { PriceCalculationRes } from '../lib/types';
import CategorySelectorBottomSheet from './CategorySelectorBottomSheet';
type StepProps = {
formData: any;
data: PriceCalculationRes | undefined;
updateForm: (key: string, value: any) => void;
};
const SCREEN_WIDTH = Dimensions.get('window').width;
const GAP = 8;
const NUM_COLUMNS = 6;
const ITEM_SIZE = (SCREEN_WIDTH - GAP * (NUM_COLUMNS + 1)) / NUM_COLUMNS;
const StepThree = forwardRef(({ formData, updateForm, data }: StepProps, ref) => {
const { isDark } = useTheme();
const { t } = useTranslation();
const theme = {
background: isDark ? '#0f172a' : '#ffffff',
cardBg: isDark ? '#1e293b' : '#f8fafc',
cardBorder: isDark ? '#334155' : '#e2e8f0',
text: isDark ? '#f8fafc' : '#0f172a',
textSecondary: isDark ? '#cbd5e1' : '#64748b',
primary: '#2563eb',
error: '#ef4444',
priceText: isDark ? '#dc2626' : '#ef4444',
companyBg: isDark ? '#1e293b' : '#f1f5f9',
companyBorder: isDark ? '#334155' : '#cbd5e1',
};
const { data: statesData } = useQuery({
queryKey: ['country-detail'],
queryFn: async () => products_api.getStates(),
select: (res) => res.data.data || [],
});
const [showCountry, setShowCountry] = useState(false);
const [showRegion, setShowRegion] = useState(false);
const [showDistrict, setShowDistrict] = useState(false);
const [regions, setRegions] = useState<any[]>([]);
const [districts, setDistricts] = useState<any[]>([]);
const [error, setError] = useState<string | null>(null);
const corporations = Array.from({ length: 26 }).map((_, i) => ({
id: i + 1,
latter: String.fromCharCode(65 + i),
}));
const onCompanyPress = (item: { id: number; latter: string }) => {
const selected = formData.company || [];
const exists = selected.some((c: any) => c.id === item.id);
if (exists) {
updateForm(
'company',
selected.filter((c: any) => c.id !== item.id)
);
} else {
updateForm('company', [...selected, item]);
}
};
const toggleSelectAllCompanies = () => {
const selected = formData.company || [];
if (selected.length === corporations.length) {
// Deselect all
updateForm('company', []);
} else {
// Select all
updateForm('company', corporations);
}
};
useEffect(() => {
const country = statesData?.find((c) => c.code === formData.country);
setRegions(country?.region || []);
if (!country?.region.some((r) => r.code === formData.region)) {
updateForm('region', '');
updateForm('district', '');
setDistricts([]);
}
}, [formData.country, statesData]);
useEffect(() => {
const country = statesData?.find((c) => c.code === formData.country);
const region = country?.region.find((r) => r.code === formData.region);
setDistricts(region?.districts || []);
// If region is 'all', automatically set district to 'all'
if (formData.region === 'all') {
updateForm('district', 'all');
} else if (!region?.districts.some((d) => d.code === formData.district)) {
updateForm('district', '');
}
}, [formData.region, formData.country, statesData]);
const getLabel = (arr: { name: string; code: string }[], val: string) => {
if (val === 'all') return t('Hammasi');
return arr.find((item) => item.code === val)?.name || t('— Tanlang —');
};
const renderCompanyItem = ({ item }: ListRenderItemInfo<{ id: number; latter: string }>) => {
const isSelected = formData.company?.some((c: any) => c.id === item.id);
return (
<TouchableOpacity
style={[
styles.companyItem,
{
backgroundColor: isSelected ? theme.primary : theme.companyBg,
borderColor: isSelected ? theme.primary : theme.companyBorder,
},
]}
onPress={() => onCompanyPress(item)}
>
<Text
style={[
styles.companyText,
{ color: isSelected ? '#fff' : theme.text },
isSelected && styles.companyTextActive,
]}
>
{item.latter}
</Text>
</TouchableOpacity>
);
};
const validate = () => {
if (!formData.country) {
setError('Iltimos, davlat tanlang');
return false;
}
if (!formData.region) {
setError('Iltimos, viloyat tanlang');
return false;
}
if (!formData.district) {
setError('Iltimos, tuman/shahar tanlang');
return false;
}
setError(null);
return true;
};
useImperativeHandle(ref, () => ({
validate,
}));
return (
<ScrollView
contentContainerStyle={[styles.container, { backgroundColor: theme.background }]}
showsVerticalScrollIndicator={false}
>
{error && <Text style={[styles.error, { color: theme.error }]}>{t(error)}</Text>}
<Text style={[styles.label, { color: theme.text }]}>{t('Davlat')}</Text>
<TouchableOpacity
style={[
styles.pickerButton,
{
backgroundColor: theme.cardBg,
borderColor: theme.cardBorder,
flexDirection: 'row',
alignItems: 'center',
gap: 10,
},
]}
onPress={() => setShowCountry(true)}
>
<Text style={[styles.pickerText, { color: theme.text }]}>
{statesData &&
getLabel(
statesData.map((c) => ({ name: c.name, code: c.code })),
formData.country
)}
</Text>
</TouchableOpacity>
<Text style={[styles.label, { color: theme.text }]}>{t('Viloyat')}</Text>
<TouchableOpacity
style={[
styles.pickerButton,
{ backgroundColor: theme.cardBg, borderColor: theme.cardBorder },
]}
onPress={() => setShowRegion(true)}
>
<Text style={[styles.pickerText, { color: theme.text }]}>
{getLabel(
regions.map((r) => ({ name: r.name, code: r.code })),
formData.region
)}
</Text>
</TouchableOpacity>
<Text style={[styles.label, { color: theme.text }]}>{t('Tuman / Shahar')}</Text>
<TouchableOpacity
style={[
styles.pickerButton,
{
backgroundColor: theme.cardBg,
borderColor: theme.cardBorder,
opacity: formData.region === 'all' ? 0.5 : 1,
},
]}
onPress={() => {
if (formData.region !== 'all') {
setShowDistrict(true);
}
}}
disabled={formData.region === 'all'}
>
<Text style={[styles.pickerText, { color: theme.text }]}>
{getLabel(
districts.map((d) => ({ name: d.name, code: d.code })),
formData.district
)}
</Text>
</TouchableOpacity>
<View style={{ flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' }}>
<Text style={[styles.sectionTitle, { color: theme.text }]}>
{t('Reklama joylashtirish kompaniyasi')}
</Text>
<TouchableOpacity
style={[
styles.selectAllButton,
{
backgroundColor:
formData.company?.length === corporations.length ? theme.primary : theme.cardBg,
borderColor: theme.primary,
},
]}
onPress={toggleSelectAllCompanies}
>
<Text
style={[
styles.selectAllText,
{
color:
formData.company?.length === corporations.length ? '#fff' : theme.primary,
},
]}
>
{formData.company?.length === corporations.length ? t('Bekor qilish') : t('Hammasi')}
</Text>
</TouchableOpacity>
</View>
<FlatList
data={corporations}
renderItem={renderCompanyItem}
keyExtractor={(item) => item.id.toString()}
numColumns={6}
columnWrapperStyle={{ gap: 2, marginBottom: GAP, justifyContent: 'flex-start' }}
scrollEnabled={false}
/>
<View
style={[styles.priceCard, { backgroundColor: theme.cardBg, borderColor: theme.cardBorder }]}
>
<Text style={[styles.priceLine, { color: theme.text }]}>
{t('Jami kampaniyalar soni')}: {data ? data.user_count : '0'}
</Text>
<Text style={[styles.priceLine, { color: theme.text }]}>
{t('Reklama narxi')}: {data ? data.one_person_price : '0'}
</Text>
<Text style={[styles.totalPrice, { color: theme.priceText }]}>
{t('Umumiy narx')}: {data ? data.total_price : '0'}
</Text>
</View>
<CategorySelectorBottomSheet
isOpen={showCountry}
onClose={() => setShowCountry(false)}
selectedValue={formData.country}
data={
statesData ? statesData.map((c) => ({ label: c.name, value: c.code, flag: c.flag })) : []
}
onSelect={(v) => updateForm('country', v)}
/>
<CategorySelectorBottomSheet
isOpen={showRegion}
onClose={() => setShowRegion(false)}
selectedValue={formData.region}
data={[
{ label: t('Hammasi'), value: 'all' },
...regions.map((r) => ({ label: r.name, value: r.code })),
]}
onSelect={(v) => updateForm('region', v)}
/>
<CategorySelectorBottomSheet
isOpen={showDistrict}
onClose={() => setShowDistrict(false)}
selectedValue={formData.district}
data={[
{ label: t('Hammasi'), value: 'all' },
...districts.map((d) => ({ label: d.name, value: d.code })),
]}
onSelect={(v) => updateForm('district', v)}
/>
</ScrollView>
);
});
export default StepThree;
const styles = StyleSheet.create({
container: { flexGrow: 1 },
label: { fontSize: 14, fontWeight: '700', marginBottom: 6, marginTop: 10 },
pickerButton: {
borderWidth: 1,
borderRadius: 12,
padding: 16,
marginBottom: 12,
},
pickerText: { fontSize: 16 },
sectionTitle: { fontSize: 16, fontWeight: '700', marginVertical: 12 },
companyItem: {
width: 55,
height: 55,
borderRadius: ITEM_SIZE / 2,
borderWidth: 1,
alignItems: 'center',
justifyContent: 'center',
},
companyText: { fontSize: 14 },
companyTextActive: { fontWeight: '600' },
priceCard: {
marginTop: 24,
padding: 20,
borderRadius: 16,
borderWidth: 1,
gap: 8,
},
priceLine: { fontSize: 15 },
totalPrice: { fontSize: 18, fontWeight: '700', marginTop: 6 },
error: { fontWeight: '600', marginBottom: 10 },
selectAllButton: {
paddingHorizontal: 16,
paddingVertical: 8,
borderRadius: 8,
borderWidth: 1,
},
selectAllText: {
fontSize: 14,
fontWeight: '600',
},
});