Files
hub/app/Http/Controllers/Seller/ConversationController.php
kelly c7d6ee5e21 feat: multiple UI/UX improvements and case-insensitive search
- Refactor New Quote page to enterprise data-entry layout (2-column, dense)
- Add Payment Terms dropdown (COD, NET 15, NET 30, NET 60)
- Fix sidebar menu active states and route names
- Fix brand filter badge visibility on brands page
- Remove company_name references (use business instead)
- Polish Promotions page layout
- Fix double-click issue on sidebar menu collapse
- Make all searches case-insensitive (like -> ilike for PostgreSQL)
2025-12-14 15:36:00 -07:00

172 lines
5.3 KiB
PHP

<?php
namespace App\Http\Controllers\Seller;
use App\Http\Controllers\Controller;
use App\Models\Business;
use App\Models\Conversation;
use App\Models\Message;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail;
class ConversationController extends Controller
{
public function index(Business $business)
{
$status = request('status'); // open / closed
$unread = request('unread'); // '1'
$hasSms = request('has_sms'); // '1'
$hasEmail = request('has_email'); // '1'
$search = request('q');
$query = Conversation::with('contact')
->orderBy('last_message_at', 'desc');
if ($search) {
$query->where(function ($q) use ($search) {
$q->whereHas('contact', function ($c) use ($search) {
$c->where('name', 'ilike', "%{$search}%")
->orWhere('email', 'ilike', "%{$search}%")
->orWhere('phone', 'ilike', "%{$search}%");
})
->orWhereHas('messages', function ($m) use ($search) {
$m->where('message_body', 'ilike', "%{$search}%");
});
});
}
if ($status === 'open' || $status === 'closed') {
$query->where('status', $status);
}
if ($unread === '1') {
$query->whereHas('messages', function ($q) {
$q->where('direction', 'inbound')
->where('is_read', false);
});
}
if ($hasSms === '1') {
$query->whereHas('messages', function ($q) {
$q->where('channel', 'sms');
});
}
if ($hasEmail === '1') {
$query->whereHas('messages', function ($q) {
$q->where('channel', 'email');
});
}
$conversations = $query->paginate(20);
return view('seller.messaging.conversations.index', compact('business', 'conversations'));
}
public function show(Business $business, Conversation $conversation)
{
$messages = $conversation->messages()
->orderBy('created_at', 'asc')
->get();
$conversation->messages()
->where('direction', 'inbound')
->where('is_read', false)
->update(['is_read' => true]);
$conversation->refresh();
return view('seller.messaging.conversations.show', compact('business', 'conversation', 'messages'));
}
public function reply(Request $request, Business $business, Conversation $conversation)
{
$request->validate([
'message_body' => 'required|string',
]);
$body = $request->input('message_body');
// Determine channel: default to email if available, otherwise SMS
$contact = $conversation->contact;
// If both exist AND reply_channel is provided
if ($request->filled('reply_channel')) {
$channel = $request->input('reply_channel'); // email or sms
} else {
// Fallback: auto-detect based on available contact info
$channel = $contact->email
? 'email'
: ($contact->phone ? 'sms' : 'in_app');
}
// Validate email subject for email replies
if ($channel === 'email') {
$request->validate([
'email_subject' => 'required|string|max:200',
]);
}
// Store outbound message
$service = app(\App\Services\ConversationService::class);
$messageModel = $service->storeMessage(
$conversation,
$channel,
'outbound',
$body
);
// Now send via email or SMS
if ($channel === 'email') {
// outbound email
$subject = $request->input('email_subject') ?: ('Reply from '.$conversation->brand->name);
Mail::raw($body, function ($message) use ($conversation, $contact, $subject) {
$message->to($contact->email)
->from($conversation->brand->inbound_email)
->subject($subject);
});
// Mark as 'sent' after handing to mail provider
// Provider webhooks can later update to 'delivered' or 'failed'
$messageModel->update([
'delivery_status' => 'sent',
'delivery_status_at' => now(),
]);
}
if ($channel === 'sms') {
// outbound SMS
// (Hook into your SMS provider here)
// Example placeholder:
// Sms::send($contact->phone, $body, $conversation->brand->sms_number);
// Mark as 'sent' after handing to SMS provider
// Provider webhooks can later update to 'delivered' or 'failed'
$messageModel->update([
'delivery_status' => 'sent',
'delivery_status_at' => now(),
]);
}
$conversation->update(['last_message_at' => now()]);
return back();
}
public function close(Business $business, Conversation $conversation)
{
$conversation->update(['status' => 'closed']);
return back();
}
public function reopen(Business $business, Conversation $conversation)
{
$conversation->update(['status' => 'open']);
return back();
}
}