updated delete & logout functionality && added reate listing property
This commit is contained in:
parent
0fa054e096
commit
de4bfefb41
11 changed files with 179 additions and 10 deletions
|
@ -19,7 +19,7 @@ const Navbar = () => {
|
||||||
<input type="text" placeholder="Search your dream property" className="bg-transparent px-4 py-2 focus:outline-none text-sm w-60 sm:w-64"/>
|
<input type="text" placeholder="Search your dream property" className="bg-transparent px-4 py-2 focus:outline-none text-sm w-60 sm:w-64"/>
|
||||||
<IoIosSearch className="text-slate-600 text-lg"/>
|
<IoIosSearch className="text-slate-600 text-lg"/>
|
||||||
</form>*/}
|
</form>*/}
|
||||||
<ul className="flex gap-4 sm:px-10">
|
<ul className="flex gap-4 sm:px-10 px-5">
|
||||||
<Link to="/"><li className="text-white tracking-wide text-center uppercase text-sm hidden md:inline">Home</li></Link>
|
<Link to="/"><li className="text-white tracking-wide text-center uppercase text-sm hidden md:inline">Home</li></Link>
|
||||||
<Link to="/"><li className="text-white tracking-wide text-center uppercase text-sm hidden md:inline">Buying</li></Link>
|
<Link to="/"><li className="text-white tracking-wide text-center uppercase text-sm hidden md:inline">Buying</li></Link>
|
||||||
<Link to="/"><li className="text-white tracking-wide text-center uppercase text-sm hidden md:inline">Selling</li></Link>
|
<Link to="/"><li className="text-white tracking-wide text-center uppercase text-sm hidden md:inline">Selling</li></Link>
|
||||||
|
|
|
@ -2,7 +2,7 @@ import {useSelector} from'react-redux'
|
||||||
import { useEffect, useRef, useState } from 'react'
|
import { useEffect, useRef, useState } from 'react'
|
||||||
import {getDownloadURL, getStorage, ref, uploadBytesResumable} from 'firebase/storage'
|
import {getDownloadURL, getStorage, ref, uploadBytesResumable} from 'firebase/storage'
|
||||||
import { app } from '../firebase';
|
import { app } from '../firebase';
|
||||||
import {updateUserStart, updateUserSuccess, updateUserFailure} from '../redux/user/userSlice.js'
|
import {updateUserStart, updateUserSuccess, updateUserFailure, deleteUserFailure, deleteUserStart, deleteUserSuccess, logoutUserStart} from '../redux/user/userSlice.js'
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
|
|
||||||
export const Profile = () => {
|
export const Profile = () => {
|
||||||
|
@ -33,7 +33,6 @@ export const Profile = () => {
|
||||||
const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
|
const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
|
||||||
setFilePercentage(Math.round(progress));
|
setFilePercentage(Math.round(progress));
|
||||||
},
|
},
|
||||||
|
|
||||||
(error) => {
|
(error) => {
|
||||||
setFileUploadError(true);
|
setFileUploadError(true);
|
||||||
},
|
},
|
||||||
|
@ -68,10 +67,44 @@ export const Profile = () => {
|
||||||
dispatch(updateUserFailure(error.message));
|
dispatch(updateUserFailure(error.message));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
//delete user functionality
|
||||||
|
const handleDeleteUser = async () => {
|
||||||
|
try {
|
||||||
|
dispatch(deleteUserStart());
|
||||||
|
const res = await fetch(`/server/user/delete/${currentUser._id}`, {
|
||||||
|
method: 'DELETE',
|
||||||
|
});
|
||||||
|
const data = await res.json();
|
||||||
|
if(data.success === false){
|
||||||
|
dispatch(deleteUserFailure(data.message));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dispatch(deleteUserSuccess(data));
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
dispatch(deleteUserFailure(error.message))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//logout functionality
|
||||||
|
const handleLogout = async () => {
|
||||||
|
try {
|
||||||
|
dispatch(logoutUserStart());
|
||||||
|
const res = await fetch('/server/auth/logout');
|
||||||
|
const data = await res.json();
|
||||||
|
if(data.success === false){
|
||||||
|
dispatch(deleteUserFailure(data.message))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dispatch(deleteUserSuccess(data))
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
dispatch(deleteUserFailure(error.message))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='max-w-lg p-3 mx-auto'>
|
<div className='max-w-sm p-3 mx-auto'>
|
||||||
<h1 className="text-2xl uppercase text-center text-blue-900 font-serif my-10 tracking-wide">Profile</h1>
|
<h1 className="text-2xl uppercase text-center text-blue-900 font-serif my-10 tracking-wide">Profile</h1>
|
||||||
<form onSubmit={handleSubmit} className='flex flex-col gap-4'>
|
<form onSubmit={handleSubmit} className='flex flex-col gap-4'>
|
||||||
<input onChange={(e) => setFile(e.target.files[0])} type="file" ref={fileRef} hidden accept='image/*'/>
|
<input onChange={(e) => setFile(e.target.files[0])} type="file" ref={fileRef} hidden accept='image/*'/>
|
||||||
|
@ -89,8 +122,8 @@ export const Profile = () => {
|
||||||
<button disabled={loading} className='bg-blue-950 text-white text-sm p-2 rounded-md uppercase hover:opacity-90 disabled:opacity-80'>{loading ? 'Loading...' : 'Update'}</button>
|
<button disabled={loading} className='bg-blue-950 text-white text-sm p-2 rounded-md uppercase hover:opacity-90 disabled:opacity-80'>{loading ? 'Loading...' : 'Update'}</button>
|
||||||
</form>
|
</form>
|
||||||
<div className='flex justify-between mt-4'>
|
<div className='flex justify-between mt-4'>
|
||||||
<span className='text-red-700 cursor-pointer'>Delete Account</span>
|
<span onClick={handleDeleteUser} className='text-red-700 cursor-pointer'>Delete Account</span>
|
||||||
<span className='text-red-700 cursor-pointer'>Log Out</span>
|
<span onClick={handleLogout} className='text-red-700 cursor-pointer'>Log Out</span>
|
||||||
</div>
|
</div>
|
||||||
<p className='text-red-700 mt-4'>{error ? error : ''}</p>
|
<p className='text-red-700 mt-4'>{error ? error : ''}</p>
|
||||||
<p className='text-green-900 mt-4'>{updateSuccess ? 'User profile is updated successfully' : ''}</p>
|
<p className='text-green-900 mt-4'>{updateSuccess ? 'User profile is updated successfully' : ''}</p>
|
||||||
|
|
|
@ -34,8 +34,37 @@ const userSlice = createSlice({
|
||||||
state.error = action.payload;
|
state.error = action.payload;
|
||||||
state.loading = false;
|
state.loading = false;
|
||||||
},
|
},
|
||||||
|
deleteUserStart: (state) => {
|
||||||
|
state.loading = true;
|
||||||
|
},
|
||||||
|
deleteUserSuccess: (state) => {
|
||||||
|
state.currentUser = null;
|
||||||
|
state.loading = false;
|
||||||
|
state.error = null;
|
||||||
|
},
|
||||||
|
deleteUserFailure: (state, action) => {
|
||||||
|
state.error = action.payload;
|
||||||
|
state.loading = false;
|
||||||
|
},
|
||||||
|
logoutUserStart: (state) => {
|
||||||
|
state.loading = true;
|
||||||
|
},
|
||||||
|
logoutUserSuccess: (state) => {
|
||||||
|
state.currentUser = null;
|
||||||
|
state.loading = false;
|
||||||
|
state.error = null;
|
||||||
|
},
|
||||||
|
logoutUserFailure: (state, action) => {
|
||||||
|
state.error = action.payload;
|
||||||
|
state.loading = false;
|
||||||
|
},
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export const {loginStart, loginSuccess, loginFailure, updateUserStart, updateUserSuccess, updateUserFailure} = userSlice.actions;
|
export const {
|
||||||
|
loginStart, loginSuccess, loginFailure,
|
||||||
|
updateUserStart, updateUserSuccess, updateUserFailure,
|
||||||
|
deleteUserStart, deleteUserSuccess, deleteUserFailure,
|
||||||
|
logoutUserStart, logoutUserSuccess, logoutUserFailure} = userSlice.actions;
|
||||||
export default userSlice.reducer;
|
export default userSlice.reducer;
|
|
@ -58,4 +58,13 @@ export const google = async(req, res, next) => {
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
next(error)
|
next(error)
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const logout = async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
res.clearCookie('access_token');
|
||||||
|
res.status(200).json('User has been logged out');
|
||||||
|
} catch (error) {
|
||||||
|
next(error)
|
||||||
|
}
|
||||||
}
|
}
|
10
real_estate/server/controllers/listing.controller.js
Normal file
10
real_estate/server/controllers/listing.controller.js
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import Listing from "../models/listing.model.js";
|
||||||
|
|
||||||
|
export const createListing = async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
const listing = await Listing.create(req.body);
|
||||||
|
return res.status(201).json(listing)
|
||||||
|
} catch (error) {
|
||||||
|
next(error)
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,4 +28,15 @@ export const updateUser = async (req, res, next) =>{
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
next(error)
|
next(error)
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const deleteUser = async (req, res, next) => {
|
||||||
|
if(req.user.id !== req.params.id) return next(errorHandler(401, 'You can only delete your account'))
|
||||||
|
try {
|
||||||
|
await User.findByIdAndDelete(req.params.id)
|
||||||
|
res.clearCookie('access_token');
|
||||||
|
res.status(200).json('User has been deleted')
|
||||||
|
} catch (error) {
|
||||||
|
next(error)
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -3,6 +3,7 @@ import mongoose from 'mongoose';
|
||||||
import dotenv from 'dotenv';
|
import dotenv from 'dotenv';
|
||||||
import userRouter from './routes/user.route.js';
|
import userRouter from './routes/user.route.js';
|
||||||
import authRouter from './routes/auth.route.js';
|
import authRouter from './routes/auth.route.js';
|
||||||
|
import listingRouter from './routes/listing.route.js'
|
||||||
import cookieParser from 'cookie-parser';
|
import cookieParser from 'cookie-parser';
|
||||||
|
|
||||||
|
|
||||||
|
@ -28,6 +29,7 @@ app.listen(3000, () =>{
|
||||||
//create api route
|
//create api route
|
||||||
app.use('/server/user', userRouter)
|
app.use('/server/user', userRouter)
|
||||||
app.use('/server/auth', authRouter)
|
app.use('/server/auth', authRouter)
|
||||||
|
app.use('/server/listing', listingRouter)
|
||||||
|
|
||||||
//middleware to catch an error
|
//middleware to catch an error
|
||||||
app.use((err, req, res, next) => {
|
app.use((err, req, res, next) => {
|
||||||
|
|
63
real_estate/server/models/listing.model.js
Normal file
63
real_estate/server/models/listing.model.js
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
import mongoose from "mongoose";
|
||||||
|
|
||||||
|
const listingSchema = new mongoose.Schema(
|
||||||
|
{
|
||||||
|
name:{
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
description:{
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
address:{
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
currentPrice:{
|
||||||
|
type: Number,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
discountPrice:{
|
||||||
|
type: Number,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
bath:{
|
||||||
|
type: Number,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
bed:{
|
||||||
|
type: Number,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
furnished:{
|
||||||
|
type: Boolean,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
parking:{
|
||||||
|
type: Boolean,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
type:{
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
offer:{
|
||||||
|
type: Boolean,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
imageUrls:{
|
||||||
|
type: Array,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
userRef:{
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ timestamps: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
const Listing = mongoose.model('Listing', listingSchema);
|
||||||
|
|
||||||
|
export default Listing;
|
|
@ -1,10 +1,11 @@
|
||||||
import express from 'express'
|
import express from 'express'
|
||||||
import { google, login, signup } from '../controllers/auth.controller.js';
|
import { google, login, logout, signup } from '../controllers/auth.controller.js';
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
router.post('/signup', signup);
|
router.post('/signup', signup);
|
||||||
router.post('/login', login);
|
router.post('/login', login);
|
||||||
router.post('/google', google)
|
router.post('/google', google);
|
||||||
|
router.get('/logout', logout);
|
||||||
|
|
||||||
export default router
|
export default router
|
10
real_estate/server/routes/listing.route.js
Normal file
10
real_estate/server/routes/listing.route.js
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import express from 'express';
|
||||||
|
import { createListing } from '../controllers/listing.controller.js';
|
||||||
|
import { verifyToken } from '../utils/verifyUser.js';
|
||||||
|
|
||||||
|
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
router.post('/create', verifyToken,createListing)
|
||||||
|
|
||||||
|
export default router;
|
|
@ -1,10 +1,11 @@
|
||||||
import express from 'express'
|
import express from 'express'
|
||||||
import { test, updateUser } from '../controllers/user.controller.js';
|
import { deleteUser, test, updateUser } from '../controllers/user.controller.js';
|
||||||
import { verifyToken } from '../utils/verifyUser.js';
|
import { verifyToken } from '../utils/verifyUser.js';
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
router.get('/test', test)
|
router.get('/test', test)
|
||||||
router.post('/update/:id', verifyToken, updateUser)
|
router.post('/update/:id', verifyToken, updateUser)
|
||||||
|
router.delete('/delete/:id', verifyToken, deleteUser)
|
||||||
|
|
||||||
export default router
|
export default router
|
Loading…
Add table
Reference in a new issue