Render different component for different users? - node.js

I have set a 3 login for admin doctor and user and need to render different dashboard for each of the user.
I have set a table user in MongoDB. In that, there is IsAdmin & IsDoctor field.
How do I do this?
function Home() {
const [doctors, setDoctors] = useState([]);
const dispatch = useDispatch();
const { user } = useSelector((state) => state.user);
const getData = async () => {
try {
dispatch(showLoading());
const response = await axios.get(
"http://localhost:5000/api/user/get-all-approved-doctors",
{
headers: {
Authorization: "Bearer " + localStorage.getItem("token"),
},
}
);
dispatch(hideLoading());
if (response.data.success) {
setDoctors(response.data.data);
}
} catch (error) {
dispatch(hideLoading());
}
};
useEffect(() => {
getData();
}, []);
return (
<div id="page-top">
<div id="wrapper">
<Sidebar />
<div id="content-wrapper" class="d-flex flex-column">
<div id="content">
<Navbar />
<div class="container-fluid">
<Breadcrumb />
// here i want to render diffrent dashboard page content
</div>
</div>
</div>
</div>
</div>
);
}
export default Home;
I am expecting to render different content for different users. The user has the properties isAdmin: false and isDoctor: true.

Related

How to get the object id after the button click in Reactjs

I am working in MERN project.
what I want
I am fetching the project list from the backend If i click on any project it should give the members list that is working on that project so i want to get the objectid of that clicked project
what i tried
import React, { useState, useEffect } from 'react'
import { NavLink } from 'react-router-dom'
import { useNavigate } from 'react-router-dom';
const AdminDash = () => {
const navigate = useNavigate()
const [userData, setuserData] = useState([])
const [data, setData] = useState({});
const callAboutPage = async () => {
try {
const res = await fetch("/alldata", {
method: "GET",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
credentials: "include"
})
const data = await res.json()
setuserData(data)
console.log(setuserData);
if (!res.status === 200) {
const error = new Error(res.error)
throw error
}
} catch (error) {
console.log(error);
navigate("/")
}
}
function handleButtonClick(id) {
fetch(`/api/get-data/${id}`)
.then(response => response.json())
.then(data => {
setData(data);
console.log(data);
});
}
useEffect(() => {
callAboutPage()
}, [])
return (
<>
<div className='container mt-5'>
<div className='row'>
<div className='col-sm-10 col-md-10 col-lg-10'>
<div class="row align-items-md-stretch">
<div class="col-md-6">
<div class="h-100 p-5 text-bg-light rounded-3">
<h2>Current Ongoing Projects</h2>
<ol class="list-group list-group-numbered mt-5">
{
userData.map((item, i) => (
<li class="list-group-item d-flex justify-content-between align-items-start">
<div class="ms-2 me-auto">
<NavLink onClick={() => handleButtonClick()} to="/admindash" className="text-decoration-none"><div class="fw-bold">{item.name}</div></NavLink>
Content for list item
</div>
<i class="bi bi-at"></i>
</li>
))}
</ol>
<label>{data.name}</label>
</div>
</div>
</div>
</div>
</div>
</div>
</>
)
}
export default AdminDash
backend
app.get('/api/get-data/:id', (req, res) => {
ProjectSchema.findById(req.params.id, (err, doc) => {
if (err) {
res.send(err);
} else {
res.json(doc);
}
});
});
the output i get in my console
{stringValue: '"undefined"', valueType: 'string', kind: 'ObjectId', value: 'undefined', path: '_id', …}
How to achieve this ..any suggestions?
In the mapping onClick pass item.id.
First make sure you getting it in your data while Fetching.
<NavLink onClick={() => handleButtonClick(item.id)} to="/admindash" className="text-decoration-none">{item.name}

Stripe js: uncompleted payment, payment is not defined

So I am working on payment processing with stripe. When I go to the payments on stripe it says they are uncompleted, the customer did not define the payment method...
React component
useEffect(() => {
const getClientSecret = async () => {
const responce = await axios({
method: "post",
url: `/payments/create?total=${getBasketTotal(basket) * 100}`,
});
setClientSecret(responce.data.clientSecret);
};
getClientSecret();
}, [basket]);
console.log("THE SECRET IS >>> ", clientSecret);
const submitHandler = async (e) => {
//stripe magic
e.preventDefault();
setProcessing(true);
const payload = await stripe
.confirmCardPayment(clientSecret, {
payment_method: {
card: elements?.getElement(CardElement),
},
})
.then(({ paymentIntent }) => {
//paymentIntent = payment confirmation
console.log(paymentIntent);
setSucceeded(true);
setError(null);
setProcessing(false);
dispatch({
type: "EMPTY_BASKET",
});
history.replace("/orders");
});
};
const changeHandler = (e) => {
//stripe magic
setDisabled(e.empty);
setError(e.error ? e.error.message : "");
};
return (
<div className="payment">
<div className="payment__container">
<h1>
Checkout(<Link to="/checkout">{basket?.length} items</Link>)
</h1>
<div className="payment__section">
<div className="payment__title">
<h3>Delivery Address</h3>
</div>
<div className="payment__address">
<p>{user?.email}</p>
<p>123 React Lane</p>
<p>Los Angeles, CA</p>
</div>
</div>
<div className="payment__section">
<div className="payment__title">
<h3>Review items and delivery</h3>
</div>
<div className="payment__items">
<FlipMove>
{basket.map((item) => (
<div>
<CheckoutProduct
id={item.id}
title={item.title}
image={item.image}
price={item.price}
rating={item.rating}
/>
</div>
))}
</FlipMove>
</div>
</div>
<div className="payment__section">
<div className="payment__title">
<h3>Payment Method</h3>
</div>
<div className="payment__details">
<form onSubmit={submitHandler}>
<CardElement onChange={changeHandler} />
<div className="payment__priceContainer">
<CurrencyFormat
renderText={(value) => (
<>
<h3>Order Total: {value}</h3>
</>
)}
decimalScale={2}
value={getBasketTotal(basket)}
displayType={"text"}
thousandSeperator={true}
prefix={"$"}
/>
<button
disabled={
processing || disabled || succeeded || clientSecret === null
}
>
<span>{processing ? <p>Processing</p> : "Buy Now"}</span>
</button>
</div>
{error && <div>{error}</div>}
</form>
</div>
</div>
</div>
</div>
);
}
export default Payment;
Node JS
const app = express();
// - Middlewares
app.use(cors({ origin: true }));
app.use(express.json());
// - API routes
app.get("/", (request, responce) => responce.status(200).send("hello world"));
app.post("/payments/create", async (request, responce) => {
const total = request.query.total;
console.log("Payment Request Received >>> ", total);
const paymentIntent = await stripe.paymentIntents.create({
amount: total,
currency: "usd",
});
// OK - Created
responce.status(201).send({
clientSecret: paymentIntent.client_secret,
});
});
// - Listen command
exports.api = functions.https.onRequest(app);
I have two questions: 1st, is this going to b a problem when working on order history? an 2nd, how do I fix this?
Thank you in advance

Unable to fetch data from Form using FormData

I am creating an 'edit profile' page for a dashboard the technologies that I use for the same are Next.js, Node.js & MongoDB.
Note: skip to the backend part if you just wanted to know the issue.
Frontend
Firstly,let me explain the Frontend part.
I am using useRef() inorder to reference data(name,bio) in the inputfields. which are working nicely.
Everything is fine the issue is in the handlesbumit() event_handler.
I am using FormData to send my form data to the backend API
If you're thinking why I'm not using a usual body object to send data the reason is that I have to add the profile picture updation later for which I have to send files , which as far I know we can't do that with an Object and yeah just to inform you it works fine if I would have used that Object part but can't use it with profilepicture updation.
The value that I have consoled out for the references are all good, and the rest of the handler is just as it is written can't find anything odd in that.
import { useUser } from '../../../lib/hooks';
import React, { useState, useEffect, useRef } from 'react';
import Head from 'next/head';
import { ImBook, ImListNumbered } from 'react-icons/im';
import { AiFillGithub, AiOutlineTwitter, AiFillFacebook, AiFillInstagram, AiFillLinkedin } from 'react-icons/ai'
import { FaFacebook, FaStackOverflow } from 'react-icons/fa';
const ProfileSection = () => {
const [user, { mutate }] = useUser();
const [isUpdating, setIsUpdating] = useState(false);
const nameRef = useRef();
const profilePictureRef = useRef();
const bioRef = useRef();
const [msg, setMsg] = useState({ message: '', isError: false });
useEffect(() => {
nameRef.current.value = user.name;
bioRef.current.value = user.Bio;
}, [user]);
const handleSubmit = async (event) => {
event.preventDefault();
if (isUpdating) return;
setIsUpdating(true);
console.log(nameRef.current.value); //Testing
console.log(bioRef.current.value); //Testing
const formData = new FormData();
formData.append('name', nameRef.current.value);
formData.append('Bio', bioRef.current.value);
console.log(formData.get('name'));
const res = await fetch('/api/user', {
method: 'PATCH',
body: formData,
});
if (res.status === 200) {
const userData = await res.json();
mutate({
user: {
...user,
...userData.user,
},
});
setMsg({ message: 'Profile updated' });
} else {
setMsg({ message: await res.text(), isError: true });
}
};
return (
<>
<Head>
<title>Settings</title>
</Head>
<main>
<div class="row">
<div class="col s12 m12">
<div className="card-panel br-10">
{msg.message ? <p style={{ color: msg.isError ? 'red' : '#0070f3', textAlign: 'center' }}>{msg.message}</p> : null}
<form onSubmit={handleSubmit}>
<div className="row">
<div className="col s12 m6 l6">
<label htmlFor="name">
Name
<input
required
id="name"
name="name"
type="text"
ref={nameRef}
/>
</label>
</div>
<div className="col s12 m6 l6">
<label htmlFor="bio">
Bio
<textarea
id="bio"
name="bio"
type="text"
ref={bioRef}
/>
</label>
</div>
</div>
<div className="center-align">
<button disabled={isUpdating} className="btn" type="submit" >Save</button>
</div>
</form>
</div>
</div>
</div>
</main>
</>
);
};
const SettingPage = () => {
const [user] = useUser();
if (!user) {
return (
<>
<p>Please sign in</p>
</>
);
}
return (
<>
<ProfileSection />
</>
);
};
export default SettingPage;
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
import { useUser } from '../../../lib/hooks';
import React, { useState, useEffect, useRef } from 'react';
import Head from 'next/head';
import { ImBook, ImListNumbered } from 'react-icons/im';
import { AiFillGithub, AiOutlineTwitter, AiFillFacebook, AiFillInstagram, AiFillLinkedin } from 'react-icons/ai'
import { FaFacebook, FaStackOverflow } from 'react-icons/fa';
const ProfileSection = () => {
const [user, { mutate }] = useUser();
const [isUpdating, setIsUpdating] = useState(false);
const nameRef = useRef();
const profilePictureRef = useRef();
const bioRef = useRef();
const [msg, setMsg] = useState({ message: '', isError: false });
useEffect(() => {
nameRef.current.value = user.name;
bioRef.current.value = user.Bio;
}, [user]);
const handleSubmit = async (event) => {
event.preventDefault();
if (isUpdating) return;
setIsUpdating(true);
console.log(nameRef.current.value);
console.log(bioRef.current.value);
const formData = new FormData();
formData.append('name', nameRef.current.value);
formData.append('Bio', bioRef.current.value);
console.log(formData.get('name'));
const res = await fetch('/api/user', {
method: 'PATCH',
body: formData,
});
if (res.status === 200) {
const userData = await res.json();
mutate({
user: {
...user,
...userData.user,
},
});
setMsg({ message: 'Profile updated' });
} else {
setMsg({ message: await res.text(), isError: true });
}
};
return (
<>
<Head>
<title>Settings</title>
</Head>
<main>
<div class="row">
<div class="col s12 m12">
<div className="card-panel br-10">
{msg.message ? <p style={{ color: msg.isError ? 'red' : '#0070f3', textAlign: 'center' }}>{msg.message}</p> : null}
<form onSubmit={handleSubmit}>
<div className="row">
<div className="col s12 m6 l6">
<label htmlFor="name">
Name
<input
required
id="name"
name="name"
type="text"
ref={nameRef}
/>
</label>
</div>
<div className="col s12 m6 l6">
<label htmlFor="bio">
Bio
<textarea
id="bio"
name="bio"
type="text"
ref={bioRef}
/>
</label>
</div>
</div>
<div className="center-align">
<button disabled={isUpdating} className="btn" type="submit" >Save</button>
</div>
</form>
</div>
</div>
</div>
</main>
</>
);
};
const SettingPage = () => {
const [user] = useUser();
if (!user) {
return (
<>
<p>Please sign in</p>
</>
);
}
return (
<>
<ProfileSection />
</>
);
};
export default SettingPage;
Backend
Now, the backend API for the same handlesubmit() event_handler i.e. 'api/user'
Please ignore the handler, it's just a predefined middleware npm next-connect which itself checks what type of request is coming if its 'PATCH' it will run handler.patch.
The Issue is the value of name & Bio is undefined,which means its not getting values from req.body;
And to check I also consoled out req.body which give out this
The data is correct but req.body is not a Object its a String now and I get it, its because I'm using formdata so how to get the values of name & Bio from this req.body ?
import nextConnect from 'next-connect';
import middleware from '../../../middlewares/middleware';
import { extractUser } from '../../../lib/api-helpers';
const handler = nextConnect();
handler.use(middleware);
handler.get(async (req, res) => res.json({ user: extractUser(req) }));
handler.patch(async (req, res) => {
if (!req.user) {
req.status(401).end();
return;
}
const { name, Bio } = req.body;
await req.db.collection('users').updateOne(
{ _id: req.user._id },
{
$set: {
name:name,
Bio: Bio,
},
},
);
res.json({ user: { name, Bio } });
});
export default handler;
I have encountered a this issue.
I was resolve it by use 2 form, a form use to get user's info as email, password and the other for send user's picture.
Maybe has best practice for this case.

Delete an item with ReactJS

I'm trying to delete an item after the user clicks on the Delete button. Through the handleDelete function, I am passing an id (idBooks) via axios when the user clicks a book. How do I withdraw it from the click?
Below you will find the React code and then the backend side code in node js.
Frontend
(class extends React.Component {
handleDelete = (e) => {
e.preventDefault();
const { book } = this.props;
axios.delete("http://localhost:8081/delete", book.idBooks )
.then(res => {
console.log(res.data);
}).catch(err => {
console.warn(err.warn);
});
};
render() {
const { book, classes } = this.props;
const token = localStorage.getItem('token');
return(
<Paper className= { classes.marginTopBottom }>
<h2 className={ classes.title }>
{ book.title }
</h2><hr />
<div className= { classes.scrollingDiv }>
<p>
{ book.plot }
</p>
</div>
<hr/>
<div className={ classes.pStyle }>
<p>Publish date:<br /> { new Date(book.publish_date).toLocaleDateString() }</p>
<p>Author:<br /> { book.author }
</p>
<p>Genre:<br /> { book.genre }</p>
</div>
<div>
{ token && (
<Button className={ classes.delete } size="small" onClick={this.handleDelete} type="button" variant="contained" color="primary"
component= {Link} to="delete">
Delete
<DeleteIcon className={ classes.rightIcon } />
</Button>
)}
</div>
</Paper>
)
}
});
Backend
const deleteBook = (req, res) => {
const connection = mysql.createConnection(connectionProperties);
connection.connect();
const query = `DELETE FROM Books WHERE idBooks = ${ req.body.idBooks }`;
connection.query(query, (err, res) => {
if (err) {
res.status(500).send(err);
} else {
res.status(200).send('Book deleted correctly.');
}
});
};
I'd add a prop onDeleteCallback, and on successful delete call that function with deleted book id. In parent component (with all the books are listed) update the state with filtered out books.
I guess passing the parameter might help you fix this issue.
On the delete Button add a parameter to the onClick={()=>this.handleDelete(e,book.idBooks)}
Change the handleDelete function a bit as below
handleDelete = (e,idBooks) => {
e.preventDefault();
axios.delete("http://localhost:8081/delete", idBooks )
.then(res => {
console.log(res.data);
}).catch(err => {
console.warn(err.warn);
});
};

Reactjs - setState doesn't re-render after update

Simply all i'm trying to do is re render the notes list when i add another note to the database. i tried several methods even redux dispatch method. but none worked and it kinda make sense because when i add a note i don't add anything so it can get the updated notes through /budget. maybe i have a big misunderstanding.
here's how i add a new note
export function saveOneNote() {
// saving a note
const _id = $('input[name="_id"]').val(),
firstItem = $('input[name="firstItem"]').val(),
firstPrice = $('input[name="firstPrice"]').val(),
secondItem = $('input[name="secondItem"]').val(),
secondPrice = $('input[name="secondPrice"]').val(),
thirdItem = $('input[name="thirdItem"]').val(),
thirdPrice = $('input[name="thirdPrice"]').val(),
tBudget = $('input[name="tBudget"]').val();
let currency = $("#currency").val();
console.log(currency);
$.ajax({
url: "/newNote",
type: "post",
dataType: "json",
contentType: "application/json",
data: JSON.stringify({
currency,
_id,
firstItem,
firstPrice,
secondItem,
secondPrice,
thirdItem,
thirdPrice,
tBudget
}),
success: function(Data) {
console.log("note was saved!", Data);
},
error: function(err, status, xhr) {
console.log("err", err);
}
});
}
here's how i fetch notes
class ShowAll extends Component {
constructor(props){
super(props);
this.state = {
Data: [],
length:[],
searchbyid:[],
isLoggedIn:[]
}
}
componentDidMount(){
// fetch notes
Rquest.get('/budget').then((res)=>{
let DataString = Array.from(res.body);
this.setState((prevState,props)=>{
return {
Data: DataString,
length: res.body.length
}
})
}).catch((err)=> {
console.log(err);
})
// check if user is logged in
Request.get('/auth').then((user)=>{
if(user){
this.setState({
isLoggedIn: true
})
}
}).catch((err)=> {
this.setState({
isLoggedIn: false
})
});
}
render(){
const count = this.state.length;
const myNotes = this.state.Data;
const isLoggedIn = this.state.isLoggedIn;
const listItems = myNotes.map((dynamicData)=>{
return(
<Fragment key={dynamicData.id}>
<div className='jumbotron'>
<div className='row'>
<button className='btn btn-danger delete-note-btn' onClick={DeleteOneNote}>Delete</button>
<input className='col-12 title form-control' id='deleteById' value={dynamicData._id} readOnly/>
<div className="dropdown-divider"></div> {/*line divider*/}
<div className='col-6' >
<ul className='list-unstyled'>
<li className='items'>items</li>
<li >{dynamicData.firstItem}</li>
<li >{dynamicData.secondItem}</li>
<li >{dynamicData.thirdItem}</li>
{/* <li>Total Budget :</li> */}
</ul>
</div>
<div className='dynamicData col-6'>
<ul className ='list-unstyled'>
<li className='prices'>Prices</li>
<li>{dynamicData.firstPrice} {dynamicData.currency}</li>
<li>{dynamicData.secondPrice} {dynamicData.currency}</li>
<li>{dynamicData.thirdPrice} {dynamicData.currency}</li>
</ul>
</div>
</div>
<h3 className='col-12 totalprice'>{dynamicData.tBudget} {dynamicData.currency}</h3>
</div>
</Fragment>
)
})
return (
<Fragment>
{isLoggedIn ===true?(
<div className='myNotesList '>
number of notes : {count}
{listItems}
</div>
):(
<Fragment>
</Fragment>
)
}
</Fragment>
)
}
}
React components are re-rendering only on state or props change. In your code - you're not mutating state nor props of your component.
What you should do in your case probably is to re-fetch the items after save or add the new items to the state or pass through props.
Example:
class Notes extends React.Component {
state = { note: '', notes: [] }
changeNote = ({ target: { value } }) => {
this.setState({ note: value });
}
addNote = () => {
this.setState((state) => ({ notes: [...state.notes, state.note] }));
}
render() {
return (
<div>
<input type="text" onChange={this.changeNote} />
<button onClick={this.addNote}>Add</button>
<ul>
{this.state.notes.map(note =>
<li>{note}</li>
)}
</ul>
</div>
)
}
}
ReactDOM.render(
<Notes />,
document.getElementById('app')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.2.0/umd/react-dom.production.min.js"></script>
<div id="app">
</div>

Resources