contentoh-components-library 21.4.77 → 21.4.79

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.
@@ -11,8 +11,9 @@ const Template = (args) => <EditGroup {...args} />;
11
11
  export const EditGroupDefault = Template.bind({});
12
12
  EditGroupDefault.args = {
13
13
  groups : [
14
- { text: 'Impuestos', editing: false },
15
- { text: 'Legal', editing: false },
16
- { text: 'Datos Maestros', editing: false },
17
- ]
14
+ { groupName: 'Impuestos', editing: false },
15
+ { groupName: 'Legal', editing: false },
16
+ { groupName: 'Datos Maestros', editing: false },
17
+ ],
18
+ token:"eyJraWQiOiJkQWJkZCtlclwvTlwveVRQUWNvUlVyOCtrNUd2M1hMM2N1MWUzQ09zWExVRnc9IiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiIxZmFjNjY2Ny1hMDMzLTQ1NjAtOWU5ZC01MTQwMDc2MmI2MWYiLCJjb2duaXRvOmdyb3VwcyI6WyJ1c3VhcmlvX2NvbnRlbnRvaCJdLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiaXNzIjoiaHR0cHM6XC9cL2NvZ25pdG8taWRwLnVzLWVhc3QtMS5hbWF6b25hd3MuY29tXC91cy1lYXN0LTFfWE1aUWRxa0dqIiwicGhvbmVfbnVtYmVyX3ZlcmlmaWVkIjpmYWxzZSwiY29nbml0bzp1c2VybmFtZSI6IjFmYWM2NjY3LWEwMzMtNDU2MC05ZTlkLTUxNDAwNzYyYjYxZiIsImNvZ25pdG86cm9sZXMiOlsiYXJuOmF3czppYW06Ojg5ODY3MDIzMjgwNzpyb2xlXC9jb250ZW50b2gtZGV2LXVzLWVhc3QtMS1sYW1iZGFSb2xlIl0sImF1ZCI6IjVhYzh0cGdzNmdic3ExM2ZydnJwaWVlcDQwIiwiZXZlbnRfaWQiOiI4ZGIyZjdhZS01ZGFlLTQ3NDAtOGRiYS04YWYzYzQyNmIyOTkiLCJ0b2tlbl91c2UiOiJpZCIsImF1dGhfdGltZSI6MTcwMzc4Mzk0NywibmFtZSI6IlJhZGlvc2NoYWNrIE9uYm9hcmRpbmciLCJwaG9uZV9udW1iZXIiOiIrNTIxMjM0NTY3ODk4IiwiZXhwIjoxNzAzNzg3NTQ3LCJpYXQiOjE3MDM3ODM5NDcsImVtYWlsIjoicmFkaW9zaGFja2Ryb3BzaGlwQGFsbGZyZWVtYWlsLm5ldCJ9.kE0DTZhG3QNJCcVACjWQd4nm-QQKRU9n2jHwC9XtNC9H3Xz7T2F80qxcOUkaOU1IwuJLhxThzpJ9rMKS5XgyjSz_SO7nUQZFY4_vLXgmVowaV798kXRpP5uuUVPJ0b07BMjw12_k0QLeOiAfs4gP4micwedD8ItmsxfjJvv6OPir5NX0KgBjgd5OSlCafgH72yZX8SNmiCyzZkQIEO0MNLwEiIm2COgu4MwvFd73CnlJYYQa-WjCnhB35jgoc8gLpFUfBjgpMUSNRZU2Ndzt9CNuQ6he6RwsVmteMgm0e2Fyn_viRhOsMMxbP8wDXnA9pXwZHB2P-DqXYKhC4blsVA"
18
19
  }
@@ -1,160 +1,323 @@
1
- import React, { useState, useEffect } from 'react';
2
- import { Container } from './styles';
3
- import { Button } from '@mui/material';
4
- import { GroupRow } from './styles';
5
- import { ButtonV2 } from '../../atoms/ButtonV2';
6
- import trash from '../../../assets/images/Icons/trash.svg';
7
- import undo from '../../../assets/images/Icons/undo.svg';
8
- import { Modal } from '../../organisms/Modal';
9
-
10
- export const EditGroup = ({ groups: initialGroups }) => {
11
- const [groups, setGroups] = useState(initialGroups);
1
+ import React, { useState, useEffect, useReducer, useRef } from "react";
2
+ import { Container } from "./styles";
3
+ import { Button } from "@mui/material";
4
+ import { GroupRow } from "./styles";
5
+ import { ButtonV2 } from "../../atoms/ButtonV2";
6
+ import trash from "../../../assets/images/Icons/trash.svg";
7
+ import edit from "../../../assets/images/Icons/edit.svg";
8
+ import close from "../../../assets/images/Icons/close.svg";
9
+ import save from "../../../assets/images/Icons/save.svg";
10
+ import { Modal } from "../../organisms/Modal";
11
+ import axios from "axios";
12
+
13
+ const reducerGroups = (state, action) => {
14
+ let { values } = state;
15
+ switch (action.type) {
16
+ case "init":
17
+ return { ...state, values: action.payload };
18
+ case "addGroup":
19
+ values = [...values, action.group];
20
+ return { ...state, values };
21
+ case "updateGroup":
22
+ values[action.payload.index][action.payload.property] =
23
+ action.payload.value;
24
+ return { ...state, values };
25
+ case "deleteGroup":
26
+ values = values.map((item) =>
27
+ item.groupId !== action.payload.id ? item : { ...item, isDeleted: true }
28
+ );
29
+ return { ...state, values };
30
+ default:
31
+ return state;
32
+ }
33
+ };
34
+
35
+ export const EditGroup = ({ token }) => {
36
+ const [groups, setGroups] = useState([]);
37
+ const [state, dispatch] = useReducer(reducerGroups, {});
12
38
  const [isMoreThanTenGroups, setIsMoreThanTenGroups] = useState(false);
13
39
  const [editingIndex, setEditingIndex] = useState(null);
14
40
  const [deletingIndex, setDeletingIndex] = useState(null);
15
- const [showUndoButton, setShowUndoButton] = useState(false);
16
41
  const [deletedRows, setDeletedRows] = useState([]);
42
+ const [hoveredIndex, setHoveredIndex] = useState(null);
43
+ const [isEditingList, setIsEditingList] = useState([]);
44
+ const [newGroup, setNewGroup] = useState(false);
45
+ const [currentEditIndex, setCurrentEditIndex] = useState(null);
46
+ const [inputValue, setInputValue] = useState([]);
17
47
  const [modalData, setModalData] = useState({
18
48
  show: false,
19
- title: 'Actualización completa',
20
- message: '',
21
- icon: 'success',
49
+ title: "Actualización completa",
50
+ message: "",
51
+ icon: "success",
22
52
  });
23
53
 
54
+ const modalRef = useRef();
55
+
24
56
  useEffect(() => {
25
- console.log('Se eliminaron datos');
26
57
  }, [groups]);
27
58
 
28
- const handleAddGroup = () => {
29
- if (groups.length < 20) {
30
- setGroups([...groups, { text: '', editing: true }]);
31
- setIsMoreThanTenGroups(groups.length + 1 > 10);
59
+ useEffect(() => {
60
+ loadData();
61
+ }, []);
62
+
63
+ const loadData = async () => {
64
+ try {
65
+ const response = await axios.post(
66
+ `${process.env.REACT_APP_GROUPS_ENDPOINT}/get`,
67
+ {},
68
+ {
69
+ headers: {
70
+ Authorization: sessionStorage.getItem("jwt"),
71
+ },
72
+ }
73
+ );
74
+
75
+ const receivedGroups = JSON.parse(response.data.body).groups;
76
+ const groupsArray = [];
77
+ receivedGroups.forEach(({ id, name, retailer_id }) => {
78
+ groupsArray.push({
79
+ groupId: id,
80
+ groupName: name || null,
81
+ retailerId: retailer_id || null,
82
+ });
83
+ });
84
+ setGroups(groupsArray);
85
+
86
+ dispatch({ type: "init", payload: groupsArray });
87
+ } catch (error) {
88
+ console.error("Error al obtener grupos:", error);
32
89
  }
33
90
  };
34
91
 
35
- const handleEditGroup = (index) => {
36
- setEditingIndex(index);
37
- };
92
+ const AddGroup = async (index, concatenatedValue) => {
93
+ try {
94
+ const response = await axios.post(
95
+ `${process.env.REACT_APP_GROUPS_ENDPOINT}/create`,
96
+ {
97
+ groupName: concatenatedValue,
98
+ },
99
+ {
100
+ headers: {
101
+ Authorization: token,
102
+ },
103
+ }
104
+ );
38
105
 
39
- const handleDeleteGroup = (index) => {
40
- setDeletingIndex(index);
41
- const updatedGroups = groups.map((group, i) =>
42
- i === index ? { ...group, isDeleted: true } : group
43
- );
106
+ const createdGroup = response.data.body;
107
+ dispatch({ type: "addGroup", payload: createdGroup });
108
+ setEditingIndex(null);
109
+ setInputValue([]);
110
+ setIsEditingList((prevList) => {
111
+ const newList = [...prevList];
112
+ newList[index] = false;
113
+ return newList;
114
+ });
115
+ setCurrentEditIndex(null);
116
+ loadData();
117
+ } catch (error) {
118
+ console.error("Error al agregar grupo:", error);
119
+ }
120
+ };
44
121
 
45
- setGroups(updatedGroups);
46
- setDeletedRows((prev) => [...prev, index]);
47
- setShowUndoButton(true);
122
+ const handleUpdateGroup = async (index, groupId, updatedGroupName) => {
123
+ try {
124
+ const response = await axios.post(
125
+ `${process.env.REACT_APP_GROUPS_ENDPOINT}/update?id=${groupId}&groupName=${updatedGroupName}`,
126
+ {},
127
+ {
128
+ headers: {
129
+ Authorization: token,
130
+ },
131
+ }
132
+ );
133
+ const updatedData = response.data.body;
134
+ dispatch({
135
+ type: "updateGroup",
136
+ payload: {
137
+ index,
138
+ property: "groupName",
139
+ value: updatedData.groupName,
140
+ },
141
+ });
142
+ setEditingIndex(null);
143
+ setInputValue([]);
144
+ setIsEditingList((prevList) => {
145
+ const newList = [...prevList];
146
+ newList[index] = false;
147
+ return newList;
148
+ });
149
+ setCurrentEditIndex(null);
150
+ loadData();
151
+ } catch (error) {
152
+ console.error("Error al actualizar grupo:", error);
153
+ }
48
154
  };
49
155
 
50
- const handleUndoEdit = (index) => {
51
- setDeletingIndex(null);
156
+ const deleteGroup = async (groupId) => {
157
+ try {
158
+ const response = await axios.post(
159
+ `${process.env.REACT_APP_GROUPS_ENDPOINT}/delete?id=${groupId}`,
160
+ {},
161
+ {
162
+ headers: {
163
+ Authorization: token,
164
+ },
165
+ }
166
+ );
167
+ dispatch({
168
+ type: "deleteGroup",
169
+ payload: { id: groupId },
170
+ });
171
+ loadData();
172
+ } catch (error) {
173
+ console.error("Error al borrar grupo:", error);
174
+ }
175
+ };
52
176
 
53
- const updatedGroups = groups.map((group, i) =>
54
- i === index ? { ...group, isDeleted: false } : group
55
- );
177
+ const handleEditButtonClick = (index) => {
178
+ if (isEditingList[index]) {
179
+ handleSaveChanges(index);
180
+ } else {
181
+ setIsEditingList((prevList) => {
182
+ const newList = [...prevList];
183
+ newList[index] = true;
184
+ return newList;
185
+ });
186
+ setEditingIndex(index);
187
+ setInputValue(groups[index].groupName);
188
+ setNewGroup(groups[index].groupId);
189
+ setCurrentEditIndex(index);
190
+ }
191
+ };
56
192
 
57
- setGroups(updatedGroups);
58
- setDeletedRows((prev) => prev.filter((rowIndex) => rowIndex !== index));
59
- setShowUndoButton(false);
193
+ const handleDeleteButtonClick = async (groupId) => {
194
+ await deleteGroup(groupId);
60
195
  };
61
196
 
62
- const handleSaveChanges = () => {
63
- const updatedGroups = groups.filter((group, index) => !deletedRows.includes(index));
64
- setGroups(updatedGroups);
65
- setModalData({
66
- show: true,
67
- className: 'modal-save',
68
- message:
69
- 'El cambio de grupo fue aplicado correctamente a los usuarios seleccionados.',
70
- icon: 'success',
71
- buttons: [
72
- <ButtonV2
73
- key="btn-Aceptar"
74
- type="pink"
75
- label="Aceptar"
76
- size={12}
77
- onClick={() => setModalData((prev) => ({ ...prev, show: false }))}
78
- />,
79
- ],
197
+ const handleInputChange = (value, index) => {
198
+ setInputValue((prevInputValue) => prevInputValue + value);
199
+
200
+ setGroups((prevGroups) => {
201
+ const updatedGroups = [...prevGroups];
202
+ if (index !== undefined) {
203
+ updatedGroups[index] = { ...updatedGroups[index], groupName: value };
204
+ }
205
+ return updatedGroups;
80
206
  });
81
- console.log('Guardando cambios:', groups);
82
- setShowUndoButton(false);
83
- setEditingIndex(null);
84
207
  };
85
208
 
86
- const handleInputChange = (index, value) => {
87
- const updatedGroups = [...groups];
88
- updatedGroups[index].text = value;
89
- setGroups(updatedGroups);
209
+ const handleAddButtonClick = () => {
210
+ const isAnyGroupEditing = isEditingList.some((editing) => editing);
211
+ if (!isAnyGroupEditing && groups.length < 20) {
212
+ setIsEditingList((prevList) => {
213
+ const newList = [...prevList];
214
+ newList[groups.length] = true;
215
+ return newList;
216
+ });
217
+ setEditingIndex(groups.length);
218
+ const nuevoGrupo = {
219
+ groupName: inputValue,
220
+ isEditing: true,
221
+ };
222
+ setGroups([...groups, nuevoGrupo]);
223
+ setIsMoreThanTenGroups(groups.length + 1 > 10);
224
+ setNewGroup(undefined);
225
+ setCurrentEditIndex(groups.length);
226
+ }
227
+ };
228
+
229
+ const handleSaveChanges = (index) => {
230
+ const concatenatedValue = groups[index].groupName;
231
+ if (newGroup !== undefined) {
232
+ handleUpdateGroup(index, newGroup, concatenatedValue);
233
+ } else {
234
+ AddGroup(index,concatenatedValue);
235
+ }
90
236
  };
91
237
 
238
+ const handleCloseModal = (e) => {
239
+ if (modalRef.current && !modalRef.current.contains(e.target)) {
240
+ setEditingIndex(null);
241
+ }
242
+ };
243
+
244
+ useEffect(() => {
245
+ document.addEventListener("mousedown", handleCloseModal);
246
+
247
+ return () => {
248
+ document.removeEventListener("mousedown", handleCloseModal);
249
+ };
250
+ }, []);
251
+
92
252
  return (
93
- <Container>
94
- <div className={`contentModal`}>
95
- <h2 className="title-edit">Editar grupos</h2>
253
+ <Container ref={modalRef}>
254
+ <div className={`contentModal`}>
255
+ <div className="header">
256
+ <h2 className="title-edit">Editar grupos</h2>
257
+ <Button className={`circular-button close-button`} onClick={handleCloseModal}>
258
+ <img src={close} alt="close icon" />
259
+ </Button>
260
+ </div>
96
261
  <p className="details-edit">
97
262
  Agrega, edita y borra. Luego guarda los cambios.
98
263
  </p>
99
- <div className={`${isMoreThanTenGroups ? 'table-groups-max' : 'table-groups-edit'}`}>
264
+ <div
265
+ className={`${
266
+ isMoreThanTenGroups ? "table-groups-max" : "table-groups-edit"
267
+ }`}
268
+ >
100
269
  {groups.map((group, index) => (
101
270
  <GroupRow
102
- key={index}
271
+ key={group.groupId}
103
272
  editing={editingIndex === index}
104
- hasText={Boolean(group.text)}
105
273
  deleting={deletingIndex === index}
106
- onClick={() => handleEditGroup(index)}
107
- isDeleted={group.isDeleted}
274
+ onMouseEnter={() => setHoveredIndex(index)}
275
+ onMouseLeave={() => setHoveredIndex(null)}
276
+ className={`group-row ${isEditingList[index] ? "editing" : ""}`}
108
277
  >
109
278
  <input
110
279
  key={index}
111
- className={`input-group ${
112
- group.isDeleted ? 'deleted' : 'original'
113
- }`}
114
- value={group.text}
115
- onChange={(e) => handleInputChange(index, e.target.value)}
280
+ className={`input-group`}
281
+ placeholder="Escribe el nombre del grupo"
282
+ value={index !== undefined ? group.groupName : inputValue}
283
+ onChange={(e) => handleInputChange(e.target.value, index)}
284
+ disabled={!isEditingList[index]}
285
+ autoFocus={isEditingList[index] && editingIndex === index}
116
286
  />
117
- <Button
118
- className="circular-button"
119
- onClick={() => {
120
- handleDeleteGroup(index);
121
- }}
122
- style={{
123
- display:
124
- showUndoButton && deletingIndex === index ? 'none' : 'block',
125
- }}
126
- >
127
- <img src={trash} alt="trash icon" />
128
- </Button>
129
- {editingIndex === index && (
287
+ { currentEditIndex === index ? (
130
288
  <Button
131
- className="circular-button"
132
- onClick={() => handleUndoEdit(index)}
133
- style={{
134
- display:
135
- showUndoButton && deletingIndex === index
136
- ? 'block'
137
- : 'none',
138
- }}
289
+ className={`circular-button save-button visible`}
290
+ onClick={() => handleSaveChanges(index)}
139
291
  >
140
- <img src={undo} alt="undo icon" />
292
+ <img src={save} alt="save update icon" />
141
293
  </Button>
294
+ ) : (
295
+ <>
296
+ <Button
297
+ className={`circular-button edit-button ${
298
+ hoveredIndex === index ? "visible" : ""
299
+ }`}
300
+ onClick={() => handleEditButtonClick(index)}
301
+ >
302
+ <img src={edit} alt="edit icon" />
303
+ </Button>
304
+ <Button
305
+ className={`circular-button delete-button ${
306
+ hoveredIndex === index ? "visible" : ""
307
+ }`}
308
+ onClick={() => handleDeleteButtonClick(group.groupId)}
309
+ >
310
+ <img src={trash} alt="trash icon" />
311
+ </Button>
312
+ </>
142
313
  )}
143
314
  </GroupRow>
144
315
  ))}
145
316
  </div>
146
317
  <div className="container-save-add">
147
- <Button className="button-add" onClick={() => handleAddGroup()}>
318
+ <Button className="button-add" onClick={() => handleAddButtonClick()}>
148
319
  + Agregar Grupo
149
320
  </Button>
150
- <ButtonV2
151
- key="btn-guardar"
152
- type="pink"
153
- borderType="oval"
154
- label="Guardar"
155
- size={12}
156
- onClick={() => handleSaveChanges()}
157
- />
158
321
  </div>
159
322
  <Modal
160
323
  {...modalData}
@@ -1,18 +1,61 @@
1
- import styled from "styled-components";
1
+ import styled, {keyframes} from "styled-components";
2
2
  import { GlobalColors, FontFamily } from "../../../global-files/variables";
3
3
 
4
+ const fadeIn = keyframes`
5
+ from {
6
+ opacity: 0;
7
+ }
8
+ to {
9
+ opacity: 1;
10
+ }
11
+ `;
12
+
4
13
  export const Container = styled.div`
5
14
  width: 100%;
6
15
  height: 100%;
7
16
  overflow: auto;
8
17
  display: grid;
9
18
  place-items: center;
19
+ .header {
20
+ width: 100%;
21
+ display: flex;
22
+ justify-content: space-between;
23
+ }
24
+ .close-button {
25
+ min-width: 24px;
26
+ height: 24px;
27
+ background-color: transparent;
28
+ border: none;
29
+ border-radius: 50%;
30
+ cursor: pointer;
31
+ transition: background-color 0.3s ease, opacity 0.3s ease;
32
+ display: flex;
33
+ justify-content: center;
34
+ align-items: center;
35
+ -webkit-filter: grayscale(100%);
36
+ filter: grayscale(100%);
37
+ opacity:0.4;
38
+ img {
39
+ width: 10px;
40
+ height: 10px;
41
+ }
42
+
43
+ &:hover {
44
+ background-color: ${GlobalColors.blue_light};
45
+ -webkit-filter: grayscale(0);
46
+ filter: grayscale(0);
47
+ opacity:1;
48
+ }
49
+ }
10
50
  .contentModal {
51
+ position: absolute;
52
+ top: 10%;
53
+ z-index: 20;
11
54
  width: fit-content;
12
55
  max-width: 80%;
13
56
  min-width: 80px;
14
57
  height: fit-content;
15
- max-height: 90%;
58
+ max-height: 100%;
16
59
  min-height: 120px;
17
60
  display: flex;
18
61
  flex-direction: column;
@@ -62,6 +105,11 @@ export const Container = styled.div`
62
105
  color: ${GlobalColors.magenta_s2};
63
106
  text-transform: capitalize;
64
107
  border: none;
108
+ background: transparent;
109
+ border-radius: 20px;
110
+ &:hover {
111
+ background-color: ${GlobalColors.blue_light};
112
+ }
65
113
  }
66
114
  .table-groups-edit {
67
115
  width: 100%;
@@ -69,11 +117,11 @@ export const Container = styled.div`
69
117
  border: 1px solid ${GlobalColors.gray_light};
70
118
  border-radius: 5px;
71
119
  }
72
- .table-groups-max{
120
+ .table-groups-max {
73
121
  min-width: 288px;
74
122
  border: 1px solid ${GlobalColors.gray_light};
75
123
  border-radius: 5px;
76
- display:grid;
124
+ display: grid;
77
125
  grid-template-columns: repeat(2, 1fr);
78
126
  }
79
127
  .modal-save {
@@ -97,19 +145,63 @@ export const GroupRow = styled.div`
97
145
  letter-spacing: 0em;
98
146
  text-align: left;
99
147
  text-decoration: none;
100
- background: ${({ isDeleted }) => (isDeleted ? "#FF7373" : "transparent")};
101
148
  border-bottom: 1px solid ${GlobalColors.gray_light};
149
+ padding: 0 8px 0 0;
102
150
  input {
103
- background: ${({ isDeleted }) => (isDeleted ? "#FF7373" : "transparent")};
104
- color: ${({ isDeleted }) =>
105
- isDeleted ? GlobalColors.white : GlobalColors.gray};
106
- text-decoration: ${({ isDeleted }) =>
107
- isDeleted ? "line-through" : "none"};
151
+ width:100%;
152
+ min-width: 215px;
153
+ background: transparent;
154
+ color: ${GlobalColors.gray};
108
155
  border: 0;
156
+ font-size: 12px;
157
+ font-family:${FontFamily.RobotoRegular}, sans-serif;
109
158
  padding: 5px 20px;
159
+ ::placeholder {
160
+ color: #CBCBCB;
161
+ }
110
162
  }
111
163
 
112
164
  input:focus {
113
165
  border: 0;
114
166
  }
167
+ &.editing {
168
+ background-color: ${GlobalColors.blue_light};
169
+ color: black;
170
+ input{
171
+ color: ${GlobalColors.black};
172
+ }
173
+ }
174
+
175
+ .save-button,
176
+ .edit-button,
177
+ .delete-button {
178
+ min-width: 24px;
179
+ height: 24px;
180
+ background-color: transparent;
181
+ border: none;
182
+ border-radius: 50%;
183
+ cursor: pointer;
184
+ transition: background-color 0.3s ease, opacity 0.3s ease;
185
+ display: flex;
186
+ justify-content: center;
187
+ align-items: center;
188
+
189
+ img {
190
+ width: 12px;
191
+ height: 12px;
192
+ }
193
+
194
+ &:hover {
195
+ background-color: ${GlobalColors.blue_light};
196
+ }
197
+ }
198
+ .edit-button,
199
+ .delete-button {
200
+ display: none;
201
+ }
202
+
203
+ .visible {
204
+ display: flex;
205
+ animation: ${fadeIn} 0.3s ease-in-out forwards;
206
+ }
115
207
  `;