diff --git a/daily-thought-frontend/src/components/form/FriendRequests.tsx b/daily-thought-frontend/src/components/form/FriendRequests.tsx index 88da9f8b0494a97094aac3dab7b86e163706342c..09bf28d7ef5e0b0e93318208ebb82ffdeaacaf80 100644 --- a/daily-thought-frontend/src/components/form/FriendRequests.tsx +++ b/daily-thought-frontend/src/components/form/FriendRequests.tsx @@ -1,65 +1,63 @@ -import { useRequests } from "@/hooks/useRequests"; -import { CheckIcon, XCircleIcon } from "@heroicons/react/24/outline"; -import { FC, PropsWithChildren, useEffect, useState } from "react" -import UserAvatar from "../user/UserAvatar"; +import { useRequests } from '@/hooks/useRequests'; +import { CheckIcon, XCircleIcon } from '@heroicons/react/24/outline'; +import { FC, PropsWithChildren, useEffect, useState } from 'react'; +import UserAvatar from '../user/UserAvatar'; - -const FriendRequestMenu:FC<PropsWithChildren> = ({ -}) => { - const [userRequestList, setUserRequestList] = useState<Map<string, any>>(new Map()) - const {requests, rehydrateRequests, setRehydrateRequests} = useRequests(); +const FriendRequestMenu: FC<PropsWithChildren> = ({}) => { + const [userRequestList, setUserRequestList] = useState<Map<string, any>>(new Map()); + const { requests, rehydrateRequests, setRehydrateRequests } = useRequests(); const fetchUserDetails = async () => { - const endpoint = `${process.env.NEXT_PUBLIC_USER_SERVICE_URL}api/userlist` - if(requests){ - const JsonData = JSON.stringify({userIdList: Array.from(requests?.keys())}) + const endpoint = `${process.env.NEXT_PUBLIC_USER_SERVICE_URL}api/userlist`; + if (requests) { + const JsonData = JSON.stringify({ userIdList: Array.from(requests?.keys()) }); const options = { method: 'POST', - headers: {'Content-Type': 'application/json',}, - body: JsonData, - } - - const response = await fetch(endpoint, options) - const data = await response.json() + headers: { 'Content-Type': 'application/json' }, + body: JsonData + }; - console.log(data) - setUserRequestList(new Map(data.userList)) + const response = await fetch(endpoint, options); + const data = await response.json(); + setUserRequestList(new Map(data.userList)); } - } + }; const handleRequest = async (userId: string, accept: boolean) => { - const endpoint = `${process.env.NEXT_PUBLIC_FRIEND_SERVICE_URL}friends/requests/${accept ? "accept" : "reject"}` - const JsonData = JSON.stringify({request_id: requests?.get(userId)._id}) + const endpoint = `${process.env.NEXT_PUBLIC_FRIEND_SERVICE_URL}friends/requests/${ + accept ? 'accept' : 'reject' + }`; + const JsonData = JSON.stringify({ request_id: requests?.get(userId)._id }); const options = { method: 'PUT', - headers: {'Content-Type': 'application/json','Authorization': `Bearer ${sessionStorage.getItem("token")}`}, - body: JsonData, - } + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${sessionStorage.getItem('token')}` + }, + body: JsonData + }; - const response = await fetch(endpoint, options) - if(!response.ok){ - const data = await response.json() - console.log(data) + const response = await fetch(endpoint, options); + if (!response.ok) { + const data = await response.json(); } else { - setRehydrateRequests(true) + setRehydrateRequests(true); } - } + }; useEffect(() => { - fetchUserDetails() - },[rehydrateRequests]) + fetchUserDetails(); + }, [rehydrateRequests]); return ( <div className="p-1"> - <div className="text-xs text-gray-400 border-b w-full pb-1"> - Friend requests - </div> - + <div className="text-xs text-gray-400 border-b w-full pb-1">Friend requests</div> + <div> {Array.from(userRequestList?.values()).map((req, index) => { - const {profile, username, firstName, lastName} = req[1] + const { profile, username, firstName, lastName } = req[1]; return ( <div key={req[0]}> <div className="flex justify-between items-center"> @@ -82,14 +80,18 @@ const FriendRequestMenu:FC<PropsWithChildren> = ({ </div> </div> </div> - ) + ); })} </div> - {userRequestList.size === 0 && <div className="text-xs text-gray-400 flex justify-center mt-2"> No pending friend requests</div>} - + {userRequestList.size === 0 && ( + <div className="text-xs text-gray-400 flex justify-center mt-2"> + {' '} + No pending friend requests + </div> + )} </div> - ) -} + ); +}; -export default FriendRequestMenu \ No newline at end of file +export default FriendRequestMenu; diff --git a/daily-thought-frontend/src/components/form/UserSearch.tsx b/daily-thought-frontend/src/components/form/UserSearch.tsx index 0f6b44cadc5b21038a4899b7694ca3539908b72c..9eb8a5cbab442def17d9d2174ab99a4c73faae99 100644 --- a/daily-thought-frontend/src/components/form/UserSearch.tsx +++ b/daily-thought-frontend/src/components/form/UserSearch.tsx @@ -1,139 +1,152 @@ -import useDebounce from "@/hooks/useDebounce"; -import { useFriends } from "@/hooks/useFriends"; -import { useSentRequests } from "@/hooks/useSentRequests"; -import { useUser } from "@/hooks/useUser"; -import { UserPlusIcon } from "@heroicons/react/24/outline"; -import { FC, PropsWithChildren, useEffect, useState } from "react"; -import UserAvatar from "../user/UserAvatar"; -import BasicField from "./BasicField"; +import useDebounce from '@/hooks/useDebounce'; +import { useFriends } from '@/hooks/useFriends'; +import { useSentRequests } from '@/hooks/useSentRequests'; +import { useUser } from '@/hooks/useUser'; +import { UserPlusIcon } from '@heroicons/react/24/outline'; +import { FC, PropsWithChildren, useEffect, useState } from 'react'; +import UserAvatar from '../user/UserAvatar'; +import BasicField from './BasicField'; type UserSearchProps = { limit?: number; -} +}; -const UserSearch:FC<PropsWithChildren<UserSearchProps>> = ({ - limit = 6 -}) => { - const [searchQuery, setSearchQuery] = useState<string>(""); - const debouncedSearchQuery = useDebounce<string>(searchQuery, 500) +const UserSearch: FC<PropsWithChildren<UserSearchProps>> = ({ limit = 6 }) => { + const [searchQuery, setSearchQuery] = useState<string>(''); + const debouncedSearchQuery = useDebounce<string>(searchQuery, 500); const [searchResults, setSearchResults] = useState<Map<string, any>>(new Map([])); const [loading, setLoading] = useState<boolean>(false); - const {sentRequests, rehydrateSentRequests, setRehydrateSentRequests} = useSentRequests(); - const {friends, rehydrateFriends, setRehydrateFriends} = useFriends(); - const [sentRequestsIds, setSentRequestIds] = useState<Set<string>>(new Set([])) - const {user, setRehydrateUser} = useUser() - + const { sentRequests, rehydrateSentRequests, setRehydrateSentRequests } = useSentRequests(); + const { friends, rehydrateFriends, setRehydrateFriends } = useFriends(); + const [sentRequestsIds, setSentRequestIds] = useState<Set<string>>(new Set([])); + const { user, setRehydrateUser } = useUser(); useEffect(() => { - if(sentRequests !== undefined){ - setSentRequestIds(new Set(Array.from(sentRequests?.keys()))) + if (sentRequests !== undefined) { + setSentRequestIds(new Set(Array.from(sentRequests?.keys()))); } - }, [rehydrateSentRequests]) + }, [rehydrateSentRequests]); useEffect(() => { - setLoading(true) - if(searchQuery.length === 0){ - setSearchResults(new Map([])) + setLoading(true); + if (searchQuery.length === 0) { + setSearchResults(new Map([])); } - }, [searchQuery, setSearchResults]) + }, [searchQuery, setSearchResults]); useEffect(() => { - if(debouncedSearchQuery.length > 0){ + if (debouncedSearchQuery.length > 0) { const endpoint = `${process.env.NEXT_PUBLIC_USER_SERVICE_URL}api/search?searchQuery=${debouncedSearchQuery}`; fetch(endpoint).then(async (result) => { const data = await result.json(); - setLoading(false) - const newResults = new Map<string, any>(data.result) - if(user) - newResults.delete(user?.id) - setSearchResults(newResults) + setLoading(false); + const newResults = new Map<string, any>(data.result); + if (user) newResults.delete(user?.id); + setSearchResults(newResults); }); } - }, [debouncedSearchQuery]) + }, [debouncedSearchQuery]); const sendRequest = async (receiverId: string) => { - const endpoint = `${process.env.NEXT_PUBLIC_FRIEND_SERVICE_URL}friends/requests` - const JSONdata = JSON.stringify({receiver_id: receiverId}) - const headers = {'Authorization': `Bearer ${sessionStorage.getItem("token")}`, 'Content-Type': 'application/json'} - const response = await fetch(endpoint, {method: "POST",headers, body: JSONdata}) - - if(!response.ok){ - const data = await response.json() - console.log(data.error) + const endpoint = `${process.env.NEXT_PUBLIC_FRIEND_SERVICE_URL}friends/requests`; + const JSONdata = JSON.stringify({ receiver_id: receiverId }); + const headers = { + Authorization: `Bearer ${sessionStorage.getItem('token')}`, + 'Content-Type': 'application/json' + }; + const response = await fetch(endpoint, { method: 'POST', headers, body: JSONdata }); + + if (!response.ok) { + const data = await response.json(); } else { - setRehydrateSentRequests(true) + setRehydrateSentRequests(true); } - } + }; return ( <div> - <BasicField name="search" placeholder="Search users" onChange={setSearchQuery} autocomplete={false}/> - <div className="border-t pt-2 flex item-center flex-col"> - {!searchQuery && - <div className='flex items-center justify-center mb-2'> - <p className='text-xs text-gray-500'> - Enter a search query to find friends - </p> + <BasicField + name="search" + placeholder="Search users" + onChange={setSearchQuery} + autocomplete={false} + /> + <div className="border-t pt-2 flex item-center flex-col"> + {!searchQuery && ( + <div className="flex items-center justify-center mb-2"> + <p className="text-xs text-gray-500">Enter a search query to find friends</p> </div> - } + )} <div className="border-b"> - {searchQuery && !loading && Array.from(searchResults.values()).map((result, index) => { - if(index < limit && !friends?.has(result._id) && result._id !== user?.id){ - return ( - <div className="flex justify-between items-center hover:bg-gray-100 rounded-md mb-2" key={index}> - <UserAvatar key={result._id} username={result.username} firstName={result.firstName} lastName={result.lastName} /> - - {!sentRequestsIds.has(result._id) && - <button - type="button" - className="ml-auto mr-1 flex-shrink-1 rounded-full text-c-pink p-1 hover:text-gray-200 focus:outline-none " - onClick={() => sendRequest(result._id)} + {searchQuery && + !loading && + Array.from(searchResults.values()).map((result, index) => { + if (index < limit && !friends?.has(result._id) && result._id !== user?.id) { + return ( + <div + className="flex justify-between items-center hover:bg-gray-100 rounded-md mb-2" + key={index} > - <UserPlusIcon className="h-6 w-6" aria-hidden="true" /> - </button> - } - - {sentRequestsIds.has(result._id) && - <p className="text-xs text-gray-400 mr-3">Pending</p> - } - - </div> - ) + <UserAvatar + key={result._id} + username={result.username} + firstName={result.firstName} + lastName={result.lastName} + /> + + {!sentRequestsIds.has(result._id) && ( + <button + type="button" + className="ml-auto mr-1 flex-shrink-1 rounded-full text-c-pink p-1 hover:text-gray-200 focus:outline-none " + onClick={() => sendRequest(result._id)} + > + <UserPlusIcon className="h-6 w-6" aria-hidden="true" /> + </button> + )} + + {sentRequestsIds.has(result._id) && ( + <p className="text-xs text-gray-400 mr-3">Pending</p> + )} + </div> + ); } - })} + })} - {searchQuery && loading && + {searchQuery && loading && ( <div className="flex justify-center mb-2"> <div className="h-6 w-6 animate-spin text-gray-300 rounded-full border-4 border-solid border-current border-r-transparent align-[-0.125em] motion-reduce:animate-[spin_1.5s_linear_infinite]" - role="status"> - </div> - </div>} + role="status" + ></div> + </div> + )} - {searchQuery && !loading && searchResults.size === 0 && + {searchQuery && !loading && searchResults.size === 0 && ( <div> - <p className='text-xs text-gray-500 flex justify-center mb-2'> - No results found - </p> + <p className="text-xs text-gray-500 flex justify-center mb-2">No results found</p> </div> - } + )} </div> - - <div className="w-full pt-2 text-xs mx-auto flex text-c-pink justify-center"> - {friends && friends.size > 0? "Friends" : "No friends added"} + {friends && friends.size > 0 ? 'Friends' : 'No friends added'} </div> - {friends && Array.from(friends.values()).map((result, index) => { - return ( - <div className="flex justify-between hover:bg-gray-100 rounded-md" key={index}> - <UserAvatar key={index} username={result[1].username} firstName={result[1].firstName} lastName={result[1].lastName} /> - </div> - ) + {friends && + Array.from(friends.values()).map((result, index) => { + return ( + <div className="flex justify-between hover:bg-gray-100 rounded-md" key={index}> + <UserAvatar + key={index} + username={result[1].username} + firstName={result[1].firstName} + lastName={result[1].lastName} + /> + </div> + ); })} - </div> </div> - ) -} + </div> + ); +}; -export default UserSearch; \ No newline at end of file +export default UserSearch;