diff --git a/server/.env.example b/server/.env.example new file mode 100644 index 0000000..ae680ee --- /dev/null +++ b/server/.env.example @@ -0,0 +1,5 @@ +MONGO_URI=mongodb://localhost:27017/finveda +PORT=5000 +EMAIL_ID= +PASS_KEY= +ADMIN_EMAIL_ID= \ No newline at end of file diff --git a/server/.gitignore b/server/.gitignore new file mode 100644 index 0000000..aff6b1d --- /dev/null +++ b/server/.gitignore @@ -0,0 +1,6 @@ +node_modules +./node_modules +.env +package-lock.json +uploads +./uploads \ No newline at end of file diff --git a/server/app.js b/server/app.js new file mode 100644 index 0000000..9b2ee27 --- /dev/null +++ b/server/app.js @@ -0,0 +1,22 @@ +import express from 'express'; +import dotenv from 'dotenv'; +import connectDB from './utils/db.js'; +import cors from 'cors'; +import contactRoutes from './routes/contactRoutes.js'; + +dotenv.config(); +const app = express(); +connectDB(); + +app.use(express.json()); + +// to avoid cross-origin error +app.use(cors()); + +// Serve static files from the uploads directory +app.use('/api/contact', contactRoutes); + +const PORT = process.env.PORT || 5000; +app.listen(PORT, () => { + console.log(`Server running on port ${PORT}`); +}); diff --git a/server/controllers/contactController.js b/server/controllers/contactController.js new file mode 100644 index 0000000..2076e67 --- /dev/null +++ b/server/controllers/contactController.js @@ -0,0 +1,28 @@ +import Contact from '../model/contact.js'; +import { sendMailToAdmin } from '../utils/sendMail.js'; + +export async function saveContact(req, res) { + try { + const { fullName, phoneNumber, email, message } = req.body; + + if (!fullName || !phoneNumber || !email || !message) { + return res.status(400).json({ message: 'All fields are required.' }); + } + + const newContact = new Contact({ fullName, phoneNumber, email, message }); + sendMailToAdmin(newContact); + + await newContact.save(); + + res + .status(201) + .json({ message: 'Contact form submitted successfully!', newContact }); + } catch (error) { + console.error('Error saving contact form:', error); + res.status(500).json({ message: 'Failed to submit contact form.', error }); + } +} + +export async function getContact(req, res) { + res.send('hello contact'); +} diff --git a/server/model/contact.js b/server/model/contact.js new file mode 100644 index 0000000..9cb2189 --- /dev/null +++ b/server/model/contact.js @@ -0,0 +1,34 @@ +import mongoose from 'mongoose'; + +const contactSchema = new mongoose.Schema({ + fullName: { + type: String, + required: true, + trim: true, + }, + phoneNumber: { + type: String, + required: true, + trim: true, + match: [/^\d{10}$/, 'Please enter a valid 10-digit phone number'], + }, + email: { + type: String, + required: true, + trim: true, + match: [/^\S+@\S+\.\S+$/, 'Please enter a valid email address'], + }, + message: { + type: String, + required: true, + trim: true, + }, + createdAt: { + type: Date, + default: Date.now, + }, +}); + +const Contact = mongoose.model('Contact', contactSchema); + +export default Contact; diff --git a/server/package.json b/server/package.json new file mode 100644 index 0000000..813bb3b --- /dev/null +++ b/server/package.json @@ -0,0 +1,24 @@ +{ + "name": "server", + "version": "1.0.0", + "main": "app.js", + "type": "module", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [ + "finveda" + ], + "author": "", + "license": "ISC", + "dependencies": { + "cors": "^2.8.5", + "dotenv": "^16.4.5", + "express": "^4.21.1", + "mongoose": "^8.8.0", + "multer": "^1.4.5-lts.1", + "nodemailer": "^6.9.16", + "nodemon": "^3.1.7" + }, + "description": "" +} diff --git a/server/routes/contactRoutes.js b/server/routes/contactRoutes.js new file mode 100644 index 0000000..3140aad --- /dev/null +++ b/server/routes/contactRoutes.js @@ -0,0 +1,8 @@ +import express from 'express'; +const router = express.Router(); +import { getContact, saveContact } from '../controllers/contactController.js'; + +router.post('/saveContact', saveContact); +router.get('/saveContact', getContact); + +export default router; diff --git a/server/utils/db.js b/server/utils/db.js new file mode 100644 index 0000000..c951c34 --- /dev/null +++ b/server/utils/db.js @@ -0,0 +1,15 @@ +import mongoose from 'mongoose'; +import dotenv from 'dotenv'; +dotenv.config(); + +const connectDB = async () => { + try { + await mongoose.connect(process.env.MONGO_URI); + console.log('MongoDB Connected'); + } catch (error) { + console.error('Database connection error:', error); + process.exit(1); + } +}; + +export default connectDB; diff --git a/server/utils/sendMail.js b/server/utils/sendMail.js new file mode 100644 index 0000000..3b5c100 --- /dev/null +++ b/server/utils/sendMail.js @@ -0,0 +1,71 @@ +import nodemailer from 'nodemailer'; +import 'dotenv/config'; + +const sendMailToAdmin = userdata => { + const transporter = nodemailer.createTransport({ + service: 'gmail', + host: 'smtp.gmail.com', + port: 587, + secure: false, // Use `true` for port 465, `false` for all other ports + auth: { + user: process.env.EMAIL_ID, // Email ID to send the mail + pass: process.env.PASS_KEY, // Passkey + }, + }); + + async function main() { + await transporter.sendMail({ + from: { + name: `GLASSYUI Contact Form - ${new Date().toLocaleString()}`, + address: process.env.EMAIL_ID, + }, // sender address + to: process.env.ADMIN_EMAIL_ID, // list of receivers + subject: 'New Contact Form Submission from GLASSYUI ✔', // Subject line + text: 'GLASSYUI Contact Form Submission', // plain text body + html: `
+
+ GLASSYUI Contact Form Submission +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Field + + Value +
Name${userdata.fullName}
Phone${userdata.phoneNumber}
Email${userdata.email}
Message${userdata.message}
Submitted At${new Date().toLocaleString()}
+
`, // html body + }); + } + + main().catch(console.error); +}; + +// Export as a named export +export { sendMailToAdmin }; diff --git a/src/App.tsx b/src/App.tsx index 67b6847..aff2a75 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -43,7 +43,10 @@ import Statistic from './components/StatisticDetails'; import GalleryDetailsPage from './components/GalleryDetailsPage'; import SpinnerDetailsPage from './components/SpinnerDetailsPage'; import ProductCardDetailsPage from './components/ProductCardDetailsPage'; - + import ContactUs from './components/ContactUs'; + import AiChatbot from './components/AIChatbot'; + import { TermsOfUse } from './components/TermsOfUse'; + const ThemeToggle: React.FC = () => { const [theme, setTheme] = useState(localStorage.getItem('theme') || 'light'); @@ -74,6 +77,7 @@ const App: React.FC = () => { return (
+ {/* */} {/* Add the ScrollProgressBar component here */} @@ -112,14 +116,18 @@ const App: React.FC = () => { } /> } /> } /> - } /> + } /> + } /> + } /> {/* */} ); }; -// const ConditionalFooter: React.FC = () => { -// const location = useLocation(); -// return location.pathname === '/' ?