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:
I-Fun
2026-04-01 12:46:58 +07:00
parent 1126877ef5
commit d3c35ad730
29 changed files with 1849 additions and 96 deletions

View File

@@ -1,8 +1,20 @@
<?php
use App\Services\NotificationDispatcher;
use Illuminate\Foundation\Inspiring;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Schedule;
Artisan::command('inspire', function () {
$this->comment(Inspiring::quote());
})->purpose('Display an inspiring quote');
Artisan::command('notifications:dispatch', function () {
/** @var NotificationDispatcher $dispatcher */
$dispatcher = app(NotificationDispatcher::class);
$dispatcher->dispatchAll();
$this->info('🔔 Notifications dispatched.');
})->purpose('Send all pending KOL Manager notifications');
// Run every hour automatically
Schedule::command('notifications:dispatch')->hourly();

View File

@@ -2,13 +2,16 @@
declare(strict_types=1);
use App\Http\Controllers\ClientCategoryController;
use App\Http\Controllers\ClientController;
use App\Http\Controllers\ContentBriefController;
use App\Http\Controllers\DashboardController;
use App\Http\Controllers\EventController;
use App\Http\Controllers\InvoiceController;
use App\Http\Controllers\MediaFileController;
use App\Http\Controllers\NotificationSettingController;
use App\Http\Controllers\RateCardController;
use App\Http\Controllers\SearchController;
use App\Http\Controllers\SocialHubController;
use Illuminate\Support\Facades\Route;
@@ -17,10 +20,19 @@ Route::get('/', [DashboardController::class, 'index'])->name('dashboard');
// CRM – Clients
Route::resource('clients', ClientController::class);
// Client Categories
Route::prefix('client-categories')->name('client-categories.')->group(function (): void {
Route::get('/', [ClientCategoryController::class, 'index'])->name('index');
Route::post('/', [ClientCategoryController::class, 'store'])->name('store');
Route::put('/{category}', [ClientCategoryController::class, 'update'])->name('update');
Route::delete('/{category}', [ClientCategoryController::class, 'destroy'])->name('destroy');
});
// Schedule & Calendar
Route::prefix('schedule')->name('schedule.')->group(function (): void {
Route::get('/', [EventController::class, 'index'])->name('index');
Route::post('/', [EventController::class, 'store'])->name('store');
Route::get('/{event}/edit', [EventController::class, 'edit'])->name('edit');
Route::put('/{event}', [EventController::class, 'update'])->name('update');
Route::patch('/{event}/dates', [EventController::class, 'updateDates'])->name('update-dates');
Route::delete('/{event}', [EventController::class, 'destroy'])->name('destroy');
@@ -60,3 +72,19 @@ Route::prefix('files')->name('files.')->group(function (): void {
Route::get('/{mediaFile}/serve', [MediaFileController::class, 'serve'])->name('serve');
Route::delete('/{mediaFile}', [MediaFileController::class, 'destroy'])->name('destroy');
});
// Global Search
Route::prefix('search')->name('search.')->group(function (): void {
Route::get('/', [SearchController::class, 'index'])->name('index');
Route::get('/quick', [SearchController::class, 'quick'])->name('quick');
});
// Settings
Route::prefix('settings')->name('settings.')->group(function (): void {
Route::get('/notifications', [NotificationSettingController::class, 'index'])->name('notifications');
Route::post('/notifications', [NotificationSettingController::class, 'store'])->name('notifications.store');
Route::put('/notifications/{setting}', [NotificationSettingController::class, 'update'])->name('notifications.update');
Route::delete('/notifications/{setting}', [NotificationSettingController::class, 'destroy'])->name('notifications.destroy');
Route::post('/notifications/{setting}/test', [NotificationSettingController::class, 'test'])->name('notifications.test');
Route::post('/notifications/{setting}/toggle', [NotificationSettingController::class, 'toggle'])->name('notifications.toggle');
});