import type { Route } from './+types/route' import Fuse from 'fuse.js' import { BanIcon } from 'lucide-react' import { DateTime as LuxonDateTime } from 'luxon' import { Suspense, useMemo } from 'react' import { Await, useSearchParams } from 'react-router' import { Abbr } from '@repo/ui/components/abbr' import { Currency } from '@repo/ui/components/currency' import { DateTime } from '@repo/ui/components/datetime' import { SearchForm } from '@repo/ui/components/search-form' import { Skeleton } from '@repo/ui/components/skeleton' import { Button } from '@repo/ui/components/ui/button' import { Card, CardContent } from '@repo/ui/components/ui/card' import { Empty, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle } from '@repo/ui/components/ui/empty' import { Kbd } from '@repo/ui/components/ui/kbd' import { Table, TableBody, TableCell, TableFooter, TableHead, TableHeader, TableRow } from '@repo/ui/components/ui/table' import { cn } from '@repo/ui/lib/utils' import { request as req } from '@repo/util/request' import { TZ } from '@/conf' import { workspaceContext } from '@/middleware/workspace' import { statuses } from './data' import { RangePeriod } from './range-period' import { billingPeriod, formatDate } from './util' export function meta({}) { return [{ title: 'Resumo de cobranças' }] } export async function loader({ context, request, params }: Route.LoaderArgs) { const workspace = context.get(workspaceContext) const { searchParams } = new URL(request.url) const { billing_day = 1 } = workspace?.subscription || {} const [startDate, endDate] = billingPeriod( billing_day, LuxonDateTime.now().setZone(TZ).toJSDate() ) const start = searchParams.get('start') || formatDate(startDate) const end = searchParams.get('end') || formatDate(endDate) const billing = req({ url: `/orgs/${params.orgid}/billing?start_date=${start}&end_date=${end}`, context, request }).then((r) => r.json()) return { billing_day, billing, startDate: LuxonDateTime.fromISO(start, { zone: TZ }).toJSDate(), endDate: LuxonDateTime.fromISO(end, { zone: TZ }).toJSDate() } } export default function Route({ loaderData: { billing_day, billing, startDate, endDate } }: Route.ComponentProps) { const [searchParams, setSearchParams] = useSearchParams() const search = searchParams.get('s') as string return ( <> }>

Resumo de cobranças

Acompanhe as cobranças em tempo real e garanta mais eficiência no controle financeiro.

{({ items = [], ...billing }) => { const { icon: Icon, label: status, color } = statuses?.[billing?.status || 'CLOSED'] return (
Digite /{' '} para pesquisar } onChange={(value) => setSearchParams((searchParams) => { searchParams.set('s', String(value)) return searchParams }) } />
) }}
) } function List({ items, search }) { const fuse = useMemo(() => { return new Fuse(items, { keys: ['user.name'], threshold: 0.3, includeMatches: true }) }, [items]) const filtered = useMemo(() => { if (!search) { return items } return fuse.search(search).map(({ item }) => item) }, [search, fuse, items]) const charges = filtered ?.filter((item) => item?.unit_price > 0) ?.sort(sortBy('enrolled_at')) const credits = filtered ?.filter((item) => item?.unit_price < 0) ?.sort(sortBy('created_at')) if (items.length === 0) { return ( Nenhuma cobrança encontrada Não há nenhuma cobrança para este período. ) } if (filtered.length === 0) { return ( Nada encontrado Nenhum resultado para {search}. ) } const subtotal = filtered ?.filter(({ unit_price }) => unit_price > 0) ?.reduce((acc, { unit_price }) => acc + unit_price, 0) const discounts = filtered ?.filter(({ unit_price }) => unit_price < 0) ?.reduce((acc, { unit_price }) => acc + unit_price, 0) const total = filtered?.reduce((acc, { unit_price }) => acc + unit_price, 0) return ( {charges.length ? ( <> Colaborador Curso Matriculado por Matriculado em Valor unit. {charges?.map( ( { user, course, author: created_by, unit_price, enrolled_at }, index ) => ( {user.name} {course.name} {created_by ? created_by.name : 'N/A'} {enrolled_at} {unit_price} ) )} ) : null} {credits.length ? ( <> Cancelado por Cancelado em {credits?.map( ( { user, course, author: canceled_by, unit_price, created_at }, index ) => ( {user.name} {course.name} {canceled_by ? canceled_by.name : 'N/A'} {created_at} {unit_price} ) )} ) : null} Subtotal {subtotal} Descontos {discounts} Total {total}
) } const sortBy = (field: 'enrolled_at' | 'created_at') => (a: any, b: any) => new Date(a[field]).getTime() - new Date(b[field]).getTime()