Initial commit

This commit is contained in:
Samandar Turgunboyev
2025-08-26 16:26:59 +05:00
commit fd95422447
318 changed files with 38301 additions and 0 deletions

224
src/components/FileDrop.tsx Normal file
View File

@@ -0,0 +1,224 @@
import React, { useCallback, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import {
Alert,
Image,
StyleSheet,
Text,
TouchableOpacity,
View,
} from 'react-native';
import {
ImagePickerResponse,
launchImageLibrary,
MediaType,
} from 'react-native-image-picker';
import Feather from 'react-native-vector-icons/Feather';
interface FileData {
uri: string;
name: string;
type: string;
base64: string;
}
interface SingleFileDropProps {
title: string;
onFileSelected?: (file: FileData) => void;
}
const SingleFileDrop: React.FC<SingleFileDropProps> = ({
title,
onFileSelected,
}) => {
const [selectedImage, setSelectedImage] = useState<string | null>(null);
const { t } = useTranslation();
const imagePickerOptions = useMemo(
() => ({
mediaType: 'photo' as MediaType,
includeBase64: true,
}),
[],
);
const handleImagePickerResponse = useCallback(
(response: ImagePickerResponse) => {
if (response.didCancel) return; // foydalanuvchi bekor qilsa
if (response.errorCode) {
Alert.alert('Xato', response.errorMessage || 'Rasmni yuklashda xato');
return;
}
if (response.assets && response.assets[0]) {
const asset = response.assets[0];
if (!asset.uri || !asset.type || !asset.base64) return;
// faqat PNG fayllarni qabul qilish
if (asset.type !== 'image/png') {
Alert.alert('Xato', 'Faqat PNG fayllarni yuklashingiz mumkin');
return;
}
setSelectedImage(asset.uri);
const fileData: FileData = {
uri: asset.uri,
name: asset.fileName || 'image.png',
type: asset.type,
base64: `data:${asset.type};base64,${asset.base64}`,
};
onFileSelected?.(fileData);
}
},
[onFileSelected],
);
const openGallery = useCallback((): void => {
launchImageLibrary(imagePickerOptions, handleImagePickerResponse);
}, [imagePickerOptions, handleImagePickerResponse]);
const UploadIcon = useMemo(
() => () =>
(
<View style={styles.iconContainer}>
<View style={styles.downloadIcon}>
<Feather name="download" color="#28A7E8" size={35} />
</View>
</View>
),
[],
);
const renderContent = useMemo(() => {
if (selectedImage) {
return (
<Image source={{ uri: selectedImage }} style={styles.previewImage} />
);
}
return (
<>
<View style={styles.innerContainer}>
<View style={styles.topContent}>
{selectedImage ? (
<Image
source={{ uri: selectedImage }}
style={styles.previewImage}
/>
) : (
<>
<UploadIcon />
<Text style={styles.sectionTitle}>{title}</Text>
</>
)}
</View>
<View style={styles.bottomContent}>
<View style={styles.dividerContainer}>
<View style={styles.dividerLine} />
<Text style={styles.orDividerText}>OR</Text>
<View style={styles.dividerLine} />
</View>
<View style={styles.browseButton}>
<Text style={styles.browseButtonText}>{t('Faylni yuklang')}</Text>
</View>
</View>
</View>
</>
);
}, [selectedImage, title, UploadIcon]);
return (
<TouchableOpacity style={styles.dropSection} onPress={openGallery}>
{renderContent}
</TouchableOpacity>
);
};
const styles = StyleSheet.create({
dropSection: {
borderWidth: 2,
borderColor: '#28A7E8',
borderStyle: 'dashed',
borderRadius: 8,
padding: 20,
alignItems: 'center',
justifyContent: 'center',
minHeight: 200,
flex: 1,
},
iconContainer: {
marginBottom: 15,
},
downloadIcon: {
width: 40,
height: 40,
borderRadius: 20,
alignItems: 'center',
justifyContent: 'center',
},
iconText: {
fontSize: 20,
color: '#007bff',
fontWeight: 'bold',
},
sectionTitle: {
fontSize: 16,
fontWeight: '500',
color: '#333',
marginBottom: 10,
},
browseButton: {
borderWidth: 1,
borderColor: '#28A7E8',
borderRadius: 8,
padding: 8,
},
browseButtonText: {
color: '#28A7E8',
fontSize: 14,
fontWeight: '500',
},
previewImage: {
width: '100%',
height: 150,
borderRadius: 8,
resizeMode: 'cover',
},
dividerContainer: {
width: '100%',
alignItems: 'center',
justifyContent: 'center',
marginVertical: 16,
position: 'relative',
flexDirection: 'row',
},
dividerLine: {
width: 30,
height: 2,
backgroundColor: '#E7E7E7',
},
orDividerText: {
paddingHorizontal: 12,
fontSize: 14,
color: '#999',
zIndex: 1,
},
innerContainer: {
flex: 1,
justifyContent: 'space-between',
width: '100%',
},
topContent: {
alignItems: 'center',
},
bottomContent: {
width: '100%',
alignItems: 'center',
},
});
export default SingleFileDrop;