aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJeff Kleinaitis <jeffkleinaitis@gmail.com>2024-04-18 10:28:13 -0700
committerGitHub <noreply@github.com>2024-04-18 10:28:13 -0700
commit0af66ac5c814b9cf01e60f13a4c174722d33d939 (patch)
tree56812cfb8e5401981015f0b77ffcd76244d02d29 /src
parent04694856be7624ae9e80f673effc3104d7842e34 (diff)
parent3a5e9dfee0f26c03e12bb2940ca42bba1f172f7c (diff)
Merge pull request #27 from digadoo/develop
4/18 PR
Diffstat (limited to 'src')
-rw-r--r--src/App.js7
-rw-r--r--src/components/FlexibleForm.js30
-rw-r--r--src/components/Footer.js2
-rw-r--r--src/components/Home.js41
-rw-r--r--src/components/Navbar.js171
-rw-r--r--src/layouts/AuthenticatedLayout.js17
-rw-r--r--src/layouts/GridLayout.js72
-rw-r--r--src/pages/Dashboard.js12
-rw-r--r--src/pages/Login.js65
-rw-r--r--src/pages/SignUp.js52
-rw-r--r--src/providers/AuthContext.js58
11 files changed, 421 insertions, 106 deletions
diff --git a/src/App.js b/src/App.js
index 9703cfc..678f26f 100644
--- a/src/App.js
+++ b/src/App.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, { useState } from 'react';
import { BrowserRouter as Router, Routes, Route, useLocation } from 'react-router-dom';
import Navbar from './components/Navbar';
import Footer from './components/Footer';
@@ -13,12 +13,15 @@ import Careers from "./pages/Careers";
import HelpCenter from "./pages/HelpCenter";
import TermsOfService from "./pages/TermsOfService";
import PrivacyPolicy from "./pages/PrivacyPolicy";
+import Dashboard from "./pages/Dashboard";
+import {AuthProvider} from "./providers/AuthContext";
function App() {
const location = useLocation();
const excludedRoutes = ['/login', '/sign-up', '/forgot-password'];
return (
+ <AuthProvider>
<div className="App">
{!excludedRoutes.includes(location.pathname) && <Navbar />}
<Routes>
@@ -30,12 +33,14 @@ function App() {
<Route path="/terms-of-service" element={<TermsOfService />} />
<Route path="/privacy-policy" element={<PrivacyPolicy />} />
<Route path="/login" element={<Login />} />
+ <Route path="/dashboard" element={<Dashboard />} />
<Route path="/forgot-password" element={<ForgotPassword />} />
<Route path="/sign-up" element={<SignUp />} />
</Routes>
{!excludedRoutes.includes(location.pathname) && <Footer />}
{!excludedRoutes.includes(location.pathname) && <PopupWidget />}
</div>
+ </AuthProvider>
);
}
diff --git a/src/components/FlexibleForm.js b/src/components/FlexibleForm.js
index 831f972..d8c959d 100644
--- a/src/components/FlexibleForm.js
+++ b/src/components/FlexibleForm.js
@@ -2,27 +2,13 @@ import React from 'react';
import { Link } from "react-router-dom";
import logo from "../assets/img/logo.svg";
-const FlexibleForm = ({ data, onSuccess }) => {
- const handleSubmit = async (event) => {
- event.preventDefault();
- const formData = new FormData(event.target);
-
- try {
- const response = await fetch(process.env.NEXT_PUBLIC_HOST + data.formAction, {
- method: data.formMethod,
- body: JSON.stringify(Object.fromEntries(formData)),
- headers: {
- 'Content-Type': 'application/json'
- },
- });
-
- const token = response.headers.get('Authorization');
- onSuccess(token);
-
- } catch (error) {
- console.error('Error submitting form:', error);
- }
- }
+const FlexibleForm = ({ data, onFormSubmit }) => {
+ const handleSubmit = (event) => {
+ event.preventDefault();
+ if (typeof onFormSubmit === 'function') {
+ onFormSubmit(event);
+ }
+ };
return (
<div className="flex flex-col items-center justify-center min-h-screen">
@@ -56,6 +42,8 @@ const FlexibleForm = ({ data, onSuccess }) => {
type={field.type}
autoComplete={field.autoComplete}
required={field.required}
+ value={field.value}
+ onChange={field.onChange}
className="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
/>
</div>
diff --git a/src/components/Footer.js b/src/components/Footer.js
index 2878c5c..bb29839 100644
--- a/src/components/Footer.js
+++ b/src/components/Footer.js
@@ -18,7 +18,7 @@ export default function Footer() {
return (
<div className="relative">
<Container>
- <div className="grid max-w-screen-xl grid-cols-1 gap-10 pt-10 mx-auto mt-5 border-t border-gray-100 dark:border-trueGray-700 lg:grid-cols-5">
+ <div className="grid max-w-screen grid-cols-1 gap-10 pt-10 mx-auto mt-5 border-t border-gray-100 dark:border-trueGray-700 lg:grid-cols-5">
<div className="lg:col-span-2">
<div>
{" "}
diff --git a/src/components/Home.js b/src/components/Home.js
index c0e2b24..dd368ed 100644
--- a/src/components/Home.js
+++ b/src/components/Home.js
@@ -4,26 +4,35 @@ import { benefitOne, benefitTwo } from "./Data";
import Benefits from "../components/Benefits";
import Cta from "../components/Cta";
import Faq from "../components/Faq";
+import {AuthContext} from "../providers/AuthContext";
+import React, {useContext} from "react";
const Home = () => {
+ const {user} = useContext(AuthContext);
+
return (
<>
- <Hero />
- <SectionTitle
- pretitle="How It Works"
- title="Getting Started with Helping Hands"
- >
- Helping Hands simplifies the process of finding or offering volunteer opportunities. Here's a step-by-step guide:
- </SectionTitle>
- <Benefits data={benefitOne} />
- <Benefits imgPos="right" data={benefitTwo} />
- <SectionTitle pretitle="FAQ" title="Frequently Asked Questions">
- Welcome to our FAQ section! Browse through common questions for quick answers. Your clarity and support matter to us. For any unanswered queries, reach out to our support team.
- </SectionTitle>
- <Faq />
- <Cta />
+ {!user ? (
+ <>
+ <Hero/>
+ <SectionTitle pretitle="How It Works" title="Getting Started with Helping Hands">
+ Helping Hands simplifies the process of finding or offering volunteer opportunities. Here's a
+ step-by-step guide:
+ </SectionTitle>
+ <Benefits data={benefitOne}/>
+ <Benefits imgPos="right" data={benefitTwo}/>
+ <SectionTitle pretitle="FAQ" title="Frequently Asked Questions">
+ Welcome to our FAQ section! Browse through common questions for quick answers. Your clarity and
+ support matter to us. For any unanswered queries, reach out to our support team.
+ </SectionTitle>
+ <Faq/>
+ <Cta/>
+ </>
+ ) : (
+ <>
+ </>
+ )}
</>
);
}
-
-export default Home; \ No newline at end of file
+ export default Home; \ No newline at end of file
diff --git a/src/components/Navbar.js b/src/components/Navbar.js
index 9b40882..3fdf94d 100644
--- a/src/components/Navbar.js
+++ b/src/components/Navbar.js
@@ -1,20 +1,36 @@
-import React from 'react';
+import React, {useContext} from 'react';
import { Disclosure } from "@headlessui/react";
import { Link } from "react-router-dom";
import logo from "../assets/img/logo.svg";
+import {AuthContext} from "../providers/AuthContext";
+import Container from "./Container";
+import {ChevronDownIcon} from "@heroicons/react/24/solid";
+import {BellIcon} from "@heroicons/react/24/outline";
+
+
const Navbar = () => {
- const navigation = [
+ const { user } = useContext(AuthContext);
+
+ const loggedOutNavigation = [
"Find Opportunities",
"Recruit Volunteers",
- "Help Center",
- "About Us",
+ "Sign Up",
+ "Login"
+ ];
+
+ const loggedInNavigation = [
+ "Edit Profile",
+ "Settings",
+ "Help",
+ "Sign Out"
];
return (
+ <Container>
<div className="w-full">
- <nav className="container relative flex flex-wrap items-center justify-between p-8 mx-auto lg:justify-between lg:flex-nowrap lg:px-0.5 xl:px-0">
- {/* Logo */}
+ <nav className="container relative flex flex-wrap border-b border-gray-100 items-center justify-between p-8 mx-auto lg:justify-between lg:flex-nowrap lg:px-0.5 xl:px-0">
+ {/* Logo */}
<Disclosure>
{({ open }) => (
<>
@@ -34,67 +50,114 @@ const Navbar = () => {
</span>
</Link>
- <Disclosure.Button
- aria-label="Toggle Menu"
- className="px-2 py-1 ml-auto text-gray-500 rounded-md lg:hidden hover:text-indigo-500 focus:text-indigo-500 focus:bg-indigo-100 focus:outline-none dark:text-gray-300 dark:focus:bg-trueGray-700">
- <svg
- className="w-6 h-6 fill-current"
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 24 24">
- {open && (
- <path
- fillRule="evenodd"
- clipRule="evenodd"
- d="M18.278 16.864a1 1 0 0 1-1.414 1.414l-4.829-4.828-4.828 4.828a1 1 0 0 1-1.414-1.414l4.828-4.829-4.828-4.828a1 1 0 0 1 1.414-1.414l4.829 4.828 4.828-4.828a1 1 0 1 1 1.414 1.414l-4.828 4.829 4.828 4.828z"
- />
- )}
- {!open && (
- <path
- fillRule="evenodd"
- d="M4 5h16a1 1 0 0 1 0 2H4a1 1 0 1 1 0-2zm0 6h16a1 1 0 0 1 0 2H4a1 1 0 0 1 0-2zm0 6h16a1 1 0 0 1 0 2H4a1 1 0 0 1 0-2z"
- />
- )}
- </svg>
- </Disclosure.Button>
+ {/* Hamburger drop down menu */}
+ {!user ? (
+ <Disclosure.Button aria-label="Toggle Menu" className="px-2 py-1 ml-auto text-gray-500 rounded-md lg:hidden hover:text-indigo-500 focus:text-indigo-500 focus:bg-indigo-100 focus:outline-none dark:text-gray-300 dark:focus:bg-trueGray-700">
+ <svg className="w-6 h-6 fill-current" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
+ {open && (
+ <path fillRule="evenodd" clipRule="evenodd" d="M18.278 16.864a1 1 0 0 1-1.414 1.414l-4.829-4.828-4.828 4.828a1 1 0 0 1-1.414-1.414l4.828-4.829-4.828-4.828a1 1 0 0 1 1.414-1.414l4.829 4.828 4.828-4.828a1 1 0 1 1 1.414 1.414l-4.828 4.829 4.828 4.828z"/>
+ )}
+ {!open && (
+ <path fillRule="evenodd" d="M4 5h16a1 1 0 0 1 0 2H4a1 1 0 1 1 0-2zm0 6h16a1 1 0 0 1 0 2H4a1 1 0 0 1 0-2zm0 6h16a1 1 0 0 1 0 2H4a1 1 0 0 1 0-2z"/>
+ )}
+ </svg>
+ </Disclosure.Button>
+ ) : (
+ <Disclosure.Button aria-label="Toggle Menu" className="px-2 py-1 ml-auto text-gray-500 rounded-md lg:hidden hover:text-indigo-500 focus:text-indigo-500 focus:bg-indigo-100 focus:outline-none dark:text-gray-300 dark:focus:bg-trueGray-700">
+ <svg className="w-6 h-6 fill-current" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
+ {open && (
+ <path fillRule="evenodd" clipRule="evenodd" d="M18.278 16.864a1 1 0 0 1-1.414 1.414l-4.829-4.828-4.828 4.828a1 1 0 0 1-1.414-1.414l4.828-4.829-4.828-4.828a1 1 0 0 1 1.414-1.414l4.829 4.828 4.828-4.828a1 1 0 1 1 1.414 1.414l-4.828 4.829 4.828 4.828z"/>
+ )}
+ {!open && (
+ <path fillRule="evenodd" d="M4 5h16a1 1 0 0 1 0 2H4a1 1 0 1 1 0-2zm0 6h16a1 1 0 0 1 0 2H4a1 1 0 0 1 0-2zm0 6h16a1 1 0 0 1 0 2H4a1 1 0 0 1 0-2z"/>
+ )}
+ </svg>
+ </Disclosure.Button>
+ )}
+
- <Disclosure.Panel className="flex flex-wrap w-full my-5 lg:hidden">
- <>
- {navigation.map((item, index) => (
- <Link key={index} to="/" className="w-full px-4 py-2 -ml-4 text-gray-500 rounded-md dark:text-gray-300 hover:text-indigo-500 focus:text-indigo-500 focus:bg-indigo-100 dark:focus:bg-gray-800 focus:outline-none">
+ {/* Hamburger drop down menu options */}
+ {!user ? (
+ <Disclosure.Panel className="flex flex-wrap w-full my-5 lg:hidden">
+ {loggedOutNavigation.map((item, index) => (
+ <Link key={index} to={`/${item.toLowerCase().replace(/\s+/g, '-')}`} className="w-full px-4 py-2 -ml-4 text-gray-500 rounded-md dark:text-gray-300 hover:text-indigo-500 focus:text-indigo-500 focus:bg-indigo-100 dark:focus:bg-gray-800 focus:outline-none">
{item}
</Link>
))}
<Link to="/login" className="w-full px-6 py-2 mt-3 text-center text-white bg-indigo-600 rounded-md lg:ml-5">
Login
</Link>
- </>
- </Disclosure.Panel>
+ </Disclosure.Panel>
+ ) : (
+ <Disclosure.Panel className="w-full flex flex-wrap my-5 lg:hidden">
+ <div className="w-full border-b-2 border-gray-150 px-4 py-2 -ml-4 flex items-center">
+ <img className="w-10 h-10 rounded-full" src={logo} alt="user-img" />
+ <div className="ml-4">
+ <strong>{user.name}</strong>
+ <br />
+ <span>{user.email}</span>
+ </div>
+ </div>
+ {loggedInNavigation.map((item, index) => (
+ <Link key={index} to={`/${item.toLowerCase().replace(/\s+/g, '-')}`} className="w-full px-4 py-2 -ml-4 text-gray-500 rounded-md dark:text-gray-300 hover:text-indigo-500 focus:text-indigo-500 focus:bg-indigo-100 dark:focus:bg-gray-800 focus:outline-none">
+ {item}
+ </Link>
+ ))}
+ </Disclosure.Panel>
+ )}
</div>
</>
)}
</Disclosure>
- {/* menu */}
- <div className="hidden text-center lg:flex lg:items-center">
- <ul className="items-center justify-end flex-1 pt-6 list-none lg:pt-0 lg:flex">
- {navigation.map((menu, index) => (
- <li className="mr-3 nav__item" key={index}>
- <Link to="/" className="inline-block px-4 py-2 text-lg font-normal text-gray-800 no-underline rounded-md dark:text-gray-200 hover:text-indigo-500 focus:text-indigo-500 focus:bg-indigo-100 focus:outline-none dark:focus:bg-gray-800">
- {menu}
- </Link>
- </li>
- ))}
- </ul>
- </div>
-
- <div className="hidden mr-3 space-x-4 lg:flex nav__item">
- <Link to="/login" className="px-6 py-2 text-white bg-indigo-600 rounded-md md:ml-5">
- Login
- </Link>
- </div>
+ {/* Right side header bar */}
+ {!user ? (
+ <div className="hidden text-center lg:flex lg:items-center">
+ <ul className="items-center justify-end flex-1 pt-6 list-none lg:pt-0 lg:flex">
+ {loggedOutNavigation.map((menu, index) => (
+ <li className="mr-3 nav__item" key={index}>
+ <Link key={index} to={`/${menu.toLowerCase().replace(/\s+/g, '-')}`} className="inline-block px-4 py-2 text-lg font-normal text-gray-800 no-underline rounded-md dark:text-gray-200 hover:text-indigo-500 focus:text-indigo-500 focus:bg-indigo-100 focus:outline-none dark:focus:bg-gray-800">
+ {menu}
+ </Link>
+ </li>
+ ))}
+ </ul>
+ </div>
+ ) : (
+ <div className="hidden lg:flex lg:items-center">
+ <div className="flex items-center space-x-3">
+ <button className="w-5 h-5 text-gray-400"> <BellIcon /></button>
+ <span className="border-l border-gray-300 h-6"></span>
+ <Disclosure as="div" className="relative">
+ <Disclosure.Button as="button" aria-label="Toggle Profile Menu" className="flex items-center justify-center text-sm rounded-full focus:ring-4 focus:ring-gray-300 dark:focus:ring-gray-600">
+ <img className="w-8 h-8 rounded-full" src={logo} alt="user-img" />
+ <ChevronDownIcon className="w-4 h-4 ml-1 text-gray-400" />
+ </Disclosure.Button>
+ <Disclosure.Panel className="absolute right-0 mt-2 bg-white overflow-hidden whitespace-nowrap overflow-ellipsis divide-y divide-gray-100 rounded-lg shadow w-64 dark:bg-gray-700 dark:divide-gray-600 z-10">
+ <div className="flex items-center mb-2 mt-2">
+ <img className="w-10 h-10 rounded-full" src={logo} alt="user-img" />
+ <div className="ml-2 ,b flex flex-col">
+ <strong className="text-sm">{user.name}</strong>
+ <span className="text-xs text-gray-600">{user.email}</span>
+ </div>
+ </div>
+ <ul className="py-2 text-sm text-gray-700 dark:text-gray-200">
+ {loggedInNavigation.map((menu, index) => (
+ <li className="mr-3 nav__item" key={index}>
+ <Link key={index} to={`/${menu.toLowerCase().replace(/\s+/g, '-')}`} className="inline-block px-4 py-2 text-md font-normal text-gray-800 no-underline rounded-md dark:text-gray-200 hover:text-indigo-500 focus:text-indigo-500 focus:bg-indigo-100 focus:outline-none dark:focus:bg-gray-800">
+ {menu}
+ </Link>
+ </li>
+ ))}
+ </ul>
+ </Disclosure.Panel>
+ </Disclosure>
+ </div>
+ </div>
+ )}
</nav>
</div>
- );
-}
+ </Container>
+ )}
export default Navbar;
diff --git a/src/layouts/AuthenticatedLayout.js b/src/layouts/AuthenticatedLayout.js
new file mode 100644
index 0000000..7c39672
--- /dev/null
+++ b/src/layouts/AuthenticatedLayout.js
@@ -0,0 +1,17 @@
+import React from 'react';
+import Navbar from './components/Navbar';
+import Footer from './components/Footer';
+import PopupWidget from './components/PopupWidget';
+
+const AuthenticatedLayout = ({ children }) => {
+ return (
+ <>
+ <Navbar />
+ {children} {/* This will render the content */}
+ <Footer />
+ <PopupWidget />
+ </>
+ );
+};
+
+export default AuthenticatedLayout; \ No newline at end of file
diff --git a/src/layouts/GridLayout.js b/src/layouts/GridLayout.js
new file mode 100644
index 0000000..a96b351
--- /dev/null
+++ b/src/layouts/GridLayout.js
@@ -0,0 +1,72 @@
+import React from "react";
+import {
+ HomeIcon,
+ EnvelopeIcon,
+ UserIcon,
+ BuildingStorefrontIcon,
+ BriefcaseIcon,
+} from "@heroicons/react/24/outline"
+
+const GridLayout = ({ children }) => {
+ return (
+ <div className="container px-8 mx-auto grid grid-cols-[96px,1fr,96px] gap-10">
+
+ {/*Left column - sticky */}
+ <div className="self-start sticky top-0 col-span-1 pt-8 ">
+ <nav className="p-2 ">
+ <a href="/" className="flex items-center flex-col mb-4 text-trueGray-500 hover:text-indigo-500 focus:text-indigo-500 focus:bg-indigo-100">
+ <HomeIcon className="w-8 h-8" />
+ <button
+ rel="noopener"
+ className="mb-1 text-xs font-light">
+ Home
+ </button>
+ </a>
+ <a href="/profile" className="flex items-center flex-col mb-4 text-trueGray-500 hover:text-indigo-500 focus:text-indigo-500 focus:bg-indigo-100">
+ <UserIcon className="w-8 h-8" />
+ <button
+ rel="noopener"
+ className="mb-1 text-xs font-light">
+ Profile
+ </button>
+ </a>
+ <a href="/volunteer" className="flex items-center flex-col mb-4 text-trueGray-500 hover:text-indigo-500 focus:text-indigo-500 focus:bg-indigo-100">
+ <BriefcaseIcon className="w-8 h-8" />
+ <button
+ rel="noopener"
+ className="mb-1 text-xs font-light whitespace-nowrap">
+ Find Opportunities
+ </button>
+ </a>
+ <a href="/volunteer" className="flex items-center flex-col mb-4 text-trueGray-500 hover:text-indigo-500 focus:text-indigo-500 focus:bg-indigo-100">
+ <BuildingStorefrontIcon className="w-8 h-8" />
+ <button
+ rel="noopener"
+ className="mb-1 text-xs font-light whitespace-nowrap">
+ Recruit Volunteers
+ </button>
+ </a>
+ <a href="/" className="flex items-center flex-col mb-4 text-trueGray-500 hover:text-indigo-500 focus:text-indigo-500 focus:bg-indigo-100">
+ <EnvelopeIcon className="w-8 h-8 " />
+ <button
+ rel="noopener"
+ className="mb-1 text-xs font-light">
+ Messages
+ </button>
+ </a>
+ </nav>
+ </div>
+
+ {/*Middle column */}
+ <div className="overflow-auto bg-blue-300 h-screen">01
+ <div>01 asdfasdf</div>
+ </div>
+
+ {/*Right column */}
+ <div className="bg-green-300">01</div>
+ {children}
+ </div>
+ );
+}
+
+export default GridLayout; \ No newline at end of file
diff --git a/src/pages/Dashboard.js b/src/pages/Dashboard.js
new file mode 100644
index 0000000..c7f136d
--- /dev/null
+++ b/src/pages/Dashboard.js
@@ -0,0 +1,12 @@
+import Sidebar from "../components/Sidebar";
+
+const Dashboard = () => {
+ return (
+ <>
+ <Sidebar />
+ </>
+ );
+}
+
+
+export default Dashboard; \ No newline at end of file
diff --git a/src/pages/Login.js b/src/pages/Login.js
index 700de0d..2aa90f5 100644
--- a/src/pages/Login.js
+++ b/src/pages/Login.js
@@ -1,20 +1,73 @@
-import React from "react";
+import React, {useContext, useState} from "react";
import FlexibleForm from "../components/FlexibleForm";
import benefitTwoImg from "../assets/img/benefit-two.png";
+import { AuthContext } from '../providers/AuthContext';
+import {useNavigate} from "react-router-dom";
const Login = () => {
+ const navigate = useNavigate();
+ const { login } = useContext(AuthContext);
+ const [formData, setFormData] = useState({
+ email: "",
+ password: "",
+ });
+
+ const handleChange = (e) => {
+ const { name, value } = e.target;
+ setFormData((prevData) => ({
+ ...prevData,
+ [name]: value,
+ }));
+ };
+
+ const handleSubmit = async (event) => {
+ event.preventDefault();
+ const { email, password } = formData;
+ const basicAuth = btoa(`${email}:${password}`)
+
+ try {
+ const response = await fetch(process.env.REACT_APP_LOGIN_ROUTE, {
+ method: "GET",
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Authorization': `Basic ${basicAuth}`,
+ },
+ });
+ if (response.ok) {
+ const jwt = await response.text();
+ const tokenParts = jwt.split(".")
+ const decodedPayload = atob(tokenParts[1]);
+ const payload = JSON.parse(decodedPayload);
+ const userId = payload.sub;
+
+ const userDetailsResponse = await fetch(process.env.REACT_APP_REGISTER_ROUTE + '/' + userId , {
+ method: "GET",
+ });
+
+ if (userDetailsResponse.ok) {
+ const userDetails = await userDetailsResponse.json();
+ login(userDetails, jwt);
+ navigate("/")
+
+ } else { console.error("Failed to fetch details") }
+
+ } else { console.error("Login failed") }
+
+ } catch (error) {
+ console.error('Error submitting form:', error);
+ }
+ }
+
return (
<>
<FlexibleForm
- onSuccess={''}
+ onFormSubmit={handleSubmit}
data={{
image: benefitTwoImg,
title: "Sign in to your account",
subtitle: "Sign in please",
- formAction: "/login",
- formMethod: "POST",
formFields: [
- { label: "Email address", name: "email", type: "email", autoComplete: "email", required: true },
- { label: "Password", name: "password", type: "password", autoComplete: "current-password", required: true },
+ { label: "Email address", name: "email", type: "email", autoComplete: "email", required: true, value: formData.email, onChange: handleChange },
+ { label: "Password", name: "password", type: "password", autoComplete: "current-password", required: true, value: formData.password, onChange: handleChange },
],
ctaText: "Login",
ctaLink: { text: "Don't have an account?", linkText: "Create an account instead!", url: "/sign-up" },
diff --git a/src/pages/SignUp.js b/src/pages/SignUp.js
index 038b75c..11ab367 100644
--- a/src/pages/SignUp.js
+++ b/src/pages/SignUp.js
@@ -1,23 +1,61 @@
-import React from "react";
+import React, {useState} from "react";
+import { useNavigate } from "react-router-dom";
import FlexibleForm from "../components/FlexibleForm";
import benefitTwoImg from "../assets/img/benefit-two.png";
const SignUp = () => {
+ const navigate = useNavigate();
+
+ const [formData, setFormData] = useState({
+ name: "",
+ email: "",
+ password: "",
+ });
+
+ const handleChange = (e) => {
+ const { name, value } = e.target;
+ setFormData((prevData) => ({
+ ...prevData,
+ [name]: value,
+ }));
+ };
+
+
+ const handleSubmit = async (event) => {
+ event.preventDefault();
+
+ try {
+ const response = await fetch(process.env.REACT_APP_REGISTER_ROUTE, {
+ method: "POST",
+ body: JSON.stringify(formData),
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ });
+
+ if (!response.ok) {
+ throw new Error(await response.text());
+ }
+
+ console.log('Form submitted successfully');
+ navigate("/login");
+ } catch (error) {
+ console.error('Error submitting form:', error);
+ }
+ }
return (
<>
<FlexibleForm
- onSuccess={''}
+ onFormSubmit={handleSubmit}
data={{
image: benefitTwoImg,
title: "Create your account",
subtitle: "maybe edit this text hmm",
- formAction: "/register",
- formMethod: "POST",
formFields: [
- { label: "Full Name", name: "name", type: "text", autoComplete: "name", required: true },
- { label: "Email address", name: "email", type: "email", autoComplete: "email", required: true },
- { label: "Password", name: "password", type: "password", autoComplete: "new-password", required: true },
+ { label: "Full Name", name: "name", type: "text", autoComplete: "name", required: true, value: formData.name, onChange: handleChange },
+ { label: "Email address", name: "email", type: "email", autoComplete: "email", required: true, value: formData.email, onChange: handleChange },
+ { label: "Password", name: "password", type: "password", autoComplete: "new-password", required: true, value: formData.password, onChange: handleChange },
],
ctaText: "Create Account",
ctaLink: { text: "Already have an account?", linkText: "Log in instead!", url: "/login" },
diff --git a/src/providers/AuthContext.js b/src/providers/AuthContext.js
new file mode 100644
index 0000000..a32fb01
--- /dev/null
+++ b/src/providers/AuthContext.js
@@ -0,0 +1,58 @@
+import React, { createContext, useEffect, useState } from 'react';
+
+export const AuthContext = createContext();
+
+export const AuthProvider = ({ children }) => {
+ const [user, setUser] = useState(null);
+ const [refreshToken, setRefreshToken] = useState(null);
+ const [loading, setLoading] = useState(true);
+
+ useEffect(() => {
+ const initializeAuth = async () => {
+ try {
+ const storedUser = localStorage.getItem('user');
+ const storedRefreshToken = localStorage.getItem('refreshToken');
+ if (storedUser && storedRefreshToken) {
+ setUser(JSON.parse(storedUser));
+ setRefreshToken(storedRefreshToken);
+ }
+ } catch (error) {
+ console.error('Error initializing auth:', error);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ initializeAuth();
+ }, []);
+
+ const login = (userData, token) => {
+ setUser(userData);
+ setRefreshToken(token);
+ localStorage.setItem('user', JSON.stringify(userData));
+ localStorage.setItem('refreshToken', token);
+ };
+
+ const logout = () => {
+ setUser(null);
+ setRefreshToken(null);
+ localStorage.removeItem('user');
+ localStorage.removeItem('refreshToken');
+ };
+
+ const authContextValue = {
+ user,
+ refreshToken,
+ login,
+ logout,
+ };
+
+ // Maybe make a loading screen animation/component to use?
+ return (
+ <AuthContext.Provider value={authContextValue}>
+ {loading ? <div></div> : children}
+ </AuthContext.Provider>
+ );
+};
+
+export default AuthProvider;