Merge branch 'dev' of github.com:JoaquinPar/2800-202510-BBY14 into dev

This commit is contained in:
SowinskiBraeden committed 2025-05-09 10:07:16 -07:00
commit 18bee21941
11 files changed
+402 -126

No files matched your search

+3
View File
@@ -1,6 +1,9 @@
# Environment variables
.env
#vscode files
.vscode
# Node modules
node_modules/
+96 -3
View File
@@ -3,6 +3,7 @@ const MongoStore = require("connect-mongo");
const session = require("express-session");
const express = require('express');
const path = require('path');
const bcrypt = require('bcrypt');
const joi = require('joi');
require('dotenv').config();
@@ -11,7 +12,7 @@ const port = process.env.PORT || 3000;
const mongoURI = process.env.MONGO_URI;
const database = process.env.DATABASE; // Database name
const secret = process.env.SECRET || "123-secret-xyz";
const secret = process.env.SECRET || "123-secret-xyz";
/*** Sessions ***/
app.use(session({
@@ -39,9 +40,9 @@ async function initDatabase() {
const db = await connectMongo(mongoURI, database);
// For any collection, init here
users = await getCollection(db, "users");
users = await getCollection(db, "users");
assets = await getCollection(db, "assets");
plans = await getCollection(db, "plans");
plans = await getCollection(db, "plans");
}
/*** ROUTINGS ***/
@@ -73,6 +74,96 @@ app.get('/aboutUs', (req, res) => {
return res.status(status.Ok);
});
app.get('/forgotPassword', (req, res) => {
const error = req.session.error;
const reset = req.session.reset;
req.session.reset = '';
req.session.error = '';
res.render('forgotPass', { error: error, reset: reset });
return res.status(status.Ok);
});
// Reset with token given to user via email
app.get('/reset/:token', async (req, res) => {
const token = req.params.token;
const user = await users.findOne({
resetToken: token,
resetTokenExpires: { $gt: Date.now() },
});
if (!user) {
req.session.error = 'reset link not valid or has expired';
return res.redirect('/forgotPassword');
}
const error = req.session.error;
delete req.session.error;
res.render('resetPass', {
token: token,
errMessage: error,
});
});
app.post('/resetLink', async (req, res) => {
const { token, password, confirmPassword, } = req.body;
const passwordSchema = joi.object({
password: joi.string().max(20).required(),
confirmPassword: joi.string().max(20).required(),
});
const valid = passwordSchema.validate({ password, confirmPassword });
if (valid.error) {
console.log("houston we have a problem");
req.session.error = 'Invalid input';
res.status(status.BadRequest);
return res.redirect(`/reset/${token}`);
}
if (!token || !password || !confirmPassword) {
req.session.error = 'field may be missing';
return res.redirect(`/reset/${token}`);
}
if (password !== confirmPassword) {
req.session.error = 'passwords do not match';
return res.redirect(`/reset/${token}`);
}
const user = await users.findOne({
resetToken: token,
resetTokenExpires: { $gt: Date.now() },
});
if (!user) {
req.session.error = 'Reset link is invalid.';
return res.redirect(`/reset`);
}
const hashPassword = await bcrypt.hash(password, 12);
await users.updateOne(
{
email: user.email
},
{
$set: {
password: hashPassword,
resetToken: '',
resetTokenExpires: 0,
},
}
);
req.session.success = 'Password has been reset';
res.redirect('/login');
});
app.post('/api/location', async (req, res) => {
const { latitude, longitude } = req.body;
const response = await fetch(`https://maps.googleapis.com/maps/api/geocode/json?latlng=${latitude},${longitude}&result_type=country&key=${process.env.geolocation_api}`);
const data = await response.json();
res.json(data);
});
// 404 handler - keep the actual notFound route please
// REALLY DONT DELETE THIS
app.get('/notFound', (req, res) => {
@@ -86,6 +177,8 @@ initDatabase().then(() => {
// Import authentication handler
app.use(require("./src/auth/authentication")(users));
app.use(require('./src/auth/forgotPass')(users));
// Import middleware & apply to user routes
const middleware = require("./src/auth/middleware")(users);
+17 -1
View File
@@ -11,12 +11,14 @@
"dependencies": {
"bcrypt": "^5.1.1",
"connect-mongo": "^5.1.0",
"crypto": "^1.0.1",
"dotenv": "^16.5.0",
"ejs": "^3.1.10",
"express": "^5.1.0",
"express-session": "^1.18.1",
"joi": "^17.13.3",
"mongodb": "^6.16.0"
"mongodb": "^6.16.0",
"nodemailer": "^7.0.3"
},
"devDependencies": {
"nodemon": "^3.1.10"
@@ -483,6 +485,12 @@
"node": ">=6.6.0"
}
},
"node_modules/crypto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/crypto/-/crypto-1.0.1.tgz",
"integrity": "sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig==",
"deprecated": "This package is no longer supported. It's now a built-in Node module. If you've depended on crypto, you should switch to the one that's built-in."
},
"node_modules/debug": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
@@ -1430,6 +1438,14 @@
"webidl-conversions": "^3.0.0"
}
},
"node_modules/nodemailer": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-7.0.3.tgz",
"integrity": "sha512-Ajq6Sz1x7cIK3pN6KesGTah+1gnwMnx5gKl3piQlQQE/PwyJ4Mbc8is2psWYxK3RJTVeqsDaCv8ZzXLCDHMTZw==",
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/nodemon": {
"version": "3.1.10",
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.10.tgz",
+3 -1
View File
@@ -20,12 +20,14 @@
"dependencies": {
"bcrypt": "^5.1.1",
"connect-mongo": "^5.1.0",
"crypto": "^1.0.1",
"dotenv": "^16.5.0",
"ejs": "^3.1.10",
"express": "^5.1.0",
"express-session": "^1.18.1",
"joi": "^17.13.3",
"mongodb": "^6.16.0"
"mongodb": "^6.16.0",
"nodemailer": "^7.0.3"
},
"devDependencies": {
"nodemon": "^3.1.10"
+68
View File
@@ -0,0 +1,68 @@
const express = require('express');
const crypto = require('crypto');
const joi = require('joi');
const nodeMail = require('nodemailer');
require('dotenv').config();
const transporter = nodeMail.createTransport({
service: 'gmail',
auth: {
user: process.env.EMAIL_USER,
pass: process.env.PASS,
}
});
// users info
module.exports = (users) => {
const router = express.Router();
router.post('/auth/resetPass', async (req, res) => {
console.log("we are inside of the post");
const resetSchema = joi.object({
email: joi.string().email().required(),
});
req.session.error = '';
req.session.reset = '';
const valid = resetSchema.validate(req.body);
if (valid.error) {
req.session.error = 'invalid email';
return res.redirect('/forgotPassword')
}
const { email } = req.body;
const user = await users.findOne({ email });
if (!user) {
req.session.error = 'No user found'
return res.redirect('/forgotPassword');
}
const token = crypto.randomBytes(32).toString('hex');
console.log(`The reset token is ${token}`)
const expiration = Date.now() + 360000;
await users.updateOne({ email }, {
$set: { resetToken: token, resetTokenExpires: expiration }
});
const resetUrl = `http://localhost:3000/reset/${token}`;
const mailSend = {
from: process.env.EMAIL_USER,
to: email,
subject: 'Password reset',
text: `reset your password here ${resetUrl} this link will expire within 1 hour`,
};
try {
await transporter.sendMail(mailSend);
req.session.reset = 'Reset link sent Check your email';
res.redirect('/forgotPassword');
} catch (err) {
console.log('there was an error', err);
res.status(500).send('email failed to send try again');
}
});
return router;
}
+9 -9
View File
@@ -98,7 +98,7 @@ module.exports = (middleware, users, plans, assets) => {
router.get('/plans', async (req, res) => {
try {
const userPlansFromDB = await plans.find({userId: new ObjectId(req.session.user._id) }).toArray();
const userPlansFromDB = await plans.find({ userId: new ObjectId(req.session.user._id) }).toArray();
// Use a for...of loop for proper async/await behavior in series for updates
for (const plan of userPlansFromDB) {
@@ -163,7 +163,7 @@ module.exports = (middleware, users, plans, assets) => {
});
router.get('/newPlan', (req, res) => {
if(!req.session.user.financialData){
if (!req.session.user.financialData) {
req.session.errMessage = "Please complete your financial data before creating a plan.";
return res.status(status.Unauthorized).redirect('/questionnaire');
}
@@ -204,12 +204,12 @@ module.exports = (middleware, users, plans, assets) => {
progress: "0"
};
try{
await plans.insertOne({userId: new ObjectId(req.session.user._id), ...newPlan});
try {
await plans.insertOne({ userId: new ObjectId(req.session.user._id), ...newPlan });
req.session.errMessage = "";
res.redirect('/plans');
}
catch(err){
catch (err) {
console.error("Error saving plan:", err);
req.session.errMessage = "An error occurred while saving your plan. Please try again.";
res.status(status.InternalServerError).redirect("/newPlan");
@@ -320,7 +320,7 @@ module.exports = (middleware, users, plans, assets) => {
if (valid.err) {
req.session.errMessage = "Invalid input",
res.status(status.BadRequest);
res.status(status.BadRequest);
return res.redirect("/profile");
}
@@ -375,7 +375,7 @@ module.exports = (middleware, users, plans, assets) => {
if (valid.err) {
req.session.errMessage = "Invalid input",
res.status(status.BadRequest);
res.status(status.BadRequest);
return res.redirect("/assets");
}
@@ -420,13 +420,13 @@ module.exports = (middleware, users, plans, assets) => {
if (valid.err) {
req.session.errMessage = "Invalid input",
res.status(status.BadRequest);
res.status(status.BadRequest);
return res.redirect("/assets");
}
if (req.body.userId != req.session.user._id) {
req.session.errMessage = "Cannot change asset owner",
res.status(status.BadRequest);
res.status(status.BadRequest);
return res.redirect("/assets");
}
+88 -68
View File
@@ -1,5 +1,5 @@
<%- include("./partials/fileHeader") %>
<%- include("./partials/header") %>
<%- include("./partials/header") %>
<main>
<!-- Buttons -->
@@ -22,73 +22,93 @@
class="block text-right antialiased tracking-normal font-sans text-2xl font-semibold leading-snug text-blue-gray-900">
$53k</h4>
</div>
<div class="border-t border-blue-gray-50 p-10">
<p class=" antialiased font-sans text-base leading-relaxed font-normal text-blue-gray-600">
<strong class="text-green-500">Make this percent bar or graph or something </strong>&nbsp;than lastweek
</p>
</div>
</div>
<div class="relative flex flex-col bg-clip-border rounded-xl bg-white text-gray-700 shadow-md">
<div class="p-4 flex items-center justify-between">
<p class="font-sans text-2xl leading-normal font-normal text-blue-gray-600">
Retirement goal</p>
<h4
class="block text-right antialiased tracking-normal font-sans text-2xl font-semibold leading-snug text-blue-gray-900">
$53k</h4>
</div>
<div class="border-t border-blue-gray-50 p-10">
<p class=" antialiased font-sans text-base leading-relaxed font-normal text-blue-gray-600">
<strong class="text-green-500">Make this percent bar or graph or something </strong>&nbsp;than last
week
</p>
</div>
</div>
<div class="relative flex flex-col bg-clip-border rounded-xl bg-white text-gray-700 shadow-md">
<!-- <div -->
<!-- class="bg-clip-border mx-4 rounded-xl overflow-hidden bg-gradient-to-tr from-green-600 to-green-400 text-white shadow-green-500/40 shadow-lg absolute -mt-4 grid h-16 w-16 place-items-center"> -->
<!-- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" -->
<!-- class="w-6 h-6 text-white"> -->
<!-- <path -->
<!-- d="M6.25 6.375a4.125 4.125 0 118.25 0 4.125 4.125 0 01-8.25 0zM3.25 19.125a7.125 7.125 0 0114.25 0v.003l-.001.119a.75.75 0 01-.363.63 13.067 13.067 0 01-6.761 1.873c-2.472 0-4.786-.684-6.76-1.873a.75.75 0 01-.364-.63l-.001-.122zM19.75 7.5a.75.75 0 00-1.5 0v2.25H16a.75.75 0 000 1.5h2.25v2.25a.75.75 0 001.5 0v-2.25H22a.75.75 0 000-1.5h-2.25V7.5z"> -->
<!-- </path> -->
<!-- </svg> -->
<!-- </div> -->
<!-- we can use this later if needed not sure what it shoudl be for right now. -->
<!-- <div class="p-4 text-right"> -->
<!-- <p class="block antialiased font-sans text-sm leading-normal font-normal text-blue-gray-600">New Clients -->
<!-- </p> -->
<!-- <h4 -->
<!-- class="block antialiased tracking-normal font-sans text-2xl font-semibold leading-snug text-blue-gray-900"> -->
<!-- 3,462</h4> -->
<!-- </div> -->
<!-- <div class="border-t border-blue-gray-50 p-4"> -->
<!-- <p class="block antialiased font-sans text-base leading-relaxed font-normal text-blue-gray-600"> -->
<!-- <strong class="text-red-500">-2%</strong>&nbsp;than yesterday -->
<!-- </p> -->
<!-- </div> -->
<!-- </div> -->
<div class="relative flex flex-col bg-clip-border rounded-xl bg-white text-gray-700 shadow-md">
<div class="relative flex flex-col bg-clip-border rounded-xl bg-white text-gray-700 shadow-md">
<div class="p-4 flex items-center justify-between">
<p class="font-sans text-2xl leading-normal font-normal text-blue-gray-600">
Retirement goal</p>
<h4
class="block text-right antialiased tracking-normal font-sans text-2xl font-semibold leading-snug text-blue-gray-900">
$53k</h4>
</div>
<div class="border-t border-blue-gray-50 p-10">
<p class=" antialiased font-sans text-base leading-relaxed font-normal text-blue-gray-600">
<strong class="text-green-500">Make this percent bar or graph or something </strong>&nbsp;than last
week
</p>
</div>
</div>
</div>
</div>
</div>
<div class="text-blue-gray-600">
</div>
</main>
<!--This is the cards for plans and other things-->
<div class="mt-12">
<div class="mb-12 grid gap-y-10 gap-x-6 md:grid-cols-2 mr-3 ml-3 xl:grid-cols-4">
<!--box to put logo icon if we want on in a box-->
<div class=" relative flex flex-col bg-clip-border rounded-xl bg-white text-gray-700 shadow-md">
<!-- <div -->
<!-- class="bg-clip-border mx-4 rounded-xl overflow-hidden bg-gradient-to-tr from-blue-600 to-blue-400 text-white shadow-blue-500/40 shadow-lg absolute mt-2 grid h-16 w-16 place-items-center"> -->
<!-- </div> -->
<div class="p-4 flex items-center justify-between">
<p class="font-sans text-2xl leading-normal font-normal text-blue-gray-600">
Retirement goal</p>
<h4
class="block text-right antialiased tracking-normal font-sans text-2xl font-semibold leading-snug text-blue-gray-900">
$53k</h4>
</div>
<div class="border-t border-blue-gray-50 p-10">
<p class=" antialiased font-sans text-base leading-relaxed font-normal text-blue-gray-600">
<strong class="text-green-500">Make this percent bar or graph or something
</strong>&nbsp;than lastweek
</p>
</div>
</div>
<div class="relative flex flex-col bg-clip-border rounded-xl bg-white text-gray-700 shadow-md">
<div class="p-4 flex items-center justify-between">
<p class="font-sans text-2xl leading-normal font-normal text-blue-gray-600">
Retirement goal</p>
<h4
class="block text-right antialiased tracking-normal font-sans text-2xl font-semibold leading-snug text-blue-gray-900">
$53k</h4>
</div>
<div class="border-t border-blue-gray-50 p-10">
<p class=" antialiased font-sans text-base leading-relaxed font-normal text-blue-gray-600">
<strong class="text-green-500">Make this percent bar or graph or something
</strong>&nbsp;than last
week
</p>
</div>
</div>
<div class="relative flex flex-col bg-clip-border rounded-xl bg-white text-gray-700 shadow-md">
<!-- <div -->
<!-- class="bg-clip-border mx-4 rounded-xl overflow-hidden bg-gradient-to-tr from-green-600 to-green-400 text-white shadow-green-500/40 shadow-lg absolute -mt-4 grid h-16 w-16 place-items-center"> -->
<!-- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" -->
<!-- class="w-6 h-6 text-white"> -->
<!-- <path -->
<!-- d="M6.25 6.375a4.125 4.125 0 118.25 0 4.125 4.125 0 01-8.25 0zM3.25 19.125a7.125 7.125 0 0114.25 0v.003l-.001.119a.75.75 0 01-.363.63 13.067 13.067 0 01-6.761 1.873c-2.472 0-4.786-.684-6.76-1.873a.75.75 0 01-.364-.63l-.001-.122zM19.75 7.5a.75.75 0 00-1.5 0v2.25H16a.75.75 0 000 1.5h2.25v2.25a.75.75 0 001.5 0v-2.25H22a.75.75 0 000-1.5h-2.25V7.5z"> -->
<!-- </path> -->
<!-- </svg> -->
<!-- </div> -->
<!-- we can use this later if needed not sure what it shoudl be for right now. -->
<!-- <div class="p-4 text-right"> -->
<!-- <p class="block antialiased font-sans text-sm leading-normal font-normal text-blue-gray-600">New Clients -->
<!-- </p> -->
<!-- <h4 -->
<!-- class="block antialiased tracking-normal font-sans text-2xl font-semibold leading-snug text-blue-gray-900"> -->
<!-- 3,462</h4> -->
<!-- </div> -->
<!-- <div class="border-t border-blue-gray-50 p-4"> -->
<!-- <p class="block antialiased font-sans text-base leading-relaxed font-normal text-blue-gray-600"> -->
<!-- <strong class="text-red-500">-2%</strong>&nbsp;than yesterday -->
<!-- </p> -->
<!-- </div> -->
<!-- </div> -->
<div class="relative flex flex-col bg-clip-border rounded-xl bg-white text-gray-700 shadow-md">
<div
class="relative flex flex-col bg-clip-border rounded-xl bg-white text-gray-700 shadow-md">
<div class="p-4 flex items-center justify-between">
<p class="font-sans text-2xl leading-normal font-normal text-blue-gray-600">
Retirement goal</p>
<h4
class="block text-right antialiased tracking-normal font-sans text-2xl font-semibold leading-snug text-blue-gray-900">
$53k</h4>
</div>
<div class="border-t border-blue-gray-50 p-10">
<p
class=" antialiased font-sans text-base leading-relaxed font-normal text-blue-gray-600">
<strong class="text-green-500">Make this percent bar or graph or something
</strong>&nbsp;than last
week
</p>
</div>
</div>
</div>
</div>
</div>
<div class="text-blue-gray-600">
</div>
</main>
<%- include("./partials/navBar") %>
<%- include("./partials/scriptLoader") %>
+38
View File
@@ -0,0 +1,38 @@
<%- include("./partials/fileHeader") %>
<main>
<div class="flex justify-center items-center h-screen">
<form action="/auth/resetPass" method="POST">
<div class="w-96 p-6 shadow-1g bg-white rounded-md">
<h1 class="text-3xl block text-center font-semibold">Reset Password</h1>
<hr class="mt-3">
<% if (reset==='' ) { %>
<div class="mt-3">
<label for="email" class="block text-base mb-2">Email</label>
<input type="text" id="email" name="email"
class="border focus:border-gray-600 w-full rounded-md text-base px-2 py-1 focus:outline-none focus:ring-0 "
placeholder="Enter Email" />
</div>
<% } else { %>
<div class="mt-3">
<h1 class="text-2xl block text-center font-bold text-red-600"> Reset link sent. </h1>
</div>
<% } %>
<!---->
<div class="text-red-800 font-bold" id="forgor">
<%= error%>
</div>
<% if (reset==='' ) { %>
<div class="mt-5">
<button type="submit"
class="cursor-pointer border-2 border-gray-600 bg-blue-600 text-white py-1 w-full rounded-md hover:bg-transparent hover:text-indigo-700 font-semibold">Send
reset Link</button>
</div>
<% } %>
</div>
</form>
</div>
</main>
<%- include("./partials/footer") %> <%- include("./partials/footer") %>
+1 -1
View File
@@ -25,7 +25,7 @@
<label>Remember me</label>
</div>
<div>
<a href="#" class="text-indigo-600 font-semibold">Forgot Password? </a>
<a href="/forgotPassword" class="text-indigo-600 font-semibold">Forgot Password? </a>
</div>
</div>
<div class="mt-5">
+36
View File
@@ -0,0 +1,36 @@
<%- include("./partials/fileHeader") %>
<main>
<div class="flex justify-center items-center h-screen">
<form action="/resetLink" method="POST">
<div class="w-96 p-6 shadow-1g bg-white rounded-md">
<h1 class="text-3xl block text-center font-semibold">Reset Password</h1>
<hr class="mt-3">
<input type="hidden" name="token" value="<%=token %>">
<div class="mt-3">
<label for="password" class="block text-base mb-2">New Password:</label>
<input type="text" id="password" name="password"
class="border focus:border-gray-600 w-full rounded-md text-base px-2 py-1 focus:outline-none focus:ring-0 "
placeholder="Enter Password" />
</div>
<div class="mt-3">
<label for="password" class="block text-base mb-2">Confirm Password:</label>
<input type="text" id="Repassword" name="confirmPassword"
class="border focus:border-gray-600 w-full rounded-md text-base px-2 py-1 focus:outline-none focus:ring-0 "
placeholder="ReType Password" />
</div>
<% if (typeof errMessage !=='undefined' ) { %>
<div class="text-red-800 font-bold" id="forgor">
<%= errMessage %>
</div>
<% } %>
<div class="mt-5">
<button type="submit"
class="cursor-pointer border-2 border-gray-600 bg-blue-600 text-white py-1 w-full rounded-md hover:bg-transparent hover:text-indigo-700 font-semibold">Change
Password</button>
</div>
</div>
</form>
</div>
</main>
<%- include("./partials/footer") %>
+43 -43
View File
@@ -1,46 +1,46 @@
<%- include("./partials/fileHeader") %>
<%- include("./partials/headerStart") %>
<%- include("./partials/headerStart") %>
<main>
<div class="flex justify-center items-center h-screen">
<form action="/signup" method="POST">
<div class="w-96 p-6 shadow-1g bg-white rounded-md">
<h1 class="text-3xl block text-center font-semibold">Signup</h1>
<hr class="mt-3">
<div class="mt-3">
<label for="name" class="block text-base mb-2">Name</label>
<input type="text" id="name" name="name"
class="border focus:border-gray-600 w-full rounded-md text-base px-2 py-1 focus:outline-none focus:ring-0 "
placeholder="Enter Name" />
</div>
<div class="mt-3">
<label for="email" class="block text-base mb-2">Email</label>
<input type="text" id="email" name="email"
class="border focus:border-gray-600 w-full rounded-md text-base px-2 py-1 focus:outline-none focus:ring-0 "
placeholder="Enter Email" />
</div>
<div class="mt-3">
<label for="password" class="block text-base mb-2">Password</label>
<input type="password" id="password" name="password"
class="border focus:border-gray-600 w-full rounded-md text-base px-2 py-1 focus:outline-none focus:ring-0 "
placeholder="Enter Password" />
<label for="password" class="block text-base mb-2 mt-3">Re-type Password</label>
<input type="password" id="repassword" name="repassword"
class="border focus:border-gray-600 w-full rounded-md text-base px-2 py-1 focus:outline-none focus:ring-0 "
placeholder="Enter Password" />
</div>
<div class="text-red-800 font-bold " id="forgor"> <%= errMessage %></div>
<div class="mt-5">
<button type="submit"
class="border-2 border-gray-600 bg-blue-600 text-white py-1 w-full rounded-md hover:bg-transparent hover:text-indigo-700 font-semibold">Signup</button>
</div>
<div class="mt-5 block justify-between items-center">
<label>Already have an account?</label>
<a href="/login" class="text-indigo-600 font-semibold">Login</a>
</div>
</div>
</form>
</div>
</main>
<main>
<div class="flex justify-center items-center h-screen">
<form action="/signup" method="POST">
<div class="w-96 p-6 shadow-1g bg-white rounded-md">
<h1 class="text-3xl block text-center font-semibold">Signup</h1>
<hr class="mt-3">
<div class="mt-3">
<label for="name" class="block text-base mb-2">Name</label>
<input type="text" id="name" name="name"
class="border focus:border-gray-600 w-full rounded-md text-base px-2 py-1 focus:outline-none focus:ring-0 "
placeholder="Enter Name" />
</div>
<div class="mt-3">
<label for="email" class="block text-base mb-2">Email</label>
<input type="text" id="email" name="email"
class="border focus:border-gray-600 w-full rounded-md text-base px-2 py-1 focus:outline-none focus:ring-0 "
placeholder="Enter Email" />
</div>
<div class="mt-3">
<label for="password" class="block text-base mb-2">Password</label>
<input type="password" id="password" name="password"
class="border focus:border-gray-600 w-full rounded-md text-base px-2 py-1 focus:outline-none focus:ring-0 "
placeholder="Enter Password" />
<label for="password" class="block text-base mb-2 mt-3">Re-type Password</label>
<input type="password" id="repassword" name="repassword"
class="border focus:border-gray-600 w-full rounded-md text-base px-2 py-1 focus:outline-none focus:ring-0 "
placeholder="Enter Password" />
</div>
<div class="text-red-800 font-bold " id="forgor">
<%= errMessage %>
</div>
<div class="mt-5">
<button type="submit"
class="border-2 border-gray-600 bg-blue-600 text-white py-1 w-full rounded-md hover:bg-transparent hover:text-indigo-700 font-semibold">Signup</button>
</div>
<div class="mt-5 block justify-between items-center">
<label>Already have an account?</label>
<a href="/login" class="text-indigo-600 font-semibold">Login</a>
</div>
</div>
</main>
<%- include("./partials/footer") %>
<%- include("./partials/footer") %>