diff --git a/client/src/app/quotes/components/QuoteItemsInlineRowActions.test.tsx b/client/src/app/quotes/components/QuoteItemsInlineRowActions.test.tsx new file mode 100644 index 0000000..3b5f65e --- /dev/null +++ b/client/src/app/quotes/components/QuoteItemsInlineRowActions.test.tsx @@ -0,0 +1,56 @@ +import { act } from "react"; +import { createRoot } from "react-dom/client"; +import type { ButtonHTMLAttributes } from "react"; +import { QuoteItemsInlineRowActions } from "./QuoteItemsInlineRowActions"; + +declare global { + var IS_REACT_ACT_ENVIRONMENT: boolean; +} + +globalThis.IS_REACT_ACT_ENVIRONMENT = true; + +jest.mock("i18next", () => ({ t: (key: string) => key })); +jest.mock("@/ui", () => ({ + Button: (props: ButtonHTMLAttributes) => + + + + +); diff --git a/client/src/app/quotes/components/QuoteItemsSortableDataTable.tsx b/client/src/app/quotes/components/QuoteItemsSortableDataTable.tsx index c67e5d7..21c5a18 100644 --- a/client/src/app/quotes/components/QuoteItemsSortableDataTable.tsx +++ b/client/src/app/quotes/components/QuoteItemsSortableDataTable.tsx @@ -30,13 +30,14 @@ import { getCoreRowModel, useReactTable, } from "@tanstack/react-table"; -import { useMemo, useState } from "react"; +import { Fragment, useMemo, useState } from "react"; import { createPortal } from "react-dom"; import { FieldValues, UseFieldArrayReturn } from "react-hook-form"; import { AppendBlockRowButton } from "./AppendBlockRowButton"; import { AppendCatalogArticleRowButton } from "./AppendCatalogArticleRowButton"; import { AppendEmptyRowButton } from "./AppendEmptyRowButton"; import { QuoteItemsSortableDataTableToolbar } from "./QuoteItemsSortableDataTableToolbar"; +import { QuoteItemsInlineRowActions } from "./QuoteItemsInlineRowActions"; import { QuoteItemsSortableTableRow } from "./QuoteItemsSortableTableRow"; export type RowIdData = { [x: string]: any }; @@ -120,6 +121,7 @@ export function QuoteItemsSortableDataTable) { const [rowSelection, setRowSelection] = useState({}); const [activeId, setActiveId] = useState(); + const [activeRowId, setActiveRowId] = useState(null); const sorteableRowIds = useMemo(() => data.map((item) => item.id), [data]); @@ -337,24 +339,46 @@ export function QuoteItemsSortableDataTable - {filterItems(table.getRowModel().rows).map((row) => ( - ).id} id={(row as Row).id}> - {(row as Row).getVisibleCells().map((cell) => ( - { + const typedRow = row as Row; + const isActive = typedRow.id === activeRowId; + + return ( + + setActiveRowId(typedRow.id)} > - {flexRender(cell.column.columnDef.cell, cell.getContext())} - - ))} - - ))} + {typedRow.getVisibleCells().map((cell) => ( + + {flexRender(cell.column.columnDef.cell, cell.getContext())} + + ))} + + {isActive && ( + + + setActiveRowId(null)} + /> + + + )} + + ); + })} diff --git a/client/src/app/quotes/components/QuoteItemsSortableTableRow.tsx b/client/src/app/quotes/components/QuoteItemsSortableTableRow.tsx index 2266646..64a0448 100644 --- a/client/src/app/quotes/components/QuoteItemsSortableTableRow.tsx +++ b/client/src/app/quotes/components/QuoteItemsSortableTableRow.tsx @@ -12,6 +12,11 @@ export interface QuoteItemsSortableTableRowContextValue { ref(node: HTMLElement | null): void; isDragging: boolean; } + +export interface QuoteItemsSortableTableRowProps extends QuoteItemsSortableProps { + isActive?: boolean; + onActivate?: () => void; +} export const QuoteItemsSortableTableRowContext = createContext({ attributes: { role: "button", @@ -37,7 +42,9 @@ function animateLayoutChanges(args: any) { export function QuoteItemsSortableTableRow({ id, children, -}: PropsWithChildren) { + isActive = false, + onActivate, +}: PropsWithChildren) { const { attributes, isDragging, @@ -73,10 +80,15 @@ export function QuoteItemsSortableTableRow({ id={String(id)} className={cn( isDragging ? "opacity-60" : "opacity-100", - "m-0 hover:bg-muted hover:focus-within:bg-accent focus-within:bg-accent" + isActive + ? "border border-destructive/30 border-b-0 border-l-4 border-l-destructive bg-destructive/5 hover:bg-destructive/5 focus-within:bg-destructive/5" + : "hover:bg-muted hover:focus-within:bg-accent focus-within:bg-accent", + "m-0" )} ref={setNodeRef} style={style} + onClick={onActivate} + onFocusCapture={onActivate} > {children} diff --git a/client/src/app/quotes/components/editors/QuoteDetailsCardEditor.tsx b/client/src/app/quotes/components/editors/QuoteDetailsCardEditor.tsx index fe52b14..bae6675 100644 --- a/client/src/app/quotes/components/editors/QuoteDetailsCardEditor.tsx +++ b/client/src/app/quotes/components/editors/QuoteDetailsCardEditor.tsx @@ -12,7 +12,6 @@ import { useToast } from "@/ui/use-toast"; import { CurrencyData, Language, Quantity, UnitPrice } from "@shared/contexts"; import { ColumnDef } from "@tanstack/react-table"; import { t } from "i18next"; -import { ChevronDownIcon, ChevronUpIcon, CopyIcon, Trash2Icon } from "lucide-react"; import { useCallback, useState } from "react"; import { useFieldArray, useFormContext } from "react-hook-form"; import { useDetailColumns } from "../../hooks"; @@ -192,39 +191,6 @@ export const QuoteDetailsCardEditor = ({ { enableDragHandleColumn: true, enableSelectionColumn: true, - enableActionsColumn: true, - rowActionFn: (props) => { - const { table, row } = props; - return [ - { - label: t("common.duplicate_row"), - icon: , - onClick: () => table.options.meta?.duplicateItems(row.index), - }, - { - label: t("common.insert_row_above"), - icon: , - onClick: () => table.options.meta?.insertItem(row.index), - }, - { - label: t("common.insert_row_below"), - icon: , - onClick: () => table.options.meta?.insertItem(row.index + 1), - }, - - { - label: "-", - }, - { - label: t("common.remove_row"), - //shortcut: "⌘⌫", - icon: , - onClick: () => { - table.options.meta?.deleteItems(row.index); - }, - }, - ]; - }, } );