-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* wip create comments in public page * add comment component and create get request comment * covert static comments to dynamic comments * change variable and condition for dynamic object * create register page * wip create comments in frontEnd * create and test send and get comment component * create and test send and get comment component --------- Co-authored-by: esakh <[email protected]>
- Loading branch information
1 parent
b9e1212
commit 75c2cd9
Showing
6 changed files
with
387 additions
and
65 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,58 +1,73 @@ | ||
<template> | ||
<div> | ||
<h5 class="mb-3"> | ||
<span class="fa-regular fa-comment"></span> | ||
<span class="mx-1">دیدگاه ها</span> | ||
</h5> | ||
|
||
<form v-if="params.isLogin" class="my-3"> | ||
<textarea class="form-control mb-3" placeholder="دیدگاه خود را اینجا بنویسید" rows="3" required></textarea> | ||
<button class="btn btn-success" type="submit">ثبت دیدگاه</button> | ||
</form> | ||
|
||
<div v-else class="alert alert-light"> | ||
<i class="fa-regular fa-bell fa-shake fa-xl"></i> | ||
<span class="mx-1">برای ثبت دیدگاه خود</span> | ||
<NuxtLink class="mx-1" href="/auth/register">ثبت نام کنید</NuxtLink> | ||
<span>یا</span> | ||
<NuxtLink class="mx-1" to="/auth/login">وارد شوید</NuxtLink> | ||
</div> | ||
|
||
<section class="card mb-3"> | ||
<div class="card-body d-flex flex-start"> | ||
<img class="rounded-circle shadow-1-strong ms-3" src="https://mdbcdn.b-cdn.net/img/Photos/Avatars/img%20(3).webp" alt="avatar" width="65" height="65"> | ||
<div class="flex-grow-1 flex-shrink-1"> | ||
<div class="d-flex justify-content-between align-items-center"> | ||
<p class="mb-1"> | ||
<span>افشار زند</span> | ||
<span class="text-muted small"> | ||
<span class="fa-regular fa-clock mx-1"></span> | ||
<time datetime="">{{ useTime().toAgo('2024/05/20') }}</time> | ||
</span> | ||
</p> | ||
<div v-if="params.isLogin" class="text-nowrap"> | ||
<button class="btn text-danger btn-sm"> | ||
<i class="fas fa-trash fa-xs"></i> | ||
</button> | ||
<span>|</span> | ||
<button class="btn btn-sm"> | ||
<i class="fas fa-reply fa-xs"></i> | ||
</button> | ||
</div> | ||
</div> | ||
<p class="small mb-0 pt-2 border-top"> | ||
طراحان معمولا از لورم ایپسوم | ||
استفاده میکنند تا فقط به مشتری یا کار فرما نشان دهند که قالب طراحی شده بعد از اینکه متن | ||
در آن قرار میگرد چگونه خواهد بود و فونت ها و اندازه ها چگونه در نظر گرفته شده است. | ||
</p> | ||
</div> | ||
</div> | ||
</section> | ||
<section> | ||
<h5 class="mb-3"> | ||
<span class="fa-regular fa-comment"></span> | ||
<span class="mx-1">دیدگاه ها</span> | ||
</h5> | ||
<comments-write-new :disabled="disabled" | ||
@sendComment="sendComment" v-if="params.isLogin"/> | ||
<div v-else class="alert alert-light"> | ||
<i class="fa-regular fa-bell fa-shake fa-xl"></i> | ||
<span class="mx-1">برای ثبت دیدگاه خود</span> | ||
<NuxtLink class="mx-1" href="/auth/register">ثبت نام کنید</NuxtLink> | ||
<span>یا</span> | ||
<NuxtLink class="mx-1" to="/auth/login">وارد شوید</NuxtLink> | ||
</div> | ||
<comments-item v-for="(item , index) in comments" :key="index" :data="item" v-if="comments && comments.length"/> | ||
</section> | ||
</template> | ||
|
||
<script lang="ts" setup> | ||
const params = reactive({ | ||
isLogin: useAuth().isLogin(), | ||
const route = useRoute() | ||
const {data} = defineProps(['data']) | ||
useState('clearDataAfterCloseComment', ()=>false) | ||
const comments = (data && data.length) ? createTree(data) : "" | ||
const disabled = ref() | ||
function createTree(comments: []): [] { | ||
const map = new Map(); | ||
comments.forEach(comment => map.set(comment.uuid, comment)); | ||
const tree: [] = []; | ||
comments.forEach(comment => { | ||
const parent = map.get(comment.parent_uuid); | ||
if (!parent) { | ||
tree.push(comment); | ||
} | ||
}); | ||
// تکمیل کردن زیرمجموعهها | ||
tree.forEach((node: object) => { | ||
const fillSubtree = (node: object) => { | ||
node.sub = comments.filter(comment => comment.parent_uuid === node.uuid); | ||
node.sub.forEach(fillSubtree); | ||
}; | ||
fillSubtree(node); | ||
}); | ||
return tree; | ||
} | ||
const sendComment = async (text: string) => { | ||
const body = { | ||
object_uuid: route.params.uuid, | ||
body: text, | ||
object_type: 'article', | ||
parent_uuid: "" | ||
} | ||
try { | ||
disabled.value = true /* برای غیر فعال شدن دکمه ارسال کامنت بعد فشرده شدن تا زمان برشگت درخواست */ | ||
useState('clearDataAfterCloseComment').value = false /* برای خالی کردن مقدار کامنت در صورت موفقیت بودن درخواست */ | ||
const data = await useUser().$fetch(useApiUrlResolver().resolve('api/comments'), { | ||
method: 'POST', | ||
headers: {authorization: `Bearer ${useAuth().accessToken()}`}, | ||
body: JSON.stringify(body), | ||
}) | ||
</script> | ||
useState('clearDataAfterCloseComment').value = true | ||
} catch (e) { | ||
console.log(e) | ||
} finally { | ||
disabled.value = false /*جواب درخواست ما هرچی که باشه درانتها هر چی که باشه دکمه از حالت disable در میاد*/ | ||
} | ||
} | ||
const params = reactive({ | ||
isLogin: useAuth().isLogin(), | ||
}) | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
<template> | ||
<section :class="{child:child }" v-if="data"> | ||
<section class="card mb-3"> | ||
<div class="card-body d-flex flex-start"> | ||
<img v-if="data.author.avatar" class="rounded-circle shadow-1-strong ms-3" | ||
:src="useFilesUrlResolver().resolve(data.author.avatar)" alt="avatar" width="65" | ||
height="65"> | ||
<div class="flex-grow-1 flex-shrink-1 "> | ||
<div class="d-flex justify-content-between align-items-center"> | ||
<p class="info mb-1"> | ||
<span v-if="data.author.name">{{ data.author.name }}</span> | ||
<span class="text-muted small me-1" v-if="data.created_at && data.created_at.length"> | ||
<span class="fa-regular fa-clock mx-1"></span> | ||
<time datetime="">{{ useTime().toAgo(data.created_at) }}</time> | ||
</span> | ||
</p> | ||
<div v-if="params.isLogin" class="text-nowrap"> | ||
<button class="btn text-danger btn-sm" v-if="false"> | ||
<i class="fas fa-trash fa-xs"></i> | ||
</button> | ||
<span v-if="false">|</span> | ||
<button class="btn btn-sm" @click="showWriteComment"> | ||
<i class="fas fa-reply fa-xs"></i> | ||
</button> | ||
</div> | ||
</div> | ||
<p v-if="data.body && data.body.length" class="text small mb-0 pt-2 border-top ">{{ data.body }}</p> | ||
</div> | ||
</div> | ||
</section> | ||
<section class="write-comment px-1" ref="writeComment"> | ||
<comments-write-new :clear-data="clearDataAfterCloseComment" :disabled="disabled" :parentInfo="data.uuid" | ||
@send-comment="sendComment" :replyTheme="true"> | ||
<button class="btn btn-sm btn-md-lg btn-danger align-self-start mt-2" @click.prevent="showWriteComment">بستن | ||
</button> | ||
</comments-write-new> | ||
</section> | ||
<comments-item v-if="data.sub && data.sub.length" v-for="(item , index) in data.sub" :key="index" :data="item" | ||
:child="true"/> | ||
</section> | ||
</template> | ||
|
||
<script setup lang="ts"> | ||
const {uuid} = useRoute().params | ||
import {useFilesUrlResolver} from "~/composables/urlResolver"; | ||
const disabled = ref() | ||
const writeComment = ref(null) | ||
const clearDataAfterCloseComment = ref(false) | ||
const {data, child} = defineProps({ | ||
data: { | ||
type: Object, | ||
}, | ||
child: { | ||
type: Boolean | ||
} | ||
}) | ||
/* در فانکشن زیر ما برای ظاهر شدن کامپوننت کامنت از maxHeight استفاده کردیم | ||
به این صورت که در ابتدا صفر و با کلیک برروی ریپلای به اندازه طول | ||
اسکرول آن بعلاوه 20 پیکسل بیشتر که ارفاع ارور آن دررمان ظاهر شدن است */ | ||
const showWriteComment = () => { | ||
if (writeComment.value.style.maxHeight) { | ||
writeComment.value.style.maxHeight = null | ||
useState('clearDataAfterCloseComment').value = true | ||
} else { | ||
writeComment.value.style.maxHeight = writeComment.value.scrollHeight + 'px' | ||
useState('clearDataAfterCloseComment').value = false | ||
} | ||
} | ||
const sendComment = async (text: string, parentUuid: string) => { | ||
const body = { | ||
body: text, | ||
object_type: 'article', | ||
parent_uuid: parentUuid, | ||
object_uuid: uuid | ||
} | ||
try { | ||
disabled.value = true /* برای غیر فعال شدن دکمه ارسال کامنت بعد فشرده شدن تا زمان برشگت درخواست */ | ||
const data = await useUser().$fetch(useApiUrlResolver().resolve('api/comments'), { | ||
method: 'POST', | ||
headers: {authorization: `Bearer ${useAuth().accessToken()}`}, | ||
body: JSON.stringify(body) | ||
}) | ||
showWriteComment() /*برای بسته شدن ریپلای در صورت موفقیت آمیز بودن ارسال درخواست */ | ||
} catch (e) { | ||
console.log(e) | ||
} finally { | ||
disabled.value = false /* عملیات ارسال دیتا در نهایت هرچی که باشه دکمه ما تغیر حالت میده */ | ||
} | ||
} | ||
const params = reactive({ | ||
isLogin: useAuth().isLogin(), | ||
}) | ||
</script> | ||
|
||
<style scoped lang="scss"> | ||
card { | ||
transition: 0.5s; | ||
} | ||
.child { | ||
margin-right: 3%; | ||
} | ||
p { | ||
&.text { | ||
line-height: 30px; | ||
font-size: 14px; | ||
color: #6c757d; | ||
} | ||
&.info { | ||
line-height: 20px; | ||
font-size: 14px; | ||
} | ||
} | ||
.transform-enter-active { | ||
animation: reply ease-out 0.35s; | ||
z-index: 1; | ||
} | ||
.transform-leave-active { | ||
animation: reply ease-in 0.35s reverse; | ||
} | ||
.write-comment { | ||
max-height: 0; | ||
overflow: hidden; | ||
transition: 0.5s !important; | ||
} | ||
@keyframes reply { | ||
0% { | ||
transform: translateY(-10%); | ||
opacity: -1; | ||
} | ||
100% { | ||
transform: translateY(0); | ||
opacity: 1; | ||
} | ||
} | ||
</style> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
<script setup lang="ts"> | ||
const {parentInfo, replyTheme, disabled} = defineProps({ | ||
parentInfo: { | ||
type: String | ||
}, | ||
replyTheme: { | ||
type: Boolean | ||
}, | ||
disabled: { | ||
type: Boolean | ||
} | ||
}) | ||
const emit = defineEmits(['sendComment']) | ||
const commentData = reactive({ | ||
body: "", | ||
error: false | ||
}) | ||
watch(() => useState('clearDataAfterCloseComment').value, () => { | ||
commentData.body = "" | ||
}) | ||
const sendComment = () => { | ||
if (commentData.body.length > 4) { | ||
emit('sendComment', commentData.body, parentInfo) | ||
} else { | ||
commentData.error = true | ||
} | ||
} | ||
const removeError = () => { | ||
commentData.error ? commentData.error = false : "" | ||
} | ||
</script> | ||
|
||
<template> | ||
<form class="my-3 py-1 d-flex flex-column" :class="{'mt-0':replyTheme}" @submit.prevent="sendComment"> | ||
<textarea class="form-control mb-1" placeholder="دیدگاه خود را اینجا بنویسید" rows="3" required | ||
v-model.trim="commentData.body" @keyup="removeError"></textarea> | ||
<span class="error text-danger" v-if="commentData.error">متن پیام باید بیشتر باشد .</span> | ||
<div class="d-flex gap-2"> | ||
<button :class="`btn btn-success align-self-start ${ replyTheme ?'btn-sm mt-2': 'mt-3'}`" :disabled="disabled" | ||
type="submit">ثبت دیدگاه | ||
</button> | ||
<slot/> | ||
</div> | ||
</form> | ||
</template> | ||
|
||
<style scoped> | ||
.error { | ||
font-size: 12px; | ||
} | ||
</style> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.