import type { Route } from './+types' import { flatten } from 'flat' import { CalendarIcon, ChevronDownIcon, DownloadIcon, FileSpreadsheetIcon, FileTextIcon, PlusCircleIcon, PlusIcon } from 'lucide-react' import { MeiliSearchFilterBuilder } from 'meilisearch-helper' import { Suspense, useState } from 'react' import { Await, Link, useParams, useSearchParams } from 'react-router' import type { BookType } from 'xlsx' import * as XLSX from 'xlsx' import { DataTable, DataTableViewOptions } from '@/components/data-table' import { RangeCalendarFilter } from '@/components/range-calendar-filter' import { FacetedFilter } from '@repo/ui/components/faceted-filter' import { SearchForm } from '@repo/ui/components/search-form' import { Skeleton } from '@repo/ui/components/skeleton' import { Button } from '@repo/ui/components/ui/button' import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuTrigger } from '@repo/ui/components/ui/dropdown-menu' import { Kbd } from '@repo/ui/components/ui/kbd' import { createSearch } from '@repo/util/meili' import { columns, type Enrollment } from './columns' import { headers, sortings, statuses } from './data' export function meta({}: Route.MetaArgs) { return [{ title: 'Matrículas' }] } export async function loader({ params, context, request }: Route.LoaderArgs) { const { searchParams } = new URL(request.url) const { orgid } = params const query = searchParams.get('q') || '' const from = searchParams.get('from') const to = searchParams.get('to') const sort = searchParams.get('sort') || 'created_at:desc' const status = searchParams.get('status') const page = Number(searchParams.get('p')) + 1 const hitsPerPage = Number(searchParams.get('perPage')) || 25 let builder = new MeiliSearchFilterBuilder().where('org_id', '=', orgid) if (status) { builder = builder.where('status', 'in', status.split(',')) } if (from && to) { const [field, from_] = from.split(':') builder = builder.where(field, 'between', [from_, to]) } return { data: createSearch({ index: 'betaeducacao-prod-enrollments', filter: builder.build(), sort: [sort], query, page, hitsPerPage, env: context.cloudflare.env }) } } const formatted = new Intl.DateTimeFormat('en-CA', { year: 'numeric', month: '2-digit', day: '2-digit' }) export default function Route({ loaderData: { data } }) { const [searchParams, setSearchParams] = useSearchParams() const [selectedRows, setSelectedRows] = useState([]) const status = searchParams.get('status') const rangeParams = useRangeParams() return ( }>

Gerenciar matrículas

Matricule colaboradores de forma rápida e acompanhe seu progresso.

{({ hits, page, hitsPerPage, totalHits }) => (
{selectedRows.length ? ( <>
) : ( <>
Digite / para pesquisar } onChange={(value) => setSearchParams((searchParams) => { searchParams.set('q', String(value)) searchParams.delete('p') return searchParams }) } />
{ setSearchParams((searchParams) => { searchParams.delete('status') searchParams.delete('p') if (statuses.length) { searchParams.set('status', statuses.join(',')) } return searchParams }) }} options={Object.entries(statuses).map( ([key, value]) => ({ value: key, ...value }) )} /> ({ value, label }) )} onChange={(props) => { setSearchParams((searchParams) => { if (!props) { searchParams.delete('from') searchParams.delete('to') return searchParams } const { rangeField, dateRange } = props searchParams.set( 'from', `${rangeField}:${formatted.format(dateRange?.from)}` ) searchParams.set( 'to', formatted.format(dateRange?.to) ) return searchParams }) }} />
)}
)}
) } function useRangeParams() { const [searchParams] = useSearchParams() const [from, to] = [searchParams.get('from'), searchParams.get('to')] if (!from || !to) { return {} } const [rangeField, from_] = from.split(':') return { rangeField, dateRange: { from: new Date(from_), to: new Date(to) } } } export function ExportMenu({ headers, selectedRows = [] }: { headers: Record selectedRows: object[] }) { const { orgid } = useParams() const exportFile = (bookType: BookType) => () => { if (!selectedRows.length) { return } const now = new Date() const header = Object.keys(headers) const data = selectedRows.map((data) => { const obj: Record = flatten(data) return Object.fromEntries(header.map((k) => [k, obj?.[k]])) }) const workbook = XLSX.utils.book_new() const worksheet = XLSX.utils.json_to_sheet(data, { header }) XLSX.utils.sheet_add_aoa(worksheet, [Object.values(headers)], { origin: 'A1' }) XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1') XLSX.writeFile(workbook, `${orgid}_users_${+now}.${bookType}`, { bookType, compression: true }) } return ( Microsoft Excel (.xlsx) CSV (.csv) ) }