262 lines
7.0 KiB
TypeScript
262 lines
7.0 KiB
TypeScript
import React from "react";
|
|
import {
|
|
View,
|
|
Text,
|
|
StyleSheet,
|
|
Image,
|
|
TouchableOpacity,
|
|
ScrollView,
|
|
} from "react-native";
|
|
import { MaterialIcons } from "@expo/vector-icons";
|
|
import LanguageModal from "@/components/Profile/LangaugeModal";
|
|
import { useSelector } from "react-redux";
|
|
import { AppDispatch, RootState } from "@/store";
|
|
import EditIcon from "../../assets/icons/edit.svg";
|
|
import { router } from "expo-router";
|
|
import { useDispatch } from "react-redux";
|
|
import { logout } from "@/store/authSlice";
|
|
import * as ImagePicker from "expo-image-picker";
|
|
import { useSnackbar } from "@/contexts/Snackbar";
|
|
import { AWS, BASE_URL, USER_PROFILE } from "@/constants/config";
|
|
import { bytesToMB, updateUserProfile, uploadImage } from "@/utils/User";
|
|
import { setUserData } from "@/store/userSlice";
|
|
import { Overlay } from "@/components/common/Overlay";
|
|
import Header from "@/components/common/Header";
|
|
|
|
export default function ProfileScreen() {
|
|
const [isLangaugeModalVisible, setLanguageModalVisible] =
|
|
React.useState(false);
|
|
const { showSnackbar } = useSnackbar();
|
|
const toggleLanguageModal = () => {
|
|
setLanguageModalVisible(!isLangaugeModalVisible);
|
|
};
|
|
|
|
const [isUploading, setIsUploading] = React.useState(false);
|
|
|
|
const { data } = useSelector((state: RootState) => state.user);
|
|
|
|
const userName = data?.name || "User";
|
|
const mobileNumber = data?.mobile || "Not provided";
|
|
const userImageUrl = data?.profile_url;
|
|
const dispatch = useDispatch<AppDispatch>();
|
|
|
|
const handleLogout = () => {
|
|
dispatch(logout());
|
|
router.replace("/auth/login");
|
|
};
|
|
|
|
const handlePickImage = async () => {
|
|
let result = await ImagePicker.launchImageLibraryAsync({
|
|
mediaTypes: ImagePicker.MediaTypeOptions.Images,
|
|
quality: 1,
|
|
allowsEditing: true,
|
|
aspect: [1, 1],
|
|
});
|
|
|
|
if (!result.canceled) {
|
|
try {
|
|
setIsUploading(true);
|
|
const { uri, fileSize } = result.assets[0];
|
|
console.log(uri, "File size:", fileSize);
|
|
if (!fileSize) {
|
|
showSnackbar("Image size is not available", "error");
|
|
return;
|
|
}
|
|
const size = bytesToMB(fileSize);
|
|
if (size > USER_PROFILE.MAX_IMAGE_SIZE_IN_MB) {
|
|
showSnackbar(
|
|
`Image size exceeds ${USER_PROFILE.MAX_IMAGE_SIZE_IN_MB}MB limit`,
|
|
"error"
|
|
);
|
|
throw new Error(
|
|
`Image size exceeds ${USER_PROFILE.MAX_IMAGE_SIZE_IN_MB}MB limit`
|
|
);
|
|
}
|
|
const uploadedImageUrl = await uploadImage(uri);
|
|
|
|
console.log("Uploaded image URL:", uploadedImageUrl);
|
|
await updateUserProfile({
|
|
profile_url: uploadedImageUrl,
|
|
mobile: mobileNumber,
|
|
});
|
|
|
|
dispatch(setUserData({ profile_url: uri }));
|
|
showSnackbar("Image uploaded successfully", "success");
|
|
} catch (error) {
|
|
console.error("Error uploading image:", error);
|
|
showSnackbar("Image upload failed", "error");
|
|
} finally {
|
|
setIsUploading(false);
|
|
}
|
|
}
|
|
};
|
|
return (
|
|
<>
|
|
<Header title="My Account" showBackButton={true} />
|
|
<ScrollView contentContainerStyle={styles.scrollContent}>
|
|
<View style={styles.avatarContainer}>
|
|
<Image
|
|
source={
|
|
userImageUrl
|
|
? { uri: userImageUrl }
|
|
: require("@/assets/images/user_image.jpg")
|
|
}
|
|
style={styles.avatar}
|
|
/>
|
|
|
|
<TouchableOpacity
|
|
style={styles.editAvatar}
|
|
onPress={() => handlePickImage()}
|
|
>
|
|
<EditIcon />
|
|
</TouchableOpacity>
|
|
</View>
|
|
<View style={styles.card}>
|
|
<View style={styles.row}>
|
|
<View style={styles.textGroup}>
|
|
<Text style={styles.label}>Name</Text>
|
|
<Text style={styles.value}>{userName}</Text>
|
|
</View>
|
|
<TouchableOpacity
|
|
onPress={() => {
|
|
router.push("/user/edit_name");
|
|
}}
|
|
style={styles.edit_button}
|
|
>
|
|
<MaterialIcons name="edit" size={20} color="#555C70" />
|
|
</TouchableOpacity>
|
|
</View>
|
|
<View style={styles.divider} />
|
|
<View style={styles.row}>
|
|
<View style={styles.textGroup}>
|
|
<Text style={styles.label}>Mobile Number</Text>
|
|
<Text style={styles.value}>{mobileNumber}</Text>
|
|
</View>
|
|
</View>
|
|
</View>
|
|
|
|
<View style={styles.card}>
|
|
{menuItem("My Vehicle", () => router.push("/user/MyVechicle"))}
|
|
<View style={styles.divider} />
|
|
{menuItem("Language", () => toggleLanguageModal())}
|
|
</View>
|
|
|
|
<View style={styles.card}>
|
|
{menuItem("About App")}
|
|
<View style={styles.divider} />
|
|
{menuItem("Logout", handleLogout)}
|
|
</View>
|
|
</ScrollView>
|
|
<LanguageModal
|
|
onClose={() => setLanguageModalVisible(false)}
|
|
visible={isLangaugeModalVisible}
|
|
/>
|
|
<Overlay isUploading={isUploading} />
|
|
</>
|
|
);
|
|
}
|
|
|
|
const menuItem = (title: string, onPress?: () => void) => (
|
|
<TouchableOpacity style={styles.menuRow} onPress={onPress}>
|
|
<Text style={styles.menuText}>{title}</Text>
|
|
<MaterialIcons name="chevron-right" size={20} color="#555C70" />
|
|
</TouchableOpacity>
|
|
);
|
|
|
|
const styles = StyleSheet.create({
|
|
edit_button: {
|
|
position: "absolute",
|
|
bottom: 0,
|
|
right: 0,
|
|
width: 40,
|
|
height: 40,
|
|
},
|
|
container: {
|
|
borderWidth: 1,
|
|
flex: 1,
|
|
backgroundColor: "#F3F5F8",
|
|
},
|
|
topBar: {
|
|
flexDirection: "row",
|
|
alignItems: "center",
|
|
paddingHorizontal: 8,
|
|
paddingVertical: 12,
|
|
backgroundColor: "#F3F5F8",
|
|
},
|
|
backButton: {
|
|
padding: 8,
|
|
},
|
|
headerText: {
|
|
fontSize: 16,
|
|
fontWeight: "600",
|
|
marginLeft: 8,
|
|
color: "#252A34",
|
|
},
|
|
scrollContent: {
|
|
paddingHorizontal: 16,
|
|
paddingBottom: 32,
|
|
backgroundColor: "#F3F5F8",
|
|
},
|
|
avatarContainer: {
|
|
alignItems: "center",
|
|
marginVertical: 24,
|
|
},
|
|
avatar: {
|
|
width: 120,
|
|
height: 120,
|
|
borderRadius: 60,
|
|
},
|
|
editAvatar: {
|
|
position: "absolute",
|
|
bottom: 0,
|
|
right: "35%",
|
|
width: 40,
|
|
height: 40,
|
|
backgroundColor: "#008866",
|
|
borderRadius: 20,
|
|
justifyContent: "center",
|
|
alignItems: "center",
|
|
},
|
|
card: {
|
|
backgroundColor: "#FCFCFC",
|
|
borderRadius: 8,
|
|
marginBottom: 16,
|
|
paddingHorizontal: 16,
|
|
paddingVertical: 8,
|
|
},
|
|
row: {
|
|
flexDirection: "row",
|
|
justifyContent: "space-between",
|
|
alignItems: "center",
|
|
paddingVertical: 12,
|
|
},
|
|
textGroup: {
|
|
flexDirection: "column",
|
|
},
|
|
label: {
|
|
fontSize: 14,
|
|
color: "#252A34",
|
|
},
|
|
value: {
|
|
fontSize: 14,
|
|
fontWeight: "600",
|
|
color: "#252A34",
|
|
marginTop: 2,
|
|
},
|
|
divider: {
|
|
height: 1,
|
|
backgroundColor: "#E5E9F0",
|
|
marginVertical: 4,
|
|
},
|
|
menuRow: {
|
|
flexDirection: "row",
|
|
justifyContent: "space-between",
|
|
alignItems: "center",
|
|
paddingVertical: 16,
|
|
},
|
|
menuText: {
|
|
fontSize: 14,
|
|
color: "#252A34",
|
|
},
|
|
});
|