forked from kaverti/website
444 lines
9.5 KiB
Vue
444 lines
9.5 KiB
Vue
<template>
|
|
<main>
|
|
<div class='user_posts' :class='{ "user_posts--no_border_bottom": posts && !posts.length }'>
|
|
<div class='user_posts__title'>{{username}}'s wall</div>
|
|
<div
|
|
class='editor'
|
|
:class='{
|
|
"editor--focus": focusInput,
|
|
"editor--error": errors.content
|
|
}'
|
|
>
|
|
<div class='editor__input'>
|
|
<input-editor-core
|
|
v-model='editor'
|
|
@mentions='setMentions'
|
|
@focus='setFocusInput(true)'
|
|
@blur='setFocusInput(false)'
|
|
></input-editor-core>
|
|
</div>
|
|
</div>
|
|
<error-tooltip :error='errors.content' class='editor_error'></error-tooltip>
|
|
<b-button class='submit' :loading='loading' @click='postThread'>Post on wall</b-button>
|
|
<template v-if='!posts'>
|
|
<thread-post-placeholder v-if='!posts'>
|
|
</thread-post-placeholder>
|
|
</template>
|
|
|
|
<scroll-load
|
|
:loading='loadingPosts'
|
|
@loadNext='loadNewPosts'
|
|
v-else-if='posts.length'
|
|
>
|
|
<wall-post
|
|
v-for='(post, index) in posts'
|
|
:key='"thread-post-" + post.id'
|
|
|
|
:post='post'
|
|
:show-thread='true'
|
|
:click-for-post='true'
|
|
:class='{"post--last": index === posts.length-1}'
|
|
></wall-post>
|
|
<template v-if='loadingPosts'>
|
|
<thread-post-placeholder
|
|
v-for='n in nextPostsCount'
|
|
:key='"thread-post-placeholder-" + n'
|
|
></thread-post-placeholder>
|
|
</template>
|
|
</scroll-load>
|
|
<template v-else><br><br>There are no wall posts yet</template>
|
|
</div>
|
|
</main>
|
|
</template>
|
|
|
|
<script>
|
|
import ScrollLoad from '../ScrollLoad'
|
|
import WallPost from '../WallPost'
|
|
import ThreadPostPlaceholder from '../ThreadPostPlaceholder'
|
|
import InputEditorCore from '../InputEditorCore'
|
|
import ErrorTooltip from '../ErrorTooltip'
|
|
import AjaxErrorHandler from '../../assets/js/errorHandler'
|
|
import logger from '../../assets/js/logger'
|
|
|
|
export default {
|
|
name: 'ThreadNew',
|
|
props: ['username'],
|
|
components: {
|
|
WallPost,
|
|
ScrollLoad,
|
|
ThreadPostPlaceholder,
|
|
InputEditorCore,
|
|
ErrorTooltip
|
|
},
|
|
data () {
|
|
return {
|
|
selectedCategory: this.$store.state.category.selectedCategory,
|
|
editor: '',
|
|
mentions: [],
|
|
name: '',
|
|
loading: false,
|
|
focusInput: false,
|
|
threads: null,
|
|
loadingThreads: false,
|
|
nextURL: '',
|
|
nextThreadsCount: 0,
|
|
posts: null,
|
|
|
|
errors: {
|
|
content: '',
|
|
name: '',
|
|
pollQuestion: '',
|
|
pollAnswer: ''
|
|
},
|
|
|
|
showPoll: false,
|
|
pollQuestion: '',
|
|
newPollAnswer: '',
|
|
pollAnswers: []
|
|
}
|
|
},
|
|
computed: {
|
|
categories () {
|
|
return this.$store.getters.categoriesWithoutAll
|
|
}
|
|
},
|
|
methods: {
|
|
loadNewPosts () {
|
|
if(this.nextURL === null) return
|
|
|
|
this.loadingThreads = true
|
|
|
|
this.axios
|
|
.get(this.nextURL)
|
|
.then(res => {
|
|
this.loadingThreads = false
|
|
|
|
if(!this.threads) this.threads = []
|
|
|
|
this.threads.push(...res.data.Threads)
|
|
this.nextThreadsCount = res.data.meta.nextThreadsCount
|
|
})
|
|
.catch((e) => {
|
|
this.loadingThreads = false
|
|
|
|
AjaxErrorHandler(this.$store)(e)
|
|
})
|
|
},
|
|
togglePoll (val) {
|
|
if(val !== undefined) {
|
|
this.showPoll = val
|
|
} else {
|
|
this.showPoll = !this.showPoll
|
|
}
|
|
},
|
|
addPollAnswer () {
|
|
if(!this.newPollAnswer.trim().length) return
|
|
|
|
this.pollAnswers.push({ answer: this.newPollAnswer })
|
|
this.newPollAnswer = ''
|
|
},
|
|
removePollAnswer ($index) {
|
|
this.pollAnswers.splice($index, 1)
|
|
},
|
|
removePoll () {
|
|
this.pollQuestion = ''
|
|
this.pollAnswers = []
|
|
this.newPollAnswer = ''
|
|
|
|
this.togglePoll()
|
|
},
|
|
|
|
setErrors (errors) {
|
|
errors.forEach(error => {
|
|
this.errors[error.name] = error.error
|
|
})
|
|
},
|
|
getUserInfo () {
|
|
this.axios
|
|
.get('/api/v1/user/' + this.$route.params.username)
|
|
.catch((e) => {
|
|
AjaxErrorHandler(this.$store)(e)
|
|
})
|
|
},
|
|
clearErrors () {
|
|
this.errors.content = ''
|
|
this.errors.name = ''
|
|
this.errors.pollQuestion = ''
|
|
this.errors.pollAnswer = ''
|
|
},
|
|
|
|
hasDuplicates (array, cb) {
|
|
if(cb) array = array.map(cb)
|
|
|
|
return array.length !== (new Set(array)).size
|
|
},
|
|
|
|
postThread () {
|
|
let errors = []
|
|
|
|
this.clearErrors()
|
|
|
|
if(!this.editor.trim().length) {
|
|
errors.push({name: 'content', error: 'Post content cannot be blank'})
|
|
} if(errors.length) {
|
|
this.setErrors(errors)
|
|
return
|
|
}
|
|
|
|
this.loading = true
|
|
|
|
this.axios.post(`/api/v1/wall/post`, {
|
|
username: this.$route.params.username,
|
|
content: this.editor,
|
|
mentions: this.mentions
|
|
}).then(() => {
|
|
let ajax = []
|
|
return Promise.all(ajax)
|
|
}).then(() => {
|
|
this.loading = false
|
|
this.axios
|
|
.get(`/api/v1/user/${this.$route.params.username}?wall=true`)
|
|
.then(res => {
|
|
this.posts = res.data.Posts
|
|
this.nextPostsCount = res.data.meta.postNumber
|
|
})
|
|
}).catch(e => {
|
|
this.loading = false
|
|
|
|
AjaxErrorHandler(this.$store)(e, (error, errors) => {
|
|
let path = error.path
|
|
|
|
if(this.errors[path] !== undefined) {
|
|
this.errors[path] = error.message
|
|
} else {
|
|
errors.push(error.message)
|
|
}
|
|
})
|
|
})
|
|
},
|
|
setFocusInput (val) {
|
|
this.focusInput = val
|
|
},
|
|
setMentions (mentions) {
|
|
this.mentions = mentions
|
|
}
|
|
},
|
|
watch: {
|
|
'$store.state.username' (username) {
|
|
if(!username) {
|
|
this.$router.push('/')
|
|
}
|
|
}
|
|
},
|
|
mounted () {
|
|
this.getUserInfo();
|
|
this.$store.dispatch('setTitle', this.$route.params.username + '\'s wall')
|
|
this.axios
|
|
.get(`/api/v1/user/${this.$route.params.username}?wall=true`)
|
|
.then(res => {
|
|
this.posts = res.data.Posts
|
|
this.nextPostsCount = res.data.meta.postNumber
|
|
})
|
|
|
|
logger('userWall', this.$route.params.username)
|
|
},
|
|
beforeRouteEnter (to, from, next) {
|
|
next(vm => {
|
|
if(!vm.$store.state.username) {
|
|
vm.$store.commit('setAccountModalState', true);
|
|
next('/')
|
|
}
|
|
})
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang='scss'>
|
|
@import '../../assets/scss/variables.scss';
|
|
|
|
.thread_new {
|
|
margin-top: 1rem;
|
|
}
|
|
|
|
.thread_meta_info {
|
|
background-color: #fff;
|
|
border: thin solid $color__gray--darker;
|
|
border-radius: 0.25rem;
|
|
padding: 1rem;
|
|
margin: 1rem 0;
|
|
|
|
@at-root #{&}__title {
|
|
margin: 0 0.5rem;
|
|
margin-top: 0.5rem;
|
|
display: inline-block;
|
|
}
|
|
|
|
@at-root #{&}__form {
|
|
display: flex;
|
|
align-items: baseline;
|
|
}
|
|
|
|
@at-root #{&}__add_poll {
|
|
margin-top: 0.5rem;
|
|
}
|
|
|
|
@at-root #{&}__text {
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
@at-root #{&}__poll {
|
|
border-top: thin solid $color__gray--primary;
|
|
margin-top: 1rem;
|
|
padding-top: 0.75rem;
|
|
position: relative;
|
|
|
|
@at-root #{&}__top_bar {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: baseline;
|
|
}
|
|
|
|
@at-root #{&}__answer {
|
|
display: flex;
|
|
align-items: baseline;
|
|
|
|
& > span {
|
|
opacity: 0;
|
|
pointer-events: none;
|
|
transition: all 0.1s;
|
|
|
|
font-size: 1.5rem;
|
|
margin-left: 0.5rem;
|
|
cursor: pointer;
|
|
@include user-select(none);
|
|
}
|
|
|
|
&:hover > span {
|
|
opacity: 1;
|
|
pointer-events: all;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.submit {
|
|
margin-top: 1rem;
|
|
}
|
|
|
|
.editor {
|
|
display: flex;
|
|
background-color: #fff;
|
|
border-radius: 0.25rem;
|
|
border: thin solid $color__gray--darker;
|
|
|
|
transition: all 0.2s;
|
|
|
|
@at-root #{&}--focus {
|
|
border: thin solid $color__gray--darkest;
|
|
}
|
|
@at-root #{&}--error {
|
|
border: thin solid $color__red--primary;
|
|
}
|
|
|
|
@at-root #{&}__format_bar {
|
|
height: 2.5rem;
|
|
background-color: $color__gray--primary;
|
|
display: flex;
|
|
padding-right: 1rem;
|
|
padding-bottom: 0.25rem;
|
|
justify-content: flex-end;
|
|
align-items: center;
|
|
font-variant: small-caps;
|
|
|
|
@at-root #{&}--preview {
|
|
border-radius: 0 0.25rem 0 0;
|
|
}
|
|
@at-root #{&}--editor {
|
|
border-radius: 0.25rem 0 0 0;
|
|
}
|
|
}
|
|
|
|
@at-root #{&}__input {
|
|
width: 100%;
|
|
position: relative;
|
|
|
|
.input_editor_core__format_bar {
|
|
left: 0rem;
|
|
}
|
|
.input_editor_core textarea {
|
|
height: 5rem;
|
|
}
|
|
}
|
|
|
|
@at-root #{&}__preview {
|
|
border-left: 1px solid $color__gray--darker;
|
|
|
|
div.input_editor_preview__markdownHTML {
|
|
height: 14.1rem;
|
|
}
|
|
}
|
|
}
|
|
|
|
.editor_error {
|
|
width: 100%;
|
|
background: #fff;
|
|
margin-top: 0.5rem;
|
|
border-radius: 0.2rem;
|
|
border: thin solid $color__red--primary;
|
|
|
|
&.error_tooltip--show {
|
|
max-height: 4rem;
|
|
padding: 0.5rem;
|
|
}
|
|
}
|
|
|
|
@media (max-width: 600px) {
|
|
.thread_meta_info {
|
|
@at-root #{&}__form {
|
|
flex-direction: column;
|
|
}
|
|
|
|
@at-root #{&}__title.fancy_input {
|
|
margin: 0;
|
|
margin-top: 0.5rem;
|
|
}
|
|
|
|
@at-root #{&}__poll__question {
|
|
width: 100%;
|
|
|
|
> div, input {
|
|
width: 100% ;
|
|
}
|
|
}
|
|
}
|
|
|
|
.editor {
|
|
flex-direction: column;
|
|
overflow-x: hidden;
|
|
|
|
@at-root #{&}__input, #{&}__preview {
|
|
border: 0;
|
|
width: 100%;
|
|
}
|
|
}
|
|
}
|
|
.user_posts {
|
|
background: #fff;
|
|
border-radius: 0.25rem;
|
|
padding: 1rem;
|
|
border: thin solid $color__gray--darker;
|
|
|
|
@at-root #{&}__title {
|
|
font-size: 1.5rem;
|
|
margin-bottom: 1rem;
|
|
}
|
|
}
|
|
|
|
@media (max-width: $breakpoint--tablet) {
|
|
.user_posts {
|
|
margin-top: 1rem;
|
|
overflow: hidden;
|
|
}
|
|
}
|
|
</style>
|