Skip to content

Commit

Permalink
Merge pull request #19 from kanishbodhwani/dev_13
Browse files Browse the repository at this point in the history
Authentication
  • Loading branch information
adarshanand67 authored Jan 19, 2023
2 parents ddec8ec + f2f6597 commit eab5369
Show file tree
Hide file tree
Showing 13 changed files with 212 additions and 85 deletions.
8 changes: 4 additions & 4 deletions src/common/components/Profile/Profile.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,10 @@
color: #ffffff;
}

.rank > div > span {
font-size: 30px;
margin-right: -5px;
font-weight: bold;
.rank > div {
display: flex;
flex-direction: column;
margin-left: 15px;
}

.rank > div {
Expand Down
30 changes: 26 additions & 4 deletions src/common/components/Profile/Profile.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Bar, Pie } from "react-chartjs-2";
import styles from "./Profile.module.css";
import { faker } from '@faker-js/faker';
import useUser from "../../../hooks/use-user";

import {
Chart as ChartJS,
Expand All @@ -12,6 +13,9 @@ import {
Title,
ArcElement,
} from 'chart.js';
import { doesUsernameExists } from "../../../services/firebase";
import { useEffect, useState } from "react";


ChartJS.register(
CategoryScale,
Expand Down Expand Up @@ -73,11 +77,26 @@ export const data = {
};

export default function Profile() {
const [userData, setUserData] = useState<any>(null);

const user = useUser();
console.log(user);

useEffect( () => {
if(user.user?.username) {
(async () => {
const codeforcesData = await doesUsernameExists(user.user?.username);
setUserData(codeforcesData?.result[0]);
console.log(codeforcesData);
})();
}
}, [user.user]);

return (
<div className={styles.profile}>
<div className={styles.profile_stats}>
<div className={styles.profile_user}>
<h1> Hey Kanish </h1>
<h1> Hey {user.user?.fullname.split(" ")[0]} </h1>
<span> Hope you are doing well! </span>
</div>
<div className={styles.bar_chart}>
Expand All @@ -87,15 +106,18 @@ export default function Profile() {
<div className={styles.sidebar}>
<div className={styles.rank}>
<Pie data={data} />
<div> <span> 34 </span> Rank </div>
<div>
<span> Ranking </span>
<span> {userData?.rank ? userData?.rank : "Do contests to improve your ranking"} </span>
</div>
</div>
<div className={styles.user}>
<div className={styles.followers}>
<span> 10 </span>
<span> {user.user?.followers ? user.user?.followers.length : "0"}</span>
<span> followers </span>
</div>
<div className={styles.following}>
<span> 20 </span>
<span> {user.user?.following ? user.user?.following.length : "0"} </span>
<span> following </span>
</div>
</div>
Expand Down
48 changes: 24 additions & 24 deletions src/hooks/use-auth-listener.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,31 @@ import { onAuthStateChanged } from "firebase/auth";
// import { User } from "../types/user";s
import { auth } from "../lib/firebase";

type userObj = string | null;
let userObj = '';
// type userObj = string | null;
// let userObj = '';

const useAuthListener = () => {
const [user, setUser] = useState(userObj !== null ? JSON.parse(userObj || '{}') : null);
useEffect(() => {
if(typeof window !== undefined) {
userObj = localStorage.getItem('authUser')!;
}
const listener = onAuthStateChanged(auth, (authUser) => {
if(authUser) {
localStorage.setItem("authUser", JSON.stringify(authUser));
setUser(authUser);
} else {
localStorage.removeItem("authUser");
setUser(null);
}
});
// const useAuthListener = () => {
// const [user, setUser] = useState(userObj !== null ? JSON.parse(userObj || '{}') : null);
// useEffect(() => {
// if(typeof window !== undefined) {
// userObj = localStorage.getItem('authUser')!;
// }
// const listener = onAuthStateChanged(auth, (authUser) => {
// if(authUser) {
// localStorage.setItem("authUser", JSON.stringify(authUser));
// setUser(authUser);
// } else {
// localStorage.removeItem("authUser");
// setUser(null);
// }
// });

return () => {
listener();
}
}, [auth, onAuthStateChanged]);
// return () => {
// listener();
// }
// }, [auth, onAuthStateChanged]);

return { user };
};
// return { user };
// };

export default useAuthListener;
// export default useAuthListener;
22 changes: 22 additions & 0 deletions src/hooks/use-user.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { useState, useEffect, useContext } from "react";
import UserContext from "../context/user";
import { getUserByUserId } from "../services/firebase";

export default function useUser() {
const [activeUser, setAvtiveUser] = useState();
const user = useContext(UserContext);

useEffect(() => {
async function getUserObjByUserId() {
// we need a func that gets user based on the id
const [response] = await getUserByUserId(user.uid);
setAvtiveUser(response);
}
if (user?.uid) {
getUserObjByUserId();
}
;
}, [user]);

return { user: activeUser };
}
24 changes: 21 additions & 3 deletions src/pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,35 @@
import { useState, useEffect } from 'react';
import '../styles/globals.css'
import type { AppProps } from 'next/app'
import { Poppins } from "@next/font/google";
import * as ROUTES from "../constants/routes";
import UserContext from '../context/user';
import useAuthListener from '../hooks/use-auth-listener';
import {User} from "../types/user";
import { onAuthStateChanged } from 'firebase/auth';
import { auth } from '../lib/firebase';
import { useRouter }from 'next/router';

const poppins = Poppins({
weight: "500",
});

export default function App({ Component, pageProps }: AppProps) {
const { user } = useAuthListener();

const [user, setUser] = useState(null);
const router = useRouter();

useEffect(() => {
onAuthStateChanged(auth, (authUser: any) => {
if(authUser) {
localStorage.setItem("authUser", JSON.stringify(authUser));
setUser(authUser);
} else {
localStorage.removeItem("authUser");
setUser(null);
router.push(ROUTES.SIGNUP);
}
})
}, []);

return (
<>
<style jsx global>{`
Expand Down
2 changes: 1 addition & 1 deletion src/pages/dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ export default function dashboard() {
<MainMenu />
</div>
)
}
}
17 changes: 12 additions & 5 deletions src/pages/login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { HiMail } from "react-icons/hi";
import { RiLockPasswordFill } from "react-icons/ri";
import { signInWithEmailAndPassword } from "firebase/auth";
import { auth } from "../lib/firebase";
// import { signupWithGoogle } from "../services/firebase";
import { signupWithGoogle } from "../services/firebase";

export default function Login() {
const router = useRouter();
Expand All @@ -25,7 +25,7 @@ export default function Login() {
signInWithEmailAndPassword(auth, email, password)
.then(userCred => {
console.log(userCred);
router.push("/login/username");
router.push(ROUTES.DASHBOARD);
})
.catch(err => {
console.error(err);
Expand All @@ -37,6 +37,13 @@ export default function Login() {
}
}

const googleSignup = async () => {
const user = await signupWithGoogle();
if(user !== null) {
router.push(ROUTES.DASHBOARD);
}
}

useEffect(() => {
document.title = "Canonforces Login"
}, []);
Expand All @@ -54,7 +61,7 @@ export default function Login() {
<div className={`${styles.login__form} w-6/12 flex flex-col items-center justify-center`}>
<h3> Welcome Back! </h3>
<p> Lorem Ipsum is simply dummy text of the printing and typesetting industry. </p>

{error && <p className="mb-4 text-xs text-read-primary">{error} </p>}
<form onSubmit={(e) => handleLogin(e)} className={styles.form} method="POST">
<div className="flex flex-col">
<div className={styles.form__credentials}>
Expand All @@ -81,8 +88,8 @@ export default function Login() {
</div>
</div>
<div className={styles.form__buttons}>
<button className={styles.login__button} disabled={isInvalid} type="submit"> Login </button>
<button className={styles.google__button} onClick={() => signupWithGoogle(email)} > <FcGoogle size={"1.6em"} className={styles.google__icon}/> <span> Sign in with Google </span> </button>
<button className={`${styles.login__button} ${isInvalid ? styles.invalid : ""}`} disabled={isInvalid} type="submit"> Login </button>
<button className={styles.google__button} onClick={() => googleSignup()} > <FcGoogle size={"1.6em"} className={styles.google__icon}/> <span> Sign in with Google </span> </button>
</div>
<div className={styles.login__text}>
<p> Already a user ? <Link href={ROUTES.SIGNUP}> Signup </Link> </p>
Expand Down
69 changes: 58 additions & 11 deletions src/pages/signup/index.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,31 @@
import { useState } from "react";
import Link from "next/link";
import Image from "next/image";
import { useRouter } from "next/router";
import styles from "../../styles/Signup.module.css";
import * as ROUTES from "../../constants/routes";
import { FcGoogle } from "react-icons/fc";
import { HiMail } from "react-icons/hi";
import { RiLockPasswordFill } from "react-icons/ri";
import { BsPatchExclamation, BsPatchCheck} from "react-icons/bs";
import { doesUsernameExists } from "../../services/firebase";
import { doesUsernameExists , signupWithGoogle} from "../../services/firebase";
import { createUserWithEmailAndPassword } from "firebase/auth";
import { auth, db } from "../../lib/firebase";
import { addDoc, collection, setDoc } from "firebase/firestore";

export default function Signup() {
const router = useRouter();

const [username, setUsername] = useState("");
const [fullname, setFullname] = useState("");
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState("");

const isInvalid = password === "" || email === "" || username === "";

const handleSignup = async (e: any) => {
e.preventDefault();

const usernameExists = await doesUsernameExists(username);
if(usernameExists !== null) {
try {
Expand All @@ -38,22 +41,36 @@ export default function Signup() {
})
.then((userRef) => {
console.log(userRef);
console.log(user);
setDoc(userRef, {userId: user.user.uid}, {merge: true})
.then(() => {
const currentUser: any = auth.currentUser;
if(currentUser) {
currentUser.displayName = username;
}
// navigate the user
router.push(ROUTES.DASHBOARD);
});
});
})
}).catch(err => {
console.error(err);
setError(err.message);
})
} catch (err: any) {
setFullname('');
setEmail("");
setEmail('');
setPassword('');
setError(err.message);
}
} else {
setError('Username does not exists on codeforces');
setUsername('');
}
}

const googleSignup = async () => {
const user = await signupWithGoogle();
if(user !== null) {
router.push(ROUTES.DASHBOARD);
}
}

Expand All @@ -63,27 +80,57 @@ export default function Signup() {
<div className={`${styles.signup__form} w-6/12 flex flex-col items-center justify-center`}>
<h3> Welcome to Canonforces! </h3>
<p> Lorem Ipsum is simply dummy text of the printing and typesetting industry. printing and typesetting industry. </p>
<form className={styles.form} action="">
{error && <p className="mb-4 text-xs text-read-primary">{error} </p>}
<form className={styles.form} method="POST">
<div className="flex flex-col">
<div className={styles.form__credentials}>
<label className={styles.username__label}>Enter your Codeforces username </label>
<div className={styles.input}>
<input className="shadow appearance-none text-sm rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" placeholder="Username"/>
<input
className="shadow appearance-none text-sm rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
placeholder="Username"
type="text"
onChange={({target}) => setUsername(target.value)}
value={username}
name="username"
/>
{username ? <BsPatchCheck className={styles.check__icon}/> : <BsPatchExclamation className={styles.exclaimation__icon}/>}
</div>
<div className={styles.input}>
<input className="shadow appearance-none text-sm rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" placeholder="Email"/>
<input className="shadow appearance-none text-sm rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
placeholder="Fullname"
type="text"
onChange={({target}) => setFullname(target.value)}
value={fullname}
name="fullname"
/>
<HiMail className={styles.mail__icon}/>
</div>
<div className={styles.input}>
<input className="shadow appearance-none text-sm rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
placeholder="Email"
type="email"
onChange={({target}) => setEmail(target.value)}
value={email}
name="email"
/>
<HiMail className={styles.mail__icon}/>
</div>
<div className={styles.input}>
<input className="shadow appearance-none text-sm rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" id="password" name="password" placeholder="Password"/>
<input
className="shadow appearance-none text-sm rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
name="password"
placeholder="Password"
value={password}
onChange={({target}) => setPassword(target.value)}
/>
<RiLockPasswordFill className={styles.lock__icon}/>
</div>
</div>
</div>
<div className={styles.form__buttons}>
<button className={styles.signup__button} onClick={(e) => handleSignup(e)}> Signup </button>
<button className={styles.google__button}> <FcGoogle size={"1.6em"} className={styles.google__icon}/> <span> Sign in with Google </span> </button>
<button className={`${styles.signup__button} ${isInvalid ? styles.invalid : ""}`} disabled={isInvalid} onClick={(e) => handleSignup(e)}> Signup </button>
<button className={styles.google__button} onClick={() => googleSignup()}> <FcGoogle size={"1.6em"} className={styles.google__icon}/> <span> Sign in with Google </span> </button>
</div>
<div className={styles.signup__text}>
<p> Already a user ? <Link href={ROUTES.LOGIN}> Login </Link> </p>
Expand Down
Loading

0 comments on commit eab5369

Please sign in to comment.