Files
cpost-mobile/src/components/FileDrop.tsx
Samandar Turgunboyev f55a3a50ed added notification
2025-09-04 10:06:46 +05:00

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;