@controleonline/ui-customers 1.0.81
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/.github/agents/developer.agent.md +30 -0
- package/.github/agents/devops.agent.md +30 -0
- package/.github/agents/qa.agent.md +30 -0
- package/.github/agents/security.agent.md +30 -0
- package/.scrutinizer.yml +20 -0
- package/AGENTS.md +50 -0
- package/FUNDING.yml +1 -0
- package/README.md +23 -0
- package/docs/technical/Client-Details-Franquia-Filial.md +18 -0
- package/docs/technical/Client-Details-People-Name-Case.md +103 -0
- package/docs/technical/Cliente-Vendedor-Vinculo-e-Permissoes.md +152 -0
- package/docs/wiki.md +1 -0
- package/package.json +32 -0
- package/scripts/validate-wiki-pointer.cjs +13 -0
- package/src/react/components/tabs/AddressesTab.js +494 -0
- package/src/react/components/tabs/CategoriesTab.js +196 -0
- package/src/react/components/tabs/ClassificationChips.js +494 -0
- package/src/react/components/tabs/ContactTab.js +621 -0
- package/src/react/components/tabs/ContactTab.styles.js +119 -0
- package/src/react/components/tabs/ContractsTab.js +13 -0
- package/src/react/components/tabs/DocumentsTab.js +463 -0
- package/src/react/components/tabs/DocumentsTab.styles.js +133 -0
- package/src/react/components/tabs/EmployeeContactRow.js +83 -0
- package/src/react/components/tabs/EmployeesTab.js +454 -0
- package/src/react/components/tabs/EmployeesTab.styles.js +172 -0
- package/src/react/components/tabs/FiscalTab.js +6 -0
- package/src/react/components/tabs/FranchiseCommissionSection.js +307 -0
- package/src/react/components/tabs/FranchiseLinksManageModal.js +215 -0
- package/src/react/components/tabs/FranchiseLinksTab.js +282 -0
- package/src/react/components/tabs/GeneralTab.js +466 -0
- package/src/react/components/tabs/GeneralTab.styles.js +101 -0
- package/src/react/components/tabs/MediaTab.js +356 -0
- package/src/react/components/tabs/PeopleCategoriesPanel.js +601 -0
- package/src/react/components/tabs/ProductsTab.js +236 -0
- package/src/react/components/tabs/ProductsTab.styles.js +143 -0
- package/src/react/components/tabs/SalesmanCommissionBlock.js +120 -0
- package/src/react/components/tabs/SalesmanManageModal.js +208 -0
- package/src/react/components/tabs/SalesmanTab.js +436 -0
- package/src/react/components/tabs/SalesmanTab.styles.js +4 -0
- package/src/react/components/tabs/UserApiKeyModal.js +90 -0
- package/src/react/components/tabs/UserFormModal.js +301 -0
- package/src/react/components/tabs/UsersTab.js +426 -0
- package/src/react/components/tabs/UsersTab.styles.js +283 -0
- package/src/react/components/tabs/UsersTab.styles.test.js +42 -0
- package/src/react/components/tabs/contactMutationMessage.js +18 -0
- package/src/react/components/tabs/employeeContacts.js +214 -0
- package/src/react/components/tabs/employeeUnlink.js +68 -0
- package/src/react/components/tabs/employeesTabHelpers.js +227 -0
- package/src/react/components/tabs/franchiseCommissionHelpers.js +134 -0
- package/src/react/components/tabs/franchiseLinksTab.helpers.js +247 -0
- package/src/react/components/tabs/generalTabHelpers.js +120 -0
- package/src/react/components/tabs/salesmanTab.helpers.js +114 -0
- package/src/react/components/tabs/salesmanTabHelpers.js +173 -0
- package/src/react/components/tabs/salesmanTabMedia.js +55 -0
- package/src/react/components/tabs/salesmanTabSession.js +39 -0
- package/src/react/components/tabs/useEmployeeUnlink.js +58 -0
- package/src/react/components/tabs/useFranchiseLinksManage.js +215 -0
- package/src/react/components/tabs/useSalesmanManage.js +222 -0
- package/src/react/components/tabs/usersTabHelpers.js +221 -0
- package/src/react/domain/productSupplierFlow.js +37 -0
- package/src/react/index.js +4 -0
- package/src/react/pages/ClientDetailsSkeleton.js +84 -0
- package/src/react/pages/clientDetailsHelpers.js +17 -0
- package/src/react/pages/clients.js +27 -0
- package/src/react/pages/details.js +529 -0
- package/src/react/pages/details.page.styles.js +105 -0
- package/src/react/pages/details.styles.js +15 -0
- package/src/react/pages/employees.js +69 -0
- package/src/react/pages/franchisees.js +30 -0
- package/src/react/pages/prospects.js +21 -0
- package/src/react/pages/provider.js +21 -0
- package/src/react/router/routes.js +104 -0
- package/src/react/styles/details.js +571 -0
- package/src/store/people_categories/index.js +72 -0
- package/src/tests/browser/manager/client-details-create-user.spec.js +321 -0
- package/src/tests/browser/manager/client-details-employee-unlink.spec.js +215 -0
- package/src/tests/browser/manager/client-details-employees-refresh.spec.js +271 -0
- package/src/tests/browser/manager/client-details-enable.spec.js +241 -0
- package/src/tests/browser/manager/client-details-fiscal-tabs.spec.js +410 -0
- package/src/tests/browser/manager/client-details-franchise-commission.spec.js +318 -0
- package/src/tests/browser/manager/client-details-franchise-links.spec.js +365 -0
- package/src/tests/browser/manager/client-details-media.spec.js +405 -0
- package/src/tests/browser/manager/client-details-relationships.spec.js +313 -0
- package/src/tests/browser/manager/client-details-salesman-commission.spec.js +291 -0
- package/src/tests/browser/manager/client-details-salesman-manage.spec.js +448 -0
- package/src/tests/react/components/tabs/contactMutationMessage.test.js +25 -0
- package/src/tests/react/components/tabs/employeeContacts.test.js +266 -0
- package/src/tests/react/components/tabs/employeeUnlink.test.js +67 -0
- package/src/tests/react/components/tabs/employeesTabHelpers.media.test.js +78 -0
- package/src/tests/react/components/tabs/employeesTabHelpers.test.js +64 -0
- package/src/tests/react/components/tabs/fiscalTabContract.test.mjs +29 -0
- package/src/tests/react/components/tabs/franchiseCommissionHelpers.test.js +128 -0
- package/src/tests/react/components/tabs/franchiseLinksTab.helpers.test.mjs +166 -0
- package/src/tests/react/components/tabs/generalTabHelpers.test.js +130 -0
- package/src/tests/react/components/tabs/peopleMediaTabs.test.js +322 -0
- package/src/tests/react/components/tabs/salesmanTab.helpers.test.mjs +75 -0
- package/src/tests/react/components/tabs/salesmanTabHelpers.test.js +142 -0
- package/src/tests/react/components/tabs/salesmanTabHelpers.test.mjs +92 -0
- package/src/tests/react/components/tabs/usersTabHelpers.test.js +59 -0
- package/src/tests/react/domain/productSupplierFlow.test.mjs +55 -0
- package/src/tests/react/pages/clientDetailsHelpers.test.js +98 -0
- package/src/tests/react/pages/employees.test.js +44 -0
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
Text,
|
|
5
|
+
TouchableOpacity,
|
|
6
|
+
View,
|
|
7
|
+
} from 'react-native';
|
|
8
|
+
|
|
9
|
+
import FeatherIcon from 'react-native-vector-icons/Feather';
|
|
10
|
+
import Icon from 'react-native-vector-icons/MaterialIcons';
|
|
11
|
+
import { useStores } from '@store';
|
|
12
|
+
import {useMessage} from '@controleonline/ui-common/src/react/components/MessageService';
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
import {
|
|
16
|
+
copyTextToClipboard,
|
|
17
|
+
extractCollectionItems,
|
|
18
|
+
extractErrorMessage,
|
|
19
|
+
extractId,
|
|
20
|
+
mapUsersForClient,
|
|
21
|
+
normalizeUserItem,
|
|
22
|
+
toPeopleIri,
|
|
23
|
+
toTimezoneIri,
|
|
24
|
+
buildUsersListQuery,
|
|
25
|
+
embeddedUsersFromClient,
|
|
26
|
+
} from './usersTabHelpers';
|
|
27
|
+
import UserFormModal from './UserFormModal';
|
|
28
|
+
import UserApiKeyModal from './UserApiKeyModal';
|
|
29
|
+
|
|
30
|
+
const UsersTab = ({ client, customStyles, isEditing, onUpdateClient }) => {
|
|
31
|
+
const {showError, showSuccess, showDialog} = useMessage();
|
|
32
|
+
const [users, setUsers] = useState([]);
|
|
33
|
+
const [showModal, setShowModal] = useState(false);
|
|
34
|
+
const [showApiKeyModal, setShowApiKeyModal] = useState(false);
|
|
35
|
+
const [editingItem, setEditingItem] = useState(null);
|
|
36
|
+
const [apiKeyItem, setApiKeyItem] = useState(null);
|
|
37
|
+
const [formData, setFormData] = useState({});
|
|
38
|
+
const [showPassword, setShowPassword] = useState(false);
|
|
39
|
+
const [showConfirmPassword, setShowConfirmPassword] = useState(false);
|
|
40
|
+
const [isRefreshingApiKey, setIsRefreshingApiKey] = useState(false);
|
|
41
|
+
const [isLoadingUsers, setIsLoadingUsers] = useState(false);
|
|
42
|
+
const [usersError, setUsersError] = useState('');
|
|
43
|
+
|
|
44
|
+
const usersStore = useStores(state => state.users) || {};
|
|
45
|
+
const actions = usersStore.actions || {};
|
|
46
|
+
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
const query = buildUsersListQuery(client);
|
|
49
|
+
const fallbackUsers = embeddedUsersFromClient(client);
|
|
50
|
+
let mounted = true;
|
|
51
|
+
|
|
52
|
+
if (!query || typeof actions.getItems !== 'function') {
|
|
53
|
+
setUsers(fallbackUsers);
|
|
54
|
+
setUsersError('');
|
|
55
|
+
setIsLoadingUsers(false);
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
setIsLoadingUsers(true);
|
|
60
|
+
setUsersError('');
|
|
61
|
+
|
|
62
|
+
actions
|
|
63
|
+
.getItems(query)
|
|
64
|
+
.then(response => {
|
|
65
|
+
if (!mounted) return;
|
|
66
|
+
const entries = extractCollectionItems(response);
|
|
67
|
+
setUsers(entries.map(normalizeUserItem).filter(Boolean));
|
|
68
|
+
})
|
|
69
|
+
.catch(error => {
|
|
70
|
+
if (!mounted) return;
|
|
71
|
+
setUsersError(
|
|
72
|
+
extractErrorMessage(error) || 'Falha ao carregar usuários. Tente novamente.',
|
|
73
|
+
);
|
|
74
|
+
setUsers(fallbackUsers);
|
|
75
|
+
})
|
|
76
|
+
.finally(() => {
|
|
77
|
+
if (mounted) setIsLoadingUsers(false);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
return () => {
|
|
81
|
+
mounted = false;
|
|
82
|
+
};
|
|
83
|
+
}, [actions.getItems, client?.id, client?.['@id']]);
|
|
84
|
+
|
|
85
|
+
const syncUsers = nextUsers => {
|
|
86
|
+
setUsers(nextUsers);
|
|
87
|
+
onUpdateClient?.('user', mapUsersForClient(nextUsers));
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const openModal = (item = null) => {
|
|
91
|
+
setEditingItem(item);
|
|
92
|
+
setFormData(item ? { ...item, username: item.username || item.name } : {});
|
|
93
|
+
setShowPassword(false);
|
|
94
|
+
setShowConfirmPassword(false);
|
|
95
|
+
setShowModal(true);
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const closeModal = () => {
|
|
99
|
+
setShowModal(false);
|
|
100
|
+
setEditingItem(null);
|
|
101
|
+
setFormData({});
|
|
102
|
+
setShowPassword(false);
|
|
103
|
+
setShowConfirmPassword(false);
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const openApiKeyModal = item => {
|
|
107
|
+
setApiKeyItem(item || null);
|
|
108
|
+
setShowApiKeyModal(true);
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
const closeApiKeyModal = () => {
|
|
112
|
+
setApiKeyItem(null);
|
|
113
|
+
setShowApiKeyModal(false);
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
const handleSave = async () => {
|
|
118
|
+
if (!editingItem) {
|
|
119
|
+
if (formData.password !== formData.confirmPassword) {
|
|
120
|
+
showError('As senhas não coincidem.');
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (!formData.username || !formData.password) {
|
|
125
|
+
showError('Nome de usuário e senha são obrigatórios.');
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const timezoneIri = toTimezoneIri(formData.timezoneId);
|
|
130
|
+
if (!timezoneIri) {
|
|
131
|
+
showError('Timezone é obrigatório.');
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
try {
|
|
136
|
+
const userData = {
|
|
137
|
+
username: formData.username,
|
|
138
|
+
password: formData.password,
|
|
139
|
+
confirmPassword: formData.confirmPassword,
|
|
140
|
+
people: toPeopleIri(client?.id || client?.['@id']),
|
|
141
|
+
timezone: timezoneIri,
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
if (!userData.people) {
|
|
145
|
+
showError('Nao foi possivel identificar a pessoa para criar o usuario.');
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const createdUser = normalizeUserItem(await actions.createUser(userData)) || {
|
|
150
|
+
id: `temp-${Date.now()}`,
|
|
151
|
+
username: formData.username,
|
|
152
|
+
name: formData.username,
|
|
153
|
+
role: 'Usuario',
|
|
154
|
+
apiKey: '',
|
|
155
|
+
};
|
|
156
|
+
const updatedUsers = [...users, createdUser];
|
|
157
|
+
syncUsers(updatedUsers);
|
|
158
|
+
|
|
159
|
+
showSuccess('Usuário criado com sucesso!');
|
|
160
|
+
closeModal();
|
|
161
|
+
} catch (error) {
|
|
162
|
+
showError(extractErrorMessage(error) || 'Falha ao criar usuário. Tente novamente.');
|
|
163
|
+
}
|
|
164
|
+
} else {
|
|
165
|
+
try {
|
|
166
|
+
if (!String(formData.password || '').trim()) {
|
|
167
|
+
showError('Nova senha é obrigatória.');
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (
|
|
172
|
+
formData.password &&
|
|
173
|
+
formData.password !== formData.confirmPassword
|
|
174
|
+
) {
|
|
175
|
+
showError('As senhas não coincidem.');
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (formData.password) {
|
|
180
|
+
const savedUser = normalizeUserItem(await actions.changePassword({
|
|
181
|
+
id: editingItem.id,
|
|
182
|
+
password: formData.password,
|
|
183
|
+
active: true,
|
|
184
|
+
confirmPassword: formData.confirmPassword,
|
|
185
|
+
}));
|
|
186
|
+
|
|
187
|
+
const updatedUser = {
|
|
188
|
+
...editingItem,
|
|
189
|
+
...savedUser,
|
|
190
|
+
username: savedUser?.username || editingItem.username,
|
|
191
|
+
name: savedUser?.username || editingItem.name,
|
|
192
|
+
apiKey: savedUser?.apiKey || editingItem.apiKey,
|
|
193
|
+
};
|
|
194
|
+
const updatedUsers = users.map(u =>
|
|
195
|
+
String(u.id) === String(editingItem.id) ? updatedUser : u,
|
|
196
|
+
);
|
|
197
|
+
syncUsers(updatedUsers);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
showSuccess('Senha do usuário atualizada com sucesso!');
|
|
201
|
+
closeModal();
|
|
202
|
+
} catch (error) {
|
|
203
|
+
showError(extractErrorMessage(error) || 'Falha ao atualizar usuário. Tente novamente.');
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
const handleCopyApiKey = async () => {
|
|
209
|
+
const currentApiKey = String(apiKeyItem?.apiKey || '').trim();
|
|
210
|
+
if (!currentApiKey) {
|
|
211
|
+
showError('Nenhuma chave de API disponivel para copiar.');
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
try {
|
|
216
|
+
const copied = await copyTextToClipboard(currentApiKey);
|
|
217
|
+
if (!copied) {
|
|
218
|
+
showError('A copia da chave de API esta disponivel apenas no navegador nesta versao.');
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
showSuccess('Chave de API copiada com sucesso!');
|
|
223
|
+
} catch (error) {
|
|
224
|
+
showError(extractErrorMessage(error) || 'Nao foi possivel copiar a chave de API.');
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
const handleRefreshApiKey = item => {
|
|
229
|
+
if (!item?.id) {
|
|
230
|
+
showError('Nao foi possivel identificar o usuario para atualizar a chave de API.');
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
showDialog({
|
|
235
|
+
title: 'Gerar nova chave de API',
|
|
236
|
+
message:
|
|
237
|
+
'Ao confirmar, a chave atual deixara de funcionar imediatamente. Deseja continuar?',
|
|
238
|
+
onConfirm: async () => {
|
|
239
|
+
setIsRefreshingApiKey(true);
|
|
240
|
+
|
|
241
|
+
try {
|
|
242
|
+
const savedUser = normalizeUserItem(
|
|
243
|
+
await actions.changeApiKey({ id: item.id }),
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
if (!savedUser) {
|
|
247
|
+
throw new Error('A nova chave de API nao foi retornada pela API.');
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
let nextActiveApiKeyItem = null;
|
|
251
|
+
const updatedUsers = users.map(user => {
|
|
252
|
+
if (String(user.id) !== String(item.id)) {
|
|
253
|
+
return user;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
nextActiveApiKeyItem = {
|
|
257
|
+
...user,
|
|
258
|
+
...savedUser,
|
|
259
|
+
username: savedUser.username || user.username,
|
|
260
|
+
name: savedUser.username || user.name,
|
|
261
|
+
apiKey: savedUser.apiKey || user.apiKey,
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
return nextActiveApiKeyItem;
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
syncUsers(updatedUsers);
|
|
268
|
+
if (nextActiveApiKeyItem) {
|
|
269
|
+
setApiKeyItem(nextActiveApiKeyItem);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
showSuccess('Chave de API atualizada com sucesso!');
|
|
273
|
+
} catch (error) {
|
|
274
|
+
showError(
|
|
275
|
+
extractErrorMessage(error) ||
|
|
276
|
+
'Falha ao atualizar a chave de API. Tente novamente.',
|
|
277
|
+
);
|
|
278
|
+
} finally {
|
|
279
|
+
setIsRefreshingApiKey(false);
|
|
280
|
+
}
|
|
281
|
+
},
|
|
282
|
+
});
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
const handleDelete = id => {
|
|
286
|
+
showDialog({
|
|
287
|
+
title: 'Confirmar exclusão',
|
|
288
|
+
message: 'Deseja realmente remover este item?',
|
|
289
|
+
confirmLabel: 'Remover',
|
|
290
|
+
cancelLabel: 'Cancelar',
|
|
291
|
+
onConfirm: async () => {
|
|
292
|
+
try {
|
|
293
|
+
await actions.remove(id);
|
|
294
|
+
const updatedUsers = users.filter(u => u.id !== id);
|
|
295
|
+
syncUsers(updatedUsers);
|
|
296
|
+
showSuccess('Usuário removido com sucesso!');
|
|
297
|
+
} catch (error) {
|
|
298
|
+
showError(extractErrorMessage(error) || 'Falha ao remover usuário. Tente novamente.');
|
|
299
|
+
}
|
|
300
|
+
},
|
|
301
|
+
});
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
const renderModals = () => (
|
|
305
|
+
<>
|
|
306
|
+
<UserFormModal
|
|
307
|
+
visible={showModal}
|
|
308
|
+
onClose={closeModal}
|
|
309
|
+
editingItem={editingItem}
|
|
310
|
+
formData={formData}
|
|
311
|
+
setFormData={setFormData}
|
|
312
|
+
showPassword={showPassword}
|
|
313
|
+
setShowPassword={setShowPassword}
|
|
314
|
+
showConfirmPassword={showConfirmPassword}
|
|
315
|
+
setShowConfirmPassword={setShowConfirmPassword}
|
|
316
|
+
onSave={handleSave}
|
|
317
|
+
/>
|
|
318
|
+
<UserApiKeyModal
|
|
319
|
+
visible={showApiKeyModal}
|
|
320
|
+
onClose={closeApiKeyModal}
|
|
321
|
+
apiKeyItem={apiKeyItem}
|
|
322
|
+
isRefreshingApiKey={isRefreshingApiKey}
|
|
323
|
+
onCopy={handleCopyApiKey}
|
|
324
|
+
onRefresh={handleRefreshApiKey}
|
|
325
|
+
/>
|
|
326
|
+
</>
|
|
327
|
+
);
|
|
328
|
+
|
|
329
|
+
return (
|
|
330
|
+
<>
|
|
331
|
+
<View style={customStyles.tabContent}>
|
|
332
|
+
<View style={customStyles.section}>
|
|
333
|
+
<View style={customStyles.sectionHeader}>
|
|
334
|
+
<Text style={customStyles.sectionTitle}>Usuários</Text>
|
|
335
|
+
{isEditing && (
|
|
336
|
+
<TouchableOpacity
|
|
337
|
+
onPress={() => openModal()}
|
|
338
|
+
style={customStyles.iconButtonPrimary}>
|
|
339
|
+
<FeatherIcon
|
|
340
|
+
name="plus"
|
|
341
|
+
size={16}
|
|
342
|
+
color={customStyles.iconButtonPrimaryIcon.color}
|
|
343
|
+
/>
|
|
344
|
+
</TouchableOpacity>
|
|
345
|
+
)}
|
|
346
|
+
</View>
|
|
347
|
+
{usersError ? (
|
|
348
|
+
<Text style={customStyles.emptyText}>{usersError}</Text>
|
|
349
|
+
) : null}
|
|
350
|
+
{isLoadingUsers ? (
|
|
351
|
+
<Text testID="users-tab-loading" style={customStyles.emptyText}>
|
|
352
|
+
Carregando usuários...
|
|
353
|
+
</Text>
|
|
354
|
+
) : users.length === 0 ? (
|
|
355
|
+
<Text testID="users-tab-empty" style={customStyles.emptyText}>
|
|
356
|
+
Nenhum usuário cadastrado
|
|
357
|
+
</Text>
|
|
358
|
+
) : (
|
|
359
|
+
users.map(user => (
|
|
360
|
+
<View
|
|
361
|
+
key={user.id}
|
|
362
|
+
style={[
|
|
363
|
+
customStyles.listItem,
|
|
364
|
+
customStyles.listItemWithActions,
|
|
365
|
+
]}>
|
|
366
|
+
<View style={customStyles.itemContent}>
|
|
367
|
+
<Icon
|
|
368
|
+
name="person"
|
|
369
|
+
size={20}
|
|
370
|
+
color={customStyles.cardItemIcon.color}
|
|
371
|
+
/>
|
|
372
|
+
<View>
|
|
373
|
+
<Text style={customStyles.itemText}>
|
|
374
|
+
{String(user.username || user.name || '')}
|
|
375
|
+
</Text>
|
|
376
|
+
<Text style={customStyles.itemSubtext}>
|
|
377
|
+
{String(user.role || '')}
|
|
378
|
+
</Text>
|
|
379
|
+
</View>
|
|
380
|
+
</View>
|
|
381
|
+
{isEditing && (
|
|
382
|
+
<View
|
|
383
|
+
style={[
|
|
384
|
+
customStyles.itemActions,
|
|
385
|
+
customStyles.itemActionsPinned,
|
|
386
|
+
]}>
|
|
387
|
+
<TouchableOpacity
|
|
388
|
+
onPress={() => openModal(user)}
|
|
389
|
+
style={customStyles.iconButtonGhost}>
|
|
390
|
+
<FeatherIcon
|
|
391
|
+
name="edit-2"
|
|
392
|
+
size={16}
|
|
393
|
+
color={customStyles.iconButtonGhostIcon.color}
|
|
394
|
+
/>
|
|
395
|
+
</TouchableOpacity>
|
|
396
|
+
<TouchableOpacity
|
|
397
|
+
onPress={() => openApiKeyModal(user)}
|
|
398
|
+
style={customStyles.iconButtonGhost}>
|
|
399
|
+
<FeatherIcon
|
|
400
|
+
name="eye"
|
|
401
|
+
size={16}
|
|
402
|
+
color={customStyles.iconButtonGhostIcon.color}
|
|
403
|
+
/>
|
|
404
|
+
</TouchableOpacity>
|
|
405
|
+
<TouchableOpacity
|
|
406
|
+
onPress={() => handleDelete(user.id)}
|
|
407
|
+
style={customStyles.iconButtonGhost}>
|
|
408
|
+
<FeatherIcon
|
|
409
|
+
name="trash-2"
|
|
410
|
+
size={16}
|
|
411
|
+
color={customStyles.iconButtonGhostIcon.color}
|
|
412
|
+
/>
|
|
413
|
+
</TouchableOpacity>
|
|
414
|
+
</View>
|
|
415
|
+
)}
|
|
416
|
+
</View>
|
|
417
|
+
))
|
|
418
|
+
)}
|
|
419
|
+
</View>
|
|
420
|
+
</View>
|
|
421
|
+
{renderModals()}
|
|
422
|
+
</>
|
|
423
|
+
);
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
export default UsersTab;
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
export const inlineStyle_174_6 = {
|
|
2
|
+
justifyContent: 'flex-end',
|
|
3
|
+
};
|
|
4
|
+
|
|
5
|
+
export const inlineStyle_175_12 = {
|
|
6
|
+
backgroundColor: '#fff',
|
|
7
|
+
borderTopLeftRadius: 24,
|
|
8
|
+
borderTopRightRadius: 24,
|
|
9
|
+
maxHeight: '80%',
|
|
10
|
+
width: '100%',
|
|
11
|
+
shadowColor: '#000',
|
|
12
|
+
|
|
13
|
+
shadowOffset: {
|
|
14
|
+
width: 0,
|
|
15
|
+
height: -4,
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
shadowOpacity: 0.1,
|
|
19
|
+
shadowRadius: 12,
|
|
20
|
+
elevation: 10,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const inlineStyle_188_14 = {
|
|
24
|
+
flexDirection: 'row',
|
|
25
|
+
alignItems: 'center',
|
|
26
|
+
justifyContent: 'space-between',
|
|
27
|
+
paddingHorizontal: 24,
|
|
28
|
+
paddingVertical: 20,
|
|
29
|
+
borderBottomWidth: 1,
|
|
30
|
+
borderBottomColor: '#F1F5F9',
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const inlineStyle_197_16 = {
|
|
34
|
+
fontSize: 20,
|
|
35
|
+
fontWeight: '700',
|
|
36
|
+
color: '#0F172A',
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const inlineStyle_200_49 = {
|
|
40
|
+
width: 32,
|
|
41
|
+
height: 32,
|
|
42
|
+
borderRadius: 16,
|
|
43
|
+
backgroundColor: '#F1F5F9',
|
|
44
|
+
alignItems: 'center',
|
|
45
|
+
justifyContent: 'center',
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export const inlineStyle_208_10 = {
|
|
49
|
+
padding: 24,
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export const inlineStyle_213_20 = {
|
|
53
|
+
marginBottom: 20,
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export const inlineStyle_214_22 = {
|
|
57
|
+
fontSize: 16,
|
|
58
|
+
fontWeight: '600',
|
|
59
|
+
color: '#212529',
|
|
60
|
+
marginBottom: 8,
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export const inlineStyle_216_18 = {
|
|
64
|
+
borderWidth: 1,
|
|
65
|
+
borderColor: '#e9ecef',
|
|
66
|
+
borderRadius: 12,
|
|
67
|
+
paddingHorizontal: 16,
|
|
68
|
+
paddingVertical: 12,
|
|
69
|
+
fontSize: 16,
|
|
70
|
+
backgroundColor: '#e9ecef',
|
|
71
|
+
color: '#6c757d',
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export const inlineStyle_224_20 = {
|
|
75
|
+
marginBottom: 20,
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export const inlineStyle_225_22 = {
|
|
79
|
+
fontSize: 16,
|
|
80
|
+
fontWeight: '600',
|
|
81
|
+
color: '#212529',
|
|
82
|
+
marginBottom: 8,
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
export const inlineStyle_226_22 = {
|
|
86
|
+
position: 'relative',
|
|
87
|
+
justifyContent: 'center',
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
export const inlineStyle_228_20 = {
|
|
91
|
+
borderWidth: 1,
|
|
92
|
+
borderColor: '#e9ecef',
|
|
93
|
+
borderRadius: 12,
|
|
94
|
+
paddingHorizontal: 16,
|
|
95
|
+
paddingVertical: 12,
|
|
96
|
+
paddingRight: 48,
|
|
97
|
+
fontSize: 16,
|
|
98
|
+
backgroundColor: '#f8f9fa',
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
export const inlineStyle_239_20 = {
|
|
102
|
+
position: 'absolute',
|
|
103
|
+
right: 14,
|
|
104
|
+
alignSelf: 'stretch',
|
|
105
|
+
justifyContent: 'center',
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
export const inlineStyle_248_20 = {
|
|
109
|
+
marginBottom: 24,
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
export const inlineStyle_249_22 = {
|
|
113
|
+
fontSize: 16,
|
|
114
|
+
fontWeight: '600',
|
|
115
|
+
color: '#212529',
|
|
116
|
+
marginBottom: 8,
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
export const inlineStyle_250_22 = {
|
|
120
|
+
position: 'relative',
|
|
121
|
+
justifyContent: 'center',
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
export const inlineStyle_252_20 = {
|
|
125
|
+
borderWidth: 1,
|
|
126
|
+
borderColor: '#e9ecef',
|
|
127
|
+
borderRadius: 12,
|
|
128
|
+
paddingHorizontal: 16,
|
|
129
|
+
paddingVertical: 12,
|
|
130
|
+
paddingRight: 48,
|
|
131
|
+
fontSize: 16,
|
|
132
|
+
backgroundColor: '#f8f9fa',
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
export const inlineStyle_263_20 = {
|
|
136
|
+
position: 'absolute',
|
|
137
|
+
right: 14,
|
|
138
|
+
alignSelf: 'stretch',
|
|
139
|
+
justifyContent: 'center',
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
export const inlineStyle_275_20 = {
|
|
143
|
+
marginBottom: 20,
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
export const inlineStyle_276_22 = {
|
|
147
|
+
fontSize: 16,
|
|
148
|
+
fontWeight: '600',
|
|
149
|
+
color: '#212529',
|
|
150
|
+
marginBottom: 8,
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
export const inlineStyle_278_18 = {
|
|
154
|
+
borderWidth: 1,
|
|
155
|
+
borderColor: '#e9ecef',
|
|
156
|
+
borderRadius: 12,
|
|
157
|
+
paddingHorizontal: 16,
|
|
158
|
+
paddingVertical: 12,
|
|
159
|
+
fontSize: 16,
|
|
160
|
+
backgroundColor: '#f8f9fa',
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
export const inlineStyle_288_20 = {
|
|
164
|
+
marginBottom: 20,
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
export const inlineStyle_289_22 = {
|
|
168
|
+
fontSize: 16,
|
|
169
|
+
fontWeight: '600',
|
|
170
|
+
color: '#212529',
|
|
171
|
+
marginBottom: 8,
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
export const inlineStyle_290_22 = {
|
|
175
|
+
position: 'relative',
|
|
176
|
+
justifyContent: 'center',
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
export const inlineStyle_292_20 = {
|
|
180
|
+
borderWidth: 1,
|
|
181
|
+
borderColor: '#e9ecef',
|
|
182
|
+
borderRadius: 12,
|
|
183
|
+
paddingHorizontal: 16,
|
|
184
|
+
paddingVertical: 12,
|
|
185
|
+
paddingRight: 48,
|
|
186
|
+
fontSize: 16,
|
|
187
|
+
backgroundColor: '#f8f9fa',
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
export const inlineStyle_303_20 = {
|
|
191
|
+
position: 'absolute',
|
|
192
|
+
right: 14,
|
|
193
|
+
alignSelf: 'stretch',
|
|
194
|
+
justifyContent: 'center',
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
export const inlineStyle_312_20 = {
|
|
198
|
+
marginBottom: 24,
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
export const inlineStyle_313_22 = {
|
|
202
|
+
fontSize: 16,
|
|
203
|
+
fontWeight: '600',
|
|
204
|
+
color: '#212529',
|
|
205
|
+
marginBottom: 8,
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
export const inlineStyle_314_22 = {
|
|
209
|
+
position: 'relative',
|
|
210
|
+
justifyContent: 'center',
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
export const inlineStyle_316_20 = {
|
|
214
|
+
borderWidth: 1,
|
|
215
|
+
borderColor: '#e9ecef',
|
|
216
|
+
borderRadius: 12,
|
|
217
|
+
paddingHorizontal: 16,
|
|
218
|
+
paddingVertical: 12,
|
|
219
|
+
paddingRight: 48,
|
|
220
|
+
fontSize: 16,
|
|
221
|
+
backgroundColor: '#f8f9fa',
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
export const inlineStyle_327_20 = {
|
|
225
|
+
position: 'absolute',
|
|
226
|
+
right: 14,
|
|
227
|
+
alignSelf: 'stretch',
|
|
228
|
+
justifyContent: 'center',
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
export const inlineStyle_339_16 = {
|
|
232
|
+
flexDirection: 'row',
|
|
233
|
+
gap: 12,
|
|
234
|
+
paddingHorizontal: 24,
|
|
235
|
+
paddingTop: 12,
|
|
236
|
+
paddingBottom: 24,
|
|
237
|
+
borderTopWidth: 1,
|
|
238
|
+
borderTopColor: '#F1F5F9',
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
export const inlineStyle_341_14 = {
|
|
242
|
+
flex: 1,
|
|
243
|
+
paddingVertical: 14,
|
|
244
|
+
borderRadius: 12,
|
|
245
|
+
borderWidth: 1,
|
|
246
|
+
borderColor: '#64748B',
|
|
247
|
+
alignItems: 'center',
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
export const inlineStyle_348_20 = {
|
|
251
|
+
flex: 1,
|
|
252
|
+
paddingVertical: 14,
|
|
253
|
+
borderRadius: 12,
|
|
254
|
+
backgroundColor: '#0F172A',
|
|
255
|
+
alignItems: 'center',
|
|
256
|
+
justifyContent: 'center',
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
export const timezoneListStyle = {
|
|
260
|
+
borderWidth: 1,
|
|
261
|
+
borderColor: '#e9ecef',
|
|
262
|
+
borderRadius: 12,
|
|
263
|
+
backgroundColor: '#f8f9fa',
|
|
264
|
+
overflow: 'hidden',
|
|
265
|
+
maxHeight: 220,
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
export const timezoneOptionStyle = {
|
|
269
|
+
flexDirection: 'row',
|
|
270
|
+
alignItems: 'center',
|
|
271
|
+
justifyContent: 'space-between',
|
|
272
|
+
paddingHorizontal: 16,
|
|
273
|
+
paddingVertical: 12,
|
|
274
|
+
borderBottomWidth: 1,
|
|
275
|
+
borderBottomColor: '#e9ecef',
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
export const timezoneOptionTextStyle = {
|
|
279
|
+
fontSize: 15,
|
|
280
|
+
color: '#212529',
|
|
281
|
+
flex: 1,
|
|
282
|
+
paddingRight: 8,
|
|
283
|
+
};
|