import type { Route } from './+types/route'
import { useRequest, useToggle } from 'ahooks'
import {
AlertTriangleIcon,
BanIcon,
CalendarIcon,
CircleXIcon,
ClockAlertIcon,
ClockCheckIcon,
ClockIcon,
EllipsisIcon,
PlusIcon,
RocketIcon,
UserIcon
} from 'lucide-react'
import { DateTime as LuxonDateTime } from 'luxon'
import type { MouseEvent, ReactNode } from 'react'
import { Fragment, Suspense } from 'react'
import { Await } from 'react-router'
import { toast } from 'sonner'
import { Abbr } from '@repo/ui/components/abbr'
import { DateTime } from '@repo/ui/components/datetime'
import { Skeleton } from '@repo/ui/components/skeleton'
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogTrigger
} from '@repo/ui/components/ui/alert-dialog'
import { Avatar, AvatarFallback } from '@repo/ui/components/ui/avatar'
import { Button } from '@repo/ui/components/ui/button'
import { Card, CardContent } from '@repo/ui/components/ui/card'
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger
} from '@repo/ui/components/ui/dropdown-menu'
import {
Empty,
EmptyContent,
EmptyDescription,
EmptyHeader,
EmptyMedia,
EmptyTitle
} from '@repo/ui/components/ui/empty'
import {
Item,
ItemActions,
ItemContent,
ItemDescription,
ItemGroup,
ItemMedia,
ItemSeparator,
ItemTitle
} from '@repo/ui/components/ui/item'
import { Spinner } from '@repo/ui/components/ui/spinner'
import {
Tabs,
TabsContent,
TabsList,
TabsTrigger
} from '@repo/ui/components/ui/tabs'
import { initials } from '@repo/ui/lib/utils'
import { request as req } from '@repo/util/request'
import { Link, useParams, useRevalidator, 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 = sorting(grouping(filtering(items, 'EXECUTED')))
const failed = sorting(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) => (
{LuxonDateTime.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}
-
{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}
{sorting(items).map(({ course, user, created_at }, index) => (
-
{initials(user.name)}
{course.name}
{user.name}
{user.email}
{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}
-
{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]))
}
function sorting(items) {
return items.sort((a, b) => {
return new Date(b[0]).getTime() - new Date(a[0]).getTime()
})
}