add enrollments to order

This commit is contained in:
2026-01-25 20:47:21 -03:00
parent 3719842ae9
commit 0d1258f666
11 changed files with 303 additions and 64 deletions

View File

@@ -0,0 +1,168 @@
import {
BanIcon,
CheckCircle2Icon,
CircleDashedIcon,
ClockIcon,
HelpCircleIcon,
type LucideIcon
} from 'lucide-react'
import { Abbr } from '@repo/ui/components/abbr'
import { DateTime } from '@repo/ui/components/datetime'
import { Avatar, AvatarFallback } from '@repo/ui/components/ui/avatar'
import { Badge } from '@repo/ui/components/ui/badge'
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle
} from '@repo/ui/components/ui/card'
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow
} from '@repo/ui/components/ui/table'
import { cn, initials } from '@repo/ui/lib/utils'
import type { Enrollment, Seat } from './route'
const dtOptions: Intl.DateTimeFormatOptions = {
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
}
export function Enrollments({
enrollments,
seats
}: {
enrollments: Enrollment[]
seats: Seat[]
}) {
return (
<Card className="lg:max-w-4xl mx-auto">
<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.
</CardDescription>
</CardHeader>
<CardContent>
<Table className="pointer-events-none">
<TableHeader>
<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>
{enrollments.map(
(
{
user,
course,
status,
executed_at,
scheduled_at,
rollback_at
},
idx
) => {
return (
<TableRow key={idx}>
<TableCell>
<div className="flex gap-2.5 items-center">
<Avatar className="size-10 hidden lg:block">
<AvatarFallback className="border">
{initials(user.name)}
</AvatarFallback>
</Avatar>
<ul>
<li className="font-bold">
<Abbr>{user.name}</Abbr>
</li>
<li className="text-muted-foreground text-sm">
<Abbr>{user.email}</Abbr>
</li>
</ul>
</div>
</TableCell>
<TableCell>
<Abbr>{course.name}</Abbr>
</TableCell>
<TableCell>
<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>
) : null}
</TableCell>
</TableRow>
)
}
)}
</TableBody>
</Table>
</CardContent>
</Card>
)
}
const statuses: Record<string, { icon: LucideIcon; color?: string }> = {
PENDING: {
icon: CircleDashedIcon,
color: 'text-blue-400 [&_svg]:text-blue-500'
},
SCHEDULED: {
icon: ClockIcon,
color: 'text-blue-400 [&_svg]:text-blue-500'
},
EXECUTED: {
icon: CheckCircle2Icon,
color: 'text-green-400 [&_svg]:text-green-500'
},
ROLLBACK: {
icon: BanIcon,
color: 'text-orange-400 [&_svg]:text-orange-500'
}
}
const labels: Record<string, string> = {
PENDING: 'Pendente',
EXECUTED: 'Executado',
SCHEDULED: 'Agendado',
ROLLBACK: 'Revogado'
}
function Status({ status: s }: { status: string }) {
const status = labels[s] ?? s
const { icon: Icon, color } = statuses?.[s] ?? { icon: HelpCircleIcon }
return (
<Badge variant="outline" className={cn(color, 'px-1.5')}>
<Icon className={cn('stroke-2', color)} />
{status}
</Badge>
)
}

View File

@@ -17,7 +17,10 @@ import { useForm } from 'react-hook-form'
import { Link, useRevalidator } from 'react-router'
import { z } from 'zod'
import { Abbr } from '@repo/ui/components/abbr'
import { Currency } from '@repo/ui/components/currency'
import { DateTime } from '@repo/ui/components/datetime'
import { Badge } from '@repo/ui/components/ui/badge'
import {
Breadcrumb,
BreadcrumbItem,
@@ -26,34 +29,13 @@ import {
BreadcrumbPage,
BreadcrumbSeparator
} from '@repo/ui/components/ui/breadcrumb'
import { Button } from '@repo/ui/components/ui/button'
import {
Card,
CardContent,
CardHeader,
CardTitle
} from '@repo/ui/components/ui/card'
import {
Item,
ItemActions,
ItemContent,
ItemGroup,
ItemTitle
} from '@repo/ui/components/ui/item'
import {
Table,
TableBody,
TableCell,
TableFooter,
TableHead,
TableHeader,
TableRow
} from '@repo/ui/components/ui/table'
import { request as req } from '@repo/util/request'
import { Abbr } from '@repo/ui/components/abbr'
import { DateTime } from '@repo/ui/components/datetime'
import { Badge } from '@repo/ui/components/ui/badge'
import { Button } from '@repo/ui/components/ui/button'
import {
Dialog,
DialogClose,
@@ -64,6 +46,13 @@ import {
DialogTitle,
DialogTrigger
} from '@repo/ui/components/ui/dialog'
import {
Item,
ItemActions,
ItemContent,
ItemGroup,
ItemTitle
} from '@repo/ui/components/ui/item'
import { Kbd } from '@repo/ui/components/ui/kbd'
import {
Popover,
@@ -72,12 +61,22 @@ import {
} from '@repo/ui/components/ui/popover'
import { Separator } from '@repo/ui/components/ui/separator'
import { Spinner } from '@repo/ui/components/ui/spinner'
import {
Table,
TableBody,
TableCell,
TableFooter,
TableHead,
TableHeader,
TableRow
} from '@repo/ui/components/ui/table'
import { cn } from '@repo/ui/lib/utils'
import {
labels,
statuses,
type Order as Order_
} from '@repo/ui/routes/orders/data'
import { request as req } from '@repo/util/request'
import {
CreditCard,
creditCardSchema,
@@ -85,6 +84,7 @@ import {
} from '../_.$orgid.enrollments.buy/payment'
import type { Address } from '../_.$orgid.enrollments.buy/review'
import { useWizardStore } from '../_.$orgid.enrollments.buy/store'
import { Enrollments } from './enrollments'
export function meta() {
return [
@@ -131,6 +131,24 @@ type Attempts = {
last4: string
}
type Course = {
id: string
name: string
}
export type Enrollment = {
status: 'PENDING' | 'EXECUTED' | 'ROLLBACK'
user: { id: string; name: string; email: string }
course: Course
executed_at?: string
rollback_at?: string
scheduled_at?: string
}
export type Seat = {
course: Course
}
type Order = Order_ & {
items: Item[]
interest_amount: number
@@ -142,6 +160,8 @@ type Order = Order_ & {
payment_attempts: Attempts[]
credit_card?: CreditCardProps
coupon?: string
enrollments?: Enrollment[]
seats?: Seat[]
installments?: number
created_by?: User
invoice: Invoice
@@ -173,6 +193,8 @@ export default function Route({ loaderData: { order } }: Route.ComponentProps) {
discount,
invoice,
payment_attempts = [],
enrollments = [],
seats = [],
items = [],
subtotal
} = order
@@ -185,7 +207,7 @@ export default function Route({ loaderData: { order } }: Route.ComponentProps) {
useEffect(() => {
reset()
}, [])
console.log(seats)
return (
<div className="space-y-2.5">
<Breadcrumb>
@@ -320,6 +342,10 @@ export default function Route({ loaderData: { order } }: Route.ComponentProps) {
</Table>
</CardContent>
</Card>
{enrollments.length > 0 ? (
<Enrollments enrollments={enrollments} seats={seats} />
) : null}
</div>
)
}