This commit is contained in:
omkieit 2024-09-30 21:09:00 +05:30
parent 8b49882f18
commit c43f306d57
18 changed files with 774 additions and 228 deletions

View File

@ -1,5 +1,6 @@
import dotenv from "dotenv"; import dotenv from "dotenv";
import UserModal from "../models/user.js"; import UserModal from "../models/user.js";
import mongoose from 'mongoose';
import bcrypt from "bcryptjs"; import bcrypt from "bcryptjs";
import jwt from "jsonwebtoken"; import jwt from "jsonwebtoken";
import { sendEmail } from "../utils/sendEmail.js"; import { sendEmail } from "../utils/sendEmail.js";
@ -119,22 +120,35 @@ export const signin = async (req, res) => {
//To show user //To show user
export const showUser = async (req, res) => { export const showUser = async (req, res) => {
const { id } = req.params; const { userId } = req.params;
// Optional: Validate if userId is a MongoDB ObjectId
if (mongoose.Types.ObjectId.isValid(userId)) {
try { try {
const user = await UserModal.findById(userId);
const user = await UserModal.findById({id});
if (!user) { if (!user) {
return res.status(404).json({ message: "User not found" }); return res.status(404).json({ message: 'User not found' });
} }
return res.json(user);
res.status(200).json(user);
} catch (error) { } catch (error) {
console.error(error); return res.status(500).json({ message: 'Server Error' });
res.status(500).json({ message: "Internal servers error" }); }
} else {
// If the userId is not an ObjectId, search by other fields (e.g., custom userId)
try {
const user = await UserModal.findOne({ userId }); // Adjust based on how your schema stores userId
if (!user) {
return res.status(404).json({ message: 'User not found' });
}
return res.json(user);
} catch (error) {
return res.status(500).json({ message: 'Server Error' });
}
} }
}; };
//forgot password //forgot password
export const forgotPassword = async (req, res) => { export const forgotPassword = async (req, res) => {
@ -196,3 +210,27 @@ export const resetPassword = async (req, res) => {
res.status(500).json({ message: "Something went wrong" }); res.status(500).json({ message: "Something went wrong" });
} }
}; };
// Update user controller
export const updateUser = async (req, res) => {
try {
const { userId, title, firstName, middleName, lastName, email, aboutme, profileImage } = req.body;
// Use findOneAndUpdate instead, querying by userId (custom field)
const updatedUser = await UserModal.findOneAndUpdate(
{ userId }, // Query by custom userId, not ObjectId
{ title, firstName, middleName, lastName, email, aboutme, profileImage },
{ new: true } // Return the updated document
);
if (!updatedUser) {
return res.status(404).json({ message: "User not found" });
}
res.status(200).json(updatedUser);
} catch (error) {
console.error("Error updating user:", error);
res.status(500).json({ message: "Error updating user", error });
}
};

View File

@ -6,6 +6,9 @@ const userSchema = new mongoose.Schema({
middleName: { type: String, required: true }, middleName: { type: String, required: true },
lastName: { type: String, required: true }, lastName: { type: String, required: true },
email: { type: String, required: true, unique: true }, email: { type: String, required: true, unique: true },
profileImage:String,
// profileImage: { type: String, required: true, unique: true },
aboutme: { type: String, required: true, unique: true },
password: { type: String, required: true }, password: { type: String, required: true },
termsconditions:{type: String,}, termsconditions:{type: String,},
userType:{ type: String, required: true }, userType:{ type: String, required: true },

View File

@ -1,14 +1,15 @@
import express from "express"; import express from "express";
const router = express.Router(); const router = express.Router();
import { signup, signin, verifyUser, showUser, forgotPassword, resetPassword, } from "../controllers/user.js"; import { signup, signin, verifyUser, showUser, forgotPassword, resetPassword, updateUser } from "../controllers/user.js";
router.post("/signin", signin); router.post("/signin", signin);
router.post("/signup", signup); router.post("/signup", signup);
router.get('/:id/verify/:token/', verifyUser); router.get('/:id/verify/:token/', verifyUser);
router.get('/:id', showUser); router.get('/:userId', showUser);
router.post("/forgotpassword", forgotPassword); router.post("/forgotpassword", forgotPassword);
router.post("/resetpassword/:id/:token", resetPassword); router.post("/resetpassword/:id/:token", resetPassword);
router.put('/update', updateUser);

File diff suppressed because one or more lines are too long

85
ef-ui/dist/assets/index-DPPwfV95.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -45,8 +45,8 @@
<script type="module" crossorigin src="/assets/index-BsVOnNCb.js"></script> <script type="module" crossorigin src="/assets/index-DPPwfV95.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-DepkKhoc.css"> <link rel="stylesheet" crossorigin href="/assets/index-iEl-il0E.css">
</head> </head>

View File

@ -18,6 +18,7 @@ import Services from "./components/Services";
import PropertyMysqlView from "./components/PropertyMysqlView"; import PropertyMysqlView from "./components/PropertyMysqlView";
import EditProperty from "./components/EditProperty"; import EditProperty from "./components/EditProperty";
import SearchProperties from "./components/SearchProperties"; import SearchProperties from "./components/SearchProperties";
import ProfileView from "./components/ProfileView";
const App = () => { const App = () => {
return ( return (
@ -63,8 +64,10 @@ const App = () => {
<Route path="/properties/:house_id" element={<PropertyMysqlView />} /> <Route path="/properties/:house_id" element={<PropertyMysqlView />} />
<Route path="/searchmyproperties" element={<SearchMysqlProperties />} /> <Route path="/searchmyproperties" element={<SearchMysqlProperties />} />
<Route path="/searchproperties" element={<SearchProperties />} /> <Route path="/searchproperties" element={<SearchProperties />} />
<Route path="/editproperty/:id" element={<PrivateRoute><EditProperty /></PrivateRoute>} />
<Route path="/profile/:userId" element={<ProfileView />} />
<Route path="/editproperty/:id" element={<EditProperty />} />
</Routes> </Routes>
</BrowserRouter> </BrowserRouter>
); );

View File

@ -1,92 +1,37 @@
import { useState } from "react"; import { useState } from "react";
import Footer from "./Footer"; import Footer from "./Footer";
import Navbar from "./Navbar"; import Navbar from "./Navbar";
import { useSelector } from "react-redux";
import profilepic from "../img/samplepic.jpg"; import profilepic from "../img/samplepic.jpg";
import Addproperty from "./Addproperty"; import Addproperty from "./Addproperty";
import UserProperties from "./UserProperties"; import UserProperties from "./UserProperties";
// import { fetchUserProperties } from "../redux/features/propertySlice";
import "../dashboard.css"; import "../dashboard.css";
import { useSelector } from "react-redux";
import UserProfile from "./UserProfile";
import { NavLink } from "react-router-dom";
const Dashboard = () => { const Dashboard = () => {
// const dispatch = useDispatch();
const { user } = useSelector((state) => ({ ...state.auth }));
// const { userProperties} = useSelector((state) => state.property);
const [activeTab, setActiveTab] = useState("dashboard"); const [activeTab, setActiveTab] = useState("dashboard");
const { user } = useSelector((state) => state.auth);
// Fetch user properties when "Active Properties" tab is selected
// useEffect(() => {
// if (activeTab === "activeProperties") {
// dispatch(fetchUserProperties(user?.result?.userId));
// }
// }, [activeTab, dispatch, user?.result?.userId]);
const renderTabContent = () => { const renderTabContent = () => {
switch (activeTab) { switch (activeTab) {
case "Userdetails":
return <UserProfile />;
case "addProperty": case "addProperty":
return <Addproperty />; return <Addproperty />;
case "activeProperties":
return <div>
<h3>Active Properties</h3>
{/* {userProperties.length > 0 ? (
<ul>
{userProperties.map((property) => (
<li key={property._id}>{property.title}</li>
))}
</ul>
) : (
<p>No active properties found.</p>
)} */}
<UserProperties /> case "activeProperties":
</div>;
case "closedProperties":
return <p>These are your closed properties.</p>;
default:
return ( return (
<div className="d-flex justify-content-center mt-7 gap-2 p-3"> <div>
<div className="col-md-6"> <h3>Active Properties</h3>
<div className="card cardchildchild p-2"> <UserProperties />
<div className="profile1">
<img
src="https://i.imgur.com/NI5b1NX.jpg"
height={90}
width={90}
className="rounded-circle"
/>
</div>
<div className="d-flex flex-column justify-content-center align-items-center mt-5">
<span className="name">Bess Wills</span>
<span className="mt-1 braceletid">Bracelet ID: SFG 38393</span>
<span className="dummytext mt-3 p-3">
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Text elit more smtit. Kimto lee.
</span>
</div>
</div>
</div>
<div className="col-md-6">
<div className="card cardchildchild p-2">
<div className="profile1">
<img
src="https://i.imgur.com/YyoCGsa.jpg"
height={90}
width={90}
className="rounded-circle"
/>
</div>
<div className="d-flex flex-column justify-content-center align-items-center mt-5">
<span className="name">Bess Wills</span>
<span className="mt-1 braceletid">Bracelet ID: SFG 38393</span>
<span className="dummytext mt-3 p-3">
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Text elit more smtit. Kimto lee.
</span>
</div>
</div>
</div>
</div> </div>
); );
case "closedProperties":
return <p>These are your closed properties.</p>;
default:
return <></>;
} }
}; };
@ -105,7 +50,7 @@ const Dashboard = () => {
<div className="card card1 p-5"> <div className="card card1 p-5">
<img <img
className="img-fluid" className="img-fluid"
src={profilepic} src={user.result.profileImage || profilepic}
alt="ProfileImage" alt="ProfileImage"
style={{ style={{
marginTop: "0px", marginTop: "0px",
@ -125,21 +70,37 @@ const Dashboard = () => {
</button> </button>
<button <button
className={`btn mt-3 ${activeTab === "addProperty" ? "active" : ""}`} className={`btn mt-3 ${
activeTab === "Userdetails" ? "active" : ""
}`}
onClick={() => setActiveTab("Userdetails")}
>
<span className="fa fa-home" style={{ color: "#F74B02" }} />
<span>User Profile</span>
</button>
<button
className={`btn mt-3 ${
activeTab === "addProperty" ? "active" : ""
}`}
onClick={() => setActiveTab("addProperty")} onClick={() => setActiveTab("addProperty")}
> >
<span className="fa fa-home" style={{ color: "#F74B02" }} /> <span className="fa fa-home" style={{ color: "#F74B02" }} />
<span>Add Property</span> <span>Add Property</span>
</button> </button>
<button <button
className={`btn mt-3 ${activeTab === "activeProperties" ? "active" : ""}`} className={`btn mt-3 ${
activeTab === "activeProperties" ? "active" : ""
}`}
onClick={() => setActiveTab("activeProperties")} onClick={() => setActiveTab("activeProperties")}
> >
<span className="fa fa-home" style={{ color: "#F74B02" }} /> <span className="fa fa-home" style={{ color: "#F74B02" }} />
<span>Active Properties</span> <span>Active Properties</span>
</button> </button>
<button <button
className={`btn mt-3 ${activeTab === "closedProperties" ? "active" : ""}`} className={`btn mt-3 ${
activeTab === "closedProperties" ? "active" : ""
}`}
onClick={() => setActiveTab("closedProperties")} onClick={() => setActiveTab("closedProperties")}
> >
<span className="fa fa-home" style={{ color: "#F74B02" }} /> <span className="fa fa-home" style={{ color: "#F74B02" }} />
@ -162,19 +123,27 @@ const Dashboard = () => {
<span> <span>
Welcome to{" "} Welcome to{" "}
<span style={{ color: "#067ADC" }}> <span style={{ color: "#067ADC" }}>
{user.result.title}. {user.result.firstName} {user.result.middleName} {user.result.lastName}
<NavLink
to={`/profile/${user.result.userId}`}
className="link-primary text-decoration-none"
target="_blank"
>
{user.result.title}. {user.result.firstName}{" "}
{user.result.middleName} {user.result.lastName}
</NavLink>
</span> </span>
</span> </span>
<br /> <br />
{/* Dynamic content based on the selected tab */} {/* Dynamic content based on the selected tab */}
<div className="tab-content p-2">
{renderTabContent()} {renderTabContent()}
</div> </div>
</div> </div>
</div> </div>
</div>
<Footer /> <Footer />
</> </>
); );

View File

@ -3,6 +3,8 @@ import { useDispatch, useSelector } from "react-redux";
import { fetchPropertyById } from "../redux/features/propertySlice"; import { fetchPropertyById } from "../redux/features/propertySlice";
import { updateProperty } from "../redux/features/propertySlice"; import { updateProperty } from "../redux/features/propertySlice";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import Navbar from "./Navbar";
import Footer from "./Footer";
const EditProperty = () => { const EditProperty = () => {
const { id } = useParams(); const { id } = useParams();
@ -40,6 +42,11 @@ const EditProperty = () => {
return ( return (
<>
<Navbar />
<br /> <br /> <br /> <br /> <br /> <br />
<div className="edit-property-form"> <div className="edit-property-form">
<h2>Edit Property</h2> <h2>Edit Property</h2>
<form onSubmit={handleSubmit}> <form onSubmit={handleSubmit}>
@ -95,6 +102,8 @@ const EditProperty = () => {
<button type="submit">Update Property</button> <button type="submit">Update Property</button>
</form> </form>
</div> </div>
<Footer />
</>
); );
}; };

View File

@ -67,7 +67,10 @@ const Navbar = () => {
</NavLink> </NavLink>
</li> </li>
<li className="nav-item"> <li className="nav-item">
<NavLink to="/services" className="nav-link"> <NavLink to="/services" className="nav-link" style={{
fontSize: "20px",
fontWeight: "normal",
}}>
Services Services
</NavLink> </NavLink>
</li> </li>
@ -86,7 +89,10 @@ const Navbar = () => {
</NavLink> </NavLink>
</li> </li>
<li className="nav-item"> <li className="nav-item">
<NavLink to="/about" className="nav-link"> <NavLink to="/about" className="nav-link" style={{
fontSize: "20px",
fontWeight: "normal",
}}>
About About
</NavLink> </NavLink>
</li> </li>
@ -107,7 +113,10 @@ const Navbar = () => {
</li> </li>
<li className="nav-item"> <li className="nav-item">
<NavLink to="/contact" className="nav-link"> <NavLink to="/contact" className="nav-link" style={{
fontSize: "20px",
fontWeight: "normal",
}}>
Contact Contact
</NavLink> </NavLink>
</li> </li>

View File

@ -0,0 +1,250 @@
import { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { showUser } from "../redux/features/userSlice";
import { useParams } from "react-router-dom";
import "../profileview.css";
import Navbar from "./Navbar";
const ProfileView = () => {
const { userId } = useParams(); // Extract the userId from the route
const dispatch = useDispatch();
const { user, loading } = useSelector((state) => state.user); // Access the loading state as well
console.log("user", user);
useEffect(() => {
// Fetch the user by ID when the component loads
if (userId) {
dispatch(showUser(userId));
}
}, [userId, dispatch]);
if (loading) {
return <div>Loading...</div>; // Show a loading message while data is being fetched
}
return (
<>
<Navbar />
<br />
<br />
<br />
<br />
<br />
<div className="main-body">
{/* /Breadcrumb */}
<div className="row gutters-sm">
<div className="col-md-4 mb-3">
<div className="card">
<div className="card-body">
<div className="d-flex flex-column align-items-center text-center">
<img
src="https://bootdey.com/img/Content/avatar/avatar7.png"
// src={user.profileImage}
alt="Admin"
className="rounded-circle"
width={150}
/>
<div className="mt-3">
<h4>John Doe</h4>
<p className="text-secondary mb-1">Full Stack Developer</p>
<p className="text-muted font-size-sm">
Bay Area, San Francisco, CA
</p>
{/* <button className="btn btn-outline-primary">Message</button> */}
</div>
</div>
</div>
</div>
</div>
<div className="col-md-8">
<div className="card mb-3">
<div className="card-body">
<div className="row">
<div className="col-sm-3">
<h6 className="mb-0">Full Name</h6>
</div>
<div className="col-sm-9 text-secondary">Kenneth Valdez</div>
</div>
<hr />
<div className="row">
<div className="col-sm-3">
<h6 className="mb-0">Email</h6>
</div>
<div className="col-sm-9 text-secondary">fip@jukmuh.al</div>
</div>
<hr />
<div className="row">
<div className="col-sm-3">
<h6 className="mb-0">Phone</h6>
</div>
<div className="col-sm-9 text-secondary">(239) 816-9029</div>
</div>
<hr />
<div className="row">
<div className="col-sm-3">
<h6 className="mb-0">Mobile</h6>
</div>
<div className="col-sm-9 text-secondary">(320) 380-4539</div>
</div>
<hr />
<div className="row">
<div className="col-sm-3">
<h6 className="mb-0">Address</h6>
</div>
<div className="col-sm-9 text-secondary">
Bay Area, San Francisco, CA
</div>
</div>
<hr />
</div>
</div>
<div className="row gutters-sm">
<div className="col-sm-6 mb-3">
<div className="card h-100">
<div className="card-body">
<h6 className="d-flex align-items-center mb-3">
<i className="material-icons text-info mr-2">
assignment
</i>
Project Status
</h6>
<small>Web Design</small>
<div className="progress mb-3" style={{ height: "5px" }}>
<div
className="progress-bar bg-primary"
role="progressbar"
style={{ width: "80%" }}
aria-valuenow={80}
aria-valuemin={0}
aria-valuemax={100}
/>
</div>
<small>Website Markup</small>
<div className="progress mb-3" style={{ height: "5px" }}>
<div
className="progress-bar bg-primary"
role="progressbar"
style={{ width: "72%" }}
aria-valuenow={72}
aria-valuemin={0}
aria-valuemax={100}
/>
</div>
<small>One Page</small>
<div className="progress mb-3" style={{ height: "5px" }}>
<div
className="progress-bar bg-primary"
role="progressbar"
style={{ width: "89%" }}
aria-valuenow={89}
aria-valuemin={0}
aria-valuemax={100}
/>
</div>
<small>Mobile Template</small>
<div className="progress mb-3" style={{ height: "5px" }}>
<div
className="progress-bar bg-primary"
role="progressbar"
style={{ width: "55%" }}
aria-valuenow={55}
aria-valuemin={0}
aria-valuemax={100}
/>
</div>
<small>Backend API</small>
<div className="progress mb-3" style={{ height: "5px" }}>
<div
className="progress-bar bg-primary"
role="progressbar"
style={{ width: "66%" }}
aria-valuenow={66}
aria-valuemin={0}
aria-valuemax={100}
/>
</div>
</div>
</div>
</div>
<div className="col-sm-6 mb-3">
<div className="card h-100">
<div className="card-body">
<h6 className="d-flex align-items-center mb-3">
<i className="material-icons text-info mr-2">
assignment
</i>
Project Status
</h6>
<small>Web Design</small>
<div className="progress mb-3" style={{ height: "5px" }}>
<div
className="progress-bar bg-primary"
role="progressbar"
style={{ width: "80%" }}
aria-valuenow={80}
aria-valuemin={0}
aria-valuemax={100}
/>
</div>
<small>Website Markup</small>
<div className="progress mb-3" style={{ height: "5px" }}>
<div
className="progress-bar bg-primary"
role="progressbar"
style={{ width: "72%" }}
aria-valuenow={72}
aria-valuemin={0}
aria-valuemax={100}
/>
</div>
<small>One Page</small>
<div className="progress mb-3" style={{ height: "5px" }}>
<div
className="progress-bar bg-primary"
role="progressbar"
style={{ width: "89%" }}
aria-valuenow={89}
aria-valuemin={0}
aria-valuemax={100}
/>
</div>
<small>Mobile Template</small>
<div className="progress mb-3" style={{ height: "5px" }}>
<div
className="progress-bar bg-primary"
role="progressbar"
style={{ width: "55%" }}
aria-valuenow={55}
aria-valuemin={0}
aria-valuemax={100}
/>
</div>
<small>Backend API</small>
<div className="progress mb-3" style={{ height: "5px" }}>
<div
className="progress-bar bg-primary"
role="progressbar"
style={{ width: "66%" }}
aria-valuenow={66}
aria-valuemin={0}
aria-valuemax={100}
/>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</>
);
};
export default ProfileView;

View File

@ -0,0 +1,201 @@
import { useState, useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { updateUser } from "../redux/features/authSlice";
import { useNavigate } from "react-router-dom";
import FileBase from "react-file-base64";
const UserProfile = () => {
const { user, isLoading, error } = useSelector((state) => state.auth);
const dispatch = useDispatch();
const navigate = useNavigate();
const [formData, setFormData] = useState({
userId: user?.result?.userId || "",
title: user?.result?.title || "",
firstName: user?.result?.firstName || "",
middleName: user?.result?.middleName || "",
lastName: user?.result?.lastName || "",
email: user?.result?.email || "",
aboutme: user?.result?.aboutme || "",
profileImage: user?.result?.profileImage || "", // For storing the image
});
useEffect(() => {
if (user) {
setFormData({
userId: user.result.userId,
title: user.result.title,
firstName: user.result.firstName,
middleName: user.result.middleName,
lastName: user.result.lastName,
email: user.result.email,
aboutme: user.result.aboutme,
profileImage: user.result.profileImage,
});
}
}, [user]);
const handleChange = (e) => {
setFormData({ ...formData, [e.target.name]: e.target.value });
};
const handleImageDelete = () => {
setFormData({ ...formData, profileImage: "" }); // Reset the profileImage field
};
const handleSubmit = (e) => {
e.preventDefault();
dispatch(updateUser(formData)); // Dispatching updateUser with form data
navigate("/login");
};
return (
<>
<form onSubmit={handleSubmit}>
<div className="col-4">
Title
<select
className="form-floating mb-3 form-control"
aria-label="Default select example"
name="title"
value={formData.title}
onChange={handleChange}
>
<option value="None">Please Select Title</option>
<option value="Dr">Dr</option>
<option value="Prof">Prof</option>
<option value="Mr">Mr</option>
<option value="Miss">Miss</option>
</select>
</div>
<div className="col-4">
<div className="form-floating mb-3">
First Name
<input
type="text"
className="form-control"
placeholder="First Name"
required="required"
name="firstName"
value={formData.firstName}
onChange={handleChange}
/>
</div>
</div>
<div className="col-4">
<div className="form-floating mb-3">
Middle Name
<input
type="text"
className="form-control"
placeholder="Middle Name"
required="required"
name="middleName"
value={formData.middleName}
onChange={handleChange}
/>
</div>
</div>
<div className="col-4">
<div className="form-floating mb-3">
Last Name
<input
type="text"
className="form-control"
placeholder="Last Name"
required="required"
name="lastName"
value={formData.lastName}
onChange={handleChange}
/>
</div>
</div>
<div className="col-4">
<div className="form-floating mb-3">
Email
<input
type="text"
className="form-control"
placeholder="Email"
required="required"
name="email"
value={formData.email}
onChange={handleChange}
disabled
/>
</div>
</div>
<div className="col-4">
<div className="form-floating mb-3">
About me
<textarea
type="text"
id="aboutme"
name="aboutme"
className="form-control h-100"
value={formData.aboutme}
onChange={handleChange}
/>
</div>
</div>
{/* Profile Image Upload Section */}
<div className="col-4">
<label>Profile Image</label>
<div className="mb-3">
<FileBase
type="file"
multiple={false}
onDone={({ base64 }) =>
setFormData({ ...formData, profileImage: base64 })
}
/>
</div>
</div>
{/* Display Preview of Uploaded Image */}
{formData.profileImage && (
<div className="col-4 mb-3">
<img
src={formData.profileImage}
alt="Profile Preview"
style={{ width: "150px", height: "150px", borderRadius: "50%" }}
/>
{/* Delete Image Button */}
<button
type="button"
className="btn btn-danger mt-2"
onClick={handleImageDelete}
>
Delete Image
</button>
</div>
)}
<div className="col-12">
<div className="d-grid">
<button
className="btn btn-primary btn-lg"
type="submit"
style={{
backgroundColor: "#fda417",
border: "#fda417",
}}
disabled={isLoading}
>
{isLoading ? "Updating..." : "Update"}
</button>
</div>
</div>
{error && <p>{error}</p>}
</form>
</>
);
};
export default UserProfile;

View File

@ -112,7 +112,6 @@ const UserProperties = () => {
<NavLink <NavLink
to={`/editproperty/${property.propertyId}`} to={`/editproperty/${property.propertyId}`}
target="_blank"
> >
<button <button
className="btn btn-outline-primary btn-sm mt-2" className="btn btn-outline-primary btn-sm mt-2"

53
ef-ui/src/profileview.css Normal file
View File

@ -0,0 +1,53 @@
body{
margin-top:20px;
color: #1a202c;
text-align: left;
background-color: #e2e8f0;
}
.main-body {
padding: 15px;
}
.card {
box-shadow: 0 1px 3px 0 rgba(0,0,0,.1), 0 1px 2px 0 rgba(0,0,0,.06);
}
.card {
position: relative;
display: flex;
flex-direction: column;
min-width: 0;
word-wrap: break-word;
background-color: #fff;
background-clip: border-box;
border: 0 solid rgba(0,0,0,.125);
border-radius: .25rem;
}
.card-body {
flex: 1 1 auto;
min-height: 1px;
padding: 1rem;
}
.gutters-sm {
margin-right: -8px;
margin-left: -8px;
}
.gutters-sm>.col, .gutters-sm>[class*=col-] {
padding-right: 8px;
padding-left: 8px;
}
.mb-3, .my-3 {
margin-bottom: 1rem!important;
}
.bg-gray-300 {
background-color: #e2e8f0;
}
.h-100 {
height: 100%!important;
}
.shadow-none {
box-shadow: none!important;
}

View File

@ -25,6 +25,7 @@ export const submitProperty = (propertyData) => API.post("/properties", property
export const fetchUserProperties = (userId, page, limit) => API.get( `/properties/user/${userId}?page=${page}&limit=${limit}`, userId); export const fetchUserProperties = (userId, page, limit) => API.get( `/properties/user/${userId}?page=${page}&limit=${limit}`, userId);
export const fetchPropertyById = (id) => API.get(`/properties/${id}`, id); export const fetchPropertyById = (id) => API.get(`/properties/${id}`, id);
export const updateProperty = (id, propertyData) => API.put(`/properties/${id}`, propertyData); export const updateProperty = (id, propertyData) => API.put(`/properties/${id}`, propertyData);
export const showUser = (userId) => API.get(`/users/${userId}`);

View File

@ -1,5 +1,7 @@
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit"; import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import * as api from "../api"; import * as api from "../api";
import axios from "axios";
export const login = createAsyncThunk( export const login = createAsyncThunk(
@ -29,24 +31,30 @@ export const register = createAsyncThunk(
} }
); );
// Thunk to update user details
export const updateUser = createAsyncThunk( export const updateUser = createAsyncThunk(
"auth/updateUser", 'auth/updateUser',
async ({ id, data }, { rejectWithValue }) => { async (updatedUserData, { rejectWithValue }) => {
try { try {
const response = await api.updateuser(data, id); const response = await axios.put(`http://localhost:3002/users/update`, updatedUserData);
// console.log('Update user response:', response.data);
return response.data; return response.data;
} catch (err) { } catch (error) {
return rejectWithValue(err.response.data); return rejectWithValue(error.response.data);
} }
} }
); );
const authSlice = createSlice({ const authSlice = createSlice({
name: "auth", name: "auth",
initialState: { initialState: {
user: null, user: null,
error: "", error: "",
loading: false, loading: false,
isLoading: false,
}, },
reducers: { reducers: {
setUser: (state, action) => { setUser: (state, action) => {
@ -59,6 +67,10 @@ const authSlice = createSlice({
setUserDetails: (state, action) => { setUserDetails: (state, action) => {
state.user = action.payload; state.user = action.payload;
}, },
updateUser: (state, action) => {
const updatedUser = action.payload;
state.user = { ...state.user, ...updatedUser }; // Update user state without removing it
},
}, },
extraReducers: (builder) => { extraReducers: (builder) => {
builder builder
@ -87,15 +99,15 @@ const authSlice = createSlice({
state.error = action.payload.message; state.error = action.payload.message;
}) })
.addCase(updateUser.pending, (state) => { .addCase(updateUser.pending, (state) => {
state.loading = true; state.isLoading = true;
}) })
.addCase(updateUser.fulfilled, (state, action) => { .addCase(updateUser.fulfilled, (state, action) => {
state.loading = false; state.isLoading = false;
state.user = action.payload; state.user = action.payload; // Update the user state with the new data
}) })
.addCase(updateUser.rejected, (state, action) => { .addCase(updateUser.rejected, (state, action) => {
state.loading = false; state.isLoading = false;
state.error = action.payload.message; state.error = action.payload;
}); });
}, },
}); });

View File

@ -1,18 +1,16 @@
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit"; import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import * as api from "../api"; import * as api from "../api";
export const showUser = createAsyncThunk(
"user/showUser", export const showUser = createAsyncThunk('user/showUser', async (userId, { rejectWithValue }) => {
async ({ id, data }, { rejectWithValue }) => {
try { try {
const response = await api.showUser(data, id); const response = await api.showUser(userId);
console.log("dsdsdsds22", response); // console.log("response", response);
return response.data; return response.data;
} catch (err) { } catch (error) {
return rejectWithValue(err.response.data); return rejectWithValue(error.response.data);
} }
} });
);
export const verifyEmail = createAsyncThunk( export const verifyEmail = createAsyncThunk(
"user/verifyEmail", "user/verifyEmail",
@ -33,23 +31,23 @@ const userSlice = createSlice({
error: "", error: "",
loading: false, loading: false,
verified: false, verified: false,
user: null,
}, },
reducers: {}, reducers: {},
extraReducers: (builder) => { extraReducers: (builder) => {
builder builder
.addCase(showUser.pending, (state) => { .addCase(showUser.pending, (state) => {
state.loading = true; state.loading = true;
state.error = null;
}) })
.addCase(showUser.fulfilled, (state, action) => { .addCase(showUser.fulfilled, (state, action) => {
state.loading = false; state.loading = false;
localStorage.setItem("profile", JSON.stringify({ ...action.payload })); state.user = action.payload;
state.users = Array.isArray(action.payload) ? action.payload : [];
}) })
.addCase(showUser.rejected, (state, action) => { .addCase(showUser.rejected, (state, action) => {
state.loading = false; state.loading = false;
state.error = action.payload; state.error = action.payload;
}) })
.addCase(verifyEmail.pending, (state) => { .addCase(verifyEmail.pending, (state) => {
state.loading = true; state.loading = true;
state.error = null; state.error = null;