add feedback

This commit is contained in:
2025-12-16 13:46:03 -03:00
parent ab5bf50900
commit 68320b0042
2 changed files with 171 additions and 54 deletions

View File

@@ -3,9 +3,13 @@ import type { Route } from './+types/route'
import type { MouseEvent, ReactNode } from 'react'
import { useRequest, useToggle } from 'ahooks'
import {
AlertTriangleIcon,
BanIcon,
CalendarClockIcon,
CalendarIcon,
CircleXIcon,
ClockAlertIcon,
ClockCheckIcon,
EllipsisIcon,
PlusIcon,
RocketIcon,
@@ -151,19 +155,37 @@ export default function Route({
<TabsContent value="pending" className="space-y-5">
<Timeline events={scheduled}>
{({ items }) => (
<Scheduled items={items} className="col-span-4" />
<Card className="col-span-4">
<CardContent>
<Scheduled items={items} />
</CardContent>
</Card>
)}
</Timeline>
</TabsContent>
<TabsContent value="executed" className="space-y-5">
<Timeline events={executed}>
{({ items }) => <>...</>}
{({ items }) => (
<Card className="col-span-4">
<CardContent>
<Executed items={items} />
</CardContent>
</Card>
)}
</Timeline>
</TabsContent>
<TabsContent value="failed" className="space-y-5">
<Timeline events={failed}>{({ items }) => <>...</>}</Timeline>
<Timeline events={failed}>
{({ items }) => (
<Card className="col-span-4">
<CardContent>
<Failed items={items} />
</CardContent>
</Card>
)}
</Timeline>
</TabsContent>
</Tabs>
</div>
@@ -198,13 +220,10 @@ function Timeline({
)
}
function Scheduled({ items, className }) {
function Scheduled({ items = [] }) {
return (
<Card className={className}>
<CardContent>
<ItemGroup>
{items.map(
({ sk, user, course, created_by, scheduled_at }, index) => (
{items.map(({ sk, user, course, created_by, scheduled_at }, index) => (
<Fragment key={index}>
<Item className="max-lg:px-0 max-lg:first:pt-0 max-lg:last:pb-0">
<ItemMedia className="hidden lg:block">
@@ -225,11 +244,12 @@ function Scheduled({ items, className }) {
<div className="mt-1">
<ul className="lg:flex gap-2.5 text-muted-foreground text-sm *:flex *:gap-1 *:items-center">
<li>
<CalendarIcon className="size-3.5" />{' '}
{datetime.format(new Date(scheduled_at))}
<CalendarIcon className="size-3.5" />
<span>{datetime.format(new Date(scheduled_at))}</span>
</li>
<li>
<UserIcon className="size-3.5" /> {created_by.name}
<UserIcon className="size-3.5" />
<span>{created_by.name}</span>
</li>
</ul>
</div>
@@ -242,11 +262,92 @@ function Scheduled({ items, className }) {
{index !== items.length - 1 && <ItemSeparator />}
</Fragment>
)
)}
))}
</ItemGroup>
)
}
function Executed({ items = [] }) {
return (
<ItemGroup>
{items.map(({ course, user, created_at }, index) => (
<Fragment key={index}>
<Item className="max-lg:px-0 max-lg:first:pt-0 max-lg:last:pb-0">
<ItemMedia className="hidden lg:block">
<Avatar className="size-10 ">
<AvatarFallback className="border">
{initials(user.name)}
</AvatarFallback>
</Avatar>
</ItemMedia>
<ItemContent>
<ItemTitle>{course.name}</ItemTitle>
<ItemDescription className="flex flex-col">
<Abbr>{user.name}</Abbr>
<Abbr>{user.email}</Abbr>
</ItemDescription>
<div className="mt-1">
<ul className="lg:flex gap-2.5 text-muted-foreground text-sm *:flex *:gap-1 *:items-center">
<li>
<ClockCheckIcon className="size-3.5" />
<span>{datetime.format(new Date(created_at))}</span>
</li>
</ul>
</div>
</ItemContent>
</Item>
{index !== items.length - 1 && <ItemSeparator />}
</Fragment>
))}
</ItemGroup>
)
}
function Failed({ items = [] }) {
return (
<ItemGroup>
{items.map(({ snapshot: { course, user }, cause, created_at }, index) => (
<Fragment key={index}>
<Item className="max-lg:px-0 max-lg:first:pt-0 max-lg:last:pb-0">
<ItemMedia className="hidden lg:block">
<Avatar className="size-10 ">
<AvatarFallback className="border">
{initials(user.name)}
</AvatarFallback>
</Avatar>
</ItemMedia>
<ItemContent>
<ItemTitle>{course.name}</ItemTitle>
<ItemDescription className="flex flex-col">
<Abbr>{user.name}</Abbr>
<Abbr>{user.email}</Abbr>
</ItemDescription>
<div className="mt-1">
<ul className="lg:flex gap-2.5 text-muted-foreground text-sm *:flex *:gap-1 *:items-center">
<li>
<ClockAlertIcon className="size-3.5" />
<span>{datetime.format(new Date(created_at))}</span>
</li>
{cause?.type === 'DeduplicationConflictError' ? (
<li className="text-red-400">
<AlertTriangleIcon className="size-3.5" />
<span>Protegido contra duplicação</span>
</li>
) : null}
</ul>
</div>
</ItemContent>
</Item>
{index !== items.length - 1 && <ItemSeparator />}
</Fragment>
))}
</ItemGroup>
</CardContent>
</Card>
)
}
@@ -266,9 +367,7 @@ function ActionMenu({ sk }: { sk: string }) {
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="*:cursor-pointer w-42">
<DropdownMenuItem disabled>
<RocketIcon /> Matricular agora
</DropdownMenuItem>
<Proceedtem sk={sk} onSuccess={onSuccess} />
<DropdownMenuSeparator />
<CancelItem sk={sk} onSuccess={onSuccess} />
</DropdownMenuContent>
@@ -276,6 +375,26 @@ function ActionMenu({ sk }: { sk: string }) {
)
}
function Proceedtem({ sk, onSuccess }: { sk: string; onSuccess?: () => void }) {
const { runAsync, loading } = useRequest(
async () => {
await new Promise((r) => setTimeout(r, 1000))
},
{ manual: true }
)
const proceed = async (e: MouseEvent) => {
e.preventDefault()
await runAsync()
}
return (
<DropdownMenuItem onClick={proceed}>
{loading ? <Spinner /> : <RocketIcon />} Matricular agora
</DropdownMenuItem>
)
}
function CancelItem({ sk, onSuccess }: { sk: string; onSuccess?: () => void }) {
const { orgid } = useParams()
const [open, { set: setOpen }] = useToggle(false)

View File

@@ -8,7 +8,6 @@ from aws_lambda_powertools.utilities.data_classes import (
from aws_lambda_powertools.utilities.typing import LambdaContext
from layercake.dateutils import now
from layercake.dynamodb import DynamoDBPersistenceLayer
from layercake.funcs import pick
from boto3clients import dynamodb_client
from config import ENROLLMENT_TABLE
@@ -58,14 +57,13 @@ def lambda_handler(event: EventBridgeEvent, context: LambdaContext) -> bool:
persistence_layer=dyn,
)
keys = ('id', 'name')
dyn.put_item(
item={
'id': old_image['id'],
'sk': f'{sk}#EXECUTED',
'enrollment_id': enrollment.id,
'user': pick(keys, old_image['user']),
'course': pick(keys, old_image['course']),
'user': old_image['user'],
'course': old_image['course'],
'created_by': created_by,
'created_at': now_,
}