diff --git a/backend/controllers/shop/sub-controllers/deliveryPersonController.js b/backend/controllers/shop/sub-controllers/deliveryPersonController.js new file mode 100644 index 00000000..ea24cc4b --- /dev/null +++ b/backend/controllers/shop/sub-controllers/deliveryPersonController.js @@ -0,0 +1,269 @@ +const DeliveryPerson = require("../../../model/shop/sub-model/DeliveryPerson"); +const { hashPassword } = require("../../../services/sub-service/hashPassword"); +const { + validateEmail, + validatePhoneNumber, +} = require("../../../services/sub-service/couponValidator"); + +exports.successResponse = (res, statusCode, message, data = {}) => { + res.status(statusCode).json({ + status: "success", + message, + data, + }); +}; + +exports.errorResponse = (res, statusCode, message, error = {}) => { + res.status(statusCode).json({ + status: "error", + message, + error, + }); +}; + +// Create a new Delivery Person +exports.createDeliveryPerson = async (req, res) => { + try { + const { + name, + email, + phone_number, + status, + assigned_routes, + vehicle_details, + profile_picture, + password, + } = req.body; + + // Validate required fields + if (!name || !email || !phone_number || !status) { + return errorResponse(res, 400, "All required fields must be provided."); + } + + // Validate email and phone number formats + if (!validateEmail(email)) + return errorResponse(res, 400, "Invalid email format."); + if (!validatePhoneNumber(phone_number)) + return errorResponse(res, 400, "Invalid phone number format."); + + // Check if email already exists + const existingEmail = await DeliveryPerson.findOne({ email }); + if (existingEmail) return errorResponse(res, 400, "Email already exists."); + + // Hash password if provided + const hashedPassword = password ? await hashPassword(password) : undefined; + + const newDeliveryPerson = new DeliveryPerson({ + name, + email, + phone_number, + status, + assigned_routes, + vehicle_details, + profile_picture, + password: hashedPassword, + }); + + await newDeliveryPerson.save(); + successResponse( + res, + 201, + "Delivery person created successfully.", + newDeliveryPerson + ); + } catch (error) { + errorResponse(res, 500, error.message); + } +}; + +// Get all Delivery Persons with pagination +exports.getAllDeliveryPersons = async (req, res) => { + try { + const { page = 1, limit = 10 } = req.query; + const deliveryPersons = await DeliveryPerson.find() + .select("name status vehicle_details.vehicle_type") + .limit(parseInt(limit)) + .skip((parseInt(page) - 1) * parseInt(limit)); + const count = await DeliveryPerson.countDocuments(); + + successResponse(res, 200, "Delivery persons retrieved successfully.", { + deliveryPersons, + totalPages: Math.ceil(count / limit), + currentPage: parseInt(page), + }); + } catch (error) { + errorResponse(res, 500, error.message); + } +}; + +// Get a Delivery Person by ID +exports.getDeliveryPersonById = async (req, res) => { + try { + const deliveryPerson = await DeliveryPerson.findById( + req.params.id + ).populate("assigned_routes"); + if (!deliveryPerson) + return errorResponse(res, 404, "Delivery person not found."); + successResponse( + res, + 200, + "Delivery person retrieved successfully.", + deliveryPerson + ); + } catch (error) { + errorResponse(res, 500, error.message); + } +}; + +// Update a Delivery Person +exports.updateDeliveryPerson = async (req, res) => { + try { + const updates = req.body; + + // Validate and hash password if provided + if (updates.password) + updates.password = await hashPassword(updates.password); + + // Validate email and phone number if updated + if (updates.email && !validateEmail(updates.email)) + return errorResponse(res, 400, "Invalid email format."); + if (updates.phone_number && !validatePhoneNumber(updates.phone_number)) + return errorResponse(res, 400, "Invalid phone number format."); + + // Check if email already exists (excluding current delivery person) + if (updates.email) { + const existingEmail = await DeliveryPerson.findOne({ + email: updates.email, + _id: { $ne: req.params.id }, + }); + if (existingEmail) + return errorResponse(res, 400, "Email already exists."); + } + + const updatedDeliveryPerson = await DeliveryPerson.findByIdAndUpdate( + req.params.id, + updates, + { new: true } + ); + if (!updatedDeliveryPerson) + return errorResponse(res, 404, "Delivery person not found."); + successResponse( + res, + 200, + "Delivery person updated successfully.", + updatedDeliveryPerson + ); + } catch (error) { + errorResponse(res, 500, error.message); + } +}; + +// Soft delete (deactivate) a Delivery Person +exports.deleteDeliveryPerson = async (req, res) => { + try { + const deliveryPerson = await DeliveryPerson.findById(req.params.id); + if (!deliveryPerson) + return errorResponse(res, 404, "Delivery person not found."); + + deliveryPerson.status = "inactive"; + await deliveryPerson.save(); + successResponse(res, 200, "Delivery person deactivated successfully."); + } catch (error) { + errorResponse(res, 500, error.message); + } +}; + +// Activate or Deactivate Delivery Person +exports.toggleStatus = async (req, res) => { + try { + const { status } = req.body; + if (!["active", "inactive"].includes(status)) + return errorResponse(res, 400, "Invalid status."); + + const deliveryPerson = await DeliveryPerson.findById(req.params.id); + if (!deliveryPerson) + return errorResponse(res, 404, "Delivery person not found."); + + deliveryPerson.status = status; + await deliveryPerson.save(); + successResponse(res, 200, "Delivery person status updated successfully.", { + status: deliveryPerson.status, + }); + } catch (error) { + errorResponse(res, 500, error.message); + } +}; + +// Helper functions for response handling +const validateVehicleDetails = (vehicleDetails) => { + const { vehicle_type, vehicle_number } = vehicleDetails; + if (vehicle_type && typeof vehicle_type !== "string") return false; + if (vehicle_number && typeof vehicle_number !== "string") return false; + return true; +}; + +// Search Delivery Person by name +exports.searchDeliveryPersonByName = async (req, res) => { + try { + const { name } = req.query; + const deliveryPersons = await DeliveryPerson.find({ + name: { $regex: name, $options: "i" }, + }); + successResponse( + res, + 200, + "Search results retrieved successfully.", + deliveryPersons + ); + } catch (error) { + errorResponse(res, 500, error.message); + } +}; + +// Get all assigned routes for a Delivery Person +exports.getAssignedRoutes = async (req, res) => { + try { + const deliveryPerson = await DeliveryPerson.findById( + req.params.id + ).populate("assigned_routes"); + if (!deliveryPerson) + return errorResponse(res, 404, "Delivery person not found."); + successResponse( + res, + 200, + "Assigned routes retrieved successfully.", + deliveryPerson.assigned_routes + ); + } catch (error) { + errorResponse(res, 500, error.message); + } +}; + +// Change Delivery Person's vehicle details +exports.updateVehicleDetails = async (req, res) => { + try { + const { vehicle_details } = req.body; + + // Validate vehicle details format + if (vehicle_details && !validateVehicleDetails(vehicle_details)) { + return errorResponse(res, 400, "Invalid vehicle details format."); + } + + const updatedDeliveryPerson = await DeliveryPerson.findByIdAndUpdate( + req.params.id, + { vehicle_details }, + { new: true } + ); + + if (!updatedDeliveryPerson) + return errorResponse(res, 404, "Delivery person not found."); + successResponse( + res, + 200, + "Vehicle details updated successfully.", + updatedDeliveryPerson.vehicle_details + ); + } catch (error) { + errorResponse(res, 500, error.message); + } +}; diff --git a/backend/middleware/sub-ware/validate.js b/backend/middleware/sub-ware/validate.js new file mode 100644 index 00000000..792c4a16 --- /dev/null +++ b/backend/middleware/sub-ware/validate.js @@ -0,0 +1,15 @@ + +const { check, validationResult } = require('express-validator'); + +exports.validateDeliveryPerson = [ + check('email').isEmail().withMessage('Email is invalid'), + check('phone_number').isMobilePhone().withMessage('Phone number is invalid'), + check('status').isIn(['active', 'inactive']).withMessage('Status must be active or inactive'), + (req, res, next) => { + const errors = validationResult(req); + if (!errors.isEmpty()) { + return res.status(400).json({ errors: errors.array() }); + } + next(); + } +]; diff --git a/backend/model/shop/sub-model/DeliveryPerson.js b/backend/model/shop/sub-model/DeliveryPerson.js new file mode 100644 index 00000000..03d9afe3 --- /dev/null +++ b/backend/model/shop/sub-model/DeliveryPerson.js @@ -0,0 +1,44 @@ +// models/DeliveryPerson.js +const mongoose = require("mongoose"); + +const deliveryPersonSchema = new mongoose.Schema({ + name: { + type: String, + required: true, + }, + email: { + type: String, + required: true, + unique: true, + }, + phone_number: { + type: String, + required: true, + }, + status: { + type: String, + enum: ["active", "inactive"], + required: true, + }, + assigned_routes: [{ type: mongoose.Schema.Types.ObjectId, ref: "Route" }], + vehicle_details: { + vehicle_type: { type: String }, + vehicle_number: { type: String }, + }, + created_at: { + type: Date, + default: Date.now, + }, + updated_at: { + type: Date, + default: Date.now, + }, + password: { + type: String +}, + profile_picture: { + type: String + }, +}); + +module.exports = mongoose.model("DeliveryPerson", deliveryPersonSchema); diff --git a/backend/services/sub-service/hashPassword.js b/backend/services/sub-service/hashPassword.js new file mode 100644 index 00000000..0c0a30a2 --- /dev/null +++ b/backend/services/sub-service/hashPassword.js @@ -0,0 +1,9 @@ + +const bcrypt = require('bcrypt'); + +const hashPassword = async (password) => { + const salt = await bcrypt.genSalt(10); + return bcrypt.hash(password, salt); +}; + +module.exports = { hashPassword }; diff --git a/frontend/src/AgroRentAI/components/RentSupportPage.jsx b/frontend/src/AgroRentAI/components/RentSupportPage.jsx new file mode 100644 index 00000000..4a6dff18 --- /dev/null +++ b/frontend/src/AgroRentAI/components/RentSupportPage.jsx @@ -0,0 +1,35 @@ +import React from "react"; +import RentOrderTracking from "./sub-component/OrderTracking"; +import FAQ from "./sub-component/Fa"; +import LiveChat from "./sub-component/Livechat"; + + +const RentSupportPage = () => { + return ( +
+

Customer Support

+ + {/* Live Chat Support Section */} +
+
+ +
+
+ + {/* Help Center & FAQ Section */} +
+
+ +
+
+ + {/* Order Tracking Section */} +
+
+ +
+
+
+ ); +}; +export default RentSupportPage; diff --git a/frontend/src/AgroRentAI/components/sub-component/Fa.jsx b/frontend/src/AgroRentAI/components/sub-component/Fa.jsx new file mode 100644 index 00000000..bd34ce1b --- /dev/null +++ b/frontend/src/AgroRentAI/components/sub-component/Fa.jsx @@ -0,0 +1,85 @@ +import React, { useState } from "react"; +import { FaChevronDown, FaChevronUp, FaSearch } from "react-icons/fa"; // Icons for toggling and search + +const FAQ = () => { + const [activeIndex, setActiveIndex] = useState(null); // For handling which FAQ is open + const [searchQuery, setSearchQuery] = useState(""); + + const faqs = [ + { + question: "How do I rent a product?", + answer: "To rent a product, browse our catalog, choose the item you want, and select the rental duration.", + }, + { + question: "What payment methods are accepted?", + answer: "We accept credit/debit cards, PayPal, and bank transfers.", + }, + { + question: "How do I return a product?", + answer: "You can return the product by following the return instructions sent via email after your rental period ends.", + }, + { + question: "What should I do if the product is damaged?", + answer: "If the product is damaged, please contact us immediately to arrange for repairs or a replacement.", + }, + { + question: "Can I track my rental order?", + answer: "Yes, you can track your rental order status from your account dashboard.", + }, + ]; + + const handleToggle = (index) => { + setActiveIndex(activeIndex === index ? null : index); // Toggle open/close + }; + + const filteredFaqs = faqs.filter((faq) => + faq.question.toLowerCase().includes(searchQuery.toLowerCase()) + ); + + return ( +
+

Help Center & FAQ

+ + {/* Search Bar */} +
+ + setSearchQuery(e.target.value)} + placeholder="Search FAQ" + className="w-full p-2 border-none focus:outline-none text-gray-600" + /> +
+ + {/* FAQ List */} +
+ {filteredFaqs.length > 0 ? ( + filteredFaqs.map((faq, index) => ( +
handleToggle(index)} + > +
+

{faq.question}

+ {activeIndex === index ? ( + + ) : ( + + )} +
+ {activeIndex === index && ( +

{faq.answer}

+ )} +
+ )) + ) : ( +

No results found. Please try a different search term.

+ )} +
+
+ ); +}; + +export default FAQ; diff --git a/frontend/src/AgroRentAI/components/sub-component/Livechat.jsx b/frontend/src/AgroRentAI/components/sub-component/Livechat.jsx new file mode 100644 index 00000000..f4754b74 --- /dev/null +++ b/frontend/src/AgroRentAI/components/sub-component/Livechat.jsx @@ -0,0 +1,89 @@ +import React, { useState } from "react"; +import { FaPaperPlane, FaUserCircle } from "react-icons/fa"; // For icons + +const LiveChat = () => { + const [userName, setUserName] = useState(""); + const [userMessage, setUserMessage] = useState(""); + const [chatHistory, setChatHistory] = useState([ + { sender: "Support", message: "Hello! How can we assist you today?" }, + ]); + + const handleMessageChange = (e) => { + setUserMessage(e.target.value); + }; + + const handleNameChange = (e) => { + setUserName(e.target.value); + }; + + const handleSendMessage = () => { + if (userMessage.trim() !== "") { + setChatHistory([...chatHistory, { sender: userName || "Guest", message: userMessage }]); + setUserMessage(""); // Clear input after sending message + setTimeout(() => { + setChatHistory((prevHistory) => [ + ...prevHistory, + { sender: "Support", message: "We are here to help!" }, + ]); + }, 1000); // Simulating a response after 1 second + } + }; + + return ( +
+

+ Live Chat Support +

+ + {/* User Name Field */} +
+ + +
+ + {/* Chat History */} +
+
+ {chatHistory.map((chat, index) => ( +
+ {chat.sender}: + {chat.message} +
+ ))} +
+
+ + {/* Message Input */} +
+ + +
+ + {/* Send Button */} + +
+ ); +}; + +export default LiveChat; diff --git a/frontend/src/AgroRentAI/components/sub-component/OrderTracking.jsx b/frontend/src/AgroRentAI/components/sub-component/OrderTracking.jsx new file mode 100644 index 00000000..0582dfaa --- /dev/null +++ b/frontend/src/AgroRentAI/components/sub-component/OrderTracking.jsx @@ -0,0 +1,106 @@ +import React, { useState } from "react"; +import { FaSearch, FaSpinner, FaCheckCircle, FaTimesCircle } from "react-icons/fa"; // Icons for search, loading, and status + +const RentOrderTracking = () => { + const [orderId, setOrderId] = useState(""); + const [orderStatus, setOrderStatus] = useState(null); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + + + const handleTrackOrder = () => { + if (!orderId) return; // Avoid empty submission + + setLoading(true); + setError(null); + setOrderStatus(null); + + + // Simulate order tracking (In a real app, you would fetch this from an API) + const mockOrderStatus = { + 123: "Shipped - Expected delivery: 2 days", + 456: "In Transit - Expected delivery: 1 day", + 789: "Delivered - Thank you for renting!", + }; + + // Simulate an API request delay + setTimeout(() => { + if (mockOrderStatus[orderId]) { + setOrderStatus(mockOrderStatus[orderId]); + } else { + setError("Order ID not found. Please check and try again."); + } + setLoading(false); + }, 1500); // Simulate network delay + }; + + return ( +
+

Order Tracking

+ + {/* Order ID Input */} +
+ + setOrderId(e.target.value)} + className="p-3 border-2 border-gray-300 rounded-lg w-full" + /> +
+ + {/* Track Order Button */} + + + {/* Display Order Status */} + {loading &&

Tracking your order...

} + + {/* Error or Order Status */} + {orderStatus && !loading && ( +
+ + Order Status: {orderStatus} +
+ )} + + {error && !loading && ( +
+ + Error: {error} +
+ )} + + {/* Order History Section */} +
+

Past Orders

+ +
+
+ ); +}; + +export default RentOrderTracking; diff --git a/frontend/src/AgroShopAI/components/Pages/Admin-Dashboard.jsx b/frontend/src/AgroShopAI/components/Pages/Admin-Dashboard.jsx index 61dbc155..b61a8644 100644 --- a/frontend/src/AgroShopAI/components/Pages/Admin-Dashboard.jsx +++ b/frontend/src/AgroShopAI/components/Pages/Admin-Dashboard.jsx @@ -6,6 +6,7 @@ import { useState } from "react"; import StatisticComponent from "./components/StatisticComponent"; import ReturnPanel from "./components/ReturnPage"; import AdminProductManagement from "./ProductManagement"; +import ProfileEdit from "./components/ProfileManage"; export default function AdminDashboard() { const [activeView, setActiveView] = useState("dashboard"); // Track active view @@ -25,6 +26,7 @@ export default function AdminDashboard() { {activeView === "analytics" && } {activeView === "return" && } {activeView === "product" && } + {activeView === "settings" && } ); diff --git a/frontend/src/AgroShopAI/components/Pages/components/ActiveSessions.jsx b/frontend/src/AgroShopAI/components/Pages/components/ActiveSessions.jsx new file mode 100644 index 00000000..2cc037cd --- /dev/null +++ b/frontend/src/AgroShopAI/components/Pages/components/ActiveSessions.jsx @@ -0,0 +1,33 @@ +import React, { useState } from 'react'; + +const ActiveSessions = () => { + const [sessions, setSessions] = useState([ + { id: 1, device: 'MacBook Pro', location: 'New York', lastActive: '10 minutes ago' }, + { id: 2, device: 'iPhone', location: 'Los Angeles', lastActive: '1 hour ago' }, + ]); + + const handleLogout = (id) => { + setSessions(sessions.filter(session => session.id !== id)); + }; + + return ( +
+

Active Sessions

+ {sessions.length === 0 ? ( +

No active sessions.

+ ) : ( +
    + {sessions.map((session) => ( +
  • + {session.device} ({session.location}) + {session.lastActive} + +
  • + ))} +
+ )} +
+ ); +}; + +export default ActiveSessions; diff --git a/frontend/src/AgroShopAI/components/Pages/components/ActivityLog.jsx b/frontend/src/AgroShopAI/components/Pages/components/ActivityLog.jsx new file mode 100644 index 00000000..45a46cad --- /dev/null +++ b/frontend/src/AgroShopAI/components/Pages/components/ActivityLog.jsx @@ -0,0 +1,22 @@ +import React from 'react'; + +const ActivityLog = () => { + const activities = [ + 'Logged in from a new device', + 'Changed email address', + 'Password updated', + ]; + + return ( +
+

Activity Log

+
    + {activities.map((activity, index) => ( +
  • {activity}
  • + ))} +
+
+ ); +}; + +export default ActivityLog; diff --git a/frontend/src/AgroShopAI/components/Pages/components/Message.jsx b/frontend/src/AgroShopAI/components/Pages/components/Message.jsx new file mode 100644 index 00000000..e6a15b7a --- /dev/null +++ b/frontend/src/AgroShopAI/components/Pages/components/Message.jsx @@ -0,0 +1,12 @@ +import React from 'react'; + +const Message = ({ message }) => { + return ( +
+

{message}

+
+ ); +}; + +export default Message; + diff --git a/frontend/src/AgroShopAI/components/Pages/components/Notifications.jsx b/frontend/src/AgroShopAI/components/Pages/components/Notifications.jsx new file mode 100644 index 00000000..f5233936 --- /dev/null +++ b/frontend/src/AgroShopAI/components/Pages/components/Notifications.jsx @@ -0,0 +1,86 @@ +import React, { useState } from 'react'; + +const Notifications = () => { + // State for managing notification preferences + const [emailNotifications, setEmailNotifications] = useState(true); + const [smsNotifications, setSmsNotifications] = useState(false); + const [appNotifications, setAppNotifications] = useState(true); + const [orderNotifications, setOrderNotifications] = useState(true); + const [inventoryNotifications, setInventoryNotifications] = useState(false); + + const handleToggle = (setting, setter) => { + setter(!setting); + }; + + const handleSubmit = (e) => { + e.preventDefault(); + // Handle the form submission for saving the changes + alert('Notification preferences saved!'); + }; + + return ( +
+

Notification Settings

+
+
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ ); +}; + +export default Notifications; diff --git a/frontend/src/AgroShopAI/components/Pages/components/PasswordForm.jsx b/frontend/src/AgroShopAI/components/Pages/components/PasswordForm.jsx new file mode 100644 index 00000000..5ca96497 --- /dev/null +++ b/frontend/src/AgroShopAI/components/Pages/components/PasswordForm.jsx @@ -0,0 +1,94 @@ +const PasswordForm = ({ + password, + setPassword, + isLoading, + setIsLoading, + setMessage, +}) => { + const handlePasswordChange = (e) => { + setPassword({ ...password, [e.target.name]: e.target.value }); + }; + + const handlePasswordSubmit = (e) => { + e.preventDefault(); + if (password.new !== password.confirm) { + setMessage({ type: "error", text: "New passwords do not match!" }); + return; + } + setIsLoading(true); + // Simulate API call + setTimeout(() => { + setIsLoading(false); + setMessage({ type: "success", text: "Password changed successfully!" }); + setPassword({ current: "", new: "", confirm: "" }); + }, 1500); + }; + + return ( +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+ ); +}; + +export default PasswordForm; diff --git a/frontend/src/AgroShopAI/components/Pages/components/PersonalInfo.jsx b/frontend/src/AgroShopAI/components/Pages/components/PersonalInfo.jsx new file mode 100644 index 00000000..0e52afd6 --- /dev/null +++ b/frontend/src/AgroShopAI/components/Pages/components/PersonalInfo.jsx @@ -0,0 +1,86 @@ +const PersonalInfo = ({ + personalInfo, + setPersonalInfo, + isLoading, + setIsLoading, + setMessage, +}) => { + const handlePersonalInfoChange = (e) => { + setPersonalInfo({ ...personalInfo, [e.target.name]: e.target.value }); + }; + + const handleSubmit = (e) => { + e.preventDefault(); + setIsLoading(true); + // Simulate API call + setTimeout(() => { + setIsLoading(false); + setMessage({ type: "success", text: "Profile updated successfully!" }); + }, 1500); + }; + + return ( +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+ ); +}; + +export default PersonalInfo; diff --git a/frontend/src/AgroShopAI/components/Pages/components/ProfileManage.jsx b/frontend/src/AgroShopAI/components/Pages/components/ProfileManage.jsx new file mode 100644 index 00000000..d534201b --- /dev/null +++ b/frontend/src/AgroShopAI/components/Pages/components/ProfileManage.jsx @@ -0,0 +1,107 @@ +import React, { useState } from "react"; +import TabNav from "./TabNav"; +import PersonalInfo from "./PersonalInfo"; +import PasswordForm from "./PasswordForm"; +import Notifications from "./Notifications"; +import SecuritySettings from "./SecuritySettings"; +import ActivityLog from "./ActivityLog"; +import ActiveSessions from "./ActiveSessions"; +import Message from "./Message"; + +export default function ProfileEdit() { + const [activeTab, setActiveTab] = useState("personal"); + const [personalInfo, setPersonalInfo] = useState({ + name: "John Doe", + email: "john.doe@agroshop.com", + profilePicture: "/placeholder.svg?height=100&width=100", + }); + const [password, setPassword] = useState({ + current: "", + new: "", + confirm: "", + }); + const [notifications, setNotifications] = useState({ + email: true, + sms: false, + app: true, + newOrders: true, + lowInventory: false, + }); + const [securitySettings, setSecuritySettings] = useState({ + securityQuestion: "What was your first pet's name?", + securityAnswer: "", + accountLockout: true, + }); + const [activityLog] = useState([ + { + type: "login", + date: "2023-11-10 09:30:00", + details: "Logged in from Chrome on Windows", + }, + { + type: "profile_update", + date: "2023-11-09 14:15:00", + details: "Updated email address", + }, + { + type: "password_change", + date: "2023-11-08 11:00:00", + details: "Changed password", + }, + ]); + const [activeSessions] = useState([ + { device: "Chrome on Windows", lastActive: "2023-11-10 10:30:00" }, + { device: "Safari on iPhone", lastActive: "2023-11-10 09:45:00" }, + ]); + const [isLoading, setIsLoading] = useState(false); + const [message, setMessage] = useState({ type: "", text: "" }); + + return ( +
+

Profile Edit

+ + + + {message.text && } + + {activeTab === "personal" && ( + + )} + {activeTab === "password" && ( + + )} + {activeTab === "notifications" && ( + + )} + {activeTab === "security" && ( + + )} + {activeTab === "activity" && } + {activeTab === "sessions" && ( + + )} +
+ ); +} diff --git a/frontend/src/AgroShopAI/components/Pages/components/SecuritySettings.jsx b/frontend/src/AgroShopAI/components/Pages/components/SecuritySettings.jsx new file mode 100644 index 00000000..d388a5d7 --- /dev/null +++ b/frontend/src/AgroShopAI/components/Pages/components/SecuritySettings.jsx @@ -0,0 +1,36 @@ +import React, { useState } from 'react'; + +const SecuritySettings = () => { + const [twoFactorAuth, setTwoFactorAuth] = useState(false); + const [changePassword, setChangePassword] = useState(false); + + const handleToggle2FA = () => { + setTwoFactorAuth(!twoFactorAuth); + }; + + const handleChangePassword = () => { + setChangePassword(true); + // Implement password change functionality here + }; + + return ( +
+

Security Settings

+
+ +
+
+ +
+
+ ); +}; + +export default SecuritySettings; diff --git a/frontend/src/AgroShopAI/components/Pages/components/TabNav.jsx b/frontend/src/AgroShopAI/components/Pages/components/TabNav.jsx new file mode 100644 index 00000000..4177288f --- /dev/null +++ b/frontend/src/AgroShopAI/components/Pages/components/TabNav.jsx @@ -0,0 +1,30 @@ +const TabNav = ({ activeTab, setActiveTab }) => { + return ( +
+ +
+ ); +}; + +export default TabNav; diff --git a/frontend/src/MainContent.jsx b/frontend/src/MainContent.jsx index fadc8c0d..536ddcd4 100644 --- a/frontend/src/MainContent.jsx +++ b/frontend/src/MainContent.jsx @@ -102,12 +102,16 @@ import AffiliateProgramPage from './AgroShopAI/components/Pages/Affiliate'; import TicketManagement from './AgroShopAI/components/Pages/AdminTicket'; import SupportPage from './AgroShopAI/components/Pages/TicketUser'; + +import RentSupportPage from './AgroRentAI/components/RentSupportPage'; + import WarehouseInventory from './AgroShopAI/components/Pages/Admin-Warehouse'; + const MainContent = () => { UseScrollToTop(); const location = useLocation(); // Get the current route @@ -199,6 +203,7 @@ const MainContent = () => { } /> } /> + } /> } /> {/* AgroShopAI Routes */}