government ui complated
This commit is contained in:
@@ -1,190 +1,395 @@
|
||||
import { useTheme } from '@/components/ThemeContext';
|
||||
import { ResizeMode, Video } from 'expo-av';
|
||||
import { useRouter } from 'expo-router';
|
||||
import { ArrowLeft } from 'lucide-react-native';
|
||||
import React, { useState } from 'react';
|
||||
import { router } from 'expo-router';
|
||||
import { VideoView, useVideoPlayer } from 'expo-video';
|
||||
import { ArrowLeft, Check, ChevronDown, X } from 'lucide-react-native';
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
Dimensions,
|
||||
FlatList,
|
||||
Image,
|
||||
Pressable,
|
||||
ScrollView,
|
||||
StyleSheet,
|
||||
Text,
|
||||
TouchableOpacity,
|
||||
View,
|
||||
} from 'react-native';
|
||||
import ImageViewer from 'react-native-image-zoom-viewer';
|
||||
import Modal from 'react-native-modal';
|
||||
|
||||
const { width } = Dimensions.get('window');
|
||||
|
||||
type ManualStep = {
|
||||
title: string;
|
||||
text: string;
|
||||
image?: any;
|
||||
image: any;
|
||||
description?: string;
|
||||
};
|
||||
|
||||
type Language = {
|
||||
code: 'uz' | 'ru' | 'en';
|
||||
label: string;
|
||||
flag: string;
|
||||
};
|
||||
|
||||
const languages: Language[] = [
|
||||
{ code: 'uz', label: "O'zbekcha", flag: '🇺🇿' },
|
||||
{ code: 'ru', label: 'Русский', flag: '🇷🇺' },
|
||||
{ code: 'en', label: 'English', flag: '🇬🇧' },
|
||||
];
|
||||
|
||||
export function ManualTab() {
|
||||
const { isDark } = useTheme();
|
||||
const { t } = useTranslation();
|
||||
const router = useRouter();
|
||||
const [videoLang, setVideoLang] = useState<'uz' | 'ru' | 'en'>('uz');
|
||||
const { t, i18n } = useTranslation();
|
||||
|
||||
/** 🔹 Modal states */
|
||||
const [imageVisible, setImageVisible] = useState(false);
|
||||
const [imageIndex, setImageIndex] = useState(0);
|
||||
const [langPickerVisible, setLangPickerVisible] = useState(false);
|
||||
|
||||
/** 🔹 Video tili (SELECT uchun) */
|
||||
const userLang = i18n.language.startsWith('ru')
|
||||
? 'ru'
|
||||
: i18n.language.startsWith('en')
|
||||
? 'en'
|
||||
: 'uz';
|
||||
|
||||
const [selectedLang, setSelectedLang] = useState<'uz' | 'ru' | 'en'>(userLang);
|
||||
|
||||
/** 🔹 RASM tili (faqat app tili bo‘yicha) */
|
||||
const imageLang: 'uz' | 'ru' | 'en' = userLang;
|
||||
|
||||
/** 🔹 Theme */
|
||||
const theme = {
|
||||
background: isDark ? '#0f172a' : '#f8fafc',
|
||||
cardBg: isDark ? '#1e293b' : '#ffffff',
|
||||
text: isDark ? '#ffffff' : '#0f172a',
|
||||
textSecondary: isDark ? '#94a3b8' : '#64748b',
|
||||
primary: '#3b82f6',
|
||||
textMuted: isDark ? '#94a3b8' : '#64748b',
|
||||
border: isDark ? '#334155' : '#e2e8f0',
|
||||
};
|
||||
|
||||
const steps: ManualStep[] = [
|
||||
{
|
||||
title: "Foydalanish qo'lanmasi",
|
||||
text: "Foydalanish qo'lanmasi",
|
||||
image: require('@/assets/manual/step1.jpg'),
|
||||
},
|
||||
{
|
||||
title: "Ro'yxatdan o'tish (Registratsiya) – 1 daqiqa ichida",
|
||||
text: "Platformaga kirish uchun avval ro'yxatdan o'ting.",
|
||||
image: require('@/assets/manual/step2.jpg'),
|
||||
},
|
||||
{
|
||||
title: "Profilni to'ldirish va tasdiqlash",
|
||||
text: "Muhim: Ro'yxatdan o'tgandan keyin profil to'liq bo'lishi kerak — aks holda platforma cheklangan rejimda ishlaydi.",
|
||||
image: require('@/assets/manual/step3.jpg'),
|
||||
},
|
||||
{
|
||||
title: "Xodimlarni qo'shish",
|
||||
text: "Profil ichida Xodimlar bo'limiga o'ting va + tugmasi orqali xodim qo'shing.",
|
||||
image: require('@/assets/manual/step4.jpg'),
|
||||
},
|
||||
{
|
||||
title: "E'lon berish va o'z mahsulot/xizmatlaringizni ko'rsatish",
|
||||
text: "Pastki menyudan E'lonlar bo'limiga o'ting va yangi e'lon yarating.",
|
||||
image: require('@/assets/manual/step5.jpg'),
|
||||
},
|
||||
{
|
||||
title: 'Mijozlarni qidirish va topish',
|
||||
text: 'Filtrdan foydalanib kerakli kompaniyalarni toping va profiliga kirib xabar yuboring.',
|
||||
image: require('@/assets/manual/step6.jpg'),
|
||||
},
|
||||
{
|
||||
title: 'Muhim maslahatlar va xavfsizlik',
|
||||
text: 'Faqat tasdiqlangan profillarga ishonch bilan murojaat qiling.',
|
||||
image: require('@/assets/manual/step7.jpg'),
|
||||
},
|
||||
];
|
||||
|
||||
const videos: Record<'uz' | 'ru' | 'en', any> = {
|
||||
/** 🔹 Video manbalari (SELECT ga bog‘liq) */
|
||||
const videos = {
|
||||
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 handleVideoChange = (lang: 'uz' | 'ru' | 'en') => {
|
||||
setVideoLang(lang);
|
||||
};
|
||||
const player = useVideoPlayer(videos[selectedLang], (player) => {
|
||||
player.loop = false;
|
||||
});
|
||||
/** 🔹 Rasmlar (FAqat imageLang) */
|
||||
const steps: ManualStep[] = [
|
||||
{
|
||||
image:
|
||||
imageLang === 'uz'
|
||||
? require('@/assets/manual/image_uz/step1.jpg')
|
||||
: imageLang === 'ru'
|
||||
? require('@/assets/manual/image_ru/step1.jpg')
|
||||
: require('@/assets/manual/image_en/step1.jpg'),
|
||||
description: t("Ilovani oching va ro'yxatdan o'ting"),
|
||||
},
|
||||
{
|
||||
image:
|
||||
imageLang === 'uz'
|
||||
? require('@/assets/manual/image_uz/step2.jpg')
|
||||
: imageLang === 'ru'
|
||||
? require('@/assets/manual/image_ru/step2.jpg')
|
||||
: require('@/assets/manual/image_en/step2.jpg'),
|
||||
description: t("Profilni to'ldiring"),
|
||||
},
|
||||
{
|
||||
image:
|
||||
imageLang === 'uz'
|
||||
? require('@/assets/manual/image_uz/step3.jpg')
|
||||
: imageLang === 'ru'
|
||||
? require('@/assets/manual/image_ru/step3.jpg')
|
||||
: require('@/assets/manual/image_en/step3.jpg'),
|
||||
description: t("To'lov usulini qo'shing"),
|
||||
},
|
||||
{
|
||||
image:
|
||||
imageLang === 'uz'
|
||||
? require('@/assets/manual/image_uz/step4.jpg')
|
||||
: imageLang === 'ru'
|
||||
? require('@/assets/manual/image_ru/step4.jpg')
|
||||
: require('@/assets/manual/image_en/step4.jpg'),
|
||||
description: t('Xaridni tanlang'),
|
||||
},
|
||||
{
|
||||
image:
|
||||
imageLang === 'uz'
|
||||
? require('@/assets/manual/image_uz/step5.jpg')
|
||||
: imageLang === 'ru'
|
||||
? require('@/assets/manual/image_ru/step5.jpg')
|
||||
: require('@/assets/manual/image_en/step5.jpg'),
|
||||
description: t("To'lovni amalga oshiring"),
|
||||
},
|
||||
{
|
||||
image:
|
||||
imageLang === 'uz'
|
||||
? require('@/assets/manual/image_uz/step6.jpg')
|
||||
: imageLang === 'ru'
|
||||
? require('@/assets/manual/image_ru/step6.jpg')
|
||||
: require('@/assets/manual/image_en/step6.jpg'),
|
||||
description: t("Natijani ko'ring"),
|
||||
},
|
||||
{
|
||||
image:
|
||||
imageLang === 'uz'
|
||||
? require('@/assets/manual/image_uz/step7.jpg')
|
||||
: imageLang === 'ru'
|
||||
? require('@/assets/manual/image_ru/step7.jpg')
|
||||
: require('@/assets/manual/image_en/step7.jpg'),
|
||||
description: t("Natijani ko'ring"),
|
||||
},
|
||||
{
|
||||
image:
|
||||
imageLang === 'uz'
|
||||
? require('@/assets/manual/image_uz/step8.jpg')
|
||||
: imageLang === 'ru'
|
||||
? require('@/assets/manual/image_ru/step8.jpg')
|
||||
: require('@/assets/manual/image_en/step8.jpg'),
|
||||
description: t("Natijani ko'ring"),
|
||||
},
|
||||
];
|
||||
|
||||
/** 🔹 Image viewer */
|
||||
const images = useMemo(
|
||||
() => steps.map((step) => ({ url: '', props: { source: step.image } })),
|
||||
[imageLang]
|
||||
);
|
||||
|
||||
const selectedLanguage = languages.find((l) => l.code === selectedLang);
|
||||
|
||||
const renderStep = ({ item, index }: { item: ManualStep; index: number }) => (
|
||||
<Pressable
|
||||
onPress={() => {
|
||||
setImageIndex(index);
|
||||
setImageVisible(true);
|
||||
}}
|
||||
>
|
||||
<View style={[styles.stepCard, { backgroundColor: theme.cardBg }]}>
|
||||
<Image source={item.image} style={styles.stepImage} />
|
||||
</View>
|
||||
</Pressable>
|
||||
);
|
||||
|
||||
return (
|
||||
<ScrollView style={[styles.container, { backgroundColor: theme.background }]}>
|
||||
<View style={[styles.header, { backgroundColor: isDark ? '#0f172a' : '#fff' }]}>
|
||||
<Pressable onPress={() => router.push('/profile')}>
|
||||
<ArrowLeft color={isDark ? '#fff' : '#0f172a'} />
|
||||
</Pressable>
|
||||
{/* HEADER */}
|
||||
<View style={styles.hero}>
|
||||
<View style={styles.topHeader}>
|
||||
<Pressable onPress={() => router.back()}>
|
||||
<ArrowLeft color={theme.text} size={24} />
|
||||
</Pressable>
|
||||
<Text style={[styles.headerTitle, { color: theme.text }]}>
|
||||
{t("Foydalanish qo'llanmasi")}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<Text style={[styles.headerTitle, { color: isDark ? '#fff' : '#0f172a' }]}>
|
||||
{t("Foydalanish qo'lanmasi")}
|
||||
<Text style={[styles.subtitle, { color: theme.textMuted }]}>
|
||||
{t("Quyidagi qisqa video yoki rasmlarni ko'rib chiqing")}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
{steps.map((step, index) => (
|
||||
<View key={index} style={[styles.card, { backgroundColor: theme.cardBg }]}>
|
||||
<Text style={[styles.headerTitle, { color: theme.text }]}>{t(step.title)}</Text>
|
||||
<Text style={[styles.text, { color: theme.textSecondary, marginTop: 8 }]}>
|
||||
{t(step.text)}
|
||||
</Text>
|
||||
{step.image && <Image source={step.image} style={styles.image} resizeMode="contain" />}
|
||||
</View>
|
||||
))}
|
||||
|
||||
{/* Video bo'limi */}
|
||||
<View style={[styles.card, { backgroundColor: theme.cardBg }]}>
|
||||
<Text style={[styles.headerTitle, { color: theme.text }]}>{t("Qo'llanma video")}</Text>
|
||||
|
||||
{/* Til tanlash tugmalari */}
|
||||
<View style={styles.buttonRow}>
|
||||
<TouchableOpacity
|
||||
{/* VIDEO */}
|
||||
<View style={styles.section}>
|
||||
<Text style={[styles.sectionTitle, { color: theme.text }]}>
|
||||
{t("Foydalanish video qo'llanma")}
|
||||
</Text>
|
||||
<View style={{ alignContent: 'flex-end', alignItems: 'flex-end', paddingHorizontal: 16 }}>
|
||||
<Pressable
|
||||
style={[
|
||||
styles.langButton,
|
||||
{
|
||||
backgroundColor: videoLang === 'uz' ? theme.primary : theme.cardBg,
|
||||
borderColor: theme.primary,
|
||||
},
|
||||
styles.langSelector,
|
||||
{ backgroundColor: theme.cardBg, borderColor: theme.border },
|
||||
]}
|
||||
onPress={() => handleVideoChange('uz')}
|
||||
onPress={() => setLangPickerVisible(true)}
|
||||
>
|
||||
<Text style={{ color: videoLang === 'uz' ? '#fff' : theme.text }}>O'zbek</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.langButton,
|
||||
{
|
||||
backgroundColor: videoLang === 'ru' ? theme.primary : theme.cardBg,
|
||||
borderColor: theme.primary,
|
||||
},
|
||||
]}
|
||||
onPress={() => handleVideoChange('ru')}
|
||||
>
|
||||
<Text style={{ color: videoLang === 'ru' ? '#fff' : theme.text }}>Русский</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.langButton,
|
||||
{
|
||||
backgroundColor: videoLang === 'en' ? theme.primary : theme.cardBg,
|
||||
borderColor: theme.primary,
|
||||
},
|
||||
]}
|
||||
onPress={() => handleVideoChange('en')}
|
||||
>
|
||||
<Text style={{ color: videoLang === 'en' ? '#fff' : theme.text }}>English</Text>
|
||||
</TouchableOpacity>
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
||||
<Text style={{ fontSize: 20 }}>{selectedLanguage?.flag}</Text>
|
||||
</View>
|
||||
<ChevronDown color={theme.textMuted} />
|
||||
</Pressable>
|
||||
</View>
|
||||
|
||||
<Video
|
||||
source={videos[videoLang]}
|
||||
style={styles.video}
|
||||
useNativeControls
|
||||
isLooping
|
||||
resizeMode={ResizeMode.COVER}
|
||||
<View style={[styles.videoCard, { backgroundColor: theme.cardBg }]}>
|
||||
<VideoView
|
||||
player={player}
|
||||
style={styles.video}
|
||||
allowsFullscreen
|
||||
allowsPictureInPicture
|
||||
contentFit="cover"
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* RASMLAR */}
|
||||
<View style={styles.section}>
|
||||
<Text style={[styles.sectionTitle, { color: theme.text }]}>
|
||||
{t('Foydalanish rasm qo‘llanma')}
|
||||
</Text>
|
||||
|
||||
<FlatList
|
||||
horizontal
|
||||
data={steps}
|
||||
renderItem={renderStep}
|
||||
showsHorizontalScrollIndicator={false}
|
||||
contentContainerStyle={{ paddingHorizontal: 16, gap: 20 }}
|
||||
/>
|
||||
</View>
|
||||
|
||||
{/* IMAGE MODAL */}
|
||||
<Modal isVisible={imageVisible} style={{ margin: 0 }}>
|
||||
<ImageViewer
|
||||
imageUrls={images}
|
||||
index={imageIndex}
|
||||
enableSwipeDown
|
||||
onSwipeDown={() => setImageVisible(false)}
|
||||
renderHeader={() => (
|
||||
<Pressable style={styles.closeButton} onPress={() => setImageVisible(false)}>
|
||||
<X size={32} color="#fff" />
|
||||
</Pressable>
|
||||
)}
|
||||
/>
|
||||
</Modal>
|
||||
|
||||
{/* LANGUAGE MODAL */}
|
||||
<Modal isVisible={langPickerVisible} onBackdropPress={() => setLangPickerVisible(false)}>
|
||||
<View style={[styles.langModalContent, { backgroundColor: theme.cardBg }]}>
|
||||
<Text style={{ color: 'white', marginBottom: 10, fontSize: 18 }}>
|
||||
{t('Video tilini tanlang')}
|
||||
</Text>
|
||||
{languages.map((lang) => {
|
||||
const isSelected = selectedLang === lang.code;
|
||||
|
||||
return (
|
||||
<Pressable
|
||||
key={lang.code}
|
||||
onPress={() => {
|
||||
setSelectedLang(lang.code);
|
||||
setLangPickerVisible(false);
|
||||
}}
|
||||
style={[
|
||||
styles.langOption,
|
||||
{
|
||||
borderColor: isSelected ? theme.primary : theme.border,
|
||||
backgroundColor: isSelected ? theme.primary + '15' : 'transparent',
|
||||
},
|
||||
]}
|
||||
>
|
||||
<View style={styles.langOptionLeft}>
|
||||
<Text style={{ fontSize: 26 }}>{lang.flag}</Text>
|
||||
<Text
|
||||
style={{
|
||||
color: isSelected ? theme.primary : theme.text,
|
||||
fontWeight: isSelected ? '700' : '500',
|
||||
fontSize: 16,
|
||||
}}
|
||||
>
|
||||
{lang.label}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
{isSelected && (
|
||||
<View style={[styles.checkmark, { backgroundColor: theme.primary }]}>
|
||||
<Check size={20} color={'white'} />
|
||||
</View>
|
||||
)}
|
||||
</Pressable>
|
||||
);
|
||||
})}
|
||||
</View>
|
||||
</Modal>
|
||||
</ScrollView>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: { flex: 1, padding: 16 },
|
||||
card: { borderRadius: 16, padding: 16, marginBottom: 16 },
|
||||
headerTitle: { fontSize: 18, fontWeight: '700', lineHeight: 24 },
|
||||
text: { fontSize: 14, lineHeight: 20 },
|
||||
image: { width: width - 64, height: 200, marginTop: 12, borderRadius: 12 },
|
||||
video: { width: width - 64, height: 320, marginTop: 12, borderRadius: 12 },
|
||||
buttonRow: { flexDirection: 'row', justifyContent: 'space-around', marginVertical: 12 },
|
||||
langButton: {
|
||||
paddingVertical: 8,
|
||||
paddingHorizontal: 16,
|
||||
borderRadius: 8,
|
||||
borderWidth: 1,
|
||||
container: { flex: 1 },
|
||||
hero: { padding: 20 },
|
||||
topHeader: { flexDirection: 'row', alignItems: 'center', gap: 12 },
|
||||
headerTitle: { fontSize: 22, fontWeight: '700' },
|
||||
subtitle: { marginTop: 8 },
|
||||
|
||||
section: { marginBottom: 28 },
|
||||
sectionTitle: { fontSize: 20, fontWeight: '700', marginLeft: 16 },
|
||||
|
||||
langSelector: {
|
||||
margin: 5,
|
||||
width: 80,
|
||||
gap: 5,
|
||||
paddingVertical: 5,
|
||||
borderRadius: 14,
|
||||
borderWidth: 1.5,
|
||||
alignContent: 'center',
|
||||
alignItems: 'center',
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
header: {
|
||||
padding: 16,
|
||||
|
||||
videoCard: {
|
||||
marginHorizontal: 16,
|
||||
borderRadius: 20,
|
||||
overflow: 'hidden',
|
||||
position: 'relative',
|
||||
},
|
||||
video: { width: '100%', aspectRatio: 9 / 13 },
|
||||
|
||||
stepCard: { borderRadius: 16, overflow: 'hidden' },
|
||||
stepImage: { width: 300, height: 300 },
|
||||
|
||||
closeButton: {
|
||||
position: 'absolute',
|
||||
top: 50,
|
||||
right: 20,
|
||||
padding: 8,
|
||||
zIndex: 50,
|
||||
backgroundColor: 'rgba(0,0,0,0.5)',
|
||||
borderRadius: 20,
|
||||
},
|
||||
|
||||
langModalContent: {
|
||||
padding: 20,
|
||||
borderRadius: 20,
|
||||
},
|
||||
langOption: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'flex-start',
|
||||
gap: 10,
|
||||
elevation: 3,
|
||||
justifyContent: 'space-between',
|
||||
paddingVertical: 14,
|
||||
paddingHorizontal: 16,
|
||||
borderRadius: 14,
|
||||
borderWidth: 1.5,
|
||||
marginBottom: 10,
|
||||
},
|
||||
|
||||
langOptionLeft: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: 12,
|
||||
},
|
||||
|
||||
checkmark: {
|
||||
width: 24,
|
||||
height: 24,
|
||||
borderRadius: 12,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
|
||||
checkmarkText: {
|
||||
color: '#fff',
|
||||
fontSize: 14,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
playOverlay: {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
backgroundColor: 'rgba(0,0,0,0.25)',
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user