feature(Live Support): add chat ui

- add chat ui for live support
- fix misc bugs
This commit is contained in:
kusowl 2026-02-09 19:07:16 +05:30
parent 0d0818baf3
commit 2f566cc4d8
18 changed files with 177 additions and 83 deletions

View File

@ -97,7 +97,7 @@ function setDealDetails(dealDetails) {
async function setComments(dealId, dealModal) {
const commentsContainer = dealModal.querySelector('.comments-container');
toggleShimmer(false, commentsContainer);
commentsContainer.innerHTML = await getComments(dealId);
commentsContainer.outerHTML = await getComments(dealId);
toggleShimmer(true, commentsContainer);
}

View File

@ -0,0 +1,17 @@
<x-layout>
<div class="flex">
<x-dashboard.broker.sidebar.layout>
<div class="">
<div class="flex space-x-4 items-center border-b border-b-gray-300 pb-6 mb-4">
<x-logo/>
<p class="font-bold text-2xl whitespace-nowrap group-[.w-20]:hidden">Messages</p>
</div>
{{$sidebarItems ?? ''}}
</div>
</x-dashboard.broker.sidebar.layout>
<section
class="flex relative flex-col space-y-4 md:space-y-8 bg-[#F9FAFB] overflow-y-auto overflow-x-hidden h-screen w-full">
{{$slot}}
</section>
</div>
</x-layout>

View File

@ -0,0 +1,8 @@
<div class="absolute bottom-5 w-8/12 rounded-xl left-50 p-2 bg-white">
<form action="" class="flex space-x-4 items-center">
<x-ui.textarea class="flex-1" rows="1" name="message" placeholder="Enter your message...">hi</x-ui.textarea>
<x-ui.button variant="neutral" icon="">
<x-heroicon-o-paper-airplane class="w-5 h-5" />
</x-ui.button>
</form>
</div>

View File

@ -0,0 +1,6 @@
@props(['right' => false])
<div class="grid px-4 my-2 w-full @if($right) place-items-end @else place-items-start @endif">
<div class="w-fit px-6 py-2 rounded-full bg-gray-200">
{{ $slot }}
</div>
</div>

View File

@ -0,0 +1,8 @@
@props(['avatar', 'name', 'status' => 'inactive', 'message' => ''])
<x-dashboard.broker.sidebar.item class="w-full">
<x-ui.avatar class="w-12! h-12! text-xl!">{{$avatar}}</x-ui.avatar>
<div class="flex flex-col text-left">
<p class="sidebar-text text-sm font-bold">{{$name}}</p>
<p class="sidebar-text text-sm text-accent-600">{{$message}}</p>
</div>
</x-dashboard.broker.sidebar.item>

View File

@ -6,7 +6,7 @@
<div id="sidebar"
class="flex flex-col p-4 pt-6 justify-between font-medium h-full w-full transition-all duration-300 ease-in-out">
<div>
<div class="flex space-x-4 border-b border-b-gray-300 pb-6 n">
<div class="flex space-x-4 border-b border-b-gray-300 pb-6 ">
<x-logo/>
<a href="{{route('home')}}" class="whitespace-nowrap group-[.w-20]:hidden">
<p class="text-2xl font-bold">DealHub</p>
@ -64,7 +64,7 @@ class="py-3 pl-3 border border-white hover:bg-red-50 hover:border-red-200 rounde
{{-- Toggle Button --}}
<div
class="text-gray-500 cursor-pointer hover:text-gray-900 rounded-full p-1.5 bg-white border border-gray-300 absolute -right-3.5 top-21">
class="text-gray-500 cursor-pointer hover:text-gray-900 rounded-full p-1.5 bg-white border border-gray-300 absolute -right-3.5 top-21 z-20">
<x-heroicon-c-chevron-left id="closeSidebarBtn" class="w-4"/>
<x-heroicon-c-chevron-right id="openSidebarBtn" class="w-4 hidden"/>
</div>

View File

@ -1,8 +1,4 @@
@props(['activeClass' => 'bg-gray-100 text-gray-900'])
<div id="sidebarWrapper" {{$attributes->merge([ 'class' => 'border-r border-r-gray-300 transition-all duration-300 ease-in-out w-64 relative'])}}>
<div class="hidden md:flex h-screen items-center">
<div id="sidebar" class="flex flex-col p-4 pt-6 justify-between font-medium h-full w-full overflow-hidden transition-all duration-300 ease-in-out">
<x-dashboard.broker.sidebar.layout>
<div class="">
<div class="flex space-x-4 border-b border-b-gray-300 pb-6">
<x-logo/>
@ -39,7 +35,8 @@
<form method="post" action="{{route('logout')}}">
@csrf
@method('delete')
<button class="py-3 pl-3 border border-white hover:bg-red-50 hover:border-red-200 rounded-xl w-full mt-4 transition-all">
<button
class="py-3 pl-3 border border-white hover:bg-red-50 hover:border-red-200 rounded-xl w-full mt-4 transition-all">
<div class="flex space-x-3 items-center text-red-500">
<x-heroicon-o-arrow-right-start-on-rectangle class="w-5 min-w-5"/>
<p class="sidebar-text transition-opacity duration-300 ease-in-out">Logout</p>
@ -47,15 +44,4 @@
</button>
</form>
</div>
</div>
{{-- Toggle Button --}}
<div class="text-gray-500 cursor-pointer hover:text-gray-900 rounded-full p-1.5 bg-white border border-gray-300 absolute -right-3.5 top-21">
<x-heroicon-c-chevron-left id="closeSidebarBtn" class="w-4"/>
<x-heroicon-c-chevron-right id="openSidebarBtn" class="w-4 hidden"/>
</div>
</div>
</div>
@vite(['resources/js/sidebar.js'])
</x-dashboard.broker.sidebar.layout>

View File

@ -6,9 +6,15 @@
@endphp
@aware(['activeClass' => 'bg-gray-100 text-gray-900'])
<div class="relative group/item w-full hover:z-10">
@if(filled($link))
<a href="{{$link}}" {{$attributes->class(["flex space-x-3 items-center pl-3 py-3 rounded-xl hover:bg-gray-100 border border-transparent ease-in-out transition-all duration-300 active:scale-80 hover:border-gray-300", $activeClass => $active])}} >
{{$slot}}
</a>
@else
<button {{$attributes->class(["flex space-x-3 items-center pl-3 py-3 rounded-xl hover:bg-gray-100 border border-transparent ease-in-out transition-all duration-300 active:scale-80 hover:border-gray-300", $activeClass => $active])}} >
{{$slot}}
</button>
@endif
@if($tooltip !== '')
<span
class="absolute z-10 top-[30%] hidden group-[.w-20]:group-hover/item:block left-[110%] py-1 px-2 rounded-lg bg-gray-900 text-xs whitespace-nowrap text-white">

View File

@ -0,0 +1,19 @@
@props(['activeClass' => 'bg-gray-100 text-gray-900'])
<div id="sidebarWrapper" {{$attributes->merge([ 'class' => 'border-r border-r-gray-300 transition-all group duration-300 ease-in-out w-64 relative z-10'])}}>
<div class="hidden md:flex w-max h-screen items-center">
<div id="sidebar" class="flex flex-col p-4 pt-6 justify-between font-medium h-full w-full overflow-hidden transition-all duration-300 ease-in-out">
{{$slot}}
</div>
{{-- Toggle Button --}}
<div class="text-gray-500 cursor-pointer hover:text-gray-900 rounded-full p-1.5 bg-white border border-gray-300 absolute -right-3.5 top-21 z-30">
<x-heroicon-c-chevron-left id="closeSidebarBtn" class="w-4"/>
<x-heroicon-c-chevron-right id="openSidebarBtn" class="w-4 hidden"/>
</div>
</div>
</div>
@push('scripts')
@vite(['resources/js/sidebar.js'])
@endpush

View File

@ -1,5 +1,5 @@
@props(['title' => '', 'description' => '', 'backLink' => ''])
<section class="flex space-x-6 items-center justify-between wrapper py-6 shadow w-full">
<section {{$attributes->merge(['class' => 'flex space-x-6 items-center justify-between wrapper py-6 shadow w-full'])}}>
<div class="flex space-x-6 items-center">
@if($backLink !== '')
<div class="">

View File

@ -1,11 +1,15 @@
@props(['broker' => '', 'is_followed' => false])
<div {{$attributes->merge(['class' => "p-4 text-sm bg-gray-100 border-gray-200 border rounded-xl"])}}>
<div class="flex space-x-4 items-baseline">
<p class="font-bold mb-2">Broker Contact</p>
<x-ui.button-sm data-is-loading="false" data-followed="{{$is_followed ? 'true' : 'false'}}" onclick="follow(this, {{$broker->role_id ?? ''}})" class="followBtn group p-0! mt-0.5">
<div class="flex space-x-2 items-center mb-2">
<p class="font-bold">Broker Contact</p>
<x-ui.button-sm data-is-loading="false" data-followed="{{$is_followed ? 'true' : 'false'}}"
onclick="follow(this, {{$broker->role_id ?? ''}})" class="followBtn group p-0! mt-0.5">
<span class="group-data-[followed=true]:hidden text-blue-600">Follow</span>
<span class="group-data-[followed=false]:hidden text-accent-600">Unfollow</span>
</x-ui.button-sm>
<x-ui.button-sm>
<x-heroicon-o-chat-bubble-oval-left class="w-4 text-accent-600"/>
</x-ui.button-sm>
</div>
<div class="text-accent-600 space-y-1">
<p data-is-loading="false" class="broker-name">{{$broker->name ?? ''}}</p>

View File

@ -1,5 +1,5 @@
@props(['comments' => []])
<div data-is-loading="true" class="comments-container mt-2 space-y-2 max-h-40 overflow-y-scroll data-[is-loading=true]:h-10">
<div data-is-loading="true" class="comments-container mt-2 space-y-2 max-h-40 overflow-y-auto data-[is-loading=true]:h-10">
@forelse($comments as $comment)
<x-dashboard.user.deal-comment.item :comment="$comment"/>
@empty

View File

@ -1,4 +1,4 @@
<x-ui.modal id="deal-modal" class="deal-identifier w-11/12 md:w-10/12 overflow-scroll">
<x-ui.modal id="deal-modal" class="deal-identifier w-11/12 md:w-10/12 overflow-y-auto">
<form class="flex justify-between items-start mb-4" method="dialog">
<p class="text-xl font-bold">Deal Details</p>
<button type="submit" class="">

View File

@ -0,0 +1,4 @@
<section
{{$attributes->merge(['class' => 'w-25 h-25 rounded-xl bg-linear-150 from-[#305afc] to-[#941dfb] text-5xl text-white flex justify-center items-center'])}}>
{{$slot}}
</section>

View File

@ -1,7 +1,6 @@
@props(['label' => '', 'name' => '', 'placeholder' => '', 'required' => false, 'value' => '', 'description'])
@props(['label' => '', 'name' => '', 'placeholder' => '', 'required' => false, 'value' => '', 'description', 'rows'=>1])
<div {{$attributes->merge(['class' => 'flex flex-col space-y-2'])}}>
@if($label !== '')
<div class="flex flex-col space-y-2">
<label class="text-sm font-bold" for="{{$name}}">
{{$label}}
@ -9,9 +8,10 @@
*
@endif
</label>
@endif
<textarea
class="bg-[#F3F3F5] py-2 px-4 rounded-lg h-40"
class="bg-[#F3F3F5] py-2 px-4 rounded-lg"
rows="{{$rows}}"
name="{{$name}}" placeholder="{{$placeholder}}"
required="{{$required?'required':''}}"
>{{old($name, $value)}}</textarea>
@ -22,4 +22,3 @@ class="bg-[#F3F3F5] py-2 px-4 rounded-lg h-40"
<x-ui.inline-error :name="$name"/>
</div>
@endif

View File

@ -23,10 +23,7 @@ class="border border-accent-600/40">
<div
class="col-span-8 place-self-start md:col-span-2 lg:col-span-1 flex items-center justify-center w-full">
<div
class="w-25 h-25 rounded-xl bg-linear-150 from-[#305afc] to-[#941dfb] text-5xl text-white flex justify-center items-center">
{{$initials}}
</div>
<x-ui.avatar>{{$initials}}</x-ui.avatar>
</div>
<div class="col-span-8 md:col-span-6 lg:col-span-7 flex flex-col space-y-6">

View File

@ -0,0 +1,39 @@
<x-chat.layout>
<x-slot:sidebarItems>
<x-chat.sidebar-item name="Kushal Saha" avatar="Ku" message="Hi, how do i do that ?"/>
<x-chat.sidebar-item name="Jhon Doe" avatar="JD" message="How much for thr tv ?"/>
<x-chat.sidebar-item name="Jane Marry" avatar="JM" message="I will let you know"/>
</x-slot:sidebarItems>
<x-dashboard.page-heading class="m-0" title="Kushal Saha" description="Active now"/>
<div class="bg-gray-100 h-full overflow-hidden">
<div class="text-sm flex flex-col-reverse overflow-y-scroll max-h-screen pb-50 scroll-snap-y-container">
<x-chat.message right>Hi</x-chat.message>
<x-chat.message>Hello !</x-chat.message>
<x-chat.message right>Hi</x-chat.message>
<x-chat.message right>Hi</x-chat.message>
<x-chat.message>Hello !</x-chat.message>
<x-chat.message>Hello !</x-chat.message>
<x-chat.message right>Hi</x-chat.message>
<x-chat.message>Hello !</x-chat.message>
<x-chat.message right>Hi</x-chat.message>
<x-chat.message>Hello !</x-chat.message>
<x-chat.message right>Hi</x-chat.message>
<x-chat.message>Hello !</x-chat.message>
<x-chat.message right>Hi</x-chat.message>
<x-chat.message>Hello !</x-chat.message>
<x-chat.message right>Hi</x-chat.message>
<x-chat.message>Hello !</x-chat.message>
<x-chat.message right>Hi</x-chat.message>
<x-chat.message>Hello !</x-chat.message>
<x-chat.message right>Hi</x-chat.message>
<x-chat.message>Hello !</x-chat.message>
<x-chat.message right>Hi</x-chat.message>
<x-chat.message>Hello !</x-chat.message>
<x-chat.message right>Hi</x-chat.message>
<x-chat.message>Hello !</x-chat.message>
<x-chat.message right>Hi</x-chat.message>
<x-chat.message>Hello !</x-chat.message>
</div>
<x-chat.message-input/>
</div>
</x-chat.layout>

View File

@ -9,4 +9,5 @@
->middleware([HasRole::class.':'.UserTypes::User->value, 'auth'])
->group(function () {
Route::resource('profile', UserProfileController::class)->except('index', 'store', 'create');
Route::get('/chat', fn () => view('dashboards.user.chat.index'));
});