@zauru-sdk/components 2.0.119 → 2.0.121
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/dist/DynamicTable/GenericDynamicTable.d.ts +48 -4
- package/dist/Form/DynamicBaculoForm/index.d.ts +10 -1
- package/dist/Form/FileUpload/index.d.ts +0 -1
- package/dist/Modal/ItemModal.d.ts +16 -5
- package/dist/NavBar/NavBar.types.d.ts +2 -1
- package/dist/NavBar/NavBar.utils.d.ts +7 -0
- package/dist/esm/Buttons/Button.js +11 -7
- package/dist/esm/DynamicTable/GenericDynamicTable.js +78 -19
- package/dist/esm/Form/DynamicBaculoForm/index.js +29 -5
- package/dist/esm/Form/FileUpload/index.js +59 -52
- package/dist/esm/Form/ReactZodForm/index.js +11 -3
- package/dist/esm/Modal/ItemModal.js +93 -22
- package/dist/esm/NavBar/NavBar.js +14 -4
- package/dist/esm/NavBar/NavBar.utils.js +7 -0
- package/package.json +3 -3
- package/src/Buttons/Button.tsx +6 -1
- package/src/DynamicTable/GenericDynamicTable.tsx +140 -39
- package/src/Form/DynamicBaculoForm/index.tsx +32 -6
- package/src/Form/FileUpload/index.tsx +100 -77
- package/src/Form/ReactZodForm/index.tsx +16 -3
- package/src/Modal/ItemModal.tsx +351 -96
- package/src/NavBar/NavBar.tsx +53 -48
- package/src/NavBar/NavBar.types.ts +9 -1
- package/src/NavBar/NavBar.utils.ts +7 -0
|
@@ -3,65 +3,72 @@ import { DownloadIconSVG, IdeaIconSVG } from "@zauru-sdk/icons";
|
|
|
3
3
|
import { useState } from "react";
|
|
4
4
|
import { useFormContext } from "react-hook-form";
|
|
5
5
|
export const FileUploadField = (props) => {
|
|
6
|
-
const { id, name, title, helpText, hint, onChange,
|
|
7
|
-
const { register: tempRegister, formState: { errors }, } = useFormContext() || { formState: {} };
|
|
8
|
-
const error = errors ? errors[
|
|
9
|
-
const register = tempRegister
|
|
10
|
-
? tempRegister(props.name ?? "-1", { required })
|
|
11
|
-
: undefined; // Solo usar register si está disponible
|
|
6
|
+
const { id, name, title, helpText, hint, onChange, readOnly = false, fileTypes = [], showAvailableTypes = false, className, defaultValue, download = false, required = false, } = props;
|
|
7
|
+
const { register: tempRegister, formState: { errors }, } = useFormContext() || { formState: {} };
|
|
8
|
+
const error = errors ? errors[name] : undefined;
|
|
9
|
+
const register = tempRegister ? tempRegister(name, { required }) : undefined;
|
|
12
10
|
const [showTooltip, setShowTooltip] = useState(false);
|
|
13
|
-
|
|
11
|
+
// Para mostrar en el hint los tipos de archivo permitidos (opcional)
|
|
12
|
+
let hintMessage = hint;
|
|
13
|
+
if (showAvailableTypes && fileTypes.length > 0) {
|
|
14
|
+
hintMessage = `${hint || ""} Archivos permitidos: ${fileTypes.join(", ")}`;
|
|
15
|
+
}
|
|
16
|
+
// Clases de estilo basadas en si hay error (color rojo) o no (gris),
|
|
17
|
+
// pero ahora ignoramos el "disabled" y nos centramos en "readOnly".
|
|
18
|
+
const color = error ? "red" : "gray";
|
|
19
|
+
const isReadOnly = readOnly;
|
|
20
|
+
// En modo readOnly, puedes poner un fondo distinto, o dejarlo en blanco
|
|
21
|
+
const bgColor = isReadOnly ? "bg-gray-100" : `bg-${color}-50`;
|
|
22
|
+
const textColor = isReadOnly ? "text-gray-700" : `text-${color}-900`;
|
|
23
|
+
const borderColor = error ? "border-red-500" : `border-${color}-500`;
|
|
24
|
+
/**
|
|
25
|
+
* onChange normal del input.
|
|
26
|
+
* Sólo se llama cuando readOnly es false (porque si es true ni renderizamos el input).
|
|
27
|
+
*/
|
|
28
|
+
const handleInputChange = (event) => {
|
|
29
|
+
onChange && onChange(event);
|
|
30
|
+
// Si usas register, la parte interna de react-hook-form también se encargará
|
|
31
|
+
// del cambio, no necesitas llamarlo manualmente.
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Para el "preview" cuando `defaultValue` es string:
|
|
35
|
+
* - Si `download` es true, mostramos un icono de descarga.
|
|
36
|
+
* - Si `download` es false, mostramos la imagen en miniatura.
|
|
37
|
+
* El click abre la URL en nueva ventana.
|
|
38
|
+
*/
|
|
39
|
+
function renderPreview(defaultValue) {
|
|
14
40
|
if (download) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}, onKeyDown: (event) => {
|
|
18
|
-
// Permite que el evento se active con la tecla Enter
|
|
41
|
+
// Botón de descarga
|
|
42
|
+
return (_jsxs("div", { role: "button", tabIndex: 0, onClick: () => window.open(defaultValue, "_blank"), onKeyDown: (event) => {
|
|
19
43
|
if (event.key === "Enter") {
|
|
20
44
|
window.open(defaultValue, "_blank");
|
|
21
45
|
}
|
|
22
|
-
}, children: [
|
|
46
|
+
}, className: "inline-flex items-center cursor-pointer", children: [_jsx(DownloadIconSVG, {}), _jsx("span", { className: "ml-1 text-blue-600 underline", children: "Descargar archivo" })] }));
|
|
23
47
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
value: defaultValue,
|
|
29
|
-
},
|
|
30
|
-
});
|
|
31
|
-
}
|
|
48
|
+
else {
|
|
49
|
+
// Vista previa como imagen
|
|
50
|
+
return (_jsx("div", { role: "button", tabIndex: 0, onClick: () => window.open(defaultValue, "_blank"), onKeyDown: (event) => {
|
|
51
|
+
if (event.key === "Enter") {
|
|
32
52
|
window.open(defaultValue, "_blank");
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
value: defaultValue,
|
|
40
|
-
},
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
window.open(defaultValue, "_blank");
|
|
44
|
-
}
|
|
45
|
-
}, children: _jsx("img", { src: defaultValue, alt: name, className: `h-48 w-48 inline mr-1 pb-1`, style: {
|
|
46
|
-
stroke: "currentColor",
|
|
47
|
-
strokeWidth: 2,
|
|
48
|
-
strokeLinecap: "round",
|
|
49
|
-
strokeLinejoin: "round",
|
|
50
|
-
fill: "none",
|
|
51
|
-
backgroundColor: "transparent",
|
|
52
|
-
} }) })] }));
|
|
53
|
+
}
|
|
54
|
+
}, className: "inline-block cursor-pointer", children: _jsx("img", { src: defaultValue, alt: name, className: "h-48 w-48 inline mr-1 pb-1", style: {
|
|
55
|
+
objectFit: "contain",
|
|
56
|
+
backgroundColor: "transparent",
|
|
57
|
+
} }) }));
|
|
58
|
+
}
|
|
53
59
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
+
/**
|
|
61
|
+
* 1) Si readOnly = true:
|
|
62
|
+
* - Si defaultValue es string -> Sólo mostramos el preview (descarga/imagen).
|
|
63
|
+
* - Si no hay defaultValue (o es File) -> mostramos "nada" o un texto de "Sin archivo".
|
|
64
|
+
*/
|
|
65
|
+
if (readOnly) {
|
|
66
|
+
return (_jsxs("div", { className: `col-span-6 sm:col-span-3 ${className}`, children: [title && (_jsx("label", { htmlFor: name, className: `block mb-1 text-sm font-medium text-gray-700`, children: title })), typeof defaultValue === "string" && defaultValue ? (renderPreview(defaultValue)) : (_jsx("div", { className: "text-sm italic text-gray-400", children: "No hay archivo disponible" }))] }));
|
|
60
67
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
return (_jsxs("div", { className: `col-span-6 sm:col-span-3 ${className}`, children: [title && (
|
|
68
|
+
/**
|
|
69
|
+
* 2) readOnly = false:
|
|
70
|
+
* - Si hay defaultValue y es string, mostramos la vista previa + el input
|
|
71
|
+
* - Si no hay defaultValue (o no es string) mostramos solo el input
|
|
72
|
+
*/
|
|
73
|
+
return (_jsxs("div", { className: `col-span-6 sm:col-span-3 ${className}`, children: [title && (_jsxs("label", { htmlFor: name, className: `block mb-1 text-sm font-medium text-${color}-700`, children: [title, required && _jsx("span", { className: "text-red-500 ml-1", children: "*" })] })), typeof defaultValue === "string" && defaultValue && (_jsx("div", { className: "mb-2", children: renderPreview(defaultValue) })), _jsxs("div", { className: "flex relative items-center", children: [_jsx("input", { type: "file", id: id ?? name, accept: fileTypes.map((ft) => `.${ft}`).join(", "), className: `block w-full rounded-md ${bgColor} ${borderColor} ${textColor} shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm`, ...(register ?? {}), name: name, onChange: handleInputChange }), helpText && (_jsx("div", { className: "flex items-center relative ml-3", children: _jsxs("div", { className: "relative cursor-pointer", onMouseEnter: () => setShowTooltip(true), onMouseLeave: () => setShowTooltip(false), children: [_jsx(IdeaIconSVG, {}), showTooltip && (_jsx("div", { className: "absolute -left-48 top-0 mt-8 p-2 bg-white border rounded shadow text-black z-50", children: helpText }))] }) }))] }), error && (_jsxs("p", { className: `mt-2 text-sm text-red-600`, children: [_jsx("span", { className: "font-medium", children: "Oops!" }), " ", error.message?.toString()] })), !error && hintMessage && (_jsx("p", { className: `mt-2 italic text-sm text-${color}-500`, children: hintMessage }))] }));
|
|
67
74
|
};
|
|
@@ -14,11 +14,19 @@ export const ReactZodForm = (props) => {
|
|
|
14
14
|
const handleSubmit = (data, event) => {
|
|
15
15
|
if (onSubmit) {
|
|
16
16
|
onSubmit(data, event);
|
|
17
|
+
return;
|
|
17
18
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
const form = event?.target;
|
|
20
|
+
const nativeEvent = event?.nativeEvent;
|
|
21
|
+
// Armamos el FormData a partir del propio <form>
|
|
22
|
+
const formData = new FormData(form);
|
|
23
|
+
// Detectamos el botón que disparó el submit (submitter),
|
|
24
|
+
// en caso de que tenga un name/value, lo agregamos al formData
|
|
25
|
+
const submitter = nativeEvent.submitter;
|
|
26
|
+
if (submitter instanceof HTMLButtonElement && submitter.name) {
|
|
27
|
+
formData.append(submitter.name, submitter.value);
|
|
21
28
|
}
|
|
29
|
+
submit(formData, { method, encType });
|
|
22
30
|
};
|
|
23
31
|
return (_jsx(FormProvider, { ...methods, children: _jsx(Form, { onSubmit: methods.handleSubmit(handleSubmit), method: method, id: id, className: className, encType: encType, children: children }) }));
|
|
24
32
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useState } from "react";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useRef } from "react";
|
|
3
3
|
import { createRoot } from "react-dom/client";
|
|
4
|
-
const ItemSelectionModal = ({ itemList, onClose, config, }) => {
|
|
4
|
+
const ItemSelectionModal = ({ itemList, onClose, config, categoryViewMode = "text", }) => {
|
|
5
5
|
const defaultConfig = {
|
|
6
6
|
itemSize: {
|
|
7
7
|
width: config?.itemSize?.width || "150px",
|
|
@@ -10,6 +10,18 @@ const ItemSelectionModal = ({ itemList, onClose, config, }) => {
|
|
|
10
10
|
};
|
|
11
11
|
const [searchTerm, setSearchTerm] = useState("");
|
|
12
12
|
const [expandedCategories, setExpandedCategories] = useState({});
|
|
13
|
+
const [selectedItem, setSelectedItem] = useState(null);
|
|
14
|
+
const [quantity, setQuantity] = useState(1);
|
|
15
|
+
const [customPrice, setCustomPrice] = useState(null);
|
|
16
|
+
// Ref para forzar el scroll al tope cuando seleccionamos un ítem
|
|
17
|
+
const modalContentRef = useRef(null);
|
|
18
|
+
const filteredList = itemList
|
|
19
|
+
.map((category) => ({
|
|
20
|
+
...category,
|
|
21
|
+
items: category.items.filter((item) => item.name.toLowerCase().includes(searchTerm.toLowerCase())),
|
|
22
|
+
}))
|
|
23
|
+
.filter((category) => category.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
|
24
|
+
category.items.length > 0);
|
|
13
25
|
const toggleCategory = (categoryName) => {
|
|
14
26
|
setExpandedCategories((prev) => ({
|
|
15
27
|
...prev,
|
|
@@ -17,27 +29,86 @@ const ItemSelectionModal = ({ itemList, onClose, config, }) => {
|
|
|
17
29
|
}));
|
|
18
30
|
};
|
|
19
31
|
const handleItemClick = (item) => {
|
|
20
|
-
|
|
32
|
+
setSelectedItem(item);
|
|
33
|
+
setQuantity(1);
|
|
34
|
+
// Si el ítem tiene precio flexible, inicializamos el customPrice con su precio actual
|
|
35
|
+
setCustomPrice(item.flexiblePrice ? item.unitPrice : null);
|
|
36
|
+
// Forzar scroll a la parte superior del contenido, ya que antes se iniciaba el scroll desde donde se había quedado.
|
|
37
|
+
if (modalContentRef.current) {
|
|
38
|
+
modalContentRef.current.scrollTo({ top: 0, behavior: "smooth" });
|
|
39
|
+
}
|
|
21
40
|
};
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
41
|
+
const handleConfirmQuantity = () => {
|
|
42
|
+
if (selectedItem) {
|
|
43
|
+
// (5) Devolver el precio correcto
|
|
44
|
+
const finalPrice = selectedItem.flexiblePrice
|
|
45
|
+
? // si el precio es flexible, tomar lo que el usuario haya ingresado (o fallback al precio original)
|
|
46
|
+
customPrice ?? selectedItem.unitPrice
|
|
47
|
+
: // si NO es flexible, solo usamos el precio que ya tenía
|
|
48
|
+
selectedItem.unitPrice;
|
|
49
|
+
onClose({
|
|
50
|
+
...selectedItem,
|
|
51
|
+
quantity,
|
|
52
|
+
unitPrice: finalPrice,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
const handleCancelQuantity = () => {
|
|
57
|
+
setSelectedItem(null);
|
|
58
|
+
setQuantity(1);
|
|
59
|
+
setCustomPrice(null);
|
|
60
|
+
};
|
|
61
|
+
const handleCloseModal = () => {
|
|
62
|
+
onClose(null);
|
|
63
|
+
};
|
|
64
|
+
return (_jsx("div", { className: "fixed inset-0 bg-black bg-opacity-50 flex justify-center items-center z-50", onClick: handleCloseModal, children: _jsxs("div", {
|
|
65
|
+
//Le ponemos ref para poder scrollear al tope
|
|
66
|
+
ref: modalContentRef, className: "bg-white p-4 rounded-lg shadow-lg w-11/12 max-w-4xl h-5/6 overflow-y-auto", onClick: (e) => e.stopPropagation(), children: [_jsxs("div", { className: "flex justify-between items-center mb-4", children: [_jsx("h2", { className: "text-2xl font-bold", children: selectedItem ? "Confirmar selección" : "Seleccionar un Ítem" }), _jsx("button", { className: "text-gray-500 hover:text-gray-800 text-3xl", onClick: handleCloseModal, children: "\u00D7" })] }), !selectedItem ? (
|
|
67
|
+
/* ==============================
|
|
68
|
+
PASO 1: SELECCIONAR ÍTEM
|
|
69
|
+
============================== */
|
|
70
|
+
_jsxs(_Fragment, { children: [_jsxs("div", { className: "relative mb-4", children: [_jsx("input", { type: "text", placeholder: "Buscar por nombre o categor\u00EDa...", value: searchTerm, onChange: (e) => setSearchTerm(e.target.value), className: "p-2 border rounded-lg w-full" }), searchTerm && (_jsx("button", { className: "absolute right-2 top-1/2 transform -translate-y-1/2 text-gray-500 hover:text-gray-800", onClick: () => setSearchTerm(""), children: "\u00D7" }))] }), filteredList.length === 0 ? (_jsx("p", { className: "text-gray-500 text-center", children: "No se encontraron resultados." })) : (filteredList.map((category) => {
|
|
71
|
+
const isExpanded = expandedCategories[category.name];
|
|
72
|
+
// Estilos condicionales para "text" vs. "card"
|
|
73
|
+
const categoryContainerClasses = categoryViewMode === "card"
|
|
74
|
+
? "w-full mb-2 px-4 py-3 bg-blue-50 rounded-md flex justify-between items-center cursor-pointer hover:bg-blue-100"
|
|
75
|
+
: "text-lg font-semibold mb-2 cursor-pointer flex justify-between items-center hover:text-blue-600";
|
|
76
|
+
return (_jsxs("div", { className: "mb-4", children: [_jsxs("div", { className: categoryContainerClasses, onClick: () => toggleCategory(category.name), children: [_jsxs("span", { children: [category.name, " ", _jsxs("span", { className: "text-gray-500", children: ["(", category.items.length, ")"] })] }), _jsx("span", { className: `transform transition-transform duration-200 ${isExpanded ? "rotate-90" : ""}`, children: "\u25B6" })] }), isExpanded && (_jsx("div", { className: "grid gap-5", style: {
|
|
77
|
+
gridTemplateColumns: `repeat(auto-fit, minmax(${defaultConfig.itemSize.width}, 1fr))`,
|
|
78
|
+
}, children: category.items.map((item) => {
|
|
79
|
+
// Verificamos si es un "paquete" usando item_id
|
|
80
|
+
const isPackage = item.item_id.startsWith("b");
|
|
81
|
+
return (_jsxs("div", { onClick: () => handleItemClick(item), className: `border rounded-lg shadow-lg hover:shadow-xl cursor-pointer relative ${isPackage ? "bg-yellow-50" : ""}`, style: {
|
|
82
|
+
backgroundImage: `url(${item.imageUrl})`,
|
|
83
|
+
backgroundSize: "cover",
|
|
84
|
+
backgroundPosition: "center",
|
|
85
|
+
width: defaultConfig.itemSize.width,
|
|
86
|
+
height: defaultConfig.itemSize.height,
|
|
87
|
+
}, children: [_jsx("div", { className: `p-2 rounded absolute top-0 left-0 right-0 ${isPackage
|
|
88
|
+
? "bg-yellow-300 text-black"
|
|
89
|
+
: "bg-white bg-opacity-80"}`, children: _jsx("h4", { className: "font-semibold text-sm text-center", children: item.name }) }), _jsx("div", { className: `absolute bottom-0 left-0 p-2 rounded ${isPackage
|
|
90
|
+
? "bg-yellow-300"
|
|
91
|
+
: "bg-white bg-opacity-80"}`, children: _jsxs("span", { className: "text-xs font-normal", children: ["Stock: ", item.stock] }) }), _jsx("div", { className: `absolute bottom-0 right-0 p-2 rounded ${isPackage
|
|
92
|
+
? "bg-yellow-300"
|
|
93
|
+
: "bg-white bg-opacity-80"}`, children: _jsxs("span", { className: "text-xs font-normal", children: [item.currencyPrefix, item.priceText] }) })] }, item.code));
|
|
94
|
+
}) }))] }, category.name));
|
|
95
|
+
}))] })) : (
|
|
96
|
+
/* ==============================
|
|
97
|
+
PASO 2: CONFIRMAR SELECCIÓN
|
|
98
|
+
============================== */
|
|
99
|
+
_jsxs("div", { className: "flex flex-col items-center justify-center", children: [_jsx("img", { src: selectedItem.imageUrl, alt: selectedItem.name, className: "w-40 h-40 object-cover rounded mb-4 shadow-md" }), _jsx("p", { className: "mb-2 text-xl font-bold", children: selectedItem.name }), _jsxs("p", { className: "mb-2 text-base font-semibold text-gray-700", children: ["Stock disponible:", _jsx("span", { className: "ml-1 font-normal text-gray-800", children: selectedItem.stock })] }), !selectedItem.flexiblePrice && (_jsxs("p", { className: "mb-4 text-base font-semibold text-gray-700", children: ["Precio unitario:", _jsxs("span", { className: "ml-1 font-normal text-gray-800", children: [selectedItem.currencyPrefix, selectedItem.priceText] })] })), _jsxs("div", { className: "mb-4 w-full max-w-sm flex flex-col items-center", children: [_jsx("p", { className: "text-base font-semibold text-gray-700 mb-2", children: "Seleccionar cantidad" }), _jsxs("div", { className: "flex items-center space-x-4", children: [_jsx("button", { className: "bg-gray-300 rounded-full w-12 h-12 flex justify-center items-center text-2xl font-bold hover:bg-gray-400", onClick: () => setQuantity((prev) => (prev > 1 ? prev - 1 : 1)), children: "-" }), _jsx("input", { className: "w-16 text-center border rounded text-lg", type: "number", min: 1, value: quantity, onChange: (e) => {
|
|
100
|
+
const val = parseInt(e.target.value, 10);
|
|
101
|
+
setQuantity(isNaN(val) || val < 1 ? 1 : val);
|
|
102
|
+
} }), _jsx("button", { className: "bg-gray-300 rounded-full w-12 h-12 flex justify-center items-center text-2xl font-bold hover:bg-gray-400", onClick: () => setQuantity((prev) => prev + 1), children: "+" })] })] }), selectedItem.flexiblePrice && (_jsxs("div", { className: "mb-4 w-full max-w-sm flex flex-col items-center", children: [_jsx("p", { className: "text-base font-semibold text-gray-700 mb-2", children: "Seleccionar precio" }), _jsxs("div", { className: "flex items-center space-x-4", children: [_jsx("button", { className: "bg-gray-300 rounded-full w-12 h-12 flex justify-center items-center text-2xl font-bold hover:bg-gray-400", onClick: () => setCustomPrice((prev) => {
|
|
103
|
+
const newVal = (prev ?? 0) - 1;
|
|
104
|
+
return newVal < 0 ? 0 : newVal;
|
|
105
|
+
}), children: "-" }), _jsx("input", { className: "w-16 text-center border rounded text-lg", type: "number", min: 0, value: customPrice ?? 0, onChange: (e) => {
|
|
106
|
+
const val = parseInt(e.target.value, 10);
|
|
107
|
+
setCustomPrice(isNaN(val) || val < 0 ? 0 : val);
|
|
108
|
+
} }), _jsx("button", { className: "bg-gray-300 rounded-full w-12 h-12 flex justify-center items-center text-2xl font-bold hover:bg-gray-400", onClick: () => setCustomPrice((prev) => (prev == null ? 1 : prev + 1)), children: "+" })] })] })), _jsxs("div", { className: "flex space-x-4 mt-6", children: [_jsx("button", { className: "bg-gray-300 px-4 py-2 rounded hover:bg-gray-400", onClick: handleCancelQuantity, children: "Volver" }), _jsx("button", { className: "bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700", onClick: handleConfirmQuantity, children: "Confirmar" })] })] }))] }) }));
|
|
38
109
|
};
|
|
39
110
|
// Función para crear el modal
|
|
40
|
-
export const createItemModal = (itemList, config) => {
|
|
111
|
+
export const createItemModal = (itemList, config, categoryViewMode) => {
|
|
41
112
|
return new Promise((resolve) => {
|
|
42
113
|
const handleClose = (selectedItem) => {
|
|
43
114
|
resolve(selectedItem);
|
|
@@ -49,6 +120,6 @@ export const createItemModal = (itemList, config) => {
|
|
|
49
120
|
const modalWrapper = document.createElement("div");
|
|
50
121
|
document.body.appendChild(modalWrapper);
|
|
51
122
|
const root = createRoot(modalWrapper);
|
|
52
|
-
root.render(_jsx(ItemSelectionModal, { itemList: itemList, onClose: handleClose, config: config }));
|
|
123
|
+
root.render(_jsx(ItemSelectionModal, { itemList: itemList, onClose: handleClose, config: config, categoryViewMode: categoryViewMode }));
|
|
53
124
|
});
|
|
54
125
|
};
|
|
@@ -2,13 +2,15 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
2
2
|
import React, { useState, useEffect } from "react";
|
|
3
3
|
import { DropDownArrowSvgIcon, LogoutDropDownSvgIcon, MenuAlt4Svg, OpcionButtonSvgIcon, } from "@zauru-sdk/icons";
|
|
4
4
|
import { COLORS } from "./NavBar.utils.js";
|
|
5
|
-
import { Link, useNavigate } from "@remix-run/react";
|
|
5
|
+
import { Link, useNavigate, useLocation } from "@remix-run/react";
|
|
6
6
|
import { useAppSelector } from "@zauru-sdk/redux";
|
|
7
7
|
const OptionsDropDownButton = ({ color, options, name }) => {
|
|
8
8
|
const [showOptionsMenu, setShowOptionsMenu] = useState(true);
|
|
9
9
|
return (_jsx("div", { className: "nav-item ml-auto", children: _jsx("div", { className: "flex justify-center", children: _jsxs("div", { className: "relative inline-block", children: [_jsxs("button", { onClick: () => setShowOptionsMenu(!showOptionsMenu), className: `relative flex items-center p-2 text-xs text-white ${color.bg700} active:${color.bg900} border border-transparent rounded-full uppercase focus:ring-opacity-40 focus:outline-none`, children: [name ?? _jsx(OpcionButtonSvgIcon, {}), _jsx(DropDownArrowSvgIcon, {})] }), _jsx("div", { className: "absolute right-0 z-20 w-56 py-2 mt-2 overflow-hidden bg-white rounded-md shadow-xl dark:bg-gray-800", hidden: showOptionsMenu, onMouseLeave: () => setShowOptionsMenu(true), children: options.map((option, index) => (_jsx(React.Fragment, { children: option }, index))) })] }) }) }));
|
|
10
10
|
};
|
|
11
11
|
const NavItem = ({ name, link, icon, selectedColor, childrens = [], reduxNotificationBadge, }) => {
|
|
12
|
+
const location = useLocation();
|
|
13
|
+
const isActive = location.pathname === link;
|
|
12
14
|
const specialColor = selectedColor
|
|
13
15
|
? COLORS[selectedColor]
|
|
14
16
|
: COLORS["slate"];
|
|
@@ -18,7 +20,15 @@ const NavItem = ({ name, link, icon, selectedColor, childrens = [], reduxNotific
|
|
|
18
20
|
useEffect(() => {
|
|
19
21
|
setNotificationBadge(relevantState);
|
|
20
22
|
}, [relevantState]);
|
|
21
|
-
|
|
23
|
+
// Si este NavItem tiene elementos hijos, renderiza el botón desplegable:
|
|
24
|
+
if (childrens.length > 0) {
|
|
25
|
+
return (_jsx(OptionsDropDownButton, { name: name, color: specialColor, options: childrens.map((x, index) => (_jsx(Link, { to: x.link, className: `block px-4 py-3 text-sm text-gray-600 capitalize transition-colors duration-200 transform dark:text-gray-300 hover:bg-red-100 dark:hover:bg-gray-700 dark:hover:text-white`, children: x.name }, index))) }));
|
|
26
|
+
}
|
|
27
|
+
// Si NO tiene elementos hijos, se renderiza como un ítem simple:
|
|
28
|
+
return (_jsx("li", { className: "nav-item relative", children: _jsx("div", {
|
|
29
|
+
// Si está activo, usamos color de fondo más oscuro (bg900)
|
|
30
|
+
// De lo contrario, usamos el color normal (bg700)
|
|
31
|
+
className: `${isActive ? specialColor.bg900 : specialColor.bg700} container text-white w-full sm:w-auto h-10 text-sm py-1 uppercase shadow hover:shadow-lg outline-none rounded-full focus:outline-none my-auto sm:my-0 sm:mr-1 mb-1 ease-linear transition-all duration-150`, children: _jsxs(Link, { className: "px-3 flex items-center text-xs leading-snug text-white uppercase hover:opacity-75 relative", to: link, children: [_jsxs("div", { className: "mx-auto pt-2", children: [icon, _jsx("span", { children: name })] }), notificationBadge !== undefined && (_jsx("span", { className: "absolute -top-2 -right-2 bg-red-500 text-white text-xs font-bold rounded-full flex items-center justify-center w-5 h-5", children: notificationBadge }))] }) }) }));
|
|
22
32
|
};
|
|
23
33
|
export const NavBar = ({ title, loggedIn, items, selectedColor, version, }) => {
|
|
24
34
|
const color = COLORS[selectedColor];
|
|
@@ -39,7 +49,7 @@ export const NavBar = ({ title, loggedIn, items, selectedColor, version, }) => {
|
|
|
39
49
|
}) }, index));
|
|
40
50
|
}) }));
|
|
41
51
|
const options = (_jsxs(_Fragment, { children: [_jsx("ul", { className: "w-full lg:flex lg:items-center", children: renderNavItems(items.filter((item) => item.loggedIn === loggedIn)) }), _jsx("ul", { className: "sm:flex sm:flex-col lg:flex-row ml-auto", children: loggedIn && (_jsx(OptionsDropDownButton, { color: color, options: [
|
|
42
|
-
_jsx(Link, { className: `block px-4 py-3 text-sm text-gray-600 capitalize transition-colors duration-200 transform dark:text-gray-300 hover:bg-red-100 dark:hover:bg-gray-700 dark:hover:text-white`, to: "/logout", children: _jsxs("div", { className: "mx-auto pt-2", children: [_jsx(LogoutDropDownSvgIcon, {}), _jsx("span", { children: "Cerrar sesi\u00F3n" })] }) }),
|
|
52
|
+
_jsx(Link, { className: `block px-4 py-3 text-sm text-gray-600 capitalize transition-colors duration-200 transform dark:text-gray-300 hover:bg-red-100 dark:hover:bg-gray-700 dark:hover:text-white`, to: "/logout", children: _jsxs("div", { className: "mx-auto pt-2", children: [_jsx(LogoutDropDownSvgIcon, {}), _jsx("span", { children: "Cerrar sesi\u00F3n" })] }) }, "cerrar-sesion"),
|
|
43
53
|
] })) })] }));
|
|
44
|
-
return (_jsx("nav", { className: `py-3 ${color.bg600}`, children: _jsxs("div", { className: "flex items-center justify-between ml-5 mr-5", children: [_jsxs("div", { className: "flex justify-between items-center w-full lg:w-auto", children: [
|
|
54
|
+
return (_jsx("nav", { className: `py-3 ${color.bg600}`, children: _jsxs("div", { className: "flex items-center justify-between ml-5 mr-5", children: [_jsxs("div", { className: "flex justify-between items-center w-full lg:w-auto", children: [_jsxs(Link, { className: "text-sm font-bold leading-relaxed inline-block mr-4 py-2 whitespace-nowrap uppercase text-white", to: "/home", children: [_jsx("div", { className: "inline-block mr-2 mb-2 align-middle", children: _jsx("img", { className: "w-auto h-7", src: "/logo.png", alt: "logo-zauru" }) }), title] }), version !== currentVersion && (_jsx("button", { className: `ml-2 px-2 py-1 text-xs text-white ${color.bg700} rounded-full hover:${color.bg900} transition-colors duration-200`, onClick: refreshPage, children: "\uD83D\uDD04 Actualizar versi\u00F3n" })), _jsx("button", { className: `rounded lg:hidden focus:outline-none focus:ring focus:${color.ring600} focus:ring-opacity-50`, "aria-label": "Toggle mobile menu", type: "button", onClick: () => setNavBarOpen(!NavBarOpen), children: _jsx(MenuAlt4Svg, { open: NavBarOpen }) })] }), _jsx("div", { className: `lg:hidden fixed top-0 left-0 z-50 w-64 h-full ${color.bg700} dark:bg-gray-900 shadow-lg transform ${NavBarOpen ? "translate-x-0" : "-translate-x-full"} transition-transform duration-300 ease-in-out overflow-y-auto`, children: _jsx("div", { className: "p-4", children: options }) }), _jsx("div", { className: "hidden lg:flex lg:items-center w-full lg:w-auto", children: options })] }) }));
|
|
45
55
|
};
|
|
@@ -4,6 +4,7 @@ export const COLORS = {
|
|
|
4
4
|
bg700: "bg-sky-700",
|
|
5
5
|
bg600: "bg-sky-600",
|
|
6
6
|
bg500: "bg-sky-500",
|
|
7
|
+
bg200: "bg-sky-200",
|
|
7
8
|
ring600: "ring-sky-600",
|
|
8
9
|
ring500: "ring-sky-500",
|
|
9
10
|
},
|
|
@@ -12,6 +13,7 @@ export const COLORS = {
|
|
|
12
13
|
bg700: "bg-purple-700",
|
|
13
14
|
bg600: "bg-purple-600",
|
|
14
15
|
bg500: "bg-purple-500",
|
|
16
|
+
bg200: "bg-purple-200",
|
|
15
17
|
ring600: "ring-purple-600",
|
|
16
18
|
ring500: "ring-purple-500",
|
|
17
19
|
},
|
|
@@ -20,6 +22,7 @@ export const COLORS = {
|
|
|
20
22
|
bg700: "bg-pink-700",
|
|
21
23
|
bg600: "bg-pink-600",
|
|
22
24
|
bg500: "bg-pink-500",
|
|
25
|
+
bg200: "bg-pink-200",
|
|
23
26
|
ring600: "ring-pink-600",
|
|
24
27
|
ring500: "ring-pink-500",
|
|
25
28
|
},
|
|
@@ -28,6 +31,7 @@ export const COLORS = {
|
|
|
28
31
|
bg700: "bg-slate-700",
|
|
29
32
|
bg600: "bg-slate-600",
|
|
30
33
|
bg500: "bg-slate-500",
|
|
34
|
+
bg200: "bg-slate-200",
|
|
31
35
|
ring600: "ring-slate-600",
|
|
32
36
|
ring500: "ring-slate-500",
|
|
33
37
|
},
|
|
@@ -36,6 +40,7 @@ export const COLORS = {
|
|
|
36
40
|
bg700: "bg-green-700",
|
|
37
41
|
bg600: "bg-green-600",
|
|
38
42
|
bg500: "bg-green-500",
|
|
43
|
+
bg200: "bg-green-200",
|
|
39
44
|
ring600: "ring-green-600",
|
|
40
45
|
ring500: "ring-green-500",
|
|
41
46
|
},
|
|
@@ -44,6 +49,7 @@ export const COLORS = {
|
|
|
44
49
|
bg700: "bg-yellow-700",
|
|
45
50
|
bg600: "bg-yellow-600",
|
|
46
51
|
bg500: "bg-yellow-500",
|
|
52
|
+
bg200: "bg-yellow-200",
|
|
47
53
|
ring600: "ring-yellow-600",
|
|
48
54
|
ring500: "ring-yellow-500",
|
|
49
55
|
},
|
|
@@ -52,6 +58,7 @@ export const COLORS = {
|
|
|
52
58
|
bg700: "bg-red-700",
|
|
53
59
|
bg600: "bg-red-600",
|
|
54
60
|
bg500: "bg-red-500",
|
|
61
|
+
bg200: "bg-red-200",
|
|
55
62
|
ring600: "ring-red-600",
|
|
56
63
|
ring500: "ring-red-500",
|
|
57
64
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zauru-sdk/components",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.121",
|
|
4
4
|
"description": "Componentes reutilizables en las WebApps de Zauru.",
|
|
5
5
|
"main": "./dist/esm/index.js",
|
|
6
6
|
"module": "./dist/esm/index.js",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"@reduxjs/toolkit": "^2.2.1",
|
|
35
35
|
"@remix-run/react": "^2.8.1",
|
|
36
36
|
"@zauru-sdk/common": "^2.0.118",
|
|
37
|
-
"@zauru-sdk/hooks": "^2.0.
|
|
37
|
+
"@zauru-sdk/hooks": "^2.0.121",
|
|
38
38
|
"@zauru-sdk/icons": "^2.0.99",
|
|
39
39
|
"@zauru-sdk/types": "^2.0.109",
|
|
40
40
|
"@zauru-sdk/utils": "^2.0.119",
|
|
@@ -49,5 +49,5 @@
|
|
|
49
49
|
"styled-components": "^5.3.5",
|
|
50
50
|
"zod": "^3.23.8"
|
|
51
51
|
},
|
|
52
|
-
"gitHead": "
|
|
52
|
+
"gitHead": "1ab1f6514793de7ce7f19aa022f7642db78ac9ad"
|
|
53
53
|
}
|
package/src/Buttons/Button.tsx
CHANGED
|
@@ -43,6 +43,7 @@ export const Button = (props: Props) => {
|
|
|
43
43
|
bg700: "bg-green-700",
|
|
44
44
|
bg600: "bg-green-600",
|
|
45
45
|
bg500: "bg-green-500",
|
|
46
|
+
bg200: "bg-green-200",
|
|
46
47
|
ring600: "ring-green-600",
|
|
47
48
|
ring500: "ring-green-500",
|
|
48
49
|
},
|
|
@@ -51,6 +52,7 @@ export const Button = (props: Props) => {
|
|
|
51
52
|
bg700: "bg-indigo-700",
|
|
52
53
|
bg600: "bg-indigo-600",
|
|
53
54
|
bg500: "bg-indigo-500",
|
|
55
|
+
bg200: "bg-indigo-200",
|
|
54
56
|
ring600: "ring-indigo-600",
|
|
55
57
|
ring500: "ring-indigo-500",
|
|
56
58
|
},
|
|
@@ -59,6 +61,7 @@ export const Button = (props: Props) => {
|
|
|
59
61
|
bg700: "bg-red-700",
|
|
60
62
|
bg600: "bg-red-600",
|
|
61
63
|
bg500: "bg-red-500",
|
|
64
|
+
bg200: "bg-red-200",
|
|
62
65
|
ring600: "ring-red-600",
|
|
63
66
|
ring500: "ring-red-500",
|
|
64
67
|
},
|
|
@@ -67,6 +70,7 @@ export const Button = (props: Props) => {
|
|
|
67
70
|
bg700: "bg-yellow-700",
|
|
68
71
|
bg600: "bg-yellow-600",
|
|
69
72
|
bg500: "bg-yellow-500",
|
|
73
|
+
bg200: "bg-yellow-200",
|
|
70
74
|
ring600: "ring-yellow-600",
|
|
71
75
|
ring500: "ring-yellow-500",
|
|
72
76
|
},
|
|
@@ -84,9 +88,10 @@ export const Button = (props: Props) => {
|
|
|
84
88
|
|
|
85
89
|
const buttonContent = (
|
|
86
90
|
<>
|
|
87
|
-
<input type="hidden" name="action" value={name} />
|
|
88
91
|
<button
|
|
89
92
|
type={type}
|
|
93
|
+
name={"action"}
|
|
94
|
+
value={name}
|
|
90
95
|
disabled={
|
|
91
96
|
loading || disabled || (enableFormErrorsValidation && formHasErrors)
|
|
92
97
|
}
|