Autocomplete data in input - javascript

I want to display data from the autocomplete in the input as indicated below:
Autocomplete function
When i'm trying to do this i get an error:
×
TypeError: Cannot read property 'setState' of undefined
onSelect
94 | onSelect={ value => this.setState({ value }) }
I'm stuck on this and i'm probably doing it wrong. Hopefully someone can help me because i've tried everything i know and just cant see the problem. So please help me :)
privateMovie.js
import React, { useState, useEffect, setState } from "react";
import Layout from "../core/Layout";
import axios from "axios";
import { isAuth, getCookie, signout, updateUser } from "../auth/helpers";
import { ToastContainer, toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.min.css";
import Autocomplete from "react-autocomplete";
import { MoviesData, renderMovieTitle } from "./movie-data";
const Private = ({ history }) => {
const [values, setValues ] = useState({
value: "",
suggestions: [],
movie: "",
buttonText: "Submit"
});
const token = getCookie("token");
useEffect(() => {
loadProfile();
}, []);
const loadProfile = () => {
axios({
method: "get",
url: `${process.env.REACT_APP_API}/user/${isAuth()._id}`,
headers: {
Authorization: `Bearer ${token}`
}
})
.then(response => {
console.log("PRIVATE PROFILE UPDATE", response);
const { movie } = response.data;
setValues({ ...values, movie });
})
.catch(error => {
console.log("PRIVATE PROFILE UPDATE ERROR", error.response.data.error);
if (error.response.status === 401) {
signout(() => {
history.push("/");
});
}
});
};
const { movie, buttonText } = values;
const handleChange = value => event => {
// console.log(event.target.value);
setValues({ ...values, [value]: event.target.value });
};
const clickSubmit = event => {
event.preventDefault();
setValues({ ...values, buttonText: "Submitting" });
axios({
method: "POST",
url: `${process.env.REACT_APP_API}/movie/create`,
headers: {
Authorization: `Bearer ${token}`
},
data: { movie }
})
.then(response => {
console.log("PRIVATE PROFILE UPDATE SUCCESS", response);
updateUser(response, () => {
setValues({ ...values, buttonText: "Submitted" });
toast.success("Profile updated successfully");
});
})
.catch(error => {
console.log("PRIVATE PROFILE UPDATE ERROR", error.response.data.error);
setValues({ ...values, buttonText: "Submit" });
toast.error(error.response.data.error);
});
};
const updateForm = () => (
<form>
<div className="form-group">
<label className="text-muted">AUTOCOMPLETE</label>
<Autocomplete
type="text"
getItemValue={item => item.title}
items={MoviesData()}
shouldItemRender={renderMovieTitle}
renderItem={(item, isHighlighted) => (
<div style={{ background: isHighlighted ? "lightgray" : "white" }}>
{item.title}
</div>
)}
onChange={(event, value) => this.setState({ value }) }
onSelect={ value => this.setState({ value }) }
/>
<input
onChange={handleChange("movie")}
value={movie}
type="text"
className="form-control"
/>
</div>
<div>
<button className="btn btn-primary" onClick={clickSubmit}>
{buttonText}
</button>
</div>
</form>
);
return (
<Layout>
<div className="col-md-6 offset-md-3">
<ToastContainer />
<h1 className="pt-5 text-center"></h1>
<p className="lead text-center"></p>
{updateForm()}
</div>
</Layout>
);
};
export default Private;

I think you mixed it up.
Instead you call this.setState()
call your destructed function setValues()
wich you have declared in the beginning of your component function
const [values, setValues ] = useState({
value: "",
suggestions: [],
movie: "",
buttonText: "Submit"
});
And if you use "useState" and destruct it in "getValues" and "setValues" you can get rid of setState in your import.
See the docs:
https://reactjs.org/docs/hooks-state.html

Related

How to grab (orderId) payload value in form body to update the status of the order?

I am working on mern stack e-commerce project . I have a order update route . Order status get updated only by the admin . While updating order status admin gets the default(preload) status . Then admin enter new status for updation .
When I enter (accept) into input fields and hit update button it shows this and status may not get updated .
I am not able to grab orderID .
Here is my update status backend controller
exports.updateStatus = (req, res) => { Order.updateOne(
{ _id: req.body.orderId },
{ $set: { status: req.body.status } },
{ new: true, useFindAndModify: false },
(err, order) => {
if (err) {
return res.status(400).json({ error: "Cannot update order status" });
}
res.json(order);
} );};
update order route
router.put(
"/order-update/:userId",
isSignedIn,
isAuthenticated,
isAdmin,
updateStatus
);
API handler for frontend
export const updateOrder = (userId, token, order) => {
return fetch(`${API}/order-update/${userId}`, {
method: "PUT",
headers: {
Accept: "application/json",
Authorization: `Bearer ${token}`,
},
body: JSON.stringify(order),
})
.then((response) => {
return response.json();
})
.catch((err) => console.log(err));
};
Form for updating status
import React, { useEffect, useState } from "react";
import { isAutheticated } from "../auth/helper";
import Base from "../core/Base";
import { getOrder, updateOrder } from "./helper/adminapicall";
const UpdateOrder = ({ match }) => {
const { user, token } = isAutheticated();
const [status, setStatus] = useState("");
const [error, setError] = useState(false);
const [success, setSuccess] = useState(false);
const preload = (orderId) => {
getOrder(orderId, user._id, token).then((data) => {
console.log(data);
if (data?.error) {
setError(data?.error);
} else {
setStatus(data.status);
setError("");
setSuccess("");
}
});
};
useEffect(() => {
preload(match.params.orderId);
}, []);
const handleChange = (event) => {
setError(false);
setStatus(event.target.value);
setSuccess(false);
};
const onSubmit = (e) => {
e.preventDefault();
setError("");
setSuccess("");
updateOrder(user._id, token, { status }).then((data) => {
if (data?.error) {
setError(true);
} else {
setError("");
setSuccess(true);
setStatus("");
}
});
};
const successMessage = () => (
<div
className="alert alert-success mt-3"
style={{ display: success ? "" : "none" }}
>
<h4>updation successfull</h4>
</div>
);
const warningMessage = () => (
<div
className="alert alert-success mt-3"
style={{ display: error ? "" : "none" }}
>
<h4>updation failedl</h4>
</div>
);
const orderUpdateForm = () => (
<form>
<div className="form-group col-md-6">
<p className="lead">Update Order Status</p>
<input
type="text"
className="form-control my-3 col-md-6"
onChange={handleChange}
value={status}
autoFocus
required
/>
<button onClick={onSubmit} className="btn btn-outline-info col-md-6">
Update Order
</button>
</div>
</form>
);
return (
//
<Base title="Update Order Status" description="">
{successMessage()}
{warningMessage()}
{orderUpdateForm()}
</Base>
//
);
};
export default UpdateOrder;
You are trying to fetch orderId from the body but you are not sending OrderId in the body. Also, I am not able to understand why you sen UserId in route "/order-update/:userId".
I think you can send orderId as request param from the front end also you can update your route as
router.put(
"/order-update/:orderId",
isSignedIn,
isAuthenticated,
isAdmin,
updateStatus
);
After that, you can get orderId as
let { orderId } = req.params;

TypeError: Failed to fetch from API server React JS

So I get TypeError: Failed to fetch on React JS code. It says the error is on index.js line 5 and 15, My API server is up and running so i don't think its the API server. Whenever i click on submit, I get empty data undefined which should have been an array and typeerror. It was supposed to pass me an array when I clicked on submit in console
index.js
import {API} from "../../backend"
import {cartEmpty} from "../../core/helper/cartHelper"
export const signup = user => {
return fetch(`${API}users/`, {
method: "POST",
headers: {
Accecpt : "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify(user)
})
.then((response) => {
return response.json()
})
.catch(err => console.log(err))
}
export const signin = user => {
const formData = new FormData()
for (const name in user) {
formData.append(name, user[name])
}
return fetch(`${API}user/login`, {
method: "POST",
body: FormData
})
.then(response => {
return response.json()
})
.catch(err => console.log(err))
}
export const authenticate = (data, next) => {
if (typeof window !== undefined) {
localStorage.setItem("jwt", JSON.stringify(data))
next()
}
}
export const isAuthenticated = () => {
if (typeof window == undefined) {
return false
}
if (localStorage.getItem("jwt")) {
return JSON.parse(localStorage.getItem("jwt"))
} else {
return false
}
}
export const signout = next => {
const userId = isAuthenticated() && isAuthenticated().user.id
if (typeof window !== undefined) {
localStorage.removeItem("jwt")
cartEmpty(() => {})
//next()
return fetch(`${API}user/logout/${userId}`, {
method: "GET"
})
.then(response => {
console.log("Signout success")
next()
})
.catch(err => console.log(err))
}
}
Signup.js
import React, {useState} from 'react'
import Base from '../core/Base'
import {Link} from "react-router-dom"
import { signup } from '../auth/helper'
import { stringify } from 'query-string'
const Signup = () => {
const [values, setValues] = useState({
name: "",
email: "",
pasword: "",
error: "",
success: false
})
const {name, email, password, error, success} = values
const handleChange = name => event => {
setValues({...values, error: false, [name]: event.target.value})
}
const onSubmit = (event) => {
event.preventDefault()
setValues({...values, error: false})
signup({name, email, password})
.then(data => {
console.log("DATA", data)
})
.catch(err => console.log(err))
}
const signUpForm = () => {
return (
<div className="row">
<div className="col-md-6 offset-sm-3 text-left">
<form>
<div className="form-group">
<label className="text-light">Name</label>
<input onChange={handleChange("name")} value={name} className="form-control" type="text"></input>
</div>
<div className="form-group">
<label className="text-light">Email</label>
<input onChange={handleChange("email")} value={email} className="form-control" type="email"></input>
</div>
<div className="form-group">
<label className="text-light">Password</label>
<input onChange={handleChange("password")} value={password} className="form-control" type="password"></input>
</div>
<button onClick={onSubmit} className="btn btn-success btn-block">Submit</button>
</form>
</div>
</div>
)
}
return (
<Base title="Sign up Page" description="A signup">
{signUpForm()}
<p className="text-white text-center">{JSON.stringify(values)}</p>
</Base>
)
}
export default Signup

POST request is empty

I try to send a form values to DB (use redux-thunk, express, and MongoDB). My component looks like
const AddPerson = (props) => {
const [person, setPerson] = useState({
name: '',
age: '',
status: ''
})
const handleChange = (event) => {
setPerson({
...person,
[event.target.name]: event.target.value
})
}
const handleSubmit = (event) => {
props.putCustomersData({ person })
// eslint-disable-next-line no-console
console.log(person)
event.preventDefault()
}
return (
<div>
<Head title="This is new person" />
<form onSubmit={
handleSubmit
}
>
<div>
<div>name</div>
<input
name="name"
type="text"
value={person.name}
onChange={handleChange}
/>
<div>age</div>
<input
type="text"
name="age"
value={person.age}
onChange={handleChange}
/>
<div>status</div>
<input
name="status"
type="text"
value={person.status}
onChange={handleChange}
/>
<div>
<button type="submit">Ok</button>
</div>
</div>
</form>
</div>
);
}
AddPerson.propTypes = {}
AddPerson.defaultProps = {
person: { }
}
const mapStateToProps = state => ({
persons: state.persons.data
})
const mapDispatchToProps = dispatch => bindActionCreators({ putCustomersData }, dispatch)
export default connect(mapStateToProps, mapDispatchToProps)(AddPerson)
and redux
const initialState = {
data: []
}
export default (state = initialState, action) => {
switch (action.type) {
case POST_CUSTOMER:
return {
...state,
data: action.data
}
default:
return state
}
}
export function putCustomersData(person) {
return (dispatch) => {
axios.post('someUrl', {
headers: {
'Content-Type': 'application/json',
},
body: { person }
})
.then((responce) => {
dispatch({
type: POST_CUSTOMER,
data: responce.data
})
// eslint-disable-next-line no-console
console.log('ok', responce.data)
})
.catch((error) => {
dispatch({ type: POST_CUSTOMER_ERROR, error })
// eslint-disable-next-line no-console
console.log('err', error)
})
}
}
And my request writes as empty in DB. console.log(person) show a right object in console:
{name: "Anna", age: "14", status: "student"}
But console.log(responce.data) shows only
{_id: "5e888cb9ca6e5518a5bdf0c2", __v: 0}
I check my requests with Postman and they work. I don`t understand where my problem is. Why object does not write in DB?
The parameters of your axios.post(...) call are in the wrong order.
You have:
axios.post('someUrl', {
headers: {
'Content-Type': 'application/json',
},
body: { person }
})
The correct order is:
axios.post('someUrl', {
{ person },
headers: {
'Content-Type': 'application/json',
}
})
From the docs
axios.post(url[, data[, config]])

React: re render componet after button click

How do I make page refresh or reender content in page after I click submit button? I've trying to put window.location.reload() (I know that not the React way, this.forceUpdate() have same result) in submit functions(closeTicket(), openTicketSubmit()) but POST request don't get response
OpenTickets.js
import React from "react";
import axios from "axios";
import CardConversation from './CardConversation.jsx';
export default class PersonList extends React.Component {
constructor(props) {
super(props);
this.state = {
people: [],
send_to_number: "",
message_body: ""
};
this.closeTicket = this.closeTicket.bind(this);
this.openTicketsReply = this.openTicketsReply.bind(this);
this.openTicketsSubmit = this.openTicketsSubmit.bind(this);
this.getPhoneNumberOpenTickets = this.getPhoneNumberOpenTickets.bind(this);
}
openTicketsReply = async e => {
this.setState({
[e.target.name]: e.target.value
});
};
getPhoneNumberOpenTickets = async e => {
this.setState({
send_to_number: e
});
};
openTicketsSubmit = async e => {
e.preventDefault();
const formData = new FormData();
formData.set("send_to_number", this.state.send_to_number.slice(1));
formData.set("message_body", this.state.message_body);
axios({
method: "post",
url: "/outgoingsms",
data: formData,
headers: { "Content-Type": "multipart/form-data" }
})
};
closeTicket = async e => {
e.preventDefault();
const formData = new FormData();
formData.set("customernum", this.state.send_to_number.slice(1));
axios({
method: "post",
url: "/closeticket",
data: formData,
headers: { "Content-Type": "multipart/form-data" }
})
};
componentDidMount() {
this.getPeopleData();
}
getPeopleData = async () => {
try {
const { data } = await axios.get(`/getongoing?limit=10`);
this.setState({ people: data });
} catch (e) {
console.log("error: ", e);
}
};
render() {
const {
closeTicket,
openTicketsSubmit,
getPhoneNumberOpenTickets,
openTicketsReply
} = this;
return this.state.people.map(person => (
<CardConversation
person={person}
closeTicket={closeTicket}
openTicketsSubmit={openTicketsSubmit}
getPhoneNumberOpenTickets={getPhoneNumberOpenTickets}
openTicketsReply={openTicketsReply}
/>
));
}
}
CardConversation.jsx
import React, { useCallback, useEffect, useState } from "react";
import { Button, Accordion, Card, Form, Row, Col } from "react-bootstrap";
import axios from "axios";
const CardConversation = ({
person,
closeTicket,
openTicketsSubmit,
getPhoneNumberOpenTickets,
openTicketsReply,
}) => {
const [conversation, setConversation] = useState([]);
// Handlers
const handleSubmit = useCallback(
e => {
openTicketsSubmit(e);
},
[openTicketsSubmit]
);
const handleCloseTicket = useCallback(
e => {
closeTicket(e);
},
[closeTicket],
);
const handleClick = useCallback(() => {
getPhoneNumberOpenTickets(person);
},
[person, getPhoneNumberOpenTickets]);
const handleChange = useCallback(
e => {
openTicketsReply(e);
},
[openTicketsReply]
);
// Methods
const fetchConversation = useCallback(async () => {
try {
const { data } = await axios.get(
"/getconvfornum?customer_number=" + person.slice(1)
);
setConversation(data);
} catch (e) {
console.log("error: ", e);
}
}, [person, conversation]);
// Effects
useEffect(() => {
fetchConversation(person)
}, [person]);
return (
<Accordion defaultActiveKey="0">
<Card>
<Card.Header>
<Accordion.Toggle as={Button} variant="button" eventKey="0">
Conversation {person.indexOf(person)+1+ ' '}
Phone number: {person}
</Accordion.Toggle>
</Card.Header>
<Accordion.Collapse eventKey="0">
<Card.Body>
{conversation.map(message => (
<div>
<p>{message.from}</p>
<p>{message.body}</p>
</div>
))}
<Form onSubmit={handleSubmit}>
<br />
<Form.Group as={Row} controlId="formPlaintextPassword">
<Col sm="10">
<Form.Control
type="text"
placeholder="Reply"
name="message_body"
onChange={handleChange}
/>
</Col>
<Button type={"submit"}
onClick={handleClick} column sm="2">
Reply
</Button>
</Form.Group>
</Form>
<Form onSubmit={handleCloseTicket}>
<Form.Group>
<Col sm="11">
<Button type={"submit"}
onClick={handleClick} column sm="4">
Close Ticket
</Button>
</Col>
</Form.Group>
</Form>
</Card.Body>
</Accordion.Collapse>
</Card>
<br />
</Accordion>
);
};
export default CardConversation;
A simple way to re-render would be to change the state variable on the submission of the Axios request causing the component to re-render automatically.
Example:
axios({...}).then(resp => {
this.setState({message_body:'',send_to_number:''}); // will cause to re-render
})
You can make the component re-render by updating its state ( after the POST ) :
closeTicket = async e => {
e.preventDefault();
const formData = new FormData();
formData.set("customernum", this.state.send_to_number.slice(1));
axios({
method: "post",
url: "/closeticket",
data: formData,
headers: { "Content-Type": "multipart/form-data" }
})
.then(() => {
this.setState({ /* */ })
// or
// this.forceUpdate();
})
};
React will rerender components once the state changes, which means that what you need is to change the state once the submit button is clicked. Since the submit button is inside the PersonList component and you also want to reload PersonList, you want to change the state of PersonList when the submit button is clicked.
Here is what you might want to do:
1) add a 'reload' state to PersonList, defaulting it to false. This will tell the component if you need to reload or not.
2) pass a function that sets the state of PersonList's reload value into the child component, in this case CardConversion. something like this.setState({reload:!this.state.reload}) should do.
3) when you finish handling what you need to handle within CardConversion, call your passed function to set the parent's state value, and the whole component should reload.
this.state = {
reload: false
...
}
...
shouldReload() {
this.setState({reload:!this.state.reload});
}
...
<CardConversation
person={person}
closeTicket={closeTicket}
openTicketsSubmit={openTicketsSubmit}
getPhoneNumberOpenTickets={getPhoneNumberOpenTickets}
openTicketsReply={openTicketsReply}
reloadParent={this.shouldReload.bind(this)}
/>
and on CardConversation
const handleClick = useCallback(() => {
getPhoneNumberOpenTickets(person);
this.props.reloadParent();
},
in opentickets.js
create a function updatePeople and in that function call this.getPeopleData();
eg
updatePeople = () =>{
this.getPeopleData();
}
then in
return this.state.people.map(person => (
<CardConversation
person={person}
closeTicket={closeTicket}
openTicketsSubmit={openTicketsSubmit}
getPhoneNumberOpenTickets={getPhoneNumberOpenTickets}
openTicketsReply={openTicketsReply}
refreshPeople = {this.updatePeople}
/>
));
in cardConversion.jsx
when you click the close button or whichever button gets you back to openTickets, put the callback function
this.props.refreshPeople();
because you have componentDidMount, everytime you call whatever is in componentDidMount, it will update the information and re render it
First of all, regarding you are not getting any data issue, you can check axios, and how they use post:
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function (response) {
// where you can setState here
console.log(response);
})
.catch(function (error) {
console.log(error);
});
Mainly axios are handling the data asynchronously. By that, once you call the api, React will executes next line of code.
For more discussion of how to force update the component, you can check this post: Can you force a React component to rerender without calling setState?, which explain how to update component very well.
As far as I can see, what you're trying to do is reload the people list. If that's the case, you can solve it in two ways:
In both axios API calls, add .then() block and call this.getPeopleData().
Instead of re-fetching people's data, you get the added/deleted post data and update state in the .then() block with setState().
I suggest you to adopt Option 2, because fetching the list again will require more time for you to get the refreshed list.
Either way, just adding this.forceUpdate() to your .then() block will not give you the updated list. It won't do anything actually to the UI. (though it makes it re-render)
CardConversatio.jsx
import React, { useCallback, useEffect, useState } from "react";
import { Button, Accordion, Card, Form, Row, Col } from "react-bootstrap";
import axios from "axios";
const CardConversation = ({
person,
closeTicket,
openTicketsSubmit,
getPhoneNumberOpenTickets,
openTicketsReply,
getPhoneToCloseTicket,
}) => {
const [conversation, setConversation] = useState([]);
const [trigger, fireUpdate] = useState(false);
// Handlers
const renderConversation = useCallback(() => {
return conversation.map(message => (
<div key={message.date.$date + person}>
<p>{message.from}</p>
<p>{message.body}</p>
</div>
));
}, [conversation, person]);
const fetchConversation = useCallback(async () => {
try {
const { data } = await axios.get(
"/getconvfornum?customer_number=" + person.slice(1)
);
setConversation(data);
console.log("fetch ", data);
} catch (e) {
console.log("error: ", e);
}
}, [person]);
const handleClick = useCallback(async () => {
await getPhoneNumberOpenTickets(person);
setTimeout(() => fetchConversation(person), 500);
}, [getPhoneNumberOpenTickets, person, fetchConversation]);
const handleClickClose = useCallback(async () => {
await getPhoneToCloseTicket(person);
}, [person, getPhoneToCloseTicket]);
const handleChange = useCallback(
e => {
openTicketsReply(e);
},
[openTicketsReply]
);
useEffect(() => {
console.log("effect");
fetchConversation(person);
}, [fetchConversation, person]);
return (
<Accordion defaultActiveKey="0">
<Card>
<Card.Header>
<Accordion.Toggle as={Button} variant="button" eventKey="0">
Conversation {person.indexOf(person) + 1 + " "}
Phone number: {person}
</Accordion.Toggle>
</Card.Header>
<Accordion.Collapse eventKey="0">
<Card.Body>
{renderConversation()}
<Form>
<br />
<Form.Group as={Row} controlId="formPlaintextPassword">
<Col sm="10">
<Form.Control
type="text"
placeholder="Reply"
name="message_body"
onChange={handleChange}
/>
</Col>
<Button onClick={handleClick} column sm="2">
Reply
</Button>
</Form.Group>
</Form>
<Form>
<Form.Group>
<Col sm="11">
<Button onClick={handleClickClose} column sm="4">
Close Ticket
</Button>
</Col>
</Form.Group>
</Form>
</Card.Body>
</Accordion.Collapse>
</Card>
<br />
</Accordion>
);
};
export default CardConversation;
OpenTickets.js
import React from "react";
import axios from "axios";
import CardConversation from './CardConversation.jsx';
export default class PersonList extends React.Component {
constructor(props) {
super(props);
this.state = {
people: [],
send_to_number: "",
message_body: "",
closed: false
};
this.closeTicket = this.closeTicket.bind(this);
this.openTicketsReply = this.openTicketsReply.bind(this);
this.openTicketsSubmit = this.openTicketsSubmit.bind(this);
this.getPhoneNumberOpenTickets = this.getPhoneNumberOpenTickets.bind(this);
this.getPhoneToCloseTicket = this.getPhoneToCloseTicket.bind(this);
}
openTicketsReply = async e => {
e.preventDefault();
this.setState({
message_body: e.target.value
});
};
getPhoneNumberOpenTickets = async e => {
//e.preventDefault();
this.setState({
send_to_number: e
}, async () => await this.openTicketsSubmit());
};
getPhoneToCloseTicket = async e => {
this.setState({
send_to_number: e
}, async () => this.closeTicket());
};
openTicketsSubmit = async e => {
const formData = new FormData();
formData.set("send_to_number", this.state.send_to_number.slice(1));
formData.set("message_body", this.state.message_body);
axios({
method: "post",
url: "/outgoingsms",
data: formData,
headers: { "Content-Type": "multipart/form-data" }
}).then(resp => {
this.setState({ closed: true });
}).catch(error => console.log(error))
};
closeTicket = async e => {
const formData = new FormData();
formData.set("customernum", this.state.send_to_number.slice(1));
axios({
method: "post",
url: "/closeticket",
data: formData,
headers: { "Content-Type": "multipart/form-data" }
}).then(resp => {
this.setState({ closed: true });
}).catch(error => console.log(error))
};
componentDidMount() {
this.getPeopleData();
}
getPeopleData = async () => {
try {
const { data } = await axios.get(`/getongoing?limit=10`);
this.setState({ people: data });
} catch (e) {
console.log("error: ", e);
}
};
render() {
const {
closeTicket,
getPhoneNumberOpenTickets,
openTicketsReply,
getPhoneToCloseTicket
} = this;
return this.state.people.map(person => (
<CardConversation
key={person}
person={person}
closeTicket={closeTicket}
getPhoneNumberOpenTickets={getPhoneNumberOpenTickets}
openTicketsReply={openTicketsReply}
getPhoneToCloseTicket={getPhoneToCloseTicket}
/>
));
}
}

createStore not changing from initial state to Action proved value

Im trying to get access a variable called isSuperAdmin, It basically tells me if the logged in user is a super admin or not allowing me to disable some features.
I currently have no access to the variable in the current page however my redux action is showing it as being there, I think I may have configured something incorrectly, as of now my code doesn't change from the initial state value of null to the bool value isSuperUser. Here is the page that I am trying to use this variable.
import React, { PropTypes } from 'react';
import withStyles from 'isomorphic-style-loader/lib/withStyles';
import { connect } from 'react-redux';
import Modal from '../Modal';
import Summary from '../Summary';
import s from './BookingDetailsModal.scss';
import AmendConsumerDetails from './AmendConsumerDetails';
import ChangeBookingSession from './ChangeBookingSession';
import payReservationCashActionCreator from '../../actions/payReservationCash';
import payReservationCardActionCreator from '../../actions/payReservationCard';
import payRestActionCreator from '../../actions/payRest';
import refundCashActionCreator from '../../actions/refundCash';
import cancelReservationActionCreator from '../../actions/cancelReservation';
import formatPrice from '../../../../../core/formatPrice';
import {
BOXOFFICE_HIDE_BOOKING_DETAILS,
BOXOFFICE_SET_BOOKING_DETAILS_ACTION_TYPE,
resendConfirmationEmail as resendConfirmationEmailActionCreator,
} from '../../actions';
function renderActionButtons({
isSuperAdmin,
setActionType,
resendConfirmationEmail,
order: {
type: orderType,
paid: orderPaid,
amount: orderAmount,
refundedAt: orderRefundedAt,
canceledAt: orderCanceledAt,
sessionId,
},
isCreatingPayment,
payReservationCard,
payReservationCash,
payRest,
refundCash,
cancelReservation,
}) {
debugger;
return (
<div className={s.buttonsContainer}>
<div className={s.buttonsContainer}>
<div className={s.buttonContainer}>
<button
onClick={(e) => {
e.preventDefault();
setActionType('AMEND_CONSUMER_DETAILS');
}}
>Amend consumer details</button>
</div>
{ sessionId ?
<div className={s.buttonContainer}>
<button
onClick={(e) => {
e.preventDefault();
setActionType('CHANGE_SESSION');
}}
>Move to another session</button>
</div> : null
}
<div className={s.buttonContainer}>
<button disabled>Amend tickets or products</button>
</div>
{ orderType === 'reservation' && isCreatingPayment && !orderPaid ?
<div>
<div className={s.buttonContainer}>
<button
onClick={(e) => {
e.preventDefault();
payReservationCash();
}}
>Pay Reservation CASH</button>
</div>
<div className={s.buttonContainer}>
<button
onClick={(e) => {
e.preventDefault();
payReservationCard();
}}
>Pay Reservation CARD</button>
</div>
</div> :
null
}
{ orderType === 'deposit' && isCreatingPayment && !orderPaid ?
<div>
<div className={s.buttonContainer}>
<button
onClick={(e) => {
e.preventDefault();
payRest('CASH');
}}
>Pay Rest CASH</button>
</div>
<div className={s.buttonContainer}>
<button
onClick={(e) => {
e.preventDefault();
payRest('CARD');
}}
>Pay Rest CARD</button>
</div>
</div> :
null
}
{ !orderRefundedAt && orderPaid ?
<div className={s.buttonContainer}>
<button
disabled={isSuperAdmin}
onClick={(e) => {
e.preventDefault();
refundCash(orderAmount);
}}
>Refund CASH, {formatPrice(orderAmount)}</button>
</div> : null
}
{ orderCanceledAt === null && orderType === 'reservation' ?
<div className={s.buttonContainer}>
<button
onClick={(e) => {
e.preventDefault();
cancelReservation();
}}
>Cancel Reservation</button>
</div> : null
}
<div className={s.buttonContainer}>
<button
onClick={(e) => {
e.preventDefault();
resendConfirmationEmail();
}}
>Resend confirmation email</button>
</div>
</div>
</div>
);
}
renderActionButtons.propTypes = {
isSuperAdmin: PropTypes.bool.isRequired,
setActionType: PropTypes.func.isRequired,
resendConfirmationEmail: PropTypes.func.isRequired,
order: PropTypes.shape({
type: PropTypes.string.isRequired,
paid: PropTypes.bool.isRequired,
sessionId: PropTypes.string.isRequired,
amount: PropTypes.number.isRequired,
// reservationPaidCashAt: PropTypes.string.isRequired,
// reservationPaidCardAt: PropTypes.string.isRequired,
}).isRequired,
payReservationCard: PropTypes.func.isRequired,
payReservationCash: PropTypes.func.isRequired,
payRest: PropTypes.func.isRequired,
isCreatingPayment: PropTypes.bool.isRequired,
refundCash: PropTypes.func.isRequired,
cancelReservation: PropTypes.func.isRequired,
};
const components = {
AMEND_CONSUMER_DETAILS: AmendConsumerDetails,
CHANGE_SESSION: ChangeBookingSession,
};
function renderAction(actionType, props) {
const Component = components[actionType];
return <Component {...props} />;
}
function BookingDetailsModal(props) {
const { hideOrderDetails, orderId, bookingDetailsActionType } = props;
return (
<Modal onClose={hideOrderDetails}>
<div className={s.container}>
<div className={s.summaryContainer}>
<Summary orderId={orderId} withEdits={false} />
</div>
<div className={s.actionsContainer}>
{bookingDetailsActionType ?
renderAction(bookingDetailsActionType, props) :
renderActionButtons(props)
}
</div>
</div>
</Modal>
);
}
BookingDetailsModal.propTypes = {
orderId: PropTypes.string.isRequired,
hideOrderDetails: PropTypes.func.isRequired,
bookingDetailsActionType: PropTypes.oneOf([
'AMEND_CONSUMER_DETAILS',
]),
};
const mapStateToProps = (state, { orderId }) => (
{
ui: { bookingDetailsActionType },
ui: { isSuperAdmin },
orders: {
data: { [orderId]: order },
edits: { [orderId]: orderEdits },
},
}
) => ({
bookingDetailsActionType,
isSuperAdmin,
order,
isCreatingPayment: orderEdits.isCreatingPayment,
});
const mapDispatchToProps = (dispatch, { orderId }) => ({
hideOrderDetails: () => dispatch({ type: BOXOFFICE_HIDE_BOOKING_DETAILS }),
setActionType: actionType =>
dispatch({ type: BOXOFFICE_SET_BOOKING_DETAILS_ACTION_TYPE, actionType }),
resendConfirmationEmail: () => dispatch(resendConfirmationEmailActionCreator(orderId)),
payReservationCard: () => dispatch(payReservationCardActionCreator(orderId)),
payReservationCash: () => dispatch(payReservationCashActionCreator(orderId)),
payRest: type => dispatch(payRestActionCreator(orderId, type)),
refundCash: amount => dispatch(refundCashActionCreator(orderId, amount)),
cancelReservation: () => dispatch(cancelReservationActionCreator(orderId)),
});
export default connect(mapStateToProps, mapDispatchToProps)(withStyles(s)(BookingDetailsModal));
My Redux tab on page load shows the following:
type(pin): "BOXOFFICE_IS_SUPER_USER"
isSuperAdmin(pin): true
This is how I have used createStore to access the variable:
const isSuperAdmin = createStore(null, {
[BOXOFFICE_IS_SUPER_USER]: isSuperAdmin => isSuperAdmin,
});
I then proceeded to add it to the reducer at the bottom.
edit I have changed the variable isSuperAdmin in the createStore to true and this can be read perfectly fine, it must now be an issue with the variable passed to the action in the first place.
Here is the code where I get the value of the variable and pass it on:
Export default ({ knex }) => authenticateAdmin(knex)(
async (req, res) => {
try {
const { eventId } = req;
const event = await fetchEvent(knex, eventId);
const isSuperAdmin = await res.isSuperAdmin;
res.send({ event, isSuperAdmin});
} catch (err) {
res.send(err.stack);
console.error(err.stack); // eslint-disable-line no-console
throw err;
}
}
);
And the dispatch:
export const fetchEvent = () => async (dispatch, getState) => {
try {
const state = getState();
const { auth: { password } } = state;
const response = await fetch('/api/event', {
headers: {
Accept: 'application-json',
'X-Password': password,
},
});
if (response.status === 200) {
const { event, isSuperAdmin } = await response.json();
dispatch({ type: BOXOFFICE_SET_EVENT, event });
dispatch({ type: BOXOFFICE_IS_SUPER_USER, isSuperAdmin });
} else {
localStorage.removeItem('password');
dispatch({ type: BOXOFFICE_UNAUTHENTICATE });
}
} catch (err) {
console.log(err); // eslint-disable-line no-console
throw err;
}
};
EDIT
Here is the reducer:
export default combineReducers({
isSuperAdmin, ------- My variable
isProcessingPayment,
isSelectDateCollapsed,
isLoadingBookings,
shouldShowBookings,
shouldShowDepositModal,
shouldShowReservationModal,
shouldShowConsumerDetailsModal,
shouldShowDiscountModal,
shouldShowOrderConfirmationModal,
bookingFilter,
selectedOrderId,
sendConfirmationEmail,
bookingIds,
orderDetailsId,
bookingDetailsActionType,
});
I guess the way you defined your mapStateToProps is incorrect.
Updated the code
try following:
const mapStateToProps = ({
ui: {
bookingDetailsActionType,
isSuperAdmin
},
orders: {
data,
edits
}
}, {
orderId
}) => {
const order = data[orderId],
orderEdits = edits[orderId];
return {
bookingDetailsActionType,
isSuperAdmin,
order,
isCreatingPayment: orderEdits.isCreatingPayment
};
};
I finally have a solution! Turns out my issue was not setting a property type for my isSuperUser variable. Despite my colleague telling me that it will work without any property type (which still makes sense to me and confuses me as to why it wont work?!).
A simple change in the index.js file from:
[BOXOFFICE_IS_SUPER_USER]: isSuperAdmin => isSuperAdmin,
to
[BOXOFFICE_IS_SUPER_USER]: (state, { isSuperAdmin }) => isSuperAdmin,
and adding a property type to the show.js file where I used res.send()
res.send({ event, isSuperAdmin: isSuperAdmin});
Im still at a loss as to why it won't work with no property type but oh well...!

Categories

Resources