React Redux problem on dispatching on button - javascript

I have a button that dispatches an action to create a post, for some reason the request never proceeds and it fails. This is the action. I have constants that's why types is not on a string
export const createPost = () => async (dispatch, getState) => {
try {
dispatch({
type: POST_CREATE_REQUEST,
});
const {
userLogin: { userInfo },
} = getState();
const config = {
headers: {
Authorization: `Bearer ${userInfo.token}`,
},
};
const { data } = await axios.post(
`http://localhost:5000/api/posts`,
config
);
dispatch({
type: POST_CREATE_SUCCESS,
payload: data,
});
} catch (error) {
const message =
error.response && error.response.data.message
? error.response.data.message
: error.message;
// if (message === 'Not authorized, token failed') {
// dispatch(logout());
// }
dispatch({
type: POST_CREATE_FAIL,
payload: message,
});
}
};
It continues to the POST_CREATE_REQUEST but always errors out to the POST_CREATE_FAIL.
I tried using postman and it works fine, I think the problem is the createPost action can't seem to receive the token even though im logged in as an admin, I'm not sure.
This is the useSelector of the postCreate
const postCreate = useSelector(state => state.postCreate);
const {
loading: loadingCreate,
error: errorCreate,
success: successCreate,
post: createdPost,
} = postCreate;
and this is the useSelector of the user that is logged in, currently as an admin.
const userLogin = useSelector(state => state.userLogin);
const { userInfo } = userLogin;

Rewrite this code
const { data } = await axios.post(
`http://localhost:5000/api/posts`,
config
);
as
const res = await axios.post(
`http://localhost:5000/api/posts`,
config
);
const data = res && res.data

There is already values on my Controller at the backend and just needed to add brackets in the action
from this
const { data } = await axios.post(
`http://localhost:5000/api/posts`,
config
);
to this
const { data } = await axios.post(
`http://localhost:5000/api/posts`, {},
config
);

Related

"Error: Error serializing .customerId returned from getServerSideProps in "/pricing"

I keep trying to call an api from my getServerSideProps function in my Next.js application, but everytime I try to do so I get this error
"Error: Error serializing .customerId returned from getServerSideProps in "/pricing".
Reason: undefined cannot be serialized as JSON. Please use null or omit this value."
This is the code for the Pricing page
const Pricing = ({customerId}) => {
console.log(customerId, 'Customerid Pricing')
return(
<div>
<ProductDisplay customerId={customerId}/>
</div>
)
}
export const getServerSideProps = async (ctx) => {
//create customer variable
let customerId
// Create authenticated Supabase Client
const supabase = createServerSupabaseClient(ctx)
// get the user session from supabase
const { data: { session }, } = await supabase.auth.getSession()
//get the user email from the session
const email = session.user.email
//create stripe customer
const createCustomer = async () => {
let createdCustomer;
let customerAvailable;
try {
const checkCustomer = await stripe.customers.search({
query: `email: '${email}'`
})
createdCustomer = JSON.parse(JSON.stringify(checkCustomer))
customerAvailable = createdCustomer.data
} catch (error) {
console.log(error)
}
if (customerAvailable.length) {
customerId = createdCustomer.data[0].id
} else {
try {
const res = await fetch('/api/create-customer', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email
})
})
const newCustomer = await res.json();
customerId = newCustomer.customer.id
} catch (error) {
console.log(error)
}
}
}
if (session) {
createCustomer()
} else {
return{
redirect: {
destination: '/signin',
permanent: false,
}
}
}
return {
props: {
customerId
},
}
}
export default Pricing;
This is the /api/create-customer the fetch function is trying to call
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY)
const handler = async (req, res) => {
const {email} = req.body
try {
const customer = await stripe.customers.create({
email: email
});
res.status(200).json({
code: 'customer_created',
customer,
})
} catch (error) {
console.log(error);
res.status(400).json({
code: 'customer_creation_failed',
error: error
})
}
};
export default handler;
please help me, thank you very much.

How can I use axios.defaults.baseURL conditionally? [duplicate]

I am having a config file . where i am setting the baseURL for the entire app and also saving the bearer token for the entire API requests. Here i am in situation to add another api . I dont know how to add another baseURL & use this on my API requests.Here i am sharing the code of what i have done.
BASE URL FILE:
import axios from 'axios';
axios.defaults.baseURL = http://localhost:3000/summary;
const setAuthToken = (token) => {
if (token) {
axios.defaults.headers.common.Authorization = `Bearer ${token}`;
} else {
delete axios.defaults.headers.common.Authorization;
}
};
export default setAuthToken;
API ACTION FILE:
export const login = ({ email, password }) => async (dispatch) => {
const userData = {
username: email,
password,
};
try {
const res = await axios.post('/license-api/auth/login', userData, config);
dispatch({
type: LOGIN_SUCCESS,
payload: res.data.token,
});
} catch (error) {
dispatch({
type: LOGIN_FAIL,
});
}
};
i need to add another url like this in BASE URL FILE
axios.defaults.baseURL = http://localhost:6000/profile
how to add this one and use this in API action file.
Please help me with this.
Thanks in advance
As said you could create two instances of axios and use them as needed:
In you BASE URL file:
import axios from 'axios';
const setAuthToken = (token) => {
if (token) {
axios.defaults.headers.common.Authorization = `Bearer ${token}`;
} else {
delete axios.defaults.headers.common.Authorization;
}
};
const mainAxios = axios.create({
baseURL: 'http://localhost:3000/summary'
});
const profileAxios = axios.create({
baseURL: 'http://localhost:6000/profile'
});
export default setAuthToken;
export { mainAxios, profileAxios };
Then in your API ACTION file:
import { profileAxios } from 'path/to/baseurl';
export const login = ({ email, password }) => async (dispatch) => {
const userData = {
username: email,
password,
};
try {
const res = await profileAxios.post('/license-api/auth/login', userData, config);
dispatch({
type: LOGIN_SUCCESS,
payload: res.data.token,
});
} catch (error) {
dispatch({
type: LOGIN_FAIL,
});
}
};
The above code works well. I don't see where setAuthToken is called so if you don't want to call setAuthToken manually then you might want to do this.
import axios from "axios";
import { config } from "./config";
const pythonAPI = axios.create({
baseURL: config.pythonServerUrl,
});
const nodeApi = axios.create({
baseURL: config.nodeServerUrl,
});
const setToken = () => {
const token = localStorage.getItem("auth_token");
if (token) {
pythonAPI.defaults.headers.common.Authorization = `Basic ${token}`;
} else {
delete pythonAPI.defaults.headers.common.Authorization;
}
};
const pythonApi = {};
pythonApi.get = async (url) => {
setToken();
return pythonAPI.get(url).catch((e) => e.response);
};
pythonApi.post = async (url, data) => {
setToken();
return pythonAPI.post(url, data).catch((e) => e.response);
};
export { pythonApi, nodeApi };

Deleting a user is returning nothing in the backend

I'm trying to delete an user, but the req.body in the backend is an empty object.
In the backend I have the following code:
const deleteUser = async (req, res) => {
console.log(req.body);
console.log(req.config);
const user = await User.findById(req.body.userId);
if (user) {
const deleteUser = await user.remove();
res.send({ message: "User Deleted", user: deleteUser });
} else {
res.status(404).send({ message: "User Not Found" });
}
};
Here the console log is an empty object, I must that the other functions work perfectly.
In the frontend, I'm using redux, I think I'm doing something wrong in the actions, but I can't find out what, I will post all my code for reference.
action.js:
export const deleteUser = (userId) => async (dispatch, getState) => {
dispatch({ type: USER_DELETE_REQUEST, payload: userId });
try {
const { data } = await Axios.delete(
"http://localhost:3030/v1/user/userProfile/deleteUser",
{
userId: userId,
}
);
dispatch({ type: USER_DELETE_SUCCESS, payload: data });
} catch (error) {
const message =
error.response && error.response.data.message
? error.response.data.message
: error.message;
dispatch({ type: USER_DELETE_FAIL, payload: message });
}
};
In the reducer:
export const userDeleteReducer = (state = {}, action) => {
switch (action.type) {
case USER_DELETE_REQUEST:
return { loading: true };
case USER_DELETE_SUCCESS:
return { loading: false, success: true };
case USER_DELETE_FAIL:
return { loading: false, error: action.payload };
default:
return state;
}
};
And I'm calling the action like that:
const userSignin = useSelector((state) => state.userSignin);
const { userInfo, loading, error } = userSignin;
<button
onClick={() => {
console.log(userInfo._id);
dispatch(deleteUser(userInfo._id));
props.onClose();
}}
className='deleteAccountModalButton'
>
Delete account!
</button>
I tried everything, but I can't find where the problem, can somebody tell me why the req.body is empty in the backend?
EDIT:
I managed to make it work by modifying the order of parameters in actions:
export const deleteUser = (userId) => async (dispatch, getState) => {
dispatch({ type: USER_DELETE_REQUEST, payload: userId });
const {
userSignin: { userInfo },
} = getState();
try {
const { data } = await Axios.delete(
"http://localhost:3030/v1/user/userProfile/deleteUser",
{
data: {
headers: { Authorization: `Bearer ${userInfo.token}` },
userId,
},
}
);
dispatch({ type: USER_DELETE_SUCCESS, payload: data });
} catch (error) {
const message =
error.response && error.response.data.message
? error.response.data.message
: error.message;
dispatch({ type: USER_DELETE_FAIL, payload: message });
}
};
I will leave this here in case somebody else will have this problem.

Nodejs MongoDB - add new entry Post()

so trying to post new entry into MongoDB. but getting this error in Redux Product validation failed: name: Path 'name' is required., description: Path 'description' is required.
nodejs version: 14.9.0
and Atlas mongodb.
frontEnd addProduct.js page:
import { createProduct } from '../redux/actions/productActions'
const [name, setName] = useState('')
const [description, setDescription] = useState('')
const createProductHandler = (e) => {
e.preventDefault()
dispatch(createProduct({
name,
description
}))
}
const nameHandler = (e) => {
setName(e.target.value)
}
const descriptionHandler = (e) => {
setDescription(e.target.value)
}
return (
<input type='text' onChange={nameHandler} />
<input type='text' onChange={descriptionHandler} />
<input type="submit" value='submit' onClick={createProductHandler} />
)
productController:
const createdProduct = asyncHandler(async (req, res) => {
const mongoProduct = async (data) => {
return new Product({
name: data.name,
description: data.description
})
}
const product = await mongoProduct(req.body)
const createdProduct = await product.save()
res.status(201).json(createdProduct)
})
productActions:
export const createProduct = () => async (dispatch, getState) => {
try {
dispatch({
type: 'PRODUCT_CREATE_REQUEST',
})
const {
userLogin: {userInfo},
} = getState()
const config = {
headers: {
Authorization: `Bearer ${userInfo.token}`,
},
}
const { data } = await axios.post(`/api/products`, {}, config)
dispatch({
type: 'PRODUCT_CREATE_SUCCESS',
payload: data
})
} catch (error) {
dispatch({
type: 'PRODUCT_CREATE_FAIL',
payload:
error.response && error.response.data.message
? error.response.data.message
: error.meessage,
})
}
}
productReducers.js:
export const productCreateReducer = (state = {}, action) => {
switch (action.type) {
case 'PRODUCT_CREATE_REQUEST':
return {loading: true}
case 'PRODUCT_CREATE_SUCCESS':
return {loading: false, success: true, product: action.payload}
case 'PRODUCT_CREATE_FAIL':
return {loading: false, error: action.payload}
default:
return state
}
}
alternatively when i try to populate the database from post-man using this code in productController.js it works fine with sample data:
const createdProduct = asyncHandler(async (req, res) => {
const product = new Product({
name: 'Sample Name',
description: 'Sample Description'
})
const createdProduct = await product.save()
res.status(201).json(createdProduct)
})
plus im getting POST ipadress/api/products 500 (Internal Server Error) in console
You can config your axios api service config to separate file and use axios
const request = axios.create({
// baseURL: 'https://mock-api.com',
baseURL: BASE_URL ,
timeout: 5000
})
request.interceptors.request.use(
config => {
// get token
if (// check your token) {
config.headers["Authorization"] = "Bearer ${your-token}"
}
return config
},
error => {
// Do something with request error
console.log(error) // for debug
Promise.reject(error)
}
)
// Can also config axios response interceptors to handle API error
Your redux action
import axiosInstance from './your-axios-config-path'
export const createProduct = (product) => async (dispatch, _getState) => {
try {
dispatch({ type: 'PRODUCT_CREATE_REQUEST' })
const response = await axiosInstance.post(`/api/products`, {...product})
dispatch({
type: 'PRODUCT_CREATE_SUCCESS',
payload: response?.data ?? {}
})
} catch (error) {
dispatch({
type: 'PRODUCT_CREATE_FAIL',
payload: // error message,
})
}
}
Alternatively, you can use Redux Toolkit, It much easier to setup store and using. It includes createAsyncThunk, RTK Query to handle side effect.

How to set response of an api on submit using redux in react js.?

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
);

Categories

Resources