From 9154a1482c97d27d70d02833c1b4ffe1048273a2 Mon Sep 17 00:00:00 2001 From: Jaanu423 Date: Wed, 1 Oct 2025 15:44:11 +0530 Subject: [PATCH] align business logic organizer side --- src/screens/GroupCreation.tsx | 9 +- src/screens/GroupScreen.tsx | 6 +- src/screens/OrgnizerRagister.tsx | 2 +- src/screens/home/RequestList.tsx | 4 +- src/screens/home/user-home/UserHome.tsx | 2 +- src/screens/management/EditGroupScreen.tsx | 63 +++-- src/screens/management/ManagementScreen.tsx | 2 +- src/screens/management/Payments.tsx | 12 +- .../management/RandomSelectUserScreen.tsx | 11 +- src/screens/management/WinnerUser.tsx | 251 ++++++++++++++++++ src/screens/profile/BecomeOrg.tsx | 2 +- src/screens/profile/EditBankDetails.tsx | 2 +- src/screens/profile/Profile.tsx | 8 +- src/utils/ApiUrls.tsx | 3 +- src/utils/HelperFunction.tsx | 2 +- 15 files changed, 335 insertions(+), 44 deletions(-) create mode 100644 src/screens/management/WinnerUser.tsx diff --git a/src/screens/GroupCreation.tsx b/src/screens/GroupCreation.tsx index 62a08bf..e51bd18 100644 --- a/src/screens/GroupCreation.tsx +++ b/src/screens/GroupCreation.tsx @@ -52,12 +52,12 @@ export default function GroupCreationForm() { const newErrors: any = {}; if (!form.groupName.trim()) newErrors.groupName = "Group name 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.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.lateFeeMode && (!form.lateFeeValue || Number(form.lateFeeValue) <= 0)) newErrors.lateFeeValue = "Late fee value is required."; - + 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."; + console.log("new errors : ", newErrors) setErrors(newErrors); return Object.keys(newErrors).length === 0; }; @@ -82,7 +82,6 @@ export default function GroupCreationForm() { return ( - { Alert.alert("Success", "Organizer registered successfully!"); } catch (err: any) { 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 { setLoading(false); } diff --git a/src/screens/home/RequestList.tsx b/src/screens/home/RequestList.tsx index 6668595..c58d5ad 100644 --- a/src/screens/home/RequestList.tsx +++ b/src/screens/home/RequestList.tsx @@ -152,7 +152,7 @@ const RequestList: React.FC = () => { } } catch (error) { 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); } finally { setProcessingRequest(null); @@ -198,7 +198,7 @@ const RequestList: React.FC = () => { } } catch (error) { 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); } finally { setProcessingRequest(null); diff --git a/src/screens/home/user-home/UserHome.tsx b/src/screens/home/user-home/UserHome.tsx index 57da78e..869de65 100644 --- a/src/screens/home/user-home/UserHome.tsx +++ b/src/screens/home/user-home/UserHome.tsx @@ -84,7 +84,7 @@ const UserHome = () => { } } catch (error) { console.error("❌ Error fetching groups:", error); - Alert.alert("Error", "Could not connect to server"); + // Alert.alert("Error", "Could not connect to server"); } finally { setLoading(false) } diff --git a/src/screens/management/EditGroupScreen.tsx b/src/screens/management/EditGroupScreen.tsx index 00c5996..fc6832a 100644 --- a/src/screens/management/EditGroupScreen.tsx +++ b/src/screens/management/EditGroupScreen.tsx @@ -22,12 +22,14 @@ import Clipboard from '@react-native-clipboard/clipboard'; import { CompositeScreenProps, useNavigation } from '@react-navigation/native'; import { BottomTabScreenProps } from '@react-navigation/bottom-tabs'; // 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 *as Keychain from 'react-native-keychain' import Ionicons from '@react-native-vector-icons/ionicons'; import { CustomButton } from '../../components/common/Custom'; import { StackNavigationProp } from '@react-navigation/stack'; +import CustomModal from '../../components/common/CustomModal'; +import WinnerUser from './WinnerUser'; // --- Type Definitions --- @@ -91,7 +93,9 @@ type EditingCard = 'groupInfo' | 'financialRules' | 'configuration' | null; type GroupManagementNavProp = StackNavigationProp; // --- Main Screen Component --- const EditGroupScreen: React.FC = ({ route }) => { - const { groupId } = route.params; + const { groupId } = route?.params; + + console.log("edit group screen groupId : ", route?.params) const navigation = useNavigation(); const [editingCard, setEditingCard] = useState(null); @@ -118,7 +122,8 @@ const EditGroupScreen: React.FC = ({ route }) => { const [currentCycle, setCurrentCycle] = useState(null); const [selectedImage, setSelectedImage] = useState() const [imageUpdating, setImageUpdating] = useState(false) - + const [selectedUser, setSelectedUser] = useState() as any + const [selectedUserModal, setSelectedUserModel] = useState(false) const initializeEditableData = (data: GroupDetails) => { setEditableData({ groupName: data.groupName, @@ -139,8 +144,9 @@ const EditGroupScreen: React.FC = ({ route }) => { setLoading(true); setError(null); try { - const response = await apiCall(`https://exotic-humpback-mistakenly.ngrok-free.app/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) + if (response.status === 'success' && response.data) { setGroupDetails(response.data); initializeEditableData(response.data); @@ -154,7 +160,7 @@ const EditGroupScreen: React.FC = ({ route }) => { } }, [groupId]); // const getPaymentStatus = async()=>{ - // const response = await apiCall(`https://exotic-humpback-mistakenly.ngrok-free.app/api/payments/group/${groupId}/payment/paid`, 'GET') as { status: string; data?: { currentCycle: number ,status: 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) // if (response.status === 'success') { // setPaymentStatus(response.data?.status || false); @@ -163,18 +169,22 @@ const EditGroupScreen: React.FC = ({ route }) => { // } const getPaymentStatus = async () => { - const response = await apiCall(`https://exotic-humpback-mistakenly.ngrok-free.app/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, 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(() => { fetchGroupDetails(); - getPaymentStatus(); }, [fetchGroupDetails]); @@ -197,7 +207,7 @@ const EditGroupScreen: React.FC = ({ route }) => { setSaving(true); try { - await apiCall(`https://exotic-humpback-mistakenly.ngrok-free.app/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.'); setEditingCard(null); await fetchGroupDetails(); @@ -207,10 +217,14 @@ const EditGroupScreen: React.FC = ({ route }) => { setSaving(false); } }; + + const handleDistribute = async () => { - navigation.navigate('RandomSelectUserScreen', { groupId: groupDetails?.id || '', cycleNumber: currentCycle || 0 }); + navigation.navigate('RandomSelectUserScreen', { groupId , cycleNumber: currentCycle || 0 }); }; + + const handleStartGroup = async () => { if (!groupDetails) return; @@ -225,9 +239,10 @@ const EditGroupScreen: React.FC = ({ route }) => { onPress: async () => { setStarting(true); try { - await apiCall(`https://exotic-humpback-mistakenly.ngrok-free.app/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.'); await fetchGroupDetails(); + navigation.goBack() } catch (e: any) { Alert.alert('Start Error', e.message || 'An unexpected error occurred.'); } finally { @@ -244,7 +259,7 @@ const EditGroupScreen: React.FC = ({ route }) => { if (!groupDetails) return; setInviting(true); try { - const response = await apiCall(`https://exotic-humpback-mistakenly.ngrok-free.app/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; @@ -363,6 +378,7 @@ const EditGroupScreen: React.FC = ({ route }) => { const isInvitable = groupDetails.status === 'APPROVED'; const canStartGroup = groupDetails.status === 'APPROVED' && groupDetails.totalParticipants >= groupDetails.minParticipants; + console.log(" myu status : ", groupDetails.status) // const pickImage = () => { // launchImageLibrary({ mediaType: "photo", quality: 0.5 }, (response) => { // if (response.didCancel) return; @@ -412,7 +428,7 @@ const EditGroupScreen: React.FC = ({ route }) => { console.log("✅ Image selected:", { uri: selectedImage.uri, - size: (selectedImage.fileSize / 1024).toFixed(2) + "KB", + size: (selectedImage?.fileSize / 1024).toFixed(2) + "KB", width: selectedImage.width, height: selectedImage.height }); @@ -470,7 +486,7 @@ const EditGroupScreen: React.FC = ({ route }) => { } catch (error: any) { 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 { setImageUpdating(false); } @@ -589,7 +605,7 @@ const EditGroupScreen: React.FC = ({ route }) => { )} - {paymentStatus && ( + {selectedUser?.cycleStatus !== "PENDING_PAYMENTS" && groupDetails.status === 'ACTIVE' &&( = ({ route }) => { )} - )} + ) + } + + { + selectedUser?.selectedUser !== null && selectedUser?.cycleStatus === "READY_FOR_WITHDRAWAL" && selectedUser?.canProceedToWithdrawal && + + setSelectedUserModel(true)} + /> + + } + + { + selectedUserModal && setSelectedUserModel(false)} /> + } ); }; diff --git a/src/screens/management/ManagementScreen.tsx b/src/screens/management/ManagementScreen.tsx index 1ea0cc6..82de7b7 100644 --- a/src/screens/management/ManagementScreen.tsx +++ b/src/screens/management/ManagementScreen.tsx @@ -114,7 +114,7 @@ const ManagementScreen: FC = () => { throw new Error(res?.message || failureMessage); } } catch (err: any) { - Alert.alert("Error", err.message || "An unexpected error occurred."); + // Alert.alert("Error", err.message || "An unexpected error occurred."); } }; diff --git a/src/screens/management/Payments.tsx b/src/screens/management/Payments.tsx index f6af32b..5bb7c6d 100644 --- a/src/screens/management/Payments.tsx +++ b/src/screens/management/Payments.tsx @@ -5,6 +5,7 @@ import { Ionicons } from "@react-native-vector-icons/ionicons"; import colors from '../../components/colors'; import AppView from '../../components/AppView'; import { apiCall } from '../../utils/ApiHelper'; +import { BASE_URL } from '../../utils/ApiUrls'; // --- CONSTANTS --- const API_BASE_URL = 'https://exotic-humpback-mistakenly.ngrok-free.app/api/payments'; @@ -58,14 +59,17 @@ const Payments: React.FC = () => { const fetchPaymentDetails = useCallback(async () => { if (!refreshing) setLoading(true); try { - const response = await apiCall(`${API_BASE_URL}/current/payment/details/${groupId}`, 'GET') as ApiResponse; + const response = await apiCall(`${BASE_URL}payments/current/payment/details/${groupId}`, 'GET') as ApiResponse; + + console.log("payment response :", response) if (response && response.statusCode === 200) { setPaymentDetails(response.data); } else { Alert.alert("Error", response?.message || "Failed to fetch details."); } } 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 { setLoading(false); setRefreshing(false); @@ -105,9 +109,9 @@ const Payments: React.FC = () => { try { // 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) { Alert.alert("Success", `₹${amountToWaive} has been waived successfully.`); diff --git a/src/screens/management/RandomSelectUserScreen.tsx b/src/screens/management/RandomSelectUserScreen.tsx index 7d9ccae..1cddebb 100644 --- a/src/screens/management/RandomSelectUserScreen.tsx +++ b/src/screens/management/RandomSelectUserScreen.tsx @@ -4,14 +4,17 @@ import { apiCall } from '../../utils/ApiHelper'; import { Ionicons } from "@react-native-vector-icons/ionicons"; import { useNavigation } from '@react-navigation/native'; import ContributionDetails from '../ContributionScreen'; +import { BASE_URL } from '../../utils/ApiUrls'; const { width } = Dimensions.get('window'); const NUM_COLUMNS = 3; const ITEM_SIZE = width / NUM_COLUMNS - 20; const RandomSelectUserScreen: React.FC<{ route: any }> = ({ route }) => { - const navigation = useNavigation() as never + const navigation = useNavigation() const { groupId, cycleNumber } = route.params; + + const [users, setUsers] = useState<{ id: string; name: string }[]>([]); const [highlightedIndex, setHighlightedIndex] = useState(null); const [winner, setWinner] = useState<{ id: string; name: string } | null>(null); @@ -24,7 +27,7 @@ const RandomSelectUserScreen: React.FC<{ route: any }> = ({ route }) => { useEffect(() => { const fetchParticipants = async () => { try { - const response = await apiCall(`https://exotic-humpback-mistakenly.ngrok-free.app/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) { const formattedUsers = response.data.map((u: any) => ({ id: u.id, @@ -77,7 +80,7 @@ const RandomSelectUserScreen: React.FC<{ route: any }> = ({ route }) => { const fetchWinner = async () => { const payload = { groupId: groupId }; try { - const response = await apiCall('https://exotic-humpback-mistakenly.ngrok-free.app/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) if (response.status === 'success' && response.data?.selectedUser?.id) { 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 { Alert.alert('Error', 'Failed to determine a winner from the API.'); } + navigation.navigate('EditGroup',{groupId}) } catch (error) { // Alert.alert('Error', 'Could not connect to the server to fetch the winner.'); } finally { @@ -156,7 +160,6 @@ const RandomSelectUserScreen: React.FC<{ route: any }> = ({ route }) => { )} -