Notify showing nothing on vuex subscribe - javascript

I'm trying to show a notification when I try to create a user in my pwa. to do that I'm subscribing the mutation that set the notification and then calling the notify but nothing is showed and no errors on console.
That's what I'm trying to do:
export default {
...,
mounted: function() {
var self = this
this.$store.subscribe(function(mutation, state) {
if (mutation === 'usuario/setError') {
self.$q.notify({
message: state.usuario.error.mensagem,
timeout: 3000,
type: state.usuario.error.sucesso ? 'positive' : 'negative',
position: 'top'
})
}
})
}
}
I tried import Notify from qusar and call Notify.create but without success.

I found a solution, instead use subscribe I could use watch from vue and watch the changes on a computed. This way:
export default {
...,
computed: {
error: function() {
return this.$store.state.usuario.error
}
},
watch: {
error: function(newError, oldError) {
console.log(newError)
this.$q.notify({
message: newError.mensagem,
timeout: 3000,
type: newError.sucesso ? 'positive' : 'negative',
position: 'top'
})
}
},
...
}

try if (mutation.type === 'usuario/setError'), if that doesn't work console log mutation to see what the type is and use that.

Related

Can't connect custom action with the custom reducer react-admin

8.4 of react-admin. I've been trying to implement a custom action that connects with the custom reducer but so far nothing has worked.
I've Implemented this part of the guide in the official documentation for the action side https://marmelab.com/react-admin/doc/3.8/Actions.html#querying-the-api-with-fetch and this for the reducer https://marmelab.com/react-admin/doc/3.8/Admin.html#customreducers. The problem stems from that I can only use useUpdate method which sends update request, instead of a get without connecting to the reducer and there is no clear explanation of how I can chain those two things together. I also tried using an older way of dispatching actions, but still didn't work. Please help I've been trying this for 2 weeks now. Nothing gets updates and the redux store stays the same.
component
const { data, loading, error } = useQueryWithStore({
type: 'getList',
resource: 'goals',
action: "GET_USER_GOALS",
payload: { pagination: { page: 1, perPage: 10 }, sort: { field: "a-z", order: "ABC" }, filter: {} }
});
reducer
export default (previousState = 0, { type, payload }) => {
console.log(type)
if (type === 'GET_USER_GOALS') {
return payload.rate;
}
return previousState;
}
I even wrote a custom action
but it says that "Cannot read property 'update' of undefined" which isn't supported in the newer version I guess.
import { UPDATE } from 'react-admin';
export const UPDATE_PAGE = 'GET_USER_GOALS';
export const setGoals = (id, data) => {
return {
type: UPDATE_PAGE,
payload: { id, data: { ...data, is_updated: true } },
meta: { fetch: UPDATE, resource: 'goals' },
}
};
admin
<Admin
locale="en"
customReducers={{ userGoals: userGaolsReducer }}
loginPage={LoginPage}
authProvider={authProvider}
dataProvider={testProvider}
i18nProvider={i18nProvider}
history={history}
dashboard={Dashboard}
customSagas={[userGoalsSaga]}
>
I had to include it in the store.js as well
const reducer = combineReducers({
admin: adminReducer,
router: connectRouter(history),
userDashboardSettings: userGaolsReducer
});

Unable to get data from created() to data() in VueJS 2

I am fetching data from API inside the created method and i want to use these data in the page.
Here is my code.
created(){
let id = this.$route.params.id
let videos;
this.$axios.get(this.$axios.defaults.apiURL + 'v1.0.0/tips/' +id,).then((response) => {
this.videos = response.data.data;
}, (error) => {
toast.$toast.error('Something went wrong! Please try again', {
position: 'top'
})
});
},
data(){
let videos = this.videos;
return {
video: {
sources: [{
src: videos.video_url,
type: 'video/mp4'
}],
options: {
autoplay: true,
volume: 0.6,
poster: videos.thumbnail
}
}
}
}
I am getting error that thumbnail and video_url is not defined. This 2 values are coming from API response. How can i solve this? Thanks
I can see two obvious issues with your code (without seeing it in action):
created is a synchronous hook, but your axios request is returning a promise. Instead of waiting for the promise, you are immediately trying to show the result, hence the issue you are encountering - the data just hasn't arrived yet.
Your use of this seems a bit chaotic (i.e. let videos = this.videos - where would this.videos come from? The only other 'videos' is declared inside of a different function with let)
There are multiple ways to solve this, depending on what you want to show while you are fetching the data and what type of component this is - if you want to show a spinner while you are waiting for the request to be answered, or if you just want to show some progress bar on the previous page and only enter this one once it's loaded.
In-component loading
In the first case, I would suggest setting a variable or using a loader management solution like vue-wait. Your code could look like this then:
data() {
return {
loading: true,
videos: null,
}
},
computed: {
video() {
return this.videos ? {
sources: [{
src: this.videos.video_url,
type: 'video/mp4'
}],
options: {
autoplay: true,
volume: 0.6,
poster: this.videos.thumbnail
}
} : null
}
},
methods: {
fetch() {
let id = this.$route.params.id
this.$axios.get(this.$axios.defaults.apiURL + 'v1.0.0/tips/' + id, ).then((response) => {
this.videos = response.data.data;
}, (error) => {
toast.$toast.error('Something went wrong! Please try again', {
position: 'top'
})
}).finally(() => (this.loading = false));
},
},
created() {
this.fetch()
},
In your template, you would add somewhere v-if=!loading to make sure that the request has finished before you try to show something
Data-fetching before entering page
If this is a page though, you could request the data in beforeRouteEnter - there's a whole article that explains the principle on the vue site

Vue: Component method from vuex module?

I'm using namespaced modules for state management in vuex, I try to keep all my actions mutations inside my modules as this helps me keep most of my code in the same place (modules acting like classes or similar) hoever there's an issue, I'd like to fire a component method to clear a form when a vuex action is successfull (that is the axios request gets an OK/200 response) but sadly I can't fire a methos from vuex module into my component ( there's no this inisde module).
I also tried adding a .then to my action call but it fires right after I call the action...
I guess I could move the action into the component itself but I'd rather not, what do you guys suggest?
My component:
stripeSourceHandler: function(sourceId)
{
if(this.customerSources.length == 0)
{
console.log('createSourceAndCustomer');
this.createSourceAndCustomer({ id: sourceId });
}
else
{
console.log('addSource');
this.addSource({ id: sourceId }).then(alert('Form cleared')); //this fires right after calling addSource
};
},
My module action:
addSource({ commit }, sourceId)
{
commit('Loader/SET_LOADER', { status:1, message: 'Procesando...' }, { root: true });
axios.post('/stripe/add-source', sourceId)
.then((response) => {
commit('Loader/SET_LOADER', { status:2, message: response.data.message }, { root: true });
commit('ADD_SOURCE', response.data.customer);
//I can't clear component form from this...
},
(error) => {
commit('Loader/SET_LOADER', { status:3, errors: error, message: 'Error al añadir el pago.' }, { root: true });
});
},
Two issues:
You need to return the promise from the action so that you can use .then() to schedule code to be executed once the action has completed (this code being whatever you need to do to clear the form).
.then() takes one (or two) functions as parameters which will be called once the promise has resolved, instead you're just calling alert() immediately.
It'll be something like:
Component method
stripeSourceHandler(sourceId) {
if (this.customerSources.length == 0) {
this.createSourceAndCustomer({ id: sourceId });
} else {
this.addSource({ id: sourceId }).then(() => {
// Clear the form here
alert('Form cleared');
});
}
}
Vuex action
addSource({ commit }, sourceId) {
commit('Loader/SET_LOADER', { status:1, message: 'Procesando...' }, { root: true });
// Return the promise here
return axios.post('/stripe/add-source', sourceId)
.then(response => {
commit('Loader/SET_LOADER', { status:2, message: response.data.message }, { root: true });
commit('ADD_SOURCE', response.data.customer);
}, error => {
commit('Loader/SET_LOADER', { status:3, errors: error, message: 'Error al añadir el pago.' }, { root: true });
});
}

Is it possible to use startUndoable with custom action in react-admin?

I wondered if passing a custom action with a custom fetch and type (which is not update) to startUndoable is feasible.
Or is it possible that somehow define a pattern with values in meta and based on this pattern the view would be re-rendered?
In this case the IMPORT is updating only one property in the database with a fixed value.
This is the action:
export const importParcel = ({ id }) => ({
type: IMPORT_PARCEL,
payload: {
id
},
meta: {
resource: 'parcels',
fetch: IMPORT,
refresh: true,
onSuccess: {
notification: {
body: 'Parcel Imported',
level: 'info'
}
},
onFailure: {
notification: {
body: 'Error: Import failed',
level: 'warning'
}
}
}
});
This is the handler:
fetchUtils
.fetchJson(`/${resource}/import/${params.id}`, {
method: 'PUT',
headers: getAuthenticationHeaders()
})
.then(res => ({ data: res.json }));
Thanks for your help! :)
Sure, as explained in the Optimistic Rendering and Undo documentation you can create whatever action you want with startUndoable:
import { startUndoable as startUndoableAction } from 'ra-core';
class App extends Component {
handleImport = () => {
this.props.startUndoable(importParcel());
};
render() {
return <Button onClick={this.handleImport}>Import Parcel</Button>;
}
}
export default connect(null, { startUndoable: startUndoableAction })(App);
You action must have a onSuccess notification in order to display the undo button.
The rest should be implemented in your data provider.

Problem with vue-google-oauth-2 in Vue.js

I am trying to add a Google Sign-In button to my Vue.js application and I found the vue-google-oauth2 plugin. I installed it and followed exactly the sample.html code to integrate it in my application, this way:
<template>
<div>
<h1>Test</h1>
<button #click="handleClickSignIn" :disabled="!isLoaded">signIn</button>
</div>
</template>
<script>
/**
* You should first need to place these 2 lines of code in your APP ENTRY file, e.g. src/main.js
*
* import GAuth from 'vue-google-oauth2'
* Vue.use(GAuth, {clientId: '4584XXXXXXXX-2gqknkvdjfkdfkvb8uja2k65sldsms7qo9.apps.googleusercontent.com'})
*
*/
export default {
name: 'test',
props: [],
components: {
},
data () {
return {
isLoaded: false
}
},
computed: {
},
methods: {
handleClickSignIn(){
this.$gAuth.signIn(function (user) {
//on success do something
console.log('user', user)
}, function (error) {
//on fail do something
})
}
},
mounted(){
let that = this
let checkGauthLoad = setInterval(function(){
that.isLoaded = that.$gAuth.isLoaded()
console.log('checked', that.isLoaded)
if(that.isLoaded) clearInterval(checkGauthLoad)
}, 1000);
}
}
</script>
The problem is that the isLoaded() method never returns true, with the Google Chrome console telling me every time I press on the button that the google api is not ready, that is the plugin console message printed when the GoogleAuthInstance is false. Could anyone help me?
Use isInit instead of isLoaded as the latter will be/is deprecated.
Add to main.js
import GAuth from 'vue-google-oauth2'
Vue.use(GAuth, {
clientId: '....apps.googleusercontent.com',
scope: 'email',
prompt: 'consent',
fetch_basic_profile: true
})
new Vue({
...
render: (h) => h(App),
}).$mount("#app");

Categories