Initial commit
This commit is contained in:
353
src/screens/profile/myProfile/ui/ProfileHeader.tsx
Normal file
353
src/screens/profile/myProfile/ui/ProfileHeader.tsx
Normal file
@@ -0,0 +1,353 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { authApi } from 'api/auth';
|
||||
import React, { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
Dimensions,
|
||||
Image,
|
||||
Linking,
|
||||
StyleSheet,
|
||||
Text,
|
||||
TouchableOpacity,
|
||||
View,
|
||||
} from 'react-native';
|
||||
import ImagePicker from 'react-native-image-crop-picker';
|
||||
import Modal from 'react-native-modal';
|
||||
import SendIntentAndroid from 'react-native-send-intent';
|
||||
import Fontisto from 'react-native-vector-icons/Fontisto';
|
||||
import GalleryEdit from 'svg/GalleryEdit';
|
||||
import Plus from 'svg/Plus';
|
||||
import Trash from 'svg/Trash';
|
||||
|
||||
const { width } = Dimensions.get('window');
|
||||
const isSmallScreen = width < 360;
|
||||
|
||||
const ProfileHeader = ({ userName = 'Samandar' }: { userName?: string }) => {
|
||||
const [imageError, setImageError] = useState(true);
|
||||
const { t } = useTranslation();
|
||||
const [selectedImage, setSelectedImage] = useState<string>(
|
||||
'https://static.vecteezy.com/system/resources/previews/019/879/186/non_2x/user-icon-on-transparent-background-free-png.png',
|
||||
);
|
||||
const getStatusMeta = (status?: string) => {
|
||||
const key = (status || '').toLowerCase();
|
||||
switch (key) {
|
||||
case 'active':
|
||||
return { label: t('Faol'), bg: '#E6F7EE', fg: '#1F9254' };
|
||||
case 'pending':
|
||||
return { label: t('Kutilmoqda'), bg: '#FFF7E6', fg: '#B26A00' };
|
||||
case 'inactive':
|
||||
case 'blocked':
|
||||
return { label: t('Faol emas'), bg: '#FDECEF', fg: '#A61D24' };
|
||||
default:
|
||||
return { label: t('Faol emas'), bg: '#EDF2F7', fg: '#A61D24' };
|
||||
}
|
||||
};
|
||||
|
||||
const { data: getMe } = useQuery({
|
||||
queryKey: ['getMe'],
|
||||
queryFn: authApi.getMe,
|
||||
});
|
||||
|
||||
const [isModalVisible, setModalVisible] = useState(false);
|
||||
|
||||
const openGallery = async () => {
|
||||
try {
|
||||
const image = await ImagePicker.openPicker({
|
||||
width: 0,
|
||||
height: 0,
|
||||
cropping: true,
|
||||
cropperCircleOverlay: true,
|
||||
freeStyleCropEnabled: true,
|
||||
hideBottomControls: false,
|
||||
cropperToolbarTitle: 'Edit Image',
|
||||
cropperToolbarColor: '#28A7E8',
|
||||
cropperToolbarWidgetColor: '#ffffff',
|
||||
cropperStatusBarColor: '#28A7E8',
|
||||
cropperActiveWidgetColor: '#28A7E8',
|
||||
compressImageQuality: 0.8,
|
||||
mediaType: 'photo',
|
||||
forceJpg: true,
|
||||
});
|
||||
if (image?.path) {
|
||||
setSelectedImage(image.path);
|
||||
setImageError(false);
|
||||
setModalVisible(false);
|
||||
}
|
||||
} catch (error) {}
|
||||
};
|
||||
|
||||
const handleImagePress = () => {
|
||||
if (!imageError) {
|
||||
setModalVisible(true);
|
||||
} else {
|
||||
openGallery();
|
||||
}
|
||||
};
|
||||
|
||||
const removePhoto = () => {
|
||||
setSelectedImage('');
|
||||
setImageError(true);
|
||||
setModalVisible(false);
|
||||
};
|
||||
|
||||
const openTelegram = async () => {
|
||||
const telegramUri = 'tg://resolve?domain=cpostuz';
|
||||
try {
|
||||
const success = await SendIntentAndroid.openAppWithUri(telegramUri);
|
||||
if (!success) Linking.openURL('https://t.me/cpostuz');
|
||||
} catch (error) {
|
||||
Linking.openURL('https://t.me/cpostuz');
|
||||
}
|
||||
};
|
||||
|
||||
const openInstagram = async () => {
|
||||
const instagramUri = 'instagram://user?username=cpost_cargo';
|
||||
try {
|
||||
const success = await SendIntentAndroid.openAppWithUri(instagramUri);
|
||||
if (!success) Linking.openURL('https://instagram.com/cpost_cargo');
|
||||
} catch (error) {
|
||||
Linking.openURL('https://instagram.com/cpost_cargo');
|
||||
}
|
||||
};
|
||||
|
||||
const openFacebook = () => {
|
||||
SendIntentAndroid.openAppWithData(
|
||||
'com.facebook.katana',
|
||||
'fb://page/PAGE_ID',
|
||||
).catch(() => Linking.openURL('https://facebook.com/'));
|
||||
};
|
||||
|
||||
const capitalizeWords = (str: string) => {
|
||||
if (!str) return '';
|
||||
return str
|
||||
.split(' ')
|
||||
.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
||||
.join(' ');
|
||||
};
|
||||
|
||||
const formatPhone = (value: string) => {
|
||||
const digits = value.replace(/\D/g, '');
|
||||
if (digits.length === 0) return '';
|
||||
|
||||
const prefix = '+998 ';
|
||||
|
||||
let formattedNumber = prefix;
|
||||
|
||||
if (digits.length > 3) {
|
||||
formattedNumber += `(${digits.slice(3, 5)}) `;
|
||||
}
|
||||
|
||||
if (digits.length > 5) {
|
||||
formattedNumber += digits.slice(5, 8);
|
||||
}
|
||||
|
||||
if (digits.length > 8) {
|
||||
formattedNumber += '-' + digits.slice(8, 10);
|
||||
}
|
||||
|
||||
if (digits.length > 10) {
|
||||
formattedNumber += '-' + digits.slice(10, 12);
|
||||
}
|
||||
|
||||
return formattedNumber.trim();
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View style={styles.imageWrapper}>
|
||||
{imageError ? (
|
||||
<Text style={styles.fallbackText}>
|
||||
{getMe?.fullName.charAt(0).toUpperCase()}
|
||||
</Text>
|
||||
) : (
|
||||
<Image
|
||||
source={{ uri: selectedImage }}
|
||||
style={styles.image}
|
||||
onError={() => setImageError(true)}
|
||||
/>
|
||||
)}
|
||||
<TouchableOpacity style={styles.circle} onPress={handleImagePress}>
|
||||
<Plus color="#FFFFFF" />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
<View style={styles.infoUser}>
|
||||
<Text style={styles.name}>
|
||||
{capitalizeWords(getMe?.fullName || '')}
|
||||
</Text>
|
||||
{getMe?.status && (
|
||||
<View
|
||||
style={[
|
||||
styles.statusBadge,
|
||||
{ backgroundColor: getStatusMeta(getMe.status).bg },
|
||||
]}
|
||||
>
|
||||
<Text
|
||||
style={[
|
||||
styles.statusText,
|
||||
{ color: getStatusMeta(getMe.status).fg },
|
||||
]}
|
||||
>
|
||||
{getStatusMeta(getMe.status).label}
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
<Text style={styles.userId}>ID: {getMe?.aviaCargoId}</Text>
|
||||
<Text style={styles.telUser}>
|
||||
{getMe?.phone ? formatPhone(getMe.phone) : ''}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.links}>
|
||||
<TouchableOpacity onPress={openTelegram}>
|
||||
<Fontisto
|
||||
name="telegram"
|
||||
color="#28A7E8"
|
||||
size={isSmallScreen ? 20 : 24}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity onPress={openInstagram}>
|
||||
<Fontisto
|
||||
name="instagram"
|
||||
color="#28A7E8"
|
||||
size={isSmallScreen ? 18 : 22}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
|
||||
{/* <TouchableOpacity onPress={openFacebook}>
|
||||
<MaterialIcons
|
||||
name="facebook"
|
||||
color="#28A7E8"
|
||||
size={isSmallScreen ? 22 : 26}
|
||||
/>
|
||||
</TouchableOpacity> */}
|
||||
</View>
|
||||
|
||||
<Modal
|
||||
isVisible={isModalVisible}
|
||||
onBackdropPress={() => setModalVisible(false)}
|
||||
style={styles.modal}
|
||||
>
|
||||
<View style={styles.modalContent}>
|
||||
<TouchableOpacity style={styles.modalBtn} onPress={openGallery}>
|
||||
<GalleryEdit fill="#28A7E8" width={26} height={26} />
|
||||
<Text style={styles.modalText}>{t("Rasmni o'zgartirish")}</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity style={styles.modalBtn} onPress={removePhoto}>
|
||||
<Trash color="red" width={26} height={26} />
|
||||
<Text style={[styles.modalText, { color: 'red' }]}>
|
||||
{t("Rasmni o'chirish")}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</Modal>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
marginTop: 10,
|
||||
alignItems: 'center',
|
||||
},
|
||||
imageWrapper: {
|
||||
width: 100,
|
||||
height: 100,
|
||||
borderRadius: 50,
|
||||
backgroundColor: '#D3D6DA',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
image: {
|
||||
width: 100,
|
||||
height: 100,
|
||||
resizeMode: 'cover',
|
||||
borderRadius: 50,
|
||||
},
|
||||
fallbackText: {
|
||||
fontSize: 50,
|
||||
fontWeight: 'bold',
|
||||
color: '#555',
|
||||
},
|
||||
circle: {
|
||||
position: 'absolute',
|
||||
bottom: -5,
|
||||
right: 0,
|
||||
backgroundColor: '#28A7E8',
|
||||
zIndex: 10,
|
||||
borderRadius: 50,
|
||||
borderColor: '#FFFFFF',
|
||||
borderWidth: 2,
|
||||
padding: 5,
|
||||
},
|
||||
statusBadge: {
|
||||
alignSelf: 'center',
|
||||
marginTop: 5,
|
||||
marginBottom: 10,
|
||||
paddingHorizontal: 14,
|
||||
paddingVertical: 4,
|
||||
borderRadius: 20,
|
||||
shadowColor: '#000',
|
||||
shadowOffset: { width: 0, height: 2 },
|
||||
shadowOpacity: 0.15,
|
||||
shadowRadius: 3,
|
||||
elevation: 3, // Android uchun chiroyli ko‘rinishi
|
||||
},
|
||||
statusText: {
|
||||
fontSize: 13,
|
||||
fontWeight: '600',
|
||||
},
|
||||
infoUser: {
|
||||
marginTop: 10,
|
||||
},
|
||||
name: {
|
||||
fontSize: 18,
|
||||
fontWeight: '500',
|
||||
},
|
||||
userId: {
|
||||
textAlign: 'center',
|
||||
fontWeight: '600',
|
||||
fontSize: 30,
|
||||
color: '#28A7E8',
|
||||
},
|
||||
telUser: {
|
||||
color: '#373737',
|
||||
fontWeight: '400',
|
||||
fontSize: 16,
|
||||
textAlign: 'center',
|
||||
},
|
||||
links: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: 10,
|
||||
marginTop: 10,
|
||||
},
|
||||
modal: {
|
||||
justifyContent: 'flex-end',
|
||||
margin: 0,
|
||||
},
|
||||
modalContent: {
|
||||
backgroundColor: 'white',
|
||||
padding: 20,
|
||||
borderTopLeftRadius: 12,
|
||||
borderTopRightRadius: 12,
|
||||
},
|
||||
modalBtn: {
|
||||
paddingVertical: 15,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: '#eee',
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'center',
|
||||
gap: 8,
|
||||
alignItems: 'center',
|
||||
},
|
||||
modalText: {
|
||||
fontSize: 16,
|
||||
fontWeight: '500',
|
||||
color: '#28A7E8',
|
||||
textAlign: 'center',
|
||||
},
|
||||
});
|
||||
|
||||
export default ProfileHeader;
|
||||
Reference in New Issue
Block a user