in App.vue I get user data (if he is authorized)
onMounted( async () => {
await init();
});
added the initialization function to the useAuthComposables file
import { authService } from '#/shared/services/v1/auth.service';
import { useAuthStore } from '#/store/auth';
export default function () {
const authStore = useAuthStore();
const init = async () => {
const [error, data] = await authService.getAuthUser();
if (error) {
console.log(error);
} else {
authStore.setUser(data);
authStore.setToken(true);
}
};
return {
init
};
}
and the store itself useAuthStore
import { defineStore } from 'pinia';
export const useAuthStore = defineStore('authStore', {
state: () => ({
user: null,
isLoggedIn: false
}),
actions: {
setUser(data: any) {
this.user = data;
},
setToken(isAuth: boolean) {
this.isLoggedIn = isAuth;
}
},
getters: {
getUser(state: any) {
return state.user;
}
}
});
when I reload the page (f5) in the route does not see the side
router.beforeEach(async (to, from, next): Promise<any> => {
const authStore = useAuthStore();
console.log('beforeEach',authStore.getUser);
if (!authStore.isLoggedIn) {
next({ name: 'Login' });
}
else {
next();
}
});
but when I just follow the links, it displays a stor
Related
When I Try to dispatch in getServerSideProps the Redux Store won't change
When i Console.log the store After Dispatch I see the changes in console but when the page load the Store is empty array..
Why Changes won't effect?
createSlice
import { createSlice } from "#reduxjs/toolkit";
import { Store } from "../../types/type";
const { actions, reducer } = createSlice({
name: "dashboard",
initialState: { users: [], roles: [], ads: [], category: [] },
reducers: {
SET_ROLES: (store, { payload }) => {
store.roles = payload;
return store;
},
SET_USERS: (store, { payload }) => {
store.users = payload;
return store;
},
SET_ADS: (store, { payload }) => {
store.ads = payload;
return store;
},
SET_CATEGORY: (store, { payload }) => {
store.category = payload;
return store;
},
},
});
// Selector
export const selectDashboard = (store: Store) => store.entities.dashboard;
export const { SET_ROLES, SET_ADS, SET_USERS, SET_CATEGORY } = actions;
export default reducer;
Page
export const getServerSideProps = wrapper.getServerSideProps(
(store) => async (context) => {
const { data: ads } = await axios.get(endPoint);
const { data: users } = await axios.get(endPoint);
const { data: roles } = await axios.get(endPoint);
const { data: categories } = await axios.get(endPoint);
console.log("Before DISPATCH", store.getState());
store.dispatch(SET_USERS(users));
store.dispatch(SET_ADS(ads));
store.dispatch(SET_CATEGORY(categories));
store.dispatch(SET_ROLES(roles));
console.log("After DISPATCH", store.getState()); // I Can See The Changes In Console
return {
props: {},
};
}
);
The state set in the server will get cleared when dehydrations happen. You need to update server state with client state.
const reducer = (
state: ReturnType<typeof combinedReducer> | undefined,
action: AnyAction
) => {
if (action.type === HYDRATE) {
const nextState = {
...state, // use previous state
...action.payload, // apply delta from hydration
};
return nextState;
} else {
return combinedReducer(state, action);
}
};
export const store = configureStore({
reducer,
devTools: process.env.NODE_ENV !== 'production',
middleware: (getDefaultMiddleware) =>
....
How do I use getStaticPaths when using Redux with Next.js?
I am using next-redux-wrapper to store my content and i am having trouble getting the data to display.
Please see my code example below
import { useSelector } from "react-redux";
import {getPageData} from '../redux/actions/pages'
import { useRouter } from "next/router";
import {wrapper} from '../redux'
import { getNavItems } from '../redux/actions/navItems';
import { getServiceData } from '../redux/actions/services';
import { getHomePage } from '../redux/actions/homePage';
export default function pageTemplate({page}) {
return(
<h1>{page.title}</h1>
)
}
export const getStaticPaths = async () => {
const pages = await getPageData()
const paths = Object.keys(pages).map((key) => {
const page = pages[key]
return{
params: {slug: page.slug.current}
}
})
return{
paths,
fallback: false
}
}
export const getStaticProps = wrapper.getStaticProps((store) => async (context) => {
await store.dispatch(getHomePage());
await store.dispatch(getServiceData());
await store.dispatch(getNavItems());
const slug = context.params.slug
console.log(slug)
const page = await store.dispatch(getPageData(slug))
return {
props: {page},
revalidate: 60
};
}
You can also see my redux action which is working fine as I have tested it in the sanity.io groq playground.
import * as actionTypes from '../actions/actionTypes';
import { groq } from 'next-sanity';
import { getClient } from '../../lib/sanity.server';
export const getPageData = (slug) => async (dispatch) => {
const query = groq`
*[_type == "page"]{
_id,
title,
slug
}
`;
const queryTwo = groq`
*[_type == "page" && slug.current != $slug]{
_id,
title,
slug
}
`;
if(slug) {
try {
// const client = ...
const pageData = await getClient().fetch(query);
dispatch({
type: actionTypes.GET_ALL_PAGES,
payload: pageData
});
} catch (err) {
console.log(err);
}
}
try {
// const client = ...
const pageData = await getClient().fetch(queryTwo);
dispatch({
type: actionTypes.GET_ALL_PAGES,
payload: pageData || pagesData
});
} catch (err) {
console.log(err);
}
};
I have faced the same issue before just releasing that you can use getStaticPaths without the need of the next-redux-wrapper
here is some example from a code that I've been working on lately
import { ReduxWrapper, store } from '#store/store'
export const getStaticPaths = async () => {
const postsSlugs = store
.getState()
.posts.posts.map((post) => ({ params: { slug: post.slug } }))
return {
paths: postsSlugs,
fallback: true,
}
}
export const getStaticProps = ReduxWrapper.getStaticProps(
(store) => async (context) => {
const slug = context.params?.slug
const post = store.getState().posts.post
return {
props: { post },
}
},
)
I hope that it may help you or anyone searching for the same issue
userSlice
import { createSlice, createAsyncThunk } from "#reduxjs/toolkit";
import LoginService from "../../Services/Login.service";
export const userRegister = createAsyncThunk(
"users/register",
async (params) => {
try {
const { registerForm } = params;
const { data } = await LoginService.register(registerForm);
return data;
} catch (error) {
}
}
);
const initialState = {
userData: {},
errorResponse: null,
status: "idle",
};
export const userSlice = createSlice({
name: "User",
initialState,
reducers: {},
extraReducers: {
[userRegister.pending]: (state, action) => {
state.status = "loading";
},
[userRegister.fulfilled]: (state, action) => {
state.status = "succeeded";
state.userData = action.payload;
},
[userRegister.error]: (state, action) => {
state.status = "failed";
state.errorResponse = action.payload;
},
},
});
export default userSlice.reducer;
Login.service.js
import axios from "axios";
const API = axios.create({ baseURL: 'http://localhost:3001'});
const LoginService = {
register: async (registerData ) => {
await API.post('/users/register', registerData)
}
};
export default LoginService;
Hi.I try add register feature to my app. But when i submit register form, the datas is saved to the database without any problems. But this line const data = await LoginService.register(registerForm); doesnt work data is undefined but when i same post request in postman i get response data the way i want.
LoginService.register is not returning anything,
you can fix that by doing:
const LoginService = {
register: async (registerData ) => {
const response = await API.post('/users/register', registerData);
return response.data;
}
};
I had asked this question before.
I looked carefully at the exchange section, which I advised, and I think there is no problem with the exchange section.
At least in my opinion there is no problem and I hardly know the cause of the problem.
And I was so frustrated that I put everything in the code.
If anyone can provide us with a clue to this problem, please reply to me.
interactions.js
import Web3 from 'web3'
import {
web3Loaded,
web3AccountLoaded,
tokenLoaded,
exchangeLoaded,
cancelledOrdersLoaded
} from './actions'
import Token from '../abis/Token.json'
import Exchange from '../abis/Exchange.json'
export const loadWeb3 = (dispatch) => {
const web3 = new Web3(Web3.givenProvider || 'http://localhost:7545')
dispatch(web3Loaded(web3))
return web3
}
export const loadAccount = async (web3, dispatch) => {
const accounts = await web3.eth.getAccounts()
const account = accounts[0]
dispatch(web3AccountLoaded(account))
return account
}
export const loadToken = async (web3, networkId, dispatch) => {
try {
const token = new web3.eth.Contract(Token.abi, Token.networks[networkId].address)
dispatch(tokenLoaded(token))
return token
} catch (error) {
console.log('Contract not deployed to the current network. Please select another network with Metamask.')
return null
}
}
export const loadExchange = async (web3, networkId, dispatch) => {
try {
const exchange = new web3.eth.Contract(Exchange.abi, Exchange.networks[networkId].address)
dispatch(exchangeLoaded(exchange))
return exchange
} catch (error) {
console.log('Contract not deployed to the current network. Please select another network with Metamask.')
return null
}
}
export const loadAllOrders = async (exchange, dispatch) => {
// if (exchange) { // Make sure exchange has been defined
// const exchange = new web3.eth.Contract(Exchange.abi, Exchange.networks[networkId].address)
const cancelStream = await exchange.getPastEvents('Cancel', { fromBlock: 0, toBlock: 'latest' })
// // await loadAllOrders(this.props.exchange, dispatch)
console.log(cancelStream)
}
App.js
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import Navbar from './Navbar'
import Web3 from 'web3';
import Content from './Content'
import { connect } from 'react-redux'
// import Token from '../abis/Token.json'
import {
loadWeb3,
loadAccount,
loadToken,
loadExchange
} from '../store/interactions'
import { contractsLoadedSelector } from '../store/selectors'
class App extends Component {
componentWillMount() {
this.loadBlockchainData(this.props.dispatch)
}
async loadBlockchainData(dispatch) {
const web3 = loadWeb3(dispatch)
const network = await web3.eth.net.getNetworkType()
const networkId = await web3.eth.net.getId()
const accounts = await loadAccount(web3, dispatch)
const token = await loadToken(web3, networkId, dispatch)
if(!token) {
window.alert('Token smart contract not detected on the current network. Please select another network with Metamask.')
return
}
const exchange = await loadExchange(web3, networkId, dispatch)
if(!exchange) {
window.alert('Exchange smart contract not detected on the current network. Please select another network with Metamask.')
return
}
}
render() {
return (
<div>
<Navbar />
{ this.props.contractsLoaded ? <Content /> : <div className="content"></div> }
</div>
);
}
}
function mapStateToProps(state) {
return {
contractsLoaded: contractsLoadedSelector(state)
}
}
export default connect(mapStateToProps)(App);
reducers.js
import { combineReducers } from 'redux';
function web3(state={}, action) {
switch (action.type) {
case 'WEB3_LOADED':
return { ...state, connection: action.connection }
case 'WEB3_ACCOUNT_LOADED':
return { ...state, account: action.account }
default:
return state
}
}
function token(state = {}, action) {
switch (action.type) {
case 'TOKEN_LOADED':
return { ...state, loaded: true, contract: action.contract }
default:
return state
}
}
function exchange(state = {}, action) {
switch (action.type) {
case 'EXCHANGE_LOADED':
return { ...state, loaded: true, contract: action.contract }
case 'CANCELLED_ORDERS_LOADED':
return { ...state, cancelledOrders: { loaded: true, data: action.cancelledOrders } }
// case 'FILLED_ORDERS_LOADED':
// return { ...state, filledOrders: { loaded: true, data: action.filledOrders } }
// case 'ALL_ORDERS_LOADED':
// return { ...state, allOrders: { loaded: true, data: action.allOrders } }
default:
return state
}
}
const rootReducer = combineReducers({
web3,
token,
exchange
})
export default rootReducer
Content.js
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { exchangeSelector } from '../store/selectors'
import { loadAllOrders } from '../store/interactions'
class Content extends Component {
componentWillMount() {
this.loadBlockchainData(this.props.dispatch)
}
// async loadBlockchainData(exchange, dispatch) {
async loadBlockchainData(dispatch) {
await loadAllOrders(this.props.exchange, dispatch)
// this.loadBlockchainData(this.props.exchange)
// await loadAllOrders(exchange, dispatch)
}
function mapStateToProps(state) {
return {
exchange: state.exchangeSelector
}
}
export default connect(mapStateToProps)(Content)
selectors.js
import { get } from 'lodash'
import { createSelector } from 'reselect'
const account = state => get(state, 'web3.account')
export const accountSelector = createSelector(account, a => a)
const tokenLoaded = state => get(state, 'token.loaded', false)
export const tokenLoadedSelector = createSelector(tokenLoaded, tl => tl)
const exchangeLoaded = state => get(state, 'exchange.loaded', false)
export const exchangeLoadedSelector = createSelector(exchangeLoaded, el => el)
const exchange = state => get(state, 'exchange.contract')
export const exchangeSelector = createSelector(exchange, e => e)
export const contractsLoadedSelector = createSelector(
tokenLoaded,
exchangeLoaded,
(tl, el) => (tl && el)
)
Check exchange to make sure not undefined
export const loadAllOrders = async (exchange, dispatch) => {
const cancelStream = exchange ?
await exchange.getPastEvents('Cancel', { fromBlock: 0, toBlock: 'latest' })
: null // Check if exchange defined then call getPastEvents
console.log(cancelStream)
}
I am in trouble...
After registration in my application the user need's to create a workspace, I need to oblige the workspace creation otherwise the API will not work, but I am unable to lock it on the workspace creation page.
When I try to check if the user already has a workspace on the first load of the application vuex is still empty because the axios request has not yet been finalized...
How can I be sure that the vue router will wait for axios to receive the api data?
router.js
import Vue from 'vue'
import Router from 'vue-router'
import store from './../store'
import auth from './modules/auth'
import api from './modules/api'
import common from './modules/common'
import projects from './modules/projects'
import wabas from './modules/wabas'
Vue.use(Router)
const router = new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [
...auth,
...api,
...common,
...projects,
...wabas,
]
})
router.beforeEach((to, from, next) => {
store.dispatch('auth/setToken').then(() => {
// will return an empty array
console.log(store.getters['workspaces/workspaces'])
if (!store.state.workspaces.workspaces.length && to.name !== 'welcome_a' && to.name !== 'welcome_b' && to.name !== 'welcome_c') {
next({
name: 'welcome_a'
})
} else {
if (to.meta.visitor || to.name === 'welcome_a' || to.name === 'welcome_b' || to.name === 'welcome_c') {
next({
name: 'home'
})
return
}
next()
}
}).catch(() => {
if (to.meta.auth) {
next({
name: 'login'
})
return
}
next()
})
})
export default router
router/modules/common.js
const routes = [
{
path: '/',
name: 'home',
component: () => import('../../pages/Home'),
meta: {
auth: true
}
},
{
path: '/bem-vindo',
name: 'welcome_a',
component: () => import('../../pages/WelcomeA'),
meta: {
auth: true
}
},
{
path: '/finalizar-cadastro',
name: 'welcome_b',
component: () => import('../../pages/WelcomeB'),
meta: {
auth: true
}
},
{
path: '/area-de-trabalho',
name: 'welcome_c',
component: () => import('../../pages/WelcomeC'),
meta: {
auth: true
}
}
]
export default routes
main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import localforage from "localforage";
localforage.config({
driver: localforage.LOCALSTORAGE,
storeName: 'positus'
})
Vue.config.productionTip = false
window._ = require('lodash')
import components from './components'
components.forEach(component => {
Vue.component(component.name, component);
});
import helpersMixin from './support/mixins/helpers'
Vue.mixin(helpersMixin)
import notifications from './support/notifications'
Vue.use(notifications)
import bus from './support/bus'
Vue.use(bus)
import VueClipboard from 'vue-clipboard2'
Vue.use(VueClipboard)
import http from './support/http'
Vue.use(http)
store.dispatch('auth/setToken').then(() => {
store.dispatch('auth/fetchSystemData').catch(() => {
store.dispatch('auth/clearAuth')
})
}).catch(() => {
store.dispatch('auth/clearAuth')
})
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
store/modules/auth.js
import Vue from 'vue'
import authApi from '../../api/auth'
import {setHttpToken} from '../../support/http'
import axios from 'axios'
import localforage from 'localforage'
import router from '../../router'
const state = {
user: {}
}
const getters = {
user(state) {
return state.user
}
}
const actions = {
fetchData({commit}) {
return axios.all([
authApi().user.get()
]).then(axios.spread((user) => {
commit('SET_USER_DATA', user.data.data)
})).catch(error => console.error(error))
},
fetchSystemData({dispatch}) {
return Promise.all([
dispatch('fetchData'),
dispatch('workspaces/fetchData', null, {root: true})
]).finally(() => {
dispatch('app/setProcessing', false, {root: true})
})
},
authenticateUser({commit, dispatch}, data) {
dispatch('app/setProcessing', true, {root: true})
return authApi().login(data)
.then(({data}) => {
dispatch('setToken', data).then(() => {
dispatch('fetchSystemData').then(() => {
router.push({
name: 'home'
})
}).catch(() => {
Vue.$n('Ocorreu um erro ao receber os dados da sua conta, tente novamente mais tarde.', 'error')
})
})
}).catch(() => {
dispatch('app/setProcessing', false, {root: true})
Vue.$n('Algum erro ocorreu na tentativa de acessar sua conta.', 'error')
})
},
setToken({dispatch}, token) {
if (_.isEmpty(token)) {
return dispatch('checkTokenExists').then((token) => {
setHttpToken(token)
})
}
dispatch('setTokenLocalStorage', token)
setHttpToken(token)
return token
},
setTokenLocalStorage({commit}, token) {
if (_.isEmpty(token)) {
localforage.removeItem('token', token)
return
}
localforage.setItem('token', token)
},
checkTokenExists() {
return localforage.getItem('token').then((token) => {
if (_.isEmpty(token)) {
return Promise.reject('NO_STORAGE_TOKEN')
}
return Promise.resolve(token)
})
},
clearAuth({dispatch}) {
Promise.all([
dispatch('setTokenLocalStorage', null)
]).finally(() => {
setHttpToken(null)
router.push({
name: 'login'
})
})
},
updateActiveWorkspace({commit}, data) {
commit('UPDATE_ACTIVE_WORKSPACE', data)
}
}
const mutations = {
SET_USER_DATA(state, user) {
state.user = user
},
UPDATE_ACTIVE_WORKSPACE(state, data) {
state.user.active_workspace = data
}
}
export default {
namespaced: true,
state,
getters,
actions,
mutations
}
store/modules/workspaces.js
import workspacesApi from "../../api/workspaces"
import axios from "axios"
const state = {
workspaces: []
}
const getters = {
workspace(state) {
return (id) => {
return _.find(state.workspaces, (workspace) => {
return workspace.id === id
})
}
},
workspaces(state) {
return state.workspaces
}
}
const actions = {
fetchData({commit}) {
return axios.all([
workspacesApi().get()
]).then(axios.spread((workspaces) => {
commit('SET_WORKSPACES', workspaces.data.data)
})).catch(error => console.error(error))
},
setWorkspaces({commit}, data) {
commit('SET_WORKSPACES', data)
},
setWorkspace({commit, state}, data) {
let index = _.findIndex(state.workspaces, (space) => {
return space.id === data.id
})
if (index >= 0) {
commit('UPDATE_WORKSPACE', {
index: index,
data: data
})
} else {
commit('SET_WORKSPACE', data)
}
}
}
const mutations = {
SET_WORKSPACES(state, bool) {
state.workspaces = bool
},
SET_WORKSPACE(state, data) {
state.workspaces.push(data)
},
UPDATE_WORKSPACE(state, data) {
state.workspaces.splice(data.index, 1, data.data);
}
}
export default {
namespaced: true,
state,
getters,
actions,
mutations
}
from the title of this question, you can add a hook in vue component that will run when before the route is changed
beforeRouteLeave (to, from, next) {
// called when the route that renders this component is about to
// be navigated away from.
// has access to `this` component instance.
}
if you want user to move to the next route on which he clicked, you will call next() inside this hook and he will be navigated to the next page.
if you want to lock him and not navigate, pass false in this next() method like next(false)
Why don't you just create a middleware server side that redirects the user to the workspace creation page if the user didn't have one yet? Something like that in laravel
class RedirectIfWorkspaceNotCreated
{
public function handle($request, Closure $next, $guard = null)
{
$user = Auth::guard($guard)->user();
if ($user && !checkForUserWorkspace) {
return redirect('/your/workspace/creation/page');
}
return $next($request);
}
}