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

Contact us frontend with email functionality #275

Merged
merged 6 commits into from
Jun 15, 2024
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
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@emailjs/browser": "^4.3.3",
"@react-icons/all-files": "^4.1.0",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
Expand All @@ -12,7 +14,7 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hot-toast": "^2.4.1",
"react-icons": "^4.11.0",
"react-icons": "^4.12.0",
"react-icons-kit": "^2.0.0",
"react-modal": "^3.16.1",
"react-router-dom": "^6.16.0",
Expand Down
Binary file added public/c4.png
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/i9.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 25 additions & 0 deletions server/controllers/Auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@ const User = require("../models/studentLoginInfo");
const jwt = require("jsonwebtoken");
const Canteen = require("../models/canteenLoginInfo");
const Session = require("../models/session");
<<<<<<< HEAD
const Contact = require('../models/Contact');
=======
const {
forgotPasswordToken,
verifyToken,
findUserByEmail,
findUserById,
} = require("../utils/PasswordTokenAndUser");
const nodemailer = require("nodemailer");
>>>>>>> upstream/main

require("dotenv").config();

Expand Down Expand Up @@ -441,6 +445,26 @@ exports.changeCanteenPassword = async (req, res) => {
});
};

<<<<<<< HEAD

//contactUs

exports.saveContactMessage = async (req, res) => {
try {
const { name, email, message } = req.body;
if (!name || !email || !message) {
return res.status(400).send('All fields are required');
}
const newContact = new Contact({ name, email, message });
await newContact.save();
res.status(201).send('Message received');
} catch (error) {
console.error('Error saving message:', error.message, error);
res.status(500).send('Error saving message');
}
};

=======
// verify user for reset password
exports.forgotPassword = async (req, res) => {
try {
Expand Down Expand Up @@ -578,3 +602,4 @@ exports.resetPassword = async (req, res) => {
res.status(500).json("Some error occurred!");
}
};
>>>>>>> upstream/main
11 changes: 11 additions & 0 deletions server/models/Contact.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const mongoose = require('mongoose');

const contactSchema = new mongoose.Schema({
name: { type: String, required: true },
email: { type: String, required: true },
message: { type: String, required: true },
});

const Contact = mongoose.model('Contact', contactSchema);

module.exports = Contact;
7 changes: 7 additions & 0 deletions server/routes/contactRoutes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const express = require('express');
const { saveContactMessage } = require('../controllers/Auth');
const router = express.Router();

router.post('/', saveContactMessage);

module.exports = router;
4 changes: 4 additions & 0 deletions server/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ const cors = require("cors");
var cookieParser = require("cookie-parser");
const PORT = process.env.PORT || 4000;
const cloudinaryConfig = require("./config/cloudinaryConfig");
const contactRoutes = require('./routes/contactRoutes');
const bodyParser = require('body-parser');


app.use(
cors({
Expand All @@ -22,6 +25,7 @@ const uploadFileRouter = require("./routes/uploadFile");
app.use("/api/v1", canteenRoutes);
app.use("/api/v1", studentRoutes);
app.use("/api/v1", uploadFileRouter);
app.use('/api/contact', contactRoutes);

app.listen(PORT, () => {
console.log(`Server started succesfully at ${PORT}`);
Expand Down
7 changes: 7 additions & 0 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,13 @@ import Loader from './components/Loader/Loader';
import ForgotPassword from './pages/ForgotPassword';
import ResetPassword from './pages/ResetPassword';
import { ThemeProvider } from './themeContext';

import ContactUs from './pages/ContactUs';

import { AuthProvider } from './authContext'
import EditProfile from './pages/EditProfile';


const Layout = ({ children }) => {
return (
<div className="bg-cover bg-center min-h-screen bg-gradient-to-t from-blue-950 via-blue-950 to-gray-900 bg-no-repeat dark:bg-none">
Expand All @@ -35,8 +39,11 @@ function App() {
<Route path='/home' element={<Layout><Home /></Layout>} />
<Route path='/login' element={<Login />} />
<Route path='/signup' element={<Signup />} />
<Route path='/contact' element={<ContactUs />} />

<Route path='/forgotPassword' element={<ForgotPassword/>} />
<Route path='/api/v1/newPassword/:id/:token' element={<ResetPassword/>} />

<Route path='/about' element={<Layout><About /></Layout>} />
<Route path='/rateus' element={<Layout><Rateus /></Layout>} />
<Route path='/section/:_id' element={<Layout><SectionPage /></Layout>} />
Expand Down
15 changes: 15 additions & 0 deletions src/components/Navbar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,18 @@ const Navbar = () => {
</div>

<div className="hidden md:block">

<div className="ml-16 flex gap-6 items-baseline space-x-4">

<NavItem to="/home">Home</NavItem>
<NavItem to="/about">About</NavItem>
<NavItem to="/news">News</NavItem>
<NavItem to="/contact">Contact</NavItem>
<NavItem to="/home" icon={<IconHome />}>Home</NavItem>
<NavItem to="/about" icon={<IconAbout />}>About</NavItem>
<NavItem to="/news" icon={<IconNews />}>News</NavItem>
<NavItem to="/rateus" icon={<IconRateUs />}>RateUs</NavItem>

<div className="ml-16 flex gap-6 items-baseline space-x-4 ">
<NavItem to="/home" className="nav-item" icon={<IconHome />}>Home</NavItem>
<NavItem to="/about" className="nav-item" icon={<IconAbout />}>About</NavItem>
Expand Down Expand Up @@ -86,7 +98,10 @@ const Navbar = () => {
<MobileNavItem to="/home">Home</MobileNavItem>
<MobileNavItem to="/about">About us</MobileNavItem>
<MobileNavItem to="/news">News</MobileNavItem>
<MobileNavItem to="/contact">Contact</MobileNavItem>

<MobileNavItem to="/rateus">Rateus</MobileNavItem>

<MobileNavItem to="/">
<Link to="/">
<button
Expand Down
167 changes: 167 additions & 0 deletions src/pages/ContactUs.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
import React, { useRef, useState } from "react";
import { motion } from "framer-motion";
import emailjs from "@emailjs/browser";
import axios from "axios";


const Contact = () => {
const formRef = useRef();
const [form, setForm] = useState({
name: "",
email: "",
message: "",
});

const [loading, setLoading] = useState(false);

const handleChange = (e) => {
const { target } = e;
const { name, value } = target;

setForm({
...form,
[name]: value,
});
};

const handleEmailSubmit = async (e) => {
e.preventDefault();
setLoading(true);

try {
await emailjs.send(
'process.env.SERVICE_ID',//write service id here
'process.env.TEMPLETS_ID',//write templet id here
{
from_name: form.name,
to_name: "FoodiesWeb",
from_email: form.email,
to_email: "[email protected]",
message: form.message,
},
'process.env.PUBLIC_KEY' //write public_key here
);




setLoading(false);
alert("Thank you. I will get back to you as soon as possible.");

setForm({
name: "",
email: "",
message: "",
});
} catch (error) {
setLoading(false);
console.error(error);

alert("Sorry, something went wrong while sending your message. Please try again later.");
}
};
const handleSaveToDB = async (e) => {
e.preventDefault();
setLoading(true);

try {
// Save to MongoDB
await axios.post('http://localhost:3000/api/contact', form);

setLoading(false);
alert("Your message has been saved to the database.");

setForm({
name: "",
email: "",
message: "",
});
} catch (error) {
setLoading(false);
console.error(error);
alert("Sorry, something went wrong while saving your message to the database. Please try again later.");
}
};

return (
<div className="absolute overflow-hidden w-screen h-screen bg-gradient-to-t from-blue-950 via-blue-950 to-gray-950 ">
<p className="text-white font-medium text-4xl pl-10 pt-8">Get in touch</p>
<h3 className="text-white font-medium text-4xl pl-20 pt-3">Contact Us.</h3>
<div
className={`xl:mt-12 pl-64 flex xl:flex-row flex-col-reverse gap-10 overflow-hidden `}
>

<div className="absolute -bottom-32 -left-40 w-80 h-80 border-4 rounded-full border-opacity-30 border-t-8"></div>
<div className="absolute -bottom-40 -left-20 w-80 h-80 border-4 rounded-full border-opacity-30 border-t-8"></div>
<div className="absolute -top-40 -right-0 w-80 h-80 border-4 rounded-full border-opacity-30 border-t-8"></div>
<div className="absolute -top-20 -right-20 w-80 h-80 border-4 rounded-full border-opacity-30 border-t-8"></div>


<div className="ml-20 w-96 h-[20%] px-7 text-black shadow-blue-900 shadow3xl bg-blue-900 bg-gradient-to-t from-gray-900 rounded-3xl">

<form
ref={formRef}
onSubmit={handleEmailSubmit}
className='my-10 flex flex-col gap-8'
>
<label className='flex flex-col '>
<span className=' font-medium mb-2'>Your Name</span>
<input
type='text'
name='name'
value={form.name}
onChange={handleChange}
placeholder="What's your good name?"
className='bg-tertiary py-3 px-6 placeholder:text-secondary rounded-lg outline-none border-none font-medium '
/>
</label>
<label className='flex flex-col'>
<span className=' font-medium mb-2'>Your email</span>
<input
type='email'
name='email'
value={form.email}
onChange={handleChange}
placeholder="What's your web address?"
className='bg-tertiary py-3 px-6 placeholder:text-secondary rounded-lg outline-none border-none font-medium '
/>
</label>
<label className='flex flex-col'>
<span className=' font-medium mb-2'>Your Message</span>
<textarea
rows={5}
name='message'
value={form.message}
onChange={handleChange}
placeholder='What you want to say?'
className='bg-tertiary py-3 px-6 placeholder:text-secondary text-white rounded-lg outline-none border-none font-medium bg-gradient-to-t from-blue-950 via-blue-950 to-gray-900'
/>
</label>

<div className='flex gap-8'>
<button
type='submit'
className='bg-tertiary py-3 px-8 rounded-xl outline-none w-fit text-white font-bold shadow-md shadow-primary bg-cyan-700 hover:scale-[1.1]'
>
{loading ? "Sending..." : "Send_Mail"}
</button>
<button
type='button'
onClick={handleSaveToDB}
className='bg-tertiary py-3 px-8 rounded-xl outline-none w-fit text-white font-bold shadow-md shadow-primary bg-cyan-800 hover:scale-[1.1]'
>
{loading ? "Saving..." : "Submit"}
</button>
</div>
</form></div>
<div className=" -mt-10 ml-10 ">
<img src="/i9.png" className="w-full h-full"/>
</div>

</div><div className="p-10"></div>

</div>
);
};

export default Contact;
27 changes: 27 additions & 0 deletions src/pages/Login.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,33 @@ function Login() {
}

return (
<>
{loading ? (
<Loader />
) : (
<div className="relative h-screen md:flex">
<div className="absolute top-0 right-0 m-3">
<Link to="/contact">
<button
className="hover:shadow-blue-950 hover:shadow-sm text-white py-1 px-2 w-full h-auto text-l relative z-0 rounded-full transition-all duration-200 hover:scale-110"
>
<img src="/c4.png" className="h-10 w-10" />
</button>
</Link>
</div>
<div className="relative overflow-hidden md:flex w-1/2 bg-gradient-to-t from-blue-950 via-blue-950 to-gray-900 bg-no-repeat justify-around items-center hidden">
<div>
<img src={logo} alt="logo" className="w-48 h-12 mb-2" />
<p className="text-white mt-1 ml-3">
Connecting You to Your College Canteens
</p>
</div>
<div className="absolute -bottom-32 -left-40 w-80 h-80 border-4 rounded-full border-opacity-30 border-t-8"></div>
<div className="absolute -bottom-40 -left-20 w-80 h-80 border-4 rounded-full border-opacity-30 border-t-8"></div>
<div className="absolute -top-40 -right-0 w-80 h-80 border-4 rounded-full border-opacity-30 border-t-8"></div>
<div className="absolute -top-20 -right-20 w-80 h-80 border-4 rounded-full border-opacity-30 border-t-8"></div>
</div>

<div className="h-screen md:flex">

<div className="relative overflow-hidden md:flex w-1/2 bg-gradient-to-t from-blue-950 via-blue-950 to-gray-900 bg-no-repeat justify-around items-center hidden">
Expand Down
4 changes: 3 additions & 1 deletion tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
module.exports = {
darkMode: 'class',
content: [
"./src/**/*.{js,jsx,ts,tsx}",
"./index.html",
"./src/**/*.{js,ts,jsx,tsx}",
],

theme: {
extend: {
colors:{
Expand Down
Loading