Files
hub/app/Http/Controllers/Seller/Crm/TaskController.php
kelly 496ca61489 feat: dashboard redesign and sidebar consolidation
- Redesign dashboard as daily briefing format with action-first layout
- Consolidate sidebar menu structure (Dashboard as single link)
- Fix CRM form styling to use consistent UI patterns
- Add PWA icons and push notification groundwork
- Update SuiteMenuResolver for cleaner navigation
2025-12-14 03:41:31 -07:00

204 lines
6.9 KiB
PHP

<?php
namespace App\Http\Controllers\Seller\Crm;
use App\Http\Controllers\Controller;
use App\Models\Business;
use App\Models\Crm\CrmTask;
use App\Models\User;
use Illuminate\Http\Request;
class TaskController extends Controller
{
/**
* Display tasks listing
*/
public function index(Request $request, Business $business)
{
$user = $request->user();
$tasksQuery = CrmTask::where('seller_business_id', $business->id)
->with(['assignee', 'creator', 'contact', 'business'])
->orderBy('due_at');
// Filter by status (completed vs incomplete)
if ($request->filled('status')) {
if ($request->status === 'completed') {
$tasksQuery->whereNotNull('completed_at');
} elseif ($request->status === 'pending') {
$tasksQuery->whereNull('completed_at');
}
}
// Filter by assignee
if ($request->filled('assignee_id')) {
$tasksQuery->where('assigned_to', $request->assignee_id);
}
// Filter by type
if ($request->filled('type')) {
$tasksQuery->where('type', $request->type);
}
// Search filter
if ($request->filled('q')) {
$search = $request->q;
$tasksQuery->where(function ($q) use ($search) {
$q->where('title', 'ILIKE', "%{$search}%")
->orWhere('details', 'ILIKE', "%{$search}%");
});
}
$tasks = $tasksQuery->paginate(25);
// Return JSON for AJAX/API requests (live search)
if ($request->wantsJson()) {
return response()->json([
'data' => $tasks->map(fn ($t) => [
'id' => $t->id,
'name' => $t->title,
'type' => $t->type,
'assignee' => $t->assignee?->name ?? 'Unassigned',
'due_at' => $t->due_at?->format('M j, Y'),
])->values()->toArray(),
]);
}
// Get stats with single efficient query
$statsQuery = CrmTask::where('seller_business_id', $business->id)
->selectRaw('
SUM(CASE WHEN assigned_to = ? AND completed_at IS NULL THEN 1 ELSE 0 END) as my_tasks,
SUM(CASE WHEN completed_at IS NULL AND due_at < NOW() THEN 1 ELSE 0 END) as overdue,
SUM(CASE WHEN completed_at IS NULL AND DATE(due_at) = CURRENT_DATE THEN 1 ELSE 0 END) as due_today
', [$user->id])
->first();
$stats = [
'my_tasks' => $statsQuery->my_tasks ?? 0,
'overdue' => $statsQuery->overdue ?? 0,
'due_today' => $statsQuery->due_today ?? 0,
];
$counts = $stats; // View expects $counts
// Get team members for assignment filter
$teamMembers = User::whereHas('businesses', fn ($q) => $q->where('businesses.id', $business->id))->get();
// Get buyer businesses (accounts) for filtering
$buyerBusinesses = Business::where('type', 'buyer')
->orderBy('name')
->get(['id', 'name']);
return view('seller.crm.tasks.index', compact('business', 'tasks', 'counts', 'teamMembers', 'buyerBusinesses'));
}
/**
* Show create task form
*/
public function create(Request $request, Business $business)
{
$teamMembers = User::whereHas('businesses', fn ($q) => $q->where('businesses.id', $business->id))->get();
// Prefill from query params (when creating task from contact/account/etc)
$prefill = [
'title' => $request->get('title'),
'business_id' => $request->get('business_id'),
'contact_id' => $request->get('contact_id'),
'opportunity_id' => $request->get('opportunity_id'),
'conversation_id' => $request->get('conversation_id'),
'order_id' => $request->get('order_id'),
];
return view('seller.crm.tasks.create', compact('business', 'teamMembers', 'prefill'));
}
/**
* Store a new task
*/
public function store(Request $request, Business $business)
{
$validated = $request->validate([
'title' => 'required|string|max:255',
'details' => 'nullable|string',
'type' => 'required|in:call,email,meeting,follow_up,demo,other',
'priority' => 'required|in:low,normal,high,urgent',
'due_at' => 'required|date',
'assigned_to' => 'nullable|exists:users,id',
'contact_id' => 'nullable|exists:contacts,id',
'business_id' => 'nullable|exists:businesses,id',
]);
$task = CrmTask::create([
'title' => $validated['title'],
'details' => $validated['details'] ?? null,
'type' => $validated['type'],
'priority' => $validated['priority'],
'due_at' => $validated['due_at'],
'contact_id' => $validated['contact_id'] ?? null,
'business_id' => $validated['business_id'] ?? null,
'seller_business_id' => $business->id,
'created_by' => $request->user()->id,
'assigned_to' => $validated['assigned_to'] ?? $request->user()->id,
]);
return redirect()
->route('seller.business.crm.tasks.show', [$business->slug, $task])
->with('success', 'Task created successfully.');
}
/**
* Show task details
*/
public function show(Request $request, Business $business, CrmTask $task)
{
$task->load(['assignee', 'creator', 'contact', 'business', 'opportunity', 'order']);
return view('seller.crm.tasks.show', compact('business', 'task'));
}
/**
* Update task
*/
public function update(Request $request, Business $business, CrmTask $task)
{
$validated = $request->validate([
'title' => 'sometimes|string|max:255',
'details' => 'nullable|string',
'type' => 'sometimes|in:call,email,meeting,follow_up,demo,other',
'priority' => 'sometimes|in:low,normal,high,urgent',
'due_at' => 'sometimes|date',
'assigned_to' => 'nullable|exists:users,id',
]);
$task->update($validated);
return redirect()
->back()
->with('success', 'Task updated successfully.');
}
/**
* Delete task
*/
public function destroy(Request $request, Business $business, CrmTask $task)
{
$task->delete();
return redirect()
->route('seller.business.crm.tasks.index', $business->slug)
->with('success', 'Task deleted successfully.');
}
/**
* Mark task as complete
*/
public function complete(Request $request, Business $business, CrmTask $task)
{
$task->markComplete($request->user());
return redirect()
->back()
->with('success', 'Task marked as complete.');
}
}