diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md index 275a361..731dbab 100644 --- a/ISSUE_TEMPLATE.md +++ b/ISSUE_TEMPLATE.md @@ -5,9 +5,3 @@ **If your issue was not created using the app above, it will be closed immediately.** --> - - diff --git a/src/api/ManageUser/users.js b/src/api/ManageUser/users.js new file mode 100644 index 0000000..7abc093 --- /dev/null +++ b/src/api/ManageUser/users.js @@ -0,0 +1,52 @@ +import axios from "axios"; +import baseURL from "config"; + +// Function to delete a user +export async function deleteUser(userId) { + try { + const response = await axios.post(`${baseURL}/delete-user`, { user_ID: userId }); + if (response.status === 200) { + console.log(response.data.message); // Assuming the response has a message field + } else { + console.error("Failed to delete user:", response.statusText); + } + } catch (error) { + console.error("Error deleting user:", error); + throw error; + } +} + +// Function to edit user details +export async function editUser(userId, updatedData) { + try { + const response = await axios.post(`${baseURL}/updateUser`, { + userId: userId, + fullName: updatedData.fullName, + mobile: updatedData.contactNumber, + profession: updatedData.profession, + }); + if (response.status === 200) { + console.log(response.data.message); // Assuming the response has a message field + } else { + console.error("Failed to edit user:", response.statusText); + } + } catch (error) { + console.error("Error editing user:", error); + throw error; + } +} + +// Function to get the list of users +export async function getUserList() { + try { + const response = await axios.get(`${baseURL}/getAllUsers`); + if (response.status === 200) { + return response.data; + } else { + console.error("Failed to fetch user list:", response.statusText); + } + } catch (error) { + console.error("Error fetching user list:", error); + throw error; + } +} diff --git a/src/api/sendImg.js b/src/api/advertisementextract/sendImg.js similarity index 100% rename from src/api/sendImg.js rename to src/api/advertisementextract/sendImg.js diff --git a/src/api/sendPdf.js b/src/api/advertisementextract/sendPdf.js similarity index 100% rename from src/api/sendPdf.js rename to src/api/advertisementextract/sendPdf.js diff --git a/src/api/sendUrl.js b/src/api/advertisementextract/sendUrl.js similarity index 80% rename from src/api/sendUrl.js rename to src/api/advertisementextract/sendUrl.js index 186d58e..9a455c0 100644 --- a/src/api/sendUrl.js +++ b/src/api/advertisementextract/sendUrl.js @@ -2,14 +2,14 @@ import baseURL from "config"; -export async function sendUrlToBackend(inputUrl) { +export async function sendUrlToBackend(inputUrl, publish) { try { const response = await fetch(`${baseURL}/sendurl`, { method: "POST", headers: { "Content-Type": "application/json", }, - body: JSON.stringify({ url: inputUrl }), + body: JSON.stringify({ url: inputUrl, publish: publish }), }); if (!response.ok) { diff --git a/src/api/graphViewer/prediction.js b/src/api/graphViewer/prediction.js new file mode 100644 index 0000000..8bb6eb5 --- /dev/null +++ b/src/api/graphViewer/prediction.js @@ -0,0 +1,13 @@ +import axios from "axios"; +import baseURL from "config"; + +// Function to fetch data from the backend +export async function getPriceFluct() { + try { + const response = await axios.get(`${baseURL}/priceFluctuationData`); // Adjust the endpoint URL + return response.data; + } catch (error) { + console.error("Error fetching data from the backend:", error); + throw error; + } +} diff --git a/src/api/pendingAdvertisement/pendingAdvertisemnet.js b/src/api/pendingAdvertisement/pendingAdvertisemnet.js new file mode 100644 index 0000000..39bd37a --- /dev/null +++ b/src/api/pendingAdvertisement/pendingAdvertisemnet.js @@ -0,0 +1,12 @@ +import axios from "axios"; +import baseURL from "config"; + +export async function fetchPendingAdvertisements() { + try { + const response = await axios.get(`${baseURL}/pendingAdvertisements`); // Adjust the endpoint URL + return response.data; + } catch (error) { + console.error("Error fetching pending advertisements:", error); + throw error; + } +} diff --git a/src/api/report/getReports.js b/src/api/report/getReports.js index 179dbc9..1bbb9b0 100644 --- a/src/api/report/getReports.js +++ b/src/api/report/getReports.js @@ -1,25 +1,47 @@ import axios from "axios"; import baseURL from "config"; -// Function to fetch a saved PDF report from the backend -export async function getReportPdf(reportId) { +// Function to delete a user +export async function deleteUser(userId) { try { - const response = await axios.get(`${baseURL}/view-pdf?ReportID=${reportId}`, { - responseType: "blob", // Specify the response type as a blob - }); + const response = await axios.delete(`${baseURL}/users/${userId}`); + if (response.status === 200) { + console.log(`User with ID ${userId} has been deleted`); + } else { + console.error("Failed to delete user:", response.statusText); + } + } catch (error) { + console.error("Error deleting user:", error); + throw error; + } +} +// Function to edit user details +export async function editUser(userId, updatedData) { + try { + const response = await axios.put(`${baseURL}/users/${userId}`, updatedData); if (response.status === 200) { - // Create a blob URL for the PDF data - const blob = new Blob([response.data], { type: "application/pdf" }); - const url = window.URL.createObjectURL(blob); + console.log(`User with ID ${userId} has been updated`); + } else { + console.error("Failed to edit user:", response.statusText); + } + } catch (error) { + console.error("Error editing user:", error); + throw error; + } +} - // Open the PDF in a new tab - window.open(url, "_blank"); +// Function to get the list of users +export async function getUserList() { + try { + const response = await axios.get(`${baseURL}/users`); + if (response.status === 200) { + return response.data; } else { - console.error("Failed to fetch PDF report:", response.statusText); + console.error("Failed to fetch user list:", response.statusText); } } catch (error) { - console.error("Error fetching PDF report:", error); + console.error("Error fetching user list:", error); throw error; } } diff --git a/src/api/submitAdvertisement/submitAdvertisement.js b/src/api/submitAdvertisement/submitAdvertisement.js new file mode 100644 index 0000000..86b5ea9 --- /dev/null +++ b/src/api/submitAdvertisement/submitAdvertisement.js @@ -0,0 +1,13 @@ +import axios from "axios"; +import baseURL from "config"; + +export async function submitAdvertisement(formData) { + console.log("submitAdvertisement formData:", formData); + try { + const response = await axios.post(`${baseURL}/submitAdvertisement`, formData); // Adjust the endpoint URL + return response.data; + } catch (error) { + console.error("Error submitting advertisement:", error); + throw error; + } +} diff --git a/src/api/updateUser/updateUser.js b/src/api/updateUser/updateUser.js index b0873a9..35af6ca 100644 --- a/src/api/updateUser/updateUser.js +++ b/src/api/updateUser/updateUser.js @@ -12,3 +12,33 @@ export async function updateUser(userData) { throw error; } } + +export async function updateProfilePicture(url, userId) { + try { + const response = await axios.post(`${baseURL}/updateProfilePicture`, { url, userId }); // Adjust the endpoint URL + console.log(response.data); + return response.data; + } catch (error) { + console.error("Error updating user data on the backend:", error); + throw error; + } +} + +export async function updateLastSeen(userid) { + try { + const last_seen = Date.now(); // Obtain the timestamp + const date = new Date(last_seen); // Convert the timestamp to a Date object + const lastSeenDate = date.toLocaleDateString(); // Obtain the date in a locale-specific format + const lastSeenTime = date.toLocaleTimeString(); // Obtain the time in a locale-specific format + const lastSeenDateTime = `${lastSeenDate} ${lastSeenTime}`; // Combine the date and time + console.log(userid, lastSeenDateTime); + const response = await axios.post(`${baseURL}/updateLastSeen`, { + last_seen: lastSeenDateTime, + userId: userid, + }); + return response.data; + } catch (error) { + console.error("Error updating user data on the backend:", error); + throw error; + } +} diff --git a/src/assets/images/newsback.jpg b/src/assets/images/newsback.jpg new file mode 100644 index 0000000..bdab124 Binary files /dev/null and b/src/assets/images/newsback.jpg differ diff --git a/src/examples/Cards/InfoCards/ProfileInfoCard/index.js b/src/examples/Cards/InfoCards/ProfileInfoCard/index.js index 04df700..f5fd122 100644 --- a/src/examples/Cards/InfoCards/ProfileInfoCard/index.js +++ b/src/examples/Cards/InfoCards/ProfileInfoCard/index.js @@ -34,6 +34,7 @@ import colors from "assets/theme/base/colors"; import typography from "assets/theme/base/typography"; import UpdateInfoModal from "./updateInfo"; import { useState } from "react"; +import MDAlert from "components/MDAlert"; function ProfileInfoCard({ title, description, info, social, action, shadow }) { const labels = []; @@ -88,6 +89,7 @@ function ProfileInfoCard({ title, description, info, social, action, shadow }) { )); const [isModalOpen, setIsModalOpen] = useState(false); + const [isPasswordChanged, setIsPasswordChanged] = useState(false); const handleOpenModal = () => { setIsModalOpen(true); @@ -105,6 +107,11 @@ function ProfileInfoCard({ title, description, info, social, action, shadow }) { return ( + {isPasswordChanged && ( + + Your password have been changed + + )} {title} @@ -119,6 +126,7 @@ function ProfileInfoCard({ title, description, info, social, action, shadow }) { onClose={handleCloseModal} onSave={handleSaveInfo} initialValues={updatedInfo} // Pass the current info data as initialValues + setChangePassword={setIsPasswordChanged} /> diff --git a/src/examples/Cards/InfoCards/ProfileInfoCard/updateInfo.js b/src/examples/Cards/InfoCards/ProfileInfoCard/updateInfo.js index 0ab3047..05fac49 100644 --- a/src/examples/Cards/InfoCards/ProfileInfoCard/updateInfo.js +++ b/src/examples/Cards/InfoCards/ProfileInfoCard/updateInfo.js @@ -11,8 +11,9 @@ import MDButton from "components/MDButton"; import { updateUser } from "api/updateUser/updateUser"; import { useUser } from "utils/userContext"; -function UpdateInfoModal({ open, onClose, onSave, initialValues }) { +function UpdateInfoModal({ open, onClose, onSave, initialValues, setChangePassword }) { const [formData, setFormData] = useState(initialValues); + // const [changePassword, setChangePassword] = useState(false); // State to hold the change password checkbox value const { user } = useUser(); const handleInputChange = (e) => { @@ -24,13 +25,23 @@ function UpdateInfoModal({ open, onClose, onSave, initialValues }) { }; const handleSave = async () => { - onSave(formData); + // eslint-disable-next-line no-unused-vars + const { password, ...formDataToSave } = formData; + onSave(formDataToSave); + try { const userId = user.user_ID; // Extract the user ID from the form data - const { fullName, mobile, profession, location } = formData; + const { fullName, mobile, profession, location, password } = formData; console.log(formData); - const userData = { fullName, mobile, profession, location, userId }; - await updateUser(userData); // Call the updateUser API function + const userData = { fullName, mobile, profession, location, password, userId }; + const response = await updateUser(userData); // Call the updateUser API function + + // Check if the password was updated + if (response && response.password_updated) { + setChangePassword(true); // Reset the change password checkbox + // You can use a state or a notification library here to show the message to the user + console.log("Password has been updated."); + } onClose(); // Close the modal after the update is successful } catch (error) { @@ -93,6 +104,23 @@ function UpdateInfoModal({ open, onClose, onSave, initialValues }) { {/* Add more fields as needed */} + + + Change Account Password + + + +
+ +
+ +
Save @@ -114,6 +142,7 @@ UpdateInfoModal.propTypes = { onClose: PropTypes.func.isRequired, onSave: PropTypes.func.isRequired, initialValues: PropTypes.object.isRequired, + setChangePassword: PropTypes.func.isRequired, }; export default UpdateInfoModal; diff --git a/src/examples/Cards/ProjectCards/DefaultProjectCard/index.js b/src/examples/Cards/ProjectCards/DefaultProjectCard/index.js index 3f7c523..8ad5f03 100644 --- a/src/examples/Cards/ProjectCards/DefaultProjectCard/index.js +++ b/src/examples/Cards/ProjectCards/DefaultProjectCard/index.js @@ -30,6 +30,7 @@ import MDTypography from "components/MDTypography"; import MDButton from "components/MDButton"; import MDAvatar from "components/MDAvatar"; import { useRef, useState, useEffect } from "react"; +import { Box } from "@mui/material"; function DefaultProjectCard({ image, label, title, description, action, authors }) { const renderAuthors = authors.map(({ image: media, name }) => ( @@ -94,30 +95,44 @@ function DefaultProjectCard({ image, label, title, description, action, authors }} > - md, - objectFit: "cover", - objectPosition: "center", - }} - /> + + md, + objectFit: "cover", + objectPosition: "center", + position: "absolute", + top: 0, + left: 0, + width: "100%", + height: "100%", + }} + /> + + {label} - + {action.type === "internal" ? ( {title} @@ -129,13 +144,29 @@ function DefaultProjectCard({ image, label, title, description, action, authors rel="noreferrer" variant="h5" textTransform="capitalize" + style={{ + whiteSpace: "nowrap", + textOverflow: "ellipsis", + overflow: "hidden", + maxWidth: "100%", // You can adjust this value as needed + }} > {title} )} - - + + {description} diff --git a/src/examples/Navbars/DashboardNavbar/index.js b/src/examples/Navbars/DashboardNavbar/index.js index d06adf9..e92ba06 100644 --- a/src/examples/Navbars/DashboardNavbar/index.js +++ b/src/examples/Navbars/DashboardNavbar/index.js @@ -153,7 +153,7 @@ function DashboardNavbar({ absolute, light, isMini }) { {isMini ? null : ( navbarRow(theme, { isMini })}> - + account_circle diff --git a/src/firebase.js b/src/firebase.js index 2cee295..41e0b2b 100644 --- a/src/firebase.js +++ b/src/firebase.js @@ -24,10 +24,21 @@ const firebaseConfig = { measurementId: measurementId, }; +// const firebaseConfig = { +// apiKey: "AIzaSyAjKWWDuBXnKH40Ik3GX_4MIDUcjFGfjX4", +// authDomain: "advizor-71682.firebaseapp.com", +// projectId: "advizor-71682", +// storageBucket: "advizor-71682.appspot.com", +// messagingSenderId: "436861904344", +// appId: "1:436861904344:web:52966dfa3937c3c9e9bead", +// measurementId: "G-4MSLN0VTVP", +// }; + // Initialize Firebase const app = initializeApp(firebaseConfig); const auth = getAuth(app); const provider = new GoogleAuthProvider(); -export { auth, provider }; -export const storage = getStorage(app); +const storage = getStorage(app); + +export { auth, provider, storage }; diff --git a/src/layouts/admin/contentapproval/contentApproval.js b/src/layouts/admin/contentapproval/contentApproval.js index a17bbb5..e485b63 100644 --- a/src/layouts/admin/contentapproval/contentApproval.js +++ b/src/layouts/admin/contentapproval/contentApproval.js @@ -3,39 +3,48 @@ import Container from "@mui/material/Container"; import Typography from "@mui/material/Typography"; import Card from "@mui/material/Card"; import CardContent from "@mui/material/CardContent"; -import Button from "@mui/material/Button"; import Box from "@mui/material/Box"; import DashboardLayout from "examples/LayoutContainers/DashboardLayout"; import DashboardNavbar from "examples/Navbars/DashboardNavbar"; +import { fetchPendingAdvertisements } from "api/pendingAdvertisement/pendingAdvertisemnet"; +import MDButton from "components/MDButton"; // Simulated data for advertisements pending approval -const advertisements = [ - { - id: 1, - title: "Historic Estate", - location: "Jaffna", - date: "Sun, 03 Sep 2023 18:30:04 GMT", - description: "This is a historic estate.", - image: "image_url_here", - }, - { - id: 2, - title: "Historic Estate", - location: "Jaffna", - date: "Sun, 03 Sep 2023 18:30:04 GMT", - description: "This is a historic estate.", - image: "image_url_here", - }, - // Add more advertisements as needed -]; +// const advertisements = [ +// { +// id: 1, +// title: "Historic Estate", +// location: "Jaffna", +// date: "Sun, 03 Sep 2023 18:30:04 GMT", +// description: "This is a historic estate.", +// image: "image_url_here", +// }, +// { +// id: 2, +// title: "Historic Estate", +// location: "Jaffna", +// date: "Sun, 03 Sep 2023 18:30:04 GMT", +// description: "This is a historic estate.", +// image: "image_url_here", +// }, +// // Add more advertisements as needed +// ]; function ContentApprovalPage() { - const [pendingAds, setPendingAds] = useState(advertisements); + const [pendingAds, setPendingAds] = useState([]); const [currentAdIndex, setCurrentAdIndex] = useState(0); useEffect(() => { - // Fetch pending advertisements from the server here if needed - // Update the 'pendingAds' state with the fetched data + async function fetchData() { + try { + const data = await fetchPendingAdvertisements(); + setPendingAds(data); + console.log(pendingAds); + } catch (error) { + console.error("Error fetching pending advertisements:", error); + } + } + fetchData(); }, []); const approveAd = () => { @@ -64,7 +73,7 @@ function ContentApprovalPage() { } }; - const currentAd = pendingAds[currentAdIndex]; + //const currentAd = pendingAds[currentAdIndex]; return ( @@ -74,46 +83,59 @@ function ContentApprovalPage() { Content Approval - {currentAd ? ( - - - - Advertisement ID: {currentAd.id} - - - Title: {currentAd.title} - - - Location: {currentAd.location} - - - Date: {currentAd.date} - - - Description: {currentAd.description} - - {currentAd.image && ( - Advertisement - )} - - - - - - + {pendingAds.length ? ( + pendingAds.map((currentAd, index) => ( + + + + Advertisement ID: {currentAd.Advertisement_ID} + + + Category: {currentAd.Category} + + + Title: {currentAd.Title} + + + Location: {currentAd.Location.City} + + + Date: {currentAd.Posted_Date} + + + Description: {currentAd.Description} + + {currentAd.image && ( + Advertisement + )} + + + Approve + + + Edit + + + Reject + + + + + )) ) : ( No pending advertisements. diff --git a/src/layouts/admin/managereports/data/managereportsdata.js b/src/layouts/admin/managereports/data/managereportsdata.js new file mode 100644 index 0000000..af56ddb --- /dev/null +++ b/src/layouts/admin/managereports/data/managereportsdata.js @@ -0,0 +1,135 @@ +/* eslint-disable react/prop-types */ +/* eslint-disable react/function-component-definition */ +/** + * ========================================================= + * Material Dashboard 2 React - v2.2.0 + * ========================================================= + * + * Product Page: https://www.creative-tim.com/product/material-dashboard-react + * Copyright 2023 Creative Tim (https://www.creative-tim.com) + * + * Coded by www.creative-tim.com + * + * ========================================================= + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + */ + +// Material Dashboard 2 React components +import MDBox from "components/MDBox"; +import MDTypography from "components/MDTypography"; +import MDBadge from "components/MDBadge"; +import { useEffect, useState } from "react"; +import { getReportList } from "api/report/reportsdata"; +import { useUser } from "utils/userContext"; + +export default function Data() { + const Job = ({ title, description }) => ( + + + {title} + + {description} + + ); + + const [reportDetails, setReportsDetails] = useState([]); + const { user } = useUser(); + const userID = user.user_ID; + + useEffect(() => { + // Fetch average price data from the Flask API endpoint + getReportList(userID) + .then((data) => { + setReportsDetails(data); + console.log(data); // Use 'data' instead of 'reportDetails' + }) + .catch((error) => { + console.error("Error fetching data:", error); + }); + }, []); + + const getFileExtension = (pdfUrl) => { + if (pdfUrl.toLowerCase().includes("pdf")) { + return "pdf"; + } else if (pdfUrl.toLowerCase().includes("xlsx")) { + return "xlsx"; + } else if (pdfUrl.toLowerCase().includes("csv")) { + return "csv"; + } else { + return "pdf"; + } + }; + const mapExtensionToColor = (extension) => { + switch (extension) { + case "pdf": + return "error"; + case "xlsx": + return "success"; // Change to the desired color for xls + case "csv": + return "warning"; // Change to the desired color for csv + default: + return "text"; // Replace with your default color + } + }; + + const handleDownload = (pdf_Url) => { + if (pdf_Url) { + // Create an anchor element to trigger the download + const anchor = document.createElement("a"); + anchor.href = pdf_Url; + anchor.target = "_blank"; // Open the link in a new tab + anchor.download = "your_file_name.ext"; // Replace with the desired file name + + // Trigger the download + anchor.click(); + } else { + console.error("Download URL is not available."); + } + }; + + return { + columns: [ + { Header: "Title", accessor: "author", align: "left" }, + { Header: "Type", accessor: "function", align: "left" }, + { Header: "Format", accessor: "status", align: "center" }, + { Header: "Date", accessor: "employed", align: "center" }, + { Header: "Download", accessor: "action", align: "center" }, + ], + rows: reportDetails.map((report) => ({ + author: ( + + {report.Title} + + ), + function: , + status: ( + + + + ), + employed: ( + + {report.timestamp} + + ), + action: ( + handleDownload(report.PDF_URL)} // Use an arrow function + > + Download + + ), + })), + }; +} diff --git a/src/layouts/admin/managereports/reportView.js b/src/layouts/admin/managereports/reportView.js new file mode 100644 index 0000000..94bd4f8 --- /dev/null +++ b/src/layouts/admin/managereports/reportView.js @@ -0,0 +1,56 @@ +// export default ReportViewer; +import React from "react"; +import Grid from "@mui/material/Grid"; +import Card from "@mui/material/Card"; + +// Material Dashboard 2 React components +import MDBox from "components/MDBox"; +import MDTypography from "components/MDTypography"; + +import DataTable from "examples/Tables/DataTable"; + +import data from "./data/managereportsdata"; +import DashboardLayout from "examples/LayoutContainers/DashboardLayout"; +import DashboardNavbar from "examples/Navbars/DashboardNavbar"; + +function ManageReports() { + const { columns, rows } = data(); + return ( + + + + + + + + + Reports History + + + + + + + + + + + ); +} + +export default ManageReports; diff --git a/src/layouts/admin/manageuser/data/userData.js b/src/layouts/admin/manageuser/data/userData.js index 9b144ad..1e75abe 100644 --- a/src/layouts/admin/manageuser/data/userData.js +++ b/src/layouts/admin/manageuser/data/userData.js @@ -1,102 +1,102 @@ -/* eslint-disable react/prop-types */ -/* eslint-disable react/function-component-definition */ -/** - * ========================================================= - * Material Dashboard 2 React - v2.2.0 - * ========================================================= - * - * Product Page: https://www.creative-tim.com/product/material-dashboard-react - * Copyright 2023 Creative Tim (https://www.creative-tim.com) - * - * Coded by www.creative-tim.com - * - * ========================================================= - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - */ - -// Material Dashboard 2 React components import MDBox from "components/MDBox"; import MDTypography from "components/MDTypography"; import MDBadge from "components/MDBadge"; import { useEffect, useState } from "react"; -import { getReportList } from "api/report/reportsdata"; +import { deleteUser, editUser, getUserList } from "api/ManageUser/users"; +import PropTypes from "prop-types"; export default function Data() { - const Job = ({ title, description }) => ( + const UserDetails = ({ name, email }) => ( - {title} + {name} - {description} + {email} ); - const [reportDetails, setReportsDetails] = useState([]); + UserDetails.propTypes = { + name: PropTypes.string.isRequired, + email: PropTypes.string.isRequired, + }; + const [userDetails, setUserDetails] = useState([]); useEffect(() => { - // Fetch average price data from the Flask API endpoint - getReportList() + getUserList() .then((data) => { - setReportsDetails(data); - console.log(data); // Use 'data' instead of 'reportDetails' + setUserDetails(data); + console.log(data); }) .catch((error) => { - console.error("Error fetching data:", error); + console.error("Error fetching user data:", error); }); }, []); - const handleDownload = (pdf_Url) => { - if (pdf_Url) { - // Create an anchor element to trigger the download - const anchor = document.createElement("a"); - anchor.href = pdf_Url; - anchor.target = "_blank"; // Open the link in a new tab - anchor.download = "your_file_name.ext"; // Replace with the desired file name + const handleUserDelete = (userId) => { + if (userId) { + // Add code to delete the user using the user ID + deleteUser(userId); + } else { + console.error("User ID is not available."); + } + }; - // Trigger the download - anchor.click(); + const handleUserEdit = (userId) => { + if (userId) { + // Add code to edit the user using the user ID + editUser(userId); } else { - console.error("Download URL is not available."); + console.error("User ID is not available."); } }; return { columns: [ - { Header: "User", accessor: "author", align: "left" }, - { Header: "Profession", accessor: "function", align: "left" }, - { Header: "Status", accessor: "status", align: "center" }, - { Header: "Last Seen", accessor: "employed", align: "center" }, + { Header: "Name", accessor: "name", align: "left" }, + { Header: "Email", accessor: "email", align: "left" }, + { Header: "Role", accessor: "role", align: "center" }, + { Header: "Last Seen", accessor: "lastSeen", align: "center" }, { Header: "Manage", accessor: "action", align: "center" }, ], - rows: reportDetails.map((report) => ({ - author: ( + rows: userDetails.map((user) => ({ + name: ( - {report.Title} + {user.Full_Name} ), - function: , - status: ( - - - + email: , + role: ( + + {user.Profession} + ), - employed: ( + lastSeen: ( - {report.timestamp} + {user.Last_Seen} ), action: ( - handleDownload(report.PDF_URL)} // Use an arrow function - > - Download - +
+ handleUserDelete(user._id)} // Use an arrow function + /> + handleUserEdit(user._id)} // Use an arrow function + /> +
), })), }; diff --git a/src/layouts/admin/submitadvertisement/submitad.js b/src/layouts/admin/submitadvertisement/submitad.js index a1ad889..dbfed9d 100644 --- a/src/layouts/admin/submitadvertisement/submitad.js +++ b/src/layouts/admin/submitadvertisement/submitad.js @@ -151,7 +151,7 @@ // export default AdvertisementForm; -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import Container from "@mui/material/Container"; import Typography from "@mui/material/Typography"; import TextField from "@mui/material/TextField"; @@ -160,29 +160,49 @@ import Box from "@mui/material/Box"; import CloudUploadIcon from "@mui/icons-material/CloudUpload"; import DashboardLayout from "examples/LayoutContainers/DashboardLayout"; import DashboardNavbar from "examples/Navbars/DashboardNavbar"; -import { Card } from "@mui/material"; +import { Card, Menu, MenuItem } from "@mui/material"; import MDButton from "components/MDButton"; +import MDBox from "components/MDBox"; +import MDInput from "components/MDInput"; +import { submitAdvertisement } from "api/submitAdvertisement/submitAdvertisement"; +import { storage } from "../../../firebase"; +import { ref, uploadBytes, getDownloadURL } from "firebase/storage"; +import { v4 } from "uuid"; function AdvertisementForm() { const [formData, setFormData] = useState({ title: "", location: "", - date: "", description: "", image: null, category: "", // New category field }); + const initialFormData = { + title: "", + location: "", + description: "", + image: null, + category: "", + }; const [imagePreview, setImagePreview] = useState(null); const handleChange = (e) => { const { name, value } = e.target; - setFormData({ ...formData, [name]: value }); + if (name === "phoneNumbers" || name == "landMarks") { + const phoneNumbers = value.split(",").map((number) => number.trim()); + setFormData({ ...formData, [name]: phoneNumbers }); + } else { + setFormData({ ...formData, [name]: value }); + } }; - const handleImageChange = (e) => { + const handleImageChange = async (e) => { const file = e.target.files[0]; - setFormData({ ...formData, image: file }); + const imageRef = ref(storage, `advertisement-picture/${v4()}`); // Define the reference to the image + await uploadBytes(imageRef, file); // Upload the image bytes + const url = await getDownloadURL(imageRef); + setFormData({ ...formData, image: url }); const reader = new FileReader(); reader.onload = (event) => { @@ -191,19 +211,70 @@ function AdvertisementForm() { reader.readAsDataURL(file); }; - const handleSubmit = (e) => { + // const [position, setPosition] = useState([]); + + useEffect(() => { + const fetchData = async () => { + try { + // Split the locationsParam into individual city names + const cityName = formData.nearestCity; + // Initialize an array to store marker locations + const markerLocations = []; + // Use a geocoding service (like OpenStreetMap Nominatim) to get coordinates for each city + const response = await fetch( + `https://nominatim.openstreetmap.org/search?format=json&q=${cityName}` + ); + if (!response.ok) { + throw new Error("Network response was not ok"); + } + const data = await response.json(); + // Check if the response contains valid data + if (Array.isArray(data) && data.length > 0) { + const location = data[0]; // Take the first result + // const position = [parseFloat(location.lat), parseFloat(location.lon)]; + // setPosition([parseFloat(location.lat), parseFloat(location.lon)]); + formData.longitude = parseFloat(location.lon); + formData.lattitude = parseFloat(location.lat); + markerLocations.push({ + name: cityName, + Location: { + Latitude: parseFloat(location.lat), + Longitude: parseFloat(location.lon), + }, + }); + } + + // Update the markers state with the retrieved locations + } catch (error) { + console.error("Error fetching marker data:", error); + } + }; + fetchData(); + }, [formData.nearestCity, formData.longitude, formData.lattitude]); + + const handleSubmit = async (e) => { e.preventDefault(); - console.log("Form data:", formData); + if (formData.category) { + try { + const response = await submitAdvertisement(formData); + console.log("Advertisement submitted successfully:", response); + setFormData(initialFormData); + } catch (error) { + console.error("Error submitting advertisement:", error); + } + } else { + alert("Select a category"); + } }; // Define form fields based on category let categoryFields; - if (formData.category === "landsale") { + if (formData.category === "Land Sale") { categoryFields = ( <> - Price per Perch + Price per Perch in LKR @@ -218,11 +290,11 @@ function AdvertisementForm() { Number of Perches
@@ -230,12 +302,12 @@ function AdvertisementForm() { Posted on @@ -284,6 +356,31 @@ function AdvertisementForm() { name="nearestCity" value={formData.nearestCity} onChange={handleChange} + required + /> + + + + Longitude + + + + + + Lattitude + + @@ -312,12 +409,12 @@ function AdvertisementForm() { ); - } else if (formData.category === "housesale") { + } else if (formData.category === "House Sale") { categoryFields = ( <> - Price + Price in LKR @@ -332,11 +430,11 @@ function AdvertisementForm() { Number of rooms @@ -344,12 +442,12 @@ function AdvertisementForm() { Posted on @@ -398,6 +496,31 @@ function AdvertisementForm() { name="nearestCity" value={formData.nearestCity} onChange={handleChange} + required + /> + + + + Longitude + + + + + + Lattitude + + @@ -415,7 +538,7 @@ function AdvertisementForm() { {/* Add more fields for housesale */} ); - } else if (formData.category === "marriageproposals") { + } else if (formData.category === "Marriage Proposals") { categoryFields = ( <> @@ -423,23 +546,33 @@ function AdvertisementForm() { Gender + select + SelectProps={{ + // Add this prop to style the Select component + style: { minHeight: "40px", minWidth: "100px" }, // You can adjust the height as needed + }} + > + Male + Female + Other + Age @@ -477,6 +610,7 @@ function AdvertisementForm() { value={formData.requirements} onChange={handleChange} style={{ width: "100%" }} + required /> @@ -484,12 +618,12 @@ function AdvertisementForm() { Posted on @@ -538,6 +672,31 @@ function AdvertisementForm() { name="nearestCity" value={formData.nearestCity} onChange={handleChange} + required + /> + + + + Longitude + + + + + + Lattitude + + @@ -557,27 +716,82 @@ function AdvertisementForm() { ); } + // const handleChangeMenu = (event) => {}; + + const [categoryMenu, setCategoryMenu] = useState(null); + + const openCategoryMenu = ({ currentTarget }) => setCategoryMenu(currentTarget); + const closeCategoryMenu = () => setCategoryMenu(null); + const [category, setCategory] = useState(""); + + const handleCategoryMenuItemClick = (dataKey) => { + setCategory(dataKey); + formData.category = dataKey; + closeCategoryMenu(); + }; + + const renderCategoryMenu = ( + + handleCategoryMenuItemClick("Land Sale")}>Land Sales + handleCategoryMenuItemClick("House Sale")}>House Sales + handleCategoryMenuItemClick("Marriage Proposals")}> + Marriage Proposals + + + ); return ( - - + + Submit Advertisement
- + {/* Category + */} + + + Category + + + + + {renderCategoryMenu} + + {categoryFields /* Render category-specific fields */} + Title @@ -591,6 +805,18 @@ function AdvertisementForm() { required /> + + + Description + + + Upload Image @@ -621,8 +847,8 @@ function AdvertisementForm() { /> )} - - + + Submit Advertisement diff --git a/src/layouts/advertisement/addetails.js b/src/layouts/advertisement/addetails.js index 7e236cc..7e0b065 100644 --- a/src/layouts/advertisement/addetails.js +++ b/src/layouts/advertisement/addetails.js @@ -17,7 +17,7 @@ const Addetail = () => { try { const data = await getAdDetail(id); setADDetails(data); - console.log(adDetails); + console.log(adDetails.Source); } catch (error) { console.error("Error fetching data from the backend:", error); } @@ -305,7 +305,7 @@ const Addetail = () => { - {adDetails.source} + {adDetails.Source} @@ -562,7 +562,7 @@ const Addetail = () => { - {adDetails.source} + {adDetails.Source} diff --git a/src/layouts/authentication/components/Footer/index.js b/src/layouts/authentication/components/Footer/index.js index 812de4a..69473fd 100644 --- a/src/layouts/authentication/components/Footer/index.js +++ b/src/layouts/authentication/components/Footer/index.js @@ -57,7 +57,7 @@ function Footer({ light }) { by - +  Advizor  diff --git a/src/layouts/authentication/reset-password/cover/index.js b/src/layouts/authentication/reset-password/cover/index.js index 67b17cf..6fb317b 100644 --- a/src/layouts/authentication/reset-password/cover/index.js +++ b/src/layouts/authentication/reset-password/cover/index.js @@ -1,36 +1,57 @@ -/** -========================================================= -* Material Dashboard 2 React - v2.2.0 -========================================================= - -* Product Page: https://www.creative-tim.com/product/material-dashboard-react -* Copyright 2023 Creative Tim (https://www.creative-tim.com) - -Coded by www.creative-tim.com - - ========================================================= - -* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -*/ - -// @mui material components +import React, { useState } from "react"; import Card from "@mui/material/Card"; - -// Material Dashboard 2 React components import MDBox from "components/MDBox"; import MDTypography from "components/MDTypography"; import MDInput from "components/MDInput"; import MDButton from "components/MDButton"; - -// Authentication layout components import CoverLayout from "layouts/authentication/components/CoverLayout"; +import bgImage from "assets/images/newsback.jpg"; +import baseURL from "config"; +import { useNavigate } from "react-router-dom"; +import MDAlert from "components/MDAlert"; +import VerificationDialog from "layouts/authentication/sign-up/VerificationDialog"; + +function ResetPSW() { + const [email, setEmail] = useState(""); + const [verificationOpen, setVerificationOpen] = useState(false); + const [showSuccessAlert, setShowSuccessAlert] = useState(false); + const navigate = useNavigate(); + + const handleSend = () => { + console.log(email); + if (email === "") { + alert("Please enter email"); + return; + } + + // Send the email to the backend + fetch(`${baseURL}/reset-password`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ email }), + }) + .then((response) => { + response.json(); + }) -// Images -import bgImage from "assets/images/bg-reset-cover.jpeg"; + .then((data) => { + console.log("this is verification", data); + setVerificationOpen(true); + }) + .catch((error) => { + console.error("Error:", error); + }); + }; -function Cover() { return ( + {showSuccessAlert && ( + + entered code is correct + + )} - You will receive an e-mail in maximum 60 seconds + You will receive a temporary password - + setEmail(e.target.value)} + /> - - reset + + SEND CODE + {verificationOpen && ( + setVerificationOpen(false)} + email={email} // Pass the email to the dialog + onSuccess={() => { + // Handle successful verification if needed + setShowSuccessAlert(true); + setTimeout(() => { + setShowSuccessAlert(false); + navigate(`/authentication/sign-in`); + }, 1000); + }} + address={"verify-email"} + /> + )} ); } -export default Cover; +export default ResetPSW; diff --git a/src/layouts/authentication/reset-password/cover/newpassword.js b/src/layouts/authentication/reset-password/cover/newpassword.js new file mode 100644 index 0000000..a53ebca --- /dev/null +++ b/src/layouts/authentication/reset-password/cover/newpassword.js @@ -0,0 +1,58 @@ +import DashboardLayout from "examples/LayoutContainers/DashboardLayout"; + +import baseURL from "config"; +import React, { useState } from "react"; + +function NewPassword() { + const [password, setPassword] = useState(""); + + const handleSubmit = (event) => { + event.preventDefault(); + if (password === "") { + alert("Please enter password"); + return; + } + + // Send the password to the backend + fetch(`${baseURL}/new-password`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ password }), + }) + .then((response) => { + response.json(); + }) + + .then((data) => { + console.log("this is verification", data); + }) + .catch((error) => { + console.error("Error:", error); + }); + // TODO: handle password submission + }; + + return ( +
+ +

Reset Password

+ + +
+ + +
+
+ ); +} + +export default NewPassword; diff --git a/src/layouts/authentication/sign-in/index.js b/src/layouts/authentication/sign-in/index.js index 157669d..1e3dee7 100644 --- a/src/layouts/authentication/sign-in/index.js +++ b/src/layouts/authentication/sign-in/index.js @@ -1,18 +1,3 @@ -/** -========================================================= -* Material Dashboard 2 React - v2.2.0 -========================================================= - -* Product Page: https://www.creative-tim.com/product/material-dashboard-react -* Copyright 2023 Creative Tim (https://www.creative-tim.com) - -Coded by www.creative-tim.com - - ========================================================= - -* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -*/ - import { useState } from "react"; // react-router-dom components @@ -20,7 +5,7 @@ import { Link } from "react-router-dom"; // @mui material components import Card from "@mui/material/Card"; -import Switch from "@mui/material/Switch"; +// import Switch from "@mui/material/Switch"; // Material Dashboard 2 React components import MDBox from "components/MDBox"; @@ -46,13 +31,16 @@ function Basic() { const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); - const [rememberMe, setRememberMe] = useState(false); + // const [rememberMe, setRememberMe] = useState(false); - const handleSetRememberMe = () => setRememberMe(!rememberMe); - const handleForgetPassword = () => {}; + // const handleSetRememberMe = () => setRememberMe(!rememberMe); const [value, setValue] = useState(""); const navigate = useNavigate(); + const handleForgetPassword = () => { + navigate("/authentication/reset-password"); + }; + const handleClick = () => { signInWithPopup(auth, provider).then((data) => { setValue(data.user.email); @@ -61,44 +49,6 @@ function Basic() { }); }; - // const handleLogin = () => { - // if (!email || !password) { - // alert("Please enter both email and password"); - // return; - // } - // fetch("/login", { - // method: "POST", - // headers: { - // "Content-Type": "application/json", - // }, - // body: JSON.stringify({ - // email: email, - // password: password, - // }), - // }) - // .then((response) => { - // if (!response.ok) { - // throw response.status; - // } - // return response.json(); - // }) - // .then((data) => { - // console.log(data); - // // Display a success message if applicable - // login({ name: email, role: "user" }); - // navigate("/dashboard"); - // }) - // .catch((status) => { - // console.log(status, "error"); - // if (status === 400) { - // alert("Email and password are required."); - // } else if (status === 401) { - // alert("Invalid User Name or Incorrect Password."); - // } else { - // alert("An error occurred during login."); - // } - // }); - // }; const handleLogin = () => { if (!email || !password) { alert("Please enter both email and password"); @@ -124,7 +74,6 @@ function Basic() { if (data && data.user) { // Display a success message if applicable const userData = data.user; - console.log(userData); login({ name: userData.User_Name, full_name: userData.Full_Name, @@ -133,23 +82,24 @@ function Basic() { email: userData.email, phone_Number: userData.Contact_Number, profession: userData.Profession, + Profile_Picture: userData.Profile_Picture, + Last_Seen: userData.Last_Seen, }); - // Now you can use userData as needed in your frontend - // For example, you can store it in state or context for later use - // login({ name: userData.User_Name, role: "user" }); + // if (rememberMe) { + // Cookies.set("user_id", userData.UserID, { expires: 365 }); // The cookie expires in 365 days + // } navigate("/dashboard"); } else { alert("User data not found in the response."); } }) .catch((status) => { - console.log(status, "error"); if (status === 400) { alert("Email and password are required."); } else if (status === 401) { alert("Invalid User Name or Incorrect Password."); } else { - alert("An error occurred during login."); + alert("Check your Network Connection"); } }); }; @@ -157,38 +107,6 @@ function Basic() { return ( - {/* - - Sign in - - - - - - - - - - - - - - - - - - - */} - + {/*   Remember me - +
*/}
- - - Use "test@advizor.com" and "test" as demo-credentials - - Log in diff --git a/src/layouts/authentication/sign-up/VerificationDialog.js b/src/layouts/authentication/sign-up/VerificationDialog.js index fa1219a..5754784 100644 --- a/src/layouts/authentication/sign-up/VerificationDialog.js +++ b/src/layouts/authentication/sign-up/VerificationDialog.js @@ -9,11 +9,16 @@ import DialogTitle from "@mui/material/DialogTitle"; import TextField from "@mui/material/TextField"; import Button from "@mui/material/Button"; import baseURL from "config"; +import { useUser } from "utils/userContext"; -export default function VerificationDialog({ open, onClose, email, onSuccess }) { +export default function VerificationDialog({ open, onClose, email, onSuccess, address }) { const [verificationCode, setVerificationCode] = useState(""); const [timeRemaining, setTimeRemaining] = useState(60); const [alertType, setAlertType] = useState(null); + const [alertPassword, setAlertPassword] = useState(false); + const [hideComponent, sethideComponent] = useState(true); + const [newpassword, setNewPassword] = useState(""); + const { login } = useUser(); useEffect(() => { let interval = null; @@ -23,12 +28,10 @@ export default function VerificationDialog({ open, onClose, email, onSuccess }) setTimeRemaining((prevTime) => prevTime - 1); }, 1000); - // Clear interval when component unmounts or dialog closes return () => { clearInterval(interval); }; } else if (!open) { - // Reset timer when dialog closes setTimeRemaining(60); } }, [open, timeRemaining]); @@ -36,22 +39,39 @@ export default function VerificationDialog({ open, onClose, email, onSuccess }) const handleVerificationSubmit = () => { if (verificationCode) { axios - .post(`${baseURL}/verify`, { + .post(`${baseURL}/${address}`, { email: email, verificationCode: verificationCode, }) .then(function (response) { console.log(response); if (response.data.success) { - // alert("Registration successful!"); setAlertType("success"); console.log(alertType); - onSuccess(); - } else { - setAlertType("error"); - alert("Verification code is incorrect or expired."); + if (address === "verify") { + const userData = response.data.user; + login({ + name: userData.User_Name, + full_name: userData.Full_Name, + user_ID: userData.UserID, + role: userData.Role, + email: userData.email, + phone_Number: userData.Contact_Number, + profession: userData.Profession, + Profile_Picture: userData.Profile_Picture, + }); + onSuccess(); + onClose(); + } else if (address === "verify-email") { + setAlertPassword(true); + sethideComponent(false); + setNewPassword(response.data.newpassword); + // onSuccess(); + } else { + setAlertType("error"); + alert("Verification code is incorrect or expired."); + } } - onClose(); }) .catch(function (error) { console.log(error, "error"); @@ -59,16 +79,20 @@ export default function VerificationDialog({ open, onClose, email, onSuccess }) } }; + const handlePasswordSubmit = () => { + onSuccess(); + onClose(); + }; + const handleCancel = () => { axios .post(`${baseURL}/verify`, { email: email, - verificationCode: "", // Provide an empty code to indicate cancellation - cancel: true, // Add a flag to indicate cancellation + verificationCode: "", + cancel: true, }) .then(function (response) { console.log(response); - // setVerificationOpen(false); onClose(); }) .catch(function (error) { @@ -77,46 +101,64 @@ export default function VerificationDialog({ open, onClose, email, onSuccess }) }; return ( - - Verification Code - - - Please enter the verification code you received: - {timeRemaining > 0 ? ( - ({timeRemaining} seconds left) - ) : ( - (Timeout) - )} - + <> + + {hideComponent && ( + <> + Verification Code + + + Please enter the verification code you received: + {timeRemaining > 0 ? ( + ({timeRemaining} seconds left) + ) : ( + (Timeout) + )} + - {/* {alertType === "success" && ( - Registration successful! + setVerificationCode(e.target.value)} + /> + + + <> + + + + + )} - - {alertType === "error" && ( - - Verification code is incorrect or expired. - - )} */} - - setVerificationCode(e.target.value)} - /> - - - - - - + {alertPassword && ( + <> + Verification Successful + + + Your new password is {newpassword} Important: Please imediately change your password + after login + + + + + + + )} + + ); } diff --git a/src/layouts/authentication/sign-up/index.js b/src/layouts/authentication/sign-up/index.js index 989f6c7..e030aff 100644 --- a/src/layouts/authentication/sign-up/index.js +++ b/src/layouts/authentication/sign-up/index.js @@ -23,7 +23,6 @@ import bgImage from "assets/images/newspaper2.jpg"; import VerificationDialog from "./VerificationDialog"; import { useNavigate } from "react-router-dom"; -import { useUser } from "utils/userContext"; import baseURL from "config"; import TermModal from "./term"; @@ -33,7 +32,6 @@ function Cover() { const [name, setName] = useState(""); const navigate = useNavigate(); const [showSuccessAlert, setShowSuccessAlert] = useState(false); - const { login } = useUser(); const [verificationOpen, setVerificationOpen] = useState(false); @@ -94,22 +92,7 @@ function Cover() { } else { return response.json().then((data) => { console.log(data); - // Handle success, e.g., show a success message to the user - // alert(data.message); - const userData = data.user; - console.log(userData); - login({ - name: userData.User_Name, - full_name: userData.Full_Name, - user_ID: userData.UserID, - role: userData.Role, - email: userData.email, - phone_Number: userData.Contact_Number, - profession: userData.Profession, - }); setVerificationOpen(true); - - // navigate("/dashboard"); }); } }) @@ -200,8 +183,6 @@ function Cover() {   I agree the  setVerificationOpen(false)} - email={email} // Pass the email to the dialog + email={email} onSuccess={() => { - // Handle successful verification if needed setShowSuccessAlert(true); setTimeout(() => { setShowSuccessAlert(false); navigate("/dashboard"); }, 1000); }} + address={"verify"} /> )} diff --git a/src/layouts/authentication/sign-up/term.js b/src/layouts/authentication/sign-up/term.js index 09ece52..8e19660 100644 --- a/src/layouts/authentication/sign-up/term.js +++ b/src/layouts/authentication/sign-up/term.js @@ -9,10 +9,9 @@ import MDTypography from "components/MDTypography"; function TermModal({ open, onClose }) { const cardContentStyle = { - // Add your desired width and height for the modal - width: "80%", // Adjust as needed - height: "80vh", // Adjust as needed - overflowY: "scroll", // Add a vertical scroll when the content exceeds the height + width: "80%", + height: "80vh", + overflowY: "scroll", }; return ( ({ @@ -63,11 +62,7 @@ export default function data() { date: ad.Posted_Date, address: ad.Location.Address, // Use the correct field for the address phoneNumber: ad.Contact_Info.Phone_Number.join(", "), // Join multiple phone numbers if available - price: ( - - Rs.{ad.Price_per_Perch} - - ), + price: ad.Price_per_Perch, })), }, @@ -81,7 +76,7 @@ export default function data() { { Header: "Posted Date", accessor: "date", align: "center" }, //{ Header: "Address", accessor: "address", align: "center" }, { Header: "PhoneNumber", accessor: "phoneNumber", align: "center" }, - { Header: "Price", accessor: "price", align: "center" }, + { Header: "Price in Rs.", accessor: "price", align: "center" }, ], rows: recentHouseAds.map((ad, index) => ({ @@ -93,11 +88,7 @@ export default function data() { address: ad.Location.Address, // Use the correct field for the address phoneNumber: ad.Contact_Info.Phone_Number.join(", "), // Join multiple phone numbers if available No_of_Rooms: ad.Number_of_Rooms, - price: ( - - Rs.{ad.Price} - - ), + price: ad.Price, })), }, diff --git a/src/layouts/dashboard/components/Projects/index.js b/src/layouts/dashboard/components/Projects/index.js index c79e7df..e6938e1 100644 --- a/src/layouts/dashboard/components/Projects/index.js +++ b/src/layouts/dashboard/components/Projects/index.js @@ -1,19 +1,4 @@ -/** -========================================================= -* Material Dashboard 2 React - v2.2.0 -========================================================= - -* Product Page: https://www.creative-tim.com/product/material-dashboard-react -* Copyright 2023 Creative Tim (https://www.creative-tim.com) - -Coded by www.creative-tim.com - - ========================================================= - -* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -*/ - -import { useState } from "react"; +import { useEffect, useState } from "react"; // @mui material components import Card from "@mui/material/Card"; @@ -34,10 +19,12 @@ import data from "layouts/dashboard/components/Projects/data"; function Projects() { const { landSale, houseSale, marriageProposals } = data(); const [menu, setMenu] = useState(null); - const [selectedData, setSelectedData] = useState(landSale); - + const [selectedData, setSelectedData] = useState(() => landSale); const openMenu = ({ currentTarget }) => setMenu(currentTarget); const closeMenu = () => setMenu(null); + useEffect(() => { + setSelectedData(landSale); + }, []); const handleMenuItemClick = (dataKey) => { setSelectedData(dataKey); closeMenu(); diff --git a/src/layouts/dashboard/components/SearchBar/searchBar.js b/src/layouts/dashboard/components/SearchBar/searchBar.js index a46b8d8..be29e22 100644 --- a/src/layouts/dashboard/components/SearchBar/searchBar.js +++ b/src/layouts/dashboard/components/SearchBar/searchBar.js @@ -12,7 +12,7 @@ import { Grid, Pagination, useMediaQuery } from "@mui/material"; import { getAdbyFilter } from "api/searchBar/getAdbyFilter"; import MDTypography from "components/MDTypography"; import { Link } from "react-router-dom"; -import Loading from "components/Loading"; +import Loading from "react-loading"; // import MDPagination from "components/MDPagination"; const AdvertisementSearch = () => { @@ -48,12 +48,14 @@ const AdvertisementSearch = () => { const [selectedData, setSelectedData] = useState([]); const [currentPage, setCurrentPage] = useState(0); + const [noresult, setNoresult] = useState(false); const adsPerPage = 20; const handleSearch = async () => { try { // Implement your search logic here, fetching data based on the selected option and query // For example, you can use the getRecentAd function from the API file + setNoresult(false); setCurrentPage(0); setLoading(true); const searchData = await getAdbyFilter( @@ -64,6 +66,9 @@ const AdvertisementSearch = () => { category ); setSelectedData(searchData); + if (searchData.length === 0) { + setNoresult(true); + } setLoading(false); } catch (error) { console.error("Error searching:", error); @@ -146,28 +151,6 @@ const AdvertisementSearch = () => { // Get ads for the current page const currentAds = selectedData.slice(startIndex, endIndex); - // const advertisementData = { - // columns: [ - // { Header: "#", accessor: "index", width: "5%", align: "left" }, - // { Header: "Title", accessor: "title", width: "10%", align: "left" }, - // { Header: "Source", accessor: "source", align: "center" }, - // { Header: "Location", accessor: "city", align: "center" }, - // { Header: "Posted Date", accessor: "date", align: "center" }, - // //{ Header: "Address", accessor: "address", align: "center" }, - // { Header: "PhoneNumber", accessor: "phoneNumber", align: "center" }, - // { Header: "Description", accessor: "description", align: "center" }, - // ], - // rows: selectedData.map((ad, index) => ({ - // index: index + 1, - // title: ad.Title, - // source: ad.Source, // You can choose an appropriate field for the source - // city: ad.Location.City, - // date: ad.Posted_Date, - // phoneNumber: ad.Contact_Info.Phone_Number.join(", "), // Join multiple phone numbers if available - // description: ad.Description, - // })), // Add your data here - // }; - // Customized page options starting from 1 const isMobile = useMediaQuery("(max-width: 600px)"); return ( @@ -267,57 +250,29 @@ const AdvertisementSearch = () => {
- - - {loading && } - - {" "} - {/* Use Grid container */} - {currentAds.map((ad, index) => ( - - {" "} - {/* Use Grid item */} - - - ))} - - {selectedData.length > adsPerPage && ( - // - // - // - // keyboard_arrow_left - // - // - // 1 - // - // 2 - // 3 - // - // keyboard_arrow_right - // - // - - - handlePageChange(page)} - /> - - - )} -
+ + {loading && } + {noresult && No Search results found} + + {currentAds.map((ad, index) => ( + + + + ))} + + {selectedData.length > adsPerPage && ( + + + handlePageChange(page)} + /> + + + )} + ); }; diff --git a/src/layouts/dashboard/components/SearchBar/searchResultCard.js b/src/layouts/dashboard/components/SearchBar/searchResultCard.js index 5c2a0f1..ce230fd 100644 --- a/src/layouts/dashboard/components/SearchBar/searchResultCard.js +++ b/src/layouts/dashboard/components/SearchBar/searchResultCard.js @@ -7,6 +7,7 @@ import homeDecor2 from "assets/images/house (1).jpg"; import homeDecor3 from "assets/images/wedding.jpg"; const SearchResultCard = ({ ad }) => { + const { Image } = ad; // Extract the category from the Advertisement_ID const getCategoryFromId = (advertisementId) => { const idNumber = parseInt(advertisementId[2]); @@ -33,7 +34,7 @@ const SearchResultCard = ({ ad }) => { return ( { { color: "info", label: "view Ad", }} - // authors={123} /> diff --git a/src/layouts/feedback/feedback.js b/src/layouts/feedback/feedback.js index 76d01af..e4ba577 100644 --- a/src/layouts/feedback/feedback.js +++ b/src/layouts/feedback/feedback.js @@ -3,14 +3,26 @@ import { Card, Checkbox, TextField } from "@mui/material"; import MDBox from "components/MDBox"; import MDButton from "components/MDButton"; import MDTypography from "components/MDTypography"; -import React, { useState } from "react"; +import React, { useState, useEffect } from "react"; import { submitFeedback } from "api/feedback/saveFeedback"; import { useUser } from "utils/userContext"; +import { getFeedbackData } from "api/feedback/getFeedback"; +import Loading from "components/Loading"; + +// Helper function to render the rating as stars +const renderRatingStars = (rating) => { + const starArray = []; + for (let i = 0; i < rating; i++) { + starArray.push(); // Render a star character + } + return starArray; +}; const FeedbackSection = () => { const [rating, setRating] = useState(0); const [feedback, setFeedback] = useState(""); const [publish, setPublish] = useState(false); + const [loading, setLoading] = useState(false); const { user } = useUser(); const userID = user.user_ID; @@ -36,60 +48,104 @@ const FeedbackSection = () => { } }; + const [feedbackData, setFeedbackData] = useState([]); + + useEffect(() => { + // Fetch feedback data when the component mounts + async function fetchFeedbackData() { + try { + setLoading(true); + const data = await getFeedbackData(); + setFeedbackData(data); + setLoading(false); + } catch (error) { + console.error("Error fetching feedback data:", error); + } + } + fetchFeedbackData(); + }, []); + return ( - - -
- - Rate our Newspaper Advertisement Analyzer - - - {[1, 2, 3, 4, 5].map((star) => ( - handleRatingChange(star)} - style={{ - cursor: "pointer", - color: star <= rating ? "orange" : "gray", - fontSize: "50px", - }} - > - ★ - - ))} +
+ + +
+ + Rate our Newspaper Advertisement Analyzer + + + {[1, 2, 3, 4, 5].map((star) => ( + handleRatingChange(star)} + style={{ + cursor: "pointer", + color: star <= rating ? "orange" : "gray", + fontSize: "50px", + }} + > + ★ + + ))} + +
+
+ Your Comment is extremely valuable to us + +
+
+ + +
+ + + Submit Feedback + -
-
- Your Comment is extremely valuable to us - -
-
- - -
- - - Submit Feedback - -
- + + + {loading && } + {feedbackData.map((feedback, index) => ( + +
+ + {feedback.user_name || feedback.Full_Name || "Anonymous"} + + + {feedback.email} + + + {feedback.rating && renderRatingStars(feedback.rating)} |{" "} + {feedback.date && new Date(feedback.date).toDateString()} + + + {feedback.feedback} + + + {new Date(feedback.timestamp.$date).toLocaleString() || feedback.timestamp.$date} + + {/* You can add buttons or actions here for managing feedback */} +
+
+ ))} +
); }; diff --git a/src/layouts/landing/App.js b/src/layouts/landing/App.js index 61747ea..8920c9c 100644 --- a/src/layouts/landing/App.js +++ b/src/layouts/landing/App.js @@ -9,7 +9,7 @@ import Action from "./Page/Action"; import "./index.css"; // import DashboardLayout from "examples/LayoutContainers/DashboardLayout"; // import DashboardNavbar from "examples/Navbars/DashboardNavbar"; -// import backgroundImage from "./Assets/images/background8.jpg"; +import backgroundImage from "./Assets/images/background11.png"; import DefaultNavbar from "examples/Navbars/DefaultNavbar"; import Configurator from "examples/Configurator"; import { useMaterialUIController, setOpenConfigurator } from "context"; @@ -18,7 +18,7 @@ import MDBox from "components/MDBox"; function App() { const containerStyle = { - // backgroundImage: `url(${backgroundImage})`, + backgroundImage: `url(${backgroundImage})`, backgroundSize: "cover", backgroundRepeat: "no-repeat", }; diff --git a/src/layouts/landing/Assets/images/background11.png b/src/layouts/landing/Assets/images/background11.png new file mode 100644 index 0000000..9731a9f Binary files /dev/null and b/src/layouts/landing/Assets/images/background11.png differ diff --git a/src/layouts/profile/components/Header/index.js b/src/layouts/profile/components/Header/index.js index 1c93135..e79bc0e 100644 --- a/src/layouts/profile/components/Header/index.js +++ b/src/layouts/profile/components/Header/index.js @@ -35,17 +35,20 @@ import MDAvatar from "components/MDAvatar"; import breakpoints from "assets/theme/base/breakpoints"; // Images -import burceMars from "assets/images/socrates.jpeg"; +//import burceMars from "assets/images/socrates.jpeg"; import backgroundImage from "assets/images/bg-profile.jpeg"; import { useUser } from "utils/userContext"; +import ProfileModal from "./updateprofile"; function Header({ children }) { const [tabsOrientation, setTabsOrientation] = useState("horizontal"); const [tabValue, setTabValue] = useState(0); const { user } = useUser(); + const [image, setImage] = useState(user.Profile_Picture); useEffect(() => { // A function that sets the orientation state of the tabs. + console.log(image); function handleTabsOrientation() { return window.innerWidth < breakpoints.values.sm ? setTabsOrientation("vertical") @@ -66,6 +69,16 @@ function Header({ children }) { const handleSetTabValue = (event, newValue) => setTabValue(newValue); + const [isModalOpen, setIsModalOpen] = useState(false); + + const handleOpenModal = () => { + setIsModalOpen(true); + }; + + const handleCloseModal = () => { + setIsModalOpen(false); + }; + return ( - + + {/* */} diff --git a/src/layouts/profile/components/Header/updateprofile.js b/src/layouts/profile/components/Header/updateprofile.js new file mode 100644 index 0000000..eb64fd6 --- /dev/null +++ b/src/layouts/profile/components/Header/updateprofile.js @@ -0,0 +1,125 @@ +import React, { useState } from "react"; +import PropTypes from "prop-types"; +import Modal from "@mui/material/Modal"; +import Card from "@mui/material/Card"; +import CardContent from "@mui/material/CardContent"; +import Grid from "@mui/material/Grid"; +import MDTypography from "components/MDTypography"; +import MDButton from "components/MDButton"; +import MDBox from "components/MDBox"; +import { storage } from "../../../../firebase"; +import { ref, uploadBytes, getDownloadURL } from "firebase/storage"; +import { useUser } from "utils/userContext"; +import { updateProfilePicture } from "api/updateUser/updateUser"; +import ReactLoading from "react-loading"; + +function ProfileModal({ open, onClose, image, setImage }) { + const [selectedImage, setSelectedImage] = useState(image); // State to hold the selected image + const [imageUpload, setImageUpload] = useState(null); // State to hold the uploaded image + const { user } = useUser(); + const [loading, setLoading] = useState(false); + // Function to handle file input change + const handleUpload = async () => { + console.log(user); + setLoading(true); + try { + // Upload selectedImage to Firebase storage + const imageRef = ref(storage, `profile-picture/${user.user_ID}`); // Define the reference to the image + await uploadBytes(imageRef, imageUpload); // Upload the image bytes + + // Get the download URL + const url = await getDownloadURL(imageRef); + // Call setImage with the download URL to update the image + updateProfilePicture(url, user.user_ID); + setImage(url); + setLoading(false); + onClose(); + } catch (error) { + console.error("Error uploading image to Firebase storage:", error); + } + }; + + const handleImageChange = (event) => { + const file = event.target.files[0]; + + if (file) { + const reader = new FileReader(); + + reader.onload = (e) => { + // Ensure that the result is set to the selectedImage state + setSelectedImage(e.target.result); + setImageUpload(file); // Set the uploaded image in the state + }; + + // Read the file as a data URL + reader.readAsDataURL(file); + } + }; + + return ( + + + + + + + Update the Profile Picture + + + + undraw-Add-user-re-5oib + + + + + + + + + Upload + {loading && ( + + )} + + + {/* + + */} + + + + + ); +} + +ProfileModal.propTypes = { + open: PropTypes.bool.isRequired, + onClose: PropTypes.func.isRequired, + image: PropTypes.string.isRequired, + setImage: PropTypes.func.isRequired, +}; + +export default ProfileModal; diff --git a/src/layouts/profile/index.js b/src/layouts/profile/index.js index c52dd76..eaec131 100644 --- a/src/layouts/profile/index.js +++ b/src/layouts/profile/index.js @@ -69,7 +69,11 @@ function Overview() { { + if (pdfUrl.toLowerCase().includes("pdf")) { + return "pdf"; + } else if (pdfUrl.toLowerCase().includes("xlsx")) { + return "xlsx"; + } else if (pdfUrl.toLowerCase().includes("csv")) { + return "csv"; + } else { + return "pdf"; + } + }; + const mapExtensionToColor = (extension) => { + switch (extension) { + case "pdf": + return "error"; + case "xlsx": + return "success"; // Change to the desired color for xls + case "csv": + return "warning"; // Change to the desired color for csv + default: + return "text"; // Replace with your default color + } + }; + const handleDownload = (pdf_Url) => { if (pdf_Url) { // Create an anchor element to trigger the download @@ -65,88 +89,6 @@ export default function Data() { }; return { - rawData: [ - { - id: 1, - name: "Historic Estate", - location: "Jaffna", - date: "Sun, 03 Sep 2023 18:30:04 GMT", - contactNumbers: ["0774698456", "0768596489"], - price: "Rs.250000", - }, - { - id: 2, - name: "Seaview Bungalow", - location: "Trincomalee", - date: "Wed, 30 Aug 2023 18:30:07 GMT", - contactNumbers: ["0774698459", "0768596492"], - price: "Rs.190000", - }, - { - id: 3, - name: "Ancient Property", - location: "Anuradhapura", - date: "Wed, 30 Aug 2023 18:30:05 GMT", - contactNumbers: ["0774698457", "0768596490"], - price: "Rs.120000", - }, - { - id: 4, - name: "Mountain View Property", - location: "Kandy", - date: "Wed, 30 Aug 2023 18:30:01 GMT", - contactNumbers: ["0774698453", "0768596486"], - price: "Rs.150000", - }, - { - id: 5, - name: "Hillside Property", - location: "Nuwara Eliya", - date: "Thu, 24 Aug 2023 18:30:09 GMT", - contactNumbers: ["0774698461", "0768596494"], - price: "Rs.120000", - }, - { - id: 6, - name: "Seaside Paradise", - location: "Galle", - date: "Sat, 19 Aug 2023 18:30:02 GMT", - contactNumbers: ["0774698454", "0768596487"], - price: "Rs.200000", - }, - { - id: 7, - name: "Beachfront Villa", - location: "Negombo", - date: "Thu, 10 Aug 2023 18:30:03 GMT", - contactNumbers: ["0774698455", "0768596488"], - price: "Rs.180000", - }, - { - id: 8, - name: "Riverside Land", - location: "Matara", - date: "Fri, 04 Aug 2023 18:30:08 GMT", - contactNumbers: ["0774698460", "0768596493"], - price: "Rs.80000", - }, - { - id: 9, - name: "Lakefront Retreat", - location: "Batticaloa", - date: "Thu, 03 Aug 2023 18:30:06 GMT", - contactNumbers: ["0774698458", "0768596491"], - price: "Rs.150000", - }, - { - id: 10, - name: "Prime Lands", - location: "Colombo", - date: "Sun, 30 Jul 2023 18:30:00 GMT", - contactNumbers: ["0774698452", "0768596485"], - price: "Rs.100000", - }, - ], columns: [ { Header: "Title", accessor: "author", align: "left" }, { Header: "Type", accessor: "function", align: "left" }, @@ -163,7 +105,12 @@ export default function Data() { function: , status: ( - + ), employed: ( diff --git a/src/layouts/reports/graphs/graphdetails.js b/src/layouts/reports/graphs/graphdetails.js index b361175..e40787b 100644 --- a/src/layouts/reports/graphs/graphdetails.js +++ b/src/layouts/reports/graphs/graphdetails.js @@ -1,21 +1,36 @@ -import React from "react"; +import React, { useState } from "react"; import { useParams } from "react-router-dom"; // For accessing route parameters import { Container, Typography } from "@mui/material"; // Material Dashboard 2 React components import MDBox from "components/MDBox"; -import data from "../data/reportsdata"; import MDButton from "components/MDButton"; -import { generateExcel } from "../reports"; +import { generateCSV, generateExcel } from "../reports"; import { CSVLink } from "react-csv"; -import Projects from "layouts/dashboard/components/Projects"; +// import Projects from "layouts/dashboard/components/Projects"; +import DataTable from "examples/Tables/DataTable"; +import data1 from "layouts/dashboard/components/Projects/data"; +import { useEffect } from "react"; +import { useUser } from "utils/userContext"; const GraphDetails = () => { - const { rawData } = data(); + const { user } = useUser(); + const { landSale, houseSale, marriageProposals } = data1(); + const dataMapping = { + "Land Sales": landSale, + "House Sales": houseSale, + "Marriage Proposals": marriageProposals, + }; + const [isValidTitle, setIsValidTitle] = useState(false); // Get the advertisement id from the URL const { title } = useParams(); - + useEffect(() => { + if (title in dataMapping) { + setIsValidTitle(true); + } + }, [title]); + const selectedData = dataMapping[title]; // Include id in the dependency array to refetch when id changes return ( @@ -23,17 +38,39 @@ const GraphDetails = () => { {title} - - - generateExcel(rawData, "uselessReport")}> - Export to Excel - - - - - Export to CSV - - + {isValidTitle && ( + + + + )} + {isValidTitle && ( + <> + + generateExcel(selectedData.rows, `${user.name}Report`, user.user_ID)} + > + Export to Excel + + + + + generateCSV(selectedData.rows, `${user.name}Report`, user.user_ID)} + > + Export to CSV + + + + + )} ); }; diff --git a/src/layouts/reports/index.js b/src/layouts/reports/index.js index 6d5f95e..a503d17 100644 --- a/src/layouts/reports/index.js +++ b/src/layouts/reports/index.js @@ -50,16 +50,6 @@ function Report() {
- {/* - generateExcel(rawData, "uselessReport")}> - Export to Excel - - - - - Export to CSV - - */}