Compare commits
No commits in common. "be53dc63c166a5cc5cb051da429978659edc445e" and "e891e4def9a80c280b9d6507f6f5e37c315c4810" have entirely different histories.
be53dc63c1
...
e891e4def9
@ -1,11 +1,9 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { Platform, View, TouchableOpacity, StyleSheet } from "react-native";
|
import { Platform } from "react-native";
|
||||||
import { Button, TextInput, Dialog, Portal, Avatar, useTheme, Text } from "react-native-paper";
|
import { Button, TextInput, Dialog, Portal, Avatar, useTheme } from "react-native-paper";
|
||||||
import { Asset } from 'expo-asset';
|
import { Asset } from 'expo-asset';
|
||||||
import * as FileSystem from 'expo-file-system';
|
import * as FileSystem from 'expo-file-system';
|
||||||
import * as ImagePicker from "expo-image-picker";
|
import * as ImagePicker from "expo-image-picker";
|
||||||
import { themes } from '@/app/themes';
|
|
||||||
import { featureFlags } from '@/featureFlags';
|
|
||||||
|
|
||||||
interface ProfileScreenProps {
|
interface ProfileScreenProps {
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
@ -15,26 +13,21 @@ interface ProfileScreenProps {
|
|||||||
image: string;
|
image: string;
|
||||||
setImage: (image: string) => void;
|
setImage: (image: string) => void;
|
||||||
setChanged: (dataChanged: boolean) => void;
|
setChanged: (dataChanged: boolean) => void;
|
||||||
setTheme: (theme: string) => void;
|
|
||||||
currentTheme: string;
|
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ProfileScreen: React.FC<ProfileScreenProps> = ({ visible, name, setName, image, setImage, setChanged, currentTheme, setTheme, onClose }) => {
|
const ProfileScreen: React.FC<ProfileScreenProps> = ({ visible, name, setName, image, setImage, setChanged, onClose }) => {
|
||||||
const theme = useTheme();
|
const { colors } = useTheme();
|
||||||
const isNameEmpty = !name.trim();
|
const isNameEmpty = !name.trim();
|
||||||
const themeColors = ['red', 'blue', 'yellow', 'green', 'orange', 'purple'];
|
|
||||||
|
|
||||||
// Track the initial values when the component first mounts
|
// Track the initial values when the component first mounts
|
||||||
const [initialName, setInitialName] = useState(name);
|
const [initialName, setInitialName] = useState(name);
|
||||||
const [initialImage, setInitialImage] = useState(image);
|
const [initialImage, setInitialImage] = useState(image);
|
||||||
const [initialTheme, setInitialTheme] = useState(currentTheme);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
setInitialName(name); // Store initial name when the profile opens
|
setInitialName(name); // Store initial name when the profile opens
|
||||||
setInitialImage(image);
|
setInitialImage(image); // Store initial image when the profile opens
|
||||||
setInitialTheme(currentTheme)// Store initial image when the profile opens
|
|
||||||
}
|
}
|
||||||
}, [visible]); // Reset when the dialog is opened
|
}, [visible]); // Reset when the dialog is opened
|
||||||
|
|
||||||
@ -85,7 +78,7 @@ const ProfileScreen: React.FC<ProfileScreenProps> = ({ visible, name, setName, i
|
|||||||
|
|
||||||
const handleSave = () => {
|
const handleSave = () => {
|
||||||
// Check if the name or image has changed
|
// Check if the name or image has changed
|
||||||
const hasChanged = name !== initialName || image !== initialImage || currentTheme !== initialTheme;
|
const hasChanged = name !== initialName || image !== initialImage;
|
||||||
if (hasChanged) {
|
if (hasChanged) {
|
||||||
setChanged(true);
|
setChanged(true);
|
||||||
}
|
}
|
||||||
@ -101,8 +94,8 @@ const ProfileScreen: React.FC<ProfileScreenProps> = ({ visible, name, setName, i
|
|||||||
onClose();
|
onClose();
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
style={{ backgroundColor: theme.colors.background }}>
|
style={{ backgroundColor: colors.background }}>
|
||||||
<Dialog.Title style={{ color: theme.colors.onBackground, textAlign: 'center' }}>Edit Your Profile</Dialog.Title>
|
<Dialog.Title style={{ color: colors.onBackground, textAlign: 'center' }}>Edit Your Profile</Dialog.Title>
|
||||||
<Dialog.Content>
|
<Dialog.Content>
|
||||||
<Avatar.Image
|
<Avatar.Image
|
||||||
size={100}
|
size={100}
|
||||||
@ -112,8 +105,8 @@ const ProfileScreen: React.FC<ProfileScreenProps> = ({ visible, name, setName, i
|
|||||||
<Button
|
<Button
|
||||||
onPress={pickImage}
|
onPress={pickImage}
|
||||||
mode="contained"
|
mode="contained"
|
||||||
style={{ backgroundColor: theme.colors.primary, marginBottom: 10 }}
|
style={{ backgroundColor: colors.primary, marginBottom: 10 }}
|
||||||
labelStyle={{ color: theme.colors.onPrimary }}
|
labelStyle={{ color: colors.onPrimary }}
|
||||||
>
|
>
|
||||||
Change Profile Picture
|
Change Profile Picture
|
||||||
</Button>
|
</Button>
|
||||||
@ -127,26 +120,10 @@ const ProfileScreen: React.FC<ProfileScreenProps> = ({ visible, name, setName, i
|
|||||||
console.log("Name change");
|
console.log("Name change");
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
style={{ marginBottom: 15, backgroundColor: theme.colors.surface }}
|
style={{ marginBottom: 15, backgroundColor: colors.surface }}
|
||||||
placeholderTextColor={theme.colors.onSurface}
|
placeholderTextColor={colors.onSurface}
|
||||||
theme={{ colors: { text: theme.colors.onSurface } }}
|
theme={{ colors: { text: colors.onSurface } }}
|
||||||
/>
|
/>
|
||||||
{featureFlags.enableThemeSelection && (
|
|
||||||
<>
|
|
||||||
<Text style={{ color: theme.colors.onBackground, fontSize: 18, textAlign: 'center' }}>Choose Theme</Text>
|
|
||||||
<View style={styles.themeContainer}>
|
|
||||||
{themeColors.map((userTheme) => (
|
|
||||||
<TouchableOpacity
|
|
||||||
key={userTheme}
|
|
||||||
style={[styles.themeButton, { backgroundColor: themes[userTheme as keyof typeof themes]['light'].colors.primary }]}
|
|
||||||
onPress={() => {setTheme(userTheme); console.log("Changing Theme: ", userTheme)}}
|
|
||||||
>
|
|
||||||
<View style={[styles.halfCircle, { backgroundColor: themes[userTheme as keyof typeof themes]['dark'].colors.primary }]} />
|
|
||||||
</TouchableOpacity>
|
|
||||||
))}
|
|
||||||
</View>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Dialog.Content>
|
</Dialog.Content>
|
||||||
<Dialog.Actions>
|
<Dialog.Actions>
|
||||||
<Button
|
<Button
|
||||||
@ -154,39 +131,17 @@ const ProfileScreen: React.FC<ProfileScreenProps> = ({ visible, name, setName, i
|
|||||||
mode="contained"
|
mode="contained"
|
||||||
disabled={isNameEmpty} // Disable if name is empty
|
disabled={isNameEmpty} // Disable if name is empty
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: theme.colors.primary,
|
backgroundColor: isNameEmpty ? colors.tertiary : colors.secondary, // Dim the button
|
||||||
opacity: isNameEmpty ? 0.5 : 1, // Visually dim the button
|
opacity: isNameEmpty ? 0.5 : 1, // Visually dim the button
|
||||||
}}
|
}}
|
||||||
labelStyle={{ color: theme.colors.onPrimary }}>Save</Button>
|
labelStyle={{ color: colors.onPrimary }}
|
||||||
|
>
|
||||||
|
Save
|
||||||
|
</Button>
|
||||||
</Dialog.Actions>
|
</Dialog.Actions>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</Portal>
|
</Portal>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
themeContainer: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
justifyContent: 'space-around',
|
|
||||||
marginTop: 10,
|
|
||||||
},
|
|
||||||
themeButton: {
|
|
||||||
width: 50,
|
|
||||||
height: 50,
|
|
||||||
borderRadius: 25,
|
|
||||||
justifyContent: 'center',
|
|
||||||
alignItems: 'flex-start',
|
|
||||||
overflow: 'hidden',
|
|
||||||
borderWidth: 1,
|
|
||||||
borderColor: 'black',
|
|
||||||
},
|
|
||||||
halfCircle: {
|
|
||||||
width: '50%',
|
|
||||||
height: '100%',
|
|
||||||
position: 'absolute',
|
|
||||||
bottom: 0,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default ProfileScreen;
|
export default ProfileScreen;
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
import React, { useEffect, useState, useRef } from "react";
|
import React, { useEffect, useState, useRef } from "react";
|
||||||
import useWebSocket from "react-use-websocket";
|
import useWebSocket from "react-use-websocket";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import {Animated, Easing, ImageBackground, StyleSheet, useColorScheme, View} from "react-native";
|
import { Animated, Easing, ImageBackground, StyleSheet, View } from "react-native";
|
||||||
import { Avatar, List, Button, useTheme, } from "react-native-paper";
|
import { Avatar, List, Button, useTheme, } from "react-native-paper";
|
||||||
import { themes } from "@/app/themes";
|
|
||||||
|
|
||||||
export const API_URL = process.env.EXPO_PUBLIC_API_URL;
|
export const API_URL = process.env.EXPO_PUBLIC_API_URL;
|
||||||
export const WS_URL = process.env.EXPO_PUBLIC_WS_URL;
|
export const WS_URL = process.env.EXPO_PUBLIC_WS_URL;
|
||||||
@ -13,7 +12,6 @@ interface Message {
|
|||||||
Name: string;
|
Name: string;
|
||||||
Image: string;
|
Image: string;
|
||||||
Status: string;
|
Status: string;
|
||||||
Theme: string;
|
|
||||||
Timestamp: string;
|
Timestamp: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,15 +69,13 @@ interface StatusProps {
|
|||||||
image: string;
|
image: string;
|
||||||
currentStatus: string;
|
currentStatus: string;
|
||||||
setStatus: (currentStatus: string) => void;
|
setStatus: (currentStatus: string) => void;
|
||||||
currentTheme: string;
|
|
||||||
isProfileActive: boolean;
|
isProfileActive: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const StatusPage: React.FC<StatusProps> = ({ id, name, image, currentStatus, setStatus, currentTheme, isProfileActive }) => {
|
const StatusPage: React.FC<StatusProps> = ({ id, name, image, currentStatus, setStatus, isProfileActive }) => {
|
||||||
//console.log("WebSocket URL: ", WS_URL);
|
//console.log("WebSocket URL: ", WS_URL);
|
||||||
//console.log("API URL: ", API_URL);
|
//console.log("API URL: ", API_URL);
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const colorScheme = useColorScheme();
|
|
||||||
const [messages, setMessages] = useState<Message[]>([]);
|
const [messages, setMessages] = useState<Message[]>([]);
|
||||||
const { lastMessage } = useWebSocket(WS_URL + "/ws", {
|
const { lastMessage } = useWebSocket(WS_URL + "/ws", {
|
||||||
shouldReconnect: () => true,
|
shouldReconnect: () => true,
|
||||||
@ -150,7 +146,6 @@ const StatusPage: React.FC<StatusProps> = ({ id, name, image, currentStatus, set
|
|||||||
Name: name,
|
Name: name,
|
||||||
Image: image,
|
Image: image,
|
||||||
Status: "none",
|
Status: "none",
|
||||||
Theme: currentTheme,
|
|
||||||
Timestamp: new Date().toISOString()
|
Timestamp: new Date().toISOString()
|
||||||
};
|
};
|
||||||
await axios.post(API_URL + "/set", message);
|
await axios.post(API_URL + "/set", message);
|
||||||
@ -165,7 +160,6 @@ const StatusPage: React.FC<StatusProps> = ({ id, name, image, currentStatus, set
|
|||||||
Name: name,
|
Name: name,
|
||||||
Image: image,
|
Image: image,
|
||||||
Status: status,
|
Status: status,
|
||||||
Theme: currentTheme,
|
|
||||||
Timestamp: new Date().toISOString()
|
Timestamp: new Date().toISOString()
|
||||||
};
|
};
|
||||||
await axios.post(API_URL + "/set", message);
|
await axios.post(API_URL + "/set", message);
|
||||||
@ -219,14 +213,13 @@ const StatusPage: React.FC<StatusProps> = ({ id, name, image, currentStatus, set
|
|||||||
{messages.filter(msg => msg.Status === "On the Way")
|
{messages.filter(msg => msg.Status === "On the Way")
|
||||||
.sort((a, b) => new Date(a.Timestamp).getTime() - new Date(b.Timestamp).getTime())
|
.sort((a, b) => new Date(a.Timestamp).getTime() - new Date(b.Timestamp).getTime())
|
||||||
.map(item => (
|
.map(item => (
|
||||||
<View key={item.Id} style={[styles.card,
|
<View key={item.Id} style={[styles.card, { backgroundColor: theme.colors.primaryContainer }]}>
|
||||||
{ backgroundColor: themes[item.Theme as keyof typeof themes][colorScheme === 'dark' ? 'dark' : 'light'].colors.primaryContainer }]}>
|
|
||||||
<List.Item
|
<List.Item
|
||||||
key={item.Id}
|
key={item.Id}
|
||||||
title={item.Name}
|
title={item.Name}
|
||||||
titleStyle={{ color: themes[item.Theme as keyof typeof themes][colorScheme === 'dark' ? 'dark' : 'light'].colors.onSurface }}
|
titleStyle={{ color: theme.colors.onSurface }}
|
||||||
description={new Date(item.Timestamp).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', hour12: true })}
|
description={new Date(item.Timestamp).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', hour12: true })}
|
||||||
descriptionStyle={{ color: themes[item.Theme as keyof typeof themes][colorScheme === 'dark' ? 'dark' : 'light'].colors.onSurface }}
|
descriptionStyle={{ color: theme.colors.onSurface }}
|
||||||
left={(props) => <Avatar.Image {...props} size={40} source={{ uri: `data:image/png;base64,${item.Image}` }} />}
|
left={(props) => <Avatar.Image {...props} size={40} source={{ uri: `data:image/png;base64,${item.Image}` }} />}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
@ -239,14 +232,13 @@ const StatusPage: React.FC<StatusProps> = ({ id, name, image, currentStatus, set
|
|||||||
{messages.filter(msg => msg.Status === "Arrived")
|
{messages.filter(msg => msg.Status === "Arrived")
|
||||||
.sort((a, b) => new Date(a.Timestamp).getTime() - new Date(b.Timestamp).getTime())
|
.sort((a, b) => new Date(a.Timestamp).getTime() - new Date(b.Timestamp).getTime())
|
||||||
.map(item => (
|
.map(item => (
|
||||||
<View key={item.Id} style={[styles.card,
|
<View key={item.Id} style={[styles.card, { backgroundColor: theme.colors.primaryContainer }]}>
|
||||||
{ backgroundColor: themes[item.Theme as keyof typeof themes][colorScheme === 'dark' ? 'dark' : 'light'].colors.primaryContainer }]}>
|
|
||||||
<List.Item
|
<List.Item
|
||||||
key={item.Id}
|
key={item.Id}
|
||||||
title={item.Name}
|
title={item.Name}
|
||||||
titleStyle={{ color: themes[item.Theme as keyof typeof themes][colorScheme === 'dark' ? 'dark' : 'light'].colors.onSurface }}
|
titleStyle={{ color: theme.colors.onSurface }}
|
||||||
description={new Date(item.Timestamp).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', hour12: true })}
|
description={new Date(item.Timestamp).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', hour12: true })}
|
||||||
descriptionStyle={{ color: themes[item.Theme as keyof typeof themes][colorScheme === 'dark' ? 'dark' : 'light'].colors.onSurface }}
|
descriptionStyle={{ color: theme.colors.onSurface }}
|
||||||
left={(props) => <Avatar.Image {...props} size={40} source={{ uri: `data:image/png;base64,${item.Image}` }} />}
|
left={(props) => <Avatar.Image {...props} size={40} source={{ uri: `data:image/png;base64,${item.Image}` }} />}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
@ -6,27 +6,17 @@ import 'react-native-reanimated';
|
|||||||
import { useColorScheme } from 'react-native';
|
import { useColorScheme } from 'react-native';
|
||||||
import { PaperProvider, Provider } from "react-native-paper";
|
import { PaperProvider, Provider } from "react-native-paper";
|
||||||
import { themes } from '@/app/themes'
|
import { themes } from '@/app/themes'
|
||||||
import { UserProvider, useUser } from "@/context/UserContext";
|
|
||||||
|
|
||||||
// Prevent the splash screen from auto-hiding before asset loading is complete.
|
// Prevent the splash screen from auto-hiding before asset loading is complete.
|
||||||
SplashScreen.preventAutoHideAsync();
|
SplashScreen.preventAutoHideAsync();
|
||||||
|
|
||||||
export default function RootLayout() {
|
export default function RootLayout() {
|
||||||
return (
|
|
||||||
<UserProvider>
|
|
||||||
<InnerRootLayout />
|
|
||||||
</UserProvider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function InnerRootLayout() {
|
|
||||||
const { currentTheme } = useUser(); // Access the currentTheme from UserContext
|
|
||||||
console.log(currentTheme);
|
|
||||||
const colorScheme = useColorScheme();
|
const colorScheme = useColorScheme();
|
||||||
console.log(colorScheme);
|
console.log(colorScheme);
|
||||||
const [loaded] = useFonts({
|
const [loaded] = useFonts({
|
||||||
SpaceMono: require('../assets/fonts/SpaceMono-Regular.ttf'),
|
SpaceMono: require('../assets/fonts/SpaceMono-Regular.ttf'),
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (loaded) {
|
if (loaded) {
|
||||||
SplashScreen.hideAsync();
|
SplashScreen.hideAsync();
|
||||||
@ -36,18 +26,12 @@ function InnerRootLayout() {
|
|||||||
if (!loaded) {
|
if (!loaded) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
const selectedTheme = 'green';
|
||||||
// Ensure currentTheme is treated as a valid key, or fallback to 'blue'
|
//const [selectedTheme, setSelectedTheme] = useState<'red' | 'blue' | 'yellow' | 'green' | 'orange'>('red');
|
||||||
const themeKey: 'blue' | 'green' | 'red' | 'yellow' | 'orange' = (currentTheme as 'blue' | 'green' | 'red' | 'yellow' | 'orange') || 'blue';
|
const appTheme = themes[selectedTheme][colorScheme === 'dark' ? 'dark' : 'light'];
|
||||||
|
|
||||||
// Use the themeKey to index into the themes object
|
|
||||||
|
|
||||||
const appTheme = themes[themeKey][colorScheme === 'dark' ? 'dark' : 'light'];
|
|
||||||
const appTheme2 = themes[currentTheme as keyof typeof themes][colorScheme === 'dark' ? 'dark' : 'light']
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Provider>
|
<Provider>
|
||||||
<PaperProvider theme={appTheme2}>
|
<PaperProvider theme={appTheme} >
|
||||||
<Stack>
|
<Stack>
|
||||||
<Stack.Screen name="index" options={{ headerShown: false }} />
|
<Stack.Screen name="index" options={{ headerShown: false }} />
|
||||||
</Stack>
|
</Stack>
|
||||||
|
116
app/index.tsx
116
app/index.tsx
@ -1,29 +1,106 @@
|
|||||||
import React from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import {View, StyleSheet, Text } from "react-native";
|
import {View, StyleSheet, Text, AppState } from "react-native";
|
||||||
import { useTheme } from "react-native-paper";
|
import { useTheme } from "react-native-paper";
|
||||||
|
import { v4 as uuidv4 } from "uuid";
|
||||||
|
import AsyncStorage from "@react-native-async-storage/async-storage";
|
||||||
import ProfileScreen from "@/app/ProfileScreen";
|
import ProfileScreen from "@/app/ProfileScreen";
|
||||||
import StatusPage from "@/app/StatusPage";
|
import StatusPage from "@/app/StatusPage";
|
||||||
import Nav from "@/app/Nav";
|
import Nav from "@/app/Nav";
|
||||||
import { useUser } from "@/context/UserContext";
|
import axios from "axios";
|
||||||
|
export const API_URL = process.env.EXPO_PUBLIC_API_URL;
|
||||||
|
|
||||||
const Index = () => {
|
const Index = () => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
const [isProfileActive, setProfileActive] = useState(false);
|
||||||
|
const [userId, setUserId] = useState("");
|
||||||
|
const [userName, setUserName] = useState("");
|
||||||
|
const [userImage, setUserImage] = useState("");
|
||||||
|
const [userStatus, setUserStatus] = useState("none");
|
||||||
|
const [userDataChanged, setUserDataChanged] = useState(false);
|
||||||
|
const [isLoading, setIsLoading] = useState(true); // New loading state
|
||||||
|
const [appState, setAppState] = useState(AppState.currentState);
|
||||||
|
|
||||||
const {
|
useEffect(() => {
|
||||||
isProfileActive,
|
const loadUserData = async () => {
|
||||||
setProfileActive,
|
try {
|
||||||
userId,
|
const storedUserId = await AsyncStorage.getItem("userId");
|
||||||
userName,
|
const storedUserName = await AsyncStorage.getItem("userName");
|
||||||
setUserName,
|
const storedUserImage = await AsyncStorage.getItem("userImage");
|
||||||
userImage,
|
console.log("User Id: ", storedUserId);
|
||||||
setUserImage,
|
if (storedUserId) {
|
||||||
userStatus,
|
setUserId(storedUserId || uuidv4());
|
||||||
setUserStatus,
|
setUserName(storedUserName || "");
|
||||||
setUserDataChanged,
|
setUserImage(storedUserImage || "");
|
||||||
setTheme,
|
setProfileActive(false);
|
||||||
currentTheme,
|
} else {
|
||||||
isLoading,
|
setUserId(uuidv4());
|
||||||
} = useUser();
|
setUserName("");
|
||||||
|
setUserImage("");
|
||||||
|
setProfileActive(true);
|
||||||
|
}
|
||||||
|
console.log("Loading data ", userId);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error loading user data:", error);
|
||||||
|
} finally {
|
||||||
|
setIsLoading(false); // Mark loading as complete
|
||||||
|
}
|
||||||
|
};
|
||||||
|
loadUserData();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!userDataChanged) return;
|
||||||
|
|
||||||
|
const saveUserData = async () => {
|
||||||
|
try {
|
||||||
|
console.log("Saving data ", userId);
|
||||||
|
await AsyncStorage.setItem("userId", userId);
|
||||||
|
await AsyncStorage.setItem("userName", userName);
|
||||||
|
await AsyncStorage.setItem("userImage", userImage);
|
||||||
|
setUserDataChanged(false);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error saving user data:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
saveUserData();
|
||||||
|
}, [userDataChanged]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleAppStateChange = (nextAppState: string) => {
|
||||||
|
//console.log("App state", appState);
|
||||||
|
//console.log("Next App state", nextAppState);
|
||||||
|
if (appState.match(/inactive|background/) && nextAppState === "active") {
|
||||||
|
// When the app comes to the foreground, fetch the status
|
||||||
|
if (!isLoading) {
|
||||||
|
fetchCurrentStatus().then()
|
||||||
|
} else {
|
||||||
|
console.log("Waiting for loading to complete before fetching status...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setAppState(AppState.currentState);
|
||||||
|
};
|
||||||
|
|
||||||
|
const listener = AppState.addEventListener("change", handleAppStateChange);
|
||||||
|
|
||||||
|
// Cleanup listener on unmount
|
||||||
|
return () => {
|
||||||
|
listener.remove();
|
||||||
|
};
|
||||||
|
}, [appState]);
|
||||||
|
|
||||||
|
const fetchCurrentStatus = async () => {
|
||||||
|
try {
|
||||||
|
const response = await axios.post(API_URL + "/get", { id: userId });
|
||||||
|
console.log("response: ", response);
|
||||||
|
if (response.data?.status) {
|
||||||
|
setTimeout(() => {
|
||||||
|
setUserStatus("none"); // Reset status
|
||||||
|
}, 0)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching status:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
console.log("Still loading");
|
console.log("Still loading");
|
||||||
@ -45,7 +122,6 @@ const Index = () => {
|
|||||||
image={userImage}
|
image={userImage}
|
||||||
currentStatus={userStatus}
|
currentStatus={userStatus}
|
||||||
setStatus={setUserStatus}
|
setStatus={setUserStatus}
|
||||||
currentTheme={currentTheme}
|
|
||||||
isProfileActive={isProfileActive}
|
isProfileActive={isProfileActive}
|
||||||
/>
|
/>
|
||||||
<ProfileScreen
|
<ProfileScreen
|
||||||
@ -55,8 +131,6 @@ const Index = () => {
|
|||||||
setName={setUserName}
|
setName={setUserName}
|
||||||
image={userImage}
|
image={userImage}
|
||||||
setImage={setUserImage}
|
setImage={setUserImage}
|
||||||
setTheme={setTheme}
|
|
||||||
currentTheme={currentTheme}
|
|
||||||
setChanged={setUserDataChanged}
|
setChanged={setUserDataChanged}
|
||||||
onClose={() => setProfileActive(false)}
|
onClose={() => setProfileActive(false)}
|
||||||
/>
|
/>
|
||||||
|
@ -1,157 +0,0 @@
|
|||||||
import React, { createContext, useContext, useEffect, useState, ReactNode } from "react";
|
|
||||||
import AsyncStorage from "@react-native-async-storage/async-storage";
|
|
||||||
import { AppState } from "react-native";
|
|
||||||
import { v4 as uuidv4 } from "uuid";
|
|
||||||
import axios from "axios";
|
|
||||||
|
|
||||||
export const API_URL = process.env.EXPO_PUBLIC_API_URL;
|
|
||||||
|
|
||||||
// Define context type
|
|
||||||
interface UserContextType {
|
|
||||||
isProfileActive: boolean;
|
|
||||||
setProfileActive: (active: boolean) => void;
|
|
||||||
userId: string;
|
|
||||||
userName: string;
|
|
||||||
setUserName: (name: string) => void;
|
|
||||||
userImage: string;
|
|
||||||
setUserImage: (image: string) => void;
|
|
||||||
userStatus: string;
|
|
||||||
setUserStatus: (status: string) => void;
|
|
||||||
setUserDataChanged: (changed: boolean) => void;
|
|
||||||
isLoading: boolean;
|
|
||||||
currentTheme: string;
|
|
||||||
setTheme: (theme: string) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create context with default values
|
|
||||||
const UserContext = createContext<UserContextType | undefined>(undefined);
|
|
||||||
|
|
||||||
// Define provider props type
|
|
||||||
interface UserProviderProps {
|
|
||||||
children: ReactNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const UserProvider: React.FC<UserProviderProps> = ({ children }) => {
|
|
||||||
const [isProfileActive, setProfileActive] = useState(false);
|
|
||||||
const [userId, setUserId] = useState("");
|
|
||||||
const [userName, setUserName] = useState("");
|
|
||||||
const [userImage, setUserImage] = useState("");
|
|
||||||
const [userStatus, setUserStatus] = useState("none");
|
|
||||||
const [userDataChanged, setUserDataChanged] = useState(false);
|
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
|
||||||
const [appState, setAppState] = useState(AppState.currentState);
|
|
||||||
const [currentTheme, setTheme] = useState("");
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const loadUserData = async () => {
|
|
||||||
try {
|
|
||||||
const storedUserId = await AsyncStorage.getItem("userId");
|
|
||||||
const storedUserName = await AsyncStorage.getItem("userName");
|
|
||||||
const storedUserImage = await AsyncStorage.getItem("userImage");
|
|
||||||
const storedUserTheme = await AsyncStorage.getItem("theme");
|
|
||||||
console.log("Stored theme: ", storedUserTheme);
|
|
||||||
if (storedUserId) {
|
|
||||||
setUserId(storedUserId);
|
|
||||||
setUserName(storedUserName || "");
|
|
||||||
setUserImage(storedUserImage || "");
|
|
||||||
setTheme(storedUserTheme || "blue");
|
|
||||||
setProfileActive(false);
|
|
||||||
} else {
|
|
||||||
setUserId(uuidv4());
|
|
||||||
setUserName("");
|
|
||||||
setUserImage("");
|
|
||||||
setTheme("blue")
|
|
||||||
setProfileActive(true);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error loading user data:", error);
|
|
||||||
} finally {
|
|
||||||
setIsLoading(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
loadUserData();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!userDataChanged) return;
|
|
||||||
|
|
||||||
const saveUserData = async () => {
|
|
||||||
try {
|
|
||||||
await AsyncStorage.setItem("userId", userId);
|
|
||||||
await AsyncStorage.setItem("userName", userName);
|
|
||||||
await AsyncStorage.setItem("userImage", userImage);
|
|
||||||
await AsyncStorage.setItem("theme", currentTheme);
|
|
||||||
console.log("Current theme: ", currentTheme);
|
|
||||||
setUserDataChanged(false);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error saving user data:", error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
saveUserData();
|
|
||||||
}, [userDataChanged]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const handleAppStateChange = (nextAppState: string) => {
|
|
||||||
if (appState.match(/inactive|background/) && nextAppState === "active") {
|
|
||||||
if (!isLoading) {
|
|
||||||
fetchCurrentStatus();
|
|
||||||
} else {
|
|
||||||
console.log("Waiting for loading to complete before fetching status...");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setAppState(AppState.currentState);
|
|
||||||
};
|
|
||||||
|
|
||||||
const listener = AppState.addEventListener("change", handleAppStateChange);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
listener.remove();
|
|
||||||
};
|
|
||||||
}, [appState]);
|
|
||||||
|
|
||||||
const fetchCurrentStatus = async () => {
|
|
||||||
try {
|
|
||||||
const response = await axios.post(API_URL + "/get", { id: userId });
|
|
||||||
if (response.data?.status) {
|
|
||||||
setTimeout(() => {
|
|
||||||
setUserStatus("none");
|
|
||||||
}, 0);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error fetching status:", error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<UserContext.Provider
|
|
||||||
value={{
|
|
||||||
isProfileActive,
|
|
||||||
setProfileActive,
|
|
||||||
userId,
|
|
||||||
userName,
|
|
||||||
setUserName,
|
|
||||||
userImage,
|
|
||||||
setUserImage,
|
|
||||||
userStatus,
|
|
||||||
setUserStatus,
|
|
||||||
setUserDataChanged,
|
|
||||||
isLoading,
|
|
||||||
currentTheme,
|
|
||||||
setTheme,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</UserContext.Provider>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Custom hook to use context
|
|
||||||
export const useUser = (): UserContextType => {
|
|
||||||
const context = useContext(UserContext);
|
|
||||||
if (!context) {
|
|
||||||
throw new Error("useUser must be used within a UserProvider");
|
|
||||||
}
|
|
||||||
return context;
|
|
||||||
};
|
|
@ -1,3 +0,0 @@
|
|||||||
export const featureFlags = {
|
|
||||||
enableThemeSelection: true, // Toggle this to true or false to enable/disable the feature
|
|
||||||
};
|
|
Loading…
Reference in New Issue
Block a user