From dd603dcff71e853baf600ac7be5639877b8a5468 Mon Sep 17 00:00:00 2001 From: Jaanu423 Date: Wed, 17 Sep 2025 16:24:06 +0530 Subject: [PATCH] Requeste api implelented --- package-lock.json | 16 + package.json | 1 + src/components/colors.ts | 2 +- src/redux/userSlice.ts | 34 +- src/screens/LoginScreen.tsx | 44 +- src/screens/OtpVarificationScreen.tsx | 7 +- src/screens/SplashScreen.tsx | 74 +++- src/screens/home/DeclineModal.tsx | 74 ++++ src/screens/home/GroupList.tsx | 86 ++-- src/screens/home/GroupsTabs.tsx | 207 ++------- src/screens/home/Home.tsx | 27 +- src/screens/home/RequestList.tsx | 606 ++++++++++++++++++++++++++ src/screens/profile/Profile.tsx | 46 +- 13 files changed, 921 insertions(+), 303 deletions(-) create mode 100644 src/screens/home/DeclineModal.tsx create mode 100644 src/screens/home/RequestList.tsx diff --git a/package-lock.json b/package-lock.json index 8e4674c..541717d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,6 +26,7 @@ "react": "19.1.0", "react-native": "0.81.1", "react-native-calendars": "^1.1313.0", + "react-native-dialog": "^9.3.0", "react-native-elements": "^3.4.3", "react-native-image-picker": "^8.2.1", "react-native-keychain": "^10.0.0", @@ -4803,6 +4804,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" @@ -8099,6 +8101,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "devOptional": true, "license": "ISC" }, "node_modules/istanbul-lib-coverage": { @@ -8855,6 +8858,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "devOptional": true, "license": "MIT" }, "node_modules/json-schema-traverse": { @@ -9786,6 +9790,7 @@ "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" @@ -13256,6 +13261,15 @@ "react-native": "*" } }, + "node_modules/react-native-dialog": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/react-native-dialog/-/react-native-dialog-9.3.0.tgz", + "integrity": "sha512-JEOJY/0AzTM9grIl0BL8o/IJPIJru7k5MPj9POTE9RRezUEtgn0YSvCpTlBtG0obWgOdzg2otMz1OQvMXS0wMQ==", + "license": "MIT", + "peerDependencies": { + "react-native": ">=0.63.0" + } + }, "node_modules/react-native-elements": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/react-native-elements/-/react-native-elements-3.4.3.tgz", @@ -14785,6 +14799,7 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, "license": "MIT" }, "node_modules/throat": { @@ -15243,6 +15258,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "devOptional": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" diff --git a/package.json b/package.json index 6210659..8825a10 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "react": "19.1.0", "react-native": "0.81.1", "react-native-calendars": "^1.1313.0", + "react-native-dialog": "^9.3.0", "react-native-elements": "^3.4.3", "react-native-image-picker": "^8.2.1", "react-native-keychain": "^10.0.0", diff --git a/src/components/colors.ts b/src/components/colors.ts index 0206238..7431c86 100644 --- a/src/components/colors.ts +++ b/src/components/colors.ts @@ -15,7 +15,7 @@ const colors = { textLight: "#555555", white: "#FFFFFF", black: "#000000", - primary: "#007AFF", + primary: "#a57ae9ff", }; export default colors; diff --git a/src/redux/userSlice.ts b/src/redux/userSlice.ts index 562a5b9..2b7c211 100644 --- a/src/redux/userSlice.ts +++ b/src/redux/userSlice.ts @@ -3,20 +3,44 @@ import type { PayloadAction } from "@reduxjs/toolkit"; export interface UserState { id: string; - name: string; + userId: number | null; + username: string; + firstName: string; + lastName: string; + gender: string; + mobile: string; email: string; + address: string; + bankAccountNumber: string; + bankName: string; + branchCode: string; profilePicture: string; + filePath: string; + imageBlob: string; role: string; + organizerId: string; organizerStatus: string; profileStatus: boolean; } const initialState: UserState = { id: "", - name: "", + userId: null, + username: "", + firstName: "", + lastName: "", + gender: "", + mobile: "", email: "", + address: "", + bankAccountNumber: "", + bankName: "", + branchCode: "", profilePicture: "", + filePath: "", + imageBlob: "", role: "", + organizerId: "", organizerStatus: "", profileStatus: false, }; @@ -26,12 +50,12 @@ export const userSlice = createSlice({ initialState, reducers: { // ✅ set all user details at once (e.g. after login) - setUser: (state, action: PayloadAction) => { + setUserData: (state, action: PayloadAction) => { return { ...action.payload }; }, // ✅ update only selected fields (e.g. profile update) - updateUser: (state, action: PayloadAction>) => { + updateUserData: (state, action: PayloadAction>) => { return { ...state, ...action.payload }; }, @@ -41,6 +65,6 @@ export const userSlice = createSlice({ }); // Action creators -export const { setUser, updateUser, clearUser } = userSlice.actions; +export const { setUserData, updateUserData, clearUser } = userSlice.actions; export default userSlice.reducer; diff --git a/src/screens/LoginScreen.tsx b/src/screens/LoginScreen.tsx index 048ca04..9e53fac 100644 --- a/src/screens/LoginScreen.tsx +++ b/src/screens/LoginScreen.tsx @@ -10,24 +10,29 @@ import { Platform, Animated, StatusBar, + ActivityIndicator, } from "react-native"; import { LOGIN_URL } from "../utils/ApiUrls"; import axios from "axios"; import { useNavigation } from "@react-navigation/native"; -import type { StackNavigationProp } from '@react-navigation/stack'; +import type { StackNavigationProp } from "@react-navigation/stack"; import { RootStackParamList } from "../navigation/AppNavigator"; +import { CustomButton, CustomInput } from "../components/common/Custom"; +import colors from "../components/colors"; const theme = { primary: "#111111", - accent: "#FF7A00", + accent: colors.primary, background: "#F9F9F9", + surface: "#FFFFFF", text: "#1A1A1A", subText: "#6B6B6B", outline: "#E5E5E5", + error: "#E53935", + success: "#2E7D32", }; export default function LoginScreen() { - const navigation = useNavigation>(); const [mobile, setMobile] = useState(""); const [loading, setLoading] = useState(false); @@ -48,16 +53,14 @@ export default function LoginScreen() { if (mobile.length === 10) { setLoading(true); try { - console.log("Mobile submitted:", mobile); - const res = await axios.get(LOGIN_URL + mobile) - console.log('loginres', res.data) + const res = await axios.get(LOGIN_URL + mobile); if (res.data.statusCode === 200) { - navigation.navigate('OtpVarify', { mobile: mobile }) + navigation.navigate("OtpVarify", { mobile }); } } catch (error) { console.error("Login error:", error); Alert.alert("Error", "Failed to send OTP. Please try again."); - }finally { + } finally { setLoading(false); } } else { @@ -102,15 +105,14 @@ export default function LoginScreen() { { opacity: fade, transform: [{ translateY: slide }] }, ]} > - Mobile Number - @@ -119,14 +121,8 @@ export default function LoginScreen() { - - Continue - + + By continuing, you agree to our{" "} @@ -142,7 +138,7 @@ const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: theme.background, padding: 20 }, topSection: { flex: 1, justifyContent: "center" }, brand: { - fontSize: 20, + fontSize: 30, fontWeight: "700", color: theme.accent, marginBottom: 24, @@ -166,7 +162,7 @@ const styles = StyleSheet.create({ color: theme.text, }, input: { - backgroundColor: "#fff", + backgroundColor: theme.surface, borderRadius: 14, padding: 14, fontSize: 16, diff --git a/src/screens/OtpVarificationScreen.tsx b/src/screens/OtpVarificationScreen.tsx index f3e2ebc..c611f49 100644 --- a/src/screens/OtpVarificationScreen.tsx +++ b/src/screens/OtpVarificationScreen.tsx @@ -20,10 +20,11 @@ import { RootStackParamList } from "../navigation/AppNavigator"; import * as Keychain from "react-native-keychain"; import { LOGIN_URL, VARIFY_OTP_URL } from "../utils/ApiUrls"; import { StackNavigationProp } from "@react-navigation/stack"; +import colors from "../components/colors"; const theme = { primary: "#111111", - accent: "#FF7A00", + accent: colors.primary, background: "#F9F9F9", text: "#1A1A1A", subText: "#6B6B6B", @@ -245,13 +246,13 @@ const styles = StyleSheet.create({ cellFilled: { borderColor: "#D1D1D1" }, bottomSection: { marginBottom: 30 }, button: { - backgroundColor: theme.primary, + backgroundColor: colors.primary, paddingVertical: 18, borderRadius: 14, alignItems: "center", justifyContent: "center", }, - buttonText: { color: "#fff", fontWeight: "700", fontSize: 16 }, + buttonText: { color: "#000", fontWeight: "700", fontSize: 16 }, footerText: { textAlign: "center", color: theme.subText, diff --git a/src/screens/SplashScreen.tsx b/src/screens/SplashScreen.tsx index 541c028..38b6529 100644 --- a/src/screens/SplashScreen.tsx +++ b/src/screens/SplashScreen.tsx @@ -1,13 +1,75 @@ import React, { useEffect, useRef } from "react"; -import { View, Text, StyleSheet, ActivityIndicator, Animated } from "react-native"; +import { View, Text, StyleSheet, ActivityIndicator, Animated, Alert } from "react-native"; import * as Keychain from "react-native-keychain"; import { StackNavigationProp } from "@react-navigation/stack"; import { useNavigation } from "@react-navigation/native"; import { RootStackParamList } from "../navigation/AppNavigator"; // adjust path +import { BASE_URL } from "../utils/ApiUrls"; +import { useDispatch, useSelector } from "react-redux"; +import { setUserData } from "../redux/userSlice"; +import colors from "../components/colors"; const SplashScreen = () => { + const dispatch = useDispatch(); + const user = useSelector((state: any) => state.user); const navigation = useNavigation>(); - const fadeAnim = useRef(new Animated.Value(1)).current; // opacity starts at 1 + const fadeAnim = useRef(new Animated.Value(1)).current; + + const fetchUserProfile = async () => { + try { + const credentials = await Keychain.getGenericPassword(); + if (!credentials) { + Alert.alert("Error", "You are not logged in"); + return; + } + const token = credentials.password; + + const response = await fetch( + `${BASE_URL}user/profile/view`, + { + method: "GET", + headers: { + Accept: "*/*", + Authorization: `Bearer ${token}`, + }, + } + ); + + const result = await response.json(); + if (result.status === "success") { + dispatch(setUserData({ + id: result?.data.id, + userId: result?.data.userId, + username: result?.data.username, + firstName: result?.data.firstName, + lastName: result?.data.lastName, + gender: result?.data.gender, + mobile: result?.data.mobile, + email: result?.data.email, + address: result?.data.address, + bankAccountNumber: result?.data.bankAccountNumber, + bankName: result?.data.bankName, + branchCode: result?.data.branchCode, + profilePicture: result?.data.filePath, // or keep as `filePath` + filePath: result?.data.filePath, + imageBlob: result?.data.imageBlob, + role: result?.data.role, + organizerId: result?.data.organizerId, + organizerStatus: result?.data.organizerStatus, + profileStatus: true, // set true once profile is fetched + })); + + console.log("splash user data:", result.data); + } else { + Alert.alert("Error", "Failed to fetch user profile"); + } + } catch (error) { + console.error("❌ Error fetching profile:", error); + Alert.alert("Error", "Could not connect to server"); + } + }; + + console.log("redux user", user); useEffect(() => { const checkLogin = async () => { @@ -36,12 +98,16 @@ const SplashScreen = () => { }); }, [navigation, fadeAnim]); + useEffect(() => { + fetchUserProfile(); + }, []) + return ( Circle Collect - + ); }; @@ -58,7 +124,7 @@ const styles = StyleSheet.create({ title: { fontSize: 28, fontWeight: "800", - color: "#FF7A00", + color: colors.Home, letterSpacing: 1, }, }); diff --git a/src/screens/home/DeclineModal.tsx b/src/screens/home/DeclineModal.tsx new file mode 100644 index 0000000..93bd75e --- /dev/null +++ b/src/screens/home/DeclineModal.tsx @@ -0,0 +1,74 @@ +import React, { useState } from "react"; +import { View, Text, TextInput, Button, Modal, StyleSheet } from "react-native"; + +const DeclineModal = ({ visible, onClose, onSubmit }: { + visible: boolean; + onClose: () => void; + onSubmit: (reason: string) => void; +}) => { + const [reason, setReason] = useState(""); + + return ( + + + + Decline Request + + +