themed style
This commit is contained in:
@@ -58,7 +58,7 @@ export interface GroupDetails {
|
||||
organizerId: string;
|
||||
totalParticipants: number;
|
||||
participants: Participant[];
|
||||
imageBlob:string
|
||||
imageBlob: string
|
||||
}
|
||||
|
||||
export interface EditGroupPayload {
|
||||
@@ -323,82 +323,127 @@ const EditGroupScreen: React.FC<EditGroupScreenProps> = ({ route }) => {
|
||||
const isInvitable = groupDetails.status === 'APPROVED';
|
||||
const canStartGroup = groupDetails.status === 'APPROVED' && groupDetails.totalParticipants >= groupDetails.minParticipants;
|
||||
|
||||
// const pickImage = () => {
|
||||
// launchImageLibrary({ mediaType: "photo", quality: 0.5 }, (response) => {
|
||||
// if (response.didCancel) return;
|
||||
// if (response.errorCode) {
|
||||
// Alert.alert("Error", response.errorMessage || "Something went wrong");
|
||||
// } else if (response.assets && response.assets.length > 0) {
|
||||
// const selectedImage = response.assets[0];
|
||||
// console.log(selectedImage?.uri)
|
||||
// setSelectedImage(selectedImage?.uri)
|
||||
// }
|
||||
// });
|
||||
// };
|
||||
|
||||
const pickImage = () => {
|
||||
launchImageLibrary({ mediaType: "photo", quality: 0.5 }, (response) => {
|
||||
if (response.didCancel) return;
|
||||
|
||||
if (response.errorCode) {
|
||||
Alert.alert("Error", response.errorMessage || "Something went wrong");
|
||||
} else if (response.assets && response.assets.length > 0) {
|
||||
const selectedImage = response.assets[0];
|
||||
console.log(selectedImage?.uri)
|
||||
setSelectedImage(selectedImage?.uri)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!response.assets || response.assets.length === 0) {
|
||||
Alert.alert("Error", "No image selected");
|
||||
return;
|
||||
}
|
||||
|
||||
const selectedImage = response.assets[0];
|
||||
const maxSizeKB = 1000;
|
||||
const maxSizeBytes = maxSizeKB * 1024;
|
||||
|
||||
// Size validation
|
||||
if (selectedImage.fileSize && selectedImage.fileSize > maxSizeBytes) {
|
||||
const currentSizeKB = (selectedImage.fileSize / 1024).toFixed(2);
|
||||
Alert.alert(
|
||||
"File Too Large",
|
||||
`Selected image is ${currentSizeKB}KB. Please select an image smaller than ${maxSizeKB}KB.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Additional validation for required fields
|
||||
if (!selectedImage.uri) {
|
||||
Alert.alert("Error", "Invalid image file");
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("✅ Image selected:", {
|
||||
uri: selectedImage.uri,
|
||||
size: (selectedImage.fileSize / 1024).toFixed(2) + "KB",
|
||||
width: selectedImage.width,
|
||||
height: selectedImage.height
|
||||
});
|
||||
|
||||
setSelectedImage(selectedImage.uri);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
const handleUpdateImage = async () => {
|
||||
try {
|
||||
const credentials = await Keychain.getGenericPassword();
|
||||
if (!credentials) {
|
||||
Alert.alert("Error", "You are not logged in");
|
||||
return;
|
||||
}
|
||||
const token = credentials.password;
|
||||
|
||||
if (!selectedImage) {
|
||||
Alert.alert("Error", "Please select an image first");
|
||||
return;
|
||||
try {
|
||||
const credentials = await Keychain.getGenericPassword();
|
||||
if (!credentials) {
|
||||
Alert.alert("Error", "You are not logged in");
|
||||
return;
|
||||
}
|
||||
const token = credentials.password;
|
||||
|
||||
if (!selectedImage) {
|
||||
Alert.alert("Error", "Please select an image first");
|
||||
return;
|
||||
}
|
||||
|
||||
setImageUpdating(true);
|
||||
|
||||
// Get file extension and mime type dynamically
|
||||
const fileExtension = selectedImage.split('.').pop();
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append("file", {
|
||||
uri: selectedImage,
|
||||
type: "image/jpeg",
|
||||
name: `group_${groupId}_profile.${fileExtension || "jpg"}`,
|
||||
});
|
||||
|
||||
const url = `${UPLOAD_GROUP_IMAGE}${groupId}/upload-image`;
|
||||
|
||||
console.log("url : ", url)
|
||||
console.log("formdata : ", formData)
|
||||
|
||||
// return
|
||||
const response = await fetch(url, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "multipart/form-data",
|
||||
"Authorization": `Bearer ${token}`,
|
||||
},
|
||||
body: formData,
|
||||
});
|
||||
|
||||
console.log("image response : ", response)
|
||||
if (response?.status === 200) {
|
||||
fetchGroupDetails()
|
||||
ToastAndroid.show('Group uploaded successfully', ToastAndroid.SHORT)
|
||||
}
|
||||
|
||||
} catch (error: any) {
|
||||
console.error("❌ Error updating group image:", error);
|
||||
Alert.alert("Error", error.message || "Could not update group image");
|
||||
} finally {
|
||||
setImageUpdating(false);
|
||||
}
|
||||
};
|
||||
|
||||
setImageUpdating(true);
|
||||
|
||||
// Get file extension and mime type dynamically
|
||||
const fileExtension = selectedImage.split('.').pop();
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append("file", {
|
||||
uri: selectedImage,
|
||||
type: "image/jpeg",
|
||||
name: `group_${groupId}_profile.${fileExtension || "jpg"}`,
|
||||
});
|
||||
|
||||
const url = `${UPLOAD_GROUP_IMAGE}${groupId}/upload-image`;
|
||||
|
||||
console.log("url : ", url)
|
||||
console.log("formdata : ", formData)
|
||||
|
||||
// return
|
||||
const response = await fetch(url, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "multipart/form-data",
|
||||
"Authorization": `Bearer ${token}`,
|
||||
},
|
||||
body: formData,
|
||||
});
|
||||
|
||||
console.log("image response : ", response)
|
||||
if(response?.status === 200){
|
||||
fetchGroupDetails()
|
||||
ToastAndroid.show('Group uploaded successfully', ToastAndroid.SHORT)
|
||||
}
|
||||
|
||||
} catch (error:any) {
|
||||
console.error("❌ Error updating group image:", error);
|
||||
Alert.alert("Error", error.message || "Could not update group image");
|
||||
} finally {
|
||||
setImageUpdating(false);
|
||||
}
|
||||
};
|
||||
|
||||
const getProfileImage = () => {
|
||||
return selectedImage
|
||||
? selectedImage
|
||||
: groupDetails?.imageBlob
|
||||
? `data:image/jpeg;base64,${groupDetails.imageBlob}`
|
||||
: "https://img.freepik.com/premium-vector/people-group-frame-icon_791764-2649.jpg";
|
||||
};
|
||||
// Helper function to get MIME type
|
||||
const getProfileImage = () => {
|
||||
return selectedImage
|
||||
? selectedImage
|
||||
: groupDetails?.imageBlob
|
||||
? `data:image/jpeg;base64,${groupDetails.imageBlob}`
|
||||
: "https://img.freepik.com/premium-vector/people-group-frame-icon_791764-2649.jpg";
|
||||
};
|
||||
// Helper function to get MIME type
|
||||
|
||||
|
||||
return (
|
||||
@@ -430,12 +475,12 @@ const getProfileImage = () => {
|
||||
<Ionicons name="camera" size={18} color="#000" />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
<View style={{justifyContent:'center'}}>
|
||||
<View style={{ justifyContent: 'center' }}>
|
||||
<CustomButton
|
||||
title={imageUpdating ? "Updating..." : "Update Image"}
|
||||
onPress={handleUpdateImage}
|
||||
icon={imageUpdating ? undefined : "cloud-upload"}
|
||||
style={{paddingHorizontal:20}}
|
||||
style={{ paddingHorizontal: 20 }}
|
||||
buttonBackground={colors.pastelBlue}
|
||||
/>
|
||||
</View>
|
||||
|
||||
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
|
||||
import { View, Text, StyleSheet, Platform, TouchableOpacity } from 'react-native';
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import Ionicons from 'react-native-vector-icons/Ionicons'; // Correct import for react-native-vector-icons
|
||||
import {Ionicons} from '@react-native-vector-icons/ionicons'; // Correct import for react-native-vector-icons
|
||||
|
||||
import { NativeStackScreenProps } from '@react-navigation/native-stack';
|
||||
import { RootStackParamList } from '../../navigation/AppNavigator'; // Adjust path
|
||||
@@ -28,7 +28,7 @@ const FloatingTabBar = ({ state, descriptors, navigation }: BottomTabBarProps) =
|
||||
|
||||
console.log("option : ", options)
|
||||
// A custom option to pass the icon name
|
||||
const iconName = options.tabBarIconName ?? 'help-circle';
|
||||
const iconName = label === "Settings" ? "trail-sign-outline" : label === "Payments" ? "trending-up" : label === "Members" ? "people-outline" : "flower";
|
||||
|
||||
const isFocused = state.index === index;
|
||||
|
||||
@@ -79,7 +79,7 @@ const FloatingTabBar = ({ state, descriptors, navigation }: BottomTabBarProps) =
|
||||
|
||||
// --- Main Tab Navigator Component ---
|
||||
const ManagementTabNavigation: React.FC<Props> = ({ route }) => {
|
||||
const { groupId } = route.params
|
||||
const { groupId } = route.params
|
||||
|
||||
return (
|
||||
<Tab.Navigator
|
||||
@@ -97,10 +97,10 @@ const ManagementTabNavigation: React.FC<Props> = ({ route }) => {
|
||||
options={{
|
||||
tabBarLabel: 'Settings',
|
||||
// Custom prop to define the icon for our FloatingTabBar
|
||||
|
||||
|
||||
}}
|
||||
/>
|
||||
<Tab.Screen
|
||||
<Tab.Screen
|
||||
name="Payments"
|
||||
component={Payments}
|
||||
// Pass the groupId to the EditGroupScreen as an initial parameter
|
||||
@@ -111,16 +111,16 @@ const ManagementTabNavigation: React.FC<Props> = ({ route }) => {
|
||||
|
||||
}}
|
||||
/>
|
||||
<Tab.Screen
|
||||
<Tab.Screen
|
||||
name="Member"
|
||||
component={Member}
|
||||
// Pass the groupId to the EditGroupScreen as an initial parameter
|
||||
initialParams={{ groupId }}
|
||||
initialParams={{ groupId }}
|
||||
options={{
|
||||
tabBarLabel: 'Members',
|
||||
|
||||
|
||||
}}
|
||||
|
||||
|
||||
/>
|
||||
{/* You can easily add more tabs here in the future */}
|
||||
</Tab.Navigator>
|
||||
|
||||
Reference in New Issue
Block a user