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 "./axios";
|
||||||
|
export * from "./build-text-filters";
|
||||||
export * from "./datasource-context";
|
export * from "./datasource-context";
|
||||||
export * from "./datasource.interface";
|
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 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
|
||||||
|
|||||||
@ -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();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user