У меня проблема с тем, что после входа пользователя в систему пользователь не обновляет последние данные, и я не вижу его в пользовательском интерфейсе.
Пользователь является частью последнего возвращенного объекта токена, и я могу см. в консоли, что vue загружает пользователя с его предыдущим состоянием, не загружая его снова с последним полученным токеном после того, как jwt был обновлен и установлен как постоянный.
Я думаю, что мне нужно создать вычисленный на функция, которая возвращает токен, или свойство токена, которое изменяется, я не уверен ...
следующий код:
root-component.vue
<template>
<app v-bind:tokenInstance="tokenInstance" v-bind:saveUserLocales="saveUserLocales"></app>
</template>
<script>
const { getTokenInstance, getTokenInstanceFromStorage, fetchProtectedApi } = require('../auth/jwt.js');
const { onAkuoJwtChanged } = require('../jwt-akuo-token-listener.js');
const { sendToAllTabs } = require('../cross-environment-code/messaging');
const storedTokenInstance = getTokenInstanceFromStorage();
const rootComponent = {
components: {
'app': require('./app.vue')
},
data() {
return {
tokenInstance: storedTokenInstance
};
},
created() {
onAkuoJwtChanged(this.setTokenInstance);
console.log('creation of function onAkuoJwtChanged with ');
},
methods: {
setTokenInstance(jwt) {
console.log('setTokenInstance:', jwt)
this.tokenInstance = getTokenInstance(jwt);
},
// this could probably be ubstracted to a more generic `saveUser`. Maybe we will save user elsewhere too and we do not want to deal with seting token there as well
saveUserLocales(userId, locales) {
return fetchProtectedApi(`users/${userId}`, {
method: 'PUT',
body: { locales }
}).then(
({ token }) => {
this.setTokenInstance(token); // this could be removed if sending singedIn would trigger a local storage set and this in turn would trigger onAkuoJwtChanged that calls thissetTokenInstance
// here -> engine.content -> background page (where we store the token)
sendToAllTabs({
fn: 'signedIn',
message: token
}); // this is fine since both options page and background page share the same localStorage! according to this stackoverflow post: https://stackoverflow.com/a/8790423
},
(error) => {
// TODO notify user that it failed
console.error(error);
}
);
}
}
};
app.vue
<template>
<div>
<no-token v-if="displaySignIn" v-bind:tokenInstance="tokenInstance"></no-token>
<with-chosen-locales v-else v-bind:userLocales="user.locales" v-bind:saveUserLocales="saveUserLocales" v-bind:userId="userId"></with-chosen-locales>
</div>
</template>
<script>
const { getUserIntance } = require('../models/user');
module.exports = {
components: {
'no-token': require('./no-token.vue'),
'no-locales': require('./no-locales.vue'),
'with-chosen-locales': require('./with-chosen-locales.vue')
},
props: ['tokenInstance', 'saveUserLocales'],
data() {
return {};
},
computed: {
displaySignIn() {
console.log('displaySignIn: ', (!this.tokenInstance || this.tokenInstance.isExpired()));
return !this.tokenInstance || this.tokenInstance.isExpired();
},
hasNotChosenLocales() {
console.log('hasNotChosenLocales: ', (this.userInstance && !this.userInstance.hasChosenLocales()))
return this.userInstance && !this.userInstance.hasChosenLocales();
},
hasNotDetectedLocales() {
console.log('hasNotDetectedLocales: ', (this.userInstance && !this.userInstance.detectedLocales()))
return this.userInstance && !this.userInstance.detectedLocales();
},
user() {
console.log('user: ', this.tokenInstance.getUser())
return this.tokenInstance.getUser();
},
userInstance() {
console.log('userInstance: ', this.user && getUserIntance(this.user))
return this.user && getUserIntance(this.user);
},
userId() {
console.log('userId: ', (this.userInstance && this.userInstance.getJson()._id))
return this.userInstance && this.userInstance.getJson()._id;
}
}
};
</script>
с выбранными локалями. vue
<template>
<div v-if="isEditMode === false">
<div>chosen locales</div>
<template v-for="localeObj in chosenLocales">
<div>{{localeObj.locale}}</div>
</template>
<button v-on:click="switchToEditMode">Edit</button>
</div>
<div v-else>
<div>Edit locales</div>
<template v-for="localeObj in availableLocales">
<input type="checkbox" id="localeObj.locale" v-bind:checked="localeObj.chosen" v-on:click="localeObj.chosen = !localeObj.chosen">
<label for="localeObj.locale">{{localeObj.locale}}</label>
</template>
<button v-on:click="save">Save</button>
</div>
</template>
<script>
const { fetchProtected } = require('../auth/jwt.js');
function cloneLocales(locales) {
return locales.map(x => Object.assign({}, x));
}
module.exports = {
props: ['userLocales', 'saveUserLocales', 'userId'],
data() {
return {
componentLocales: cloneLocales(this.userLocales),
availableLocales: [],
editMode: false };
},
computed: {
chosenLocales() {
return this.componentLocales.filter(x => x.chosen);
},
isEditMode()
{
console.log('this.userLocales:', this.userLocales);
return this.editMode;
}
},
methods: {
switchToEditMode() {
return fetchProtected(`data/list.json`, {
method: 'GET'
}).then(
(v) => {
this.availableLocales = v.map(l => {
return {
locale:l,
chosen: this.chosenLocales.filter(x => x.locale === l).length > 0
};});
this.editMode = true;
},
(error) => {
// TODO notify user that it failed
console.error(error);
}
);
},
save() {
this.saveUserLocales(this.userId, this.availableLocales.filter(x => x.chosen));
this.componentLocales = this.availableLocales;
this.editMode = false;
},
}};
</script>
Ваша помощь, Ассаф