diff options
Diffstat (limited to 'app/components')
| -rw-r--r-- | app/components/comment.js | 17 | ||||
| -rw-r--r-- | app/components/comment_form.js | 73 | ||||
| -rw-r--r-- | app/components/comments.js | 76 | ||||
| -rw-r--r-- | app/components/post.js | 23 | ||||
| -rw-r--r-- | app/components/post_form.js | 19 | ||||
| -rw-r--r-- | app/components/posts.js | 24 |
6 files changed, 217 insertions, 15 deletions
diff --git a/app/components/comment.js b/app/components/comment.js new file mode 100644 index 0000000..33ce2c7 --- /dev/null +++ b/app/components/comment.js @@ -0,0 +1,17 @@ +import Vue from 'vue'; + +const internals = {}; + +export default internals.CommentComponent = Vue.component('comment', { + template: '<article class="comment">' + + '<aside class="comment-meta">' + + '<img :src="comment.userImage" v-bind:alt="\'Avatar for @\' + comment.userId">' + + '<a v-bind:href="\'https://twitter.com/\' + comment.userId">{{comment.userName}}</a> said on ' + + '<time v-bind:datetime="comment.timestamp | datetime">{{comment.timestamp | usertime}}</time>' + + '</aside>' + + '<div class="comment-content">{{comment.content}}</div>' + + '</article>', + + props: ['comment'] +}); + diff --git a/app/components/comment_form.js b/app/components/comment_form.js new file mode 100644 index 0000000..bf60d06 --- /dev/null +++ b/app/components/comment_form.js @@ -0,0 +1,73 @@ +import Axios from 'axios'; +import Vue from 'vue'; +import AuthService from '../services/auth'; + +const internals = {}; + +internals.kPostsRoute = '/api/posts'; +internals.kCommentsRoute = '/comments'; + +export default internals.CommentFormComponent = Vue.component('comment-form', { + template: '<div class="comment-form-container">' + + '<p v-show="!active" class="comment-form-error">' + + '<button class="comment-activate" v-on:click="activate">Add comment.</button>' + + '</p>' + + '<textarea v-show="active" :disabled="submitting" v-model="content" class="comment-content-input" placeholder="tell us something" maxlength=255></textarea>' + + '<p v-show="message" class="comment-form-error">{{message}}</p>' + + '<button v-show="active" :disabled="submitting" class="comment-submit" v-on:click="submit">Go.</button>' + + '</div>', + + props: ['postUuid'], + + data() { + + return { + content: '', + message: '', + active: false, + submitting: false, + authService: new AuthService() + }; + }, + + methods: { + + // Activates the form. + + activate() { + + this.active = true; + }, + + // Creates a comment + + submit() { + + this.submitting = true; + const route = `${internals.kPostsRoute}/${this.postUuid}${internals.kCommentsRoute}`; + + return Axios({ + method: 'post', + headers: { + Authorization: `Bearer ${this.authService.token}` + }, + data: { + content: this.content + }, + url: route + }).then((response) => { + + this.$emit('comment-submitted', response.data); + this.content = ''; + this.message = ''; + this.submitting = false; + this.active = false; + }).catch((err) => { + + console.error(err.stack); + this.submitting = false; + this.message = 'Error while creating the post...'; + }); + } + } +}); diff --git a/app/components/comments.js b/app/components/comments.js new file mode 100644 index 0000000..e29cedc --- /dev/null +++ b/app/components/comments.js @@ -0,0 +1,76 @@ +import Axios from 'axios'; +import Vue from 'vue'; +import AuthService from '../services/auth'; + +import CommentFormComponent from './comment_form'; +import CommentComponent from './comment'; +import DatetimeFilter from '../filters/datetime'; +import UsertimeFilter from '../filters/usertime'; + +const internals = {}; + +internals.kPostsRoute = '/api/posts'; +internals.kCommentsRoute = '/comments'; +internals.kPollFrequency = 2000; + +export default internals.CommentsComponent = Vue.component('comments', { + template: '<div class="comments-container">' + + '<p v-show="message" class="comments-error">{{message}}</p>' + + '<comment v-for="comment in comments" v-bind:comment="comment" :key="comment.uuid"></comment>' + + '<comment-form v-bind:postUuid="postUuid" v-on:comment-submitted="addComment"></comment-form>' + + '</div>', + + props: ['postUuid'], + + data() { + + return { + message: '', + poller: null, + authService: new AuthService(), + comments: [] + }; + }, + + methods: { + fetchComments() { + + const route = `${internals.kPostsRoute}/${this.postUuid}${internals.kCommentsRoute}`; + + return Axios({ + method: 'get', + headers: { + Authorization: `Bearer ${this.authService.token}` + }, + url: route + }).then((response) => { + + this.comments = response.data; + if (!this._isBeingDestroyed) { + setTimeout(this.fetchComments.bind(this), internals.kPollFrequency); + } + }).catch((err) => { + + console.error(err.stack); + this.message = 'Error while loading the comments...'; + }); + }, + + addComment(comment) { + + this.comments.push(comment); + } + }, + + components: { + commentForm: CommentFormComponent, + comment: CommentComponent, + datetime: DatetimeFilter, + usertime: UsertimeFilter + }, + + mounted() { + + this.fetchComments(); + } +}); diff --git a/app/components/post.js b/app/components/post.js new file mode 100644 index 0000000..bb72189 --- /dev/null +++ b/app/components/post.js @@ -0,0 +1,23 @@ +import Vue from 'vue'; + +import CommentsComponent from './comments'; + +const internals = {}; + +export default internals.PostComponent = Vue.component('post', { + template: '<article class="post">' + + '<aside class="post-meta">' + + '<img :src="post.userImage" v-bind:alt="\'Avatar for @\' + post.userId">' + + '<a v-bind:href="\'https://twitter.com/\' + post.userId">{{post.userName}}</a> said on ' + + '<time v-bind:datetime="post.timestamp | datetime">{{post.timestamp | usertime}}</time>' + + '</aside>' + + '<div class="post-content">{{post.content}}</div>' + + '<comments v-bind:postUuid="post.uuid"></post>' + + '</article>', + + props: ['post'], + + components: { + comments: CommentsComponent + } +}); diff --git a/app/components/post_form.js b/app/components/post_form.js index cee17b0..1f45f0c 100644 --- a/app/components/post_form.js +++ b/app/components/post_form.js @@ -8,10 +8,11 @@ internals.kPostsRoute = '/api/posts'; export default internals.PostFormComponent = Vue.component('post-form', { template: '<div class="post-form-container">' + - '<h1>sup.</h1>' + - '<textarea :disabled="submitting" v-model="content" class="post-content-input" placeholder="tell us something" maxlength=255></textarea>' + + '<h1>hi {{authService.user.name}}</h1>' + + '<button v-show="!active" class="post-submit" v-on:click="activate">Post something.</button>' + + '<textarea v-show="active" :disabled="submitting" v-model="content" class="post-content-input" placeholder="tell us something" maxlength=255></textarea>' + '<p v-show="message" class="post-form-error">{{message}}</p>' + - '<button :disabled="submitting" class="post-submit" v-on:click="submit">Go.</button>' + + '<button v-show="active" :disabled="submitting" class="post-submit" v-on:click="submit">Go.</button>' + '</div>', data() { @@ -20,11 +21,22 @@ export default internals.PostFormComponent = Vue.component('post-form', { content: '', message: '', submitting: false, + active: false, authService: new AuthService() }; }, methods: { + + // Activates the form. + + activate() { + + this.active = true; + }, + + // Creates a post + submit() { this.submitting = true; @@ -44,6 +56,7 @@ export default internals.PostFormComponent = Vue.component('post-form', { this.content = ''; this.message = ''; this.submitting = false; + this.active = false; }).catch((err) => { console.error(err.stack); diff --git a/app/components/posts.js b/app/components/posts.js index c41707f..d0e0338 100644 --- a/app/components/posts.js +++ b/app/components/posts.js @@ -3,26 +3,21 @@ import Vue from 'vue'; import AuthService from '../services/auth'; import PostFormComponent from './post_form'; +import PostComponent from './post'; import DatetimeFilter from '../filters/datetime'; import UsertimeFilter from '../filters/usertime'; const internals = {}; internals.kPostsRoute = '/api/posts'; +internals.kPollFrequency = 5000; export default internals.PostsComponent = Vue.component('posts', { - template: '<div class="posts-container">' + + template: '<div v-if="authService.authenticated" class="posts-container">' + '<post-form v-on:post-submitted="addPost"></post-form>' + '<h1>Posts.</h1>' + '<p v-show="message" class="posts-error">{{message}}</p>' + - '<article class="post" v-for="post in posts">' + - '<aside class="post-meta">' + - '<img :src="post.userImage" v-bind:alt="\'Avatar for @\' + post.userId">' + - '<a v-bind:href="\'https://twitter.com/\' + post.userId">{{post.userName}}</a> said on ' + - '<time v-bind:datetime="post.timestamp | datetime">{{post.timestamp | usertime}}</time>' + - '</aside>' + - '<div class="post-content">{{post.content}}</div>' + - '</article>' + + '<post v-for="post in posts" v-bind:post="post" :key="post.uuid"></post>' + '</div>', data() { @@ -46,9 +41,12 @@ export default internals.PostsComponent = Vue.component('posts', { }).then((response) => { this.posts = response.data; + if (!this._isBeingDestroyed) { + setTimeout(this.fetchPosts.bind(this), internals.kPollFrequency); + } }).catch((err) => { - console.err(err.stack); + console.error(err.stack); this.message = 'Error while loading the posts...'; }); }, @@ -61,17 +59,19 @@ export default internals.PostsComponent = Vue.component('posts', { components: { postForm: PostFormComponent, + post: PostComponent, datetime: DatetimeFilter, usertime: UsertimeFilter }, - mounted: function mounted() { + mounted() { if (!this.authService.authenticated) { return this.$router.push('/login'); } - return this.fetchPosts(); + this.fetchPosts(); + } }); |