212 lines
4.8 KiB
TypeScript
212 lines
4.8 KiB
TypeScript
import React, { useCallback, useMemo, useState } from 'react';
|
|
import { useTranslation } from 'react-i18next';
|
|
import {
|
|
Alert,
|
|
Image,
|
|
StyleSheet,
|
|
Text,
|
|
TouchableOpacity,
|
|
View,
|
|
} from 'react-native';
|
|
import {
|
|
Asset,
|
|
ImagePickerResponse,
|
|
launchImageLibrary,
|
|
MediaType,
|
|
} from 'react-native-image-picker';
|
|
import Download from 'svg/Download';
|
|
|
|
export interface FileData {
|
|
uri: string;
|
|
name: string;
|
|
type: string;
|
|
base64: string;
|
|
}
|
|
|
|
export interface SingleFileDropProps {
|
|
title: string;
|
|
onFileSelected?: (file: FileData) => void;
|
|
/**
|
|
* Ruxsat berilgan MIME tipi (masalan: "image/png" yoki "image/jpeg")
|
|
*/
|
|
type?: string;
|
|
}
|
|
|
|
const SingleFileDrop: React.FC<SingleFileDropProps> = ({
|
|
title,
|
|
onFileSelected,
|
|
type = 'image/png',
|
|
}) => {
|
|
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;
|
|
}
|
|
|
|
const asset: Asset | undefined = response.assets?.[0];
|
|
if (!asset || !asset.uri || !asset.type || !asset.base64) return;
|
|
|
|
// faqat belgilangan tipdagi fayllarni qabul qilish
|
|
if (!asset.type.startsWith('image/')) {
|
|
Alert.alert('Xato', 'Faqat rasm fayllarni yuklashingiz mumkin');
|
|
return;
|
|
}
|
|
|
|
setSelectedImage(asset.uri);
|
|
|
|
const fileData: FileData = {
|
|
uri: asset.uri,
|
|
name: asset.fileName || `file.${asset.type.split('/')[1]}`,
|
|
type: asset.type,
|
|
base64: `data:${asset.type};base64,${asset.base64}`,
|
|
};
|
|
|
|
onFileSelected?.(fileData);
|
|
},
|
|
[onFileSelected, type],
|
|
);
|
|
|
|
const openGallery = useCallback((): void => {
|
|
launchImageLibrary(imagePickerOptions, handleImagePickerResponse);
|
|
}, [imagePickerOptions, handleImagePickerResponse]);
|
|
|
|
const UploadIcon = useMemo(
|
|
() => () =>
|
|
(
|
|
<View style={styles.iconContainer}>
|
|
<View style={styles.downloadIcon}>
|
|
<Download fill="#28A7E8" width={50} height={50} />
|
|
</View>
|
|
</View>
|
|
),
|
|
[],
|
|
);
|
|
|
|
const renderContent = useMemo(() => {
|
|
if (selectedImage) {
|
|
return (
|
|
<Image source={{ uri: selectedImage }} style={styles.previewImage} />
|
|
);
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<View style={styles.innerContainer}>
|
|
<View style={styles.topContent}>
|
|
<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',
|
|
},
|
|
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,
|
|
flexDirection: 'row',
|
|
},
|
|
dividerLine: {
|
|
width: 30,
|
|
height: 2,
|
|
backgroundColor: '#E7E7E7',
|
|
},
|
|
orDividerText: {
|
|
paddingHorizontal: 12,
|
|
fontSize: 14,
|
|
color: '#999',
|
|
},
|
|
innerContainer: {
|
|
flex: 1,
|
|
justifyContent: 'space-between',
|
|
width: '100%',
|
|
},
|
|
topContent: {
|
|
alignItems: 'center',
|
|
},
|
|
bottomContent: {
|
|
width: '100%',
|
|
alignItems: 'center',
|
|
},
|
|
});
|
|
|
|
export default SingleFileDrop;
|