Wavelength/components/home/RequestRelationship.tsx

149 lines
4.2 KiB
TypeScript

import React, { useState, useCallback, useEffect } from 'react';
import {TextInput, FlatList, TouchableOpacity, StyleSheet, ActivityIndicator } from 'react-native';
import { ThemedView } from '@/components/ThemedView';
import { ThemedText } from '@/components/ThemedText';
import { getUserData } from '@/components/services/securestorage/UserData';
import { Colors } from '@/constants/Colors';
import { useColorScheme } from '@/hooks/useColorScheme';
import debounce from 'lodash.debounce';
type UserData = {
id: number;
appleId: string | null;
appleEmail: string | null;
fullName: string;
pfpURL: string | null;
pushToken: string;
createdAt: Date;
};
type RelationshipData = {
relationship: {
id: number;
title: string;
status: "pending" | "accepted" | "rejected";
relationshipStartDate: Date;
createdAt: Date;
};
partner: UserData;
};
const RequestRelationship: React.FC<{ onRequestSent: (data: RelationshipData) => void }> = ({ onRequestSent }) => {
const scheme = useColorScheme() ?? 'light';
const [searchTerm, setSearchTerm] = useState('');
const [searchResults, setSearchResults] = useState<UserData[]>([]);
const [isLoading, setIsLoading] = useState(false);
const [currentUserId, setCurrentUserId] = useState<number | null>(null);
useEffect(() => {
const fetchCurrentUser = async () => {
const userData = await getUserData();
if (userData) {
setCurrentUserId(userData.id);
}
};
fetchCurrentUser();
}, []);
const searchUsers = useCallback(
debounce(async (term: string) => {
if (term.length < 3) {
setSearchResults([]);
return;
}
setIsLoading(true);
try {
const response = await fetch(`${process.env.EXPO_PUBLIC_API_URL}/users/getUserByName?usersName=${encodeURIComponent(term)}`, {
headers: {
'x-api-key': process.env.EXPO_PUBLIC_API_KEY ?? '',
},
});
if (!response.ok) throw new Error('Search failed');
const data = await response.json();
setSearchResults(data);
} catch (error) {
console.error('Error searching users:', error);
} finally {
setIsLoading(false);
}
}, 300),
[]
);
const handleSearch = (text: string) => {
setSearchTerm(text);
searchUsers(text);
};
const sendRequest = async (targetUserId: number) => {
if (!currentUserId) return;
try {
const response = await fetch(`${process.env.EXPO_PUBLIC_API_URL}/relationships/createRequest`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': process.env.EXPO_PUBLIC_API_KEY ?? '',
},
body: JSON.stringify({ userId: currentUserId, targetUserId }),
});
if (!response.ok) throw new Error('Request failed');
const data: RelationshipData = await response.json();
onRequestSent(data);
} catch (error) {
console.error('Error sending relationship request:', error);
}
};
const renderUserItem = ({ item }: { item: UserData }) => (
<TouchableOpacity style={styles.userItem} onPress={() => sendRequest(item.id)}>
<ThemedText>{item.fullName}</ThemedText>
<ThemedText>{item.appleEmail}</ThemedText>
</TouchableOpacity>
);
return (
<ThemedView style={styles.container}>
<TextInput
style={[
styles.searchInput,
{color: Colors[scheme].text}
]}
placeholder="Search users..."
value={searchTerm}
onChangeText={handleSearch}
/>
{isLoading ? (
<ActivityIndicator />
) : (
<FlatList
data={searchResults}
renderItem={renderUserItem}
keyExtractor={(item) => item.id.toString()}
ListEmptyComponent={<ThemedText>No users found</ThemedText>}
/>
)}
</ThemedView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
},
searchInput: {
height: 40,
borderColor: 'gray',
borderWidth: 1,
marginBottom: 20,
paddingHorizontal: 10,
},
userItem: {
padding: 10,
borderBottomWidth: 1,
borderBottomColor: 'gray',
},
});
export default RequestRelationship;