contentoh-components-library 21.6.62 → 21.6.64
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/dist/components/atoms/MetricCard/index.js +3 -1
- package/dist/components/organisms/DashboardMetric/DashboardMetric.stories.js +12 -2
- package/dist/components/organisms/DashboardMetric/index.js +36 -8
- package/dist/components/organisms/DashboardMetric/styles.js +1 -1
- package/dist/components/pages/Dashboard/dashboardUtils.js +3 -3
- package/dist/components/pages/Dashboard/index.js +102 -88
- package/dist/components/pages/Dashboard/styles.js +1 -1
- package/package.json +1 -1
- package/src/components/atoms/MetricCard/index.js +2 -2
- package/src/components/organisms/DashboardMetric/DashboardMetric.stories.js +11 -0
- package/src/components/organisms/DashboardMetric/index.js +18 -2
- package/src/components/organisms/DashboardMetric/styles.js +19 -0
- package/src/components/pages/Dashboard/dashboardUtils.js +3 -3
- package/src/components/pages/Dashboard/index.js +62 -106
- package/src/components/pages/Dashboard/styles.js +17 -12
|
@@ -11,8 +11,10 @@ var _jsxRuntime = require("react/jsx-runtime");
|
|
|
11
11
|
|
|
12
12
|
var MetricCard = function MetricCard(_ref) {
|
|
13
13
|
var label = _ref.label,
|
|
14
|
-
number = _ref.number
|
|
14
|
+
number = _ref.number,
|
|
15
|
+
hint = _ref.hint;
|
|
15
16
|
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_styles.Container, {
|
|
17
|
+
title: hint,
|
|
16
18
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("p", {
|
|
17
19
|
children: label
|
|
18
20
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)("p", {
|
|
@@ -5,7 +5,7 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", {
|
|
6
6
|
value: true
|
|
7
7
|
});
|
|
8
|
-
exports.default = exports.DashboardMetricDefault = void 0;
|
|
8
|
+
exports.default = exports.DashboardMetricDoughnut = exports.DashboardMetricDefault = void 0;
|
|
9
9
|
|
|
10
10
|
var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/esm/objectSpread2"));
|
|
11
11
|
|
|
@@ -42,4 +42,14 @@ DashboardMetricDefault.args = {
|
|
|
42
42
|
RC: 11,
|
|
43
43
|
RP: 49
|
|
44
44
|
}
|
|
45
|
-
};
|
|
45
|
+
};
|
|
46
|
+
var DashboardMetricDoughnut = Template.bind({});
|
|
47
|
+
exports.DashboardMetricDoughnut = DashboardMetricDoughnut;
|
|
48
|
+
DashboardMetricDoughnut.args = (0, _objectSpread2.default)((0, _objectSpread2.default)({}, DashboardMetricDefault.args), {}, {
|
|
49
|
+
type: "doughnut",
|
|
50
|
+
displayLegend: true,
|
|
51
|
+
showPercent: true,
|
|
52
|
+
displayScale: false,
|
|
53
|
+
total: 1610,
|
|
54
|
+
totalFiltered: 1610
|
|
55
|
+
});
|
|
@@ -11,6 +11,8 @@ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/es
|
|
|
11
11
|
|
|
12
12
|
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/esm/slicedToArray"));
|
|
13
13
|
|
|
14
|
+
var _react = require("react");
|
|
15
|
+
|
|
14
16
|
var _styles = require("./styles");
|
|
15
17
|
|
|
16
18
|
var _Graphic = require("../../atoms/Graphic");
|
|
@@ -41,10 +43,34 @@ var DashboardMetric = function DashboardMetric(_ref) {
|
|
|
41
43
|
borderColor = _ref.borderColor,
|
|
42
44
|
total = _ref.total,
|
|
43
45
|
totalFiltered = _ref.totalFiltered;
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
// Chart.js coloca la leyenda por opción, no por CSS. Se mide el panel y no
|
|
47
|
+
// la ventana, porque el ancho real depende también del menú de la app: a
|
|
48
|
+
// 828px de ventana el panel queda en 331 y la leyenda de lado sale cortada.
|
|
49
|
+
var containerRef = (0, _react.useRef)(null);
|
|
50
|
+
|
|
51
|
+
var _useState = (0, _react.useState)(false),
|
|
52
|
+
_useState2 = (0, _slicedToArray2.default)(_useState, 2),
|
|
53
|
+
isNarrow = _useState2[0],
|
|
54
|
+
setIsNarrow = _useState2[1];
|
|
55
|
+
|
|
56
|
+
(0, _react.useEffect)(function () {
|
|
57
|
+
var node = containerRef.current;
|
|
58
|
+
if (!node || typeof ResizeObserver === "undefined") return undefined;
|
|
59
|
+
var observer = new ResizeObserver(function (_ref2) {
|
|
60
|
+
var _ref3 = (0, _slicedToArray2.default)(_ref2, 1),
|
|
61
|
+
entry = _ref3[0];
|
|
62
|
+
|
|
63
|
+
return setIsNarrow(entry.contentRect.width < 420);
|
|
64
|
+
});
|
|
65
|
+
observer.observe(node);
|
|
66
|
+
return function () {
|
|
67
|
+
return observer.disconnect();
|
|
68
|
+
};
|
|
69
|
+
}, []);
|
|
70
|
+
var labels = type === "doughnut" ? Object.entries(dataObject).map(function (_ref4) {
|
|
71
|
+
var _ref5 = (0, _slicedToArray2.default)(_ref4, 2),
|
|
72
|
+
key = _ref5[0],
|
|
73
|
+
value = _ref5[1];
|
|
48
74
|
|
|
49
75
|
return key !== "NS" && "".concat((0, _dashboardMetricUtils.getFullStatus)(key), " (").concat(value, ")");
|
|
50
76
|
}) : Object.keys(dataObject);
|
|
@@ -74,11 +100,11 @@ var DashboardMetric = function DashboardMetric(_ref) {
|
|
|
74
100
|
plugins: {
|
|
75
101
|
tooltip: {
|
|
76
102
|
callbacks: {
|
|
77
|
-
label: function label(
|
|
103
|
+
label: function label(_ref6) {
|
|
78
104
|
var _dataset$data;
|
|
79
105
|
|
|
80
|
-
var dataset =
|
|
81
|
-
element =
|
|
106
|
+
var dataset = _ref6.dataset,
|
|
107
|
+
element = _ref6.element;
|
|
82
108
|
var sum = dataset === null || dataset === void 0 ? void 0 : (_dataset$data = dataset.data) === null || _dataset$data === void 0 ? void 0 : _dataset$data.reduce(function (accumulator, value) {
|
|
83
109
|
return accumulator + value;
|
|
84
110
|
}, 0);
|
|
@@ -90,7 +116,7 @@ var DashboardMetric = function DashboardMetric(_ref) {
|
|
|
90
116
|
}
|
|
91
117
|
},
|
|
92
118
|
legend: {
|
|
93
|
-
position: "right",
|
|
119
|
+
position: isNarrow ? "bottom" : "right",
|
|
94
120
|
display: displayLegend,
|
|
95
121
|
labels: {
|
|
96
122
|
usePointStyle: true,
|
|
@@ -113,6 +139,8 @@ var DashboardMetric = function DashboardMetric(_ref) {
|
|
|
113
139
|
showTooltips: true
|
|
114
140
|
};
|
|
115
141
|
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_styles.Container, {
|
|
142
|
+
ref: containerRef,
|
|
143
|
+
className: isNarrow ? "is-narrow" : "",
|
|
116
144
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
|
|
117
145
|
className: "text-container",
|
|
118
146
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("p", {
|
|
@@ -15,6 +15,6 @@ var _variables = require("../../../global-files/variables");
|
|
|
15
15
|
|
|
16
16
|
var _templateObject;
|
|
17
17
|
|
|
18
|
-
var Container = _styledComponents.default.div(_templateObject || (_templateObject = (0, _taggedTemplateLiteral2.default)(["\n border: 1px solid ", ";\n border-radius: 5px;\n padding: 24px;\n position: relative;\n\n .text-container {\n p {\n font-family: ", ";\n color: ", ";\n font-size: 17px;\n\n &:last-of-type {\n font-size: 12px;\n color: ", ";\n }\n\n & + * {\n margin-top: 5px;\n }\n }\n\n & + * {\n margin-top: 15px;\n }\n }\n\n .select-container {\n display: flex;\n\n .select {\n flex: 0.1 1 30%;\n\n select {\n width: 100%;\n }\n\n & + * {\n margin-left: 10px;\n }\n }\n\n & + * {\n margin-top: 10px;\n }\n }\n\n .graphic-cotainer {\n height: 350px;\n border: 1px solid ", ";\n padding: 10px;\n border-radius: 5px;\n\n div {\n height: fill-available;\n }\n }\n\n & > p {\n font-family: ", ";\n color: ", ";\n font-size: 17px;\n\n &.x-label {\n position: absolute;\n left: 50%;\n transform: translate(-50%);\n bottom: 4px;\n }\n\n &.y-label {\n position: absolute;\n transform: rotate(-90deg);\n left: -28px;\n top: 50%;\n }\n\n &.center-label {\n position: absolute;\n top: 52%;\n right: 58%;\n font-size: 28px;\n color: #000;\n font-feature-settings: \"pnum\", \"lnum\";\n font-family: ", ";\n }\n }\n"])), _variables.GlobalColors.s3, _variables.FontFamily.Raleway, _variables.GlobalColors.s5, _variables.GlobalColors.s4, _variables.GlobalColors.s3, _variables.FontFamily.Raleway, _variables.GlobalColors.s5, _variables.FontFamily.Raleway_600);
|
|
18
|
+
var Container = _styledComponents.default.div(_templateObject || (_templateObject = (0, _taggedTemplateLiteral2.default)(["\n border: 1px solid ", ";\n border-radius: 5px;\n padding: 24px;\n position: relative;\n\n @media (max-width: 600px) {\n padding: 12px;\n\n .graphic-cotainer {\n padding: 5px;\n }\n\n /* Va rotada y fuera del recuadro; con el padding chico se encima. */\n > p.y-label {\n display: none;\n }\n }\n\n .text-container {\n p {\n font-family: ", ";\n color: ", ";\n font-size: 17px;\n\n &:last-of-type {\n font-size: 12px;\n color: ", ";\n }\n\n & + * {\n margin-top: 5px;\n }\n }\n\n & + * {\n margin-top: 15px;\n }\n }\n\n .select-container {\n display: flex;\n\n .select {\n flex: 0.1 1 30%;\n\n select {\n width: 100%;\n }\n\n & + * {\n margin-left: 10px;\n }\n }\n\n & + * {\n margin-top: 10px;\n }\n }\n\n /* Con la leyenda abajo, Chart.js le da un m\xE1ximo de la altura del recuadro\n y descarta las entradas que no caben; por eso crece junto con ella. */\n &.is-narrow .graphic-cotainer {\n height: 500px;\n }\n\n .graphic-cotainer {\n height: 350px;\n border: 1px solid ", ";\n padding: 10px;\n border-radius: 5px;\n\n div {\n height: fill-available;\n }\n }\n\n & > p {\n font-family: ", ";\n color: ", ";\n font-size: 17px;\n\n &.x-label {\n position: absolute;\n left: 50%;\n transform: translate(-50%);\n bottom: 4px;\n }\n\n &.y-label {\n position: absolute;\n transform: rotate(-90deg);\n left: -28px;\n top: 50%;\n }\n\n &.center-label {\n position: absolute;\n top: 52%;\n right: 58%;\n font-size: 28px;\n color: #000;\n font-feature-settings: \"pnum\", \"lnum\";\n font-family: ", ";\n }\n }\n"])), _variables.GlobalColors.s3, _variables.FontFamily.Raleway, _variables.GlobalColors.s5, _variables.GlobalColors.s4, _variables.GlobalColors.s3, _variables.FontFamily.Raleway, _variables.GlobalColors.s5, _variables.FontFamily.Raleway_600);
|
|
19
19
|
|
|
20
20
|
exports.Container = Container;
|
|
@@ -111,9 +111,9 @@ exports.getCategories = getCategories;
|
|
|
111
111
|
var formatDate = function formatDate(date) {
|
|
112
112
|
var newDate = new Date(date);
|
|
113
113
|
var year = newDate.getFullYear();
|
|
114
|
-
var month = newDate.getMonth() + 1;
|
|
115
|
-
var day = newDate.getDate();
|
|
116
|
-
return "".concat(year, "
|
|
114
|
+
var month = "".concat(newDate.getMonth() + 1).padStart(2, "0");
|
|
115
|
+
var day = "".concat(newDate.getDate()).padStart(2, "0");
|
|
116
|
+
return "".concat(year, "-").concat(month, "-").concat(day);
|
|
117
117
|
};
|
|
118
118
|
|
|
119
119
|
exports.formatDate = formatDate;
|
|
@@ -32,7 +32,7 @@ var _axios = _interopRequireDefault(require("axios"));
|
|
|
32
32
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
33
33
|
|
|
34
34
|
var Dashboard = function Dashboard(_ref) {
|
|
35
|
-
var _company$financedReta
|
|
35
|
+
var _company$financedReta;
|
|
36
36
|
|
|
37
37
|
var jwt = _ref.jwt,
|
|
38
38
|
user = _ref.user,
|
|
@@ -135,21 +135,17 @@ var Dashboard = function Dashboard(_ref) {
|
|
|
135
135
|
var _useState31 = (0, _react.useState)(0),
|
|
136
136
|
_useState32 = (0, _slicedToArray2.default)(_useState31, 2),
|
|
137
137
|
totalCount = _useState32[0],
|
|
138
|
-
setTotalCount = _useState32[1];
|
|
138
|
+
setTotalCount = _useState32[1]; // Total sin filtros, solo para el porcentaje de la dona.
|
|
139
139
|
|
|
140
|
-
var _useState33 = (0, _react.useState)((company === null || company === void 0 ? void 0 : (_company$financedReta = company.financedRetailers) === null || _company$financedReta === void 0 ? void 0 : _company$financedReta.length) > 0),
|
|
141
|
-
_useState34 = (0, _slicedToArray2.default)(_useState33, 1),
|
|
142
|
-
isProviderFinanced = _useState34[0];
|
|
143
140
|
|
|
144
|
-
var
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
141
|
+
var _useState33 = (0, _react.useState)(0),
|
|
142
|
+
_useState34 = (0, _slicedToArray2.default)(_useState33, 2),
|
|
143
|
+
totalUnfiltered = _useState34[0],
|
|
144
|
+
setTotalUnfiltered = _useState34[1];
|
|
148
145
|
|
|
149
|
-
var
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
setTradesSelected = _useState38[1];
|
|
146
|
+
var _useState35 = (0, _react.useState)((company === null || company === void 0 ? void 0 : (_company$financedReta = company.financedRetailers) === null || _company$financedReta === void 0 ? void 0 : _company$financedReta.length) > 0),
|
|
147
|
+
_useState36 = (0, _slicedToArray2.default)(_useState35, 1),
|
|
148
|
+
isProviderFinanced = _useState36[0];
|
|
153
149
|
|
|
154
150
|
var loadProductVersions = /*#__PURE__*/function () {
|
|
155
151
|
var _ref2 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(queryObject) {
|
|
@@ -241,71 +237,99 @@ var Dashboard = function Dashboard(_ref) {
|
|
|
241
237
|
|
|
242
238
|
var loadProductsByStatus = /*#__PURE__*/function () {
|
|
243
239
|
var _ref4 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee3(orderByStatus) {
|
|
244
|
-
var
|
|
240
|
+
var _ordersByActive$regis;
|
|
241
|
+
|
|
242
|
+
var isBaseline,
|
|
243
|
+
isRetailer,
|
|
244
|
+
isProvider,
|
|
245
|
+
isCollaborator,
|
|
246
|
+
_ref5,
|
|
247
|
+
ordersBydate,
|
|
248
|
+
_ref5$ordersByStatus,
|
|
249
|
+
ordersByStatus,
|
|
250
|
+
_ref5$ordersByActive,
|
|
251
|
+
ordersByActive,
|
|
252
|
+
_ordersByStatus$total,
|
|
253
|
+
total,
|
|
254
|
+
_ordersByStatus$R,
|
|
255
|
+
R,
|
|
256
|
+
_ordersByStatus$PA,
|
|
257
|
+
PA,
|
|
258
|
+
_ordersByStatus$Ex,
|
|
259
|
+
Ex,
|
|
260
|
+
_ordersByStatus$ACA,
|
|
261
|
+
ACA,
|
|
262
|
+
productsFinished,
|
|
263
|
+
unassigned,
|
|
264
|
+
inProcess,
|
|
265
|
+
registeredProducts,
|
|
266
|
+
metricsArray,
|
|
267
|
+
_args3 = arguments;
|
|
245
268
|
|
|
246
269
|
return _regenerator.default.wrap(function _callee3$(_context3) {
|
|
247
270
|
while (1) {
|
|
248
271
|
switch (_context3.prev = _context3.next) {
|
|
249
272
|
case 0:
|
|
273
|
+
isBaseline = _args3.length > 1 && _args3[1] !== undefined ? _args3[1] : false;
|
|
250
274
|
isRetailer = user.is_retailer && company.retailers;
|
|
251
275
|
isProvider = !user.is_retailer && user.id_role === 0;
|
|
252
276
|
isCollaborator = user.id_role > 0;
|
|
253
|
-
_context3.next =
|
|
277
|
+
_context3.next = 6;
|
|
254
278
|
return loadProductVersions(orderByStatus);
|
|
255
279
|
|
|
256
|
-
case
|
|
280
|
+
case 6:
|
|
257
281
|
_context3.t0 = _context3.sent;
|
|
258
282
|
|
|
259
283
|
if (_context3.t0) {
|
|
260
|
-
_context3.next =
|
|
284
|
+
_context3.next = 9;
|
|
261
285
|
break;
|
|
262
286
|
}
|
|
263
287
|
|
|
264
288
|
_context3.t0 = {};
|
|
265
289
|
|
|
266
|
-
case
|
|
290
|
+
case 9:
|
|
267
291
|
_ref5 = _context3.t0;
|
|
268
292
|
ordersBydate = _ref5.ordersBydate;
|
|
269
|
-
ordersByStatus = _ref5.ordersByStatus;
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
293
|
+
_ref5$ordersByStatus = _ref5.ordersByStatus;
|
|
294
|
+
ordersByStatus = _ref5$ordersByStatus === void 0 ? {} : _ref5$ordersByStatus;
|
|
295
|
+
_ref5$ordersByActive = _ref5.ordersByActive;
|
|
296
|
+
ordersByActive = _ref5$ordersByActive === void 0 ? {} : _ref5$ordersByActive;
|
|
273
297
|
_ordersByStatus$total = ordersByStatus.total, total = _ordersByStatus$total === void 0 ? 0 : _ordersByStatus$total, _ordersByStatus$R = ordersByStatus.R, R = _ordersByStatus$R === void 0 ? 0 : _ordersByStatus$R, _ordersByStatus$PA = ordersByStatus.PA, PA = _ordersByStatus$PA === void 0 ? 0 : _ordersByStatus$PA, _ordersByStatus$Ex = ordersByStatus.Ex, Ex = _ordersByStatus$Ex === void 0 ? 0 : _ordersByStatus$Ex, _ordersByStatus$ACA = ordersByStatus.ACA, ACA = _ordersByStatus$ACA === void 0 ? 0 : _ordersByStatus$ACA;
|
|
274
298
|
productsFinished = 0;
|
|
275
299
|
if (isRetailer) productsFinished = Ex;
|
|
276
|
-
if (isProvider) productsFinished = ACA;
|
|
277
|
-
if (isCollaborator) productsFinished = Ex + ACA;
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
label: "Productos activos",
|
|
288
|
-
value: registeredProducts
|
|
300
|
+
if (isProvider) productsFinished = ACA + Ex;
|
|
301
|
+
if (isCollaborator) productsFinished = Ex + ACA; // Lo que no está sin asignar ni terminado está en proceso, para que las
|
|
302
|
+
// tres tarjetas siempre sumen el total filtrado.
|
|
303
|
+
|
|
304
|
+
unassigned = PA + R;
|
|
305
|
+
inProcess = total - unassigned - productsFinished;
|
|
306
|
+
registeredProducts = (_ordersByActive$regis = ordersByActive.registered) !== null && _ordersByActive$regis !== void 0 ? _ordersByActive$regis : 0;
|
|
307
|
+
metricsArray = [{
|
|
308
|
+
label: "Catálogo activo",
|
|
309
|
+
value: registeredProducts,
|
|
310
|
+
hint: "Productos dados de alta y activos. No depende del filtro de fechas, que aplica a la fecha de la orden."
|
|
289
311
|
}, {
|
|
290
|
-
label: "
|
|
291
|
-
value: total
|
|
312
|
+
label: "En órdenes de trabajo",
|
|
313
|
+
value: total,
|
|
314
|
+
hint: "Productos con orden de trabajo viva dentro de los filtros. Un producto en dos órdenes cuenta en cada una."
|
|
292
315
|
}, {
|
|
293
|
-
label: "
|
|
294
|
-
value:
|
|
316
|
+
label: "Sin asignar",
|
|
317
|
+
value: unassigned
|
|
295
318
|
}, {
|
|
296
|
-
label: "
|
|
319
|
+
label: "En proceso",
|
|
297
320
|
value: inProcess
|
|
298
321
|
}, {
|
|
299
|
-
label: "
|
|
322
|
+
label: "Terminados",
|
|
300
323
|
value: productsFinished
|
|
301
|
-
}
|
|
324
|
+
}];
|
|
302
325
|
setMetricsData(metricsArray);
|
|
303
326
|
setTotalCount(total);
|
|
327
|
+
if (isBaseline) setTotalUnfiltered(total);
|
|
304
328
|
delete ordersByStatus.total;
|
|
305
329
|
setRequiredProducts(ordersBydate);
|
|
306
330
|
setProductsByStatus(ordersByStatus);
|
|
307
331
|
|
|
308
|
-
case
|
|
332
|
+
case 30:
|
|
309
333
|
case "end":
|
|
310
334
|
return _context3.stop();
|
|
311
335
|
}
|
|
@@ -319,7 +343,23 @@ var Dashboard = function Dashboard(_ref) {
|
|
|
319
343
|
}();
|
|
320
344
|
|
|
321
345
|
var datesSelect = function datesSelect() {
|
|
322
|
-
|
|
346
|
+
// Cada rango se calcula al momento de elegirlo y con fechas locales: si se
|
|
347
|
+
// parte de un Date compartido, los options se pisan entre sí, y
|
|
348
|
+
// new Date("2026-11-01") cae en el día anterior al oeste de UTC.
|
|
349
|
+
var applyRange = function applyRange(startDate) {
|
|
350
|
+
var endDate = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : new Date();
|
|
351
|
+
return setDatesRange({
|
|
352
|
+
startDate: (0, _dashboardUtils.formatDate)(startDate),
|
|
353
|
+
endDate: (0, _dashboardUtils.formatDate)(endDate)
|
|
354
|
+
});
|
|
355
|
+
};
|
|
356
|
+
|
|
357
|
+
var daysAgo = function daysAgo(days) {
|
|
358
|
+
var date = new Date();
|
|
359
|
+
date.setDate(date.getDate() - days);
|
|
360
|
+
return date;
|
|
361
|
+
};
|
|
362
|
+
|
|
323
363
|
setDateOptions([{
|
|
324
364
|
id: 0,
|
|
325
365
|
name: "Rango de fechas"
|
|
@@ -327,64 +367,46 @@ var Dashboard = function Dashboard(_ref) {
|
|
|
327
367
|
id: 1,
|
|
328
368
|
name: "Todo el tiempo",
|
|
329
369
|
function: function _function() {
|
|
330
|
-
return
|
|
331
|
-
startDate: (0, _dashboardUtils.formatDate)(new Date("1900-01-01")),
|
|
332
|
-
endDate: (0, _dashboardUtils.formatDate)(new Date())
|
|
333
|
-
});
|
|
370
|
+
return applyRange(new Date(1900, 0, 1));
|
|
334
371
|
}
|
|
335
372
|
}, {
|
|
336
373
|
id: 2,
|
|
337
374
|
name: "Hoy",
|
|
338
375
|
function: function _function() {
|
|
339
|
-
return
|
|
340
|
-
startDate: (0, _dashboardUtils.formatDate)(new Date()),
|
|
341
|
-
endDate: (0, _dashboardUtils.formatDate)(new Date())
|
|
342
|
-
});
|
|
376
|
+
return applyRange(new Date());
|
|
343
377
|
}
|
|
344
378
|
}, {
|
|
345
379
|
id: 3,
|
|
346
380
|
name: "Ayer",
|
|
347
381
|
function: function _function() {
|
|
348
|
-
return
|
|
349
|
-
startDate: (0, _dashboardUtils.formatDate)(new Date(today.setDate(today.getDate() - 1))),
|
|
350
|
-
endDate: (0, _dashboardUtils.formatDate)(new Date())
|
|
351
|
-
});
|
|
382
|
+
return applyRange(daysAgo(1), daysAgo(1));
|
|
352
383
|
}
|
|
353
384
|
}, {
|
|
354
385
|
id: 4,
|
|
355
386
|
name: "Esta semana",
|
|
356
387
|
function: function _function() {
|
|
357
|
-
return
|
|
358
|
-
startDate: (0, _dashboardUtils.formatDate)(new Date(today.setDate(today.getDate() - today.getDay()))),
|
|
359
|
-
endDate: (0, _dashboardUtils.formatDate)(new Date())
|
|
360
|
-
});
|
|
388
|
+
return applyRange(daysAgo(new Date().getDay()));
|
|
361
389
|
}
|
|
362
390
|
}, {
|
|
363
391
|
id: 5,
|
|
364
392
|
name: "La semana pasada",
|
|
365
393
|
function: function _function() {
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
endDate: (0, _dashboardUtils.formatDate)(new Date(today.setDate(today.getDate() - today.getDay() + 7)))
|
|
369
|
-
});
|
|
394
|
+
var weekday = new Date().getDay();
|
|
395
|
+
return applyRange(daysAgo(weekday + 7), daysAgo(weekday + 1));
|
|
370
396
|
}
|
|
371
397
|
}, {
|
|
372
398
|
id: 6,
|
|
373
399
|
name: "Este mes",
|
|
374
400
|
function: function _function() {
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
endDate: (0, _dashboardUtils.formatDate)(today)
|
|
378
|
-
});
|
|
401
|
+
var today = new Date();
|
|
402
|
+
return applyRange(new Date(today.getFullYear(), today.getMonth(), 1));
|
|
379
403
|
}
|
|
380
404
|
}, {
|
|
381
405
|
id: 7,
|
|
382
406
|
name: "El mes pasado",
|
|
383
407
|
function: function _function() {
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
endDate: (0, _dashboardUtils.formatDate)(new Date("".concat(today.getFullYear(), "-").concat(today.getMonth() + 1, "-01")))
|
|
387
|
-
});
|
|
408
|
+
var today = new Date();
|
|
409
|
+
return applyRange(new Date(today.getFullYear(), today.getMonth() - 1, 1), new Date(today.getFullYear(), today.getMonth(), 0));
|
|
388
410
|
}
|
|
389
411
|
}]);
|
|
390
412
|
};
|
|
@@ -427,7 +449,7 @@ var Dashboard = function Dashboard(_ref) {
|
|
|
427
449
|
});
|
|
428
450
|
setOrderByStatus(queryObject);
|
|
429
451
|
setOrderByRequired(queryObject);
|
|
430
|
-
loadProductsByStatus(queryObject);
|
|
452
|
+
loadProductsByStatus(queryObject, true);
|
|
431
453
|
|
|
432
454
|
case 21:
|
|
433
455
|
case "end":
|
|
@@ -455,18 +477,17 @@ var Dashboard = function Dashboard(_ref) {
|
|
|
455
477
|
if (companyId.length > 0) queryObject["companyId"] = companyId.join(",");
|
|
456
478
|
if (retailerId.length > 0) queryObject["retailerId"] = retailerId.join(",");
|
|
457
479
|
if (categoryId.length > 0) queryObject["categoryId"] = categoryId.join(",");
|
|
458
|
-
if (tradesSelected.length > 0) queryObject["trades"] = encodeURIComponent(tradesSelected.join(","));
|
|
459
480
|
applicantsFilter.length > 0 && (queryObject["requestedBy"] = applicantsFilter.join(","));
|
|
460
|
-
_context5.next =
|
|
461
|
-
return loadProductsByStatus(queryObject
|
|
481
|
+
_context5.next = 8;
|
|
482
|
+
return loadProductsByStatus(queryObject);
|
|
462
483
|
|
|
463
|
-
case
|
|
484
|
+
case 8:
|
|
464
485
|
case "end":
|
|
465
486
|
return _context5.stop();
|
|
466
487
|
}
|
|
467
488
|
}
|
|
468
489
|
}, _callee5);
|
|
469
|
-
})), [companyId, retailerId, categoryId, datesRange, applicantsFilter
|
|
490
|
+
})), [companyId, retailerId, categoryId, datesRange, applicantsFilter]);
|
|
470
491
|
return loading ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_Loading.Loading, {}) : /*#__PURE__*/(0, _jsxRuntime.jsxs)(_styles.Container, {
|
|
471
492
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
|
|
472
493
|
className: "filters",
|
|
@@ -517,21 +538,14 @@ var Dashboard = function Dashboard(_ref) {
|
|
|
517
538
|
parameterArray: applicantsFilter,
|
|
518
539
|
setParameterArray: setApplicantsFilter,
|
|
519
540
|
defaultOption: "Todos los solicitantes"
|
|
520
|
-
}), user.id_role === 0 && (trades === null || trades === void 0 ? void 0 : trades.length) > 0 && /*#__PURE__*/(0, _jsxRuntime.jsx)(_CustomSelect.CustomSelect, {
|
|
521
|
-
showSearchBar: true,
|
|
522
|
-
options: trades,
|
|
523
|
-
selectLabel: "Todas las marcas",
|
|
524
|
-
placeHolder: "Buscar marca",
|
|
525
|
-
customSelectId: "trade-select",
|
|
526
|
-
parameterArray: tradesSelected,
|
|
527
|
-
setParameterArray: setTradesSelected
|
|
528
541
|
})]
|
|
529
542
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
|
|
530
543
|
className: "metric-cards",
|
|
531
544
|
children: metricsData.map(function (metric, index) {
|
|
532
545
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_MetricCard.MetricCard, {
|
|
533
546
|
label: metric.label,
|
|
534
|
-
number: metric.value
|
|
547
|
+
number: metric.value,
|
|
548
|
+
hint: metric.hint
|
|
535
549
|
}, "".concat(index, "-").concat(metric.value));
|
|
536
550
|
})
|
|
537
551
|
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
|
|
@@ -551,7 +565,7 @@ var Dashboard = function Dashboard(_ref) {
|
|
|
551
565
|
showPercent: true,
|
|
552
566
|
displayScale: false,
|
|
553
567
|
totalFiltered: totalCount,
|
|
554
|
-
total:
|
|
568
|
+
total: totalUnfiltered
|
|
555
569
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_DashboardMetric.DashboardMetric, {
|
|
556
570
|
label: "Productos solicitados",
|
|
557
571
|
description: "Filtra los productos solicitados por fecha y alcance para revisar rápidamente el flujo de trabajo.",
|
|
@@ -13,6 +13,6 @@ var _styledComponents = _interopRequireDefault(require("styled-components"));
|
|
|
13
13
|
|
|
14
14
|
var _templateObject;
|
|
15
15
|
|
|
16
|
-
var Container = _styledComponents.default.div(_templateObject || (_templateObject = (0, _taggedTemplateLiteral2.default)(["\n padding: 30px;\n\n .filters {\n display: flex;\n
|
|
16
|
+
var Container = _styledComponents.default.div(_templateObject || (_templateObject = (0, _taggedTemplateLiteral2.default)(["\n padding: 30px;\n\n .filters {\n display: flex;\n flex-wrap: wrap;\n gap: 10px;\n\n & + * {\n margin-top: 20px;\n }\n }\n\n .metric-cards {\n display: flex;\n flex-wrap: wrap;\n gap: 10px;\n\n & + * {\n margin-top: 10px;\n }\n }\n\n .metrics-main-container {\n display: grid;\n /* Dos paneles mientras quepan 320px cada uno; si no, uno debajo del otro.\n El min() evita que la columna siga midiendo 320px en pantallas menores. */\n grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr));\n gap: 10px;\n\n /* Sin esto las gr\xE1ficas no pueden encogerse por debajo de su ancho. */\n > * {\n min-width: 0;\n }\n }\n\n @media (max-width: 600px) {\n padding: 15px;\n }\n"])));
|
|
17
17
|
|
|
18
18
|
exports.Container = Container;
|
package/package.json
CHANGED
|
@@ -26,3 +26,14 @@ DashboardMetricDefault.args = {
|
|
|
26
26
|
RP: 49,
|
|
27
27
|
},
|
|
28
28
|
};
|
|
29
|
+
|
|
30
|
+
export const DashboardMetricDoughnut = Template.bind({});
|
|
31
|
+
DashboardMetricDoughnut.args = {
|
|
32
|
+
...DashboardMetricDefault.args,
|
|
33
|
+
type: "doughnut",
|
|
34
|
+
displayLegend: true,
|
|
35
|
+
showPercent: true,
|
|
36
|
+
displayScale: false,
|
|
37
|
+
total: 1610,
|
|
38
|
+
totalFiltered: 1610,
|
|
39
|
+
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useEffect, useRef, useState } from "react";
|
|
1
2
|
import { Container } from "./styles";
|
|
2
3
|
import { Graphic } from "../../atoms/Graphic";
|
|
3
4
|
import {
|
|
@@ -20,6 +21,21 @@ export const DashboardMetric = ({
|
|
|
20
21
|
total,
|
|
21
22
|
totalFiltered,
|
|
22
23
|
}) => {
|
|
24
|
+
// Chart.js coloca la leyenda por opción, no por CSS. Se mide el panel y no
|
|
25
|
+
// la ventana, porque el ancho real depende también del menú de la app: a
|
|
26
|
+
// 828px de ventana el panel queda en 331 y la leyenda de lado sale cortada.
|
|
27
|
+
const containerRef = useRef(null);
|
|
28
|
+
const [isNarrow, setIsNarrow] = useState(false);
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
const node = containerRef.current;
|
|
31
|
+
if (!node || typeof ResizeObserver === "undefined") return undefined;
|
|
32
|
+
const observer = new ResizeObserver(([entry]) =>
|
|
33
|
+
setIsNarrow(entry.contentRect.width < 420)
|
|
34
|
+
);
|
|
35
|
+
observer.observe(node);
|
|
36
|
+
return () => observer.disconnect();
|
|
37
|
+
}, []);
|
|
38
|
+
|
|
23
39
|
const labels =
|
|
24
40
|
type === "doughnut"
|
|
25
41
|
? Object.entries(dataObject).map(
|
|
@@ -75,7 +91,7 @@ export const DashboardMetric = ({
|
|
|
75
91
|
},
|
|
76
92
|
},
|
|
77
93
|
legend: {
|
|
78
|
-
position: "right",
|
|
94
|
+
position: isNarrow ? "bottom" : "right",
|
|
79
95
|
display: displayLegend,
|
|
80
96
|
labels: {
|
|
81
97
|
usePointStyle: true,
|
|
@@ -101,7 +117,7 @@ export const DashboardMetric = ({
|
|
|
101
117
|
};
|
|
102
118
|
|
|
103
119
|
return (
|
|
104
|
-
<Container>
|
|
120
|
+
<Container ref={containerRef} className={isNarrow ? "is-narrow" : ""}>
|
|
105
121
|
<div className="text-container">
|
|
106
122
|
<p>{label}</p>
|
|
107
123
|
<p>{description}</p>
|
|
@@ -7,6 +7,19 @@ export const Container = styled.div`
|
|
|
7
7
|
padding: 24px;
|
|
8
8
|
position: relative;
|
|
9
9
|
|
|
10
|
+
@media (max-width: 600px) {
|
|
11
|
+
padding: 12px;
|
|
12
|
+
|
|
13
|
+
.graphic-cotainer {
|
|
14
|
+
padding: 5px;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/* Va rotada y fuera del recuadro; con el padding chico se encima. */
|
|
18
|
+
> p.y-label {
|
|
19
|
+
display: none;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
10
23
|
.text-container {
|
|
11
24
|
p {
|
|
12
25
|
font-family: ${FontFamily.Raleway};
|
|
@@ -48,6 +61,12 @@ export const Container = styled.div`
|
|
|
48
61
|
}
|
|
49
62
|
}
|
|
50
63
|
|
|
64
|
+
/* Con la leyenda abajo, Chart.js le da un máximo de la altura del recuadro
|
|
65
|
+
y descarta las entradas que no caben; por eso crece junto con ella. */
|
|
66
|
+
&.is-narrow .graphic-cotainer {
|
|
67
|
+
height: 500px;
|
|
68
|
+
}
|
|
69
|
+
|
|
51
70
|
.graphic-cotainer {
|
|
52
71
|
height: 350px;
|
|
53
72
|
border: 1px solid ${GlobalColors.s3};
|
|
@@ -52,9 +52,9 @@ export const getCategories = async (jwt, user, company) => {
|
|
|
52
52
|
export const formatDate = (date) => {
|
|
53
53
|
const newDate = new Date(date);
|
|
54
54
|
const year = newDate.getFullYear();
|
|
55
|
-
const month = newDate.getMonth() + 1;
|
|
56
|
-
const day = newDate.getDate();
|
|
57
|
-
return `${year}
|
|
55
|
+
const month = `${newDate.getMonth() + 1}`.padStart(2, "0");
|
|
56
|
+
const day = `${newDate.getDate()}`.padStart(2, "0");
|
|
57
|
+
return `${year}-${month}-${day}`;
|
|
58
58
|
};
|
|
59
59
|
|
|
60
60
|
const getCategoriesRecursive = (object) => {
|
|
@@ -39,9 +39,9 @@ export const Dashboard = ({ jwt, user, company }) => {
|
|
|
39
39
|
];
|
|
40
40
|
const [applicantsFilter, setApplicantsFilter] = useState([]);
|
|
41
41
|
const [totalCount, setTotalCount] = useState(0);
|
|
42
|
+
// Total sin filtros, solo para el porcentaje de la dona.
|
|
43
|
+
const [totalUnfiltered, setTotalUnfiltered] = useState(0);
|
|
42
44
|
const [isProviderFinanced] = useState(company?.financedRetailers?.length > 0);
|
|
43
|
-
const [trades, setTrades] = useState([]);
|
|
44
|
-
const [tradesSelected, setTradesSelected] = useState([]);
|
|
45
45
|
|
|
46
46
|
const loadProductVersions = async (queryObject) => {
|
|
47
47
|
const keys = Object.keys(queryObject);
|
|
@@ -82,127 +82,102 @@ export const Dashboard = ({ jwt, user, company }) => {
|
|
|
82
82
|
setRetailers(retailers);
|
|
83
83
|
};
|
|
84
84
|
|
|
85
|
-
const loadProductsByStatus = async (orderByStatus) => {
|
|
85
|
+
const loadProductsByStatus = async (orderByStatus, isBaseline = false) => {
|
|
86
86
|
const isRetailer = user.is_retailer && company.retailers;
|
|
87
87
|
const isProvider = !user.is_retailer && user.id_role === 0;
|
|
88
88
|
const isCollaborator = user.id_role > 0;
|
|
89
|
-
const { ordersBydate, ordersByStatus, ordersByActive
|
|
89
|
+
const { ordersBydate, ordersByStatus = {}, ordersByActive = {} } =
|
|
90
90
|
(await loadProductVersions(orderByStatus)) || {};
|
|
91
91
|
|
|
92
|
-
if (trades.length === 0) setTrades(companyTrades);
|
|
93
92
|
const { total = 0, R = 0, PA = 0, Ex = 0, ACA = 0 } = ordersByStatus;
|
|
94
93
|
let productsFinished = 0;
|
|
95
94
|
if (isRetailer) productsFinished = Ex;
|
|
96
|
-
if (isProvider) productsFinished = ACA;
|
|
95
|
+
if (isProvider) productsFinished = ACA + Ex;
|
|
97
96
|
if (isCollaborator) productsFinished = Ex + ACA;
|
|
98
97
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
: prev,
|
|
104
|
-
0
|
|
105
|
-
);
|
|
98
|
+
// Lo que no está sin asignar ni terminado está en proceso, para que las
|
|
99
|
+
// tres tarjetas siempre sumen el total filtrado.
|
|
100
|
+
const unassigned = PA + R;
|
|
101
|
+
const inProcess = total - unassigned - productsFinished;
|
|
106
102
|
|
|
107
|
-
const registeredProducts = ordersByActive.registered;
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
103
|
+
const registeredProducts = ordersByActive.registered ?? 0;
|
|
104
|
+
const metricsArray = [
|
|
105
|
+
{
|
|
106
|
+
label: "Catálogo activo",
|
|
107
|
+
value: registeredProducts,
|
|
108
|
+
hint: "Productos dados de alta y activos. No depende del filtro de fechas, que aplica a la fecha de la orden.",
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
label: "En órdenes de trabajo",
|
|
112
|
+
value: total,
|
|
113
|
+
hint: "Productos con orden de trabajo viva dentro de los filtros. Un producto en dos órdenes cuenta en cada una.",
|
|
114
|
+
},
|
|
115
|
+
{ label: "Sin asignar", value: unassigned },
|
|
116
|
+
{ label: "En proceso", value: inProcess },
|
|
117
|
+
{ label: "Terminados", value: productsFinished },
|
|
112
118
|
];
|
|
113
|
-
|
|
114
|
-
metricsArray.push(
|
|
115
|
-
{ label: "Productos activos", value: registeredProducts },
|
|
116
|
-
{ label: "Productos filtrados", value: total },
|
|
117
|
-
{ label: "Productos sin asignar", value: PA + R },
|
|
118
|
-
{ label: "Productos en proceso", value: inProcess },
|
|
119
|
-
{ label: "Productos terminados", value: productsFinished }
|
|
120
|
-
);
|
|
121
119
|
setMetricsData(metricsArray);
|
|
122
120
|
setTotalCount(total);
|
|
121
|
+
if (isBaseline) setTotalUnfiltered(total);
|
|
123
122
|
delete ordersByStatus.total;
|
|
124
123
|
setRequiredProducts(ordersBydate);
|
|
125
124
|
setProductsByStatus(ordersByStatus);
|
|
126
125
|
};
|
|
127
126
|
|
|
128
127
|
const datesSelect = () => {
|
|
129
|
-
|
|
128
|
+
// Cada rango se calcula al momento de elegirlo y con fechas locales: si se
|
|
129
|
+
// parte de un Date compartido, los options se pisan entre sí, y
|
|
130
|
+
// new Date("2026-11-01") cae en el día anterior al oeste de UTC.
|
|
131
|
+
const applyRange = (startDate, endDate = new Date()) =>
|
|
132
|
+
setDatesRange({
|
|
133
|
+
startDate: formatDate(startDate),
|
|
134
|
+
endDate: formatDate(endDate),
|
|
135
|
+
});
|
|
136
|
+
const daysAgo = (days) => {
|
|
137
|
+
const date = new Date();
|
|
138
|
+
date.setDate(date.getDate() - days);
|
|
139
|
+
return date;
|
|
140
|
+
};
|
|
130
141
|
setDateOptions([
|
|
131
142
|
{ id: 0, name: "Rango de fechas" },
|
|
132
143
|
{
|
|
133
144
|
id: 1,
|
|
134
145
|
name: "Todo el tiempo",
|
|
135
|
-
function: () =>
|
|
136
|
-
setDatesRange({
|
|
137
|
-
startDate: formatDate(new Date("1900-01-01")),
|
|
138
|
-
endDate: formatDate(new Date()),
|
|
139
|
-
}),
|
|
140
|
-
},
|
|
141
|
-
{
|
|
142
|
-
id: 2,
|
|
143
|
-
name: "Hoy",
|
|
144
|
-
function: () =>
|
|
145
|
-
setDatesRange({
|
|
146
|
-
startDate: formatDate(new Date()),
|
|
147
|
-
endDate: formatDate(new Date()),
|
|
148
|
-
}),
|
|
149
|
-
},
|
|
150
|
-
{
|
|
151
|
-
id: 3,
|
|
152
|
-
name: "Ayer",
|
|
153
|
-
function: () =>
|
|
154
|
-
setDatesRange({
|
|
155
|
-
startDate: formatDate(new Date(today.setDate(today.getDate() - 1))),
|
|
156
|
-
endDate: formatDate(new Date()),
|
|
157
|
-
}),
|
|
146
|
+
function: () => applyRange(new Date(1900, 0, 1)),
|
|
158
147
|
},
|
|
148
|
+
{ id: 2, name: "Hoy", function: () => applyRange(new Date()) },
|
|
149
|
+
{ id: 3, name: "Ayer", function: () => applyRange(daysAgo(1), daysAgo(1)) },
|
|
159
150
|
{
|
|
160
151
|
id: 4,
|
|
161
152
|
name: "Esta semana",
|
|
162
|
-
function: () =>
|
|
163
|
-
setDatesRange({
|
|
164
|
-
startDate: formatDate(
|
|
165
|
-
new Date(today.setDate(today.getDate() - today.getDay()))
|
|
166
|
-
),
|
|
167
|
-
endDate: formatDate(new Date()),
|
|
168
|
-
}),
|
|
153
|
+
function: () => applyRange(daysAgo(new Date().getDay())),
|
|
169
154
|
},
|
|
170
155
|
{
|
|
171
156
|
id: 5,
|
|
172
157
|
name: "La semana pasada",
|
|
173
|
-
function: () =>
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
),
|
|
178
|
-
endDate: formatDate(
|
|
179
|
-
new Date(today.setDate(today.getDate() - today.getDay() + 7))
|
|
180
|
-
),
|
|
181
|
-
}),
|
|
158
|
+
function: () => {
|
|
159
|
+
const weekday = new Date().getDay();
|
|
160
|
+
return applyRange(daysAgo(weekday + 7), daysAgo(weekday + 1));
|
|
161
|
+
},
|
|
182
162
|
},
|
|
183
163
|
{
|
|
184
164
|
id: 6,
|
|
185
165
|
name: "Este mes",
|
|
186
|
-
function: () =>
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
),
|
|
191
|
-
endDate: formatDate(today),
|
|
192
|
-
}),
|
|
166
|
+
function: () => {
|
|
167
|
+
const today = new Date();
|
|
168
|
+
return applyRange(new Date(today.getFullYear(), today.getMonth(), 1));
|
|
169
|
+
},
|
|
193
170
|
},
|
|
194
171
|
{
|
|
195
172
|
id: 7,
|
|
196
173
|
name: "El mes pasado",
|
|
197
|
-
function: () =>
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
),
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
),
|
|
205
|
-
}),
|
|
174
|
+
function: () => {
|
|
175
|
+
const today = new Date();
|
|
176
|
+
return applyRange(
|
|
177
|
+
new Date(today.getFullYear(), today.getMonth() - 1, 1),
|
|
178
|
+
new Date(today.getFullYear(), today.getMonth(), 0)
|
|
179
|
+
);
|
|
180
|
+
},
|
|
206
181
|
},
|
|
207
182
|
]);
|
|
208
183
|
};
|
|
@@ -219,7 +194,7 @@ export const Dashboard = ({ jwt, user, company }) => {
|
|
|
219
194
|
setDatesRange({ startDate, endDate });
|
|
220
195
|
setOrderByStatus(queryObject);
|
|
221
196
|
setOrderByRequired(queryObject);
|
|
222
|
-
loadProductsByStatus(queryObject);
|
|
197
|
+
loadProductsByStatus(queryObject, true);
|
|
223
198
|
}, []);
|
|
224
199
|
|
|
225
200
|
useEffect(() => {
|
|
@@ -241,20 +216,11 @@ export const Dashboard = ({ jwt, user, company }) => {
|
|
|
241
216
|
if (companyId.length > 0) queryObject["companyId"] = companyId.join(",");
|
|
242
217
|
if (retailerId.length > 0) queryObject["retailerId"] = retailerId.join(",");
|
|
243
218
|
if (categoryId.length > 0) queryObject["categoryId"] = categoryId.join(",");
|
|
244
|
-
if (tradesSelected.length > 0)
|
|
245
|
-
queryObject["trades"] = encodeURIComponent(tradesSelected.join(","));
|
|
246
219
|
applicantsFilter.length > 0 &&
|
|
247
220
|
(queryObject["requestedBy"] = applicantsFilter.join(","));
|
|
248
221
|
|
|
249
|
-
await loadProductsByStatus(queryObject
|
|
250
|
-
}, [
|
|
251
|
-
companyId,
|
|
252
|
-
retailerId,
|
|
253
|
-
categoryId,
|
|
254
|
-
datesRange,
|
|
255
|
-
applicantsFilter,
|
|
256
|
-
tradesSelected,
|
|
257
|
-
]);
|
|
222
|
+
await loadProductsByStatus(queryObject);
|
|
223
|
+
}, [companyId, retailerId, categoryId, datesRange, applicantsFilter]);
|
|
258
224
|
|
|
259
225
|
return loading ? (
|
|
260
226
|
<Loading />
|
|
@@ -319,17 +285,6 @@ export const Dashboard = ({ jwt, user, company }) => {
|
|
|
319
285
|
defaultOption="Todos los solicitantes"
|
|
320
286
|
/>
|
|
321
287
|
)}
|
|
322
|
-
{user.id_role === 0 && trades?.length > 0 && (
|
|
323
|
-
<CustomSelect
|
|
324
|
-
showSearchBar={true}
|
|
325
|
-
options={trades}
|
|
326
|
-
selectLabel="Todas las marcas"
|
|
327
|
-
placeHolder="Buscar marca"
|
|
328
|
-
customSelectId="trade-select"
|
|
329
|
-
parameterArray={tradesSelected}
|
|
330
|
-
setParameterArray={setTradesSelected}
|
|
331
|
-
/>
|
|
332
|
-
)}
|
|
333
288
|
</div>
|
|
334
289
|
<div className="metric-cards">
|
|
335
290
|
{metricsData.map((metric, index) => (
|
|
@@ -337,6 +292,7 @@ export const Dashboard = ({ jwt, user, company }) => {
|
|
|
337
292
|
key={`${index}-${metric.value}`}
|
|
338
293
|
label={metric.label}
|
|
339
294
|
number={metric.value}
|
|
295
|
+
hint={metric.hint}
|
|
340
296
|
/>
|
|
341
297
|
))}
|
|
342
298
|
</div>
|
|
@@ -358,7 +314,7 @@ export const Dashboard = ({ jwt, user, company }) => {
|
|
|
358
314
|
showPercent={true}
|
|
359
315
|
displayScale={false}
|
|
360
316
|
totalFiltered={totalCount}
|
|
361
|
-
total={
|
|
317
|
+
total={totalUnfiltered}
|
|
362
318
|
/>
|
|
363
319
|
<DashboardMetric
|
|
364
320
|
label={"Productos solicitados"}
|
|
@@ -5,11 +5,9 @@ export const Container = styled.div`
|
|
|
5
5
|
|
|
6
6
|
.filters {
|
|
7
7
|
display: flex;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
12
|
-
}
|
|
8
|
+
flex-wrap: wrap;
|
|
9
|
+
gap: 10px;
|
|
10
|
+
|
|
13
11
|
& + * {
|
|
14
12
|
margin-top: 20px;
|
|
15
13
|
}
|
|
@@ -17,10 +15,8 @@ export const Container = styled.div`
|
|
|
17
15
|
|
|
18
16
|
.metric-cards {
|
|
19
17
|
display: flex;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
margin-left: 10px;
|
|
23
|
-
}
|
|
18
|
+
flex-wrap: wrap;
|
|
19
|
+
gap: 10px;
|
|
24
20
|
|
|
25
21
|
& + * {
|
|
26
22
|
margin-top: 10px;
|
|
@@ -28,10 +24,19 @@ export const Container = styled.div`
|
|
|
28
24
|
}
|
|
29
25
|
|
|
30
26
|
.metrics-main-container {
|
|
31
|
-
display:
|
|
27
|
+
display: grid;
|
|
28
|
+
/* Dos paneles mientras quepan 320px cada uno; si no, uno debajo del otro.
|
|
29
|
+
El min() evita que la columna siga midiendo 320px en pantallas menores. */
|
|
30
|
+
grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr));
|
|
31
|
+
gap: 10px;
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
/* Sin esto las gráficas no pueden encogerse por debajo de su ancho. */
|
|
34
|
+
> * {
|
|
35
|
+
min-width: 0;
|
|
35
36
|
}
|
|
36
37
|
}
|
|
38
|
+
|
|
39
|
+
@media (max-width: 600px) {
|
|
40
|
+
padding: 15px;
|
|
41
|
+
}
|
|
37
42
|
`;
|