7 Commits d2751c3584 ... e6730879a0

Author SHA1 Message Date
  joycekepler e6730879a0 Merge branch 'feature/SERPRATI-JOY-868kf2642-alteracoes-associado' of Softpar/sfp_api_laravel_serprati into development 6 days ago
  joykepler c1f407f285 feat: :sparkles: adicionar 'first_access_at' para acesso de app 6 days ago
  joycekepler 49488f8633 Merge branch 'feature/SERPRATI-JOY-868kf24hh-alteracoes-administrador' of Softpar/sfp_api_laravel_serprati into development 6 days ago
  joykepler 616d631367 feat: :sparkles: adicionar numero de pessoas que ja acessaram o app 6 days ago
  joykepler a6238cf0b6 fix: :bug: habilitar extensao unaccent no postgres 6 days ago
  joykepler 0fab913066 feat: :sparkles: adicionar aprovacao de usuario, position_id e sector_id 6 days ago
  joykepler e650998804 chore: :see_no_evil: atualizar gitignore 1 week ago

+ 3 - 0
.gitignore

@@ -55,3 +55,6 @@ Thumbs.db
 
 # Meta
 .phpstorm.meta.php
+
+# Claude Code
+CLAUDE.md

+ 15 - 1
app/Http/Controllers/UserController.php

@@ -68,7 +68,7 @@ class UserController extends Controller
 
     public function indexPaginated(Request $request): JsonResponse
     {
-        $filters = $request->only(['type', 'status', 'search']);
+        $filters = $request->only(['type', 'status', 'search', 'position_id', 'sector_id']);
         $perPage = min((int) $request->get('per_page', 10), 100);
         $paginator = $this->service->getAllPaginated($filters, $perPage);
 
@@ -144,4 +144,18 @@ class UserController extends Controller
             message: __("messages.updated"),
         );
     }
+
+    public function approve(int $id): JsonResponse
+    {
+        $item = $this->service->approve($id);
+
+        if (!$item) {
+            return $this->errorResponse(message: __('messages.not_found'), code: 404);
+        }
+
+        return $this->successResponse(
+            payload: new UserResource($item),
+            message: __("messages.updated"),
+        );
+    }
 }

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

@@ -38,6 +38,9 @@ class UserResource extends JsonResource
                                                 : null,
             'on_leave_at'                => $this->on_leave_at?->format('Y-m-d H:i:s'),
             'on_leave_by_user_id'        => $this->on_leave_by_user_id,
+            'first_access_at'            => $this->access_logs_min_accessed_at
+                                                ? Carbon::parse($this->access_logs_min_accessed_at)->format('Y-m-d H:i:s')
+                                                : null,
             'unread_notifications_count' => (int) ($this->unread_notifications_count ?? 0),
             'created_at'                 => Carbon::parse($this->created_at)->format('Y-m-d H:i:s'),
             'updated_at'                 => Carbon::parse($this->updated_at)->format('Y-m-d H:i:s'),

+ 3 - 0
app/Services/DashboardService.php

@@ -24,6 +24,9 @@ class DashboardService
       'novos_mes'           => PartnerAgreement::whereMonth('created_at', now()->month)->whereYear('created_at', now()->year)->count(),
       'associados_pendentes' => User::where('type', UserTypeEnum::ASSOCIADO)->where('status', UserStatusEnum::PENDING)->count(),
       'ultimos_acessos'     => UserAccessLog::distinct('user_id')->count('user_id'),
+      'associados_com_acesso_app' => UserAccessLog::whereHas('user', fn ($q) => $q->where('type', UserTypeEnum::ASSOCIADO))
+        ->distinct('user_id')
+        ->count('user_id'),
     ];
   }
 

+ 21 - 1
app/Services/UserService.php

@@ -24,7 +24,7 @@ class UserService
 
     public function getAllPaginated(array $filters = [], int $perPage = 10): \Illuminate\Pagination\LengthAwarePaginator
     {
-        $query = User::with(['position', 'sector'])->orderBy('name', 'asc');
+        $query = User::with(['position', 'sector'])->withMin('accessLogs', 'accessed_at')->orderBy('name', 'asc');
 
         if (!empty($filters['type'])) {
             $query->where('type', $filters['type']);
@@ -34,6 +34,14 @@ class UserService
             $query->where('status', $filters['status']);
         }
 
+        if (!empty($filters['position_id'])) {
+            $query->where('position_id', $filters['position_id']);
+        }
+
+        if (!empty($filters['sector_id'])) {
+            $query->where('sector_id', $filters['sector_id']);
+        }
+
         if (!empty($filters['search'])) {
             $term = '%' . mb_strtolower($filters['search']) . '%';
             $query->where(function ($q) use ($term) {
@@ -106,6 +114,18 @@ class UserService
         return $model->fresh();
     }
 
+    public function approve(int $id): ?User
+    {
+        $model = $this->findById($id);
+        if (!$model) return null;
+
+        $model->update([
+            'status' => UserStatusEnum::ACTIVE,
+        ]);
+
+        return $model->fresh();
+    }
+
     public function getUserTypes(): array
     {
         return UserTypeEnum::toArray();

+ 17 - 0
database/migrations/2026_07_22_000001_enable_unaccent_extension.php

@@ -0,0 +1,17 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Support\Facades\DB;
+
+return new class extends Migration
+{
+    public function up(): void
+    {
+        DB::statement('CREATE EXTENSION IF NOT EXISTS unaccent');
+    }
+
+    public function down(): void
+    {
+        DB::statement('DROP EXTENSION IF EXISTS unaccent');
+    }
+};

+ 2 - 0
routes/authRoutes/user.php

@@ -27,4 +27,6 @@ Route::controller(UserController::class)->prefix('user')->group(function () {
     Route::delete('/my/avatar', 'deleteAvatar');
 
     Route::put('/{id}/on-leave', 'setOnLeave')->middleware('permission:config.user,edit');
+
+    Route::put('/{id}/approve', 'approve')->middleware('permission:config.user,edit');
 });