This commit is contained in:
David Arranz 2024-08-25 14:14:21 +02:00
parent e1ae090c9f
commit 6a3e42acbb
12 changed files with 119 additions and 100 deletions

View File

@ -9,6 +9,7 @@ import {
} from "@/ui";
import { DataTableProvider } from "@/lib/hooks";
import { t } from "i18next";
import { CatalogPickerDataTable } from "../CatalogPickerDataTable";
export const CatalogPickerDialog = ({
@ -24,18 +25,15 @@ export const CatalogPickerDialog = ({
<Dialog modal open={isOpen} onOpenChange={onOpenChange}>
<DialogContent className='w-11/12 max-w-full'>
<DialogHeader>
<DialogTitle>Are you absolutely sure?</DialogTitle>
<DialogDescription>
This action cannot be undone. This will permanently delete your account and remove your
data from our servers.
</DialogDescription>
<DialogTitle>{t("quotes.catalog_picker_dialog.title")}</DialogTitle>
<DialogDescription>{t("quotes.catalog_picker_dialog.subtitle")}</DialogDescription>
</DialogHeader>
<DataTableProvider syncWithLocation={false} initialPageSize={5}>
<CatalogPickerDataTable onSelect={onSelect} />
</DataTableProvider>
<DialogFooter>
<Button type='submit'>Choose</Button>
<Button type='submit'>{t("common.close")}</Button>
</DialogFooter>
</DialogContent>
</Dialog>

View File

@ -11,6 +11,7 @@ import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from "@/ui";
import { CurrencyData, Language, Quantity } 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";
@ -51,6 +52,16 @@ export const QuoteDetailsCardEditor = ({
enableSorting: false,
enableResizing: false,
},*/
{
id: "description" as const,
accessorKey: "description",
header: t("quotes.form_fields.items.description.label"),
size: 24,
cell: ({ row: { index } }) => {
return <FormTextAreaField autoSize {...register(`items.${index}.description`)} />;
},
},
{
id: "quantity" as const,
accessorKey: "quantity",
@ -61,7 +72,6 @@ export const QuoteDetailsCardEditor = ({
cell: ({ row: { index } }) => {
return (
<FormQuantityField
variant='outline'
scale={0}
className='text-right'
{...register(`items.${index}.quantity`)}
@ -69,21 +79,6 @@ export const QuoteDetailsCardEditor = ({
);
},
},
{
id: "description" as const,
accessorKey: "description",
header: t("quotes.form_fields.items.description.label"),
size: 24,
cell: ({ row: { index } }) => {
return (
<FormTextAreaField
variant='outline'
autoSize
{...register(`items.${index}.description`)}
/>
);
},
},
{
id: "unit_price" as const,
accessorKey: "unit_price",
@ -93,7 +88,6 @@ export const QuoteDetailsCardEditor = ({
cell: ({ row: { index } }) => {
return (
<FormCurrencyField
variant='outline'
currency={currency}
language={language}
scale={4}
@ -113,7 +107,6 @@ export const QuoteDetailsCardEditor = ({
cell: ({ row: { index } }) => {
return (
<FormCurrencyField
variant='outline'
currency={currency}
language={language}
scale={4}
@ -134,7 +127,6 @@ export const QuoteDetailsCardEditor = ({
cell: ({ row: { index } }) => {
return (
<FormPercentageField
variant='outline'
scale={2}
className='text-right'
{...register(`items.${index}.discount`)}
@ -152,7 +144,7 @@ export const QuoteDetailsCardEditor = ({
cell: ({ row: { index } }) => {
return (
<FormCurrencyField
variant='outline'
variant='ghost'
currency={currency}
language={language}
scale={4}
@ -172,15 +164,18 @@ export const QuoteDetailsCardEditor = ({
const { table, row } = props;
return [
{
label: t("common.duplicate_rows"),
label: t("common.duplicate_row"),
icon: <CopyIcon className='w-4 h-4 mr-2' />,
onClick: () => table.options.meta?.duplicateItems(row.index),
},
{
label: t("common.insert_row_above"),
icon: <ChevronUpIcon className='w-4 h-4 mr-2' />,
onClick: () => table.options.meta?.insertItem(row.index),
},
{
label: t("common.insert_row_below"),
icon: <ChevronDownIcon className='w-4 h-4 mr-2' />,
onClick: () => table.options.meta?.insertItem(row.index + 1),
},
@ -189,7 +184,8 @@ export const QuoteDetailsCardEditor = ({
},
{
label: t("common.remove_row"),
shortcut: "⌘⌫",
//shortcut: "⌘⌫",
icon: <Trash2Icon className='w-4 h-4 mr-2' />,
onClick: () => {
table.options.meta?.deleteItems(row.index);
},

View File

@ -1,6 +1,7 @@
import {
BackHistoryButton,
FormDatePickerField,
FormGroup,
FormTextAreaField,
FormTextField,
LoadingOverlay,
@ -9,7 +10,7 @@ import { t } from "i18next";
import { SubmitButton } from "@/components";
import { useUnsavedChangesNotifier } from "@/lib/hooks";
import { Button, Form } from "@/ui";
import { Button, Form, Separator } from "@/ui";
import { joiResolver } from "@hookform/resolvers/joi";
import { ICreateQuote_Request_DTO } from "@shared/contexts";
import Joi from "joi";
@ -17,6 +18,7 @@ import { useMemo } from "react";
import { SubmitHandler, useForm } from "react-hook-form";
import { useNavigate } from "react-router-dom";
import { toast } from "react-toastify";
import SpanishJoiMessages from "../../spanish-joi-messages.json";
import { useQuotes } from "./hooks";
interface QuoteDataForm extends ICreateQuote_Request_DTO {}
@ -41,13 +43,14 @@ export const QuoteCreate = () => {
defaultValues,
resolver: joiResolver(
Joi.object({
//reference: Joi.string().required(),
customer_information: Joi.string().required(),
date: Joi.date().required(),
customer_reference: Joi.string(),
date: Joi.date().required(),
customer_information: Joi.string().required(),
}),
{
//messages: SpanishJoiMessages,
messages: {
es: SpanishJoiMessages,
},
}
),
});
@ -101,49 +104,47 @@ export const QuoteCreate = () => {
</div>
<div className='grid w-6/12 gap-6 mx-auto'>
{/*<FormTextField
className='row-span-2'
name='reference'
required
label={t("quotes.form_fields.reference.label")}
description={t("quotes.form_fields.reference.desc")}
placeholder={t("quotes.form_fields.reference.placeholder")}
/>*/}
<FormGroup
className='md:col-span-4'
title={t("quotes.create.form_groups.general.title")}
description={t("quotes.create.form_groups.general.desc")}
footerActions={
<div className='flex items-stretch justify-between flex-1'>
<Button size='sm' variant={"ghost"} onClick={() => navigate("/quotes")}>
{t("common.discard")}
</Button>
<SubmitButton size='sm' label={t("common.continue")}></SubmitButton>
</div>
}
>
<FormTextField
required
name='customer_reference'
label={t("quotes.form_fields.customer_reference.label")}
description={t("quotes.form_fields.customer_reference.desc")}
placeholder={t("quotes.form_fields.customer_reference.placeholder")}
/>
<FormTextField
className='row-span-2'
name='customer_reference'
required
label={t("quotes.form_fields.customer_reference.label")}
description={t("quotes.form_fields.customer_reference.desc")}
placeholder={t("quotes.form_fields.customer_reference.placeholder")}
/>
<FormDatePickerField
required
label={t("quotes.form_fields.date.label")}
description={t("quotes.form_fields.date.desc")}
placeholder={t("quotes.form_fields.date.placeholder")}
name='date'
/>
<FormDatePickerField
required
label={t("quotes.form_fields.date.label")}
description={t("quotes.form_fields.date.desc")}
placeholder={t("quotes.form_fields.date.placeholder")}
name='date'
/>
<Separator />
<FormTextAreaField
rows={4}
className='row-span-2'
name='customer_information'
required
label={t("quotes.form_fields.customer_information.label")}
description={t("quotes.form_fields.customer_information.desc")}
placeholder={t("quotes.form_fields.customer_information.placeholder")}
/>
<div className='flex items-center justify-around gap-2'>
<Button size='sm' variant={"outline"} onClick={() => navigate("/quotes")}>
{t("common.discard")}
</Button>
<SubmitButton size='sm' label={t("common.continue")}></SubmitButton>
</div>
<FormTextAreaField
rows={4}
className='row-span-2'
name='customer_information'
required
label={t("quotes.form_fields.customer_information.label")}
description={t("quotes.form_fields.customer_information.desc")}
placeholder={t("quotes.form_fields.customer_information.placeholder")}
/>
</FormGroup>
</div>
</div>
</form>

View File

@ -28,6 +28,23 @@ export function useDetailColumns<TData = unknown, TValue = unknown>(
// const lastSelectedId = "";
return useMemo(() => {
if (enableDragHandleColumn) {
columns.unshift({
id: "row_drag_handle",
/*header: () => (
<UnfoldVertical aria-label='Mover fila' className='items-center justify-center w-4 h-4' />
),*/
header: () => null,
cell: (info) => <DataTableRowDragHandleCell rowId={info.row.id} />,
size: 2,
minSize: 2,
maxSize: 2,
enableSorting: false,
enableHiding: false,
});
}
if (enableSelectionColumn) {
columns.unshift({
id: "select",
@ -63,23 +80,6 @@ export function useDetailColumns<TData = unknown, TValue = unknown>(
});
}
if (enableDragHandleColumn) {
columns.unshift({
id: "row_drag_handle",
/*header: () => (
<UnfoldVertical aria-label='Mover fila' className='items-center justify-center w-4 h-4' />
),*/
header: () => null,
cell: (info) => <DataTableRowDragHandleCell rowId={info.row.id} />,
size: 2,
minSize: 2,
maxSize: 2,
enableSorting: false,
enableHiding: false,
});
}
if (enableActionsColumn) {
columns.push({
id: "row_actions",

View File

@ -13,7 +13,8 @@ import {
} from "@/ui";
import { CellContext } from "@tanstack/react-table";
import { t } from "i18next";
import { MoreHorizontalIcon } from "lucide-react";
import { MoreVerticalIcon } from "lucide-react";
import { ReactElement } from "react";
export type DataTablaRowActionFunction<TData> = (
props: CellContext<TData, unknown>
@ -21,6 +22,7 @@ export type DataTablaRowActionFunction<TData> = (
export type DataTableRowActionDefinition<TData> = {
label: string | "-";
icon?: ReactElement<any, any>;
shortcut?: string;
onClick?: (props: CellContext<TData, unknown>, e: React.BaseSyntheticEvent) => void;
};
@ -46,7 +48,7 @@ export function DataTableRowActions<TData = any, TValue = unknown>({
variant='link'
className={cn("w-4 h-4 mt-2 text-ring hover:text-muted-foreground", className)}
>
<MoreHorizontalIcon className='w-4 h-4' />
<MoreVerticalIcon className='w-4 h-4' />
<span className='sr-only'>{t("common.open_menu")}</span>
</Button>
</DropdownMenuTrigger>
@ -62,8 +64,9 @@ export function DataTableRowActions<TData = any, TValue = unknown>({
key={index}
onClick={(event) => (action.onClick ? action.onClick(rowContext, event) : null)}
>
{action.icon && <>{action.icon}</>}
{action.label}
<DropdownMenuShortcut>{action.shortcut}</DropdownMenuShortcut>
{action.shortcut && <DropdownMenuShortcut>{action.shortcut}</DropdownMenuShortcut>}
</DropdownMenuItem>
)
)}

View File

@ -5,7 +5,7 @@ import { DataTableFilterField, useDataTableContext } from "@/lib/hooks";
import { cn } from "@/lib/utils";
import { Button, Input } from "@/ui";
import { t } from "i18next";
import { XIcon } from "lucide-react";
import { SearchIcon, XIcon } from "lucide-react";
import { DataTableColumnOptions } from "./DataTableColumnOptions";
interface DataTableToolbarProps<TData> extends React.HTMLAttributes<HTMLDivElement> {
@ -32,6 +32,7 @@ export function DataTableToolbar<TData>({
{...props}
>
<div className='flex items-center flex-1 space-x-2'>
<SearchIcon className='w-4 h-4 text-gray-500' />
<Input
key='global-filter'
placeholder={t("common.filter_placeholder")}

View File

@ -17,6 +17,7 @@ const formCurrencyFieldVariants = cva(
default:
"border border-input ring-offset-background focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 ",
outline: "focus-visible:border focus-visible:border-input",
ghost: "bg-transparent",
},
},
defaultVariants: {

View File

@ -66,7 +66,6 @@ export const FormDatePickerField = React.forwardRef<
<PopoverTrigger asChild>
<FormControl>
<Button
variant={"outline"}
className={cn(
"pl-3 text-left font-normal",
!field.value && "text-muted-foreground"
@ -79,7 +78,7 @@ export const FormDatePickerField = React.forwardRef<
) : (
<span>{t("common.pick_date")}</span>
)}
<CalendarIcon className='w-4 h-4 ml-auto text-input' />
<CalendarIcon className='w-4 h-4 ml-auto text-' />
</Button>
</FormControl>
</PopoverTrigger>

View File

@ -13,7 +13,7 @@ const formTextFieldVariants = cva("", {
variants: {
variant: {
default: "",
outline:
ghost:
"border-0 focus-visible:border focus-visible:border-input focus-visible:ring-0 focus-visible:ring-offset-0 ",
},
},
@ -48,6 +48,7 @@ export const FormTextField = React.forwardRef<HTMLInputElement, FormTextFieldPro
rules,
type,
variant,
required,
button,
leadIcon,
@ -62,12 +63,19 @@ export const FormTextField = React.forwardRef<HTMLInputElement, FormTextFieldPro
control={control}
name={name}
disabled={disabled}
rules={rules}
rules={{
required,
...rules,
}}
render={({ field, fieldState }) => {
return (
<FormItem ref={ref} className={cn(className, "space-y-3")}>
{label && (
<FormLabel label={label} hint={hint} required={Boolean(rules?.required ?? false)} />
<FormLabel
label={label}
hint={hint}
required={Boolean(rules?.required ?? required)}
/>
)}
<div className={cn(button ? "flex" : null)}>
<div

View File

@ -62,7 +62,7 @@
--card: 334 62% 100%;
--card-foreground: 334 55% 1%;
--border: 334 5% 95%;
--input: 334 5% 95%;
--input: 214.29 31.82% 91.37%;
--primary: 242.93 100% 67.84%;
--primary-foreground: 0 0% 100%;
--secondary: 213.75 20.25% 69.02%;

View File

@ -12,6 +12,7 @@
"back": "Back",
"upload": "Upload",
"continue": "Continue",
"close": "Close",
"sort_asc": "Asc",
"sort_asc_description": "In ascending order. Click to sort descending order.",
"sort_desc": "Desc",
@ -30,6 +31,7 @@
"error": "Error",
"actions": "Actions",
"open_menu": "Open menu",
"duplicate_row": "Duplicate",
"duplicate_selected_rows": "Duplicate",
"duplicate_selected_rows_tooltip": "Duplicate selected row(s)",
"append_empty_row": "Append row",
@ -183,6 +185,10 @@
"cancel_button": "Cancel the download",
"toast_success": "Quote downloaded"
},
"catalog_picker_dialog": {
"title": "Select catalog items",
"description": "To complete your quote, you can add items from the catalog."
},
"status": {
"draft": "Draft"
},

View File

@ -12,6 +12,7 @@
"back": "Volver",
"upload": "Cargar",
"continue": "Continuar",
"close": "Cerrar",
"sort_asc": "Asc",
"sort_asc_description": "En order ascendente. Click para ordenar descendentemente.",
"sort_desc": "Desc",
@ -30,6 +31,7 @@
"error": "Error",
"actions": "Acciones",
"open_menu": "Abrir el menú",
"duplicate_row": "Duplicar",
"duplicate_selected_rows": "Duplicar",
"duplicate_selected_rows_tooltip": "Duplica las fila(s) seleccionadas(s)",
"append_empty_row": "Añadir fila",
@ -179,6 +181,10 @@
"cancel_button": "Cancelar la descarga",
"toast_success": "Quote downloaded"
},
"catalog_picker_dialog": {
"title": "Seleccionar artículos del catálogo",
"description": "Para rellenar su cotización, puede añadir artículos del catálogo."
},
"status": {
"draft": "Borrador"
},