merge code

This commit is contained in:
Abin Toppo
2025-10-07 16:10:37 +05:30
8 changed files with 108 additions and 47 deletions
+2
View File
@@ -22,6 +22,8 @@ const colors = {
// Special background colors with transparency // Special background colors with transparency
alertBackground: "rgba(255, 255, 255, 0.8)", alertBackground: "rgba(255, 255, 255, 0.8)",
androidBackdrop: "rgba(0, 0, 0, 0.4)", androidBackdrop: "rgba(0, 0, 0, 0.4)",
warning:'#b9b61cff',
danger:'#f04814ff'
}; };
export default colors; export default colors;
+2 -1
View File
@@ -13,6 +13,7 @@ import { RootStackParamList } from '../navigation/AppNavigator'; // Adjust path
import { apiCall } from '../utils/ApiHelper'; // Adjust path import { apiCall } from '../utils/ApiHelper'; // Adjust path
import AppView from '../components/AppView'; // Adjust path import AppView from '../components/AppView'; // Adjust path
import colors from '../components/colors'; // Adjust path import colors from '../components/colors'; // Adjust path
import { BASE_URL } from '../utils/ApiUrls';
// --- Type Definitions --- // --- Type Definitions ---
interface Participant { interface Participant {
@@ -52,7 +53,7 @@ const InviteScreen: FC<InviteScreenProps> = ({ route }) => {
setLoading(true); setLoading(true);
setError(null); setError(null);
try { try {
const response = await apiCall(`http://192.168.1.5:9060/api/fund/group/details?groupId=${groupId}`, 'GET') as { status: string; data?: GroupDetails; message?: string }; const response = await apiCall(`${BASE_URL}fund/group/details?groupId=${groupId}`, 'GET') as { status: string; data?: GroupDetails; message?: string };
if (response.status === 'success' && response.data) { if (response.status === 'success' && response.data) {
setGroupDetails(response.data); setGroupDetails(response.data);
} else { } else {
+2 -1
View File
@@ -14,6 +14,7 @@ import { Ionicons } from '@react-native-vector-icons/ionicons';
import colors from '../../components/colors'; import colors from '../../components/colors';
import DeclineModal from './DeclineModal'; import DeclineModal from './DeclineModal';
import * as keychain from 'react-native-keychain' import * as keychain from 'react-native-keychain'
import { BASE_URL } from '../../utils/ApiUrls';
// Define TypeScript interfaces // Define TypeScript interfaces
interface GroupRequest { interface GroupRequest {
@@ -58,7 +59,7 @@ const RequestList: React.FC = () => {
setError(null); setError(null);
const response = await fetch( const response = await fetch(
"http://192.168.1.5:9060/api/fund/group/pending/request", `${BASE_URL}`,
{ {
method: "GET", method: "GET",
headers: { headers: {
+10 -9
View File
@@ -71,6 +71,7 @@ export interface EditGroupPayload {
groupName: string; groupName: string;
description: string; description: string;
maxParticipants: number; maxParticipants: number;
minParticipants?:number;
contributionAmount: number; contributionAmount: number;
customCycleDays: number | null; customCycleDays: number | null;
cycleType: 'QUARTERLY' | 'MONTHLY' | 'WEEKLY' | 'CUSTOM'; cycleType: 'QUARTERLY' | 'MONTHLY' | 'WEEKLY' | 'CUSTOM';
@@ -288,7 +289,7 @@ const EditGroupScreen: React.FC<EditGroupScreenProps> = ({ route }) => {
}; };
const renderField = (field: keyof EditGroupPayload, label: string, displayValue: string | number, isEditing: boolean, isEditable: boolean) => { const renderField = (field: keyof EditGroupPayload, label: string, displayValue: string | number, isEditing: boolean, isEditable?: boolean) => {
const commonInputProps = { style: styles.input, placeholderTextColor: "#9CA3AF" }; const commonInputProps = { style: styles.input, placeholderTextColor: "#9CA3AF" };
const getInputForField = () => { const getInputForField = () => {
@@ -426,12 +427,12 @@ const EditGroupScreen: React.FC<EditGroupScreenProps> = ({ route }) => {
return; return;
} }
console.log("✅ Image selected:", { // console.log("✅ Image selected:", {
uri: selectedImage.uri, // uri: selectedImage.uri,
size: (selectedImage?.fileSize / 1024).toFixed(2) + "KB", // size: (selectedImage?.fileSize / 1024).toFixed(2) + "KB",
width: selectedImage.width, // width: selectedImage.width,
height: selectedImage.height // height: selectedImage.height
}); // });
setSelectedImage(selectedImage.uri); setSelectedImage(selectedImage.uri);
}); });
@@ -605,7 +606,7 @@ const EditGroupScreen: React.FC<EditGroupScreenProps> = ({ route }) => {
</TouchableOpacity> </TouchableOpacity>
</View> </View>
)} )}
{selectedUser?.cycleStatus !== "PENDING_PAYMENTS" && groupDetails.status === 'ACTIVE' &&( {selectedUser?.cycleStatus !== "PENDING_PAYMENTS" && groupDetails.status === 'ACTIVE' && selectedUser?.cycleStatus === "PENDING_SELECTION" &&(
<View style={styles.floatingButtonContainer}> <View style={styles.floatingButtonContainer}>
<TouchableOpacity <TouchableOpacity
style={styles.activateButton} style={styles.activateButton}
@@ -623,7 +624,7 @@ const EditGroupScreen: React.FC<EditGroupScreenProps> = ({ route }) => {
} }
{ {
selectedUser?.selectedUser !== null && selectedUser?.cycleStatus === "READY_FOR_WITHDRAWAL" && selectedUser?.canProceedToWithdrawal && selectedUser?.selectedUser !== null && selectedUser?.cycleStatus === "READY_FOR_WITHDRAWAL" &&
<View style={styles.floatingButtonContainer}> <View style={styles.floatingButtonContainer}>
<CustomButton <CustomButton
buttonBackground={colors?.pastelBlue} buttonBackground={colors?.pastelBlue}
+23 -13
View File
@@ -14,7 +14,8 @@ import { Ionicons } from "@react-native-vector-icons/ionicons"; // Assuming you
import { apiCall } from '../../utils/ApiHelper'; // Adjust path to your apiCall utility import { apiCall } from '../../utils/ApiHelper'; // Adjust path to your apiCall utility
import AppView from '../../components/AppView'; import AppView from '../../components/AppView';
import colors from '../../components/colors'; import colors from '../../components/colors';
import { useRoute } from '@react-navigation/native'; import { RouteProp, useRoute } from '@react-navigation/native';
import { BASE_URL } from '../../utils/ApiUrls';
// --- Type Definitions --- // --- Type Definitions ---
interface Member { interface Member {
@@ -36,10 +37,19 @@ interface ApiResponse {
statusCode: number; statusCode: number;
data: Member[]; data: Member[];
} }
type RootStackParamList = {
Member: { groupId: string }; // or number, depending on your data type
};
type MemberScreenRouteProp = RouteProp<RootStackParamList, 'Member'>;
interface Props {
route: MemberScreenRouteProp;
}
// --- Main Screen Component --- // --- Main Screen Component ---
// This assumes the component receives `groupId` from a navigator (e.g., Tab Navigator) // This assumes the component receives `groupId` from a navigator (e.g., Tab Navigator)
const MemberScreen = ({ route }) => { const MemberScreen = ({ route }: Props) => {
const { groupId } = route.params; const { groupId } = route.params;
const [members, setMembers] = useState<Member[]>([]); const [members, setMembers] = useState<Member[]>([]);
@@ -56,7 +66,7 @@ const MemberScreen = ({ route }) => {
setLoading(true); setLoading(true);
try { try {
const response = await apiCall<ApiResponse>( const response = await apiCall<ApiResponse>(
`http://192.168.1.5:9060/api/fund/group/all/member?groupId=${groupId}`, `${BASE_URL}fund/group/all/member?groupId=${groupId}`,
'GET' 'GET'
); );
@@ -90,13 +100,13 @@ const MemberScreen = ({ route }) => {
<Text style={styles.avatarText}>{initial}</Text> <Text style={styles.avatarText}>{initial}</Text>
</View> </View>
<View style={styles.infoContainer}> <View style={styles.infoContainer}>
<View style={{flexDirection:"row",justifyContent:"space-between"}}> <View style={{ flexDirection: "row", justifyContent: "space-between" }}>
<Text style={styles.name}>{fullName}</Text> <Text style={styles.name}>{fullName}</Text>
{isOrganizer && ( {isOrganizer && (
<View style={styles.organizerIcon}> <View style={styles.organizerIcon}>
<Text>Orginzer</Text> <Text>Orginzer</Text>
</View> </View>
)} )}
</View> </View>
<Text style={styles.username}>@{item.username}</Text> <Text style={styles.username}>@{item.username}</Text>
@@ -126,9 +136,9 @@ const MemberScreen = ({ route }) => {
if (members.length === 0) { if (members.length === 0) {
return ( return (
<View style={styles.centered}> <View style={styles.centered}>
<Ionicons name="people-outline" size={60} color="#9CA3AF" /> <Ionicons name="people-outline" size={60} color="#9CA3AF" />
<Text style={styles.emptyTitle}>No Members Yet</Text> <Text style={styles.emptyTitle}>No Members Yet</Text>
<Text style={styles.emptyText}>Invite people to join your group.</Text> <Text style={styles.emptyText}>Invite people to join your group.</Text>
</View> </View>
) )
} }
@@ -145,7 +155,7 @@ const MemberScreen = ({ route }) => {
}; };
return ( return (
<AppView> <AppView>
<View style={styles.header}> <View style={styles.header}>
<Text style={styles.headerTitle}>Group Members</Text> <Text style={styles.headerTitle}>Group Members</Text>
<Text style={styles.headerSubtitle}>{members.length} member(s)</Text> <Text style={styles.headerSubtitle}>{members.length} member(s)</Text>
@@ -5,17 +5,22 @@ import { Ionicons } from "@react-native-vector-icons/ionicons";
import { useNavigation } from '@react-navigation/native'; import { useNavigation } from '@react-navigation/native';
import ContributionDetails from '../ContributionScreen'; import ContributionDetails from '../ContributionScreen';
import { BASE_URL } from '../../utils/ApiUrls'; import { BASE_URL } from '../../utils/ApiUrls';
import colors from '../../components/colors';
const { width } = Dimensions.get('window'); const { width } = Dimensions.get('window');
const NUM_COLUMNS = 3; const NUM_COLUMNS = 3;
const ITEM_SIZE = width / NUM_COLUMNS - 20; const ITEM_SIZE = width / NUM_COLUMNS - 20;
interface User {
id: string;
name: string;
selected: boolean;
}
const RandomSelectUserScreen: React.FC<{ route: any }> = ({ route }) => { const RandomSelectUserScreen: React.FC<{ route: any }> = ({ route }) => {
const navigation = useNavigation() const navigation = useNavigation<any>()
const { groupId, cycleNumber } = route.params; const { groupId, cycleNumber } = route.params;
const [users, setUsers] = useState<User[]>([]);
const [users, setUsers] = useState<{ id: string; name: string }[]>([]);
const [highlightedIndex, setHighlightedIndex] = useState<number | null>(null); const [highlightedIndex, setHighlightedIndex] = useState<number | null>(null);
const [winner, setWinner] = useState<{ id: string; name: string } | null>(null); const [winner, setWinner] = useState<{ id: string; name: string } | null>(null);
const [isAnimating, setIsAnimating] = useState(false); const [isAnimating, setIsAnimating] = useState(false);
@@ -28,11 +33,15 @@ const RandomSelectUserScreen: React.FC<{ route: any }> = ({ route }) => {
const fetchParticipants = async () => { const fetchParticipants = async () => {
try { try {
const response = await apiCall(`${BASE_URL}fund/group/all/member?groupId=${groupId}`, "GET") as any; const response = await apiCall(`${BASE_URL}fund/group/all/member?groupId=${groupId}`, "GET") as any;
if (response.status === 'success' && response.data) { if (response.status === 'success' && response.data) {
const formattedUsers = response.data.map((u: any) => ({ const formattedUsers = response.data.map((u: any) => ({
id: u.id, id: u.id,
name: `${u.firstName} ${u.lastName}`, name: `${u.firstName} ${u.lastName}`,
selected: u?.selected
})); }));
console.log("all mem : ", formattedUsers)
setUsers(formattedUsers); setUsers(formattedUsers);
} else { } else {
Alert.alert('Error', 'Failed to fetch participants.'); Alert.alert('Error', 'Failed to fetch participants.');
@@ -56,18 +65,53 @@ const RandomSelectUserScreen: React.FC<{ route: any }> = ({ route }) => {
} }
}, [highlightedIndex]); }, [highlightedIndex]);
// const handleStartSelection = () => {
// if (users.length === 0 || isAnimating) return;
// setWinner(null);
// setIsAnimating(true);
// let highlightCount = 0;
// const maxHighlights = 30 + Math.floor(Math.random() * 10); // Add some randomness
// const highlightInterval = setInterval(() => {
// const randomIndex = Math.floor(Math.random() * users.length);
// setHighlightedIndex(randomIndex);
// highlightCount++;
// if (highlightCount >= maxHighlights) {
// clearInterval(highlightInterval);
// fetchWinner();
// }
// }, 120);
// };
const handleStartSelection = () => { const handleStartSelection = () => {
if (users.length === 0 || isAnimating) return; // Exclude already selected users
const availableUsers = users.filter(u => !u.selected);
if (availableUsers.length === 0 || isAnimating) {
Alert.alert('Info', 'All users are already selected.');
return;
}
setWinner(null); setWinner(null);
setIsAnimating(true); setIsAnimating(true);
let highlightCount = 0; let highlightCount = 0;
const maxHighlights = 30 + Math.floor(Math.random() * 10); // Add some randomness const maxHighlights = 30 + Math.floor(Math.random() * 10);
const highlightInterval = setInterval(() => { const highlightInterval = setInterval(() => {
const randomIndex = Math.floor(Math.random() * users.length); const randomIndex = Math.floor(Math.random() * availableUsers.length);
setHighlightedIndex(randomIndex); const selectedUser = availableUsers[randomIndex];
// Get original index in `users` for highlighting
const originalIndex = users.findIndex(u => u.id === selectedUser.id);
setHighlightedIndex(originalIndex);
highlightCount++; highlightCount++;
if (highlightCount >= maxHighlights) { if (highlightCount >= maxHighlights) {
@@ -81,7 +125,7 @@ const RandomSelectUserScreen: React.FC<{ route: any }> = ({ route }) => {
const payload = { groupId: groupId }; const payload = { groupId: groupId };
try { try {
const response = await apiCall(`${BASE_URL}fund/method/based/userSelect`, 'POST', payload) as any; const response = await apiCall(`${BASE_URL}fund/method/based/userSelect`, 'POST', payload) as any;
console.log("random select user response : ", response) console.log("random select user response : ", response)
if (response.status === 'success' && response.data?.selectedUser?.id) { if (response.status === 'success' && response.data?.selectedUser?.id) {
const winnerData = { id: response?.data?.selectedUser?.id, name: `${response.data.selectedUser.firstName} ${response.data.selectedUser.lastName}` }; const winnerData = { id: response?.data?.selectedUser?.id, name: `${response.data.selectedUser.firstName} ${response.data.selectedUser.lastName}` };
const winnerIndex = users.findIndex(u => u.id === winnerData.id); const winnerIndex = users.findIndex(u => u.id === winnerData.id);
@@ -95,7 +139,7 @@ const RandomSelectUserScreen: React.FC<{ route: any }> = ({ route }) => {
} else { } else {
Alert.alert('Error', 'Failed to determine a winner from the API.'); Alert.alert('Error', 'Failed to determine a winner from the API.');
} }
navigation.navigate('EditGroup',{groupId}) navigation.replace('EditGroup', { groupId })
} catch (error) { } catch (error) {
// Alert.alert('Error', 'Could not connect to the server to fetch the winner.'); // Alert.alert('Error', 'Could not connect to the server to fetch the winner.');
} finally { } finally {
@@ -103,7 +147,7 @@ const RandomSelectUserScreen: React.FC<{ route: any }> = ({ route }) => {
} }
}; };
const renderItem = ({ item, index }: { item: { id: string; name: string }, index: number }) => { const renderItem = ({ item, index }: { item: { id: string; name: string, selected: boolean }, index: number }) => {
const isHighlighted = index === highlightedIndex; const isHighlighted = index === highlightedIndex;
const isWinner = winner?.id === item.id && !isAnimating; const isWinner = winner?.id === item.id && !isAnimating;
@@ -119,6 +163,7 @@ const RandomSelectUserScreen: React.FC<{ route: any }> = ({ route }) => {
isHighlighted && styles.highlightedItem, isHighlighted && styles.highlightedItem,
isWinner && styles.winnerItem, isWinner && styles.winnerItem,
animatedStyle, animatedStyle,
{ backgroundColor: item?.selected ? colors.pastelGreen : '#fff' }
]} ]}
> >
<Ionicons name="person" size={40} color={isHighlighted || isWinner ? '#000000ff' : '#4b5563'} /> <Ionicons name="person" size={40} color={isHighlighted || isWinner ? '#000000ff' : '#4b5563'} />
@@ -223,14 +268,14 @@ const styles = StyleSheet.create({
borderWidth: 1, borderWidth: 1,
borderColor: '#e5e7eb', borderColor: '#e5e7eb',
padding: 8, padding: 8,
shadowColor: "#000", // shadowColor: "#000",
shadowOffset: { // shadowOffset: {
width: 0, // width: 0,
height: 2, // height: 2,
}, // },
shadowOpacity: 0.1, // shadowOpacity: 0.1,
shadowRadius: 3.84, // shadowRadius: 3.84,
elevation: 5, // elevation: 5,
}, },
highlightedItem: { highlightedItem: {
borderWidth: 5, borderWidth: 5,
+1 -1
View File
@@ -33,7 +33,7 @@ interface WinnerUserProps {
} }
visible: boolean visible: boolean
onClose: () => void onClose: () => void
groupId:string groupId:string | number
} }
const WinnerUser: React.FC<WinnerUserProps> = ({ data, visible, onClose, groupId }) => { const WinnerUser: React.FC<WinnerUserProps> = ({ data, visible, onClose, groupId }) => {
+2 -1
View File
@@ -16,6 +16,7 @@ import colors from "../../components/colors";
import { useNavigation } from "@react-navigation/native"; import { useNavigation } from "@react-navigation/native";
import AppView from "../../components/AppView"; import AppView from "../../components/AppView";
import { Ionicons } from "@react-native-vector-icons/ionicons"; import { Ionicons } from "@react-native-vector-icons/ionicons";
import { BASE_URL } from "../../utils/ApiUrls";
const BecomeOrg = () => { const BecomeOrg = () => {
const navigation = useNavigation<any>(); const navigation = useNavigation<any>();
@@ -43,7 +44,7 @@ const BecomeOrg = () => {
const token = credentials.password; const token = credentials.password;
const response = await fetch( const response = await fetch(
"http://192.168.1.5:9060/api/organizer/registration/apply", `${BASE_URL}organizer/registration/apply`,
{ {
method: "POST", method: "POST",
headers: { headers: {