Skip to content

authentication added #9

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 16 additions & 10 deletions frontend/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,33 +9,39 @@ import ViewPatientList from './pages/ViewPatientList/ViewPatientList'
import Tutorials from './pages/Tutorials/Tutorials'
import CreatePlan from './pages/CreatePlan/CreatePlan'
import ViewPlan from './pages/ViewPlan/ViewPlan'
import ProtectedRoute from './pages/ProtectedRoute'
import RunModel from './pages/RunModel/RunModel'
import './App.css'

import Login from './pages/Login'
import Register from './pages/Register'

import ContactTherapist from './pages/ContactTherapist/ContactTherapist'
import { AuthProvider } from './contexts/authContext'

export default function App() {
return (
<Router>
// <Router>
<AuthProvider>
<Routes>
{/* open routes */}
<Route path='/login' element={<Login />} />
<Route path='/register' element={<Register />} />

<Route path='/' element={<Home />}/>
<Route path='/start' element={<Yoga />} />
<Route path='/test' element={<Yoga1 />} />
<Route path='/tutorials' element={<Tutorials />} />
<Route path='/create-plan' element={<CreatePlan />} />
<Route path='/view-plan' element={<ViewPlan />} />
<Route path="/run_model" element={<RunModel />} />
<Route path="/contact-therapist" element={<ContactTherapist />} />
<Route path="/view-patient-list" element={<ViewPatientList />} />

{/* routes that need authentication */}
<Route path='/start' element={<ProtectedRoute><Yoga /></ProtectedRoute>} />
<Route path='/tutorials' element={<ProtectedRoute><Tutorials /></ProtectedRoute>} />
<Route path='/create-plan' element={<ProtectedRoute><CreatePlan /></ProtectedRoute>} />
<Route path='/view-plan' element={ <ProtectedRoute><ViewPlan /></ProtectedRoute> } />
<Route path="/run_model" element={<ProtectedRoute><RunModel /></ProtectedRoute>} />
<Route path="/contact-therapist" element={<ProtectedRoute><ContactTherapist /></ProtectedRoute>} />
<Route path="/view-patient-list" element={<ProtectedRoute><ViewPatientList /></ProtectedRoute>} />

</Routes>
</Router>
</AuthProvider>
//</Router>
)
}

Expand Down
11 changes: 7 additions & 4 deletions frontend/src/components/Sidebar.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@ import React, { useEffect, useState } from 'react';
import { LuLayoutDashboard } from 'react-icons/lu';
import { RiAddFill, RiLogoutCircleLine } from 'react-icons/ri';
import { TbBulb } from 'react-icons/tb';
import { Link } from 'react-router-dom';
import { Link, useNavigate } from 'react-router-dom';

import Cookies from 'universal-cookie';
import { auth } from '../firebase/firebase';


export default function Sidebar({ poseList, currentPose, setCurrentPose }) {
const cookie = new Cookies();
const [isDoc, setIsDoc] = useState(false);

const navigate = useNavigate();

useEffect(() => {
const email = cookie.get('email');
if (email.includes('doc')) {
Expand Down Expand Up @@ -45,10 +48,10 @@ return (
</Link>
</li>
<li className='mb-4'>
<Link to='/' className='flex items-center border-2 border-slate-400 rounded-lg py-2 px-4 hover:bg-slate-700 hover:border-slate-600 hover:text-white'>
<button onClick={()=>{ auth.signOut(); navigate('/'); }} className='flex w-full items-center border-2 border-slate-400 rounded-lg py-2 px-4 hover:bg-slate-700 hover:border-slate-600 hover:text-white'>
<RiLogoutCircleLine className='mr-2' />
<span>Logout</span>
</Link>
Logout
</button>
</li>
</ul>
</div>
Expand Down
39 changes: 39 additions & 0 deletions frontend/src/contexts/authContext/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React, { useState, useEffect, useContext } from "react";
import { auth } from "../../firebase/firebase";
import { onAuthStateChanged } from "firebase/auth";

const AuthContext = React.createContext();

export function useAuth(){
return useContext(AuthContext);
}

export function AuthProvider({ children}){
const [currentUser, setCurrentUser] = useState(null);
const [userLoggedIn, setUserLoggedIn] = useState(false);
const [loading, setLoading] = useState(true);

async function initializeUser(user){
if(user){
setCurrentUser(user);
setUserLoggedIn(true);
}else{
setCurrentUser(null);
setUserLoggedIn(false);
}
setLoading(false);
}

useEffect(()=>{
const unsubscribe = onAuthStateChanged(auth, initializeUser);
return unsubscribe;
})

const value = { currentUser, userLoggedIn, loading };

return(
<AuthContext.Provider value={value}>
{!loading && children}
</AuthContext.Provider>
)
}
14 changes: 14 additions & 0 deletions frontend/src/firebase/auth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { createUserWithEmailAndPassword, signInWithEmailAndPassword } from "firebase/auth";
import { auth } from "./firebase";

export const doCreateUserWithEmailAndPassword = async (email, password) => {
return createUserWithEmailAndPassword(auth, email, password);
};

export const doSignInWithEmailAndPassword = async (email, password) => {
return signInWithEmailAndPassword(auth, email, password);
};

export const doSignOut = async () => {
return auth.signOut();
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ const firebaseConfig = {
appId: "1:670415538010:web:4a424d581b2f8281c99563",
measurementId: "G-2R1PB6BVDQ"
};


// Initialize Firebase
const app = initializeApp(firebaseConfig)
Expand Down
8 changes: 6 additions & 2 deletions frontend/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@ import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { BrowserRouter } from 'react-router-dom';

ReactDOM.render(
<React.StrictMode>
// <React.StrictMode>
// <App />
// </React.StrictMode>,
<BrowserRouter>
<App />
</React.StrictMode>,
</BrowserRouter>,
document.getElementById('root')
);

Expand Down
16 changes: 5 additions & 11 deletions frontend/src/pages/CreatePlan/CreatePlan.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useState, useEffect } from 'react';
import { db, auth } from '../../firebase'; // Adjust the import path as needed
import { db, auth } from '../../firebase/firebase'; // Adjust the import path as needed
import { collection, addDoc, doc, updateDoc, getDoc } from 'firebase/firestore';
import { onAuthStateChanged } from 'firebase/auth';
import { exercises } from '../../utils/data';
Expand All @@ -10,6 +10,7 @@ import { div } from '@tensorflow/tfjs';
import { MdDelete } from 'react-icons/md';

import Sidebar from '../../components/Sidebar';
import { useAuth } from '../../contexts/authContext';



Expand All @@ -20,17 +21,10 @@ function CreatePlan() {
const [planType, setPlanType] = useState('neck');
const [selectedExercises, setSelectedExercises] = useState([]);
const [showExerciseList, setShowExerciseList] = useState(false);
const [user, setUser] = useState(null);
const [successMessage, setSuccessMessage] = useState('');
const [errorMessage, setErrorMessage] = useState('');
const navigate = useNavigate();

useEffect(() => {
const unsubscribe = onAuthStateChanged(auth, (currentUser) => {
setUser(currentUser);
});
return () => unsubscribe();
}, []);
const { currentUser, userLoggedIn } = useAuth();

const handleAddExercise = (exercise) => {
setSelectedExercises([...selectedExercises, { ...exercise, duration: 0 }]);
Expand All @@ -50,7 +44,7 @@ function CreatePlan() {
};

const handleSubmit = async () => {
if (!user) {
if (!userLoggedIn) {
console.log('User not authenticated');
return;
}
Expand All @@ -62,7 +56,7 @@ function CreatePlan() {

try {
const docRef = await addDoc(collection(db, 'plans'), {
userId: user.uid,
userId: currentUser.uid,
planName,
planType,
exercises: selectedExercises,
Expand Down
59 changes: 45 additions & 14 deletions frontend/src/pages/Login.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,52 @@
// src/Login.js
import React, { useState } from "react";
import { signInWithEmailAndPassword } from "firebase/auth";
import { auth } from "../firebase";
import heroImage from '../utils/images/landing_page_hero_image.svg';
import { Link, useNavigate } from 'react-router-dom';
import { Link, Navigate, useNavigate } from 'react-router-dom';
import Cookies from "universal-cookie";
import { doSignInWithEmailAndPassword } from "../firebase/auth";
import { useAuth } from "../contexts/authContext";
import { IoMdClose, IoMdWarning } from "react-icons/io";
import { AiOutlineLoading3Quarters } from "react-icons/ai";

const cookie = new Cookies();

function Login() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [errorMessage, setErrorMessage] = useState("");
const [isLoggingIn, setIsLoggingIn] = useState(false);

const { userLoggedIn } = useAuth();

const navigate = useNavigate();

const handleLogin = async (e) => {
e.preventDefault();
try {
await signInWithEmailAndPassword(auth, email, password);
cookie.set('email', email, { path: '/' });
navigate('/view-plan');
} catch (error) {
alert(error.message);
if(!isLoggingIn){
try {
setIsLoggingIn(true);
await doSignInWithEmailAndPassword(email, password);
cookie.set('email', email, { path: '/' });
navigate('/view-plan');
} catch (error) {
// alert(error.message);
if(error.code == 'auth/invalid-credential'){
setErrorMessage("Invalid Credentials. Try again.");
setPassword("");
}else{
setErrorMessage(error.message);
}
} finally{
setIsLoggingIn(false);
}
}
};

return (
<div className="w-full h-screen flex justify-center items-center bg-slate-200">
<div className="md:w-[60%] w-[90%] h-[70vh] rounded-xl overflow-hidden bg-slate-500 grid grid-cols-12 shadow-xl">
{ userLoggedIn && <Navigate to='/view-plan' /> }
<div className="lg:w-[60%] md:w-[80%] w-[90%] h-[70vh] rounded-xl overflow-hidden bg-slate-500 grid grid-cols-12 shadow-xl relative">
<Link to='/' className="absolute top-2 left-2 p-2 bg-slate-100 rounded-full cursor-pointer hover:text-slate-600"><IoMdClose /> </Link>
<div className="bg-white h-full px-16 py-4 md:col-span-7 hidden md:block text-center">
<img src={heroImage} alt="hero image" width={300} className="pt-10 pb-6 mx-auto"/>
<Link to='/' className="text-3xl hover:text-black font-bold">PosturePusle</Link>
Expand All @@ -40,19 +60,30 @@ function Login() {
type="email"
placeholder="Email"
value={email}
onChange={(e) => setEmail(e.target.value)}
onChange={(e) => {setEmail(e.target.value); setErrorMessage("");}}
className="w-full px-3 py-2 m-1 rounded-lg"
required
/>
<input
type="password"
placeholder="Password"
value={password}
onChange={(e) => setPassword(e.target.value)}
onChange={(e) => {setPassword(e.target.value); setErrorMessage("");}}
className="w-full px-3 py-2 m-1 rounded-lg"
required
/>
<button type="submit" className="w-full px-3 py-2 m-1 rounded-lg bg-slate-700 text-white font-bold mt-3">Login</button>
{
errorMessage &&
<div className="text-white flex items-center gap-1 ml-2 mt-2"><IoMdWarning className="inline" /> {errorMessage}</div>
}
{
!isLoggingIn ?
<button type="submit" className="w-full px-3 py-2 m-1 rounded-lg bg-slate-700 text-white font-bold mt-3" disabled={isLoggingIn}>Login</button>
:
<div className="w-full px-3 py-2 m-1 rounded-lg bg-slate-700 text-white font-bold mt-3 flex justify-center"><AiOutlineLoading3Quarters className="animate-spin my-1" /></div>
}
<p className="text-center mt-2 text-sm">
Don't have an account? <a href="/register" className="text-slate-200 underline hover:text-slate-400">sign up</a>
Don't have an account? <Link to="/register" className="text-slate-200 underline hover:text-slate-400">sign up</Link>
</p>
</form>
</div>
Expand Down
12 changes: 12 additions & 0 deletions frontend/src/pages/ProtectedRoute.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from "react";
import { useAuth } from "../contexts/authContext";
import { Navigate } from "react-router-dom";

export default function ProtectedRoute({ children }){
const { userLoggedIn } = useAuth();

if(userLoggedIn){
return children;
}
return <Navigate to = "/login" replace={true} />;
}
Loading