Skip to content

Commit

Permalink
Add contact form
Browse files Browse the repository at this point in the history
  • Loading branch information
ajaynegi45 committed Dec 8, 2024
1 parent bc5a638 commit 6924ed5
Show file tree
Hide file tree
Showing 16 changed files with 864 additions and 49 deletions.
Binary file added public/MakarSankranti.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/makarsankranti.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
78 changes: 50 additions & 28 deletions src/app/api/auth/register/route.ts
Original file line number Diff line number Diff line change
@@ -1,84 +1,106 @@
import {db} from "@/lib/drizzle";
import {otps, users} from "@/lib/schema";
import {signupSchema} from "@/lib/zod";
import {hash} from "bcryptjs";
import {NextRequest, NextResponse} from "next/server";
import {z} from "zod";

import otpEmailTemplate from "@/lib/templates/otp-template";
import mailer from "@/lib/mailer";


// `[email protected]` email is for development only
import {z} from "zod"; // Zod is a validation library for handling structured data validation
import {hash} from "bcryptjs"; // bcryptjs is used for securely hashing passwords
import {db} from "@/lib/drizzle"; // This imports the database handler from Drizzle ORM
import mailer from "@/lib/mailer"; // This imports the mailer function for sending emails
import {signupSchema} from "@/lib/zod"; // A Zod schema for validating incoming signup data
import {otps, users} from "@/lib/schema"; // Imports the OTP and users tables from the database schema
import {NextRequest, NextResponse} from "next/server"; // These are Next.js server functions for handling HTTP requests and responses
import otpEmailTemplate from "@/lib/templates/otp-template"; // A template for the OTP email

// Define the sender email address for OTP verification emails.
// This is used in the development environment as a fallback if the environment variable is not set.
const senderEmail = process.env.SENDER_EMAIL || "[email protected]";


// POST request handler for user registration
export async function POST(req: NextRequest) {
try {
// Parse the incoming request JSON to extract the user data
const payload = await req.json();

// Validate the request data using the predefined Zod schema
// This checks that the data conforms to the expected types and structure
const {email, name, password, username, alerts} = signupSchema.parse(payload)

// Basic validation to ensure required fields are provided
if (!email || !name || !password || !username) {
return NextResponse.json(
{error: "name, username, email and password are required."},
{status: 400}
);
}

// Check if a user with the same username already exists in the database
const userWithUsername = await db.query.users.findFirst({
where: (users, {eq}) => eq(users.username, username),
});

// If the username already exists, return an error
if (userWithUsername) throw new Error("User with username already exists.");

// Check if a user with the same email already exists
const userWithEmail = await db.query.users.findFirst({
where: (users, {eq}) => eq(users.email, email),
});

// If the email already exists, return an error
if (userWithEmail) throw new Error("User with email already exists.");

// If no duplicates, hash the password for secure storage
const hashedPassword = await hash(password, 10);

// Insert the new user data into the 'users' table in the database
await db.insert(users).values({
username,
email,
name,
password: hashedPassword,
alerts,
username
alerts // 'alerts' is a user setting, likely indicating whether the user wants notifications
});

// Generate a 6-digit OTP (One Time Password) for email verification
const otp = Math.floor(100000 + Math.random() * 900000).toString();

const otp = Math.floor(100000 + Math.random() * 900000).toString(); // 6-digit OTP
// Set expiration time (e.g., 10 minutes from now)
// Set an expiration time for the OTP (10 minutes from now)
const expiresAt = new Date(Date.now() + 10 * 60 * 1000); // 10 minutes in the future

// Fetch the user from the database by email to associate the OTP with the correct user
const user = await db.query.users.findFirst({
where: (users, {eq}) => eq(users.email, email),
})
});

// Insert the OTP and its expiration time into the 'otps' table
await db.insert(otps).values({
expiresAt,
otp,
userId: user!.id,
createdAt: new Date(),
userId: user!.id, // Use the user's ID from the fetched record
createdAt: new Date(), // Set the current time as the creation time of the OTP
});


// Send an email to the user with the OTP for email verification
await mailer.sendMail({
from: `Uttarakhand Culture <${senderEmail}>`,
to: [email],
subject: 'Verify you email with OTP',
html: otpEmailTemplate(name, otp),
})

from: `Uttarakhand Culture <${senderEmail}>`, // From address (e.g., a sender email)
to: [email], // Recipient email
subject: 'Verify you email with OTP', // Email subject
html: otpEmailTemplate(name, otp), // The email body generated using the OTP template
});

// Return a success response indicating the user has been registered
return NextResponse.json({
message: `Registered. Now login!`,
});

} catch (error: any) {
// Handle errors that occur during the registration process

// If the error is a Zod validation error, return the validation error details
if (error instanceof z.ZodError) {
return NextResponse.json({error: error.errors}, {status: 500});
}

// Log unexpected errors to the console for debugging purposes
console.log("[REGISTER_ERROR]: ", error);

// Return a generic error message
return NextResponse.json({error: error.message}, {status: 500});
}
}
}
43 changes: 43 additions & 0 deletions src/app/api/contact/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { NextResponse } from 'next/server';
import mailer from '@/lib/mailer';

export async function POST(request: Request) {
try {
const { name, email, reason, message } = await request.json();

if (!name || !email || !reason || !message) {
return NextResponse.json({ error: 'All fields are required.' }, { status: 400 });
}

// Send the email using Nodemailer
await mailer.sendMail({
from: process.env.SENDER_EMAIL,
to: process.env.CONTACT_FORM_RECEIVER_EMAIL,
subject: `Contact Form: ${reason}`,
html: `
<div style="font-family: Arial, sans-serif; line-height: 1.6; color: #333;">
<h2 style="color: #0070f3;">You Have a New Contact Form Submission</h2>
<p><strong>Name:</strong> ${name}</p>
<p><strong>Email:</strong> ${email}</p>
<p><strong>Reason:</strong> ${reason}</p>
<p><strong>Message:</strong></p>
<blockquote style="background: #f9f9f9; padding: 15px; border-left: 5px solid #0070f3; margin: 10px 0;">
${message}
</blockquote>
<hr style="border: none; border-top: 1px solid #ddd; margin: 20px 0;">
<p style="font-size: 12px; color: #888;">This is an automated email. Please do not reply to this email.</p>
</div>
`,
});

return NextResponse.json({ message: 'Email sent successfully.' }, { status: 200 });
} catch (error) {
console.error('Error sending email:', error);
return NextResponse.json({ error: 'Failed to send email.' }, { status: 500 });
}
}

// Handle other HTTP methods
export async function GET() {
return NextResponse.json({ error: 'Method Not Allowed' }, { status: 405 });
}
7 changes: 4 additions & 3 deletions src/app/auth/page.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@
}

.container {
width: 100%; /* Make the container take full available width */
max-width: 500px; /* Limit the container width to 500px */
/*min-width: 300px; !* Ensure it doesn't go below 300px *!*/
width: 500px; /* Limit the container width to 500px */
margin: 0 auto; /* Center it horizontally */
padding: 40px 30px; /* Add padding */
background-color: #fff; /* Soft white background */
Expand Down Expand Up @@ -150,7 +148,10 @@

/* Responsive design: Stack elements on small screens */
@media (max-width: 480px) {

.container {
max-width: 500px;
width: 100%;
padding: 20px;
}

Expand Down
132 changes: 132 additions & 0 deletions src/app/contactform/ContactForm.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/* Container styles */
.container {
display: flex;
justify-content: center;
align-items: center;
height: 85vh;
box-sizing: border-box;
padding: 20px;
}

/* Card styles */
.card {
background: #ffffff;
border-radius: 12px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
width: 100%;
max-width: 500px;
min-width: 300px;
padding: 20px;
text-align: center;
overflow: hidden;
transition: transform 0.3s ease-in-out;
}

.card:hover {
transform: translateY(-10px);
}

/* Title styles */
.title {
font-size: 26px;
font-weight: 600;
color: #333333;
margin-bottom: 10px;
}

/* Subtitle styles */
.subtitle {
font-size: 16px;
color: #666666;
line-height: 1.6;
}

.lastsubtitle{
font-size: 16px;
color: #666666;
line-height: 1.6;
margin-bottom: 20px;
}

/* Form styles */
.form {
display: flex;
flex-direction: column;
gap: 20px;
}

/* Input group styles */
.inputGroup {
margin-bottom: 15px;
}

/* Label styles */
.label {
font-size: 15px;
font-weight: 500;
color: #333333;
text-align: left;
margin-bottom: 8px;
display: block;
}

/* Input field styles */
.input,
.textarea {
width: 100%;
padding: 12px;
font-size: 15px;
border: 1px solid #cccccc;
border-radius: 6px;
outline: none;
transition: border-color 0.3s ease;
}

.input:focus,
.textarea:focus {
border-color: #0070f3;
}

/* Textarea styles */
.textarea {
height: auto;
min-height: 120px;
resize: vertical;
transition: height 0.2s ease;

}

/* Button styles */
.button {
padding: 12px 24px;
background-color: #333333;
color: #ffffff;
border: none;
border-radius: 6px;
font-size: 16px;
cursor: pointer;
transition: background-color 0.3s ease;
}

.button:hover {
background-color: #444444;
}

/* Status message styles */
.status {
margin-top: 20px;
font-size: 15px;
color: #0070f3;
text-align: center;
}

/* Responsive styles */
@media (max-width: 768px) {
.container {
padding: 10px;
}

.card {
padding: 15px;
}
}
Loading

0 comments on commit 6924ed5

Please sign in to comment.