aboutsummaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorRubén Beltrán del Río <ben@nsovocal.com>2017-01-31 00:49:26 -0600
committerGitHub <noreply@github.com>2017-01-31 00:49:26 -0600
commit9b1f50fefe021578113b8f5935084fe4fed110b2 (patch)
tree98805583b7c5041f16b195de823c5524f4de7672 /app
parenta6ccda0fbc4df683f9568d85eb22b21684d2a0bd (diff)
Add Comments (#4)
* Preserve whitespace in posts * Create comments handler * Use comments handler * Update paw * Add comment components * Style comments * Remove unnecessary code from app * Fix linter warning * Add key to handle children (thx @javierbyte) * Add toggling to the form * Return all keys always * Correct missing semicolons * Restore redirect * Render posts conditionally * Set poll time to 1s * Set post frequency to 2s * Add polling to comments * Correct typo in error logging * Clear intervals and reduce polling * Stops polling if it's being destroyed * Update changelog
Diffstat (limited to 'app')
-rw-r--r--app/components/comment.js17
-rw-r--r--app/components/comment_form.js73
-rw-r--r--app/components/comments.js76
-rw-r--r--app/components/post.js23
-rw-r--r--app/components/post_form.js19
-rw-r--r--app/components/posts.js24
-rw-r--r--app/dasein.js7
7 files changed, 217 insertions, 22 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();
+
}
});
diff --git a/app/dasein.js b/app/dasein.js
index 6b3fd95..699a01f 100644
--- a/app/dasein.js
+++ b/app/dasein.js
@@ -22,13 +22,6 @@ export default internals.Dasein = {
this.vm = new Vue({
router: this._setupRouter(),
el: '#dasein',
- components: {
- login: LoginComponent,
- welcome: WelcomeComponent
- },
- data: {
- message: 'Hello Vue!'
- },
methods: {
authenticated() {