i have created a asyncthunk, but when status code is 400, the result of request is still fulfilled, which method is to handle a 400 error with createasyncthunk and fetch api?
This is a action code:
import { createSlice, createAsyncThunk } from "#reduxjs/toolkit";
import authService from "./auth-service";
// Get user from localStorage
const user = JSON.parse(localStorage.getItem("user"));
const initialState = {
user: user ? user : "",
isError: false,
isSuccess: false,
isLoading: false,
message: "",
};
// Register user
export const register = createAsyncThunk(
"auth/signup",
async (user, thunkAPI) => {
try {
return await authService.register(user);
} catch (error) {
const message =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString();
return thunkAPI.rejectWithValue(message);
}
}
);
// Login user
export const login = createAsyncThunk("auth/login", async (user, thunkAPI) => {
try {
return await authService.login(user);
} catch (error) {
const message =
(error.response && error.response.data && error.response.data.message) ||
error.message ||
error.toString();
return thunkAPI.rejectWithValue(message);
}
});
export const logout = createAsyncThunk("auth/logout", async () => {
await authService.logout();
});
export const authSlice = createSlice({
name: "auth",
initialState,
reducers: {
reset: (state) => {
state.isLoading = false;
state.isSuccess = false;
state.isError = false;
state.message = "";
},
},
extraReducers: (builder) => {
builder
.addCase(register.pending, (state) => {
state.isLoading = true;
})
.addCase(register.rejected, (state, action) => {
state.isLoading = false;
state.isError = true;
state.isSuccess = false;
state.user = "";
})
.addCase(register.fulfilled, (state, action) => {
state.isLoading = false;
state.isError = false;
state.isSuccess = true;
state.message = action.payload;
})
.addCase(login.pending, (state) => {
state.isLoading = true;
})
.addCase(login.fulfilled, (state, action) => {
state.isLoading = false;
state.isSuccess = true;
state.user = action.payload;
})
.addCase(login.rejected, (state, action) => {
state.isLoading = false;
state.isError = true;
state.message = action.payload;
state.user = "";
})
.addCase(logout.fulfilled, (state) => {
state.user = "";
});
},
});
export const { reset } = authSlice.actions;
export default authSlice.reducer;
This is a service code:
import React from 'react'
import Cookies from 'js-cookie'
const API_URL = "http://localhost:5000/api/auth/";
const token = Cookies.get('XSRF-Token')
// Register user
const register = async (userData) => {
const response = await fetch(API_URL + "signup", {
method: "POST",
credentials: 'include',
headers: {
'X-CSRF-Token': token,
'Accept': "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify(userData),
});
const responseData = await response.json();
if (response.ok) {
localStorage.setItem("user", JSON.stringify(responseData));
return responseData;
}
};
// Login user
const login = async (userData) => {
const response = await fetch(API_URL + "login", {
method: "POST",
credentials: 'include',
body: JSON.stringify(userData),
headers: {
'X-CSRF-Token': token,
'Accept': "application/json",
"Content-Type": "application/json",
},
});
const responseData = await response.json();
if (response.ok) {
localStorage.setItem("user", JSON.stringify(responseData));
return responseData;
}
};
// Logout user
const logout = () => {
localStorage.removeItem("user");
};
const authService = {
register,
logout,
login,
};
export default authService;
The problem is both register and login action, return a fulfilled even if the code of post request is 400 and my intention is send a message about error
Your code doesn't do anything if response.ok is not truthy. That's what will happen when you get a 4xx status.
So, for example, in this code:
// Register user
const register = async (userData) => {
const response = await fetch(API_URL + "signup", {
method: "POST",
credentials: 'include',
headers: {
'X-CSRF-Token': token,
'Accept': "application/json",
"Content-Type": "application/json",
},
// body: JSON.stringify(userData),
});
const responseData = await response.json();
if (response.ok) {
localStorage.setItem("user", JSON.stringify(responseData));
return responseData;
}
};
You just allow the async function to have an undefined return value if response.ok is not truthy. That will resolve the promise, with an undefined resolved value.
Perhaps, you want to turn any non-2xx status into a rejection like this:
// Register user
const register = async (userData) => {
const response = await fetch(API_URL + "signup", {
method: "POST",
credentials: 'include',
headers: {
'X-CSRF-Token': token,
'Accept': "application/json",
"Content-Type": "application/json",
},
// body: JSON.stringify(userData),
});
if (response.ok) {
const responseData = await response.json();
localStorage.setItem("user", JSON.stringify(responseData));
} else {
// reject the promise
throw new Error(`status code ${response.status}`)
}
};
You would probably want to do something similar for all your uses of fetch().
Since I find that I want this to be the standard behavior when making requests, I have my own fetchWrapper() function that automatically converts any non-2xx status to a promise rejection so I don't have to code that into every use of fetch().
Here's an example of a fetchWrapper function that turns any http status that is not in the range of 200-299 into a rejected promise:
async function fetchJSON(url, options) {
let response = await fetch(url, options);
if (!response.ok) {
throw new Error(`status code ${response.status}`);
}
return response.json();
}
Related
How are messages sent slowly? I am using socket.io for sending messages but my app sending messages is working very slowly it almost takes 8-10 seconds on average to send messages how can I improve its performance? I tried using use callback but still is not sending messages fast what can i do to improve its performance?
const { otheruser } = route.params;
const [mydata, setMyData] = useState(null);
const [userid, setUserid] = useState(null);
const [roomid, setRoomid] = useState(null);
const [chat, setChat] = useState(['']);
const [currentmessage, setCurrentmessage] = useState(null);
useEffect(() => {
LoadData()
}, [])
useEffect(() => {
socket.on('receive_message', (data) => {
LoadMessages(roomid)
})
}, [socket])
const SortRoomId = (id1, id2) => {
if (id1 > id2) {
return id1 + id2
} else {
return id2 + id1
}
}
const LoadData = async () => {
try {
const value = await AsyncStorage.getItem('user');
const { token, user: { email } } = JSON.parse(value);
const res = await fetch('http://10.0.2.2:3000/userdata', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer' + token
},
body: JSON.stringify({ email })
});
const { message, user } = await res.json();
if (message === 'User Found') {
setMyData(user);
setUserid(user._id);
const ChatRoomId = await SortRoomId(otheruser[0]._id, user._id);
setRoomid(ChatRoomId);
socket.emit('joinroom', { roomid: ChatRoomId });
LoadMessages(ChatRoomId);
} else {
alert('Login Again');
navigation.navigate('Login');
}
} catch (err) {
navigation.navigate('Login');
}
};
const SendMessage = useCallback(async () => {
const MessageData = {
message: currentmessage,
RoomId: roomid,
SenderId: userid,
RecieverId: otheruser[0]._id
};
try {
const response = await fetch('http://10.0.2.2:3000/SaveMessage', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(MessageData)
});
const data = await response.json();
if (data.message === 'Message saved') {
socket.emit('sendmessage', MessageData);
LoadMessages(roomid);
console.log('message sent');
setCurrentmessage('');
} else {
alert('Network Error');
setCurrentmessage('');
}
} catch (error) {
console.error(error);
}
}, [currentmessage, roomid, userid, otheruser, socket]);
useEffect(() => {
LoadMessages(roomid)
}, [chat])
const LoadMessages = async (ChatRoomId) => {
try {
const res = await fetch('http://10.0.2.2:3000/GetMessages', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ RoomId: ChatRoomId })
});
const data = await res.json();
setChat(data);
} catch (error) {
console.error(error);
}
}
how to write a method to return async storage value in react native.
I have done login authentication using Context API.
AuthContext.js
import React, { createContext } from "react";
import { useState, useEffect } from "react";
import { Alert } from "react-native";
import AsyncStorage from '#react-native-async-storage/async-storage';
import NetInfo from "#react-native-community/netinfo";
import { BASE_URL } from "../constants/Const";
export const AuthContext = createContext();
export const AuthProvider = ({ children }) => {
// loading & usertoken hooks
const [isLoading, setIsLoading] = useState(false);
const [userToken, setuserToken] = useState(null);
//login method
const login = async (email, password) => {
setIsLoading(true);
//fetch method to get access token
fetch(`${BASE_URL}/sign_in`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: email,
password: password,
})
})
.then((res) => res.json())
.then((json) => {
//console.log("login auth ", json)
if (json.responseCode == 200) {
try {
setuserToken(json.responseData.access_token);
//storing usertoken value in react-native encrypted storage
AsyncStorage.setItem("userToken", json.responseData.access_token)
//console.log("user token",userToken);
}
catch (error) {
console.log("Error while saving user token data", userToken);
}
}
//showing invalid email & password alert messaqge
else {
Alert.alert('Invalid email or password.');
return;
}
})
.catch((error) => {
console.error(error);
});
setIsLoading(false);
}
//logout method
const logout = async () => {
setIsLoading(true);
//setting user token as null
setuserToken(null);
try {
//removing usertoken value in react-native encrypted storage
await AsyncStorage.removeItem("userToken");
} catch (error) {
// There was an error on the native side
console.log("Error while removing data", error);
}
setIsLoading(false);
}
// checking user is already logged in each time when app starts
const isLoggenIn = async () => {
try {
setIsLoading(true);
//let userToken = await EncryptedStorage.getItem("userToken");
let userToken = await AsyncStorage.getItem("userToken");
//console.log("accesed user token",userToken);
setuserToken(userToken);
setIsLoading(false);
} catch (error) {
console.log("Error retrieving data", error);
}
}
const [connected, setConnected] = useState(true);
useEffect(() => {
isLoggenIn();
// Subscribe
const unsubscribe = NetInfo.addEventListener(state => {
// console.log("Connection type", state.type);
// console.log("Is connected?", state.isConnected);
setConnected(state.isConnected);
});
//clean up function
return () => unsubscribe();
}, [])
return (
<AuthContext.Provider value={{ login, logout, isLoading, userToken ,connected,}}>
{children}
</AuthContext.Provider>
)
}
in Redux slice file I want access token values to make a fetch request to a server.i defined getAccessToken Method to return accessToken value but it is not returning value
DataSlice.js
import { createSlice, createAsyncThunk } from '#reduxjs/toolkit'
import { useState } from 'react';
import { Alert } from 'react-native';
import { BASE_URL } from '../constants/Const';
import AsyncStorage from '#react-native-async-storage/async-storage';
//const accessToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiNjM2YTFlNTc4YWNlNTRjM2E5OWE4YWI2IiwiZW1haWwiOiJhZG1pbkBnbWFpbC5jb20iLCJpYXQiOjE2Njg0MDY2MzgsImV4cCI6MTY2ODQ2MDYzOH0.i_GHy2K91I0_159AIpQ4m2eFUmyXYFmF3_0sQ-o_x-w";
//user token function
const getAcessToken = async () => {
const token = await AsyncStorage.getItem('userToken');
return token;
}
var userToken = getAcessToken();
// get and delete method request options
const getDeleteRequestOptions = (methodType) => {
return {
method: methodType,
headers: {
'Content-Type': 'application/json',
'autherization': userToken
}
}
}
// save and edit method request options
const saveEditRequestOptions = (methodType, data) => {
console.log("img uri",data.imgUri)
const imgData = new FormData();
imgData.append('first_name', data.firstName);
imgData.append('last_name', data.lastName);
imgData.append('phone', data.phoneNo);
imgData.append('email', data.email);
imgData.append('image', { uri: data.imgUri, name: 'image', type: 'image/jpg' });
return {
method: methodType,
headers: {
'Content-Type': 'multipart/form-data',
'autherization': userToken
},
body: imgData
}
};
// fetch data
export const getData = createAsyncThunk('fetch', async ({pageNo,limit}) => {
return fetch(`${BASE_URL}/list_profile?page_number=${pageNo}&limit=${limit}`, getDeleteRequestOptions('GET'))
.then((response) => response.json())
.then((json) => {
//returning json receive array
if(pageNo === 0 && limit === 0){
return {data:json.receive,fetchAllData:true};
}
return {data:json.receive,fetchAllData:false};
})
.catch((error) => {
console.error(error);
});
});
// delete data
export const deleteData = createAsyncThunk('delete', async ({id}) => {
return fetch(`${BASE_URL}/delete_profile/${id}`, getDeleteRequestOptions('DELETE',userToken))
.then((res) => res.json())
.catch((error) => {
console.error(error);
});
});
// save data
export const saveData = createAsyncThunk('save', async (data) => {
return fetch(`${BASE_URL}/add_profile`, saveEditRequestOptions('POST', data))
.then((res) => res.json())
.then((json) => {
if (json.responseCode === 211) {
Alert.alert('Input Error', json.responseMessage, [
{ text: "OK" }
])
return;
}
console.log("save responese message ", json.responseMessage);
})
.catch((error) => {
console.error(error);
});
});
// edit data
export const editData = createAsyncThunk('edit', async (data) => {
return fetch(`${BASE_URL}/update_profile/${data.id}`, saveEditRequestOptions('PUT', data))
.then((res) => res.json())
.then((json) => {
console.log("edit data response message ", json.responseMessage);
})
.catch((error) => {
console.error(error);
});
});
const initialState = {
masterData: [],
filteredData: [], //array to implement search
allData:[],
imgurl: '',
};
export const dataSlice = createSlice({
name: 'crud',
initialState,
reducers: {
filterData: (state, action) => {
state.filteredData = action.payload;
},
selectedImage: (state, action) => {
state.imgurl = action.payload;
},
},
extraReducers: {
// get data
[getData.pending]: (state, action) => {
console.log('fetching data is pending');
},
[getData.fulfilled]: (state, action) => {
console.log('data fetched successfully')
if (!action.payload) {
Alert.alert('Network error', 'Data Fetching is Failded Please try Again later.', [
{ text: "OK" }
])
return;
}
console.log(action.payload.fetchAllData)
if(action.payload.fetchAllData){
//console.log("inside fetch all data")
state.allData = action.payload.data;
}
state.masterData = action.payload.data;
state.filteredData = action.payload.data;
},
[getData.rejected]: (state, action) => {
console.log('fetching request rejected');
},
// delete data
[deleteData.pending]: (state, action) => {
console.log('delete data is pending');
},
[deleteData.fulfilled]: (state, action) => {
console.log('data deleted successfully');
},
[deleteData.rejected]: (state, action) => {
console.log('data delete request rejected');
Alert.alert('Delete Data Failure', 'Deleting Data Failed. Please try Again later.', [
{ text: "OK" }
])
},
// save data
[saveData.pending]: (state, action) => {
console.log('saving data is pending');
},
[saveData.fulfilled]: (state, action) => {
console.log('data saved successfully');
},
[saveData.rejected]: (state, action) => {
console.log('data save request rejected');
Alert.alert('Data Save Failure', 'Data Save Failed. Please try Again later.', [
{ text: "OK" }
])
},
//edit data
[editData.pending]: (state, action) => {
console.log('edit data is pending');
},
[editData.fulfilled]: (state, action) => {
console.log('data edited successfully');
},
[editData.rejected]: (state, action) => {
console.log('edit data request rejected');
Alert.alert('Data Edit Failure', 'Edit data Failed. Please try Again later.', [
{ text: "OK" }
])
},
},
})
// Action creators are generated for each case reducer function
export const { filterData, selectedImage } = dataSlice.actions;
export default dataSlice.reducer
i want to get access token values
The reason is that you are not calling getAccessToken() with await like this:
var userToken = await getAcessToken();
since it is asynchronous function.
I am trying to use js-cookie to store access_token as cookies in the cookie strorage. But whenever I set the cookie, it gets displayed like this: %22eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjU5NDIzOTA3LCJpYXQiOjE2NTg1NTk5MDcsImp0aSI6IjAyMmRlMTg2MTk0NzRhYzY5ZThjOTVmOGNhZDE3OTM4IiwidXNlcl9pZCI6Mn0.xkOTI4uO93_YIvlGrcnnKLFjbLZiM_RdNo9J9A8Clk4%22
But I dont want it that way. I weant to get the token without "%22" at the beginning and end.
This is my code. Thank you.
import {createContext, useState, useEffect} from 'react'
import Cookie from "js-cookie";
import jwt_decode from "jwt-decode"
import {useHistory} from 'react-router-dom'
const SetCookie = (cookiename, cookie) => {
Cookie.set(cookiename, cookie)
}
const GetCookie = (cookiename) => {
return Cookie.get(cookiename)
}
const AuthContext = createContext()
export default AuthContext
export const AuthProvider = ({children}) => {
let [authTokens, setAuthTokens] = useState(localStorage.getItem('authTokens') ? JSON.parse(localStorage.getItem('authTokens')):null)
let [user, setUser] = useState(localStorage.getItem('authTokens') ? JSON.parse(localStorage.getItem('authTokens')):null)
const histroy = useHistory()
histroy.push('/')
let loginUser = async (e)=> {
e.preventDefault()
let response = await fetch('http://127.0.0.1:8000/users/login/', {
method: "POST",
credentials: "include",
headers: {
"Content-Type": "application/json",
},
body:JSON.stringify({'email':e.target.email.value, 'password':e.target.password.value})
})
let data = await response.json()
console.log('response:', response)
if (response.status === 200) {
setAuthTokens(data)
setUser(data)
SetCookie('cookie', JSON.stringify(data.access_token))
localStorage.setItem('authTokens', JSON.stringify(data))
} else{
alert('there was problem signing in')
}
}
let registerUser = async (e)=> {
e.preventDefault()
let response = await fetch('http://127.0.0.1:8000/users/register/', {
method: 'POST',
headers:{
'Content-Type':'application/json'
},
body:JSON.stringify({'username':e.target.username.value, 'email':e.target.email.value, 'password1':e.target.password1.value, 'password2':e.target.password2.value})
})
let data = await response.json()
console.log('response:', response)
if (response.status === 201) {
alert('An email verification message has been sent to your email address')
} else{
alert('Something went wrong! Check your credentials and try again')
}
}
let passwordReset = async (e)=> {
e.preventDefault()
let response = await fetch('http://127.0.0.1:8000/password-reset/', {
method: 'POST',
headers:{
'Content-Type':'application/json'
},
body:JSON.stringify({'email':e.target.email.value})
})
let data = await response.json()
console.log('response:', response)
}
let passwordresetConfirm = async (e)=> {
e.preventDefault()
let response = await fetch('http://127.0.0.1:8000/password-reset-confirm/', {
method: 'POST',
headers:{
'Content-Type':'application/json'
},
body:JSON.stringify({'new_password1':e.target.new_password1.value, 'new_password2':e.target.new_password2.value,})
})
let data = await response.json()
console.log('response:', response)
}
let logoutUser = () => {
setAuthTokens(null)
setUser(null)
localStorage.removeItem('authTokens')
histroy.push('/login')
}
let contextData = {
user:user,
loginUser : loginUser,
logoutUser : logoutUser,
registerUser : registerUser,
passwordReset : passwordReset,
passwordresetConfirm : passwordresetConfirm,
}
return(
<AuthContext.Provider value={contextData}>
{children}
</AuthContext.Provider>
)
}
Hi all I'm new to authentication. I was building an app where a user can login and create a story using an api, and the story is sent to the backend using a POST request. The app was authenticating fine, until I built the app. Now when I sign in and try to add a story, I get 401 Unauthorized and SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data in actions.js.
Then if I refresh the page, the errors go away and the app is working.
I am able to logout and login again normally.
I have no idea why that's happening. Any help will be appreciated.
The backend server does say Error in authorization JsonWebTokenError: jwt malformed
actions.js
import * as t from './actionTypes';
import { setUserSession } from '../utils/Common';
import { getToken } from '../utils/Common'
const token = getToken();
// this is what our action should look like which dispatches the "payload" to reducer
const setLoginState = (loginData) => {
return {
type: t.SET_LOGIN_STATE,
payload: loginData, //{ ...json, userId: email }
};
};
const setStoryState = (storyData) => {
return {
type: t.CREATE_STORY,
payload: storyData, //storyData is the object with summary, description, type, etc.
};
};
const getStoryState = (storyData) => {
return {
type: t.GET_STORIES,
payload: storyData, //storyData is the object with summary, description, type, etc.
};
};
const getSingleStoryState = (storyData) => {
return {
type: t.GET_STORY,
payload: storyData, //storyData is the object with summary, description, type, etc.
};
};
export const login = (loginInput) => { //our login action
const { email, password, isAdmin } = loginInput;
return (dispatch) => { // don't forget to use dispatch here!
return fetch('http://localhost:3000/api/v1/signin', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(loginInput),
})
.then((response) => response.json()) //json will be the response body
.then((json) => {
// if (json.msg === 'success') { // response success checking logic could differ
// console.log(json)
dispatch(setLoginState({ ...json, userId: email, isAdmin: isAdmin })); // our action is called here with object as parameter, this is our payload
//we appended json object to our state
// } else {
// alert('Login Failed', 'Email or Password is incorrect');
// }
setUserSession(json.token, json.lastName)
})
.catch((err) => {
alert('Login Failed', 'Some error occured, please retry');
console.log(err);
});
};
};
export const getStories = () => {
return (dispatch) => { // don't forget to use dispatch here!
return fetch('http://localhost:3000/api/v1/stories', {
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
})
.then((response) => response.json()) //json will be the response body
.then((json) => {
// if (json.msg === 'success') { // response success checking logic could differ
console.log(json)
dispatch(getStoryState( [...json ])); // our action is called here with object as parameter, this is our payload
//we appended json object to our state
// } else {
// alert('Login Failed', 'Email or Password is incorrect');
// }
})
.catch((err) => {
alert('Login Failed', 'Some error occured, please retry');
console.log(err);
});
};
}
export const viewStory = id => {
return (dispatch) => { // don't forget to use dispatch here!
return fetch(`http://localhost:3000/api/v1/stories/${id}`, {
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
})
.then((response) => response.json()) //json will be the response body
.then((json) => {
// if (json.msg === 'success') { // response success checking logic could differ
console.log(json)
dispatch(getSingleStoryState( {...json } )); // our action is called here with object as parameter, this is our payload
//we appended json object to our state
// } else {
// alert('Login Failed', 'Email or Password is incorrect');
// }
})
.catch((err) => {
alert('Login Failed', 'Some error occured, please retry');
console.log(err);
});
};
}
export const roleChange = () => {
return {
type: t.SET_ROLE_STATE,
//payload: role
};
}
export const logout = () => {
return {
type: t.LOGOUT,
};
}
export const createStory = storyInput => {
console.log(token)
const { summary, description, type, complexity, time, cost } = storyInput;
return (dispatch) => { // don't forget to use dispatch here!
return fetch('http://localhost:3000/api/v1/stories', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`,
},
body: JSON.stringify(storyInput),
})
.then((response) => response.json()) //json will be the response body
.then((json) => {
// if (json.msg === 'success') { // response success checking logic could differ
console.log(json)
//dispatch(setStoryState( [...json ]));
dispatch(setStoryState({ // our action is called here with object as parameter, this is our payload
summary: summary,
description: description,
type: type,
complexity: complexity,
time: time,
cost: cost
})); // our action is called here
// } else {
// alert('Login Failed', 'Email or Password is incorrect');
// }
})
.catch((err) => {
alert('Some error occured, please retry');
console.log(err);
});
};
}
export const addStory = story => {
return {
type: t.ADD_STORY,
payload: story,
}
}
export const setStatus = (id, status) => {
return (dispatch) => { // don't forget to use dispatch here!
return fetch(`http://localhost:3000/api/v1/stories/${id}/${status}`, {
method: 'PUT',
headers: {
Accept: 'application/json',
'Content-Type': 'text/html',
'Authorization': `Bearer ${token}`
},
})
.then((response) => response.json()) //json will be the response body
.then((json) => {
// if (json.msg === 'success') { // response success checking logic could differ
console.log(json)
// dispatch(getStoryState( {...json } )); // our action is called here with object as parameter, this is our payload
//we appended json object to our state
// } else {
// alert('Login Failed', 'Email or Password is incorrect');
// }
})
.catch((err) => {
alert('Login Failed', 'Some error occured, please retry');
console.log(err);
});
};
}
CreateStory.js
import React, { useState } from 'react'
import { createStory } from '../redux/actions'
import { useDispatch, useSelector } from "react-redux";
import history from '../utils/history';
import { withRouter } from 'react-router-dom';
const CreateStory = () => {
const [summary, setSummary] = useState("");
const [description, setDescription] = useState("");
const [type, setType] = useState("");
const [complexity, setcomplexity] = useState("");
const [time, setTime] = useState("");
const [cost, setCost] = useState(0);
const usedispatch = useDispatch();
const userCreateStory = (summary, description, type, complexity) => usedispatch(createStory({
'summary': summary,
'description': description,
'type': type,
'complexity': complexity,
'time': time,
'cost': cost
}));
const handleSummaryChange = e => {
setSummary(e.target.value)
}
const handleDescriptionChange = e => {
setDescription(e.target.value)
}
const handleTypeChange = e => {
setType(e.target.value)
}
const handleComplexityChange = e => {
setcomplexity(e.target.value)
}
const handleTimeChange = e => {
setTime(e.target.value)
}
const handleCostChange = e => {
setCost(e.target.value)
}
// const currStory = useSelector((state)=> state.storyReducer.story)
const handleSubmit = e => {
e.preventDefault();
userCreateStory(summary,description,type,complexity,time,cost)
setTimeout(()=> history.push("/userStories"), 1000 );
//setTimeout(()=> console.log(currStory) ,1000)
}
return (
<div>
<form className='create-story-form'>
<label for="summary">Summary:</label>
<input name="summary" type='text' onChange={handleSummaryChange}/>
<label for="desc">Description:</label>
<textarea name="desc" type='text' onChange={handleDescriptionChange}/>
<label for="type">Type:</label>
<select name="type" onChange={handleTypeChange}>
<option value="enhancement" defaultValue>Enchancement</option>
<option value="bugfix">Bugfix</option>
<option value="development">Development</option>
<option value="qa">QA</option>
</select>
<label for="complexity">Complexity:</label>
<select name="complexity" onChange={handleComplexityChange}>
<option value="low" defaultValue>Low</option>
<option value="mid">Mid</option>
<option value="high">High</option>
</select>
<label for="time">Estimated time for completion:</label>
<input name="time" type='text' onChange={handleTimeChange}/>
<label for="cost">Cost:</label>
<input name="cost" type='number' onChange={handleCostChange}/>
<button onClick={handleSubmit}>Submit</button>
</form>
</div>
)
}
export default withRouter(CreateStory);
Login.js
import React, { useState } from "react";
import { useDispatch } from "react-redux";
import { login, roleChange } from '../redux/actions' //OUR ACTIONS
import { useSelector } from 'react-redux'
import history from '../utils/history';
import { withRouter } from 'react-router-dom';
const Login = () => {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [isAdmin, setIsAdmin] = useState(false);
const usedispatch = useDispatch();
const userLogin = (email, password, isAdmin) => usedispatch(login({'email': email, 'password': password, 'isAdmin': isAdmin }));
const handleRoleChange = e => {
setIsAdmin(true)
if(isAdmin)
setIsAdmin(false)
console.log(isAdmin)
}
const handleEmailChange = e => {
setEmail(e.target.value)
}
const handlePasswordChange = e => {
setPassword(e.target.value)
}
const handleSubmit = e => {
e.preventDefault();
userLogin(email, password, isAdmin)
setTimeout(()=> history.push("/user"), 1000 );
}
const disabled = () => {
return email === "" || password === ""
}
return (
<div>
<form className='login-form'>
<input type='email' name='email' placeholder='Email' onChange={handleEmailChange}/>
<input type='password' name='password' placeholder='Password' onChange={handlePasswordChange}/>
<button type='submit' disabled={disabled()} onClick={handleSubmit}>Login</button>
</form>
<button onClick={handleRoleChange}>Switch to {isAdmin ? 'user' : 'admin'}</button>
</div>
)
}
export default withRouter(Login);
reducers.js
import { initialState } from './initialState';
import * as t from './actionTypes';
export const loginReducer = (state = initialState, action) => {
switch (action.type) {
case t.SET_ROLE_STATE:
return {
...state,
isAdmin: true
};
case t.SET_LOGIN_STATE:
return {
...state,
...action.payload, // this is what we expect to get back from API call and login page input
isLoggedIn: true, // we set this as true on login
};
case t.LOGOUT:
return {
initialState
};
default:
return state;
}
};
export const storyReducer = (state = [], action) => {
switch (action.type) {
case t.CREATE_STORY:
return {
...state,
stories: [...state.stories, action.payload],
};
case t.GET_STORIES:
return {
...state,
stories: action.payload,
};
case t.GET_STORY:
return {
...state,
story: action.payload,
};
// case t.ADD_STORY:
// return {
// ...state,
// stories: [...state.stories, action.payload], //stories is an object
// };
case t.LOGOUT:
return {
stories: [{complexity: "",
cost: 0,
description: "",
summary: "",
time: "",
type: ""}]
};
default:
return state;
}
}
I'm trying to send an response to the api on submit but the problem I'm having is that when ever i hit submit button my paymentMethod parameter is somehow not going through in the api. below I'm posting my submit button and my action. other than that I'm also getting this error.
submit
submitPaypal = () => {
const { frequencyPaypal, paymentMethod } = this.state;
this.setState({
paymentMethod: "Paypal",
});
this.props.setPaymentOption({
frequencyPaypal,
paymentMethod,
});
};
Action/payment.js
export const setPaymentOption = (userdata) => {
return async (dispatch) => {
dispatch(fullScreenLoader(true));
let token = await getToken();
const api = new Axios();
const response = await api.post(
SET_PAYMENT_OPTION,
{
paymentOption: userdata.paymentOption,
paypalPaymentOption: userdata.paypalPaymentOption,
trustlyPaymentOption: userdata.trustlyPaymentOption,
payoutReferenceId: userdata.payoutReferenceId,
varation_id: userdata.varation_id,
},
{
Authorization: `Bearer ${token}`,
},
API_URL2
);
const { data } = response;
console.log(userdata)
dispatch(fullScreenLoader(false));
dispatch({
type: SET_PAYMENT,
payload: data,
});
};
};
reducer
case SET_PAYMENT:
return {
...state,
paymentGateway: action.payload,
};
map state to props
const mapStateToProps = (data) => ({
webSercvices: data.payments.webServices,
paymentGate: data.payments.paymentGateway,
payByPaypal: data.payments.payByPaypal,
user: data.authenticateUser.user,
isAuthenticated: data.authUser,
});
const mapDispatchToProps = (dispatch) =>
bindActionCreators(
{
getPaymentWebServiceApi,
alertPopUp,
setPaymentOption,
savePaypal,
authenticateUser,
},
dispatch
);
ISSUE
on submit you are sending frequencyPaypal and paymentMethod in setPaymentOption action and there you are accessing many properties which is undefined there like paymentOption and more...
SUGGESTION
In (Action/payment.js)
const response = await api.post(
SET_PAYMENT_OPTION,
{
paymentOption: userdata.paymentOption, // this is undefined
paymentOption: userdata.frequencyPaypal, // this is valid
paymentOption: userdata.paymentMethod, // this is valid
paypalPaymentOption: userdata.paypalPaymentOption, // this is undefined
trustlyPaymentOption: userdata.trustlyPaymentOption, // this is undefined
payoutReferenceId: userdata.payoutReferenceId, // this is undefined
varation_id: userdata.varation_id, // this is undefined
},
{
Authorization: `Bearer ${token}`,
},
API_URL2
);