From d52750003401210b36c5e8ac088bd172cf601ff8 Mon Sep 17 00:00:00 2001 From: Julian Cuni Date: Fri, 9 Sep 2022 10:39:19 +0200 Subject: [PATCH] FrontEnd: Playing with store (solidjs) --- frontend/src/components/AuthLoader.tsx | 9 ++++ frontend/src/components/TestComponent.tsx | 13 +++++ frontend/src/context/AuthContext.tsx | 58 ++++++++++++++++++++--- frontend/src/hooks/auth/login.hook.ts | 50 +++++++++++++++---- frontend/src/index.tsx | 5 +- frontend/src/routes/views/home/Home.tsx | 25 ++++++---- frontend/src/services/auth.service.ts | 32 +++++++++++++ 7 files changed, 169 insertions(+), 23 deletions(-) create mode 100644 frontend/src/components/AuthLoader.tsx create mode 100644 frontend/src/components/TestComponent.tsx create mode 100644 frontend/src/services/auth.service.ts diff --git a/frontend/src/components/AuthLoader.tsx b/frontend/src/components/AuthLoader.tsx new file mode 100644 index 0000000..720098f --- /dev/null +++ b/frontend/src/components/AuthLoader.tsx @@ -0,0 +1,9 @@ +const AuthLoader = () => { + return ( +
+

Auth Loading...

+
+ ) +} + +export default AuthLoader; \ No newline at end of file diff --git a/frontend/src/components/TestComponent.tsx b/frontend/src/components/TestComponent.tsx new file mode 100644 index 0000000..44b44dc --- /dev/null +++ b/frontend/src/components/TestComponent.tsx @@ -0,0 +1,13 @@ +interface TestComponentProps { + // add props here +} + +function TestComponent(props: TestComponentProps) { + return ( +
+

TestComponent

+
+ ) +} + +export default TestComponent; \ No newline at end of file diff --git a/frontend/src/context/AuthContext.tsx b/frontend/src/context/AuthContext.tsx index 7b60d66..7789666 100644 --- a/frontend/src/context/AuthContext.tsx +++ b/frontend/src/context/AuthContext.tsx @@ -1,22 +1,68 @@ import { useLocation, useNavigate } from "@solidjs/router"; -import { createContext } from "solid-js"; +import { createContext, onMount, Show, useContext } from "solid-js"; import { createStore } from "solid-js/store"; +import { UserType } from "supertokens-web-js/recipe/emailpassword"; +import AuthLoader from "../components/AuthLoader"; +import { currentUser } from "../services/auth.service"; const AuthStateContext = createContext(); -const AuthDispatchContext = createContext(); +const AuthDispatchContext = createContext(); -const initialState = { +interface InitState { + isLoading: boolean; + isAuthenticated: boolean; + currentUser: UserType | null; +} + +const initialState: InitState = { + isLoading: false, isAuthenticated: false, - isLoading: true, currentUser: null, - currentAccount: null, }; const AuthProvider = (props: any) => { + const [store, setStore] = createStore(initialState); const navigate = useNavigate(); - const location = useLocation(); + const loadCurrentUser = async () => { + const user = await currentUser(); + if (user) { + setStore("isAuthenticated", true); + setStore("currentUser", user); + } + }; + + onMount(async () => { + await loadCurrentUser(); + }); + + const setCurrentUser = (user: UserType) => { + setStore("isAuthenticated", true); + setStore("currentUser", user); + setStore("isLoading", false); + }; + const removeCurrentUser = () => { + setStore("isAuthenticated", false); + setStore("currentUser", null); + }; + + return ( + + + }> + {props.children} + + + + ); }; export default AuthProvider; +export const useAuthState = () => useContext(AuthStateContext); +export const useAuthDispatch = () => useContext(AuthDispatchContext); diff --git a/frontend/src/hooks/auth/login.hook.ts b/frontend/src/hooks/auth/login.hook.ts index 554752b..78f8a4c 100644 --- a/frontend/src/hooks/auth/login.hook.ts +++ b/frontend/src/hooks/auth/login.hook.ts @@ -1,15 +1,21 @@ +import { useNavigate } from "@solidjs/router"; import { createSignal } from "solid-js"; import { createStore } from "solid-js/store"; import EmailPassRecipe from "supertokens-web-js/recipe/emailpassword"; import Session from "supertokens-web-js/recipe/session"; - +import { useAuthDispatch } from "../../context/AuthContext"; +import { loginService } from "../../services/auth.service"; const useLogin = () => { const [loading, setLoading] = createSignal(false); const [form, setForm] = createStore({ email: "", password: "", }); + + const { setCurrentUser } = useAuthDispatch(); + const navigate = useNavigate(); + const handleInput = (ev: any) => { setForm([ev.currentTarget.name], ev.currentTarget.value); }; @@ -17,18 +23,46 @@ const useLogin = () => { ev.preventDefault(); setLoading(true); try { - const login = await EmailPassRecipe.signIn({ + const loginData = await loginService({ formFields: [ { id: "email", value: form.email }, { id: "password", value: form.password }, ], }); - console.log(login) + if (loginData.status === "OK") { + //TODO: Add user in store. Set Authenticated true. + localStorage.setItem("current_user", JSON.stringify(loginData.user)); + setCurrentUser(loginData.user); + navigate("/", { replace: true }); + } + if (loginData.status === "FIELD_ERROR") { + // TODO: Handle error in UI + console.log("FIELD_ERROR", loginData); + } + if (loginData.status === "WRONG_CREDENTIALS_ERROR") { + // TODO: Handle error in UI + console.log("WRONG_CREDENTIALS_ERROR", loginData); + } } catch (error) { - console.error(error); + //TODO: Handle error in UI + console.error("ERRRRRRRRRRr", error); } finally { setLoading(false); } + + // try { + // const login = await EmailPassRecipe.signIn({ + // formFields: [ + // { id: "email", value: form.email }, + // { id: "password", value: form.password }, + // ], + // }); + // console.log(login) + // } catch (error) { + // console.error(error); + // } finally { + // setLoading(false); + // } }; const handleLogout = async () => { @@ -41,10 +75,10 @@ const useLogin = () => { let userId = await Session.getUserId(); let jwt = (await Session.getAccessTokenPayloadSecurely()).jwt; // console.log(userId, jwt); - const {isVerified} = await EmailPassRecipe.isEmailVerified(); - console.log(isVerified) - if(!isVerified) { - const sendEmail = await EmailPassRecipe.sendVerificationEmail() + const { isVerified } = await EmailPassRecipe.isEmailVerified(); + console.log(isVerified); + if (!isVerified) { + const sendEmail = await EmailPassRecipe.sendVerificationEmail(); console.log(sendEmail); } } diff --git a/frontend/src/index.tsx b/frontend/src/index.tsx index 2edee34..dc4b645 100644 --- a/frontend/src/index.tsx +++ b/frontend/src/index.tsx @@ -4,11 +4,14 @@ import { render } from "solid-js/web"; import "./index.css"; import App from "./App"; import { Router } from "@solidjs/router"; +import AuthProvider from "./context/AuthContext"; render( () => ( - + + + ), document.getElementById("main-container") as HTMLElement diff --git a/frontend/src/routes/views/home/Home.tsx b/frontend/src/routes/views/home/Home.tsx index 17d66d8..f3f9d5a 100644 --- a/frontend/src/routes/views/home/Home.tsx +++ b/frontend/src/routes/views/home/Home.tsx @@ -1,11 +1,20 @@ -import type { Component } from "solid-js"; +import { Component, Show } from "solid-js"; +import { useAuthState } from "../../../context/AuthContext"; const Home: Component = () => { - return ( -
-

Home

-
- ) -} + const authState: any = useAuthState(); -export default Home; \ No newline at end of file + return ( +
+

Home

+ + +
+

{JSON.parse(authState?.currentUser)}

+
+
+
+ ); +}; + +export default Home; diff --git a/frontend/src/services/auth.service.ts b/frontend/src/services/auth.service.ts new file mode 100644 index 0000000..07c913c --- /dev/null +++ b/frontend/src/services/auth.service.ts @@ -0,0 +1,32 @@ +import EmailPassRecipe from "supertokens-web-js/recipe/emailpassword"; +import Session from "supertokens-web-js/recipe/session"; + +export interface AuthData { + formFields: FormFields[]; +} +interface FormFields { + id: string; + value: string; +} + +const currentUser = async () => { + // This method might produce bugs. Localstorage may not be the same as logged in user + // TODO: endpoing in backend (getCurrentUser) + if ( + localStorage.getItem("current_user") && + (await Session.doesSessionExist()) + ) { + let sessionUserId = await Session.getUserId(); + const user: EmailPassRecipe.UserType = JSON.parse(localStorage.getItem("current_user")!); + if (sessionUserId === user.id) { + return user; + } + } + return null; +}; + +const loginService = async (loginData: AuthData) => { + return await EmailPassRecipe.signIn(loginData); +}; + +export { loginService, currentUser };