En el filtro de la búsqueda del catálogo, poner filtros complejos compuestos por AND
This commit is contained in:
parent
560fe06a08
commit
53ea788142
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@uecko-presupuestador/client",
|
"name": "@uecko-presupuestador/client",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.0.7",
|
"version": "1.0.8",
|
||||||
"author": "Rodax Software <dev@rodax-software.com>",
|
"author": "Rodax Software <dev@rodax-software.com>",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { Container, FormTextField } from "@/components";
|
import { Container, FormTextField } from "@/components";
|
||||||
import { FormSubmitButton } from "@/components/Forms/FormSubmitButton";
|
import { FormSubmitButton } from "@/components/Forms/FormSubmitButton";
|
||||||
import { UeckoLogo } from "@/components/UeckoLogo/UeckoLogo";
|
import { UeckoLogo } from "@/components/UeckoLogo/UeckoLogo";
|
||||||
import { useLogin } from "@/lib/hooks";
|
import { useIsLoggedIn, useLogin } from "@/lib/hooks";
|
||||||
import {
|
import {
|
||||||
Alert,
|
Alert,
|
||||||
AlertDescription,
|
AlertDescription,
|
||||||
@ -42,6 +42,9 @@ const languages = [
|
|||||||
|
|
||||||
export const LoginPageWithLanguageSelector = () => {
|
export const LoginPageWithLanguageSelector = () => {
|
||||||
const { t, i18n } = useTranslation();
|
const { t, i18n } = useTranslation();
|
||||||
|
|
||||||
|
const { isSuccess: isLoggedInSuccess, data: { authenticated = false } = {} } = useIsLoggedIn();
|
||||||
|
|
||||||
const [language, setLanguage] = useState(i18n.language);
|
const [language, setLanguage] = useState(i18n.language);
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
@ -54,6 +57,12 @@ export const LoginPageWithLanguageSelector = () => {
|
|||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isLoggedInSuccess && authenticated) {
|
||||||
|
navigate("/quotes", { replace: true });
|
||||||
|
}
|
||||||
|
}, [isLoggedInSuccess, authenticated]);
|
||||||
|
|
||||||
const changeLanguage = (lng: string) => {
|
const changeLanguage = (lng: string) => {
|
||||||
i18n.changeLanguage(lng);
|
i18n.changeLanguage(lng);
|
||||||
setLanguage(lng);
|
setLanguage(lng);
|
||||||
|
|||||||
@ -4,18 +4,16 @@ import { ButtonGroup } from "@/components";
|
|||||||
import { DataTableFilterField, useDataTableContext } from "@/lib/hooks";
|
import { DataTableFilterField, useDataTableContext } from "@/lib/hooks";
|
||||||
import { Badge, Button, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/ui";
|
import { Badge, Button, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/ui";
|
||||||
import { t } from "i18next";
|
import { t } from "i18next";
|
||||||
import { PlusIcon, XIcon } from "lucide-react";
|
import { PlusIcon, SearchIcon, XIcon } from "lucide-react";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
interface CatalogDataTableFilterProps<TData> extends React.HTMLAttributes<HTMLDivElement> {
|
interface CatalogDataTableFilterProps<TData> extends React.HTMLAttributes<HTMLDivElement> {
|
||||||
table: Table<TData>;
|
table: Table<TData>;
|
||||||
filterFields?: DataTableFilterField<TData>[];
|
filterFields?: DataTableFilterField<TData>[];
|
||||||
fullWidthFilter?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function CatalogDataTableFilter<TData>({
|
export function CatalogDataTableFilter<TData>({
|
||||||
table,
|
table,
|
||||||
fullWidthFilter,
|
|
||||||
className,
|
className,
|
||||||
children,
|
children,
|
||||||
...props
|
...props
|
||||||
@ -54,9 +52,10 @@ export function CatalogDataTableFilter<TData>({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<TooltipProvider>
|
<TooltipProvider>
|
||||||
<div className='space-y-2'>
|
<div className='w-full space-y-2'>
|
||||||
<div className='relative p-2 border rounded-md border-input'>
|
<div className='relative flex items-center flex-1 p-2 space-x-2 border rounded-md border-input'>
|
||||||
<div className='flex flex-wrap items-center gap-2'>
|
<SearchIcon className='w-4 h-4 text-gray-500' />
|
||||||
|
<div className='flex flex-wrap items-center flex-1 gap-2'>
|
||||||
{globalFilter &&
|
{globalFilter &&
|
||||||
globalFilter.map((filterTerm) => (
|
globalFilter.map((filterTerm) => (
|
||||||
<Badge
|
<Badge
|
||||||
@ -75,10 +74,10 @@ export function CatalogDataTableFilter<TData>({
|
|||||||
<XIcon className='w-4 h-4' />
|
<XIcon className='w-4 h-4' />
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent>
|
<TooltipContent>
|
||||||
<p>Quitar este término del filtro</p>
|
<p>{t("catalog.filter.badget_remove_tooltip")}</p>
|
||||||
</TooltipContent>
|
</TooltipContent>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<span className='sr-only'>Eliminar filtro {filterTerm}</span>
|
<span className='sr-only'>{t("catalog.filter.badget_remove_tooltip")}</span>
|
||||||
</Button>
|
</Button>
|
||||||
</Badge>
|
</Badge>
|
||||||
))}
|
))}
|
||||||
@ -88,7 +87,7 @@ export function CatalogDataTableFilter<TData>({
|
|||||||
value={inputValue}
|
value={inputValue}
|
||||||
onChange={(e) => setInputValue(e.target.value)}
|
onChange={(e) => setInputValue(e.target.value)}
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
placeholder='Escribe aquí para filtrar...'
|
placeholder={t("common.filter.input_placeholder")}
|
||||||
className='flex-1 w-full h-8 bg-transparent outline-none placeholder:text-muted-foreground'
|
className='flex-1 w-full h-8 bg-transparent outline-none placeholder:text-muted-foreground'
|
||||||
/>
|
/>
|
||||||
<ButtonGroup>
|
<ButtonGroup>
|
||||||
@ -101,11 +100,11 @@ export function CatalogDataTableFilter<TData>({
|
|||||||
className='h-8 px-2 transition-all lg:px-3'
|
className='h-8 px-2 transition-all lg:px-3'
|
||||||
>
|
>
|
||||||
<XIcon className='w-4 h-4 mr-2' />
|
<XIcon className='w-4 h-4 mr-2' />
|
||||||
{t("common.reset_filter")}
|
{t("common.filter.reset_filter")}
|
||||||
</Button>
|
</Button>
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent>
|
<TooltipContent>
|
||||||
<p>Quitar todos los términos del filtro</p>
|
<p>{t("common.filter.reset_filter")}</p>
|
||||||
</TooltipContent>
|
</TooltipContent>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
@ -118,22 +117,18 @@ export function CatalogDataTableFilter<TData>({
|
|||||||
className='w-8 h-8 p-0 hover:bg-muted'
|
className='w-8 h-8 p-0 hover:bg-muted'
|
||||||
>
|
>
|
||||||
<PlusIcon className='w-4 h-4' />
|
<PlusIcon className='w-4 h-4' />
|
||||||
<span className='sr-only'>Añadir término al filtro</span>
|
<span className='sr-only'>{t("common.filter.button_add_term")}</span>
|
||||||
</Button>
|
</Button>
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent>
|
<TooltipContent>
|
||||||
<p>Añadir término al filtro (o pulsa Enter)</p>
|
<p>{t("common.filter.button_add_term_tooltip")}</p>
|
||||||
</TooltipContent>
|
</TooltipContent>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<p className='text-sm text-muted-foreground'>{t("common.filter.help_text")}</p>
|
||||||
<p className='text-sm text-muted-foreground'>
|
|
||||||
Presiona Enter o haz clic en el botón + para añadir un término al filtro. Usa múltiples
|
|
||||||
términos para una búsqueda más amplia.
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import { DataTableSkeleton, ErrorOverlay, SimpleEmptyState } from "@/components";
|
import { DataTableSkeleton, ErrorOverlay, SimpleEmptyState } from "@/components";
|
||||||
|
|
||||||
|
import { CatalogDataTableFilter } from "@/app/catalog/components/CatalogDataTableFilter";
|
||||||
import { useCatalogList } from "@/app/catalog/hooks";
|
import { useCatalogList } from "@/app/catalog/hooks";
|
||||||
import { DataTable } from "@/components";
|
import { DataTable } from "@/components";
|
||||||
import { DataTableToolbar } from "@/components/DataTable/DataTableToolbar";
|
|
||||||
import { useDataTable, useDataTableContext } from "@/lib/hooks";
|
import { useDataTable, useDataTableContext } from "@/lib/hooks";
|
||||||
import { Button } from "@/ui";
|
import { Button } from "@/ui";
|
||||||
import { IListArticles_Response_DTO, MoneyValue } from "@shared/contexts";
|
import { IListArticles_Response_DTO, MoneyValue } from "@shared/contexts";
|
||||||
@ -141,7 +141,7 @@ export const CatalogPickerDataTable = ({
|
|||||||
paginationOptions={{ visible: true, enablePageSizeSelector: false }}
|
paginationOptions={{ visible: true, enablePageSizeSelector: false }}
|
||||||
footerClassName='px-10 pt-2 border-t'
|
footerClassName='px-10 pt-2 border-t'
|
||||||
>
|
>
|
||||||
<DataTableToolbar fullWidthFilter={true} table={table} />
|
<CatalogDataTableFilter table={table} />
|
||||||
</DataTable>
|
</DataTable>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -215,7 +215,6 @@ export const QuoteDetailsCardEditor = ({
|
|||||||
|
|
||||||
const handleAppendCatalogArticle = useCallback(
|
const handleAppendCatalogArticle = useCallback(
|
||||||
(article: any, quantity: number = 1) => {
|
(article: any, quantity: number = 1) => {
|
||||||
console.log(article);
|
|
||||||
fieldActions.append({
|
fieldActions.append({
|
||||||
...article,
|
...article,
|
||||||
quantity: {
|
quantity: {
|
||||||
|
|||||||
@ -86,7 +86,6 @@ export default function SupportModal() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
console.log("handleClose", incidenceValue.trim());
|
|
||||||
if (incidenceValue.trim()) {
|
if (incidenceValue.trim()) {
|
||||||
setShowConfirmDialog(true);
|
setShowConfirmDialog(true);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { cn } from "@/lib/utils";
|
|||||||
import { Button, Input } from "@/ui";
|
import { Button, Input } from "@/ui";
|
||||||
import { t } from "i18next";
|
import { t } from "i18next";
|
||||||
import { SearchIcon, XIcon } from "lucide-react";
|
import { SearchIcon, XIcon } from "lucide-react";
|
||||||
|
import { ChangeEvent } from "react";
|
||||||
import { DataTableColumnOptions } from "./DataTableColumnOptions";
|
import { DataTableColumnOptions } from "./DataTableColumnOptions";
|
||||||
|
|
||||||
interface DataTableToolbarProps<TData> extends React.HTMLAttributes<HTMLDivElement> {
|
interface DataTableToolbarProps<TData> extends React.HTMLAttributes<HTMLDivElement> {
|
||||||
@ -21,6 +22,15 @@ export function DataTableToolbar<TData>({
|
|||||||
}: DataTableToolbarProps<TData>) {
|
}: DataTableToolbarProps<TData>) {
|
||||||
const { globalFilter, isFiltered, setGlobalFilter, resetGlobalFilter } = useDataTableContext();
|
const { globalFilter, isFiltered, setGlobalFilter, resetGlobalFilter } = useDataTableContext();
|
||||||
|
|
||||||
|
const handleOnChange = (event: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const value = String(event.target.value);
|
||||||
|
if (value === "") {
|
||||||
|
resetGlobalFilter();
|
||||||
|
} else {
|
||||||
|
setGlobalFilter([value]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
@ -33,9 +43,9 @@ export function DataTableToolbar<TData>({
|
|||||||
<SearchIcon className='w-4 h-4 text-gray-500' />
|
<SearchIcon className='w-4 h-4 text-gray-500' />
|
||||||
<Input
|
<Input
|
||||||
key='global-filter'
|
key='global-filter'
|
||||||
placeholder={t("common.filter_placeholder")}
|
placeholder={t("common.filter.input_placeholder")}
|
||||||
value={globalFilter}
|
value={globalFilter}
|
||||||
onChange={(event) => setGlobalFilter(String(event.target.value))}
|
onChange={handleOnChange}
|
||||||
className={cn("h-8 w-full transition-all")}
|
className={cn("h-8 w-full transition-all")}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@ -46,7 +56,7 @@ export function DataTableToolbar<TData>({
|
|||||||
className='h-8 px-2 transition-all lg:px-3'
|
className='h-8 px-2 transition-all lg:px-3'
|
||||||
>
|
>
|
||||||
<XIcon className='w-4 h-4 mr-2' />
|
<XIcon className='w-4 h-4 mr-2' />
|
||||||
{t("common.reset_filter")}
|
{t("common.filter.reset_filter")}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -206,12 +206,6 @@ export function SortableDataTable({ columns, data, actions }: SortableDataTableP
|
|||||||
updateItem: (rowIndex: number, rowData: any, fieldName: string, value: unknown) => {
|
updateItem: (rowIndex: number, rowData: any, fieldName: string, value: unknown) => {
|
||||||
// Skip page index reset until after next rerender
|
// Skip page index reset until after next rerender
|
||||||
// skipAutoResetPageIndex();
|
// skipAutoResetPageIndex();
|
||||||
console.log({
|
|
||||||
rowIndex,
|
|
||||||
rowData,
|
|
||||||
fieldName,
|
|
||||||
value,
|
|
||||||
});
|
|
||||||
|
|
||||||
actions.update(rowIndex, { ...rowData, [`${fieldName}`]: value });
|
actions.update(rowIndex, { ...rowData, [`${fieldName}`]: value });
|
||||||
},
|
},
|
||||||
|
|||||||
@ -127,7 +127,7 @@ export const createAxiosDataProvider = (
|
|||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append(key || "file", file);
|
formData.append(key || "file", file);
|
||||||
|
|
||||||
console.log(file);
|
//console.log(file);
|
||||||
|
|
||||||
const response = await httpClient.post<R>(url, formData, {
|
const response = await httpClient.post<R>(url, formData, {
|
||||||
headers: {
|
headers: {
|
||||||
@ -181,7 +181,7 @@ export const createAxiosDataProvider = (
|
|||||||
throw new Error('"url" or "path" param is missing');
|
throw new Error('"url" or "path" param is missing');
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(apiUrl, path, url, requestUrl.toString());
|
//console.log(apiUrl, path, url, requestUrl.toString());
|
||||||
|
|
||||||
// Preparar la respuesta personalizada
|
// Preparar la respuesta personalizada
|
||||||
let customResponse;
|
let customResponse;
|
||||||
|
|||||||
@ -153,7 +153,7 @@ export function useDataTable<TData, TValue>({
|
|||||||
const sortingUpdater: OnChangeFn<SortingState> = (updater) => {
|
const sortingUpdater: OnChangeFn<SortingState> = (updater) => {
|
||||||
if (typeof updater === "function") {
|
if (typeof updater === "function") {
|
||||||
const newSorting = updater(sorting);
|
const newSorting = updater(sorting);
|
||||||
console.log(newSorting);
|
//console.log(newSorting);
|
||||||
//setSorting(newSorting);
|
//setSorting(newSorting);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -35,7 +35,7 @@ export const UnsavedWarnProvider = ({ children }: PropsWithChildren) => {
|
|||||||
<CustomDialog
|
<CustomDialog
|
||||||
//type='warning'
|
//type='warning'
|
||||||
onCancel={() => {
|
onCancel={() => {
|
||||||
console.log("onCancel");
|
//console.log("onCancel");
|
||||||
onCancel();
|
onCancel();
|
||||||
}}
|
}}
|
||||||
onConfirm={() => onConfirm()}
|
onConfirm={() => onConfirm()}
|
||||||
|
|||||||
@ -29,8 +29,6 @@
|
|||||||
"go_to_prev_page": "Go to previous page",
|
"go_to_prev_page": "Go to previous page",
|
||||||
"go_to_next_page": "Go to next page",
|
"go_to_next_page": "Go to next page",
|
||||||
"go_to_last_page": "Go to last page",
|
"go_to_last_page": "Go to last page",
|
||||||
"filter_placeholder": "Type here to filter...",
|
|
||||||
"reset_filter": "Reset filter",
|
|
||||||
"error": "Error",
|
"error": "Error",
|
||||||
"actions": "Actions",
|
"actions": "Actions",
|
||||||
"open_menu": "Open menu",
|
"open_menu": "Open menu",
|
||||||
@ -57,7 +55,16 @@
|
|||||||
"duplicate": "Duplicate",
|
"duplicate": "Duplicate",
|
||||||
"print": "Print",
|
"print": "Print",
|
||||||
"disable_preview": "Disable preview",
|
"disable_preview": "Disable preview",
|
||||||
"enable_preview": "Enable preview"
|
"enable_preview": "Enable preview",
|
||||||
|
"filter": {
|
||||||
|
"reset_filter": "Reset filter",
|
||||||
|
"badget_remove_tooltip": "Remove this filter term",
|
||||||
|
"input_placeholder": "Type here to filter...",
|
||||||
|
"button_add_term": "Add filter term",
|
||||||
|
"button_add_term_tooltip": "Add filter term (or press Enter)",
|
||||||
|
"button_remove_all": "Remove all terms from filter",
|
||||||
|
"help_text": "Press Enter or click the + button to add a term to the filter. Use multiple terms for a broader search."
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
"loading_indicator": {
|
"loading_indicator": {
|
||||||
|
|||||||
@ -29,8 +29,6 @@
|
|||||||
"go_to_prev_page": "Ir a la página anterior",
|
"go_to_prev_page": "Ir a la página anterior",
|
||||||
"go_to_next_page": "Ir a la página siguiente",
|
"go_to_next_page": "Ir a la página siguiente",
|
||||||
"go_to_last_page": "Ir a la última página",
|
"go_to_last_page": "Ir a la última página",
|
||||||
"filter_placeholder": "Escribe aquí para filtrar...",
|
|
||||||
"reset_filter": "Quitar el filtro",
|
|
||||||
"error": "Error",
|
"error": "Error",
|
||||||
"actions": "Acciones",
|
"actions": "Acciones",
|
||||||
"open_menu": "Abrir el menú",
|
"open_menu": "Abrir el menú",
|
||||||
@ -57,7 +55,16 @@
|
|||||||
"duplicate": "Duplicar",
|
"duplicate": "Duplicar",
|
||||||
"print": "Imprimir",
|
"print": "Imprimir",
|
||||||
"disable_preview": "Ocultar vista previa",
|
"disable_preview": "Ocultar vista previa",
|
||||||
"enable_preview": "Mostrar vista previa"
|
"enable_preview": "Mostrar vista previa",
|
||||||
|
"filter": {
|
||||||
|
"reset_filter": "Quitar el filtro",
|
||||||
|
"badget_remove_tooltip": "Quitar este término del filtro",
|
||||||
|
"input_placeholder": "Escribe aquí para filtrar...",
|
||||||
|
"button_add_term": "Añadir término al filtro",
|
||||||
|
"button_add_term_tooltip": "Añadir término al filtro (o pulsa Enter)",
|
||||||
|
"button_remove_all": "Quitar todos los términos del filtro",
|
||||||
|
"help_text": "Presiona Enter o haz clic en el botón + para añadir un término al filtro. Usa múltiples términos para una búsqueda más amplia."
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
"LoadingIndicator": {
|
"LoadingIndicator": {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "uecko-presupuestador",
|
"name": "uecko-presupuestador",
|
||||||
"version": "1.0.6",
|
"version": "1.0.8",
|
||||||
"author": "Rodax Software <dev@rodax-software.com>",
|
"author": "Rodax Software <dev@rodax-software.com>",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@uecko-presupuestador/server",
|
"name": "@uecko-presupuestador/server",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.0.6",
|
"version": "1.0.8",
|
||||||
"author": "Rodax Software <dev@rodax-software.com>",
|
"author": "Rodax Software <dev@rodax-software.com>",
|
||||||
"main": "./src/index.ts",
|
"main": "./src/index.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@uecko-presupuestador/shared",
|
"name": "@uecko-presupuestador/shared",
|
||||||
"private": false,
|
"private": false,
|
||||||
"version": "1.0.6",
|
"version": "1.0.8",
|
||||||
"main": "./index.ts",
|
"main": "./index.ts",
|
||||||
"author": "Rodax Software <dev@rodax-software.com>",
|
"author": "Rodax Software <dev@rodax-software.com>",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user