Przeglądaj źródła

implementacao API na dashboard do cliente + garantindo atualizacao de rating e total_services em client e provider ao finalizar um schedulejob

Gustavo Zanatta 1 miesiąc temu
rodzic
commit
9349bc6bd9

+ 27 - 0
app/Http/Controllers/DashboardController.php

@@ -0,0 +1,27 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use App\Services\DashboardService;
+use App\Http\Resources\DashboardResource;
+use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
+use Illuminate\Http\JsonResponse;
+use Illuminate\Support\Facades\Log;
+
+class DashboardController extends Controller
+{
+  public function __construct(private readonly DashboardService $service) {}
+
+  public function dadosDashboardCliente(): JsonResponse
+  {
+    try {
+      $dados = $this->service->dadosDashboardCliente();
+      return $this->successResponse(
+        payload: new DashboardResource($dados),
+      );
+    } catch (\Exception $e) {
+      Log::error("Erro ao obter dados do dashboard do cliente: " . $e->getMessage());
+      return $this->errorResponse(message: __("messages.error_fetching_data"), code: 500);
+    }
+  }
+}

+ 26 - 0
app/Http/Resources/DashboardResource.php

@@ -0,0 +1,26 @@
+<?php
+
+namespace App\Http\Resources;
+
+use Illuminate\Http\Request;
+use Illuminate\Http\Resources\Json\JsonResource;
+
+class DashboardResource extends JsonResource
+{
+  /**
+   * Transform the resource into an array.
+   *
+   * @return array<string, mixed>
+   */
+  public function toArray(Request $request): array
+  {
+    return [
+      'headerBar' => $this['headerBar'],
+      'summaryInfos' => $this['summaryInfos'],
+      'nextSchedules' => $this['nextSchedules'],
+      'lastDoneSchedules' => $this['lastDoneSchedules'],
+      'favoriteProviders' => $this['favoriteProviders'],
+      'providersClose' => $this['providersClose'],
+    ];
+  }
+}

+ 13 - 0
app/Jobs/FinishScheduleJob.php

@@ -2,6 +2,8 @@
 
 namespace App\Jobs;
 
+use App\Models\Client;
+use App\Models\Provider;
 use App\Models\Schedule;
 use Carbon\Carbon;
 use Illuminate\Bus\Queueable;
@@ -60,6 +62,17 @@ class FinishScheduleJob implements ShouldQueue
       $schedule->update([
         'status' => 'finished'
       ]);
+
+      $provider = Provider::find($schedule->provider_id);
+      $provider->update([
+        'total_services' => $provider->total_services + 1,
+      ]);
+      
+      $client = Client::find($schedule->client_id);
+      $client->update([
+        'total_services' => $client->total_services + 1,
+      ]);
+
     } catch (\Exception $e) {
       Log::channel('schedule_end_jobs')->error('Erro ao finalizar agendamento id: ' . $this->scheduleId . '. Erro: ' . $e->getMessage());
       return;

+ 18 - 0
app/Models/Client.php

@@ -46,4 +46,22 @@ class Client extends Model
     {
         return $this->hasMany(ClientProviderBlock::class);
     }
+
+    public function updateAverageRating(float $newRating): void
+    {
+      $totalReviews = Review::where('reviews.origin', 'provider')
+        ->leftJoin('schedules', 'schedules.id', '=', 'reviews.schedule_id')
+        ->where('schedules.client_id', $this->id)
+        ->count();
+
+      if ($totalReviews === 0) {
+        $this->average_rating = $newRating;
+      } else {
+        $currentTotalRating = $this->average_rating * ($totalReviews - 1);
+        $newAverage = ($currentTotalRating + $newRating) / $totalReviews;
+        $this->average_rating = round($newAverage, 2);
+      }
+
+      $this->save();
+    }
 }

+ 18 - 0
app/Models/Provider.php

@@ -96,4 +96,22 @@ class Provider extends Model
     {
         return $this->hasMany(ClientProviderBlock::class);
     }
+
+    public function updateAverageRating(float $newRating): void
+    {
+      $totalReviews = Review::where('reviews.origin', 'client')
+        ->leftJoin('schedules', 'schedules.id', '=', 'reviews.schedule_id')
+        ->where('schedules.provider_id', $this->id)
+        ->count();
+
+      if ($totalReviews === 0) {
+        $this->average_rating = $newRating;
+      } else {
+        $currentTotalRating = $this->average_rating * ($totalReviews - 1);
+        $newAverage = ($currentTotalRating + $newRating) / $totalReviews;
+        $this->average_rating = round($newAverage, 2);
+      }
+
+      $this->save();
+    }
 }

+ 113 - 0
app/Services/DashboardService.php

@@ -0,0 +1,113 @@
+<?php
+
+namespace App\Services;
+
+use App\Models\Address;
+use App\Models\Client;
+use App\Models\ClientFavoriteProvider;
+use App\Models\Provider;
+use App\Models\Review;
+use App\Models\Schedule;
+use Illuminate\Support\Facades\Auth;
+use Illuminate\Support\Facades\DB;
+
+class DashboardService
+{
+  public function __construct() {}
+
+  public function dadosDashboardCliente(): array
+  {
+    $user = Auth::user();
+    $cliente = Client::where('user_id', $user->id)->first();
+    $headerBar = [
+      'rating' => $cliente->average_rating,
+      'total_ratings' => Review::where('reviews.origin', 'provider')->leftJoin('schedules', 'schedules.id', '=', 'reviews.schedule_id')->where('schedules.client_id', $cliente->id)->count(),
+      'total_services' => $cliente->total_services,
+    ];
+
+    $summaryInfos = [
+      'name' => $user->name,
+      'address' => Address::where('source', 'client')->where('source_id', $cliente->id)->first()->address ?? null,
+      'pending_services' => Schedule::where('client_id', $cliente->id)->where('status', 'pending')->count(),
+    ];
+
+    $nextSchedules = Schedule::where('schedules.client_id', $cliente->id)
+      ->whereIn('schedules.status', ['accepted', 'paid'])
+      ->leftJoin('providers', 'providers.id', '=', 'schedules.provider_id')
+      ->leftJoin('users as provider_user', 'provider_user.id', '=', 'providers.user_id')
+      ->leftJoin('addresses', function ($join) {
+        $join->on('addresses.source_id', '=', 'providers.id')
+          ->where('addresses.source', 'provider');
+      })
+      ->where('schedules.date', '>=', now()->toDateString())
+      ->select(
+        'schedules.id',
+        'provider_user.name as provider_name',
+        'schedules.date',
+        'schedules.start_time',
+        'schedules.end_time',
+        'schedules.total_amount',
+        'schedules.period_type',
+        'schedules.schedule_type',
+        'addresses.address_type',
+      )
+      ->orderBy('schedules.date', 'asc')
+      ->get();
+
+    $lastDoneSchedules = Schedule::where('schedules.client_id', $cliente->id)
+      ->where('schedules.status', 'finished')
+      ->leftJoin('providers', 'providers.id', '=', 'schedules.provider_id')
+      ->leftJoin('users as provider_user', 'provider_user.id', '=', 'providers.user_id')
+      ->leftJoin('addresses', function ($join) {
+        $join->on('addresses.source_id', '=', 'providers.id')
+          ->where('addresses.source', 'provider');
+      })
+      ->select(
+        'schedules.id',
+        'provider_user.name as provider_name',
+      )
+      ->orderBy('schedules.date', 'desc')
+      ->limit(5)
+      ->get();
+
+    $favoriteProviders = ClientFavoriteProvider::where('client_id', $cliente->id)
+      ->leftJoin('providers', 'providers.id', '=', 'client_favorite_providers.provider_id')
+      ->leftJoin('users as provider_user', 'provider_user.id', '=', 'providers.user_id')
+      ->select(
+        'providers.id',
+        'provider_user.name as provider_name',
+        'providers.average_rating',
+      )
+      ->get();
+
+    $providersClose = Provider::leftJoin('users as provider_user', 'provider_user.id', '=', 'providers.user_id')
+      ->leftJoin('addresses as provider_address', function ($join) {
+        $join->on('provider_address.source_id', '=', 'providers.id')
+          ->where('provider_address.source', 'provider');
+      })
+      ->leftJoin('addresses as client_address', function ($join) use ($cliente) {
+          $join->where('client_address.source_id', $cliente->id)
+              ->where('client_address.source', 'client');
+      })
+      ->whereColumn('provider_address.city_id', '=', 'client_address.city_id')
+      ->select(
+        'providers.id',
+        'provider_user.name as provider_name',
+        'provider_address.address_type', // refatorar para pegar o bairro
+        'providers.average_rating',
+        DB::raw("(SELECT COUNT(*) FROM reviews LEFT JOIN schedules ON schedules.id = reviews.schedule_id WHERE reviews.origin = 'provider' AND schedules.provider_id = providers.id) as total_reviews"),
+        'providers.total_services',
+        'providers.daily_price_8h',
+      )
+      ->get();
+
+    return [
+      'headerBar' => $headerBar,
+      'summaryInfos' => $summaryInfos,
+      'nextSchedules' => $nextSchedules,
+      'lastDoneSchedules' => $lastDoneSchedules,
+      'favoriteProviders' => $favoriteProviders,
+      'providersClose' => $providersClose,
+    ];
+  }
+}

+ 17 - 0
app/Services/ReviewService.php

@@ -2,7 +2,9 @@
 
 namespace App\Services;
 
+use App\Models\Client;
 use App\Models\ClientProviderBlock;
+use App\Models\Provider;
 use App\Models\ProviderClientBlock;
 use App\Models\Review;
 use App\Models\Schedule;
@@ -44,6 +46,21 @@ class ReviewService
       $review->fill($data);
       $review->save();
       $review->refresh();
+
+      if (isset($data['origin']) && isset($data['origin_id'])) {
+        switch ($data['origin']) {
+          case 'client':
+            $schedule = Schedule::find($data['schedule_id']);
+            $provider = Provider::find($schedule->provider_id);
+            $provider->updateAverageRating();
+            break;
+          case 'provider':
+            $schedule = Schedule::find($data['schedule_id']);
+            $client = Client::find($schedule->client_id);
+            $client->updateAverageRating();
+            break;
+        }
+      }
   
       if (isset($data['improvements_ids'])) {
         $review->improvements()->sync($data['improvements_ids']);

+ 26 - 0
database/migrations/2026_03_23_093413_add_rating_and_total_services_to_client.php

@@ -0,0 +1,26 @@
+<?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('clients', function (Blueprint $table) {
+      //
+      $table->decimal('average_rating', 2, 1)->nullable();
+      $table->integer('total_services')->default(0);
+    });
+  }
+
+  public function down(): void
+  {
+    Schema::table('clients', function (Blueprint $table) {
+      //
+      $table->dropColumn('average_rating');
+      $table->dropColumn('total_services');
+    });
+  }
+};

+ 6 - 0
routes/authRoutes/dashboard.php

@@ -0,0 +1,6 @@
+<?php
+
+use App\Http\Controllers\DashboardController;
+use Illuminate\Support\Facades\Route;
+
+Route::get('/dados-dashboard-cliente', [DashboardController::class, 'dadosDashboardCliente'])->middleware('permission:dashboard,view');