@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.
Files changed (102) hide show
  1. package/.github/agents/developer.agent.md +30 -0
  2. package/.github/agents/devops.agent.md +30 -0
  3. package/.github/agents/qa.agent.md +30 -0
  4. package/.github/agents/security.agent.md +30 -0
  5. package/.scrutinizer.yml +20 -0
  6. package/AGENTS.md +50 -0
  7. package/FUNDING.yml +1 -0
  8. package/README.md +23 -0
  9. package/docs/technical/Client-Details-Franquia-Filial.md +18 -0
  10. package/docs/technical/Client-Details-People-Name-Case.md +103 -0
  11. package/docs/technical/Cliente-Vendedor-Vinculo-e-Permissoes.md +152 -0
  12. package/docs/wiki.md +1 -0
  13. package/package.json +32 -0
  14. package/scripts/validate-wiki-pointer.cjs +13 -0
  15. package/src/react/components/tabs/AddressesTab.js +494 -0
  16. package/src/react/components/tabs/CategoriesTab.js +196 -0
  17. package/src/react/components/tabs/ClassificationChips.js +494 -0
  18. package/src/react/components/tabs/ContactTab.js +621 -0
  19. package/src/react/components/tabs/ContactTab.styles.js +119 -0
  20. package/src/react/components/tabs/ContractsTab.js +13 -0
  21. package/src/react/components/tabs/DocumentsTab.js +463 -0
  22. package/src/react/components/tabs/DocumentsTab.styles.js +133 -0
  23. package/src/react/components/tabs/EmployeeContactRow.js +83 -0
  24. package/src/react/components/tabs/EmployeesTab.js +454 -0
  25. package/src/react/components/tabs/EmployeesTab.styles.js +172 -0
  26. package/src/react/components/tabs/FiscalTab.js +6 -0
  27. package/src/react/components/tabs/FranchiseCommissionSection.js +307 -0
  28. package/src/react/components/tabs/FranchiseLinksManageModal.js +215 -0
  29. package/src/react/components/tabs/FranchiseLinksTab.js +282 -0
  30. package/src/react/components/tabs/GeneralTab.js +466 -0
  31. package/src/react/components/tabs/GeneralTab.styles.js +101 -0
  32. package/src/react/components/tabs/MediaTab.js +356 -0
  33. package/src/react/components/tabs/PeopleCategoriesPanel.js +601 -0
  34. package/src/react/components/tabs/ProductsTab.js +236 -0
  35. package/src/react/components/tabs/ProductsTab.styles.js +143 -0
  36. package/src/react/components/tabs/SalesmanCommissionBlock.js +120 -0
  37. package/src/react/components/tabs/SalesmanManageModal.js +208 -0
  38. package/src/react/components/tabs/SalesmanTab.js +436 -0
  39. package/src/react/components/tabs/SalesmanTab.styles.js +4 -0
  40. package/src/react/components/tabs/UserApiKeyModal.js +90 -0
  41. package/src/react/components/tabs/UserFormModal.js +301 -0
  42. package/src/react/components/tabs/UsersTab.js +426 -0
  43. package/src/react/components/tabs/UsersTab.styles.js +283 -0
  44. package/src/react/components/tabs/UsersTab.styles.test.js +42 -0
  45. package/src/react/components/tabs/contactMutationMessage.js +18 -0
  46. package/src/react/components/tabs/employeeContacts.js +214 -0
  47. package/src/react/components/tabs/employeeUnlink.js +68 -0
  48. package/src/react/components/tabs/employeesTabHelpers.js +227 -0
  49. package/src/react/components/tabs/franchiseCommissionHelpers.js +134 -0
  50. package/src/react/components/tabs/franchiseLinksTab.helpers.js +247 -0
  51. package/src/react/components/tabs/generalTabHelpers.js +120 -0
  52. package/src/react/components/tabs/salesmanTab.helpers.js +114 -0
  53. package/src/react/components/tabs/salesmanTabHelpers.js +173 -0
  54. package/src/react/components/tabs/salesmanTabMedia.js +55 -0
  55. package/src/react/components/tabs/salesmanTabSession.js +39 -0
  56. package/src/react/components/tabs/useEmployeeUnlink.js +58 -0
  57. package/src/react/components/tabs/useFranchiseLinksManage.js +215 -0
  58. package/src/react/components/tabs/useSalesmanManage.js +222 -0
  59. package/src/react/components/tabs/usersTabHelpers.js +221 -0
  60. package/src/react/domain/productSupplierFlow.js +37 -0
  61. package/src/react/index.js +4 -0
  62. package/src/react/pages/ClientDetailsSkeleton.js +84 -0
  63. package/src/react/pages/clientDetailsHelpers.js +17 -0
  64. package/src/react/pages/clients.js +27 -0
  65. package/src/react/pages/details.js +529 -0
  66. package/src/react/pages/details.page.styles.js +105 -0
  67. package/src/react/pages/details.styles.js +15 -0
  68. package/src/react/pages/employees.js +69 -0
  69. package/src/react/pages/franchisees.js +30 -0
  70. package/src/react/pages/prospects.js +21 -0
  71. package/src/react/pages/provider.js +21 -0
  72. package/src/react/router/routes.js +104 -0
  73. package/src/react/styles/details.js +571 -0
  74. package/src/store/people_categories/index.js +72 -0
  75. package/src/tests/browser/manager/client-details-create-user.spec.js +321 -0
  76. package/src/tests/browser/manager/client-details-employee-unlink.spec.js +215 -0
  77. package/src/tests/browser/manager/client-details-employees-refresh.spec.js +271 -0
  78. package/src/tests/browser/manager/client-details-enable.spec.js +241 -0
  79. package/src/tests/browser/manager/client-details-fiscal-tabs.spec.js +410 -0
  80. package/src/tests/browser/manager/client-details-franchise-commission.spec.js +318 -0
  81. package/src/tests/browser/manager/client-details-franchise-links.spec.js +365 -0
  82. package/src/tests/browser/manager/client-details-media.spec.js +405 -0
  83. package/src/tests/browser/manager/client-details-relationships.spec.js +313 -0
  84. package/src/tests/browser/manager/client-details-salesman-commission.spec.js +291 -0
  85. package/src/tests/browser/manager/client-details-salesman-manage.spec.js +448 -0
  86. package/src/tests/react/components/tabs/contactMutationMessage.test.js +25 -0
  87. package/src/tests/react/components/tabs/employeeContacts.test.js +266 -0
  88. package/src/tests/react/components/tabs/employeeUnlink.test.js +67 -0
  89. package/src/tests/react/components/tabs/employeesTabHelpers.media.test.js +78 -0
  90. package/src/tests/react/components/tabs/employeesTabHelpers.test.js +64 -0
  91. package/src/tests/react/components/tabs/fiscalTabContract.test.mjs +29 -0
  92. package/src/tests/react/components/tabs/franchiseCommissionHelpers.test.js +128 -0
  93. package/src/tests/react/components/tabs/franchiseLinksTab.helpers.test.mjs +166 -0
  94. package/src/tests/react/components/tabs/generalTabHelpers.test.js +130 -0
  95. package/src/tests/react/components/tabs/peopleMediaTabs.test.js +322 -0
  96. package/src/tests/react/components/tabs/salesmanTab.helpers.test.mjs +75 -0
  97. package/src/tests/react/components/tabs/salesmanTabHelpers.test.js +142 -0
  98. package/src/tests/react/components/tabs/salesmanTabHelpers.test.mjs +92 -0
  99. package/src/tests/react/components/tabs/usersTabHelpers.test.js +59 -0
  100. package/src/tests/react/domain/productSupplierFlow.test.mjs +55 -0
  101. package/src/tests/react/pages/clientDetailsHelpers.test.js +98 -0
  102. package/src/tests/react/pages/employees.test.js +44 -0
@@ -0,0 +1,466 @@
1
+ import React, { useEffect, useMemo, useState } from 'react';
2
+
3
+ import {
4
+ ActivityIndicator,
5
+ Platform,
6
+ ScrollView,
7
+ Switch,
8
+ Text,
9
+ TextInput,
10
+ TouchableOpacity,
11
+ View,
12
+ } from 'react-native';
13
+
14
+ import { Picker } from '@react-native-picker/picker';
15
+ import Icon from 'react-native-vector-icons/MaterialIcons';
16
+ import { useStore } from '@store';
17
+ import {useMessage} from '@controleonline/ui-common/src/react/components/MessageService';
18
+ import ContactTab from './ContactTab';
19
+ import DocumentsTab from './DocumentsTab';
20
+ import AddressesTab from './AddressesTab';
21
+ import PeopleCategoriesPanel from './PeopleCategoriesPanel';
22
+ import { createGeneralTabStyles } from './GeneralTab.styles';
23
+ import {
24
+ normalizeIdentityValue,
25
+ extractId,
26
+ normalizeEnable,
27
+ formatYmdToBr,
28
+ formatDateInput,
29
+ parseBrDateToYmd,
30
+ LINK_TYPE_OPTIONS,
31
+ normalizeLinkType,
32
+ toPeopleIri,
33
+ } from './generalTabHelpers';
34
+ import FranchiseCommissionSection from './FranchiseCommissionSection';
35
+
36
+ const GeneralTab = ({
37
+ client,
38
+ customStyles,
39
+ isEditing,
40
+ onUpdateClient,
41
+ onSaveClientData,
42
+ parentCompanyIri,
43
+ initialContactLinkType,
44
+ onChangeClientAvatar,
45
+ isSavingClientAvatar = false,
46
+ }) => {
47
+ const {showError, showSuccess} = useMessage();
48
+ const peopleLinkStore = useStore('people_link');
49
+ const themeStore = useStore('theme');
50
+ const themeColors = themeStore.getters.colors;
51
+ const styles = useMemo(() => createGeneralTabStyles(themeColors), [themeColors]);
52
+ const peopleLinkActions = peopleLinkStore?.actions || {};
53
+ const [isSavingRegistration, setIsSavingRegistration] = useState(false);
54
+ const [isSavingLinkType, setIsSavingLinkType] = useState(false);
55
+ const [peopleLinkId, setPeopleLinkId] = useState('');
56
+ const [linkTypeOptions, setLinkTypeOptions] = useState(
57
+ LINK_TYPE_OPTIONS.map(option => ({
58
+ value: option.value,
59
+ label: option.value,
60
+ })),
61
+ );
62
+ const [registrationForm, setRegistrationForm] = useState({
63
+ name: '',
64
+ alias: '',
65
+ dateBr: '',
66
+ enable: false,
67
+ peopleType: 'J',
68
+ linkType: 'employee',
69
+ });
70
+ const [originalRegistrationForm, setOriginalRegistrationForm] = useState({
71
+ name: '',
72
+ alias: '',
73
+ dateBr: '',
74
+ enable: false,
75
+ peopleType: 'J',
76
+ linkType: 'employee',
77
+ });
78
+
79
+ const pickerMode = Platform.OS === 'android' ? 'dropdown' : undefined;
80
+ const contactPeopleIri = useMemo(() => toPeopleIri(client), [client]);
81
+ const canEditLinkType =
82
+ isEditing &&
83
+ String(registrationForm.peopleType || '').toUpperCase() === 'F' &&
84
+ String(parentCompanyIri || '').startsWith('/people/') &&
85
+ String(contactPeopleIri || '').startsWith('/people/');
86
+
87
+ useEffect(() => {
88
+ const initial = {
89
+ name: normalizeIdentityValue(client?.name),
90
+ alias: normalizeIdentityValue(client?.alias),
91
+ dateBr: formatYmdToBr(client?.foundationDate),
92
+ enable: normalizeEnable(client?.enable ?? client?.enabled),
93
+ peopleType: String(client?.peopleType || 'J').toUpperCase(),
94
+ linkType: normalizeLinkType(initialContactLinkType),
95
+ };
96
+
97
+ setRegistrationForm(initial);
98
+ setOriginalRegistrationForm(initial);
99
+ }, [client?.id, client?.name, client?.alias, client?.foundationDate, client?.enable, client?.enabled, client?.peopleType, initialContactLinkType]);
100
+
101
+ useEffect(() => {
102
+ setLinkTypeOptions(
103
+ LINK_TYPE_OPTIONS.map(option => ({
104
+ value: option.value,
105
+ label: global.t?.t('people', 'label', option.translationKey),
106
+ })),
107
+ );
108
+ }, []);
109
+
110
+ useEffect(() => {
111
+ if (!canEditLinkType || !peopleLinkActions?.getItems) {
112
+ return;
113
+ }
114
+
115
+ let cancelled = false;
116
+
117
+ peopleLinkActions
118
+ .getItems({
119
+ people: extractId(contactPeopleIri),
120
+ company: extractId(parentCompanyIri),
121
+ })
122
+ .then(items => {
123
+ if (cancelled || !Array.isArray(items) || items.length === 0) {
124
+ return;
125
+ }
126
+
127
+ const link = items[0];
128
+ const nextLinkType = normalizeLinkType(link?.linkType);
129
+ const nextLinkId = String(link?.id || link?.['@id'] || '').replace(/\D/g, '');
130
+
131
+ setPeopleLinkId(nextLinkId);
132
+ setRegistrationForm(prev => ({ ...prev, linkType: nextLinkType }));
133
+ setOriginalRegistrationForm(prev => ({ ...prev, linkType: nextLinkType }));
134
+ })
135
+ .catch(() => {});
136
+
137
+ return () => {
138
+ cancelled = true;
139
+ };
140
+ }, [canEditLinkType, contactPeopleIri, parentCompanyIri, peopleLinkActions]);
141
+
142
+ const isPessoaFisica = registrationForm.peopleType === 'F';
143
+ const isAvatarUploadDisabled = isSavingClientAvatar;
144
+ const avatarUploadLabel = isPessoaFisica ? 'subir avatar' : 'subir ícone';
145
+ const nameLabel = isPessoaFisica ? global.t?.t('users','label','name') : global.t?.t('users','label','companyName');
146
+ const aliasLabel = isPessoaFisica ? global.t?.t('users','label','nickname') : global.t?.t('users','label','fantasyName');
147
+ const dateLabel = isPessoaFisica ? global.t?.t('users','label','birthDate') : global.t?.t('users','label','foundationDate');
148
+
149
+ const hasRegistrationChanges = useMemo(() => {
150
+ return (
151
+ normalizeIdentityValue(registrationForm.name) !== normalizeIdentityValue(originalRegistrationForm.name) ||
152
+ normalizeIdentityValue(registrationForm.alias) !== normalizeIdentityValue(originalRegistrationForm.alias) ||
153
+ String(registrationForm.dateBr || '') !== String(originalRegistrationForm.dateBr || '') ||
154
+ Boolean(registrationForm.enable) !== Boolean(originalRegistrationForm.enable) ||
155
+ (canEditLinkType &&
156
+ normalizeLinkType(registrationForm.linkType) !==
157
+ normalizeLinkType(originalRegistrationForm.linkType))
158
+ );
159
+ }, [canEditLinkType, registrationForm, originalRegistrationForm]);
160
+
161
+ const saveRegistration = async () => {
162
+ if (!isEditing || isSavingRegistration || isSavingLinkType || !hasRegistrationChanges) {
163
+ return;
164
+ }
165
+
166
+ const name = normalizeIdentityValue(registrationForm.name);
167
+ const alias = normalizeIdentityValue(registrationForm.alias);
168
+
169
+ if (!name || !alias) {
170
+ showError?.(GeneralTab.t?.t('users','error','nameAndAliasRequired'));
171
+ return;
172
+ }
173
+
174
+ let foundationDate;
175
+ if (registrationForm.dateBr) {
176
+ foundationDate = parseBrDateToYmd(registrationForm.dateBr);
177
+ if (!foundationDate) {
178
+ showError?.(GeneralTab.t?.t('users','error','invalidDate'));
179
+ return;
180
+ }
181
+ }
182
+
183
+ if (!onSaveClientData) {
184
+ showError?.(GeneralTab.t?.t('users','error','saveUnavailable'));
185
+ return;
186
+ }
187
+
188
+ setIsSavingRegistration(true);
189
+ try {
190
+ // people_link currently only exposes GetCollection on the API.
191
+ // Persist linkType only when it actually changed to avoid Method Not Allowed
192
+ // on unrelated cadastral saves (e.g. enable/active toggle).
193
+ const linkTypeChanged =
194
+ canEditLinkType &&
195
+ normalizeLinkType(registrationForm.linkType) !==
196
+ normalizeLinkType(originalRegistrationForm.linkType);
197
+
198
+ if (linkTypeChanged && peopleLinkActions?.save) {
199
+ setIsSavingLinkType(true);
200
+ const savedLink = await peopleLinkActions.save({
201
+ ...(peopleLinkId ? { id: peopleLinkId } : {}),
202
+ company: parentCompanyIri,
203
+ people: contactPeopleIri,
204
+ linkType: normalizeLinkType(registrationForm.linkType),
205
+ });
206
+
207
+ const nextLinkId = String(savedLink?.id || savedLink?.['@id'] || '').replace(/\D/g, '');
208
+ if (nextLinkId) {
209
+ setPeopleLinkId(nextLinkId);
210
+ }
211
+ }
212
+
213
+ const payload = {
214
+ name,
215
+ alias,
216
+ enable: Boolean(registrationForm.enable),
217
+ };
218
+
219
+ if (foundationDate) {
220
+ payload.foundationDate = foundationDate;
221
+ }
222
+
223
+ await onSaveClientData(payload);
224
+
225
+ onUpdateClient?.('name', name);
226
+ onUpdateClient?.('alias', alias);
227
+ onUpdateClient?.('enable', Boolean(registrationForm.enable));
228
+ if (canEditLinkType) {
229
+ onUpdateClient?.('linkType', normalizeLinkType(registrationForm.linkType));
230
+ }
231
+ if (foundationDate) {
232
+ onUpdateClient?.('foundationDate', foundationDate);
233
+ }
234
+
235
+ const updated = {
236
+ ...registrationForm,
237
+ name,
238
+ alias,
239
+ enable: Boolean(registrationForm.enable),
240
+ dateBr: foundationDate ? formatYmdToBr(foundationDate) : registrationForm.dateBr,
241
+ linkType: normalizeLinkType(registrationForm.linkType),
242
+ };
243
+
244
+ setRegistrationForm(updated);
245
+ setOriginalRegistrationForm(updated);
246
+ showSuccess?.(global.t?.t('users','success','registrationUpdated'));
247
+ } catch {
248
+ showError?.(global.t?.t('users','error','registrationUpdateFailed'));
249
+ } finally {
250
+ setIsSavingLinkType(false);
251
+ setIsSavingRegistration(false);
252
+ }
253
+ };
254
+
255
+ return (
256
+ <ScrollView
257
+ style={styles.container}
258
+ contentContainerStyle={styles.content}
259
+ nestedScrollEnabled
260
+ showsVerticalScrollIndicator={false}>
261
+ <View style={customStyles.section}>
262
+ <View style={customStyles.sectionHeader}>
263
+ <Text style={customStyles.sectionTitle}>Dados Cadastrais</Text>
264
+ </View>
265
+
266
+ {isEditing && onChangeClientAvatar && (
267
+ <View style={styles.fieldGroupLarge}>
268
+ <Text style={styles.fieldLabel}>Imagem</Text>
269
+ <TouchableOpacity
270
+ onPress={onChangeClientAvatar}
271
+ disabled={isAvatarUploadDisabled}
272
+ activeOpacity={0.85}
273
+ accessibilityLabel={avatarUploadLabel}
274
+ style={[
275
+ styles.uploadImageButton,
276
+ isAvatarUploadDisabled ? styles.saveButtonDisabled : null,
277
+ ]}>
278
+ {isSavingClientAvatar ? (
279
+ <ActivityIndicator size="small" color={themeColors.buttonText} />
280
+ ) : (
281
+ <>
282
+ <Icon
283
+ name="photo-camera"
284
+ size={18}
285
+ color={themeColors.buttonIcon}
286
+ />
287
+ <Text style={styles.uploadImageButtonText}>
288
+ {avatarUploadLabel}
289
+ </Text>
290
+ </>
291
+ )}
292
+ </TouchableOpacity>
293
+ </View>
294
+ )}
295
+
296
+ <View style={styles.fieldGroup}>
297
+ <Text style={styles.fieldLabel}>
298
+ {nameLabel}
299
+ </Text>
300
+ <TextInput
301
+ value={registrationForm.name}
302
+ onChangeText={text => setRegistrationForm(prev => ({ ...prev, name: text }))}
303
+ placeholder={nameLabel}
304
+ style={styles.input}
305
+ placeholderTextColor={themeColors.inputPlaceholderText}
306
+ />
307
+ </View>
308
+
309
+ <View style={styles.fieldGroup}>
310
+ <Text style={styles.fieldLabel}>
311
+ {aliasLabel}
312
+ </Text>
313
+ <TextInput
314
+ value={registrationForm.alias}
315
+ onChangeText={text => setRegistrationForm(prev => ({ ...prev, alias: text }))}
316
+ placeholder={aliasLabel}
317
+ style={styles.input}
318
+ placeholderTextColor={themeColors.inputPlaceholderText}
319
+ />
320
+ </View>
321
+
322
+ <View style={styles.fieldGroupLarge}>
323
+ <Text style={styles.fieldLabel}>
324
+ {dateLabel}
325
+ </Text>
326
+ <View style={styles.inputRow}>
327
+ <Icon
328
+ name="event"
329
+ size={18}
330
+ color={themeColors.inputIcon}
331
+ style={styles.inputIcon}
332
+ />
333
+ <TextInput
334
+ value={registrationForm.dateBr}
335
+ onChangeText={text =>
336
+ setRegistrationForm(prev => ({
337
+ ...prev,
338
+ dateBr: formatDateInput(text),
339
+ }))
340
+ }
341
+ placeholder="DD/MM/AAAA" // @todo // mostrar também no padrão americano, MM/DD/AAAA
342
+ keyboardType="numeric"
343
+ maxLength={10}
344
+ style={styles.inputRowField}
345
+ placeholderTextColor={themeColors.inputPlaceholderText}
346
+ />
347
+ </View>
348
+ </View>
349
+
350
+ <View style={styles.fieldGroupLarge}>
351
+ <Text style={styles.fieldLabel}>
352
+ Acesso do usuário
353
+ </Text>
354
+ <View style={styles.switchRow}>
355
+ <Text style={styles.switchLabel}>
356
+ {registrationForm.enable ? 'Liberado' : 'Bloqueado'}
357
+ </Text>
358
+ <Switch
359
+ value={Boolean(registrationForm.enable)}
360
+ onValueChange={value =>
361
+ setRegistrationForm(prev => ({
362
+ ...prev,
363
+ enable: value,
364
+ }))
365
+ }
366
+ trackColor={{
367
+ false: themeColors.switchOffTrack,
368
+ true: themeColors.switchOnTrack,
369
+ }}
370
+ thumbColor={
371
+ registrationForm.enable
372
+ ? themeColors.switchOnThumb
373
+ : themeColors.switchOffThumb
374
+ }
375
+ />
376
+ </View>
377
+ </View>
378
+
379
+ {canEditLinkType && (
380
+ <View style={styles.fieldGroup}>
381
+ <Text style={styles.fieldLabel}>Tipo de Vinculo</Text>
382
+ <View style={styles.inputRow}>
383
+ <Picker
384
+ selectedValue={registrationForm.linkType}
385
+ onValueChange={value =>
386
+ setRegistrationForm(prev => ({
387
+ ...prev,
388
+ linkType: normalizeLinkType(value),
389
+ }))
390
+ }
391
+ mode={pickerMode}
392
+ style={styles.inputRowField}>
393
+ {linkTypeOptions.map(option => (
394
+ <Picker.Item
395
+ key={option.value}
396
+ label={option.label || option.value}
397
+ value={option.value}
398
+ />
399
+ ))}
400
+ </Picker>
401
+ </View>
402
+ </View>
403
+ )}
404
+
405
+ {isEditing && (
406
+ <TouchableOpacity
407
+ onPress={saveRegistration}
408
+ disabled={!hasRegistrationChanges || isSavingRegistration || isSavingLinkType}
409
+ activeOpacity={0.85}
410
+ style={[
411
+ styles.saveButton,
412
+ !hasRegistrationChanges || isSavingRegistration || isSavingLinkType
413
+ ? styles.saveButtonDisabled
414
+ : null,
415
+ ]}>
416
+ {isSavingRegistration || isSavingLinkType ? (
417
+ <ActivityIndicator size="small" color={themeColors.buttonText} />
418
+ ) : (
419
+ <Text
420
+ style={[
421
+ styles.saveButtonText,
422
+ !hasRegistrationChanges || isSavingRegistration || isSavingLinkType
423
+ ? styles.saveButtonTextDisabled
424
+ : null,
425
+ ]}>
426
+ {global.t?.t('users','button','saveChanges')}
427
+ </Text>
428
+ )}
429
+ </TouchableOpacity>
430
+ )}
431
+ </View>
432
+ <FranchiseCommissionSection
433
+ client={client}
434
+ parentCompanyIri={parentCompanyIri}
435
+ isEditing={isEditing}
436
+ />
437
+ <PeopleCategoriesPanel
438
+ client={client}
439
+ isEditing={isEditing}
440
+ parentCompanyIri={parentCompanyIri}
441
+ />
442
+ {isPessoaFisica && (
443
+ <ContactTab
444
+ client={client}
445
+ customStyles={customStyles}
446
+ isEditing={isEditing}
447
+ onUpdateClient={onUpdateClient}
448
+ />
449
+ )}
450
+ <DocumentsTab
451
+ client={client}
452
+ customStyles={customStyles}
453
+ isEditing={isEditing}
454
+ onUpdateClient={onUpdateClient}
455
+ />
456
+ <AddressesTab
457
+ client={client}
458
+ customStyles={customStyles}
459
+ isEditing={isEditing}
460
+ onUpdateClient={onUpdateClient}
461
+ />
462
+ </ScrollView>
463
+ );
464
+ };
465
+
466
+ export default GeneralTab;
@@ -0,0 +1,101 @@
1
+ import {StyleSheet} from 'react-native';
2
+
3
+ export const createGeneralTabStyles = themeColors =>
4
+ StyleSheet.create({
5
+ container: {
6
+ flex: 1,
7
+ backgroundColor: themeColors.pageBackground,
8
+ },
9
+ content: {
10
+ paddingBottom: 80,
11
+ },
12
+ fieldGroup: {
13
+ marginBottom: 12,
14
+ },
15
+ fieldGroupLarge: {
16
+ marginBottom: 16,
17
+ },
18
+ fieldLabel: {
19
+ fontSize: 14,
20
+ fontWeight: '600',
21
+ color: themeColors.textSecondary,
22
+ marginBottom: 6,
23
+ },
24
+ input: {
25
+ borderWidth: 1,
26
+ borderColor: themeColors.inputBorder,
27
+ borderRadius: 10,
28
+ paddingHorizontal: 12,
29
+ paddingVertical: 10,
30
+ fontSize: 15,
31
+ color: themeColors.inputText,
32
+ backgroundColor: themeColors.inputBackground,
33
+ },
34
+ inputRow: {
35
+ flexDirection: 'row',
36
+ alignItems: 'center',
37
+ borderWidth: 1,
38
+ borderColor: themeColors.inputBorder,
39
+ borderRadius: 10,
40
+ backgroundColor: themeColors.inputBackground,
41
+ },
42
+ inputIcon: {
43
+ marginLeft: 10,
44
+ },
45
+ inputRowField: {
46
+ flex: 1,
47
+ paddingHorizontal: 10,
48
+ paddingVertical: 10,
49
+ fontSize: 15,
50
+ color: themeColors.inputText,
51
+ },
52
+ switchRow: {
53
+ flexDirection: 'row',
54
+ alignItems: 'center',
55
+ justifyContent: 'space-between',
56
+ borderWidth: 1,
57
+ borderColor: themeColors.inputBorder,
58
+ borderRadius: 10,
59
+ backgroundColor: themeColors.inputBackground,
60
+ paddingHorizontal: 12,
61
+ paddingVertical: 8,
62
+ },
63
+ switchLabel: {
64
+ fontSize: 14,
65
+ color: themeColors.textSecondary,
66
+ },
67
+ saveButton: {
68
+ height: 42,
69
+ borderRadius: 10,
70
+ alignItems: 'center',
71
+ justifyContent: 'center',
72
+ backgroundColor: themeColors.buttonBackground,
73
+ },
74
+ uploadImageButton: {
75
+ height: 42,
76
+ borderRadius: 10,
77
+ alignItems: 'center',
78
+ justifyContent: 'center',
79
+ flexDirection: 'row',
80
+ gap: 8,
81
+ backgroundColor: themeColors.buttonBackground,
82
+ borderWidth: 1,
83
+ borderColor: themeColors.buttonBorder,
84
+ },
85
+ uploadImageButtonText: {
86
+ color: themeColors.buttonText,
87
+ fontSize: 15,
88
+ fontWeight: '700',
89
+ },
90
+ saveButtonDisabled: {
91
+ backgroundColor: themeColors.buttonDisabledBackground,
92
+ },
93
+ saveButtonText: {
94
+ color: themeColors.buttonText,
95
+ fontSize: 15,
96
+ fontWeight: '700',
97
+ },
98
+ saveButtonTextDisabled: {
99
+ color: themeColors.buttonDisabledText,
100
+ },
101
+ });