From be1b1de451a312b588aea358ce0443159a6beb08 Mon Sep 17 00:00:00 2001 From: olukukoyi Date: Fri, 2 May 2025 23:59:48 -0400 Subject: [PATCH 1/7] need to fix ui --- .../(private)/friends/_components/Friends.tsx | 153 ++++++++++-------- src/app/(private)/friends/actions.ts | 27 ++++ .../hangouts/_components/AddFriendModal.tsx | 115 +++++++++++++ 3 files changed, 227 insertions(+), 68 deletions(-) create mode 100644 src/app/(private)/friends/actions.ts create mode 100644 src/app/(private)/hangouts/_components/AddFriendModal.tsx diff --git a/src/app/(private)/friends/_components/Friends.tsx b/src/app/(private)/friends/_components/Friends.tsx index 9043e46..8a725e8 100644 --- a/src/app/(private)/friends/_components/Friends.tsx +++ b/src/app/(private)/friends/_components/Friends.tsx @@ -8,15 +8,16 @@ import { getApiBase } from "@/utils/etc/apiBase"; import { useUser } from "@/utils/context/userContext"; import { toast } from "react-hot-toast"; import Loading from "@/app/components/loading"; +import AddFriendModal from "../../hangouts/_components/AddFriendModal"; type FetchFriendsResponse = { status: string; friends: Friend[]; }; -type Friend = { +export type Friend = { id: string; - friend_uuid: string; + friend_auth_id: string; friend_email: string; friend_username: string; status: string; @@ -38,6 +39,7 @@ export default function Friends() { const [suggestion, setSuggestion] = useState(null); const [loading, setLoading] = useState(false); const user = useUser(); + const [isModalOpen, setIsModalOpen] = useState(false); async function fetchFriends() { setLoading(true); @@ -145,37 +147,73 @@ export default function Friends() { }, [query]); return ( -
-
Friends
- {loading ? ( - - ) : ( - <> -
- -
- {suggestion ? ( - suggestion?.map((friend) => { - if (friend.status === "pending") { - return ( - { - acceptFriendRequest(friend.id); - }} - onDeny={() => { - declineFriendRequest(friend.id, false); - }} - /> - ); - } else - return ( + <> + friend.friend_auth_id)} + isOpen={isModalOpen} + onClose={() => { + setIsModalOpen(false); + }} + /> + +
+
Friends
+ {loading ? ( + + ) : ( + <> +
+ +
+ {suggestion ? ( + suggestion?.map((friend) => { + if (friend.status === "pending") { + return ( + { + acceptFriendRequest(friend.id); + }} + onDeny={() => { + declineFriendRequest(friend.id, false); + }} + /> + ); + } else + return ( +
+ { + declineFriendRequest(friend.id, true); + }} + /> +
+ ); + }) + ) : ( +
+ {pendingFriends.map((friend) => (
+ { + acceptFriendRequest(friend.id); + }} + onDeny={() => { + declineFriendRequest(friend.id, false); + }} + /> +
+ ))} + {friends.map((friend) => ( +
{ @@ -183,42 +221,21 @@ export default function Friends() { }} />
- ); - }) - ) : ( -
- {pendingFriends.map((friend) => ( -
- { - acceptFriendRequest(friend.id); - }} - onDeny={() => { - declineFriendRequest(friend.id, false); - }} - /> -
- ))} - {friends.map((friend) => ( -
- { - declineFriendRequest(friend.id, true); - }} - /> -
- ))} + ))} +
+ )} + +
{ + setIsModalOpen(true); + }} + > +
- )} - -
- -
- - )} -
+ + )} +
+ ); } diff --git a/src/app/(private)/friends/actions.ts b/src/app/(private)/friends/actions.ts new file mode 100644 index 0000000..42420ac --- /dev/null +++ b/src/app/(private)/friends/actions.ts @@ -0,0 +1,27 @@ +"use server"; +import { createClient } from "@/utils/supabase/server"; + +export type Suggestions = { + auth_id: string; + username: string; +}[]; + +export async function findPeople(username: string) { + const supabase = await createClient(); + + const { + data: { user }, + } = await supabase.auth.getUser(); + + if (!user?.id) { + console.error("User not authenticated"); + return { status: 401, error: "User not authenticated" }; + } + + const { data, error } = await supabase + .from("users") + .select("auth_id, username") + .ilike("username", `%${username}%`); + + return data as Suggestions; +} diff --git a/src/app/(private)/hangouts/_components/AddFriendModal.tsx b/src/app/(private)/hangouts/_components/AddFriendModal.tsx new file mode 100644 index 0000000..5f1b152 --- /dev/null +++ b/src/app/(private)/hangouts/_components/AddFriendModal.tsx @@ -0,0 +1,115 @@ +"use client"; + +import React, { ChangeEvent, useRef, useState } from "react"; +import { Participant } from "./Hangouts"; +import { XIcon } from "@/app/components/Icons"; +import { getApiBase } from "@/utils/etc/apiBase"; +import toast from "react-hot-toast"; +import { useUser } from "@/utils/context/userContext"; +import SearchBar from "../../friends/_components/SearchBar"; +import { findPeople, Suggestions } from "../../friends/actions"; +import Friends, { Friend } from "../../friends/_components/Friends"; + +type AddFriendModalProps = { + isOpen: boolean; + friends: string[]; + onClose(): void; + // onClose: () => void; + // hangoutId: number; +}; + +const TIMER: number = 150; // ms + +const AddFriendModal = ({ isOpen, friends, onClose }: AddFriendModalProps) => { + if (!isOpen) return null; + const [people, setPeople] = useState([]); + const timeoutRef = useRef(null); + const user = useUser(); + + const handleChange = (e: ChangeEvent) => { + // debounce + if (timeoutRef.current) { + clearTimeout(timeoutRef.current); + } + timeoutRef.current = setTimeout(async () => { + // make api call + const username = e.target.value; + console.log(username); + if (username.trim() === "" || !username) { + setPeople([]); + return; + } + const suggestions = await findPeople(e.target.value); + if (Array.isArray(suggestions)) { + setPeople( + suggestions.filter((person) => !friends.includes(person.auth_id)) + ); + } + }, TIMER); + }; + + const sendFriendRequest = async (idToAdd: string) => { + const base = getApiBase(); + const response = await fetch(`${base}/send-friend-request`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + user_A: user?.auth_id, + user_B: idToAdd, + }), + }); + if (!response.ok) { + console.error("Failed to add friend", response.statusText); + toast.error("Error while sending friend request."); + } else { + toast.success("Successfully sent friend request."); + } + onClose(); + }; + + return ( + <> + {isOpen && ( +
+ hello world +
+
+ +
+
+

+ Search for a friend +

+
+ +
+ {people.map((person) => { + return ( +
+ {person.username} -{" "} + {" "} +
+ ); + })} +
+
+
+ )} + + ); +}; + +export default AddFriendModal; From 5eea4d94fb8eaf655e3d546fd9a52cd804ccbdf0 Mon Sep 17 00:00:00 2001 From: olukukoyi Date: Sun, 4 May 2025 20:58:50 -0400 Subject: [PATCH 2/7] done --- .../(private)/friends/_components/Friends.tsx | 6 +- .../hangouts/_components/AddFriendModal.tsx | 99 +++++++++++++------ 2 files changed, 74 insertions(+), 31 deletions(-) diff --git a/src/app/(private)/friends/_components/Friends.tsx b/src/app/(private)/friends/_components/Friends.tsx index 8a725e8..8d9cef1 100644 --- a/src/app/(private)/friends/_components/Friends.tsx +++ b/src/app/(private)/friends/_components/Friends.tsx @@ -150,8 +150,12 @@ export default function Friends() { <> friend.friend_auth_id)} + pendingFriends={pendingFriends.map((friend) => friend.friend_auth_id)} isOpen={isModalOpen} - onClose={() => { + onClose={(rerender: boolean) => { + if (rerender) { + fetchFriends(); + } setIsModalOpen(false); }} /> diff --git a/src/app/(private)/hangouts/_components/AddFriendModal.tsx b/src/app/(private)/hangouts/_components/AddFriendModal.tsx index 5f1b152..be20b7a 100644 --- a/src/app/(private)/hangouts/_components/AddFriendModal.tsx +++ b/src/app/(private)/hangouts/_components/AddFriendModal.tsx @@ -1,28 +1,31 @@ "use client"; import React, { ChangeEvent, useRef, useState } from "react"; -import { Participant } from "./Hangouts"; import { XIcon } from "@/app/components/Icons"; import { getApiBase } from "@/utils/etc/apiBase"; import toast from "react-hot-toast"; import { useUser } from "@/utils/context/userContext"; import SearchBar from "../../friends/_components/SearchBar"; import { findPeople, Suggestions } from "../../friends/actions"; -import Friends, { Friend } from "../../friends/_components/Friends"; type AddFriendModalProps = { isOpen: boolean; friends: string[]; - onClose(): void; - // onClose: () => void; - // hangoutId: number; + pendingFriends: string[]; + onClose(rerender: boolean): void; // closes modal }; const TIMER: number = 150; // ms -const AddFriendModal = ({ isOpen, friends, onClose }: AddFriendModalProps) => { +const AddFriendModal = ({ + isOpen, + friends, + onClose, + pendingFriends, +}: AddFriendModalProps) => { if (!isOpen) return null; const [people, setPeople] = useState([]); + const [requestSent, setRequestSent] = useState([]); const timeoutRef = useRef(null); const user = useUser(); @@ -32,17 +35,24 @@ const AddFriendModal = ({ isOpen, friends, onClose }: AddFriendModalProps) => { clearTimeout(timeoutRef.current); } timeoutRef.current = setTimeout(async () => { - // make api call const username = e.target.value; - console.log(username); if (username.trim() === "" || !username) { setPeople([]); return; } const suggestions = await findPeople(e.target.value); + console.log(suggestions); + if (Array.isArray(suggestions)) { setPeople( - suggestions.filter((person) => !friends.includes(person.auth_id)) + suggestions.filter((person) => { + if (!user) { + return; + } + return ( + !friends.includes(user.auth_id) && person.auth_id != user?.auth_id + ); + }) ); } }, TIMER); @@ -65,42 +75,71 @@ const AddFriendModal = ({ isOpen, friends, onClose }: AddFriendModalProps) => { toast.error("Error while sending friend request."); } else { toast.success("Successfully sent friend request."); + setRequestSent((prev) => [...prev, idToAdd]); } - onClose(); }; return ( <> {isOpen && (
- hello world -
-
+
+
{ + onClose(requestSent.length > 0); + }} + >
-
+

Search for a friend

- -
+
+ +
+
{people.map((person) => { return ( -
- {person.username} -{" "} - {" "} +
+

{person.username}

+ {requestSent.includes(person.auth_id) || + pendingFriends.includes(person.auth_id) ? ( +
+ + + +
+ ) : ( + + )}
); })} From cf59b5a7a2eb36af2fb0031041b5caa7dc833e28 Mon Sep 17 00:00:00 2001 From: olukukoyi Date: Sun, 4 May 2025 21:05:56 -0400 Subject: [PATCH 3/7] removed console log --- src/app/(private)/hangouts/_components/AddFriendModal.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/app/(private)/hangouts/_components/AddFriendModal.tsx b/src/app/(private)/hangouts/_components/AddFriendModal.tsx index be20b7a..609e75f 100644 --- a/src/app/(private)/hangouts/_components/AddFriendModal.tsx +++ b/src/app/(private)/hangouts/_components/AddFriendModal.tsx @@ -41,7 +41,6 @@ const AddFriendModal = ({ return; } const suggestions = await findPeople(e.target.value); - console.log(suggestions); if (Array.isArray(suggestions)) { setPeople( From f201ec3bd1df7ea88ad1c1b2c4b8b41297a4649d Mon Sep 17 00:00:00 2001 From: olukukoyi Date: Sun, 4 May 2025 21:25:52 -0400 Subject: [PATCH 4/7] replaced svg with react component --- .../hangouts/_components/AddFriendModal.tsx | 17 ++--------------- src/app/components/Icons.tsx | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/app/(private)/hangouts/_components/AddFriendModal.tsx b/src/app/(private)/hangouts/_components/AddFriendModal.tsx index 609e75f..18f8444 100644 --- a/src/app/(private)/hangouts/_components/AddFriendModal.tsx +++ b/src/app/(private)/hangouts/_components/AddFriendModal.tsx @@ -1,7 +1,7 @@ "use client"; import React, { ChangeEvent, useRef, useState } from "react"; -import { XIcon } from "@/app/components/Icons"; +import { CheckIcon, XIcon } from "@/app/components/Icons"; import { getApiBase } from "@/utils/etc/apiBase"; import toast from "react-hot-toast"; import { useUser } from "@/utils/context/userContext"; @@ -114,20 +114,7 @@ const AddFriendModal = ({ {requestSent.includes(person.auth_id) || pendingFriends.includes(person.auth_id) ? (
- - - +
) : ( diff --git a/src/app/(private)/friends/_components/Friends.tsx b/src/app/(private)/friends/_components/Friends.tsx index 8d9cef1..dd05a43 100644 --- a/src/app/(private)/friends/_components/Friends.tsx +++ b/src/app/(private)/friends/_components/Friends.tsx @@ -38,11 +38,15 @@ export default function Friends() { const [query, setQuery] = useState(""); const [suggestion, setSuggestion] = useState(null); const [loading, setLoading] = useState(false); + const [hasTrigged, setHasTrigged] = useState(false); const user = useUser(); const [isModalOpen, setIsModalOpen] = useState(false); async function fetchFriends() { - setLoading(true); + if (!hasTrigged) { + setLoading(true); + setHasTrigged(true); + } const base = getApiBase(); const response = await fetch(`${base}/fetch-friends`, { method: "POST", @@ -93,7 +97,11 @@ export default function Friends() { } } - async function declineFriendRequest(friendshipId: string, removing: boolean) { + async function declineFriendRequest( + friendshipId: string, + removing: boolean, + canceling?: boolean + ) { const base = getApiBase(); const response = await fetch(`${base}/remove-friend`, { method: "POST", @@ -106,12 +114,17 @@ export default function Friends() { }); if (response.ok) { - const toastSuccessMessage = removing + let toastSuccessMessage = removing ? "Succesfully removed friend" : "Succesfully declined friend request"; - const toastErrorMessage = removing + let toastErrorMessage = removing ? "Unable to removed friend" : "Unable to decline friend request"; + if (canceling) { + toastSuccessMessage = "Succesfully canceled pending friend request."; + toastErrorMessage = "Unable to cancel pending friend-request"; + } + const data = (await response.json()) as APIResponse; if (data.status !== 200) { toast.error(toastErrorMessage, { @@ -186,6 +199,9 @@ export default function Friends() { onDeny={() => { declineFriendRequest(friend.id, false); }} + onCancel={() => { + declineFriendRequest(friend.id, false, true); + }} /> ); } else @@ -202,6 +218,14 @@ export default function Friends() { }) ) : (
+
{ + setIsModalOpen(true); + }} + > + +
{pendingFriends.map((friend) => (
{ declineFriendRequest(friend.id, false); }} + onCancel={() => { + declineFriendRequest(friend.id, false, true); + }} />
))} @@ -228,15 +255,6 @@ export default function Friends() { ))}
)} - -
{ - setIsModalOpen(true); - }} - > - -
)}
From 2b820511a48918720394387607526eaded4bcdcb Mon Sep 17 00:00:00 2001 From: olukukoyi Date: Mon, 5 May 2025 15:13:14 -0400 Subject: [PATCH 6/7] some ui changes --- .../friends/_components/AddFriendButton.tsx | 22 ++++----- .../(private)/friends/_components/Friends.tsx | 46 ++++++++++--------- 2 files changed, 35 insertions(+), 33 deletions(-) diff --git a/src/app/(private)/friends/_components/AddFriendButton.tsx b/src/app/(private)/friends/_components/AddFriendButton.tsx index 83e3d08..7fcd13b 100644 --- a/src/app/(private)/friends/_components/AddFriendButton.tsx +++ b/src/app/(private)/friends/_components/AddFriendButton.tsx @@ -1,14 +1,14 @@ "use client"; -import React from 'react'; -import { UserRoundPlus } from 'lucide-react'; +import React from "react"; +import { UserRoundPlus } from "lucide-react"; export default function AddFriendButton() { - return ( - - ); -} \ No newline at end of file + return ( + + ); +} diff --git a/src/app/(private)/friends/_components/Friends.tsx b/src/app/(private)/friends/_components/Friends.tsx index dd05a43..8b938e8 100644 --- a/src/app/(private)/friends/_components/Friends.tsx +++ b/src/app/(private)/friends/_components/Friends.tsx @@ -179,30 +179,40 @@ export default function Friends() { ) : ( <> -
+
+
{ + setIsModalOpen(true); + }} + > + +
{suggestion ? ( suggestion?.map((friend) => { if (friend.status === "pending") { return ( - { - acceptFriendRequest(friend.id); - }} - onDeny={() => { - declineFriendRequest(friend.id, false); - }} - onCancel={() => { - declineFriendRequest(friend.id, false, true); - }} - /> +
+ { + acceptFriendRequest(friend.id); + }} + onDeny={() => { + declineFriendRequest(friend.id, false); + }} + onCancel={() => { + declineFriendRequest(friend.id, false, true); + }} + /> +
); } else return ( @@ -218,14 +228,6 @@ export default function Friends() { }) ) : (
-
{ - setIsModalOpen(true); - }} - > - -
{pendingFriends.map((friend) => (
Date: Mon, 5 May 2025 15:14:13 -0400 Subject: [PATCH 7/7] remoed mr-4 --- src/app/(private)/friends/_components/AddFriendButton.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/(private)/friends/_components/AddFriendButton.tsx b/src/app/(private)/friends/_components/AddFriendButton.tsx index 7fcd13b..33e43a4 100644 --- a/src/app/(private)/friends/_components/AddFriendButton.tsx +++ b/src/app/(private)/friends/_components/AddFriendButton.tsx @@ -4,7 +4,7 @@ import { UserRoundPlus } from "lucide-react"; export default function AddFriendButton() { return ( -