| import { useState, useEffect, useCallback } from 'react'; |
| import { eq, desc, and } from 'drizzle-orm'; |
| import { useDatabase } from './useDatabase'; |
| import { friends } from '../db/schema'; |
|
|
| |
|
|
| type FriendStatus = 'pending' | 'accepted' | 'blocked'; |
|
|
| interface FriendData { |
| id: string; |
| userId: string; |
| friendId: string; |
| friendFullName: string; |
| friendAvatar: string | null; |
| friendPhone: string | null; |
| status: FriendStatus; |
| createdAt: string | null; |
| } |
|
|
| interface NewFriend { |
| id: string; |
| userId: string; |
| friendId: string; |
| friendFullName: string; |
| friendAvatar?: string; |
| friendPhone?: string; |
| } |
|
|
| interface UseFriendsReturn { |
| friends: FriendData[]; |
| pendingRequests: FriendData[]; |
| loading: boolean; |
| acceptFriend: (friendId: string) => Promise<void>; |
| declineFriend: (friendId: string) => Promise<void>; |
| addFriend: (data: NewFriend) => Promise<FriendData | null>; |
| blockFriend: (friendId: string) => Promise<void>; |
| refresh: () => Promise<void>; |
| } |
|
|
| |
|
|
| export function useFriends(userId?: string): UseFriendsReturn { |
| const { db } = useDatabase(); |
| const [friendsList, setFriendsList] = useState<FriendData[]>([]); |
| const [loading, setLoading] = useState(true); |
|
|
| |
|
|
| const loadFriends = useCallback(async () => { |
| try { |
| setLoading(true); |
|
|
| let results; |
|
|
| if (userId) { |
| results = await db |
| .select() |
| .from(friends) |
| .where(eq(friends.userId, userId)) |
| .orderBy(desc(friends.createdAt)) |
| .all(); |
| } else { |
| results = await db |
| .select() |
| .from(friends) |
| .orderBy(desc(friends.createdAt)) |
| .all(); |
| } |
|
|
| setFriendsList(results as FriendData[]); |
| } catch (error) { |
| console.error('[useFriends] Failed to load friends:', error); |
| setFriendsList([]); |
| } finally { |
| setLoading(false); |
| } |
| }, [db, userId]); |
|
|
| useEffect(() => { |
| loadFriends(); |
| }, [loadFriends]); |
|
|
| |
|
|
| const pendingRequests = friendsList.filter( |
| (f) => f.status === 'pending', |
| ); |
|
|
| |
|
|
| const acceptFriend = useCallback( |
| async (friendId: string) => { |
| try { |
| await db |
| .update(friends) |
| .set({ status: 'accepted' }) |
| .where(and(eq(friends.friendId, friendId), eq(friends.status, 'pending'))) |
| .run(); |
|
|
| await loadFriends(); |
| } catch (error) { |
| console.error('[useFriends] Failed to accept friend:', error); |
| } |
| }, |
| [db, loadFriends], |
| ); |
|
|
| |
|
|
| const declineFriend = useCallback( |
| async (friendId: string) => { |
| try { |
| |
| await db |
| .delete(friends) |
| .where(and(eq(friends.friendId, friendId), eq(friends.status, 'pending'))) |
| .run(); |
|
|
| await loadFriends(); |
| } catch (error) { |
| console.error('[useFriends] Failed to decline friend:', error); |
| } |
| }, |
| [db, loadFriends], |
| ); |
|
|
| |
|
|
| const addFriend = useCallback( |
| async (data: NewFriend): Promise<FriendData | null> => { |
| try { |
| await db.insert(friends).values({ |
| id: data.id, |
| userId: data.userId, |
| friendId: data.friendId, |
| friendFullName: data.friendFullName, |
| friendAvatar: data.friendAvatar ?? null, |
| friendPhone: data.friendPhone ?? null, |
| status: 'pending', |
| }).run(); |
|
|
| await loadFriends(); |
|
|
| return friendsList.find((f) => f.friendId === data.friendId) ?? null; |
| } catch (error) { |
| console.error('[useFriends] Failed to add friend:', error); |
| return null; |
| } |
| }, |
| [db, loadFriends, friendsList], |
| ); |
|
|
| |
|
|
| const blockFriend = useCallback( |
| async (friendId: string) => { |
| try { |
| await db |
| .update(friends) |
| .set({ status: 'blocked' }) |
| .where(eq(friends.friendId, friendId)) |
| .run(); |
|
|
| await loadFriends(); |
| } catch (error) { |
| console.error('[useFriends] Failed to block friend:', error); |
| } |
| }, |
| [db, loadFriends], |
| ); |
|
|
| return { |
| friends: friendsList, |
| pendingRequests, |
| loading, |
| acceptFriend, |
| declineFriend, |
| addFriend, |
| blockFriend, |
| refresh: loadFriends, |
| }; |
| } |
|
|