test promise

This commit is contained in:
2025-11-12 19:59:39 -03:00
parent 01af999de1
commit b5e0684de7
8 changed files with 42 additions and 23 deletions

View File

@@ -20,6 +20,11 @@ def get_admins(org_id: str):
) )
@router.post('/<org_id>/admins')
def add(org_id: str):
return JSONResponse(HTTPStatus.CREATED)
@router.delete('/<org_id>/admins/<user_id>') @router.delete('/<org_id>/admins/<user_id>')
def revoke(org_id: str, user_id: str): def revoke(org_id: str, user_id: str):
with dyn.transact_writer() as transact: with dyn.transact_writer() as transact:
@@ -28,4 +33,4 @@ def revoke(org_id: str, user_id: str):
key=KeyPair(org_id, f'admins#{user_id}'), key=KeyPair(org_id, f'admins#{user_id}'),
) )
return JSONResponse(status_code=HTTPStatus.NO_CONTENT) return JSONResponse(HTTPStatus.NO_CONTENT)

View File

@@ -78,6 +78,11 @@ def unlink(org_id: str, user_id: str):
sk=user_id, sk=user_id,
) )
) )
transact.delete(
key=KeyPair(org_id, f'admins#{user_id}'),
# Post-migration: uncomment the following line
# key=KeyPair(org_id, f'ADMIN#{user_id}'),
)
transact.delete( transact.delete(
key=KeyPair( key=KeyPair(
pk=user_id, pk=user_id,

View File

@@ -68,12 +68,12 @@ export function RangeCalendarFilter({
<Popover> <Popover>
<div <div
className={cn( className={cn(
'h-9 border rounded-md bg-muted border-dashed flex items-center justify-center', 'h-9 border rounded-md dark:bg-input/30 border-dashed flex items-center justify-center',
className className
)} )}
> >
<PopoverTrigger asChild> <PopoverTrigger asChild>
<Button variant="ghost" size="sm" className="cursor-pointer"> <Button variant="ghost" size="sm" className="cursor-pointer h-full">
<Icon /> {title} <Icon /> {title}
{dateRange && ( {dateRange && (
<> <>

View File

@@ -46,14 +46,14 @@ export function meta({}: Route.MetaArgs) {
} }
export async function loader({ context, request, params }: Route.LoaderArgs) { export async function loader({ context, request, params }: Route.LoaderArgs) {
const admins = req({ const users = req({
url: `/orgs/${params.orgid}/admins`, url: `/orgs/${params.orgid}/admins`,
context, context,
request request
}).then((r) => r.json()) }).then((r) => r.json())
return { return {
data: admins data: Promise.all([users, new Promise((r) => setTimeout(r, 5000))])
} }
} }
@@ -69,7 +69,7 @@ export default function Route({ loaderData: { data } }) {
<Suspense fallback={<Skeleton />}> <Suspense fallback={<Skeleton />}>
<Await resolve={data}> <Await resolve={data}>
{({ items }) => { {([{ items }, _]) => {
return ( return (
<div className="grid gap-4 lg:gap-8 md:grid-cols-2 lg:grid-cols-3"> <div className="grid gap-4 lg:gap-8 md:grid-cols-2 lg:grid-cols-3">
{items.map(({ sk, name, email }: Admin) => { {items.map(({ sk, name, email }: Admin) => {
@@ -151,7 +151,7 @@ function RevokeItem({ id }: { id: string }) {
const { orgid } = useParams() const { orgid } = useParams()
const { revalidate } = useRevalidator() const { revalidate } = useRevalidator()
const revoke = async (e: MouseEvent) => { const revoke = async (e) => {
e.preventDefault() e.preventDefault()
set(true) set(true)

View File

@@ -8,12 +8,11 @@ import {
FileSpreadsheetIcon, FileSpreadsheetIcon,
FileTextIcon, FileTextIcon,
PlusCircleIcon, PlusCircleIcon,
PlusIcon, PlusIcon
TagIcon
} from 'lucide-react' } from 'lucide-react'
import { MeiliSearchFilterBuilder } from 'meilisearch-helper' import { MeiliSearchFilterBuilder } from 'meilisearch-helper'
import { Suspense, useState } from 'react' import { Suspense, useState } from 'react'
import { Await, Link, useSearchParams } from 'react-router' import { Await, Link, useParams, useSearchParams } from 'react-router'
import type { BookType } from 'xlsx' import type { BookType } from 'xlsx'
import * as XLSX from 'xlsx' import * as XLSX from 'xlsx'
@@ -119,10 +118,7 @@ export default function Route({ loaderData: { data } }) {
{selectedRows.length ? ( {selectedRows.length ? (
<> <>
<div className="flex gap-2.5 items-center"> <div className="flex gap-2.5 items-center">
<DropdownMenuExport <ExportMenu headers={headers} selectedRows={selectedRows} />
headers={headers}
selectedRows={selectedRows}
/>
</div> </div>
</> </>
) : ( ) : (
@@ -248,18 +244,20 @@ function useRangeParams() {
} }
} }
export function DropdownMenuExport({ export function ExportMenu({
headers, headers,
selectedRows = [] selectedRows = []
}: { }: {
headers: Record<string, string> headers: Record<string, string>
selectedRows: object[] selectedRows: object[]
}) { }) {
const handleExport = (bookType: BookType) => () => { const { orgid } = useParams()
const exportFile = (bookType: BookType) => () => {
if (!selectedRows.length) { if (!selectedRows.length) {
return return
} }
const now = new Date()
const header = Object.keys(headers) const header = Object.keys(headers)
const data = selectedRows.map((data) => { const data = selectedRows.map((data) => {
const obj: Record<string, string> = flatten(data) const obj: Record<string, string> = flatten(data)
@@ -272,7 +270,7 @@ export function DropdownMenuExport({
origin: 'A1' origin: 'A1'
}) })
XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1') XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1')
XLSX.writeFile(workbook, `${formatted.format(new Date())}.${bookType}`, { XLSX.writeFile(workbook, `${orgid}_users_${+now}.${bookType}`, {
bookType, bookType,
compression: true compression: true
}) })
@@ -287,10 +285,10 @@ export function DropdownMenuExport({
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent className="w-52" align="start"> <DropdownMenuContent className="w-52" align="start">
<DropdownMenuGroup className="*:cursor-pointer"> <DropdownMenuGroup className="*:cursor-pointer">
<DropdownMenuItem onClick={handleExport('xlsx')}> <DropdownMenuItem onClick={exportFile('xlsx')}>
<FileSpreadsheetIcon /> Microsoft Excel (.xlsx) <FileSpreadsheetIcon /> Microsoft Excel (.xlsx)
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuItem onClick={handleExport('csv')}> <DropdownMenuItem onClick={exportFile('csv')}>
<FileTextIcon /> CSV (.csv) <FileTextIcon /> CSV (.csv)
</DropdownMenuItem> </DropdownMenuItem>
</DropdownMenuGroup> </DropdownMenuGroup>

View File

@@ -1,3 +1,5 @@
import type { Route } from './+types'
import { Link } from 'react-router' import { Link } from 'react-router'
import { import {
@@ -16,6 +18,10 @@ import {
CardTitle CardTitle
} from '@repo/ui/components/ui/card' } from '@repo/ui/components/ui/card'
export function meta({}: Route.MetaArgs) {
return [{ title: 'Adicionar matrícula' }]
}
export default function Route() { export default function Route() {
return ( return (
<div className="space-y-2.5"> <div className="space-y-2.5">
@@ -33,7 +39,7 @@ export default function Route() {
</BreadcrumbList> </BreadcrumbList>
</Breadcrumb> </Breadcrumb>
<div className="lg:max-w-2xl mx-auto space-y-2.5"> <div className="lg:max-w-3xl mx-auto space-y-2.5">
<Card> <Card>
<CardHeader> <CardHeader>
<CardTitle className="text-2xl">Adicionar matrícula</CardTitle> <CardTitle className="text-2xl">Adicionar matrícula</CardTitle>

View File

@@ -154,7 +154,7 @@ function UnlinkItem({ id }: { id: string }) {
const { orgid } = useParams() const { orgid } = useParams()
const { table } = useDataTable<User>() const { table } = useDataTable<User>()
const unlink = async (e: MouseEvent) => { const unlink = async (e) => {
e.preventDefault() e.preventDefault()
set(true) set(true)

View File

@@ -84,7 +84,12 @@ export default function Route({ loaderData }: Route.ComponentProps) {
<main className="p-4"> <main className="p-4">
<div className="container mx-auto relative"> <div className="container mx-auto relative">
<Outlet /> <Outlet />
<Toaster position="top-center" richColors={true} /> <Toaster
position="top-center"
richColors={true}
duration={Infinity}
closeButton={true}
/>
</div> </div>
</main> </main>
</SidebarInset> </SidebarInset>