feat: Add notification services for Email, Telegram, and WhatsApp
- Implement EmailNotifier for sending batch and test notifications via email. - Implement TelegramNotifier for sending batch and test notifications via Telegram. - Implement WahaNotifier for sending batch and test notifications via WhatsApp using WAHA API. - Create migration for client_categories table and update clients table to include category_id. - Create migration for notification_settings table to manage notification configurations. - Add ClientCategorySeeder to populate default client categories. - Create manifest.json for PWA support. - Implement service worker (sw.js) for caching static assets and offline support. - Add edit event view for modifying scheduled events. - Create search results view for displaying search queries. - Develop notification settings view for configuring notification channels and triggers.
This commit is contained in:
@@ -6,25 +6,61 @@ namespace App\Http\Controllers;
|
||||
|
||||
use App\Enums\ClientStatus;
|
||||
use App\Models\Client;
|
||||
use App\Models\ClientCategory;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class ClientController extends Controller
|
||||
{
|
||||
public function index(): View
|
||||
private function categoryTree(): \Illuminate\Support\Collection
|
||||
{
|
||||
$clients = Client::withCount(['invoices', 'events', 'contentBriefs'])
|
||||
->latest()
|
||||
->paginate(12);
|
||||
return ClientCategory::with('children')
|
||||
->whereNull('parent_id')
|
||||
->orderBy('sort_order')
|
||||
->get();
|
||||
}
|
||||
|
||||
return view('clients.index', compact('clients'));
|
||||
private function flatCategories(): \Illuminate\Support\Collection
|
||||
{
|
||||
$flat = collect();
|
||||
foreach ($this->categoryTree() as $parent) {
|
||||
$flat->push($parent);
|
||||
foreach ($parent->children as $child) {
|
||||
$flat->push($child);
|
||||
}
|
||||
}
|
||||
return $flat;
|
||||
}
|
||||
|
||||
public function index(Request $request): View
|
||||
{
|
||||
$query = Client::with('category')
|
||||
->withCount(['invoices', 'events', 'contentBriefs'])
|
||||
->latest();
|
||||
|
||||
if ($request->filled('category')) {
|
||||
$query->where('category_id', $request->category);
|
||||
}
|
||||
|
||||
if ($request->filled('status')) {
|
||||
$query->where('status', $request->status);
|
||||
}
|
||||
|
||||
$clients = $query->paginate(12)->withQueryString();
|
||||
$categories = $this->categoryTree();
|
||||
$statuses = ClientStatus::cases();
|
||||
|
||||
return view('clients.index', compact('clients', 'categories', 'statuses'));
|
||||
}
|
||||
|
||||
public function create(): View
|
||||
{
|
||||
$statuses = ClientStatus::cases();
|
||||
return view('clients.create', compact('statuses'));
|
||||
$statuses = ClientStatus::cases();
|
||||
$categories = $this->flatCategories();
|
||||
$categoryTree = $this->categoryTree();
|
||||
|
||||
return view('clients.create', compact('statuses', 'categories', 'categoryTree'));
|
||||
}
|
||||
|
||||
public function store(Request $request): RedirectResponse
|
||||
@@ -44,6 +80,7 @@ class ClientController extends Controller
|
||||
'postal_code' => 'nullable|string|max:20',
|
||||
'country' => 'nullable|string|max:100',
|
||||
'status' => 'required|in:active,inactive,prospect',
|
||||
'category_id' => 'nullable|exists:client_categories,id',
|
||||
'notes' => 'nullable|string',
|
||||
]);
|
||||
|
||||
@@ -55,18 +92,24 @@ class ClientController extends Controller
|
||||
|
||||
public function show(Client $client): View
|
||||
{
|
||||
$client->load(['events' => fn ($q) => $q->latest()->limit(5)]);
|
||||
$client->load(['invoices' => fn ($q) => $q->latest()->limit(5)]);
|
||||
$client->load(['contentBriefs' => fn ($q) => $q->latest()->limit(5)]);
|
||||
$client->load(['mediaFiles' => fn ($q) => $q->latest()->limit(10)]);
|
||||
$client->load([
|
||||
'category',
|
||||
'events' => fn ($q) => $q->latest()->limit(5),
|
||||
'invoices' => fn ($q) => $q->latest()->limit(5),
|
||||
'contentBriefs'=> fn ($q) => $q->latest()->limit(5),
|
||||
'mediaFiles' => fn ($q) => $q->latest()->limit(10),
|
||||
]);
|
||||
|
||||
return view('clients.show', compact('client'));
|
||||
}
|
||||
|
||||
public function edit(Client $client): View
|
||||
{
|
||||
$statuses = ClientStatus::cases();
|
||||
return view('clients.edit', compact('client', 'statuses'));
|
||||
$statuses = ClientStatus::cases();
|
||||
$categories = $this->flatCategories();
|
||||
$categoryTree = $this->categoryTree();
|
||||
|
||||
return view('clients.edit', compact('client', 'statuses', 'categories', 'categoryTree'));
|
||||
}
|
||||
|
||||
public function update(Request $request, Client $client): RedirectResponse
|
||||
@@ -86,6 +129,7 @@ class ClientController extends Controller
|
||||
'postal_code' => 'nullable|string|max:20',
|
||||
'country' => 'nullable|string|max:100',
|
||||
'status' => 'required|in:active,inactive,prospect',
|
||||
'category_id' => 'nullable|exists:client_categories,id',
|
||||
'notes' => 'nullable|string',
|
||||
]);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user