how to set up redux with NextJs and allow dispatching of actions - react-redux

Im trying to set up redux for my NextJS React App and I'm having some complications when dispatching this action through the indicated link. An error of 'Network Error' is displayed on LIST_FAIL. Any well available resources or advice would be appreciated. Thanks.
import axios from 'axios';
import {
//NOte that these are actions which will be dispatched or fired in the action y using dispatch()
LIST_REQUEST,
LIST_SUCCESS,
LIST_FAIL,
} from '../constants/customerConstants';
export const listCusts = () => async (dispatch, getState) => {
try {
//our first request to the backend to get the token
dispatch({
type:LIST_REQUEST,
});
const { data } = await axios.get('https://byronochara.tech/gassystem/api/v1/customers');
console.log(data);
const result = data.results;
// console.log('Results now an Array', result); //This is now an array to be looped in the list screen
dispatch({
type: LIST_SUCCESS,
payload: result,
});
} catch (error) {
dispatch({
type: LIST_FAIL,
payload:
error.response && error.response.data.message
? error.response.data.message
: error.message,
});
}
};

Related

Write on session with Sapper and Svelte

I wrote a Sapper app with session management following the RealWorld example:
polka()
.use(bodyParser.json())
.use(session({
name: 'kidways-app',
secret: 'conduit',
resave: false,
saveUninitialized: true,
cookie: {
maxAge: 31536000
},
store: new FileStore({
path: 'data/sessions',
})
}))
.use(
compression({ threshold: 0 }),
sirv('static', { dev }),
pdfMiddleware,
sapper.middleware({
session: req => ({
token: req.session && req.session.token
})
})
)
.listen(PORT, err => {
if (err) console.log('error', err);
});
Then on my _layout.sevlte:
<script context="module">
export async function preload({ query }, session) {
console.log('preload', session)
return {
// ...
};
}
</script>
<script>
import { onMount, createEventDispatcher } from 'svelte';
import { Splash } from 'project-components';
import * as sapper from '#sapper/app';
import { user } from '../stores';
import client from '../feathers';
const { session } = sapper.stores();
onMount(async () => {
try {
await client.reAuthenticate();
const auth = await client.get('authentication');
user.set(auth.user);
$session.token = 'test';
} catch (e) {
} finally {
loaded = true;
}
});
console.log($session)
</script>
<h1>{$session.token}</h1>
This work on client side rendering, but the token is still undefined on preload, making my SSR template rendering broken.
What did I missed?
When a page renders, session is populated according to the return value of the function you specified here:
sapper.middleware({
session: req => ({
token: req.session && req.session.token
})
})
So while the client may have an up-to-date token, it won't take effect on page reload unless you somehow persist the token to the server in such a way that the session middleware knows about it.
Typically you'd achieve this by having a server route, like routes/auth/token.js or something...
export function post(req, res) {
req.session.token = req.body.token;
res.writeHead(200, {
'Content-Type': 'application/json'
});
res.end();
}
...and posting the token from the client:
onMount(async () => {
try {
await client.reAuthenticate();
const auth = await client.get('authentication');
user.set(auth.user);
await fetch(`auth/token`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ token })
});
// writing to the session store on the client means
// it's immediately available to the rest of the app,
// without needing to reload the page
$session.token = 'test';
} catch (e) {
} finally {
loaded = true;
}
});

Apollo Server: How can I send a response based on a callback?

I am currently trying to validate iOS receipts for in app purchases using this package: https://github.com/Wizcorp/node-iap
This is my incomplete resolver:
export default {
Query: {
isSubscribed: combineResolvers(
isAuthenticated,
async (parent, args, { models, currentUser }) => {
const subscription = await models.Subscription.find({ user: currentUser.id });
const payment = {
...
};
iap.verifyPayment(subscription.platform, payment, (error, response) => {
/* How do I return a response here if it is async and I don't have the response object? */
});
}
),
},
};
How do I return a response here if it is async and I don't have the response object? Normally, I'm just used to returning whatever the model returns. However, this time I'm using node-iap and it's callback based.
You can use a Promise:
const response = await new Promise((resolve, reject) => {
iap.verifyPayment(subscription.platform, payment, (error, response) => {
if(error){
reject(error);
}else{
resolve(response);
}
});
});

use async/await instead of (.then)

I am trying to replace .then with async/await
here is my code
export const loginUser = (userData) => async dispatch => {
try {
await axios.post('/api/users/login', userData);
// Save to localStorage
const {token} = res.data;
// Save token to local storage
localStorage.setItem('jwtToken', token);
// Set token to Auth header
setAuthToken(token);
// Decode to get user data
const decoded = jwt_decode(token);
// set current user
dispatch(setCurrentUser(decoded));
} catch (err) {
dispatch({
type: GET_ERRORS,
payload: err.response.data
})
}
};
and then this is the error
Unhandled Rejection (TypeError): Cannot read property 'data' of
undefined ▶ 6 stack frames were collapsed.

ReactJS rxjs obervable dom ajax, get request treated as an option method

I am using 2 seperate libraries to make an http get in my reactjs application as follows
import { ajax } from 'rxjs/observable/dom/ajax';
import { Observable } from 'rxjs/Observable';
import * as actionType from '../types';
import types from '../types';
export default (action$, store) => {
return action$.ofType(types.getIssuers.requested).mergeMap(action => {
return ajax({
url: 'http://127.0.0.1:8181/api/v1/status',
responseType: 'json',
method: 'GET',
timeout: 2000
}).map(xhr => {
console.log("Issuer Epic")
const jsonBody = xhr.response;
return {
type: types.getIssuers.completed,
payload: jsonBody,
};
}).catch(error => {
return Observable.of({ type: actionType.LOAD_CUSTOMER_ERROR });
});
});
};
var request = require('request');
request('http://127.0.0.1:8181/api/v1/status', function (error, response, body) {
console.log('error:', error);
console.log('statusCode:', response && response.statusCode);
console.log('body:', body);
});
I can retrieve data without an issue if um using request library
I need to use rxjs/observable/dom/ajax as per the project requirement but it seems my HTTP GET request turned out to be an HTTP OPTION. Is there a fix for this ?

How to handle Google OAuth flow via redux-saga

I am trying to implement Google OAuth 2 with with redux saga.
I have a watcher in my saga listening for GOOGLE_AUTH action which then executes googleLogin
function *watchGoogleAuth() {
yield *takeLatest(GOOGLE_AUTH, googleLogin)
}
function *googleLogin() {
const id_token = yield call(GoogleSignIn);
console.log(id_token);
const response = yield call(HttpHelper, 'google_token', 'POST', id_token, null);
console.log(response);
}
The implementation for GoogleSignIn is in apis.js
export function GoogleSignIn() {
const GoogleAuth = window.gapi.auth2.getAuthInstance();
GoogleAuth.signIn({scope: 'profile email'})
.then(
(res) => {
const GoogleUser = GoogleAuth.currentUser.get();
return {
id_token: GoogleUser.getAuthResponse().id_token
};
},
(err) => {
console.log(err)
}
)
}
But saga doesn't seem to wait for the GoogleSignIn to complete. As soon as OAuth consent screen pops up, saga proceeds executing the console.log without waiting for google signin promise to return actual data.
Is there any better way to handle this situation? Thanks!
To expand on #HenrikR's answer, the generator will not wait unless it receives a promise.
export const GoogleSignIn = () => {
const GoogleAuth = window.gapi.auth2.getAuthInstance();
return new Promise((resolve, reject) => {
GoogleAuth.signIn({scope: 'profile email'})
.then(
(res) => {
const GoogleUser = GoogleAuth.currentUser.get();
resolve(GoogleUser.getAuthResponse().id_token);
},
(err) => {
reject(err);
}
);
});
};
Accordingly, you should wrap the yield statement in a try/catch. Simplified and somewhat lazy:
function *googleLogin() {
try {
const id_token = yield call(GoogleSignIn);
if (id_token) { /* Possibly with more checks and validations */
console.log(id_token);
const response = yield call(HttpHelper, 'google_token', 'POST', id_token, null);
console.log(response);
}
} catch (e) {
console.log(e);
}
}

Resources