contentoh-components-library 21.6.37 → 21.6.39

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.
@@ -150,8 +150,7 @@ var LinkVariantsModal = function LinkVariantsModal(_ref) {
150
150
  var _useState21 = (0, _react.useState)({
151
151
  attributes: [],
152
152
  descriptions: [],
153
- images: [],
154
- categoryRetailers: []
153
+ images: []
155
154
  }),
156
155
  _useState22 = (0, _slicedToArray2.default)(_useState21, 2),
157
156
  offered = _useState22[0],
@@ -160,8 +159,7 @@ var LinkVariantsModal = function LinkVariantsModal(_ref) {
160
159
  var _useState23 = (0, _react.useState)({
161
160
  attributes: [],
162
161
  descriptions: [],
163
- images: [],
164
- categoryRetailers: []
162
+ images: []
165
163
  }),
166
164
  _useState24 = (0, _slicedToArray2.default)(_useState23, 2),
167
165
  chosen = _useState24[0],
@@ -177,7 +175,6 @@ var LinkVariantsModal = function LinkVariantsModal(_ref) {
177
175
 
178
176
 
179
177
  var _useState27 = (0, _react.useState)({
180
- categoryRetailers: null,
181
178
  descriptions: null,
182
179
  attributes: null,
183
180
  images: null
@@ -451,19 +448,16 @@ var LinkVariantsModal = function LinkVariantsModal(_ref) {
451
448
  listas = {
452
449
  attributes: data.attributes || [],
453
450
  descriptions: data.descriptions || [],
454
- images: data.images || [],
455
- categoryRetailers: data.categoryRetailers || []
451
+ images: data.images || []
456
452
  };
457
453
  setOffered(listas);
458
454
  setNameScope((_data$nameScope = data.nameScope) !== null && _data$nameScope !== void 0 ? _data$nameScope : null);
459
455
  setChosen({
460
456
  attributes: [],
461
457
  descriptions: [],
462
- images: [],
463
- categoryRetailers: []
458
+ images: []
464
459
  });
465
460
  setModes({
466
- categoryRetailers: null,
467
461
  descriptions: null,
468
462
  attributes: null,
469
463
  images: null
@@ -544,34 +538,28 @@ var LinkVariantsModal = function LinkVariantsModal(_ref) {
544
538
  });
545
539
 
546
540
  var buildInherit = function buildInherit(seleccion) {
547
- var parejas = offered.categoryRetailers.map(function (item) {
548
- return {
549
- clave: "".concat(item.retailerId, "-").concat(item.categoryId),
550
- retailerId: item.retailerId,
551
- categoryId: item.categoryId
552
- };
553
- });
554
541
  return {
555
542
  attributes: seleccion.modes.attributes === "all" ? "all-filled" : seleccion.chosen.attributes,
556
543
  descriptions: seleccion.modes.descriptions === "all" ? "all" : seleccion.chosen.descriptions,
557
544
  images: seleccion.modes.images === "all" ? "all" : seleccion.chosen.images,
558
- categoryRetailers: parejas.filter(function (par) {
559
- return seleccion.chosen.categoryRetailers.includes(par.clave);
560
- }).map(function (_ref6) {
561
- var retailerId = _ref6.retailerId,
562
- categoryId = _ref6.categoryId;
563
- return {
564
- retailerId: retailerId,
565
- categoryId: categoryId
566
- };
567
- })
545
+
546
+ /*
547
+ Siempre "all", nunca una lista.
548
+ El hijo se queda con las cadenas del padre, sin preguntar. No es una
549
+ preferencia: es lo que hace que la copia de atributos SE VEA. La ficha
550
+ arma su lista desde `attribute_manager` acotado por las cadenas del
551
+ propio producto, así que un valor copiado a un atributo que la cadena del
552
+ hijo no configura queda escrito y invisible.
553
+ Se manda la palabra y no la lista para que signifique "todas" también si
554
+ alguien agregó una cadena al padre entre abrir el modal y guardar.
555
+ */
556
+ categoryRetailers: "all"
568
557
  };
569
558
  };
570
559
 
571
560
  var seleccionVacia = function seleccionVacia() {
572
561
  return {
573
562
  modes: {
574
- categoryRetailers: null,
575
563
  descriptions: null,
576
564
  attributes: null,
577
565
  images: null
@@ -579,8 +567,7 @@ var LinkVariantsModal = function LinkVariantsModal(_ref) {
579
567
  chosen: {
580
568
  attributes: [],
581
569
  descriptions: [],
582
- images: [],
583
- categoryRetailers: []
570
+ images: []
584
571
  }
585
572
  };
586
573
  };
@@ -606,7 +593,7 @@ var LinkVariantsModal = function LinkVariantsModal(_ref) {
606
593
  };
607
594
 
608
595
  var submit = /*#__PURE__*/function () {
609
- var _ref7 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee5() {
596
+ var _ref6 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee5() {
610
597
  var inherit, inheritByChild, body, data;
611
598
  return _regenerator.default.wrap(function _callee5$(_context5) {
612
599
  while (1) {
@@ -678,24 +665,19 @@ var LinkVariantsModal = function LinkVariantsModal(_ref) {
678
665
  }));
679
666
 
680
667
  return function submit() {
681
- return _ref7.apply(this, arguments);
668
+ return _ref6.apply(this, arguments);
682
669
  };
683
670
  }(); // Una dimensión está decidida si el usuario eligió un modo, o si el padre no
684
671
  // ofrece nada en ella —no se puede pedir que decida sobre una lista vacía—.
685
672
 
686
673
 
687
674
  var decidida = function decidida(dimension) {
688
- if (modes[dimension] !== null) return true;
689
-
690
- if (dimension === "categoryRetailers") {
691
- return offered.categoryRetailers.length === 0;
692
- } // Una imagen cuyo archivo no existe no es algo sobre lo que se pueda decidir.
693
-
675
+ if (modes[dimension] !== null) return true; // Una imagen cuyo archivo no existe no es algo sobre lo que se pueda decidir.
694
676
 
695
677
  return dimension === "images" ? imagenesUtiles.length === 0 : offered[dimension].length === 0;
696
678
  };
697
679
 
698
- var DIMENSIONES = ["categoryRetailers", "descriptions", "attributes", "images"]; // Con pestañas, que la que estoy viendo esté completa no basta: ligar escribe
680
+ var DIMENSIONES = ["descriptions", "attributes", "images"]; // Con pestañas, que la que estoy viendo esté completa no basta: ligar escribe
699
681
  // en todos, así que todos tienen que estar decididos. Si no, un producto se
700
682
  // ligaría sin heredar nada solo porque nadie abrió su pestaña.
701
683
 
@@ -707,24 +689,19 @@ var LinkVariantsModal = function LinkVariantsModal(_ref) {
707
689
  if (!guardado) return false;
708
690
  return DIMENSIONES.every(function (dimension) {
709
691
  if (guardado.modes[dimension] !== null) return true;
710
-
711
- if (dimension === "categoryRetailers") {
712
- return offered.categoryRetailers.length === 0;
713
- }
714
-
715
692
  return dimension === "images" ? imagenesUtiles.length === 0 : offered[dimension].length === 0;
716
693
  });
717
694
  };
718
695
 
719
696
  var todoDecidido = step === "inherit" && (mode === "parent" ? pushToParent !== null : applyToAll ? DIMENSIONES.every(decidida) : selected.every(decididoPara));
720
- var faltantes = [["categoryRetailers", "cadenas"], ["descriptions", "descripciones"], ["attributes", "atributos"], ["images", "imágenes"]].filter(function (_ref8) {
721
- var _ref9 = (0, _slicedToArray2.default)(_ref8, 1),
722
- clave = _ref9[0];
697
+ var faltantes = [["descriptions", "descripciones"], ["attributes", "atributos"], ["images", "imágenes"]].filter(function (_ref7) {
698
+ var _ref8 = (0, _slicedToArray2.default)(_ref7, 1),
699
+ clave = _ref8[0];
723
700
 
724
701
  return !decidida(clave);
725
- }).map(function (_ref10) {
726
- var _ref11 = (0, _slicedToArray2.default)(_ref10, 2),
727
- nombre = _ref11[1];
702
+ }).map(function (_ref9) {
703
+ var _ref10 = (0, _slicedToArray2.default)(_ref9, 2),
704
+ nombre = _ref10[1];
728
705
 
729
706
  return nombre;
730
707
  });
@@ -1003,73 +980,6 @@ var LinkVariantsModal = function LinkVariantsModal(_ref) {
1003
980
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
1004
981
  className: "paso",
1005
982
  children: "1"
1006
- }), " Cadenas y categor\xEDas"]
1007
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_styles.Choices, {
1008
- children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("label", {
1009
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("input", {
1010
- type: "radio",
1011
- name: "categoryRetailers-".concat(activeChild !== null && activeChild !== void 0 ? activeChild : "todos"),
1012
- checked: modes.categoryRetailers === "all",
1013
- onChange: function onChange() {
1014
- return chooseMode("categoryRetailers", "all", offered.categoryRetailers.map(function (item) {
1015
- return "".concat(item.retailerId, "-").concat(item.categoryId);
1016
- }));
1017
- }
1018
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", {
1019
- children: ["Todas las del producto padre", /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", {
1020
- className: "hint",
1021
- children: [offered.categoryRetailers.length, " cadena(s)."]
1022
- })]
1023
- })]
1024
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("label", {
1025
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("input", {
1026
- type: "radio",
1027
- name: "categoryRetailers-".concat(activeChild !== null && activeChild !== void 0 ? activeChild : "todos"),
1028
- checked: modes.categoryRetailers === "some",
1029
- onChange: function onChange() {
1030
- return chooseMode("categoryRetailers", "some", []);
1031
- }
1032
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", {
1033
- children: ["Elegir cu\xE1les", /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
1034
- className: "hint",
1035
- children: "Solo se puede heredar de las que ya tiene el padre."
1036
- })]
1037
- })]
1038
- })]
1039
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_styles.List, {
1040
- children: offered.categoryRetailers.map(function (item) {
1041
- return (0, _objectSpread7.default)((0, _objectSpread7.default)({}, item), {}, {
1042
- clave: "".concat(item.retailerId, "-").concat(item.categoryId)
1043
- });
1044
- }).map(function (item) {
1045
- return /*#__PURE__*/(0, _jsxRuntime.jsx)("li", {
1046
- children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("label", {
1047
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("input", {
1048
- type: "checkbox",
1049
- disabled: modes.categoryRetailers === "all",
1050
- checked: chosen.categoryRetailers.includes(item.clave),
1051
- onChange: function onChange() {
1052
- return toggleChoice("categoryRetailers", item.clave);
1053
- }
1054
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)("img", {
1055
- className: "logo",
1056
- src: (0, _helper.getRetailerPicture)(item.retailerId, 24, 24),
1057
- alt: ""
1058
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", {
1059
- children: [item.retailerName, /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
1060
- className: "meta",
1061
- children: item.categoryName || "Sin categoría"
1062
- })]
1063
- })]
1064
- })
1065
- }, item.clave);
1066
- })
1067
- })]
1068
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_styles.Block, {
1069
- children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("h3", {
1070
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
1071
- className: "paso",
1072
- children: "2"
1073
983
  }), " Descripciones"]
1074
984
  }), offered.descriptions.length ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
1075
985
  children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_styles.Choices, {
@@ -1136,7 +1046,7 @@ var LinkVariantsModal = function LinkVariantsModal(_ref) {
1136
1046
  children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("h3", {
1137
1047
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
1138
1048
  className: "paso",
1139
- children: "3"
1049
+ children: "2"
1140
1050
  }), " Atributos de la ficha t\xE9cnica"]
1141
1051
  }), offered.attributes.length ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
1142
1052
  children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_styles.Choices, {
@@ -1208,7 +1118,7 @@ var LinkVariantsModal = function LinkVariantsModal(_ref) {
1208
1118
  children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("h3", {
1209
1119
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
1210
1120
  className: "paso",
1211
- children: "4"
1121
+ children: "3"
1212
1122
  }), " Im\xE1genes"]
1213
1123
  }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_styles.Choices, {
1214
1124
  children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("label", {
@@ -51,7 +51,7 @@ var SearchRow = _styledComponents.default.form(_templateObject6 || (_templateObj
51
51
 
52
52
  exports.SearchRow = SearchRow;
53
53
 
54
- var List = _styledComponents.default.ul(_templateObject7 || (_templateObject7 = (0, _taggedTemplateLiteral2.default)(["\n list-style: none;\n margin: 0 0 16px;\n padding: 0;\n border: 1px solid ", ";\n border-radius: 6px;\n\n li + li {\n border-top: 1px solid ", ";\n }\n\n label {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 12px;\n cursor: pointer;\n font-size: 13px;\n color: ", ";\n }\n\n .meta {\n display: block;\n font-size: 12px;\n color: ", ";\n }\n\n .logo {\n width: 24px;\n height: 24px;\n object-fit: contain;\n border-radius: 3px;\n flex-shrink: 0;\n }\n\n li {\n display: flex;\n align-items: center;\n }\n\n li > label {\n flex: 1;\n min-width: 0;\n }\n\n .count {\n margin-left: auto;\n font-size: 12px;\n color: ", ";\n white-space: nowrap;\n }\n"])), _variables.GlobalColors.s2, _variables.GlobalColors.s2, _variables.GlobalColors.deep_gray, _variables.GlobalColors.gray, PINK);
54
+ var List = _styledComponents.default.ul(_templateObject7 || (_templateObject7 = (0, _taggedTemplateLiteral2.default)(["\n list-style: none;\n margin: 0 0 16px;\n padding: 0;\n border: 1px solid ", ";\n border-radius: 6px;\n\n li + li {\n border-top: 1px solid ", ";\n }\n\n label {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 12px;\n cursor: pointer;\n font-size: 13px;\n color: ", ";\n }\n\n .meta {\n display: block;\n font-size: 12px;\n color: ", ";\n }\n\n li {\n display: flex;\n align-items: center;\n }\n\n li > label {\n flex: 1;\n min-width: 0;\n }\n\n .count {\n margin-left: auto;\n font-size: 12px;\n color: ", ";\n white-space: nowrap;\n }\n"])), _variables.GlobalColors.s2, _variables.GlobalColors.s2, _variables.GlobalColors.deep_gray, _variables.GlobalColors.gray, PINK);
55
55
 
56
56
  exports.List = List;
57
57
  var AttributeList = (0, _styledComponents.default)(List)(_templateObject8 || (_templateObject8 = (0, _taggedTemplateLiteral2.default)(["\n max-height: 220px;\n overflow-y: auto;\n\n .note {\n display: block;\n font-size: 11px;\n font-style: italic;\n color: ", ";\n }\n\n .value {\n margin-left: auto;\n max-width: 45%;\n font-size: 12px;\n color: ", ";\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n"])), _variables.GlobalColors.gray, _variables.GlobalColors.gray);
@@ -176,7 +176,7 @@ function _regenerateVideoThumbnails() {
176
176
 
177
177
  case 2:
178
178
  return _context18.abrupt("return", Promise.all(values.map( /*#__PURE__*/function () {
179
- var _ref21 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee17(value) {
179
+ var _ref22 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee17(value) {
180
180
  var base64, videoSrc, thumbnail;
181
181
  return _regenerator.default.wrap(function _callee17$(_context17) {
182
182
  while (1) {
@@ -221,7 +221,7 @@ function _regenerateVideoThumbnails() {
221
221
  }));
222
222
 
223
223
  return function (_x10) {
224
- return _ref21.apply(this, arguments);
224
+ return _ref22.apply(this, arguments);
225
225
  };
226
226
  }())));
227
227
 
@@ -1073,26 +1073,35 @@ var RetailerProductEditionView = function RetailerProductEditionView(_ref) {
1073
1073
 
1074
1074
  return ((_state$product5 = state.product) === null || _state$product5 === void 0 ? void 0 : _state$product5.id_auditor) === (user === null || user === void 0 ? void 0 : user.id_user);
1075
1075
  };
1076
+ /**
1077
+ * ¿Ocupo este slot EN ESTE producto?
1078
+ *
1079
+ * La calidad en la que actúas sale de la ASIGNACIÓN, no del rol. Con la
1080
+ * estructura nueva de Creators, quien produce un servicio también lo valida:
1081
+ * un especialista de textos puede ser el auditor del mismo producto y tiene
1082
+ * que recorrer las dos fases, AS -> AC como especialista y AC -> AA como QA.
1083
+ */
1076
1084
 
1077
- var isUserAssignedToService = function isUserAssignedToService(tab, rol) {
1085
+
1086
+ var isAssignedAs = function isAssignedAs(rol, concept) {
1078
1087
  var _state$product6;
1079
1088
 
1089
+ var assigned = (_state$product6 = state.product) === null || _state$product6 === void 0 ? void 0 : _state$product6["id_".concat(concept, "_").concat(rol)];
1090
+ return !!assigned && assigned === (user === null || user === void 0 ? void 0 : user.id_user);
1091
+ };
1092
+
1093
+ var isUserAssignedToService = function isUserAssignedToService(tab, rol) {
1080
1094
  var concept = (0, _utils.getConceptByTab)(state.active_tab);
1081
1095
  var allowedRoles = [1, 4, 5, 6, 7, 8];
1082
- var validUser = allowedRoles.includes(user === null || user === void 0 ? void 0 : user.id_role); // Determinar rol por defecto si no se pasa
1083
-
1084
- if (!rol) {
1085
- if (user.id_role === 4 || user.id_role === 5) {
1086
- rol = "facilitator";
1087
- } else if (user.id_role === 7 || user.id_role === 8) {
1088
- rol = "especialist";
1089
- }
1090
- }
1091
-
1096
+ var validUser = allowedRoles.includes(user === null || user === void 0 ? void 0 : user.id_role);
1092
1097
  var isAdmin = user.id_role === 1;
1093
- var idUserAssigned = (_state$product6 = state.product) === null || _state$product6 === void 0 ? void 0 : _state$product6["id_".concat(concept, "_").concat(rol)];
1094
- var isAssigned = idUserAssigned === user.id_user;
1095
- return isAdmin || isAssigned && validUser;
1098
+ if (isAdmin) return true; // Sin `rol` explícito se prueba por asignación, no por rol. Antes se
1099
+ // infería del `id_role`: un rol 6 caía en `id_<concept>_undefined` —columna
1100
+ // inexistente, siempre falso— y un rol 7 solo podía ser especialista, nunca
1101
+ // auditor. Es el mismo defecto que se corrigió en el backend.
1102
+
1103
+ var isAssigned = rol ? isAssignedAs(rol, concept) : isAssignedAs("especialist", concept) || isAssignedAs("facilitator", concept);
1104
+ return isAssigned && validUser;
1096
1105
  };
1097
1106
 
1098
1107
  var canShowSingleEvaluationButtons = function canShowSingleEvaluationButtons(action) {
@@ -1103,10 +1112,13 @@ var RetailerProductEditionView = function RetailerProductEditionView(_ref) {
1103
1112
  var _state$active_retaile2;
1104
1113
 
1105
1114
  return srv.id_retailer === ((_state$active_retaile2 = state.active_retailer) === null || _state$active_retaile2 === void 0 ? void 0 : _state$active_retaile2.id_retailer) && srv.service === concept;
1106
- })) === null || _state$services_data$ === void 0 ? void 0 : (_state$services_data$2 = _state$services_data$.status) === null || _state$services_data$2 === void 0 ? void 0 : _state$services_data$2.replace(/.*\//, "");
1107
- var adminFacilitatorCanEvaluate = retailerStatus === "IE" && [1, 4, 5].includes(user.id_role);
1108
- var adminAuditorCanEvaluate = ["AC", "RP", "RCA", "SAC"].includes(retailerStatus) && [1, 6].includes(user.id_role);
1109
- return adminFacilitatorCanEvaluate || adminAuditorCanEvaluate;
1115
+ })) === null || _state$services_data$ === void 0 ? void 0 : (_state$services_data$2 = _state$services_data$.status) === null || _state$services_data$2 === void 0 ? void 0 : _state$services_data$2.replace(/.*\//, ""); // Se SUMA la vía por asignación a la que ya había por rol; no la
1116
+ // reemplaza. Así los coordinadores y el administrador conservan su acceso
1117
+ // tal cual, y el especialista que además es auditor alcanza la segunda fase.
1118
+
1119
+ var canEvaluateAsFacilitator = retailerStatus === "IE" && ([1, 4, 5].includes(user.id_role) || isAssignedAs("facilitator", concept));
1120
+ var canEvaluateAsAuditor = ["AC", "RP", "RCA", "SAC"].includes(retailerStatus) && ([1, 6].includes(user.id_role) || isAuditorAssigned());
1121
+ return canEvaluateAsFacilitator || canEvaluateAsAuditor;
1110
1122
  };
1111
1123
 
1112
1124
  var canShowBulkEvaluationButtons = function canShowBulkEvaluationButtons() {
@@ -1115,17 +1127,20 @@ var RetailerProductEditionView = function RetailerProductEditionView(_ref) {
1115
1127
  var service = _ref7.service;
1116
1128
  return concepts.includes(service);
1117
1129
  });
1118
- var adminFacilitatorCanEvaluate = services.every(function (srv) {
1130
+ var canEvaluateAsFacilitator = services.every(function (srv) {
1119
1131
  var _srv$status;
1120
1132
 
1121
1133
  return (srv === null || srv === void 0 ? void 0 : (_srv$status = srv.status) === null || _srv$status === void 0 ? void 0 : _srv$status.replace(/.*\//, "")) === "IE";
1122
- }) && [1, 4, 5].includes(user.id_role);
1123
- var adminAuditorCanEvaluate = state.services_data.every(function (srv) {
1134
+ }) && ([1, 4, 5].includes(user.id_role) || services.some(function (_ref8) {
1135
+ var service = _ref8.service;
1136
+ return isAssignedAs("facilitator", service);
1137
+ }));
1138
+ var canEvaluateAsAuditor = state.services_data.every(function (srv) {
1124
1139
  var _srv$status2;
1125
1140
 
1126
1141
  return ["AC", "RP", "RCA"].includes(srv === null || srv === void 0 ? void 0 : (_srv$status2 = srv.status) === null || _srv$status2 === void 0 ? void 0 : _srv$status2.replace(/.*\//, ""));
1127
- }) && [1, 6].includes(user.id_role);
1128
- return adminFacilitatorCanEvaluate || adminAuditorCanEvaluate;
1142
+ }) && ([1, 6].includes(user.id_role) || isAuditorAssigned());
1143
+ return canEvaluateAsFacilitator || canEvaluateAsAuditor;
1129
1144
  };
1130
1145
 
1131
1146
  var getStatusByCurrentServiceAndRetailer = function getStatusByCurrentServiceAndRetailer() {
@@ -1156,7 +1171,7 @@ var RetailerProductEditionView = function RetailerProductEditionView(_ref) {
1156
1171
 
1157
1172
 
1158
1173
  var loadFamily = /*#__PURE__*/function () {
1159
- var _ref8 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee5() {
1174
+ var _ref9 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee5() {
1160
1175
  var forzar,
1161
1176
  _state$product8,
1162
1177
  res,
@@ -1213,7 +1228,7 @@ var RetailerProductEditionView = function RetailerProductEditionView(_ref) {
1213
1228
  }));
1214
1229
 
1215
1230
  return function loadFamily() {
1216
- return _ref8.apply(this, arguments);
1231
+ return _ref9.apply(this, arguments);
1217
1232
  };
1218
1233
  }();
1219
1234
  /*
@@ -1321,8 +1336,8 @@ var RetailerProductEditionView = function RetailerProductEditionView(_ref) {
1321
1336
  };
1322
1337
 
1323
1338
  var openFamilyMember = /*#__PURE__*/function () {
1324
- var _ref9 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee6(articleId) {
1325
- var _readPayload, res, _ref10, data, encontrado;
1339
+ var _ref10 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee6(articleId) {
1340
+ var _readPayload, res, _ref11, data, encontrado;
1326
1341
 
1327
1342
  return _regenerator.default.wrap(function _callee6$(_context6) {
1328
1343
  while (1) {
@@ -1347,7 +1362,7 @@ var RetailerProductEditionView = function RetailerProductEditionView(_ref) {
1347
1362
  // read-order-services responde { total, data: [...] }. La vista trae una
1348
1363
  // fila por orden, así que puede haber varias del mismo artículo; llegan
1349
1364
  // ordenadas por order_id DESC y la primera es la orden más reciente.
1350
- _ref10 = (_readPayload = (0, _api.readPayload)(res)) !== null && _readPayload !== void 0 ? _readPayload : {}, data = _ref10.data;
1365
+ _ref11 = (_readPayload = (0, _api.readPayload)(res)) !== null && _readPayload !== void 0 ? _readPayload : {}, data = _ref11.data;
1351
1366
  encontrado = (data !== null && data !== void 0 ? data : []).find(function (item) {
1352
1367
  var _item$article;
1353
1368
 
@@ -1394,7 +1409,7 @@ var RetailerProductEditionView = function RetailerProductEditionView(_ref) {
1394
1409
  }));
1395
1410
 
1396
1411
  return function openFamilyMember(_x3) {
1397
- return _ref9.apply(this, arguments);
1412
+ return _ref10.apply(this, arguments);
1398
1413
  };
1399
1414
  }();
1400
1415
  /*
@@ -1483,7 +1498,7 @@ var RetailerProductEditionView = function RetailerProductEditionView(_ref) {
1483
1498
 
1484
1499
 
1485
1500
  var handleOnRestoreInheritance = /*#__PURE__*/function () {
1486
- var _ref11 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee7(attributeId) {
1501
+ var _ref12 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee7(attributeId) {
1487
1502
  var _state$product14;
1488
1503
 
1489
1504
  var kind,
@@ -1569,7 +1584,7 @@ var RetailerProductEditionView = function RetailerProductEditionView(_ref) {
1569
1584
  }));
1570
1585
 
1571
1586
  return function handleOnRestoreInheritance(_x4) {
1572
- return _ref11.apply(this, arguments);
1587
+ return _ref12.apply(this, arguments);
1573
1588
  };
1574
1589
  }();
1575
1590
  /*
@@ -1596,7 +1611,7 @@ var RetailerProductEditionView = function RetailerProductEditionView(_ref) {
1596
1611
  };
1597
1612
 
1598
1613
  var handleOnClickSave = /*#__PURE__*/function () {
1599
- var _ref12 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee8() {
1614
+ var _ref13 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee8() {
1600
1615
  var _familia$variants, cambios, familia, hijos;
1601
1616
 
1602
1617
  return _regenerator.default.wrap(function _callee8$(_context8) {
@@ -1751,7 +1766,7 @@ var RetailerProductEditionView = function RetailerProductEditionView(_ref) {
1751
1766
  }));
1752
1767
 
1753
1768
  return function handleOnClickSave() {
1754
- return _ref12.apply(this, arguments);
1769
+ return _ref13.apply(this, arguments);
1755
1770
  };
1756
1771
  }();
1757
1772
 
@@ -1819,7 +1834,7 @@ var RetailerProductEditionView = function RetailerProductEditionView(_ref) {
1819
1834
  };
1820
1835
 
1821
1836
  var handleOnApproveSingleService = /*#__PURE__*/function () {
1822
- var _ref13 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee9() {
1837
+ var _ref14 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee9() {
1823
1838
  return _regenerator.default.wrap(function _callee9$(_context9) {
1824
1839
  while (1) {
1825
1840
  switch (_context9.prev = _context9.next) {
@@ -1836,7 +1851,7 @@ var RetailerProductEditionView = function RetailerProductEditionView(_ref) {
1836
1851
  }));
1837
1852
 
1838
1853
  return function handleOnApproveSingleService() {
1839
- return _ref13.apply(this, arguments);
1854
+ return _ref14.apply(this, arguments);
1840
1855
  };
1841
1856
  }();
1842
1857
 
@@ -1845,7 +1860,7 @@ var RetailerProductEditionView = function RetailerProductEditionView(_ref) {
1845
1860
  };
1846
1861
 
1847
1862
  var sendSingleEvaluation = /*#__PURE__*/function () {
1848
- var _ref14 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee10(result) {
1863
+ var _ref15 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee10(result) {
1849
1864
  var _state$product$id_ord, _state$active_retaile4;
1850
1865
 
1851
1866
  var concept, articleId, orderId, sectionStatusKey, evalStatus, retailerId, data, res, message, icon, activeTab, newStatuses, serviceStatus, articleStatus, updatedStatusByRetailer, updatedProduct, specialistDone, _objectSpread2, _state$services_data2, _JSON$parse2, newStatus, newOrderStatus, newArticleStatus, _articleStatus, updatedStatusByRetailerForSend, _updatedProduct, updatedServicesData, sessionProduct, _objectSpread3, productInSession, updatedProductInSession;
@@ -2071,12 +2086,12 @@ var RetailerProductEditionView = function RetailerProductEditionView(_ref) {
2071
2086
  }));
2072
2087
 
2073
2088
  return function sendSingleEvaluation(_x5) {
2074
- return _ref14.apply(this, arguments);
2089
+ return _ref15.apply(this, arguments);
2075
2090
  };
2076
2091
  }();
2077
2092
 
2078
2093
  var handleOnApproveAllServices = /*#__PURE__*/function () {
2079
- var _ref15 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee11() {
2094
+ var _ref16 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee11() {
2080
2095
  return _regenerator.default.wrap(function _callee11$(_context11) {
2081
2096
  while (1) {
2082
2097
  switch (_context11.prev = _context11.next) {
@@ -2093,7 +2108,7 @@ var RetailerProductEditionView = function RetailerProductEditionView(_ref) {
2093
2108
  }));
2094
2109
 
2095
2110
  return function handleOnApproveAllServices() {
2096
- return _ref15.apply(this, arguments);
2111
+ return _ref16.apply(this, arguments);
2097
2112
  };
2098
2113
  }();
2099
2114
 
@@ -2103,7 +2118,7 @@ var RetailerProductEditionView = function RetailerProductEditionView(_ref) {
2103
2118
  };
2104
2119
 
2105
2120
  var sendBulkEvaluation = /*#__PURE__*/function () {
2106
- var _ref16 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee12(result) {
2121
+ var _ref17 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee12(result) {
2107
2122
  var _state$services_data3, evaluationArray, conceptArray, status, updatedStatusByRetailer, updatedProduct, updatedServicesData;
2108
2123
 
2109
2124
  return _regenerator.default.wrap(function _callee12$(_context12) {
@@ -2219,12 +2234,12 @@ var RetailerProductEditionView = function RetailerProductEditionView(_ref) {
2219
2234
  }));
2220
2235
 
2221
2236
  return function sendBulkEvaluation(_x6) {
2222
- return _ref16.apply(this, arguments);
2237
+ return _ref17.apply(this, arguments);
2223
2238
  };
2224
2239
  }();
2225
2240
 
2226
2241
  var handleOnChangeAssignations = /*#__PURE__*/function () {
2227
- var _ref17 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee13(assignationType, assignationId) {
2242
+ var _ref18 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee13(assignationType, assignationId) {
2228
2243
  var concept, data, updatedProduct;
2229
2244
  return _regenerator.default.wrap(function _callee13$(_context13) {
2230
2245
  while (1) {
@@ -2265,7 +2280,7 @@ var RetailerProductEditionView = function RetailerProductEditionView(_ref) {
2265
2280
  }));
2266
2281
 
2267
2282
  return function handleOnChangeAssignations(_x7, _x8) {
2268
- return _ref17.apply(this, arguments);
2283
+ return _ref18.apply(this, arguments);
2269
2284
  };
2270
2285
  }();
2271
2286
 
@@ -2300,7 +2315,7 @@ var RetailerProductEditionView = function RetailerProductEditionView(_ref) {
2300
2315
  };
2301
2316
 
2302
2317
  var handleOnSubmitComment = /*#__PURE__*/function () {
2303
- var _ref18 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee14(e) {
2318
+ var _ref19 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee14(e) {
2304
2319
  var commentText;
2305
2320
  return _regenerator.default.wrap(function _callee14$(_context14) {
2306
2321
  while (1) {
@@ -2348,7 +2363,7 @@ var RetailerProductEditionView = function RetailerProductEditionView(_ref) {
2348
2363
  }));
2349
2364
 
2350
2365
  return function handleOnSubmitComment(_x9) {
2351
- return _ref18.apply(this, arguments);
2366
+ return _ref19.apply(this, arguments);
2352
2367
  };
2353
2368
  }();
2354
2369
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "contentoh-components-library",
3
- "version": "21.6.37",
3
+ "version": "21.6.39",
4
4
  "dependencies": {
5
5
  "@aws-amplify/auth": "^4.5.3",
6
6
  "@aws-amplify/datastore": "^3.11.0",
@@ -2,7 +2,7 @@ import { useCallback, useEffect, useMemo, useState } from "react";
2
2
  import axios from "axios";
3
3
 
4
4
  import { readPayload, ApiError } from "./api";
5
- import { getProductImage, getRetailerPicture } from "../../../_utils/helper";
5
+ import { getProductImage } from "../../../_utils/helper";
6
6
 
7
7
  import {
8
8
  Overlay,
@@ -106,13 +106,11 @@ export const LinkVariantsModal = ({
106
106
  attributes: [],
107
107
  descriptions: [],
108
108
  images: [],
109
- categoryRetailers: [],
110
109
  });
111
110
  const [chosen, setChosen] = useState({
112
111
  attributes: [],
113
112
  descriptions: [],
114
113
  images: [],
115
- categoryRetailers: [],
116
114
  });
117
115
  const [nameScope, setNameScope] = useState(null);
118
116
 
@@ -121,7 +119,6 @@ export const LinkVariantsModal = ({
121
119
  // se pudiera ligar sin haber mirado nada, que es justo lo que hay que evitar
122
120
  // en una operación que sobrescribe valores capturados.
123
121
  const [modes, setModes] = useState({
124
- categoryRetailers: null,
125
122
  descriptions: null,
126
123
  attributes: null,
127
124
  images: null,
@@ -285,7 +282,6 @@ export const LinkVariantsModal = ({
285
282
  attributes: data.attributes || [],
286
283
  descriptions: data.descriptions || [],
287
284
  images: data.images || [],
288
- categoryRetailers: data.categoryRetailers || [],
289
285
  };
290
286
 
291
287
  setOffered(listas);
@@ -294,10 +290,8 @@ export const LinkVariantsModal = ({
294
290
  attributes: [],
295
291
  descriptions: [],
296
292
  images: [],
297
- categoryRetailers: [],
298
293
  });
299
294
  setModes({
300
- categoryRetailers: null,
301
295
  descriptions: null,
302
296
  attributes: null,
303
297
  images: null,
@@ -367,12 +361,6 @@ export const LinkVariantsModal = ({
367
361
  );
368
362
 
369
363
  const buildInherit = (seleccion) => {
370
- const parejas = offered.categoryRetailers.map((item) => ({
371
- clave: `${item.retailerId}-${item.categoryId}`,
372
- retailerId: item.retailerId,
373
- categoryId: item.categoryId,
374
- }));
375
-
376
364
  return {
377
365
  attributes:
378
366
  seleccion.modes.attributes === "all"
@@ -384,15 +372,24 @@ export const LinkVariantsModal = ({
384
372
  : seleccion.chosen.descriptions,
385
373
  images:
386
374
  seleccion.modes.images === "all" ? "all" : seleccion.chosen.images,
387
- categoryRetailers: parejas
388
- .filter((par) => seleccion.chosen.categoryRetailers.includes(par.clave))
389
- .map(({ retailerId, categoryId }) => ({ retailerId, categoryId })),
375
+ /*
376
+ Siempre "all", nunca una lista.
377
+
378
+ El hijo se queda con las cadenas del padre, sin preguntar. No es una
379
+ preferencia: es lo que hace que la copia de atributos SE VEA. La ficha
380
+ arma su lista desde `attribute_manager` acotado por las cadenas del
381
+ propio producto, así que un valor copiado a un atributo que la cadena del
382
+ hijo no configura queda escrito y invisible.
383
+
384
+ Se manda la palabra y no la lista para que signifique "todas" también si
385
+ alguien agregó una cadena al padre entre abrir el modal y guardar.
386
+ */
387
+ categoryRetailers: "all",
390
388
  };
391
389
  };
392
390
 
393
391
  const seleccionVacia = () => ({
394
392
  modes: {
395
- categoryRetailers: null,
396
393
  descriptions: null,
397
394
  attributes: null,
398
395
  images: null,
@@ -401,7 +398,6 @@ export const LinkVariantsModal = ({
401
398
  attributes: [],
402
399
  descriptions: [],
403
400
  images: [],
404
- categoryRetailers: [],
405
401
  },
406
402
  });
407
403
 
@@ -478,21 +474,13 @@ export const LinkVariantsModal = ({
478
474
  // ofrece nada en ella —no se puede pedir que decida sobre una lista vacía—.
479
475
  const decidida = (dimension) => {
480
476
  if (modes[dimension] !== null) return true;
481
- if (dimension === "categoryRetailers") {
482
- return offered.categoryRetailers.length === 0;
483
- }
484
477
  // Una imagen cuyo archivo no existe no es algo sobre lo que se pueda decidir.
485
478
  return dimension === "images"
486
479
  ? imagenesUtiles.length === 0
487
480
  : offered[dimension].length === 0;
488
481
  };
489
482
 
490
- const DIMENSIONES = [
491
- "categoryRetailers",
492
- "descriptions",
493
- "attributes",
494
- "images",
495
- ];
483
+ const DIMENSIONES = ["descriptions", "attributes", "images"];
496
484
 
497
485
  // Con pestañas, que la que estoy viendo esté completa no basta: ligar escribe
498
486
  // en todos, así que todos tienen que estar decididos. Si no, un producto se
@@ -503,9 +491,6 @@ export const LinkVariantsModal = ({
503
491
 
504
492
  return DIMENSIONES.every((dimension) => {
505
493
  if (guardado.modes[dimension] !== null) return true;
506
- if (dimension === "categoryRetailers") {
507
- return offered.categoryRetailers.length === 0;
508
- }
509
494
  return dimension === "images"
510
495
  ? imagenesUtiles.length === 0
511
496
  : offered[dimension].length === 0;
@@ -521,7 +506,6 @@ export const LinkVariantsModal = ({
521
506
  : selected.every(decididoPara));
522
507
 
523
508
  const faltantes = [
524
- ["categoryRetailers", "cadenas"],
525
509
  ["descriptions", "descripciones"],
526
510
  ["attributes", "atributos"],
527
511
  ["images", "imágenes"],
@@ -858,96 +842,32 @@ export const LinkVariantsModal = ({
858
842
  </>
859
843
  )}
860
844
 
861
- {/* El orden no es casual: primero se decide en qué cadenas vive el
862
- hijo, porque de eso depende qué atributos le aplican. Las
863
- imágenes van al final: son la decisión más visual y la que menos
864
- arrastra a las demás. */}
845
+ {/* Ya no se pregunta por cadenas ni categorías.
865
846
 
866
- <Block>
867
- <h3>
868
- <span className="paso">1</span> Cadenas y categorías
869
- </h3>
870
- <Choices>
871
- <label>
872
- <input
873
- type="radio"
874
- name={`categoryRetailers-${activeChild ?? "todos"}`}
875
- checked={modes.categoryRetailers === "all"}
876
- onChange={() =>
877
- chooseMode(
878
- "categoryRetailers",
879
- "all",
880
- offered.categoryRetailers.map(
881
- (item) => `${item.retailerId}-${item.categoryId}`
882
- )
883
- )
884
- }
885
- />
886
- <span>
887
- Todas las del producto padre
888
- <span className="hint">
889
- {offered.categoryRetailers.length} cadena(s).
890
- </span>
891
- </span>
892
- </label>
893
- <label>
894
- <input
895
- type="radio"
896
- name={`categoryRetailers-${activeChild ?? "todos"}`}
897
- checked={modes.categoryRetailers === "some"}
898
- onChange={() =>
899
- chooseMode("categoryRetailers", "some", [])
900
- }
901
- />
902
- <span>
903
- Elegir cuáles
904
- <span className="hint">
905
- Solo se puede heredar de las que ya tiene el padre.
906
- </span>
907
- </span>
908
- </label>
909
- </Choices>
847
+ El valor de un atributo vive en `article_data` por (artículo,
848
+ versión, atributo): no está partido por cadena, así que copiar
849
+ el atributo 27 del padre al hijo es lo mismo sin importar en
850
+ qué cadenas esté cada uno. Elegir cadenas aquí no cambiaba nada
851
+ de eso; solo servía para decidir en qué cadenas vive el hijo, y
852
+ la respuesta correcta resultó ser siempre «las del padre».
910
853
 
911
- <List>
912
- {offered.categoryRetailers
913
- .map((item) => ({
914
- ...item,
915
- clave: `${item.retailerId}-${item.categoryId}`,
916
- }))
917
- .map((item) => (
918
- <li key={item.clave}>
919
- <label>
920
- <input
921
- type="checkbox"
922
- disabled={modes.categoryRetailers === "all"}
923
- checked={chosen.categoryRetailers.includes(
924
- item.clave
925
- )}
926
- onChange={() =>
927
- toggleChoice("categoryRetailers", item.clave)
928
- }
929
- />
930
- <img
931
- className="logo"
932
- src={getRetailerPicture(item.retailerId, 24, 24)}
933
- alt=""
934
- />
935
- <span>
936
- {item.retailerName}
937
- <span className="meta">
938
- {item.categoryName || "Sin categoría"}
939
- </span>
940
- </span>
941
- </label>
942
- </li>
943
- ))}
944
- </List>
854
+ Medido en dev sobre las 24 familias reales: cuando el hijo
855
+ comparte al menos una cadena con el padre, 0 atributos quedan
856
+ sin mostrarse; cuando no comparte ninguna, quedan entre 3 y 31.
857
+ 91 de 394 en total (23%). La razón es que la ficha arma su lista
858
+ desde `attribute_manager` acotado por las cadenas DEL PROPIO
859
+ producto, así que un valor copiado a un atributo que su cadena
860
+ no configura se escribe pero no se ve. Heredar todas las del
861
+ padre es lo que hace visible la copia.
945
862
 
946
- </Block>
863
+ Por eso `buildInherit` manda "all" y esto ya no se pregunta.
864
+
865
+ El orden de lo que queda no es casual: las imágenes van al
866
+ final, son la decisión más visual y la que menos arrastra. */}
947
867
 
948
868
  <Block>
949
869
  <h3>
950
- <span className="paso">2</span> Descripciones
870
+ <span className="paso">1</span> Descripciones
951
871
  </h3>
952
872
  {offered.descriptions.length ? (
953
873
  <>
@@ -1030,7 +950,7 @@ export const LinkVariantsModal = ({
1030
950
 
1031
951
  <Block>
1032
952
  <h3>
1033
- <span className="paso">3</span> Atributos de la ficha técnica
953
+ <span className="paso">2</span> Atributos de la ficha técnica
1034
954
  </h3>
1035
955
  {offered.attributes.length ? (
1036
956
  <>
@@ -1127,7 +1047,7 @@ export const LinkVariantsModal = ({
1127
1047
  {imagenesUtiles.length > 0 && (
1128
1048
  <Block>
1129
1049
  <h3>
1130
- <span className="paso">4</span> Imágenes
1050
+ <span className="paso">3</span> Imágenes
1131
1051
  </h3>
1132
1052
  <Choices>
1133
1053
  <label>
@@ -184,14 +184,6 @@ export const List = styled.ul`
184
184
  color: ${GlobalColors.gray};
185
185
  }
186
186
 
187
- .logo {
188
- width: 24px;
189
- height: 24px;
190
- object-fit: contain;
191
- border-radius: 3px;
192
- flex-shrink: 0;
193
- }
194
-
195
187
  li {
196
188
  display: flex;
197
189
  align-items: center;
@@ -707,26 +707,38 @@ const RetailerProductEditionView = ({
707
707
  return state.product?.id_auditor === user?.id_user;
708
708
  };
709
709
 
710
+ /**
711
+ * ¿Ocupo este slot EN ESTE producto?
712
+ *
713
+ * La calidad en la que actúas sale de la ASIGNACIÓN, no del rol. Con la
714
+ * estructura nueva de Creators, quien produce un servicio también lo valida:
715
+ * un especialista de textos puede ser el auditor del mismo producto y tiene
716
+ * que recorrer las dos fases, AS -> AC como especialista y AC -> AA como QA.
717
+ */
718
+ const isAssignedAs = (rol, concept) => {
719
+ const assigned = state.product?.[`id_${concept}_${rol}`];
720
+ return !!assigned && assigned === user?.id_user;
721
+ };
722
+
710
723
  const isUserAssignedToService = (tab, rol) => {
711
724
  const concept = getConceptByTab(state.active_tab);
712
725
 
713
726
  const allowedRoles = [1, 4, 5, 6, 7, 8];
714
727
  const validUser = allowedRoles.includes(user?.id_role);
715
728
 
716
- // Determinar rol por defecto si no se pasa
717
- if (!rol) {
718
- if (user.id_role === 4 || user.id_role === 5) {
719
- rol = "facilitator";
720
- } else if (user.id_role === 7 || user.id_role === 8) {
721
- rol = "especialist";
722
- }
723
- }
724
-
725
729
  const isAdmin = user.id_role === 1;
726
- const idUserAssigned = state.product?.[`id_${concept}_${rol}`];
727
- const isAssigned = idUserAssigned === user.id_user;
728
-
729
- return isAdmin || (isAssigned && validUser);
730
+ if (isAdmin) return true;
731
+
732
+ // Sin `rol` explícito se prueba por asignación, no por rol. Antes se
733
+ // infería del `id_role`: un rol 6 caía en `id_<concept>_undefined` —columna
734
+ // inexistente, siempre falso— y un rol 7 solo podía ser especialista, nunca
735
+ // auditor. Es el mismo defecto que se corrigió en el backend.
736
+ const isAssigned = rol
737
+ ? isAssignedAs(rol, concept)
738
+ : isAssignedAs("especialist", concept) ||
739
+ isAssignedAs("facilitator", concept);
740
+
741
+ return isAssigned && validUser;
730
742
  };
731
743
 
732
744
  const canShowSingleEvaluationButtons = (action) => {
@@ -740,13 +752,19 @@ const RetailerProductEditionView = ({
740
752
  )
741
753
  ?.status?.replace(/.*\//, "");
742
754
 
743
- const adminFacilitatorCanEvaluate =
744
- retailerStatus === "IE" && [1, 4, 5].includes(user.id_role);
745
- const adminAuditorCanEvaluate =
755
+ // Se SUMA la vía por asignación a la que ya había por rol; no la
756
+ // reemplaza. Así los coordinadores y el administrador conservan su acceso
757
+ // tal cual, y el especialista que además es auditor alcanza la segunda fase.
758
+ const canEvaluateAsFacilitator =
759
+ retailerStatus === "IE" &&
760
+ ([1, 4, 5].includes(user.id_role) ||
761
+ isAssignedAs("facilitator", concept));
762
+
763
+ const canEvaluateAsAuditor =
746
764
  ["AC", "RP", "RCA", "SAC"].includes(retailerStatus) &&
747
- [1, 6].includes(user.id_role);
765
+ ([1, 6].includes(user.id_role) || isAuditorAssigned());
748
766
 
749
- return adminFacilitatorCanEvaluate || adminAuditorCanEvaluate;
767
+ return canEvaluateAsFacilitator || canEvaluateAsAuditor;
750
768
  };
751
769
 
752
770
  const canShowBulkEvaluationButtons = () => {
@@ -756,15 +774,17 @@ const RetailerProductEditionView = ({
756
774
  concepts.includes(service),
757
775
  );
758
776
 
759
- const adminFacilitatorCanEvaluate =
777
+ const canEvaluateAsFacilitator =
760
778
  services.every((srv) => srv?.status?.replace(/.*\//, "") === "IE") &&
761
- [1, 4, 5].includes(user.id_role);
779
+ ([1, 4, 5].includes(user.id_role) ||
780
+ services.some(({ service }) => isAssignedAs("facilitator", service)));
762
781
 
763
- const adminAuditorCanEvaluate =
782
+ const canEvaluateAsAuditor =
764
783
  state.services_data.every((srv) =>
765
784
  ["AC", "RP", "RCA"].includes(srv?.status?.replace(/.*\//, "")),
766
- ) && [1, 6].includes(user.id_role);
767
- return adminFacilitatorCanEvaluate || adminAuditorCanEvaluate;
785
+ ) && ([1, 6].includes(user.id_role) || isAuditorAssigned());
786
+
787
+ return canEvaluateAsFacilitator || canEvaluateAsAuditor;
768
788
  };
769
789
 
770
790
  const getStatusByCurrentServiceAndRetailer = () => {