Facturas de cliente
This commit is contained in:
parent
0e59a18cbb
commit
0e6ecaad22
13
modules/core/src/web/lib/data-source/build-text-filters.tsx
Normal file
13
modules/core/src/web/lib/data-source/build-text-filters.tsx
Normal 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,
|
||||
}));
|
||||
}
|
||||
@ -1,3 +1,4 @@
|
||||
export * from "./axios";
|
||||
export * from "./build-text-filters";
|
||||
export * from "./datasource-context";
|
||||
export * from "./datasource.interface";
|
||||
|
||||
1
modules/customers/src/common/index.ts
Normal file
1
modules/customers/src/common/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from "./dto";
|
||||
@ -2,6 +2,8 @@ import { LookupDialog } from "@repo/rdx-ui/components";
|
||||
import DataTable, { TableColumn } from "react-data-table-component";
|
||||
import { useDebounce } from "use-debounce";
|
||||
|
||||
import { buildTextFilters } from "@erp/core/client";
|
||||
import { ListCustomersResultDTO } from "@erp/customer-invoices/common/dto";
|
||||
import {
|
||||
Badge,
|
||||
Button,
|
||||
@ -19,13 +21,7 @@ import { Building, Calendar, Mail, MapPin, Phone, Plus, User } from "lucide-reac
|
||||
import { useState } from "react";
|
||||
import { useCustomersQuery } from "../hooks";
|
||||
|
||||
type Customer = {
|
||||
id: string;
|
||||
name: string;
|
||||
email: string;
|
||||
company: string;
|
||||
status: string;
|
||||
};
|
||||
type Customer = ListCustomersResultDTO["items"][number];
|
||||
|
||||
const columns: TableColumn<Customer>[] = [
|
||||
{
|
||||
@ -36,19 +32,17 @@ const columns: TableColumn<Customer>[] = [
|
||||
{
|
||||
name: "Email",
|
||||
selector: (row) => row.email,
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: "Empresa",
|
||||
selector: (row) => row.company,
|
||||
selector: (row) => row.trade_name ?? row.metadata?.company_name ?? "-",
|
||||
sortable: false,
|
||||
},
|
||||
{
|
||||
name: "Estado",
|
||||
selector: (row) => row.status,
|
||||
cell: (row) => (
|
||||
<span className={row.status === "Activo" ? "text-green-600" : "text-gray-400"}>
|
||||
{row.status}
|
||||
</span>
|
||||
),
|
||||
sortable: false,
|
||||
},
|
||||
];
|
||||
|
||||
@ -128,30 +122,19 @@ async function fetchClientes(search: string): Promise<Customer[]> {
|
||||
}
|
||||
|
||||
export const ClientSelector = () => {
|
||||
const [isCreateOpen, setIsCreateOpen] = useState(false);
|
||||
const [open, setOpen] = useState(false);
|
||||
const [search, setSearch] = useState("");
|
||||
const [pageNumber, setPageNumber] = useState(1);
|
||||
const [pageSize] = useState(10);
|
||||
const [selectedCustomer, setSelectedCustomer] = useState(undefined);
|
||||
const [selectedCustomer, setSelectedCustomer] = useState<Customer | undefined>(undefined);
|
||||
|
||||
const [debouncedSearch] = useDebounce(search, 400);
|
||||
const paginated = filtered.slice((pageNumber - 1) * pageSize, pageNumber * pageSize);
|
||||
|
||||
const { data, isLoading, isError, error, refetch } = useCustomersQuery({
|
||||
filters: [
|
||||
{
|
||||
field: "name",
|
||||
operator: "CONTAINS",
|
||||
value: debouncedSearch,
|
||||
},
|
||||
{
|
||||
field: "trade_name",
|
||||
operator: "CONTAINS",
|
||||
value: debouncedSearch,
|
||||
},
|
||||
],
|
||||
pageNumber,
|
||||
const { data, isLoading, isError, refetch } = useCustomersQuery({
|
||||
filters: buildTextFilters(["name", "email", "trade_name"], debouncedSearch),
|
||||
pageSize,
|
||||
pageNumber,
|
||||
});
|
||||
|
||||
return (
|
||||
@ -189,13 +172,16 @@ export const ClientSelector = () => {
|
||||
open={open}
|
||||
onOpenChange={setOpen}
|
||||
items={data?.items ?? []}
|
||||
totalItems={data?.total_items ?? 0}
|
||||
search={search}
|
||||
onSearchChange={setSearch}
|
||||
isLoading={isLoading}
|
||||
isError={isError}
|
||||
refetch={refetch}
|
||||
title='Seleccionar cliente'
|
||||
description='Busca un cliente por nombre, email o empresa'
|
||||
onSelect={(item) => {
|
||||
setSelectedCustomer(item);
|
||||
onSelect={(customer) => {
|
||||
setSelectedCustomer(customer);
|
||||
setOpen(false);
|
||||
}}
|
||||
onCreate={() => {
|
||||
@ -203,9 +189,8 @@ export const ClientSelector = () => {
|
||||
console.log("Crear nuevo cliente");
|
||||
}}
|
||||
page={pageNumber}
|
||||
perPage={perPage}
|
||||
totalItems={filtered.length}
|
||||
onPageChange={setPage}
|
||||
perPage={pageSize}
|
||||
onPageChange={setPageNumber}
|
||||
renderItem={() => null} // No se usa con DataTable
|
||||
renderContainer={(items) => (
|
||||
<DataTable
|
||||
@ -218,7 +203,7 @@ export const ClientSelector = () => {
|
||||
pagination
|
||||
paginationServer
|
||||
paginationPerPage={perPage}
|
||||
paginationTotalRows={filtered.length}
|
||||
paginationTotalRows={data?.total ?? 0}
|
||||
onChangePage={(p) => setPage(p)}
|
||||
highlightOnHover
|
||||
pointerOnHover
|
||||
|
||||
@ -1,12 +1,10 @@
|
||||
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";
|
||||
|
||||
type UseCustomersQueryParams = ListCustomersQueryDTO;
|
||||
|
||||
// Obtener clientes
|
||||
export const useCustomersQuery = (
|
||||
params: UseCustomersQueryParams
|
||||
params: ListCustomersQueryDTO
|
||||
): UseQueryResult<ListCustomersResultDTO, Error> => {
|
||||
const dataSource = useDataSource();
|
||||
const keys = useQueryKey();
|
||||
|
||||
Loading…
Reference in New Issue
Block a user