Skip to content

Commit

Permalink
update bootstrap submit function
Browse files Browse the repository at this point in the history
  • Loading branch information
iibarbari committed Nov 15, 2024
1 parent 5b53b31 commit 6ccd0f6
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 31 deletions.
12 changes: 12 additions & 0 deletions frontend/src/@types/api/auth.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
type User = {
createdAt: string;
email: string;
id: number;
isEmailVerified: boolean;
isPasswordSet: boolean;
name: string;
role: UserRole;
updatedAt: string;
};

type UserRole = "ADMIN" | "OWNER" | "USER";
5 changes: 3 additions & 2 deletions frontend/src/components/App/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Route, Switch } from "wouter";
import "../../styles/style.css";
import AuthProvider from "~/components/AuthProvider";
import Bootstrap from "~/components/Bootstrap";
import Error from "~/components/Error";
import Home from "~/components/Home";
Expand All @@ -8,7 +9,7 @@ import SignIn from "~/components/SignIn";

export default function App() {
return (
<>
<AuthProvider>
<Switch>
<Route component={Bootstrap} path="/bootstrap" />
<Route component={Home} path="/" />
Expand All @@ -19,6 +20,6 @@ export default function App() {
<Error />
</Route>
</Switch>
</>
</AuthProvider>
);
}
53 changes: 53 additions & 0 deletions frontend/src/components/AuthProvider/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { ReactNode, useCallback, useEffect, useMemo, useState } from "react";
import { useErrorBoundary } from "react-error-boundary";
import AuthContext, { AuthContextType } from "~/contexts/AuthContext";
import { setUserAccessToken } from "~/lib/user-access-token";

export default function AuthProvider({ children }: { children: ReactNode }) {
const { showBoundary } = useErrorBoundary();
const [user] = useState<AuthContextType["user"] | null>(null);
const canWrite = useMemo<AuthContextType["canWrite"]>(() => ["ADMIN", "OWNER"].includes(user?.role || ""), [user]);
const isOrganizationOwner = useMemo<AuthContextType["isOrganizationOwner"]>(() => user?.role === "OWNER", [user]);

const getAuthUser = useCallback(async () => {
try {
/* TODO: Update endpoint */
// const response = await api.get("/authentication/user");
// const responseJson = await response.json();
//
// if (response.ok) {
// setUser(responseJson);
// } else {
// await signOut();
// }
} catch (error) {
return showBoundary(error);
}
}, []);

const refreshUser = useCallback(async () => getAuthUser(), [getAuthUser]);

const signOut = useCallback(async () => {
setUserAccessToken(null);

await getAuthUser();
}, []);

useEffect(() => {
getAuthUser();
}, []);

return (
<AuthContext.Provider
value={{
canWrite,
isOrganizationOwner,
refreshUser,
signOut,
user,
}}
>
{children}
</AuthContext.Provider>
);
}
16 changes: 8 additions & 8 deletions frontend/src/components/Bootstrap/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import { Link } from "wouter";
import ActivityOverlay from "~/components/ActivityOverlay";
import Layout from "~/components/Layout";
import Title from "~/components/Title";
import { base64Encode } from "~/helpers/base64";
import { api } from "~/lib/api";
import { setErrors } from "~/lib/form";
import { setUserAccessToken } from "~/lib/user-access-token";
import styles from "./Bootstrap.module.css";

type Form = {
Expand Down Expand Up @@ -36,18 +38,16 @@ export default function Bootstrap() {
const responseJson = await response.json();

if (response.ok) {
const accessTokenResponse = await api.post("/authentication/user-access-tokens", {
email: data.userEmail,
password: data.userPassword,
const accessTokenResponse = await api.post("/authentication/user-access-tokens", undefined, {
headers: {
authorization: `Basic ${base64Encode(`${data.userEmail}:${data.userPassword}`)}`,
},
});
const accessTokenResponseJson = await accessTokenResponse.json();

debugger;
const accessTokenResponseJson = await accessTokenResponse.json();

if (accessTokenResponse.ok) {
console.log(accessTokenResponseJson);

localStorage.setItem("accessToken", accessTokenResponseJson.accessToken);
setUserAccessToken(accessTokenResponseJson.accessToken);
} else {
setErrors(setError, accessTokenResponseJson);
}
Expand Down
39 changes: 18 additions & 21 deletions frontend/src/components/SignIn/index.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { IconX } from "@tabler/icons-react";
import clsx from "clsx";
import { useState } from "react";
import { useEffect, useState } from "react";
import { useErrorBoundary } from "react-error-boundary";
import { useForm } from "react-hook-form";
import { Link } from "wouter";
import { Link, useLocation, useSearch } from "wouter";
import ActivityOverlay from "~/components/ActivityOverlay";
import Layout from "~/components/Layout";
import Title from "~/components/Title";
import { base64Encode } from "~/helpers/base64";
import useUser from "~/hooks/useUser";
import { api } from "~/lib/api";
import { setErrors } from "~/lib/form";
import { setUserAccessToken } from "~/lib/user-access-token";
import FormTitle from "./FormTitle";
import styles from "./SignIn.module.css";

Expand All @@ -19,16 +21,23 @@ type Form = {
};

type State = {
/* TODO: Implement this logic after auth handler is ready */
isAlreadySignedIn: boolean;
isSignInComplete: boolean;
};

export default function SignIn() {
const { showBoundary } = useErrorBoundary();
const [state, setState] = useState<State>({ isAlreadySignedIn: false, isSignInComplete: false });
const location = useLocation();
const searchParams = useSearch();
const user = useUser();
const [state, setState] = useState<State>({ isAlreadySignedIn: false });
const { clearErrors, formState: { errors, isSubmitting }, handleSubmit, register, setError } = useForm<Form>();

useEffect(() => {
if (user) {
setState((prev) => ({ ...prev, isAlreadySignedIn: true }));
}
}, []);

async function submit(data: Form) {
try {
const response = await api.post("/authentication/user-access-tokens", undefined, {
Expand All @@ -40,9 +49,11 @@ export default function SignIn() {
const responseJson = await response.json();

if (response.ok) {
localStorage.setItem("accessToken", responseJson.accessToken);
setUserAccessToken(responseJson.accessToken);

setState((prev) => ({ ...prev, isSignInComplete: true }));
const next = new URLSearchParams(searchParams).get("next");

location.push(next || "/sites");
} else {
setErrors(setError, responseJson);
}
Expand All @@ -69,20 +80,6 @@ export default function SignIn() {
title="Signed in!"
/>
</div>
) : state.isSignInComplete ? (
<div className="container">
<FormTitle
actions={(
<Link className="button button-lg button-blue" to="/sites">
Go to dashboard
</Link>
)}
description="You are successfully signed in."
showGoBack={false}
summary="Sign in"
title="Signed in!"
/>
</div>
) : (
<div className="container">
<FormTitle
Expand Down
19 changes: 19 additions & 0 deletions frontend/src/contexts/AuthContext.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { createContext } from "react";

export type AuthContextType = {
canWrite: boolean;
isOrganizationOwner: boolean;
refreshUser: () => void;
signOut: () => void;
user: User | null;
};

const AuthContext = createContext<AuthContextType>({
canWrite: false,
isOrganizationOwner: false,
refreshUser: () => {},
signOut: () => {},
user: null,
});

export default AuthContext;
12 changes: 12 additions & 0 deletions frontend/src/hooks/useUser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { useContext } from "react";
import AuthContext from "~/contexts/AuthContext";

export default function useUser() {
const { user } = useContext(AuthContext);

if (AuthContext === undefined) {
throw new Error("useUser must be used within a UserProvider");
}

return user;
}

0 comments on commit 6ccd0f6

Please sign in to comment.