JSX if/else syntax within React - reactjs

I'm trying to figure out how to add an if/else here so that if classroomId has a value, the importUserToClassroom endpoint will be hit. If not, I'd like to execute the same code, but with the importUsers endpoint. Any ideas on where I'm going wrong with my syntax would be much appreciated!
handleFormSubmit(data) {
const {
importUserToClassroom,
importUsers,
addFlashMessage,
formatErrors,
showUiBlocked,
hideUiBlocked,
match: {params: {classroomId}},
} = this.props;
showUiBlocked();
const users = userDataToList(data);
{
classroomId !== undefined ? (
importUserToClassroom({
users,
classroomId,
})
) : (
importUsers({users})
)
}
.then(() => {
hideUiBlocked();
addFlashMessage('Users imported successfully', 'success');
this.context.router.history.push('/users');
})
.catch(err => {
hideUiBlocked();
if (err.status !== 409) {
return formatErrors(err).then(err => {
this.setState({
errors: err,
});
});
} else {
this.setState({
errors: {
usernames: err.data.message,
}
});
}
});
}
Update: The following ended up working!
handleFormSubmit(data) {
const {
importUserToClassroom,
importUsers,
addFlashMessage,
formatErrors,
showUiBlocked,
hideUiBlocked,
match: {params: {classroomId}},
} = this.props;
showUiBlocked();
const users = userDataToList(data);
if (!isEmpty(classroomId)) {
importUserToClassroom({
users,
classroomId,
})
.then(() => {
hideUiBlocked();
addFlashMessage('Users imported successfully', 'success');
this.context.router.history.push('/users');
})
.catch(err => {
hideUiBlocked();
if (err.status !== 409) {
return formatErrors(err).then(err => {
this.setState({
errors: err,
});
});
} else {
this.setState({
errors: {
usernames: err.data.message,
}
});
}
});
} else {
importUsers({users})
.then(() => {
hideUiBlocked();
addFlashMessage('Users imported successfully', 'success');
this.context.router.history.push('/users');
})
.catch(err => {
hideUiBlocked();
if (err.status !== 409) {
return formatErrors(err).then(err => {
this.setState({
errors: err,
});
});
} else {
this.setState({
errors: {
usernames: err.data.message,
}
});
}
});
}
}

This isn't really JSX, but you do have some syntax errors. You can't use curly brackets like that. If importUserToClassroom and importUsers return promises, you could try something like this:
const savePromise = classroomId ?
importUserToClassroom({
users,
classroomId,
}) :
importUsers({users});
savePromise.then(() => {
hideUiBlocked();
addFlashMessage('Users imported successfully', 'success');
this.context.router.history.push('/users');
})

Related

Thunk is fulfilled before array map finishes

I have a thunk which fetches data from firestore and maps doc IDs to each doc. For some reason it's fulfilled and returns undefined before the mapping finishes. I can verify this because the log before return statement appears a second or two after the fulfilled reducer logs.
My thunk:
export const fetchNotesByCustomerId = createAsyncThunk(
'fetchNotesByCustomerId',
async (custId, { getState, dispatch }) => {
const customerId = custId;
if (customerId !== undefined) {
notesService
.fetchNotesByCustomerId(customerId)
.then((snapshot) => {
if (snapshot.docs.length !== 0) {
const notes = snapshot.docs.map(
(doc) =>
({
...doc.data(),
docId: doc.id
} as INote)
);
console.log('notes inside thunk: ', notes); // This shows after the fulfilled reducer logs
return {
error: false,
data: notes
};
} else
return {
error: true,
message: 'No notes found in firebase',
data: []
};
})
.catch((error) => {
return { error: true, message: error.message, data: [] };
});
} else return { error: true, message: 'No Customer Id' };
}
);
I know .map is an async function that returns an array of promises, but when I use await, intellisense notifies me that it makes no difference on the behavior of the function.
So as an alternative, I tried to resolve the array of promises like this, but saw no difference:
.then(async (snapshot) => {
if (snapshot.docs.length !== 0) {
const notesPromisesArray = snapshot.docs.map(
(doc) =>
({
...doc.data(),
docId: doc.id
} as INote)
);
await Promise.all(notesPromisesArray).then((notes) => {
console.log('notes inside thunk: ', notes);
return {
error: false,
data: notes
};
});
} else
return {
error: true,
message: 'No notes found in firebase',
data: []
};
})
How can I get this .map to return before the thunk is fulfilled?
The problem you're facing has nothing to do with Redux Async Thunk but basic JavaScript only.
In the if condition that you have:
if (customerId !== undefined) {
notesService
.fetchNotesByCustomerId(customerId)
.then((snapshot) => {
if (snapshot.docs.length !== 0) {
const notes = snapshot.docs.map(
(doc) =>
({
...doc.data(),
docId: doc.id,
} as INote)
)
console.log('notes inside thunk: ', notes) // This shows after the fulfilled reducer logs
return {
error: false,
data: notes,
}
} else
return {
error: true,
message: 'No notes found in firebase',
data: [],
}
})
.catch((error) => {
return { error: true, message: error.message, data: [] }
})
}
You're using noteService.fetchNotesByCustomerId() which is an async function.
When the execution goes to this block, since JavaScript Event loop will forward the async function to its thread pool, it goes to the next step without even the execution of noteService.fetchNotesByCustomerId() getting over and resolves the thunk without returning anything.
You can easily resolve this by adding a return statement next to your call:
export const fetchNotesByCustomerId = createAsyncThunk('fetchNotesByCustomerId', async (custId, { getState, dispatch }) => {
const customerId = custId
if (customerId !== undefined) {
return notesService
.fetchNotesByCustomerId(customerId)
.then((snapshot) => {
if (snapshot.docs.length !== 0) {
const notes = snapshot.docs.map(
(doc) =>
({
...doc.data(),
docId: doc.id,
} as INote)
)
console.log('notes inside thunk: ', notes) // This shows after the fulfilled reducer logs
return {
error: false,
data: notes,
}
} else
return {
error: true,
message: 'No notes found in firebase',
data: [],
}
})
.catch((error) => {
return { error: true, message: error.message, data: [] }
})
} else return { error: true, message: 'No Customer Id' }
})

How to make a PATCH request in ReactJS ? (with Nestjs)

nestjs controller.ts
#Patch(':id')
async updateProduct(
#Param('id') addrId: string,
#Body('billingAddr') addrBilling: boolean,
#Body('shippingAddr') addrShipping: boolean,
) {
await this.addrService.updateProduct(addrId, addrBilling, addrShipping);
return null;
}
nestjs service.ts
async updateProduct(
addressId: string,
addrBilling: boolean,
addrShipping: boolean,
) {
const updatedProduct = await this.findAddress(addressId);
if (addrBilling) {
updatedProduct.billingAddr = addrBilling;
}
if (addrShipping) {
updatedProduct.shippingAddr = addrShipping;
}
updatedProduct.save();
}
there is no problem here. I can patch in localhost:8000/address/addressid in postman and change billingAddr to true or false.the backend is working properly.
how can i call react with axios?
page.js
const ChangeBillingAddress = async (param,param2) => {
try {
await authService.setBilling(param,param2).then(
() => {
window.location.reload();
},
(error) => {
console.log(error);
}
);
}
catch (err) {
console.log(err);
}
}
return....
<Button size='sm' variant={data.billingAddr === true ? ("outline-secondary") : ("info")} onClick={() => ChangeBillingAddress (data._id,data.billingAddr)}>
auth.service.js
const setBilling = async (param,param2) => {
let adressid = `${param}`;
const url = `http://localhost:8001/address/`+ adressid ;
return axios.patch(url,param, param2).then((response) => {
if (response.data.token) {
localStorage.setItem("user", JSON.stringify(response.data));
}
return response.data;
})
}
I have to make sure the parameters are the billlingddress field and change it to true.
I can't make any changes when react button click
Since patch method is working fine in postman, and server is also working fine, here's a tip for frontend debugging
Hard code url id and replace param with hard coded values too:
const setBilling = async (param,param2) => {
// let adressid = `${param}`;
const url = `http://localhost:8001/address/123`; // hard code a addressid
return axios.patch(url,param, param2).then((response) => { // hard code params too
console.log(response); // see console result
if (response.data.token) {
// localStorage.setItem("user", JSON.stringify(response.data));
}
// return response.data;
})
}
now it worked correctly
#Patch('/:id')
async updateProduct(
#Param('id') addrId: string,
#Body('billingAddr') addrBilling: boolean,
) {
await this.addrService.updateProduct(addrId, addrBilling);
return null;
}
const ChangeBillingAddress = async (param) => {
try {
await authService.setBilling(param,true).then(
() => {
window.location.reload();
},
(error) => {
console.log(error);
}
);
}
catch (err) {
console.log(err);
}
}
const setBilling= async (param,param2) => {
let id = `${param}`;
const url = `http://localhost:8001/address/`+ id;
return axios.patch(url,{billingAddr: param2}).then((response) => {
if (response.data.token) {
localStorage.setItem("user", JSON.stringify(response.data));
}
return response.data;
})
}

props becomes undefined on page refresh which resist socket re-establishment

I have implemented the socket, which was not able to established after pressing F5 button,
when users logged into the app, socket has been establishes successfully, when I hit F5, page refreshes but socketConnection is not invoked because props is undefined due to which conditional statement has been failed to execute.
After inspecting I have found that, I invoked the main socket creation function inside App.js, it takes props as as argument and one conditional statement. I have found that the props itself is undefined due to which the socket i not able t re-established.
App.js
import React, { useEffect } from 'react';
import './App.scss';
import Routes from './Routes';
import { connect } from 'react-redux';
import socketConnection from '#Hoc/SocketComponent';
const App = () => {
useEffect((props) => {
if (props?.session?.user?.extraDetails?.extensionNo) {
socketConnection(props);
}
}, []);
return (
<div>
<Routes />
</div>
);
};
const mapStateToProps = (state) => ({
session: state.session
});
export default connect(mapStateToProps)(App);
SocketComponent
export default function socketConnection(socketEvent) {
if (!window?.socket)
sessionService.loadUser().then((currentUser) => {
if (
currentUser?.extraDetails?.extensionNo &&
currentUser?.params?.AgentID
)
socket = window.socket = io(REACT_APP_SOCKET_URL, {
query: {
agentId: currentUser.params.AgentID,
extensionNo: currentUser.extraDetails.extensionNo,
},
});
socket.on("connect", (data) => {
console.info(data);
});
socket.on("EventEstablished", (data) => {
eventEstablished(data, currentUser, socketEvent);
});
socket.on("EventAgentLogout", () => {
notification.error({
message: "Softphone loggedout, please re-login",
duration: 0,
});
socketEvent.history.push("/home");
});
socket.on("EventPropertiesChanged", (data) => {
manualGeocode(data);
});
socket.on("EventAttachedDataChanged", (data) => {
if (data.data?.incidentNumber) {
store.dispatch({
type: SET_LIVE_CALL_DATA,
payLoad: { psapReferenceId: data?.data?.incidentNumber },
});
}
if (data.data?.updateLocation && data.data?.isRetransmit) {
let functionCall = "retransmit" ;
// if (data.data?.isRetransmit) {
// functionCall = "retransmit" ;
// }
getCallData( functionCall );
}
// manualGeocode(data);
});
socket.on("EventDestinationBusy", (data) => {
console.log("EventDestinationBusy", data);
});
socket.on("EventAbandoned", (data) => {
notification.error({
message: "Call abandoned",
description: "The caller abandoned the call before it was answered",
duration: 0,
});
});
socket.on("EventDNOutOfService", (data) => {
notification.error({
message: "Extension Out of Service !",
description:
"This extension is out of service and cannot make or receive calls. ",
duration: 0,
});
});
socket.on("EventAgentReady", (data) => {
console.log("EventAgentReady", data);
});
socket.on("EventAgentNotReady", (data) => {
console.log("EventAgentNotReady", data);
});
socket.on("EventReleased", (data) => {
eventReleased(data);
});
socket.on("EventPartyDeleted", (data) => {
eventPartyDeleted(data);
});
socket.on("EventInvite", (data) => {
console.log(data);
if (
!store?.getState()?.secondAgent?.secondAgent?.isSecondAgent &&
socketEvent.history.location.pathname === "/waiting"
) {
eventInvite(data, currentUser, socketEvent);
}
});
socket.on("disconnect", (data) => {
console.log(data);
});
socket.on("workflow", (data) => {
store.dispatch({ type: SET_WORKFLOW_DATA, payLoad: data });
});
socket.on("workflowUpdatedComponent", (data) => {
store.dispatch({ type: SET_WORKFLOW_OPTIONS, payLoad: data });
});
socket.on("gather-info", (data) => {
console.log(data);
if (data?.data?.extensionNo != currentUser.extraDetails.extensionNo) {
store.dispatch({
type: SET_GATHER_INFO,
payLoad: data?.data?.gatherInfo,
});
}
});
socket.on("geoCodeSession", (data) => {
console.log(data);
if (data?.data?.extensionNo != currentUser.extraDetails.extensionNo) {
if (data?.data?.updateLocation) {
store.dispatch({
type: SET_MANUAL_GEOCODE,
payLoad: { updateLocation: true },
});
}
// let timeFrame = new Date(data.data.timestamp);
// timestamp = timeFrame.toLocaleDateString() + ' ' + timeFrame.toLocaleTimeString();
store.dispatch({
type: SET_MANUAL_GEOCODE,
payLoad: {
status: true,
latitude: data?.data?.latitude,
longitude: data?.data?.longitude,
address: data?.data?.address,
country: data?.data?.country,
region: data?.data?.region,
timestamp: data?.data?.timestamp,
},
});
}
});
socket.on("EventSessionInfo", (data) => {
if (data?.data?.extensionNo !== currentUser?.extraDetails.extensionNo) {
if (data.data.sessionStatus === "Over") {
store.dispatch({
type: SET_SECOND_AGENT,
payLoad: { status: "Disconnected", isSecondAgent: false },
});
} else if (
data.data.sessionStatus === "Alive" &&
data.data.agentNameChat
) {
store.dispatch({
type: SET_SECOND_AGENT,
payLoad: {
isSecondAgent: true,
status: "Connected",
anotherAgent: data.data.messageText,
isSecondAgent: true,
},
});
} else if (
data.data.sessionStatus === "Alive" &&
!data.data.messageText.includes("Leaving ChatRoom..") &&
!data.data.messageText.includes("Join Chat Session")
) {
chatStore(data);
}
}
});
});
}
I am not able to figured it out what went wrong, however I am trying to load when props are there but not able to do the same.
PROBLEM
It seems like props are not loaded while execution of `useEffect
Solution might be require some kind of delay to useEffect, so once props properly loaded form localstorage

React dispatch not working (userService function not triggered in userAction)

When I submit my form, it triggers an action login (from userActions). In this action, I use dispatch to use my userService which makes an API call.
When I submit it, the dispatch is not working. If I console.log the result of the action I have my code that appears, like this:
Action was called // Custom message
dispatch => {
dispatch(request({
email
}))
_services_userService__WEBPACK_IMPORTED_MODULE_1__["userService"].login(email, password).then( appSate => {return appSate;},error => {console.lo…
I am supposed to retrieve my user... What is wrong here ?
LoginForm.js
handleFormSubmit(e) {
e.preventDefault();
const credentials = {
email: this.state.email,
password: this.state.password
}
if (credentials) {
let test = login(credentials);
console.log("Action was called");
console.log(test);
this.setState(redirect => true)
}
}
userActions.js -> login()
export const login = (email,password) => {
console.log('is in action');
return dispatch => {
dispatch(request({ email }));
userService.login(email,password)
.then(
appSate => {
return appSate;
},
error => {
console.log(error);
}
);
};
function request(user) { return { type: userConstants.LOGIN_REQUEST,user } }
}
userService.js -> login()
function login(credentials) {
console.log("In userService login function");
return axios.post('/api/login',credentials)
.then(response => {
if (response.data.success) {
console.log("Login Successful!");
let userData = {
firstname: response.data.user.firstname,
surname: response.data.user.surname,
id: response.data.user.id,
email: response.data.user.email,
auth_token: response.data.access_token,
};
let appState = {
isLoggedIn: true,
user: userData
};
localStorage.setItem("appState",JSON.stringify(appState));
return appState;
}
});
}
I think you forgot return statement userActions.js. Try this
export const login = (email,password) => {
console.log('is in action');
return dispatch => {
dispatch(request({ email }));
return userService.login(email,password)
.then(
appSate => {
return appSate;
},
error => {
console.log(error);
}
);
};
function request(user) { return { type: userConstants.LOGIN_REQUEST,user } }
}

The page is not updated after adding an item

I'm new and just started to learn react. I encountered the problem that when I add an element, I do not overload the entire list. Although the update and deletion work fine, and the changes are immediately overwritten. A new item appears in the list after the page is reloaded.
it turns out, I get a list when I mount the component and I pull it out, and when I add a new element, the state is not aware of its change. Probably you need to immediately transfer to the state what came to me with fetchNotes (). How to create it correctly, please tell me, I have already tried to play with willMount () and do all sorts of manipulations, but either I manage to fill in the state, but then I don’t work this.state.map () or any other nonsense ...
My method for adding item:
class Note extends Component {
state = {
text: "",
updateNoteId: null,
};
componentDidMount() {
this.props.fetchNotes();
};
resetForm = () => {
this.setState({text: "", updateNoteId: null});
};
selectForEdit = (id) => {
let note = this.props.notes[id];
this.setState({text: note.text, updateNoteId: id});
};
submitNote = (e) => {
e.preventDefault();
if (this.state.updateNoteId === null) {
this.props.addNote(this.state.text).then(this.resetForm);
} else {
this.props.updateNote(this.state.updateNoteId,
this.state.text).then(this.resetForm);
}
this.resetForm();
};
render() {
return (
<div>
<div style={{textAlign: "right"}}>
{this.props.user.username} (<a onClick={this.props.logout}>logout</a>)
</div>
<h3>Add new note</h3>
<form onSubmit={this.submitNote}>
<input
value={this.state.text}
placeholder="Enter note here..."
onChange={(e) => this.setState({text: e.target.value})}
required />
<input type="submit" value="Save Note" />
</form>
<button onClick={this.resetForm}>Reset</button>
<h3>Notes</h3>
<table>
<tbody>
{this.props.notes.map((note, id) => (
<tr key={`note_${id}`}>
<td>{note.text}</td>
<td><button onClick={() => this.selectForEdit(id)}>edit</button></td>
<td><button onClick={() => this.props.deleteNote(id)}>delete</button></td>
</tr>
))}
</tbody>
</table>
</div>
)
}
}
const mapStateToProps = state => {
return {
notes: state.notes,
user: state.auth.user,
}
};
const mapDispatchToProps = dispatch => {
return {
fetchNotes: () => {
dispatch(notes.fetchNotes());
},
addNote: (text) => {
return dispatch(notes.addNote(text));
},
updateNote: (id, text) => {
return dispatch(notes.updateNote(id, text));
},
deleteNote: (id) => {
dispatch(notes.deleteNote(id));
},
logout: () => dispatch(auth.logout()),
}
};
export default connect(mapStateToProps, mapDispatchToProps)(Note);
reducers/
const initialState = [];
export default function notes(state=initialState, action) {
let noteList = state.slice();
switch (action.type) {
case 'FETCH_NOTES':
return [...state, ...action.notes];
case 'ADD_NOTE':
return [...state, ...action.note];
case 'UPDATE_NOTE':
let noteToUpdate = noteList[action.index];
noteToUpdate.text = action.note.text;
noteList.splice(action.index, 1, noteToUpdate);
return noteList;
case 'DELETE_NOTE':
noteList.splice(action.index, 1);
return noteList;
default:
return state;
}
}
action
export const fetchNotes = () => {
return (dispatch, getState) => {
let headers = {"Content-Type": "application/json"};
let {token} = getState().auth;
if (token) {
headers["Authorization"] = `Token ${token}`;
}
return fetch("/api/notes/", {headers, })
.then(res => {
if (res.status < 500) {
return res.json().then(data => {
return {status: res.status, data};
})
} else {
console.log("Server Error!");
throw res;
}
})
.then(res => {
if (res.status === 200) {
return dispatch({type: 'FETCH_NOTES', notes: res.data});
} else if (res.status === 401 || res.status === 403) {
dispatch({type: "AUTHENTICATION_ERROR", data: res.data});
throw res.data;
}
})
}
};
export const addNote = text => {
return (dispatch, getState) => {
let headers = {"Content-Type": "application/json"};
let {token} = getState().auth;
if (token) {
headers["Authorization"] = `Token ${token}`;
}
let body = JSON.stringify({text, });
return fetch("/api/notes/", {headers, method: "POST", body})
.then(res => {
if (res.status < 500) {
return res.json().then(data => {
return {status: res.status, data};
})
} else {
console.log("Server Error!");
throw res;
}
})
.then(res => {
if (res.status === 201) {
return dispatch({type: 'ADD_NOTE', note: res.data});
} else if (res.status === 401 || res.status === 403) {
dispatch({type: "AUTHENTICATION_ERROR", data: res.data});
throw res.data;
}
})
}
};
I think that I should somehow call setState in order to explicitly indicate the changes, or maybe I need to re-create the request for the backend as when initializing the component?
I will be glad to any hints and help from your side. Thank you in advance!
you should change reducer ADD case as follow :
case 'ADD_NOTE':
return {
...state,
noteList:[action.note,...state.noteList]
}

Resources