trying to get push notifications to work
This commit is contained in:
@ -1,10 +1,11 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { StyleSheet, ActivityIndicator, TouchableOpacity } from 'react-native';
|
||||
import { StyleSheet, ActivityIndicator, TouchableOpacity, View } from 'react-native';
|
||||
import { ThemedText } from '@/components/ThemedText';
|
||||
import { ThemedView } from '@/components/ThemedView';
|
||||
import { SafeAreaView } from 'react-native-safe-area-context'; // Import for safe area handling
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import axios from 'axios';
|
||||
import ChangeDateDrawer from '@/components/ChangeDateDrawer';
|
||||
import ChangeDateDrawer from '@/components/ChangeDateDrawer'; // Date drawer component
|
||||
|
||||
const API_KEY = process.env.EXPO_PUBLIC_API_KEY;
|
||||
const BASE_URL = process.env.EXPO_PUBLIC_BASE_URL;
|
||||
@ -16,7 +17,6 @@ const fetchCountdownDate = async () => {
|
||||
params: { apiKey: API_KEY }
|
||||
});
|
||||
if (response.data && response.data[0] && response.data[0].countdown) {
|
||||
//console.log('Countdown date:', response.data[0].countdown);
|
||||
return new Date(response.data[0].countdown);
|
||||
} else {
|
||||
console.error('Unexpected API response format:', response.data);
|
||||
@ -98,29 +98,32 @@ export default function TabTwoScreen() {
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 1 }}
|
||||
>
|
||||
<ThemedView style={styles.container}>
|
||||
<ThemedText style={styles.title}>Countdown to Next Visit</ThemedText>
|
||||
<ThemedView style={styles.countdownContainer}>
|
||||
<CountdownItem value={countdown.days} label={days} />
|
||||
<CountdownItem value={countdown.hours} label={hours} />
|
||||
<CountdownItem value={countdown.minutes} label={minutes} />
|
||||
<CountdownItem value={countdown.seconds} label={seconds} />
|
||||
<SafeAreaView style={styles.safeContainer}>
|
||||
<ThemedView style={styles.innerContainer}>
|
||||
<ThemedText style={styles.title}>Countdown to Next Visit</ThemedText>
|
||||
<ThemedView style={styles.countdownContainer}>
|
||||
{/* Countdown items displayed horizontally with flexbox */}
|
||||
<CountdownItem value={countdown.days} label={days} />
|
||||
<CountdownItem value={countdown.hours} label={hours} />
|
||||
<CountdownItem value={countdown.minutes} label={minutes} />
|
||||
<CountdownItem value={countdown.seconds} label={seconds} />
|
||||
</ThemedView>
|
||||
<TouchableOpacity
|
||||
style={styles.changeButton}
|
||||
onPress={() => setIsDateDrawerVisible(true)}
|
||||
>
|
||||
<ThemedText style={styles.changeButtonText}>Change Date</ThemedText>
|
||||
</TouchableOpacity>
|
||||
{targetDate && (
|
||||
<ChangeDateDrawer
|
||||
isVisible={isDateDrawerVisible}
|
||||
onClose={() => setIsDateDrawerVisible(false)}
|
||||
onDateChange={handleDateChange}
|
||||
currentDate={targetDate}
|
||||
/>
|
||||
)}
|
||||
</ThemedView>
|
||||
<TouchableOpacity
|
||||
style={styles.changeButton}
|
||||
onPress={() => setIsDateDrawerVisible(true)}
|
||||
>
|
||||
<ThemedText style={styles.changeButtonText}>Change Date</ThemedText>
|
||||
</TouchableOpacity>
|
||||
{targetDate && (
|
||||
<ChangeDateDrawer
|
||||
isVisible={isDateDrawerVisible}
|
||||
onClose={() => setIsDateDrawerVisible(false)}
|
||||
onDateChange={handleDateChange}
|
||||
currentDate={targetDate}
|
||||
/>
|
||||
)}
|
||||
</ThemedView>
|
||||
</SafeAreaView>
|
||||
</LinearGradient>
|
||||
);
|
||||
}
|
||||
@ -135,31 +138,39 @@ function CountdownItem({ value, label }: { value: number; label: string }) {
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
safeContainer: {
|
||||
flex: 1,
|
||||
backgroundColor: 'transparent', // Background color for safety area view
|
||||
},
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
innerContainer: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
paddingHorizontal: 20, // Padding around the edges
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
title: {
|
||||
fontSize: 64,
|
||||
lineHeight: 64,
|
||||
fontWeight: 'bold',
|
||||
marginTop: 100,
|
||||
marginBottom: 60,
|
||||
fontSize: 40, // Shrinking the title for smaller screens
|
||||
lineHeight: 50,
|
||||
fontWeight: '600',
|
||||
textAlign: 'center',
|
||||
paddingHorizontal: 20,
|
||||
paddingHorizontal: 10,
|
||||
},
|
||||
countdownContainer: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'center',
|
||||
justifyContent: 'space-around', // Spread countdown items more evenly
|
||||
alignItems: 'center',
|
||||
width: '100%',
|
||||
backgroundColor: 'transparent',
|
||||
marginBottom: 180,
|
||||
marginVertical: 40, // Added some space between countdown and title/button
|
||||
},
|
||||
countdownItem: {
|
||||
margin: 10,
|
||||
lineHeight: 42,
|
||||
alignItems: 'center',
|
||||
marginHorizontal: 10, // Each item has horizontal spacing
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
countdownValue: {
|
||||
@ -168,18 +179,18 @@ const styles = StyleSheet.create({
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
countdownLabel: {
|
||||
fontSize: 32,
|
||||
lineHeight: 42,
|
||||
fontSize: 18, // Reducing size of the label for better fit
|
||||
lineHeight: 24,
|
||||
},
|
||||
changeButton: {
|
||||
backgroundColor: '#730FF8',
|
||||
padding: 15,
|
||||
borderRadius: 10,
|
||||
marginTop: 40,
|
||||
padding: 12,
|
||||
borderRadius: 8,
|
||||
marginTop: 20,
|
||||
},
|
||||
changeButtonText: {
|
||||
color: 'white',
|
||||
fontSize: 22,
|
||||
fontSize: 18,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
});
|
||||
});
|
@ -1,5 +1,5 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { StyleSheet } from 'react-native';
|
||||
import { StyleSheet, SafeAreaView } from 'react-native';
|
||||
import { ThemedText } from '@/components/ThemedText';
|
||||
import { ThemedView } from '@/components/ThemedView';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
@ -50,9 +50,11 @@ export default function HomeScreen() {
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 1 }}
|
||||
>
|
||||
<ThemedView style={styles.container}>
|
||||
<ThemedText style={styles.title}>{message}</ThemedText>
|
||||
</ThemedView>
|
||||
<SafeAreaView style={styles.container}>
|
||||
<ThemedView style={styles.container}>
|
||||
<ThemedText style={styles.title}>{message}</ThemedText>
|
||||
</ThemedView>
|
||||
</SafeAreaView>
|
||||
</LinearGradient>
|
||||
);
|
||||
}
|
||||
|
@ -7,44 +7,49 @@ import {
|
||||
Keyboard,
|
||||
TouchableWithoutFeedback,
|
||||
KeyboardAvoidingView,
|
||||
Platform,
|
||||
View
|
||||
Platform,
|
||||
SafeAreaView, // SafeAreaView import for handling safe areas
|
||||
View
|
||||
} from 'react-native';
|
||||
import { ThemedText } from '@/components/ThemedText';
|
||||
import { ThemedView } from '@/components/ThemedView';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
import axios from 'axios';
|
||||
|
||||
// Environment variables
|
||||
const API_KEY = process.env.EXPO_PUBLIC_API_KEY;
|
||||
const BASE_URL = process.env.EXPO_PUBLIC_BASE_URL;
|
||||
|
||||
export default function SendMessageScreen() {
|
||||
const [message, setMessage] = useState('');
|
||||
const [userId, setUserId] = useState(null);
|
||||
const [inputHeight, setInputHeight] = useState(100);
|
||||
const [userId, setUserId] = useState<number | null>(null); // Use number type for userId
|
||||
const [inputHeight, setInputHeight] = useState(120); // Set initial height for TextInput
|
||||
|
||||
// Update TextInput height dynamically
|
||||
const updateInputHeight = (height: number) => {
|
||||
setInputHeight(Math.max(100, height));
|
||||
setInputHeight(Math.max(120, height)); // Ensure it doesn't shrink below 120px
|
||||
};
|
||||
|
||||
// On component mount, get the user ID from AsyncStorage
|
||||
useEffect(() => {
|
||||
const getUserId = async () => {
|
||||
try {
|
||||
const storedUser = await AsyncStorage.getItem('@user');
|
||||
if (storedUser) {
|
||||
const user = JSON.parse(storedUser);
|
||||
setUserId(user.id);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to get user ID:', error);
|
||||
}
|
||||
};
|
||||
|
||||
getUserId();
|
||||
}, []);
|
||||
|
||||
const getUserId = async () => {
|
||||
try {
|
||||
const storedUser = await AsyncStorage.getItem('@user');
|
||||
if (storedUser) {
|
||||
const user = JSON.parse(storedUser);
|
||||
setUserId(user.id);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to get user ID:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// Function to send a message
|
||||
const sendMessage = async () => {
|
||||
// Input validation
|
||||
if (!message.trim()) {
|
||||
Alert.alert('Error', 'Please enter a message');
|
||||
return;
|
||||
@ -60,8 +65,8 @@ export default function SendMessageScreen() {
|
||||
params: { apiKey: API_KEY, userId, message }
|
||||
});
|
||||
Alert.alert('Success', 'Message sent successfully');
|
||||
setMessage('');
|
||||
Keyboard.dismiss();
|
||||
setMessage(''); // Clear the message input on success
|
||||
Keyboard.dismiss(); // Dismiss the keyboard
|
||||
} catch (error) {
|
||||
console.error('Failed to send message:', error);
|
||||
Alert.alert('Error', 'Failed to send message. Please try again.');
|
||||
@ -69,75 +74,87 @@ export default function SendMessageScreen() {
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
// Ensure keyboard behaves correctly on both iOS and Android
|
||||
<KeyboardAvoidingView
|
||||
behavior={Platform.OS === "ios" ? "padding" : "height"}
|
||||
style={{flex: 1}}
|
||||
behavior={Platform.OS === "ios" ? "padding" : "height"}
|
||||
style={{ flex: 1 }}
|
||||
>
|
||||
<TouchableWithoutFeedback onPress={Keyboard.dismiss} accessible={false}>
|
||||
<LinearGradient
|
||||
colors={['#F67C0A', '#F60AD3']}
|
||||
style={styles.container}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 1 }}
|
||||
>
|
||||
<View style={styles.container}>
|
||||
<TextInput
|
||||
style={[styles.input, { height: inputHeight }]}
|
||||
value={message}
|
||||
onChangeText={setMessage}
|
||||
placeholder="Send a message"
|
||||
placeholderTextColor="#FFFFFF"
|
||||
multiline
|
||||
numberOfLines={4}
|
||||
textAlignVertical="top"
|
||||
onContentSizeChange={(event) =>
|
||||
updateInputHeight(event.nativeEvent.contentSize.height)
|
||||
}
|
||||
/>
|
||||
<TouchableOpacity style={styles.button} onPress={sendMessage}>
|
||||
<ThemedText style={styles.buttonText}>Send Message</ThemedText>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</LinearGradient>
|
||||
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
|
||||
{/* SafeAreaView for notch and layout safety */}
|
||||
<SafeAreaView style={styles.safeContainer}>
|
||||
<LinearGradient
|
||||
colors={['#F67C0A', '#F60AD3']}
|
||||
style={styles.container}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 1 }}
|
||||
>
|
||||
<View style={styles.chatContainer}>
|
||||
<TextInput
|
||||
style={[styles.input, { height: inputHeight }]} // Dynamic height
|
||||
value={message}
|
||||
onChangeText={setMessage}
|
||||
placeholder="Write a message"
|
||||
placeholderTextColor="#FFFFFF"
|
||||
multiline // Allows multiple lines
|
||||
numberOfLines={4}
|
||||
textAlignVertical="top" // Align text at the top
|
||||
onContentSizeChange={(event) =>
|
||||
updateInputHeight(event.nativeEvent.contentSize.height)
|
||||
}
|
||||
/>
|
||||
|
||||
{/* Send Message Button */}
|
||||
<TouchableOpacity style={styles.button} onPress={sendMessage}>
|
||||
<ThemedText style={styles.buttonText}>Send Message</ThemedText>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</LinearGradient>
|
||||
</SafeAreaView>
|
||||
</TouchableWithoutFeedback>
|
||||
</KeyboardAvoidingView>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
safeContainer: {
|
||||
flex: 1,
|
||||
backgroundColor: 'transparent', // Ensure full-screen safe area
|
||||
},
|
||||
container: {
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
padding: 20,
|
||||
backgroundColor: 'transparent',
|
||||
width: '100%',
|
||||
},
|
||||
chatContainer: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
paddingHorizontal: 20, // Ensures padding around the input and button
|
||||
},
|
||||
input: {
|
||||
width: '100%',
|
||||
minHeight: 120,
|
||||
minHeight: 150, // Minimum height for the TextInput
|
||||
borderColor: 'transparent',
|
||||
borderWidth: 1,
|
||||
borderRadius: 10,
|
||||
padding: 10,
|
||||
marginBottom: 20,
|
||||
marginTop: 160,
|
||||
fontSize: 42,
|
||||
lineHeight: 60,
|
||||
marginBottom: 10,
|
||||
fontSize: 32, // Adjust font size to shrink for smaller devices
|
||||
lineHeight: 40, // Adjust line height for better readability
|
||||
textAlign: 'center',
|
||||
color: '#FFFFFF',
|
||||
fontWeight: 'bold',
|
||||
backgroundColor: 'transparent',
|
||||
//backgroundColor: 'rgba(0, 0, 0, 0.1)', // Subtle background for text input
|
||||
backgroundColor: 'transparent', // Transparent background
|
||||
},
|
||||
button: {
|
||||
backgroundColor: '#730FF8',
|
||||
padding: 15,
|
||||
borderColor: '#730FF8',
|
||||
paddingVertical: 12,
|
||||
paddingHorizontal: 20,
|
||||
borderRadius: 10,
|
||||
},
|
||||
buttonText: {
|
||||
color: 'white',
|
||||
fontSize: 22,
|
||||
fontSize: 18,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
});
|
||||
});
|
@ -62,14 +62,11 @@ export default function RootLayout() {
|
||||
}, [loaded]);
|
||||
|
||||
const handleUserSelected = async (selectedUser: User) => {
|
||||
setUser(selectedUser);
|
||||
console.log('User selected:', selectedUser); // Debug log
|
||||
try {
|
||||
await AsyncStorage.setItem('@user', JSON.stringify(selectedUser));
|
||||
|
||||
// Store the Push Token to your server when the user is selected (optional)
|
||||
if (expoPushToken) {
|
||||
await savePushToken(selectedUser.id, expoPushToken); // Hypothetical function to send token to server
|
||||
}
|
||||
console.log('User data stored in AsyncStorage:', selectedUser); // Debug log
|
||||
setUser(selectedUser);
|
||||
} catch (e) {
|
||||
console.error('Failed to save user or push token', e);
|
||||
}
|
||||
@ -89,35 +86,37 @@ export default function RootLayout() {
|
||||
useEffect(() => {
|
||||
// Register for push notifications and set the push token
|
||||
registerForPushNotificationsAsync().then(async (token) => {
|
||||
if (token) {
|
||||
setExpoPushToken(token);
|
||||
const storedUser = await AsyncStorage.getItem('@user');
|
||||
if (!storedUser) {
|
||||
console.log('No user found in AsyncStorage'); // Debug log
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const storedUser = await AsyncStorage.getItem('@user');
|
||||
console.log('Stored user data:', storedUser); // Debug log
|
||||
|
||||
// Upload push token to backend when successfully received
|
||||
try {
|
||||
const storedUser = await AsyncStorage.getItem('@user');
|
||||
if (storedUser) {
|
||||
const user = JSON.parse(storedUser);
|
||||
if (storedUser) {
|
||||
const user = JSON.parse(storedUser);
|
||||
console.log('Parsed user data:', user); // Debug log
|
||||
|
||||
// Send the push token to your Next.js API, along with the user's ID
|
||||
await fetch(`${BASE_URL}/api/updatePushToken`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
apiKey: API_KEY, // Use the API key stored in the environment
|
||||
userId: user.id, // The logged-in user's ID
|
||||
pushToken: token, // The Expo push token collected
|
||||
}),
|
||||
});
|
||||
|
||||
console.log('Push token successfully sent to backend');
|
||||
} else {
|
||||
console.log('No user found in AsyncStorage');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to send push token to backend', error);
|
||||
// Send the push token to your Next.js API
|
||||
await fetch(`${BASE_URL}/updatePushToken`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
apiKey: API_KEY,
|
||||
userId: user.id,
|
||||
pushToken: token,
|
||||
}),
|
||||
});
|
||||
console.log('Push token update request sent with user ID:', user.id); // Debug log
|
||||
} else {
|
||||
console.log('No user found in AsyncStorage');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to send push token to backend', error);
|
||||
}
|
||||
});
|
||||
|
||||
@ -215,10 +214,3 @@ async function registerForPushNotificationsAsync() {
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
// (Optional) A function to store push tokens in your backend server
|
||||
async function savePushToken(userId: number, expoPushToken: string) {
|
||||
// You would need to implement this function to save the user's push token to your backend.
|
||||
// For example, you could send a POST request to your Next.js API that stores expoPushToken
|
||||
console.log('Saving push token for user:', userId, 'with token:', expoPushToken);
|
||||
}
|
||||
|
Reference in New Issue
Block a user