code7-leia 1.0.11 → 1.0.13

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 (62) hide show
  1. package/dist/index.es.js +3356 -2922
  2. package/package.json +6 -6
  3. package/src/components/CustomToast/index.tsx +62 -0
  4. package/src/components/CustomToast/styles.tsx +74 -0
  5. package/src/components/EmptyState/index.tsx +88 -0
  6. package/src/components/EmptyState/styles.tsx +81 -0
  7. package/src/components/FileArea/components/AreaUpload/index.tsx +137 -0
  8. package/src/components/FileArea/components/AreaUpload/styles.tsx +86 -0
  9. package/src/components/FileArea/components/Modal/ModalButtonClose.tsx +23 -0
  10. package/src/components/FileArea/components/Modal/ModalContent.tsx +26 -0
  11. package/src/components/FileArea/components/Modal/ModalFooter.tsx +18 -0
  12. package/src/components/FileArea/components/Modal/ModalHeader.tsx +18 -0
  13. package/src/components/FileArea/components/Modal/ModalTitle.tsx +18 -0
  14. package/src/components/FileArea/components/Modal/index.tsx +131 -0
  15. package/src/components/FileArea/components/Modal/styles.tsx +121 -0
  16. package/src/components/FileArea/components/Search/index.tsx +45 -0
  17. package/src/components/FileArea/components/Search/styles.tsx +26 -0
  18. package/src/components/FileArea/components/Spinner/index.tsx +22 -0
  19. package/src/components/FileArea/components/Spinner/styles.tsx +59 -0
  20. package/src/components/FileArea/components/Table/index.tsx +34 -0
  21. package/src/components/FileArea/components/Table/styles.tsx +60 -0
  22. package/src/components/FileArea/index.tsx +279 -0
  23. package/src/components/FileArea/styles.tsx +183 -0
  24. package/src/components/LengthCounter/index.tsx +29 -0
  25. package/src/components/LengthCounter/styles.ts +11 -0
  26. package/src/components/Modal/index.tsx +30 -0
  27. package/src/components/Modal/styles.ts +52 -0
  28. package/src/components/MultiSelect/index.tsx +102 -0
  29. package/src/components/MultiSelect/styles.tsx +85 -0
  30. package/src/components/PersonasArea/index.tsx +196 -0
  31. package/src/components/PersonasArea/styles.ts +137 -0
  32. package/src/components/Select/index.tsx +60 -0
  33. package/src/components/Select/styles.tsx +49 -0
  34. package/src/components/TestArea/components/InputTest/index.tsx +23 -0
  35. package/src/components/TestArea/components/InputTest/styles.tsx +28 -0
  36. package/src/components/TestArea/components/TextArea/index.tsx +97 -0
  37. package/src/components/TestArea/components/TextArea/styles.tsx +173 -0
  38. package/src/components/TestArea/index.tsx +99 -0
  39. package/src/components/TestArea/styles.tsx +112 -0
  40. package/src/contexts/LeiaProvider.tsx +133 -0
  41. package/src/index.tsx +6 -0
  42. package/src/interface/FileData.ts +11 -0
  43. package/src/interface/Language.ts +95 -0
  44. package/src/interface/Table.ts +12 -0
  45. package/src/service/Api.ts +9 -0
  46. package/src/service/ApiDev.ts +9 -0
  47. package/src/service/ApiHml.ts +9 -0
  48. package/src/store/index.ts +13 -0
  49. package/src/store/modules/actions.ts +88 -0
  50. package/src/store/modules/reducer.ts +46 -0
  51. package/src/store/modules/sagas.ts +127 -0
  52. package/src/store/modules/types.ts +19 -0
  53. package/src/types/image.d.ts +4 -0
  54. package/src/utils/formatAxios.tsx +15 -0
  55. package/src/utils/getApi.tsx +16 -0
  56. package/src/utils/getLanguage.tsx +17 -0
  57. package/src/utils/languages/en.ts +107 -0
  58. package/src/utils/languages/es.ts +107 -0
  59. package/src/utils/languages/pt-br.ts +111 -0
  60. package/src/utils/stringNormalize.ts +9 -0
  61. package/dist/code7-leia.css +0 -1
  62. package/dist/index.cjs.js +0 -1073
@@ -0,0 +1,85 @@
1
+ import styled from 'styled-components';
2
+
3
+ export const MultiSelectWrapper = styled.div`
4
+ width: 100%;
5
+ height: 45px;
6
+
7
+ `;
8
+
9
+ export const SelectBox = styled.div`
10
+ position: relative;
11
+
12
+
13
+ select {
14
+ width: 100%;
15
+ font-weight: bold;
16
+ height: 45px;
17
+ border-radius: 4px;
18
+ padding-left: 10px;
19
+ }
20
+ `;
21
+
22
+ export const OverSelect = styled.div`
23
+ position: absolute;
24
+ left: 0;
25
+ right: 0;
26
+ top: 0;
27
+ bottom: 0;
28
+ display: flex;
29
+ color: white;
30
+ padding-left: 10px;
31
+
32
+
33
+ input {
34
+ height: 43px;
35
+ width: calc(100% - 30px);
36
+ border: none;
37
+ margin: 1px;
38
+
39
+ &:focus {
40
+ outline: none;
41
+ box-shadow: 0 0 0 3px #6690ff;
42
+ }
43
+
44
+ }
45
+
46
+ `;
47
+
48
+ export const Checkboxes = styled.div`
49
+ display: none;
50
+ background: white;
51
+ position: absolute;
52
+ width: 95%;
53
+ z-index: 10;
54
+
55
+ label {
56
+ padding: 10px 5px;
57
+ }
58
+ `;
59
+
60
+ export const CheckboxLabel = styled.label`
61
+ display: block;
62
+
63
+ &:hover {
64
+ background-color: #6690ff;
65
+ }
66
+ `;
67
+
68
+ export const SelectedValues = styled.div`
69
+ position: absolute;
70
+ top: 9px;
71
+ display: flex;
72
+ flex-wrap: wrap;
73
+ margin-left: 5px;
74
+ right: 30px;
75
+ `;
76
+
77
+ export const SelectedValue = styled.div`
78
+ background-color: #254EDB;
79
+ color: white;
80
+ border-radius: 15px;
81
+ padding: 5px 10px;
82
+ margin-right: 5px;
83
+ margin-bottom: 5px;
84
+ white-space: nowrap;
85
+ `;
@@ -0,0 +1,196 @@
1
+ import { useState } from 'react';
2
+ import { getLanguage } from '../../utils/getLanguage';
3
+ import { FaPlus, FaCopy, FaEdit, FaTrash } from 'react-icons/fa';
4
+ import Modal from '../Modal';
5
+ import Input from '../TestArea/components/InputTest';
6
+ import TextArea from '../TestArea/components/TextArea';
7
+ import Search from '../FileArea/components/Search';
8
+ import LengthCounter from '../LengthCounter';
9
+
10
+ import { useLeia } from '../../contexts/LeiaProvider';
11
+
12
+ import * as S from './styles';
13
+
14
+ interface Persona {
15
+ id: number;
16
+ name: string;
17
+ description: string;
18
+ prompt: string;
19
+ type?: string;
20
+ }
21
+
22
+ export const PersonasArea = () => {
23
+ const { language } = useLeia();
24
+ const t = getLanguage(language);
25
+ const [_,setPersonas] = useState<Persona[]>([]);
26
+ const { createPersona, personas, updatePersona, deletePersona } = useLeia();
27
+
28
+ const [search, setSearch] = useState('');
29
+ const [isOpen, setIsOpen] = useState(false);
30
+ const [editingPersona, setEditingPersona] = useState<any>(null);
31
+ const [isDeleteOpen, setIsDeleteOpen] = useState(false);
32
+ const [personaToDelete, setPersonaToDelete] = useState<any>(null);
33
+
34
+ const [form, setForm] = useState({
35
+ name: '',
36
+ description: '',
37
+ prompt: '',
38
+ });
39
+
40
+ const openCreate = () => {
41
+ setEditingPersona(null);
42
+ setForm({ name: '', description: '', prompt: '' });
43
+ setIsOpen(true);
44
+ };
45
+
46
+ const openEdit = (persona: any) => {
47
+ setEditingPersona(persona);
48
+ setForm({
49
+ name: persona.name,
50
+ description: persona.description,
51
+ prompt: persona.prompt,
52
+ });
53
+ setIsOpen(true);
54
+ };
55
+
56
+ const openClone = (persona: any) => {
57
+ setEditingPersona(null);
58
+ setForm({
59
+ name: `${t.copyPrefix} ${persona.name}`,
60
+ description: persona.description,
61
+ prompt: persona.prompt,
62
+ });
63
+ setIsOpen(true);
64
+ };
65
+
66
+ const handleSave = async () => {
67
+ try {
68
+ if (!editingPersona) {
69
+ const payload = {
70
+ name: form.name,
71
+ description: form.description,
72
+ prompt: form.prompt,
73
+ type: 'persona',
74
+ };
75
+ await createPersona(payload);
76
+ } else {
77
+ await updatePersona(editingPersona._id, form);
78
+ }
79
+
80
+ setIsOpen(false);
81
+ } catch (err) {
82
+ console.error('Erro ao salvar persona', err);
83
+ }
84
+ };
85
+
86
+ const openDelete = (persona: any) => {
87
+ setPersonaToDelete(persona);
88
+ setIsDeleteOpen(true);
89
+ };
90
+
91
+ const confirmDelete = async () => {
92
+ try {
93
+ await deletePersona(personaToDelete._id);
94
+ setIsDeleteOpen(false);
95
+ setPersonaToDelete(null);
96
+ } catch (err) {
97
+ console.error('Erro ao deletar persona', err);
98
+ }
99
+ };
100
+
101
+ const filteredPersonas = personas?.filter((p) =>
102
+ p.name.toLowerCase().includes(search.toLowerCase())
103
+ );
104
+
105
+ return (
106
+ <S.Container>
107
+ <S.Header>
108
+ <div>
109
+ <h2>{t.personas?.title}</h2>
110
+ <p>{t.personas?.description}</p>
111
+ </div>
112
+ <button onClick={openCreate}>
113
+ <FaPlus /> {t.personas?.add}
114
+ </button>
115
+ </S.Header>
116
+ <Search placeholder={t.search} setFiles={setPersonas} initialFiles={personas} />
117
+ <S.List>
118
+ {filteredPersonas?.map((persona: any) => (
119
+ <S.Row key={persona.id}>
120
+ <div className="info">
121
+ <strong>{persona.name}</strong>
122
+ <span>{persona.description}</span>
123
+ </div>
124
+ {/**
125
+ * Se tiver o created_at, significa que é uma persona criada pelo usuário
126
+ * e pode ser editada ou clonada. Caso contrário, é uma persona padrão e não pode ser editada.
127
+ */}
128
+ {persona.created_at && (
129
+ <div className="actions">
130
+ <button onClick={() => openEdit(persona)}>
131
+ <FaEdit /> {t.edit}
132
+ </button>
133
+ <button onClick={() => openClone(persona)}>
134
+ <FaCopy /> {t.clone}
135
+ </button>
136
+ <button onClick={() => openDelete(persona)}>
137
+ <FaTrash /> {t.delete}
138
+ </button>
139
+ </div>
140
+ )}
141
+
142
+ </S.Row>
143
+ ))}
144
+ </S.List>
145
+
146
+ {isOpen && (
147
+ <Modal onClose={() => setIsOpen(false)} title={t.personas?.modalTitle}>
148
+ <S.InputWrapper>
149
+ <Input
150
+ value={form.name}
151
+ placeholder={t.personas?.fields.name}
152
+ onChange={(value: any) => setForm({ ...form, name: value })}
153
+ />
154
+ <Input
155
+ value={form.description}
156
+ placeholder={t.personas?.fields.description}
157
+ onChange={(value: any) => setForm({ ...form, description: value })}
158
+ />
159
+ </S.InputWrapper>
160
+ <TextArea
161
+ label={t.personas?.fields.prompt}
162
+ maxLength={10000}
163
+ value={form.prompt}
164
+ onChange={(e: any) => setForm({ ...form, prompt: e.target.value })}
165
+ />
166
+ <LengthCounter value={form.prompt} maxLength={10000} />
167
+
168
+ <S.ModalActions>
169
+ <button onClick={() => setIsOpen(false)}>{t.buttons.cancel}</button>
170
+ <button onClick={handleSave}>{t.save}</button>
171
+ </S.ModalActions>
172
+ </Modal>
173
+ )}
174
+
175
+ {isDeleteOpen && personaToDelete && (
176
+ <Modal
177
+ onClose={() => setIsDeleteOpen(false)}
178
+ title={t.delete}
179
+ >
180
+ <p>
181
+ {t.personas.modalAlert} <strong>{personaToDelete.name}</strong>?
182
+ </p>
183
+
184
+ <S.ModalActions>
185
+ <button onClick={() => setIsDeleteOpen(false)}>
186
+ {t.buttons.cancel}
187
+ </button>
188
+ <button onClick={confirmDelete}>
189
+ {t.buttons.delete}
190
+ </button>
191
+ </S.ModalActions>
192
+ </Modal>
193
+ )}
194
+ </S.Container>
195
+ );
196
+ };
@@ -0,0 +1,137 @@
1
+ import styled from 'styled-components';
2
+
3
+ export const Container = styled.div`
4
+ display: flex;
5
+ flex-direction: column;
6
+ `;
7
+
8
+ export const Header = styled.div`
9
+ display: flex;
10
+ justify-content: space-between;
11
+ align-items: center;
12
+ margin-bottom: 12px;
13
+
14
+ .infos {
15
+ display: flex;
16
+ flex-direction: column;
17
+ padding: 14px 0;
18
+
19
+ h2 {
20
+ font-size: 20px;
21
+ margin: 0;
22
+ }
23
+
24
+ p {
25
+ font-size: 14px;
26
+ margin-top: 4px;
27
+ color: #5a5d68;
28
+ }
29
+ }
30
+
31
+ button {
32
+ background: #102693;
33
+ padding: 10px 16px;
34
+ color: white;
35
+ border-radius: 4px;
36
+ height: 40px;
37
+
38
+ display: flex;
39
+ align-items: center;
40
+ gap: 8px;
41
+
42
+ svg {
43
+ width: 14px;
44
+ height: 14px;
45
+ }
46
+ }
47
+ `;
48
+
49
+ export const Search = styled.div`
50
+ width: 320px;
51
+ margin-bottom: 15px;
52
+ `;
53
+
54
+ export const List = styled.div`
55
+ display: flex;
56
+ flex-direction: column;
57
+ gap: 10px;
58
+ margin-top: 12px;
59
+ `;
60
+
61
+ export const Row = styled.div`
62
+ display: flex;
63
+ justify-content: space-between;
64
+ align-items: center;
65
+
66
+ background: #f3f5f9;
67
+ padding: 14px;
68
+ border-radius: 5px;
69
+
70
+ .info {
71
+ display: flex;
72
+ flex-direction: column;
73
+
74
+ strong {
75
+ font-size: 14px;
76
+ }
77
+
78
+ span {
79
+ font-size: 13px;
80
+ color: #5a5d68;
81
+ margin-top: 2px;
82
+ }
83
+ }
84
+
85
+ .actions {
86
+ display: flex;
87
+ gap: 8px;
88
+
89
+ button {
90
+ background: white;
91
+ border: 1px solid #dcdfe6;
92
+ padding: 6px 10px;
93
+ border-radius: 4px;
94
+
95
+ display: flex;
96
+ align-items: center;
97
+ gap: 6px;
98
+
99
+ font-size: 13px;
100
+
101
+ svg {
102
+ width: 12px;
103
+ height: 12px;
104
+ }
105
+ }
106
+ }
107
+ `;
108
+
109
+ export const ModalActions = styled.div`
110
+ display: flex;
111
+ justify-content: flex-end;
112
+ gap: 10px;
113
+ margin-top: 20px;
114
+
115
+ button {
116
+ padding: 8px 14px;
117
+ border-radius: 4px;
118
+ font-size: 14px;
119
+ }
120
+
121
+ button:first-child {
122
+ background: #e5e7eb;
123
+ }
124
+
125
+ button:last-child {
126
+ background: #102693;
127
+ color: white;
128
+ }
129
+ `;
130
+
131
+ export const InputWrapper = styled.div`
132
+ display: flex;
133
+ flex-direction: column;
134
+ gap: 12px;
135
+ margin-bottom: 12px;
136
+ max-width: 100%;
137
+ `;
@@ -0,0 +1,60 @@
1
+ import React, { useState } from 'react';
2
+ import * as S from './styles';
3
+
4
+ interface SelectOption {
5
+ value: string | number;
6
+ label: string;
7
+ }
8
+
9
+ interface SelectProps {
10
+ options: SelectOption[];
11
+ onSelect: (value: string) => void;
12
+ placeholder?: string;
13
+ }
14
+
15
+ const CustomSelect: React.FC<SelectProps> = ({
16
+ options,
17
+ onSelect,
18
+ placeholder,
19
+ }) => {
20
+ const [isOpen, setIsOpen] = useState(false);
21
+ const [selectedValue, setSelectedValue] = useState<string | number>('');
22
+
23
+ const handleSelectOption = (value: string | number) => {
24
+ const selected = String(value);
25
+ setSelectedValue(selected);
26
+ onSelect(selected);
27
+ setIsOpen(false);
28
+ };
29
+
30
+ return (
31
+ <S.Container>
32
+ <div className="custom-select" onClick={() => setIsOpen(!isOpen)}>
33
+ <div className="selected-option">
34
+ {selectedValue || placeholder}
35
+ <span className="arrow">&#9660;</span>
36
+ </div>
37
+ {isOpen && (
38
+ <div className="options">
39
+ {options?.map?.(option => (
40
+ <div
41
+ key={option.value}
42
+ style={{
43
+ background:
44
+ option.value === selectedValue ? '#a0b7f5' : undefined,
45
+ color: option.value === selectedValue ? 'white' : undefined,
46
+ }}
47
+ className="option"
48
+ onClick={() => handleSelectOption(option.value)}
49
+ >
50
+ {option.label}
51
+ </div>
52
+ ))}
53
+ </div>
54
+ )}
55
+ </div>
56
+ </S.Container>
57
+ );
58
+ };
59
+
60
+ export default CustomSelect;
@@ -0,0 +1,49 @@
1
+ import styled from 'styled-components';
2
+
3
+ export const Container = styled.div`
4
+ position: relative;
5
+ width: 50%;
6
+ margin-right: 5px;
7
+
8
+ .custom-select {
9
+ position: relative;
10
+ width: 100%;
11
+ cursor: pointer;
12
+
13
+ .selected-option {
14
+ padding: 12px;
15
+ border-radius: 4px;
16
+ border: 1px solid #979AA5;
17
+ height: 45px;
18
+ display: flex;
19
+ align-items: center;
20
+ justify-content: space-between;
21
+ font-size: 14px;
22
+ }
23
+
24
+ .options {
25
+ position: absolute;
26
+ top: 100%;
27
+ left: 0;
28
+ width: 100%;
29
+ border: 1px solid #979AA5;
30
+ border-top: none;
31
+ border-radius: 0 0 4px 4px;
32
+ background-color: #fff;
33
+ z-index: 9;
34
+
35
+ .option {
36
+ padding: 12px;
37
+ cursor: pointer;
38
+ transition: background-color 0.1s;
39
+ letter-spacing: 0.5px;
40
+ font-size: 14px;
41
+
42
+ &:hover {
43
+ background-color: #6690ff;
44
+ color: white;
45
+ }
46
+ }
47
+ }
48
+ }
49
+ `;
@@ -0,0 +1,23 @@
1
+ import React from 'react';
2
+ import * as S from './styles';
3
+
4
+ interface InputTestProps {
5
+ placeholder: string;
6
+ onChange: (value: string) => void;
7
+ value?: string;
8
+ }
9
+
10
+ const InputTest: React.FC<InputTestProps> = ({ placeholder, onChange, value }) => {
11
+ return (
12
+ <S.Container>
13
+ <S.StyledInput
14
+ type="text"
15
+ value={value}
16
+ onChange={(e: any) => onChange(e.target.value)}
17
+ placeholder={placeholder}
18
+ />
19
+ </S.Container>
20
+ );
21
+ };
22
+
23
+ export default InputTest;
@@ -0,0 +1,28 @@
1
+ import styled from 'styled-components';
2
+
3
+ export const Container = styled.div`
4
+ position: relative;
5
+ width: 100%;
6
+ margin-right: 5px;
7
+ `;
8
+
9
+ export const StyledInput = styled.input`
10
+ padding-left: 10px;
11
+ padding-right: 40px;
12
+ border-radius: 5px;
13
+ border: 1px solid #ccc;
14
+ height: 45px;
15
+ width: 100%;
16
+
17
+ &:focus {
18
+ outline: none;
19
+ box-shadow: 0 0 0 3px #6690ff;
20
+ }
21
+ `;
22
+
23
+ export const RecordAudioButton = styled.div`
24
+ position: absolute;
25
+ top: 14px;
26
+ right: 10px;
27
+ cursor: pointer;
28
+ `;
@@ -0,0 +1,97 @@
1
+ import React, { forwardRef, ReactNode } from 'react';
2
+ import cc from 'classcat';
3
+
4
+ import {
5
+ Container,
6
+ LabelWrapper,
7
+ CustomTextArea,
8
+ InputWrapper,
9
+ Helper,
10
+ Error,
11
+ } from './styles';
12
+
13
+ type TextAreaProps = {
14
+ id?: string;
15
+ label?: string;
16
+ placeholder?: string;
17
+ className?: string;
18
+ description?: string;
19
+ helper?: string;
20
+ error?: string;
21
+ color?: '' | 'danger' | 'success';
22
+ size?: 'small' | 'medium' | 'large';
23
+ startIcon?: string | ReactNode;
24
+ endIcon?: string | ReactNode;
25
+ disabled?: boolean;
26
+ marginBottom?: string;
27
+ rows?: number;
28
+ } & React.TextareaHTMLAttributes<HTMLTextAreaElement>;
29
+
30
+ const TextArea: React.FC<TextAreaProps> = forwardRef<HTMLTextAreaElement, TextAreaProps>(
31
+ (
32
+ {
33
+ id,
34
+ label,
35
+ description,
36
+ helper,
37
+ error,
38
+ placeholder,
39
+ className,
40
+ size = 'medium',
41
+ color = '',
42
+ disabled = false,
43
+ startIcon,
44
+ endIcon,
45
+ marginBottom = '3px',
46
+ rows = 4,
47
+ ...props
48
+ },
49
+ ref
50
+ ) => {
51
+ const selfId = id || `input__${Math.random().toString(36).substr(2, 9)}`;
52
+
53
+ return (
54
+ <Container className={className} marginBottom={marginBottom}>
55
+ {label && (
56
+ <LabelWrapper htmlFor={selfId}>
57
+ <span className="label">{label}</span>
58
+ {description && <span className="description">{description}</span>}
59
+ </LabelWrapper>
60
+ )}
61
+
62
+ <InputWrapper className={cc({ hasLabel: Boolean(label) })}>
63
+ <CustomTextArea
64
+ className={cc([
65
+ 'input',
66
+ size,
67
+ color,
68
+ {
69
+ error: Boolean(error),
70
+ 'has-start-icon': Boolean(startIcon),
71
+ 'has-end-icon': Boolean(endIcon),
72
+ },
73
+ ])}
74
+ id={selfId}
75
+ placeholder={placeholder}
76
+ disabled={disabled}
77
+ rows={rows}
78
+ ref={ref}
79
+ {...props}
80
+ />
81
+ {startIcon && (
82
+ <span className={cc(['icon', 'start-icon'])}>{startIcon}</span>
83
+ )}
84
+ {endIcon && (
85
+ <span className={cc(['icon', 'end-icon'])}>{endIcon}</span>
86
+ )}
87
+ </InputWrapper>
88
+
89
+ {helper && <Helper className={cc(['helper', color])}>{helper}</Helper>}
90
+
91
+ {error && <Error className={cc(['error'])}>{error}</Error>}
92
+ </Container>
93
+ );
94
+ }
95
+ );
96
+
97
+ export default TextArea;