import React, { useState } from "react"; import { View, Text, StyleSheet, ScrollView, KeyboardAvoidingView, Platform, TouchableOpacity, Alert, Image, } from "react-native"; import { useNavigation } from "@react-navigation/native"; import { CustomInput } from "../components/common/Custom"; import CustomButton from "../components/CustomButton"; import colors from "../components/colors"; import { launchImageLibrary } from "react-native-image-picker"; import Ionicons from "@react-native-vector-icons/ionicons"; import { UPLOAD_GROUP_IMAGE } from "../utils/ApiUrls"; export default function GroupCreationForm() { const navigation = useNavigation(); const [form, setForm] = useState({ groupName: "", description: "", visibility: "PRIVATE", withdrawalMethod: "RANDOM", minParticipants: "", maxParticipants: "", contributionAmount: "", cycleType: "MONTHLY", customCycleDays: "", lateFeeMode: "DAILY", lateFeeValue: "", }); const [errors, setErrors] = useState({}); const [selectedImage, setSelectedImage] = useState() const handleChange = (key: string, value: string) => { setForm({ ...form, [key]: value }); if (errors[key]) { setErrors({ ...errors, [key]: null }); } }; const cycleTypes = ["CUSTOM", "MONTHLY", "QUARTERLY", "YEARLY", "HALF_YEARLY"]; const distributionTypes = ["SEQUENTIAL", "RANDOM"]; const lateFeeModes = ["DAILY", "MONTHLY"]; const validateForm = () => { 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) <= 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."; console.log("new errors : ", newErrors) setErrors(newErrors); return Object.keys(newErrors).length === 0; }; const handleReview = () => { if (validateForm()) { const payload = { ...form, contributionAmount: Number(form.contributionAmount), customCycleDays: Number(form.customCycleDays) || 0, lateFeeValue: Number(form.lateFeeValue) || 0, maxParticipants: Number(form.maxParticipants), minParticipants: Number(form.minParticipants), }; console.log("Reviewing Payload:", payload); navigation.navigate("GroupReview", { form: payload }); } else { Alert.alert("Incomplete Form", "Please fill out all required fields correctly."); setErrors('') } }; return ( Create New Group handleChange("groupName", val)} icon="people" error={errors.groupName} /> handleChange("description", val)} multiline icon="document-text" error={errors.description} />
handleChange("visibility", val)} /> handleChange("withdrawalMethod", val)} />
handleChange("minParticipants", val)} keyboardType="numeric" icon="person-add" error={errors.minParticipants} /> handleChange("maxParticipants", val)} keyboardType="numeric" icon="people-circle" error={errors.maxParticipants} />
handleChange("contributionAmount", val)} keyboardType="numeric" icon="cash" error={errors.contributionAmount} /> handleChange("cycleType", val)} isWrap={true} /> {form.cycleType === "CUSTOM" && ( handleChange("customCycleDays", val)} keyboardType="numeric" icon="calendar" error={errors.customCycleDays} />)}
handleChange("lateFeeMode", val)} /> handleChange("lateFeeValue", val)} keyboardType="numeric" icon="alert-circle" error={errors.lateFeeValue} />
); } // --- Helper Components for a cleaner layout --- const Section: React.FC<{ title: string, children: React.ReactNode }> = ({ title, children }) => ( {title} {children} ); const SettingRow: React.FC<{ label: string, children: React.ReactNode }> = ({ label, children }) => ( {label} {children} ); const ToggleButtons: React.FC<{ options: string[], selectedValue: string, onSelect: (value: string) => void, isWrap?: boolean }> = ({ options, selectedValue, onSelect, isWrap = false }) => ( {options.map((option) => ( onSelect(option)} style={[styles.toggleButton, selectedValue === option && styles.selectedButton, isWrap && { flex: 0, paddingHorizontal: 15 }]} > {option.charAt(0) + option.slice(1).toLowerCase()} ))} ); const styles = StyleSheet.create({ container: { flexGrow: 1, padding: 16, backgroundColor: "#f5f6fa" }, titleContainer: { marginBottom: 20, paddingHorizontal: 4 }, title: { fontSize: 28, fontWeight: "bold", color: "#1F2937" }, section: { backgroundColor: '#fff', borderRadius: 12, padding: 16, marginBottom: 16, elevation: 1, shadowColor: '#4A5568', shadowOpacity: 0.06, shadowRadius: 10, }, sectionTitle: { fontSize: 18, fontWeight: '600', color: '#374151', marginBottom: 16, borderBottomWidth: 1, borderBottomColor: '#F3F4F6', paddingBottom: 10, }, avatarContainer: { position: "relative", marginBottom: 16, }, avatar: { width: 120, height: 120, borderRadius: 60, borderWidth: 4, borderColor: "#e2e8f0", }, cameraIcon: { position: "absolute", right: 0, bottom: 0, backgroundColor: colors.pastelBlue, borderRadius: 20, width: 40, height: 40, justifyContent: "center", alignItems: "center", borderWidth: 3, borderColor: "#fff", elevation: 2, }, settingRow: { marginBottom: 16, }, label: { fontSize: 14, fontWeight: "600", marginBottom: 8, color: "#4B5563" }, toggleContainer: { flexDirection: "row", gap: 10 }, toggleButton: { flex: 1, paddingVertical: 12, borderWidth: 1, borderColor: "#D1D5DB", borderRadius: 8, alignItems: "center", backgroundColor: "#F9FAFB" }, selectedButton: { backgroundColor: colors.pastelGreen, borderColor: "#62b59a" }, toggleButtonText: { color: "#374151", fontWeight: "600", textTransform: 'capitalize' }, selectedButtonText: { color: "#1F2937" }, participantsRow: { flexDirection: "row", gap: 15 }, participantInput: { flex: 1 }, });