Reorganize web folder structurally
This commit is contained in:
@@ -0,0 +1,166 @@
|
||||
import { create } from 'zustand';
|
||||
import { UserApi } from '../../users/infrastructure/userApi';
|
||||
import { FriendApi } from '../infrastructure/friendApi';
|
||||
import type { FriendWithId, FriendRequest, UserPresence } from '../../../core/domain/types';
|
||||
import { getSocket } from '../../../core/infrastructure/socket';
|
||||
|
||||
interface FriendState {
|
||||
friends: FriendWithId[];
|
||||
friendRequests: FriendRequest[];
|
||||
isLoading: boolean;
|
||||
searchQuery: string;
|
||||
searchResults: UserPresence[];
|
||||
isSearching: boolean;
|
||||
|
||||
setSearchQuery: (query: string) => void;
|
||||
loadFriends: () => Promise<void>;
|
||||
acceptRequest: (requestId: string) => Promise<void>;
|
||||
declineRequest: (requestId: string) => Promise<void>;
|
||||
removeFriend: (friendshipId: string) => Promise<void>;
|
||||
sendRequest: (friendId: string) => Promise<void>;
|
||||
searchFriends: (query: string, currentUserId?: string) => Promise<void>;
|
||||
clearSearch: () => void;
|
||||
initializeSocketEvents: () => () => void;
|
||||
}
|
||||
|
||||
export const useFriendStore = create<FriendState>((set, get) => ({
|
||||
friends: [],
|
||||
friendRequests: [],
|
||||
isLoading: false,
|
||||
searchQuery: '',
|
||||
searchResults: [],
|
||||
isSearching: false,
|
||||
|
||||
setSearchQuery: (query) => set({ searchQuery: query }),
|
||||
|
||||
loadFriends: async () => {
|
||||
set({ isLoading: true });
|
||||
try {
|
||||
const [friendsList, requests] = await Promise.all([
|
||||
FriendApi.getFriends(),
|
||||
FriendApi.getFriendRequests(),
|
||||
]);
|
||||
set({ friends: friendsList, friendRequests: requests });
|
||||
} catch (e) {
|
||||
console.error('Load friends error:', e);
|
||||
} finally {
|
||||
set({ isLoading: false });
|
||||
}
|
||||
},
|
||||
|
||||
acceptRequest: async (requestId) => {
|
||||
try {
|
||||
await FriendApi.acceptFriendRequest(requestId);
|
||||
const req = get().friendRequests.find(r => r.id === requestId);
|
||||
if (req) {
|
||||
const socket = getSocket();
|
||||
if (socket) socket.emit('friend_accepted', { friendId: req.user.id });
|
||||
}
|
||||
await get().loadFriends();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
},
|
||||
|
||||
declineRequest: async (requestId) => {
|
||||
try {
|
||||
await FriendApi.declineFriendRequest(requestId);
|
||||
set((state) => ({
|
||||
friendRequests: state.friendRequests.filter(r => r.id !== requestId)
|
||||
}));
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
},
|
||||
|
||||
removeFriend: async (friendshipId) => {
|
||||
try {
|
||||
const friend = get().friends.find(f => f.friendshipId === friendshipId);
|
||||
await FriendApi.removeFriend(friendshipId);
|
||||
if (friend) {
|
||||
const socket = getSocket();
|
||||
if (socket) socket.emit('friend_removed', { friendId: friend.id });
|
||||
}
|
||||
set((state) => ({
|
||||
friends: state.friends.filter(f => f.friendshipId !== friendshipId)
|
||||
}));
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
},
|
||||
|
||||
sendRequest: async (friendId) => {
|
||||
try {
|
||||
const result = await FriendApi.sendFriendRequest(friendId);
|
||||
const socket = getSocket();
|
||||
if (socket) socket.emit('friend_request', { friendId });
|
||||
|
||||
if (result.status === 'accepted') {
|
||||
await get().loadFriends();
|
||||
}
|
||||
set((state) => ({
|
||||
searchResults: state.searchResults.filter(u => u.id !== friendId)
|
||||
}));
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
},
|
||||
|
||||
searchFriends: async (query, currentUserId) => {
|
||||
const raw = query.trim();
|
||||
const q = raw.startsWith('@') ? raw.slice(1) : raw;
|
||||
|
||||
if (q.length < 3) {
|
||||
set({ searchResults: [] });
|
||||
return;
|
||||
}
|
||||
|
||||
set({ isSearching: true });
|
||||
try {
|
||||
const results = await UserApi.searchUsers(q);
|
||||
const { friends } = get();
|
||||
const friendIds = new Set(friends.map(f => f.id));
|
||||
|
||||
set({
|
||||
searchResults: results.filter(u => u.id !== currentUserId && !friendIds.has(u.id))
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
} finally {
|
||||
set({ isSearching: false });
|
||||
}
|
||||
},
|
||||
|
||||
clearSearch: () => set({ searchQuery: '', searchResults: [] }),
|
||||
|
||||
initializeSocketEvents: () => {
|
||||
const socket = getSocket();
|
||||
if (!socket) return () => {};
|
||||
|
||||
const onFriendRequestReceived = () => {
|
||||
FriendApi.getFriendRequests()
|
||||
.then(reqs => set({ friendRequests: reqs }))
|
||||
.catch(() => {});
|
||||
};
|
||||
|
||||
const onFriendRequestAccepted = () => {
|
||||
get().loadFriends();
|
||||
};
|
||||
|
||||
const onFriendRemoved = (data: { userId: string }) => {
|
||||
set((state) => ({
|
||||
friends: state.friends.filter(f => f.id !== data.userId)
|
||||
}));
|
||||
};
|
||||
|
||||
socket.on('friend_request_received', onFriendRequestReceived);
|
||||
socket.on('friend_request_accepted', onFriendRequestAccepted);
|
||||
socket.on('friend_removed', onFriendRemoved);
|
||||
|
||||
return () => {
|
||||
socket.off('friend_request_received', onFriendRequestReceived);
|
||||
socket.off('friend_request_accepted', onFriendRequestAccepted);
|
||||
socket.off('friend_removed', onFriendRemoved);
|
||||
};
|
||||
}
|
||||
}));
|
||||
@@ -0,0 +1,39 @@
|
||||
import { httpClient } from '../../../core/infrastructure/httpClient';
|
||||
import type { FriendshipStatus, FriendRequest, FriendWithId } from '../../../core/domain/types';
|
||||
|
||||
export class FriendApi {
|
||||
static async getFriends() {
|
||||
return httpClient.request<FriendWithId[]>('/friends');
|
||||
}
|
||||
|
||||
static async getFriendRequests() {
|
||||
return httpClient.request<FriendRequest[]>('/friends/requests');
|
||||
}
|
||||
|
||||
static async getOutgoingRequests() {
|
||||
return httpClient.request<FriendRequest[]>('/friends/outgoing');
|
||||
}
|
||||
|
||||
static async getFriendshipStatus(userId: string) {
|
||||
return httpClient.request<FriendshipStatus>(`/friends/status/${userId}`);
|
||||
}
|
||||
|
||||
static async sendFriendRequest(friendId: string) {
|
||||
return httpClient.request<{ status: string }>('/friends/request', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ friendId }),
|
||||
});
|
||||
}
|
||||
|
||||
static async acceptFriendRequest(friendshipId: string) {
|
||||
return httpClient.request<{ id: string }>(`/friends/${friendshipId}/accept`, { method: 'POST' });
|
||||
}
|
||||
|
||||
static async declineFriendRequest(friendshipId: string) {
|
||||
return httpClient.request<{ success: boolean }>(`/friends/${friendshipId}/decline`, { method: 'POST' });
|
||||
}
|
||||
|
||||
static async removeFriend(friendshipId: string) {
|
||||
return httpClient.request<{ success: boolean }>(`/friends/${friendshipId}`, { method: 'DELETE' });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user