v0.10.1
This commit is contained in:
parent
84bb21e527
commit
10a5c25fc1
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@erp/factuges-server",
|
||||
"version": "0.10.0",
|
||||
"version": "0.10.1",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "tsup src/index.ts --config tsup.config.ts",
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@erp/factuges-web",
|
||||
"private": true,
|
||||
"version": "0.10.0",
|
||||
"version": "0.10.1",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"typecheck": "tsc -p tsconfig.json --noEmit",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@erp/auth",
|
||||
"version": "0.10.0",
|
||||
"version": "0.10.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@erp/catalogs",
|
||||
"description": "Catalogs module",
|
||||
"version": "0.10.0",
|
||||
"version": "0.10.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@erp/companies",
|
||||
"description": "Companies module",
|
||||
"version": "0.10.0",
|
||||
"version": "0.10.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@erp/core",
|
||||
"version": "0.10.0",
|
||||
"version": "0.10.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@erp/customer-invoices",
|
||||
"version": "0.10.0",
|
||||
"version": "0.10.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
|
||||
@ -193,6 +193,27 @@
|
||||
"title": "Customer proformas",
|
||||
"description": "List non-archived and non-deleted customer proformas",
|
||||
"loadErrorTitle": "Unable to load the proformas list",
|
||||
"actions": {
|
||||
"view": "View",
|
||||
"edit": "Edit",
|
||||
"change_status": "Change status",
|
||||
"issue": "Issue invoice",
|
||||
"duplicate": "Duplicate",
|
||||
"archive": "Archive",
|
||||
"unarchive": "Unarchive",
|
||||
"download_pdf": "Download PDF",
|
||||
"delete": "Delete",
|
||||
"view_linked_invoice": "View linked invoice",
|
||||
"disabled_reasons": {
|
||||
"archived_scope": "This action is not available from the archived proformas list.",
|
||||
"deleted_scope": "This action is not available from the deleted proformas list.",
|
||||
"archived_only": "This action is only available for archived proformas.",
|
||||
"edit_issued": "Issued proformas cannot be edited.",
|
||||
"status_issued": "Issued proformas do not allow status changes.",
|
||||
"linked_invoice_unavailable": "This action is only available when the issued proforma has a linked invoice.",
|
||||
"operation_in_progress": "The operation is already in progress."
|
||||
}
|
||||
},
|
||||
"empty": {
|
||||
"normal": "There are no proformas.",
|
||||
"archived": "There are no archived proformas.",
|
||||
|
||||
@ -194,6 +194,27 @@
|
||||
"title": "Proformas",
|
||||
"description": "Lista las proformas no archivadas ni eliminadas",
|
||||
"loadErrorTitle": "No se pudo cargar el listado de proformas",
|
||||
"actions": {
|
||||
"view": "Ver",
|
||||
"edit": "Editar",
|
||||
"change_status": "Cambiar estado",
|
||||
"issue": "Emitir factura",
|
||||
"duplicate": "Duplicar",
|
||||
"archive": "Archivar",
|
||||
"unarchive": "Desarchivar",
|
||||
"download_pdf": "Descargar PDF",
|
||||
"delete": "Eliminar",
|
||||
"view_linked_invoice": "Ver factura vinculada",
|
||||
"disabled_reasons": {
|
||||
"archived_scope": "No se puede ejecutar desde el listado de proformas archivadas.",
|
||||
"deleted_scope": "No se puede ejecutar desde el listado de proformas eliminadas.",
|
||||
"archived_only": "Solo está disponible en proformas archivadas.",
|
||||
"edit_issued": "No se puede editar una proforma emitida.",
|
||||
"status_issued": "Una proforma emitida no admite cambios de estado.",
|
||||
"linked_invoice_unavailable": "Solo está disponible cuando la proforma emitida tiene una factura vinculada.",
|
||||
"operation_in_progress": "La operación está en curso."
|
||||
}
|
||||
},
|
||||
"empty": {
|
||||
"normal": "No hay proformas.",
|
||||
"archived": "No hay proformas archivadas.",
|
||||
|
||||
@ -20,6 +20,7 @@ import {
|
||||
import type { ColumnDef } from "@tanstack/react-table";
|
||||
import {
|
||||
CopyIcon,
|
||||
EyeIcon,
|
||||
ExternalLinkIcon,
|
||||
FileDownIcon,
|
||||
FileTextIcon,
|
||||
@ -44,7 +45,6 @@ import { ProformaStatusBadge } from "../../components";
|
||||
|
||||
type GridActionHandlers = {
|
||||
onViewClick?: (proforma: ProformaListRow) => void;
|
||||
onPreviewClick?: (proforma: ProformaListRow) => void;
|
||||
onEditClick?: (proforma: ProformaListRow) => void;
|
||||
onIssueClick?: (proforma: ProformaListRow) => void;
|
||||
onArchiveClick?: (proforma: ProformaListRow) => void;
|
||||
@ -64,6 +64,29 @@ type GridActionHandlers = {
|
||||
isPdfDownloading?: boolean;
|
||||
};
|
||||
|
||||
type RowAction = {
|
||||
key: string;
|
||||
label: string;
|
||||
icon: React.ComponentType<{ className?: string }>;
|
||||
disabled: boolean;
|
||||
disabledReason?: string;
|
||||
destructive?: boolean;
|
||||
loading?: boolean;
|
||||
href?: string;
|
||||
onClick?: () => void;
|
||||
};
|
||||
|
||||
const stopRowPropagation = (event: React.MouseEvent | React.KeyboardEvent) => {
|
||||
event.stopPropagation();
|
||||
};
|
||||
|
||||
const stopRowPropagationAndPreventDefault = (
|
||||
event: React.MouseEvent | React.KeyboardEvent
|
||||
) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
};
|
||||
|
||||
export function useProformasGridColumns(
|
||||
scope: ProformaListScope,
|
||||
actionHandlers: GridActionHandlers = {}
|
||||
@ -297,16 +320,8 @@ export function useProformasGridColumns(
|
||||
? (PROFORMA_STATUS_TRANSITIONS[proforma.status as ProformaStatus] ?? [])
|
||||
: [];
|
||||
|
||||
const canEdit = isNormalScope && !isIssued && actionHandlers.onEditClick;
|
||||
const canView = !isDeletedScope && actionHandlers.onViewClick;
|
||||
const canDuplicate = !isDeletedScope && actionHandlers.onDuplicateClick;
|
||||
const canIssue = isNormalScope && !isIssued && isApproved && actionHandlers.onIssueClick;
|
||||
const canDelete = !isDeletedScope && isDraft && actionHandlers.onDeleteClick;
|
||||
const canDownloadPdf = !isDeletedScope && actionHandlers.onDownloadPdf;
|
||||
|
||||
const isPDFLoading =
|
||||
actionHandlers.isPdfDownloading && actionHandlers.pdfDownloadingId === proforma.id;
|
||||
const stop = (e: React.MouseEvent | React.KeyboardEvent) => e.stopPropagation();
|
||||
const nextTransition = availableTransitions[0] ?? null;
|
||||
|
||||
const handleView = () => actionHandlers.onViewClick?.(proforma);
|
||||
@ -325,263 +340,259 @@ export function useProformasGridColumns(
|
||||
actionHandlers.onChangeStatusClick?.(proforma, nextTransition);
|
||||
};
|
||||
|
||||
const primaryAction = (() => {
|
||||
if (isIssued && proforma.linkedInvoiceId) {
|
||||
return {
|
||||
href: `/issed-invoices/${proforma.linkedInvoiceId}`,
|
||||
icon: ExternalLinkIcon,
|
||||
label: "Ver factura",
|
||||
};
|
||||
const getScopeReason = () => {
|
||||
if (isArchivedScope) {
|
||||
return t("pages.proformas.list.actions.disabled_reasons.archived_scope");
|
||||
}
|
||||
|
||||
if (canIssue) {
|
||||
return {
|
||||
icon: FileTextIcon,
|
||||
label: "Emitir factura",
|
||||
onClick: handleIssue,
|
||||
};
|
||||
if (isDeletedScope) {
|
||||
return t("pages.proformas.list.actions.disabled_reasons.deleted_scope");
|
||||
}
|
||||
|
||||
if (isUnarchivable) {
|
||||
return {
|
||||
icon: Undo2Icon,
|
||||
label: "Desarchivar",
|
||||
onClick: handleUnarchive,
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
if (!isDraft && nextTransition && actionHandlers.onChangeStatusClick) {
|
||||
return {
|
||||
icon: RefreshCwIcon,
|
||||
label: "Cambiar estado",
|
||||
onClick: handleChangeStatus,
|
||||
};
|
||||
}
|
||||
const visibleActions: RowAction[] = [
|
||||
{
|
||||
key: "view",
|
||||
label: t("pages.proformas.list.actions.view"),
|
||||
icon: EyeIcon,
|
||||
disabled: !actionHandlers.onViewClick || isDeletedScope,
|
||||
disabledReason: isDeletedScope
|
||||
? t("pages.proformas.list.actions.disabled_reasons.deleted_scope")
|
||||
: undefined,
|
||||
onClick: handleView,
|
||||
},
|
||||
{
|
||||
key: "edit",
|
||||
label: t("pages.proformas.list.actions.edit"),
|
||||
icon: PencilIcon,
|
||||
disabled: !actionHandlers.onEditClick || !isNormalScope || isIssued,
|
||||
disabledReason: !isNormalScope
|
||||
? getScopeReason()
|
||||
: isIssued
|
||||
? t("pages.proformas.list.actions.disabled_reasons.edit_issued")
|
||||
: undefined,
|
||||
onClick: handleEdit,
|
||||
},
|
||||
];
|
||||
|
||||
if (canEdit) {
|
||||
return {
|
||||
icon: PencilIcon,
|
||||
label: "Editar",
|
||||
onClick: handleEdit,
|
||||
};
|
||||
}
|
||||
const menuActions: RowAction[] = [
|
||||
{
|
||||
key: "linked-invoice",
|
||||
label: t("pages.proformas.list.actions.view_linked_invoice"),
|
||||
icon: ExternalLinkIcon,
|
||||
disabled: !isIssued || !proforma.linkedInvoiceId,
|
||||
disabledReason:
|
||||
!isIssued || !proforma.linkedInvoiceId
|
||||
? t("pages.proformas.list.actions.disabled_reasons.linked_invoice_unavailable")
|
||||
: undefined,
|
||||
href: proforma.linkedInvoiceId
|
||||
? `/issed-invoices/${proforma.linkedInvoiceId}`
|
||||
: undefined,
|
||||
},
|
||||
{
|
||||
key: "change-status",
|
||||
label: t("pages.proformas.list.actions.change_status"),
|
||||
icon: RefreshCwIcon,
|
||||
disabled:
|
||||
!actionHandlers.onChangeStatusClick || !isNormalScope || !nextTransition || isIssued,
|
||||
disabledReason: !isNormalScope
|
||||
? getScopeReason()
|
||||
: isIssued
|
||||
? t("pages.proformas.list.actions.disabled_reasons.status_issued")
|
||||
: !nextTransition
|
||||
? t("proformas.change_proforma_status_dialog.empty_available_statuses")
|
||||
: undefined,
|
||||
onClick: handleChangeStatus,
|
||||
},
|
||||
{
|
||||
key: "issue",
|
||||
label: t("pages.proformas.list.actions.issue"),
|
||||
icon: FileTextIcon,
|
||||
disabled: !actionHandlers.onIssueClick || !isNormalScope || !isApproved || isIssued,
|
||||
disabledReason: !isNormalScope
|
||||
? getScopeReason()
|
||||
: !isApproved
|
||||
? t("proformas.issue_proforma_dialog.not_allowed_description")
|
||||
: undefined,
|
||||
onClick: handleIssue,
|
||||
},
|
||||
{
|
||||
key: "duplicate",
|
||||
label: t("pages.proformas.list.actions.duplicate"),
|
||||
icon: CopyIcon,
|
||||
disabled: !actionHandlers.onDuplicateClick || isDeletedScope,
|
||||
disabledReason: isDeletedScope
|
||||
? t("pages.proformas.list.actions.disabled_reasons.deleted_scope")
|
||||
: undefined,
|
||||
onClick: handleDuplicate,
|
||||
},
|
||||
{
|
||||
key: "archive",
|
||||
label: t("pages.proformas.list.actions.archive"),
|
||||
icon: FolderArchiveIcon,
|
||||
disabled: !actionHandlers.onArchiveClick || !isArchivable,
|
||||
disabledReason: !actionHandlers.onArchiveClick
|
||||
? undefined
|
||||
: !isNormalScope
|
||||
? getScopeReason()
|
||||
: t("proformas.archive.error_conflict_message"),
|
||||
onClick: handleArchive,
|
||||
},
|
||||
{
|
||||
key: "unarchive",
|
||||
label: t("pages.proformas.list.actions.unarchive"),
|
||||
icon: Undo2Icon,
|
||||
disabled: !actionHandlers.onUnarchiveClick || !isUnarchivable,
|
||||
disabledReason: !actionHandlers.onUnarchiveClick
|
||||
? undefined
|
||||
: !isArchivedScope
|
||||
? t("pages.proformas.list.actions.disabled_reasons.archived_only")
|
||||
: t("proformas.unarchive.error_conflict_message"),
|
||||
onClick: handleUnarchive,
|
||||
},
|
||||
{
|
||||
key: "download-pdf",
|
||||
label: t("pages.proformas.list.actions.download_pdf"),
|
||||
icon: FileDownIcon,
|
||||
disabled: !actionHandlers.onDownloadPdf || isDeletedScope || isPDFLoading,
|
||||
disabledReason: isDeletedScope
|
||||
? t("pages.proformas.list.actions.disabled_reasons.deleted_scope")
|
||||
: isPDFLoading
|
||||
? t("pages.proformas.list.actions.disabled_reasons.operation_in_progress")
|
||||
: undefined,
|
||||
loading: isPDFLoading,
|
||||
onClick: handleDownloadPdf,
|
||||
},
|
||||
{
|
||||
key: "delete",
|
||||
label: t("pages.proformas.list.actions.delete"),
|
||||
icon: Trash2Icon,
|
||||
destructive: true,
|
||||
disabled: !actionHandlers.onDeleteClick || isDeletedScope || !isDraft,
|
||||
disabledReason: isDeletedScope
|
||||
? t("pages.proformas.list.actions.disabled_reasons.deleted_scope")
|
||||
: !isDraft
|
||||
? t("proformas.delete_proforma_dialog.error_conflict_message")
|
||||
: undefined,
|
||||
onClick: handleDelete,
|
||||
},
|
||||
];
|
||||
|
||||
if (nextTransition && actionHandlers.onChangeStatusClick) {
|
||||
return {
|
||||
icon: RefreshCwIcon,
|
||||
label: "Cambiar estado",
|
||||
onClick: handleChangeStatus,
|
||||
};
|
||||
}
|
||||
const renderIconButton = (action: RowAction) => {
|
||||
const button = (
|
||||
<Button
|
||||
aria-label={action.label}
|
||||
className="size-8 text-muted-foreground hover:text-foreground"
|
||||
disabled={action.disabled}
|
||||
onClick={(event) => {
|
||||
stopRowPropagationAndPreventDefault(event);
|
||||
if (!action.disabled) {
|
||||
action.onClick?.();
|
||||
}
|
||||
}}
|
||||
size="icon-sm"
|
||||
variant="ghost"
|
||||
>
|
||||
<action.icon className="size-4" />
|
||||
</Button>
|
||||
);
|
||||
|
||||
if (isArchivable && actionHandlers.onArchiveClick) {
|
||||
return {
|
||||
icon: FolderArchiveIcon,
|
||||
label: "Archivar",
|
||||
onClick: handleArchive,
|
||||
};
|
||||
}
|
||||
return (
|
||||
<Tooltip key={action.key}>
|
||||
<TooltipTrigger
|
||||
render={action.disabled ? <span className="inline-flex">{button}</span> : button}
|
||||
/>
|
||||
<TooltipContent>{action.disabledReason ?? action.label}</TooltipContent>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
return null;
|
||||
})();
|
||||
const renderMenuItem = (action: RowAction) => {
|
||||
const item = (
|
||||
<DropdownMenuItem
|
||||
aria-label={action.label}
|
||||
className={
|
||||
action.destructive ? "text-destructive focus:text-destructive" : undefined
|
||||
}
|
||||
disabled={action.disabled}
|
||||
onClick={(event) => {
|
||||
stopRowPropagationAndPreventDefault(event);
|
||||
if (action.disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
const quickAction = (() => {
|
||||
if (primaryAction?.label !== "Editar" && canEdit) {
|
||||
return {
|
||||
icon: PencilIcon,
|
||||
label: "Editar",
|
||||
loading: false,
|
||||
onClick: handleEdit,
|
||||
};
|
||||
}
|
||||
if (action.href) {
|
||||
window.location.href = action.href;
|
||||
return;
|
||||
}
|
||||
|
||||
return null;
|
||||
})();
|
||||
action.onClick?.();
|
||||
}}
|
||||
variant={action.destructive ? "destructive" : "default"}
|
||||
>
|
||||
{action.loading ? (
|
||||
<Spinner className="mr-2 size-4" />
|
||||
) : (
|
||||
<action.icon className="mr-2 size-4" />
|
||||
)}
|
||||
<span>{action.label}</span>
|
||||
</DropdownMenuItem>
|
||||
);
|
||||
|
||||
const menuActions = [
|
||||
canView
|
||||
? {
|
||||
icon: ExternalLinkIcon,
|
||||
label: "Ver",
|
||||
onClick: handleView,
|
||||
}
|
||||
: null,
|
||||
!isIssued &&
|
||||
nextTransition &&
|
||||
actionHandlers.onChangeStatusClick &&
|
||||
primaryAction?.label !== "Cambiar estado"
|
||||
? {
|
||||
icon: RefreshCwIcon,
|
||||
label: "Cambiar estado",
|
||||
onClick: handleChangeStatus,
|
||||
}
|
||||
: null,
|
||||
canIssue && primaryAction?.label !== "Emitir factura"
|
||||
? {
|
||||
icon: FileTextIcon,
|
||||
label: "Emitir factura",
|
||||
onClick: handleIssue,
|
||||
}
|
||||
: null,
|
||||
canEdit && primaryAction?.label !== "Editar" && quickAction?.label !== "Editar"
|
||||
? {
|
||||
icon: PencilIcon,
|
||||
label: "Editar",
|
||||
onClick: handleEdit,
|
||||
}
|
||||
: null,
|
||||
canDuplicate
|
||||
? {
|
||||
icon: CopyIcon,
|
||||
label: "Duplicar",
|
||||
onClick: handleDuplicate,
|
||||
}
|
||||
: null,
|
||||
isArchivable && actionHandlers.onArchiveClick && primaryAction?.label !== "Archivar"
|
||||
? {
|
||||
icon: FolderArchiveIcon,
|
||||
label: "Archivar",
|
||||
onClick: handleArchive,
|
||||
}
|
||||
: null,
|
||||
isUnarchivable &&
|
||||
actionHandlers.onUnarchiveClick &&
|
||||
primaryAction?.label !== "Desarchivar"
|
||||
? {
|
||||
icon: Undo2Icon,
|
||||
label: "Desarchivar",
|
||||
onClick: handleUnarchive,
|
||||
}
|
||||
: null,
|
||||
canDownloadPdf
|
||||
? {
|
||||
icon: FileDownIcon,
|
||||
label: "Descargar PDF",
|
||||
onClick: handleDownloadPdf,
|
||||
loading: isPDFLoading,
|
||||
}
|
||||
: null,
|
||||
canDelete
|
||||
? {
|
||||
destructive: true,
|
||||
icon: Trash2Icon,
|
||||
label: "Eliminar",
|
||||
onClick: handleDelete,
|
||||
}
|
||||
: null,
|
||||
].filter(Boolean);
|
||||
return (
|
||||
<Tooltip key={action.key}>
|
||||
<TooltipTrigger render={action.disabled ? <div className="w-full">{item}</div> : item} />
|
||||
<TooltipContent side="left">{action.disabledReason ?? action.label}</TooltipContent>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-end gap-1 [@media(hover:hover)_and_(pointer:fine)]:pointer-events-none [@media(hover:hover)_and_(pointer:fine)]:opacity-0 [@media(hover:hover)_and_(pointer:fine)]:transition-opacity [@media(hover:hover)_and_(pointer:fine)]:duration-150 [@media(hover:hover)_and_(pointer:fine)]:group-hover:pointer-events-auto [@media(hover:hover)_and_(pointer:fine)]:group-hover:opacity-100 [@media(hover:hover)_and_(pointer:fine)]:group-focus-within:pointer-events-auto [@media(hover:hover)_and_(pointer:fine)]:group-focus-within:opacity-100">
|
||||
{primaryAction && "href" in primaryAction ? (
|
||||
<Button className="h-8 gap-2 px-3" size="sm" variant="outline">
|
||||
<a
|
||||
href={primaryAction.href}
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
}}
|
||||
>
|
||||
<primaryAction.icon className="size-4" />
|
||||
<span>{primaryAction.label}</span>
|
||||
</a>
|
||||
</Button>
|
||||
) : primaryAction ? (
|
||||
<Button
|
||||
className="h-8 gap-2 px-3"
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
primaryAction.onClick?.();
|
||||
}}
|
||||
size="sm"
|
||||
variant="outline"
|
||||
>
|
||||
<primaryAction.icon className="size-4" />
|
||||
<span>{primaryAction.label}</span>
|
||||
</Button>
|
||||
) : null}
|
||||
|
||||
{quickAction ? (
|
||||
<TooltipProvider>
|
||||
<TooltipProvider>
|
||||
<div className="flex items-center justify-end gap-1">
|
||||
{visibleActions.map(renderIconButton)}
|
||||
<DropdownMenu>
|
||||
<Tooltip>
|
||||
<TooltipTrigger
|
||||
render={
|
||||
<Button
|
||||
className="size-8 text-muted-foreground hover:text-primary"
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
quickAction.onClick();
|
||||
}}
|
||||
size="icon"
|
||||
variant="ghost"
|
||||
>
|
||||
{quickAction.loading ? (
|
||||
<Spinner className="size-4 cursor-progress" />
|
||||
) : (
|
||||
<quickAction.icon className="size-4" />
|
||||
)}
|
||||
<span className="sr-only">{quickAction.label}</span>
|
||||
</Button>
|
||||
<DropdownMenuTrigger
|
||||
render={
|
||||
<Button
|
||||
aria-label={t("common.more_actions")}
|
||||
className="size-8 text-muted-foreground hover:text-foreground"
|
||||
onClick={stopRowPropagation}
|
||||
size="icon-sm"
|
||||
variant="ghost"
|
||||
>
|
||||
<MoreHorizontalIcon className="size-4" />
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<TooltipContent>{quickAction.label}</TooltipContent>
|
||||
<TooltipContent>{t("common.more_actions")}</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
) : null}
|
||||
|
||||
{menuActions.length > 0 ? (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger
|
||||
render={
|
||||
<Button
|
||||
className="size-8 text-muted-foreground hover:text-primary"
|
||||
onClick={stop}
|
||||
size="icon"
|
||||
variant="ghost"
|
||||
>
|
||||
<MoreHorizontalIcon className="size-4" />
|
||||
<span className="sr-only">Más acciones</span>
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
<DropdownMenuContent align="end" className="w-52" onClick={stop}>
|
||||
<DropdownMenuContent
|
||||
align="end"
|
||||
className="w-56"
|
||||
onClick={stopRowPropagation}
|
||||
>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel>Acciones</DropdownMenuLabel>
|
||||
<DropdownMenuLabel>{t("common.actions")}</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
{menuActions.length &&
|
||||
menuActions.map((action, index) =>
|
||||
action ? (
|
||||
<React.Fragment key={action.label}>
|
||||
{action.destructive && index > 0 ? <DropdownMenuSeparator /> : null}
|
||||
<DropdownMenuItem
|
||||
className={
|
||||
action.destructive
|
||||
? "text-destructive focus:text-destructive"
|
||||
: undefined
|
||||
}
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
action.onClick();
|
||||
}}
|
||||
variant={action.destructive ? "destructive" : "default"}
|
||||
>
|
||||
{"loading" in action && action.loading ? (
|
||||
<Spinner className="mr-2 size-4" />
|
||||
) : (
|
||||
<action.icon className="mr-2 size-4" />
|
||||
)}
|
||||
<span>{action.label}</span>
|
||||
</DropdownMenuItem>
|
||||
</React.Fragment>
|
||||
) : null
|
||||
)}
|
||||
{menuActions.map((action, index) => (
|
||||
<React.Fragment key={action.key}>
|
||||
{action.destructive && index > 0 ? <DropdownMenuSeparator /> : null}
|
||||
{renderMenuItem(action)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
</TooltipProvider>
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@erp/customers",
|
||||
"description": "Customers",
|
||||
"version": "0.10.0",
|
||||
"version": "0.10.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@erp/document-series",
|
||||
"description": "Document series module",
|
||||
"version": "0.10.0",
|
||||
"version": "0.10.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@erp/factuges",
|
||||
"version": "0.10.0",
|
||||
"version": "0.10.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@erp/identity",
|
||||
"description": "Identity module",
|
||||
"version": "0.10.0",
|
||||
"version": "0.10.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@erp/supplier-invoices",
|
||||
"description": "Supplier invoices",
|
||||
"version": "0.10.0",
|
||||
"version": "0.10.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@erp/suppliers",
|
||||
"description": "Suppliers",
|
||||
"version": "0.10.0",
|
||||
"version": "0.10.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "uecko-erp-2025",
|
||||
"private": true,
|
||||
"version": "0.10.0",
|
||||
"version": "0.10.1",
|
||||
"workspaces": [
|
||||
"apps/*",
|
||||
"modules/*",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@repo/i18next",
|
||||
"version": "0.10.0",
|
||||
"version": "0.10.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@repo/rdx-criteria",
|
||||
"version": "0.10.0",
|
||||
"version": "0.10.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@repo/rdx-ddd",
|
||||
"version": "0.10.0",
|
||||
"version": "0.10.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@repo/rdx-logger",
|
||||
"version": "0.10.0",
|
||||
"version": "0.10.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@repo/rdx-ui",
|
||||
"version": "0.10.0",
|
||||
"version": "0.10.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@repo/rdx-utils",
|
||||
"version": "0.10.0",
|
||||
"version": "0.10.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@repo/shadcn-ui",
|
||||
"version": "0.10.0",
|
||||
"version": "0.10.1",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"exports": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@repo/typescript-config",
|
||||
"version": "0.10.0",
|
||||
"version": "0.10.1",
|
||||
"private": true,
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user