浏览代码

feat: :sparkles: feat (layout / login) refatorado layout e ajuste login

foi ajustado login e refatorado alguns layouts, necessitando ajuste nos campos do retorno

fase:dev | origin:escopo
Gustavo Zanatta 2 天之前
父节点
当前提交
5726fe38e2

+ 71 - 76
app/Http/Controllers/UserController.php

@@ -3,86 +3,81 @@
 namespace App\Http\Controllers;
 
 use App\Http\Requests\UpdateMeRequest;
-use App\Http\Requests\UserRequest;
-use App\Http\Resources\UserResource;
 use App\Http\Resources\UserTypeResource;
 use App\Services\UserService;
+use App\Http\Requests\UserRequest;
+use App\Http\Resources\UserResource;
 use Illuminate\Http\JsonResponse;
+use Illuminate\Support\Facades\Log;
 
 class UserController extends Controller
 {
-    public function __construct(protected UserService $service) {}
-
-    public function me(): JsonResponse
-    {
-        $user = $this->service->me();
-
-        return $this->successResponse(payload: new UserResource($user));
-    }
-
-    public function index(): JsonResponse
-    {
-        $items = $this->service->getAll();
-
-        return $this->successResponse(
-            payload: UserResource::collection($items),
-        );
-    }
-
-    public function store(UserRequest $request): JsonResponse
-    {
-        $item = $this->service->create($request->validated());
-
-        return $this->successResponse(
-            payload: new UserResource($item),
-            message: __('messages.created'),
-            code: 201,
-        );
-    }
-
-    public function show(int $id): JsonResponse
-    {
-        $item = $this->service->findById($id);
-
-        return $this->successResponse(payload: new UserResource($item));
-    }
-
-    public function update(UserRequest $request, int $id): JsonResponse
-    {
-        $item = $this->service->update($id, $request->validated());
-
-        return $this->successResponse(
-            payload: new UserResource($item),
-            message: __('messages.updated'),
-        );
-    }
-
-    public function destroy(int $id): JsonResponse
-    {
-        $this->service->delete($id);
-
-        return $this->successResponse(
-            message: __('messages.deleted'),
-            code: 204,
-        );
-    }
-
-    public function updateMe(UpdateMeRequest $request): JsonResponse
-    {
-        $user = $this->service->updateMe($request->validated());
-
-        return $this->successResponse(
-            payload: new UserResource($user),
-            message: __('messages.updated'),
-        );
-    }
-
-    public function getUserTypes(): JsonResponse
-    {
-        $user_types = $this->service->getUserTypes();
-
-        return $this->successResponse(
-            payload: new UserTypeResource($user_types),
-        );
-    }
+  public function __construct(protected UserService $service) {}
+
+  public function me(): JsonResponse
+  {
+    $user = $this->service->me();
+    return $this->successResponse(payload: new UserResource($user));
+  }
+
+  public function index(): JsonResponse
+  {
+    $items = $this->service->getAll();
+    return $this->successResponse(
+      payload: UserResource::collection($items),
+    );
+  }
+
+  public function store(UserRequest $request): JsonResponse
+  {
+    $item = $this->service->create($request->validated());
+    return $this->successResponse(
+      payload: new UserResource($item),
+      message: __("messages.created"),
+      code: 201,
+    );
+  }
+
+  public function show(int $id): JsonResponse
+  {
+    $item = $this->service->findById($id);
+    return $this->successResponse(payload: new UserResource($item));
+  }
+
+  public function update(UserRequest $request, int $id): JsonResponse
+  {
+    $item = $this->service->update($id, $request->validated());
+    return $this->successResponse(
+      payload: new UserResource($item),
+      message: __("messages.updated"),
+    );
+  }
+
+  public function destroy(int $id): JsonResponse
+  {
+      $this->service->delete($id);
+
+      return $this->successResponse(
+          message: __('messages.deleted'),
+          code: 204,
+      );
+  }
+
+  public function updateMe(UpdateMeRequest $request): JsonResponse
+  {
+      $user = $this->service->updateMe($request->validated());
+
+      return $this->successResponse(
+          payload: new UserResource($user),
+          message: __('messages.updated'),
+      );
+  }
+
+  public function getUserTypes(): JsonResponse
+  {
+    $user_types = $this->service->getUserTypes();
+    return $this->successResponse(
+      payload: new UserTypeResource($user_types),
+    );
+  }
 }

+ 6 - 1
app/Http/Resources/CustomScheduleResource.php

@@ -4,6 +4,7 @@ namespace App\Http\Resources;
 
 use Illuminate\Http\Request;
 use Illuminate\Http\Resources\Json\JsonResource;
+use Illuminate\Support\Facades\Storage;
 
 class CustomScheduleResource extends JsonResource
 {
@@ -36,7 +37,11 @@ class CustomScheduleResource extends JsonResource
                     'id'          => $this->schedule->id,
                     'client_id'   => $this->schedule->client_id,
                     'provider_id' => $this->schedule->provider_id,
-                    'client_name' => $this->schedule->client?->user?->name,
+                    'client_name'    => $this->schedule->client?->user?->name,
+                    'customer_photo' => (function () {
+                        $path = $this->schedule->client?->profileMedia?->path;
+                        return $path ? Storage::temporaryUrl($path, now()->addMinutes(60)) : null;
+                    })(),
                     'address_id'  => $this->schedule->address_id,
 
                     'address' => $this->schedule->address ? [

+ 9 - 0
app/Http/Resources/ProviderClientBlockResource.php

@@ -4,6 +4,7 @@ namespace App\Http\Resources;
 
 use Illuminate\Http\Request;
 use Illuminate\Http\Resources\Json\JsonResource;
+use Illuminate\Support\Facades\Storage;
 
 class ProviderClientBlockResource extends JsonResource
 {
@@ -17,8 +18,16 @@ class ProviderClientBlockResource extends JsonResource
             'client_email'  => $this->client->user->email ?? null,
             'client_phone'  => $this->client->user->phone ?? null,
             'client_rating' => $this->client->average_rating ?? null,
+            'client_photo'  => $this->resolveClientPhoto(),
             'created_at'    => $this->created_at?->format('Y-m-d H:i'),
             'updated_at'    => $this->updated_at?->format('Y-m-d H:i'),
         ];
     }
+
+    private function resolveClientPhoto(): ?string
+    {
+        $path = $this->client->profileMedia->path ?? null;
+
+        return $path ? Storage::temporaryUrl($path, now()->addMinutes(60)) : null;
+    }
 }

+ 5 - 14
app/Http/Resources/ReviewDetailResource.php

@@ -10,9 +10,7 @@ class ReviewDetailResource extends JsonResource
     public function toArray(Request $request): array
     {
         $schedule = $this->schedule;
-
         $customSchedule = $schedule?->customSchedule;
-
         $address = $schedule?->address;
 
         return [
@@ -22,14 +20,12 @@ class ReviewDetailResource extends JsonResource
             'stars'      => $this->stars,
             'comment'    => $this->comment,
             'created_at' => $this->created_at?->format('Y-m-d H:i'),
-
             'improvements' => $this->whenLoaded('improvements', function () {
-                return $this->improvements->map(fn ($imp) => [
+                return $this->improvements->map(fn($imp) => [
                     'id'          => $imp->id,
                     'description' => $imp->description,
                 ]);
             }),
-
             'schedule' => $schedule ? [
                 'id'            => $schedule->id,
                 'schedule_type' => $schedule->schedule_type,
@@ -40,23 +36,19 @@ class ReviewDetailResource extends JsonResource
                 'period_type'   => $schedule->period_type,
                 'total_amount'  => $schedule->total_amount,
                 'code'          => $schedule->code,
-
-                'client' => $schedule->client ? [
+                'client'        => $schedule->client ? [
                     'id'    => $schedule->client->id,
                     'name'  => $schedule->client->user?->name,
                     'email' => $schedule->client->user?->email,
                     'phone' => $schedule->client->user?->phone,
-                    'profile_photo' => $schedule->client->profile_photo
                 ] : null,
-
-                'provider' => $schedule->provider ? [
+                'provider'      => $schedule->provider ? [
                     'id'    => $schedule->provider->id,
                     'name'  => $schedule->provider->user?->name,
                     'email' => $schedule->provider->user?->email,
                     'phone' => $schedule->provider->user?->phone,
                 ] : null,
-
-                'address' => $address ? [
+                'address'       => $address ? [
                     'street'       => $address->street,
                     'number'       => $address->number,
                     'complement'   => $address->complement,
@@ -64,12 +56,11 @@ class ReviewDetailResource extends JsonResource
                     'city'         => $address->city?->name,
                     'state'        => $address->state?->name,
                 ] : null,
-
                 'custom_schedule' => $customSchedule ? [
                     'address_type' => $customSchedule->address_type,
                     'service_type' => $customSchedule->serviceType?->description,
                     'specialities' => $customSchedule->specialities
-                        ? $customSchedule->specialities->map(fn ($s) => [
+                        ? $customSchedule->specialities->map(fn($s) => [
                             'id'          => $s->id,
                             'description' => $s->description,
                         ])

+ 42 - 33
app/Http/Resources/UserResource.php

@@ -4,42 +4,51 @@ namespace App\Http\Resources;
 
 use Carbon\Carbon;
 use Illuminate\Http\Request;
-use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
 use Illuminate\Http\Resources\Json\JsonResource;
+use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
+use Illuminate\Support\Facades\Storage;
 
 class UserResource extends JsonResource
 {
-    /**
-     * Transform the resource into an array.
-     *
-     * @return array<string, mixed>
-     */
-    public function toArray(Request $request): array
-    {
-        return [
-            'id'                      => $this->id,
-            'name'                    => $this->name,
-            'email'                   => $this->email,
-            'phone'                   => $this->phone,
-            'language'                => $this->language,
-            'type'                    => $this->type,
-            'provider_id'             => $this->provider?->id,
-            'provider_daily_price_8h' => $this->provider?->daily_price_8h,
-            'provider_daily_price_6h' => $this->provider?->daily_price_6h,
-            'provider_daily_price_4h' => $this->provider?->daily_price_4h,
-            'provider_daily_price_2h' => $this->provider?->daily_price_2h,
-            'client_id'               => $this->client?->id,
-            'client_document'         => $this->client?->document,
-            'registration_complete'   => $this->registration_complete,
-            'provider'                => new ProviderResource($this->whenLoaded('provider')),
-            'client'                  => new ClientResource($this->whenLoaded('client')),
-            'created_at'              => Carbon::parse($this->created_at)->format('Y-m-d H:i'),
-            'updated_at'              => Carbon::parse($this->updated_at)->format('Y-m-d H:i'),
-        ];
-    }
+  /**
+   * Transform the resource into an array.
+   *
+   * @return array<string, mixed>
+   */
+  public function toArray(Request $request): array
+  {
+    return [
+      'id' => $this->id,
+      'name' => $this->name,
+      'email' => $this->email,
+      'phone' => $this->phone,
+      'language' => $this->language,
+      'type' => $this->type,
+      'provider_id' => $this->provider?->id,
+      'provider_daily_price_8h' => $this->provider?->daily_price_8h,
+      'provider_daily_price_6h' => $this->provider?->daily_price_6h,
+      'provider_daily_price_4h' => $this->provider?->daily_price_4h,
+      'provider_daily_price_2h' => $this->provider?->daily_price_2h,
+      'client_id' => $this->client?->id,
+      'profile_photo' => $this->resolveProfilePhoto(),
+      'client_document'         => $this->client?->document,
+      'registration_complete'   => $this->registration_complete,
+      'provider'                => new ProviderResource($this->whenLoaded('provider')),
+      'client'                  => new ClientResource($this->whenLoaded('client')),
+      'created_at' => Carbon::parse($this->created_at)->format('Y-m-d H:i'),
+      'updated_at' => Carbon::parse($this->updated_at)->format('Y-m-d H:i'),
+    ];
+  }
+
+  private function resolveProfilePhoto(): ?string
+  {
+    $path = $this->provider?->profileMedia?->path ?? $this->client?->profileMedia?->path;
+
+    return $path ? Storage::temporaryUrl($path, now()->addMinutes(60)) : null;
+  }
 
-    public static function collection($resource): AnonymousResourceCollection
-    {
-        return parent::collection($resource);
-    }
+  public static function collection($resource): AnonymousResourceCollection
+  {
+    return parent::collection($resource);
+  }
 }

+ 14 - 7
app/Services/AuthService.php

@@ -220,17 +220,20 @@ class AuthService
 
                     return ['error' => 'wrong_user_type'];
                 }
-                $provider = Provider::where('user_id', $user->id)->first();
-                if ($provider && $provider->approval_status->value !== ApprovalStatusEnum::ACCEPTED->value) {
-                    DB::rollBack();
 
-                    return ['error' => 'provider_not_accepted'];
+                if ($user->registration_complete) {
+                    $provider = Provider::where('user_id', $user->id)->first();
+                    if ($provider && $provider->approval_status->value !== ApprovalStatusEnum::ACCEPTED->value) {
+                        DB::rollBack();
+
+                        return ['error' => 'provider_not_accepted'];
+                    }
+                    $isLogin = true;
                 }
 
                 $user->code = $code;
                 $user->validated_code = false;
                 $user->save();
-                $isLogin = true;
             } else {
                 $user = new User;
                 $user->fill($data);
@@ -311,11 +314,15 @@ class AuthService
             $user->load('provider');
             $provider = $user->provider ?? null;
 
-            if ($provider && $provider->approval_status === ApprovalStatusEnum::PENDING->value) {
+            if (! $user->registration_complete || ! $provider) {
+                return ['error' => 'registration_incomplete'];
+            }
+
+            if ($provider->approval_status === ApprovalStatusEnum::PENDING->value) {
                 return ['error' => 'provider_pending'];
             }
 
-            if ($provider && $provider->approval_status === ApprovalStatusEnum::REJECTED->value) {
+            if ($provider->approval_status === ApprovalStatusEnum::REJECTED->value) {
                 return ['error' => 'provider_rejected'];
             }
 

+ 6 - 0
app/Services/CustomScheduleService.php

@@ -38,6 +38,7 @@ class CustomScheduleService
     {
         $customSchedule = CustomSchedule::with([
             'schedule.client.user',
+            'schedule.client.profileMedia',
             'schedule.address',
             'serviceType',
             'specialities.speciality',
@@ -303,6 +304,11 @@ class CustomScheduleService
                 $opportunity->address?->latitude !== null ? (float) $opportunity->address->latitude : null,
                 $opportunity->address?->longitude !== null ? (float) $opportunity->address->longitude : null,
             );
+
+            $photoPath = $opportunity->client->profileMedia?->path;
+            $opportunity->customer_photo = $photoPath
+                ? Storage::temporaryUrl($photoPath, now()->addMinutes(60))
+                : null;
         });
 
         return $availableOpportunities->values();

+ 10 - 2
app/Services/ProviderCalendarService.php

@@ -6,6 +6,7 @@ use App\Models\Provider;
 use App\Models\Schedule;
 use Illuminate\Support\Facades\Auth;
 use Illuminate\Support\Facades\DB;
+use Illuminate\Support\Facades\Storage;
 
 class ProviderCalendarService
 {
@@ -30,6 +31,7 @@ class ProviderCalendarService
             'schedules.address_id',
             'schedules.status',
             'custom_schedules.offers_meal',
+            DB::raw("(SELECT media.path FROM media WHERE media.source_id = clients.id AND media.source = 'client' AND media.deleted_at IS NULL LIMIT 1) as customer_photo"),
             DB::raw("EXISTS(
         SELECT 1 FROM reviews
         WHERE reviews.schedule_id = schedules.id
@@ -47,6 +49,10 @@ class ProviderCalendarService
       ) as provider_stars"),
         ];
 
+        $signPhoto = fn ($item) => tap($item, fn ($i) => $i->customer_photo = $i->customer_photo
+            ? Storage::temporaryUrl($i->customer_photo, now()->addMinutes(60))
+            : null);
+
         $upcomingSchedules = Schedule::with('address:district,address,number,source_id,source,id')
             ->where('schedules.provider_id', $provider->id)
             ->whereIn('schedules.status', ['pending', 'accepted', 'paid', 'started'])
@@ -57,7 +63,8 @@ class ProviderCalendarService
             ->select($selectFields)
             ->orderBy('schedules.date', 'asc')
             ->orderBy('schedules.start_time', 'asc')
-            ->get();
+            ->get()
+            ->map($signPhoto);
 
         $completedSchedules = Schedule::with('address:district,address,number,source_id,source,id')
             ->where('schedules.provider_id', $provider->id)
@@ -68,7 +75,8 @@ class ProviderCalendarService
             ->select($selectFields)
             ->orderBy('schedules.date', 'desc')
             ->orderBy('schedules.start_time', 'desc')
-            ->get();
+            ->get()
+            ->map($signPhoto);
 
         return [
             'upcomingSchedules'  => $upcomingSchedules,

+ 1 - 1
app/Services/ProviderClientBlockService.php

@@ -9,7 +9,7 @@ class ProviderClientBlockService
 {
     public function getByProviderId(int $providerId)
     {
-        return ProviderClientBlock::with(['client.user'])
+        return ProviderClientBlock::with(['client.user', 'client.profileMedia'])
             ->where('provider_id', $providerId)
             ->orderBy('created_at', 'desc')
             ->get();

+ 27 - 9
app/Services/ProviderService.php

@@ -169,9 +169,15 @@ class ProviderService
 
             $user->save();
 
-            $provider = new Provider;
+            $provider = Provider::withTrashed()->where('user_id', $user->id)->first();
+
+            if (! $provider) {
+                $provider = new Provider;
+                $provider->user_id = $user->id;
+            } elseif ($provider->trashed()) {
+                $provider->restore();
+            }
 
-            $provider->user_id = $user->id;
             $provider->rg = $data['rg'] ?? null;
             $provider->document = $this->sanitizeDigits($data['document'] ?? null);
             $provider->birth_date = $data['birth_date'] ?? null;
@@ -184,31 +190,35 @@ class ProviderService
             $provider->save();
 
             $provider->refresh();
+            $provider->load('profileMedia', 'documentFrontMedia', 'documentBackMedia');
 
-            $selfie = $this->mediaService->createFromFile(
-                file: $data['selfie'],
+            $selfie = $this->mediaService->replaceFile(
+                newFile: $data['selfie'],
                 folder: "provider/avatar/{$provider->id}",
                 source: 'provider',
                 sourceId: $provider->id,
+                old: $provider->profileMedia,
             );
 
             $provider->profile_media_id = $selfie->id;
 
-            $front = $this->mediaService->createFromFile(
-                file: $data['document_front'],
+            $front = $this->mediaService->replaceFile(
+                newFile: $data['document_front'],
                 folder: "provider/documentos/{$provider->id}",
                 source: 'provider_document',
                 sourceId: $provider->id,
+                old: $provider->documentFrontMedia,
                 filename: 'frente.'.$data['document_front']->getClientOriginalExtension(),
             );
 
             $provider->document_front_media_id = $front->id;
 
-            $back = $this->mediaService->createFromFile(
-                file: $data['document_back'],
+            $back = $this->mediaService->replaceFile(
+                newFile: $data['document_back'],
                 folder: "provider/documentos/{$provider->id}",
                 source: 'provider_document',
                 sourceId: $provider->id,
+                old: $provider->documentBackMedia,
                 filename: 'verso.'.$data['document_back']->getClientOriginalExtension(),
             );
 
@@ -216,18 +226,26 @@ class ProviderService
 
             $provider->save();
 
-            if (! empty($data['recipient_name']) && ! empty($data['recipient_default_bank_account'])) {
+            if (! empty($data['recipient_name']) && ! empty($data['recipient_default_bank_account']) && empty($provider->recipient_id)) {
                 $this->pagarmeRecipientService->createRecipientForProvider($provider, $data);
             }
 
+            Address::where('source', 'provider')->where('source_id', $provider->id)->delete();
             $this->createProviderAddress($provider->id, $data);
+
+            ProviderServicesType::where('provider_id', $provider->id)->delete();
             $this->createProviderServicesTypes($provider->id, $data);
+
+            ProviderWorkingDay::where('provider_id', $provider->id)->delete();
             $this->createProviderWorkingDays($provider->id, $data);
 
             if (empty($user->email) || empty($user->code)) {
                 throw new \Exception(__('messages.user_not_found_or_code_not_validated'));
             }
 
+            $user->registration_complete = true;
+            $user->save();
+
             $result = $this->authService->loginWithEmail(
                 email: $user->email,
                 code: $user->code,

+ 97 - 101
app/Services/ReviewService.php

@@ -43,115 +43,111 @@ class ReviewService
             ->get();
     }
 
-    public function create(array $data): Review
-    {
-        try {
-            DB::beginTransaction();
-
-            $review = new Review;
-
-            $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((float) $data['stars']);
-                        break;
-                    case 'provider':
-                        $schedule = Schedule::find($data['schedule_id']);
-                        $client = Client::find($schedule->client_id);
-
-                        $client->updateAverageRating((float) $data['stars']);
-                        break;
-                }
-            }
-
-            if (isset($data['improvements_ids'])) {
-                $review->improvements()->sync($data['improvements_ids']);
-            }
-
-            if (! empty($data['block_provider'])) {
-                $schedule = Schedule::find($data['schedule_id']);
-
-                $alreadyBlocked = ClientProviderBlock::where('client_id', $schedule->client_id)
-                    ->where('provider_id', $schedule->provider_id)
-                    ->whereNull('deleted_at')
-                    ->exists();
-
-                if (! $alreadyBlocked) {
-                    ClientProviderBlock::create([
-                        'client_id'   => $schedule->client_id,
-                        'provider_id' => $schedule->provider_id,
-                    ]);
-                }
-            }
-
-            if (! empty($data['block_client'])) {
-                $schedule = Schedule::find($data['schedule_id']);
-
-                $alreadyBlocked = ProviderClientBlock::where('provider_id', $schedule->provider_id)
-                    ->where('client_id', $schedule->client_id)
-                    ->whereNull('deleted_at')
-                    ->exists();
-
-                if (! $alreadyBlocked) {
-                    ProviderClientBlock::create([
-                        'provider_id' => $schedule->provider_id,
-                        'client_id'   => $schedule->client_id,
-                    ]);
-                }
-            }
+  public function create(array $data): Review
+  {
+    try {
+      DB::beginTransaction();
+      $review = new Review();
+      $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((float) $data['stars']);
+            break;
+          case 'provider':
+            $schedule = Schedule::find($data['schedule_id']);
+            $client = Client::find($schedule->client_id);
+
+            $client->updateAverageRating((float) $data['stars']);
+            break;
+        }
+      }
+      if (isset($data['improvements_ids'])) {
+        $review->improvements()->sync($data['improvements_ids']);
+      }
+  
+      if (! empty($data['block_provider'])) {
+        $schedule = Schedule::find($data['schedule_id']);
+
+        $alreadyBlocked = ClientProviderBlock::where('client_id', $schedule->client_id)
+          ->where('provider_id', $schedule->provider_id)
+          ->whereNull('deleted_at')
+          ->exists();
+
+        if (! $alreadyBlocked) {
+          ClientProviderBlock::create([
+            'client_id'   => $schedule->client_id,
+            'provider_id' => $schedule->provider_id,
+          ]);
+        }
+      }
 
-            if (! empty($data['favorite_provider'])) {
-                $schedule = Schedule::find($data['schedule_id']);
+      if (! empty($data['block_client'])) {
+        $schedule = Schedule::find($data['schedule_id']);
 
-                $alreadyFavorited = ClientFavoriteProvider::where('client_id', $schedule->client_id)
-                    ->where('provider_id', $schedule->provider_id)
-                    ->whereNull('deleted_at')
-                    ->exists();
+        $alreadyBlocked = ProviderClientBlock::where('provider_id', $schedule->provider_id)
+          ->where('client_id', $schedule->client_id)
+          ->whereNull('deleted_at')
+          ->exists();
 
-                if (! $alreadyFavorited) {
-                    ClientFavoriteProvider::create([
-                        'client_id'   => $schedule->client_id,
-                        'provider_id' => $schedule->provider_id,
-                    ]);
-                }
-            }
+        if (! $alreadyBlocked) {
+          ProviderClientBlock::create([
+            'provider_id' => $schedule->provider_id,
+            'client_id'   => $schedule->client_id,
+          ]);
+        }
+      }
 
-            if (! empty($data['photos'])) {
-                $schedule = Schedule::find($data['schedule_id']);
-                $origin = $data['origin'];
-
-                foreach ($data['photos'] as $photo) {
-                    $media = $this->mediaService->createFromFile(
-                        file: $photo,
-                        folder: "review/{$schedule->id}/{$origin}",
-                        source: 'review',
-                        sourceId: $review->id,
-                    );
-
-                    ReviewMedia::create([
-                        'review_id' => $review->id,
-                        'media_id'  => $media->id,
-                        'origin'    => $origin,
-                    ]);
-                }
-            }
+      if (! empty($data['favorite_provider'])) {
+        $schedule = Schedule::find($data['schedule_id']);
 
-            DB::commit();
+        $alreadyFavorited = ClientFavoriteProvider::where('client_id', $schedule->client_id)
+          ->where('provider_id', $schedule->provider_id)
+          ->whereNull('deleted_at')
+          ->exists();
 
-            return $review->load('reviewMedia.media');
-        } catch (Exception $e) {
-            DB::rollBack();
-            Log::error('Error creating review: '.$e->getMessage());
-            throw $e;
+        if (! $alreadyFavorited) {
+          ClientFavoriteProvider::create([
+            'client_id'   => $schedule->client_id,
+            'provider_id' => $schedule->provider_id,
+          ]);
+        }
+      }
+
+      if (! empty($data['photos'])) {
+        $schedule = Schedule::find($data['schedule_id']);
+        $origin = $data['origin'];
+
+        foreach ($data['photos'] as $photo) {
+          $media = $this->mediaService->createFromFile(
+            file: $photo,
+            folder: "review/{$schedule->id}/{$origin}",
+            source: 'review',
+            sourceId: $review->id,
+          );
+
+          ReviewMedia::create([
+            'review_id' => $review->id,
+            'media_id'  => $media->id,
+            'origin'    => $origin,
+          ]);
         }
+      }
+  
+      DB::commit();
+      return $review;
+    } catch (Exception $e) {
+      DB::rollBack();
+      Log::error('Error creating review: ' . $e->getMessage());
+      throw $e;
     }
+  }
 
     private function detailEagerLoads(): array
     {

+ 1 - 1
app/Services/SearchService.php

@@ -77,7 +77,7 @@ class SearchService
         ) as total_reviews"),
                 $distanceSelect,
             )
-            ->orderBy('providers.average_rating', 'desc');
+            ->orderByRaw('distance_km ASC NULLS LAST');
 
         $providers = (clone $baseQuery)
             ->when(

+ 2 - 1
lang/en/auth.php

@@ -26,5 +26,6 @@ return [
     'wrong_user_type'    => 'This email cannot access this application. Please contact support for more information.',
     // 'provider_pending' => 'Your registration is awaiting approval. We will contact you soon.',
     // 'provider_rejected' => 'Your registration was rejected. Please contact support.',
-    'provider_not_accepted' => 'Your registration has not been approved yet. Please wait or contact support for more information.',
+    'provider_not_accepted'   => 'Your registration has not been approved yet. Please wait or contact support for more information.',
+    'registration_incomplete' => 'Your registration is incomplete. Please finish the registration process.',
 ];

+ 2 - 1
lang/es/auth.php

@@ -26,5 +26,6 @@ return [
     'wrong_user_type'    => 'Este correo electrónico no puede acceder a esta aplicación. Contacte al soporte para más información.',
     // 'provider_pending' => 'Su registro está pendiente de aprobación. Nos pondremos en contacto pronto.',
     // 'provider_rejected' => 'Su registro fue rechazado. Póngase en contacto con el soporte.',
-    'provider_not_accepted' => 'Su registro aún no ha sido aprobado. Por favor, espere o póngase en contacto con el soporte para más información.',
+    'provider_not_accepted'   => 'Su registro aún no ha sido aprobado. Por favor, espere o póngase en contacto con el soporte para más información.',
+    'registration_incomplete' => 'Su registro está incompleto. Por favor, finalice el proceso de registro.',
 ];

+ 2 - 1
lang/pt/auth.php

@@ -26,5 +26,6 @@ return [
     'wrong_user_type'    => 'Este e-mail não pode acessar esse aplicativo. Entre em contato com o suporte para mais informações.',
     // 'provider_pending' => 'Seu cadastro está aguardando aprovação. Em breve entraremos em contato.',
     // 'provider_rejected' => 'Seu cadastro foi recusado. Entre em contato com o suporte.',
-    'provider_not_accepted' => 'Seu cadastro ainda não foi aprovado. Por favor, aguarde ou entre em contato com o suporte para mais informações.',
+    'provider_not_accepted'    => 'Seu cadastro ainda não foi aprovado. Por favor, aguarde ou entre em contato com o suporte para mais informações.',
+    'registration_incomplete'  => 'Seu cadastro está incompleto. Por favor, finalize o processo de cadastro.',
 ];

+ 8 - 9
routes/authRoutes/review.php

@@ -4,13 +4,12 @@ use App\Http\Controllers\ReviewController;
 use Illuminate\Support\Facades\Route;
 
 Route::get('/reviews', [ReviewController::class, 'index'])->middleware('permission:config.review,view');
-
-Route::get('/reviews/schedule/{scheduleId}',          [ReviewController::class, 'indexBySchedule'])->middleware('permission:config.review,view');
-Route::get('/reviews/client/{clientId}/sent',         [ReviewController::class, 'clientSent'])->middleware('permission:config.review,view');
-Route::get('/reviews/client/{clientId}/received',     [ReviewController::class, 'clientReceived'])->middleware('permission:config.review,view');
-Route::get('/reviews/provider/{providerId}/sent',     [ReviewController::class, 'providerSent'])->middleware('permission:config.review,view');
+Route::get('/reviews/schedule/{scheduleId}', [ReviewController::class, 'indexBySchedule'])->middleware('permission:config.review,view');
+Route::get('/reviews/client/{clientId}/sent', [ReviewController::class, 'clientSent'])->middleware('permission:config.review,view');
+Route::get('/reviews/client/{clientId}/received', [ReviewController::class, 'clientReceived'])->middleware('permission:config.review,view');
+Route::get('/reviews/provider/{providerId}/sent', [ReviewController::class, 'providerSent'])->middleware('permission:config.review,view');
 Route::get('/reviews/provider/{providerId}/received', [ReviewController::class, 'providerReceived'])->middleware('permission:config.review,view');
-Route::get('/reviews/{origin}/{originId}',            [ReviewController::class, 'indexByOrigin'])->middleware('permission:config.review,view');
-Route::post('/reviews',                               [ReviewController::class, 'store'])->middleware('permission:config.review,add');
-Route::put('/reviews/{id}',                           [ReviewController::class, 'update'])->middleware('permission:config.review,edit');
-Route::delete('/reviews/{id}',                        [ReviewController::class, 'destroy'])->middleware('permission:config.review,delete');
+Route::get('/reviews/{origin}/{originId}', [ReviewController::class, 'indexByOrigin'])->middleware('permission:config.review,view');
+Route::post('/reviews', [ReviewController::class, 'store'])->middleware('permission:config.review,add');
+Route::put('/reviews/{id}', [ReviewController::class, 'update'])->middleware('permission:config.review,edit');
+Route::delete('/reviews/{id}', [ReviewController::class, 'destroy'])->middleware('permission:config.review,delete');