View.vue 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. <script setup>
  2. import AppLayout from "@/Layouts/AppLayout.vue";
  3. import {router, useForm} from "@inertiajs/vue3";
  4. import ChatInput from "@/Components/ChatInput.vue";
  5. import {useEcho} from "@laravel/echo-vue";
  6. import Message from "@/Components/Message.vue";
  7. import {nextTick, onMounted} from "vue";
  8. const {chat} = defineProps({chat: {type: Object}})
  9. const form = useForm({message: null})
  10. const submit = () => {
  11. form.post(route('chats.messages.store', chat.id), {
  12. preserveScroll: true,
  13. onSuccess: () => {
  14. scroll()
  15. form.reset()
  16. }
  17. })
  18. }
  19. useEcho(`App.Models.Chat.${chat.id}`, '.MessageCreated', (e) => {
  20. if (e?.data?.from !== 'user') {
  21. reload()
  22. }
  23. });
  24. useEcho(`App.Models.Chat.${chat.id}`, '.MessageUpdated', () => reload());
  25. const reload = () => {
  26. router.reload({preserveScroll: true, only: ['chat'], onSuccess: () => scroll()})
  27. }
  28. const scroll = () => {
  29. window.scrollBy({
  30. top: document.body.scrollHeight,
  31. behavior: 'smooth'
  32. });
  33. }
  34. onMounted(() => nextTick(() => scroll()))
  35. </script>
  36. <template>
  37. <AppLayout page-class="">
  38. <div class="max-w-5xl mx-auto flex flex-col h-full">
  39. <div class="flex-1 my-2">
  40. <div class="space-y-4">
  41. <div v-for="message in chat.messages">
  42. <div v-if="message.from === 'user'" class="flex">
  43. <div class="ml-auto border bg-card text-card-foreground p-2 rounded-lg max-w-[75%] text-sm"
  44. v-html="message.content.replaceAll('\n', '<br />')"></div>
  45. </div>
  46. <Message v-else :message="message"/>
  47. </div>
  48. </div>
  49. </div>
  50. <div class="shrink-0 sticky bottom-2">
  51. <!-- // TODO: If Last Message Not In Canceled Failed or Completed -->
  52. <ChatInput v-model="form.message" :disabled="form.processing" @submit="submit"/>
  53. </div>
  54. </div>
  55. </AppLayout>
  56. </template>
  57. <style scoped>
  58. </style>