feat/admin-portal #17
@@ -6,9 +6,9 @@ import { createPlanHandler } from '@/modules/admin/handlers/create-plan.handler'
|
|||||||
import { deletePlanHandler } from '@/modules/admin/handlers/delete-plan.handler';
|
import { deletePlanHandler } from '@/modules/admin/handlers/delete-plan.handler';
|
||||||
import { getUserSessionsHandler } from '@/modules/admin/handlers/get-user-sessions.handler';
|
import { getUserSessionsHandler } from '@/modules/admin/handlers/get-user-sessions.handler';
|
||||||
import { listComplexesHandler } from '@/modules/admin/handlers/list-complexes.handler';
|
import { listComplexesHandler } from '@/modules/admin/handlers/list-complexes.handler';
|
||||||
import { revokeAllSessionsHandler } from '@/modules/admin/handlers/revoke-all-sessions.handler';
|
|
||||||
import { listPlansAdminHandler } from '@/modules/admin/handlers/list-plans-admin.handler';
|
import { listPlansAdminHandler } from '@/modules/admin/handlers/list-plans-admin.handler';
|
||||||
import { listUsersHandler } from '@/modules/admin/handlers/list-users.handler';
|
import { listUsersHandler } from '@/modules/admin/handlers/list-users.handler';
|
||||||
|
import { revokeAllSessionsHandler } from '@/modules/admin/handlers/revoke-all-sessions.handler';
|
||||||
import { unblockUserHandler } from '@/modules/admin/handlers/unblock-user.handler';
|
import { unblockUserHandler } from '@/modules/admin/handlers/unblock-user.handler';
|
||||||
import { updatePlanHandler } from '@/modules/admin/handlers/update-plan.handler';
|
import { updatePlanHandler } from '@/modules/admin/handlers/update-plan.handler';
|
||||||
import type { AppEnv } from '@/types/hono';
|
import type { AppEnv } from '@/types/hono';
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { listAdminUsers } from '@/modules/admin/services/admin-users.service';
|
|||||||
import type { AppContext } from '@/types/hono';
|
import type { AppContext } from '@/types/hono';
|
||||||
|
|
||||||
export async function listUsersHandler(c: AppContext) {
|
export async function listUsersHandler(c: AppContext) {
|
||||||
const users = await listAdminUsers();
|
const search = c.req.query('search');
|
||||||
|
const users = await listAdminUsers(search);
|
||||||
return c.json(users);
|
return c.json(users);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,8 +13,16 @@ type AdminUser = {
|
|||||||
activeSessions: number;
|
activeSessions: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function listAdminUsers(): Promise<AdminUser[]> {
|
export async function listAdminUsers(search?: string): Promise<AdminUser[]> {
|
||||||
const users = await db.user.findMany({
|
const users = await db.user.findMany({
|
||||||
|
where: search
|
||||||
|
? {
|
||||||
|
OR: [
|
||||||
|
{ name: { contains: search, mode: 'insensitive' } },
|
||||||
|
{ email: { contains: search, mode: 'insensitive' } },
|
||||||
|
],
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
include: {
|
include: {
|
||||||
_count: {
|
_count: {
|
||||||
select: { complexes: true, sessions: true },
|
select: { complexes: true, sessions: true },
|
||||||
|
|||||||
@@ -21,10 +21,11 @@ import {
|
|||||||
LogIn,
|
LogIn,
|
||||||
Monitor,
|
Monitor,
|
||||||
RefreshCw,
|
RefreshCw,
|
||||||
|
Search,
|
||||||
ShieldAlert,
|
ShieldAlert,
|
||||||
Users,
|
Users,
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import { useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
function SessionsDialog({
|
function SessionsDialog({
|
||||||
user,
|
user,
|
||||||
@@ -284,10 +285,17 @@ export function UsersPage() {
|
|||||||
const [blockingUser, setBlockingUser] = useState<AdminUser | null>(null);
|
const [blockingUser, setBlockingUser] = useState<AdminUser | null>(null);
|
||||||
const [unblockingUser, setUnblockingUser] = useState<AdminUser | null>(null);
|
const [unblockingUser, setUnblockingUser] = useState<AdminUser | null>(null);
|
||||||
const [sessionsUser, setSessionsUser] = useState<AdminUser | null>(null);
|
const [sessionsUser, setSessionsUser] = useState<AdminUser | null>(null);
|
||||||
|
const [searchInput, setSearchInput] = useState('');
|
||||||
|
const [search, setSearch] = useState('');
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const timer = setTimeout(() => setSearch(searchInput), 300);
|
||||||
|
return () => clearTimeout(timer);
|
||||||
|
}, [searchInput]);
|
||||||
|
|
||||||
const { data, isLoading } = useQuery({
|
const { data, isLoading } = useQuery({
|
||||||
queryKey: ['admin-users'],
|
queryKey: ['admin-users', search],
|
||||||
queryFn: () => apiClient.admin.listUsers(),
|
queryFn: () => apiClient.admin.listUsers(search || undefined),
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -300,6 +308,16 @@ export function UsersPage() {
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<div className="relative">
|
||||||
|
<Search className="pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-muted-foreground" />
|
||||||
|
<Input
|
||||||
|
value={searchInput}
|
||||||
|
onChange={(e) => setSearchInput(e.target.value)}
|
||||||
|
placeholder="Buscar por nombre o email..."
|
||||||
|
className="h-9 w-56 rounded-xl pl-9 text-sm"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="icon"
|
size="icon"
|
||||||
@@ -309,6 +327,7 @@ export function UsersPage() {
|
|||||||
<RefreshCw className="size-4" />
|
<RefreshCw className="size-4" />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{blockingUser && <BlockDialog user={blockingUser} onClose={() => setBlockingUser(null)} />}
|
{blockingUser && <BlockDialog user={blockingUser} onClose={() => setBlockingUser(null)} />}
|
||||||
|
|
||||||
|
|||||||
@@ -51,8 +51,10 @@ export async function deletePlan(code: string) {
|
|||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function listUsers() {
|
export async function listUsers(search?: string) {
|
||||||
const response = await http.get<AdminUser[]>('/api/admin/users');
|
const response = await http.get<AdminUser[]>('/api/admin/users', {
|
||||||
|
params: search ? { search } : undefined,
|
||||||
|
});
|
||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user