Skip to content
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

Authentication #19

Merged
merged 4 commits into from
Jan 19, 2023
Merged
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
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