diff --git a/backend/controllers/Admin/AcustomerController.js b/backend/controllers/Admin/AcustomerController.js
index a30bf995..444b6d79 100644
--- a/backend/controllers/Admin/AcustomerController.js
+++ b/backend/controllers/Admin/AcustomerController.js
@@ -11,8 +11,6 @@ export const getAllUsers = async (req, res) => {
}
}
-
-
// Fetch single user by ID
export const getUserById = async (req, res) => {
try {
@@ -26,7 +24,6 @@ export const getUserById = async (req, res) => {
}
}
-
// Update user by ID
export const updateUserById = async (req, res) => {
const {
@@ -107,4 +104,4 @@ export const getUserCount = async (req, res) => {
} catch (error) {
res.status(500).json({ error: 'Error fetching user count' })
}
-}
\ No newline at end of file
+}
diff --git a/backend/controllers/Admin/Afarmer.js b/backend/controllers/Admin/Afarmer.js
index b30aff6c..6344bff7 100644
--- a/backend/controllers/Admin/Afarmer.js
+++ b/backend/controllers/Admin/Afarmer.js
@@ -1,4 +1,3 @@
-
import Farmer from '../../models/farmerModel'
import mongoose from 'mongoose'
export const getFarmersCount = async (req, res) => {
@@ -17,4 +16,4 @@ export const getAllFarmers = async (req, res) => {
} catch (error) {
res.status(500).json({ message: error.message })
}
-}
\ No newline at end of file
+}
diff --git a/backend/controllers/DLDeliveryController.js b/backend/controllers/DLDeliveryController.js
index c83cd95c..c93f5097 100644
--- a/backend/controllers/DLDeliveryController.js
+++ b/backend/controllers/DLDeliveryController.js
@@ -95,14 +95,20 @@ export const sendEmailToDriver = async (driver, delivery) => {
// Set up the email options
const mailOptions = {
- from: process.env.EMAIL_USER,
+ from: `'FarmCart 🌱' <${process.env.EMAIL_USER}`,
to: driver.email,
subject: `Order Assignment: Order ${delivery.oID} Assigned to You`,
html: `
-
Hi ${driver.fullName},
- We are excited to inform you that you have been assigned to deliver the following order:
- Order Details
-
+
+
+
+
Hi ${driver.fullName},
+
+ We are excited to inform you that you have been assigned to deliver the following order:
+
+
+
Order Details:
+
Order ID: ${delivery.oID}
Tracking ID: ${delivery.trackingID}
Shop Name: ${delivery.shopName}
@@ -110,11 +116,21 @@ export const sendEmailToDriver = async (driver, delivery) => {
Customer Name: ${delivery.customerName}
Drop-Off Address: ${delivery.dropOffAddress}
-
For more details, please log in to the delivery portal or contact support if needed.
+
+
+ For more details, please log in to the delivery portal or contact support if needed.
+
+
-
Thank you for being part of our delivery team!
-
Best Regards,
-
Your Company Name
+
+ Thank you for being part of our delivery team!
+
+
+
Best Regards,
+
The FarmCart Team 🌱
+
+
+
`,
}
@@ -293,3 +309,56 @@ export const getDeliveriesByDriver = async (req, res) => {
})
}
}
+
+//
+// deleteing the duplicated ones
+// Function to clean up duplicate deliveries by orderID
+export const cleanUpDuplicateDeliveries = async () => {
+ try {
+ // Find all deliveries grouped by orderID and check for duplicates
+ const duplicates = await DLDelivery.aggregate([
+ {
+ $group: {
+ _id: '$orderID', // Group by orderID
+ count: { $sum: 1 }, // Count occurrences of each orderID
+ docs: { $push: '$$ROOT' }, // Push all documents with the same orderID
+ },
+ },
+ {
+ $match: {
+ count: { $gt: 1 }, // Filter groups that have more than 1 occurrence
+ },
+ },
+ ])
+
+ // Loop through each duplicate and keep the first created, delete the rest
+ for (const duplicate of duplicates) {
+ const sortedDocs = duplicate.docs.sort(
+ (a, b) =>
+ new Date(a.assignDateTime) - new Date(b.assignDateTime)
+ ) // Sort by creation date (assignDateTime)
+
+ const [firstDoc, ...duplicatesToDelete] = sortedDocs
+
+ // Keep the first document and delete the rest
+ for (const doc of duplicatesToDelete) {
+ await DLDelivery.findByIdAndDelete(doc._id)
+ console.log(
+ `Deleted duplicate delivery with orderID: ${doc.orderID}`
+ )
+ }
+
+ console.log(
+ `Kept delivery for orderID: ${firstDoc.orderID}, removed ${duplicatesToDelete.length} duplicates`
+ )
+ }
+
+ if (duplicates.length === 0) {
+ /*
+ // console.log('No duplicate deliveries found.')
+ */
+ }
+ } catch (error) {
+ console.error('Error cleaning up duplicate deliveries:', error)
+ }
+}
diff --git a/backend/controllers/DLEmailController.js b/backend/controllers/DLEmailController.js
index 41bb655b..99c1f155 100644
--- a/backend/controllers/DLEmailController.js
+++ b/backend/controllers/DLEmailController.js
@@ -36,20 +36,46 @@ export const sendApprovalEmail = asyncHandler(async (req, res) => {
to: driver.email,
subject: 'Farmcart: Approval Confirmation',
html: `
- Dear ${driver.fullName},
- Congratulations! Your driver registration has been approved. Please click the button below to log in and complete your registration:
-
- Click Here to Log In
-
- Alternatively, you can enter your ID to log in for the first time.
- Regards, FarmCart Team
+
+
+
FarmCart: Approval Confirmation
+
+
+ Dear ${driver.fullName} ,
+
+
+
+ Congratulations! Your driver registration has been approved.
+
+
+
+ You can log in to your account by clicking the button below to complete your registration:
+
+
+
+
+
+ Alternatively, you can enter your ID to log in for the first time.
+
+
+
+ Regards, FarmCart Team
+
+
+
`,
}
diff --git a/backend/controllers/DLOcontroller.js b/backend/controllers/DLOcontroller.js
index 4eef694f..00ad754c 100644
--- a/backend/controllers/DLOcontroller.js
+++ b/backend/controllers/DLOcontroller.js
@@ -114,9 +114,9 @@ const assignReadyOrders = async () => {
orderID: order._id.toString(),
})
if (existingDelivery) {
- console.log(
- `Order with ID ${order._id} already exists in DLDelivery.`
- )
+ // console.log(
+ // `Order with ID ${order._id} already exists in DLDelivery.`
+ // )
continue // Skip this order if it already exists in DLDelivery
}
@@ -182,13 +182,10 @@ const assignReadyOrders = async () => {
await newDOrder.save()
/*console.log(`Order with ID ${order._id} has been successfully assigned to dOrder with new orderID ${newDOrder.orderID}.`)*/
-
-
- // After saving the new dOrder, update the order status to "Assigning" in the Order model
- order.orderStatus = ' Ready. '
- await order.save() // Save the updated order
- // console.log(`Order with ID ${order._id} has been marked as "Assigning" in the Order model.`)
-
+ // After saving the new dOrder, update the order status to "Assigning" in the Order model
+ order.orderStatus = ' Ready. '
+ await order.save() // Save the updated order
+ // console.log(`Order with ID ${order._id} has been marked as "Assigning" in the Order model.`)
}
} catch (error) {
console.error('Error assigning ready orders to dOrder:', error)
@@ -237,11 +234,11 @@ const syncDeliveryAndOrderStatus = async () => {
// Function to repeatedly check for ready orders every 5 seconds
const startOrderAssignment = () => {
/* console.log('Starting periodic check for ready orders...')*/
- setInterval(assignReadyOrders, 5000) // Run the check every 5 seconds
+ setInterval(assignReadyOrders, 1000) // Run the check every 5 seconds
}
const startSyncDeliveryOrderStatus = () => {
- setInterval(syncDeliveryAndOrderStatus, 5000) // Run every 5 seconds
+ setInterval(syncDeliveryAndOrderStatus, 1000) // Run every 5 seconds
}
export { startSyncDeliveryOrderStatus }
diff --git a/backend/models/DLDeliveryModel.js b/backend/models/DLDeliveryModel.js
index cb3b16b5..1333f150 100644
--- a/backend/models/DLDeliveryModel.js
+++ b/backend/models/DLDeliveryModel.js
@@ -8,13 +8,14 @@ const DLDeliverySchema = new mongoose.Schema({
orderID: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Order',
- required: [true,'Order ID is required'],
- unique: [true,'Order ID is unique'],
+ required: [true, 'Order ID is required'],
+ unique: [true, 'Order ID is unique'],
},
- oID: { type: String ,
- required: [true,'Order ID is required'],
- unique: [true,'Order ID is unique'],
+ oID: {
+ type: String,
+ required: [true, 'Order ID is required'],
+ unique: [true, 'Order ID is unique'],
},
driverID: {
diff --git a/backend/models/DLOModel.js b/backend/models/DLOModel.js
index e83f6280..c18da1dd 100644
--- a/backend/models/DLOModel.js
+++ b/backend/models/DLOModel.js
@@ -4,12 +4,10 @@ const dorderSchema = new mongoose.Schema(
{
/* generate and store the oID:{type: String,}, */
-
- oID: {
+ oID: {
type: String,
required: [true, 'Order ID required'], // Ensure each order has a unique ID
- unique: [true, 'Order already exists']
-
+ unique: [true, 'Order already exists'],
},
orderID: {
diff --git a/backend/models/OrderModel.js b/backend/models/OrderModel.js
index 6e9b85ce..332c8d91 100644
--- a/backend/models/OrderModel.js
+++ b/backend/models/OrderModel.js
@@ -36,7 +36,15 @@ const orderSchema = new mongoose.Schema(
totalPrice: { type: Number, required: true },
orderStatus: {
type: String,
- enum: ['Pending','Rejected', 'Ready',' .Ready. ', 'Picked Up', 'On The Way', 'Delivered'],
+ enum: [
+ 'Pending',
+ 'Rejected',
+ 'Ready',
+ ' Ready. ',
+ 'Picked Up',
+ 'On The Way',
+ 'Delivered',
+ ],
default: 'Pending',
},
deliveryDate: {
diff --git a/backend/routes/Admin/AfarmerRoute.js b/backend/routes/Admin/AfarmerRoute.js
index 0a08cb23..2724dd50 100644
--- a/backend/routes/Admin/AfarmerRoute.js
+++ b/backend/routes/Admin/AfarmerRoute.js
@@ -1,12 +1,9 @@
import express from 'express'
-import {
- getFarmersCount,
-getAllFarmers,
-} from '../../controllers/Admin/Afarmer'
+import { getFarmersCount, getAllFarmers } from '../../controllers/Admin/Afarmer'
const router = express.Router()
router.get('/', getAllFarmers)
router.post('/count', getFarmersCount)
-export default router
\ No newline at end of file
+export default router
diff --git a/backend/routes/Admin/AuserRoute.js b/backend/routes/Admin/AuserRoute.js
index bbcc635a..e23a0895 100644
--- a/backend/routes/Admin/AuserRoute.js
+++ b/backend/routes/Admin/AuserRoute.js
@@ -5,12 +5,12 @@ import {
updateUserById,
deleteUserById,
validateUserPassword,
- getUserCount
+ getUserCount,
} from '../../controllers/Admin/AcustomerController.js'
const router = express.Router()
-router.get('/count',getUserCount)
+router.get('/count', getUserCount)
// Get all users
router.get('/', getAllUsers)
diff --git a/backend/server.js b/backend/server.js
index fcc876df..6a080f09 100644
--- a/backend/server.js
+++ b/backend/server.js
@@ -23,16 +23,22 @@ import driverRoutes from './routes/DLDriverRoutes.js' //DL
import { fileURLToPath } from 'url' //DL
import DLEmailRoutes from './routes/DLEmailRoutes.js' //DL
import oRoutes from './routes/DLORoutes.js' // DL
-import { checkForAvailableDrivers } from './controllers/DLDeliveryController.js' //DL THIS IS CHECKING ALL ODRS AND ASSIGN DRIVERS
+import {
+ checkForAvailableDrivers,
+ cleanUpDuplicateDeliveries,
+} from './controllers/DLDeliveryController.js' //DL THIS IS CHECKING ALL ODRS AND ASSIGN DRIVERS
import deliveryRoutes from './routes/DLDeliveryRoute.js' //DL
import {
startOrderAssignment,
startSyncDeliveryOrderStatus,
} from './controllers/DLOcontroller.js' // Import the periodic check
-// checkForAvailableDrivers() //DL
+
+// {/*checkForAvailableDrivers() //DL
// startOrderAssignment()
// startSyncDeliveryOrderStatus() //DL
+// cleanUpDuplicateDeliveries() */}
+
import { errorHandler, notFound } from './middlewares/errorMiddleware.js'
diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx
index b51cb481..90df1818 100644
--- a/frontend/src/App.jsx
+++ b/frontend/src/App.jsx
@@ -213,7 +213,10 @@ const router = createBrowserRouter(
{/* delivery and driver Routes */}
}>
- } />
+ }
+ />
}>
{ // Destructure manager from props
+const StaffPrivateRoute = ({ manager }) => {
+ // Destructure manager from props
// Check if the user is authenticated by checking for a token in local storage
- const staff = localStorage.getItem('staffToken'); // Replace with your actual logic
+ const staff = localStorage.getItem('staffToken') // Replace with your actual logic
// Log the user state for debugging
- console.log(staff);
+ console.log(staff)
// If staff token exists and manager prop is true, redirect to /manager
if (manager) {
- return staff ? : ;
+ return staff ? :
}
// If staff token exists, render the Outlet, otherwise navigate to /Admin
- return staff ? : ;
-};
+ return staff ? :
+}
-export default StaffPrivateRoute;
+export default StaffPrivateRoute
diff --git a/frontend/src/Components/Admin/admnlogins.jsx b/frontend/src/Components/Admin/admnlogins.jsx
index 3e5e66c2..fa9a58d6 100644
--- a/frontend/src/Components/Admin/admnlogins.jsx
+++ b/frontend/src/Components/Admin/admnlogins.jsx
@@ -1,62 +1,60 @@
-import React, { useState } from 'react';
-import { useNavigate } from 'react-router-dom';
-import { ToastContainer, toast } from 'react-toastify';
-import 'react-toastify/dist/ReactToastify.css';
-import farmcartLogo from '../../assets/logo.png'; // Update with correct path if needed
+import React, { useState } from 'react'
+import { useNavigate } from 'react-router-dom'
+import { ToastContainer, toast } from 'react-toastify'
+import 'react-toastify/dist/ReactToastify.css'
+import farmcartLogo from '../../assets/logo.png' // Update with correct path if needed
-const AdminLogin = ({ manager }) => { // Receive the manager prop
- const navigate = useNavigate();
- const [email, setEmail] = useState('');
- const [password, setPassword] = useState('');
- const [error, setError] = useState('');
+const AdminLogin = ({ manager }) => {
+ // Receive the manager prop
+ const navigate = useNavigate()
+ const [email, setEmail] = useState('')
+ const [password, setPassword] = useState('')
+ const [error, setError] = useState('')
// Hardcoded usernames and passwords for three users
const users = [
{
email: 'sanjeewa@gmail.com',
password: 'sanjeewa',
-
-
},
{
email: 'admin@farmcart.com',
password: 'password123',
-
},
{
email: 'admin3@example.com',
password: 'securePass',
-
},
- ];
+ ]
// Login handler
const handleLogin = (e) => {
- e.preventDefault();
+ e.preventDefault()
// Find matching user from the list
const user = users.find(
(user) => user.email === email && user.password === password
- );
+ )
if (user) {
// If user exists, save token and navigate based on manager prop
- const token = 'd0ahfFiO0dPMd1StZ0W7fqYhxxuIJYtEDXgi6t39Pp2J2qaWyfcFT0gJKO3iT6pz'; // Replace with actual token logic
- localStorage.setItem('staffToken', token); // Save token in local storage
+ const token =
+ 'd0ahfFiO0dPMd1StZ0W7fqYhxxuIJYtEDXgi6t39Pp2J2qaWyfcFT0gJKO3iT6pz' // Replace with actual token logic
+ localStorage.setItem('staffToken', token) // Save token in local storage
// Navigate based on the manager prop
if (manager) {
- navigate('/manager/dashboard');
+ navigate('/manager/dashboard')
} else {
- navigate('/admindashboard');
+ navigate('/admindashboard')
}
- toast.success('Login successful!');
+ toast.success('Login successful!')
} else {
// If no match, show error message
- setError('Invalid email or password.');
- toast.error('Invalid email or password.');
+ setError('Invalid email or password.')
+ toast.error('Invalid email or password.')
}
- };
+ }
return (
@@ -86,7 +84,10 @@ const AdminLogin = ({ manager }) => { // Receive the manager prop
/>
-
+
Password
{ // Receive the manager prop
- );
-};
+ )
+}
-export default AdminLogin;
+export default AdminLogin
diff --git a/frontend/src/Components/Order/ProgressBar.jsx b/frontend/src/Components/Order/ProgressBar.jsx
index 2d27c479..d2c2808f 100644
--- a/frontend/src/Components/Order/ProgressBar.jsx
+++ b/frontend/src/Components/Order/ProgressBar.jsx
@@ -2,12 +2,12 @@ import React from 'react'
import { FaShoppingCart, FaShippingFast, FaCheckCircle } from 'react-icons/fa'
const ProgressBar = ({ currentStep }) => {
- const totalSteps = 3
-
+ const totalSteps = 3
+
const icons = [
,
,
- ,
+ ,
]
return (
diff --git a/frontend/src/Pages/Shop/ShopList.jsx b/frontend/src/Pages/Shop/ShopList.jsx
index a4289f29..36cac34d 100644
--- a/frontend/src/Pages/Shop/ShopList.jsx
+++ b/frontend/src/Pages/Shop/ShopList.jsx
@@ -122,7 +122,6 @@ const ShopList = () => {
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="mb-5 border border-gray-300 rounded-full p-2 w-full hover:border-green-500 focus:border-green-500 focus:outline-none focus:ring-1 focus:ring-green-500 transition duration-200"
-
/>
{/* Loading Message */}
diff --git a/frontend/src/Pages/delivery/DLDriverDashboard.jsx b/frontend/src/Pages/delivery/DLDriverDashboard.jsx
index 1231055f..3083eb52 100644
--- a/frontend/src/Pages/delivery/DLDriverDashboard.jsx
+++ b/frontend/src/Pages/delivery/DLDriverDashboard.jsx
@@ -37,11 +37,14 @@ const DLDriverDashboard = () => {
setIsAvailable(data.isAvailable) // Set initial availability
// Check if NIC and password are the same
- const nicCheckRes = await axios.get('/api/drivers/nic-password-check', {
- headers: {
- Authorization: `Bearer ${driverToken}`, // Pass token in headers
- },
- })
+ const nicCheckRes = await axios.get(
+ '/api/drivers/nic-password-check',
+ {
+ headers: {
+ Authorization: `Bearer ${driverToken}`, // Pass token in headers
+ },
+ }
+ )
setNicMatchesPassword(nicCheckRes.data.nicMatchesPassword) // Set NIC and password equality check result
// Fetch ongoing deliveries assigned to this driver
@@ -153,10 +156,10 @@ const DLDriverDashboard = () => {
status === 'Ready'
? 25
: status === 'Picked Up'
- ? 50
- : status === 'On The Way'
- ? 75
- : 100
+ ? 50
+ : status === 'On The Way'
+ ? 75
+ : 100
const bgColor = progress === 100 ? 'bg-gray-400' : 'bg-green-500'
return (
@@ -183,7 +186,8 @@ const DLDriverDashboard = () => {
Warning: Your NIC number and password
are the same. Please update your password for better
- security. When you change the password, you can assign orders.
+ security. When you change the password, you can assign
+ orders.
)}
@@ -216,7 +220,9 @@ const DLDriverDashboard = () => {
: 'bg-red-500 hover:bg-red-600'
}`}
>
- {isAvailable ? 'Available' : 'Unavailable'}
+ {isAvailable
+ ? 'Available'
+ : 'Unavailable'}
)}
{
'Ready'
? 25
: delivery.deliveryStatus ===
- 'Picked Up'
- ? 50
- : delivery.deliveryStatus ===
- 'On The Way'
- ? 75
- : 100
+ 'Picked Up'
+ ? 50
+ : delivery.deliveryStatus ===
+ 'On The Way'
+ ? 75
+ : 100
}%`,
}}
className={`${
@@ -295,12 +301,12 @@ const DLDriverDashboard = () => {
'Ready'
? '25%'
: delivery.deliveryStatus ===
- 'Picked Up'
- ? '50%'
- : delivery.deliveryStatus ===
- 'On The Way'
- ? '75%'
- : '100% (Delivered)'}
+ 'Picked Up'
+ ? '50%'
+ : delivery.deliveryStatus ===
+ 'On The Way'
+ ? '75%'
+ : '100% (Delivered)'}
diff --git a/frontend/src/Pages/delivery/DLDriverRegistrationForm.jsx b/frontend/src/Pages/delivery/DLDriverRegistrationForm.jsx
index 2ff8c13f..418eb063 100644
--- a/frontend/src/Pages/delivery/DLDriverRegistrationForm.jsx
+++ b/frontend/src/Pages/delivery/DLDriverRegistrationForm.jsx
@@ -81,15 +81,26 @@ const RegisterDriverForm = () => {
// Remove any leading or trailing spaces
const trimmedValue = value.trim()
+ // Advanced email validation regex
+ const emailRegex =
+ /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/
+
// Check if there are any spaces in the email
if (/\s/.test(trimmedValue)) {
errorMessage = 'Email cannot contain spaces.'
- } else if (!/^.*@gmail\.com$/.test(trimmedValue)) {
- errorMessage = 'Email must be a valid @gmail.com address.'
+ } else if (!emailRegex.test(trimmedValue)) {
+ errorMessage =
+ 'Email must be a valid address (e.g., name@example.com).'
}
}
if (name === 'phone') {
+ if (!/^\d*$/.test(value)) {
+ return // Prevent setting invalid value
+ }
+ if (value.length > 10) {
+ return // Prevent setting values longer than 10 digits
+ }
if (!/^0\d{9}$/.test(value)) {
errorMessage =
'Contact number must be 10 digits and start with 0.'
@@ -119,12 +130,18 @@ const RegisterDriverForm = () => {
.getFullYear()
.toString()
- if (!nicRegex.test(value)) {
- errorMessage = 'Please Enter valid NIC'
+ // Ensure the NIC is not longer than 12 characters
+ if (value.length > 12) {
+ return
+ errorMessage = 'NIC cannot exceed 12 characters.'
+ } else if (!nicRegex.test(value)) {
+ errorMessage = 'Please enter a valid NIC.'
} else if (!value.startsWith(birthYear)) {
- errorMessage = 'Please Enter valid NIC'
+ errorMessage =
+ 'Please enter a valid NIC that matches your birth year.'
}
}
+
// Validate Vehicle Number
if (name === 'vehicleNumber') {
const vehicleRegex6 = /^[A-Z]{2}[0-9]{4}$/ // For 6 characters (AA0000 to ZZ9999)
@@ -134,6 +151,9 @@ const RegisterDriverForm = () => {
errorMessage =
'Vehicle number must be in uppercase and follow the format AA0000 or AAA0000.'
}
+ if (value.length > 7) {
+ return // Prevent setting values longer than 10 digits
+ }
}
// Validate Vehicle Number
diff --git a/frontend/src/Pages/delivery/DLviewDelivery.jsx b/frontend/src/Pages/delivery/DLviewDelivery.jsx
index dd2cb832..2825ecbd 100644
--- a/frontend/src/Pages/delivery/DLviewDelivery.jsx
+++ b/frontend/src/Pages/delivery/DLviewDelivery.jsx
@@ -54,38 +54,38 @@ const DLViewDelivery = () => {
)
}
- // Function to generate the PDF
const generatePDF = () => {
- const doc = new jsPDF()
+ const doc = new jsPDF('p', 'mm', 'a4') // Set to A4 size (portrait orientation)
// Add logo
doc.addImage(farmcartLogo, 'PNG', 10, 10, 50, 20) // Add logo with width and height
- // Add title
- doc.setFontSize(22)
- doc.text('Delivery Details', 105, 40, null, null, 'center') // Title centered at the top
+ // Add report title
+ doc.setFontSize(24)
+ doc.setTextColor(40)
+ doc.text('Delivery Details Report', 105, 40, null, null, 'center') // Centered title
- // Add company name
+ // Add company information
doc.setFontSize(12)
doc.text('FarmCart Lanka (PVT.) LTD', 105, 50, null, null, 'center')
doc.text('No.78, Malabe, Colombo', 105, 55, null, null, 'center')
- doc.text('(+94) 011 34 56 837', 105, 60, null, null, 'center')
- doc.text('www.farmcart.com', 105, 65, null, null, 'center')
+ doc.text('Phone: (+94) 011 34 56 837', 105, 60, null, null, 'center')
+ doc.text('Website: www.farmcart.com', 105, 65, null, null, 'center')
- // Move down to add delivery details table
- doc.setFontSize(12)
- doc.text('Delivery Information', 14, 80) // Left-aligned delivery information
+ // Section for "Delivery Information"
+ doc.setFontSize(18)
+ doc.setTextColor(0, 51, 102) // Dark blue color
+ doc.text('Delivery Information', 14, 80) // Section title left-aligned
- // Create a table with delivery details
+ // Delivery details table
doc.autoTable({
- startY: 85, // Starting position on the Y-axis
+ startY: 90, // Positioning below "Delivery Information"
head: [['Field', 'Details']], // Table headers
body: [
['Tracking ID', delivery.trackingID],
['Order ID', delivery.oID],
['Driver ID', delivery.drID],
['Driver Name', driver.fullName],
-
['Shop Name', delivery.shopName],
['Pickup Address', delivery.pickupAddress],
['Customer Name', delivery.customerName || 'N/A'],
@@ -102,12 +102,28 @@ const DLViewDelivery = () => {
: 'Ongoing',
],
],
- theme: 'grid', // Use grid theme for the table
- headStyles: { fillColor: [46, 204, 113] }, // Green background for headers
- bodyStyles: { textColor: [0, 0, 0] }, // Black text color for table body
+ theme: 'grid', // Use the grid theme for a clean table format
+ headStyles: { fillColor: [46, 204, 113] }, // Green background for table headers
+ bodyStyles: { textColor: [0, 0, 0] }, // Black text color for the table body
+ alternateRowStyles: { fillColor: [245, 245, 245] }, // Light grey for alternate rows
+ margin: { top: 10 },
})
- // Save the PDF with a dynamic name based on the delivery ID
+ // Add footer section for generated date and signature space
+ const finalY = doc.autoTable.previous.finalY + 20 // Get Y position after the table
+ doc.setFontSize(12)
+ doc.text(
+ `Report Generated on: ${new Date().toLocaleString()}`,
+ 14,
+ finalY
+ )
+
+ // Add "Approved by" section with signature line
+ doc.text('Approved by:', 14, finalY + 10)
+ doc.text('__________________________', 14, finalY + 20) // Placeholder for signature
+ doc.text('Signature', 14, finalY + 25)
+
+ // Save the PDF with a dynamic name based on the delivery tracking ID
doc.save(`Delivery_${delivery.trackingID}.pdf`)
}
diff --git a/frontend/src/Pages/delivery/driver/ViewDelivery.jsx b/frontend/src/Pages/delivery/driver/ViewDelivery.jsx
index 57de7234..cab79b80 100644
--- a/frontend/src/Pages/delivery/driver/ViewDelivery.jsx
+++ b/frontend/src/Pages/delivery/driver/ViewDelivery.jsx
@@ -57,36 +57,48 @@ const DLViewDelivery = () => {
)
}
- // Function to generate the PDF
const generatePDF = () => {
- const doc = new jsPDF()
+ const doc = new jsPDF('p', 'mm', 'a4') // Ensure A4 size document
- // Add logo
+ // Add logo at the top
doc.addImage(farmcartLogo, 'PNG', 10, 10, 50, 20) // Add logo with width and height
- // Add title
- doc.setFontSize(22)
- doc.text('Delivery Details', 105, 40, null, null, 'center') // Title centered at the top
+ // Add main title (Delivery Details Report)
+ doc.setFontSize(24)
+ doc.setTextColor(40)
+ doc.text('Delivery Details Report', 105, 40, null, null, 'center') // Title centered at the top
- // Add company name
+ // Add subtitle (e.g., Report generated on)
doc.setFontSize(12)
- doc.text('FarmCart Lanka (PVT.) LTD', 105, 50, null, null, 'center')
- doc.text('No.78, Malabe, Colombo', 105, 55, null, null, 'center')
- doc.text('(+94) 011 34 56 837', 105, 60, null, null, 'center')
- doc.text('www.farmcart.com', 105, 65, null, null, 'center')
+ doc.text(
+ `Report generated on: ${new Date().toLocaleDateString()}`,
+ 105,
+ 47,
+ null,
+ null,
+ 'center'
+ )
- // Move down to add delivery details table
+ // Add company name and contact info
doc.setFontSize(12)
- doc.text('Delivery Information', 14, 80) // Left-aligned delivery information
+ doc.text('FarmCart Lanka (PVT.) LTD', 105, 55, null, null, 'center')
+ doc.text('No.78, Malabe, Colombo', 105, 60, null, null, 'center')
+ doc.text('Phone: (+94) 011 34 56 837', 105, 65, null, null, 'center')
+ doc.text('Website: www.farmcart.com', 105, 70, null, null, 'center')
+
+ // Add section for "Delivery Information"
+ doc.setFontSize(16)
+ doc.setTextColor(0, 51, 102) // Set dark blue color
+ doc.text('Delivery Information', 14, 85) // Left-aligned section title
- // Create a table with delivery details
+ // Add a table for delivery details
doc.autoTable({
- startY: 85, // Starting position on the Y-axis
- head: [['Field', 'Details']], // Table headers
+ startY: 90, // Positioning the table below the section title
+ head: [['Field', 'Details']],
body: [
['Tracking ID', delivery.trackingID],
['Order ID', delivery.oID],
- ['Driver Name', driver?.firstName + ' ' + driver?.lastName], // Adding driver name
+ ['Driver Name', driver?.firstName + ' ' + driver?.lastName],
['Driver ID', delivery.drID],
['Shop Name', delivery.shopName],
['Pickup Address', delivery.pickupAddress],
@@ -104,11 +116,29 @@ const DLViewDelivery = () => {
: 'Ongoing',
],
],
- theme: 'grid', // Use grid theme for the table
- headStyles: { fillColor: [46, 204, 113] }, // Green background for headers
+ theme: 'grid', // Table theme
+ headStyles: { fillColor: [46, 204, 113] }, // Green background for table headers
bodyStyles: { textColor: [0, 0, 0] }, // Black text color for table body
})
+ // Add "Generated at" timestamp at the bottom
+ const generatedAt = new Date().toLocaleString()
+ doc.setFontSize(12)
+ doc.text(
+ `Generated at: ${generatedAt}`,
+ 14,
+ doc.autoTable.previous.finalY + 20
+ )
+
+ // Add "Approved by" section at the bottom
+ doc.text('Approved by:', 14, doc.autoTable.previous.finalY + 30)
+ doc.text(
+ '__________________________',
+ 14,
+ doc.autoTable.previous.finalY + 40
+ ) // Placeholder for signature
+ doc.text('Signature', 14, doc.autoTable.previous.finalY + 45)
+
// Save the PDF with a dynamic name based on the delivery tracking ID
doc.save(`Delivery_${delivery.trackingID}.pdf`)
}
diff --git a/frontend/src/Pages/farmer/FarmerDashboard.jsx b/frontend/src/Pages/farmer/FarmerDashboard.jsx
index 4f8a8a3a..c42ae246 100644
--- a/frontend/src/Pages/farmer/FarmerDashboard.jsx
+++ b/frontend/src/Pages/farmer/FarmerDashboard.jsx
@@ -338,7 +338,6 @@ const Dashboard = () => {
startContent={ }
onChange={(e) => setSearch(e.target.value)}
className="border border-gray-50 hover:border-green-500 focus:border-green-500 focus:outline-none transition duration-200 rounded-full"
-
/>