diff --git a/backend/index.js b/backend/index.js index 6e8f3aef..a6404fc8 100644 --- a/backend/index.js +++ b/backend/index.js @@ -4,6 +4,8 @@ const app = express(); const cors = require("cors"); const test = require("./trackingParcel/parcelRoutes/routes"); const saveParcelRoute = require("./trackingParcel/parcelRoutes/saveParcelRoute"); +const supplierRouter = require('./routes/suppliers.js'); +const orderRouter = require('./routes/orders.js'); // Middleware section app.use(cors()); @@ -27,5 +29,8 @@ app.listen(port, () => { console.log(`Server is running on port ${port}`); }); +app.use("/supplier",supplierRouter); +app.use("/order",orderRouter); + app.use(test); app.use(saveParcelRoute); diff --git a/backend/supplierManagement/models/order.js b/backend/supplierManagement/models/order.js new file mode 100644 index 00000000..91f3dbb8 --- /dev/null +++ b/backend/supplierManagement/models/order.js @@ -0,0 +1,17 @@ +const mongoose=require('mongoose'); + +const Schema=mongoose.Schema; + +const oredrSchema=new Schema({ + + oid:{type:Number,unique:true,required:true}, + supplier:{type:String,required:true}, + date:{type:Date,required:true}, + bname:{type:String,required:true}, + quantity:{type:Number,required:true} + +}) + +const order=mongoose.model("order",oredrSchema); + +module.exports = order; \ No newline at end of file diff --git a/backend/supplierManagement/models/supplier.js b/backend/supplierManagement/models/supplier.js new file mode 100644 index 00000000..99b6bae5 --- /dev/null +++ b/backend/supplierManagement/models/supplier.js @@ -0,0 +1,18 @@ +const mongoose=require('mongoose'); + +const Schema=mongoose.Schema; + +const supplierSchema=new Schema({ + + name:{type:String,required:true}, + nic:{type:String,unique:true,required:true}, + address:{type:String,required:true}, + mobile:{type:Number,required:true}, + email:{type:String,required:true}, + wname:{type:String,required:true} + +}) + +const supplier=mongoose.model("Supplier",supplierSchema); + +module.exports = supplier; \ No newline at end of file diff --git a/backend/supplierManagement/routes/orders.js b/backend/supplierManagement/routes/orders.js new file mode 100644 index 00000000..b4c88379 --- /dev/null +++ b/backend/supplierManagement/routes/orders.js @@ -0,0 +1,107 @@ +const router= require( 'express').Router(); +let order=require('../models/order') + +router.route('/add').post((req, res)=>{ + + const oid =req.body.oid; + const supplier =req.body.supplier; + const date = req.body.date; + const bname = req.body.bname; + const quantity = req.body.quantity ; + + const newOrder=new order({ + + oid, + supplier, + date, + bname, + quantity + }) + + newOrder.save() + .then(()=>{ + res.json("order submitted") + }).catch((err)=> {res.status(400).send("unable to submit order")}) +}) + +router.route("/").get((req, res) => { + + order.find().then((orders)=>{ + res.json(orders) + + }).catch((err)=>{ + console.log(err) + }) +}) + + + +router.route("/update/:oid").put(async(req,res)=>{ + + let orderId=req.params.oid; + const{oid,supplier,date,bname,quantity}=req.body; + + const updateOrder={ + oid, + supplier, + date, + bname, + quantity + } + const update=await order.findOneAndUpdate({ oid: orderId }, updateOrder, { new: true }); + if(!update){ + return res.status(404).send('No order found') + }else{ + + return res.status(200).send({status:"order updated"}); + } +}) + + +router.route("/delete/:oid").delete(async(req,res)=>{ + + try{ + let orderId=req.params.oid; + const deleteorder = await order.findOneAndDelete({oid:orderId}); + + if (deleteorder) { + res.status(200).send({ status: 'Deleted' }); + + } else { + res.status(404).send({ status: "Supplier not found" }); + }} + catch (err) { + res.status(500).send({ status: "Error in deleting" }); + console.log(err); + } +}) + +// delete all +router.route('/delete'). delete(async(req, res) => { + try { + await order.deleteMany({}); // Delete all documents in the Order collection + res.status(200).send({ status: 'All orders deleted' }); + console.log(res); + } catch (err) { + res.status(500).send({ status: 'Error in deleting' }); + console.error(err); + } +}); + + +router.route("/get/:oid").get(async(req,res)=>{ + let orderId = req.params.oid; // Corrected variable name + try { + const foundOrder = await order.findOne({ oid: orderId }); + + if (!foundOrder) { + return res.status(404).send({ status: 'Order not found' }); + } + + return res.status(200).send({ status: 'Order fetched', order: foundOrder }); + } catch (error) { + console.error(error); + return res.status(500).send({ status: "Error in fetch", error: error.message }); + } +}); +module.exports=router; diff --git a/backend/supplierManagement/routes/suppliers.js b/backend/supplierManagement/routes/suppliers.js new file mode 100644 index 00000000..77e6ca9a --- /dev/null +++ b/backend/supplierManagement/routes/suppliers.js @@ -0,0 +1,138 @@ +const router= require( 'express').Router(); +const nodemailer = require('nodemailer'); +require('dotenv').config(); +let supplier=require('../models/supplier') + +router.route('/add').post((req, res)=>{ + + const name =req.body.name; + const nic =req.body.nic; + const address = req.body.address; + const mobile = Number(req.body.mobile); + const email= req.body.email; + const wname = req.body.wname; + + const newSupplier=new supplier({ + + name, + nic, + address, + mobile, + email, + wname + }) + + newSupplier.save() + .then(()=>{ + res.json("Supplier added") + }).catch((err)=> {res.status(400).send("unable to add Supplier")}) +}) + +router.route("/").get((req, res) => { + + supplier.find().then((suppliers)=>{ + res.json(suppliers) + + }).catch((err)=>{ + console.log(err) + }) +}) + + + +router.route("/update/:nic").put(async(req,res)=>{ + + let userNic=req.params.nic; + const{name,nic,address,mobile,email,wname}=req.body; + + const updateSupplier={ + name, + nic, + address, + mobile, + email, + wname + } + const update=await supplier.findOneAndUpdate({ nic: userNic }, updateSupplier, { new: true }); + if(!update){ + return res.status(404).send('No User found') + }else{ + + return res.status(200).send({status:"user updated"}); + } +}) + + +router.route("/delete/:nic").delete(async (req, res) => { + try { + const userNic = req.params.nic; + + const deletedSupplier = await supplier.findOneAndDelete({ nic: userNic }); + + if (deletedSupplier) { + res.status(200).send({ status: 'Deleted' }); + + } else { + res.status(404).send({ status: "Supplier not found" }); + } + } catch (err) { + res.status(500).send({ status: "Error in deleting" }); + console.log(err); + } +}); + + + + +router.route("/get/:nic").get(async(req,res)=>{ + let userId = req.params.nic; + try { + const founduser = await supplier.findOne({ nic: userId }); + + if (!founduser) { + return res.status(404).send({ status: 'user not found' }); + } + + return res.status(200).send({ status: 'user fetched', order: founduser }); + } catch (error) { + console.error(error); + return res.status(500).send({ status: "Error in fetch", error: error.message }); + } +}); + + + +const transporter = nodemailer.createTransport({ + service: 'Gmail', + host: "smtp.gmail.com", + port: 587, + secure: false, + requireTLS: true, + auth: { + user: process.env.GMAIL_USER, + pass: process.env.GMAIL_PASS + } + }); + + router.route("/Sendmail").post(async(req, res) => { + const { name, email, message } = req.body; + + const mailOptions = { + from: process.env.GMAIL_USER, + to: email, + subject: 'New message from your website contact form', + text: `Name: ${name}\nEmail: ${email}\n\nMessage:\n${message}` + }; + + transporter.sendMail(mailOptions, (error, info) => { + if (error) { + console.log(error); + console.error('Error sending email:', error); + res.status(500).send('Error sending email'); + } else { + console.log('Email sent successfully:', info.response); + res.status(200).send('Email sent successfully'); + } + }); + }); +module.exports=router; diff --git a/frontend/src/supplierComponents/AddOrder.js b/frontend/src/supplierComponents/AddOrder.js new file mode 100644 index 00000000..cd61b4da --- /dev/null +++ b/frontend/src/supplierComponents/AddOrder.js @@ -0,0 +1,168 @@ +import React, { useState, useRef } from "react"; +import axios from 'axios'; +import emailjs from '@emailjs/browser'; +import { useNavigate, useParams } from "react-router-dom"; +import DatePicker from "react-datepicker"; +import "react-datepicker/dist/react-datepicker.css"; + +function AddOrder() { + // State variables + const [oid, setOid] = useState(""); + const [supplier, setSupplier] = useState(""); + const [bname, setBname] = useState(""); + const [quantity, setQuantity] = useState(""); + const [selectedDate, setSelectedDate] = useState(new Date()); + const [errors, setErrors] = useState({}); + const form = useRef(); + + + // Function to send data to the server + + const navigate= useNavigate(); + + const sendData = (e) => { + e.preventDefault(); + const newOrder = { + oid, + supplier, + date: selectedDate, + bname, + quantity + }; + + axios.post('http://localhost:5000/order/add', newOrder) + .then(() => { + alert("Successfully added the order"); + navigate('/allOrders'); + }) + .catch((err) => { + alert(err); + }); + }; + + // Function to send email + const sendEmail = (e) => { + e.preventDefault(); + emailjs.sendForm('service_emxur9p', 'template_7o4wl1g', form.current, { + publicKey: 'LTu5eL1Qw36dHobjH', + }).then( + () => { + console.log('SUCCESS!'); + }, + (error) => { + console.log('FAILED...', error.text); + }, + ); + }; + + // Function to handle form submission + const handleSubmit = (e) => { + e.preventDefault(); + const errors = validateForm(); + if (Object.keys(errors).length === 0) { + sendData(e); + sendEmail(e); + } else { + setErrors(errors); + } + }; + + // Function to validate form fields + const validateForm = () => { + const errors = {}; + if (!oid.trim()) { + errors.oid = "Order ID is required"; + } else if (isNaN(oid.trim())) { + errors.oid = "Order ID must be a number"; + } + + if (!supplier.trim()) { + errors.supplier = "Supplier name is required"; + } + if (!bname.trim()) { + errors.bname = "Brand name is required"; + } + if (!quantity.trim()) { + errors.quantity = "Quantity is required"; + } else if (parseInt(quantity) <= 0) { + errors.quantity = "Quantity should not be a negative value"; + } + return errors; + }; + + return ( +
+
+
+
+

Add New Order

+
+ + setOid(e.target.value)} + /> + {errors.oid &&
{errors.oid}
} +
+
+ + setSupplier(e.target.value)} + /> + {errors.supplier &&
{errors.supplier}
} +
+
+ + setSelectedDate(date)} + dateFormat="dd/MM/yyyy" + className="form-control" + minDate={new Date()} + /> +
+
+ + setBname(e.target.value)} + /> + {errors.bname &&
{errors.bname}
} +
+
+ + setQuantity(e.target.value)} + /> + {errors.quantity &&
{errors.quantity}
} +
+ +
+
+
+
+ ); +} + +export default AddOrder; diff --git a/frontend/src/supplierComponents/AddSupp.js b/frontend/src/supplierComponents/AddSupp.js new file mode 100644 index 00000000..4f1c6e69 --- /dev/null +++ b/frontend/src/supplierComponents/AddSupp.js @@ -0,0 +1,162 @@ +import React, { useState } from "react"; +import axios from 'axios'; +import { useNavigate, useParams } from "react-router-dom"; + + +function AddSupp() { + const [name, setName] = useState(""); + const [nic, setNic] = useState(""); + const [address, setAddress] = useState(""); + const [mobile, setMobile] = useState(""); + const [email, setEmail] = useState(""); + const [wname, setWname] = useState(""); + + const [errors, setErrors] = useState({}); + + function validateForm() { + const errors = {}; + if (!name.trim()) { + errors.name = "Name is required"; + } else if (!/^[a-zA-Z\s]+$/.test(name.trim())) { + errors.name = "Name must contain only letters and spaces"; + } + + if (!nic.trim()) { + errors.nic = "NIC is required"; + } else if (!/^\d{12}$/.test(nic)) { + errors.nic = "NIC should be 12 digits"; + } + + if (!address.trim()) { + errors.address = "Address is required"; + } + if (!mobile.trim()) { + errors.mobile = "Mobile number is required"; + } else if (!/^\d{10}$/.test(mobile.trim())) { + errors.mobile = "Mobile number must be 10 digits"; + } + if (!email.trim()) { + errors.email = "Email is required"; + } else if (!/\S+@\S+\.\S+/.test(email.trim())) { + errors.email = "Invalid email address"; + } + + if (!wname.trim()) { + errors.wname = "Warehouse name is required"; + } + setErrors(errors); + return Object.keys(errors).length === 0; + } + const navigate= useNavigate(); + + function sendData(e) { + e.preventDefault(); + + if (validateForm()) { + const newSupplier = { name, nic, address, mobile,email, wname }; + + axios.post('http://localhost:5000/supplier/add', newSupplier) + .then(() => { + alert("Successfully added the supplier"); + navigate('/'); + }) + .catch((err) => { + alert(err); + }); + } + } + + return ( +
+
+
+
+

Add New Supplier

+
+ + setName(e.target.value)} + + /> + {errors.name &&
{errors.name}
} +
+ +
+ + setNic(e.target.value)} + + /> + {errors.nic &&
{errors.nic}
} +
+ +
+ + setAddress(e.target.value)} + /> + {errors.address &&
{errors.address}
} +
+ +
+ + setMobile(e.target.value)} + /> + {errors.mobile &&
{errors.mobile}
} +
+
+ + setEmail(e.target.value)} + /> + {errors.email &&
{errors.email}
} +
+ +
+ + setWname(e.target.value)} + /> + {errors.wname &&
{errors.wname}
} +
+ +
+
+
+
+ + ); +} + +export default AddSupp; diff --git a/frontend/src/supplierComponents/AllOrders.js b/frontend/src/supplierComponents/AllOrders.js new file mode 100644 index 00000000..1754d4ff --- /dev/null +++ b/frontend/src/supplierComponents/AllOrders.js @@ -0,0 +1,111 @@ +import React, {useState,useEffect, useRef} from "react"; +import axios from "axios"; +import { Link } from "react-router-dom"; +import {useReactToPrint} from "react-to-print"; + + export default function AllOrders(){ + + const [orders,setOrders]=useState([]); + + useEffect(()=>{ + + function getOrders(){ + + axios.get('http://localhost:5000/order/').then((res)=>{ + + setOrders(res.data) + }).catch((err)=>{ + + alert(err) + }) + } + getOrders(); + },[]) + + + const deleteOrder = (oid) => { + const isConfirmed = window.confirm("Are you sure you want to delete this Order?"); + if (isConfirmed) { + axios.delete(`http://localhost:5000/order/delete/${oid}`) + .then((res) => { + window.location.reload(); + + + }) + .catch((err) => { + alert(err); + }); + } + }; + const clearAll = () => { + const isConfirmed = window.confirm("Are you sure you want to delete all orders?"); + if (isConfirmed) { + axios.delete(`http://localhost:5000/order/delete`) + .then((res) => { + window.location.reload(); + alert("All orders deleted"); + }) + .catch((err) => { + alert(err); + }); + } + }; + + + const ComponentsRef = useRef(); + + const handlePrint = useReactToPrint({ + content:()=> ComponentsRef.current, + DocumentTitle:"Order Report", + onafterprint:(e)=>alert("Printed") + + }) + + return( + +
+
+

All Orders

+ + + + +
+ +
+ + + + + + + + + + + + + {orders.map((order, index) => ( + + + + + + + + + + Edit + + + + ))} + +
Order IDsupllierDateBrand NameQuantity.
{order.oid}{order.supplier}{order.date}{order.bname}{order.quantity}
+
+
+ + + ) + + } \ No newline at end of file diff --git a/frontend/src/supplierComponents/AllSup.js b/frontend/src/supplierComponents/AllSup.js new file mode 100644 index 00000000..c96bc821 --- /dev/null +++ b/frontend/src/supplierComponents/AllSup.js @@ -0,0 +1,108 @@ +import React, {useState,useEffect} from "react"; +import axios from "axios"; +import { Link } from "react-router-dom"; + + export default function AllSup(){ + + const [suppliers,setSuppliers]=useState([]); + + useEffect(()=>{ + + function getSuppliers(){ + + axios.get('http://localhost:5000/supplier/').then((res)=>{ + + setSuppliers(res.data) + }).catch((err)=>{ + + alert(err) + }) + } + getSuppliers(); + },[]) + + const deleteSupplier = (nic) => { + const isConfirmed = window.confirm("Are you sure you want to delete this supplier?"); + if (isConfirmed) { + axios.delete(`http://localhost:5000/supplier/delete/${nic}`) + .then((res) => { + window.location.reload(); + + }) + .catch((err) => { + alert(err); + }); + } + }; + + + const [searchQuery, setSearchQuery] = useState(""); + const [noResults, setNoResults]=useState(false); + + const handleSearch = (e) => { + const filteredSuppliers = suppliers.filter((supplier) => + Object.values(supplier).some((field) => + field.toString().toLowerCase().includes(searchQuery.toLowerCase()) + ) + ); + setSuppliers(filteredSuppliers); + setNoResults(filteredSuppliers.length === 0); + }; + + + return( + +
+

All Suppliers

+ +
+ setSearchQuery(e.target.value)} + type="text" + name="search" + placeholder="Search Supplier"> + + +
+
+ {noResults ? ( + +
+

No user

+
+ ):( + + + + + + + + + + + + + {suppliers.map((supplier, index) => ( + + + + + + + + + + ))} + +
NameNICAddressMobileEmailWarehouse Name
{supplier.name}{supplier.nic}{supplier.address}{supplier.mobile}{supplier.email}{supplier.wname} + Edit + + Mail + +
+ )} +
+
+ ) + + } \ No newline at end of file diff --git a/frontend/src/supplierComponents/UpdateOrder.js b/frontend/src/supplierComponents/UpdateOrder.js new file mode 100644 index 00000000..fb1d38b4 --- /dev/null +++ b/frontend/src/supplierComponents/UpdateOrder.js @@ -0,0 +1,143 @@ +import React, { useState, useEffect } from "react"; +import axios from "axios"; +import { useNavigate, useParams } from "react-router-dom"; + +function UpdateOrder() { + const { oid } = useParams(); + const [values, setValues] = useState({ + oid: oid || "", + supplier: "", + date: "", + bname: "", + quantity: "" + }); + + const [errors, setErrors] = useState({}); // State to hold validation errors + + useEffect(() => { + axios.get(`http://localhost:5000/order/get/${oid}`) + .then((res) => { + console.log("Response data:", res.data); + + setValues({ + ...values, + oid: res.data.order.oid, + supplier: res.data.order.supplier, + date: res.data.order.date, + bname: res.data.order.bname, + quantity: res.data.order.quantity + }); + console.log("Updated values:", values); + }) + .catch((err) => { + console.error("Error fetching supplier:", err); + setValues({ ...values, oid: "Error fetching NIC" }); + }); + },[oid]); + + const navigate= useNavigate(); + + const handleSubmit = (e) => { + e.preventDefault(); + // Validate form fields + const validationErrors = {}; + if (!values.supplier.trim()) { + validationErrors.supplier = "Supplier is required"; + } + if (!values.bname.trim()) { + validationErrors.bname = "Brand Name is required"; + } + if (!values.quantity.toString().trim()) { + validationErrors.quantity = "Quantity is required"; + } else if (parseInt(values.quantity) < 0) { + validationErrors.quantity = "Quantity cannot be negative"; + } + + + if (Object.keys(validationErrors).length === 0) { + // If no errors, submit the form + axios.put(`http://localhost:5000/order/update/${oid}`, values) + .then((res) => { + console.log("order updated successfully:", res.data); + navigate('/allOrders'); + }) + .catch((err) => { + console.error("Error updating order:", err); + }); + } else { + // If there are errors, set the errors state + setErrors(validationErrors); + } + } + + + return ( +
+
+
+

Update Order Details

+
+
+ + +
+
+ + setValues({ ...values, supplier: e.target.value })} + /> + {errors.supplier &&
{errors.supplier}
} +
+
+ + +
+ +
+ + setValues({ ...values, bname: e.target.value })} /> + {errors.bname &&
{errors.bname}
} +
+
+ + setValues({ ...values, quantity: e.target.value })} + /> + {errors.quantity &&
{errors.quantity}
} +
+ +
+
+
+
+ ); +} + +export default UpdateOrder; diff --git a/frontend/src/supplierComponents/UpdateSupplier.js b/frontend/src/supplierComponents/UpdateSupplier.js new file mode 100644 index 00000000..f3e67298 --- /dev/null +++ b/frontend/src/supplierComponents/UpdateSupplier.js @@ -0,0 +1,161 @@ +import React, { useState, useEffect } from "react"; +import axios from "axios"; +import { useNavigate, useParams } from "react-router-dom"; + +function UpdateSupplier() { + const { nic } = useParams(); + const [values, setValues] = useState({ + name: "", + nic: nic || "", + address: "", + mobile: "", + email:"", + wname: "" + }); + + const [errors, setErrors] = useState({}); // State to hold validation errors + + useEffect(() => { + axios.get(`http://localhost:5000/supplier/get/${nic}`) + .then((res) => { + console.log("Response data:", res.data); + + setValues({ + ...values, + name: res.data.order.name, + address: res.data.order.address, + mobile: res.data.order.mobile, + email: res.data.order.email, + wname: res.data.order.wname + }); + console.log("Updated values:", values); + }) + .catch((err) => { + console.error("Error fetching supplier:", err); + setValues({ ...values, nic: "Error fetching NIC" }); + }); + },[nic]); + + const navigate= useNavigate(); + + const handleSubmit = (e) => { + e.preventDefault(); + + // Validate form fields + const validationErrors = {}; + const nicRegex = /^\d{12}$/; + const mobileRegex = /^\d{10}$/; + + if (!values.name.trim()) { + validationErrors.name = "Name is required"; + } + if (!nicRegex.test(values.nic.trim())) { + validationErrors.nic = "NIC should be 12 digits"; + } + if (!values.address.trim()) { + validationErrors.address = "Address is required"; + } + if (!mobileRegex.test(values.mobile.toString().trim())) { + validationErrors.mobile = "Mobile number should be 10 digits"; + } + if (values.email && !/^\S+@\S+\.\S+$/.test(values.email)) { + validationErrors.email = "Invalid email address"; + } + + if (Object.keys(validationErrors).length === 0) { + // If no errors, submit the form + axios.put(`http://localhost:5000/supplier/update/${nic}`, values) + .then((res) => { + console.log("Supplier updated successfully:", res.data); + navigate('/'); + }) + .catch((err) => { + console.error("Error updating supplier:", err); + }); + } else { + // If there are errors, set the errors state + setErrors(validationErrors); + } + } + + return ( +
+
+
+

Update Supplier Details

+
+
+ + setValues({ ...values, name: e.target.value })} + /> + {errors.name &&
{errors.name}
} +
+
+ + + {errors.nic &&
{errors.nic}
} +
+
+ + setValues({ ...values, address: e.target.value })} + /> + {errors.address &&
{errors.address}
} +
+
+ + setValues({ ...values, mobile: e.target.value })} + /> + {errors.mobile &&
{errors.mobile}
} +
+
+ + setValues({ ...values, email: e.target.value })} + /> + {errors.email &&
{errors.email}
} +
+
+ + setValues({ ...values, wname: e.target.value })} + /> +
+ +
+
+
+
+ ); +} + +export default UpdateSupplier; diff --git a/frontend/src/supplierComponents/sendmail.js b/frontend/src/supplierComponents/sendmail.js new file mode 100644 index 00000000..8bccd0c9 --- /dev/null +++ b/frontend/src/supplierComponents/sendmail.js @@ -0,0 +1,78 @@ +import React, { useState, useEffect } from "react"; +import axios from "axios"; +import { useNavigate, useParams } from "react-router-dom"; + + +function Sendmail() { + + const { nic } = useParams(); + + const [formData, setFormData] = useState({ + name: '', + nic: nic || "", + email: '', + message: '' + }); + + useEffect(() => { + axios.get(`http://localhost:5000/supplier/get/${nic}`) + .then((res) => { + console.log("Response data:", res.data); + + setFormData({ + ...formData, + name: res.data.order.name, + email: res.data.order.email, + }); + console.log("Updated values:", formData); + }) + .catch((err) => { + console.error("Error fetching supplier:", err); + setFormData({ ...formData, nic: "Error fetching NIC" }); + }); + },[nic]); + + const handleChange = (e) => { + setFormData({ ...formData, [e.target.name]: e.target.value }); + }; + + const handleSubmit = async (e) => { + e.preventDefault(); + try { + await axios.post('http://localhost:5000/supplier/Sendmail', formData); + alert("Email sent successfully!") + console.log('Email sent successfully!'); + + } catch (error) { + console.log(formData); + alert(error) + console.error('Error sending email:', error); + } + }; + + + + return( + + +
+
+
+

Send Mail

+ + + + + + + + +