Compare commits
3 Commits
4a53730bbb
...
8826697bc3
| Author | SHA1 | Date | |
|---|---|---|---|
| 8826697bc3 | |||
| 16303fc90e | |||
| d24f8859b7 |
@ -2,6 +2,7 @@ import { Table } from "@tanstack/react-table";
|
|||||||
|
|
||||||
import { ButtonGroup } from "@/components";
|
import { ButtonGroup } from "@/components";
|
||||||
import { DataTableFilterField, useDataTableContext } from "@/lib/hooks";
|
import { DataTableFilterField, useDataTableContext } from "@/lib/hooks";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
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, SearchIcon, XIcon } from "lucide-react";
|
import { PlusIcon, SearchIcon, XIcon } from "lucide-react";
|
||||||
@ -53,8 +54,13 @@ export function CatalogDataTableFilter<TData>({
|
|||||||
return (
|
return (
|
||||||
<TooltipProvider>
|
<TooltipProvider>
|
||||||
<div className='w-full space-y-2' {...props}>
|
<div className='w-full space-y-2' {...props}>
|
||||||
<div className='relative flex items-center flex-1 p-2 space-x-2 border rounded-md border-input'>
|
<div
|
||||||
<SearchIcon className='w-4 h-4 text-gray-500' />
|
className={cn(
|
||||||
|
"relative flex items-center flex-1 p-2 space-x-2 border rounded-md",
|
||||||
|
isFiltered ? "border-primary" : "border-input"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<SearchIcon className={cn("w-4 h-4 text-gray-500")} />
|
||||||
<div className='flex flex-wrap items-center flex-1 gap-2'>
|
<div className='flex flex-wrap items-center flex-1 gap-2'>
|
||||||
{globalFilter &&
|
{globalFilter &&
|
||||||
globalFilter.map((filterTerm) => (
|
globalFilter.map((filterTerm) => (
|
||||||
@ -95,9 +101,9 @@ export function CatalogDataTableFilter<TData>({
|
|||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger asChild>
|
<TooltipTrigger asChild>
|
||||||
<Button
|
<Button
|
||||||
variant='outline'
|
variant='ghost'
|
||||||
onClick={() => resetGlobalFilter()}
|
onClick={() => resetGlobalFilter()}
|
||||||
className='h-8 px-2 transition-all lg:px-3'
|
className='h-8 px-2 transition-all lg:px-3 text-primary'
|
||||||
>
|
>
|
||||||
<XIcon className='w-4 h-4 mr-2' />
|
<XIcon className='w-4 h-4 mr-2' />
|
||||||
{t("common.filter.reset_filter")}
|
{t("common.filter.reset_filter")}
|
||||||
|
|||||||
@ -4,12 +4,12 @@ import { CatalogDataTableFilter } from "@/app/catalog/components/CatalogDataTabl
|
|||||||
import { useCatalogList } from "@/app/catalog/hooks";
|
import { useCatalogList } from "@/app/catalog/hooks";
|
||||||
import { DataTable } from "@/components";
|
import { DataTable } from "@/components";
|
||||||
import { useDataTable, useDataTableContext } from "@/lib/hooks";
|
import { useDataTable, useDataTableContext } from "@/lib/hooks";
|
||||||
import { Button } from "@/ui";
|
import { Button, Input } from "@/ui";
|
||||||
import { IListArticles_Response_DTO, MoneyValue } from "@shared/contexts";
|
import { IListArticles_Response_DTO, MoneyValue } from "@shared/contexts";
|
||||||
import { ColumnDef, Row } from "@tanstack/react-table";
|
import { createColumnHelper, Row } from "@tanstack/react-table";
|
||||||
import { t } from "i18next";
|
import { t } from "i18next";
|
||||||
import { PackagePlusIcon } from "lucide-react";
|
import { PackagePlusIcon } from "lucide-react";
|
||||||
import { useMemo, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
export const CatalogPickerDataTable = ({
|
export const CatalogPickerDataTable = ({
|
||||||
@ -23,12 +23,19 @@ export const CatalogPickerDataTable = ({
|
|||||||
const [quantities, setQuantities] = useState<number[]>([]);
|
const [quantities, setQuantities] = useState<number[]>([]);
|
||||||
|
|
||||||
const handleQuantity = (index: number, quantity: number) => {
|
const handleQuantity = (index: number, quantity: number) => {
|
||||||
|
console.log("handleQuantity", index, quantity);
|
||||||
setQuantities((prev) => {
|
setQuantities((prev) => {
|
||||||
prev[index] = quantity;
|
const newQuantities = [...prev];
|
||||||
return prev;
|
newQuantities[index] = quantity;
|
||||||
|
return newQuantities;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const resetQuantities = () => {
|
||||||
|
console.log("reset");
|
||||||
|
setQuantities([]);
|
||||||
|
};
|
||||||
|
|
||||||
const { data, isPending, isError, error } = useCatalogList({
|
const { data, isPending, isError, error } = useCatalogList({
|
||||||
pagination: {
|
pagination: {
|
||||||
pageIndex: pagination.pageIndex,
|
pageIndex: pagination.pageIndex,
|
||||||
@ -37,7 +44,79 @@ export const CatalogPickerDataTable = ({
|
|||||||
searchTerm: globalFilter,
|
searchTerm: globalFilter,
|
||||||
});
|
});
|
||||||
|
|
||||||
const columns = useMemo<ColumnDef<IListArticles_Response_DTO>[]>(() => {
|
useEffect(() => {
|
||||||
|
resetQuantities();
|
||||||
|
}, [pagination, globalFilter, isFiltered]);
|
||||||
|
|
||||||
|
console.log(quantities);
|
||||||
|
|
||||||
|
const columnHelper = createColumnHelper<IListArticles_Response_DTO>();
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
columnHelper.accessor("description", {
|
||||||
|
id: "description",
|
||||||
|
header: () => <>{t("catalog.list.columns.description")}</>,
|
||||||
|
}),
|
||||||
|
columnHelper.accessor("points", {
|
||||||
|
id: "points",
|
||||||
|
header: () => <div className='text-right'>{t("catalog.list.columns.points")}</div>,
|
||||||
|
cell: ({ renderValue }: { renderValue: () => any }) => (
|
||||||
|
<div className='text-right'>{renderValue()}</div>
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
columnHelper.accessor("retail_price", {
|
||||||
|
id: "retail_price",
|
||||||
|
header: () => <div className='text-right'>{t("catalog.list.columns.retail_price")}</div>,
|
||||||
|
cell: ({ row }: { row: Row<IListArticles_Response_DTO> }) => {
|
||||||
|
const price = MoneyValue.create(row.original.retail_price).object;
|
||||||
|
return <div className='text-right'>{price.toFormat()}</div>;
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
columnHelper.display({
|
||||||
|
id: "quantity",
|
||||||
|
header: () => (
|
||||||
|
<div className='font-medium text-right text-foreground'>
|
||||||
|
{t("catalog.list.columns.quantity")}
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
cell: ({ row: { index } }) => {
|
||||||
|
return (
|
||||||
|
<Input
|
||||||
|
type='number'
|
||||||
|
name='quantity'
|
||||||
|
defaultValue={1}
|
||||||
|
min={1}
|
||||||
|
className='w-24'
|
||||||
|
value={quantities[index]}
|
||||||
|
onChange={(event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
handleQuantity(index, parseInt(event.target.value));
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
columnHelper.display({
|
||||||
|
id: "row-actions",
|
||||||
|
header: () => null,
|
||||||
|
cell: ({ row }: { row: Row<IListArticles_Response_DTO> }) => (
|
||||||
|
<Button
|
||||||
|
size='sm'
|
||||||
|
variant='outline'
|
||||||
|
className='h-8 gap-1'
|
||||||
|
onClick={(event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
onSelect && onSelect(row.original, quantities[row.index]);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<PackagePlusIcon className='h-3.5 w-3.5' />
|
||||||
|
<span className='sr-only xl:not-sr-only xl:whitespace-nowrap'>{t("common.add")}</span>
|
||||||
|
</Button>
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
|
/*const columns2 = useMemo<ColumnDef<IListArticles_Response_DTO>[]>(() => {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
id: "description" as const,
|
id: "description" as const,
|
||||||
@ -64,18 +143,23 @@ export const CatalogPickerDataTable = ({
|
|||||||
{
|
{
|
||||||
id: "quantity" as const,
|
id: "quantity" as const,
|
||||||
accessorKey: "quantity",
|
accessorKey: "quantity",
|
||||||
header: () => <div className='text-right'>{t("catalog.list.columns.quantity")}</div>,
|
header: () => (
|
||||||
|
<div className='font-medium text-right text-foreground'>
|
||||||
|
{t("catalog.list.columns.quantity")}
|
||||||
|
</div>
|
||||||
|
),
|
||||||
cell: ({ row: { index } }) => {
|
cell: ({ row: { index } }) => {
|
||||||
return (
|
return (
|
||||||
<input
|
<Input
|
||||||
type='number'
|
type='number'
|
||||||
name='quantity'
|
name='quantity'
|
||||||
defaultValue={1}
|
defaultValue={1}
|
||||||
min={1}
|
min={1}
|
||||||
|
className='w-24 text-right'
|
||||||
value={quantities[index]}
|
value={quantities[index]}
|
||||||
onChange={(event) => {
|
onChange={(event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
handleQuantity(index, +event.target.value);
|
handleQuantity(index, parseInt(event.target.value));
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@ -100,10 +184,10 @@ export const CatalogPickerDataTable = ({
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}, []);
|
}, []);*/
|
||||||
|
|
||||||
const { table } = useDataTable({
|
const { table } = useDataTable<IListArticles_Response_DTO, any>({
|
||||||
data: data?.items ?? [],
|
data: [...(data?.items || [])],
|
||||||
columns: columns,
|
columns: columns,
|
||||||
pageCount: data?.total_pages ?? -1,
|
pageCount: data?.total_pages ?? -1,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import { DataTableProvider } from "@/lib/hooks";
|
|||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from "@/ui";
|
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from "@/ui";
|
||||||
import { useToast } from "@/ui/use-toast";
|
import { useToast } from "@/ui/use-toast";
|
||||||
import { CurrencyData, Language, Quantity } from "@shared/contexts";
|
import { CurrencyData, Language, Quantity, UnitPrice } from "@shared/contexts";
|
||||||
import { ColumnDef } from "@tanstack/react-table";
|
import { ColumnDef } from "@tanstack/react-table";
|
||||||
import { t } from "i18next";
|
import { t } from "i18next";
|
||||||
import { ChevronDownIcon, ChevronUpIcon, CopyIcon, Trash2Icon } from "lucide-react";
|
import { ChevronDownIcon, ChevronUpIcon, CopyIcon, Trash2Icon } from "lucide-react";
|
||||||
@ -241,6 +241,18 @@ export const QuoteDetailsCardEditor = ({
|
|||||||
(block: any) => {
|
(block: any) => {
|
||||||
fieldActions.append({
|
fieldActions.append({
|
||||||
description: `${block.title}\n${block.body}`,
|
description: `${block.title}\n${block.body}`,
|
||||||
|
quantity: {
|
||||||
|
amount: null,
|
||||||
|
scale: Quantity.DEFAULT_SCALE,
|
||||||
|
},
|
||||||
|
unit_price: {
|
||||||
|
amount: null,
|
||||||
|
scale: UnitPrice.DEFAULT_SCALE,
|
||||||
|
},
|
||||||
|
discount: {
|
||||||
|
amount: null,
|
||||||
|
scale: 2,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
toast({
|
toast({
|
||||||
title: t("quotes.blocks_picker_dialog.toast_article_added"),
|
title: t("quotes.blocks_picker_dialog.toast_article_added"),
|
||||||
|
|||||||
@ -91,7 +91,13 @@ export const useQuotes = () => {
|
|||||||
value: status,
|
value: status,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
: undefined,
|
: [
|
||||||
|
{
|
||||||
|
field: "status",
|
||||||
|
operator: "ne",
|
||||||
|
value: "archived",
|
||||||
|
},
|
||||||
|
],
|
||||||
pagination,
|
pagination,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|||||||
@ -11,6 +11,7 @@ export enum CONNECTING_OPERATORS {
|
|||||||
|
|
||||||
export enum OPERATORS {
|
export enum OPERATORS {
|
||||||
EQ = "EQ",
|
EQ = "EQ",
|
||||||
|
NE = "NE",
|
||||||
NOT = "NOT",
|
NOT = "NOT",
|
||||||
IN = "IN",
|
IN = "IN",
|
||||||
NOTIN = "NOTIN",
|
NOTIN = "NOTIN",
|
||||||
@ -35,6 +36,7 @@ const SEQUELIZE_OP_MAP: {
|
|||||||
[CONNECTING_OPERATORS.OR]: Op.or,
|
[CONNECTING_OPERATORS.OR]: Op.or,
|
||||||
[CONNECTING_OPERATORS.AND]: Op.and,
|
[CONNECTING_OPERATORS.AND]: Op.and,
|
||||||
[OPERATORS.EQ]: Op.eq,
|
[OPERATORS.EQ]: Op.eq,
|
||||||
|
[OPERATORS.NE]: Op.ne,
|
||||||
[OPERATORS.NOT]: Op.not,
|
[OPERATORS.NOT]: Op.not,
|
||||||
[OPERATORS.IN]: Op.in,
|
[OPERATORS.IN]: Op.in,
|
||||||
[OPERATORS.NOTIN]: Op.notIn,
|
[OPERATORS.NOTIN]: Op.notIn,
|
||||||
@ -54,13 +56,9 @@ const SEQUELIZE_FN_MAP: {
|
|||||||
} = {
|
} = {
|
||||||
[FUNCTIONS.INCLUDES]: (field: string, val: string) =>
|
[FUNCTIONS.INCLUDES]: (field: string, val: string) =>
|
||||||
Sequelize.where(
|
Sequelize.where(
|
||||||
Sequelize.fn(
|
Sequelize.fn("FIND_IN_SET", Sequelize.literal(`'${val}'`), Sequelize.col(field)),
|
||||||
"FIND_IN_SET",
|
|
||||||
Sequelize.literal(`'${val}'`),
|
|
||||||
Sequelize.col(field),
|
|
||||||
),
|
|
||||||
SEQUELIZE_OP_MAP[OPERATORS.GT],
|
SEQUELIZE_OP_MAP[OPERATORS.GT],
|
||||||
0,
|
0
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user