마이로그 상세 보기 하단에 댓글들의 리스트를 볼 수 있고, 로그인 후에는 누구나 마이로그에 대한 댓글을 쓸 수 있습니다. 댓글 리스트를 나타내기 위해서는 마이로그의 댓글들 전체 리스트를 로드하여야 합니다. 댓글을 쓰거나 삭제를 하면 댓글들의 리스트를 다시 로드합니다.
1. 댓글 쓰기
2. src/views/MyLogView.vue
<!-- src/views/MyLogView.vue -->
<template>
<v-container>
<v-row justify="center">
<v-col cols="12" md="8">
<v-card v-if="mylog">
<v-card-title>{{ mylog.title }}</v-card-title>
<v-card-subtitle>
{{ mylog.userName }} Posted on: {{ mylog.createdAt.toDate().toLocaleString() }} ({{ mylog.views }})
</v-card-subtitle>
<v-card-text>
<!-- eslint-disable -->
<v-card-text v-html="content"></v-card-text>
<!-- eslint-enable -->
</v-card-text>
<v-card-actions v-if="isAuthor">
<!-- 게시물 수정 버튼 -->
<v-btn @click="goToEditMylog()"> 수정 <v-icon>mdi-pencil</v-icon></v-btn>
</v-card-actions>
<!-- 댓글 목록 -->
<v-divider class="my-2"></v-divider>
<h3>Comments</h3>
<v-list>
<v-list-item v-for="comment in comments" :key="comment.id">
<v-list-item-content>
<v-list-item-title>{{ comment.content}}</v-list-item-title>
<v-list-item-subtitle>
{{ comment.userName }} : {{ formatDate(comment.createdAt) }}
<v-btn v-if="isCommentOwner(comment.userId)" icon @click="doDeleteComment(comment.id)">
<v-icon>mdi-delete</v-icon>
</v-btn>
</v-list-item-subtitle>
</v-list-item-content>
</v-list-item>
</v-list>
<!-- 댓글 작성 폼 -->
<v-form v-if="isAuthenticated" @submit.prevent="submitComment">
<v-textarea v-model="newComment" label="Write a comment..." rows="3" required></v-textarea>
<v-btn small outlined type="submit" color="primary"> 댓글 쓰기 </v-btn>
</v-form>
</v-card>
<v-alert v-else type="error" dismissible @input="resetErrorMsg" class="my-alert">
Mylog not found. Please check the link and try again.
</v-alert>
<!-- <v-alert v-if="error" type="error" dismissible @input="resetErrorMsg" class="my-alert">{{ error }}</v-alert> -->
</v-col>
</v-row>
</v-container>
</template>
<script>
import { mapActions, mapGetters } from "vuex";
import sanitizeHtml from 'sanitize-html';
export default {
data() {
return {
content: '',
newComment: '',
};
},
async created() {
// 마이로그 가죠오기
const mylogId = this.$route.params.id; // Get the article ID from the route parameters
await this.fetchMylog(mylogId); // 마이로그 아이디로 마이로그를 가져온다.
this.content = this.sanitizeContent(this.mylog.content); // 내용에 포한된 html을 안전한 html로 변경한다.
// 조회수를 증가한다.
// 같은 회원은 몇번을 방문해도 하루 1회, 비회원도 조회수 증가시킴
const userId = this.$store.state.auth.user ? this.$store.state.auth.user.id : null; // 로그인 여부 확인
await this.updateViewCount(mylogId, userId); // 조회수 업데이트 및 기록
// comments를 로드한다.
await this.fetchComments(mylogId); // 조회수 업데이트 및 기록
},
computed: {
// 'mylog' mylogs store의 mylog getter로서 현재 선택된 마이로그를 돌려준다.
...mapGetters('mylogs',['mylog', 'comments']),
// 작성자와 로그인한 사용자 비교
isAuthor() {
return this.$store.state.auth.user && this.$store.state.auth.user.id === this.mylog.userId;
},
isAuthenticated() {
//return !!auth.currentUser;
return this.$store.state.auth.user;
}
},
methods: {
// 'fetchMylog' mylogs의 action 함수로 마이로그를 firestore 에서 읽어온다.
...mapActions('mylogs', ['fetchMylog', 'resetError', 'updateViewCount','addComment', 'fetchComments','deleteComment']),
// content를 안전한 html로 바꿔준다.
sanitizeContent(content) {
return sanitizeHtml(content.replace(/\n/g, '<br>'), {
allowedTags: ['b', 'i', 'em', 'strong', 'p', 'br'],
allowedAttributes: {}
});
},
goToEditMylog() {
this.$router.push({ name: 'EditMyLogView', params: { mylogId: this.$route.params.id, mylog: this.mylog } });
},
resetErrorMsg() {
this.resetError();
},
async submitComment() {
//myLogId, content, autherName, author
if (this.newComment.trim()) {
await this.addComment({
mylogId: this.$route.params.id,
content: this.newComment,
userName: this.$store.state.auth.user.username,
userId: this.$store.state.auth.user.id,
});
this.newComment = ''; // 댓글 입력 필드 초기화
}
},
async doDeleteComment(commentId) {
await this.deleteComment({
mylogId: this.$route.params.id,
commentId: commentId
});
},
formatDate(date) {
//console.log(date.toDate().toLocaleString());
if (date && date.toDate) {
return date.toDate().toLocaleString();
}
return '';
},
isCommentOwner(userId) {
//console.log(userId, this.$store.state.auth.user.id);
//console.log(userId === this.$store.state.auth.user.id);
return userId === this.$store.state.auth.user.id;
},
}
};
</script>
3. src/store/modules/mylogs.js
Copy // comments 가져오기
async fetchComments({ commit }, mylogId) {
try {
const q = query(collection(db, "mylogs", mylogId, "comments"), orderBy("createdAt", "asc"));
const querySnapshot = await getDocs(q);
const comments = [];
querySnapshot.forEach((doc) => {
comments.push({ id: doc.id, ...doc.data() });
});
commit('setComments', comments); // 댓글을 상태에 저장
} catch (error) {
commit("setError", error);
console.error("댓글 가져오기 실패:", error);
}
},
// comments 추가 하기
async addComment({ commit }, { mylogId, content, userName, userId }) {
try {
const commentRef = await addDoc(collection(db, "mylogs", mylogId, "comments"), {
content: content,
userName: userName,
userId: userId,
//createdAt: serverTimestamp(),
createdAt: new Date(),
});
const newComment = { id: commentRef.id, content, userName, userId, createdAt: new Date() };
commit('addComment', newComment); // 새 댓글을 상태에 추가
} catch (error) {
commit("setError", error);
console.error("댓글 추가 실패:", error);
}
},
// comments 삭제 하기
async deleteComment({ commit, dispatch }, { mylogId, commentId }) {
const commentRef = doc(db, "mylogs", mylogId, "comments", commentId);
try {
await deleteDoc(commentRef);
dispatch('fetchComments', mylogId); // 댓글 다시 로그
//this.comments = this.comments.filter(c => c.id !== commentId);
console.log("댓글이 삭제되었습니다.");
} catch (error) {
commit("setError", error);
console.error("댓글 삭제 실패:", error);
}
}
'Vue로 PWA 개발' 카테고리의 다른 글
34. mylog 답글 구현 (0) | 2024.10.26 |
---|---|
33. mylog 답글 (0) | 2024.10.26 |
31. mylog 댓글 쓰기 (0) | 2024.10.26 |
30. mylog 수정, 내 마이로그 보기 구현 (0) | 2024.10.25 |
29. mylog 모아보기 (0) | 2024.10.25 |