Facturas de cliente

This commit is contained in:
David Arranz 2025-07-18 13:24:03 +02:00
parent 0e59a18cbb
commit 0e6ecaad22
5 changed files with 37 additions and 39 deletions

View File

@ -0,0 +1,13 @@
/**
* Utilidad para construir filtros de texto tipo CONTAINS
* para los campos especificados.
*/
export function buildTextFilters(fields: string[], value: string) {
if (!value.trim()) return [];
return fields.map((field) => ({
field,
operator: "CONTAINS" as const,
value,
}));
}

View File

@ -1,3 +1,4 @@
export * from "./axios"; export * from "./axios";
export * from "./build-text-filters";
export * from "./datasource-context"; export * from "./datasource-context";
export * from "./datasource.interface"; export * from "./datasource.interface";

View File

@ -0,0 +1 @@
export * from "./dto";

View File

@ -2,6 +2,8 @@ import { LookupDialog } from "@repo/rdx-ui/components";
import DataTable, { TableColumn } from "react-data-table-component"; import DataTable, { TableColumn } from "react-data-table-component";
import { useDebounce } from "use-debounce"; import { useDebounce } from "use-debounce";
import { buildTextFilters } from "@erp/core/client";
import { ListCustomersResultDTO } from "@erp/customer-invoices/common/dto";
import { import {
Badge, Badge,
Button, Button,
@ -19,13 +21,7 @@ import { Building, Calendar, Mail, MapPin, Phone, Plus, User } from "lucide-reac
import { useState } from "react"; import { useState } from "react";
import { useCustomersQuery } from "../hooks"; import { useCustomersQuery } from "../hooks";
type Customer = { type Customer = ListCustomersResultDTO["items"][number];
id: string;
name: string;
email: string;
company: string;
status: string;
};
const columns: TableColumn<Customer>[] = [ const columns: TableColumn<Customer>[] = [
{ {
@ -36,19 +32,17 @@ const columns: TableColumn<Customer>[] = [
{ {
name: "Email", name: "Email",
selector: (row) => row.email, selector: (row) => row.email,
sortable: true,
}, },
{ {
name: "Empresa", name: "Empresa",
selector: (row) => row.company, selector: (row) => row.trade_name ?? row.metadata?.company_name ?? "-",
sortable: false,
}, },
{ {
name: "Estado", name: "Estado",
selector: (row) => row.status, selector: (row) => row.status,
cell: (row) => ( sortable: false,
<span className={row.status === "Activo" ? "text-green-600" : "text-gray-400"}>
{row.status}
</span>
),
}, },
]; ];
@ -128,30 +122,19 @@ async function fetchClientes(search: string): Promise<Customer[]> {
} }
export const ClientSelector = () => { export const ClientSelector = () => {
const [isCreateOpen, setIsCreateOpen] = useState(false);
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const [search, setSearch] = useState(""); const [search, setSearch] = useState("");
const [pageNumber, setPageNumber] = useState(1); const [pageNumber, setPageNumber] = useState(1);
const [pageSize] = useState(10); const [pageSize] = useState(10);
const [selectedCustomer, setSelectedCustomer] = useState(undefined); const [selectedCustomer, setSelectedCustomer] = useState<Customer | undefined>(undefined);
const [debouncedSearch] = useDebounce(search, 400); const [debouncedSearch] = useDebounce(search, 400);
const paginated = filtered.slice((pageNumber - 1) * pageSize, pageNumber * pageSize);
const { data, isLoading, isError, error, refetch } = useCustomersQuery({ const { data, isLoading, isError, refetch } = useCustomersQuery({
filters: [ filters: buildTextFilters(["name", "email", "trade_name"], debouncedSearch),
{
field: "name",
operator: "CONTAINS",
value: debouncedSearch,
},
{
field: "trade_name",
operator: "CONTAINS",
value: debouncedSearch,
},
],
pageNumber,
pageSize, pageSize,
pageNumber,
}); });
return ( return (
@ -189,13 +172,16 @@ export const ClientSelector = () => {
open={open} open={open}
onOpenChange={setOpen} onOpenChange={setOpen}
items={data?.items ?? []} items={data?.items ?? []}
totalItems={data?.total_items ?? 0}
search={search} search={search}
onSearchChange={setSearch} onSearchChange={setSearch}
isLoading={isLoading} isLoading={isLoading}
isError={isError}
refetch={refetch}
title='Seleccionar cliente' title='Seleccionar cliente'
description='Busca un cliente por nombre, email o empresa' description='Busca un cliente por nombre, email o empresa'
onSelect={(item) => { onSelect={(customer) => {
setSelectedCustomer(item); setSelectedCustomer(customer);
setOpen(false); setOpen(false);
}} }}
onCreate={() => { onCreate={() => {
@ -203,9 +189,8 @@ export const ClientSelector = () => {
console.log("Crear nuevo cliente"); console.log("Crear nuevo cliente");
}} }}
page={pageNumber} page={pageNumber}
perPage={perPage} perPage={pageSize}
totalItems={filtered.length} onPageChange={setPageNumber}
onPageChange={setPage}
renderItem={() => null} // No se usa con DataTable renderItem={() => null} // No se usa con DataTable
renderContainer={(items) => ( renderContainer={(items) => (
<DataTable <DataTable
@ -218,7 +203,7 @@ export const ClientSelector = () => {
pagination pagination
paginationServer paginationServer
paginationPerPage={perPage} paginationPerPage={perPage}
paginationTotalRows={filtered.length} paginationTotalRows={data?.total ?? 0}
onChangePage={(p) => setPage(p)} onChangePage={(p) => setPage(p)}
highlightOnHover highlightOnHover
pointerOnHover pointerOnHover

View File

@ -1,12 +1,10 @@
import { useDataSource, useQueryKey } from "@erp/core/client"; import { useDataSource, useQueryKey } from "@erp/core/client";
import { ListCustomersQueryDTO, ListCustomersResultDTO } from "@erp/customer-invoices/common/dto"; import { ListCustomersQueryDTO, ListCustomersResultDTO } from "@erp/customers";
import { UseQueryResult, useQuery } from "@tanstack/react-query"; import { UseQueryResult, useQuery } from "@tanstack/react-query";
type UseCustomersQueryParams = ListCustomersQueryDTO;
// Obtener clientes // Obtener clientes
export const useCustomersQuery = ( export const useCustomersQuery = (
params: UseCustomersQueryParams params: ListCustomersQueryDTO
): UseQueryResult<ListCustomersResultDTO, Error> => { ): UseQueryResult<ListCustomersResultDTO, Error> => {
const dataSource = useDataSource(); const dataSource = useDataSource();
const keys = useQueryKey(); const keys = useQueryKey();