@roax/ui 0.1.0 → 0.3.0
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/README.md +186 -170
- package/dist/index.js +591 -76
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +613 -75
- package/dist/index.mjs.map +1 -1
- package/package.json +7 -5
- package/src/styles/_roax-colors.scss +107 -8
- package/src/styles/index.scss +3 -8
package/dist/index.mjs
CHANGED
|
@@ -2,19 +2,7 @@
|
|
|
2
2
|
import { CLoadingButton } from "@coreui/react-pro";
|
|
3
3
|
import CIcon from "@coreui/icons-react";
|
|
4
4
|
import "./SolidButton.scss";
|
|
5
|
-
function SolidButton({
|
|
6
|
-
title = "Button",
|
|
7
|
-
onClick,
|
|
8
|
-
color = "custom-primary",
|
|
9
|
-
textColor = "custom-white",
|
|
10
|
-
className = "",
|
|
11
|
-
loading = false,
|
|
12
|
-
icon,
|
|
13
|
-
svgComponent: SvgComponent,
|
|
14
|
-
type = "submit",
|
|
15
|
-
badge,
|
|
16
|
-
disabled
|
|
17
|
-
}) {
|
|
5
|
+
function SolidButton({ title = "Button", onClick, color = "custom-primary", textColor = "custom-white", className = "", loading = false, icon, svgComponent: SvgComponent, type = "submit", badge, disabled }) {
|
|
18
6
|
return /* @__PURE__ */ React.createElement(
|
|
19
7
|
CLoadingButton,
|
|
20
8
|
{
|
|
@@ -24,12 +12,7 @@ function SolidButton({
|
|
|
24
12
|
loading,
|
|
25
13
|
disabledOnLoading: true,
|
|
26
14
|
disabled,
|
|
27
|
-
style: {
|
|
28
|
-
minHeight: "44px",
|
|
29
|
-
minWidth: "fit-content",
|
|
30
|
-
fontSize: "0.95rem",
|
|
31
|
-
letterSpacing: "0.3px"
|
|
32
|
-
}
|
|
15
|
+
style: { minHeight: "44px", minWidth: "fit-content", fontSize: "0.95rem", letterSpacing: "0.3px" }
|
|
33
16
|
},
|
|
34
17
|
icon && /* @__PURE__ */ React.createElement(CIcon, { icon, className: "btn-icon" }),
|
|
35
18
|
SvgComponent && !icon && /* @__PURE__ */ React.createElement(SvgComponent, null),
|
|
@@ -42,16 +25,7 @@ function SolidButton({
|
|
|
42
25
|
import { CLoadingButton as CLoadingButton2 } from "@coreui/react-pro";
|
|
43
26
|
import CIcon2 from "@coreui/icons-react";
|
|
44
27
|
import "./OutlineButton.scss";
|
|
45
|
-
function OutlineButton({
|
|
46
|
-
title = "Button",
|
|
47
|
-
onClick,
|
|
48
|
-
color = "custom-primary",
|
|
49
|
-
className = "",
|
|
50
|
-
loading = false,
|
|
51
|
-
icon,
|
|
52
|
-
type = "submit",
|
|
53
|
-
disabled
|
|
54
|
-
}) {
|
|
28
|
+
function OutlineButton({ title = "Button", onClick, color = "custom-primary", className = "", loading = false, icon, type = "submit", disabled }) {
|
|
55
29
|
return /* @__PURE__ */ React.createElement(
|
|
56
30
|
CLoadingButton2,
|
|
57
31
|
{
|
|
@@ -62,10 +36,7 @@ function OutlineButton({
|
|
|
62
36
|
disabledOnLoading: true,
|
|
63
37
|
disabled,
|
|
64
38
|
variant: "outline",
|
|
65
|
-
style: {
|
|
66
|
-
maxHeight: "40px",
|
|
67
|
-
minWidth: "fit-content"
|
|
68
|
-
}
|
|
39
|
+
style: { maxHeight: "40px", minWidth: "fit-content" }
|
|
69
40
|
},
|
|
70
41
|
icon && /* @__PURE__ */ React.createElement(CIcon2, { icon }),
|
|
71
42
|
/* @__PURE__ */ React.createElement("span", null, title)
|
|
@@ -75,17 +46,7 @@ function OutlineButton({
|
|
|
75
46
|
// src/components/buttons/TextButton.jsx
|
|
76
47
|
import { CLoadingButton as CLoadingButton3 } from "@coreui/react-pro";
|
|
77
48
|
import CIcon3 from "@coreui/icons-react";
|
|
78
|
-
function TextButton({
|
|
79
|
-
disabled,
|
|
80
|
-
title,
|
|
81
|
-
onClick,
|
|
82
|
-
color = "dark",
|
|
83
|
-
className = "",
|
|
84
|
-
loading = false,
|
|
85
|
-
icon,
|
|
86
|
-
children
|
|
87
|
-
}) {
|
|
88
|
-
const buttonClasses = `rounded-3 px-2 d-flex justify-content-center gap-2 fw-medium ${className}`;
|
|
49
|
+
function TextButton({ disabled, title, onClick, color = "dark", className = "", loading = false, icon, children }) {
|
|
89
50
|
return /* @__PURE__ */ React.createElement("span", { className: "d-inline-block", tabIndex: 0 }, /* @__PURE__ */ React.createElement(
|
|
90
51
|
CLoadingButton3,
|
|
91
52
|
{
|
|
@@ -94,7 +55,7 @@ function TextButton({
|
|
|
94
55
|
variant: "ghost",
|
|
95
56
|
type: "button",
|
|
96
57
|
color,
|
|
97
|
-
className:
|
|
58
|
+
className: `rounded-3 px-2 d-flex justify-content-center gap-2 fw-medium ${className}`,
|
|
98
59
|
loading
|
|
99
60
|
},
|
|
100
61
|
icon && /* @__PURE__ */ React.createElement(CIcon3, { size: "xl", icon }),
|
|
@@ -109,37 +70,12 @@ import CIcon4 from "@coreui/icons-react";
|
|
|
109
70
|
// src/components/custom-tooltip/CustomTooltip.jsx
|
|
110
71
|
import Tippy from "@tippyjs/react";
|
|
111
72
|
import "tippy.js/dist/tippy.css";
|
|
112
|
-
function CustomTooltip({
|
|
113
|
-
content,
|
|
114
|
-
placement = "bottom",
|
|
115
|
-
delay = 0,
|
|
116
|
-
className = "",
|
|
117
|
-
children
|
|
118
|
-
}) {
|
|
119
|
-
return /* @__PURE__ */ React.createElement(
|
|
120
|
-
Tippy,
|
|
121
|
-
{
|
|
122
|
-
content,
|
|
123
|
-
placement,
|
|
124
|
-
className,
|
|
125
|
-
delay
|
|
126
|
-
},
|
|
127
|
-
children
|
|
128
|
-
);
|
|
73
|
+
function CustomTooltip({ content, placement = "bottom", delay = 0, className = "", children }) {
|
|
74
|
+
return /* @__PURE__ */ React.createElement(Tippy, { content, placement, className, delay }, children);
|
|
129
75
|
}
|
|
130
76
|
|
|
131
77
|
// src/components/buttons/IconButton.jsx
|
|
132
|
-
function IconButton({
|
|
133
|
-
title,
|
|
134
|
-
onClick,
|
|
135
|
-
color = "dark",
|
|
136
|
-
className = "",
|
|
137
|
-
loading = false,
|
|
138
|
-
icon,
|
|
139
|
-
tooltip = "",
|
|
140
|
-
disabled
|
|
141
|
-
}) {
|
|
142
|
-
const buttonClasses = `d-flex justify-content-center align-items-center gap-1 m-0 p-1 ${className}`;
|
|
78
|
+
function IconButton({ title, onClick, color = "dark", className = "", loading = false, icon, tooltip = "", disabled }) {
|
|
143
79
|
return /* @__PURE__ */ React.createElement(CustomTooltip, { content: tooltip, placement: "bottom" }, /* @__PURE__ */ React.createElement(
|
|
144
80
|
CLoadingButton4,
|
|
145
81
|
{
|
|
@@ -147,7 +83,7 @@ function IconButton({
|
|
|
147
83
|
variant: "ghost",
|
|
148
84
|
type: "button",
|
|
149
85
|
color,
|
|
150
|
-
className:
|
|
86
|
+
className: `d-flex justify-content-center align-items-center gap-1 m-0 p-1 ${className}`,
|
|
151
87
|
loading,
|
|
152
88
|
disabled
|
|
153
89
|
},
|
|
@@ -155,11 +91,613 @@ function IconButton({
|
|
|
155
91
|
title && /* @__PURE__ */ React.createElement("span", { className: "ml-2 d-none d-md-block" }, title)
|
|
156
92
|
));
|
|
157
93
|
}
|
|
94
|
+
|
|
95
|
+
// src/components/modal/Modal.jsx
|
|
96
|
+
import CIcon5 from "@coreui/icons-react";
|
|
97
|
+
import { CModal, CModalBody, CModalHeader, CModalTitle } from "@coreui/react-pro";
|
|
98
|
+
import { cilX } from "@coreui/icons";
|
|
99
|
+
function Modal({ title, titleIcon, visible, setVisible, alignment = "center", size, children }) {
|
|
100
|
+
return /* @__PURE__ */ React.createElement(CModal, { alignment, visible, onClose: () => setVisible(false), size, focus: true, keyboard: true, "aria-labelledby": "roax-modal-title" }, /* @__PURE__ */ React.createElement(CModalHeader, { className: "position-relative" }, /* @__PURE__ */ React.createElement(CModalTitle, { id: "roax-modal-title", className: "d-flex align-items-center gap-2" }, titleIcon && /* @__PURE__ */ React.createElement(CIcon5, { icon: titleIcon, size: "lg", className: "text-muted" }), title), /* @__PURE__ */ React.createElement(
|
|
101
|
+
"button",
|
|
102
|
+
{
|
|
103
|
+
onClick: () => setVisible(false),
|
|
104
|
+
type: "button",
|
|
105
|
+
className: "position-absolute end-0 top-0 mt-3 me-3 p-0 bg-transparent border-0",
|
|
106
|
+
style: { fontSize: "1.25rem", color: "var(--cui-body-color)", zIndex: 10 },
|
|
107
|
+
"aria-label": "Cerrar"
|
|
108
|
+
},
|
|
109
|
+
/* @__PURE__ */ React.createElement(CIcon5, { icon: cilX, size: "lg" })
|
|
110
|
+
)), /* @__PURE__ */ React.createElement(CModalBody, null, children));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// src/components/card/MetricCard.jsx
|
|
114
|
+
import { CCard, CCardBody } from "@coreui/react-pro";
|
|
115
|
+
import CIcon6 from "@coreui/icons-react";
|
|
116
|
+
import { cilArrowTop, cilArrowBottom, cilInfo } from "@coreui/icons";
|
|
117
|
+
|
|
118
|
+
// src/components/card/card-utils.js
|
|
119
|
+
var formatValue = (val, unit = "", title = "") => {
|
|
120
|
+
if (val == null || typeof val !== "number" || val === 0) return "0";
|
|
121
|
+
if (title.includes("ROAS")) return `x ${val.toFixed(2)}`;
|
|
122
|
+
if (title.includes("CAC %")) return `${val.toFixed(2)}%`;
|
|
123
|
+
if (unit === "%" || title.includes("%")) return `${val.toFixed(2)}%`;
|
|
124
|
+
if (unit === "x") return `x ${val.toFixed(2)}`;
|
|
125
|
+
if (unit === "COP") return `COP ${Math.round(val).toLocaleString("es-CO")}`;
|
|
126
|
+
return val.toLocaleString(void 0, { minimumFractionDigits: 0, maximumFractionDigits: 2 });
|
|
127
|
+
};
|
|
128
|
+
var getBadgeStyles = (isPositive) => ({
|
|
129
|
+
backgroundColor: isPositive ? "#55ed7b" : "#f74a4a",
|
|
130
|
+
color: isPositive ? "#0b3e26" : "#842029",
|
|
131
|
+
borderRadius: "9999px",
|
|
132
|
+
padding: "4px 10px",
|
|
133
|
+
fontSize: "0.75rem",
|
|
134
|
+
fontWeight: 700,
|
|
135
|
+
display: "inline-flex",
|
|
136
|
+
alignItems: "center",
|
|
137
|
+
gap: "4px"
|
|
138
|
+
});
|
|
139
|
+
function formatDateRange(previousDateRange) {
|
|
140
|
+
if (!previousDateRange) return { formattedRange: "" };
|
|
141
|
+
const parts = previousDateRange.split(" - ");
|
|
142
|
+
const parseDate = (str) => {
|
|
143
|
+
const [y, m, d] = str.split("-").map(Number);
|
|
144
|
+
return new Date(y, m - 1, d);
|
|
145
|
+
};
|
|
146
|
+
const format = (date) => {
|
|
147
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
148
|
+
const month = date.toLocaleString("es-CO", { month: "short" }).replace(".", "");
|
|
149
|
+
const year = String(date.getFullYear()).slice(-2);
|
|
150
|
+
return `${month} ${day},${year}`;
|
|
151
|
+
};
|
|
152
|
+
const since = parseDate(parts[0]);
|
|
153
|
+
const until = parts[1] ? parseDate(parts[1]) : null;
|
|
154
|
+
return { formattedRange: until ? `${format(since)} - ${format(until)}` : format(since) };
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// src/components/card/MetricCard.jsx
|
|
158
|
+
import "./MetricCard.scss";
|
|
159
|
+
function MetricCard({ title, current, previous, change, isPositive, unit = "", previousDateRange = "", tooltipText = "", backgroundColor }) {
|
|
160
|
+
const isColored = !!backgroundColor;
|
|
161
|
+
return /* @__PURE__ */ React.createElement(
|
|
162
|
+
CCard,
|
|
163
|
+
{
|
|
164
|
+
className: `metric-card w-100 h-100 d-flex flex-column border-0${isColored ? " metric-card--colored" : ""}`,
|
|
165
|
+
style: isColored ? { background: backgroundColor } : void 0
|
|
166
|
+
},
|
|
167
|
+
/* @__PURE__ */ React.createElement(CCardBody, { className: "d-flex flex-column justify-content-between h-100 p-4 position-relative" }, tooltipText && /* @__PURE__ */ React.createElement("div", { className: "position-absolute top-0 end-0 m-2" }, /* @__PURE__ */ React.createElement(CustomTooltip, { content: tooltipText, placement: "top" }, /* @__PURE__ */ React.createElement(CIcon6, { icon: cilInfo, style: { cursor: "pointer", opacity: 0.5, width: 16, height: 16 } }))), /* @__PURE__ */ React.createElement("p", { className: "metric-card__title m-0" }, title), /* @__PURE__ */ React.createElement("div", { className: "d-flex align-items-center gap-2 mt-1" }, /* @__PURE__ */ React.createElement("span", { className: "metric-card__value" }, formatValue(current, unit, title)), typeof change === "number" && isFinite(change) && current > 0 && /* @__PURE__ */ React.createElement("div", { style: getBadgeStyles(isPositive) }, /* @__PURE__ */ React.createElement(CIcon6, { icon: isPositive ? cilArrowTop : cilArrowBottom, size: "sm" }), Math.abs(change), "%")), /* @__PURE__ */ React.createElement("hr", { className: "metric-card__divider" }), (() => {
|
|
168
|
+
const { formattedRange } = formatDateRange(previousDateRange);
|
|
169
|
+
return /* @__PURE__ */ React.createElement("div", { className: "d-flex justify-content-between align-items-center metric-card__footer" }, /* @__PURE__ */ React.createElement("strong", null, formatValue(previous, unit, title)), /* @__PURE__ */ React.createElement("span", null, formattedRange));
|
|
170
|
+
})())
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// src/components/card/GeneralCard.jsx
|
|
175
|
+
import { CCard as CCard2, CCardBody as CCardBody2 } from "@coreui/react-pro";
|
|
176
|
+
import CIcon7 from "@coreui/icons-react";
|
|
177
|
+
import { cilArrowTop as cilArrowTop2, cilArrowBottom as cilArrowBottom2 } from "@coreui/icons";
|
|
178
|
+
import { Info } from "lucide-react";
|
|
179
|
+
import "./general-card.scss";
|
|
180
|
+
function GeneralCard({
|
|
181
|
+
title,
|
|
182
|
+
current,
|
|
183
|
+
previous,
|
|
184
|
+
change,
|
|
185
|
+
isPositive,
|
|
186
|
+
unit = "",
|
|
187
|
+
previousDateRange = "",
|
|
188
|
+
tooltipText = "",
|
|
189
|
+
backgroundColor
|
|
190
|
+
}) {
|
|
191
|
+
const isColored = !!backgroundColor;
|
|
192
|
+
const cardClass = `general-card w-100 h-100 d-flex flex-column border-0${isColored ? " general-card--colored" : ""}`;
|
|
193
|
+
return /* @__PURE__ */ React.createElement(
|
|
194
|
+
CCard2,
|
|
195
|
+
{
|
|
196
|
+
className: cardClass,
|
|
197
|
+
style: isColored ? { background: backgroundColor } : void 0
|
|
198
|
+
},
|
|
199
|
+
/* @__PURE__ */ React.createElement(CCardBody2, { className: "d-flex flex-column justify-content-between h-100 p-4 position-relative" }, tooltipText && /* @__PURE__ */ React.createElement("div", { className: "position-absolute top-0 end-0 m-2" }, /* @__PURE__ */ React.createElement(CustomTooltip, { content: tooltipText, placement: "top" }, /* @__PURE__ */ React.createElement(
|
|
200
|
+
Info,
|
|
201
|
+
{
|
|
202
|
+
size: 16,
|
|
203
|
+
strokeWidth: 2,
|
|
204
|
+
style: { cursor: "pointer", opacity: 0.5 }
|
|
205
|
+
}
|
|
206
|
+
))), /* @__PURE__ */ React.createElement("p", { className: "general-card__title m-0" }, title), /* @__PURE__ */ React.createElement("div", { className: "d-flex align-items-center gap-2 mt-1" }, /* @__PURE__ */ React.createElement("span", { className: "general-card__value" }, formatValue(current, unit, title)), typeof change === "number" && isFinite(change) && current > 0 && /* @__PURE__ */ React.createElement("div", { style: getBadgeStyles(isPositive) }, /* @__PURE__ */ React.createElement(CIcon7, { icon: isPositive ? cilArrowTop2 : cilArrowBottom2, size: "sm" }), Math.abs(change), "%")), /* @__PURE__ */ React.createElement("hr", { className: "general-card__divider" }), (() => {
|
|
207
|
+
const { formattedRange } = formatDateRange(previousDateRange);
|
|
208
|
+
return /* @__PURE__ */ React.createElement("div", { className: "d-flex justify-content-between align-items-center general-card__footer" }, /* @__PURE__ */ React.createElement("strong", null, formatValue(previous, unit, title)), /* @__PURE__ */ React.createElement("span", null, formattedRange));
|
|
209
|
+
})())
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// src/components/charts/FunnelChart.jsx
|
|
214
|
+
import {
|
|
215
|
+
ResponsiveContainer,
|
|
216
|
+
BarChart,
|
|
217
|
+
Bar,
|
|
218
|
+
XAxis,
|
|
219
|
+
YAxis,
|
|
220
|
+
Tooltip,
|
|
221
|
+
Cell,
|
|
222
|
+
LabelList
|
|
223
|
+
} from "recharts";
|
|
224
|
+
import { CCard as CCard3, CCardBody as CCardBody3, CRow, CCol } from "@coreui/react-pro";
|
|
225
|
+
function FunnelChart({ data = [] }) {
|
|
226
|
+
return /* @__PURE__ */ React.createElement(CCard3, { className: "mt-4 rounded-4 shadow-sm p-3" }, /* @__PURE__ */ React.createElement(CCardBody3, null, /* @__PURE__ */ React.createElement(ResponsiveContainer, { width: "100%", height: data.length * 45 + 50 }, /* @__PURE__ */ React.createElement(
|
|
227
|
+
BarChart,
|
|
228
|
+
{
|
|
229
|
+
data,
|
|
230
|
+
layout: "vertical",
|
|
231
|
+
margin: { top: 10, right: 60, left: 20, bottom: 0 },
|
|
232
|
+
barCategoryGap: 15
|
|
233
|
+
},
|
|
234
|
+
/* @__PURE__ */ React.createElement("defs", null, /* @__PURE__ */ React.createElement("linearGradient", { id: "funnelGradient", x1: "0", y1: "0", x2: "1", y2: "0" }, /* @__PURE__ */ React.createElement("stop", { offset: "0%", stopColor: "#FF8AAE" }), /* @__PURE__ */ React.createElement("stop", { offset: "100%", stopColor: "#FF1F3D" }))),
|
|
235
|
+
/* @__PURE__ */ React.createElement(XAxis, { type: "number", hide: true, domain: [0, "dataMax"] }),
|
|
236
|
+
/* @__PURE__ */ React.createElement(
|
|
237
|
+
YAxis,
|
|
238
|
+
{
|
|
239
|
+
dataKey: "title",
|
|
240
|
+
type: "category",
|
|
241
|
+
width: 130,
|
|
242
|
+
axisLine: false,
|
|
243
|
+
tickLine: false,
|
|
244
|
+
style: { fontWeight: 600, fill: "#333", fontSize: 13 }
|
|
245
|
+
}
|
|
246
|
+
),
|
|
247
|
+
/* @__PURE__ */ React.createElement(
|
|
248
|
+
Tooltip,
|
|
249
|
+
{
|
|
250
|
+
content: ({ active, payload }) => {
|
|
251
|
+
if (active && payload && payload.length > 0) {
|
|
252
|
+
const { value, payload: item } = payload[0];
|
|
253
|
+
return /* @__PURE__ */ React.createElement("div", { className: "bg-white shadow-sm p-2 rounded" }, /* @__PURE__ */ React.createElement("strong", null, item.title), ":", " ", /* @__PURE__ */ React.createElement("span", null, formatValue(value, item.unit, item.title)));
|
|
254
|
+
}
|
|
255
|
+
return null;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
),
|
|
259
|
+
/* @__PURE__ */ React.createElement(Bar, { dataKey: "value", fill: "url(#funnelGradient)", radius: [0, 10, 10, 0] }, /* @__PURE__ */ React.createElement(
|
|
260
|
+
LabelList,
|
|
261
|
+
{
|
|
262
|
+
dataKey: "value",
|
|
263
|
+
position: "right",
|
|
264
|
+
formatter: (val) => formatValue(val),
|
|
265
|
+
style: { fill: "#333", fontWeight: 500, fontSize: 12 }
|
|
266
|
+
}
|
|
267
|
+
), data.map((entry, index) => /* @__PURE__ */ React.createElement(
|
|
268
|
+
Cell,
|
|
269
|
+
{
|
|
270
|
+
key: `cell-${entry.title || index}`,
|
|
271
|
+
fill: entry.color || "url(#funnelGradient)"
|
|
272
|
+
}
|
|
273
|
+
)))
|
|
274
|
+
)), /* @__PURE__ */ React.createElement(CRow, { className: "pt-4 g-3" }, data.slice(0, 3).map((item, index) => /* @__PURE__ */ React.createElement(CCol, { xs: 12, md: 4, key: `card-top-${index}` }, /* @__PURE__ */ React.createElement(
|
|
275
|
+
GeneralCard,
|
|
276
|
+
{
|
|
277
|
+
title: item.title,
|
|
278
|
+
current: item.value,
|
|
279
|
+
previous: item.previous,
|
|
280
|
+
change: item.percentageChange,
|
|
281
|
+
isPositive: item.isPositive,
|
|
282
|
+
unit: item.unit,
|
|
283
|
+
previousDateRange: item.previousDateRange,
|
|
284
|
+
tooltipText: item.title
|
|
285
|
+
}
|
|
286
|
+
)))), data.length > 3 && /* @__PURE__ */ React.createElement(CRow, { className: "pt-3 g-3" }, data.slice(3).map((item, index) => /* @__PURE__ */ React.createElement(CCol, { xs: 12, md: 5, lg: 4, key: `card-bottom-${index}` }, /* @__PURE__ */ React.createElement(
|
|
287
|
+
GeneralCard,
|
|
288
|
+
{
|
|
289
|
+
title: item.title,
|
|
290
|
+
current: item.value,
|
|
291
|
+
previous: item.previous,
|
|
292
|
+
change: item.percentageChange,
|
|
293
|
+
isPositive: item.isPositive,
|
|
294
|
+
unit: item.unit,
|
|
295
|
+
previousDateRange: item.previousDateRange,
|
|
296
|
+
tooltipText: item.title
|
|
297
|
+
}
|
|
298
|
+
))))));
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// src/components/charts/TimeSeriesComparisonChart.jsx
|
|
302
|
+
import {
|
|
303
|
+
ResponsiveContainer as ResponsiveContainer2,
|
|
304
|
+
LineChart,
|
|
305
|
+
Line,
|
|
306
|
+
XAxis as XAxis2,
|
|
307
|
+
YAxis as YAxis2,
|
|
308
|
+
Tooltip as Tooltip2,
|
|
309
|
+
Legend,
|
|
310
|
+
CartesianGrid
|
|
311
|
+
} from "recharts";
|
|
312
|
+
import { CCard as CCard4, CCardBody as CCardBody4, CRow as CRow2, CCol as CCol2 } from "@coreui/react-pro";
|
|
313
|
+
function TimeSeriesComparisonChart({
|
|
314
|
+
data = [],
|
|
315
|
+
lines = [],
|
|
316
|
+
colors = {},
|
|
317
|
+
cards = [],
|
|
318
|
+
currency = "",
|
|
319
|
+
yAxisLabel = "",
|
|
320
|
+
displayNames = {}
|
|
321
|
+
}) {
|
|
322
|
+
const detectUnit = (name = "") => {
|
|
323
|
+
const lower = name.toLowerCase();
|
|
324
|
+
if (lower.includes("%")) return "%";
|
|
325
|
+
if (lower.includes("venta") || lower.includes("inversi\xF3n")) return currency || "";
|
|
326
|
+
return "";
|
|
327
|
+
};
|
|
328
|
+
const maxY = data.length ? Math.ceil(
|
|
329
|
+
Math.max(
|
|
330
|
+
...lines.map((lineName) => Math.max(...data.map((d) => d[lineName] || 0)))
|
|
331
|
+
) * 1.1
|
|
332
|
+
) : 100;
|
|
333
|
+
return /* @__PURE__ */ React.createElement(CCard4, { className: "mt-4 rounded-4 shadow-sm p-3" }, /* @__PURE__ */ React.createElement(CCardBody4, null, cards.length > 0 && /* @__PURE__ */ React.createElement(CRow2, { className: "pt-4 g-3 justify-content-center text-center mb-4" }, cards.map((card, index) => /* @__PURE__ */ React.createElement(CCol2, { xs: 12, md: 4, lg: 5, key: index }, /* @__PURE__ */ React.createElement(
|
|
334
|
+
GeneralCard,
|
|
335
|
+
{
|
|
336
|
+
title: card.title,
|
|
337
|
+
current: card.value,
|
|
338
|
+
previous: card.previous,
|
|
339
|
+
change: card.percentageChange,
|
|
340
|
+
isPositive: card.isPositive,
|
|
341
|
+
unit: card.unit,
|
|
342
|
+
previousDateRange: card.previousDateRange,
|
|
343
|
+
tooltipText: card.title
|
|
344
|
+
}
|
|
345
|
+
)))), /* @__PURE__ */ React.createElement(ResponsiveContainer2, { width: "100%", height: 340 }, /* @__PURE__ */ React.createElement(LineChart, { data, margin: { top: 20, right: 30, left: 10, bottom: 10 } }, /* @__PURE__ */ React.createElement(CartesianGrid, { strokeDasharray: "3 3", stroke: "#e5e5e5" }), /* @__PURE__ */ React.createElement(XAxis2, { dataKey: "date", stroke: "#333", tick: { fontSize: 12 } }), /* @__PURE__ */ React.createElement(
|
|
346
|
+
YAxis2,
|
|
347
|
+
{
|
|
348
|
+
yAxisId: "left",
|
|
349
|
+
stroke: "#333",
|
|
350
|
+
tickFormatter: (val) => `${currency ? currency + " " : ""}${val >= 1e6 ? (val / 1e6).toFixed(1) + "M" : val.toLocaleString("es-CO")}`,
|
|
351
|
+
tick: { fontSize: 12 },
|
|
352
|
+
width: 100,
|
|
353
|
+
domain: [0, maxY],
|
|
354
|
+
allowDecimals: false,
|
|
355
|
+
label: yAxisLabel ? {
|
|
356
|
+
value: yAxisLabel,
|
|
357
|
+
angle: -90,
|
|
358
|
+
position: "insideLeft",
|
|
359
|
+
style: { textAnchor: "middle", fill: "#333", fontSize: 13 }
|
|
360
|
+
} : void 0
|
|
361
|
+
}
|
|
362
|
+
), /* @__PURE__ */ React.createElement(
|
|
363
|
+
Tooltip2,
|
|
364
|
+
{
|
|
365
|
+
formatter: (val, name) => {
|
|
366
|
+
const unit = detectUnit(name);
|
|
367
|
+
return [formatValue(val, unit), displayNames[name] || name];
|
|
368
|
+
},
|
|
369
|
+
labelClassName: "fw-bold",
|
|
370
|
+
wrapperStyle: { zIndex: 1e3 }
|
|
371
|
+
}
|
|
372
|
+
), /* @__PURE__ */ React.createElement(
|
|
373
|
+
Legend,
|
|
374
|
+
{
|
|
375
|
+
verticalAlign: "bottom",
|
|
376
|
+
height: 36,
|
|
377
|
+
wrapperStyle: { marginTop: 20 },
|
|
378
|
+
iconType: "circle",
|
|
379
|
+
formatter: (value) => displayNames[value] || value
|
|
380
|
+
}
|
|
381
|
+
), lines.map((lineName) => /* @__PURE__ */ React.createElement(
|
|
382
|
+
Line,
|
|
383
|
+
{
|
|
384
|
+
key: lineName,
|
|
385
|
+
yAxisId: "left",
|
|
386
|
+
type: "monotone",
|
|
387
|
+
dataKey: lineName,
|
|
388
|
+
stroke: colors[lineName] || "#000",
|
|
389
|
+
strokeWidth: 2.5,
|
|
390
|
+
dot: { r: 4 },
|
|
391
|
+
activeDot: { r: 6 }
|
|
392
|
+
}
|
|
393
|
+
))))));
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// src/components/charts/TopProductsChart.jsx
|
|
397
|
+
import {
|
|
398
|
+
BarChart as BarChart2,
|
|
399
|
+
Bar as Bar2,
|
|
400
|
+
XAxis as XAxis3,
|
|
401
|
+
YAxis as YAxis3,
|
|
402
|
+
Tooltip as Tooltip3,
|
|
403
|
+
ResponsiveContainer as ResponsiveContainer3,
|
|
404
|
+
LabelList as LabelList2,
|
|
405
|
+
Cell as Cell2
|
|
406
|
+
} from "recharts";
|
|
407
|
+
import { CCard as CCard5, CCardBody as CCardBody5 } from "@coreui/react-pro";
|
|
408
|
+
var COLORS = ["#FF6A8D", "#FF8AAE", "#FFA3BC", "#FFC3D0", "#FFE0E7"];
|
|
409
|
+
var ChartTooltip = ({ active, payload }) => {
|
|
410
|
+
if (active && payload && payload.length) {
|
|
411
|
+
return /* @__PURE__ */ React.createElement("div", { className: "bg-white p-2 shadow rounded border border-light" }, /* @__PURE__ */ React.createElement("p", { className: "mb-1 fw-semibold" }, payload[0].payload.name), /* @__PURE__ */ React.createElement("p", { className: "mb-0 text-muted" }, "Cantidad: ", payload[0].value.toLocaleString()));
|
|
412
|
+
}
|
|
413
|
+
return null;
|
|
414
|
+
};
|
|
415
|
+
function TopProductsChart({
|
|
416
|
+
data = [],
|
|
417
|
+
title = "Productos M\xE1s Vendidos",
|
|
418
|
+
emptyText = "No se registraron productos vendidos en este rango de fechas.",
|
|
419
|
+
maxItems = 5
|
|
420
|
+
}) {
|
|
421
|
+
const processedData = (data || []).filter((item) => {
|
|
422
|
+
var _a;
|
|
423
|
+
return item.quantity > 0 && ((_a = item.name) == null ? void 0 : _a.trim());
|
|
424
|
+
}).sort((a, b) => b.quantity - a.quantity).slice(0, maxItems).map((item) => ({ name: item.name, quantity: item.quantity }));
|
|
425
|
+
if (!processedData.length) {
|
|
426
|
+
return /* @__PURE__ */ React.createElement(CCard5, { className: "mt-4 rounded-4 shadow-sm p-3" }, /* @__PURE__ */ React.createElement(CCardBody5, { className: "text-center py-5" }, /* @__PURE__ */ React.createElement("p", { className: "text-muted mb-2" }, /* @__PURE__ */ React.createElement("i", { className: "bi bi-box-seam fs-4 d-block mb-2" }), emptyText)));
|
|
427
|
+
}
|
|
428
|
+
return /* @__PURE__ */ React.createElement(CCard5, { className: "mt-4 rounded-4 shadow-sm p-3" }, /* @__PURE__ */ React.createElement(CCardBody5, null, /* @__PURE__ */ React.createElement("h5", { className: "fw-semibold text-center fs-5 mb-4" }, title), /* @__PURE__ */ React.createElement("div", { style: { height: `${Math.max(processedData.length * 50, 80)}px` } }, /* @__PURE__ */ React.createElement(ResponsiveContainer3, { width: "100%", height: "100%" }, /* @__PURE__ */ React.createElement(
|
|
429
|
+
BarChart2,
|
|
430
|
+
{
|
|
431
|
+
layout: "vertical",
|
|
432
|
+
data: processedData,
|
|
433
|
+
margin: { top: 10, right: 40, left: 20, bottom: 10 }
|
|
434
|
+
},
|
|
435
|
+
/* @__PURE__ */ React.createElement("defs", null, /* @__PURE__ */ React.createElement("linearGradient", { id: "barGradient", x1: "0", y1: "0", x2: "1", y2: "0" }, /* @__PURE__ */ React.createElement("stop", { offset: "0%", stopColor: "#FF8AAE" }), /* @__PURE__ */ React.createElement("stop", { offset: "100%", stopColor: "#FF1F3D" }))),
|
|
436
|
+
/* @__PURE__ */ React.createElement(
|
|
437
|
+
XAxis3,
|
|
438
|
+
{
|
|
439
|
+
type: "number",
|
|
440
|
+
tickFormatter: (value) => value.toLocaleString(),
|
|
441
|
+
axisLine: false,
|
|
442
|
+
tick: { fontSize: 12 }
|
|
443
|
+
}
|
|
444
|
+
),
|
|
445
|
+
/* @__PURE__ */ React.createElement(
|
|
446
|
+
YAxis3,
|
|
447
|
+
{
|
|
448
|
+
type: "category",
|
|
449
|
+
dataKey: "name",
|
|
450
|
+
width: 150,
|
|
451
|
+
tick: { fontSize: 13 },
|
|
452
|
+
tickFormatter: (value) => value.length > 30 ? value.substring(0, 30) + "..." : value
|
|
453
|
+
}
|
|
454
|
+
),
|
|
455
|
+
/* @__PURE__ */ React.createElement(Tooltip3, { content: /* @__PURE__ */ React.createElement(ChartTooltip, null) }),
|
|
456
|
+
/* @__PURE__ */ React.createElement(Bar2, { dataKey: "quantity", fill: "url(#barGradient)", radius: [0, 8, 8, 0] }, /* @__PURE__ */ React.createElement(
|
|
457
|
+
LabelList2,
|
|
458
|
+
{
|
|
459
|
+
dataKey: "quantity",
|
|
460
|
+
position: "right",
|
|
461
|
+
formatter: (value) => value.toLocaleString(),
|
|
462
|
+
style: { fill: "#333", fontWeight: 500, fontSize: 12 }
|
|
463
|
+
}
|
|
464
|
+
), processedData.map((_, index) => /* @__PURE__ */ React.createElement(Cell2, { key: `cell-${index}`, fill: COLORS[index % COLORS.length] })))
|
|
465
|
+
)))));
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// src/components/charts/SalesByChannelChart.jsx
|
|
469
|
+
import {
|
|
470
|
+
ResponsiveContainer as ResponsiveContainer4,
|
|
471
|
+
BarChart as BarChart3,
|
|
472
|
+
Bar as Bar3,
|
|
473
|
+
XAxis as XAxis4,
|
|
474
|
+
YAxis as YAxis4,
|
|
475
|
+
Tooltip as Tooltip4,
|
|
476
|
+
Legend as Legend2,
|
|
477
|
+
CartesianGrid as CartesianGrid2
|
|
478
|
+
} from "recharts";
|
|
479
|
+
import { CCard as CCard6, CCardBody as CCardBody6 } from "@coreui/react-pro";
|
|
480
|
+
function SalesByChannelChart({
|
|
481
|
+
data = [],
|
|
482
|
+
title = "Ventas por canal",
|
|
483
|
+
emptyText = "Sin datos para este per\xEDodo",
|
|
484
|
+
channels = ["Meta", "TikTok", "Google"],
|
|
485
|
+
channelColors = { Meta: "#FF2F86", TikTok: "#C0C0C0", Google: "#333333" }
|
|
486
|
+
}) {
|
|
487
|
+
const hasData = data.length > 0;
|
|
488
|
+
return /* @__PURE__ */ React.createElement(CCard6, { className: "rounded-4 shadow-sm p-3" }, /* @__PURE__ */ React.createElement(CCardBody6, null, /* @__PURE__ */ React.createElement("h5", { className: "fw-bold text-center" }, title), !hasData ? /* @__PURE__ */ React.createElement("p", { className: "text-center text-muted" }, emptyText) : /* @__PURE__ */ React.createElement(ResponsiveContainer4, { width: "100%", height: 300 }, /* @__PURE__ */ React.createElement(BarChart3, { data, margin: { top: 20, right: 30, left: 10, bottom: 10 } }, /* @__PURE__ */ React.createElement(CartesianGrid2, { strokeDasharray: "3 3", stroke: "#e5e5e5" }), /* @__PURE__ */ React.createElement(
|
|
489
|
+
XAxis4,
|
|
490
|
+
{
|
|
491
|
+
dataKey: "fecha",
|
|
492
|
+
tick: { fontSize: 12 },
|
|
493
|
+
angle: -45,
|
|
494
|
+
textAnchor: "end",
|
|
495
|
+
interval: Math.ceil(data.length / 10)
|
|
496
|
+
}
|
|
497
|
+
), /* @__PURE__ */ React.createElement(YAxis4, { tick: { fontSize: 12 } }), /* @__PURE__ */ React.createElement(Tooltip4, null), /* @__PURE__ */ React.createElement(Legend2, { verticalAlign: "top", height: 36, iconType: "circle" }), channels.map((channel) => /* @__PURE__ */ React.createElement(
|
|
498
|
+
Bar3,
|
|
499
|
+
{
|
|
500
|
+
key: channel,
|
|
501
|
+
dataKey: channel,
|
|
502
|
+
stackId: "ventas",
|
|
503
|
+
fill: channelColors[channel] || "#888"
|
|
504
|
+
}
|
|
505
|
+
))))));
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// src/components/charts/InvestmentByPlatformChart.jsx
|
|
509
|
+
import {
|
|
510
|
+
PieChart,
|
|
511
|
+
Pie,
|
|
512
|
+
Cell as Cell3,
|
|
513
|
+
Legend as Legend3,
|
|
514
|
+
Tooltip as Tooltip5,
|
|
515
|
+
ResponsiveContainer as ResponsiveContainer5
|
|
516
|
+
} from "recharts";
|
|
517
|
+
import { CCard as CCard7, CCardBody as CCardBody7 } from "@coreui/react-pro";
|
|
518
|
+
var DEFAULT_COLORS = ["#FF2F86", "#D9D9D9", "#333333"];
|
|
519
|
+
function InvestmentByPlatformChart({
|
|
520
|
+
data = [],
|
|
521
|
+
title = "Inversi\xF3n por plataforma",
|
|
522
|
+
colors = DEFAULT_COLORS,
|
|
523
|
+
currencySymbol = "COP",
|
|
524
|
+
locale = "es-CO"
|
|
525
|
+
}) {
|
|
526
|
+
return /* @__PURE__ */ React.createElement(CCard7, { className: "rounded-4 shadow-sm p-3" }, /* @__PURE__ */ React.createElement(CCardBody7, null, /* @__PURE__ */ React.createElement("h5", { className: "text-center fw-bold" }, title), /* @__PURE__ */ React.createElement(ResponsiveContainer5, { width: "100%", height: 280 }, /* @__PURE__ */ React.createElement(PieChart, null, /* @__PURE__ */ React.createElement(
|
|
527
|
+
Pie,
|
|
528
|
+
{
|
|
529
|
+
data,
|
|
530
|
+
dataKey: "value",
|
|
531
|
+
nameKey: "name",
|
|
532
|
+
cx: "50%",
|
|
533
|
+
cy: "50%",
|
|
534
|
+
innerRadius: 60,
|
|
535
|
+
outerRadius: 100,
|
|
536
|
+
paddingAngle: 5,
|
|
537
|
+
label: ({ name, percent }) => `${name} ${(percent * 100).toFixed(1)}%`
|
|
538
|
+
},
|
|
539
|
+
data.map((_, index) => /* @__PURE__ */ React.createElement(Cell3, { key: `cell-${index}`, fill: colors[index % colors.length] }))
|
|
540
|
+
), /* @__PURE__ */ React.createElement(
|
|
541
|
+
Tooltip5,
|
|
542
|
+
{
|
|
543
|
+
formatter: (value) => `${currencySymbol} ${value.toLocaleString(locale)}`
|
|
544
|
+
}
|
|
545
|
+
), /* @__PURE__ */ React.createElement(Legend3, { verticalAlign: "bottom", height: 36 })))));
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
// src/components/pagination/PaginatedTable.jsx
|
|
549
|
+
import { CTable, CTableHead, CTableBody, CTableRow, CTableHeaderCell, CSpinner } from "@coreui/react-pro";
|
|
550
|
+
function PaginatedTable({ data = [], itemsPerPage = 10, currentPage = 1, setCurrentPage = () => {
|
|
551
|
+
}, columns = [], renderRow = () => null, loading = false, emptyMessage = "No hay datos disponibles." }) {
|
|
552
|
+
const totalPages = Math.ceil(data.length / itemsPerPage);
|
|
553
|
+
const paginatedData = data.slice((currentPage - 1) * itemsPerPage, currentPage * itemsPerPage);
|
|
554
|
+
if (loading) return /* @__PURE__ */ React.createElement("div", { className: "text-center py-5" }, /* @__PURE__ */ React.createElement(CSpinner, { color: "secondary" }));
|
|
555
|
+
if (!data.length) return /* @__PURE__ */ React.createElement("div", { className: "text-center py-5 text-muted" }, emptyMessage);
|
|
556
|
+
const renderPagination = () => {
|
|
557
|
+
const pages = Array.from({ length: totalPages }, (_, i) => i + 1);
|
|
558
|
+
return /* @__PURE__ */ React.createElement("div", { className: "d-flex justify-content-center align-items-center gap-2 mt-3 flex-wrap" }, currentPage > 1 && /* @__PURE__ */ React.createElement("button", { onClick: () => setCurrentPage(currentPage - 1), className: "px-3 py-1 rounded-pill border bg-white text-dark", style: { minWidth: 80, fontWeight: 500 } }, "Anterior"), pages.map((i) => /* @__PURE__ */ React.createElement("button", { key: i, onClick: () => setCurrentPage(i), className: `px-3 py-1 rounded-pill border ${i === currentPage ? "bg-dark text-white" : "bg-white text-dark"}` }, i)), currentPage < totalPages && /* @__PURE__ */ React.createElement("button", { onClick: () => setCurrentPage(currentPage + 1), className: "px-3 py-1 rounded-pill border bg-white text-dark", style: { minWidth: 80, fontWeight: 500 } }, "Siguiente"));
|
|
559
|
+
};
|
|
560
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(CTable, { hover: true, responsive: true }, /* @__PURE__ */ React.createElement(CTableHead, { className: "bg-dark text-white" }, /* @__PURE__ */ React.createElement(CTableRow, null, columns.map((col, i) => /* @__PURE__ */ React.createElement(CTableHeaderCell, { key: i }, col)))), /* @__PURE__ */ React.createElement(CTableBody, null, paginatedData.map(renderRow))), totalPages > 1 && renderPagination());
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
// src/components/pagination/PaginatedGrid.jsx
|
|
564
|
+
import { CSpinner as CSpinner2 } from "@coreui/react-pro";
|
|
565
|
+
function PaginatedGrid({ data = [], itemsPerPage = 6, currentPage = 1, setCurrentPage = () => {
|
|
566
|
+
}, renderItem = () => null, loading = false, emptyMessage = "No hay elementos." }) {
|
|
567
|
+
const totalPages = Math.ceil(data.length / itemsPerPage);
|
|
568
|
+
const paginatedData = data.slice((currentPage - 1) * itemsPerPage, currentPage * itemsPerPage);
|
|
569
|
+
if (loading) return /* @__PURE__ */ React.createElement("div", { className: "text-center py-5" }, /* @__PURE__ */ React.createElement(CSpinner2, { color: "secondary" }));
|
|
570
|
+
if (!data.length) return /* @__PURE__ */ React.createElement("div", { className: "text-center py-5 text-muted" }, emptyMessage);
|
|
571
|
+
const renderPagination = () => {
|
|
572
|
+
const pages = Array.from({ length: totalPages }, (_, i) => i + 1);
|
|
573
|
+
return /* @__PURE__ */ React.createElement("div", { className: "d-flex justify-content-center gap-2 mt-4 flex-wrap" }, currentPage > 1 && /* @__PURE__ */ React.createElement("button", { onClick: () => setCurrentPage(currentPage - 1), className: "px-3 py-1 rounded-pill border bg-white text-dark" }, "Anterior"), pages.map((i) => /* @__PURE__ */ React.createElement("button", { key: i, onClick: () => setCurrentPage(i), className: `px-3 py-1 rounded-pill border ${i === currentPage ? "bg-dark text-white" : "bg-white text-dark"}` }, i)), currentPage < totalPages && /* @__PURE__ */ React.createElement("button", { onClick: () => setCurrentPage(currentPage + 1), className: "px-3 py-1 rounded-pill border bg-white text-dark" }, "Siguiente"));
|
|
574
|
+
};
|
|
575
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "row g-4" }, paginatedData.map(renderItem)), totalPages > 1 && renderPagination());
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
// src/components/skeletons/CardSkeleton.jsx
|
|
579
|
+
import { CCard as CCard8, CPlaceholder } from "@coreui/react-pro";
|
|
580
|
+
function CardSkeleton() {
|
|
581
|
+
return /* @__PURE__ */ React.createElement(CCard8, { className: "shadow-none p-0 m-0 bg-transparent border-0" }, /* @__PURE__ */ React.createElement(CPlaceholder, { component: "div", animation: "glow", className: "d-flex flex-column gap-2 bg-transparent" }, /* @__PURE__ */ React.createElement(CPlaceholder, { className: "p-4 mt-2 rounded-1", size: "lg", xs: 12, color: "skeleton" })));
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
// src/components/skeletons/TextSkeleton.jsx
|
|
585
|
+
import { CCard as CCard9, CPlaceholder as CPlaceholder2 } from "@coreui/react-pro";
|
|
586
|
+
function TextSkeleton() {
|
|
587
|
+
return /* @__PURE__ */ React.createElement(CCard9, { className: "shadow-none p-0 m-0 bg-transparent border-0" }, /* @__PURE__ */ React.createElement(CPlaceholder2, { component: "div", animation: "glow", className: "d-flex flex-column gap-2 bg-transparent" }, /* @__PURE__ */ React.createElement(CPlaceholder2, { className: "p-0 my-2 rounded-1", size: "lg", xs: 8, color: "skeleton" })));
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
// src/components/skeletons/MetricsSkeleton.jsx
|
|
591
|
+
import { CCard as CCard10, CPlaceholder as CPlaceholder3 } from "@coreui/react-pro";
|
|
592
|
+
function MetricsSkeleton() {
|
|
593
|
+
return /* @__PURE__ */ React.createElement(CCard10, { className: "shadow-none p-0 m-0 bg-transparent border-0" }, /* @__PURE__ */ React.createElement(CPlaceholder3, { component: "div", animation: "glow", className: "d-flex flex-column gap-2 bg-transparent" }, /* @__PURE__ */ React.createElement(CPlaceholder3, { className: "p-5 mt-2 rounded-1", size: "lg", xs: 12, color: "skeleton" }), /* @__PURE__ */ React.createElement(CPlaceholder3, { className: "p-3 mt-2 rounded-1", size: "xs", xs: 12, color: "skeleton" })));
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
// src/components/skeletons/ReportTableSkeleton.jsx
|
|
597
|
+
import { CCard as CCard11, CPlaceholder as CPlaceholder4 } from "@coreui/react-pro";
|
|
598
|
+
function ReportTableSkeleton() {
|
|
599
|
+
return /* @__PURE__ */ React.createElement(CCard11, { className: "shadow-none p-0 m-0 bg-transparent border-0" }, /* @__PURE__ */ React.createElement(
|
|
600
|
+
CPlaceholder4,
|
|
601
|
+
{
|
|
602
|
+
component: "div",
|
|
603
|
+
animation: "glow",
|
|
604
|
+
className: "d-flex flex-column gap-2 bg-transparent"
|
|
605
|
+
},
|
|
606
|
+
/* @__PURE__ */ React.createElement(CPlaceholder4, { className: "p-4 mt-2 rounded-1", size: "lg", xs: 12, color: "skeleton" }),
|
|
607
|
+
/* @__PURE__ */ React.createElement(CPlaceholder4, { className: "p-5 mt-2 rounded-1", size: "lg", xs: 12, color: "skeleton" })
|
|
608
|
+
));
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
// src/components/skeletons/SummaryReportSkeleton.jsx
|
|
612
|
+
import { CCard as CCard12, CCol as CCol3, CPlaceholder as CPlaceholder5, CRow as CRow3 } from "@coreui/react-pro";
|
|
613
|
+
var CardPlaceholder = ({ className = "" }) => /* @__PURE__ */ React.createElement(CCard12, { className: "shadow-none p-0 m-0 bg-transparent border-0" }, /* @__PURE__ */ React.createElement(
|
|
614
|
+
CPlaceholder5,
|
|
615
|
+
{
|
|
616
|
+
component: "div",
|
|
617
|
+
animation: "glow",
|
|
618
|
+
className: `d-flex flex-column gap-2 bg-transparent ${className}`
|
|
619
|
+
},
|
|
620
|
+
/* @__PURE__ */ React.createElement(CPlaceholder5, { className: "p-4 mt-2 rounded-2", size: "lg", xs: 12, color: "skeleton" })
|
|
621
|
+
));
|
|
622
|
+
function SummaryReportSkeleton({
|
|
623
|
+
layout = [
|
|
624
|
+
{ sm: 6, md: 6 },
|
|
625
|
+
{ sm: 6, md: 6 },
|
|
626
|
+
{ sm: 6, md: 4 },
|
|
627
|
+
{ sm: 6, md: 4 },
|
|
628
|
+
{ sm: 6, md: 4 },
|
|
629
|
+
{ sm: 6, md: 6 },
|
|
630
|
+
{ sm: 6, md: 4 },
|
|
631
|
+
{ sm: 6, md: 2 }
|
|
632
|
+
]
|
|
633
|
+
}) {
|
|
634
|
+
return /* @__PURE__ */ React.createElement(CRow3, { className: "g-md-3 px-4 px-sm-2 g-sm-2 pt-2 pb-4" }, layout.map((col, index) => /* @__PURE__ */ React.createElement(CCol3, { sm: col.sm, md: col.md, key: index }, /* @__PURE__ */ React.createElement(CardPlaceholder, null))));
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
// ../../node_modules/@coreui/icons-pro/dist/esm/duotone/cid-exclamation-circle.js
|
|
638
|
+
var cidExclamationCircle = ["512 512", "<path fill='var(--ci-secondary-color, currentColor)' d='M256,16C123.452,16,16,123.452,16,256S123.452,496,256,496a238.867,238.867,0,0,0,132.685-40q1.668-1.108,3.315-2.246A239.721,239.721,0,0,0,496,256C496,123.452,388.548,16,256,16Z' class='ci-secondary' opacity='var(--ci-secondary-opacity, 0.25)'/><polygon fill='var(--ci-primary-color, currentColor)' points='224 232 238 304 274 304 288 232 288 120 224 120 224 232' class='ci-primary'/><rect width='40' height='40' x='236' y='344' fill='var(--ci-primary-color, currentColor)' class='ci-primary'/>"];
|
|
639
|
+
|
|
640
|
+
// src/components/feedback/NoDataMessage.jsx
|
|
641
|
+
import CIcon8 from "@coreui/icons-react";
|
|
642
|
+
function NoDataMessage({
|
|
643
|
+
message = "No se obtuvieron datos. Revisa el rango de fechas y la integraci\xF3n."
|
|
644
|
+
}) {
|
|
645
|
+
return /* @__PURE__ */ React.createElement(
|
|
646
|
+
"div",
|
|
647
|
+
{
|
|
648
|
+
className: "d-flex align-items-center gap-2 rounded-3 px-3 py-3 mt-3 mb-3",
|
|
649
|
+
style: {
|
|
650
|
+
backgroundColor: "var(--cui-warning-bg-subtle)",
|
|
651
|
+
border: "1px solid var(--cui-warning)",
|
|
652
|
+
color: "var(--cui-body-color)"
|
|
653
|
+
}
|
|
654
|
+
},
|
|
655
|
+
/* @__PURE__ */ React.createElement(
|
|
656
|
+
CIcon8,
|
|
657
|
+
{
|
|
658
|
+
icon: cidExclamationCircle,
|
|
659
|
+
className: "flex-shrink-0 me-2 text-warning",
|
|
660
|
+
size: "xxl"
|
|
661
|
+
}
|
|
662
|
+
),
|
|
663
|
+
message
|
|
664
|
+
);
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
// src/components/back-button/BackButton.jsx
|
|
668
|
+
import { useRouter } from "next/navigation";
|
|
669
|
+
import { CButton } from "@coreui/react-pro";
|
|
670
|
+
import { cilArrowLeft } from "@coreui/icons";
|
|
671
|
+
import CIcon9 from "@coreui/icons-react";
|
|
672
|
+
function BackButton({ title, color = "dark", className = "", path }) {
|
|
673
|
+
const { back, push } = useRouter();
|
|
674
|
+
return /* @__PURE__ */ React.createElement(CustomTooltip, { content: "Volver atr\xE1s", placement: "bottom" }, /* @__PURE__ */ React.createElement(CButton, { color, variant: "ghost", className: `back-button d-flex align-items-center px-0 ${className}`, onClick: () => path ? push(path) : back() }, /* @__PURE__ */ React.createElement(CIcon9, { icon: cilArrowLeft, size: "lg", className: "mx-1" }), title && /* @__PURE__ */ React.createElement("span", { className: "px-2" }, title)));
|
|
675
|
+
}
|
|
158
676
|
export {
|
|
677
|
+
BackButton,
|
|
678
|
+
CardSkeleton,
|
|
159
679
|
CustomTooltip,
|
|
680
|
+
FunnelChart,
|
|
681
|
+
GeneralCard,
|
|
160
682
|
IconButton,
|
|
683
|
+
InvestmentByPlatformChart,
|
|
684
|
+
MetricCard,
|
|
685
|
+
MetricsSkeleton,
|
|
686
|
+
Modal,
|
|
687
|
+
NoDataMessage,
|
|
161
688
|
OutlineButton,
|
|
689
|
+
PaginatedGrid,
|
|
690
|
+
PaginatedTable,
|
|
691
|
+
ReportTableSkeleton,
|
|
692
|
+
SalesByChannelChart,
|
|
162
693
|
SolidButton,
|
|
163
|
-
|
|
694
|
+
SummaryReportSkeleton,
|
|
695
|
+
TextButton,
|
|
696
|
+
TextSkeleton,
|
|
697
|
+
TimeSeriesComparisonChart,
|
|
698
|
+
TopProductsChart,
|
|
699
|
+
formatDateRange,
|
|
700
|
+
formatValue,
|
|
701
|
+
getBadgeStyles
|
|
164
702
|
};
|
|
165
703
|
//# sourceMappingURL=index.mjs.map
|