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