From 8a7eaa7db61d898589392321d74721b92384468e Mon Sep 17 00:00:00 2001 From: Mikayla Dobson <93477693+innocuous-symmetry@users.noreply.github.com> Date: Thu, 1 Dec 2022 20:59:01 -0600 Subject: [PATCH] prototyping the remainder of user reg workflow; some progress on login after register --- client/src/App.tsx | 19 ++++- .../{register.aboutyou.tsx => aboutyou.tsx} | 18 +++-- .../components/pages/Register/addfriends.tsx | 49 +++++++++++++ .../components/pages/Register/collection.tsx | 72 +++++++++++++++++++ .../components/pages/Register/finishup.tsx | 29 ++++++++ .../src/components/pages/Register/index.tsx | 51 +++++++++++-- .../pages/Register/register.addfriends.tsx | 11 --- .../pages/Register/register.collection.tsx | 11 --- client/src/components/pages/Welcome.tsx | 1 + client/src/components/ui/Navbar/index.tsx | 5 +- client/src/components/ui/Page.tsx | 1 - client/src/components/ui/TextField.tsx | 20 ++++++ client/src/components/ui/index.ts | 10 +-- client/src/util/apiUtils.tsx | 51 ++++++++----- server/auth/index.ts | 13 +--- server/routes/auth.ts | 6 +- 16 files changed, 283 insertions(+), 84 deletions(-) rename client/src/components/pages/Register/{register.aboutyou.tsx => aboutyou.tsx} (87%) create mode 100644 client/src/components/pages/Register/addfriends.tsx create mode 100644 client/src/components/pages/Register/collection.tsx create mode 100644 client/src/components/pages/Register/finishup.tsx delete mode 100644 client/src/components/pages/Register/register.addfriends.tsx delete mode 100644 client/src/components/pages/Register/register.collection.tsx diff --git a/client/src/App.tsx b/client/src/App.tsx index df8859f..944dd05 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -1,6 +1,7 @@ import { BrowserRouter, Routes, Route } from 'react-router-dom'; -import { useEffect, useState } from 'react'; -import { AuthContext, IAuthContext } from './context/AuthContext'; +import { useCallback, useEffect, useState } from 'react'; +import { AuthContext, IAuthContext, useAuthContext } from './context/AuthContext'; +import { IUser } from './schemas'; import { checkCredientials } from './util/apiUtils'; import Subscriptions from './components/pages/Subscriptions/Subscriptions'; import Browser from './components/pages/Browser'; @@ -11,9 +12,16 @@ import Recipe from './components/pages/Recipe'; import Register from './components/pages/Register'; import Welcome from './components/pages/Welcome'; import './sass/App.scss' +import { Navbar } from './components/ui'; function App() { const [user, setUser] = useState({ user: undefined }); + const authContext = useAuthContext(); + + const receiveChange = useCallback((change: IUser) => { + console.log(change); + authContext.user = change; + }, []) useEffect(() => { const wrapper = async () => { @@ -29,13 +37,18 @@ function App() { wrapper(); }, []) + useEffect(() => { + console.log(authContext); + }, [authContext]); + return (
+ } /> - } /> + } /> } /> } /> } /> diff --git a/client/src/components/pages/Register/register.aboutyou.tsx b/client/src/components/pages/Register/aboutyou.tsx similarity index 87% rename from client/src/components/pages/Register/register.aboutyou.tsx rename to client/src/components/pages/Register/aboutyou.tsx index 57779fe..d1fa048 100644 --- a/client/src/components/pages/Register/register.aboutyou.tsx +++ b/client/src/components/pages/Register/aboutyou.tsx @@ -1,6 +1,7 @@ import { useCallback, useEffect, useMemo, useState } from "react"; import { useNavigate } from "react-router-dom"; import { v4 } from "uuid"; +import { RegisterVariantType, VariantLabel } from "."; import { useAuthContext } from "../../../context/AuthContext"; import { IUser, IUserAuth } from "../../../schemas"; import { attemptLogin, attemptRegister } from "../../../util/apiUtils"; @@ -18,7 +19,7 @@ const blankUser: IUser = { isadmin: false } -export default function AboutYou() { +const AboutYou: RegisterVariantType = ({ transitionDisplay }) => { const navigate = useNavigate(); const authContext = useAuthContext(); const [form, setForm] = useState([

Loading content...

]); @@ -40,16 +41,17 @@ export default function AboutYou() { async function handleRegister() { const res = await attemptRegister(input); - console.log(res); - setRegSuccess(res); + if (res.ok) { + transitionDisplay(VariantLabel.InitialCollection, input); + } } async function unwrapLogin() { const data: IUserAuth = { email: input.email, password: input.password || "" } - console.log(data); const login = await attemptLogin(data); - console.log(login); - authContext.user = login.user; + if (login) { + authContext.user = login.user; + } navigate('/'); } @@ -75,4 +77,6 @@ export default function AboutYou() { ) -} \ No newline at end of file +} + +export default AboutYou; \ No newline at end of file diff --git a/client/src/components/pages/Register/addfriends.tsx b/client/src/components/pages/Register/addfriends.tsx new file mode 100644 index 0000000..1e5e864 --- /dev/null +++ b/client/src/components/pages/Register/addfriends.tsx @@ -0,0 +1,49 @@ +import { ChangeEvent, useEffect, useState } from "react"; +import { RegisterVariantType, VariantLabel } from "."; +import { IUser } from "../../../schemas"; +import { Button, Divider, Page, Panel, TextField, UserCard } from "../../ui"; + +const AddFriends: RegisterVariantType = ({ transitionDisplay }) => { + const [searchTerm, setSearchTerm] = useState(); + const [friendResults, setFriendResults] = useState(); + + const handleClick = async () => { + transitionDisplay(VariantLabel.FinishUp); + } + + useEffect(() => { + // run search when state changes and store it in friendresults + console.log(searchTerm); + }, [searchTerm]) + + return ( + +

Cool, we'll keep all the recipes you post in that collection.

+ + +

You can access that any time by clicking on "Collections" in your menu bar.

+

One last thing, and you'll be good to go!

+ + +

If any of your friends already use Recipin, you can use the widget below to find them and add them!

+

This will allow you to share recipes and collections back and forth, and leave comments on each other's recipes.

+ +

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

+ +
+ ) => setSearchTerm(e.target.value)} placeholder={'Search'} /> + + { + friendResults && friendResults.map((friend: IUser) => { + return + }) + } +
+
+ + +
+ ) +} + +export default AddFriends; \ No newline at end of file diff --git a/client/src/components/pages/Register/collection.tsx b/client/src/components/pages/Register/collection.tsx new file mode 100644 index 0000000..1de24a6 --- /dev/null +++ b/client/src/components/pages/Register/collection.tsx @@ -0,0 +1,72 @@ +import { ChangeEvent, useEffect, useState } from "react"; +import { RegisterVariantType, VariantLabel } from "."; +import { useNow } from "../../../hooks/useNow"; +import { ICollection, IUser, IUserAuth } from "../../../schemas"; +import { attemptLogin, createNewCollection } from "../../../util/apiUtils"; +import { Button, Divider, Page, Panel } from "../../ui"; +import TextField from "../../ui/TextField"; + +const InitialCollection: RegisterVariantType = ({ transitionDisplay, receiveChange, input }) => { + const [collectionName, setCollectionName] = useState(); + const [view, setView] = useState(

Loading...

); + const [user, setUser] = useState(); + const now = useNow(); + + async function unwrapLogin(data: IUser) { + const userInfo: IUserAuth = { email: data.email, password: data.password! } + const login = await attemptLogin(userInfo); + setUser(login.user); + } + + const handleClick = async () => { + if (!user) return; + const collection: ICollection = { + name: collectionName || (user.firstname + "'s Collection"), + active: true, + ismaincollection: true, + ownerid: user.id!.toString(), + datecreated: now, + datemodified: now + } + + const result = await createNewCollection(collection); + console.log(result); + if (result) transitionDisplay(VariantLabel.AddFriends); + } + + useEffect(() => { + if (input) { + setTimeout(() => { + unwrapLogin(input); + }, 2000); + } + }, []) + + useEffect(() => { + if (user && receiveChange) { + receiveChange(user); + setView( + +

Hi, {user.firstname}! Great to meet you.

+ +

Before we finish up here, just a couple more things.

+ + +

First, let's get your very first recipe collection set up!

+

This is where you'll store your own recipes as well as information about all of them, such as their cuisine, prep time, and ingredients used.

+ +

What would you like to call your main collection?

+ + ) => setCollectionName(e.target.value)} placeholder={user.firstname + 's Collection'} /> +
+ + +
+ ) + } + }, [user]); + + return view; +} + +export default InitialCollection; \ No newline at end of file diff --git a/client/src/components/pages/Register/finishup.tsx b/client/src/components/pages/Register/finishup.tsx new file mode 100644 index 0000000..c7709ef --- /dev/null +++ b/client/src/components/pages/Register/finishup.tsx @@ -0,0 +1,29 @@ +import { useNavigate } from "react-router-dom"; +import { RegisterVariantType } from "."; +import { Button, Divider, Page, Panel } from "../../ui"; + +const FinishUp: RegisterVariantType = () => { + const navigate = useNavigate(); + + return ( + +

Awesome, you're good to go!

+ +

If you aren't sure where to start, here are some great things to try out first:

+ + +
    +
  • Enter some recipes!
  • +
  • Set up additional collections for your most frequented recipes
  • +
  • Tell your friends so you can share your favorites back and forth!
  • +
  • Use your collections to automatically generate grocery lists
  • +
  • Or, if you're a developer, contribute to our source code!
  • +
+
+ + +
+ ) +} + +export default FinishUp \ No newline at end of file diff --git a/client/src/components/pages/Register/index.tsx b/client/src/components/pages/Register/index.tsx index eb0fa70..ea18269 100644 --- a/client/src/components/pages/Register/index.tsx +++ b/client/src/components/pages/Register/index.tsx @@ -1,11 +1,50 @@ -import { useState } from "react"; +import { FC, useCallback, useState } from "react"; import { useAuthContext } from "../../../context/AuthContext"; +import { IUser } from "../../../schemas"; import { Page } from "../../ui"; -import AboutYou from "./register.aboutyou"; +import AboutYou from "./aboutyou"; +import AddFriends from "./addfriends"; +import InitialCollection from "./collection"; +import FinishUp from "./finishup"; -export default function Register() { - const [displayed, setDisplayed] = useState(); +export type RegisterVariantType = FC<{ + transitionDisplay: ((variant: number, input?: IUser) => void), + receiveChange?: (change: IUser) => void + input?: IUser +}> + +export enum VariantLabel { + AboutYou, + InitialCollection, + AddFriends, + FinishUp +} + +const Register: FC<{receiveChange: (change: IUser) => void}> = ({ receiveChange }) => { + const [displayed, setDisplayed] = useState(); const authContext = useAuthContext(); - return displayed; -} \ No newline at end of file + const transitionDisplay = (variant: number | VariantLabel, user?: IUser) => { + switch (variant) { + case 0: + setDisplayed(); + break; + case 1: + setDisplayed(); + break; + case 2: + setDisplayed(); + break; + case 3: + setDisplayed(); + break; + default: + setDisplayed(); + break; + } + } + + return displayed || ; +} + +export default Register; \ No newline at end of file diff --git a/client/src/components/pages/Register/register.addfriends.tsx b/client/src/components/pages/Register/register.addfriends.tsx deleted file mode 100644 index 3013dd3..0000000 --- a/client/src/components/pages/Register/register.addfriends.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import { Page } from "../../ui"; - -export default function AddFriends() { - let user = null; - - return ( - -

Hi, {user || "Mikayla"}! Great to meet you.

-
- ) -} \ No newline at end of file diff --git a/client/src/components/pages/Register/register.collection.tsx b/client/src/components/pages/Register/register.collection.tsx deleted file mode 100644 index dcb8c92..0000000 --- a/client/src/components/pages/Register/register.collection.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import { Page } from "../../ui"; - -export default function InitialCollection() { - let user = null; - - return ( - -

Hi, {user || "Mikayla"}! Great to meet you.

-
- ) -} \ No newline at end of file diff --git a/client/src/components/pages/Welcome.tsx b/client/src/components/pages/Welcome.tsx index 88a4a11..6522d8d 100644 --- a/client/src/components/pages/Welcome.tsx +++ b/client/src/components/pages/Welcome.tsx @@ -34,6 +34,7 @@ const Welcome = () => {

Welcome to Recipin

+
diff --git a/client/src/components/ui/Navbar/index.tsx b/client/src/components/ui/Navbar/index.tsx index 17b5ab6..8dc6648 100644 --- a/client/src/components/ui/Navbar/index.tsx +++ b/client/src/components/ui/Navbar/index.tsx @@ -1,11 +1,11 @@ -import { useCallback, useEffect, useState } from "react"; +import { FC, useCallback, useEffect, useState } from "react"; import { useNavigate } from "react-router-dom"; import { LoggedIn, NotLoggedIn, Registering } from "./variants"; import { useAuthContext } from "../../../context/AuthContext"; import { IUser } from "../../../schemas"; import "/src/sass/components/Navbar.scss"; -const Navbar = () => { +const Navbar: FC<{receiveChange: (change: IUser) => void}> = ({ receiveChange }) => { // setup and local state const navigate = useNavigate(); const authContext = useAuthContext(); @@ -30,6 +30,7 @@ const Navbar = () => { }, [authContext]) useEffect(() => { + if (received) receiveChange(received); setDisplayed(received ? variants.loggedin : variants.notloggedin); }, [received, setReceived]); diff --git a/client/src/components/ui/Page.tsx b/client/src/components/ui/Page.tsx index 91aa536..018db9a 100644 --- a/client/src/components/ui/Page.tsx +++ b/client/src/components/ui/Page.tsx @@ -5,7 +5,6 @@ import "/src/sass/components/Page.scss"; const Page: PageComponent = ({ extraStyles, children }) => { return (
-
{ children || null }
diff --git a/client/src/components/ui/TextField.tsx b/client/src/components/ui/TextField.tsx index e69de29..ce81845 100644 --- a/client/src/components/ui/TextField.tsx +++ b/client/src/components/ui/TextField.tsx @@ -0,0 +1,20 @@ +import { FC } from "react" +import { v4 } from 'uuid'; + +interface TextFieldParams { + onChange: (...params: any) => any + id?: string | number + label?: string + placeholder?: string +} + +const TextField: FC = ({ onChange, label, id, placeholder }) => { + return ( + <> + { label && } + + + ) +} + +export default TextField; \ No newline at end of file diff --git a/client/src/components/ui/index.ts b/client/src/components/ui/index.ts index 5ed473b..76d89f0 100644 --- a/client/src/components/ui/index.ts +++ b/client/src/components/ui/index.ts @@ -6,14 +6,8 @@ import Navbar from "./Navbar"; import Page from "./Page"; import Panel from "./Panel"; import UserCard from "./UserCard"; +import TextField from "./TextField"; export { - Button, - Card, - Divider, - Form, - Navbar, - Page, - Panel, - UserCard + Button, Card, Divider, Form, Navbar, Page, Panel, UserCard, TextField } \ No newline at end of file diff --git a/client/src/util/apiUtils.tsx b/client/src/util/apiUtils.tsx index b734363..8ee8a52 100644 --- a/client/src/util/apiUtils.tsx +++ b/client/src/util/apiUtils.tsx @@ -1,4 +1,4 @@ -import { IUser, IUserAuth } from "../schemas"; +import { ICollection, IUser, IUserAuth } from "../schemas"; import { IAuthContext } from "../context/AuthContext"; import axios from "axios"; const API = import.meta.env.APISTRING || "http://localhost:8080"; @@ -10,24 +10,7 @@ export const getBaseAPI = async () => { return fetch(API); } -// auth handlers -export const attemptLogin = async (data: IUserAuth): Promise => { - try { - const response = await axios({ - method: "POST", - url: API + '/auth/login', - data: data - }); - - console.log(response); - - const result = Promise.resolve(response.data); - return result; - } catch (e: any) { - throw e; - } -} - +// auth and general user handlers export const checkCredientials = async () => { try { const response = await axios({ @@ -41,6 +24,21 @@ export const checkCredientials = async () => { } } +export const attemptLogin = async (data: IUserAuth) => { + try { + const response = await axios({ + method: "POST", + url: API + '/auth/login', + data: data + }); + + const result = Promise.resolve(response.data); + return result; + } catch (e: any) { + throw e; + } +} + export const attemptLogout = async () => { try { await axios({ @@ -68,6 +66,21 @@ export const attemptRegister = async (body: IUser) => { } } +// methods for managing collections +export const createNewCollection = async (body: ICollection) => { + try { + const response = await axios({ + method: "POST", + url: API + '/collection', + data: JSON.stringify(body) + }); + + return Promise.resolve(response.data); + } catch (e: any) { + throw e; + } +} + // for user friendships export const getFriendships = async () => { try { diff --git a/server/auth/index.ts b/server/auth/index.ts index 0f717d3..2674933 100644 --- a/server/auth/index.ts +++ b/server/auth/index.ts @@ -33,18 +33,7 @@ export default class AuthService { password: hash } - const res: IUser | null = await UserInstance.post(newData); - if (res) receivedUser = res; - - // basic profile setup - res && await CollectionInstance.post({ - name: `${data.firstname}'s Collection`, - active: true, - ismaincollection: true, - ownerid: res.id!.toString(), - datecreated: now, - datemodified: now - }); + await UserInstance.post(newData); }) return true; diff --git a/server/routes/auth.ts b/server/routes/auth.ts index 2b3717a..d496971 100644 --- a/server/routes/auth.ts +++ b/server/routes/auth.ts @@ -59,10 +59,8 @@ export const authRoute = (app: Express, passport: PassportStatic) => { try { const data: IUser = req.body; const response = await AuthInstance.register(data); - if (!response) res.sendStatus(400); - // const login = await AuthInstance.login({ email: data.email, password: data.password! }); - // console.log(login); - res.status(200).redirect('/'); + if (!response) res.status(400).send({ ok: false }); + res.status(200).send({ ok: true }); } catch(e) { next(e); }