Vue PWA mylog

mylog 상세보기

그랜파 개발자 2024. 11. 13. 03:51

Vue로 PWA 개발 - 그랜파 개발자

Vue 프로젝트 Beta Test : mylog, 일상의 기록

개발이 진행됨에 따라 소스 코드를 계속 추가해 갑니다.

 

홈페이지의 마이로그 목록에서 마이로그를 선택하면 상세보기로 이동합니다. 상세 보기에서는 댓글과 답글을 쓸 수 있고, 구독과 수정도 할 수 있습니다.

마이로그 상세보기

마이로그는 단문 서비스이므로 마이로그 전체 목록 보기에서 각 마이로그 내용 전체를 볼 수 있습니다. 그럼에도 상세보기가 있는 이유는 마이로그에 대한 댓글과 댓글에 대한 답글을 위한 것입니다. 그리고 조회수를 카운트 합니다. 전체 목록에서 내용을 볼 수 있는데, 굳이 마이로그를 선택하여 상세 보기 페이지가 열릴 때 조회수를 카운트하는 것이 어색하긴 합니다.

  1. 마이로그 리스트에서 마이로그를 선택하면 상세보기 페이지가 열립니다.
  2. 상세보기 페이지가 열리면서 조회수를 업데이트 합니다.
  3. 선택한 마이로그를 보여주고, 마이로그를 구독 또는 수정할 수 있습니다.
  4. 마이로그에 대한 댓글과 답글을 보여 줍니다.
  5. 마이로그 저자의 마이로그 이름을 상단에 보여주고, 그것을 클릭하면 마이로그 저자의 홈으로 이동하여 저자의 모든 마이로그를 볼 수 있습니다.

1. 마이로그 선택

마이로그 전체 목록에서 마이로그를 클릭하면 해당 마이로그가 선택되고, 선택한 마이로그의 mylogId를 가지고 상세 보기 페이지로 이동합니다.

src/views/HomeView.vue

<!-- src/views/HomeView.vue -->
<template>
  <v-container>
    
    . . .

    <v-row>
      <v-col v-for="mylog in mylogs" :key="mylog.id" @click="viewMylog(mylog.id)" cols="12">
        <v-card>
          <v-card-title style="font-size:1em">{{ mylog.title }}</v-card-title>
          <!-- eslint-disable -->
          <v-card-text style="font-size:1em" class="mt-n2 mb-n6" v-html="sanitizeContent(mylog.content)"></v-card-text>
          <!-- eslint-enable -->
          <v-card-subtitle>
            <b>댓글</b> <span v-if="mylog.commentCount > 0"> {{mylog.commentCount }} </span> &nbsp;
            {{ mylog.userName }} . {{ formatDate(mylog.createdAt) }} 
            <span v-if="mylog.views > 0" > ({{ mylog.views }})</span>
          </v-card-subtitle>
        </v-card>
      </v-col>
    </v-row>

   . . .
    </div> 
      
  </v-container>
</template>

<script>
import { mapActions, mapGetters } from "vuex";
import sanitizeHtml from 'sanitize-html';

export default {
  name:'HomeView',
  data() {
    return {
      //mylogs: [],
    };
  },
  . . .
  methods: {
    ...mapActions('mylogs', ['resetError']),
    viewMylog(mylogId) {
      this.$router.push({ name: "mylog", params: { id: mylogId } });
    },
    . . .
};
</script>

2. 마이로그 상세 보기

파라미터로 mylogId를 받아 mylogId로 마이로그를 로드하여 마이로그를 나타냅니다.

src/views/MyLogView.vue

<!-- 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 ? "구독 취소" : "구독" }} &nbsp;<v-icon>mdi-check-circle</v-icon>
        </v-btn>
        <!-- 게시물 수정 버튼 -->
        <v-btn small text v-if="isAuthor" @click="goToEditMylog()">
          수정 &nbsp; <v-icon>mdi-pencil</v-icon>
        </v-btn>
      </v-card-actions>  

      . . .
    </v-card>

    . . .
  </v-container>
</template>

<script>
import { mapActions, mapGetters } from "vuex";
import sanitizeHtml from 'sanitize-html';

export default {
  data() {
    return {
      content: '',
      . . .
      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);
    . . .
  },
  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: {}
      });
    },
     . . .
    formatDate(date) {
      if (date && date.toDate) {
        return date.toDate().toISOString().replace('T', ' ').substring(0, 16); 
      }
      return '';
    },
    . . .
    // 로그인한 회원이 마이로그 작성자인가?
    isOwner(userId) {
      if(!this.$store.state.auth.user)
        return false;
      return userId === this.$store.state.auth.user.id;
    },
    . . .    
};
</script>

src/store/modules/mylogs.js

// src/store/modules/mylogs.js
import { v4 as uuidv4 } from 'uuid';
import { db, doc, collection, getDoc, getDocs, setDoc, addDoc,updateDoc, deleteDoc, arrayUnion, increment, where } from "@/firebase";
import { query, orderBy } from "@/firebase";

const state = {
  . . .
  mylog: null,
  . . .
};

const mutations = {
  . . .
  setMylog(state, mylog) {
    state.mylog = mylog;
  },
  . . .
};

const actions = {
  . . .
  // mylogId로 마이로그를 로드한다.
  async fetchMylog({ commit }, mylogId) {
    //console.log('mylogId:', mylogId);
    commit('setLoading', true);
    try {
      const docRef = doc(db, "mylogs", mylogId); // Reference to the specific article document
      const docSnap = await getDoc(docRef); // Fetch the document snapshot

      if (docSnap.exists()) {
        const mylog = docSnap.data(); // Set article data
        commit('setMylog', mylog);
      } else {
        console.error("mylog가 없습니다.");
      }
    } catch (error) {
      commit('setError', error);
    } finally {
      commit('setLoading', false);
    }
  },
  . . .
};

const getters = {
  . . .
  mylog: state => state.mylog,
  . . .
};

export default {
  namespaced: true,
  state,
  mutations,
  actions,
  getters
};

Vue PWA 프로젝트, mylog 코드

'Vue PWA mylog' 카테고리의 다른 글

mylog 조회수  (1) 2024.11.15
mylog 수정  (1) 2024.11.14
mylog 전체 보기  (0) 2024.11.11
mylog 계정  (0) 2024.11.11
mylog 로그인  (1) 2024.11.10