Skip to content

Commit 3c2a389

Browse files
authored
Feature: Add admin accounts search (#872)
1 parent e055f2e commit 3c2a389

File tree

14 files changed

+340
-10
lines changed

14 files changed

+340
-10
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace HiEvents\Http\Actions\Admin\Events;
6+
7+
use HiEvents\DomainObjects\Enums\Role;
8+
use HiEvents\Http\Actions\BaseAction;
9+
use HiEvents\Resources\Event\EventResource;
10+
use HiEvents\Services\Application\Handlers\Admin\DTO\GetUpcomingEventsDTO;
11+
use HiEvents\Services\Application\Handlers\Admin\GetUpcomingEventsHandler;
12+
use Illuminate\Http\JsonResponse;
13+
use Illuminate\Http\Request;
14+
15+
class GetUpcomingEventsAction extends BaseAction
16+
{
17+
public function __construct(
18+
private readonly GetUpcomingEventsHandler $handler,
19+
)
20+
{
21+
}
22+
23+
public function __invoke(Request $request): JsonResponse
24+
{
25+
$this->minimumAllowedRole(Role::SUPERADMIN);
26+
27+
$events = $this->handler->handle(new GetUpcomingEventsDTO(
28+
perPage: min((int)$request->query('per_page', 20), 100),
29+
));
30+
31+
return $this->resourceResponse(
32+
resource: EventResource::class,
33+
data: $events
34+
);
35+
}
36+
}

backend/app/Repository/Eloquent/AccountRepository.php

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,19 @@ public function getAllAccountsWithCounts(?string $search, int $perPage): LengthA
3737
{
3838
$query = $this->model
3939
->select('accounts.*')
40-
->withCount(['events', 'users']);
40+
->withCount(['events', 'users'])
41+
->with(['users' => function ($query) {
42+
$query->select('users.id', 'users.first_name', 'users.last_name', 'users.email')
43+
->withPivot('role');
44+
}]);
4145

4246
if ($search) {
4347
$query->where(function ($q) use ($search) {
44-
$q->where('name', 'like', "%{$search}%")
45-
->orWhere('email', 'like', "%{$search}%");
48+
$q->where('accounts.name', 'like', "{$search}%")
49+
->orWhere('accounts.email', 'like', "{$search}%")
50+
->orWhereHas('users', function ($userQuery) use ($search) {
51+
$userQuery->where('users.email', 'like', "{$search}%");
52+
});
4653
});
4754
}
4855

backend/app/Repository/Eloquent/EventRepository.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,22 @@ public function findEvents(array $where, QueryParamsDTO $params): LengthAwarePag
8383
page: $params->page,
8484
);
8585
}
86+
87+
public function getUpcomingEventsForAdmin(int $perPage): LengthAwarePaginator
88+
{
89+
$now = now();
90+
$next24Hours = now()->addDay();
91+
92+
return $this->handleResults($this->model
93+
->select('events.*')
94+
->with(['account', 'organizer'])
95+
->where(EventDomainObjectAbstract::START_DATE, '>=', $now)
96+
->where(EventDomainObjectAbstract::START_DATE, '<=', $next24Hours)
97+
->whereIn(EventDomainObjectAbstract::STATUS, [
98+
EventStatus::LIVE->name,
99+
EventStatus::DRAFT->name,
100+
])
101+
->orderBy(EventDomainObjectAbstract::START_DATE, 'asc')
102+
->paginate($perPage));
103+
}
86104
}

backend/app/Repository/Interfaces/EventRepositoryInterface.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,6 @@ interface EventRepositoryInterface extends RepositoryInterface
1717
public function findEventsForOrganizer(int $organizerId, int $accountId, QueryParamsDTO $params): LengthAwarePaginator;
1818

1919
public function findEvents(array $where, QueryParamsDTO $params): LengthAwarePaginator;
20+
21+
public function getUpcomingEventsForAdmin(int $perPage): LengthAwarePaginator;
2022
}

backend/app/Resources/Account/AdminAccountResource.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,15 @@ public function toArray(Request $request): array
1818
'created_at' => $this->resource->created_at,
1919
'events_count' => $this->resource->events_count ?? 0,
2020
'users_count' => $this->resource->users_count ?? 0,
21+
'users' => $this->resource->users->map(function ($user) {
22+
return [
23+
'id' => $user->id,
24+
'first_name' => $user->first_name,
25+
'last_name' => $user->last_name,
26+
'email' => $user->email,
27+
'role' => $user->pivot->role,
28+
];
29+
}),
2130
];
2231
}
2332
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
namespace HiEvents\Services\Application\Handlers\Admin\DTO;
4+
5+
use HiEvents\DataTransferObjects\BaseDataObject;
6+
7+
class GetUpcomingEventsDTO extends BaseDataObject
8+
{
9+
public function __construct(
10+
public readonly int $perPage = 20,
11+
)
12+
{
13+
}
14+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
namespace HiEvents\Services\Application\Handlers\Admin;
4+
5+
use HiEvents\Repository\Interfaces\EventRepositoryInterface;
6+
use HiEvents\Services\Application\Handlers\Admin\DTO\GetUpcomingEventsDTO;
7+
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
8+
9+
class GetUpcomingEventsHandler
10+
{
11+
public function __construct(
12+
private readonly EventRepositoryInterface $eventRepository,
13+
)
14+
{
15+
}
16+
17+
public function handle(GetUpcomingEventsDTO $dto): LengthAwarePaginator
18+
{
19+
return $this->eventRepository->getUpcomingEventsForAdmin($dto->perPage);
20+
}
21+
}

backend/routes/api.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@
151151
use HiEvents\Http\Actions\Users\UpdateMeAction;
152152
use HiEvents\Http\Actions\Users\UpdateUserAction;
153153
use HiEvents\Http\Actions\Admin\Accounts\GetAllAccountsAction;
154+
use HiEvents\Http\Actions\Admin\Events\GetUpcomingEventsAction;
154155
use HiEvents\Http\Actions\Admin\Stats\GetAdminStatsAction;
155156
use HiEvents\Http\Actions\Admin\Users\GetAllUsersAction;
156157
use HiEvents\Http\Actions\Admin\Users\StartImpersonationAction;
@@ -373,6 +374,7 @@ function (Router $router): void {
373374
$router->get('/stats', GetAdminStatsAction::class);
374375
$router->get('/accounts', GetAllAccountsAction::class);
375376
$router->get('/users', GetAllUsersAction::class);
377+
$router->get('/events/upcoming', GetUpcomingEventsAction::class);
376378
$router->post('/impersonate/{user_id}', StartImpersonationAction::class);
377379
$router->post('/stop-impersonation', StopImpersonationAction::class);
378380
}

frontend/src/api/admin.client.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {api} from "./client";
2-
import {GenericDataResponse, GenericPaginatedResponse, IdParam, User} from "../types";
2+
import {GenericPaginatedResponse, IdParam, User} from "../types";
33

44
export interface AdminUser extends User {
55
accounts?: AccountWithRole[];
@@ -12,6 +12,14 @@ export interface AccountWithRole {
1212
role: string;
1313
}
1414

15+
export interface AdminAccountUser {
16+
id: IdParam;
17+
first_name: string;
18+
last_name: string;
19+
email: string;
20+
role: string;
21+
}
22+
1523
export interface AdminAccount {
1624
id: IdParam;
1725
name: string;
@@ -21,6 +29,7 @@ export interface AdminAccount {
2129
created_at: string;
2230
events_count: number;
2331
users_count: number;
32+
users: AdminAccountUser[];
2433
}
2534

2635
export interface AdminStats {
@@ -86,6 +95,15 @@ export const adminClient = {
8695
return response.data;
8796
},
8897

98+
getUpcomingEvents: async (perPage: number = 10) => {
99+
const response = await api.get<GenericPaginatedResponse<any>>('admin/events/upcoming', {
100+
params: {
101+
per_page: perPage,
102+
}
103+
});
104+
return response.data;
105+
},
106+
89107
startImpersonation: async (userId: IdParam, accountId: IdParam) => {
90108
const response = await api.post<StartImpersonationResponse>(
91109
`admin/impersonate/${userId}`,

frontend/src/components/common/AdminAccountsTable/AdminAccountsTable.module.scss

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,35 @@
8383
text-align: center;
8484
padding: 3rem 1rem;
8585
}
86+
87+
.usersSection {
88+
padding-top: 1rem;
89+
border-top: 1px solid var(--mantine-color-default-border);
90+
}
91+
92+
.usersList {
93+
display: flex;
94+
flex-direction: column;
95+
gap: 0.75rem;
96+
}
97+
98+
.userItem {
99+
display: flex;
100+
justify-content: space-between;
101+
align-items: center;
102+
padding: 0.75rem;
103+
background: var(--mantine-color-gray-0);
104+
border-radius: var(--mantine-radius-sm);
105+
transition: background-color 0.2s;
106+
107+
&:hover {
108+
background: var(--mantine-color-gray-1);
109+
}
110+
}
111+
112+
.userDetails {
113+
display: flex;
114+
flex-direction: column;
115+
gap: 0.25rem;
116+
flex: 1;
117+
}

0 commit comments

Comments
 (0)