add reason hover card
This commit is contained in:
@@ -21,6 +21,11 @@ import {
|
||||
CardHeader,
|
||||
CardTitle
|
||||
} from '@repo/ui/components/ui/card'
|
||||
import {
|
||||
HoverCard,
|
||||
HoverCardContent,
|
||||
HoverCardTrigger
|
||||
} from '@repo/ui/components/ui/hover-card'
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
@@ -54,8 +59,8 @@ export function Enrollments({
|
||||
<CardHeader>
|
||||
<CardTitle className="text-xl">Matrículas relacionadas</CardTitle>
|
||||
<CardDescription>
|
||||
Acompanhe o status e os detalhes de todas as matrículas relacionadas a
|
||||
esta compra.
|
||||
Acompanhe os detalhes de todas as matrículas relacionadas a esta
|
||||
compra.
|
||||
</CardDescription>
|
||||
|
||||
<CardAction>
|
||||
@@ -64,18 +69,17 @@ export function Enrollments({
|
||||
</CardHeader>
|
||||
|
||||
<CardContent>
|
||||
<Table className="pointer-events-none">
|
||||
<TableHeader>
|
||||
<Table>
|
||||
<TableHeader className="pointer-events-none">
|
||||
<TableRow>
|
||||
<TableHead>Colaborador</TableHead>
|
||||
<TableHead>Curso</TableHead>
|
||||
<TableHead>Status</TableHead>
|
||||
<TableHead>Executada em</TableHead>
|
||||
{/*<TableHead>Agendada em</TableHead>*/}
|
||||
<TableHead>Revogada em</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
<TableBody className="[&_tr]:hover:bg-transparent">
|
||||
{enrollments.map(
|
||||
(
|
||||
{
|
||||
@@ -83,11 +87,13 @@ export function Enrollments({
|
||||
course,
|
||||
status,
|
||||
executed_at,
|
||||
// scheduled_at,
|
||||
rollback_at
|
||||
rollback_at,
|
||||
reason: reason_
|
||||
},
|
||||
idx
|
||||
) => {
|
||||
const friendlyReason = reason_ ? reason(reason_) : null
|
||||
|
||||
return (
|
||||
<TableRow key={idx}>
|
||||
<TableCell>
|
||||
@@ -112,18 +118,28 @@ export function Enrollments({
|
||||
<Abbr>{course.name}</Abbr>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{friendlyReason ? (
|
||||
<HoverCard openDelay={10} closeDelay={100}>
|
||||
<HoverCardTrigger>
|
||||
<Status status={status} />
|
||||
</HoverCardTrigger>
|
||||
<HoverCardContent align="end" className="text-sm">
|
||||
<p className="flex gap-1">
|
||||
<HelpCircleIcon className="size-4.5 mt-px" />{' '}
|
||||
{friendlyReason}
|
||||
</p>
|
||||
</HoverCardContent>
|
||||
</HoverCard>
|
||||
) : (
|
||||
<Status status={status} />
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{executed_at ? (
|
||||
<DateTime options={dtOptions}>{executed_at}</DateTime>
|
||||
) : null}
|
||||
</TableCell>
|
||||
{/*<TableCell>
|
||||
{scheduled_at ? (
|
||||
<DateTime options={dtOptions}>{scheduled_at}</DateTime>
|
||||
) : null}
|
||||
</TableCell>*/}
|
||||
|
||||
<TableCell>
|
||||
{rollback_at ? (
|
||||
<DateTime options={dtOptions}>{rollback_at}</DateTime>
|
||||
@@ -140,6 +156,17 @@ export function Enrollments({
|
||||
)
|
||||
}
|
||||
|
||||
const reasons: Record<string, string> = {
|
||||
DEDUPLICATION: 'Matrícula ou agendamento já existentes.',
|
||||
CANCELLATION: 'Cancelamento da matrícula.',
|
||||
UNSCHEDULED: 'Cancelamento do agendamento da matrícula.',
|
||||
DEADLINE: 'Data do agendamento é anterior ao dia atual.'
|
||||
} as const
|
||||
|
||||
const reason = (reason_: string): string | null => {
|
||||
return reason_ in reasons ? reasons[reason_] : null
|
||||
}
|
||||
|
||||
const statuses: Record<string, { icon: LucideIcon; color?: string }> = {
|
||||
PENDING: {
|
||||
icon: CircleDashedIcon,
|
||||
@@ -206,9 +233,9 @@ function SeatsMenu({ seats: seats_ }: { seats: Seat[] }) {
|
||||
</div>
|
||||
|
||||
<ul className="text-sm space-y-1.5">
|
||||
{seats.map(({ course, quantity }) => {
|
||||
{seats.map(({ course, quantity }, idx) => {
|
||||
return (
|
||||
<li>
|
||||
<li key={idx}>
|
||||
{quantity}x {course.name}
|
||||
</li>
|
||||
)
|
||||
|
||||
@@ -110,6 +110,7 @@ type Item = {
|
||||
type User = {
|
||||
id: string
|
||||
name: string
|
||||
email: string
|
||||
}
|
||||
|
||||
type Invoice = {
|
||||
@@ -137,12 +138,13 @@ type Course = {
|
||||
}
|
||||
|
||||
export type Enrollment = {
|
||||
status: 'PENDING' | 'EXECUTED' | 'ROLLBACK'
|
||||
user: { id: string; name: string; email: string }
|
||||
status: 'PENDING' | 'EXECUTED' | 'ROLLBACK' | 'SCHEDULED'
|
||||
user: User
|
||||
course: Course
|
||||
executed_at?: string
|
||||
rollback_at?: string
|
||||
scheduled_at?: string
|
||||
reason?: string
|
||||
}
|
||||
|
||||
export type Seat = {
|
||||
@@ -213,7 +215,7 @@ export default function Route({ loaderData: { order } }: Route.ComponentProps) {
|
||||
useEffect(() => {
|
||||
reset()
|
||||
}, [])
|
||||
console.log(seats)
|
||||
|
||||
return (
|
||||
<div className="space-y-2.5">
|
||||
<Breadcrumb>
|
||||
|
||||
@@ -42,7 +42,7 @@ def lambda_handler(event: EventBridgeEvent, context: LambdaContext) -> bool:
|
||||
expr_attr_values={
|
||||
':rollback': 'ROLLBACK',
|
||||
':scheduled': 'SCHEDULED',
|
||||
':reason': 'CANCELLATION',
|
||||
':reason': 'UNSCHEDULED',
|
||||
':now': now_,
|
||||
},
|
||||
table_name=ORDER_TABLE,
|
||||
|
||||
@@ -19,7 +19,7 @@ from layercake.dynamodb import (
|
||||
TransactKey,
|
||||
)
|
||||
from layercake.strutils import md5_hash
|
||||
from pydantic import UUID4, BaseModel, BeforeValidator, Field, FutureDate
|
||||
from pydantic import UUID4, BaseModel, BeforeValidator, Field
|
||||
|
||||
from boto3clients import dynamodb_client
|
||||
from config import (
|
||||
@@ -42,6 +42,9 @@ class DeduplicationConflictError(Exception): ...
|
||||
class EnrollmentConflictError(Exception): ...
|
||||
|
||||
|
||||
class DeadlineExceededError(Exception): ...
|
||||
|
||||
|
||||
class User(BaseModel):
|
||||
id: str
|
||||
name: str
|
||||
@@ -200,9 +203,12 @@ def _get_courses(ids: set[str]) -> tuple[Course, ...]:
|
||||
|
||||
|
||||
def _friendly_reason(reason: str) -> str:
|
||||
if reason == 'DeduplicationConflictError':
|
||||
return 'DEDUPLICATION'
|
||||
return 'CONFLICT'
|
||||
reasons = {
|
||||
'DeduplicationConflictError': 'DEDUPLICATION',
|
||||
'DeadlineExceededError': 'DEADLINE',
|
||||
}
|
||||
|
||||
return reasons.get(reason, 'CONFLICT')
|
||||
|
||||
|
||||
CreatedBy = TypedDict('CreatedBy', {'user_id': str, 'name': str})
|
||||
@@ -341,6 +347,9 @@ def _enroll_later(enrollment: Enrollment, context: Context) -> None:
|
||||
scheduled_for = _date_to_midnight(enrollment.scheduled_for) # type: ignore
|
||||
lock_hash = md5_hash(f'{user.id}{course.id}')
|
||||
|
||||
if now_ > scheduled_for:
|
||||
raise DeadlineExceededError('Deadline exceeded')
|
||||
|
||||
with dyn.transact_writer(table_name=ENROLLMENT_TABLE) as transact:
|
||||
pk = f'SCHEDULED#ORG#{org.id}'
|
||||
sk = f'{scheduled_for.isoformat()}#{lock_hash}'
|
||||
|
||||
Reference in New Issue
Block a user