<!-- src/views/MyLogView.vue -->
<template>
<v-container>
<v-card v-if="mylog">
<!--글쓴이의 마이로그 이름-->
<v-card-title v-if=author style="cursor: pointer; font-size:1em" @click="goToUserMylogs(author.id)">
{{ getMylogName }}<v-icon>mdi-chevron-right</v-icon>
</v-card-title>
<!-- 마이로그 제목 -->
<v-card-title v-if=author style="cursor: pointer; font-size:1em">
{{ mylog.title }}
</v-card-title>
<!-- 마이로그 내용 -->
<!-- eslint-disable -->
<v-card-text style="font-size:1em" v-html="content"></v-card-text>
<!-- eslint-enable -->
<!-- 글쓴이 이름, 작성일, 조회수 -->
<v-card-subtitle style="text-align:right">
{{ mylog.userName }} . {{ mylog.createdAt.toDate().toISOString().split('T')[0] }}
<span v-if="mylog.views > 0" > ({{ mylog.views }})</span>
</v-card-subtitle>
<v-card-actions >
<v-spacer></v-spacer>
<!-- 구독 버튼 -->
<v-btn small text v-if="!isAuthor && user" @click="toggleSubscription">
{{ isSubscribed ? "구독 취소" : "구독" }} <v-icon>mdi-check-circle</v-icon>
</v-btn>
<!-- 게시물 수정 버튼 -->
<v-btn small text v-if="isAuthor" @click="goToEditMylog()">
수정 <v-icon>mdi-pencil</v-icon>
</v-btn>
</v-card-actions>
<!-- 댓글 작성 폼 -->
<v-form v-if="user" @submit.prevent="submitComment" class="ml-2 mr-2">
<v-textarea outlined style="border-color: #fffeee;" v-model="newComment" label="댓글 쓰기 ..." rows="3" required></v-textarea>
<v-btn class="ml-1 mt-n10" small outlined type="submit" color="primary">댓글</v-btn>
</v-form>
<v-list >
<!-- 댓글 리스트 -->
<v-list-item v-for="comment in comments" :key="comment.id">
<v-list-item-content>
<!-- eslint-disable -->
<v-list-item-subtitle style="white-space: normal;" v-html="sanitizeContent(comment.content)"></v-list-item-subtitle>
<!--댓글 -->
<!-- eslint-enable -->
<v-list-item-subtitle class="mt-1">
{{ comment.userName }} . {{ formatDate(comment.createdAt) }}
<v-btn v-if="isOwner(comment.userId)" icon @click="doDeleteComment(comment.id)">
<v-icon>mdi-delete</v-icon>
</v-btn>
<!-- reply 버튼 -->
<v-btn v-if="user" small text @click="showReplyForm(comment.id)">답글</v-btn>
</v-list-item-subtitle>
<!-- 답글 리스트 -->
<v-list class="ml-5" v-if="comment.replies && comment.replies.length">
<!-- 답글 -->
<v-list-item v-for="reply in comment.replies" :key="reply.id">
<v-list-item-content>
<!-- eslint-disable -->
<v-list-item-subtitle style="white-space: normal;" v-html="sanitizeContent(reply.content)"></v-list-item-subtitle>
<!-- eslint-enable -->
<v-list-item-subtitle class="ml-2">
{{ reply.userName }} : {{ formatDate(reply.createdAt) }}
<v-btn v-if="isOwner(reply.userId)" icon @click="doDeleteReply(comment.id, reply.id)">
<v-icon>mdi-delete</v-icon>
</v-btn>
</v-list-item-subtitle>
</v-list-item-content>
</v-list-item>
</v-list>
<!-- 답글 쓰기-->
<v-form class="ml-5 mt-1 mr-2" v-if="replyingTo === comment.id" @submit.prevent="submitReply(comment.id)">
<v-textarea outlined style="border-color: #fffeee; width: 90%" v-model="newReply" label="답글 쓰기 ..." rows="3" required></v-textarea>
<v-btn class="ma-0 mt-n12" small text @click="showReplyForm(null)">취소</v-btn>
<v-btn class="ma-0 mt-n12" small text type="submit" color="primary">답글</v-btn>
</v-form>
<!-- reply end --->
</v-list-item-content>
</v-list-item>
</v-list>
</v-card>
<v-alert v-else-if="!loading" type="error" dismissible @input="resetErrorMsg" class="my-alert">
Mylog not found. Please check the link and try again.
</v-alert>
<div class="text-center">
<v-progress-circular v-if="loading" indeterminate></v-progress-circular>
</div>
</v-container>
</template>
<script>
import { mapActions, mapGetters } from "vuex";
import sanitizeHtml from 'sanitize-html';
export default {
data() {
return {
content: '',
newComment: '',
newReply: '',
replyingTo: null,
author: null, // 저자의 이름을 가져오기 위해
};
},
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로 변경한다.
// 마이로그 저자 찾기 - 상태에 로드되어 있는 전체 회원 정보를 이용한다.
const users = this.$store.state.auth.users;
this.author = users.find(user => user.id === this.mylog.userId);
const userId = this.$store.state.auth.user ? this.$store.state.auth.user.id : null; // 로그인 여부 확인
// 마이로그의 저자에 대해 현재 로그인한 회원이 구독중인지 확인한다.
const authorId = this.mylog.userId;
if(userId) {
this.checkSubscription({userId, authorId}); // Check if the user is subscribed when the component mounts
}
// 조회수를 증가한다.
// 같은 회원은 몇번을 방문해도 하루 1회, 비회원도 조회수 증가시킴
await this.updateViewCount(mylogId, userId); // 조회수 업데이트 및 기록
// comments를 로드한다.
await this.fetchComments(mylogId);
},
computed: {
...mapGetters('auth',['user']),
...mapGetters('mylogs',['mylog', 'comments', 'isSubscribed', 'subscriptionId', 'loading']),
getMylogName() {
return this.author.mylogname;
},
// 저자인가? - 작성자와 로그인한 사용자 비교
isAuthor() {
return this.$store.state.auth.user && this.$store.state.auth.user.id === this.mylog.userId;
},
},
methods: {
...mapActions('mylogs', ['fetchMylog', 'resetError', 'updateViewCount','addComment', 'fetchComments','deleteComment',
'addReply', 'deleteReply', 'checkSubscription', 'subscribeToUser', 'unsubscribeFromUser']),
// content를 안전한 html로 바꿔준다.
sanitizeContent(content) {
return sanitizeHtml(content.replace(/\n/g, '<br>'), {
allowedTags: ['b', 'i', 'em', 'strong', 'p', 'br'],
allowedAttributes: {}
});
},
// 마이로그 수정
goToEditMylog() {
this.$router.push({ name: 'edit', 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) {
if (date && date.toDate) {
return date.toDate().toISOString().replace('T', ' ').substring(0, 16);
}
return '';
},
// 답글 작성 폼 보이기
showReplyForm(commentId) {
this.replyingTo = commentId;
},
// 로그인한 회원이 마이로그 작성자인가?
isOwner(userId) {
if(!this.$store.state.auth.user)
return false;
return userId === this.$store.state.auth.user.id;
},
// 답글 작성
async submitReply(commentId) {
if (this.newReply && this.newReply.trim()) {
await this.addReply({
mylogId: this.$route.params.id,
commentId: commentId,
content: this.newReply,
userName: this.$store.state.auth.user.username,
userId: this.$store.state.auth.user.id,
});
this.newReply = ''; // 입력 필드 초기화
this.replyingTo = null;
}
},
// 답글 삭제 실행
async doDeleteReply(commentId, replyId) {
const mylogId = this.$route.params.id;
await this.deleteReply({
mylogId: mylogId,
commentId: commentId,
replyId: replyId
});
},
// -- 구독 -------------------------------
// Toggle subscription: subscribe if not subscribed, unsubscribe if already subscribed
async toggleSubscription() {
const userId = this.$store.state.auth.user.id;
const authorId = this.mylog.userId;
const subscriptionId = this.subscriptionId;
if (this.isSubscribed) {
// Unsubscribe the user
await this.unsubscribeFromUser({userId, subscriptionId});
} else {
// Subscribe the user
await this.subscribeToUser({userId, authorId});
}
// 변경 내용 갱신을 위하여
this.checkSubscription({userId, authorId}); // Check if the user is subscribed when the component mounts
},
// -- 구독 끝 ----------------------------
// -- 저자의 마이로그 홈으로 가기
goToUserMylogs(userId) {
this.$router.push({ name: 'userlogs', params: { userId } });
},
}
};
</script>