mirror of
https://github.com/Dannecron/ich-lerne-deutsch.git
synced 2025-12-26 05:12:34 +03:00
Fix linter, fix files by linter rules.
Fix backup file.
This commit is contained in:
28
src/App.vue
28
src/App.vue
@@ -1,23 +1,23 @@
|
||||
<template>
|
||||
<v-app>
|
||||
<app-header></app-header>
|
||||
<v-app>
|
||||
<app-header></app-header>
|
||||
|
||||
<v-content>
|
||||
<router-view />
|
||||
</v-content>
|
||||
<v-content>
|
||||
<router-view />
|
||||
</v-content>
|
||||
|
||||
<app-footer></app-footer>
|
||||
</v-app>
|
||||
<app-footer></app-footer>
|
||||
</v-app>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AppHeader from '@/components/AppHeader';
|
||||
import AppFooter from '@/components/AppFooter';
|
||||
import AppHeader from '@/components/AppHeader';
|
||||
import AppFooter from '@/components/AppFooter';
|
||||
|
||||
export default {
|
||||
export default {
|
||||
components: {
|
||||
AppHeader,
|
||||
AppFooter,
|
||||
}
|
||||
};
|
||||
AppHeader,
|
||||
AppFooter,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
|
||||
|
||||
<script>
|
||||
export default {
|
||||
computed: {
|
||||
year: () => new Date().getFullYear(),
|
||||
},
|
||||
};
|
||||
export default {
|
||||
computed: {
|
||||
year: () => new Date().getFullYear(),
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -10,10 +10,11 @@
|
||||
<v-icon left v-html="item.icon"></v-icon>
|
||||
</v-list-tile-action>
|
||||
<v-list-tile-content>
|
||||
<v-list-tile-title v-text="item.title"></v-list-tile-title>
|
||||
<v-list-tile-title v-text="item.title"></v-list-tile-title>
|
||||
</v-list-tile-content>
|
||||
</v-list-tile>
|
||||
<v-list-tile @click.prevent="signOut" v-if="isUserAuthentificated">
|
||||
|
||||
<v-list-tile @click.prevent="signOut" v-if="isUserAuthenticated">
|
||||
<v-list-tile-action>
|
||||
<v-icon left v-html="'exit_to_app'"></v-icon>
|
||||
</v-list-tile-action>
|
||||
@@ -24,7 +25,7 @@
|
||||
</v-list>
|
||||
</v-navigation-drawer>
|
||||
<v-toolbar app dark class="primary">
|
||||
<v-toolbar-side-icon @click.stop="drawer = !drawer;" class="hidden-md-and-up"></v-toolbar-side-icon>
|
||||
<v-toolbar-side-icon @click.stop="drawer = !drawer" class="hidden-md-and-up"></v-toolbar-side-icon>
|
||||
<router-link to="/" tag="span" style="cursor: pointer;">
|
||||
<v-toolbar-title v-text="'Dannc Ich Lerne Deutsch'"></v-toolbar-title>
|
||||
</router-link>
|
||||
@@ -32,9 +33,9 @@
|
||||
<v-toolbar-items class="hidden-sm-and-down">
|
||||
<v-btn v-for="(item, i) in menuItems" flat :key="`menuitem-${i}`" :to="item.route">
|
||||
<v-icon left v-html="item.icon"></v-icon>
|
||||
{{item.title}}
|
||||
{{ item.title }}
|
||||
</v-btn>
|
||||
<v-btn flat @click.prevent="signOut" v-if="isUserAuthentificated">
|
||||
<v-btn flat @click.prevent="signOut" v-if="isUserAuthenticated">
|
||||
<v-icon left v-html="'exit_to_app'"></v-icon>
|
||||
Выйти
|
||||
</v-btn>
|
||||
@@ -44,49 +45,30 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
drawer: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
signOut() {
|
||||
this.$confirm('Вы точно хотите выйти?').then(res => {
|
||||
if (res) {
|
||||
this.$store.dispatch('signOut');
|
||||
}
|
||||
});
|
||||
},
|
||||
changeLocation(to) {
|
||||
this.$router.push(to);
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isUserAuthentificated() {
|
||||
return this.$store.getters.isUserAuthentificated;
|
||||
},
|
||||
menuItems() {
|
||||
if (this.isUserAuthentificated) {
|
||||
return [
|
||||
{
|
||||
icon: 'visibility',
|
||||
title: 'Статьи',
|
||||
route: '/articles',
|
||||
},
|
||||
{
|
||||
icon: 'extension',
|
||||
title: 'Учить слова',
|
||||
route: '/words',
|
||||
},
|
||||
{
|
||||
icon: 'account_circle',
|
||||
title: 'Мой профиль',
|
||||
route: '/profile',
|
||||
},
|
||||
];
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
drawer: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
signOut() {
|
||||
this.$confirm('Вы точно хотите выйти?').then(res => {
|
||||
if (res) {
|
||||
this.$store.dispatch('signOut');
|
||||
}
|
||||
|
||||
});
|
||||
},
|
||||
changeLocation(to) {
|
||||
this.$router.push(to);
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
isUserAuthenticated() {
|
||||
return this.$store.getters.isUserAuthenticated;
|
||||
},
|
||||
menuItems() {
|
||||
if (this.isUserAuthenticated) {
|
||||
return [
|
||||
{
|
||||
icon: 'visibility',
|
||||
@@ -94,19 +76,38 @@
|
||||
route: '/articles',
|
||||
},
|
||||
{
|
||||
icon: 'input',
|
||||
title: 'Войти',
|
||||
route: '/sign_in',
|
||||
icon: 'extension',
|
||||
title: 'Учить слова',
|
||||
route: '/words',
|
||||
},
|
||||
{
|
||||
icon: 'lock_open',
|
||||
title: 'Регистрация',
|
||||
route: '/sign_up',
|
||||
icon: 'account_circle',
|
||||
title: 'Мой профиль',
|
||||
route: '/profile',
|
||||
},
|
||||
];
|
||||
},
|
||||
}
|
||||
|
||||
return [
|
||||
{
|
||||
icon: 'visibility',
|
||||
title: 'Статьи',
|
||||
route: '/articles',
|
||||
},
|
||||
{
|
||||
icon: 'input',
|
||||
title: 'Войти',
|
||||
route: '/sign_in',
|
||||
},
|
||||
{
|
||||
icon: 'lock_open',
|
||||
title: 'Регистрация',
|
||||
route: '/sign_up',
|
||||
},
|
||||
];
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -36,13 +36,25 @@
|
||||
<v-layout row>
|
||||
<v-flex xs12>
|
||||
<v-card-actions>
|
||||
<!-- <v-rating v-model="article.rating" color="yellow" readonly dense half-increments></v-rating>
|
||||
<!-- <v-rating
|
||||
v-model="article.rating"
|
||||
color="yellow"
|
||||
readonly
|
||||
dense
|
||||
half-increments
|
||||
>
|
||||
</v-rating>
|
||||
<div class="ml-1">
|
||||
<span>{{ article.rating }}</span>
|
||||
<span>({{ article.ratingsCount }})</span>
|
||||
</div> -->
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn v-if="!expandDetails" class="primary" flat :to="{ name: 'article', params: { articleId: article.id } }">
|
||||
<v-btn
|
||||
v-if="!expandDetails"
|
||||
:to="{ name: 'article', params: { articleId: article.id } }"
|
||||
class="primary"
|
||||
flat
|
||||
>
|
||||
Открыть
|
||||
</v-btn>
|
||||
<v-btn v-if="expandDetails && canAddArticle(article.id)"
|
||||
@@ -64,48 +76,48 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import YoutubeButton from '@/components/Article/YoutubeButton';
|
||||
import { getArticleLevel, declOfNum } from '@/utils';
|
||||
import { mapGetters } from 'vuex';
|
||||
import YoutubeButton from '@/components/Article/YoutubeButton';
|
||||
import { getArticleLevel, declOfNum } from '@/utils';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
article: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
expandDetails: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
export default {
|
||||
props: {
|
||||
article: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
computed: {
|
||||
partsDescription() {
|
||||
const partsCount = this.article.parts.length;
|
||||
const partsCountWord = declOfNum(partsCount, ['часть', 'части', 'частей']);
|
||||
return `${partsCount} ${partsCountWord}`;
|
||||
},
|
||||
...mapGetters(['isUserAuthentificated', 'getProcessing', 'userData']),
|
||||
expandDetails: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
methods: {
|
||||
getArticleLevel,
|
||||
getUserDataArticle(articleId) {
|
||||
return this.userData.articles[articleId];
|
||||
},
|
||||
canAddArticle(articleId) {
|
||||
const article = this.getUserDataArticle(articleId);
|
||||
return this.isUserAuthentificated && !this.getProcessing && !article;
|
||||
},
|
||||
addArticle(articleId) {
|
||||
this.$store.dispatch('addUserArticle', articleId);
|
||||
},
|
||||
getArticleAddedAt(articleId) {
|
||||
const article = this.getUserDataArticle(articleId);
|
||||
return article.addedAt;
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
partsDescription() {
|
||||
const partsCount = this.article.parts.length;
|
||||
const partsCountWord = declOfNum(partsCount, ['часть', 'части', 'частей']);
|
||||
return `${partsCount} ${partsCountWord}`;
|
||||
},
|
||||
components: {
|
||||
YoutubeButton,
|
||||
...mapGetters(['isUserAuthenticated', 'getProcessing', 'userData']),
|
||||
},
|
||||
methods: {
|
||||
getArticleLevel,
|
||||
getUserDataArticle(articleId) {
|
||||
return this.userData.articles[articleId];
|
||||
},
|
||||
};
|
||||
canAddArticle(articleId) {
|
||||
const article = this.getUserDataArticle(articleId);
|
||||
return this.isUserAuthenticated && !this.getProcessing && !article;
|
||||
},
|
||||
addArticle(articleId) {
|
||||
this.$store.dispatch('addUserArticle', articleId);
|
||||
},
|
||||
getArticleAddedAt(articleId) {
|
||||
const article = this.getUserDataArticle(articleId);
|
||||
return article.addedAt;
|
||||
},
|
||||
},
|
||||
components: {
|
||||
YoutubeButton,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -38,12 +38,20 @@
|
||||
<v-tab-item :key="'german'">
|
||||
<div v-for="(paragraph, i) in part.content" :key="`paragraph1-${i}`">
|
||||
<span> </span>
|
||||
<span v-for="(sentence, y) in paragraph.sentences" :key="`paragraph1-sentence${y}`" :style="textStyle">
|
||||
<span
|
||||
v-for="(sentence, y) in paragraph.sentences"
|
||||
:key="`paragraph1-sentence${y}`"
|
||||
:style="textStyle"
|
||||
>
|
||||
<span>
|
||||
{{ sentence.origText }}
|
||||
</span>
|
||||
<v-icon :size="fontSize" @click.prevent="toggleVisibility(i, y)">help</v-icon>
|
||||
<span class="success--text" style="font-weight:bold;" v-if="getVisibilityFlag(i, y).value">
|
||||
<span
|
||||
v-if="getVisibilityFlag(i, y).value"
|
||||
class="success--text"
|
||||
style="font-weight:bold;"
|
||||
>
|
||||
{{ sentence.transText }}
|
||||
</span>
|
||||
</span>
|
||||
@@ -55,7 +63,11 @@
|
||||
<v-layout row wrap v-for="(paragraph, i) in part.content" :key="`paragraph2-${i}`">
|
||||
<v-flex xs6>
|
||||
<span> </span>
|
||||
<span v-for="(sentence, y) in paragraph.sentences" :key="`paragraph2-sentence-orig${y}`" :style="textStyle">
|
||||
<span
|
||||
v-for="(sentence, y) in paragraph.sentences"
|
||||
:key="`paragraph2-sentence-orig${y}`"
|
||||
:style="textStyle"
|
||||
>
|
||||
<span>
|
||||
{{ sentence.origText }}
|
||||
</span>
|
||||
@@ -64,7 +76,11 @@
|
||||
|
||||
<v-flex xs6>
|
||||
<span> </span>
|
||||
<span v-for="(sentence, y) in paragraph.sentences" :key="`paragraph2-sentence-trans${y}`" :style="textStyle">
|
||||
<span
|
||||
v-for="(sentence, y) in paragraph.sentences"
|
||||
:key="`paragraph2-sentence-trans${y}`"
|
||||
:style="textStyle"
|
||||
>
|
||||
<span>
|
||||
{{ sentence.transText }}
|
||||
</span>
|
||||
@@ -76,65 +92,61 @@
|
||||
</v-tabs>
|
||||
</div>
|
||||
</div>
|
||||
</v-card>
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
part: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
export default {
|
||||
props: {
|
||||
part: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
data: () => ({
|
||||
tabMode: 'german',
|
||||
visibillityKeys: [],
|
||||
fontSize: 18,
|
||||
}),
|
||||
created() {
|
||||
for (let i = 0; i < this.part.content.length; i++) {
|
||||
for (let y = 0; y < this.part.content[i].sentences.length; y++) {
|
||||
this.visibillityKeys.push({
|
||||
key: `${i}${y}`,
|
||||
value: false,
|
||||
});
|
||||
}
|
||||
},
|
||||
data: () => ({
|
||||
tabMode: 'german',
|
||||
visibilityKeys: [],
|
||||
fontSize: 18,
|
||||
}),
|
||||
created() {
|
||||
for (let i = 0; i < this.part.content.length; i++) {
|
||||
for (let y = 0; y < this.part.content[i].sentences.length; y++) {
|
||||
this.visibilityKeys.push({
|
||||
key: `${i}${y}`,
|
||||
value: false,
|
||||
});
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
playerWidth() {
|
||||
if (this.$vuetify.breakpoint.mdAndUp) {
|
||||
return '640px';
|
||||
}
|
||||
|
||||
return '250px';
|
||||
},
|
||||
playerHeight() {
|
||||
if (this.$vuetify.breakpoint.mdAndUp) {
|
||||
return '390px';
|
||||
}
|
||||
|
||||
return '190px';
|
||||
},
|
||||
textStyle() {
|
||||
return {
|
||||
fontSize: `${this.fontSize}px`,
|
||||
};
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getVisibilityFlag(i, y) {
|
||||
return this.visibillityKeys.find(v => v.key === `${i}${y}`);
|
||||
},
|
||||
toggleVisibility(i, y) {
|
||||
let flag = this.getVisibilityFlag(i, y);
|
||||
flag.value = !flag.value;
|
||||
},
|
||||
}
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
playerWidth() {
|
||||
if (this.$vuetify.breakpoint.mdAndUp) {
|
||||
return '640px';
|
||||
}
|
||||
|
||||
return '250px';
|
||||
},
|
||||
playerHeight() {
|
||||
if (this.$vuetify.breakpoint.mdAndUp) {
|
||||
return '390px';
|
||||
}
|
||||
|
||||
return '190px';
|
||||
},
|
||||
textStyle() {
|
||||
return {
|
||||
fontSize: `${this.fontSize}px`,
|
||||
};
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getVisibilityFlag(i, y) {
|
||||
return this.visibilityKeys.find(v => v.key === `${i}${y}`);
|
||||
},
|
||||
toggleVisibility(i, y) {
|
||||
let flag = this.getVisibilityFlag(i, y);
|
||||
flag.value = !flag.value;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
|
||||
@@ -25,38 +25,38 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import { mapGetters } from 'vuex';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
part: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
articleId: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
export default {
|
||||
props: {
|
||||
part: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['isUserAuthentificated', 'getProcessing', 'userData']),
|
||||
currentUserArticle() {
|
||||
return this.userData.articles[this.articleId];
|
||||
},
|
||||
currentUserArticlePart() {
|
||||
const article = this.currentUserArticle;
|
||||
return article ? article.parts[this.part.id] : null;
|
||||
},
|
||||
isUserArticleAdded() {
|
||||
return this.isUserAuthentificated && !this.getProcessing && !!this.currentUserArticle;
|
||||
},
|
||||
finishedAt() {
|
||||
const { currentUserArticlePart } = this;
|
||||
return currentUserArticlePart ? currentUserArticlePart.finishedAt : null;
|
||||
},
|
||||
articleId: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
methods: {
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['isUserAuthenticated', 'getProcessing', 'userData']),
|
||||
currentUserArticle() {
|
||||
return this.userData.articles[this.articleId];
|
||||
},
|
||||
};
|
||||
currentUserArticlePart() {
|
||||
const article = this.currentUserArticle;
|
||||
return article ? article.parts[this.part.id] : null;
|
||||
},
|
||||
isUserArticleAdded() {
|
||||
return this.isUserAuthenticated && !this.getProcessing && !!this.currentUserArticle;
|
||||
},
|
||||
finishedAt() {
|
||||
const { currentUserArticlePart } = this;
|
||||
return currentUserArticlePart ? currentUserArticlePart.finishedAt : null;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
@@ -34,57 +34,57 @@
|
||||
{{ snackbar.text }}
|
||||
</v-snackbar>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import { getFullOriginalWord, WORD_TYPES } from '@/utils';
|
||||
import { mapGetters } from 'vuex';
|
||||
import { getFullOriginalWord, WORD_TYPES } from '@/utils';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
wordEntity: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
export default {
|
||||
props: {
|
||||
wordEntity: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
data: () => ({
|
||||
snackbar: {
|
||||
isEnabled: false,
|
||||
text: null,
|
||||
},
|
||||
}),
|
||||
computed: {
|
||||
...mapGetters(['userData', 'getProcessing']),
|
||||
isWord() {
|
||||
return this.wordEntity.type === WORD_TYPES.WORD;
|
||||
},
|
||||
isRedewndung() {
|
||||
return this.wordEntity.type === WORD_TYPES.REDEWNNDUNG;
|
||||
},
|
||||
isProcessing() {
|
||||
return this.getProcessing;
|
||||
},
|
||||
},
|
||||
data: () => ({
|
||||
snackbar: {
|
||||
isEnabled: false,
|
||||
text: null,
|
||||
},
|
||||
methods: {
|
||||
getFullOriginalWord,
|
||||
addWord(entity) {
|
||||
const userWords = this.userData.words;
|
||||
const wordAdded = userWords[entity.key];
|
||||
if (wordAdded) {
|
||||
this.snackbar.isEnabled = true;
|
||||
this.snackbar.text = 'Слово уже было добавлено';
|
||||
return;
|
||||
}
|
||||
}),
|
||||
computed: {
|
||||
...mapGetters(['userData', 'getProcessing']),
|
||||
isWord() {
|
||||
return this.wordEntity.type === WORD_TYPES.WORD;
|
||||
},
|
||||
isRedewndung() {
|
||||
return this.wordEntity.type === WORD_TYPES.REDEWNNDUNG;
|
||||
},
|
||||
isProcessing() {
|
||||
return this.getProcessing;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getFullOriginalWord,
|
||||
addWord(entity) {
|
||||
const userWords = this.userData.words;
|
||||
const wordAdded = userWords[entity.key];
|
||||
if (wordAdded) {
|
||||
this.snackbar.isEnabled = true;
|
||||
this.snackbar.text = 'Слово уже было добавлено';
|
||||
return;
|
||||
}
|
||||
|
||||
if (Object.keys(userWords).length > 100) {
|
||||
this.snackbar.isEnabled = true;
|
||||
this.snackbar.text = 'Слишком много добавленных слов';
|
||||
return;
|
||||
}
|
||||
if (Object.keys(userWords).length > 100) {
|
||||
this.snackbar.isEnabled = true;
|
||||
this.snackbar.text = 'Слишком много добавленных слов';
|
||||
return;
|
||||
}
|
||||
|
||||
this.$store.dispatch('addUserWord', entity);
|
||||
},
|
||||
this.$store.dispatch('addUserWord', entity);
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -21,35 +21,35 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import WordCard from '@/components/Article/Word/Card';
|
||||
import WordCard from '@/components/Article/Word/Card';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
data: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
export default {
|
||||
props: {
|
||||
data: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
computed: {
|
||||
userData() {
|
||||
return this.$store.getters.userData;
|
||||
},
|
||||
words() {
|
||||
const words = [];
|
||||
},
|
||||
computed: {
|
||||
userData() {
|
||||
return this.$store.getters.userData;
|
||||
},
|
||||
words() {
|
||||
const words = [];
|
||||
|
||||
for (let property in this.data) {
|
||||
if (this.data.hasOwnProperty(property)) {
|
||||
const word = Object.assign({}, this.data[property], { key: property });
|
||||
words.push(word);
|
||||
}
|
||||
for (let property in this.data) {
|
||||
if (this.data.hasOwnProperty(property)) {
|
||||
const word = Object.assign({}, this.data[property], { key: property });
|
||||
words.push(word);
|
||||
}
|
||||
}
|
||||
|
||||
return words;
|
||||
},
|
||||
return words;
|
||||
},
|
||||
components: {
|
||||
WordCard,
|
||||
},
|
||||
}
|
||||
},
|
||||
components: {
|
||||
WordCard,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
@@ -6,6 +6,6 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
};
|
||||
export default {
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -23,38 +23,40 @@
|
||||
|
||||
|
||||
<script>
|
||||
import ListItem from '@/components/Article/Details';
|
||||
import ListItem from '@/components/Article/Details';
|
||||
|
||||
export default {
|
||||
data: () => ({
|
||||
levels: ['A1', 'A2', 'B1', 'B2', 'C1', 'C2'],
|
||||
searchTerm: null,
|
||||
levelTerm: [],
|
||||
}),
|
||||
computed: {
|
||||
articles() {
|
||||
return this.$store.getters.getArticles;
|
||||
},
|
||||
filteredArticles() {
|
||||
const { articles, searchTerm, levelTerm } = this;
|
||||
let filteredArticles = articles
|
||||
|
||||
if (searchTerm) {
|
||||
filteredArticles = filteredArticles.filter(article =>
|
||||
article.title.toLowerCase().indexOf(searchTerm.toLowerCase()) >= 0
|
||||
|| article.description.toLowerCase().indexOf(searchTerm.toLowerCase()) >= 0
|
||||
);
|
||||
}
|
||||
|
||||
if (levelTerm.length) {
|
||||
filteredArticles = filteredArticles.filter(article => levelTerm.filter(val => article.level.indexOf(val) !== -1).length > 0)
|
||||
}
|
||||
|
||||
return filteredArticles;
|
||||
},
|
||||
export default {
|
||||
data: () => ({
|
||||
levels: ['A1', 'A2', 'B1', 'B2', 'C1', 'C2'],
|
||||
searchTerm: null,
|
||||
levelTerm: [],
|
||||
}),
|
||||
computed: {
|
||||
articles() {
|
||||
return this.$store.getters.getArticles;
|
||||
},
|
||||
components: {
|
||||
ListItem,
|
||||
}
|
||||
};
|
||||
filteredArticles() {
|
||||
const { articles, searchTerm, levelTerm } = this;
|
||||
let filteredArticles = articles;
|
||||
|
||||
if (searchTerm) {
|
||||
filteredArticles = filteredArticles.filter(article =>
|
||||
article.title.toLowerCase().indexOf(searchTerm.toLowerCase()) >= 0
|
||||
|| article.description.toLowerCase().indexOf(searchTerm.toLowerCase()) >= 0
|
||||
);
|
||||
}
|
||||
|
||||
if (levelTerm.length) {
|
||||
filteredArticles = filteredArticles.filter(
|
||||
article => levelTerm.filter(val => article.level.indexOf(val) !== -1).length > 0
|
||||
);
|
||||
}
|
||||
|
||||
return filteredArticles;
|
||||
},
|
||||
},
|
||||
components: {
|
||||
ListItem,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
</v-alert>
|
||||
|
||||
<v-form id="edit-profile-form" v-model="isValid" @submit.prevent="changeUserData">
|
||||
<v-text-field
|
||||
<v-text-field
|
||||
prepend-icon="email"
|
||||
v-model="email"
|
||||
name="login"
|
||||
@@ -63,7 +63,7 @@
|
||||
</v-radio-group>
|
||||
|
||||
<v-text-field
|
||||
v-if="changeType == 'changeName'"
|
||||
v-if="changeType === 'changeName'"
|
||||
prepend-icon="person"
|
||||
v-model="newName"
|
||||
name="newName"
|
||||
@@ -74,8 +74,8 @@
|
||||
>
|
||||
</v-text-field>
|
||||
|
||||
<v-text-field
|
||||
v-if="changeType == 'changeEmail'"
|
||||
<v-text-field
|
||||
v-if="changeType === 'changeEmail'"
|
||||
prepend-icon="email"
|
||||
v-model="newEmail"
|
||||
name="newLogin"
|
||||
@@ -87,7 +87,7 @@
|
||||
</v-text-field>
|
||||
|
||||
<v-text-field
|
||||
v-if="changeType == 'changePassword'"
|
||||
v-if="changeType === 'changePassword'"
|
||||
prepend-icon="lock"
|
||||
v-model="newPassword"
|
||||
name="newPassword"
|
||||
@@ -105,7 +105,7 @@
|
||||
<v-btn color="green darken-1" flat @click="dialog = false">Отмена</v-btn>
|
||||
<v-btn
|
||||
type="submit"
|
||||
color="green darken-1"
|
||||
color="green darken-1"
|
||||
form="edit-profile-form"
|
||||
flat
|
||||
:disabled="getProcessing || !isValid"
|
||||
@@ -119,56 +119,56 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import { emailRules, passwordRules, nameRules, EVENTS } from "@/utils";
|
||||
import { mapGetters } from 'vuex';
|
||||
import { emailRules, passwordRules, nameRules, EVENTS } from "@/utils";
|
||||
|
||||
export default {
|
||||
data: () => ({
|
||||
email: null,
|
||||
password: null,
|
||||
newEmail: null,
|
||||
newPassword: null,
|
||||
newName: null,
|
||||
export default {
|
||||
data: () => ({
|
||||
email: null,
|
||||
password: null,
|
||||
newEmail: null,
|
||||
newPassword: null,
|
||||
newName: null,
|
||||
|
||||
changeType: 'changeName',
|
||||
dialog: false,
|
||||
isValid: false,
|
||||
changeType: 'changeName',
|
||||
dialog: false,
|
||||
isValid: false,
|
||||
|
||||
emailRules,
|
||||
passwordRules,
|
||||
nameRules
|
||||
}),
|
||||
computed: {
|
||||
...mapGetters(['userName', 'userEmail', 'getProcessing', 'getError']),
|
||||
},
|
||||
methods: {
|
||||
changeUserData() {
|
||||
const {
|
||||
email,
|
||||
password,
|
||||
newEmail,
|
||||
newPassword,
|
||||
newName,
|
||||
changeType,
|
||||
} = this;
|
||||
emailRules,
|
||||
passwordRules,
|
||||
nameRules,
|
||||
}),
|
||||
computed: {
|
||||
...mapGetters(['userName', 'userEmail', 'getProcessing', 'getError']),
|
||||
},
|
||||
methods: {
|
||||
changeUserData() {
|
||||
const {
|
||||
email,
|
||||
password,
|
||||
newEmail,
|
||||
newPassword,
|
||||
newName,
|
||||
changeType,
|
||||
} = this;
|
||||
|
||||
this.$store.dispatch('changeUserProfileData', {
|
||||
email,
|
||||
password,
|
||||
newEmail,
|
||||
newPassword,
|
||||
newName,
|
||||
changeType,
|
||||
});
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.$bus.$on(EVENTS.USER.DATA_CHANGED, () => {
|
||||
this.dialog = false;
|
||||
this.$store.dispatch('changeUserProfileData', {
|
||||
email,
|
||||
password,
|
||||
newEmail,
|
||||
newPassword,
|
||||
newName,
|
||||
changeType,
|
||||
});
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.$bus.$off(EVENTS.USER.DATA_CHANGED);
|
||||
},
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.$bus.$on(EVENTS.USER.DATA_CHANGED, () => {
|
||||
this.dialog = false;
|
||||
});
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.$bus.$off(EVENTS.USER.DATA_CHANGED);
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -4,5 +4,5 @@ export default {
|
||||
databaseURL: "https://test.firebaseio.com",
|
||||
projectId: "test",
|
||||
storageBucket: "test.appspot.com",
|
||||
messagingSenderId: "test"
|
||||
messagingSenderId: "test",
|
||||
};
|
||||
|
||||
24
src/main.js
24
src/main.js
@@ -24,9 +24,9 @@ Vue.$db = db;
|
||||
|
||||
Vue.use(Vuetify);
|
||||
Vue.use(VuetifyConfirm, {
|
||||
buttonTrueText: 'Да',
|
||||
buttonFalseText: 'Нет',
|
||||
width: 400,
|
||||
buttonTrueText: 'Да',
|
||||
buttonFalseText: 'Нет',
|
||||
width: 400,
|
||||
});
|
||||
Vue.use(VueYouTubeEmbed);
|
||||
|
||||
@@ -35,14 +35,14 @@ Vue.filter('formattedDate', formattedDate);
|
||||
setUpEventBus();
|
||||
|
||||
new Vue({
|
||||
router,
|
||||
store,
|
||||
render: h => h(App),
|
||||
created: function onApplicationCreated() {
|
||||
firebase.auth().onAuthStateChanged((user) => {
|
||||
this.$store.dispatch('stateChanged', user);
|
||||
});
|
||||
router,
|
||||
store,
|
||||
render: h => h(App),
|
||||
created: function onApplicationCreated() {
|
||||
firebase.auth().onAuthStateChanged((user) => {
|
||||
this.$store.dispatch('stateChanged', user);
|
||||
});
|
||||
|
||||
this.$store.dispatch('loadArticles');
|
||||
}
|
||||
this.$store.dispatch('loadArticles');
|
||||
},
|
||||
}).$mount('#app');
|
||||
|
||||
110
src/router.js
110
src/router.js
@@ -7,62 +7,62 @@ import Home from '@/views/Home';
|
||||
Vue.use(Router);
|
||||
|
||||
function AuthMiddleware(from, to, next) {
|
||||
if (Store.getters.isUserAuthentificated) {
|
||||
next();
|
||||
} else {
|
||||
next('/sign_in');
|
||||
}
|
||||
if (Store.getters.isUserAuthenticated) {
|
||||
next();
|
||||
} else {
|
||||
next('/sign_in');
|
||||
}
|
||||
}
|
||||
|
||||
export default new Router({
|
||||
routes: [
|
||||
{
|
||||
path: '/',
|
||||
name: 'home',
|
||||
component: Home
|
||||
},
|
||||
{
|
||||
path: '/articles',
|
||||
name: 'articles',
|
||||
component: () => import(/* webpackChunkName: "articles/index" */ '@/views/Articles'),
|
||||
},
|
||||
{
|
||||
path: '/articles/:articleId',
|
||||
name: 'article',
|
||||
props: true,
|
||||
component: () => import(/* webpackChunkName: "articles/article" */ '@/views/Article')
|
||||
},
|
||||
{
|
||||
path: '/articles/:articleId/part/:partId',
|
||||
name: 'articlePart',
|
||||
props: true,
|
||||
component: () => import(/* webpackChunkName: "articles/article_part" */ '@/views/ArticlePart')
|
||||
},
|
||||
{
|
||||
path: '/words',
|
||||
name: 'words',
|
||||
component: () => import(/* webpackChunkName: "words" */ '@/views/Words'),
|
||||
},
|
||||
{
|
||||
path: '/profile',
|
||||
name: 'profile',
|
||||
component: () => import(/* webpackChunkName: "words" */ '@/views/Profile'),
|
||||
beforeEnter: AuthMiddleware,
|
||||
},
|
||||
{
|
||||
path: '/sign_in',
|
||||
name: 'signIn',
|
||||
component: () => import(/* webpackChunkName: "sign_in" */ '@/views/SignIn'),
|
||||
},
|
||||
{
|
||||
path: '/sign_up',
|
||||
name: 'signUp',
|
||||
component: () => import(/* webpackChunkName: "sign_up" */ '@/views/SignUp'),
|
||||
},
|
||||
{
|
||||
path: '*',
|
||||
component: NotFound,
|
||||
}
|
||||
],
|
||||
mode: 'history',
|
||||
routes: [
|
||||
{
|
||||
path: '/',
|
||||
name: 'home',
|
||||
component: Home,
|
||||
},
|
||||
{
|
||||
path: '/articles',
|
||||
name: 'articles',
|
||||
component: () => import(/* webpackChunkName: "articles/index" */ '@/views/Articles'),
|
||||
},
|
||||
{
|
||||
path: '/articles/:articleId',
|
||||
name: 'article',
|
||||
props: true,
|
||||
component: () => import(/* webpackChunkName: "articles/article" */ '@/views/Article'),
|
||||
},
|
||||
{
|
||||
path: '/articles/:articleId/part/:partId',
|
||||
name: 'articlePart',
|
||||
props: true,
|
||||
component: () => import(/* webpackChunkName: "articles/article_part" */ '@/views/ArticlePart'),
|
||||
},
|
||||
{
|
||||
path: '/words',
|
||||
name: 'words',
|
||||
component: () => import(/* webpackChunkName: "words" */ '@/views/Words'),
|
||||
},
|
||||
{
|
||||
path: '/profile',
|
||||
name: 'profile',
|
||||
component: () => import(/* webpackChunkName: "words" */ '@/views/Profile'),
|
||||
beforeEnter: AuthMiddleware,
|
||||
},
|
||||
{
|
||||
path: '/sign_in',
|
||||
name: 'signIn',
|
||||
component: () => import(/* webpackChunkName: "sign_in" */ '@/views/SignIn'),
|
||||
},
|
||||
{
|
||||
path: '/sign_up',
|
||||
name: 'signUp',
|
||||
component: () => import(/* webpackChunkName: "sign_up" */ '@/views/SignUp'),
|
||||
},
|
||||
{
|
||||
path: '*',
|
||||
component: NotFound,
|
||||
},
|
||||
],
|
||||
mode: 'history',
|
||||
});
|
||||
|
||||
12
src/store.js
12
src/store.js
@@ -9,10 +9,10 @@ import userDataModule from '@/store/userData';
|
||||
Vue.use(Vuex);
|
||||
|
||||
export default new Vuex.Store({
|
||||
modules: {
|
||||
articleModule,
|
||||
generalModule,
|
||||
userModule,
|
||||
userDataModule,
|
||||
},
|
||||
modules: {
|
||||
articleModule,
|
||||
generalModule,
|
||||
userModule,
|
||||
userDataModule,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -22,7 +22,7 @@ export default {
|
||||
parts: parts ? parts.map(part => Object.assign({}, part)) : [],
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
commit('setArticles', articles);
|
||||
})
|
||||
.catch(e => console.error(e));
|
||||
|
||||
@@ -6,7 +6,7 @@ import { EventBus, EVENTS } from '@/utils';
|
||||
export default {
|
||||
state: {
|
||||
user: {
|
||||
isAuthentificated: false,
|
||||
isAuthenticated: false,
|
||||
uid: null,
|
||||
email: null,
|
||||
name: null,
|
||||
@@ -14,12 +14,12 @@ export default {
|
||||
},
|
||||
mutations: {
|
||||
setUser(state, { uid, email }) {
|
||||
state.user.isAuthentificated = true;
|
||||
state.user.isAuthenticated = true;
|
||||
state.user.uid = uid;
|
||||
state.user.email = email;
|
||||
},
|
||||
unSetUser(state) {
|
||||
state.user.isAuthentificated = false;
|
||||
state.user.isAuthenticated = false;
|
||||
state.user.uid = null;
|
||||
},
|
||||
setUserName(state, name) {
|
||||
@@ -27,7 +27,7 @@ export default {
|
||||
},
|
||||
setUserEmail(state, email) {
|
||||
Vue.set(state.user, 'email', email);
|
||||
}
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
async signUp({ commit }, payload) {
|
||||
@@ -94,8 +94,8 @@ export default {
|
||||
if (changeType === 'changeName') {
|
||||
const { newName } = payload;
|
||||
return reauthenticatedUser.updateProfile({
|
||||
displayName: newName,
|
||||
})
|
||||
displayName: newName,
|
||||
})
|
||||
.then(() => commit('setUserName', newName))
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ export default {
|
||||
},
|
||||
},
|
||||
getters: {
|
||||
isUserAuthentificated: state => state.user.isAuthentificated,
|
||||
isUserAuthenticated: state => state.user.isAuthenticated,
|
||||
userId: state => state.user.uid,
|
||||
userName: state => state.user.name,
|
||||
userEmail: state => state.user.email,
|
||||
|
||||
@@ -44,7 +44,7 @@ export default {
|
||||
await userDataRef.set({
|
||||
articles: {
|
||||
[articleId]: article,
|
||||
}
|
||||
},
|
||||
}, { merge: true })
|
||||
.then(() => commit('addUserArticle', { articleId, article }))
|
||||
.catch(e => window.console.error(e));
|
||||
@@ -67,7 +67,7 @@ export default {
|
||||
await userDataRef.set({
|
||||
words: {
|
||||
[key]: word,
|
||||
}
|
||||
},
|
||||
}, { merge: true })
|
||||
.then(() => commit('addUserWord', { wordKey: key, word }))
|
||||
.catch(e => window.console.error(e));
|
||||
|
||||
@@ -22,4 +22,4 @@ export const setUpEventBus = () => {
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
export const emailRules = [
|
||||
(value) => !!value || 'Пожалуйста, введите email',
|
||||
(value) => /^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/.test(value) || 'Неправильный email',
|
||||
value => !!value || 'Пожалуйста, введите email',
|
||||
value => /^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/.test(value) || 'Неправильный email',
|
||||
];
|
||||
|
||||
export const passwordRules = [
|
||||
(value) => !!value || 'Пожалуйста введите пароль',
|
||||
(value) => (value && value.length >= 6) || 'Пароль слишком короткий - минимум 6 символов',
|
||||
value => !!value || 'Пожалуйста введите пароль',
|
||||
value => (value && value.length >= 6) || 'Пароль слишком короткий - минимум 6 символов',
|
||||
];
|
||||
|
||||
export const nameRules = [
|
||||
(value) => !!value || 'Пожалуйста введите ваше имя',
|
||||
value => !!value || 'Пожалуйста введите ваше имя',
|
||||
];
|
||||
|
||||
@@ -8,4 +8,3 @@ export const declOfNum = (number, titles) => {
|
||||
const cases = [2, 0, 1, 1, 1, 2];
|
||||
return titles[(number % 100 > 4 && number % 100 < 20) ? 2 : cases[(number % 10 < 5) ? number % 10 : 5]];
|
||||
};
|
||||
|
||||
|
||||
@@ -13,24 +13,24 @@
|
||||
|
||||
|
||||
<script>
|
||||
import ArticleDetails from '@/components/Article/Details';
|
||||
import ArticlePartsListItem from '@/components/Article/Part/ListItem';
|
||||
import ArticleDetails from '@/components/Article/Details';
|
||||
import ArticlePartsListItem from '@/components/Article/Part/ListItem';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
articleId: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
export default {
|
||||
props: {
|
||||
articleId: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
computed: {
|
||||
article() {
|
||||
return this.$store.getters.getArticles.find(article => article.id == this.articleId);
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
article() {
|
||||
return this.$store.getters.getArticles.find(article => article.id === this.articleId);
|
||||
},
|
||||
components: {
|
||||
ArticleDetails,
|
||||
ArticlePartsListItem,
|
||||
},
|
||||
};
|
||||
},
|
||||
components: {
|
||||
ArticleDetails,
|
||||
ArticlePartsListItem,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -58,89 +58,89 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Vue from 'vue';
|
||||
import BookPartContent from '@/components/Article/Part/Content';
|
||||
import BookPartWords from '@/components/Article/Words';
|
||||
import Vue from 'vue';
|
||||
import BookPartContent from '@/components/Article/Part/Content';
|
||||
import BookPartWords from '@/components/Article/Words';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
articleId: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
partId: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
export default {
|
||||
props: {
|
||||
articleId: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
components: {
|
||||
BookPartContent,
|
||||
BookPartWords,
|
||||
partId: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
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,
|
||||
}),
|
||||
computed: {
|
||||
currentUserArticle() {
|
||||
const articles = this.$store.getters.userData.articles;
|
||||
if (!articles) {
|
||||
return null;
|
||||
}
|
||||
return articles[this.articleId];
|
||||
},
|
||||
data: () => ({
|
||||
part: null,
|
||||
finishDialog: false,
|
||||
rating: 0,
|
||||
}),
|
||||
created() {
|
||||
const { articleId, partId } = this;
|
||||
Vue.$db.collection('articleParts')
|
||||
.where('articleId', '==', articleId)
|
||||
.where('articlePartId', '==', partId)
|
||||
.get()
|
||||
.then((querySnapshot) => {
|
||||
const snapDocs = querySnapshot.docs;
|
||||
if (snapDocs.length > 0) {
|
||||
this.part = Object.assign({}, snapDocs[0].data());
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
this.$store.dispatch('updateUserArticlePartStats', {
|
||||
articleId,
|
||||
partId,
|
||||
});
|
||||
})
|
||||
.catch(e => window.console.error(e));
|
||||
}
|
||||
};
|
||||
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;
|
||||
},
|
||||
},
|
||||
created() {
|
||||
const { articleId, partId } = this;
|
||||
Vue.$db.collection('articleParts')
|
||||
.where('articleId', '==', articleId)
|
||||
.where('articlePartId', '==', partId)
|
||||
.get()
|
||||
.then((querySnapshot) => {
|
||||
const snapDocs = querySnapshot.docs;
|
||||
if (snapDocs.length > 0) {
|
||||
this.part = { ...snapDocs[0].data() };
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
this.$store.dispatch('updateUserArticlePartStats', {
|
||||
articleId,
|
||||
partId,
|
||||
});
|
||||
})
|
||||
.catch(e => window.console.error(e));
|
||||
},
|
||||
components: {
|
||||
BookPartContent,
|
||||
BookPartWords,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
|
||||
|
||||
<script>
|
||||
import ArticlesList from '@/components/ArticlesList';
|
||||
export default {
|
||||
components: {
|
||||
ArticlesList,
|
||||
},
|
||||
};
|
||||
import ArticlesList from '@/components/ArticlesList';
|
||||
export default {
|
||||
components: {
|
||||
ArticlesList,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -1,22 +1,18 @@
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<v-alert
|
||||
:value="true"
|
||||
color="error"
|
||||
icon="warning"
|
||||
outline
|
||||
>
|
||||
Страница, которую вы запросили, не существует.
|
||||
</v-alert>
|
||||
</div>
|
||||
<div>
|
||||
<v-alert
|
||||
:value="true"
|
||||
color="error"
|
||||
icon="warning"
|
||||
outline
|
||||
>
|
||||
Страница, которую вы запросили, не существует.
|
||||
</v-alert>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: 'notFound',
|
||||
components: {
|
||||
}
|
||||
}
|
||||
name: 'notFound',
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
<template>
|
||||
<div>
|
||||
<h2>Home</h2>
|
||||
</div>
|
||||
<div>
|
||||
<h2>Home</h2>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: 'home',
|
||||
components: {
|
||||
}
|
||||
}
|
||||
name: 'home',
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -28,17 +28,17 @@
|
||||
|
||||
|
||||
<script>
|
||||
import UserProfileData from '@/components/User/ProfileData';
|
||||
import UserProfileData from '@/components/User/ProfileData';
|
||||
|
||||
export default {
|
||||
beforeMount() {
|
||||
this.$store.commit('clearError');
|
||||
},
|
||||
data: () => ({
|
||||
tabMode: 'myData',
|
||||
}),
|
||||
components: {
|
||||
UserProfileData,
|
||||
},
|
||||
};
|
||||
export default {
|
||||
beforeMount() {
|
||||
this.$store.commit('clearError');
|
||||
},
|
||||
data: () => ({
|
||||
tabMode: 'myData',
|
||||
}),
|
||||
components: {
|
||||
UserProfileData,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -1,94 +1,101 @@
|
||||
<template>
|
||||
<v-content>
|
||||
<v-container fluid fill-height>
|
||||
<v-layout align-center justify-center>
|
||||
<v-flex xs12 sm8 md6>
|
||||
<v-card class="elevation-12">
|
||||
<v-toolbar dark color="primary">
|
||||
<v-toolbar-title>Вход</v-toolbar-title>
|
||||
</v-toolbar>
|
||||
<v-card-text>
|
||||
<v-alert
|
||||
:value="error"
|
||||
type="warning"
|
||||
>
|
||||
{{error}}
|
||||
</v-alert>
|
||||
<v-container fluid fill-height>
|
||||
<v-layout align-center justify-center>
|
||||
<v-flex xs12 sm8 md6>
|
||||
<v-card class="elevation-12">
|
||||
<v-toolbar dark color="primary">
|
||||
<v-toolbar-title>Вход</v-toolbar-title>
|
||||
</v-toolbar>
|
||||
<v-card-text>
|
||||
<v-alert
|
||||
:value="error"
|
||||
type="warning"
|
||||
>
|
||||
{{error}}
|
||||
</v-alert>
|
||||
|
||||
<v-form id="sign-in-form" v-model="isValid" @submit.prevent="signIn">
|
||||
<v-text-field
|
||||
prepend-icon="email"
|
||||
v-model="email"
|
||||
name="login"
|
||||
label="Email"
|
||||
type="email"
|
||||
required
|
||||
:rules="emailRules"
|
||||
>
|
||||
</v-text-field>
|
||||
<v-form id="sign-in-form" v-model="isValid" @submit.prevent="signIn">
|
||||
<v-text-field
|
||||
prepend-icon="email"
|
||||
v-model="email"
|
||||
name="login"
|
||||
label="Email"
|
||||
type="email"
|
||||
required
|
||||
:rules="emailRules"
|
||||
>
|
||||
</v-text-field>
|
||||
|
||||
<v-text-field
|
||||
prepend-icon="lock"
|
||||
v-model="password"
|
||||
name="password"
|
||||
label="Пароль"
|
||||
id="password"
|
||||
type="password"
|
||||
required
|
||||
:rules="passwordRules"
|
||||
>
|
||||
</v-text-field>
|
||||
</v-form>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn color="primary" type="submit" form="sign-in-form" :disabled="isProcessing || !isValid">Войти</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-container>
|
||||
<v-text-field
|
||||
prepend-icon="lock"
|
||||
v-model="password"
|
||||
name="password"
|
||||
label="Пароль"
|
||||
id="password"
|
||||
type="password"
|
||||
required
|
||||
:rules="passwordRules"
|
||||
>
|
||||
</v-text-field>
|
||||
</v-form>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn
|
||||
color="primary"
|
||||
type="submit"
|
||||
form="sign-in-form"
|
||||
:disabled="isProcessing || !isValid"
|
||||
>
|
||||
Войти
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-container>
|
||||
</v-content>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { emailRules, passwordRules } from '@/utils';
|
||||
import { emailRules, passwordRules } from '@/utils';
|
||||
|
||||
export default {
|
||||
beforeMount() {
|
||||
this.$store.commit('clearError');
|
||||
},
|
||||
data: () => ({
|
||||
email: null,
|
||||
password: null,
|
||||
isValid: false,
|
||||
export default {
|
||||
beforeMount() {
|
||||
this.$store.commit('clearError');
|
||||
},
|
||||
data: () => ({
|
||||
email: null,
|
||||
password: null,
|
||||
isValid: false,
|
||||
|
||||
emailRules,
|
||||
passwordRules,
|
||||
}),
|
||||
computed: {
|
||||
error() {
|
||||
return this.$store.getters.getError;
|
||||
},
|
||||
isProcessing() {
|
||||
return this.$store.getters.getProcessing;
|
||||
},
|
||||
isUserAuthentificated() {
|
||||
return this.$store.getters.isUserAuthentificated;
|
||||
},
|
||||
emailRules,
|
||||
passwordRules,
|
||||
}),
|
||||
computed: {
|
||||
error() {
|
||||
return this.$store.getters.getError;
|
||||
},
|
||||
watch: {
|
||||
isUserAuthentificated(val) {
|
||||
if (val === true) {
|
||||
this.$router.push('/');
|
||||
}
|
||||
},
|
||||
isProcessing() {
|
||||
return this.$store.getters.getProcessing;
|
||||
},
|
||||
methods: {
|
||||
signIn() {
|
||||
const { email, password } = this;
|
||||
this.$store.dispatch('signIn', { email, password });
|
||||
},
|
||||
isUserAuthenticated() {
|
||||
return this.$store.getters.isUserAuthenticated;
|
||||
},
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
isUserAuthenticated(val) {
|
||||
if (val === true) {
|
||||
this.$router.push('/');
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
signIn() {
|
||||
const { email, password } = this;
|
||||
this.$store.dispatch('signIn', { email, password });
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -1,107 +1,114 @@
|
||||
<template>
|
||||
<v-content>
|
||||
<v-container fluid fill-height>
|
||||
<v-layout align-center justify-center>
|
||||
<v-flex xs12 sm8 md6>
|
||||
<v-card class="elevation-12">
|
||||
<v-toolbar dark color="primary">
|
||||
<v-toolbar-title>Регистрация</v-toolbar-title>
|
||||
</v-toolbar>
|
||||
<v-card-text>
|
||||
<v-alert
|
||||
:value="error"
|
||||
type="warning"
|
||||
>
|
||||
{{error}}
|
||||
</v-alert>
|
||||
<v-container fluid fill-height>
|
||||
<v-layout align-center justify-center>
|
||||
<v-flex xs12 sm8 md6>
|
||||
<v-card class="elevation-12">
|
||||
<v-toolbar dark color="primary">
|
||||
<v-toolbar-title>Регистрация</v-toolbar-title>
|
||||
</v-toolbar>
|
||||
<v-card-text>
|
||||
<v-alert
|
||||
:value="error"
|
||||
type="warning"
|
||||
>
|
||||
{{error}}
|
||||
</v-alert>
|
||||
|
||||
<v-form id="sign-up-form" v-model="isValid" @submit.prevent="signUp">
|
||||
<v-text-field
|
||||
prepend-icon="person"
|
||||
v-model="name"
|
||||
name="name"
|
||||
label="Имя"
|
||||
type="text"
|
||||
required
|
||||
:rules="nameRules"
|
||||
>
|
||||
</v-text-field>
|
||||
<v-form id="sign-up-form" v-model="isValid" @submit.prevent="signUp">
|
||||
<v-text-field
|
||||
prepend-icon="person"
|
||||
v-model="name"
|
||||
name="name"
|
||||
label="Имя"
|
||||
type="text"
|
||||
required
|
||||
:rules="nameRules"
|
||||
>
|
||||
</v-text-field>
|
||||
|
||||
<v-text-field
|
||||
prepend-icon="email"
|
||||
v-model="email"
|
||||
name="login"
|
||||
label="Email"
|
||||
type="email"
|
||||
required
|
||||
:rules="emailRules"
|
||||
>
|
||||
</v-text-field>
|
||||
<v-text-field
|
||||
prepend-icon="email"
|
||||
v-model="email"
|
||||
name="login"
|
||||
label="Email"
|
||||
type="email"
|
||||
required
|
||||
:rules="emailRules"
|
||||
>
|
||||
</v-text-field>
|
||||
|
||||
<v-text-field
|
||||
prepend-icon="lock"
|
||||
v-model="password"
|
||||
name="password"
|
||||
label="Пароль"
|
||||
id="password"
|
||||
type="password"
|
||||
required
|
||||
:rules="passwordRules"
|
||||
>
|
||||
</v-text-field>
|
||||
</v-form>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn type="submit" color="primary" form="sign-up-form" :disabled="isProcessing || !isValid">Зарегистрироваться</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-container>
|
||||
<v-text-field
|
||||
prepend-icon="lock"
|
||||
v-model="password"
|
||||
name="password"
|
||||
label="Пароль"
|
||||
id="password"
|
||||
type="password"
|
||||
required
|
||||
:rules="passwordRules"
|
||||
>
|
||||
</v-text-field>
|
||||
</v-form>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn
|
||||
type="submit"
|
||||
color="primary"
|
||||
form="sign-up-form"
|
||||
:disabled="isProcessing || !isValid"
|
||||
>
|
||||
Зарегистрироваться
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-container>
|
||||
</v-content>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { emailRules, passwordRules, nameRules } from '@/utils';
|
||||
import { emailRules, passwordRules, nameRules } from '@/utils';
|
||||
|
||||
export default {
|
||||
beforeMount() {
|
||||
this.$store.commit('clearError');
|
||||
export default {
|
||||
beforeMount() {
|
||||
this.$store.commit('clearError');
|
||||
},
|
||||
data: () => ({
|
||||
email: null,
|
||||
password: null,
|
||||
name: null,
|
||||
isValid: false,
|
||||
|
||||
emailRules,
|
||||
passwordRules,
|
||||
nameRules,
|
||||
}),
|
||||
computed: {
|
||||
error() {
|
||||
return this.$store.getters.getError;
|
||||
},
|
||||
data: () => ({
|
||||
email: null,
|
||||
password: null,
|
||||
name: null,
|
||||
isValid: false,
|
||||
|
||||
emailRules,
|
||||
passwordRules,
|
||||
nameRules,
|
||||
}),
|
||||
computed: {
|
||||
error() {
|
||||
return this.$store.getters.getError;
|
||||
},
|
||||
isProcessing() {
|
||||
return this.$store.getters.getProcessing;
|
||||
},
|
||||
isUserAuthentificated() {
|
||||
return this.$store.getters.isUserAuthentificated;
|
||||
isProcessing() {
|
||||
return this.$store.getters.getProcessing;
|
||||
},
|
||||
isUserAuthenticated() {
|
||||
return this.$store.getters.isUserAuthenticated;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
isUserAuthenticated(val) {
|
||||
if (val === true) {
|
||||
this.$router.push('/');
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
isUserAuthentificated(val) {
|
||||
if (val === true) {
|
||||
this.$router.push('/');
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
signUp() {
|
||||
const { email, password, name } = this;
|
||||
this.$store.dispatch('signUp', { email, password, name });
|
||||
},
|
||||
methods: {
|
||||
signUp() {
|
||||
const { email, password, name } = this;
|
||||
this.$store.dispatch('signUp', { email, password, name });
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
|
||||
<script>
|
||||
export default {
|
||||
|
||||
}
|
||||
export default {
|
||||
};
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user