wca-designsystem 0.0.44 → 0.0.46

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/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.0.44",
2
+ "version": "0.0.46",
3
3
  "license": "MIT",
4
4
  "main": "dist/index.js",
5
5
  "typings": "dist/index.d.ts",
@@ -93,7 +93,8 @@
93
93
  "@fullcalendar/interaction": "^6.1.15",
94
94
  "@fullcalendar/react": "^6.1.15",
95
95
  "@fullcalendar/timegrid": "^6.1.15",
96
- "@mantine/core": "7.13.4",
96
+ "@mantine/charts": "^7.13.4",
97
+ "@mantine/core": "^7.13.4",
97
98
  "@mantine/dates": "^7.13.4",
98
99
  "@mantine/form": "^7.13.4",
99
100
  "@mantine/hooks": "7.13.4",
@@ -103,6 +104,7 @@
103
104
  "axios": "^1.7.2",
104
105
  "dayjs": "^1.11.13",
105
106
  "react-router-dom": "^6.23.1",
107
+ "recharts": "^2.14.1",
106
108
  "styled-components": "^6.1.11",
107
109
  "xlsx": "^0.18.5"
108
110
  }
@@ -0,0 +1,42 @@
1
+ import React from 'react';
2
+ import DonutChart, { DonutProps } from './index';
3
+ import { Meta } from '@storybook/react/*';
4
+
5
+ import '@mantine/charts/styles.css';
6
+
7
+ export default {
8
+ title: 'Components/moleculas/Graficos/Donut',
9
+ component: DonutChart,
10
+ } as Meta;
11
+
12
+ type DataProps = {
13
+ name: string;
14
+ value: number;
15
+ color: string;
16
+ };
17
+
18
+ const data: Array<DataProps> = [
19
+ { name: 'Excelente', value: 20, color: '#4c6ef5' },
20
+ { name: 'Ótimo', value: 30, color: '#fcc419' },
21
+ { name: 'Bom', value: 10, color: '#12b886' },
22
+ { name: 'Regular', value: 20, color: '#fa5252' },
23
+ { name: 'Ruim', value: 20, color: '#7030A0' },
24
+ ];
25
+
26
+ const props: DonutProps<DataProps> = {
27
+ data: data,
28
+ };
29
+
30
+ const Template: any = (args: DonutProps<DataProps>) => (
31
+ <>
32
+ <DonutChart {...args} />
33
+ </>
34
+ );
35
+
36
+ export const DonutStory = Template.bind({
37
+ ...props,
38
+ });
39
+
40
+ DonutStory.args = {
41
+ ...props,
42
+ };
@@ -0,0 +1,57 @@
1
+ import React from 'react';
2
+ import DonutWrapper from './index';
3
+ import { render } from '../../../../test/render';
4
+
5
+ describe('DonutWrapper está renderizando corretamente', () => {
6
+ const mockData = [
7
+ { name: 'Categoria 1', value: 40, color: '#FF0000' },
8
+ { name: 'Categoria 2', value: 30, color: '#00FF00' },
9
+ { name: 'Categoria 3', value: 30, color: '#0000FF' },
10
+ ];
11
+
12
+ test('Renderizando todos os itens do gráfico', () => {
13
+ const { getAllByText, getByText } = render(
14
+ <DonutWrapper data={mockData} />
15
+ );
16
+
17
+ // Verifica se os valores das categorias estão sendo exibidos
18
+ expect(getByText('40%')).toBeDefined();
19
+
20
+ // Usa getAllByText para valores duplicados
21
+ const elements = getAllByText('30%');
22
+ expect(elements).toHaveLength(2);
23
+ });
24
+
25
+ test('Renderizando o componente com dados vazios', () => {
26
+ const { container } = render(<DonutWrapper data={[]} />);
27
+
28
+ // Verifica se não há nenhum texto percentual na tela
29
+ expect(container.textContent).not.toContain('%');
30
+ });
31
+
32
+ test('Renderizando as caixas de cores corretamente', () => {
33
+ const { container } = render(<DonutWrapper data={mockData} />);
34
+
35
+ // Verifica se as caixas de cores têm os estilos corretos
36
+ mockData.forEach(item => {
37
+ const colorBox = container.querySelector(
38
+ `[style="background-color: ${item.color};"]`
39
+ );
40
+ expect(colorBox).toBeDefined();
41
+ });
42
+ });
43
+
44
+ test('Lida com dados inválidos ou ausentes', () => {
45
+ const invalidDataMock = [
46
+ { name: 'Categoria 1', value: null, color: '#FF0000' },
47
+ { name: 'Categoria 2', color: '#00FF00' },
48
+ { value: 30, color: '#0000FF' },
49
+ ];
50
+
51
+ const { getByText } = render(<DonutWrapper data={invalidDataMock} />);
52
+
53
+ // Verifica que o componente ignora ou substitui valores inválidos
54
+ expect(getByText('Categoria 1')).toBeDefined();
55
+ expect(getByText('30%')).toBeDefined();
56
+ });
57
+ });
@@ -0,0 +1,27 @@
1
+ import { DonutChart } from '@mantine/charts';
2
+ import { Flex } from '@mantine/core';
3
+ import React from 'react';
4
+ import { ChartInfos, InfoItem, ColorBox, Label, Value } from './styles';
5
+
6
+ export type DonutProps<T = any> = {
7
+ data: Array<T>;
8
+ };
9
+
10
+ const DonutWrapper = ({ data }: DonutProps) => {
11
+ return (
12
+ <Flex gap={20} align={'center'}>
13
+ <DonutChart data={data} thickness={30} withTooltip={false} />
14
+ <ChartInfos>
15
+ {data.map((item, index) => (
16
+ <InfoItem key={index}>
17
+ <ColorBox color={item.color} />
18
+ <Label>{item.name}</Label>
19
+ <Value>{item.value}%</Value>
20
+ </InfoItem>
21
+ ))}
22
+ </ChartInfos>
23
+ </Flex>
24
+ );
25
+ };
26
+
27
+ export default DonutWrapper;
@@ -0,0 +1,34 @@
1
+ import styled from 'styled-components';
2
+
3
+ export const ChartInfos = styled.div`
4
+ display: flex;
5
+ flex-direction: column;
6
+ gap: 8px;
7
+ background-color: #ffffff;
8
+ padding: 12px;
9
+ border-radius: 8px;
10
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
11
+ `;
12
+
13
+ export const InfoItem = styled.div`
14
+ display: flex;
15
+ align-items: center;
16
+ gap: 8px;
17
+ `;
18
+
19
+ export const ColorBox = styled.div`
20
+ width: 16px;
21
+ height: 16px;
22
+ border-radius: 4px;
23
+ background-color: ${({ color }) => color};
24
+ `;
25
+
26
+ export const Label = styled.span`
27
+ font-size: 14px;
28
+ color: #333;
29
+ `;
30
+
31
+ export const Value = styled.span`
32
+ font-size: 12px;
33
+ color: #666;
34
+ `;
@@ -0,0 +1,100 @@
1
+ import React from 'react';
2
+ import * as S from './styles';
3
+ import InputDeTexto from '../../atomos/InputDeTexto';
4
+ import SelectCustomizado from '../../atomos/Select';
5
+ import Icone from '../../atomos/Icone';
6
+ import IconeBotao from '../../atomos/IconeBotao';
7
+ import Botao from '../../atomos/Botao';
8
+ import pesquisar from '../../../assets/imagens/icons/Busca.svg';
9
+ import ordernar from '../../../assets/imagens/icons/Ordernar.svg';
10
+ import { SelectDataProps } from '../../organismos/Tabela';
11
+ import filtrar from '../../../assets/imagens/icons/Filtrar.svg';
12
+ import plus from '../../../assets/imagens/icons/Mais.svg';
13
+
14
+ export type TabelaHeaderProps = {
15
+ globalFilter: string;
16
+ setGlobalFilter: React.Dispatch<React.SetStateAction<string>>;
17
+ setToogleFiltros: React.Dispatch<React.SetStateAction<boolean>>;
18
+ toogleFiltros: boolean;
19
+ color?: string;
20
+ hasOrder?: boolean;
21
+ hasAdd?: boolean;
22
+ setOrdenarPor?: React.Dispatch<React.SetStateAction<SelectDataProps>>;
23
+ handleAdicionar?: () => void;
24
+ ordenarPor?: SelectDataProps;
25
+ hasFiltersButtons?: boolean;
26
+ };
27
+ const TabelaHeader = ({
28
+ globalFilter,
29
+ setGlobalFilter,
30
+ setToogleFiltros,
31
+ toogleFiltros,
32
+ color,
33
+ hasAdd,
34
+ hasFiltersButtons,
35
+ handleAdicionar,
36
+ ordenarPor,
37
+ setOrdenarPor,
38
+ hasOrder,
39
+ }: TabelaHeaderProps) => {
40
+ return (
41
+ <S.HeaderTableContent>
42
+ <InputDeTexto
43
+ tipo="table"
44
+ onChange={e => setGlobalFilter(e.currentTarget.value)}
45
+ color={color}
46
+ value={globalFilter}
47
+ placeholder="Pesquisar na tabela"
48
+ rightSection={<Icone svg={pesquisar} fill={color} />}
49
+ />
50
+ {hasOrder && (
51
+ <SelectCustomizado
52
+ tipo="table"
53
+ data={[
54
+ { value: 'Maior', label: 'Ordenar por: Maior' },
55
+ { value: 'Menor', label: 'Ordenar por: Menor' },
56
+ ]}
57
+ onChange={(_value, option) => setOrdenarPor!(option)}
58
+ value={ordenarPor ? ordenarPor.value : null}
59
+ placeholder={`Ordenar por ${ordenarPor}`}
60
+ maw={200}
61
+ comboboxProps={{
62
+ position: 'bottom',
63
+ middlewares: { flip: false, shift: false },
64
+ offset: 0,
65
+ }}
66
+ leftSection={
67
+ <Icone width={15} height={15} fill={color} svg={ordernar} />
68
+ }
69
+ />
70
+ )}
71
+
72
+ {/* Botão de filtros */}
73
+ {hasFiltersButtons && (
74
+ <S.ToogleButton>
75
+ <IconeBotao
76
+ tipo="table"
77
+ color={color}
78
+ toolTipInfo="Filtros especificos"
79
+ onClick={() => setToogleFiltros(!toogleFiltros)}
80
+ >
81
+ <Icone svg={filtrar} fill={color} width={20} />
82
+ </IconeBotao>
83
+ </S.ToogleButton>
84
+ )}
85
+ {hasAdd && (
86
+ <Botao
87
+ tipo="round"
88
+ leftSection={<Icone svg={plus} fill={color} />}
89
+ color={color}
90
+ onClick={() => handleAdicionar!()}
91
+ h={32}
92
+ >
93
+ Adicionar Usuário
94
+ </Botao>
95
+ )}
96
+ </S.HeaderTableContent>
97
+ );
98
+ };
99
+
100
+ export default TabelaHeader;
@@ -0,0 +1,16 @@
1
+ import styled, { css } from 'styled-components';
2
+
3
+ export const HeaderTableContent = styled.div`
4
+ ${({ theme }) => css`
5
+ display: flex;
6
+ justify-content: end;
7
+ gap: 15px;
8
+ padding: 15px 0;
9
+ background-color: ${theme.colors.gray['300']};
10
+ width: 100%;
11
+ overflow-x: auto;
12
+ `}
13
+ `;
14
+ export const ToogleButton = styled.div`
15
+ ${() => css``}
16
+ `;
@@ -2,6 +2,7 @@ import React from 'react';
2
2
  import { Meta } from '@storybook/react';
3
3
  import Tabela from './index';
4
4
  import { theme } from '../../../styles/theme';
5
+ import Botao from '../../atomos/Botao';
5
6
 
6
7
  export default {
7
8
  title: 'Components/organismos/Tabela',
@@ -22,6 +23,15 @@ const data: any[] = [
22
23
  price: '$10',
23
24
  exemplo: 'opa',
24
25
  exemplo2: 'opa2',
26
+ children: [
27
+ {
28
+ id: '1-10',
29
+ name: 'Task 10',
30
+ price: '$10',
31
+ exemplo: 'opa',
32
+ exemplo2: 'opa2',
33
+ },
34
+ ],
25
35
  },
26
36
  {
27
37
  id: '1-2',
@@ -158,7 +168,7 @@ const columns: any = [
158
168
  { key: 'name', header: 'Nome' },
159
169
  { key: 'price', header: 'Preço' },
160
170
  { key: 'exemplo', header: 'Exemplo' },
161
- { key: 'exemplo2', header: 'Exemplo2' },
171
+ { key: 'acoes', header: 'acoes' },
162
172
  ];
163
173
 
164
174
  const Template: any = (args: any) => (
@@ -172,6 +182,11 @@ export const TabelaProps = Template.bind({});
172
182
  TabelaProps.args = {
173
183
  data: data,
174
184
  hasExpand: true,
185
+ acoesChildren: (row: any): JSX.Element => (
186
+ <>
187
+ <Botao onClick={() => console.log(row)} tipo={'table'} children={'▶'} />
188
+ </>
189
+ ),
175
190
  columns: columns,
176
191
  color: theme.colors.blue,
177
192
  hasFiltersButtons: true,
@@ -183,6 +198,8 @@ TabelaProps.args = {
183
198
  pageIndex: 1,
184
199
  pageSize: 10,
185
200
  },
201
+ rowSelection: [],
202
+ setRowSelection: () => console.log('selecionou'),
186
203
  setFiltrosPor: () => console.log('aqui'),
187
204
  setGlobalFilter: () => console.log('aqui'),
188
205
  setPagination: () => console.log('aqui'),
@@ -1,8 +1,7 @@
1
- import React, { useRef, useState } from 'react';
1
+ import React, { useState, useCallback } from 'react';
2
2
  import { Checkbox } from '@mantine/core';
3
3
  import { Column } from '.';
4
4
  import * as S from './styles';
5
- import { useCallback } from 'react';
6
5
  import { theme } from '../../../styles/theme';
7
6
  import Icone from '../../atomos/Icone';
8
7
  import SetaBaixo from '../../../assets/imagens/icons/SetaAbaixo.svg';
@@ -14,23 +13,25 @@ export interface BodyTableProps<
14
13
  columns: Column<T>[];
15
14
  fixedPosition?: string[] | undefined;
16
15
  color?: string;
17
- acoesChildren?: JSX.Element;
16
+ acoesChildren?: (row: T) => JSX.Element;
18
17
  calcStickPosition?: (index: number) => number;
19
18
  hasSelect?: boolean;
20
19
  rowSelection?: Array<T>;
21
20
  setRowSelection?: React.Dispatch<React.SetStateAction<Array<T>>> | undefined;
22
21
  }
23
22
 
24
- function BodyTable<T extends { id: string | number; children: Array<T> }>({
25
- data,
26
- columns,
27
- acoesChildren,
28
- hasSelect,
29
- rowSelection,
30
- setRowSelection,
31
- color,
32
- }: BodyTableProps<T>) {
33
- const rowRefs = useRef(new Map()); // Ref para armazenar alturas das linhas
23
+ function BodyTable<T extends { id: string | number; children: Array<T> }>(
24
+ props: BodyTableProps<T>
25
+ ) {
26
+ const {
27
+ data,
28
+ columns,
29
+ acoesChildren,
30
+ hasSelect,
31
+ rowSelection,
32
+ setRowSelection,
33
+ color,
34
+ } = props;
34
35
 
35
36
  const [expandedRows, setExpandedRows] = useState<Set<number | string>>(
36
37
  new Set()
@@ -61,122 +62,144 @@ function BodyTable<T extends { id: string | number; children: Array<T> }>({
61
62
  });
62
63
  }, []);
63
64
 
64
- return (
65
- <S.TabelaBody color={color} hasSelect={hasSelect}>
66
- {data.map((item, rowIndex) => (
67
- <React.Fragment key={rowIndex}>
68
- <tr>
69
- {/* Tabela Select */}
70
- {hasSelect && (
71
- <td className="select">
72
- <Checkbox
73
- size="md"
74
- color={color}
75
- type="checkbox"
76
- checked={rowSelection?.some(
77
- itemSome => item.id === itemSome.id
78
- )}
79
- onChange={() =>
80
- handleRowSelect(
81
- item,
82
- rowSelection!.some(itemSome => item.id === itemSome.id)
83
- )
84
- }
65
+ function renderRows(
66
+ item: T,
67
+ columns: Column<T>[],
68
+ expandedRows: Set<string | number>,
69
+ toggleExpandRow: (rowId: string | number) => void,
70
+ acoesChildren?: (row: T) => JSX.Element,
71
+ rowSelection?: Array<T>,
72
+ setRowSelection?:
73
+ | React.Dispatch<React.SetStateAction<Array<T>>>
74
+ | undefined,
75
+ color?: string
76
+ ): JSX.Element[] {
77
+ const isSelected = rowSelection?.some(row => row.id === item.id);
78
+ const hasChildren = item.children && item.children.length > 0;
79
+
80
+ return [
81
+ <tr key={`row-${item.id}`}>
82
+ {/* Checkbox para seleção */}
83
+ {hasSelect && (
84
+ <td className="select">
85
+ <Checkbox
86
+ size="md"
87
+ color={color}
88
+ type="checkbox"
89
+ checked={rowSelection?.some(selected => selected.id === item.id)}
90
+ onChange={() => {
91
+ handleRowSelect(
92
+ item,
93
+ rowSelection!.some(selected => selected.id === item.id)
94
+ );
95
+ }}
96
+ />
97
+ </td>
98
+ )}
99
+
100
+ {/* Colunas dinâmicas */}
101
+ {columns.map((column, colIndex) => {
102
+ if (column.key === 'expand') {
103
+ return (
104
+ <td
105
+ key={`expand-${colIndex}`}
106
+ onClick={
107
+ hasChildren ? () => toggleExpandRow(item.id) : undefined
108
+ }
109
+ className="expand"
110
+ style={{
111
+ cursor: hasChildren ? 'pointer' : 'not-allowed',
112
+ opacity: hasChildren ? 1 : 0.5,
113
+ }}
114
+ >
115
+ <Icone
116
+ svg={SetaBaixo}
117
+ fill={theme.colors.white}
118
+ style={{
119
+ transform: expandedRows.has(item.id)
120
+ ? 'rotate(-180deg)'
121
+ : hasChildren
122
+ ? 'rotate(0deg)'
123
+ : 'rotate(-90deg)',
124
+ color: theme.colors.white,
125
+ transition: 'ease-in 0.2s',
126
+ }}
85
127
  />
86
128
  </td>
87
- )}
88
- {columns.some(
89
- columnKey => columnKey.key === 'acoes' && acoesChildren
90
- )}
129
+ );
130
+ }
91
131
 
92
- {columns.map((column, index) => (
93
- <>
94
- {/* Caso tenha expand*/}
95
- {column.key === 'expand' ? (
96
- <>
97
- <td
98
- key={index}
99
- onClick={() => toggleExpandRow(item.id)}
100
- className="expand"
101
- >
102
- {expandedRows.has(item.id) ? (
103
- <Icone
104
- svg={SetaBaixo}
105
- fill={theme.colors.white}
106
- style={{
107
- transform: 'rotate(180deg)',
108
- color: theme.colors.white,
109
- transition: 'ease-in 0.2s',
110
- }}
111
- />
112
- ) : (
113
- <Icone
114
- svg={SetaBaixo}
115
- fill={theme.colors.white}
116
- style={{
117
- transform: 'rotate(0deg)',
118
- color: theme.colors.white,
119
- transition: 'ease-in 0.2s',
120
- }}
121
- />
122
- )}
123
- </td>
124
- </>
125
- ) : column.render ? (
126
- <th
127
- key={String(column.key)}
128
- style={{
129
- background: rowSelection?.some(row => row.id === item.id)
130
- ? theme.colors.gray['500']
131
- : 'transparent',
132
- }}
133
- >
134
- {column.render(item[column.key])}
135
- </th>
136
- ) : (
137
- <td
138
- key={String(column.key)}
139
- style={{
140
- background: rowSelection?.some(row => row.id === item.id)
141
- ? theme.colors.gray['500']
142
- : 'transparent',
143
- }}
144
- >
145
- {String(item[column.key])}
146
- </td>
147
- )}
148
- </>
149
- ))}
150
- </tr>
151
- {expandedRows.has(item.id) &&
152
- item.children &&
153
- item.children.map((child, childIndex) => {
154
- const rowKey = `${item.id}-${childIndex}`;
155
- const isExpanded = expandedRows.has(item.id);
132
+ if (column.key === 'acoes' && acoesChildren) {
133
+ return (
134
+ <td key={`acoes-${colIndex}`} className="acoes">
135
+ {acoesChildren(item)}
136
+ </td>
137
+ );
138
+ }
156
139
 
157
- return (
158
- <tr
159
- key={rowKey}
160
- ref={el => el && rowRefs.current.set(rowKey, el.scrollHeight)}
161
- >
162
- {columns.map(column => (
163
- <td
164
- key={String(column.key)}
165
- style={{
166
- height: isExpanded ? '40px' : '0px',
167
- transition: 'height 0.3s ease-in-out',
168
- overflow: 'hidden',
169
- background: theme.colors.gray['500'],
170
- }}
171
- >
172
- {child[column.key] ? String(child[column.key]) : ''}
173
- </td>
174
- ))}
175
- </tr>
176
- );
177
- })}
178
- </React.Fragment>
179
- ))}
140
+ // Verifica se existe a prop 'cell'
141
+ if (column.cell) {
142
+ return <td key={`cell-${colIndex}`}>{column.cell(item)}</td>;
143
+ }
144
+
145
+ // Render padrão
146
+ return column.render ? (
147
+ <td
148
+ key={`column-${colIndex}`}
149
+ style={{
150
+ background: isSelected
151
+ ? theme.colors.gray['500']
152
+ : 'transparent',
153
+ }}
154
+ >
155
+ {column.render(item[column.key])}
156
+ </td>
157
+ ) : (
158
+ <td
159
+ key={`cell-${colIndex}`}
160
+ style={{
161
+ background: isSelected
162
+ ? theme.colors.gray['500']
163
+ : 'transparent',
164
+ }}
165
+ >
166
+ {String(item[column.key])}
167
+ </td>
168
+ );
169
+ })}
170
+ </tr>,
171
+
172
+ // Renderiza os filhos recursivamente, caso existam
173
+ ...(expandedRows.has(item.id)
174
+ ? item.children.flatMap(child =>
175
+ renderRows(
176
+ child,
177
+ columns,
178
+ expandedRows,
179
+ toggleExpandRow,
180
+ acoesChildren,
181
+ rowSelection,
182
+ setRowSelection,
183
+ color
184
+ )
185
+ )
186
+ : []),
187
+ ];
188
+ }
189
+ return (
190
+ <S.TabelaBody color={color} hasselect={hasSelect ? 'true' : 'false'}>
191
+ {data.flatMap(item =>
192
+ renderRows(
193
+ item,
194
+ columns,
195
+ expandedRows,
196
+ toggleExpandRow,
197
+ acoesChildren,
198
+ rowSelection,
199
+ setRowSelection,
200
+ color
201
+ )
202
+ )}
180
203
  </S.TabelaBody>
181
204
  );
182
205
  }
@@ -7,6 +7,7 @@ import { useCallback } from 'react';
7
7
  import { theme } from '../../../styles/theme';
8
8
  import InputDeTexto from '../../atomos/InputDeTexto';
9
9
  import Icone from '../../atomos/Icone';
10
+ import { Capitalize } from '../../../utils/functions';
10
11
 
11
12
  type HeaderOptions = {
12
13
  [key: string | number | symbol]: string; // Um índice genérico para mapear headers a valores
@@ -66,15 +67,19 @@ const HeaderTabela = <T,>({
66
67
  [headerSelection]
67
68
  );
68
69
 
69
- const renderHeaderOptions = useCallback((header: string | number | symbol):
70
- | string
71
- | undefined => {
72
- const especialHeaders: HeaderOptions = {
73
- ativo: 'Status',
74
- };
70
+ const renderHeaderOptions = useCallback(
71
+ (
72
+ header: string | number | symbol,
73
+ key: string | number | symbol
74
+ ): string | undefined => {
75
+ const especialHeaders: HeaderOptions = {
76
+ ativo: 'Status',
77
+ };
75
78
 
76
- return especialHeaders[header] ?? header;
77
- }, []);
79
+ return especialHeaders[header] ?? Capitalize(String(header));
80
+ },
81
+ []
82
+ );
78
83
  return (
79
84
  <S.TabelaHeader color={color}>
80
85
  <tr>
@@ -145,7 +150,7 @@ const HeaderTabela = <T,>({
145
150
  )}
146
151
  </div>
147
152
  ) : (
148
- <>{renderHeaderOptions(header.key)}</>
153
+ <>{renderHeaderOptions(header.header, header.key)}</>
149
154
  )}
150
155
  </th>
151
156
  );
@@ -1,25 +1,19 @@
1
- import React from 'react';
1
+ import React, { useEffect } from 'react';
2
2
  import BodyTable from './body';
3
3
  import HeaderTabela from './header';
4
4
  import Paginacao from './pagination';
5
5
  import SkeletonTable from './SkeletonTable';
6
6
  import * as S from './styles';
7
- import filtrar from '../../../assets/imagens/icons/Filtrar.svg';
8
7
  import { useState } from 'react';
9
- import IconeBotao from '../../atomos/IconeBotao';
10
- import Icone from '../../atomos/Icone';
11
- import InputDeTexto from '../../atomos/InputDeTexto';
12
- import pesquisar from '../../../assets/imagens/icons/Busca.svg';
13
- import SelectCustomizado from '../../atomos/Select';
14
- import { theme } from '../../../styles/theme';
15
- import ordernar from '../../../assets/imagens/icons/Ordernar.svg';
8
+ import TabelaHeader from '../../molecules/TabelaHeader';
16
9
 
17
10
  // Tipo genérico para as colunas
18
11
  export type Column<T> = {
19
12
  key: keyof T;
20
13
  header: string;
21
14
  render?: (value: T[keyof T]) => React.ReactNode;
22
- expand?: (item: T) => React.ReactNode; // Define o conteúdo expandido.
15
+ cell?: (row: T) => React.ReactNode;
16
+ expand?: (item: T) => React.ReactNode;
23
17
  };
24
18
 
25
19
  export type SelectDataProps = {
@@ -33,9 +27,10 @@ export type CustomTableProps<
33
27
  data: T[];
34
28
  columns: Column<T>[];
35
29
  fixedPosition?: Array<String>;
36
- acoesChildren?: JSX.Element;
30
+ acoesChildren?: (row: T) => JSX.Element;
37
31
  hasSelect?: boolean;
38
32
  hasExpand?: boolean;
33
+ hasAdd?: boolean;
39
34
  hasOrder?: boolean;
40
35
  headerSelection?: Array<String>;
41
36
  rowSelection?: Array<T>;
@@ -44,11 +39,12 @@ export type CustomTableProps<
44
39
  color?: string;
45
40
  setSimples: React.Dispatch<React.SetStateAction<boolean>>;
46
41
  setGlobalFilter: React.Dispatch<React.SetStateAction<string>>;
42
+ globalFilter: string;
47
43
  setPagination: React.Dispatch<any>;
44
+ handleAdicionar?: () => void;
48
45
  hasFiltersButtons?: boolean;
49
46
  setOrdenarPor?: React.Dispatch<React.SetStateAction<SelectDataProps>>;
50
47
  ordenarPor?: SelectDataProps;
51
-
52
48
  filtrosPor: {
53
49
  value: string;
54
50
  label: string;
@@ -76,7 +72,9 @@ const Tabela = <T extends { id: string | number; children: Array<T> }>({
76
72
  setRowSelection,
77
73
  hasFiltersButtons,
78
74
  isLoading,
75
+ hasAdd,
79
76
  hasSelect,
77
+ globalFilter,
80
78
  hasExpand,
81
79
  setFiltrosPor,
82
80
  setGlobalFilter,
@@ -84,60 +82,33 @@ const Tabela = <T extends { id: string | number; children: Array<T> }>({
84
82
  headerSelection,
85
83
  setOrdenarPor,
86
84
  setSimples,
85
+ handleAdicionar,
87
86
  tabelaPaginacao,
88
87
  fixedPosition,
89
88
  }: CustomTableProps<T>) => {
90
89
  const [toogleFiltros, setToogleFiltros] = useState(false);
90
+ const [loading, setLoading] = useState(isLoading);
91
+
92
+ useEffect(() => {
93
+ setLoading(isLoading);
94
+ }, [isLoading]);
95
+
91
96
  return (
92
97
  <S.TableWrapper>
93
98
  <S.TableContainer>
94
- <S.HeaderTableContent>
95
- <InputDeTexto
96
- tipo="table"
97
- color={color}
98
- placeholder="Pesquisar na tabela"
99
- rightSection={<Icone svg={pesquisar} fill={color} />}
100
- />
101
- {hasOrder && (
102
- <SelectCustomizado
103
- tipo="table"
104
- data={[
105
- { value: 'Maior', label: 'Ordenar por: Maior' },
106
- { value: 'Menor', label: 'Ordenar por: Menor' },
107
- ]}
108
- onChange={(_value, option) => setOrdenarPor!(option)}
109
- value={ordenarPor ? ordenarPor.value : null}
110
- placeholder={`Ordenar por ${ordenarPor}`}
111
- maw={200}
112
- comboboxProps={{
113
- position: 'bottom',
114
- middlewares: { flip: false, shift: false },
115
- offset: 0,
116
- }}
117
- leftSection={
118
- <Icone
119
- width={15}
120
- height={15}
121
- fill={theme.colors.blue}
122
- svg={ordernar}
123
- />
124
- }
125
- />
126
- )}
127
- {/* Botão de filtros */}
128
- {hasFiltersButtons && (
129
- <S.ToogleButton>
130
- <IconeBotao
131
- tipo="table"
132
- color={color}
133
- toolTipInfo="Filtros especificos"
134
- onClick={() => setToogleFiltros(!toogleFiltros)}
135
- >
136
- <Icone svg={filtrar} fill={color} width={20} />
137
- </IconeBotao>
138
- </S.ToogleButton>
139
- )}
140
- </S.HeaderTableContent>
99
+ <TabelaHeader
100
+ handleAdicionar={handleAdicionar}
101
+ globalFilter={globalFilter}
102
+ setGlobalFilter={setGlobalFilter}
103
+ setToogleFiltros={setToogleFiltros}
104
+ toogleFiltros={toogleFiltros}
105
+ color={color}
106
+ hasAdd={hasAdd}
107
+ hasFiltersButtons={hasFiltersButtons}
108
+ hasOrder={hasOrder}
109
+ ordenarPor={ordenarPor}
110
+ setOrdenarPor={setOrdenarPor}
111
+ />
141
112
  <S.StyledTable>
142
113
  <HeaderTabela
143
114
  hasExpand={hasExpand}
@@ -153,7 +124,7 @@ const Tabela = <T extends { id: string | number; children: Array<T> }>({
153
124
  fixedPosition={fixedPosition!}
154
125
  onFilterColunas={id => console.log(id)}
155
126
  />
156
- {isLoading ? (
127
+ {loading ? (
157
128
  <SkeletonTable columns={columns} data={data} />
158
129
  ) : (
159
130
  <BodyTable
@@ -19,19 +19,7 @@ export const TableContainer = styled.div`
19
19
  border-radius: 5px;
20
20
  font-family: 'Open Sans', sans-serif;
21
21
  max-width: 1500px;
22
- `;
23
-
24
- export const HeaderTableContent = styled.div`
25
- ${() => css`
26
- display: flex;
27
- justify-content: end;
28
- gap: 15px;
29
- margin-bottom: 15px;
30
- `}
31
- `;
32
-
33
- export const ToogleButton = styled.div`
34
- ${() => css``}
22
+ width: 100%;
35
23
  `;
36
24
 
37
25
  export const StyledTable = styled.table`
@@ -68,11 +56,13 @@ export const StyledTable = styled.table`
68
56
  export const TabelaHeader = styled.thead<ColorsProp>`
69
57
  ${({ theme, color }) => css`
70
58
  th {
71
- min-width: 150px;
59
+ min-width: 260px;
72
60
  text-align: center;
73
- padding: 5px;
61
+ padding: 0 5px;
62
+ max-height: 24px;
74
63
  background-color: ${color};
75
64
  opacity: 0.8;
65
+ font-size: ${theme.sizes.small};
76
66
  color: ${theme.colors.white};
77
67
  font-weight: bold;
78
68
  }
@@ -102,8 +92,8 @@ export const TabelaHeader = styled.thead<ColorsProp>`
102
92
  `}
103
93
  `;
104
94
 
105
- export const TabelaBody = styled.tbody<{ color?: string; hasSelect?: boolean }>`
106
- ${({ theme, color, hasSelect }) => css`
95
+ export const TabelaBody = styled.tbody<{ color?: string; hasselect?: string }>`
96
+ ${({ theme, color, hasselect }) => css`
107
97
  /* height: 430px; */
108
98
  width: 100%;
109
99
 
@@ -114,8 +104,7 @@ export const TabelaBody = styled.tbody<{ color?: string; hasSelect?: boolean }>`
114
104
 
115
105
  .expand {
116
106
  width: 50px;
117
- position: fixed;
118
- left: ${hasSelect ? '52px' : '17px'};
107
+ left: ${hasselect === 'true' ? '52px' : '17px'};
119
108
  background-color: ${color};
120
109
  display: flex;
121
110
  align-items: center;
@@ -0,0 +1,4 @@
1
+ export const Capitalize = (palavra: string) => {
2
+ if (!palavra) return '';
3
+ return palavra.charAt(0).toUpperCase() + palavra.slice(1);
4
+ };