Последняя версия с сервера прошлого разработчика
This commit is contained in:
61
resources/js/Shared/Messanger/BoardFriendList.vue
Executable file
61
resources/js/Shared/Messanger/BoardFriendList.vue
Executable file
@@ -0,0 +1,61 @@
|
||||
<script setup>
|
||||
import { useInfinityScroll } from '@/includes/composables/useInfinityScroll'
|
||||
import MessangerModal from '@/Shared/Messanger/MessangerModal.vue'
|
||||
import UserAvatar from '@/Shared/Misc/UserAvatar.vue'
|
||||
import UserBanner from '@/Shared/Misc/UserBanner.vue'
|
||||
import axios from 'axios'
|
||||
import debounce from 'lodash/debounce'
|
||||
import { ref, watch } from 'vue'
|
||||
|
||||
const search = ref('')
|
||||
const refMessangerModal = ref()
|
||||
const { domNodeFn, cursor, loading, error, callAPI, data: userLists } = useInfinityScroll(async () => {
|
||||
const url = search.value ? `user-friend/?search=${search.value}&cursor=${cursor.value}` : `user-friend/?cursor=${cursor.value}`
|
||||
const res = await axios.get(url)
|
||||
return res.data
|
||||
})
|
||||
callAPI()
|
||||
watch(search, debounce(() => {
|
||||
callAPI()
|
||||
}, 500))
|
||||
|
||||
|
||||
function openModalMessanger(user) {
|
||||
refMessangerModal.value.openAction(user)
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<div v-if="userLists" class="mt-5 grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4 cards-block rounded-md bg-indigo-200 grid gap-2 lg:gap-4 grid-cards ">
|
||||
<messanger-modal ref="refMessangerModal" />
|
||||
<div
|
||||
v-for="user in userLists"
|
||||
:ref="el => domNodeFn(el, user.id)"
|
||||
:key="user.id"
|
||||
class="user-card relative cursor-pointer"
|
||||
@click="openModalMessanger(user)"
|
||||
>
|
||||
<div class="absolute inset-x-0 bottom-4 z-10 flex justify-center">
|
||||
<div class="flex flex-col items-center">
|
||||
<div class="flex-shrink-0">
|
||||
<user-avatar :user="user" size="small"
|
||||
class="border border-white shadow-classic h-20 w-20 text-lg"
|
||||
/>
|
||||
</div>
|
||||
<div class="mt-2 text-white text-sm text-center">
|
||||
<p class="">
|
||||
{{ user.name }}
|
||||
</p>
|
||||
<p class="text-xs">
|
||||
{{ user.username }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gradient-profile relative overflow-hidden">
|
||||
<user-banner class="h-72 bg-indigo-300" :user="user"
|
||||
size="banner"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
285
resources/js/Shared/Messanger/BoardMessage.vue
Executable file
285
resources/js/Shared/Messanger/BoardMessage.vue
Executable file
@@ -0,0 +1,285 @@
|
||||
<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>
|
||||
63
resources/js/Shared/Messanger/BoardMessageItem.vue
Executable file
63
resources/js/Shared/Messanger/BoardMessageItem.vue
Executable file
@@ -0,0 +1,63 @@
|
||||
<template>
|
||||
<div class="flex">
|
||||
<user-avatar :user="userMessage.user" size="small"
|
||||
class="flex-shrink-0 w-10 h-10 lg:w-12 lg:h-12 xl:w-14 xl:h-14 text-sm xl:text-lg"
|
||||
/>
|
||||
<div class="ml-5 flex bg-indigo-100 p-4 rounded shadow relative">
|
||||
<div v-if="isAuthorMessage" class="flex absolute top-px right-px">
|
||||
<button @click="remove">
|
||||
<svg class="text-red w-3.5 h-3.5" xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24" viewBox="0 0 24 24"
|
||||
fill="none" stroke="currentColor"
|
||||
stroke-width="2" stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
><line x1="18" y1="6"
|
||||
x2="6" y2="18"
|
||||
></line><line x1="6" y1="6"
|
||||
x2="18" y2="18"
|
||||
></line></svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="text-sm text-white break-all">
|
||||
<footer class="font-bold mb-2 text-gray-light flex items-center">
|
||||
{{ userMessage.user.first_name }}
|
||||
<span class="font-normal text-xs text-gray ml-4 lg:ml-8 flex-shrink-0">{{ userMessage.created }}</span>
|
||||
</footer>
|
||||
{{ userMessage.message }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import UserAvatar from '@/Shared/Misc/UserAvatar.vue'
|
||||
export default {
|
||||
components:{
|
||||
UserAvatar,
|
||||
},
|
||||
props: {
|
||||
userMessage: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
},
|
||||
profileId: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
},
|
||||
emits: {
|
||||
'remove': null
|
||||
},
|
||||
computed: {
|
||||
isAuthorMessage() {
|
||||
return this.profileId != this.userMessage.user.id
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
remove(){
|
||||
this.$emit('remove', this.userMessage)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
81
resources/js/Shared/Messanger/BoardRoomList.vue
Executable file
81
resources/js/Shared/Messanger/BoardRoomList.vue
Executable file
@@ -0,0 +1,81 @@
|
||||
<template>
|
||||
<div :class="{
|
||||
'bg-purple': !room.is_my_message && !room.is_reading
|
||||
}" class="relative flex items-center px-2 xl:px-8 hover:bg-indigo-300 cursor-pointer transition-colors"
|
||||
@click="selectRoom(room)"
|
||||
>
|
||||
<div v-if="!room.is_reading && !room.is_my_message" class="absolute bottom-1 right-3 text-xxs text-white">
|
||||
<span>не прочитано</span>
|
||||
</div>
|
||||
<div v-if="room.is_my_message" class="absolute bottom-0 right-3">
|
||||
<div v-show="!room.is_reading" class="flex relative w-[30px] h-[24px] text-gray-light">
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16" viewBox="0 0 24 24"
|
||||
fill="none" stroke="currentColor"
|
||||
stroke-width="2" stroke-linecap="round"
|
||||
stroke-linejoin="round" class="absolute top-0 right-0"
|
||||
><polyline points="20 6 9 17 4 12"></polyline></svg>
|
||||
</div>
|
||||
<div v-show="room.is_reading" class="flex relative w-[30px] h-[24px] text-orange">
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16" viewBox="0 0 24 24"
|
||||
fill="none" stroke="currentColor"
|
||||
stroke-width="2" stroke-linecap="round"
|
||||
stroke-linejoin="round" class="absolute top-0 right-[5px]"
|
||||
><polyline points="20 6 9 17 4 12"></polyline></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16" viewBox="0 0 24 24"
|
||||
fill="none" stroke="currentColor"
|
||||
stroke-width="2" stroke-linecap="round"
|
||||
stroke-linejoin="round" class="absolute top-0 right-0"
|
||||
><polyline points="20 6 9 17 4 12"></polyline></svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="absolute top-2 right-2 text-xxs lg:text-xs text-gray-light">
|
||||
{{ room.updated_at_human }}
|
||||
</div>
|
||||
<user-avatar :user="room.correspond" size="small"
|
||||
class="flex-shrink-0 w-10 h-10 lg:w-12 lg:h-12 xl:w-14 xl:h-14 text-sm xl:text-lg"
|
||||
/>
|
||||
<div class="ml-3 flex flex-col w-4/5 overflow-hidden">
|
||||
<span class="text-sm lg:text-base block text-white">{{ room.correspond.name }}</span>
|
||||
<span class="text-xs lg:text-sm truncate text-gray-light">
|
||||
<span v-if="room.is_my_message" class="text-orange">Вы:</span>
|
||||
{{ room.message }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import UserAvatar from '@/Shared/Misc/UserAvatar.vue'
|
||||
export default {
|
||||
components: {
|
||||
UserAvatar,
|
||||
},
|
||||
props: {
|
||||
room: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
},
|
||||
},
|
||||
emits:{
|
||||
'select-room': null
|
||||
},
|
||||
|
||||
setup(props, {emit}){
|
||||
const selectRoom = (room) => {
|
||||
emit('select-room', room)
|
||||
}
|
||||
|
||||
return {
|
||||
selectRoom
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
</script>
|
||||
56
resources/js/Shared/Messanger/BoardTop.vue
Executable file
56
resources/js/Shared/Messanger/BoardTop.vue
Executable file
@@ -0,0 +1,56 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="gradient-profile relative border-b border-indigo-300">
|
||||
<user-banner class="h-24 xl:h-40 bg-indigo-200" :user="user"
|
||||
size="hero"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="-mt-14 xl:-mt-24 relative xl:container xl:mx-auto px-5 xl:px-10">
|
||||
<div class="flex flex-col md:flex-row">
|
||||
<div class="flex-shrink-0 self-center md:self-start md:mr-6 2xl:mr-10">
|
||||
<user-avatar :user="user" size="medium"
|
||||
class="shadow-classic object-cover w-28 h-28 text-xl xl:w-48 xl:h-48 xl:text-3xl"
|
||||
/>
|
||||
</div>
|
||||
<div class="w-full">
|
||||
<div class="h-12 xl:h-24 hidden md:block"></div>
|
||||
<div class="mt-2 ">
|
||||
<div class="-mx-2 -my-2 lg:-mx-4 lg:-my-4 flex flex-col md:flex-row flex-wrap xl:flex-nowrap justify-between">
|
||||
<div class="max-w-[300px] text-center md:text-left mx-2 my-2 lg:mx-4 lg:my-4 flex flex-shrink-0 flex-col self-center md:self-start">
|
||||
<inertia-link :href="route('profile.user', user.username)" class="text-lg xl:text-2xl block font-semibold text-white">
|
||||
{{ user.name }}
|
||||
</inertia-link>
|
||||
<h2 class="text-sm xl:text-base text-gray-light">
|
||||
@{{ user.username }}
|
||||
</h2>
|
||||
</div>
|
||||
<div class="mx-2 my-2 lg:mx-4 lg:my-4 flex flex-col items-end">
|
||||
<slot name="menu" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import UserAvatar from '@/Shared/Misc/UserAvatar.vue'
|
||||
import UserBanner from '@/Shared/Misc/UserBanner.vue'
|
||||
|
||||
export default {
|
||||
components:{
|
||||
UserAvatar,
|
||||
UserBanner
|
||||
},
|
||||
props: {
|
||||
user: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
187
resources/js/Shared/Messanger/MessangerModal.vue
Executable file
187
resources/js/Shared/Messanger/MessangerModal.vue
Executable file
@@ -0,0 +1,187 @@
|
||||
<template>
|
||||
<TransitionRoot as="template" :show="open">
|
||||
<Dialog as="div" static
|
||||
class="fixed z-[1000] inset-0 overflow-y-auto" :open="open"
|
||||
@close="closeAction"
|
||||
>
|
||||
<div class="flex items-center justify-center min-h-screen pt-4 px-4 pb-4 text-center sm:block sm:p-0">
|
||||
<TransitionChild as="template" enter="ease-out duration-300"
|
||||
enter-from="opacity-0" enter-to="opacity-100"
|
||||
leave="ease-in duration-200" leave-from="opacity-100"
|
||||
leave-to="opacity-0"
|
||||
>
|
||||
<DialogOverlay class="fixed inset-0 bg-indigo-200 bg-opacity-75 transition-opacity" />
|
||||
</TransitionChild>
|
||||
|
||||
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">​</span>
|
||||
<TransitionChild as="template" enter="ease-out duration-300"
|
||||
enter-from="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" enter-to="opacity-100 translate-y-0 sm:scale-100"
|
||||
leave="ease-in duration-200" leave-from="opacity-100 translate-y-0 sm:scale-100"
|
||||
leave-to="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||
>
|
||||
<div class="inline-block align-bottom bg-indigo-300 rounded-lg px-4 pt-5 pb-4 text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle w-full sm:max-w-lg sm:w-full sm:p-6">
|
||||
<div class="sm:flex sm:items-center">
|
||||
<div class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-orange sm:mx-0 sm:h-10 sm:w-10">
|
||||
<ChatIcon class="h-6 w-6 text-red-600" aria-hidden="true" />
|
||||
</div>
|
||||
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
|
||||
<DialogTitle as="h3" class="text-lg leading-6 font-medium text-gray-light">
|
||||
Новое сообщение
|
||||
</DialogTitle>
|
||||
</div>
|
||||
<div v-if="showDialogLink" class="ml-auto">
|
||||
<a href="#" class="underline text-gray text-xs"
|
||||
@click.prevent="linkTo"
|
||||
>перейти в чат</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-5">
|
||||
<textarea ref="textarea" v-model="form.message"
|
||||
rows="3"
|
||||
name="comment" class="outline-none focus:ring-orange-dark focus:border-transparent focus:ring-offset-0 bg-indigo-200 text-white max-h-56 block w-full py-3 border-0 resize-none sm:text-sm"
|
||||
placeholder="Сообщение ..."
|
||||
/>
|
||||
</div>
|
||||
<div class="mt-5 sm:mt-4 sm:flex sm:flex-row space-x-3 justify-end">
|
||||
<button type="button"
|
||||
class="my-1 transition shadow-none hover:shadow-classic inline-flex items-center px-6 py-2 justify-center text-base rounded-md text-white bg-indigo-300 focus:outline-none"
|
||||
@click="closeAction"
|
||||
>
|
||||
Отменить
|
||||
</button>
|
||||
<button type="button"
|
||||
class="my-1 transition shadow-none hover:shadow-classic inline-flex items-center px-6 py-2 justify-center text-base rounded-md text-white bg-green focus:outline-none"
|
||||
@click="submit"
|
||||
>
|
||||
Отправить
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</TransitionChild>
|
||||
</div>
|
||||
</Dialog>
|
||||
</TransitionRoot>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
Dialog,
|
||||
DialogOverlay,
|
||||
DialogTitle,
|
||||
TransitionChild,
|
||||
TransitionRoot,
|
||||
} from '@headlessui/vue'
|
||||
import { ChatIcon } from '@heroicons/vue/outline'
|
||||
import { ref } from 'vue'
|
||||
import { useAutoresizeTextarea } from '@/includes/composables'
|
||||
import axios from 'axios'
|
||||
import { useForm } from '@inertiajs/inertia-vue3'
|
||||
import { Inertia } from '@inertiajs/inertia'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Dialog,
|
||||
DialogOverlay,
|
||||
DialogTitle,
|
||||
TransitionChild,
|
||||
TransitionRoot,
|
||||
ChatIcon,
|
||||
},
|
||||
|
||||
setup(props, {expose}) {
|
||||
|
||||
const form = useForm({
|
||||
message: null,
|
||||
chat_room: null,
|
||||
user_id: null,
|
||||
})
|
||||
|
||||
const textarea = ref()
|
||||
const user = ref()
|
||||
const open = ref(false)
|
||||
const chatCheck = ref(false)
|
||||
const showDialogLink = ref(false)
|
||||
|
||||
const openAction = (extUser) => {
|
||||
open.value = true
|
||||
user.value = extUser
|
||||
form.user_id = extUser.id
|
||||
if(!chatCheck.value){
|
||||
exsistChatRequest(user.value)
|
||||
}
|
||||
}
|
||||
const closeAction = () => {
|
||||
open.value = false
|
||||
}
|
||||
|
||||
const exsistChatRequest = (user) => {
|
||||
chatCheck.value = true
|
||||
axios.post('/messenger-check-room', {
|
||||
params: {
|
||||
user: user.id,
|
||||
}
|
||||
}).then(response => {
|
||||
if(response.data > 0){
|
||||
showDialogLink.value = 1
|
||||
form.chat_room = response.data
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const submit = () => {
|
||||
if(!form.message){
|
||||
alert('Введите сообщение')
|
||||
return
|
||||
}
|
||||
if(form.chat_room){
|
||||
createMessage()
|
||||
}else{
|
||||
createRoom()
|
||||
}
|
||||
}
|
||||
|
||||
const createMessage = () => {
|
||||
form.post(route('messenger.store.profile'), {
|
||||
onSuccess: () => {
|
||||
closeAction()
|
||||
form.message = ''
|
||||
linkTo()
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const createRoom = () => {
|
||||
form.post(route('messenger.create.room'), {
|
||||
onSuccess: () => {
|
||||
closeAction()
|
||||
showDialogLink.value = 1
|
||||
form.message = ''
|
||||
linkTo()
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
const linkTo = () => {
|
||||
Inertia.visit(`/messenger?user=${user.value.username}`, { method: 'get' })
|
||||
}
|
||||
|
||||
useAutoresizeTextarea(textarea)
|
||||
|
||||
expose({
|
||||
openAction
|
||||
})
|
||||
|
||||
return {
|
||||
form,
|
||||
textarea,
|
||||
open,
|
||||
closeAction,
|
||||
user,
|
||||
showDialogLink,
|
||||
submit,
|
||||
linkTo,
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user