applyLeaveDateForStatus($validated); } /** * Prepare data for update method */ protected function prepareUpdateData(array $validated, $user): array { unset($validated['uuid']); if (! array_key_exists('email', $validated)) { unset($validated['email']); } return $this->applyLeaveDateForStatus($validated, $user); } /** * Set or clear leave_date based on membership status transitions. */ protected function applyLeaveDateForStatus(array $validated, ?User $user = null): array { $newStatus = $validated['status'] ?? $user?->status; $currentStatus = $user?->status; if ($newStatus === 'inactive') { if ($currentStatus !== 'inactive') { $validated['leave_date'] = $validated['leave_date'] ?? now()->toDateString(); } } elseif (in_array($newStatus, ['active', 'pending'], true)) { $validated['leave_date'] = null; } return $validated; } /** * Check dependencies before deletion */ protected function checkDependencies($user): ?JsonResponse { return null; } public function assignRoles(Request $request, $id): JsonResponse { $request->validate([ 'roles' => 'required|array', 'roles.*' => 'exists:roles,id,guard_name,api', ]); $result = $this->userService->assignRoles($id, $request->roles); if (isset($result['error'])) { $status = $result['error'] === 'User not found.' ? 404 : 400; return response()->json([ 'success' => false, 'message' => $result['error'], ], $status); } return response()->json([ 'success' => true, 'message' => 'Roles assigned successfully.', 'data' => (new UserResource($result['user']))->resolve(), ]); } public function updateProfile(Request $request): JsonResponse { $user = $request->user(); $validated = $request->validate([ 'name' => 'sometimes|string|max:255', 'ic_number' => 'sometimes|string|max:255|unique:users,ic_number,'.$user->id, 'position' => 'sometimes|string|max:255', 'phone_number' => 'sometimes|string|max:255', 'image' => 'sometimes|image|mimes:jpeg,png,jpg,gif|max:2048', 'image_url' => 'sometimes|string|max:255', 'gender' => 'sometimes|string|max:255', 'marriage_status' => 'sometimes|string|max:255', 'member_number' => 'sometimes|integer', 'member_type' => 'sometimes|string|max:255', 'join_date' => 'sometimes|date', 'birth_date' => 'sometimes|date', 'birth_place' => 'sometimes|string|max:255', ]); $user = $this->userService->updateProfile( $user, $validated, $request->file('image') ); return response()->json([ 'success' => true, 'data' => new UserResource($user), 'message' => 'Profile updated successfully.', ]); } public function completeOnboarding(Request $request): JsonResponse { $user = $this->userService->completeOnboarding($request->user()); return response()->json([ 'success' => true, 'data' => new UserResource($user), 'message' => 'Onboarding completed.', ]); } public function updatePassword(Request $request): JsonResponse { $user = $request->user(); $validated = $request->validate([ 'current_password' => 'required|string', 'password' => 'required|string|min:8|confirmed', ]); $result = $this->userService->updatePassword( $user, $validated['current_password'], $validated['password'] ); if (isset($result['error'])) { return response()->json([ 'success' => false, 'message' => $result['error'], ], 400); } return response()->json([ 'success' => true, 'message' => 'Password updated successfully.', ]); } public function index(Request $request): JsonResponse { $this->authorize('viewAny', $this->modelClass); try { $request->validate([ 'join_date_from' => 'nullable|date', 'join_date_to' => 'nullable|date', 'leave_date_from' => 'nullable|date', 'leave_date_to' => 'nullable|date', ]); $perPage = min((int) $request->get('per_page', 10), 500); $dateFilters = array_filter([ 'join_date_from' => $request->get('join_date_from'), 'join_date_to' => $request->get('join_date_to'), 'leave_date_from' => $request->get('leave_date_from'), 'leave_date_to' => $request->get('leave_date_to'), ]); $items = $this->userService->getPaginatedList( $perPage, $request->get('search', ''), $request->get('status', ''), $request->get('sort_by', 'id'), $request->get('sort_order', 'asc'), $dateFilters ); return response()->json([ 'success' => true, 'data' => UserListResource::collection($items->items()), 'pagination' => [ 'current_page' => $items->currentPage(), 'per_page' => $items->perPage(), 'total' => $items->total(), 'last_page' => $items->lastPage(), 'from' => $items->firstItem(), 'to' => $items->lastItem(), 'has_more_pages' => $items->hasMorePages(), ], 'message' => $this->getSuccessMessage('index'), ]); } catch (Exception $e) { Log::error("Error fetching {$this->resourceNamePlural}: ".$e->getMessage()); return $this->errorResponse($this->getErrorMessage('index'), 500); } } public function deletedIndex(Request $request): JsonResponse { $this->authorize('viewAny', $this->modelClass); try { $perPage = min((int) $request->get('per_page', 10), 500); $items = $this->userService->getDeletedPaginatedList( $perPage, $request->get('search', ''), $request->get('status', ''), $request->get('sort_by', 'deleted_at'), $request->get('sort_order', 'desc') ); return response()->json([ 'success' => true, 'data' => UserListResource::collection($items->items()), 'pagination' => [ 'current_page' => $items->currentPage(), 'per_page' => $items->perPage(), 'total' => $items->total(), 'last_page' => $items->lastPage(), 'from' => $items->firstItem(), 'to' => $items->lastItem(), 'has_more_pages' => $items->hasMorePages(), ], 'message' => 'Deleted users retrieved successfully.', ]); } catch (Exception $e) { Log::error("Error fetching deleted {$this->resourceNamePlural}: ".$e->getMessage()); return $this->errorResponse('Failed to retrieve deleted users.', 500); } } public function stats(Request $request): JsonResponse { $this->authorize('viewAny', $this->modelClass); try { $request->validate([ 'join_date_from' => 'nullable|date', 'join_date_to' => 'nullable|date', 'leave_date_from' => 'nullable|date', 'leave_date_to' => 'nullable|date', ]); $dateFilters = array_filter([ 'join_date_from' => $request->get('join_date_from'), 'join_date_to' => $request->get('join_date_to'), 'leave_date_from' => $request->get('leave_date_from'), 'leave_date_to' => $request->get('leave_date_to'), ]); $stats = $this->userService->getListStats( $request->get('search', ''), $request->get('status', ''), $dateFilters ); return response()->json([ 'success' => true, 'data' => $stats, 'message' => 'User stats retrieved successfully.', ]); } catch (Exception $e) { Log::error("Error fetching {$this->resourceNamePlural} stats: ".$e->getMessage()); return $this->errorResponse('Failed to retrieve user stats.', 500); } } public function restore(string $id): JsonResponse { $this->authorize('restore', $this->modelClass); try { $user = $this->userService->restoreUser($id); if (! $user) { return response()->json([ 'success' => false, 'message' => 'Deleted user not found.', ], 404); } ActivityLogger::log("Restored {$this->resourceName}: {$user->name}", $user); return response()->json([ 'success' => true, 'message' => 'User restored successfully.', 'data' => (new UserListResource($user))->resolve(), ]); } catch (Exception $e) { Log::error("Error restoring {$this->resourceName}: ".$e->getMessage()); return $this->errorResponse('Failed to restore user.', 500); } } public function show($id): JsonResponse { $this->authorize('view', $this->modelClass); try { $user = $this->userService->getUserWithRelations($id); if (! $user) { return response()->json([ 'success' => false, 'message' => 'User not found.', ], 404); } return response()->json([ 'success' => true, 'data' => new UserResource($user), 'message' => 'User retrieved successfully.', ]); } catch (Exception $e) { Log::error('Error fetching user: '.$e->getMessage()); return $this->errorResponse('Failed to retrieve user.', 500); } } }