diff --git a/client/src/components/pages/Register/aboutyou.tsx b/client/src/components/pages/Register/aboutyou.tsx index d1fa048..b7a7ae3 100644 --- a/client/src/components/pages/Register/aboutyou.tsx +++ b/client/src/components/pages/Register/aboutyou.tsx @@ -30,6 +30,10 @@ const AboutYou: RegisterVariantType = ({ transitionDisplay }) => { setInput(received); }, []); + useEffect(() => { + if (authContext.user) navigate('/'); + }, [authContext]); + const formConfig: FormConfig = { parent: "register", keys: ['firstname', 'lastname', 'handle', 'email', 'password'], diff --git a/client/src/components/pages/Register/addfriends.tsx b/client/src/components/pages/Register/addfriends.tsx index 1e5e864..3cdf052 100644 --- a/client/src/components/pages/Register/addfriends.tsx +++ b/client/src/components/pages/Register/addfriends.tsx @@ -1,20 +1,49 @@ -import { ChangeEvent, useEffect, useState } from "react"; +import { Button, Divider, Page, Panel, TextField, UserCard } from "../../ui"; +import { ChangeEvent, useCallback, useEffect, useState } from "react"; import { RegisterVariantType, VariantLabel } from "."; import { IUser } from "../../../schemas"; -import { Button, Divider, Page, Panel, TextField, UserCard } from "../../ui"; +import { getAllUsers } from "../../../util/apiUtils"; +import { v4 } from 'uuid'; const AddFriends: RegisterVariantType = ({ transitionDisplay }) => { const [searchTerm, setSearchTerm] = useState(); - const [friendResults, setFriendResults] = useState(); + const [userPool, setUserPool] = useState([]); + const [friendResults, setFriendResults] = useState([]); const handleClick = async () => { transitionDisplay(VariantLabel.FinishUp); } + // this isn't really working right now i don't think + const handleRequestSent = useCallback((targetid: string | number) => { + setUserPool((prev: IUser[]) => { + const newResults = prev.filter((user: IUser) => { + return user.id !== targetid; + }) + + return newResults; + }) + }, []) + + // load available user pool on mount useEffect(() => { - // run search when state changes and store it in friendresults - console.log(searchTerm); - }, [searchTerm]) + (async function() { + const result = await getAllUsers(); + if (result) setUserPool(result); + })(); + }, []) + + useEffect(() => { + if (!searchTerm) { + setFriendResults(new Array()); + } else { + const narrowedPool = userPool?.filter((person: IUser) => { + if (person.firstname.toLowerCase().includes(searchTerm) || person.lastname.toLowerCase().includes(searchTerm) || person.handle.toLowerCase().includes(searchTerm)) return person; + }) + + setFriendResults(narrowedPool); + } + }, [userPool, searchTerm]) return ( @@ -31,11 +60,11 @@ const AddFriends: RegisterVariantType = ({ transitionDisplay }) => {

If you know their email or unique handle, type it in below!

- ) => setSearchTerm(e.target.value)} placeholder={'Search'} /> + ) => setSearchTerm(e.target.value.toLowerCase())} placeholder={'Search'} /> { friendResults && friendResults.map((friend: IUser) => { - return + return handleRequestSent(friend.id!)} /> }) }
diff --git a/client/src/components/pages/Register/index.tsx b/client/src/components/pages/Register/index.tsx index ea18269..4d42422 100644 --- a/client/src/components/pages/Register/index.tsx +++ b/client/src/components/pages/Register/index.tsx @@ -1,7 +1,6 @@ -import { FC, useCallback, useState } from "react"; +import { FC, useEffect, useState } from "react"; import { useAuthContext } from "../../../context/AuthContext"; import { IUser } from "../../../schemas"; -import { Page } from "../../ui"; import AboutYou from "./aboutyou"; import AddFriends from "./addfriends"; import InitialCollection from "./collection"; diff --git a/client/src/components/ui/Button.tsx b/client/src/components/ui/Button.tsx index f73c90c..00b76cb 100644 --- a/client/src/components/ui/Button.tsx +++ b/client/src/components/ui/Button.tsx @@ -1,10 +1,10 @@ import { ButtonComponent } from "../../util/types" import "/src/sass/components/Button.scss"; -const Button: ButtonComponent = ({ onClick = (() => {}), children, extraStyles }) => { +const Button: ButtonComponent = ({ onClick = (() => {}), children, extraStyles, disabled = false, disabledText = null }) => { return ( - ) } diff --git a/client/src/components/ui/UserCard.tsx b/client/src/components/ui/UserCard.tsx index 862cc2a..facfee9 100644 --- a/client/src/components/ui/UserCard.tsx +++ b/client/src/components/ui/UserCard.tsx @@ -1,12 +1,42 @@ +import { useEffect, useState } from "react"; +import { IUser } from "../../schemas"; +import { addFriend, getPendingFriendRequests } from "../../util/apiUtils"; import { UserCardType } from "../../util/types"; +import Button from "./Button"; import Card from "./Card"; -const UserCard: UserCardType = ({ extraStyles, user }) => { +const UserCard: UserCardType = ({ extraStyles, user, canAdd = false, liftData }) => { + const [shouldDisable, setShouldDisable] = useState(false); + + useEffect(() => { + (async function() { + const requestsOpen = await getPendingFriendRequests(); + if (!requestsOpen) return; + + for (let req of requestsOpen) { + if (req.targetid == user.id) { + setShouldDisable(true); + console.log(req); + return; + } + } + + setShouldDisable(false); + })(); + }, []) + + const handleClick = async () => { + const { id } = user; + const request = await addFriend(id!.toString()); + if (request) console.log("Friend request sent to " + user.firstname); + } + return ( - +

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

@{user.handle}

+ { canAdd && }
) } diff --git a/client/src/util/apiUtils.tsx b/client/src/util/apiUtils.tsx index 8ee8a52..a24900a 100644 --- a/client/src/util/apiUtils.tsx +++ b/client/src/util/apiUtils.tsx @@ -10,7 +10,7 @@ export const getBaseAPI = async () => { return fetch(API); } -// auth and general user handlers +// auth and general user management handlers export const checkCredientials = async () => { try { const response = await axios({ @@ -81,7 +81,46 @@ export const createNewCollection = async (body: ICollection) => { } } -// for user friendships +// for users and user friendships +export const getAllUsers = async () => { + try { + const response = await axios({ + method: "GET", + url: API + '/users' + }) + + return Promise.resolve(response.data); + } catch(e: any) { + throw e; + } +} + +export const addFriend = async (id: string) => { + try { + const response = await axios({ + method: "POST", + url: API + '/friend/' + id + }) + + return Promise.resolve(response.data); + } catch (e: any) { + throw e; + } +} + +export const getPendingFriendRequests = async () => { + try { + const response = await axios({ + method: "GET", + url: API + '/friend?pending=true' + }) + + return Promise.resolve(response.data); + } catch (e: any) { + throw e; + } +} + export const getFriendships = async () => { try { const response = await axios({ diff --git a/client/src/util/types.ts b/client/src/util/types.ts index a70d8f1..4482928 100644 --- a/client/src/util/types.ts +++ b/client/src/util/types.ts @@ -10,6 +10,8 @@ interface PortalBase { interface ButtonParams extends PortalBase { onClick?: (params?: any) => any + disabled?: boolean + disabledText?: string } export interface MultiChildPortal extends PortalBase { @@ -18,6 +20,8 @@ export interface MultiChildPortal extends PortalBase { interface UserCardProps extends PortalBase { user: IUser + canAdd?: boolean + liftData?: (data: any) => void } interface NavbarProps { diff --git a/server/controllers/UserCtl.ts b/server/controllers/UserCtl.ts index c58696d..8d268c3 100644 --- a/server/controllers/UserCtl.ts +++ b/server/controllers/UserCtl.ts @@ -64,6 +64,16 @@ export default class UserCtl { } } + async getPendingFriendRequests(senderid: string | number) { + try { + const { ok, code, result } = await UserInstance.getPendingFriendRequests(senderid); + if (ok) return result; + throw createError(code, result); + } catch (e: any) { + throw new Error(e); + } + } + async addFriendship(userid: number | string, targetid: number | string) { try { const result = await UserInstance.addFriendship(userid, targetid); diff --git a/server/models/user.ts b/server/models/user.ts index 5fa1ed0..ecec676 100644 --- a/server/models/user.ts +++ b/server/models/user.ts @@ -123,6 +123,18 @@ export class User { } } + async getPendingFriendRequests(senderid: number | string) { + try { + const statement = `SELECT * FROM recipin.cmp_userfriendships WHERE pending = true AND senderid = $1` + const result = await pool.query(statement, [senderid]); + + if (result.rows.length) return { ok: true, code: 200, result: result.rows } + return { ok: true, code: 200, result: "No pending friend requests found" } + } catch (e: any) { + throw new Error(e); + } + } + async addFriendship(userid: number | string, targetid: number | string) { try { const statement = ` diff --git a/server/routes/friend.ts b/server/routes/friend.ts index aaaabb6..76f5765 100644 --- a/server/routes/friend.ts +++ b/server/routes/friend.ts @@ -23,10 +23,16 @@ export const friendRouter = (app: Express) => { // get all friendships for a user router.get('/', async (req, res, next) => { const { user }: any = req.user; + const { pending } = req.query; try { - const result = await UserInstance.getFriends(user.id); - res.status(200).send(result); + if (pending) { + const result = await UserInstance.getPendingFriendRequests(user.id); + res.status(200).send(result); + } else { + const result = await UserInstance.getFriends(user.id); + res.status(200).send(result); + } } catch(e) { next(e); }