import type { Route } from './+types' import Fuse from 'fuse.js' import { AwardIcon, BanIcon, LaptopIcon } from 'lucide-react' import { Suspense, useMemo } from 'react' import { Await, useSearchParams } from 'react-router' import placeholder from '@/assets/placeholder.webp' import { SearchForm } from '@repo/ui/components/search-form' import { Skeleton } from '@repo/ui/components/skeleton' import { Card, CardFooter, CardHeader, CardTitle } 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 { cn } from '@repo/ui/lib/utils' import { createSearch } from '@repo/util/meili' import { request as req } from '@repo/util/request' type Cert = { exp_interval: number } type Course = { id: string name: string access_period: string cert: Cert metadata__unit_price?: number } type CustomPricing = { sk: string unit_price: number } export function meta({}: Route.MetaArgs) { return [{ title: 'Catálogo de cursos' }] } export async function loader({ context, request, params }: Route.LoaderArgs) { const courses = createSearch({ index: 'saladeaula_courses', sort: ['created_at:desc'], filter: 'draft NOT EXISTS', hitsPerPage: 100, env: context.cloudflare.env }) const customPricing = req({ url: `/orgs/${params.orgid}/custom-pricing`, context, request }).then((r) => r.json()) return { data: Promise.all([courses, customPricing]) } } export default function Route({ loaderData: { data } }) { const [searchParams, setSearchParams] = useSearchParams() const term = searchParams.get('term') as string return ( }>

Catálogo de cursos

Explore o catálogo de cursos disponíveis para sua empresa.

{([{ hits }, { items }]) => { return ( <>
Digite / para pesquisar } defaultValue={term} onChange={(term) => { setSearchParams({ term }) }} />
) }}
) } function List({ term, hits = [], customPricing = [] }: { term: string hits: Course[] customPricing: CustomPricing[] }) { const fuse = useMemo(() => { return new Fuse(hits, { keys: ['name'], threshold: 0.3, includeMatches: true }) }, [hits]) const hits_ = useMemo(() => { if (!term) { return hits } return fuse.search(term).map(({ item }) => item) }, [term, fuse, hits]) const customPricingMap = new Map( customPricing.map((x) => { const [, courseId] = x.sk.split('#') return [courseId, x.unit_price] }) ) if (hits_.length === 0) { return ( Nada encontrado Nenhum resultado para {term}. ) } return hits_.map((props: Course, idx) => { return ( ) }) } function Course({ name, access_period, cert, metadata__unit_price, custom_pricing }: Course & { custom_pricing?: number }) { return ( {name}
  • {access_period}d
  • {cert?.exp_interval && (
  • {cert.exp_interval}d
  • )} {metadata__unit_price && ( <>
  • {currency.format(metadata__unit_price)} {custom_pricing && ( {currency.format(custom_pricing)} )}
  • )}
{name}
) } const currency = new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' })