import type { Route } from './+types/route' import type { MouseEvent, ReactNode } from 'react' import { useRequest, useToggle } from 'ahooks' import { AlertTriangleIcon, BanIcon, CalendarIcon, CircleXIcon, ClockAlertIcon, ClockCheckIcon, ClockIcon, EllipsisIcon, PlusIcon, RocketIcon, UserIcon } from 'lucide-react' import { toast } from 'sonner' import { DateTime } from 'luxon' import { Fragment, Suspense } from 'react' import { Await } from 'react-router' import { request as req } from '@repo/util/request' import { Button } from '@repo/ui/components/ui/button' import { Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle } from '@repo/ui/components/ui/empty' import { Skeleton } from '@repo/ui/components/skeleton' import { Card, CardContent } from '@repo/ui/components/ui/card' import { Item, ItemActions, ItemContent, ItemDescription, ItemGroup, ItemMedia, ItemSeparator, ItemTitle } from '@repo/ui/components/ui/item' import { Link } from 'react-router' import { Avatar, AvatarFallback } from '@repo/ui/components/ui/avatar' import { initials } from '@repo/ui/lib/utils' import { Abbr } from '@repo/ui/components/abbr' import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger } from '@repo/ui/components/ui/dropdown-menu' import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger } from '@repo/ui/components/ui/alert-dialog' import { Spinner } from '@repo/ui/components/ui/spinner' import { useParams } from 'react-router' import { useRevalidator } from 'react-router' import { Tabs, TabsContent, TabsList, TabsTrigger } from '@repo/ui/components/ui/tabs' import { useSearchParams } from 'react-router' export function meta({}: Route.MetaArgs) { return [{ title: 'Matrículas agendadas' }] } export async function loader({ context, request, params }: Route.LoaderArgs) { const scheduled = req({ url: `/orgs/${params.orgid}/enrollments/scheduled`, context, request }).then((r) => r.json()) return { scheduled } } export default function Route({ loaderData: { scheduled } }: Route.ComponentProps) { const [searchParams, setSearchParams] = useSearchParams() return ( }>

Matrículas agendadas

Acompanhe todas as matrículas agendadas, cancele quando quiser ou matricule imediatamente.

{({ items }) => { if (items.length === 0) { return ( Nenhum agendamento ainda Agende a matrícula dos seus colaboradores de forma rápida e organizada. ) } const scheduled = grouping(filtering(items, undefined)) const executed = grouping(filtering(items, 'EXECUTED')) const failed = grouping(filtering(items, 'FAILED')) return (
{ setSearchParams((searchParams) => { searchParams.set('tab', value) return searchParams }) }} >
Aguardando Executada Falhou
{({ items }) => ( )} {({ items }) => ( )} {({ items }) => ( )}
) }}
) } function Timeline({ events = [], children }: { events: any[] children: (props: any) => ReactNode }) { if (events.length === 0) { return ( Nenhum agendamento encontrado Ainda não há agendamentos. Quando houver, eles aparecerão aqui. ) } return ( <> {events.map(([run_at, items], index) => (
{DateTime.fromISO(run_at) .setLocale('pt-BR') .toFormat('cccc, dd LLL yyyy')}
{children({ items })}
))} ) } function Scheduled({ items = [] }) { return ( {items.map(({ sk, user, course, created_by, scheduled_at }, index) => ( {initials(user.name)} {course.name} {user.name} {user.email}
  • {datetime.format(new Date(scheduled_at))}
  • {created_by.name}
{index !== items.length - 1 && }
))}
) } function Executed({ items = [] }) { return ( {items.length === 0 ? ( Nenhum agendamento ainda Agende a matrícula dos seus colaboradores de forma rápida e organizada. ) : null} {items.map(({ course, user, created_at }, index) => ( {initials(user.name)} {course.name} {user.name} {user.email}
  • {datetime.format(new Date(created_at))}
{index !== items.length - 1 && }
))}
) } function Failed({ items = [] }) { return ( {items.map(({ snapshot: { course, user }, cause, created_at }, index) => ( {initials(user.name)} {course.name} {user.name} {user.email}
  • {datetime.format(new Date(created_at))}
  • {cause?.type === 'DeduplicationConflictError' ? (
  • Protegido contra duplicação
  • ) : null}
{index !== items.length - 1 && }
))}
) } function ActionMenu({ sk }: { sk: string }) { const [open, { toggle, set }] = useToggle() const { revalidate } = useRevalidator() const onSuccess = () => { revalidate() set(false) } return ( ) } 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 ( {loading ? : } Matricular agora ) } function CancelItem({ sk, onSuccess }: { sk: string; onSuccess?: () => void }) { const { orgid } = useParams() const [open, { set: setOpen }] = useToggle(false) const { runAsync, loading } = useRequest( async () => { const [scheduled_for, lock_hash] = sk.split('#') return await fetch(`/~/api/orgs/${orgid}/enrollments/scheduled`, { method: 'DELETE', headers: new Headers({ 'Content-Type': 'application/json' }), body: JSON.stringify({ scheduled_for, lock_hash }) }) }, { manual: true } ) const cancel = async (e: MouseEvent) => { e.preventDefault() const r = await runAsync() if (r.ok) { toast.info('O agendamento foi cancelada.') onSuccess?.() } setOpen(false) } return ( e.preventDefault()} > Cancelar Tem certeza absoluta? Esta ação não pode ser desfeita. Isso{' '} cancela permanentemente o agendamento {' '} desta matrícula. Cancelar ) } function filtering(items, status) { return items.filter(({ sk }: { sk: string }) => { const [, , s] = sk.split('#') return s == status }) } function grouping(items) { const newItems = Object.entries( items.reduce((acc, item) => { const [run_at] = item.sk.split('#') if (!acc[run_at]) { acc[run_at] = [] } acc[run_at].push(item) return acc }, []) ) return newItems.sort((x, y) => x[0].localeCompare(y[0])) } const datetime = new Intl.DateTimeFormat('pt-BR', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' })