286 lines
9.3 KiB
Vue
Executable File
286 lines
9.3 KiB
Vue
Executable File
<template>
|
|
<div v-if="user" class="flex flex-col h-full">
|
|
<board-top :user="user">
|
|
<template v-if="partnerIsBanned !== null" #menu>
|
|
<button class="default text-gray text-sm underline" @click="bannRequest">
|
|
{{ isBannedMessage }}
|
|
</button>
|
|
<!-- <button class="default mt-2 text-gray text-sm underline" @click="exitRoom">
|
|
Покинуть беседу
|
|
</button> -->
|
|
</template>
|
|
</board-top>
|
|
<div class="px-2 sm:px-5 xl:px-10 flex bg-indigo-200 border-b border-indigo-300">
|
|
<div class="flex-1 pt-5 pb-3">
|
|
<textarea ref="textarea" v-model="textMessage"
|
|
rows="3"
|
|
autofocus
|
|
name="comment" class="placeholder-gray bg-indigo-200 text-white max-h-56 block w-full py-3 border-0 resize-none focus:ring-0 text-sm sm:text-base"
|
|
placeholder="Напишите сообщение ..."
|
|
:disabled="frozen"
|
|
@keyup.ctrl.enter="createMessage"
|
|
/>
|
|
</div>
|
|
<div v-if="!frozen" class="mt-5 ml-3 flex-shrink-0 text-pink"
|
|
@click="createMessage"
|
|
>
|
|
<button class="default">
|
|
<svg class="w-8 h-8 flex-shrink-0">
|
|
<use xlink:href="#arrow-circle"></use>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="py-5 lg:py-10 px-2 sm:px-5 xl:px-10 space-y-5 flex-1 bg-indigo-400">
|
|
<div v-if="frozen" class="p-3 text-sm rounded-md bg-orange text-white text-center">
|
|
Вы не можете отправить сообщение пользователю
|
|
</div>
|
|
|
|
<div v-if="error" class="p-3 text-sm rounded-md bg-pink text-white text-center">
|
|
Ошибка загрузки данных
|
|
</div>
|
|
|
|
<div v-for="(messageCollection, key) in messages" :key="key"
|
|
class="space-y-5"
|
|
>
|
|
<div class="text-gray-light text-xs text-right">
|
|
{{ key }}
|
|
</div>
|
|
|
|
<board-message-item v-for="message in messageCollection"
|
|
:key="message.id"
|
|
:ref="el => domNodeFn(el, message.id)"
|
|
:profile-id="user.id"
|
|
:user-message="message"
|
|
@remove="removeMessage"
|
|
/>
|
|
</div>
|
|
|
|
|
|
<div v-if="loading" class="flex items-center justify-center">
|
|
<svg class="animate-spin h-8 w-8 text-white" xmlns="http://www.w3.org/2000/svg"
|
|
fill="none" viewBox="0 0 24 24"
|
|
>
|
|
<circle class="opacity-25" cx="12"
|
|
cy="12" r="10"
|
|
stroke="currentColor" stroke-width="4"
|
|
></circle>
|
|
<path class="opacity-75" fill="currentColor"
|
|
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
|
></path>
|
|
</svg>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div v-else class="p-10 text-center">
|
|
<h2 class="text-lg xl:text-3xl font-bold text-indigo-100">
|
|
Выберите пользователя
|
|
|
|
<board-friend-list />
|
|
</h2>
|
|
</div>
|
|
</template>
|
|
<script>
|
|
import { useAutoresizeTextarea } from '@/includes/composables'
|
|
import { useInfinityScroll } from '@/includes/composables/useInfinityScroll'
|
|
import { ref, watch, toRef, computed } from 'vue'
|
|
import { Inertia } from '@inertiajs/inertia'
|
|
import axios from 'axios'
|
|
|
|
import BoardMessageItem from './BoardMessageItem.vue'
|
|
import BoardTop from './BoardTop.vue'
|
|
import BoardFriendList from './BoardFriendList.vue'
|
|
|
|
export default {
|
|
components:{
|
|
BoardTop,
|
|
BoardMessageItem,
|
|
BoardFriendList
|
|
},
|
|
props: {
|
|
user: {
|
|
type: Object,
|
|
default: () => ({})
|
|
},
|
|
roomId: {
|
|
type: Number,
|
|
default: 0
|
|
},
|
|
frozen: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
search: {
|
|
type: String,
|
|
default: ''
|
|
}
|
|
},
|
|
|
|
emits: {
|
|
'disable': null,
|
|
'last-message': null,
|
|
'change-room': null,
|
|
'leave-room': null,
|
|
},
|
|
|
|
setup(props, {emit}){
|
|
const roomId = toRef(props, 'roomId')
|
|
|
|
const partnerIsBanned = ref(null)
|
|
const textarea = ref()
|
|
const textMessage = ref()
|
|
useAutoresizeTextarea(textarea)
|
|
|
|
const { domNodeFn, cursor, loading, error, refetchApi, data: messages } = useInfinityScroll(async () => {
|
|
const url = props.search ? `messenger/${roomId.value}?search=${props.search}&cursor=${cursor.value}` : `messenger/${roomId.value}?cursor=${cursor.value}`
|
|
const res = await axios.get(url)
|
|
return res.data
|
|
})
|
|
|
|
const checkRequestBanned = () => {
|
|
axios.post(route('messenger.banned.user'), {
|
|
params: {
|
|
user: props.user.id,
|
|
}
|
|
}).then(response => {
|
|
partnerIsBanned.value = response.data.banned
|
|
})
|
|
}
|
|
|
|
watch(roomId, (id) => {
|
|
if(id){
|
|
refetchApi()
|
|
checkRequestBanned()
|
|
partnerIsBanned.value = null
|
|
}
|
|
if(textarea.value){
|
|
textarea.value.focus()
|
|
}
|
|
}, { immediate: true })
|
|
|
|
watch(loading, (loading) => {
|
|
emit('disable', loading)
|
|
})
|
|
|
|
const createMessage = () => {
|
|
if(!textMessage.value.trim()){
|
|
alert('Введите сообщение')
|
|
return
|
|
}
|
|
axios.post('messenger', {
|
|
params: {
|
|
message: textMessage.value,
|
|
room: roomId.value,
|
|
}
|
|
}).then(response => {
|
|
if(!response.data){
|
|
alert('Вы не можете отправить сообщение данному пользователю')
|
|
return
|
|
}
|
|
textMessage.value = ''
|
|
const k = response.data.keyGroupDate // keyGroupDate - ключ, eg 28.11.21
|
|
if(messages.value[k]){
|
|
messages.value[k].unshift(response.data)
|
|
}else{
|
|
messages.value = { [k]: [ response.data ], ...messages.value }
|
|
}
|
|
emit('last-message', response.data)
|
|
})
|
|
}
|
|
|
|
const bannRequest = () => {
|
|
Inertia.post(route('messenger.banned.room'), { room: roomId.value },
|
|
{
|
|
preserveState: true,
|
|
onSuccess: () => {
|
|
checkRequestBanned()
|
|
emit('change-room', roomId.value)
|
|
}
|
|
})
|
|
}
|
|
|
|
const removeMessage = (message) => {
|
|
// console.log(id)
|
|
removeMessageRequest(message)
|
|
}
|
|
|
|
const removeMessageRequest = (message) => {
|
|
|
|
const group = messages.value[message.group]
|
|
const count = group.length
|
|
const index = messages.value[message.group].findIndex((item) => item.id === message.id)
|
|
axios.delete(route('messenger.message.remove', {'id': message.id})).then(response => {
|
|
if(count === 1){
|
|
delete messages.value[message.group]
|
|
}else{
|
|
// delete messages.value[message.group][index]
|
|
messages.value[message.group] = messages.value[message.group].filter((i) => i.id != messages.value[message.group][index].id)
|
|
}
|
|
})
|
|
}
|
|
|
|
|
|
// const removeMessageRequest = (message) => {
|
|
// // console.log(message)
|
|
// // console.log(messages.value)
|
|
// const group = messages.value[message.group]
|
|
// const count = group.length
|
|
// const index = messages.value[message.group].findIndex((item) => item.id === message.id)
|
|
|
|
// Inertia.delete(route('messenger.message.remove', {'id': message.id}),
|
|
// {
|
|
// preserveState: true,
|
|
// onSuccess: () => {
|
|
// if(count === 1){
|
|
// delete messages.value[message.group]
|
|
// }else{
|
|
// delete messages.value[message.group][index]
|
|
// }
|
|
|
|
// }
|
|
|
|
// })
|
|
// }
|
|
|
|
// const exitRoom = () => {
|
|
// Inertia.post(route('messenger.leave.room'), { room: roomId.value },
|
|
// {
|
|
// preserveState: true,
|
|
// onSuccess: () => {
|
|
// emit('leave-room')
|
|
// }
|
|
// })
|
|
// }
|
|
|
|
|
|
const isBannedMessage = computed(() => {
|
|
if(partnerIsBanned.value === null){
|
|
return false
|
|
}
|
|
if(partnerIsBanned.value){
|
|
return 'Убрать из черного списка'
|
|
}
|
|
return 'Добавить в черный список'
|
|
})
|
|
|
|
|
|
|
|
return {
|
|
textarea,
|
|
textMessage,
|
|
loading,
|
|
messages,
|
|
createMessage,
|
|
error,
|
|
domNodeFn,
|
|
bannRequest,
|
|
isBannedMessage,
|
|
partnerIsBanned,
|
|
removeMessage
|
|
}
|
|
}
|
|
}
|
|
|
|
</script>
|