Explorar o código

Merge branch 'feature/diaria-kay-notificação-chamativa' of Softpar/sfp_api_laravel_diarista into development

zntt hai 1 día
pai
achega
578a0a7b1f

+ 2 - 0
.gitignore

@@ -56,3 +56,5 @@ Thumbs.db
 
 
 # Meta
 # Meta
 .phpstorm.meta.php
 .phpstorm.meta.php
+
+storage/firebase-credentials.json

+ 1 - 0
app/Enums/PushNotificationCategoryEnum.php

@@ -12,5 +12,6 @@ enum PushNotificationCategoryEnum: string
     case EDUCATIVO_CONVERSAO  = 'educativo_conversao';
     case EDUCATIVO_CONVERSAO  = 'educativo_conversao';
     case SOCIAL_PROOF         = 'social_proof';
     case SOCIAL_PROOF         = 'social_proof';
     case CONTEXTUAL           = 'contextual';
     case CONTEXTUAL           = 'contextual';
+    case AGENDA               = 'agenda';
     case TRANSACIONAL         = 'transacional';
     case TRANSACIONAL         = 'transacional';
 }
 }

+ 2 - 0
app/Http/Controllers/DeviceTokenController.php

@@ -5,6 +5,7 @@ namespace App\Http\Controllers;
 use App\Http\Requests\DeviceTokenRequest;
 use App\Http\Requests\DeviceTokenRequest;
 use App\Services\DeviceTokenService;
 use App\Services\DeviceTokenService;
 use Illuminate\Http\JsonResponse;
 use Illuminate\Http\JsonResponse;
+use Illuminate\Support\Facades\Log;
 
 
 class DeviceTokenController extends Controller
 class DeviceTokenController extends Controller
 {
 {
@@ -12,6 +13,7 @@ class DeviceTokenController extends Controller
 
 
     public function store(DeviceTokenRequest $request): JsonResponse
     public function store(DeviceTokenRequest $request): JsonResponse
     {
     {
+        Log::info('=== DEVICE TOKEN RECEBIDO ===', $request->validated());
         $this->deviceTokenService->register($request->validated());
         $this->deviceTokenService->register($request->validated());
 
 
         return $this->successResponse(code: 201);
         return $this->successResponse(code: 201);

+ 1 - 0
app/Http/Requests/UpdateMeRequest.php

@@ -23,6 +23,7 @@ class UpdateMeRequest extends FormRequest
             'document'      => 'sometimes|string|nullable',
             'document'      => 'sometimes|string|nullable',
             'avatar'        => 'sometimes|file|image|mimes:jpg,jpeg,png,webp|max:5120',
             'avatar'        => 'sometimes|file|image|mimes:jpg,jpeg,png,webp|max:5120',
             'avatar_base64' => 'sometimes|string|nullable',
             'avatar_base64' => 'sometimes|string|nullable',
+            'push_notifications_enabled' => 'sometimes|boolean',
         ];
         ];
     }
     }
 }
 }

+ 1 - 0
app/Http/Requests/UserRequest.php

@@ -27,6 +27,7 @@ class UserRequest extends FormRequest
             'language' => ['sometimes', Rule::enum(LanguageEnum::class)],
             'language' => ['sometimes', Rule::enum(LanguageEnum::class)],
             'phone'    => 'sometimes|string|nullable',
             'phone'    => 'sometimes|string|nullable',
             'gender'   => 'sometimes|string|in:'.implode(',', GenderEnum::toArray()),
             'gender'   => 'sometimes|string|in:'.implode(',', GenderEnum::toArray()),
+            'push_notifications_enabled' => 'sometimes|boolean',
         ];
         ];
 
 
         if ($this->isMethod('post')) {
         if ($this->isMethod('post')) {

+ 2 - 0
app/Http/Resources/UserResource.php

@@ -27,6 +27,8 @@ class UserResource extends JsonResource
       'type'        => $this->type,
       'type'        => $this->type,
       'provider_id' => $this->provider?->id,
       'provider_id' => $this->provider?->id,
 
 
+      'push_notifications_enabled' => $this->push_notifications_enabled,
+
       'provider_daily_price_8h' => $this->provider?->daily_price_8h,
       'provider_daily_price_8h' => $this->provider?->daily_price_8h,
       'provider_daily_price_6h' => $this->provider?->daily_price_6h,
       'provider_daily_price_6h' => $this->provider?->daily_price_6h,
       'provider_daily_price_4h' => $this->provider?->daily_price_4h,
       'provider_daily_price_4h' => $this->provider?->daily_price_4h,

+ 1 - 0
app/Models/User.php

@@ -83,6 +83,7 @@ class User extends Authenticatable
             'type'                  => UserTypeEnum::class,
             'type'                  => UserTypeEnum::class,
             'language'              => LanguageEnum::class,
             'language'              => LanguageEnum::class,
             'registration_complete' => 'boolean',
             'registration_complete' => 'boolean',
+            'push_notifications_enabled' => 'boolean',
         ];
         ];
     }
     }
 
 

+ 60 - 0
app/Notifications/Push/Prestador/Agendamento/NewPushRequest.php

@@ -0,0 +1,60 @@
+<?php
+
+namespace App\Notifications\Push\Prestador\Agendamento;
+
+use App\Enums\PushNotificationCategoryEnum;
+use App\Enums\PushNotificationTargetEnum;
+use App\Notifications\Push\BasePushNotification;
+use Illuminate\Database\Eloquent\Collection;
+
+/**
+ * Notificação enviada quando um cliente cria
+ * um agendamento direto para um prestador.
+ */
+class NewPushRequest extends BasePushNotification
+{
+    public function __construct(
+        private readonly string $clientName,
+    ) {}
+
+    public function label(): string
+    {
+        return 'provider_new_schedule_request';
+    }
+
+    public function title(): string
+    {
+        return 'Nova solicitação';
+    }
+
+    public function body(): string
+    {
+        return "{$this->clientName} solicitou um novo agendamento.";
+    }
+
+    public function target(): PushNotificationTargetEnum
+    {
+        return PushNotificationTargetEnum::PRESTADOR;
+    }
+
+    public function category(): PushNotificationCategoryEnum
+    {
+        return PushNotificationCategoryEnum::AGENDA;
+    }
+
+    public function eligibleUsers(): Collection
+    {
+        // Não utilizado para notificações transacionais.
+        return new Collection();
+    }
+
+    public function notificationCooldownDays(): int
+    {
+        return 0;
+    }
+
+    public function categoryCooldownDays(): int
+    {
+        return 0;
+    }
+}

+ 12 - 3
app/Services/PushNotificationService.php

@@ -22,6 +22,10 @@ class PushNotificationService
      */
      */
     public function sendToUser(User $user, BasePushNotification $notification): void
     public function sendToUser(User $user, BasePushNotification $notification): void
     {
     {
+        if (! $user->push_notifications_enabled) {
+            return;
+        }
+
         $tokens = DeviceToken::where('user_id', $user->id)
         $tokens = DeviceToken::where('user_id', $user->id)
             ->where('app_type', $notification->target()->value)
             ->where('app_type', $notification->target()->value)
             ->where('active', true)
             ->where('active', true)
@@ -33,10 +37,15 @@ class PushNotificationService
         }
         }
 
 
         $message = CloudMessage::new()
         $message = CloudMessage::new()
-            ->withNotification(Notification::create($notification->title(), $notification->body()))
+            ->withNotification(
+                Notification::create(
+                    $notification->title(),
+                    $notification->body()
+                )
+            )
             ->withAndroidConfig(AndroidConfig::fromArray([
             ->withAndroidConfig(AndroidConfig::fromArray([
-                'notification' => ['channel_id' => 'default'],
-                'priority'     => 'high',
+                'notification' => ['channel_id' => 'diaria'],
+                'priority' => 'high',
             ]));
             ]));
 
 
         $report = $this->messaging->sendMulticast($message, $tokens);
         $report = $this->messaging->sendMulticast($message, $tokens);

+ 11 - 1
app/Services/ScheduleService.php

@@ -12,6 +12,8 @@ use App\Models\Schedule;
 use App\Models\ServicePackage;
 use App\Models\ServicePackage;
 use App\Rules\ScheduleBusinessRules;
 use App\Rules\ScheduleBusinessRules;
 use App\Services\NotificationService;
 use App\Services\NotificationService;
+use App\Services\PushNotificationService;
+use App\Notifications\Push\Prestador\Agendamento\NewPushRequest;
 use Carbon\Carbon;
 use Carbon\Carbon;
 use Illuminate\Support\Facades\Auth;
 use Illuminate\Support\Facades\Auth;
 use Illuminate\Support\Facades\DB;
 use Illuminate\Support\Facades\DB;
@@ -80,8 +82,16 @@ class ScheduleService
                         'type'        => NotificationTypeEnum::SCHEDULE_PROVIDER_CLIENT_NEW_SOLICITATION->value,
                         'type'        => NotificationTypeEnum::SCHEDULE_PROVIDER_CLIENT_NEW_SOLICITATION->value,
                         'user_id'     => $newSchedule->provider->user_id,
                         'user_id'     => $newSchedule->provider->user_id,
                     ]);
                     ]);
+                    // Push Notification
+                    $pushNotificationService = app(PushNotificationService::class);
+
+                    $pushNotificationService->sendToUser(
+                        $newSchedule->provider->user,
+                        new NewPushRequest($newSchedule->client->user->name)
+                    );
                 }
                 }
 
 
+
                 $createdSchedules[] = $newSchedule;
                 $createdSchedules[] = $newSchedule;
             }
             }
 
 
@@ -512,7 +522,7 @@ class ScheduleService
         } catch (\Exception $e) {
         } catch (\Exception $e) {
             DB::rollBack();
             DB::rollBack();
 
 
-            Log::error('Erro ao cancelar agendamento: '.$e->getMessage());
+            Log::error('Erro ao cancelar agendamento: ' . $e->getMessage());
 
 
             throw $e;
             throw $e;
         }
         }

+ 1 - 1
app/Services/UserService.php

@@ -102,7 +102,7 @@ class UserService
             ]);
             ]);
 
 
             $userFields = array_filter(
             $userFields = array_filter(
-                array_intersect_key($data, array_flip(['name', 'email', 'phone', 'language'])),
+                array_intersect_key($data, array_flip(['name', 'email', 'phone', 'language', 'push_notifications_enabled'])),
                 fn ($v) => $v !== null,
                 fn ($v) => $v !== null,
             );
             );
 
 

+ 23 - 0
database/migrations/2026_08_10_092331_add_push_notifications_enabled_to_users_table.php

@@ -0,0 +1,23 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+    public function up(): void
+    {
+        Schema::table('users', function (Blueprint $table) {
+            $table->boolean('push_notifications_enabled')
+                ->default(false);
+        });
+    }
+
+    public function down(): void
+    {
+        Schema::table('users', function (Blueprint $table) {
+            $table->dropColumn('push_notifications_enabled');
+        });
+    }
+};