Skip to content

Commit

Permalink
Merge pull request #890 from haseebzaki-07/new_branch_7
Browse files Browse the repository at this point in the history
Add email rental confirmation
  • Loading branch information
manikumarreddyu authored Nov 8, 2024
2 parents 829cab1 + c60efa2 commit 7de8787
Show file tree
Hide file tree
Showing 5 changed files with 226 additions and 16 deletions.
69 changes: 69 additions & 0 deletions backend/controllers/rent/RentOrderController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@

const nodemailer = require('nodemailer');

const sendOrderConfirmationEmail = async (userDetails, cartItems, totalPrice, trackingID) => {
// Create a transporter using Gmail's SMTP server
const transporter = nodemailer.createTransport({
service: 'gmail', // Use your email service provider (e.g., 'gmail', 'smtp.mailtrap.io', etc.)
auth: {
user: process.env.EMAIL_USER, // Replace with your Gmail email address
pass: process.env.EMAIL_PASS, // Replace with your Gmail password or App Password
},
});

// Define the email details
const mailOptions = {
from: '[email protected]', // Sender's email
to: userDetails.email, // Recipient's email
subject: 'Order Confirmation',
html: `
<h1>Order Confirmation</h1>
<p>Thank you for your order, ${userDetails.name}!</p>
<h3>Your Order Details</h3>
<ul>
${cartItems
.map(
(item) => `
<li>
<strong>${item.name}</strong> - ${item.quantity} x ₹${item.price} = ₹${item.quantity * item.price}
</li>`
)
.join('')}
</ul>
<h3>Total Price: ₹${totalPrice}</h3>
<p>Your tracking ID: <strong>${trackingID}</strong></p>
<p>Your order will be processed shortly. Thank you!</p>
`,
};

// Send the email
try {
await transporter.sendMail(mailOptions);
console.log('Confirmation email sent successfully.');
} catch (error) {
console.error('Error sending email:', error);
throw error;
}
};

exports.OrderConfirmation = async (req, res) => {
try {
const { userDetails, cartItems, totalPrice } = req.body;

// Generate a random tracking ID
const trackingID = 'TRK' + Math.random().toString(36).substr(2, 9).toUpperCase();

// Send the confirmation email
await sendOrderConfirmationEmail(userDetails, cartItems, totalPrice, trackingID);

res.status(200).json({
message: 'Order confirmed! A confirmation email has been sent.',
trackingID,
});
} catch (error) {
console.error('Error sending email:', error);
res.status(500).json({ message: 'Failed to send confirmation email.' });
}
};


2 changes: 2 additions & 0 deletions backend/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const discussionRoutes = require('./routes/discussionRoutes');
const rentProductRoutes = require('./routes/rent/rentProductRoutes');
const rentWishlistRoutes = require('./routes/rent/rentWishlistRoutes');
const rentCartRoutes = require('./routes/rent/rentCartRoutes');
const rentOrderRoutes = require('./routes/rent/rentOrderRoutes');

const { sendEmail } = require('./services/emailService');
const session = require('express-session');
Expand Down Expand Up @@ -47,6 +48,7 @@ app.use('/api', shopRoutes);
app.use('/api', rentProductRoutes);
app.use('/api', rentWishlistRoutes);
app.use('/api', rentCartRoutes);
app.use('/api', rentOrderRoutes);
app.use('/api', userRoutes);
app.use('/api/discussions', discussionRoutes);
app.use('/api/products', agriProductRoutes);
Expand Down
15 changes: 15 additions & 0 deletions backend/routes/rent/rentOrderRoutes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// routes/productRoutes.js

const express = require('express');
const { OrderConfirmation } = require('../../controllers/rent/RentOrderController');
const router = express.Router();


// Create a new product
router.post('/rent-product', OrderConfirmation);





module.exports = router;
32 changes: 32 additions & 0 deletions frontend/src/AgroRentAI/Cart.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,38 @@ const RentCartPage = () => {
? 'https://agrotech-ai-11j3.onrender.com'
: 'http://localhost:8080';

const recommendedItems = [
{
name: 'Tractor - Model X100',
image: 'https://via.placeholder.com/150?text=Tractor',
price: 1500,
},
{
name: 'Rototiller - 2000 Series',
image: 'https://via.placeholder.com/150?text=Rototiller',
price: 1200,
},
{
name: 'Plow - Heavy Duty',
image: 'https://via.placeholder.com/150?text=Plow',
price: 800,
},
{
name: 'Seeder - Pro Seed 3000',
image: 'https://via.placeholder.com/150?text=Seeder',
price: 2200,
},
{
name: 'Lawn Mower - Eco Series',
image: 'https://via.placeholder.com/150?text=Lawn+Mower',
price: 900,
},
{
name: 'Harrow - Ground Breaker',
image: 'https://via.placeholder.com/150?text=Harrow',
price: 1100,
},
];
// Fetch user cart items from backend
useEffect(() => {
const fetchCartItems = async () => {
Expand Down
124 changes: 108 additions & 16 deletions frontend/src/AgroRentAI/RentCheckoutPage.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import React, { useState } from 'react';
import React, { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { toast, ToastContainer } from 'react-toastify';
import "react-toastify/ReactToastify.min.css";

const RentCheckoutPage = () => {
// Dummy cartItems data
Expand All @@ -22,13 +24,72 @@ const RentCheckoutPage = () => {
}
]);

const ApiUrl = process.env.NODE_ENV === 'production'
? 'https://agrotech-ai-11j3.onrender.com'
: 'http://localhost:8080';

const [userDetails, setUserDetails] = useState({
name: '',
email: '',
address: '',
phone: '',
});

const [errors, setErrors] = useState({
name: '',
email: '',
address: '',
phone: '',
});

const handleInputChange = (e) => {
const { name, value } = e.target;
setUserDetails((prevState) => ({
...prevState,
[name]: value,
}));
};

const validateForm = () => {
let isValid = true;
const newErrors = {};

// Validate Name
if (!userDetails.name) {
newErrors.name = 'Name is required';
isValid = false;
}

// Validate Email
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!userDetails.email) {
newErrors.email = 'Email is required';
isValid = false;
} else if (!emailRegex.test(userDetails.email)) {
newErrors.email = 'Please enter a valid email';
isValid = false;
}

// Validate Address
if (!userDetails.address) {
newErrors.address = 'Address is required';
isValid = false;
}

// Validate Phone
const phoneRegex = /^[0-9]{10}$/;
if (!userDetails.phone) {
newErrors.phone = 'Phone number is required';
isValid = false;
} else if (!phoneRegex.test(userDetails.phone)) {
newErrors.phone = 'Phone number must be 10 digits';
isValid = false;
}

setErrors(newErrors);
return isValid;
};

const [totalPrice, setTotalPrice] = useState(0);
const navigate = useNavigate();

Expand All @@ -44,29 +105,47 @@ const RentCheckoutPage = () => {
setCartItems(updatedCartItems);
};

const handleCheckout = () => {
// Normally you would send the order to the backend for processing
console.log('Proceeding to checkout with the following details:', userDetails);
alert('Your order is placed. Waiting for approval from the admin/seller.');
navigate('/order-confirmation'); // Redirect to order confirmation page
};
const handleCheckout = async (e) => {
e.preventDefault(); // Prevent form submission reload

// Handle form input changes
const handleInputChange = (e) => {
const { name, value } = e.target;
setUserDetails((prevState) => ({
...prevState,
[name]: value,
}));
if (!validateForm()) {
toast.error("Error in validating form");
return;
}

try {
const response = await fetch(`${ApiUrl}/api/rent-product`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
userDetails,
cartItems,
totalPrice,
}),
});

const data = await response.json();
if (response.ok) {
toast.success(`Your order has been placed. Tracking ID: ${data.trackingID}`);
} else {
toast.error(data.message || 'Error placing the order');
}
} catch (error) {
toast.error('An error occurred while placing the order.');
console.error('Error during checkout:', error);
}
};

// Recalculate total when cart items change
React.useEffect(() => {
useEffect(() => {
calculateTotalPrice();
}, [cartItems]);

return (
<div className="min-h-screen flex flex-col items-center justify-center bg-gradient-to-r from-green-50 to-green-100 p-8 mt-12">
<ToastContainer />
<h2 className="text-4xl font-extrabold text-green-900 mb-8">Checkout</h2>

<div className="max-w-5xl bg-gradient-to-b from-green-100 to-green-200 rounded-lg shadow-2xl p-6 w-full">
Expand Down Expand Up @@ -103,7 +182,8 @@ const RentCheckoutPage = () => {
{/* User Details Form */}
<div className="mb-6">
<h3 className="text-2xl font-semibold text-green-900 mb-4">Billing Details</h3>
<form>
<form >
{/* Name */}
<div className="mb-4">
<label className="block text-green-700 mb-2">Name</label>
<input
Expand All @@ -114,7 +194,10 @@ const RentCheckoutPage = () => {
className="w-full p-3 border border-green-300 rounded-md"
required
/>
{errors.name && <p className="text-red-500 text-sm">{errors.name}</p>}
</div>

{/* Email */}
<div className="mb-4">
<label className="block text-green-700 mb-2">Email</label>
<input
Expand All @@ -125,7 +208,10 @@ const RentCheckoutPage = () => {
className="w-full p-3 border border-green-300 rounded-md"
required
/>
{errors.email && <p className="text-red-500 text-sm">{errors.email}</p>}
</div>

{/* Address */}
<div className="mb-4">
<label className="block text-green-700 mb-2">Address</label>
<textarea
Expand All @@ -135,7 +221,10 @@ const RentCheckoutPage = () => {
className="w-full p-3 border border-green-300 rounded-md"
required
/>
{errors.address && <p className="text-red-500 text-sm">{errors.address}</p>}
</div>

{/* Phone */}
<div className="mb-4">
<label className="block text-green-700 mb-2">Phone</label>
<input
Expand All @@ -146,7 +235,10 @@ const RentCheckoutPage = () => {
className="w-full p-3 border border-green-300 rounded-md"
required
/>
{errors.phone && <p className="text-red-500 text-sm">{errors.phone}</p>}
</div>


</form>
</div>

Expand Down

0 comments on commit 7de8787

Please sign in to comment.