more customization on user/versus other-user profiles
This commit is contained in:
@@ -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<IFriendship[]>();
|
||||
const [userList, setUserList] = useState(new Array<IUser>());
|
||||
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 ?
|
||||
(
|
||||
<Card extraStyles="flex-row">
|
||||
<h2>Your friendships:</h2>
|
||||
<h2>Friends ({ userList?.length ?? "0" }):</h2>
|
||||
|
||||
{
|
||||
userList.map((user: IUser) => {
|
||||
return <UserCard key={v4()} user={user} />
|
||||
return <UserCard key={v4()} targetUser={user} />
|
||||
})
|
||||
}
|
||||
|
||||
<aside>
|
||||
<p>Looking for someone else?</p>
|
||||
<p>You can search for more friends <a href="/add-friends">here!</a></p>
|
||||
</aside>
|
||||
</Card>
|
||||
) :
|
||||
(
|
||||
@@ -73,4 +79,6 @@ export default function Friends() {
|
||||
}
|
||||
</>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default Friends
|
||||
@@ -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<ICollection[]>();
|
||||
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 (
|
||||
<Panel key={v4()}>
|
||||
<h2>{each.name}</h2>
|
||||
<p>{count.length} recipes</p>
|
||||
<a href={`/collections/${each.id}`}>Link to details</a>
|
||||
</Panel>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
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<CollectionDetails[]>();
|
||||
|
||||
let i = 0;
|
||||
for (let each of allRecipes) {
|
||||
}
|
||||
|
||||
setList(allRecipes);
|
||||
}
|
||||
if (allRecipes) setList(allRecipes);
|
||||
})();
|
||||
}, [token])
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
}, [list])
|
||||
|
||||
return (
|
||||
<Page>
|
||||
<h1>Browsing your {2} collections:</h1>
|
||||
|
||||
{
|
||||
list && list.map(each => {
|
||||
{ list && (
|
||||
<>
|
||||
<h1>Browsing your {list.length} collection{ (list.length !== 1) && "s" }:</h1>
|
||||
|
||||
{ list.map(each => {
|
||||
return (
|
||||
<Card key={v4()}>
|
||||
<Panel key={v4()}>
|
||||
<h2>{each.name}</h2>
|
||||
<a href={`/collections/${each.id}`}>Link to details</a>
|
||||
</Card>
|
||||
</Panel>
|
||||
)
|
||||
})
|
||||
}
|
||||
})}
|
||||
</>
|
||||
)}
|
||||
</Page>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
<Protect redirect="/">
|
||||
@@ -148,12 +144,12 @@ export default function Profile() {
|
||||
</Panel>
|
||||
|
||||
<Panel>
|
||||
<h2>My collections:</h2>
|
||||
<h2>{metadata.targetUser.firstname}'s collections ({ metadata.collections.length ?? "0" }):</h2>
|
||||
<CollectionList targetID={metadata.targetUser.id} />
|
||||
</Panel>
|
||||
|
||||
<Panel>
|
||||
<h2>My friends:</h2>
|
||||
<h2>{metadata.targetUser.firstname}'s friends:</h2>
|
||||
<Friends />
|
||||
</Panel>
|
||||
</div>
|
||||
@@ -161,6 +157,8 @@ export default function Profile() {
|
||||
</Protect>
|
||||
)
|
||||
} else {
|
||||
|
||||
// if this is the current user's profile
|
||||
setContents(
|
||||
<Protect redirect="profile">
|
||||
<div className="profile-authenticated">
|
||||
@@ -178,12 +176,11 @@ export default function Profile() {
|
||||
|
||||
<Panel>
|
||||
{/* include number of collections */}
|
||||
<h2>My collections ({ metadata.collections.length || 0 }):</h2>
|
||||
<h2><a href="/collections">My collections</a> ({ metadata.collections.length || 0 }):</h2>
|
||||
<CollectionList />
|
||||
</Panel>
|
||||
|
||||
<Panel>
|
||||
<h2>My friends:</h2>
|
||||
<Friends />
|
||||
</Panel>
|
||||
</div>
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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(<Button disabled>Request Sent!</Button>)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
setButtonVariant(<Button onClick={handleClick}>Send Request</Button>)
|
||||
} 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(<Button disabled>Request Sent!</Button>)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Card extraStyles={'user-card' + extraStyles}>
|
||||
<div className="avatar"></div>
|
||||
<h3>{user.firstname} {user.lastname.substring(0,1)}.</h3>
|
||||
<h4>@{user.handle}</h4>
|
||||
<Button disabledText={"Request Sent"} onClick={handleClick}>Add Me</Button>
|
||||
<h3><a href={`/profile?id=${targetUser.id}`}>{targetUser.firstname} {targetUser.lastname.substring(0,1)}.</a></h3>
|
||||
<h4>@{targetUser.handle}</h4>
|
||||
{ buttonVariant }
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -19,7 +19,7 @@ export interface ProtectParams extends PortalBase {
|
||||
}
|
||||
|
||||
interface UserCardProps extends PortalBase {
|
||||
user: IUser
|
||||
targetUser: IUser
|
||||
canAdd?: boolean
|
||||
liftData?: (data: any) => void
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user