diff --git a/client/src/components/derived/Friends.tsx b/client/src/components/derived/Friends.tsx index 4ec2b14..e96324c 100644 --- a/client/src/components/derived/Friends.tsx +++ b/client/src/components/derived/Friends.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from "react"; +import { FC, useEffect, useState } from "react"; import { v4 } from "uuid"; import { useAuthContext } from "../../context/AuthContext"; import { getAllUsers, getFriendships, getPendingFriendRequests, getUserByID } from "../../util/apiUtils"; @@ -8,7 +8,7 @@ import { IUser, IFriendship } from "../../schemas"; import { Card, Divider, Panel } from "../ui"; import FriendSearchWidget from "../ui/Widgets/FriendSearchWidget"; -export default function Friends() { +const Friends: FC<{ targetUser?: IUser }> = ({ targetUser }) => { const [friends, setFriends] = useState(); const [userList, setUserList] = useState(new Array()); const { user, token } = useAuthContext(); @@ -35,29 +35,35 @@ export default function Friends() { if (!token || !friends) return; friends.map(async (friend: IFriendship) => { - const Friends = new API.Friendship(token); - const userData = await Friends.getByID(friend.targetid as string); + const User = new API.User(token); + const userData = await User.getByID(friend.targetid as string); if (userData) setUserList((prev: IUser[]) => { - return [...prev, userData] + if (prev.includes(userData)) { + return prev; + } else { + return [...prev, userData] + } }) }) }, [friends]); - useEffect(() => { - console.log(userList); - }, [setUserList]) - return ( <> { userList.length ? ( -

Your friendships:

+

Friends ({ userList?.length ?? "0" }):

+ { userList.map((user: IUser) => { - return + return }) } + +
) : ( @@ -73,4 +79,6 @@ export default function Friends() { } ) -} \ No newline at end of file +} + +export default Friends \ No newline at end of file diff --git a/client/src/components/pages/CollectionBrowser.tsx b/client/src/components/pages/CollectionBrowser.tsx index ac8d70a..2ee8aca 100644 --- a/client/src/components/pages/CollectionBrowser.tsx +++ b/client/src/components/pages/CollectionBrowser.tsx @@ -1,53 +1,67 @@ import { useEffect, useState } from "react"; import { v4 } from "uuid"; import { useAuthContext } from "../../context/AuthContext"; -import { ICollection, IRecipe } from "../../schemas"; +import { ICollection } from "../../schemas"; import API from "../../util/API"; -import { Card, Page } from "../ui"; - -interface CollectionDetails { - idx: number - collection: ICollection - recipes: IRecipe[] -} +import { Page, Panel } from "../ui"; const CollectionBrowser = () => { const [list, setList] = useState(); const { token } = useAuthContext(); + async function getRecipeCount(collection: ICollection) { + if (!token) return []; + const collections = new API.Collection(token); + const result = await collections.getRecipesFromOne(collection.id); + if (result) return result; + return []; + } + + async function mapRecipes() { + if (!list) return; + + return list.map(async (each) => { + const count = await getRecipeCount(each); + + return ( + +

{each.name}

+

{count.length} recipes

+ Link to details +
+ ) + }) + } + useEffect(() => { if (!token) return; (async() => { const collections = new API.Collection(token); - const recipes = new API.Recipe(token); - const allRecipes = await collections.getAllAuthored(); - if (allRecipes) { - const result = new Array(); - - let i = 0; - for (let each of allRecipes) { - } - - setList(allRecipes); - } + if (allRecipes) setList(allRecipes); })(); }, [token]) + useEffect(() => { + + }, [list]) + return ( -

Browsing your {2} collections:

- - { - list && list.map(each => { + { list && ( + <> +

Browsing your {list.length} collection{ (list.length !== 1) && "s" }:

+ + { list.map(each => { return ( - +

{each.name}

Link to details -
+ ) - }) - } + })} + + )}
) } diff --git a/client/src/components/pages/Profile.tsx b/client/src/components/pages/Profile.tsx index 0e50f30..8dd06af 100644 --- a/client/src/components/pages/Profile.tsx +++ b/client/src/components/pages/Profile.tsx @@ -37,8 +37,6 @@ export default function Profile() { isSet: false }); - const dateFormatter = new Intl.DateTimeFormat('en-US', { timeStyle: undefined, dateStyle: "long" }); - // STEP 1: FETCH METADATA (requires token) useEffect(() => { if (!token || !user) return; @@ -115,10 +113,6 @@ export default function Profile() { } })(); - (async() => { - const Friends = new API.Friendship(token); - }) - setMetadata((prev) => { return { ...prev, @@ -135,6 +129,8 @@ export default function Profile() { // STEP 2: set up page UI based on profile config above useEffect(() => { if (metadata.isSet) { + + // if this is another user's profile if (metadata.targetUser) { setContents( @@ -148,12 +144,12 @@ export default function Profile() { -

My collections:

+

{metadata.targetUser.firstname}'s collections ({ metadata.collections.length ?? "0" }):

-

My friends:

+

{metadata.targetUser.firstname}'s friends:

@@ -161,6 +157,8 @@ export default function Profile() {
) } else { + + // if this is the current user's profile setContents(
@@ -178,12 +176,11 @@ export default function Profile() { {/* include number of collections */} -

My collections ({ metadata.collections.length || 0 }):

+

My collections ({ metadata.collections.length || 0 }):

-

My friends:

diff --git a/client/src/components/pages/Recipe.tsx b/client/src/components/pages/Recipe.tsx index 66c92a7..d6b2720 100644 --- a/client/src/components/pages/Recipe.tsx +++ b/client/src/components/pages/Recipe.tsx @@ -1,7 +1,7 @@ import { useEffect, useState } from "react"; import { useParams } from "react-router-dom"; import { Page, Panel } from "../ui"; -import { IRecipe } from "../../util/types"; +import { IRecipe } from "../../schemas"; import { getRecipeByID } from "../../util/apiUtils"; export default function Recipe() { diff --git a/client/src/components/ui/UserCard.tsx b/client/src/components/ui/UserCard.tsx index b30b0fa..34dd5cb 100644 --- a/client/src/components/ui/UserCard.tsx +++ b/client/src/components/ui/UserCard.tsx @@ -1,47 +1,55 @@ +import { AxiosError } from "axios"; import { useEffect, useState } from "react"; import { useAuthContext } from "../../context/AuthContext"; -import API from "../../util/API"; -// import { addFriend, getPendingFriendRequests } from "../../util/apiUtils"; import { UserCardType } from "../../util/types"; +import API from "../../util/API"; import Button from "./Button"; import Card from "./Card"; -const UserCard: UserCardType = ({ extraStyles, user }) => { +const UserCard: UserCardType = ({ extraStyles, targetUser }) => { + const [buttonVariant, setButtonVariant] = useState(<>); const { token } = useAuthContext(); useEffect(() => { if (!token) return; (async function() { - const friends = new API.Friendship(token); - const requestsOpen = await friends.getPendingFriendRequests(); - console.log(requestsOpen); - if (!requestsOpen) return; - - for (let req of requestsOpen) { - if (req.targetid == user.id) { - console.log('should disable'); - return; + try { + const friends = new API.Friendship(token); + const requestsOpen = await friends.getPendingFriendRequests(); + if (!requestsOpen) return; + + for (let req of requestsOpen) { + if (req.targetid == targetUser.id) { + setButtonVariant() + return; + } + } + + setButtonVariant() + } catch (error) { + if (error instanceof AxiosError) { + console.log(error.response?.statusText); } } - - console.log('should not disable'); - }); + })(); }, []) const handleClick = async () => { if (!token) return; const friends = new API.Friendship(token); - const request = await friends.addFriend(user.id!.toString()); - if (request) console.log("Friend request sent to " + user.firstname); + const request = await friends.addFriend(targetUser.id!.toString()); + if (request) { + setButtonVariant() + } } return (
-

{user.firstname} {user.lastname.substring(0,1)}.

-

@{user.handle}

- +

{targetUser.firstname} {targetUser.lastname.substring(0,1)}.

+

@{targetUser.handle}

+ { buttonVariant }
) } diff --git a/client/src/util/API.ts b/client/src/util/API.ts index f46ce05..aa27e02 100644 --- a/client/src/util/API.ts +++ b/client/src/util/API.ts @@ -154,6 +154,19 @@ module API { } } + async getTargetUserFriendships(id: string | number) { + try { + const response = await this.instance.get(this.endpoint + `?targetUser=${id}`, this.headers); + return Promise.resolve(response.data); + } catch (e) { + const error = e as AxiosError; + if (error.response?.status == 404) { + console.log('no friends found'); + return []; + } + } + } + async getPendingFriendRequests() { const response = await this.instance.get(this.endpoint + "?pending=true", this.headers); return Promise.resolve(response.data); diff --git a/client/src/util/types.ts b/client/src/util/types.ts index ff5ffea..14c122f 100644 --- a/client/src/util/types.ts +++ b/client/src/util/types.ts @@ -19,7 +19,7 @@ export interface ProtectParams extends PortalBase { } interface UserCardProps extends PortalBase { - user: IUser + targetUser: IUser canAdd?: boolean liftData?: (data: any) => void } diff --git a/server/routes/friend.ts b/server/routes/friend.ts index 08561b9..c353fb8 100644 --- a/server/routes/friend.ts +++ b/server/routes/friend.ts @@ -24,15 +24,20 @@ export const friendRouter = (app: Express) => { // get all friendships for a user router.get('/', async (req, res, next) => { const user = req.user as IUser; - const { pending } = req.query; + const { pending, targetUser } = req.query; try { if (pending) { const { code, data } = await UserInstance.getPendingFriendRequests(user.id as number); res.status(code).send(data); } else { - const { code, data } = await UserInstance.getFriends(user.id as number); - res.status(code).send(data); + if (targetUser) { + const { code, data } = await UserInstance.getFriends(parseInt(targetUser as string)); + res.status(code).send(data); + } else { + const { code, data } = await UserInstance.getFriends(user.id as number); + res.status(code).send(data); + } } } catch(e) { next(e);