diff --git a/apps/admin.saladeaula.digital/app/routes/_.$orgid.billing._index/route.tsx b/apps/admin.saladeaula.digital/app/routes/_.$orgid.billing._index/route.tsx index 6b3a83b..2702a10 100644 --- a/apps/admin.saladeaula.digital/app/routes/_.$orgid.billing._index/route.tsx +++ b/apps/admin.saladeaula.digital/app/routes/_.$orgid.billing._index/route.tsx @@ -1,12 +1,14 @@ import type { Route } from './+types/route' +import Fuse from 'fuse.js' import { DateTime } from 'luxon' -import { Suspense } from 'react' +import { Suspense, useMemo } from 'react' import { BanIcon } from 'lucide-react' +import { Await, useSearchParams } from 'react-router' +import { cn } from '@repo/ui/lib/utils' import { request as req } from '@repo/util/request' import { Skeleton } from '@repo/ui/components/skeleton' -import { Await } from 'react-router' import { Card, CardContent } from '@repo/ui/components/ui/card' import { Table, @@ -19,7 +21,7 @@ import { } from '@repo/ui/components/ui/table' import { Abbr } from '@repo/ui/components/abbr' import { Button } from '@repo/ui/components/ui/button' -import { cn } from '@repo/ui/lib/utils' +import { SearchForm } from '@repo/ui/components/search-form' import { Empty, EmptyDescription, @@ -27,6 +29,7 @@ import { EmptyMedia, EmptyTitle } from '@repo/ui/components/ui/empty' +import { Kbd } from '@repo/ui/components/ui/kbd' import { billingPeriod, formatDate } from './util' import { RangePeriod } from './range-period' @@ -68,6 +71,9 @@ export async function loader({ context, request, params }: Route.LoaderArgs) { export default function Route({ loaderData: { subscription, billing, startDate, endDate } }: Route.ComponentProps) { + const [searchParams, setSearchParams] = useSearchParams() + const search = searchParams.get('s') as string + return ( <> }> @@ -88,19 +94,36 @@ export default function Route({ label: status, color } = statuses?.[billing?.status || 'CLOSED'] - const charges = items - ?.filter((item) => 'course' in item && item?.unit_price > 0) - ?.sort(sortBy('enrolled_at')) - const credits = items - ?.filter((item) => 'course' in item && item?.unit_price < 0) - ?.sort(sortBy('created_at')) return (
+
+ + Digite / para pesquisar + + } + onChange={(value) => + setSearchParams((searchParams) => { + searchParams.set('s', String(value)) + return searchParams + }) + } + /> +
+ + + - -
- {items.length ? ( -
- - {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'} - - - - {datetime.format(new Date(enrolled_at))} - - - {currency.format(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'} - - - - {datetime.format(new Date(created_at))} - - - {currency.format(unit_price)} - - - ) - )} - - - ) : null} - - - - - Total - - - {currency.format( - items - ?.filter((x) => 'course' in x) - .reduce( - (acc, { unit_price }) => acc + unit_price, - 0 - ) - )} - - - -
-
- ) : ( - - - - - - Nenhuma cobrança encontrada - - Não há nenhuma cobrança para este período. - - - - )} +
) @@ -257,6 +143,159 @@ export default function Route({ ) } + +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) => 'course' in item && item?.unit_price > 0) + ?.sort(sortBy('enrolled_at')) + const credits = filtered + ?.filter((item) => 'course' in 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}. + + + + ) + } + + 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'} + + + {datetime.format(new Date(enrolled_at))} + + {currency.format(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'} + + + {datetime.format(new Date(created_at))} + + {currency.format(unit_price)} + + ) + )} + + + ) : null} + + + + + Total + + + {currency.format( + filtered + ?.filter((x) => 'course' in x) + .reduce((acc, { unit_price }) => acc + unit_price, 0) + )} + + + +
+
+ ) +} + const currency = new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' diff --git a/apps/saladeaula.digital/app/routes/index.tsx b/apps/saladeaula.digital/app/routes/index.tsx index b278656..3cf73d4 100644 --- a/apps/saladeaula.digital/app/routes/index.tsx +++ b/apps/saladeaula.digital/app/routes/index.tsx @@ -181,7 +181,7 @@ function List({ search, hits = [] }: { search: string; hits: Enrollment[] }) { <> Nada encontrado - Nenhum resultado para {s}. + Nenhum resultado para {search}. ) : (