diff --git a/hooks/useAuth.ts b/hooks/useAuth.ts deleted file mode 100644 index 5419a8c..0000000 --- a/hooks/useAuth.ts +++ /dev/null @@ -1,111 +0,0 @@ -import { AuthenticationContext } from '@/app/context/AuthContext'; -import axios from 'axios'; -import { deleteCookie } from 'cookies-next'; -import { useContext } from 'react'; - -const useAuth = () => { - const { setAuthState } = useContext(AuthenticationContext); - const signIn = async ( - { - email, - password, - }: { - email: string; - password: string; - }, - handleClose: () => void - ) => { - setAuthState({ - data: null, - error: null, - loading: true, - }); - try { - const response = await axios.post( - 'http://localhost:3000/api/auth/signin', - { - email, - password, - } - ); - setAuthState({ - data: response.data, - error: null, - loading: false, - }); - handleClose(); - } catch (error: any) { - setAuthState({ - data: null, - error: error.response.data.errorMessage, - loading: false, - }); - } - }; - const signUp = async ( - { - email, - password, - firstName, - lastName, - city, - phone, - }: { - email: string; - password: string; - firstName: string; - lastName: string; - city: string; - phone: string; - }, - handleClose: () => void - ) => { - setAuthState({ - data: null, - error: null, - loading: true, - }); - try { - const response = await axios.post( - 'http://localhost:3000/api/auth/signup', - { - email, - password, - firstName, - lastName, - city, - phone, - } - ); - setAuthState({ - data: response.data, - error: null, - loading: false, - }); - handleClose(); - } catch (error: any) { - setAuthState({ - data: null, - error: error.response.data.errorMessage, - loading: false, - }); - } - }; - - const signOut = () => { - deleteCookie('jwt'); - setAuthState({ - data: null, - loading: false, - error: null, - }); - }; - - return { - signIn, - signUp, - signOut, - }; -}; - -export default useAuth; diff --git a/package-lock.json b/package-lock.json index 7008b49..3ec822e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,6 +27,7 @@ "jose": "^4.14.4", "jsonwebtoken": "^9.0.1", "next": "13.4.2", + "next-auth": "^4.23.1", "postcss": "8.4.23", "prisma": "^5.1.1", "react": "18.2.0", @@ -1001,6 +1002,14 @@ "node": ">= 8" } }, + "node_modules/@panva/hkdf": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@panva/hkdf/-/hkdf-1.1.1.tgz", + "integrity": "sha512-dhPeilub1NuIG0X5Kvhh9lH4iW3ZsHlnzwgwbOlgwQ2wG1IqFzsgHqmKPk3WzsdWAeaxKJxgM0+W433RmN45GA==", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/@pkgr/utils": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.4.0.tgz", @@ -4144,6 +4153,41 @@ } } }, + "node_modules/next-auth": { + "version": "4.23.1", + "resolved": "https://registry.npmjs.org/next-auth/-/next-auth-4.23.1.tgz", + "integrity": "sha512-mL083z8KgRtlrIV6CDca2H1kduWJuK/3pTS0Fe2og15KOm4v2kkLGdSDfc2g+019aEBrJUT0pPW2Xx42ImN1WA==", + "dependencies": { + "@babel/runtime": "^7.20.13", + "@panva/hkdf": "^1.0.2", + "cookie": "^0.5.0", + "jose": "^4.11.4", + "oauth": "^0.9.15", + "openid-client": "^5.4.0", + "preact": "^10.6.3", + "preact-render-to-string": "^5.1.19", + "uuid": "^8.3.2" + }, + "peerDependencies": { + "next": "^12.2.5 || ^13", + "nodemailer": "^6.6.5", + "react": "^17.0.2 || ^18", + "react-dom": "^17.0.2 || ^18" + }, + "peerDependenciesMeta": { + "nodemailer": { + "optional": true + } + } + }, + "node_modules/next-auth/node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/next/node_modules/postcss": { "version": "8.4.14", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", @@ -4262,6 +4306,11 @@ "set-blocking": "^2.0.0" } }, + "node_modules/oauth": { + "version": "0.9.15", + "resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz", + "integrity": "sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA==" + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -4383,6 +4432,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/oidc-token-hash": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/oidc-token-hash/-/oidc-token-hash-5.0.3.tgz", + "integrity": "sha512-IF4PcGgzAr6XXSff26Sk/+P4KZFJVuHAJZj3wgO3vX2bMdNVp/QXTP3P7CEm9V1IdG8lDLY3HhiqpsE/nOwpPw==", + "engines": { + "node": "^10.13.0 || >=12.0.0" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -4422,6 +4479,28 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/openid-client": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-5.5.0.tgz", + "integrity": "sha512-Y7Xl8BgsrkzWLHkVDYuroM67hi96xITyEDSkmWaGUiNX6CkcXC3XyQGdv5aWZ6dukVKBFVQCADi9gCavOmU14w==", + "dependencies": { + "jose": "^4.14.4", + "lru-cache": "^6.0.0", + "object-hash": "^2.2.0", + "oidc-token-hash": "^5.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/openid-client/node_modules/object-hash": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz", + "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==", + "engines": { + "node": ">= 6" + } + }, "node_modules/optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -4689,6 +4768,26 @@ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" }, + "node_modules/preact": { + "version": "10.17.1", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.17.1.tgz", + "integrity": "sha512-X9BODrvQ4Ekwv9GURm9AKAGaomqXmip7NQTZgY7gcNmr7XE83adOMJvd3N42id1tMFU7ojiynRsYnY6/BRFxLA==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + } + }, + "node_modules/preact-render-to-string": { + "version": "5.2.6", + "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-5.2.6.tgz", + "integrity": "sha512-JyhErpYOvBV1hEPwIxc/fHWXPfnEGdRKxc8gFdAZ7XV4tlzyzG847XAyEZqoDnynP88akM4eaHcSOzNcLWFguw==", + "dependencies": { + "pretty-format": "^3.8.0" + }, + "peerDependencies": { + "preact": ">=10" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -4697,6 +4796,11 @@ "node": ">= 0.8.0" } }, + "node_modules/pretty-format": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-3.8.0.tgz", + "integrity": "sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==" + }, "node_modules/prisma": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.1.1.tgz", @@ -5668,6 +5772,14 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/validator": { "version": "13.11.0", "resolved": "https://registry.npmjs.org/validator/-/validator-13.11.0.tgz", @@ -6452,6 +6564,11 @@ "fastq": "^1.6.0" } }, + "@panva/hkdf": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@panva/hkdf/-/hkdf-1.1.1.tgz", + "integrity": "sha512-dhPeilub1NuIG0X5Kvhh9lH4iW3ZsHlnzwgwbOlgwQ2wG1IqFzsgHqmKPk3WzsdWAeaxKJxgM0+W433RmN45GA==" + }, "@pkgr/utils": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.4.0.tgz", @@ -8680,6 +8797,29 @@ } } }, + "next-auth": { + "version": "4.23.1", + "resolved": "https://registry.npmjs.org/next-auth/-/next-auth-4.23.1.tgz", + "integrity": "sha512-mL083z8KgRtlrIV6CDca2H1kduWJuK/3pTS0Fe2og15KOm4v2kkLGdSDfc2g+019aEBrJUT0pPW2Xx42ImN1WA==", + "requires": { + "@babel/runtime": "^7.20.13", + "@panva/hkdf": "^1.0.2", + "cookie": "^0.5.0", + "jose": "^4.11.4", + "oauth": "^0.9.15", + "openid-client": "^5.4.0", + "preact": "^10.6.3", + "preact-render-to-string": "^5.1.19", + "uuid": "^8.3.2" + }, + "dependencies": { + "cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" + } + } + }, "node-addon-api": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", @@ -8742,6 +8882,11 @@ "set-blocking": "^2.0.0" } }, + "oauth": { + "version": "0.9.15", + "resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz", + "integrity": "sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA==" + }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -8821,6 +8966,11 @@ "es-abstract": "^1.20.4" } }, + "oidc-token-hash": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/oidc-token-hash/-/oidc-token-hash-5.0.3.tgz", + "integrity": "sha512-IF4PcGgzAr6XXSff26Sk/+P4KZFJVuHAJZj3wgO3vX2bMdNVp/QXTP3P7CEm9V1IdG8lDLY3HhiqpsE/nOwpPw==" + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -8848,6 +8998,24 @@ "is-wsl": "^2.2.0" } }, + "openid-client": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-5.5.0.tgz", + "integrity": "sha512-Y7Xl8BgsrkzWLHkVDYuroM67hi96xITyEDSkmWaGUiNX6CkcXC3XyQGdv5aWZ6dukVKBFVQCADi9gCavOmU14w==", + "requires": { + "jose": "^4.14.4", + "lru-cache": "^6.0.0", + "object-hash": "^2.2.0", + "oidc-token-hash": "^5.0.3" + }, + "dependencies": { + "object-hash": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz", + "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==" + } + } + }, "optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -9002,11 +9170,29 @@ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" }, + "preact": { + "version": "10.17.1", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.17.1.tgz", + "integrity": "sha512-X9BODrvQ4Ekwv9GURm9AKAGaomqXmip7NQTZgY7gcNmr7XE83adOMJvd3N42id1tMFU7ojiynRsYnY6/BRFxLA==" + }, + "preact-render-to-string": { + "version": "5.2.6", + "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-5.2.6.tgz", + "integrity": "sha512-JyhErpYOvBV1hEPwIxc/fHWXPfnEGdRKxc8gFdAZ7XV4tlzyzG847XAyEZqoDnynP88akM4eaHcSOzNcLWFguw==", + "requires": { + "pretty-format": "^3.8.0" + } + }, "prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==" }, + "pretty-format": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-3.8.0.tgz", + "integrity": "sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==" + }, "prisma": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.1.1.tgz", @@ -9665,6 +9851,11 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + }, "validator": { "version": "13.11.0", "resolved": "https://registry.npmjs.org/validator/-/validator-13.11.0.tgz", diff --git a/package.json b/package.json index 77b50b3..276682b 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "jose": "^4.14.4", "jsonwebtoken": "^9.0.1", "next": "13.4.2", + "next-auth": "^4.23.1", "postcss": "8.4.23", "prisma": "^5.1.1", "react": "18.2.0", diff --git a/pages/api/auth/me.ts b/pages/api/auth/me.ts deleted file mode 100644 index e4cea32..0000000 --- a/pages/api/auth/me.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { NextApiRequest, NextApiResponse } from 'next'; - -import jwt from 'jsonwebtoken'; -import { PrismaClient } from '@prisma/client'; - -const prisma = new PrismaClient(); - -export default async function handler( - req: NextApiRequest, - res: NextApiResponse -) { - const bearerToken = req.headers['authorization'] as string; - const token = bearerToken.split(' ')[1]; - - const payload = jwt.decode(token) as { email: string }; - - if (!payload.email) { - return res.status(401).send({ - errorMessage: 'Unauthorized request', - }); - } - - const user = await prisma.user.findUnique({ - where: { - email: payload.email, - }, - select: { - id: true, - name: true, - email: true, - avatar: true, - phone: true, - userID: true, - }, - }); - - if (!user) { - return res.status(401).json({ - errorMessage: 'User not found', - }); - } - - return res.json({ - me: user, - }); -} diff --git a/pages/api/auth/signin.ts b/pages/api/auth/signin.ts deleted file mode 100644 index 0a0c828..0000000 --- a/pages/api/auth/signin.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { PrismaClient } from '@prisma/client'; -import { NextApiRequest, NextApiResponse } from 'next'; -import validator from 'validator'; -import bcrypt from 'bcrypt'; -import * as jose from 'jose'; -import { setCookie } from 'cookies-next'; - -const prisma = new PrismaClient(); - -export default async function handler( - req: NextApiRequest, - res: NextApiResponse -) { - if (req.method === 'POST') { - const { email, password } = req.body; - const errors: string[] = []; - const validationSchema = [ - { - valid: validator.isEmail(email), - errorMessage: 'Invalid email/User does not exists', - }, - { - valid: validator.isLength(password, { - min: 1, - }), - errorMessage: 'Password is invalid', - }, - ]; - validationSchema.forEach((check) => { - if (!check.valid) { - errors.push(check.errorMessage); - } - }); - - if (errors.length > 0) { - return res.status(400).json({ errorMessage: errors[0] }); - } - const user = await prisma.user.findUnique({ - where: { email }, - }); - - if (!user) { - return res - .status(401) - .json({ errorMessage: 'Email or password invalid ' }); - } - const isMatch = await bcrypt.compare(password, user.password); - if (!isMatch) { - return res - .status(401) - .json({ errorMessage: 'Email or password invalid ' }); - } - - const alg = 'HS256'; - const secret = new TextEncoder().encode(process.env.JWT_SECRET); - const token = await new jose.SignJWT({ - email: user.email, - }) - .setProtectedHeader({ alg }) - .setExpirationTime('24h') - .sign(secret); - setCookie('jwt', token, { - req, - res, - maxAge: 60 * 6 * 24, - }); - return res.status(200).json({ - name: user.name, - email: user.email, - phone: user.phone, - avatar: user.avatar, - }); - } - - return res.status(404).json('Undefined Endpoint'); -} diff --git a/pages/api/auth/signup.ts b/pages/api/auth/signup.ts deleted file mode 100644 index e7c30d0..0000000 --- a/pages/api/auth/signup.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { PrismaClient } from '@prisma/client'; -import { NextApiRequest, NextApiResponse } from 'next'; -import validator from 'validator'; -import bcrypt from 'bcrypt'; -import * as jose from 'jose'; -import { setCookie } from 'cookies-next'; - -const prisma = new PrismaClient(); - -export default async function handler( - req: NextApiRequest, - res: NextApiResponse -) { - if (req.method === 'POST') { - const { name, userID, email, password, phone, avatar } = req.body; - const errors: string[] = []; - const validationSchema = [ - { - valid: validator.isLength(name, { - min: 1, - max: 50, - }), - errorMessage: 'Name is too long/invalid', - }, - { - valid: validator.isLength(userID, { - min: 1, - max: 50, - }), - errorMessage: 'Name is too long/invalid', - }, - { - valid: validator.isEmail(email), - errorMessage: 'Incorrect email', - }, - { - valid: validator.isMobilePhone(phone), - errorMessage: 'Phone number is invalid', - }, - { - valid: validator.isStrongPassword(password), - errorMessage: 'Password is not strong', - }, - ]; - validationSchema.forEach((check) => { - if (!check.valid) { - errors.push(check.errorMessage); - } - }); - if (errors.length > 0) { - return res.status(400).json({ - errorMessage: errors[0], - }); - } - - const userWithEmail = await prisma.user.findUnique({ - where: { email }, - }); - if (userWithEmail) { - return res.status(400).json({ - errorMessage: 'Email already exists', - }); - } - - const userWithUserID = await prisma.user.findUnique({ - where: { userID }, - }); - if (userWithEmail) { - return res.status(400).json({ - errorMessage: 'UserID taken', - }); - } - - const hashedPassword = await bcrypt.hash(password, 10); - const user = await prisma.user.create({ - data: { - name, - password: hashedPassword, - phone, - email, - userID, - avatar, - }, - }); - const alg = 'HS256'; - const secret = new TextEncoder().encode(process.env.JWT_SECRET); - const token = await new jose.SignJWT({ - email: user.email, - userID: user.userID, - }) - .setProtectedHeader({ alg }) - .setExpirationTime('24h') - .sign(secret); - setCookie('jwt', token, { - req, - res, - maxAge: 60 * 6 * 24, - }); - return res.status(200).json({ - name: user.name, - email: user.email, - phone: user.phone, - userID: user.userID, - avatar: user.avatar, - }); - } -} diff --git a/public/gamedoora.png b/public/gamedoora.png new file mode 100644 index 0000000..5597e5a Binary files /dev/null and b/public/gamedoora.png differ diff --git a/public/next.svg b/public/next.svg deleted file mode 100644 index 5174b28..0000000 --- a/public/next.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/vercel.svg b/public/vercel.svg deleted file mode 100644 index d2f8422..0000000 --- a/public/vercel.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/app/(auth)/components/Brand.tsx b/src/app/(auth)/components/Brand.tsx new file mode 100644 index 0000000..fbc2ebc --- /dev/null +++ b/src/app/(auth)/components/Brand.tsx @@ -0,0 +1,17 @@ +import Image from 'next/image'; + +export default function Brand({ signIn }: { signIn: boolean }) { + return ( +
+

+ Gamedoora + Gamedoora +

+

+ {signIn + ? 'Sign In to access your account' + : 'Sign Up to create an account'} +

+
+ ); +} diff --git a/src/app/(auth)/components/Hero.tsx b/src/app/(auth)/components/Hero.tsx new file mode 100644 index 0000000..55614ce --- /dev/null +++ b/src/app/(auth)/components/Hero.tsx @@ -0,0 +1,32 @@ +import Image from 'next/image'; +import Link from 'next/link'; + +export default function Hero() { + return ( +
+
+
+ + Gamedoora +

Gamedoora

+ + +

+ A platform for passionate people to connect and collaborate freely. +

+
+
+
+ ); +} diff --git a/src/app/(auth)/components/SessionProvider.tsx b/src/app/(auth)/components/SessionProvider.tsx new file mode 100644 index 0000000..da59d85 --- /dev/null +++ b/src/app/(auth)/components/SessionProvider.tsx @@ -0,0 +1,3 @@ +'use client'; +import { SessionProvider } from "next-auth/react"; +export default SessionProvider; diff --git a/src/app/(auth)/login/page.tsx b/src/app/(auth)/login/page.tsx deleted file mode 100644 index d07a977..0000000 --- a/src/app/(auth)/login/page.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export default function Login() { - return
Login
; -} diff --git a/src/app/(auth)/sign-in/page.tsx b/src/app/(auth)/sign-in/page.tsx new file mode 100644 index 0000000..e50e8ae --- /dev/null +++ b/src/app/(auth)/sign-in/page.tsx @@ -0,0 +1,97 @@ +'use client'; +import Link from 'next/link'; +import Hero from '../components/Hero'; +import Brand from '../components/Brand'; +import { signIn, useSession } from 'next-auth/react'; +import { redirect } from 'next/navigation'; + +export default function SignIn() { + const { data: session } = useSession(); + if (session) { + redirect(`/`); + } + return ( +
+
+ + +
+
+ + +
+
+
+ + +
+ +
+
+ + + Forgot password? + +
+ + +
+ +
+ +
+
+ +
+ +
+ +

+ Don't have an account yet?{' '} + + Sign up + + . +

+
+
+
+
+
+ ); +} diff --git a/src/app/(auth)/sign-up/page.tsx b/src/app/(auth)/sign-up/page.tsx index e36cc7d..13a2e57 100644 --- a/src/app/(auth)/sign-up/page.tsx +++ b/src/app/(auth)/sign-up/page.tsx @@ -1,3 +1,115 @@ +'use client'; +import Link from 'next/link'; +import Hero from '../components/Hero'; +import Brand from '../components/Brand'; +import { useSession } from 'next-auth/react'; +import { redirect } from 'next/navigation'; + export default function SignUp() { - return
SignUp
; + const { data: session } = useSession(); + if (session) { + redirect(`/`); + } + return ( +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+ +
+ + +
+ +
+
+ +
+ + +
+ +
+ +
+
+ +

+ Have an account already?{' '} + + Sign In + + . +

+
+
+
+
+
+ ); } diff --git a/src/app/api/auth/[...nextauth]/auth.ts b/src/app/api/auth/[...nextauth]/auth.ts new file mode 100644 index 0000000..5b4b977 --- /dev/null +++ b/src/app/api/auth/[...nextauth]/auth.ts @@ -0,0 +1,10 @@ +import { NextAuthOptions } from 'next-auth'; +import GitHubProvider from 'next-auth/providers/github'; +export const authOptions: NextAuthOptions = { + providers: [ + GitHubProvider({ + clientId: process.env.GITHUB_ID ?? '', + clientSecret: process.env.GITHUB_SECRET ?? '', + }), + ], +}; \ No newline at end of file diff --git a/src/app/api/auth/[...nextauth]/route.ts b/src/app/api/auth/[...nextauth]/route.ts new file mode 100644 index 0000000..5cccc51 --- /dev/null +++ b/src/app/api/auth/[...nextauth]/route.ts @@ -0,0 +1,6 @@ +import NextAuth from "next-auth/next"; +import { authOptions } from "./auth"; + +const handler = NextAuth(authOptions); + +export { handler as GET, handler as POST }; diff --git a/src/app/components/AuthButton.tsx b/src/app/components/AuthButton.tsx new file mode 100644 index 0000000..67af817 --- /dev/null +++ b/src/app/components/AuthButton.tsx @@ -0,0 +1,24 @@ +'use client'; +import { signOut, useSession, signIn } from 'next-auth/react'; + +export default function AuthButton() { + const { data: session } = useSession(); + if (session) { + return ( + + ); + } + return ( + + ); +} diff --git a/src/app/components/Navbar.tsx b/src/app/components/Navbar.tsx index f1e68f1..dcd0bda 100644 --- a/src/app/components/Navbar.tsx +++ b/src/app/components/Navbar.tsx @@ -1,7 +1,36 @@ +'use client'; +import Link from 'next/link'; +import AuthButton from './AuthButton'; + /** * This is the global navbar which would be available on all screens expect the login * @returns Global navbar */ export default function Navbar() { - return
This is a demo navbar
; + return ( +
+ +
+ ); } diff --git a/src/app/components/Sidebar.tsx b/src/app/components/Sidebar.tsx index a6c80aa..99ad6c3 100644 --- a/src/app/components/Sidebar.tsx +++ b/src/app/components/Sidebar.tsx @@ -1,10 +1,24 @@ -import Link from "next/link"; +import Image from 'next/image'; +import Link from 'next/link'; export default function Sidebar() { return ( - + ); } diff --git a/src/app/context/AuthContext.tsx b/src/app/context/AuthContext.tsx deleted file mode 100644 index fb69d5e..0000000 --- a/src/app/context/AuthContext.tsx +++ /dev/null @@ -1,84 +0,0 @@ -'use client'; - -import { useState, createContext, useEffect } from 'react'; -import { getCookie } from 'cookies-next'; -import axios from 'axios'; - -interface User { - id: number; - name: string; - email: string; -} - -interface State { - loading: boolean; - error: string | null; - data: User | null; -} - -interface AuthState extends State { - setAuthState: React.Dispatch>; -} - -export const AuthenticationContext = createContext({ - loading: false, - error: null, - data: null, - setAuthState: () => {}, -}); - -export default function AuthContext({ - children, -}: { - children: React.ReactNode; -}) { - const [authState, setAuthState] = useState({ - loading: true, - data: null, - error: null, - }); - - const fetchUser = async () => { - try { - const jwt = getCookie('jwt'); - if (!jwt) { - return setAuthState({ - data: null, - error: null, - loading: false, - }); - } - const response = await axios.get('http://localhost:3000/api/login', { - headers: { - Authorization: `Bearer ${jwt}`, - }, - }); - axios.defaults.headers.common['Authorization'] = `Bearer ${jwt}`; - setAuthState({ - data: response.data, - error: null, - loading: false, - }); - } catch (error: any) { - setAuthState({ - data: null, - error: error.response.data.errorMessage, - loading: false, - }); - } - }; - - useEffect(() => { - fetchUser(); - }, []); - return ( - - {children} - - ); -} diff --git a/src/app/favicon.ico b/src/app/favicon.ico index 718d6fe..3339389 100644 Binary files a/src/app/favicon.ico and b/src/app/favicon.ico differ diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 7cf0a8d..1af1041 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,7 +1,10 @@ import ReactQueryProvider from './components/ReactQueryProvider'; -import AuthContext from './context/AuthContext'; import './globals.css'; import { Inter } from 'next/font/google'; +import { getServerSession } from 'next-auth'; +import SessionProvider from './(auth)/components/SessionProvider'; +import Sidebar from './components/Sidebar'; +import Navbar from './components/Navbar'; const inter = Inter({ subsets: ['latin'] }); @@ -10,20 +13,19 @@ export const metadata = { description: 'Gamedoora is here to revolutionize the gaming industry', }; -export default function RootLayout({ +export default async function RootLayout({ children, }: { children: React.ReactNode; }) { + const session = await getServerSession(); return (
- - -
{children}
-
-
+ + {children} +
diff --git a/src/app/page.tsx b/src/app/page.tsx index 58e5bf0..ac378f4 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,30 +1,32 @@ 'use client'; -import Link from 'next/link'; import { useFetchFeed } from '../../services/feed'; import { TFeed } from '../../services/feed/type'; +import { useSession } from 'next-auth/react'; +import { redirect } from 'next/navigation'; +import Sidebar from './components/Sidebar'; +import Navbar from './components/Navbar'; export default function Home() { const { data, isError, isLoading } = useFetchFeed('hybridx'); + const { data: session } = useSession(); + if (!session) { + redirect('/sign-in'); + } return ( -
- - Goto login - - - Goto Sign-up - - - Goto {`Hybridx's`} profile - -
The following is some feed data
-
- {data?.feed.map((f: TFeed) => ( -
-

{f.title}

-

{f.author}

-
- ))} +
+ +
+ +
+
The following is some feed data
+ {data?.feed.map((f: TFeed) => ( +
+

{f.title}

+

{f.author}

+
+ ))} +
); diff --git a/src/app/profile/[slug]/layout.tsx b/src/app/profile/[slug]/layout.tsx index de24f91..ec7587a 100644 --- a/src/app/profile/[slug]/layout.tsx +++ b/src/app/profile/[slug]/layout.tsx @@ -1,4 +1,5 @@ import Navbar from '@/app/components/Navbar'; +import Sidebar from '@/app/components/Sidebar'; export default function ProfileLayout({ children, @@ -10,9 +11,12 @@ export default function ProfileLayout({ }; }) { return ( -
- - {children} +
+ +
+ + {children} +
); } diff --git a/src/app/profile/[slug]/loading.tsx b/src/app/profile/[slug]/loading.tsx index 898336f..25a910a 100644 --- a/src/app/profile/[slug]/loading.tsx +++ b/src/app/profile/[slug]/loading.tsx @@ -1,3 +1,27 @@ export default function Loading() { - return
You project page is loading...
; + return ( +
+ {' '} +
+ {/* Profile Header Skeleton */} +
+
+
+
+
+ + {/* About Me Skeleton */} +
+
+
+
+ + {/* Contact Information Skeleton */} +
+
+
+
+
+
+ ); } diff --git a/src/app/profile/[slug]/page.tsx b/src/app/profile/[slug]/page.tsx index fe333e7..9785add 100644 --- a/src/app/profile/[slug]/page.tsx +++ b/src/app/profile/[slug]/page.tsx @@ -1,6 +1,7 @@ /* eslint-disable @next/next/no-img-element */ -import { PrismaClient, User } from '@prisma/client'; +import { PrismaClient } from '@prisma/client'; import { notFound } from 'next/navigation'; +import { getServerSession } from 'next-auth'; const prisma = new PrismaClient(); @@ -12,24 +13,24 @@ interface IUser { phone: string; } -const fetchUserByUser = async (slug: string): Promise => { - const user = await prisma.user.findUnique({ - where: { - userID: slug, - }, - select: { - name: true, - userID: true, - avatar: true, - email: true, - phone: true, - }, - }); - if (!user) { - notFound(); - } - return user; -}; +// const fetchUserByUser = async (slug: string): Promise => { +// const user = await prisma.user.findUnique({ +// where: { +// userID: slug, +// }, +// select: { +// name: true, +// userID: true, +// avatar: true, +// email: true, +// phone: true, +// }, +// }); +// if (!user) { +// notFound(); +// } +// return user; +// }; export default async function Profile({ params, @@ -38,19 +39,54 @@ export default async function Profile({ slug: string; }; }) { - const user = await fetchUserByUser(params.slug); + // const user = await fetchUserByUser(params.slug); + const session = await getServerSession(); return ( -
-
- -
-
{user.name}
-
{user.email}
-
{user.phone}
+ <> + {session?.user?.name ? ( +
+
+
+ User Photo +
+

+ {session?.user?.name} +

+

Game developer

+
+
+
+

About Me

+

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla + vitae hendrerit ante. Vivamus semper, purus id fermentum + posuere. +

+
+
+

+ Contact Information +

+

+ Email:{' '} + + {session?.user?.email} + +
+ Phone: +91 9876543210 +
+ Location: Bharat +

+
+
-
-
+ ) : ( + 'Not logged in' + )} + ); }