Skip to content
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
11 changes: 11 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Pull Request Checklist

Before submitting your pull request, please ensure you have completed the following tasks:

- [ ] Code follows the project's style guidelines
- [ ] No commented-out code or debugging statements (e.g., `console.log`)
- [ ] If a documentation update is necessary, have you updated the README and/or the main .env.example
- [ ] Tests have been added or updated to cover changes
- [ ] No sensitive information (e.g., secrets, passwords) is included in the code

Thank you for your contribution!
21 changes: 21 additions & 0 deletions .github/workflows/LintAndTestWorkflow.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: Lint and Test Workflow

on:
pull_request:

jobs:
lint-and-test:
name: Lint and Test
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [20.9]

steps:
- uses: actions/checkout@v3
- name: Set up Node.js ${{ matrix.node-version}}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- run: npm test
- run: npm run lint
Binary file added public/fonts/ThaleahFat.ttf
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { connectToDatabase } from "@/dbConfig/dbConfig";
import User from "@/models/userModel";
import { NextRequest, NextResponse } from "next/server";
import bcrypt from "bcryptjs";
import jwt from "jsonwebtoken";
import { sendMail } from "@/helpers/mailer";

connectToDatabase();
Expand All @@ -20,7 +18,7 @@ export async function POST(request: NextRequest) {
sendMail({ email: user.email, emailType: "REST", userId: user._id });

return NextResponse.json({
message: "Rest Link Send successfully",
message: "Reset Link Send successfully",
success: true,
});
} catch (error: any) {
Expand Down
1 change: 1 addition & 0 deletions src/app/api/users/login/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export async function POST(request: NextRequest) {
);
}
} catch (error: any) {
console.log(error);
return NextResponse.json({ error: error.message }, { status: 500 });
}
}
1 change: 1 addition & 0 deletions src/app/api/users/register/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export async function POST(request: NextRequest) {
savedUser,
});
} catch (error: any) {
console.log(error);
return NextResponse.json({ error: error.message }, { status: 500 });
}
}
3 changes: 2 additions & 1 deletion src/app/api/users/verifyemail/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export async function POST(req: NextRequest) {

// Find the user with the token and ensure the token is still valid (not expired)
const user = await User.findOne({
isVerified: false,
verifyToken: token,
verifyTokenExpiry: { $gt: currentTime }, // Check if verifyTokenExpiry is greater than currentTime
});
Expand All @@ -24,7 +25,7 @@ export async function POST(req: NextRequest) {
}

// Update the user's verification status
user.isverified = true;
user.isVerified = true;
user.verifyToken = undefined;
user.verifyTokenExpiry = undefined;
await user.save();
Expand Down
11 changes: 10 additions & 1 deletion src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,17 @@
}
}

.pixel-font {
font-family: PixelFont, sans-serif;
}

@font-face {
font-family: PixelFont;
src: url("../../public/fonts/ThaleahFat.ttf") format("truetype");
}

body {
background: var(--background);
color: var(--foreground);
font-family: Arial, Helvetica, sans-serif;
font-family: PixelFont, Arial, Helvetica, sans-serif;
}
6 changes: 4 additions & 2 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,10 @@ export default async function RootLayout({
<body
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
>
<Navbar isVerified={isUserVerified} />
{children}
<div className="min-h-screen bg-gradient-to-t from-black to-purple-600">
<Navbar isVerified={isUserVerified} />
{children}
</div>
</body>
</html>
);
Expand Down
78 changes: 75 additions & 3 deletions src/app/login/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,24 @@ export default function LoginPage() {
const [processing, setProcessing] = React.useState(false);

useEffect(() => {
if (user.email.length > 0 && user.password.length > 0) {
if (
user.email.length > 0 &&
user.password.length > 8 &&
/\d/.test(user.password)
) {
setButtonDisabled(false);
} else {
setButtonDisabled(true);
}
}, [user]);

const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setUser({
...user,
[e.target.name]: e.target.value,
});
};

const onLogin = async () => {
try {
setProcessing(true);
Expand All @@ -33,15 +44,76 @@ export default function LoginPage() {
toast.error(
error.response.data.message || "An error occurred during login."
);
console.log(error);
} finally {
setProcessing(false);
}
};

return (
// flex direction column, justify center, min height screen, black background, padding y-axis 12
<div className="flex flex-col justify-center min-h-screen bg-gradient-to-t from-black to-purple-600 py-12">
<div>
<Toaster position="top-left" reverseOrder={false} />
<div className="w-full max-w-xl bg-gradient-to-b from-black-900 to-purple-600 mx-auto mt-20 p-6 rounded-lg shadow-xl">
<form className="space-y-8">
<h1 className="text-4xl text-black flex justify-center">Sign In</h1>
<div>
<label htmlFor="email" className="block mb-2 text-2xl text-black">
Email
</label>
<input
type="email"
name="email"
id="email"
onChange={handleInputChange}
value={user.email}
placeholder="youremail@example.com"
className="rounded bg-purple-500 w-full px-3 py-1 font-mono text-black"
></input>
</div>
<div>
<label
htmlFor="password"
className="block mb-2 text-2xl text-black"
>
Password
</label>
<input
type="password"
name="password"
id="password"
value={user.password}
onChange={handleInputChange}
placeholder="••••••••••••••••"
className="rounded bg-purple-500 w-full px-3 py-1 font-mono text-black"
></input>
</div>
<div className="flex justify-center">
<button
type="button"
className="bg-purple-500 hover:bg-purple-300 transition-colors duration-200 text-black text-xl py-2 px-4 rounded flex justify-center"
onClick={onLogin}
disabled={buttonDisabled || processing}
>
Login
</button>
</div>
<div className="flex justify-between items-center font-mono text-sm">
<Link
href="/register"
className="text-blue-400 hover:text-purple-300 transition-colors duration-200 align-left"
>
{/* eslint-disable-next-line react/no-unescaped-entities */}
Don't have an account? Sign up
</Link>
<Link
href="/forgotpassword"
className="text-blue-400 hover:text-purple-300 transition-colors duration-200 align-right"
>
Forgot your password? Reset it
</Link>
</div>
</form>
</div>
</div>
);
}
4 changes: 2 additions & 2 deletions src/app/navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export default function Navbar({ isVerified }: { isVerified: boolean }) {

return (
<nav
className="block w-full max-w-screen px-4 py-4 mx-auto bg-white bg-opacity-10 position-fixed top-0 left-0 z-50 menu-toggle"
className="w-full max-w-screen px-4 py-4 mx-auto flex top-0 left-0 z-50 menu-toggle justify-center"
onClick={toggleMenu}
>
<button className="menu-toggle" onClick={toggleMenu}>
Expand All @@ -28,7 +28,7 @@ export default function Navbar({ isVerified }: { isVerified: boolean }) {
<Link
key={item}
href={`/${item.toLowerCase()}`}
className="mx-2 text-purple-500 hover:text-gray-300"
className="text-3xl mx-2 text-black hover:text-gray-300 transition-colors duration-200"
>
{item}
</Link>
Expand Down
134 changes: 134 additions & 0 deletions src/app/register/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
"use client";
import Link from "next/link";
import React, { useEffect } from "react";
import axios from "axios";
import { useRouter } from "next/navigation";
import toast, { Toaster } from "react-hot-toast";

export default function RegisterPage() {
const router = useRouter();
const [user, setUser] = React.useState({
username: "",
email: "",
password: "",
});

const [buttonDisabled, setButtonDisabled] = React.useState(true);
const [processing, setProcessing] = React.useState(false);

useEffect(() => {
if (
user.email.length > 0 &&
user.password.length > 8 &&
/\d/.test(user.password) &&
user.username.length > 0
) {
setButtonDisabled(false);
} else {
setButtonDisabled(true);
}
}, [user]);

const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setUser({
...user,
[e.target.name]: e.target.value,
});
};

const onRegister = async () => {
try {
setProcessing(true);
const userdata = await axios.post("/api/users/register", user);
console.log(userdata.data);
toast.success(userdata.data.message);
// add 3 seconds delay
setTimeout(() => {
router.push("/login");
}, 3000);
} catch (error: any) {
console.log(error.message);
toast.error(error.message);
} finally {
setProcessing(false);
}
};

return (
<div>
<Toaster position="top-left" reverseOrder={false} />
<div className="w-full max-w-xl bg-gradient-to-b from-black-900 to-purple-600 mx-auto mt-20 p-6 rounded-lg shadow-xl">
<form className="space-y-8">
<h1 className="text-4xl text-black flex justify-center">Sign Up</h1>
<div>
<label htmlFor="email" className="block mb-2 text-2xl text-black">
Email
</label>
<input
type="email"
name="email"
id="email"
onChange={handleInputChange}
value={user.email}
placeholder="youremail@example.com"
className="rounded bg-purple-500 w-full px-3 py-1 font-mono text-black"
></input>
</div>
<div>
<label
htmlFor="username"
className="block mb-2 text-2xl text-black"
>
Username
</label>
<input
type="text"
name="username"
id="username"
onChange={handleInputChange}
value={user.username}
placeholder="yourusername"
className="rounded bg-purple-500 w-full px-3 py-1 font-mono text-black"
></input>
</div>
<div>
<label
htmlFor="password"
className="block mb-2 text-2xl text-black"
>
Password
</label>
<input
type="password"
name="password"
id="password"
value={user.password}
onChange={handleInputChange}
placeholder="••••••••••••••••"
className="rounded bg-purple-500 w-full px-3 py-1 font-mono text-black"
></input>
</div>
<div className="flex justify-center">
<button
type="button"
className="bg-purple-500 hover:bg-purple-300 transition-colors duration-200 text-black text-xl py-2 px-4 rounded flex justify-center"
onClick={onRegister}
disabled={buttonDisabled || processing}
>
Register
</button>
</div>
<div className="flex justify-center items-center font-mono text-sm">
<Link
href="/login"
className="text-blue-400 hover:text-purple-300 transition-colors duration-200"
>
{/* eslint-disable-next-line react/no-unescaped-entities */}
Have an account? Sign in
</Link>
</div>
</form>
</div>
</div>
);
}
Loading
Loading