createAysncThunk in Redux Toolkit catching error when making fetch request - redux-thunk

I'm working on the user registration functionality of an application using Typescript and Redux Toolkit. When I make the fetch request to the signup endpoint, a new user is saved to the database I've connected, but I keep entering the catch error block.
export const registerUser = createAsyncThunk(
"user/registerUser",
async (form: { username:string, password:string }, thunkAPI) => {
try {
const response = await fetch('/api/auth/signup', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
userInfo: {
username: form.username,
password: form.password
}
}),
});
if (response.status === 200) return 200;
else return 400;
} catch (e) {
console.log('Error')
}
}
);
I've tried logging the response to the console a number of ways
const data = await response.json() console.log(data)
But have had no luck. I think this is an error with how I've done my fetch request using createAsyncThunk but haven't been able to figure out what I've missed.
This is the code for the initial state and slice:
interface UserState {
userProfile: {
id: number | null;
},
registration: {
status: 'loaded' | 'loading'
}
}
const initialState : UserState = {
userProfile: {
id: null,
},
registration: {
status: 'loaded'
}
};
export const userSlice = createSlice({
name: 'user',
initialState,
reducers: {
},
extraReducers: (builder) => {
builder.addCase(registerUser.fulfilled, (state) => { state.registration.status = 'loaded' }),
builder.addCase(registerUser.rejected, (state) => { state.registration.status = 'loaded' }),
builder.addCase(registerUser.pending, (state) => { state.registration.status = 'loading' })
}
})
And here is the code for the function where the action is dispatched on the UI
const handleRegister= async () => {
if (!username) return alert('Username field was left empty');
if (!password) return alert('Password field was left empty');
const {payload} : any = await dispatch(registerUser({ username: username, password: password}));
if (payload === 200) {
alert('Successfully registered. Redirecting to dashboard');
return navigate('/dashboard');
} else { return alert('User creation unsuccessful'); }
}
Appreciate any help as I've looked through many other posts but haven't been able to resolve my issue.

Related

How can I build nodes and use them to create pages in gatsby?

I'm able to run my code in dev just fine and works as expected. Not sure what I'm doing wrong. Am I unable to create nodes and then build pages from them in gatsby-node.js? Is there a better way of doing this in gatsby that I'm not aware of?
The problem is when I try to build I receive error.
"gatsby-node.js" threw an error while running the sourceNodes lifecycle:
Request failed with status code 400
Here is my code:
exports.sourceNodes = async ({
actions,
createNodeId,
createContentDigest,
}) => {
const { createNode } = actions
const auth_token = Buffer.from(
`${client_id}:${client_secret}`,
'utf-8'
).toString('base64')
const token_url = 'https://accounts.spotify.com/api/token'
const data = qs.stringify({ grant_type: 'client_credentials' })
const response = await axios.post(token_url, data, {
headers: {
Authorization: `Basic ${auth_token}`,
'Content-Type': 'application/x-www-form-urlencoded',
},
})
const access_token = await response.data.access_token
const spotifyData = await axios.get(
`https://api.spotify.com/v1/artists/${artistId}/albums`,
{
headers: {
Authorization: `Bearer ${access_token}`,
'Content-type': 'application/json',
},
params: {
limit: 50,
market: 'US',
groups: 'single,album',
},
}
)
const ALBUM_NODE_TYPE = `Album`
await spotifyData.data.items.forEach(album =>
createNode({
...album,
id: createNodeId(`${ALBUM_NODE_TYPE}-${album.id}`),
parent: null,
children: [],
internal: {
type: ALBUM_NODE_TYPE,
contentDigest: createContentDigest(album),
},
})
)
}
exports.createPages = async ({ graphql, actions }) => {
const { createPage } = actions
const results = await graphql(`
{
collections: allFile {
distinct(field: sourceInstanceName)
edges {
node {
id
sourceInstanceName
childMarkdownRemark {
id
fields {
slug
}
frontmatter {
title
image
}
}
}
}
}
news: allFile(filter: { sourceInstanceName: { eq: "news" } }) {
nodes {
sourceInstanceName
childMarkdownRemark {
frontmatter {
title
image
blurb
url
}
id
fields {
slug
}
}
}
}
music: allAlbum(sort: { fields: release_date, order: DESC }) {
nodes {
id
href
images {
url
}
name
artists {
name
}
release_date
album_type
external_urls {
spotify
}
}
}
}
`)
// Music
await results.data.music.nodes.forEach(node => {
console.log(node)
if (node.errors) {
node.errors.forEach(e => console.error(e.toString()))
return Promise.reject(node.errors)
}
const id = node.id
const name = node.name.replace(/\s+/g, '_').toLowerCase()
createPage({
path: `music/${name}`,
component: path.resolve(`src/templates/music/music.js`),
// additional data can be passed via context
context: {
id,
field: { ...node },
},
})
})
await results.data.news.nodes.forEach(node => {
if (node.errors) {
node.errors.forEach(e => console.error(e.toString()))
return Promise.reject(node.errors)
}
const id = node.childMarkdownRemark.id
createPage({
path: `${node.sourceInstanceName}${node.childMarkdownRemark.fields.slug}`,
component: path.resolve(
`src/templates/${String(node.sourceInstanceName)}/${String(
node.sourceInstanceName
)}.js`
),
// additional data can be passed via context
context: {
id,
field: { ...node.childMarkdownRemark.frontmatter },
},
})
})
//News Collection
await results.data.collections.distinct.forEach(collection => {
if (collection.errors) {
collection.errors.forEach(e => console.error(e.toString()))
return Promise.reject(collection.errors)
} else {
if (collection !== 'news') {
return
} else {
const edges = results.data.collections.edges
const nodes = edges.filter(
e => e.node.sourceInstanceName === 'news'
)
createPage({
path: `/collections/news`,
component: path.resolve(
`src/templates/news/collections/news.js`
),
context: {
nodes: { ...nodes },
},
})
}
}
})
}
exports.onCreateNode = ({ node, actions, getNode }) => {
const { createNodeField } = actions
if (node.internal.type === `MarkdownRemark`) {
const value = createFilePath({ node, getNode })
createNodeField({
name: `slug`,
node,
value,
})
}
}
I also tried wrapping the createPage function in sourceNodes but that didn't work either.
I ended up creating a source-plugin and passing in my Spotify credentials as a string in gatbsy-config.js. It's not able to read env variable at build time but it is when running dev and I'm not sure I understand why that is.

I cant access as an "user" on MongoDB

This is my issue, I can access to MongoDB as an admin, but when I switch to “user” I can't, and it shows a message like this: msg: "You are not an admin!", even though I switched to 'user', this is and screenshot on MongoDB:
MongoDB, please click to see the image
This is a screenshot of the app message error:
Flutter app, please click to see the image
This is my code:
admin.js
const jwt = require("jsonwebtoken"); const User = require("../models/user");
const admin = async (req, res, next) => { try {
const token = req.header("x-auth-token");
if (!token)
return res.status(401).json({ msg: "No auth token, access denied" });
const verified = jwt.verify(token, "passwordKey");
if (!verified)
return res
.status(401)
.json({ msg: "Token verification failed, authorization denied." });
const user = await User.findById(verified.id);
if (user.type == "user" || user.type == "seller") {
return res.status(401).json({ msg: "You are not an admin!" });
}
req.user = verified.id;
req.token = token;
next(); } catch (err) {
res.status(500).json({ error: err.message }); } };
module.exports = admin;
admin_services.dart
class AdminServices {
void sellProduct({
required BuildContext context,
required String name,
required String description,
required double price,
required double quantity,
required String category,
required List<File> images,
}) async {
final userProvider = Provider.of<UserProvider>(context, listen: false);
try {
final cloudinary = CloudinaryPublic('blur', 'blur');
List<String> imageUrls = [];
for (int i = 0; i < images.length; i++) {
CloudinaryResponse res = await cloudinary
.uploadFile(CloudinaryFile.fromFile(images[i].path, folder: name));
imageUrls.add(res.secureUrl);
}
Product product = Product(
name: name,
description: description,
quantity: quantity,
images: imageUrls,
category: category,
price: price,
);
http.Response res = await http.post(
Uri.parse('$uri/admin/add-product'),
headers: {
'Content-Type': 'application/json; charset=UTF-8',
'x-auth-token': userProvider.user.token,
},
body: product.toJson(),
);
httpErrorHandle(
response: res,
context: context,
onSuccess: () {
showSnackBar(context, 'Product added successfully');
Navigator.pop(context);
},
);
} catch (e) {
showSnackBar(context, e.toString());
}
}
Future<List<Product>> fetchAllProducts(BuildContext context) async {
final userProvider = Provider.of<UserProvider>(context, listen: false);
List<Product> productList = [];
try {
http.Response res = await http.get(
Uri.parse('$uri/admnin/get-products'),
headers: {
'Content-Type': 'application/json; charset=UTF-8',
'x-auth-token': userProvider.user.token,
},
);
httpErrorHandle(
response: res,
context: context,
onSuccess: () {
for (int i = 0; i < jsonDecode(res.body).length; i++) {
productList.add(
Product.fromJson(
jsonEncode(
jsonDecode(res.body)[i],
),
),
);
}
});
} catch (e) {
showSnackBar(context, e.toString());
}
return productList;
}
void deleteProduct(
{required BuildContext context,
required Product product,
required VoidCallback onSuccess}) async {
final userProvider = Provider.of<UserProvider>(context, listen: false);
try {
http.Response res = await http.post(
Uri.parse('$uri/admnin/delete-product'),
headers: {
'Content-Type': 'application/json; charset=UTF-8',
'x-auth-token': userProvider.user.token,
},
body: jsonEncode(
{
'id': product.id,
},
),
);
httpErrorHandle(
response: res,
context: context,
onSuccess: () {
onSuccess();
},
);
} catch (e) {
showSnackBar(context, e.toString());
}
}
}
Hope you can help me, thanks for your attention

Error with sending an arrays and an object in a GET API and getting them in the reducer

I'm working on a project where I need to send an arrays and an object from the backend (nodejs) through a GET api to the frontend (reactjs) and have both of those be accessible in my reducer. I have never done this, and I'm not sure if I'm going about it the right way. I am currently getting an error saying that totalPages from this line: export const orderMineListReducer = (state = {orders:[], totalPages}, action) => { is not defined. I would really appreciate any help or advice on how to go about sending a GET api with an arrays and an object and receiving an arrays and an object in the reducer. Thank you!
Below, I have included what I have tried to do so far:
Backend:
orderRouter.js
orderRouter.get(
'/mine',
isAuth,
expressAsyncHandler(async (req, res) => {
const page = req.query.page || 1;
const perPage = 20
const orders = await Order.find({ user: req.user._id }).skip(page * perPage).limit(perPage);
const total = await Order.countDocuments();
const totalPages = Math.ceil(total / perPage).toString();
res.status(200).send({
data:
[orders],
totalPages,
});
}),
);
Frontend
orderReducer.js
export const orderMineListReducer = (state = {orders:[], totalPages}, action) => {
switch (action.type) {
case ORDER_MINE_LIST_REQUEST:
return { ...state, loading: true };
case ORDER_MINE_LIST_SUCCESS:
return { ...state, loading: false, orders: action.payload.orders, totalPages: action.payload.totalPages,};
case ORDER_MINE_LIST_FAIL:
return { ...state, loading: false, error: action.payload };
default:
return state;
}
};
orderActions.js
export const listOrderMine = (page) => async (dispatch, getState) => {
dispatch({ type: ORDER_MINE_LIST_REQUEST });
const {
userSignin: { userInfo },
} = getState();
try {
const { data } = await Axios.get(`${BASE_URL}/api/orders/mine?page=${page}`, {
headers: {
Authorization: `Bearer ${userInfo.token}`,
},
});
dispatch({ type: ORDER_MINE_LIST_SUCCESS, payload: data });
} catch (error) {
const message = error.response && error.response.data.message ? error.response.data.message : error.message;
dispatch({ type: ORDER_MINE_LIST_FAIL, payload: message });
}
};
I've also tried just having
res.status(200).send({
orders,
totalPages,
});
instead of res.status(200).send({data: { orders, totalPages,}});
with my reducer like so:
export const orderMineListReducer = (state = { data: {} }, action) => {
switch (action.type) {
case ORDER_MINE_LIST_REQUEST:
return { ...state, loading: true };
case ORDER_MINE_LIST_SUCCESS:
return { ...state, loading: false, data: action.payload,};
case ORDER_MINE_LIST_FAIL:
return { ...state, loading: false, error: action.payload };
default:
return state;
}
};
however in my OrderHistoryScreen.js where I have
const orderMineList = useSelector((state) => state.orderMineList);
const { loading, data, error,} = orderMineList;
const dispatch = useDispatch();
useEffect(() => { dispatch(listOrderMine());
}, [dispatch]);
I am getting undefined for console.log(data.orders) and empty {} for console.log(data).
Your response has this scheme:
{
data: {
orders,
totalPages
}
}
Axios.get will resolve to an object with this schema:
{
data: {
data: {
orders,
totalPages
}
},
status: 200,
statusText: 'OK',
...
}
So you need to change the destructuring or dispatch data.data like this:
dispatch({ type: ORDER_MINE_LIST_SUCCESS, payload: data.data });
Check the Axios documentation on the response schema: https://axios-http.com/docs/res_schema

How to receive re-requested data when data requested by mounted() is re-requested by aixos interceptor

the code below is the first request for get list data
mounted() {
this.getList()
},
methods: {
handleClick(row) {
console.log(row.id)
console.log(row.url)
this.$router.push({ name: 'Main', query: { id: row.id } })
},
getList() {
axios
.get('/api/v1/requests/all', {
params: {
userId: this.$store.state.userInfo.id,
},
})
.then(response => {
let moment = require('moment')
for (var item of response.data.data) {
item.createdAt = moment(item.createdAt).format(
'YYYY-MM-DD HH:mm:ss',
)
}
this.items = response.data.data
})
.catch(error => {
console.log(error)
})
}
my interceptor
axios.interceptors.response.use(
function (response) {
return response
},
async function (error) {
const originalRequest = error.config
if (error.response.status === 401 && !originalRequest._retry) {
error.response.config._retry = true
sessionStorage.removeItem('access-token')
let headers = {
grant_type: 'refresh_token',
Authorization: sessionStorage.getItem('refresh-token'),
}
axios
.post('/api/v1/users/refresh_token', {}, { headers: headers })
.then(response => {
let token = response.data.data
sessionStorage.setItem('access-token', token)
originalRequest.headers['Authorization'] = token
originalRequest.headers['grant_type'] = 'grant_type'
return axios.request(originalRequest)
})
.catch(error => {
console.log(error)
alert('blablabla.')
})
}
return Promise.reject(error)
},
)
the flow is i understand
1.token expired
2.move to list page
3.mounted hook is request data
4.getList -> axios get('~~request/all')
5.interceptor->axios post('~~~refresh_token')
6.re request with new token(request/all)
7.re request is 200, but not update list page
i'd really appreciate your help :)
Seems like you need to return the second request (await for result and return). Right now the result of second request seems to be ignored
axios.interceptors.response.use(
function (response) {
return response;
},
async function (error) {
const originalRequest = error.config;
if (error.response.status === 401 && !originalRequest._retry) {
error.response.config._retry = true;
sessionStorage.removeItem("access-token");
let headers = {
grant_type: "refresh_token",
Authorization: sessionStorage.getItem("refresh-token"),
};
const [secondError, res] = await axios // await here
.post("/api/v1/users/refresh_token", {}, { headers: headers })
.then(async (response) => {
let token = response.data.data;
sessionStorage.setItem("access-token", token);
originalRequest.headers["Authorization"] = token;
originalRequest.headers["grant_type"] = "grant_type";
return [null, await axios.request(originalRequest)];
})
.catch((err) => {
console.log(err);
alert("blablabla.");
return [err, null];
});
// Handle here
if(secondError) {
return Promise.reject(secondError);
}
return Promise.resolve(res)
}
return Promise.reject(error);
}
);
The above solution worked for me perfectly. here's the modified code that I used for my requirement.
export default function axiosInterceptor() {
//Add a response interceptor
axios.interceptors.response.use(
(res) => {
// Add configurations here
return res;
},
async function (error) {
const originalRequest = error.config;
let secondError, res
if (error.response.status === 401 && !originalRequest._retry) {
originalRequest._retry = true;
[secondError, res] = await axios({
method: "POST",
url: `${baseURL}/account/token/refreshtoken`,
withCredentials: true,
headers: { "Content-Type": "application/json" },
})
.then(async (response) => {
//handle success
return [null, await axios.request(originalRequest)];
}).catch(function (error) {
console.error(error)
});
}
if (secondError) {
return Promise.reject(secondError);
}
return Promise.resolve(res)
}
);
}

mtproto/core Telegram replay to another Channel

i want collect news from different channels and echo them in a second channel, with the code i can read channels(not all but most).
I stuck now on the echo problem and have no clue about how i can do this, mtproto is completely new to me, thanks.
Im using the following code i have from another stackoverflow question.
const { MTProto, getSRPParams } = require('#mtproto/core');
const prompts = require('prompts');
const api_id = 'xxxxx';
const api_hash = 'xxxxx';
async function getPhone() {
return (await prompts({
type: 'text',
name: 'phone',
message: 'Enter your phone number:'
})).phone
}
async function getCode() {
// you can implement your code fetching strategy here
return (await prompts({
type: 'text',
name: 'code',
message: 'Enter the code sent:',
})).code
}
async function getPassword() {
return (await prompts({
type: 'text',
name: 'password',
message: 'Enter Password:',
})).password
}
const mtproto = new MTProto({
api_id,
api_hash,
});
function startListener() {
console.log('[+] starting listener')
mtproto.updates.on('updates', ({ updates }) => {
const newChannelMessages = updates.filter((update) => update._ === 'updateNewChannelMessage').map(({ message }) => message) // filter `updateNewChannelMessage` types only and extract the 'message' object
for (const message of newChannelMessages) {
// printing new channel messages
console.log(`[${message.to_id.channel_id}] ${message.message}`)
}
});
}
// checking authentication status
mtproto
.call('users.getFullUser', {
id: {
_: 'inputUserSelf',
},
})
.then(startListener) // means the user is logged in -> so start the listener
.catch(async error => {
// The user is not logged in
console.log('[+] You must log in')
const phone_number = await getPhone()
mtproto.call('auth.sendCode', {
phone_number: phone_number,
settings: {
_: 'codeSettings',
},
})
.catch(error => {
if (error.error_message.includes('_MIGRATE_')) {
const [type, nextDcId] = error.error_message.split('_MIGRATE_');
mtproto.setDefaultDc(+nextDcId);
return sendCode(phone_number);
}
})
.then(async result => {
return mtproto.call('auth.signIn', {
phone_code: await getCode(),
phone_number: phone_number,
phone_code_hash: result.phone_code_hash,
});
})
.catch(error => {
if (error.error_message === 'SESSION_PASSWORD_NEEDED') {
return mtproto.call('account.getPassword').then(async result => {
const { srp_id, current_algo, srp_B } = result;
const { salt1, salt2, g, p } = current_algo;
const { A, M1 } = await getSRPParams({
g,
p,
salt1,
salt2,
gB: srp_B,
password: await getPassword(),
});
return mtproto.call('auth.checkPassword', {
password: {
_: 'inputCheckPasswordSRP',
srp_id,
A,
M1,
},
});
});
}
})
.then(result => {
console.log('[+] successfully authenticated');
// start listener since the user has logged in now
startListener()
});
})

Resources