Files
CFDivePlatform/app/Notifications/BookingCancelledNotification.php
T
a620906209 03f8caf3e9 feat:實作通知系統 — 站內通知、Email 通知、Polling 機制
後端
- 新增 6 個 Notification class(預約建立/確認/拒絕/取消/完成、收到評價),database + mail 雙 channel
- 新增 NotificationController(list / unread-count / markRead / markAllRead / destroy)
- 整合通知觸發至 MemberBookingController、ProviderBookingController、CompleteFinishedBookings、ReviewController
- 新增 notifications / jobs / failed_jobs migration
- Docker Compose 加入 queue-worker、mailpit service
- DivingOffer 補上 provider() 關聯

前端
- 新增 notificationStore(Polling 30s/60s 自適應 + Page Visibility API)
- 新增 NotificationBell(未讀 Badge)、NotificationDrawer(側邊通知中心)
- main.js:auth store init 前置於 router.use(),修正 beforeEach guard 時序問題
- notificationAxios:依路徑動態選擇 member/coach token
- NotificationDrawer:改用 new URL().pathname 提取 action_url 路徑

OpenSpec
- 歸檔 notification-system change
- 同步 notification-core / notification-email / notification-triggers specs 至主規格
- 更新 booking-lifecycle / review-lifecycle spec(補充通知觸發 requirement)

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-05-17 22:26:14 +08:00

75 lines
2.7 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace App\Notifications;
use App\Models\Booking;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
class BookingCancelledNotification extends Notification implements ShouldQueue
{
use Queueable;
public int $tries = 3;
public function __construct(
public readonly Booking $booking,
public readonly string $cancelledBy,
) {}
public function via(object $notifiable): array
{
return ['database', 'mail'];
}
public function toArray(object $notifiable): array
{
$offer = $this->booking->schedule->divingOffer;
$date = $this->booking->schedule->scheduled_date->toDateString();
if ($this->cancelledBy === 'member') {
return [
'type' => 'booking_cancelled',
'title' => '學員取消了預約',
'body' => "學員已取消《{$offer->title}》的預約(時段:{$date}",
'action_url' => config('app.frontend_url') . '/coach/bookings',
'related_id' => $this->booking->id,
'related_type' => 'booking',
];
}
return [
'type' => 'booking_cancelled',
'title' => '教練取消了你的預約',
'body' => "教練已取消你的《{$offer->title}》預約(時段:{$date}),如有疑問請聯繫教練",
'action_url' => config('app.frontend_url') . '/my-bookings',
'related_id' => $this->booking->id,
'related_type' => 'booking',
];
}
public function toMail(object $notifiable): MailMessage
{
$offer = $this->booking->schedule->divingOffer;
$date = $this->booking->schedule->scheduled_date->toDateString();
if ($this->cancelledBy === 'member') {
return (new MailMessage)
->subject('預約已取消 — CFDivePlatform')
->greeting('通知')
->line("學員已取消《{$offer->title}》的預約(時段:{$date})。")
->action('查看所有預約', config('app.frontend_url') . '/coach/bookings')
->salutation('CFDivePlatform 團隊');
}
return (new MailMessage)
->subject('你的預約已取消 — CFDivePlatform')
->greeting('通知')
->line("教練已取消你的《{$offer->title}》預約(時段:{$date})。如有疑問,請聯繫課程教練。")
->action('查看預約', config('app.frontend_url') . '/my-bookings')
->salutation('CFDivePlatform 團隊');
}
}