manage user credancial
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import React, { FC } from 'react';
|
import React, { FC } from 'react';
|
||||||
import { View, Text, StyleSheet } from 'react-native';
|
import { View, Text, StyleSheet } from 'react-native';
|
||||||
|
import colors from './colors';
|
||||||
|
|
||||||
// Update the type to match the full data structure
|
// Update the type to match the full data structure
|
||||||
interface JoinedGroup {
|
interface JoinedGroup {
|
||||||
@@ -151,7 +152,7 @@ const styles = StyleSheet.create({
|
|||||||
paddingVertical: 16,
|
paddingVertical: 16,
|
||||||
borderTopWidth: 1,
|
borderTopWidth: 1,
|
||||||
borderBottomWidth: 1,
|
borderBottomWidth: 1,
|
||||||
borderColor: '#F3F4F6',
|
borderColor: colors.pastelOrange,
|
||||||
marginBottom: 16,
|
marginBottom: 16,
|
||||||
},
|
},
|
||||||
infoItem: {
|
infoItem: {
|
||||||
@@ -193,7 +194,7 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
progressBarFill: {
|
progressBarFill: {
|
||||||
height: '100%',
|
height: '100%',
|
||||||
backgroundColor: '#4F46E5',
|
backgroundColor: colors.Settings,
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
},
|
},
|
||||||
footer: {
|
footer: {
|
||||||
|
|||||||
@@ -50,16 +50,7 @@ export const RequestCard: FC<RequestCardProps> = ({ item, onApprove, onDecline }
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Assuming a colors object like this for context:
|
|
||||||
// const colors = {
|
|
||||||
// white: '#FFFFFF',
|
|
||||||
// textPrimary: '#212121',
|
|
||||||
// textSecondary: '#757575',
|
|
||||||
// border: '#EEEEEE',
|
|
||||||
// danger: '#C62828',
|
|
||||||
// lightDanger: '#FFEBEE',
|
|
||||||
// pastelOrange: '#FFDAB9', // The requested color
|
|
||||||
// };
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
card: {
|
card: {
|
||||||
|
|||||||
@@ -0,0 +1,154 @@
|
|||||||
|
// src/components/UserRequested.tsx
|
||||||
|
|
||||||
|
import React, { FC } from "react";
|
||||||
|
import { View, Text, StyleSheet } from "react-native";
|
||||||
|
import {Ionicons} from "@react-native-vector-icons/ionicons";
|
||||||
|
import colors from "./colors";
|
||||||
|
import { UserJoinRequest } from "../types";
|
||||||
|
import { formatDate } from "../utils/HelperFunction";
|
||||||
|
|
||||||
|
interface UserRequestedProps {
|
||||||
|
item: UserJoinRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
const getStatusStyle = (status: UserJoinRequest["status"]) => {
|
||||||
|
switch (status) {
|
||||||
|
case "APPROVED":
|
||||||
|
return {
|
||||||
|
backgroundColor: "#D1FAE5", // light green
|
||||||
|
textColor: "#065F46", // dark green
|
||||||
|
label: "Approved",
|
||||||
|
icon: "checkmark-circle-outline",
|
||||||
|
|
||||||
|
};
|
||||||
|
case "PENDING":
|
||||||
|
return {
|
||||||
|
backgroundColor: "#FEF3C7", // light yellow
|
||||||
|
textColor: "#92400E", // dark yellow/brown
|
||||||
|
label: "Pending",
|
||||||
|
icon: "time-outline",
|
||||||
|
};
|
||||||
|
case "REJECT":
|
||||||
|
return {
|
||||||
|
backgroundColor: "#E5E7EB", // light gray
|
||||||
|
textColor: "#4B5563", // dark gray
|
||||||
|
label: "Reject",
|
||||||
|
icon: "close-circle-outline",
|
||||||
|
};
|
||||||
|
default:
|
||||||
|
return {
|
||||||
|
backgroundColor: "#E5E7EB",
|
||||||
|
textColor: "#4B5563",
|
||||||
|
label: "Unknown",
|
||||||
|
icon: "help-outline",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const UserRequested: FC<UserRequestedProps> = ({ item }) => {
|
||||||
|
const { backgroundColor, textColor, label, icon } = getStatusStyle(item.status);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={styles.card}>
|
||||||
|
{/* Top row: User info + Status */}
|
||||||
|
<View style={styles.topRow}>
|
||||||
|
<View style={styles.userInfoSection}>
|
||||||
|
|
||||||
|
<Text style={styles.groupName}>{item.groupName}</Text>
|
||||||
|
|
||||||
|
<Text style={styles.userMeta}>
|
||||||
|
<Ionicons name="time-outline" size={14} color={colors.textLight} />{" "}
|
||||||
|
{formatDate(item.requestDate)}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* Status Badge */}
|
||||||
|
<View style={[styles.statusBadge, { backgroundColor }]}>
|
||||||
|
<Ionicons name={icon as any} size={16} color={textColor} />
|
||||||
|
<Text style={[styles.statusText, { color: textColor }]}>{label}</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* Group Info */}
|
||||||
|
<View style={styles.groupInfoSection}>
|
||||||
|
<Text style={styles.requestText}>
|
||||||
|
Group Created By :{" "}
|
||||||
|
<Text style={styles.userName} numberOfLines={1}>
|
||||||
|
{item.createdBy}
|
||||||
|
</Text>
|
||||||
|
</Text>
|
||||||
|
{item.reason ? (
|
||||||
|
<Text style={styles.reasonText} numberOfLines={2}>
|
||||||
|
Reason: {item.reason}
|
||||||
|
</Text>
|
||||||
|
) : null}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
card: {
|
||||||
|
backgroundColor: colors.white,
|
||||||
|
borderRadius: 16,
|
||||||
|
marginVertical: 8,
|
||||||
|
elevation: 3,
|
||||||
|
shadowColor: "#000",
|
||||||
|
shadowOpacity: 0.1,
|
||||||
|
shadowRadius: 6,
|
||||||
|
shadowOffset: { width: 0, height: 3 },
|
||||||
|
padding: 12,
|
||||||
|
},
|
||||||
|
topRow: {
|
||||||
|
flexDirection: "row",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
alignItems: "flex-start",
|
||||||
|
borderBottomWidth: 1,
|
||||||
|
borderBottomColor: colors.Settings,
|
||||||
|
paddingBottom: 8,
|
||||||
|
},
|
||||||
|
userInfoSection: {
|
||||||
|
flex: 1,
|
||||||
|
paddingRight: 8,
|
||||||
|
},
|
||||||
|
userName: {
|
||||||
|
// fontSize: 16,
|
||||||
|
fontWeight: "bold",
|
||||||
|
color: colors.textDark,
|
||||||
|
},
|
||||||
|
userMeta: {
|
||||||
|
fontSize: 13,
|
||||||
|
color: colors.textLight,
|
||||||
|
marginTop: 2,
|
||||||
|
},
|
||||||
|
groupInfoSection: {
|
||||||
|
paddingVertical: 12,
|
||||||
|
},
|
||||||
|
requestText: {
|
||||||
|
// fontSize: 15,
|
||||||
|
color: colors.textDark,
|
||||||
|
lineHeight: 20,
|
||||||
|
},
|
||||||
|
groupName: {
|
||||||
|
fontWeight: "600",
|
||||||
|
color: colors.Settings,
|
||||||
|
fontSize:18
|
||||||
|
},
|
||||||
|
reasonText: {
|
||||||
|
fontSize: 13,
|
||||||
|
color: colors.textLight,
|
||||||
|
marginTop: 4,
|
||||||
|
},
|
||||||
|
statusBadge: {
|
||||||
|
flexDirection: "row",
|
||||||
|
alignItems: "center",
|
||||||
|
borderRadius: 12,
|
||||||
|
paddingHorizontal: 8,
|
||||||
|
paddingVertical: 4,
|
||||||
|
},
|
||||||
|
statusText: {
|
||||||
|
fontSize: 13,
|
||||||
|
fontWeight: "600",
|
||||||
|
marginLeft: 4,
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -150,17 +150,17 @@ export default function GroupScreen() {
|
|||||||
const handleJoinGroup = async (groupId: string, userId: string) => {
|
const handleJoinGroup = async (groupId: string, userId: string) => {
|
||||||
console.log("Joining group:", groupId, "User:", userId);
|
console.log("Joining group:", groupId, "User:", userId);
|
||||||
try {
|
try {
|
||||||
const url = `${JOIN_GROUP_URL}/groups/${groupId}/join/0`;
|
const url = `${JOIN_GROUP_URL}groups/${groupId}/join/10`;
|
||||||
console.log("Joining group URL:", url);
|
console.log("Joining group URL:", url);
|
||||||
const res = await apiCall(url, "POST") as { statusCode?: number; message?: string };
|
const res = await apiCall(url, "POST");
|
||||||
|
|
||||||
console.log("JOIN_GROUP_URL response:", res);
|
console.log("JOIN_GROUP_URL response:", res);
|
||||||
|
|
||||||
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.");
|
||||||
@@ -264,7 +264,7 @@ export default function GroupScreen() {
|
|||||||
refreshControl={
|
refreshControl={
|
||||||
<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />
|
<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />
|
||||||
}
|
}
|
||||||
ListFooterComponent={<ActivityIndicator size={'large'} color={colors.Group} />}
|
// ListFooterComponent={<ActivityIndicator size={'large'} color={colors.Group} />}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -77,26 +77,39 @@ export default function OtpVerificationScreen() {
|
|||||||
|
|
||||||
|
|
||||||
const onSubmit = async (otp: string, mobile: string) => {
|
const onSubmit = async (otp: string, mobile: string) => {
|
||||||
try {
|
try {
|
||||||
const payload = { mobile, otp };
|
const payload = { mobile, otp };
|
||||||
const res = await axios.post(
|
const res = await axios.post(
|
||||||
VARIFY_OTP_URL,
|
VARIFY_OTP_URL,
|
||||||
payload,
|
payload,
|
||||||
{ headers: { "Content-Type": "application/json", Accept: "*/*" } }
|
{
|
||||||
);
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
console.log("✅ OTP Verified:", res.data);
|
Accept: "application/json",
|
||||||
if (res.data.statusCode === 200) {
|
},
|
||||||
saveToken(res.data.data);
|
|
||||||
fetchUserProfile()
|
|
||||||
navigation.navigate("Home", { refreshProfile: true });
|
|
||||||
ToastAndroid.show("OTP Verified Successfully!", ToastAndroid.SHORT);
|
|
||||||
}
|
}
|
||||||
} catch (err: any) {
|
);
|
||||||
console.error("❌ OTP Verification Error:", err?.response?.data || err.message);
|
|
||||||
ToastAndroid.show(err.message || "Invalid OTP. Please try again.", ToastAndroid.SHORT);
|
console.log("✅ OTP Verified:", res.data);
|
||||||
|
|
||||||
|
if (res.data?.statusCode === 200) {
|
||||||
|
const { jwt, role } = res.data?.data || {};
|
||||||
|
|
||||||
|
saveToken(jwt);
|
||||||
|
|
||||||
|
navigation.navigate("Home");
|
||||||
|
|
||||||
|
ToastAndroid.show("OTP Verified Successfully!", ToastAndroid.SHORT);
|
||||||
}
|
}
|
||||||
};
|
} catch (err: any) {
|
||||||
|
console.error("❌ OTP Verification Error:", err?.response?.data || err.message);
|
||||||
|
ToastAndroid.show(
|
||||||
|
err?.response?.data?.message || "Invalid OTP. Please try again.",
|
||||||
|
ToastAndroid.SHORT
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
const resendOtp = async () => {
|
const resendOtp = async () => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
+35
-11
@@ -7,21 +7,27 @@ import {
|
|||||||
UIManager,
|
UIManager,
|
||||||
Platform,
|
Platform,
|
||||||
Image,
|
Image,
|
||||||
|
Alert,
|
||||||
} from "react-native";
|
} from "react-native";
|
||||||
import AppView from "../../components/AppView";
|
import AppView from "../../components/AppView";
|
||||||
import UserProfileStatus from "./UserProfileStatus";
|
import UserProfileStatus from "./UserProfileStatus";
|
||||||
import colors from "../../components/colors";
|
import colors from "../../components/colors";
|
||||||
import GroupsTabs from "./GroupsTabs";
|
import GroupsTabs from "./GroupsTabs";
|
||||||
import { useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { useFocusEffect, useNavigation, useRoute } from "@react-navigation/native";
|
import { RouteProp, useFocusEffect, useNavigation, useRoute } from "@react-navigation/native";
|
||||||
import UserHome from "./user-home/UserHome";
|
import UserHome from "./user-home/UserHome";
|
||||||
import { PROFILE_URL } from "../../utils/ApiUrls";
|
import { PROFILE_URL } from "../../utils/ApiUrls";
|
||||||
import *as Keychain from "react-native-keychain"
|
import *as Keychain from "react-native-keychain"
|
||||||
|
import { setUserData } from "../../redux/userSlice";
|
||||||
// Enable animation for Android
|
// Enable animation for Android
|
||||||
if (Platform.OS === "android" && UIManager.setLayoutAnimationEnabledExperimental) {
|
if (Platform.OS === "android" && UIManager.setLayoutAnimationEnabledExperimental) {
|
||||||
UIManager.setLayoutAnimationEnabledExperimental(true);
|
UIManager.setLayoutAnimationEnabledExperimental(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type RootStackParamList = {
|
||||||
|
Home: { refreshProfile: boolean; role: string };
|
||||||
|
};
|
||||||
|
|
||||||
type UserProfile = {
|
type UserProfile = {
|
||||||
id: string;
|
id: string;
|
||||||
userId: number;
|
userId: number;
|
||||||
@@ -33,9 +39,8 @@ type UserProfile = {
|
|||||||
const Home = () => {
|
const Home = () => {
|
||||||
const user = useSelector((state: any) => state.user);
|
const user = useSelector((state: any) => state.user);
|
||||||
const navigation = useNavigation();
|
const navigation = useNavigation();
|
||||||
const route = useRoute();
|
const dispatch = useDispatch()
|
||||||
|
|
||||||
console.log("route asf : ", route?.params)
|
|
||||||
const [apiUser, setApiUser] = useState<UserProfile | null | any>(null)
|
const [apiUser, setApiUser] = useState<UserProfile | null | any>(null)
|
||||||
|
|
||||||
const fetchUserProfile = async () => {
|
const fetchUserProfile = async () => {
|
||||||
@@ -60,7 +65,29 @@ const Home = () => {
|
|||||||
console.log("👤 Profile Response:", result);
|
console.log("👤 Profile Response:", result);
|
||||||
if (result.status === "success") {
|
if (result.status === "success") {
|
||||||
setApiUser(result.data);
|
setApiUser(result.data);
|
||||||
|
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,
|
||||||
|
filePath: result.data.filePath,
|
||||||
|
imageBlob: result.data.imageBlob,
|
||||||
|
role: result.data.role,
|
||||||
|
organizerId: result.data.organizerId,
|
||||||
|
organizerStatus: result.data.organizerStatus,
|
||||||
|
profileStatus: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("❌ Error fetching profile:", error);
|
console.error("❌ Error fetching profile:", error);
|
||||||
@@ -68,10 +95,8 @@ const Home = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (route.params) {
|
fetchUserProfile();
|
||||||
fetchUserProfile();
|
}, []);
|
||||||
}
|
|
||||||
}, [route.params]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppView barStyle="dark-content" style={styles.container}>
|
<AppView barStyle="dark-content" style={styles.container}>
|
||||||
@@ -91,6 +116,7 @@ const Home = () => {
|
|||||||
</View>
|
</View>
|
||||||
{/* Status */}
|
{/* Status */}
|
||||||
<UserProfileStatus />
|
<UserProfileStatus />
|
||||||
|
{/* <UserHome /> */}
|
||||||
{user?.role === "USER" || apiUser?.role === "USER" ? <UserHome /> :
|
{user?.role === "USER" || apiUser?.role === "USER" ? <UserHome /> :
|
||||||
<GroupsTabs />}
|
<GroupsTabs />}
|
||||||
</AppView>
|
</AppView>
|
||||||
@@ -110,6 +136,4 @@ const styles = StyleSheet.create({
|
|||||||
marginBottom: 12,
|
marginBottom: 12,
|
||||||
},
|
},
|
||||||
greeting: { fontSize: 22, fontWeight: "600", color: colors.Home },
|
greeting: { fontSize: 22, fontWeight: "600", color: colors.Home },
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
@@ -54,7 +54,7 @@ const UserProfileStatus: React.FC = () => {
|
|||||||
|
|
||||||
const json: ApiResponse = await response.json();
|
const json: ApiResponse = await response.json();
|
||||||
|
|
||||||
console.log("👤 Profile Status Response:", json);
|
console.log("Profile Status :", json);
|
||||||
if (json.status === "success") {
|
if (json.status === "success") {
|
||||||
setStatusData(json.data);
|
setStatusData(json.data);
|
||||||
|
|
||||||
|
|||||||
@@ -14,86 +14,45 @@ import {
|
|||||||
import { useNavigation, useFocusEffect } from "@react-navigation/native";
|
import { useNavigation, useFocusEffect } from "@react-navigation/native";
|
||||||
import { StackNavigationProp } from "@react-navigation/stack";
|
import { StackNavigationProp } from "@react-navigation/stack";
|
||||||
import { RootStackParamList } from "../../navigation/AppNavigator";
|
import { RootStackParamList } from "../../navigation/AppNavigator";
|
||||||
import { APPROVE_REQUEST_URL, BASE_URL, DECLINE_REQUEST_URL, GET_JOINED_GROUP_URL, JOIN_GROUP_URL, MY_GROUPS_URL, REQUESTS_URL } from "../../utils/ApiUrls";
|
import { APPROVE_REQUEST_URL, BASE_URL, DECLINE_REQUEST_URL, GET_JOINED_GROUP_URL, JOIN_GROUP_URL, MY_GROUPS_URL, REQUESTS_URL, USER_REQUEST } from "../../utils/ApiUrls";
|
||||||
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 * as Keychain from "react-native-keychain";
|
import * as Keychain from "react-native-keychain";
|
||||||
import { MyGroup, JoinedGroup, JoinRequest, ApiResponse } from '../../types';
|
import { MyGroup, JoinedGroup, JoinRequest, ApiResponse, UserJoinRequest } from '../../types';
|
||||||
import { MyGroupCard } from "../../components/MyGroupCard";
|
import { MyGroupCard } from "../../components/MyGroupCard";
|
||||||
import { JoinedGroupCard } from "../../components/JoinedGroupCard";
|
import { JoinedGroupCard } from "../../components/JoinedGroupCard";
|
||||||
import { RequestCard } from "../../components/RequestCard";
|
import { RequestCard } from "../../components/RequestCard";
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
import Ionicons from "@react-native-vector-icons/ionicons";
|
import Ionicons from "@react-native-vector-icons/ionicons";
|
||||||
|
import { UserRequested } from "../../components/UserRequested";
|
||||||
|
|
||||||
type GroupManagementNavProp = StackNavigationProp<RootStackParamList>;
|
type GroupManagementNavProp = StackNavigationProp<RootStackParamList>;
|
||||||
type ActiveTab = "My Groups" | "Joined Groups" | "Requests" | "Your Requests";
|
type ActiveTab = "My Groups" | "Joined Groups" | "Requests" | "Your Requests";
|
||||||
|
|
||||||
const ManagementScreen: FC = () => {
|
const ManagementScreen: FC = () => {
|
||||||
const user = useSelector((state:any) => state.user)
|
const userRole = useSelector((state: any) => state.user)
|
||||||
const [activeTab, setActiveTab] = useState<ActiveTab>("My Groups");
|
const [activeTab, setActiveTab] = useState<ActiveTab>(userRole.role === "USER" ? "Joined Groups" : "My Groups");
|
||||||
const navigation = useNavigation<GroupManagementNavProp>();
|
const navigation = useNavigation<GroupManagementNavProp>();
|
||||||
const [myGroups, setMyGroups] = useState<MyGroup[]>([]);
|
const [myGroups, setMyGroups] = useState<MyGroup[]>([]);
|
||||||
const [joinedGroups, setJoinedGroups] = useState<JoinedGroup[]>([]);
|
const [joinedGroups, setJoinedGroups] = useState<JoinedGroup[]>([]);
|
||||||
const [requests, setRequests] = useState<JoinRequest[]>([]);
|
const [requests, setRequests] = useState<JoinRequest[]>([]);
|
||||||
const [loading, setLoading] = useState<boolean>(false);
|
const [loading, setLoading] = useState<boolean>(false);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [userRole,setUserRole] = useState<string | null>(null)
|
const [userRequest, setUserRequest] = useState<UserJoinRequest[]>([])
|
||||||
const userStatus = async () => {
|
|
||||||
try {
|
|
||||||
const credentials = await Keychain.getGenericPassword();
|
|
||||||
if (!credentials) {
|
|
||||||
Alert.alert("Error", "You are not logged in");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const token = credentials.password;
|
|
||||||
|
|
||||||
setLoading(true);
|
|
||||||
setError(null);
|
|
||||||
const response = await fetch(`${BASE_URL}user/profile/status`, {
|
|
||||||
method: "GET",
|
|
||||||
headers: {
|
|
||||||
Accept: "*/*",
|
|
||||||
Authorization: `Bearer ${token}`,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const json = await response.json();
|
|
||||||
|
|
||||||
console.log("👤 Profile Status Response:", json.data.role);
|
|
||||||
if (json.status === "success") {
|
|
||||||
setUserRole(json.data.role);
|
|
||||||
|
|
||||||
if (json.data.profileStatus === false) {
|
|
||||||
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setError(json.message || "Failed to fetch status");
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
setError("Something went wrong. Please try again.");
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
useFocusEffect(
|
|
||||||
useCallback(() => {
|
|
||||||
userStatus();
|
|
||||||
}, [])
|
|
||||||
);
|
|
||||||
|
|
||||||
const fetchData = useCallback(async () => {
|
const fetchData = useCallback(async () => {
|
||||||
if (loading) return;
|
if (loading) return;
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
setError(null);
|
setError(null);
|
||||||
try {
|
try {
|
||||||
console.log(" abin user : ", userRole)
|
console.log(" abin user : ", userRole)
|
||||||
if (userRole === "ORGANIZER") {
|
if (userRole.role === "ORGANIZER") {
|
||||||
// Fetch all data concurrently
|
// Fetch all data concurrently
|
||||||
const [myGroupsRes, joinedGroupsRes, requestsRes] = await Promise.all([
|
const [myGroupsRes, joinedGroupsRes, requestsRes] = await Promise.all([
|
||||||
apiCall(MY_GROUPS_URL, "GET") as Promise<ApiResponse<MyGroup[]>>,
|
apiCall(MY_GROUPS_URL, "GET") as Promise<ApiResponse<MyGroup[]>>,
|
||||||
apiCall(GET_JOINED_GROUP_URL, "GET") as Promise<ApiResponse<JoinedGroup[]>>, // Assuming this is also needed
|
apiCall(GET_JOINED_GROUP_URL, "GET") as Promise<ApiResponse<JoinedGroup[]>>,
|
||||||
apiCall(REQUESTS_URL, "GET") as Promise<ApiResponse<JoinRequest[]>>,
|
apiCall(REQUESTS_URL, "GET") as Promise<ApiResponse<JoinRequest[]>>,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -105,10 +64,14 @@ const ManagementScreen: FC = () => {
|
|||||||
setRequests(requestsRes.data || []);
|
setRequests(requestsRes.data || []);
|
||||||
} else {
|
} else {
|
||||||
// Fetch only joined groups for non-organizers
|
// Fetch only joined groups for non-organizers
|
||||||
const [joinedGroupsRes] = await Promise.all([
|
const [joinedGroupsRes, userRequest] = await Promise.all([
|
||||||
apiCall(GET_JOINED_GROUP_URL, "GET") as Promise<ApiResponse<JoinedGroup[]>>, // Assuming this is also needed
|
apiCall(GET_JOINED_GROUP_URL, "GET") as Promise<ApiResponse<JoinedGroup[]>>, // Assuming this is also needed
|
||||||
|
apiCall(USER_REQUEST, "GET") as Promise<ApiResponse<UserJoinRequest[]>>, // Assuming this is also needed
|
||||||
]);
|
]);
|
||||||
setJoinedGroups(joinedGroupsRes.data || []);
|
setJoinedGroups(joinedGroupsRes.data || []);
|
||||||
|
setUserRequest(userRequest?.data || []);
|
||||||
|
console.log("joinedGroupsRes data : ", joinedGroupsRes)
|
||||||
|
console.log("user request data : ", userRequest)
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Fetch Data Error:", e);
|
console.error("Fetch Data Error:", e);
|
||||||
@@ -197,12 +160,28 @@ const ManagementScreen: FC = () => {
|
|||||||
contentContainerStyle={{ paddingBottom: 100 }}
|
contentContainerStyle={{ paddingBottom: 100 }}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
case "Your Requests":
|
||||||
|
if (loading && requests.length === 0) {
|
||||||
|
return <ActivityIndicator size="large" color={colors.primary} style={styles.loader} />;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<FlatList
|
||||||
|
data={userRequest}
|
||||||
|
renderItem={({ item }: ListRenderItemInfo<UserJoinRequest>) => <UserRequested item={item} />}
|
||||||
|
keyExtractor={(item) => item.requestId}
|
||||||
|
ListEmptyComponent={<Text style={styles.emptyText}>No pending join requests.</Text>}
|
||||||
|
onRefresh={fetchData}
|
||||||
|
refreshing={loading} // This handles the "continuing loading" on pull-to-refresh
|
||||||
|
contentContainerStyle={{ paddingBottom: 100 }}
|
||||||
|
/>
|
||||||
|
);
|
||||||
default: return null;
|
default: return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const tabs: ActiveTab[] = userRole === 'ORGANIZER' ? ["My Groups", "Joined Groups", "Requests"] : ["Joined Groups", "Your Requests"];
|
const tabs: ActiveTab[] = userRole.role === 'ORGANIZER' ? ["My Groups", "Joined Groups", "Requests"] : ["Joined Groups", "Your Requests"];
|
||||||
|
|
||||||
|
console.log("user request : ", userRequest)
|
||||||
return (
|
return (
|
||||||
<AppView style={styles.container} paddingHorizontal={0}>
|
<AppView style={styles.container} paddingHorizontal={0}>
|
||||||
<View style={styles.header}>
|
<View style={styles.header}>
|
||||||
|
|||||||
@@ -37,6 +37,17 @@ export interface JoinRequest {
|
|||||||
userAvatar?: string;
|
userAvatar?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface UserJoinRequest {
|
||||||
|
createdBy: string;
|
||||||
|
groupId: string;
|
||||||
|
groupName: string;
|
||||||
|
reason: string | null;
|
||||||
|
requestDate: string;
|
||||||
|
requestId: any;
|
||||||
|
status: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// src/types.ts
|
// src/types.ts
|
||||||
|
|
||||||
|
|||||||
@@ -15,3 +15,5 @@ export const GET_JOINED_GROUP_URL = `${BASE_URL}fund/my/join/groups`
|
|||||||
export const PUT_USER_PROFILE_IMG = `${BASE_URL}user/update/userImg`
|
export const PUT_USER_PROFILE_IMG = `${BASE_URL}user/update/userImg`
|
||||||
export const PUT_USER_PROFILE = `${BASE_URL}user/profile/update`
|
export const PUT_USER_PROFILE = `${BASE_URL}user/profile/update`
|
||||||
export const PUT_USER_STATUS = `${BASE_URL}user/profile/status`
|
export const PUT_USER_STATUS = `${BASE_URL}user/profile/status`
|
||||||
|
export const USER_REQUEST = `${BASE_URL}fund/my-requests`
|
||||||
|
export const GROUP_ALL_MEMBER = `${BASE_URL}fund/group/all/member`
|
||||||
|
|||||||
@@ -58,4 +58,23 @@ export const fetchUserProfile = async () => {
|
|||||||
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");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// src/utils/dateFormatter.ts
|
||||||
|
|
||||||
|
export const formatDate = (dateString: string): string => {
|
||||||
|
const date = new Date(dateString);
|
||||||
|
|
||||||
|
if (isNaN(date.getTime())) return "Invalid Date";
|
||||||
|
|
||||||
|
const options: Intl.DateTimeFormatOptions = {
|
||||||
|
day: "2-digit",
|
||||||
|
month: "short",
|
||||||
|
year: "numeric",
|
||||||
|
hour: "2-digit",
|
||||||
|
minute: "2-digit",
|
||||||
|
hour12: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
return new Intl.DateTimeFormat("en-GB", options).format(date);
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user