feat: implementasi fitur pesan dan perbaikan logika cart
This commit is contained in:
parent
db57919bd2
commit
046365a1d6
|
|
@ -0,0 +1,113 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Pesan;
|
||||
use App\Models\Petani;
|
||||
use App\Models\Pembeli;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class PesanController extends Controller
|
||||
{
|
||||
// Menampilkan Daftar Percakapan (Inbox Utama)
|
||||
public function index()
|
||||
{
|
||||
$user = $this->getAuthenticatedUser();
|
||||
$isPetani = Auth::guard('petani')->check();
|
||||
|
||||
$allMessages = Pesan::where(function ($q) use ($user) {
|
||||
$q->where('pengirim_id', $user->id)->where('pengirim_type', get_class($user));
|
||||
})->orWhere(function ($q) use ($user) {
|
||||
$q->where('penerima_id', $user->id)->where('penerima_type', get_class($user));
|
||||
})->orderBy('created_at', 'desc')->get();
|
||||
|
||||
// Kelompokkan berdasarkan ID Lawan Bicara
|
||||
$conversations = $allMessages->groupBy(function ($pesan) use ($user) {
|
||||
return $pesan->pengirim_id == $user->id
|
||||
? $pesan->penerima_type . '_' . $pesan->penerima_id
|
||||
: $pesan->pengirim_type . '_' . $pesan->pengirim_id;
|
||||
});
|
||||
|
||||
// Format data untuk view
|
||||
$chatList = $conversations->map(function ($msgs) use ($user) {
|
||||
$lastMsg = $msgs->first();
|
||||
|
||||
// Tentukan siapa lawan bicaranya
|
||||
if ($lastMsg->pengirim_id == $user->id) {
|
||||
$lawan = $lastMsg->penerima;
|
||||
} else {
|
||||
$lawan = $lastMsg->pengirim;
|
||||
}
|
||||
|
||||
return [
|
||||
'lawan_id' => $lawan->id ?? 0,
|
||||
'lawan_type' => get_class($lawan ?? new \stdClass),
|
||||
'nama' => $lawan->nama_lengkap ?? 'User Terhapus',
|
||||
'foto' => $lawan->foto ?? null,
|
||||
'last_message' => $lastMsg->isi_pesan,
|
||||
'time' => $lastMsg->created_at->diffForHumans(),
|
||||
'unread' => $msgs->where('penerima_id', $user->id)->where('sudah_dibaca', false)->count()
|
||||
];
|
||||
});
|
||||
|
||||
$view = $isPetani ? 'petani.pesan.index' : 'landing.pesan.index';
|
||||
return view($view, compact('chatList'));
|
||||
}
|
||||
|
||||
// Menampilkan Detail Chat
|
||||
public function show($id)
|
||||
{
|
||||
$user = $this->getAuthenticatedUser();
|
||||
$isPetani = Auth::guard('petani')->check();
|
||||
|
||||
// Tentukan model lawan bicara
|
||||
$lawanType = $isPetani ? Pembeli::class : Petani::class;
|
||||
$lawan = $lawanType::findOrFail($id);
|
||||
|
||||
// Ambil percakapan antara User Login & Lawan Bicara
|
||||
$chats = Pesan::where(function ($q) use ($user, $lawan, $lawanType) {
|
||||
$q->where('pengirim_id', $user->id)->where('pengirim_type', get_class($user))
|
||||
->where('penerima_id', $lawan->id)->where('penerima_type', $lawanType);
|
||||
})->orWhere(function ($q) use ($user, $lawan, $lawanType) {
|
||||
$q->where('pengirim_id', $lawan->id)->where('pengirim_type', $lawanType)
|
||||
->where('penerima_id', $user->id)->where('penerima_type', get_class($user));
|
||||
})->orderBy('created_at', 'asc')->get();
|
||||
|
||||
// Tandai pesan masuk sebagai "Sudah Dibaca"
|
||||
Pesan::where('pengirim_id', $lawan->id)->where('pengirim_type', $lawanType)
|
||||
->where('penerima_id', $user->id)->update(['sudah_dibaca' => true]);
|
||||
|
||||
$view = $isPetani ? 'petani.pesan.show' : 'landing.pesan.show';
|
||||
return view($view, compact('chats', 'lawan'));
|
||||
}
|
||||
|
||||
// Proses Kirim Pesan
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate(['isi_pesan' => 'required']);
|
||||
$user = $this->getAuthenticatedUser();
|
||||
$isPetani = Auth::guard('petani')->check();
|
||||
|
||||
// Menentukan tipe penerima
|
||||
$penerimaType = $isPetani ? 'App\Models\Pembeli' : 'App\Models\Petani';
|
||||
|
||||
Pesan::create([
|
||||
'pengirim_id' => $user->id,
|
||||
'pengirim_type' => get_class($user),
|
||||
'penerima_id' => $request->penerima_id,
|
||||
'penerima_type' => $penerimaType,
|
||||
'isi_pesan' => $request->isi_pesan,
|
||||
'sudah_dibaca' => false,
|
||||
]);
|
||||
|
||||
return back();
|
||||
}
|
||||
|
||||
private function getAuthenticatedUser()
|
||||
{
|
||||
if (Auth::guard('petani')->check()) return Auth::guard('petani')->user();
|
||||
if (Auth::guard('pembeli')->check()) return Auth::guard('pembeli')->user();
|
||||
abort(403);
|
||||
}
|
||||
}
|
||||
|
|
@ -113,7 +113,7 @@ public function prosesCheckout(Request $request)
|
|||
$subtotal_transaksi = 0;
|
||||
$kode_invoice = 'INV/' . date('Ymd') . '/' . rand(1000, 9999);
|
||||
|
||||
// Buat Header Transaksi dulu
|
||||
// Membuat Header Transaksi
|
||||
$transaksi = Transaksi::create([
|
||||
'pembeli_id' => $pembeli_id,
|
||||
'tanggal_transaksi' => now(),
|
||||
|
|
@ -144,7 +144,6 @@ public function prosesCheckout(Request $request)
|
|||
$transaksi->update(['total_harga' => $subtotal_transaksi]);
|
||||
}
|
||||
|
||||
// Hapus Keranjang setelah sukses
|
||||
session()->forget('cart');
|
||||
}
|
||||
});
|
||||
|
|
@ -223,7 +222,7 @@ public function pesananDetail($id)
|
|||
{
|
||||
$petaniId = Auth::guard('petani')->id();
|
||||
|
||||
// Ambil transaksi berdasarkan ID, pastikan transaksi tersebut memiliki produk milik petani ini
|
||||
// Ambil transaksi berdasarkan ID
|
||||
$pesanan = Transaksi::whereHas('details.produk', function ($q) use ($petaniId) {
|
||||
$q->where('petani_id', $petaniId);
|
||||
})
|
||||
|
|
|
|||
|
|
@ -27,4 +27,14 @@ public function transaksis()
|
|||
{
|
||||
return $this->hasMany(Transaksi::class, 'pembeli_id');
|
||||
}
|
||||
|
||||
public function pesanMasuk()
|
||||
{
|
||||
return $this->morphMany(Pesan::class, 'penerima');
|
||||
}
|
||||
|
||||
public function pesanTerkirim()
|
||||
{
|
||||
return $this->morphMany(Pesan::class, 'pengirim');
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||
|
||||
class Pesan extends Model
|
||||
{
|
||||
|
|
@ -19,5 +20,15 @@ class Pesan extends Model
|
|||
'isi_pesan',
|
||||
'sudah_dibaca'
|
||||
];
|
||||
|
||||
public function pengirim(): MorphTo
|
||||
{
|
||||
return $this->morphTo();
|
||||
}
|
||||
|
||||
public function penerima(): MorphTo
|
||||
{
|
||||
return $this->morphTo();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable; // PENTING: Ganti ini
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
|
||||
class Petani extends Authenticatable
|
||||
|
|
@ -29,4 +29,14 @@ public function produks()
|
|||
{
|
||||
return $this->hasMany(Produk::class, 'petani_id');
|
||||
}
|
||||
|
||||
public function pesanMasuk()
|
||||
{
|
||||
return $this->morphMany(Pesan::class, 'penerima');
|
||||
}
|
||||
|
||||
public function pesanTerkirim()
|
||||
{
|
||||
return $this->morphMany(Pesan::class, 'pengirim');
|
||||
}
|
||||
}
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
<div class="auth-logo">
|
||||
<a href="{{ url('/') }}"><h3 class="fw-bold">TaniDesa</h3></a>
|
||||
</div>
|
||||
<h1 class="auth-title">Log in.</h1>
|
||||
<h3 class="fw-bold text-center">Log in</h3>
|
||||
|
||||
{{-- Pesan Sukses Register --}}
|
||||
@if (session('success'))
|
||||
|
|
@ -37,16 +37,16 @@
|
|||
<form action="{{ route('login.proses') }}" method="POST">
|
||||
@csrf
|
||||
<div class="form-group position-relative has-icon-left mb-4">
|
||||
<input type="text" name="username" class="form-control form-control-xl" placeholder="Username">
|
||||
<input type="text" name="username" class="form-control " placeholder="Username">
|
||||
<div class="form-control-icon"><i class="bi bi-person"></i></div>
|
||||
</div>
|
||||
<div class="form-group position-relative has-icon-left mb-4">
|
||||
<input type="password" name="password" class="form-control form-control-xl" placeholder="Password">
|
||||
<input type="password" name="password" class="form-control " placeholder="Password">
|
||||
<div class="form-control-icon"><i class="bi bi-shield-lock"></i></div>
|
||||
</div>
|
||||
<button class="btn btn-primary btn-block btn-lg shadow-lg mt-5">Masuk</button>
|
||||
<button class="btn btn-primary btn-block btn-md shadow-md mt-5">Masuk</button>
|
||||
</form>
|
||||
<div class="text-center mt-5 text-lg fs-4">
|
||||
<div class="text-center mt-5 text-md fs-6">
|
||||
<p class="text-gray-600">Belum punya akun? <a href="{{ route('register') }}" class="font-bold">Daftar</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -64,12 +64,46 @@ class="form-control form-control-sm text-center border-0" value="1"
|
|||
<button type="submit"
|
||||
class="btn border border-secondary rounded-pill px-4 py-2 mb-4 text-primary"><i
|
||||
class="fa fa-shopping-bag me-2 text-primary"></i> Masukkan Keranjang</button>
|
||||
|
||||
|
||||
<a href="{{ route('checkout', ['produk_id' => $produk->id]) }}" class="...">
|
||||
Beli Sekarang
|
||||
</a>
|
||||
</form>
|
||||
</div>
|
||||
<button type="button" class="btn btn-outline-success rounded-pill px-4" data-bs-toggle="modal"
|
||||
data-bs-target="#chatModal">
|
||||
<i class="fa fa-envelope me-2"></i> Chat Petani
|
||||
</button>
|
||||
|
||||
<div class="modal fade" id="chatModal" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Kirim Pesan ke {{ $produk->petani->nama_lengkap }}</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<form action="{{ route('pesan.kirim') }}" method="POST">
|
||||
@csrf
|
||||
<div class="modal-body">
|
||||
{{-- Hidden Input untuk Target Penerima (Petani) --}}
|
||||
<input type="hidden" name="penerima_id" value="{{ $produk->petani_id }}">
|
||||
<input type="hidden" name="penerima_type" value="App\Models\Petani">
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Isi Pesan</label>
|
||||
<textarea name="isi_pesan" class="form-control" rows="4" required
|
||||
placeholder="Halo, apakah stok produk ini masih ada?"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary"
|
||||
data-bs-dismiss="modal">Batal</button>
|
||||
<button type="submit" class="btn btn-success">Kirim Pesan</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-12">
|
||||
<nav>
|
||||
|
|
@ -83,10 +117,12 @@ class="fa fa-shopping-bag me-2 text-primary"></i> Masukkan Keranjang</button>
|
|||
</div>
|
||||
</nav>
|
||||
<div class="tab-content mb-5">
|
||||
<div class="tab-pane active" id="nav-about" role="tabpanel" aria-labelledby="nav-about-tab">
|
||||
<div class="tab-pane active" id="nav-about" role="tabpanel"
|
||||
aria-labelledby="nav-about-tab">
|
||||
<p>{{ $produk->deskripsi }}</p>
|
||||
</div>
|
||||
<div class="tab-pane" id="nav-mission" role="tabpanel" aria-labelledby="nav-mission-tab">
|
||||
<div class="tab-pane" id="nav-mission" role="tabpanel"
|
||||
aria-labelledby="nav-mission-tab">
|
||||
<div class="d-flex">
|
||||
<img src="{{ asset('template/frontend/img/avatar.jpg') }}"
|
||||
class="img-fluid rounded-circle p-3" style="width: 100px; height: 100px;"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
@extends('layouts.frontend')
|
||||
@section('title', 'Pesan Saya')
|
||||
@section('content')
|
||||
<div class="container py-5">
|
||||
<h2 class="mb-4">Pesan Saya</h2>
|
||||
<div class="card shadow-sm border-0">
|
||||
<div class="list-group list-group-flush">
|
||||
@forelse($chatList as $chat)
|
||||
<a href="{{ route('pembeli.pesan.show', $chat['lawan_id']) }}" class="list-group-item list-group-item-action py-3 d-flex align-items-center">
|
||||
<img src="{{ asset('template/frontend/img/avatar.jpg') }}" class="rounded-circle me-3" width="50" height="50">
|
||||
<div class="flex-grow-1">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h5 class="mb-1 text-primary">{{ $chat['nama'] }}</h5>
|
||||
<small class="text-muted">{{ $chat['time'] }}</small>
|
||||
</div>
|
||||
<p class="mb-1 text-muted">{{ Str::limit($chat['last_message'], 50) }}</p>
|
||||
</div>
|
||||
@if($chat['unread'] > 0)
|
||||
<span class="badge bg-danger rounded-pill ms-2">{{ $chat['unread'] }}</span>
|
||||
@endif
|
||||
</a>
|
||||
@empty
|
||||
<div class="text-center py-5">
|
||||
<i class="fa fa-envelope-open fa-3x text-muted mb-3"></i>
|
||||
<p class="text-muted">Belum ada percakapan. Mulai chat dari halaman detail produk.</p>
|
||||
<a href="{{ route('shop') }}" class="btn btn-outline-primary rounded-pill">Lihat Produk</a>
|
||||
</div>
|
||||
@endforelse
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
@extends('layouts.frontend')
|
||||
|
||||
@section('title', 'Chat dengan ' . $lawan->nama_lengkap)
|
||||
|
||||
@section('content')
|
||||
<div class="container-fluid page-header py-5 mb-5">
|
||||
<h1 class="text-center text-white display-6">Percakapan</h1>
|
||||
<ol class="breadcrumb justify-content-center mb-0">
|
||||
<li class="breadcrumb-item"><a href="{{ route('pembeli.pesan.index') }}" class="text-white">Pesan Saya</a></li>
|
||||
<li class="breadcrumb-item active text-white">Detail</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<div class="container py-3">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-8 col-md-10">
|
||||
|
||||
<div class="card border shadow-sm">
|
||||
<div class="card-header bg-white py-3 border-bottom d-flex align-items-center">
|
||||
<a href="{{ route('pembeli.pesan.index') }}"
|
||||
class="btn btn-sm btn-outline-secondary rounded-circle me-3">
|
||||
<i class="fas fa-arrow-left"></i>
|
||||
</a>
|
||||
<div>
|
||||
<h6 class="mb-0 fw-bold">{{ $lawan->nama_lengkap }}</h6>
|
||||
<small class="text-muted">Petani</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body bg-light overflow-auto" id="chatBox" style="height: 500px;">
|
||||
@foreach ($chats as $chat)
|
||||
@php
|
||||
$isMe =
|
||||
$chat->pengirim_id == Auth::guard('pembeli')->id() &&
|
||||
$chat->pengirim_type == 'App\Models\Pembeli';
|
||||
@endphp
|
||||
|
||||
<div class="d-flex mb-3 {{ $isMe ? 'justify-content-end' : 'justify-content-start' }}">
|
||||
|
||||
<div class="p-3 rounded-3"
|
||||
style="max-width: 75%;
|
||||
{{ $isMe ? 'background-color: #0d6efd; color: white;' : 'background-color: white; border: 1px solid #dee2e6;' }}">
|
||||
|
||||
<p class="mb-1">{{ $chat->isi_pesan }}</p>
|
||||
|
||||
<div class="text-end">
|
||||
<small style="font-size: 11px; {{ $isMe ? 'color: #e0e0e0;' : 'color: #6c757d;' }}">
|
||||
{{ $chat->created_at->format('H:i') }}
|
||||
@if ($isMe)
|
||||
<i
|
||||
class="fas fa-check {{ $chat->sudah_dibaca ? 'text-warning' : '' }} ms-1"></i>
|
||||
@endif
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
<div class="card-footer bg-white p-3">
|
||||
<form action="{{ route('pesan.kirim') }}" method="POST">
|
||||
@csrf
|
||||
<input type="hidden" name="penerima_id" value="{{ $lawan->id }}">
|
||||
|
||||
<div class="input-group">
|
||||
<input type="text" name="isi_pesan" class="form-control" placeholder="Tulis pesan..."
|
||||
required autocomplete="off">
|
||||
<button type="submit" class="btn btn-primary px-4">
|
||||
<i class="fas fa-paper-plane"></i>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@section('js')
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
var chatBox = document.getElementById("chatBox");
|
||||
chatBox.scrollTop = chatBox.scrollHeight;
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
|
|
@ -113,6 +113,14 @@ class="bi bi-x bi-middle"></i></a>
|
|||
<span>Pesanan Masuk</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
{{-- Manajemen Kotak Masuk(Pesan) --}}
|
||||
<li class="sidebar-item {{ request()->is('petani/pesan*') ? 'active' : '' }}">
|
||||
<a href="{{ route('petani.pesan.index') }}" class='sidebar-link'>
|
||||
<i class="bi bi-chat-dots-fill"></i>
|
||||
<span>Kotak Masuk</span>
|
||||
</a>
|
||||
</li>
|
||||
@endif
|
||||
|
||||
<li class="sidebar-title">Akun</li>
|
||||
|
|
|
|||
|
|
@ -97,13 +97,12 @@ class="position-absolute bg-secondary rounded-circle d-flex align-items-center j
|
|||
class="d-none d-xl-inline ms-1">{{ Auth::guard('pembeli')->user()->nama_lengkap }}</span>
|
||||
</a>
|
||||
<div class="dropdown-menu m-0 bg-secondary rounded-0">
|
||||
<!-- Menu Profil -->
|
||||
<a href="#" class="dropdown-item">Profil Saya</a>
|
||||
|
||||
<!-- Menu Pesanan Saya -->
|
||||
<a href="{{ route('pembeli.pesan.index') }}" class="dropdown-item">Pesan Saya</a>
|
||||
|
||||
<a href="{{ route('pesanan.saya') }}" class="dropdown-item">Pesanan Saya</a>
|
||||
|
||||
<!-- Form Logout -->
|
||||
<form action="{{ route('logout') }}" method="POST">
|
||||
@csrf
|
||||
<button type="submit" class="dropdown-item">Logout</button>
|
||||
|
|
@ -123,7 +122,7 @@ class="d-none d-xl-inline ms-1">{{ Auth::guard('pembeli')->user()->nama_lengkap
|
|||
|
||||
<!-- Main Content -->
|
||||
<div style="margin-top: 150px;">
|
||||
@if(session('success'))
|
||||
@if (session('success'))
|
||||
<div class="container mt-3">
|
||||
<div class="alert alert-success alert-dismissible fade show" role="alert">
|
||||
<i class="fa fa-check-circle me-2"></i> {{ session('success') }}
|
||||
|
|
@ -131,7 +130,7 @@ class="d-none d-xl-inline ms-1">{{ Auth::guard('pembeli')->user()->nama_lengkap
|
|||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
|
||||
@yield('content')
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
@extends('layouts.admin')
|
||||
@section('title', 'Chat')
|
||||
@section('content')
|
||||
<div class="card" style="height: 75vh;">
|
||||
<div class="row g-0 h-100">
|
||||
<div class="col-md-4 border-end h-100 overflow-auto">
|
||||
<div class="p-3 bg-light border-bottom">
|
||||
<h6 class="mb-0">Daftar Percakapan</h6>
|
||||
</div>
|
||||
<div class="list-group list-group-flush">
|
||||
@forelse($chatList as $chat)
|
||||
<a href="{{ route('petani.pesan.show', $chat['lawan_id']) }}"
|
||||
class="list-group-item list-group-item-action py-3">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h6 class="mb-1 text-primary">{{ $chat['nama'] }}</h6>
|
||||
<small class="text-muted" style="font-size: 11px">{{ $chat['time'] }}</small>
|
||||
</div>
|
||||
<p class="mb-1 text-truncate small text-secondary">{{ $chat['last_message'] }}</p>
|
||||
@if ($chat['unread'] > 0)
|
||||
<span class="badge bg-danger rounded-pill">{{ $chat['unread'] }}</span>
|
||||
@endif
|
||||
</a>
|
||||
@empty
|
||||
<div class="p-4 text-center text-muted">Belum ada pesan.</div>
|
||||
@endforelse
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-8 h-100 d-flex align-items-center justify-content-center bg-white">
|
||||
<div class="text-center text-muted">
|
||||
<i class="bi bi-chat-dots display-1"></i>
|
||||
<p class="mt-3">Pilih kontak di sebelah kiri untuk mulai chatting.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
@extends('layouts.admin')
|
||||
|
||||
@section('title', 'Chat dengan ' . $lawan->nama_lengkap)
|
||||
|
||||
@section('content')
|
||||
<section class="section">
|
||||
<div class="card" style="height: 85vh; display: flex; flex-direction: column;">
|
||||
|
||||
{{-- HEADER CHAT --}}
|
||||
<div class="card-header bg-primary py-3 d-flex align-items-center justify-content-between">
|
||||
<div class="d-flex align-items-center text-white">
|
||||
<a href="{{ route('petani.pesan.index') }}" class="btn btn-light btn-sm me-3 rounded-circle"
|
||||
style="width: 32px; height: 32px; padding: 0; display: flex; align-items: center; justify-content: center;">
|
||||
<i class="bi bi-arrow-left text-primary"></i>
|
||||
</a>
|
||||
<div>
|
||||
<h6 class="mb-0 text-white font-bold" style="font-size: 1.1rem;">{{ $lawan->nama_lengkap }}</h6>
|
||||
<small style="opacity: 0.8; font-size: 0.8rem;">
|
||||
{{ $lawan->role ?? 'Pembeli' }}
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- INBOX SECTION (SCROLLABLE) --}}
|
||||
<div class="card-body p-4" id="chatContainer"
|
||||
style="flex-grow: 1; overflow-y: auto; background-color: #f2f7ff;">
|
||||
<div class="d-flex flex-column gap-3">
|
||||
@forelse($chats as $chat)
|
||||
@php
|
||||
$isMe =
|
||||
$chat->pengirim_id == Auth::guard('petani')->id() &&
|
||||
$chat->pengirim_type == 'App\Models\Petani';
|
||||
@endphp
|
||||
|
||||
{{-- Logic Posisi: Kalau SAYA di Kanan (end), Kalau DIA di Kiri (start) --}}
|
||||
<div class="d-flex w-100 {{ $isMe ? 'justify-content-end' : 'justify-content-start' }}">
|
||||
|
||||
<div style="max-width: 70%; min-width: 120px;">
|
||||
{{-- Bubble Chat --}}
|
||||
<div class="p-3 shadow-sm position-relative"
|
||||
style="border-radius: 15px;
|
||||
border-{{ $isMe ? 'bottom-right' : 'bottom-left' }}-radius: 0;
|
||||
background-color: {{ $isMe ? '#435ebe' : '#ffffff' }};
|
||||
color: {{ $isMe ? '#ffffff' : '#212529' }};">
|
||||
|
||||
<p class="mb-1" style="font-size: 0.95rem; line-height: 1.4;">
|
||||
{{ $chat->isi_pesan }}
|
||||
</p>
|
||||
|
||||
<div class="d-flex justify-content-end align-items-center mt-1">
|
||||
<small style="font-size: 0.7rem; opacity: 0.8; margin-right: 4px;">
|
||||
{{ $chat->created_at->format('H:i') }}
|
||||
</small>
|
||||
@if ($isMe)
|
||||
<i class="bi {{ $chat->sudah_dibaca ? 'bi-check-all text-info' : 'bi-check' }}"
|
||||
style="font-size: 0.9rem;"></i>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@empty
|
||||
<div class="text-center my-5">
|
||||
<span class="badge bg-light-secondary text-secondary p-3 rounded-pill">
|
||||
Belum ada percakapan. Mulailah menyapa! 👋
|
||||
</span>
|
||||
</div>
|
||||
@endforelse
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- FOOTER INPUT PESAN --}}
|
||||
<div class="card-footer bg-white py-3 border-top">
|
||||
<form action="{{ route('pesan.kirim') }}" method="POST" class="d-flex gap-2 align-items-center">
|
||||
@csrf
|
||||
{{-- Input Hidden Data Penerima --}}
|
||||
<input type="hidden" name="penerima_id" value="{{ $lawan->id }}">
|
||||
|
||||
{{-- Input Text --}}
|
||||
<div class="input-group">
|
||||
<input type="text" name="isi_pesan" class="form-control form-control-lg border-0 bg-light"
|
||||
placeholder="Ketik pesan..." required autocomplete="off" style="border-radius: 20px;">
|
||||
|
||||
<button type="submit" class="btn btn-primary btn-lg ms-2 rounded-circle"
|
||||
style="width: 50px; height: 50px; display: flex; align-items: center; justify-content: center;">
|
||||
<i class="bi bi-send-fill fs-5"></i>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
var chatBox = document.getElementById("chatContainer");
|
||||
if (chatBox) {
|
||||
chatBox.scrollTop = chatBox.scrollHeight;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
|
|
@ -5,6 +5,7 @@
|
|||
use App\Http\Controllers\AdminController;
|
||||
use App\Http\Controllers\CartController;
|
||||
use App\Http\Controllers\LandingController;
|
||||
use App\Http\Controllers\PesanController;
|
||||
use App\Http\Controllers\Petani\DashboardController;
|
||||
use App\Http\Controllers\Petani\ProdukController;
|
||||
use App\Http\Controllers\TransaksiController;
|
||||
|
|
@ -25,6 +26,11 @@
|
|||
Route::post('/cart/add', [CartController::class, 'addToCart'])->name('cart.add');
|
||||
Route::delete('/cart/remove', [CartController::class, 'remove'])->name('cart.remove');
|
||||
|
||||
// --- ROUTE GLOBAL (BISA DIAKSES PETANI & PEMBELI) ---
|
||||
Route::post('/pesan/kirim', [PesanController::class, 'store'])
|
||||
->middleware('auth:pembeli,petani')
|
||||
->name('pesan.kirim');
|
||||
|
||||
|
||||
// --- AUTH ROUTES (Guest Only) ---
|
||||
Route::middleware('guest')->group(function () {
|
||||
|
|
@ -55,6 +61,10 @@
|
|||
|
||||
Route::patch('/cart/update', [CartController::class, 'updateCart'])->name('cart.update');
|
||||
Route::delete('/cart/remove', [CartController::class, 'remove'])->name('cart.remove');
|
||||
|
||||
// Route Pesan untuk Pembeli
|
||||
Route::get('/pesan', [PesanController::class, 'index'])->name('pembeli.pesan.index');
|
||||
Route::get('/pesan/{id}', [PesanController::class, 'show'])->name('pembeli.pesan.show');
|
||||
});
|
||||
|
||||
|
||||
|
|
@ -84,4 +94,8 @@
|
|||
Route::get('/petani/pesanan', [TransaksiController::class, 'pesananMasuk'])->name('petani.pesanan.index');
|
||||
Route::patch('/petani/pesanan/{id}', [TransaksiController::class, 'updateStatus'])->name('petani.pesanan.update');
|
||||
Route::get('/petani/pesanan/{id}', [TransaksiController::class, 'pesananDetail'])->name('petani.pesanan.detail');
|
||||
|
||||
// Route Pesan untuk Petani
|
||||
Route::get('/petani/pesan', [PesanController::class, 'index'])->name('petani.pesan.index');
|
||||
Route::get('/petani/pesan/{id}', [PesanController::class, 'show'])->name('petani.pesan.show');
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue