126 lines
4.1 KiB
TypeScript
126 lines
4.1 KiB
TypeScript
import React, { useEffect, useRef, useState } from "react";
|
|
import { View, StyleSheet, ActivityIndicator, Animated, Alert } from "react-native";
|
|
import * as Keychain from "react-native-keychain";
|
|
import { useNavigation } from "@react-navigation/native";
|
|
import { StackNavigationProp } from "@react-navigation/stack";
|
|
import { useDispatch } from "react-redux";
|
|
|
|
// --- Import your project files ---
|
|
import { RootStackParamList } from "../navigation/AppNavigator"; // Adjust path
|
|
import { BASE_URL } from "../utils/ApiUrls";
|
|
import { fetchUserProfile } from "../utils/HelperFunction";
|
|
import { setUserData } from "../redux/userSlice";
|
|
import colors from "../components/colors";
|
|
import { ApiResponse } from "./home/UserProfileStatus";
|
|
|
|
const SplashScreen = () => {
|
|
const navigation = useNavigation<StackNavigationProp<RootStackParamList>>();
|
|
const dispatch = useDispatch();
|
|
const fadeAnim = useRef(new Animated.Value(1)).current;
|
|
|
|
// State to track the outcome of initialization
|
|
const [isReady, setIsReady] = useState(false);
|
|
const [isLoggedIn, setIsLoggedIn] = useState(false);
|
|
|
|
useEffect(() => {
|
|
// A single function to handle all startup tasks
|
|
const initializeApp = async () => {
|
|
try {
|
|
// 1. Check for stored credentials
|
|
const credentials = await Keychain.getGenericPassword();
|
|
if (!credentials) {
|
|
console.log("No credentials found. User needs to log in.");
|
|
setIsLoggedIn(false);
|
|
return; // Stop here if not logged in
|
|
}
|
|
|
|
console.log("🔑 Credentials found. Proceeding with user data fetches.");
|
|
const { password: token } = credentials;
|
|
|
|
// 2. Fetch all necessary data in parallel for efficiency
|
|
const [statusResponse, userProfile] = await Promise.all([
|
|
fetch(`${BASE_URL}user/profile/status`, {
|
|
method: "GET",
|
|
headers: {
|
|
Accept: "*/*",
|
|
Authorization: `Bearer ${token}`,
|
|
},
|
|
}),
|
|
fetchUserProfile(dispatch), // Assuming fetchUserProfile handles its own errors and dispatches to Redux
|
|
]);
|
|
|
|
// 3. Process the profile status response
|
|
if (!statusResponse.ok) {
|
|
throw new Error(`Server responded with status: ${statusResponse.status}`);
|
|
}
|
|
|
|
const statusJson: ApiResponse = await statusResponse.json();
|
|
console.log("👤 Profile Status Response:", statusJson);
|
|
|
|
if (statusJson.status === "success") {
|
|
// You could dispatch more data here if needed
|
|
// dispatch(setUserData(statusJson.data));
|
|
setIsLoggedIn(true);
|
|
} else {
|
|
throw new Error(statusJson.message || "Failed to verify user status.");
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error("Initialization failed:", error);
|
|
Alert.alert("Error", "Your session may have expired. Please log in again.");
|
|
setIsLoggedIn(false); // Ensure login status is false on any error
|
|
} finally {
|
|
// 4. Signal that all tasks are done, whether they succeeded or failed
|
|
setIsReady(true);
|
|
}
|
|
};
|
|
|
|
// Trigger the animation, and run initialization logic after it completes
|
|
Animated.timing(fadeAnim, {
|
|
toValue: 0,
|
|
duration: 1500,
|
|
useNativeDriver: true,
|
|
delay: 1500,
|
|
}).start(() => {
|
|
initializeApp();
|
|
});
|
|
}, [fadeAnim, dispatch]);
|
|
|
|
// This effect handles the final navigation step once everything is ready
|
|
useEffect(() => {
|
|
if (isReady) {
|
|
if (isLoggedIn) {
|
|
navigation.replace("Home");
|
|
} else {
|
|
navigation.replace("Login");
|
|
}
|
|
}
|
|
}, [isReady, isLoggedIn, navigation]);
|
|
|
|
return (
|
|
<View style={styles.container}>
|
|
<Animated.Text style={[styles.title, { opacity: fadeAnim }]}>
|
|
Circle Collect
|
|
</Animated.Text>
|
|
<ActivityIndicator size="large" color={colors.Home} style={{ marginTop: 20 }} />
|
|
</View>
|
|
);
|
|
};
|
|
|
|
export default SplashScreen;
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
flex: 1,
|
|
justifyContent: "center",
|
|
alignItems: "center",
|
|
backgroundColor: "#FFFFFF",
|
|
},
|
|
title: {
|
|
fontSize: 28,
|
|
fontWeight: "800",
|
|
color: colors.Home,
|
|
letterSpacing: 1,
|
|
},
|
|
});
|