all over
This commit is contained in:
@@ -52,12 +52,12 @@ export default function GroupCreationForm() {
|
|||||||
const newErrors: any = {};
|
const newErrors: any = {};
|
||||||
if (!form.groupName.trim()) newErrors.groupName = "Group name is required.";
|
if (!form.groupName.trim()) newErrors.groupName = "Group name is required.";
|
||||||
if (!form.description.trim()) newErrors.description = "Description is required.";
|
if (!form.description.trim()) newErrors.description = "Description is required.";
|
||||||
if (!form.minParticipants || Number(form.minParticipants) <= 1) newErrors.minParticipants = "Min participants must be at least 2.";
|
if (!form.minParticipants || Number(form.minParticipants) <= 0) newErrors.minParticipants = "Min participants must be at least 1.";
|
||||||
if (!form.maxParticipants || Number(form.maxParticipants) < Number(form.minParticipants)) newErrors.maxParticipants = "Max must be greater than or equal to min.";
|
if (!form.maxParticipants || Number(form.maxParticipants) < Number(form.minParticipants)) newErrors.maxParticipants = "Max must be greater than or equal to min.";
|
||||||
if (!form.contributionAmount || Number(form.contributionAmount) <= 0) newErrors.contributionAmount = "Amount must be greater than 0.";
|
if (!form.contributionAmount || Number(form.contributionAmount) <= 0) newErrors.contributionAmount = "Amount must be greater than 0.";
|
||||||
// if (form.cycleType === "CUSTOM" && (!form.customCycleDays || Number(form.customCycleDays) <= 0)) newErrors.customCycleDays = "Custom days must be greater than 0.";
|
if (form.cycleType === "CUSTOM" && (!form.customCycleDays || Number(form.customCycleDays) <= 0)) newErrors.customCycleDays = "Custom days must be greater than 0.";
|
||||||
if (form.lateFeeMode && (!form.lateFeeValue || Number(form.lateFeeValue) <= 0)) newErrors.lateFeeValue = "Late fee value is required.";
|
if (!form.lateFeeMode && (!form.lateFeeValue || Number(form.lateFeeValue) <= 0)) newErrors.lateFeeValue = "Late fee value is required.";
|
||||||
|
console.log("new errors : ", newErrors)
|
||||||
setErrors(newErrors);
|
setErrors(newErrors);
|
||||||
return Object.keys(newErrors).length === 0;
|
return Object.keys(newErrors).length === 0;
|
||||||
};
|
};
|
||||||
@@ -82,7 +82,6 @@ export default function GroupCreationForm() {
|
|||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
||||||
<KeyboardAvoidingView
|
<KeyboardAvoidingView
|
||||||
style={{ flex: 1, backgroundColor: "#f5f6fa", paddingTop: Platform.OS === "android" ? 40 : 0 }}
|
style={{ flex: 1, backgroundColor: "#f5f6fa", paddingTop: Platform.OS === "android" ? 40 : 0 }}
|
||||||
behavior={Platform.OS === "ios" ? "padding" : "height"}
|
behavior={Platform.OS === "ios" ? "padding" : "height"}
|
||||||
|
|||||||
@@ -178,11 +178,11 @@ export default function GroupScreen() {
|
|||||||
if (res.statusCode === 200) {
|
if (res.statusCode === 200) {
|
||||||
Alert.alert("Success", "You requested to join the group.");
|
Alert.alert("Success", "You requested to join the group.");
|
||||||
} else {
|
} else {
|
||||||
Alert.alert("Error", res.message || "Failed to join group.");
|
// Alert.alert("Error", res.message || "Failed to join group.");
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Join Group Error:", error);
|
console.error("Join Group Error:", error);
|
||||||
Alert.alert("Error", "An unexpected error occurred.");
|
// Alert.alert("Error", "An unexpected error occurred.");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ const handleSubmit = async () => {
|
|||||||
Alert.alert("Success", "Organizer registered successfully!");
|
Alert.alert("Success", "Organizer registered successfully!");
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
console.error("❌ Register Error:", err?.response?.data || err.message);
|
console.error("❌ Register Error:", err?.response?.data || err.message);
|
||||||
Alert.alert("Error", "Failed to register. Please try again.");
|
// Alert.alert("Error", "Failed to register. Please try again.");
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ const RequestList: React.FC = () => {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const errorMessage = error instanceof Error ? error.message : "An unknown error occurred";
|
const errorMessage = error instanceof Error ? error.message : "An unknown error occurred";
|
||||||
Alert.alert("Error", `Failed to accept request: ${errorMessage}`);
|
// Alert.alert("Error", `Failed to accept request: ${errorMessage}`);
|
||||||
console.error("Accept Error:", error);
|
console.error("Accept Error:", error);
|
||||||
} finally {
|
} finally {
|
||||||
setProcessingRequest(null);
|
setProcessingRequest(null);
|
||||||
@@ -198,7 +198,7 @@ const RequestList: React.FC = () => {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const errorMessage = error instanceof Error ? error.message : "An unknown error occurred";
|
const errorMessage = error instanceof Error ? error.message : "An unknown error occurred";
|
||||||
Alert.alert("Error", `Failed to decline request: ${errorMessage}`);
|
// Alert.alert("Error", `Failed to decline request: ${errorMessage}`);
|
||||||
console.error("Decline Error:", error);
|
console.error("Decline Error:", error);
|
||||||
} finally {
|
} finally {
|
||||||
setProcessingRequest(null);
|
setProcessingRequest(null);
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ const UserHome = () => {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("❌ Error fetching groups:", error);
|
console.error("❌ Error fetching groups:", error);
|
||||||
Alert.alert("Error", "Could not connect to server");
|
// Alert.alert("Error", "Could not connect to server");
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,12 +22,14 @@ import Clipboard from '@react-native-clipboard/clipboard';
|
|||||||
import { CompositeScreenProps, useNavigation } from '@react-navigation/native';
|
import { CompositeScreenProps, useNavigation } from '@react-navigation/native';
|
||||||
import { BottomTabScreenProps } from '@react-navigation/bottom-tabs';
|
import { BottomTabScreenProps } from '@react-navigation/bottom-tabs';
|
||||||
// Adjust path
|
// Adjust path
|
||||||
import { UPLOAD_GROUP_IMAGE } from '../../utils/ApiUrls';
|
import { BASE_URL, UPLOAD_GROUP_IMAGE } from '../../utils/ApiUrls';
|
||||||
import { launchImageLibrary } from 'react-native-image-picker';
|
import { launchImageLibrary } from 'react-native-image-picker';
|
||||||
import *as Keychain from 'react-native-keychain'
|
import *as Keychain from 'react-native-keychain'
|
||||||
import Ionicons from '@react-native-vector-icons/ionicons';
|
import Ionicons from '@react-native-vector-icons/ionicons';
|
||||||
import { CustomButton } from '../../components/common/Custom';
|
import { CustomButton } from '../../components/common/Custom';
|
||||||
import { StackNavigationProp } from '@react-navigation/stack';
|
import { StackNavigationProp } from '@react-navigation/stack';
|
||||||
|
import CustomModal from '../../components/common/CustomModal';
|
||||||
|
import WinnerUser from './WinnerUser';
|
||||||
|
|
||||||
|
|
||||||
// --- Type Definitions ---
|
// --- Type Definitions ---
|
||||||
@@ -91,7 +93,9 @@ type EditingCard = 'groupInfo' | 'financialRules' | 'configuration' | null;
|
|||||||
type GroupManagementNavProp = StackNavigationProp<RootStackParamList, 'EditGroup'>;
|
type GroupManagementNavProp = StackNavigationProp<RootStackParamList, 'EditGroup'>;
|
||||||
// --- Main Screen Component ---
|
// --- Main Screen Component ---
|
||||||
const EditGroupScreen: React.FC<EditGroupScreenProps> = ({ route }) => {
|
const EditGroupScreen: React.FC<EditGroupScreenProps> = ({ route }) => {
|
||||||
const { groupId } = route.params;
|
const { groupId } = route?.params;
|
||||||
|
|
||||||
|
console.log("edit group screen groupId : ", route?.params)
|
||||||
const navigation = useNavigation<GroupManagementNavProp>();
|
const navigation = useNavigation<GroupManagementNavProp>();
|
||||||
|
|
||||||
const [editingCard, setEditingCard] = useState<EditingCard>(null);
|
const [editingCard, setEditingCard] = useState<EditingCard>(null);
|
||||||
@@ -118,7 +122,8 @@ const EditGroupScreen: React.FC<EditGroupScreenProps> = ({ route }) => {
|
|||||||
const [currentCycle, setCurrentCycle] = useState<number | null>(null);
|
const [currentCycle, setCurrentCycle] = useState<number | null>(null);
|
||||||
const [selectedImage, setSelectedImage] = useState<string | null>()
|
const [selectedImage, setSelectedImage] = useState<string | null>()
|
||||||
const [imageUpdating, setImageUpdating] = useState<boolean>(false)
|
const [imageUpdating, setImageUpdating] = useState<boolean>(false)
|
||||||
|
const [selectedUser, setSelectedUser] = useState() as any
|
||||||
|
const [selectedUserModal, setSelectedUserModel] = useState(false)
|
||||||
const initializeEditableData = (data: GroupDetails) => {
|
const initializeEditableData = (data: GroupDetails) => {
|
||||||
setEditableData({
|
setEditableData({
|
||||||
groupName: data.groupName,
|
groupName: data.groupName,
|
||||||
@@ -139,8 +144,9 @@ const EditGroupScreen: React.FC<EditGroupScreenProps> = ({ route }) => {
|
|||||||
setLoading(true);
|
setLoading(true);
|
||||||
setError(null);
|
setError(null);
|
||||||
try {
|
try {
|
||||||
const response = await apiCall(`http://192.168.1.9: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 };
|
||||||
console.log("groupDetails", response)
|
console.log("groupDetails", response)
|
||||||
|
|
||||||
if (response.status === 'success' && response.data) {
|
if (response.status === 'success' && response.data) {
|
||||||
setGroupDetails(response.data);
|
setGroupDetails(response.data);
|
||||||
initializeEditableData(response.data);
|
initializeEditableData(response.data);
|
||||||
@@ -153,19 +159,32 @@ const EditGroupScreen: React.FC<EditGroupScreenProps> = ({ route }) => {
|
|||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
}, [groupId]);
|
}, [groupId]);
|
||||||
const getPaymentStatus = async()=>{
|
// const getPaymentStatus = async()=>{
|
||||||
const response = await apiCall(`http://192.168.1.9:9060/api/payments/group/${groupId}/payment/paid`, 'GET') as { status: string; data?: { currentCycle: number ,allPaid: boolean }; message?: string };
|
// const response = await apiCall(`${BASE_URL}payments/group/${groupId}/payment/paid`, 'GET') as { status: string; data?: { currentCycle: number ,status: boolean }; message?: string };
|
||||||
console.log("paymentStatus",response)
|
// console.log("paymentStatus",response)
|
||||||
if (response.status === 'success') {
|
// if (response.status === 'success') {
|
||||||
setPaymentStatus(response.data?.allPaid || false);
|
// setPaymentStatus(response.data?.status || false);
|
||||||
setCurrentCycle(response.data?.currentCycle || null);
|
// setCurrentCycle(response.data?.currentCycle || null);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
const getPaymentStatus = async () => {
|
||||||
|
const response = await apiCall(`${BASE_URL}payments/group/${groupId}/payment/paid`, 'GET') as { status: string; data?: { currentCycle: number, allPaid: boolean, selectedUser: any }; message?: string };
|
||||||
|
console.log("paymentStatus", response)
|
||||||
|
if (response.status === 'success') {
|
||||||
|
setPaymentStatus(response.data?.allPaid || false);
|
||||||
|
setCurrentCycle(response.data?.currentCycle || null);
|
||||||
|
setSelectedUser(response.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("groupid : ", groupId)
|
||||||
|
useEffect(() => {
|
||||||
|
getPaymentStatus()
|
||||||
|
}, [])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchGroupDetails();
|
fetchGroupDetails();
|
||||||
getPaymentStatus();
|
|
||||||
}, [fetchGroupDetails]);
|
}, [fetchGroupDetails]);
|
||||||
|
|
||||||
|
|
||||||
@@ -188,7 +207,7 @@ const getPaymentStatus = async()=>{
|
|||||||
|
|
||||||
setSaving(true);
|
setSaving(true);
|
||||||
try {
|
try {
|
||||||
await apiCall(`http://192.168.1.9:9060/api/fund/groups/${groupDetails.id}/edit`, 'PUT', editableData);
|
await apiCall(`${BASE_URL}fund/groups/${groupDetails.id}/edit`, 'PUT', editableData);
|
||||||
Alert.alert('Success', 'Group has been updated.');
|
Alert.alert('Success', 'Group has been updated.');
|
||||||
setEditingCard(null);
|
setEditingCard(null);
|
||||||
await fetchGroupDetails();
|
await fetchGroupDetails();
|
||||||
@@ -198,10 +217,14 @@ const getPaymentStatus = async()=>{
|
|||||||
setSaving(false);
|
setSaving(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const handleDistribute = async () => {
|
const handleDistribute = async () => {
|
||||||
navigation.navigate('RandomSelectUserScreen', { groupId: groupDetails?.id || '', cycleNumber: currentCycle || 0 });
|
navigation.navigate('RandomSelectUserScreen', { groupId , cycleNumber: currentCycle || 0 });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const handleStartGroup = async () => {
|
const handleStartGroup = async () => {
|
||||||
if (!groupDetails) return;
|
if (!groupDetails) return;
|
||||||
|
|
||||||
@@ -216,9 +239,10 @@ const getPaymentStatus = async()=>{
|
|||||||
onPress: async () => {
|
onPress: async () => {
|
||||||
setStarting(true);
|
setStarting(true);
|
||||||
try {
|
try {
|
||||||
await apiCall(`http://192.168.1.9:9060/api/fund/group/start?groupId=${groupDetails.id}`, 'GET');
|
await apiCall(`${BASE_URL}fund/group/start?groupId=${groupDetails.id}`, 'GET');
|
||||||
Alert.alert('Success', 'Group has been started successfully.');
|
Alert.alert('Success', 'Group has been started successfully.');
|
||||||
await fetchGroupDetails();
|
await fetchGroupDetails();
|
||||||
|
navigation.goBack()
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
Alert.alert('Start Error', e.message || 'An unexpected error occurred.');
|
Alert.alert('Start Error', e.message || 'An unexpected error occurred.');
|
||||||
} finally {
|
} finally {
|
||||||
@@ -235,7 +259,7 @@ const getPaymentStatus = async()=>{
|
|||||||
if (!groupDetails) return;
|
if (!groupDetails) return;
|
||||||
setInviting(true);
|
setInviting(true);
|
||||||
try {
|
try {
|
||||||
const response = await apiCall(`http://192.168.1.9:9060/api/invite/generate?groupId=${groupDetails.id}`, 'GET') as { data?: string };
|
const response = await apiCall(`${BASE_URL}invite/generate?groupId=${groupDetails.id}`, 'GET') as { data?: string };
|
||||||
|
|
||||||
|
|
||||||
const inviteLink = response.data;
|
const inviteLink = response.data;
|
||||||
@@ -354,6 +378,7 @@ const getPaymentStatus = async()=>{
|
|||||||
const isInvitable = groupDetails.status === 'APPROVED';
|
const isInvitable = groupDetails.status === 'APPROVED';
|
||||||
const canStartGroup = groupDetails.status === 'APPROVED' && groupDetails.totalParticipants >= groupDetails.minParticipants;
|
const canStartGroup = groupDetails.status === 'APPROVED' && groupDetails.totalParticipants >= groupDetails.minParticipants;
|
||||||
|
|
||||||
|
console.log(" myu status : ", groupDetails.status)
|
||||||
// const pickImage = () => {
|
// const pickImage = () => {
|
||||||
// launchImageLibrary({ mediaType: "photo", quality: 0.5 }, (response) => {
|
// launchImageLibrary({ mediaType: "photo", quality: 0.5 }, (response) => {
|
||||||
// if (response.didCancel) return;
|
// if (response.didCancel) return;
|
||||||
@@ -403,7 +428,7 @@ const getPaymentStatus = async()=>{
|
|||||||
|
|
||||||
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
|
||||||
});
|
});
|
||||||
@@ -461,7 +486,7 @@ const getPaymentStatus = async()=>{
|
|||||||
|
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error("❌ Error updating group image:", error);
|
console.error("❌ Error updating group image:", error);
|
||||||
Alert.alert("Error", error.message || "Could not update group image");
|
// Alert.alert("Error", error.message || "Could not update group image");
|
||||||
} finally {
|
} finally {
|
||||||
setImageUpdating(false);
|
setImageUpdating(false);
|
||||||
}
|
}
|
||||||
@@ -580,7 +605,7 @@ const getPaymentStatus = async()=>{
|
|||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
{paymentStatus && (
|
{selectedUser?.cycleStatus !== "PENDING_PAYMENTS" && groupDetails.status === 'ACTIVE' &&(
|
||||||
<View style={styles.floatingButtonContainer}>
|
<View style={styles.floatingButtonContainer}>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={styles.activateButton}
|
style={styles.activateButton}
|
||||||
@@ -594,7 +619,24 @@ const getPaymentStatus = async()=>{
|
|||||||
)}
|
)}
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
selectedUser?.selectedUser !== null && selectedUser?.cycleStatus === "READY_FOR_WITHDRAWAL" && selectedUser?.canProceedToWithdrawal &&
|
||||||
|
<View style={styles.floatingButtonContainer}>
|
||||||
|
<CustomButton
|
||||||
|
buttonBackground={colors?.pastelBlue}
|
||||||
|
style={{ paddingHorizontal: 20 }}
|
||||||
|
title="View Winner of this Cycle"
|
||||||
|
onPress={() => setSelectedUserModel(true)}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
selectedUserModal && <WinnerUser groupId={groupId} data={selectedUser} visible={selectedUserModal} onClose={() => setSelectedUserModel(false)} />
|
||||||
|
}
|
||||||
</AppView>
|
</AppView>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ const ManagementScreen: FC = () => {
|
|||||||
throw new Error(res?.message || failureMessage);
|
throw new Error(res?.message || failureMessage);
|
||||||
}
|
}
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
Alert.alert("Error", err.message || "An unexpected error occurred.");
|
// Alert.alert("Error", err.message || "An unexpected error occurred.");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { Ionicons } from "@react-native-vector-icons/ionicons";
|
|||||||
import colors from '../../components/colors';
|
import colors from '../../components/colors';
|
||||||
import AppView from '../../components/AppView';
|
import AppView from '../../components/AppView';
|
||||||
import { apiCall } from '../../utils/ApiHelper';
|
import { apiCall } from '../../utils/ApiHelper';
|
||||||
|
import { BASE_URL } from '../../utils/ApiUrls';
|
||||||
|
|
||||||
// --- CONSTANTS ---
|
// --- CONSTANTS ---
|
||||||
const API_BASE_URL = 'http://192.168.1.9:9060/api/payments';
|
const API_BASE_URL = 'http://192.168.1.9:9060/api/payments';
|
||||||
@@ -73,14 +74,17 @@ const Payments: React.FC = () => {
|
|||||||
const fetchPaymentDetails = useCallback(async () => {
|
const fetchPaymentDetails = useCallback(async () => {
|
||||||
if (!refreshing) setLoading(true);
|
if (!refreshing) setLoading(true);
|
||||||
try {
|
try {
|
||||||
const response = await apiCall(`${API_BASE_URL}/current/payment/details/${groupId}`, 'GET') as ApiResponse<PaymentDetails>;
|
const response = await apiCall(`${BASE_URL}payments/current/payment/details/${groupId}`, 'GET') as ApiResponse<PaymentDetails>;
|
||||||
|
|
||||||
|
console.log("payment response :", response)
|
||||||
if (response && response.statusCode === 200) {
|
if (response && response.statusCode === 200) {
|
||||||
setPaymentDetails(response.data);
|
setPaymentDetails(response.data);
|
||||||
} else {
|
} else {
|
||||||
Alert.alert("Error", response?.message || "Failed to fetch details.");
|
Alert.alert("Error", response?.message || "Failed to fetch details.");
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
Alert.alert("Error", error.message || "An unexpected error occurred.");
|
// Alert.alert("Error", error.message || "An unexpected error occurred.");
|
||||||
|
console.log("payment error : ", error)
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
setRefreshing(false);
|
setRefreshing(false);
|
||||||
@@ -122,9 +126,9 @@ const Payments: React.FC = () => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// Construct the exact URL as provided
|
// Construct the exact URL as provided
|
||||||
const url = `${API_BASE_URL}/groups/${groupId}/cycles/${paymentDetails.currentCycle}/waive/${currentParticipant.userId}?amountToWaive=${amountToWaive}`;
|
const url = `${BASE_URL}groups/${groupId}/cycles/${paymentDetails.currentCycle}/waive/${currentParticipant.userId}?amountToWaive=${amountToWaive}`;
|
||||||
|
|
||||||
const response = await apiCall(url, 'PUT', {}); // Body is empty as amount is in URL
|
const response = await apiCall(url, 'PUT', {}) as any; // Body is empty as amount is in URL
|
||||||
|
|
||||||
if (response && response.statusCode === 200) {
|
if (response && response.statusCode === 200) {
|
||||||
Alert.alert("Success", `₹${amountToWaive} has been waived successfully.`);
|
Alert.alert("Success", `₹${amountToWaive} has been waived successfully.`);
|
||||||
|
|||||||
@@ -4,14 +4,17 @@ import { apiCall } from '../../utils/ApiHelper';
|
|||||||
import { Ionicons } from "@react-native-vector-icons/ionicons";
|
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';
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
const RandomSelectUserScreen: React.FC<{ route: any }> = ({ route }) => {
|
const RandomSelectUserScreen: React.FC<{ route: any }> = ({ route }) => {
|
||||||
const navigation = useNavigation() as never
|
const navigation = useNavigation()
|
||||||
const { groupId, cycleNumber } = route.params;
|
const { groupId, cycleNumber } = route.params;
|
||||||
|
|
||||||
|
|
||||||
const [users, setUsers] = useState<{ id: string; name: string }[]>([]);
|
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);
|
||||||
@@ -24,7 +27,7 @@ const RandomSelectUserScreen: React.FC<{ route: any }> = ({ route }) => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchParticipants = async () => {
|
const fetchParticipants = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await apiCall(`http://192.168.1.9:9060/api/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,
|
||||||
@@ -77,7 +80,7 @@ const RandomSelectUserScreen: React.FC<{ route: any }> = ({ route }) => {
|
|||||||
const fetchWinner = async () => {
|
const fetchWinner = async () => {
|
||||||
const payload = { groupId: groupId };
|
const payload = { groupId: groupId };
|
||||||
try {
|
try {
|
||||||
const response = await apiCall('http://192.168.1.9:9060/api/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}` };
|
||||||
@@ -92,6 +95,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})
|
||||||
} 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 {
|
||||||
@@ -156,7 +160,6 @@ const RandomSelectUserScreen: React.FC<{ route: any }> = ({ route }) => {
|
|||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Button title='Pay' onPress={() => setOpenModal(true)} />
|
|
||||||
{
|
{
|
||||||
openModal && <ContributionDetails data={undefined} visible={openModal} onClose={() => setOpenModal(false)} onConfirm={() => setOpenModal(false)} />
|
openModal && <ContributionDetails data={undefined} visible={openModal} onClose={() => setOpenModal(false)} onConfirm={() => setOpenModal(false)} />
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,251 @@
|
|||||||
|
import React, { useEffect, useRef } from 'react'
|
||||||
|
import { StyleSheet, Text, View, Animated, ToastAndroid } from 'react-native'
|
||||||
|
import { Ionicons } from '@react-native-vector-icons/ionicons'
|
||||||
|
import CustomModal from '../../components/common/CustomModal'
|
||||||
|
import { apiCall } from '../../utils/ApiHelper'
|
||||||
|
import { BASE_URL } from '../../utils/ApiUrls'
|
||||||
|
|
||||||
|
interface WinnerUserProps {
|
||||||
|
data: {
|
||||||
|
withdrawalDone: boolean
|
||||||
|
selectionDone: boolean
|
||||||
|
selectionId: string
|
||||||
|
currentCycle: number
|
||||||
|
pendingParticipants: number
|
||||||
|
withdrawalDetails: any
|
||||||
|
paidParticipants: number
|
||||||
|
selectedUser: {
|
||||||
|
firstName: string
|
||||||
|
lastName: string
|
||||||
|
mobile: string
|
||||||
|
id: string
|
||||||
|
userId: number
|
||||||
|
email: string
|
||||||
|
}
|
||||||
|
cycleEndDate: number[]
|
||||||
|
cycleStartDate: number[]
|
||||||
|
allPaid: boolean
|
||||||
|
selectionDate: number[]
|
||||||
|
totalParticipants: number
|
||||||
|
cycleStatus: string
|
||||||
|
selectionMethod: string
|
||||||
|
canProceedToWithdrawal: boolean
|
||||||
|
}
|
||||||
|
visible: boolean
|
||||||
|
onClose: () => void
|
||||||
|
groupId:string
|
||||||
|
}
|
||||||
|
|
||||||
|
const WinnerUser: React.FC<WinnerUserProps> = ({ data, visible, onClose, groupId }) => {
|
||||||
|
const {
|
||||||
|
withdrawalDone,
|
||||||
|
selectionDone,
|
||||||
|
currentCycle,
|
||||||
|
totalParticipants,
|
||||||
|
paidParticipants,
|
||||||
|
pendingParticipants,
|
||||||
|
allPaid,
|
||||||
|
selectedUser,
|
||||||
|
cycleStatus,
|
||||||
|
selectionMethod,
|
||||||
|
canProceedToWithdrawal,
|
||||||
|
} = data || {}
|
||||||
|
|
||||||
|
const scaleAnim = useRef(new Animated.Value(0)).current
|
||||||
|
const pulseAnim = useRef(new Animated.Value(1)).current
|
||||||
|
const fadeAnim = useRef(new Animated.Value(0)).current
|
||||||
|
|
||||||
|
console.log("winner data : ", data)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (visible) {
|
||||||
|
Animated.spring(scaleAnim, {
|
||||||
|
toValue: 1,
|
||||||
|
friction: 5,
|
||||||
|
useNativeDriver: true,
|
||||||
|
}).start()
|
||||||
|
|
||||||
|
Animated.loop(
|
||||||
|
Animated.sequence([
|
||||||
|
Animated.timing(pulseAnim, {
|
||||||
|
toValue: 1.1,
|
||||||
|
duration: 600,
|
||||||
|
useNativeDriver: true,
|
||||||
|
}),
|
||||||
|
Animated.timing(pulseAnim, {
|
||||||
|
toValue: 1,
|
||||||
|
duration: 600,
|
||||||
|
useNativeDriver: true,
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
).start()
|
||||||
|
|
||||||
|
Animated.timing(fadeAnim, {
|
||||||
|
toValue: 1,
|
||||||
|
duration: 1500,
|
||||||
|
useNativeDriver: true,
|
||||||
|
}).start()
|
||||||
|
} else {
|
||||||
|
scaleAnim.setValue(0)
|
||||||
|
pulseAnim.setValue(1)
|
||||||
|
fadeAnim.setValue(0)
|
||||||
|
}
|
||||||
|
}, [visible])
|
||||||
|
|
||||||
|
const onConfirm = async () => {
|
||||||
|
try {
|
||||||
|
const res = await apiCall(`${BASE_URL}payments/withdraw/${groupId}/${data?.selectedUser?.id}`, 'PUT')
|
||||||
|
console.log("res winner user : ", res)
|
||||||
|
ToastAndroid.show('Withdrawal successful', ToastAndroid.SHORT)
|
||||||
|
onClose()
|
||||||
|
} catch (error) {
|
||||||
|
console.log('Confirm payment error : ', error)
|
||||||
|
} finally {
|
||||||
|
onClose()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<CustomModal
|
||||||
|
visible={visible}
|
||||||
|
onClose={onClose}
|
||||||
|
confirmText={canProceedToWithdrawal ? 'Proceed to Withdraw' : 'Close'}
|
||||||
|
onConfirm={canProceedToWithdrawal ? onConfirm : onClose}
|
||||||
|
>
|
||||||
|
<View style={styles.container}>
|
||||||
|
<Animated.View style={{ transform: [{ scale: scaleAnim }] }}>
|
||||||
|
{/* Header */}
|
||||||
|
<View style={styles.header}>
|
||||||
|
<Ionicons name="trophy" size={24} color="#ff9800" />
|
||||||
|
<Text style={styles.cycle}>Cycle {currentCycle} Winner</Text>
|
||||||
|
<Ionicons name="trophy" size={24} color="#ff9800" />
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* Winner Name */}
|
||||||
|
<Animated.Text style={[styles.name, { transform: [{ scale: pulseAnim }] }]}>
|
||||||
|
{selectedUser?.firstName} {selectedUser?.lastName}
|
||||||
|
</Animated.Text>
|
||||||
|
|
||||||
|
{/* Details */}
|
||||||
|
<View style={styles.row}>
|
||||||
|
<Ionicons name="call" size={18} color="#555" />
|
||||||
|
<Text style={styles.label}>Mobile:</Text>
|
||||||
|
<Text style={styles.value}>{selectedUser?.mobile}</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={styles.row}>
|
||||||
|
<Ionicons name="mail" size={18} color="#555" />
|
||||||
|
<Text style={styles.label}>Email:</Text>
|
||||||
|
<Text style={styles.value}>{selectedUser?.email}</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={styles.row}>
|
||||||
|
<Ionicons name="people" size={18} color="#555" />
|
||||||
|
<Text style={styles.label}>Total Participants:</Text>
|
||||||
|
<Text style={styles.value}>{totalParticipants}</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={styles.row}>
|
||||||
|
<Ionicons name="cash" size={18} color="#555" />
|
||||||
|
<Text style={styles.label}>Paid Participants:</Text>
|
||||||
|
<Text style={styles.value}>{paidParticipants}</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={styles.row}>
|
||||||
|
<Ionicons name="hourglass" size={18} color="#555" />
|
||||||
|
<Text style={styles.label}>Pending Participants:</Text>
|
||||||
|
<Text style={styles.value}>{pendingParticipants}</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={styles.row}>
|
||||||
|
<Ionicons
|
||||||
|
name={allPaid ? 'checkmark-circle' : 'close-circle'}
|
||||||
|
size={18}
|
||||||
|
color={allPaid ? '#4caf50' : '#f44336'}
|
||||||
|
/>
|
||||||
|
<Text style={styles.label}>All Paid:</Text>
|
||||||
|
<Text style={styles.value}>{allPaid ? 'Yes' : 'No'}</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={styles.row}>
|
||||||
|
<Ionicons
|
||||||
|
name={withdrawalDone ? 'checkmark-done' : 'time'}
|
||||||
|
size={18}
|
||||||
|
color={withdrawalDone ? '#4caf50' : '#ff9800'}
|
||||||
|
/>
|
||||||
|
<Text style={styles.label}>Withdrawal Status:</Text>
|
||||||
|
<Text style={styles.value}>{withdrawalDone ? 'Completed' : 'Pending'}</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={styles.row}>
|
||||||
|
<Ionicons name="git-branch" size={18} color="#555" />
|
||||||
|
<Text style={styles.label}>Selection Method:</Text>
|
||||||
|
<Text style={styles.value}>{selectionMethod}</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={styles.row}>
|
||||||
|
<Ionicons name="stats-chart" size={18} color="#555" />
|
||||||
|
<Text style={styles.label}>Cycle Status:</Text>
|
||||||
|
<Text style={styles.value}>{cycleStatus}</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<Animated.Text style={[styles.congrats, { opacity: fadeAnim }]}>
|
||||||
|
{selectionDone ? 'Congratulations!' : 'Selection Pending'}
|
||||||
|
</Animated.Text>
|
||||||
|
</Animated.View>
|
||||||
|
</View>
|
||||||
|
</CustomModal>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default WinnerUser
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
padding: 20,
|
||||||
|
},
|
||||||
|
header: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: 8,
|
||||||
|
marginBottom: 16,
|
||||||
|
justifyContent: 'center',
|
||||||
|
},
|
||||||
|
cycle: {
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: '700',
|
||||||
|
color: '#ff9800',
|
||||||
|
marginHorizontal: 8,
|
||||||
|
textAlign: 'center',
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
fontSize: 22,
|
||||||
|
fontWeight: '800',
|
||||||
|
color: '#333',
|
||||||
|
marginBottom: 20,
|
||||||
|
textAlign: 'center',
|
||||||
|
},
|
||||||
|
row: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
marginBottom: 12,
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: '600',
|
||||||
|
color: '#555',
|
||||||
|
marginLeft: 6,
|
||||||
|
marginRight: 4,
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
fontSize: 16,
|
||||||
|
color: '#000',
|
||||||
|
},
|
||||||
|
congrats: {
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: '700',
|
||||||
|
color: '#4caf50',
|
||||||
|
marginTop: 20,
|
||||||
|
textAlign: 'center',
|
||||||
|
},
|
||||||
|
})
|
||||||
@@ -71,7 +71,7 @@ const BecomeOrg = () => {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("❌ Registration error:", error);
|
console.error("❌ Registration error:", error);
|
||||||
Alert.alert("Error", "An unexpected error occurred. Please try again.");
|
// Alert.alert("Error", "An unexpected error occurred. Please try again.");
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ const EditBankDetails = () => {
|
|||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error("Error updating bank details:", error);
|
console.error("Error updating bank details:", error);
|
||||||
Alert.alert("Error", error.message || "An unexpected error occurred. Please try again.");
|
// Alert.alert("Error", error.message || "An unexpected error occurred. Please try again.");
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ const Profile = () => {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("❌ Error fetching profile:", error);
|
console.error("❌ Error fetching profile:", error);
|
||||||
Alert.alert("Error", "Could not connect to server");
|
// Alert.alert("Error", "Could not connect to server");
|
||||||
} finally {
|
} finally {
|
||||||
setFetching(false);
|
setFetching(false);
|
||||||
}
|
}
|
||||||
@@ -164,7 +164,7 @@ const Profile = () => {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("❌ Error updating profile:", error);
|
console.error("❌ Error updating profile:", error);
|
||||||
Alert.alert("Error", "Could not update profile");
|
// Alert.alert("Error", "Could not update profile");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -245,7 +245,7 @@ const Profile = () => {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("❌ Error updating profile image:", error);
|
console.error("❌ Error updating profile image:", error);
|
||||||
Alert.alert("Error", "Could not update profile image");
|
// Alert.alert("Error", "Could not update profile image");
|
||||||
} finally {
|
} finally {
|
||||||
setImageUpdating(false);
|
setImageUpdating(false);
|
||||||
}
|
}
|
||||||
@@ -311,7 +311,7 @@ const Profile = () => {
|
|||||||
navigation.replace("Login");
|
navigation.replace("Login");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Logout error:", error);
|
console.error("Logout error:", error);
|
||||||
Alert.alert("Error", "Failed to log out. Please try again.");
|
// Alert.alert("Error", "Failed to log out. Please try again.");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
export const BASE_URL = "http://192.168.1.9:9060/api/"
|
|
||||||
// export const BASE_URL = "https://api.godemo.in/FundCollect/api/"
|
// export const BASE_URL = "https://api.godemo.in/FundCollect/api/"
|
||||||
|
export const BASE_URL = "http://192.168.1.9:9060/api/"
|
||||||
export const LOGIN_URL = `${BASE_URL}user/generate/otp?mobiles=`
|
export const LOGIN_URL = `${BASE_URL}user/generate/otp?mobiles=`
|
||||||
export const VARIFY_OTP_URL = `${BASE_URL}user/otp/verify`
|
export const VARIFY_OTP_URL = `${BASE_URL}user/otp/verify`
|
||||||
export const ORGRAGISTRATION = `${BASE_URL}organizer/registration/apply`
|
export const ORGRAGISTRATION = `${BASE_URL}organizer/registration/apply`
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ export const fetchUserProfile = async () => {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("❌ Error fetching profile:", error);
|
console.error("❌ Error fetching profile:", error);
|
||||||
Alert.alert("Error", "Could not connect to server");
|
// Alert.alert("Error", "Could not connect to server");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user