@imj_media/tareas 0.0.7

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.
Files changed (114) hide show
  1. package/.env.template +8 -0
  2. package/.storybook/main.ts +26 -0
  3. package/.storybook/preview.ts +15 -0
  4. package/LICENSE.md +21 -0
  5. package/README.md +50 -0
  6. package/core/actions/get_all_users.action.ts +16 -0
  7. package/core/actions/get_salesman_response.action.ts +16 -0
  8. package/core/actions/get_tasks_project.action.ts +62 -0
  9. package/core/actions/get_tasks_response.action.ts +56 -0
  10. package/eslint.config.js +28 -0
  11. package/global.d.ts +3 -0
  12. package/infraestructure/interfaces/salesmans-obp-response.ts +43 -0
  13. package/infraestructure/interfaces/salesmans-obp.ts +4 -0
  14. package/infraestructure/interfaces/tasks-campania-response.ts +118 -0
  15. package/infraestructure/interfaces/tasks-campania.ts +26 -0
  16. package/infraestructure/interfaces/tasks-kanban-general.ts +25 -0
  17. package/infraestructure/interfaces/tasks-reponse.ts +111 -0
  18. package/infraestructure/interfaces/teams-response.ts +7 -0
  19. package/infraestructure/interfaces/teams.ts +5 -0
  20. package/infraestructure/interfaces/users-obp-response.ts +52 -0
  21. package/infraestructure/interfaces/users.ts +5 -0
  22. package/infraestructure/mappers/all-users-obp.ts +12 -0
  23. package/infraestructure/mappers/campaign-tasks.ts +35 -0
  24. package/infraestructure/mappers/kanban-tasks.ts +35 -0
  25. package/infraestructure/mappers/salesmans-obp.ts +11 -0
  26. package/infraestructure/mappers/teams.ts +12 -0
  27. package/package.json +61 -0
  28. package/postcss.config.js +6 -0
  29. package/src/components/atoms/Avatar.tsx +14 -0
  30. package/src/components/atoms/Comment.tsx +33 -0
  31. package/src/components/atoms/InputSearch.tsx +40 -0
  32. package/src/components/atoms/SkeletonCard.tsx +17 -0
  33. package/src/components/atoms/TabButton.tsx +16 -0
  34. package/src/components/atoms/TooltipUser.tsx +26 -0
  35. package/src/components/atoms/index.ts +2 -0
  36. package/src/components/index.ts +3 -0
  37. package/src/components/kanban-campania/DoneBoard.tsx +12 -0
  38. package/src/components/kanban-campania/KanbanCampania.tsx +39 -0
  39. package/src/components/kanban-campania/ToDoBoard.tsx +12 -0
  40. package/src/components/kanban-campania/WorkingBoard.tsx +13 -0
  41. package/src/components/kanban-campania/filters.ts +46 -0
  42. package/src/components/kanban-campania/index.ts +3 -0
  43. package/src/components/kanban-general/DoneBoard.tsx +12 -0
  44. package/src/components/kanban-general/KanbanGeneral.tsx +40 -0
  45. package/src/components/kanban-general/ToDoBoard.tsx +12 -0
  46. package/src/components/kanban-general/WorkingBoard.tsx +13 -0
  47. package/src/components/kanban-general/filters.ts +58 -0
  48. package/src/components/kanban-general/index.ts +3 -0
  49. package/src/components/layout/FilterButton.tsx +50 -0
  50. package/src/components/layout/FilterContent.tsx +70 -0
  51. package/src/components/layout/IndexComponents.tsx +32 -0
  52. package/src/components/lista-campania/ChildTask.tsx +22 -0
  53. package/src/components/lista-campania/Date.tsx +30 -0
  54. package/src/components/lista-campania/ListaCampania.tsx +21 -0
  55. package/src/components/lista-campania/ParentTask.tsx +57 -0
  56. package/src/components/molecules/AllComments.tsx +78 -0
  57. package/src/components/molecules/ButtonAssignUsers.tsx +175 -0
  58. package/src/components/molecules/DependentTasks.tsx +64 -0
  59. package/src/components/molecules/Tabs.tsx +39 -0
  60. package/src/components/molecules/index.ts +1 -0
  61. package/src/components/organisms/Board.tsx +87 -0
  62. package/src/components/organisms/Checkbox.tsx +45 -0
  63. package/src/components/organisms/DetailsTask.tsx +286 -0
  64. package/src/components/organisms/TabDetailsTask.tsx +39 -0
  65. package/src/components/organisms/Task.tsx +176 -0
  66. package/src/components/organisms/index.ts +2 -0
  67. package/src/components/tasks/PriorityButton.tsx +79 -0
  68. package/src/components/templates/Layout.tsx +84 -0
  69. package/src/components/templates/TableList/components/TableList.scss +270 -0
  70. package/src/components/templates/TableList/components/TableList.tsx +239 -0
  71. package/src/components/templates/TableList/components/index.tsx +1 -0
  72. package/src/constants/colors.ts +64 -0
  73. package/src/constants/gaps.ts +8 -0
  74. package/src/constants/paddings.ts +8 -0
  75. package/src/constants/shadows.ts +5 -0
  76. package/src/context/filtersLayout.context.tsx +118 -0
  77. package/src/context/kanbanCampania.context.tsx +50 -0
  78. package/src/context/useApis.context.tsx +47 -0
  79. package/src/context/userLog.context.tsx +50 -0
  80. package/src/env.d.ts +10 -0
  81. package/src/functions/taskCalculations.tsx +818 -0
  82. package/src/hooks/useAllUsers.ts +18 -0
  83. package/src/hooks/useCheckTask.tsx +15 -0
  84. package/src/hooks/useComerciales.ts +58 -0
  85. package/src/hooks/useDoneTasks.ts +90 -0
  86. package/src/hooks/useElementPosition.ts +34 -0
  87. package/src/hooks/useFunctionsTasks.ts +57 -0
  88. package/src/hooks/useNormalizedData.ts +36 -0
  89. package/src/hooks/useTeams.ts +19 -0
  90. package/src/hooks/useToDoTasks.ts +89 -0
  91. package/src/hooks/useWorkingTasks.ts +85 -0
  92. package/src/index.css +55 -0
  93. package/src/index.ts +2 -0
  94. package/src/index.tsx +1 -0
  95. package/src/pages/App.tsx +42 -0
  96. package/src/pages/NoAccessToken.tsx +20 -0
  97. package/src/pages/NoUser.tsx +20 -0
  98. package/src/stories/AppTasks.stories.tsx +36 -0
  99. package/src/stories/Table.stories.tsx +160 -0
  100. package/src/types/index.ts +107 -0
  101. package/src/types/interfaces.ts +67 -0
  102. package/src/types/layout.types.ts +30 -0
  103. package/src/utils/filters.functions.ts +17 -0
  104. package/src/utils/formats.ts +33 -0
  105. package/src/utils/functionsStorybook.tsx +0 -0
  106. package/src/utils/inputs.functions.ts +25 -0
  107. package/src/utils/tanstack.functions.ts +19 -0
  108. package/src/utils/utils.ts +12 -0
  109. package/src/vite-env.d.ts +1 -0
  110. package/tailwind.config.js +31 -0
  111. package/tsconfig.app.json +26 -0
  112. package/tsconfig.json +7 -0
  113. package/tsconfig.node.json +24 -0
  114. package/vite.config.ts +16 -0
@@ -0,0 +1,79 @@
1
+ import { useState } from "react";
2
+ import ReactDOM from "react-dom";
3
+ import { Icons } from "@imj_media/tasks-modules"
4
+ import { COLORS } from "../../constants/colors";
5
+ import useFunctionsTasks from "../../hooks/useFunctionsTasks";
6
+ interface IPriorityButtonProps {
7
+ priority:number;
8
+ id:number;
9
+ }
10
+ const PriorityButton = ({priority, id}:IPriorityButtonProps) => {
11
+ const { updateTask } = useFunctionsTasks()
12
+ const buttonId = Math.random().toString(36);
13
+ const [position,setPosition] = useState<{x:number,y:number}|null>(null)
14
+
15
+ const getColor = (priority:number)=>{
16
+ const priorityColors = {
17
+ 0:COLORS.primary.regular,
18
+ 1:COLORS.success.regular,
19
+ 2:COLORS.warning.regular,
20
+ 3:COLORS.danger.regular
21
+ }[priority]
22
+
23
+ return priorityColors
24
+ }
25
+
26
+ const OptionsPortal = ()=>{
27
+ if(!position) return null;
28
+
29
+ const OptionButton = ({priority,text}:{priority:number,text:string})=>{
30
+ return (
31
+ <button onClick={()=>{
32
+ updateTask({id, data: {prioridad:priority}, user: 272})
33
+ setPosition(null)
34
+ }} className="flex gap-m items-center px-l py-s hover:bg-primary-light">
35
+ <Icons icon="flag" size="xs" strokeWidth={3} color={getColor(priority)}/>
36
+ <p className="text-sm" style={{color:getColor(priority)}}>{text}</p>
37
+ </button>
38
+ )
39
+ }
40
+
41
+ return ReactDOM.createPortal(
42
+ <div onBlur={()=>{ setPosition(null) }} id={`${buttonId}-options`} style={{top: `${position.y + 5}px`, left: `${position.x + 5}px`}} className={`absolute h-fit p-m flex flex-col gap-2 bg-bg-card rounded-xl shadow-lg
43
+ w-max`}>
44
+ <OptionButton priority={0} text="Baja"/>
45
+ <OptionButton priority={1} text="Normal"/>
46
+ <OptionButton priority={2} text="Media"/>
47
+ <OptionButton priority={3} text="Alta"/>
48
+ </div>,
49
+ document.body
50
+ )
51
+ }
52
+
53
+ return (
54
+ <div className="relative h-[22px]">
55
+ <label
56
+ onBlur={()=>{ setPosition(null) }}
57
+ htmlFor={buttonId}
58
+ className="flex items-center gap-2 cursor-pointer active:opacity-50"
59
+ >
60
+ <Icons icon="flag" size="xs" strokeWidth={3} color={getColor(priority)}/>
61
+ </label>
62
+
63
+ {/* Button to open the options */}
64
+ <button
65
+ id={buttonId}
66
+ onClick={(e)=>{
67
+ if(!position) setPosition({x:e.clientX,y:e.clientY})
68
+ else setPosition(null);
69
+ }}
70
+ className="hidden"
71
+ />
72
+
73
+ {/* Portal options */}
74
+ <OptionsPortal/>
75
+ </div>
76
+ )
77
+ }
78
+
79
+ export default PriorityButton
@@ -0,0 +1,84 @@
1
+ import { useEffect, useRef, useState } from "react";
2
+ //* components
3
+ import Tabs from "../molecules/Tabs"
4
+ import FilterButton from "../layout/FilterButton";
5
+ import FilterContent from "../layout/FilterContent";
6
+ import IndexComponents from "../layout/IndexComponents";
7
+ //* functions
8
+ import { debounce } from "../../utils/inputs.functions";
9
+ //* context
10
+ import { FiltersLayoutProvider } from "../../context/filtersLayout.context";
11
+ //* types
12
+ import { TPaths, TTab } from "../../types/layout.types";
13
+
14
+ const Layout = ({path}: { path: TPaths }) => {
15
+ const ComponentLayout = ()=>{
16
+ const [activeTab, setActiveTab] = useState<TTab>("kanban");
17
+ //TODO: add the filter by text
18
+ const [_filterByText, setFilterByText] = useState<string>("");
19
+ const filterRefs = useRef<HTMLDivElement>(null);
20
+
21
+ //* set the active tab to kanban
22
+ useEffect( () => { setActiveTab("kanban") }, [ path ] )
23
+
24
+ //* get the title of the page
25
+ const getTitle = (path: TPaths) => {
26
+ return {
27
+ "kanban-general": "Kanban General",
28
+ "lista-campanias": "Campanias",
29
+ "kanban-campania": "Kanban de Campania"
30
+ }[path];
31
+ }
32
+
33
+ //* get the menus with tabs
34
+ const menusWithTabs = [ "lista-campanias", "kanban-campania" ];
35
+
36
+ //* get the tabs of the menu
37
+ const tabs: {[key:string]: TTab[]} = {
38
+ "lista-campanias": ["lista", "gantt"],
39
+ "kanban-campania": ["kanban", "lista", "gantt"]
40
+ }
41
+
42
+ return (
43
+ <div className="bg-bg-card p-m rounded-lg border border-border-card flex flex-col gap-m w-full h-full min-h-[100%] relative overflow-hidden">
44
+ <div className="w-full justify-between flex items-end border-b border-border-card pb-m px-l flex-wrap gap-l">
45
+ <div className="flex gap-xl">
46
+ <div> <h2 className="text-texts font-medium">{getTitle(path as any)}</h2> </div>
47
+ {menusWithTabs.includes(path) &&
48
+ <Tabs
49
+ tabs={tabs[path]}
50
+ renderItem={(e: TTab) => { setActiveTab(e) }}
51
+ />
52
+ }
53
+ </div>
54
+ <div className="flex items-center gap-s">
55
+ <input
56
+ onChange={debounce((e:React.ChangeEvent<HTMLInputElement>)=>setFilterByText(e?.target?.value), 1000)}
57
+ type="text"
58
+ placeholder="Buscar"
59
+ className="w-[200px] h-[30px] border-none bg-bg-card shadow-input border border-border-card rounded-lg px-l "
60
+ />
61
+ <FilterButton filterChildren={filterRefs as React.MutableRefObject<HTMLDivElement>}>
62
+ <div ref={filterRefs} className="w-max max-w-[400px] h-fit bg-bg-card shadow-lg rounded-lg p-l">
63
+ <FilterContent />
64
+ </div>
65
+ </FilterButton>
66
+ </div>
67
+ </div>
68
+ <div className="overflow-auto">
69
+ <IndexComponents path={path} tab={activeTab}/>
70
+ </div>
71
+ </div>
72
+ )
73
+ }
74
+
75
+
76
+ //* return the component with the layout filters context
77
+ return (
78
+ <FiltersLayoutProvider>
79
+ <ComponentLayout />
80
+ </FiltersLayoutProvider>
81
+ )
82
+ }
83
+
84
+ export default Layout;
@@ -0,0 +1,270 @@
1
+ //* Primary
2
+ $primary_light: #E7E9F2;
3
+ $primary_dark: #334990;
4
+ $primary_medium: #DAE2EC;
5
+ $primary_regular: #4464C3;
6
+
7
+ //* ProgressBar
8
+ $orange_regular: #DC8921;
9
+ $blue_regular: #3658C1;
10
+ $green_regular: #039B59;
11
+
12
+ //* Silver
13
+ $silver_white: #FAFAFA;
14
+ $silver_light: #F5F5F5;
15
+ $silver_dark: #E9E9E9;
16
+ $silver_regular: #EFEFEF;
17
+
18
+ //* Gray
19
+ $gray_light: #D9D9D9;
20
+ $gray_regular: #D1D1D1;
21
+ $gray_dark: #C4C4C4;
22
+
23
+ //* Black
24
+ $black_light: #929292;
25
+ $black_medium: #4F4F4F;
26
+ $black_dark: #131313;
27
+ $black_regular: #252525;
28
+
29
+ $blue_medium: #E1EBF9;
30
+
31
+
32
+ .table-container {
33
+ width: 100%;
34
+ margin: 0 auto;
35
+ padding: 1rem;
36
+ cursor: pointer;
37
+ border-radius: 2%;
38
+ background-color: $silver_white;
39
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);
40
+
41
+ table {
42
+ width: 100%;
43
+ border-spacing: 0;
44
+ border: none;
45
+ background-color: $silver_white;
46
+
47
+ border-radius: 8px;
48
+ overflow: hidden;
49
+ cursor: pointer;
50
+ }
51
+
52
+ thead {
53
+ background-color: $silver_white;
54
+ cursor: pointer;
55
+
56
+ th {
57
+ padding: 16px;
58
+ text-align: left;
59
+ border-bottom: none; // Cambiado de "1px solid #e9ecef" a "none"
60
+ color: $gray_dark;
61
+ font-weight: 600;
62
+ font-size: 10px;
63
+ text-transform: uppercase;
64
+ letter-spacing: 0.5px;
65
+ cursor: pointer;
66
+ transition: background-color 0.2s ease;
67
+
68
+ &:hover {
69
+ background-color: #e9ecef;
70
+ }
71
+
72
+ .sort-icon {
73
+ margin-left: 8px;
74
+ opacity: 0.5;
75
+
76
+ &.active {
77
+ opacity: 1;
78
+ }
79
+ }
80
+ }
81
+ }
82
+
83
+ tbody {
84
+ tr {
85
+ transition: background-color 0.2s ease;
86
+ cursor: pointer;
87
+
88
+ &:hover {
89
+ background-color: $primary_medium;
90
+ }
91
+ }
92
+
93
+ td {
94
+ padding: 12px 16px;
95
+ text-align: left;
96
+ border-bottom: none; // Cambiado de "1px solid #e9ecef" a "none"
97
+ color: #212529;
98
+ font-size: 10px;
99
+ vertical-align: middle;
100
+ cursor: pointer;
101
+
102
+
103
+ .progress-container {
104
+ background-color: #e9ecef;
105
+ border-radius: 4px;
106
+ height: 8px;
107
+ overflow: hidden;
108
+
109
+ .progress-bar {
110
+ height: 100%;
111
+ transition: width 0.3s ease;
112
+
113
+ &.green { background-color: $green_regular; }
114
+ &.blue { background-color: $blue_regular; }
115
+ &.orange { background-color: $orange_regular; }
116
+ }
117
+ }
118
+
119
+ .avatar-container {
120
+ display: flex;
121
+ align-items: center;
122
+ gap: 12px;
123
+
124
+ .avatar {
125
+ width: 28px;
126
+ height: 28px;
127
+ border-radius: 18px;
128
+ display: flex;
129
+ align-items: center;
130
+ justify-content: center;
131
+ background-color: $primary_light;
132
+ color: dark;
133
+ font-weight: 600;
134
+ font-size: 10px!important;
135
+ }
136
+ }
137
+
138
+ .p-dropdown-sm {
139
+ font-size: 12px;
140
+ height: auto;
141
+ /* Elimina estilos como "position" o "z-index" si los hay */
142
+ }
143
+
144
+ .dropdown-container {
145
+ position: relative;
146
+ display: inline-block;
147
+ width: 100%;
148
+
149
+ .dropdown-toggle {
150
+ display: flex;
151
+ align-items: center;
152
+ justify-content: space-between;
153
+ width: 100%;
154
+ padding: 6px 12px;
155
+ font-size: 10px;
156
+ background-color: transparent;
157
+ border: 1px solid $gray_light;
158
+ border-radius: 4px;
159
+ cursor: pointer;
160
+
161
+ &:hover {
162
+ background-color: $silver_light;
163
+ }
164
+ }
165
+
166
+ .dropdown-menu {
167
+ position: absolute;
168
+ top: 100%;
169
+ left: 0;
170
+ z-index: 1000;
171
+ width: 100%;
172
+ padding: 4px 0;
173
+ margin-top: 4px;
174
+ background-color: $silver_white;
175
+ border: 1px solid $gray_light;
176
+ border-radius: 4px;
177
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
178
+
179
+ .dropdown-item {
180
+ display: block;
181
+ width: 100%;
182
+ padding: 6px 12px;
183
+ font-size: 10px;
184
+ color: $black_regular;
185
+ text-align: left;
186
+ background-color: transparent;
187
+ border: none;
188
+ cursor: pointer;
189
+
190
+ &:hover {
191
+ background-color: $primary_light;
192
+ }
193
+ }
194
+ }
195
+ }
196
+ }
197
+ }
198
+
199
+ .pagination {
200
+ margin-top: 1rem;
201
+ display: flex;
202
+ justify-content: center;
203
+ align-items: center;
204
+ gap: 8px;
205
+ padding: 1rem;
206
+ width: 100%;
207
+ height: fit-content;
208
+ background-color: $silver_white;
209
+ font-size: small;
210
+
211
+ button {
212
+ padding: 8px;
213
+ border: none;
214
+ background-color: $silver_white;
215
+ color: #495057;
216
+ border-radius: 50%;
217
+ cursor: pointer;
218
+ transition: all 0.2s ease;
219
+ width: auto;
220
+ height: auto;
221
+ align-items: center;
222
+ align-content: center;
223
+ text-align: center;
224
+ font-size: 7px;
225
+
226
+ &:disabled {
227
+ background-color: $silver_light;
228
+ color: $gray_dark;
229
+ cursor: not-allowed;
230
+ }
231
+
232
+ &:hover:not(:disabled) {
233
+ background-color: $blue_medium;
234
+ border-color: $blue_medium;
235
+ color: $blue_regular;
236
+ }
237
+ }
238
+
239
+ span {
240
+ font-size: 10px;
241
+ color: #6c757d;
242
+ }
243
+ }
244
+
245
+ input[type="checkbox"] {
246
+ width: 16px;
247
+ height: 16px;
248
+ cursor: pointer;
249
+ accent-color: #0d6efd;
250
+ }
251
+
252
+ .table-row {
253
+ transition: background-color 0.2s ease;
254
+
255
+ .table-row:nth-child(odd) {
256
+ background-color: #FAFAFA;
257
+ }
258
+
259
+ .table-row:nth-child(even) {
260
+ background-color: #F5F5F5;
261
+ }
262
+
263
+ &:hover {
264
+ background-color: $blue_medium !important; // Blue medium
265
+ color: white; // Para mejor contraste
266
+ cursor: pointer;
267
+ }
268
+ }
269
+ }
270
+
@@ -0,0 +1,239 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import { Avatar } from 'primereact/avatar';
3
+ import './TableList.scss';
4
+ import { Paginator } from 'primereact/paginator';
5
+ import { normalizeData } from '../../../../hooks/useNormalizedData';
6
+ import { Dropdown } from 'primereact/dropdown';
7
+ import { useApis } from '../../../../context/useApis.context';
8
+
9
+ const TableList = () => {
10
+ const [data, setData] = useState<any[]>([]);
11
+ const [first, setFirst] = useState(0);
12
+ const [rows, setRows] = useState(10); // Número inicial de filas por página
13
+ const [totalRecords, setTotalRecords] = useState(0);
14
+ const [orderBy, setOrderBy] = useState<string>('nombre'); // Estado para el orden
15
+ const { tasks_api } = useApis();
16
+
17
+ const fetchData = async (page: number, pageSize: number) => {
18
+ try {
19
+ const response = await tasks_api.get('/listado_campanias', {
20
+ params: {
21
+ 'pagination[page]': page,
22
+ 'pagination[pageSize]': pageSize,
23
+ orderBy: orderBy, // Agregar orderBy a los parámetros
24
+ },
25
+ });
26
+ const normalizedData = normalizeData(response.data);
27
+ setData(normalizedData);
28
+ setTotalRecords(response.data.meta.total);
29
+ } catch (error) {
30
+ console.error('Error fetching data:', error);
31
+ }
32
+ };
33
+
34
+ useEffect(() => {
35
+ const page = Math.floor(first / rows) + 1;
36
+ fetchData(page, rows);
37
+ }, [first, rows, orderBy]); // Se ejecutará cuando cambien first, rows o orderBy
38
+
39
+ const onPageChange = (event: { first: number; rows: number }) => {
40
+ setFirst(event.first);
41
+ setRows(event.rows);
42
+ };
43
+
44
+ const rowsPerPageOptions = [
45
+ { label: '5', value: 5 },
46
+ { label: '10', value: 10 },
47
+ { label: '15', value: 15 },
48
+ { label: '20', value: 20 },
49
+ ];
50
+
51
+ const onRowsPerPageChange = (e: { value: number }) => {
52
+ if (e.value !== rows) {
53
+ setRows(e.value);
54
+ setFirst(0); // Reinicia la paginación para empezar desde el inicio
55
+ }
56
+ };
57
+
58
+ const handleOrderByChange = (column: string) => {
59
+ setOrderBy((prevOrderBy) => (prevOrderBy === column ? `${column}:desc` : column));
60
+ };
61
+
62
+ const getSortIcon = (column: string) => {
63
+ if (orderBy === column) return '↑↓'; // Ascendente
64
+ if (orderBy === `${column}:desc`) return '↓↑'; // Descendente
65
+ return '↑↓'; // Sin ordenar
66
+ };
67
+
68
+ return (
69
+ <div className={'table-container'}>
70
+ <table
71
+ className={'table'}
72
+ style={{
73
+ borderCollapse: 'collapse',
74
+ width: '100%',
75
+ borderSpacing: '0',
76
+ }}
77
+ >
78
+ <thead>
79
+ <tr>
80
+ <th onClick={() => handleOrderByChange('nombre')}>
81
+ <label style={{ color: '#C4C4C4', fontSize: '10px' }}>
82
+ {getSortIcon('nombre')}
83
+ </label>
84
+ Campaña
85
+ </th>
86
+ <th onClick={() => handleOrderByChange('inicia')}>
87
+ <label style={{ color: '#C4C4C4', fontSize: '10px' }}>
88
+ {getSortIcon('inicia')}
89
+ </label>
90
+ Fecha Inicio
91
+ </th>
92
+ <th onClick={() => handleOrderByChange('termina')}>
93
+ <label style={{ color: '#C4C4C4', fontSize: '10px' }}>
94
+ {getSortIcon('termina')}
95
+ </label>
96
+ Fecha Fin
97
+ </th>
98
+ <th>Status</th>
99
+ <th>Responsable</th>
100
+ </tr>
101
+ </thead>
102
+ <tbody>
103
+ {data?.map((item, index) => (
104
+ <tr key={index} className="table-row">
105
+ <td>{item?.campania?.nombre}</td>
106
+ <td>{item?.campania?.inicia}</td>
107
+ <td>{item?.campania?.termina}</td>
108
+ <td style={{ width: '20%' }}>
109
+ <div
110
+ style={{
111
+ display: 'flex',
112
+ alignItems: 'center',
113
+ gap: '15px',
114
+ padding: 'none',
115
+ fontSize: '12px',
116
+ width: 'auto',
117
+ }}
118
+ >
119
+ <label
120
+ style={{
121
+ width: '20px',
122
+ minWidth: '50px',
123
+ textAlign: 'right',
124
+ color: '#000',
125
+ }}
126
+ >
127
+ {item?.progreso}%
128
+ </label>
129
+ <div
130
+ style={{
131
+ position: 'relative',
132
+ height: '10px',
133
+ flex: 1,
134
+ backgroundColor: '#C4C4C4',
135
+ borderRadius: '10px',
136
+ overflow: 'hidden',
137
+ }}
138
+ >
139
+ <div
140
+ style={{
141
+ position: 'absolute',
142
+ top: 0,
143
+ left: 0,
144
+ height: '100%',
145
+ width: `${item.progreso}%`,
146
+ backgroundColor:
147
+ item.progreso === 100
148
+ ? '#039B59'
149
+ : item.progreso > 50
150
+ ? '#3658C1'
151
+ : item.progreso > 0
152
+ ? '#DC8921'
153
+ : '#C4C4C4',
154
+ borderRadius: '10px',
155
+ transition: 'width 0.3s ease-in-out',
156
+ }}
157
+ />
158
+ </div>
159
+ </div>
160
+ </td>
161
+ <td style={{ width: 'auto' }}>
162
+ <div className="avatar-container">
163
+ <Avatar
164
+ className="avatar"
165
+ label={item?.campania?.responsable?.nombre?.charAt(0)}
166
+ shape="circle"
167
+ />
168
+ <span style={{ marginLeft: '8px', fontSize: '12px' }}>
169
+ {item?.campania?.responsable?.nombre}
170
+ </span>
171
+ </div>
172
+ </td>
173
+ </tr>
174
+ ))}
175
+ </tbody>
176
+ </table>
177
+ <div
178
+ className="pagination"
179
+ style={{
180
+ background: '#FAFAFA',
181
+ marginTop: '1rem',
182
+ display: 'flex',
183
+ gap: '0.5rem',
184
+ }}
185
+ >
186
+ <span
187
+ style={{
188
+ alignItems: 'center',
189
+ fontSize: '10px',
190
+ textAlign: 'left',
191
+ width: 'auto',
192
+ height: 'auto',
193
+ padding: '12px',
194
+ whiteSpace: 'nowrap',
195
+ }}
196
+ >
197
+ {rows} elementos de {totalRecords}
198
+ </span>
199
+
200
+ <Paginator
201
+ first={first}
202
+ rows={rows}
203
+ totalRecords={totalRecords}
204
+ rowsPerPageOptions={[5, 10, 20, 50]}
205
+ onPageChange={onPageChange}
206
+ className="pagination"
207
+ template="FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink"
208
+ />
209
+ <div
210
+ style={{
211
+ display: 'flex',
212
+ alignItems: 'center',
213
+ gap: '8px',
214
+ whiteSpace: 'nowrap',
215
+ padding: '0 1rem',
216
+ }}
217
+ >
218
+ <span style={{ fontSize: '12px' }}>Filas por página:</span>
219
+ <Dropdown
220
+ value={rows}
221
+ options={rowsPerPageOptions}
222
+ onChange={onRowsPerPageChange}
223
+ style={{
224
+ minWidth: '5rem',
225
+ width: 'auto',
226
+ height: '2rem',
227
+ zIndex: '999999',
228
+ transform: 'translateY(-100%)', // Move dropdown upwards
229
+ }}
230
+ className="p-dropdown-sm"
231
+ optionLabel="label"
232
+ optionValue="value"
233
+ />
234
+ </div>
235
+ </div>
236
+ </div>
237
+ );
238
+ };
239
+ export default TableList;
@@ -0,0 +1 @@
1
+ export { default as TableList } from './TableList';