diff --git a/src/components/Article/Details.vue b/src/components/Article/Details.vue
index a900e30..f78d11f 100644
--- a/src/components/Article/Details.vue
+++ b/src/components/Article/Details.vue
@@ -45,7 +45,17 @@
Открыть
- Добавить
+
+ Добавить
+
+
+ work_outline
+ Добавлено {{ getArticleAddedAt(article.id) | formattedDate }}
+
@@ -54,6 +64,7 @@
diff --git a/src/store.js b/src/store.js
index a1cf36a..d3af844 100644
--- a/src/store.js
+++ b/src/store.js
@@ -4,6 +4,7 @@ import Vuex from 'vuex';
import articleModule from '@/store/articles';
import generalModule from '@/store/general';
import userModule from '@/store/user';
+import userDataModule from '@/store/userData';
Vue.use(Vuex);
@@ -12,5 +13,6 @@ export default new Vuex.Store({
articleModule,
generalModule,
userModule,
+ userDataModule,
},
});
diff --git a/src/store/user.js b/src/store/user.js
index f040096..86a9b31 100644
--- a/src/store/user.js
+++ b/src/store/user.js
@@ -54,9 +54,10 @@ export default {
signOut() {
firebase.auth().signOut();
},
- stateChanged({ commit }, payload) {
+ stateChanged({ commit, dispatch }, payload) {
if (payload) {
commit('setUser', payload.uid);
+ dispatch('loadUserData', payload.uid);
} else {
commit('unSetUser');
}
@@ -64,5 +65,6 @@ export default {
},
getters: {
isUserAuthentificated: state => state.user.isAuthentificated,
+ userId: state => state.user.uid,
},
};
diff --git a/src/store/userData.js b/src/store/userData.js
new file mode 100644
index 0000000..f44b301
--- /dev/null
+++ b/src/store/userData.js
@@ -0,0 +1,111 @@
+import Vue from 'vue';
+
+const defaultUserData = {
+ articles: {},
+ words: {},
+};
+
+export default {
+ state: {
+ userData: defaultUserData,
+ },
+ actions: {
+ loadUserData({ commit }, userId) {
+ commit('setProcessing', true);
+
+ let userDataRef = Vue.$db.collection('userData').doc(userId);
+ userDataRef.get()
+ .then((data) => {
+ let userData = data.exists ? data.data() : defaultUserData;
+
+ if (!userData.articles) {
+ userData.articles = {};
+ }
+
+ commit('setUserData', userData);
+ })
+ .catch(e => window.console.error(e));
+
+ commit('setProcessing', false);
+ },
+ addUserArticle({ commit, getters }, articleId) {
+ commit('setProcessing', true);
+
+ const userDataRef = Vue.$db.collection('userData').doc(getters.userId);
+ const article = {
+ addedAt: new Date(),
+ parts: {},
+ };
+
+ userDataRef.set({
+ articles: {
+ [articleId]: article,
+ }
+ }, { merge: true })
+ .then(() => commit('addUserArticle', { articleId, article }))
+ .catch(e => window.console.error(e));
+
+ commit('setProcessing', false);
+ },
+ updateUserArticlePartStats({ commit, getters }, { articleId, partId }) {
+ const userDataRef = Vue.$db.collection('userData').doc(getters.userId);
+ const timestamp = new Date();
+ const articles = getters.userData.articles;
+
+ if (!articles.hasOwnProperty(articleId) || !articles[articleId].parts.hasOwnProperty(partId)) {
+ userDataRef.update({
+ [`articles.${articleId}.parts.${partId}.addedAt`]: timestamp,
+ })
+ .then(() => commit('addUserArticlePart', { articleId, partId, timestamp }))
+ .catch(e => window.console.error(e));
+ }
+
+ userDataRef.update({
+ [`articles.${articleId}.parts.${partId}.lastOpenedAt`]: timestamp,
+ })
+ .then(() => commit('openUserArticlePart', { articleId, partId, timestamp }))
+ .catch(e => window.console.error(e));
+ },
+ finishUserArticlePart({ commit, getters }, { articleId, partId, rating }) {
+ commit('setProcessing', true);
+
+ const userDataRef = Vue.$db.collection('userData').doc(getters.userId);
+ const timestamp = new Date();
+
+ userDataRef.update({
+ [`articles.${articleId}.parts.${partId}.finishedAt`]: timestamp,
+ [`articles.${articleId}.parts.${partId}.rating`]: rating,
+ })
+ .then(() => commit('finishUserArticlePart', { articleId, partId, timestamp, rating }))
+ .catch(e => window.console.error(e));
+
+ commit('setProcessing', false);
+ }
+ },
+ mutations: {
+ setUserData(state, payload) {
+ Vue.set(state, 'userData', payload);
+ },
+ addUserArticle(state, { articleId, article }) {
+ Vue.set(state.userData.articles, articleId, article);
+ },
+ addUserArticlePart(state, { articleId, partId, timestamp }) {
+ if (state.userData.articles[articleId].parts[partId]) {
+ Vue.set(state.userData.articles[articleId].parts[partId], 'addedAt', timestamp);
+ return;
+ }
+
+ Vue.set(state.userData.articles[articleId].parts, partId, { addedAt: timestamp });
+ },
+ openUserArticlePart(state, { articleId, partId, timestamp }) {
+ Vue.set(state.userData.articles[articleId].parts[partId], 'lastOpenedAt', timestamp);
+ },
+ finishUserArticlePart(state, { articleId, partId, timestamp, rating }) {
+ Vue.set(state.userData.articles[articleId].parts[partId], 'finishedAt', timestamp);
+ Vue.set(state.userData.articles[articleId].parts[partId], 'rating', rating);
+ },
+ },
+ getters: {
+ userData: state => state.userData,
+ },
+};
diff --git a/src/views/ArticlePart.vue b/src/views/ArticlePart.vue
index dd678fe..72963a0 100644
--- a/src/views/ArticlePart.vue
+++ b/src/views/ArticlePart.vue
@@ -1,12 +1,58 @@
+
+
+
+
+
+ Чтение этой части завершено {{ finishedAt | formattedDate }}
+
+
+ Оценка
+
+
+
+
+
+
+
+
+
+ check Завершить
+
+
+
+
+
+ Чтение этой части завершено.
+
+
+ Оценка
+
+
+
+
+
+ close Закрыть
+
+
+ check Подтвердить
+
+
+
+
+
@@ -31,13 +77,56 @@
BookPartContent,
BookPartWords,
},
+ computed: {
+ currentUserArticle() {
+ const articles = this.$store.getters.userData.articles;
+ if (!articles) {
+ return null;
+ }
+ return articles[this.articleId];
+ },
+ currentUserArticlePart() {
+ const article = this.currentUserArticle;
+ if (!article) {
+ return null;
+ }
+
+ const articleParts = article.parts;
+ if (!articleParts) {
+ return null;
+ }
+
+ return articleParts[this.partId];
+ },
+ finishedAt() {
+ const articlePart = this.currentUserArticlePart;
+ return articlePart ? articlePart.finishedAt : null
+ },
+ storedRating() {
+ const articlePart = this.currentUserArticlePart;
+ return articlePart ? articlePart.rating : 0;
+ }
+ },
+ methods: {
+ finishWork() {
+ this.$store.dispatch('finishUserArticlePart', {
+ articleId: this.articleId,
+ partId: this.partId,
+ rating: this.rating,
+ });
+ this.finishDialog = false;
+ }
+ },
data: () => ({
part: null,
+ finishDialog: false,
+ rating: 0,
}),
created() {
+ const { articleId, partId } = this;
Vue.$db.collection('articleParts')
- .where('articleId', '==', this.articleId)
- .where('articlePartId', '==', this.partId)
+ .where('articleId', '==', articleId)
+ .where('articlePartId', '==', partId)
.get()
.then((querySnapshot) => {
const snapDocs = querySnapshot.docs;
@@ -45,7 +134,13 @@
this.part = Object.assign({}, snapDocs[0].data());
}
})
- .catch(e => console.error(e));
+ .then(() => {
+ this.$store.dispatch('updateUserArticlePartStats', {
+ articleId,
+ partId,
+ });
+ })
+ .catch(e => window.console.error(e));
}
};