์ํ๋ ํธ์์ ํด๋ฆญํ๋ฉด
ํธ์ ํ์ด์ง๋ก ์ด๋ํด์
ํธ์์ ์์ธ ์ ๋ณด์ ๋๊ธ๋ค์ ํ์ธํ ์ ์๋ ํ์ด์ง๋ฅผ ๋ง๋ค๊ฑฐ์
router
-> index.js์ tweet ํ์ด์ง๋ฅผ ์ถ๊ฐํ๋ค.
{
path: "/tweet/:id",
name: "tweet",
component: Tweet,
meta: { isMenu: false, layout: "DefaultLayout", requireAuth: true },
},
pages์์ Tweet ์ปดํฌ๋ํธ ์์ฑ
router import ํด์
๋ค๋ก๊ฐ๊ธฐ ๋ฒํผ ํด๋ฆญํ๋ฉด router.go(-1)ํ๋ฉด ์ด์ ํ์ด์ง๋ก ๋์๊ฐ (์ ๊ธฐ)
<template>
<div class="flex-1 flex">
<div class="flex-1 border-r border-gray-100">
<div class="flex flex-col">
<!-- title -->
<div
class="flex justify-start items-center px-3 py-2 border-b border-gray-100"
>
<button @click="router.go(-1)">
<i
class="fas fa-arrow-left text-primary text-lg ml-3 hover:bg-blue-50 p2 rounded-full h-8 w-8"
></i>
</button>
<span class="font-bold text-lg ml-6">ํธ์</span>
</div>
<!-- tweet -->
<div class="px-3 py-2 flex">
<img
class="w-10 h-10 rounded-full hover:opacity-90"
/>
<div class="ml-2">
<div class="font-bold">์ด๋ฉ์ผ</div>
<div class="text-gray text-sm">@id</div>
</div>
</div>
<div class="px-3 py-2">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Obcaecati
cupiditate molestias, temporibus, sapiente consectetur atque saepe
quibusdam aut at culpa delectus quas sed impedit! Tempora suscipit est
quam id natus.
</div>
<div class="px-3 py-2 text-gray text-xs">์คํ:7:00 2021๋
2์ 20์ผ</div>
<div class="h-px w-full bg-gray-100"></div>
<div class="flex space-x-2 px-3 py-2 items-center">
<span class="">1</span>
<span class="text-sm text-gray">๋ฆฌํธ์</span>
<span class="ml-5">1</span>
<span class="text-sm text-gray">๋ง์์ ๋ค์ด์</span>
</div>
<div class="h-px w-full bg-gray-100"></div>
<!-- buttons -->
<div class="flex justify-around py-2">
<button>
<i
class="far fa-comment text-gray-400 text-xl hover:bg-blue-50 hover:text-primary p-2 rounded-full w-10 h-10"
></i>
</button>
<button>
<i
class="fas fa-retweet text-gray-400 text-xl hover:bg-green-50 hover:text-green-400 p-2 rounded-full w-10 h-10"
></i>
</button>
<button>
<i
class="far fa-heart text-gray-400 text-xl hover:bg-red-50 hover:text-red-400 p-2 rounded-full w-10 h-10"
></i>
</button>
</div>
<div class="h-px w-full bg-gray-100"></div>
<!-- comments -->
<div
v-for="comment in 10"
:key="comment"
class="flex hover:bg-gray-100 cursor-pointer px-3 py-3 border-b border-gray-100"
>
<img
class="w-10 h-10 rounded-full hover:opacity-90"
/>
<div class="ml-2 flex-1">
<div class="flex items-center space-x-2">
<span class="font-bold">hong@gmail.com</span>
<span class="text-gray text-sm">hong</span>
<span>19 days ago</span>
</div>
<div>๋๊ธ</div>
</div>
<button>
<i
class="fas fa-trash text-red-400 hover:bg-red-50 w-10 h-10 rounded-full p-2"
></i>
</button>
</div>
</div>
</div>
<Trends />
</div>
</template>
<script>
import Trends from "../components/Trends.vue";
import router from "../router";
export default {
components: { Trends },
setup() {
return {
router,
};
},
};
</script>
<style></style>
ํ์ฌ๋ ์ค์ ๋ฐ์ดํฐ๋ฅผ ๋ฃ์๊ฒ์ด ์๋ ๋๋ฏธ๋ฐ์ดํฐ๋ฅผ ๋ฃ์๋ค.
Tweet ์ปดํฌ๋ํธ์์
ํธ์ ๋ฐ๋๋ฅผ ํด๋ฆญํ๋ฉด ์์ธ๋ณด๊ธฐ ํ์ด์ง๋ก ๋์ด๊ฐ์์๊ฒ
router-link๋ก ๊ต์ฒดํ๋ค.
<!-- ํธ์ ๋ฐ๋ -->
<router-link :to="`/tweet/${tweet.id}`">
{{ tweet.tweet_body }}
</router-link>
์ด์ ํธ์์ ํด๋ฆญํ๋ฉด
ํธ์ ํ์ด์ง๋ก ๋์ด๊ฐ๋ค.
์ด์ ์ค์ ๋ฐ์ดํฐ๋ก ๊ต์ฒดํ๋ฉด๋จ
Tweetํ์ด์ง์์
<script>
import Trends from "../components/Trends.vue";
import router from "../router";
import { onBeforeMount, ref, computed } from "vue";
import store from "../store";
import { useRoute } from "vue-router";
import { doc, onSnapshot } from "firebase/firestore";
import getTweetInfo from "../utils/getTweetInfo";
import { db } from "../firebase";
import moment from "moment";
export default {
components: { Trends },
setup() {
const tweet = ref(null);
const comments = ref([]);
const currentUser = computed(() => store.state.user);
const route = useRoute();
onBeforeMount(async () => {
const unsub = onSnapshot(
doc(db, "tweets", route.params.id),
async (doc) => {
let t = await getTweetInfo(doc.data(), currentUser.value);
tweet.value = t;
}
);
});
return {
router,
tweet,
comments,
currentUser,
moment,
};
},
};
</script>
onSnapshot์ผ๋ก ์ค์๊ฐ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ด
๊ทธ๋ฆฌ๊ณ ๊ทธ ๋ฐ์ดํฐ๋ฅผ return ํด์
<template>
<div class="flex-1 flex">
<div class="flex-1 border-r border-gray-100">
<div class="flex flex-col" v-if="tweet">
<!-- title -->
<div
class="flex justify-start items-center px-3 py-2 border-b border-gray-100"
>
<button @click="router.go(-1)">
<i
class="fas fa-arrow-left text-primary text-lg ml-3 hover:bg-blue-50 p2 rounded-full h-8 w-8"
></i>
</button>
<span class="font-bold text-lg ml-6">ํธ์</span>
</div>
<!-- tweet -->
<div class="px-3 py-2 flex">
<img
:src="`${tweet.profile_image_url}`"
class="w-10 h-10 rounded-full hover:opacity-90"
/>
<div class="ml-2">
<div class="font-bold">{{ tweet.email }}</div>
<div class="text-gray text-sm">@{{ tweet.username }}</div>
</div>
</div>
<div class="px-3 py-2">
{{ tweet.tweet_body }}
</div>
<div class="px-3 py-2 text-gray text-xs">
{{ moment(tweet.created_at).fromNow() }}
</div>
<div class="h-px w-full bg-gray-100"></div>
<div class="flex space-x-2 px-3 py-2 items-center">
<span class="">{{ tweet.num_retweets }}</span>
<span class="text-sm text-gray">๋ฆฌํธ์</span>
<span class="ml-5">{{ tweet.num_likes }}</span>
<span class="text-sm text-gray">๋ง์์ ๋ค์ด์</span>
</div>
<div class="h-px w-full bg-gray-100"></div>
<!-- buttons -->
<div class="flex justify-around py-2">
<button>
<i
class="far fa-comment text-gray-400 text-xl hover:bg-blue-50 hover:text-primary p-2 rounded-full w-10 h-10"
></i>
</button>
<button>
<i
class="fas fa-retweet text-gray-400 text-xl hover:bg-green-50 hover:text-green-400 p-2 rounded-full w-10 h-10"
></i>
</button>
<button>
<i
class="far fa-heart text-gray-400 text-xl hover:bg-red-50 hover:text-red-400 p-2 rounded-full w-10 h-10"
></i>
</button>
</div>
<div class="h-px w-full bg-gray-100"></div>
<!-- comments -->
<div
v-for="comment in 10"
:key="comment"
class="flex hover:bg-gray-100 cursor-pointer px-3 py-3 border-b border-gray-100"
>
<img
class="w-10 h-10 rounded-full hover:opacity-90"
/>
<div class="ml-2 flex-1">
<div class="flex items-center space-x-2">
<span class="font-bold">hong@gmail.com</span>
<span class="text-gray text-sm">hong</span>
<span>19 days ago</span>
</div>
<div>๋๊ธ</div>
</div>
<button>
<i
class="fas fa-trash text-red-400 hover:bg-red-50 w-10 h-10 rounded-full p-2"
></i>
</button>
</div>
</div>
</div>
<Trends />
</div>
</template>
๋ฐ์ดํฐ๋ฅผ ๋ฃ์ด์ค
์ ๋ฒ์ ์์ฑํ๊ฒ๊ณผ ๊ฐ์ด ์ด๊ฑฐ๋ ์์ฑ์ผ์ ๊ธฐ์ค์ผ๋ก ์ค๋๊น์ง ๋ช์ผ ์ง๋ฌ๋์ง ํ์ธํ ์ ์๊ฒ ํด์ค
{{ moment(tweet.created_at).fromNow() }}
์์ง ๋๊ธ์ ์๊ฐ์ ธ์จ ์ํ์
์๋์ ๊ฐ์ด ์ ๊ฐ์ ธ์๋ด.
Tweet ํ์ด์ง์์
onBeforeMount ์ comments ๊ฐ์ ธ์ค๋ ์ฝ๋๋ฅผ ์ถ๊ฐํ๋ค.
onBeforeMount(async () => {
const unsub = onSnapshot(
doc(db, "tweets", route.params.id),
async (doc) => {
let t = await getTweetInfo(doc.data(), currentUser.value);
tweet.value = t;
}
);
const q = query(
collection(db, "comments"),
where("from_tweet_id", "==", route.params.id),
orderBy("created_at", "desc")
);
const unsubscribe = onSnapshot(q, (snapshot) => {
snapshot.docChanges().forEach(async (change) => {
let comment = await getTweetInfo(
change.doc.data(),
currentUser.value
);
if (change.type === "added") {
comments.value.splice(change.newIndex, 0, comment);
}
if (change.type === "modified") {
comments.value.splice(change.oldIndex, 1, comment);
}
if (change.type === "removed") {
comments.value.splice(change.oldIndex, 1);
}
});
});
});
return์ comments ์ถ๊ฐ ํ
v-for๋ฐ๋ณต๋ฌธ์ comments๋ก ๋ฐ๊ฟ์ค๋ค.
<!-- comments -->
<div
v-for="comment in comments"
:key="comment"
class="flex hover:bg-gray-50 cursor-pointer px-3 py-3 border-b border-gray-100"
>
<img
class="w-10 h-10 rounded-full hover:opacity-90"
/>
<div class="ml-2 flex-1">
<div class="flex items-center space-x-2">
<span class="font-bold">{{ comment.email }}</span>
<span class="text-gray text-sm">@{{ comment.usernae }}</span>
<span> {{ moment(comment.created_at).fromNow() }}</span>
</div>
<div>{{ comment.tweet_body }}</div>
</div>
๊ทธ๋ฆฌ๊ณ ์ค๋ฅธ์ชฝ์ ์ญ์ ๋ฒํผ์
handleDeleteCommentํจ์๋ก ์ญ์ ํด์ค๊ฑด๋ฐ
์ด ๋ฒํผ์ ํ์ฌ ์ ์์ค์ธ ์ ์ ์ ์ด ๋ต๊ธ์ ์์ฑํ ์ ์ ์ ๋์ผํด์ผ ๋ณด์ธ๋ค.
<button
@click="handleDeleteComment(comment)"
v-if="comment.uid == currentUser.uid"
>
<i
class="fas fa-trash text-red-400 hover:bg-red-50 w-10 h-10 rounded-full p-2"
></i>
</button>
๋ต๊ธ ์ญ์ ๋ฒํผ์ ์๋์ ๊ฐ๋ค.
deleteDoc์ ์ฌ์ฉํ์ฌ comment์ id๋ฅผ ๋ฐ์์ ์ญ์ ํ๊ณ
tweet์ num_comments์ count๋ฅผ 1์ค์ฌ์ค๋ค.
const handleDeleteComment = async (comment) => {
if (confirm("๋ต๊ธ์ ์ญ์ ํ์๊ฒ ์ต๋๊น?")) {
//delete comment
await deleteDoc(doc(db, "comments", comment.id));
//decrease comment counts
const updateTweetRef = doc(db, "tweets", comment.from_tweet_id);
await updateDoc(updateTweetRef, {
num_comments: increment(-1),
});
}
};
๋ค๋ฅธ ์ ์ ๋ก ์ ๊ทผํ์ ์ ์ญ์ ๋ฒํผ ์๋ณด