diff --git a/src/app/(dashboard)/aprovacoes/page.tsx b/src/app/(dashboard)/aprovacoes/page.tsx index 1cbb52bc..52dfda76 100644 --- a/src/app/(dashboard)/aprovacoes/page.tsx +++ b/src/app/(dashboard)/aprovacoes/page.tsx @@ -1,9 +1,11 @@ import type { Metadata } from 'next' +import { UnderReviewPatientRequirements } from '@/modules/patient-requirements/under-review-requirements' + export const metadata: Metadata = { title: 'Aprovações pendentes', } export default function Page() { - return

Aprovações pendentes

+ return } diff --git a/src/components/ui/search-input.tsx b/src/components/ui/search-input.tsx new file mode 100644 index 00000000..8447652f --- /dev/null +++ b/src/components/ui/search-input.tsx @@ -0,0 +1,60 @@ +'use client' + +import { SearchIcon, XIcon } from 'lucide-react' +import { useEffect, useState } from 'react' + +import { Button } from '@/components/ui/button' +import { Input, type InputProps } from '@/components/ui/input' +import { QUERY_PARAMS } from '@/constants/params' +import { useDebounce } from '@/hooks/debounce' +import { useParams } from '@/hooks/params' +import { cn } from '@/utils/class-name-merge' + +export function SearchInput({ className, ...props }: Readonly) { + const queryParam = QUERY_PARAMS.search + const pageParam = QUERY_PARAMS.page + + const { getParam, updateParams } = useParams() + const searchQuery = getParam(queryParam) || '' + + const [query, setQuery] = useState(searchQuery) + const debouncedQuery = useDebounce(query) + + useEffect(() => { + updateParams({ + set: [{ key: queryParam, value: debouncedQuery }], + remove: !debouncedQuery ? [queryParam, pageParam] : [pageParam], + }) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [debouncedQuery]) + + useEffect(() => { + if (!searchQuery) setQuery('') + }, [searchQuery]) + + return ( +
+ setQuery(e.target.value)} + className={cn('w-52 pr-10', className)} + {...props} + /> + + {query && ( + + )} +
+ ) +} diff --git a/src/helpers/get-time-distance-to-now.ts b/src/helpers/get-time-distance-to-now.ts new file mode 100644 index 00000000..9023b25c --- /dev/null +++ b/src/helpers/get-time-distance-to-now.ts @@ -0,0 +1,6 @@ +import { formatDistanceToNow } from 'date-fns' +import { ptBR } from 'date-fns/locale' + +export function getTimeDistanceToNow(date: string | Date) { + return formatDistanceToNow(date, { addSuffix: true, locale: ptBR }) +} diff --git a/src/modules/patient-requirements/pending-requirements.tsx b/src/modules/patient-requirements/pending-requirements.tsx index 5bb05470..8a91aa64 100644 --- a/src/modules/patient-requirements/pending-requirements.tsx +++ b/src/modules/patient-requirements/pending-requirements.tsx @@ -15,6 +15,7 @@ import { Skeleton } from '@/components/ui/skeleton' import { Tag } from '@/components/ui/tag' import { QUERY_CACHE_KEYS } from '@/constants/cache' import { QUERY_PARAMS } from '@/constants/params' +import { getTimeDistanceToNow } from '@/helpers/get-time-distance-to-now' import { useParams } from '@/hooks/params' import { api } from '@/lib/api' import type { OrderMappingType } from '@/types/order' @@ -123,9 +124,9 @@ export function PendingPatientRequirements() { variant={severityVariant()} className='flex flex-col gap-1 rounded-xl shadow-none' > -

+

{requirement.patient.name} -

+
Pendência: @@ -135,7 +136,7 @@ export function PendingPatientRequirements() {
- + Solicitado em {formatDate(requirement.created_at)} @@ -149,12 +150,8 @@ export function PendingPatientRequirements() { 'data-[severity="error"]:text-error', )} > - -

- {pendingDays <= 1 - ? 'Pendente há 1 dia' - : `Pendente há ${pendingDays} dias`} -

+ +

Pendente {getTimeDistanceToNow(requirement.created_at)}

) diff --git a/src/modules/patient-requirements/under-review-requirements.tsx b/src/modules/patient-requirements/under-review-requirements.tsx new file mode 100644 index 00000000..e265393a --- /dev/null +++ b/src/modules/patient-requirements/under-review-requirements.tsx @@ -0,0 +1,135 @@ +'use client' + +import { useQuery } from '@tanstack/react-query' +import { CircleAlertIcon } from 'lucide-react' +import { useEffect, useState } from 'react' + +import { DataTableHeader } from '@/components/data-table/header' +import { DataTableHeaderActions } from '@/components/data-table/header/actions' +import { DataTableHeaderOrderBy } from '@/components/data-table/header/order-by' +import { DataTableHeaderSearch } from '@/components/data-table/header/search' +import { Pagination } from '@/components/pagination' +import { Card } from '@/components/ui/card' +import { Skeleton } from '@/components/ui/skeleton' +import { Tag } from '@/components/ui/tag' +import { QUERY_CACHE_KEYS } from '@/constants/cache' +import { QUERY_PARAMS } from '@/constants/params' +import { getTimeDistanceToNow } from '@/helpers/get-time-distance-to-now' +import { useParams } from '@/hooks/params' +import { api } from '@/lib/api' +import type { OrderMappingType } from '@/types/order' +import type { PatientRequirement } from '@/types/patient-requirements' +import { + PATIENT_REQUIREMENT_TYPES, + PATIENT_REQUIREMENTS_ORDER_OPTIONS, + type PatientRequirementsOrder, +} from '@/types/patient-requirements' + +import { AddPatientRequirementButton } from './add-patient-requirement-button' + +// TODO: add dropdown actions menu +export function UnderReviewPatientRequirements() { + const [stableTotal, setStableTotal] = useState(0) + const { getParam } = useParams() + + const perPage = 12 + const page = getParam(QUERY_PARAMS.page) + const search = getParam(QUERY_PARAMS.search) + const orderBy = getParam(QUERY_PARAMS.orderBy) + + const ORDER_MAPPING: OrderMappingType = { + name_asc: { orderBy: 'name', order: 'ASC' }, + name_desc: { orderBy: 'name', order: 'DESC' }, + date_asc: { orderBy: 'submitted_at', order: 'ASC' }, + date_desc: { orderBy: 'submitted_at', order: 'DESC' }, + type_asc: { orderBy: 'type', order: 'ASC' }, + type_desc: { orderBy: 'type', order: 'DESC' }, + } + + const orderByQuery = ORDER_MAPPING[orderBy as PatientRequirementsOrder] ?? { + orderBy: 'submitted_at', + order: 'DESC', + } + + const { data: response, isLoading } = useQuery({ + queryKey: [QUERY_CACHE_KEYS.approvals.pending, search, page, orderByQuery], + queryFn: () => + api<{ requirements: PatientRequirement[]; total: number }>( + '/patient-requirements', + { + params: { + page, + perPage, + search, + status: 'under_review', + ...orderByQuery, + }, + }, + ), + }) + + const requirements = response?.data?.requirements ?? [] + const isEmpty = requirements.length === 0 + const hasActiveFilters = !!search + + useEffect(() => { + if (response?.data) { + setStableTotal(response.data.total) + } + }, [response?.data]) + + return ( + <> + + + + + + + + + + {isLoading && } + + {isEmpty && !isLoading && ( +
+ {hasActiveFilters + ? 'Nenhuma aprovação encontrada para os filtros aplicados.' + : 'Nenhuma aprovação em análise encontrada.'} +
+ )} + + {!isEmpty && + requirements.map((requirement) => ( + +

+ {requirement.patient.name} +

+
+ + + Recebido{' '} + {getTimeDistanceToNow(requirement.submitted_at ?? '')} + +
+ +
+ Tipo de solicitação: + + {PATIENT_REQUIREMENT_TYPES[requirement.type]} + +
+
+ ))} +
+ + + + ) +}