Files
Verde-Web/app/Providers/AppServiceProvider.php
admin 968ced302c feat(live): god's-eye view — heading, route, breadcrumb, click-to-detail, push
Live Tracking page upgrades:

- **Heading rotation** on each truck marker via CSS transform driven by
  the heading_degrees broadcast field.
- **Click-to-detail** opens a slide-over showing trip number, status,
  route, started-at, current load, an ordered stop list color-coded by
  status, and the last 20 timeline events.
- **Route overlay** draws planned-route polyline (stops in order →
  dumpsite, dashed), stop markers (pending/arrived/completed/skipped
  colors), a diamond marker for the dumpsite, and a translucent
  geofence polygon when the dumpsite has one configured.
- **Breadcrumb trail** of the last 60 minutes of GPS pings rendered
  as a polyline; new pings tack on incrementally while the panel is
  open.
- **Real-time push via Reverb** with polling fallback. Subscribes to
  private-admin.live, listens for `.truck.location`, and updates
  marker position + the trucks-online list immediately. When Reverb
  isn't configured or fails, falls back to 10s polling. Status pill
  shows live (push) / polling / offline.

Backend additions:
- GET /admin/live/trucks/{uuid}/trail — recent location pings
- GET /admin/live/trucks/{uuid}/active-trip — full trip + stops +
  dumpsite + boundary + recent timeline
- Broadcasting auth route now accepts Sanctum bearer tokens (admin
  web posts them via Echo's authorizer callback)

Frontend wiring:
- npm: laravel-echo + pusher-js
- window.Verde.getEcho() lazily inits Echo with bearer-token authorizer
- Layout exposes window.VERDE_BROADCAST with reverb config

196 tests passing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 17:44:13 +08:00

75 lines
2.7 KiB
PHP

<?php
namespace App\Providers;
use App\Services\Payment\ManualPaymentDriver;
use App\Services\Payment\PayMongoDriver;
use App\Services\Payment\PaymentDriver;
use App\Services\Push\FcmPushDriver;
use App\Services\Push\LogPushDriver;
use App\Services\Push\PushDriver;
use App\Services\Sms\FakeSmsService;
use App\Services\Sms\LogSmsService;
use App\Services\Sms\SemaphoreSmsService;
use App\Services\Sms\SmsService;
use Illuminate\Support\Facades\Broadcast;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function register(): void
{
$this->app->singleton(PaymentDriver::class, function ($app) {
$driver = config('services.payments.driver', 'manual');
$key = (string) config('services.paymongo.secret_key');
if ($driver === 'paymongo' && $key !== '') {
return new PayMongoDriver(
secretKey: $key,
webhookSecret: (string) config('services.paymongo.webhook_secret'),
successUrl: (string) config('services.paymongo.success_url'),
cancelUrl: (string) config('services.paymongo.cancel_url'),
);
}
return new ManualPaymentDriver();
});
$this->app->singleton(PushDriver::class, function ($app) {
$driver = config('services.push.driver', 'log');
$key = (string) config('services.fcm.server_key');
if ($driver === 'fcm' && $key !== '') {
return new FcmPushDriver($key);
}
return new LogPushDriver();
});
$this->app->singleton(SmsService::class, function ($app) {
$driver = config('services.sms.driver', 'log');
return match ($driver) {
'semaphore' => new SemaphoreSmsService(
apiKey: (string) config('services.semaphore.api_key'),
senderName: (string) config('services.semaphore.sender_name', 'VERDE'),
),
'fake' => new FakeSmsService(),
default => new LogSmsService(),
};
});
}
public function boot(): void
{
// Listeners under App\Listeners are auto-discovered by Laravel 11
// based on their handle() method's type-hint. Don't register them
// explicitly here — that causes double-dispatch.
// Broadcasting auth needs to accept Sanctum bearer tokens (admin web
// posts them via Echo's authorizer callback). Without this override
// it would only accept session cookies via the default `web` guard.
Broadcast::routes(['middleware' => ['auth:sanctum']]);
}
}