From 01af999de1dbd74d01565392254377497de760c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Rafael=20Siqueira?= Date: Wed, 12 Nov 2025 17:13:10 -0300 Subject: [PATCH] add revoke --- .../app/routes/orgs/admins.py | 6 +- .../tests/routes/test_orgs.py | 3 +- .../routes/_.$orgid.admins._index/route.tsx | 153 +++++++++++++----- .../routes/_.$orgid.users._index/columns.tsx | 74 +++++---- 4 files changed, 154 insertions(+), 82 deletions(-) diff --git a/api.saladeaula.digital/app/routes/orgs/admins.py b/api.saladeaula.digital/app/routes/orgs/admins.py index 0011a1c..e63b88a 100644 --- a/api.saladeaula.digital/app/routes/orgs/admins.py +++ b/api.saladeaula.digital/app/routes/orgs/admins.py @@ -1,8 +1,6 @@ from http import HTTPStatus -from typing import Annotated from aws_lambda_powertools.event_handler.api_gateway import Router -from aws_lambda_powertools.event_handler.openapi.params import Body from layercake.dynamodb import DynamoDBPersistenceLayer, KeyPair from api_gateway import JSONResponse @@ -22,8 +20,8 @@ def get_admins(org_id: str): ) -@router.delete('//admins') -def revoke(org_id: str, user_id: Annotated[str, Body(embed=True)]): +@router.delete('//admins/') +def revoke(org_id: str, user_id: str): with dyn.transact_writer() as transact: transact.delete( # Post-migration: rename `admins` to `ADMIN` diff --git a/api.saladeaula.digital/tests/routes/test_orgs.py b/api.saladeaula.digital/tests/routes/test_orgs.py index 9a78f23..b107ae9 100644 --- a/api.saladeaula.digital/tests/routes/test_orgs.py +++ b/api.saladeaula.digital/tests/routes/test_orgs.py @@ -34,9 +34,8 @@ def test_revoke( ): r = app.lambda_handler( http_api_proxy( - raw_path='/orgs/f6000f79-6e5c-49a0-952f-3bda330ef278/admins', + raw_path='/orgs/f6000f79-6e5c-49a0-952f-3bda330ef278/admins/15bacf02-1535-4bee-9022-19d106fd7518', method=HTTPMethod.DELETE, - body={'user_id': '15bacf02-1535-4bee-9022-19d106fd7518'}, ), lambda_context, ) diff --git a/apps/admin.saladeaula.digital/app/routes/_.$orgid.admins._index/route.tsx b/apps/admin.saladeaula.digital/app/routes/_.$orgid.admins._index/route.tsx index 0e59c7b..933d968 100644 --- a/apps/admin.saladeaula.digital/app/routes/_.$orgid.admins._index/route.tsx +++ b/apps/admin.saladeaula.digital/app/routes/_.$orgid.admins._index/route.tsx @@ -1,16 +1,29 @@ import type { Route } from './+types' +import { useToggle } from 'ahooks' import { EllipsisVerticalIcon, PencilIcon, UserRoundMinusIcon } from 'lucide-react' import { Suspense } from 'react' -import { Await, NavLink } from 'react-router' +import { Await, NavLink, useParams, useRevalidator } from 'react-router' +import { toast } from 'sonner' import { Abbr } from '@/components/abbr' import { request as req } from '@/lib/request' import { Skeleton } from '@repo/ui/components/skeleton' +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, + AlertDialogTrigger +} from '@repo/ui/components/ui/alert-dialog' import { Avatar, AvatarFallback } from '@repo/ui/components/ui/avatar' import { Button } from '@repo/ui/components/ui/button' import { @@ -22,19 +35,25 @@ import { import { Spinner } from '@repo/ui/components/ui/spinner' import { initials } from '@repo/ui/lib/utils' +type Admin = { + sk: string + name: string + email: string +} + export function meta({}: Route.MetaArgs) { return [{ title: 'Gestores' }] } export async function loader({ context, request, params }: Route.LoaderArgs) { - const data = req({ + const admins = req({ url: `/orgs/${params.orgid}/admins`, context, request }).then((r) => r.json()) return { - data + data: admins } } @@ -53,48 +72,20 @@ export default function Route({ loaderData: { data } }) { {({ items }) => { return (
- {items.map(({ sk, name, email }, index) => { + {items.map(({ sk, name, email }: Admin) => { const [_, id] = sk.split('#') + return (
- - - - - - e.preventDefault()} - > - - {({ isPending }) => ( - <> - {isPending ? : } - Editar - - )} - - - - Revogar privilégios - - - - -
+ +
@@ -124,3 +115,83 @@ export default function Route({ loaderData: { data } }) { ) } + +function ActionMenu({ id }: { id: string }) { + return ( + + + + + + e.preventDefault()}> + + {({ isPending }) => ( + <> + {isPending ? : } + Editar + + )} + + + + + + ) +} + +function RevokeItem({ id }: { id: string }) { + const [loading, { set }] = useToggle(false) + const { orgid } = useParams() + const { revalidate } = useRevalidator() + + const revoke = async (e: MouseEvent) => { + e.preventDefault() + set(true) + + const r = await fetch(`/~/api/orgs/${orgid}/admins/${id}`, { + method: 'DELETE' + }) + + if (r.ok) { + toast.info('Os privilégios foram revogados') + revalidate() + } + } + + return ( + + + e.preventDefault()} + > + Revogar privilégios + + + + + Tem certeza absoluta? + + Esta ação não pode ser desfeita. Isso revogará permanentemente os + privilégios deste gestor. + + + + Cancelar + + + + + + + ) +} diff --git a/apps/admin.saladeaula.digital/app/routes/_.$orgid.users._index/columns.tsx b/apps/admin.saladeaula.digital/app/routes/_.$orgid.users._index/columns.tsx index 0f44d23..0c2c3ff 100644 --- a/apps/admin.saladeaula.digital/app/routes/_.$orgid.users._index/columns.tsx +++ b/apps/admin.saladeaula.digital/app/routes/_.$orgid.users._index/columns.tsx @@ -1,7 +1,7 @@ 'use client' import { formatCPF } from '@brazilian-utils/brazilian-utils' -import { type ColumnDef } from '@tanstack/react-table' +import { type ColumnDef, type RowData } from '@tanstack/react-table' import { useToggle } from 'ahooks' import { EllipsisVerticalIcon, @@ -113,55 +113,59 @@ export const columns: ColumnDef[] = [ }, { id: 'actions', - cell: ({ row }) => ( -
- - - - - - e.preventDefault()}> - - {({ isPending }) => ( - <> - {isPending ? : } - Editar - - )} - - - - - -
- ) + cell: ({ row }) => } ] -function UnlinkMenuItem({ userId }: { userId: string }) { +function ActionMenu({ row }: { row: any }) { + return ( +
+ + + + + + e.preventDefault()}> + + {({ isPending }) => ( + <> + {isPending ? : } + Editar + + )} + + + + + +
+ ) +} + +function UnlinkItem({ id }: { id: string }) { const [loading, { set }] = useToggle(false) const { orgid } = useParams() const { table } = useDataTable() - const unlink = async (e) => { + const unlink = async (e: MouseEvent) => { e.preventDefault() set(true) - const r = await fetch(`/~/api/orgs/${orgid}/users/${userId}`, { + const r = await fetch(`/~/api/orgs/${orgid}/users/${id}`, { method: 'DELETE' }) if (r.ok) { toast.info('O colaborador foi desvinculado') // @ts-ignore - table.options.meta?.removeRow?.(userId) + table.options.meta?.removeRow?.(id) } } @@ -184,7 +188,7 @@ function UnlinkMenuItem({ userId }: { userId: string }) { - Cancel + Cancelar