@controleonline/ui-customers 1.0.81 → 1.0.82

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/.github/workflows/integration-source-gate.yml +68 -0
  2. package/.github/workflows/publish-npm.yml +91 -0
  3. package/AGENTS.md +12 -6
  4. package/docs/technical/Client-Details-Criar-Usuario.md +113 -0
  5. package/package.json +5 -4
  6. package/src/react/components/tabs/AddressesTab.js +240 -335
  7. package/src/react/components/tabs/DocumentAttachments.js +270 -0
  8. package/src/react/components/tabs/DocumentsTab.js +355 -463
  9. package/src/react/components/tabs/DocumentsTab.styles.js +123 -0
  10. package/src/react/components/tabs/EmployeeCreateFormFields.js +203 -0
  11. package/src/react/components/tabs/EmployeesTab.js +17 -171
  12. package/src/react/components/tabs/EmployeesTab.styles.js +220 -172
  13. package/src/react/components/tabs/GeneralTab.js +84 -46
  14. package/src/react/components/tabs/GeneralTab.styles.js +81 -77
  15. package/src/react/components/tabs/MediaTab.js +50 -5
  16. package/src/react/components/tabs/PeopleCategoriesPanel.js +161 -78
  17. package/src/react/components/tabs/SalesmanTab.js +1 -1
  18. package/src/react/components/tabs/UserFormModal.js +26 -2
  19. package/src/react/components/tabs/UsersTab.js +30 -19
  20. package/src/react/components/tabs/UsersTab.styles.js +257 -257
  21. package/src/react/components/tabs/UsersTabApiKeyModal.js +115 -0
  22. package/src/react/components/tabs/UsersTabUserModal.js +222 -0
  23. package/src/react/components/tabs/addressesTabHelpers.js +190 -0
  24. package/src/react/components/tabs/documentsTabHelpers.js +142 -0
  25. package/src/react/components/tabs/employeeContacts.js +3 -23
  26. package/src/react/components/tabs/employeeUnlink.js +7 -4
  27. package/src/react/components/tabs/employeesTabHelpers.js +33 -9
  28. package/src/react/components/tabs/generalTabHelpers.js +30 -8
  29. package/src/react/components/tabs/useGeneralTabPeopleLink.js +68 -0
  30. package/src/react/components/tabs/usersTabHelpers.js +24 -23
  31. package/src/react/pages/details.page.styles.js +114 -100
  32. package/src/react/utils/humanCompanyLinkTypes.js +28 -0
  33. package/src/tests/browser/manager/client-details-add-user-modal.spec.js +281 -0
  34. package/src/tests/browser/manager/client-details-address-create-coords.spec.js +414 -0
  35. package/src/tests/browser/manager/client-details-address-edit.spec.js +331 -0
  36. package/src/tests/browser/manager/client-details-contact-edit.spec.js +198 -0
  37. package/src/tests/browser/manager/client-details-create-contact.spec.js +306 -0
  38. package/src/tests/browser/manager/client-details-documents.spec.js +346 -0
  39. package/src/tests/browser/manager/client-details-identity-case.spec.js +227 -0
  40. package/src/tests/browser/manager/client-details-people-type.manifest.md +18 -0
  41. package/src/tests/browser/manager/client-details-people-type.spec.js +345 -0
  42. package/src/tests/browser/manager/client-details-supplier-product-create.spec.js +334 -0
  43. package/src/tests/browser/manager/client-details-users-tab-load.spec.js +194 -0
  44. package/src/tests/browser/manager/employees-salesman-after-sales.spec.js +441 -0
  45. package/src/tests/react/components/SalesmanTab.company.test.js +40 -0
  46. package/src/tests/react/components/tabs/UsersTab.styles.test.js +39 -0
  47. package/src/tests/react/components/tabs/addressesTabHelpers.test.js +78 -0
  48. package/src/tests/react/components/tabs/documentsTabContract.test.mjs +37 -0
  49. package/src/tests/react/components/tabs/documentsTabHelpers.test.mjs +93 -0
  50. package/src/tests/react/components/tabs/employeeContacts.test.js +46 -4
  51. package/src/tests/react/components/tabs/employeeLinkTypes.contract.test.mjs +52 -0
  52. package/src/tests/react/components/tabs/employeeUnlink.test.js +11 -11
  53. package/src/tests/react/components/tabs/employeesTabHelpers.media.test.js +2 -23
  54. package/src/tests/react/components/tabs/employeesTabHelpers.test.js +59 -0
  55. package/src/tests/react/components/tabs/generalTabHelpers.test.js +35 -0
  56. package/src/tests/react/components/tabs/peopleMediaTabs.test.js +217 -217
  57. package/src/tests/react/components/tabs/peopleType.contract.test.mjs +47 -0
  58. package/src/tests/react/components/tabs/resolveSeededLinkType.test.mjs +20 -0
  59. package/src/tests/react/components/tabs/salesmanTabMedia.no-redeclare.test.mjs +33 -0
  60. package/src/tests/react/components/tabs/usersTabHelpers.test.js +20 -0
  61. package/src/tests/react/components/tabs/usersTabHelpers.test.mjs +63 -0
  62. package/src/tests/react/utils/humanCompanyLinkTypes.test.js +50 -0
@@ -1,172 +1,220 @@
1
- export const inlineStyle_243_18 = {
2
- paddingVertical: 20,
3
- alignItems: 'center',
4
- };
5
-
6
- export const inlineStyle_279_8 = {
7
- justifyContent: 'flex-end',
8
- };
9
-
10
- export const inlineStyle_281_10 = {
11
- backgroundColor: '#fff',
12
- borderTopLeftRadius: 24,
13
- borderTopRightRadius: 24,
14
- maxHeight: '85%',
15
- width: '100%',
16
- shadowColor: '#000',
17
-
18
- shadowOffset: {
19
- width: 0,
20
- height: -4,
21
- },
22
-
23
- shadowOpacity: 0.1,
24
- shadowRadius: 12,
25
- elevation: 10,
26
- };
27
-
28
- export const inlineStyle_294_12 = {
29
- flexDirection: 'row',
30
- alignItems: 'center',
31
- justifyContent: 'space-between',
32
- paddingHorizontal: 24,
33
- paddingVertical: 20,
34
- borderBottomWidth: 1,
35
- borderBottomColor: '#F1F5F9',
36
- };
37
-
38
- export const inlineStyle_303_18 = {
39
- fontSize: 20,
40
- fontWeight: '700',
41
- color: '#0F172A',
42
- };
43
-
44
- export const inlineStyle_308_14 = {
45
- width: 32,
46
- height: 32,
47
- borderRadius: 16,
48
- backgroundColor: '#F1F5F9',
49
- alignItems: 'center',
50
- justifyContent: 'center',
51
- };
52
-
53
- export const inlineStyle_321_12 = {
54
- padding: 24,
55
- };
56
-
57
- export const inlineStyle_324_18 = {
58
- marginBottom: 20,
59
- };
60
-
61
- export const inlineStyle_326_16 = {
62
- fontSize: 16,
63
- fontWeight: '600',
64
- color: '#212529',
65
- marginBottom: 8,
66
- };
67
-
68
- export const inlineStyle_338_16 = {
69
- borderWidth: 1,
70
- borderColor: '#e9ecef',
71
- borderRadius: 12,
72
- paddingHorizontal: 16,
73
- paddingVertical: 12,
74
- fontSize: 16,
75
- backgroundColor: '#f8f9fa',
76
- };
77
-
78
- export const inlineStyle_351_18 = {
79
- marginBottom: 20,
80
- };
81
-
82
- export const inlineStyle_353_16 = {
83
- fontSize: 16,
84
- fontWeight: '600',
85
- color: '#212529',
86
- marginBottom: 8,
87
- };
88
-
89
- export const inlineStyle_365_16 = {
90
- borderWidth: 1,
91
- borderColor: '#e9ecef',
92
- borderRadius: 12,
93
- paddingHorizontal: 16,
94
- paddingVertical: 12,
95
- fontSize: 16,
96
- backgroundColor: '#f8f9fa',
97
- };
98
-
99
- export const inlineStyle_378_18 = {
100
- marginBottom: 8,
101
- };
102
-
103
- export const inlineStyle_380_16 = {
104
- fontSize: 16,
105
- fontWeight: '600',
106
- color: '#212529',
107
- marginBottom: 8,
108
- };
109
-
110
- export const inlineStyle_389_16 = {
111
- flexDirection: 'row',
112
- alignItems: 'center',
113
- borderWidth: 1,
114
- borderColor: '#e9ecef',
115
- borderRadius: 12,
116
- paddingHorizontal: 16,
117
- backgroundColor: '#f8f9fa',
118
- };
119
-
120
- export const inlineStyle_408_18 = {
121
- flex: 1,
122
- paddingVertical: 12,
123
- paddingHorizontal: 12,
124
- fontSize: 16,
125
- color: '#212529',
126
- };
127
-
128
- export const inlineStyle_422_18 = {
129
- marginBottom: 20,
130
- };
131
-
132
- export const inlineStyle_424_16 = {
133
- fontSize: 16,
134
- fontWeight: '600',
135
- color: '#212529',
136
- marginBottom: 8,
137
- };
138
-
139
- export const inlineStyle_433_16 = {
140
- borderWidth: 1,
141
- borderColor: '#e9ecef',
142
- borderRadius: 12,
143
- backgroundColor: '#f8f9fa',
144
- overflow: 'hidden',
145
- };
146
-
147
- export const inlineStyle_446_18 = {
148
- color: '#212529',
149
- };
150
-
151
- export const inlineStyle_460_12 = {
152
- flexDirection: 'row',
153
- padding: 20,
154
- gap: 12,
155
- borderTopWidth: 1,
156
- borderTopColor: '#e9ecef',
157
- };
158
-
159
- export const inlineStyle_472_14 = {
160
- flex: 1,
161
- paddingVertical: 14,
162
- borderRadius: 12,
163
- borderWidth: 1,
164
- borderColor: '#6c757d',
165
- alignItems: 'center',
166
- };
167
-
168
- export const inlineStyle_480_20 = {
169
- fontSize: 16,
170
- fontWeight: '600',
171
- color: '#6c757d',
172
- };
1
+ export const inlineStyle_243_18 = {
2
+ paddingVertical: 20,
3
+ alignItems: 'center',
4
+ };
5
+
6
+ export const inlineStyle_279_8 = {
7
+ justifyContent: 'flex-end',
8
+ };
9
+
10
+ export const inlineStyle_281_10 = {
11
+ backgroundColor: '#fff',
12
+ borderTopLeftRadius: 24,
13
+ borderTopRightRadius: 24,
14
+ maxHeight: '85%',
15
+ width: '100%',
16
+ flexDirection: 'column',
17
+ shadowColor: '#000',
18
+
19
+ shadowOffset: {
20
+ width: 0,
21
+ height: -4,
22
+ },
23
+
24
+ shadowOpacity: 0.1,
25
+ shadowRadius: 12,
26
+ elevation: 10,
27
+ };
28
+
29
+ export const inlineStyle_294_12 = {
30
+ flexDirection: 'row',
31
+ alignItems: 'center',
32
+ justifyContent: 'space-between',
33
+ paddingHorizontal: 24,
34
+ paddingVertical: 20,
35
+ borderBottomWidth: 1,
36
+ borderBottomColor: '#F1F5F9',
37
+ };
38
+
39
+ export const inlineStyle_303_18 = {
40
+ fontSize: 20,
41
+ fontWeight: '700',
42
+ color: '#0F172A',
43
+ };
44
+
45
+ export const inlineStyle_308_14 = {
46
+ width: 32,
47
+ height: 32,
48
+ borderRadius: 16,
49
+ backgroundColor: '#F1F5F9',
50
+ alignItems: 'center',
51
+ justifyContent: 'center',
52
+ };
53
+
54
+ export const inlineStyle_321_12 = {
55
+ padding: 24,
56
+ };
57
+
58
+ export const inlineStyle_324_18 = {
59
+ marginBottom: 20,
60
+ };
61
+
62
+ export const inlineStyle_326_16 = {
63
+ fontSize: 16,
64
+ fontWeight: '600',
65
+ color: '#212529',
66
+ marginBottom: 8,
67
+ };
68
+
69
+ export const inlineStyle_338_16 = {
70
+ borderWidth: 1,
71
+ borderColor: '#e9ecef',
72
+ borderRadius: 12,
73
+ paddingHorizontal: 16,
74
+ paddingVertical: 12,
75
+ fontSize: 16,
76
+ backgroundColor: '#f8f9fa',
77
+ };
78
+
79
+ export const inlineStyle_351_18 = {
80
+ marginBottom: 20,
81
+ };
82
+
83
+ export const inlineStyle_353_16 = {
84
+ fontSize: 16,
85
+ fontWeight: '600',
86
+ color: '#212529',
87
+ marginBottom: 8,
88
+ };
89
+
90
+ export const inlineStyle_365_16 = {
91
+ borderWidth: 1,
92
+ borderColor: '#e9ecef',
93
+ borderRadius: 12,
94
+ paddingHorizontal: 16,
95
+ paddingVertical: 12,
96
+ fontSize: 16,
97
+ backgroundColor: '#f8f9fa',
98
+ };
99
+
100
+ export const inlineStyle_378_18 = {
101
+ marginBottom: 8,
102
+ };
103
+
104
+ export const inlineStyle_380_16 = {
105
+ fontSize: 16,
106
+ fontWeight: '600',
107
+ color: '#212529',
108
+ marginBottom: 8,
109
+ };
110
+
111
+ export const inlineStyle_389_16 = {
112
+ flexDirection: 'row',
113
+ alignItems: 'center',
114
+ borderWidth: 1,
115
+ borderColor: '#e9ecef',
116
+ borderRadius: 12,
117
+ paddingHorizontal: 16,
118
+ backgroundColor: '#f8f9fa',
119
+ };
120
+
121
+ export const inlineStyle_408_18 = {
122
+ flex: 1,
123
+ paddingVertical: 12,
124
+ paddingHorizontal: 12,
125
+ fontSize: 16,
126
+ color: '#212529',
127
+ };
128
+
129
+ export const inlineStyle_422_18 = {
130
+ marginBottom: 20,
131
+ };
132
+
133
+ export const inlineStyle_424_16 = {
134
+ fontSize: 16,
135
+ fontWeight: '600',
136
+ color: '#212529',
137
+ marginBottom: 8,
138
+ };
139
+
140
+ export const inlineStyle_433_16 = {
141
+ borderWidth: 1,
142
+ borderColor: '#e9ecef',
143
+ borderRadius: 12,
144
+ backgroundColor: '#f8f9fa',
145
+ overflow: 'hidden',
146
+ };
147
+
148
+ export const inlineStyle_446_18 = {
149
+ color: '#212529',
150
+ };
151
+
152
+ export const inlineStyle_460_12 = {
153
+ flexDirection: 'row',
154
+ padding: 20,
155
+ gap: 12,
156
+ borderTopWidth: 1,
157
+ borderTopColor: '#e9ecef',
158
+ };
159
+
160
+ export const inlineStyle_472_14 = {
161
+ flex: 1,
162
+ paddingVertical: 14,
163
+ borderRadius: 12,
164
+ borderWidth: 1,
165
+ borderColor: '#6c757d',
166
+ alignItems: 'center',
167
+ };
168
+
169
+ export const inlineStyle_480_20 = {
170
+ fontSize: 16,
171
+ fontWeight: '600',
172
+ color: '#6c757d',
173
+ };
174
+
175
+ /** Footer row for create-collaborator modal (app-community#686) */
176
+ export const modalFooterRow = {
177
+ flexDirection: 'row',
178
+ padding: 20,
179
+ gap: 12,
180
+ borderTopWidth: 1,
181
+ borderTopColor: '#e9ecef',
182
+ flexShrink: 0,
183
+ };
184
+
185
+ export const modalCancelButton = {
186
+ flex: 1,
187
+ paddingVertical: 14,
188
+ borderRadius: 12,
189
+ borderWidth: 1,
190
+ borderColor: '#6c757d',
191
+ alignItems: 'center',
192
+ justifyContent: 'center',
193
+ };
194
+
195
+ export const modalCancelButtonText = {
196
+ fontSize: 16,
197
+ fontWeight: '600',
198
+ color: '#6c757d',
199
+ };
200
+
201
+ export const modalSaveButton = {
202
+ flex: 1,
203
+ flexDirection: 'row',
204
+ paddingVertical: 14,
205
+ borderRadius: 12,
206
+ backgroundColor: '#4F46E5',
207
+ alignItems: 'center',
208
+ justifyContent: 'center',
209
+ gap: 8,
210
+ };
211
+
212
+ export const modalSaveButtonDisabled = {
213
+ opacity: 0.6,
214
+ };
215
+
216
+ export const modalSaveButtonText = {
217
+ fontSize: 16,
218
+ fontWeight: '600',
219
+ color: '#fff',
220
+ };
@@ -29,10 +29,13 @@ import {
29
29
  parseBrDateToYmd,
30
30
  LINK_TYPE_OPTIONS,
31
31
  normalizeLinkType,
32
+ resolveSeededLinkType,
33
+ PEOPLE_TYPE_OPTIONS,
34
+ normalizePeopleType,
32
35
  toPeopleIri,
33
36
  } from './generalTabHelpers';
34
37
  import FranchiseCommissionSection from './FranchiseCommissionSection';
35
-
38
+ import useGeneralTabPeopleLink from './useGeneralTabPeopleLink';
36
39
  const GeneralTab = ({
37
40
  client,
38
41
  customStyles,
@@ -52,7 +55,6 @@ const GeneralTab = ({
52
55
  const peopleLinkActions = peopleLinkStore?.actions || {};
53
56
  const [isSavingRegistration, setIsSavingRegistration] = useState(false);
54
57
  const [isSavingLinkType, setIsSavingLinkType] = useState(false);
55
- const [peopleLinkId, setPeopleLinkId] = useState('');
56
58
  const [linkTypeOptions, setLinkTypeOptions] = useState(
57
59
  LINK_TYPE_OPTIONS.map(option => ({
58
60
  value: option.value,
@@ -83,6 +85,15 @@ const GeneralTab = ({
83
85
  String(registrationForm.peopleType || '').toUpperCase() === 'F' &&
84
86
  String(parentCompanyIri || '').startsWith('/people/') &&
85
87
  String(contactPeopleIri || '').startsWith('/people/');
88
+ const {peopleLinkId, setPeopleLinkId} = useGeneralTabPeopleLink({
89
+ canEditLinkType,
90
+ getItems: peopleLinkActions?.getItems,
91
+ contactPeopleIri,
92
+ parentCompanyIri,
93
+ clientLinkType: client?.linkType,
94
+ setRegistrationForm,
95
+ setOriginalRegistrationForm,
96
+ });
86
97
 
87
98
  useEffect(() => {
88
99
  const initial = {
@@ -90,13 +101,23 @@ const GeneralTab = ({
90
101
  alias: normalizeIdentityValue(client?.alias),
91
102
  dateBr: formatYmdToBr(client?.foundationDate),
92
103
  enable: normalizeEnable(client?.enable ?? client?.enabled),
93
- peopleType: String(client?.peopleType || 'J').toUpperCase(),
94
- linkType: normalizeLinkType(initialContactLinkType),
104
+ peopleType: normalizePeopleType(client?.peopleType || 'J'),
105
+ linkType: resolveSeededLinkType(client?.linkType, initialContactLinkType),
95
106
  };
96
107
 
97
108
  setRegistrationForm(initial);
98
109
  setOriginalRegistrationForm(initial);
99
- }, [client?.id, client?.name, client?.alias, client?.foundationDate, client?.enable, client?.enabled, client?.peopleType, initialContactLinkType]);
110
+ }, [
111
+ client?.id,
112
+ client?.name,
113
+ client?.alias,
114
+ client?.foundationDate,
115
+ client?.enable,
116
+ client?.enabled,
117
+ client?.peopleType,
118
+ client?.linkType,
119
+ initialContactLinkType,
120
+ ]);
100
121
 
101
122
  useEffect(() => {
102
123
  setLinkTypeOptions(
@@ -107,39 +128,7 @@ const GeneralTab = ({
107
128
  );
108
129
  }, []);
109
130
 
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';
131
+ const isPessoaFisica = normalizePeopleType(registrationForm.peopleType) === 'F';
143
132
  const isAvatarUploadDisabled = isSavingClientAvatar;
144
133
  const avatarUploadLabel = isPessoaFisica ? 'subir avatar' : 'subir ícone';
145
134
  const nameLabel = isPessoaFisica ? global.t?.t('users','label','name') : global.t?.t('users','label','companyName');
@@ -152,6 +141,8 @@ const GeneralTab = ({
152
141
  normalizeIdentityValue(registrationForm.alias) !== normalizeIdentityValue(originalRegistrationForm.alias) ||
153
142
  String(registrationForm.dateBr || '') !== String(originalRegistrationForm.dateBr || '') ||
154
143
  Boolean(registrationForm.enable) !== Boolean(originalRegistrationForm.enable) ||
144
+ normalizePeopleType(registrationForm.peopleType) !==
145
+ normalizePeopleType(originalRegistrationForm.peopleType) ||
155
146
  (canEditLinkType &&
156
147
  normalizeLinkType(registrationForm.linkType) !==
157
148
  normalizeLinkType(originalRegistrationForm.linkType))
@@ -197,12 +188,19 @@ const GeneralTab = ({
197
188
 
198
189
  if (linkTypeChanged && peopleLinkActions?.save) {
199
190
  setIsSavingLinkType(true);
200
- const savedLink = await peopleLinkActions.save({
201
- ...(peopleLinkId ? { id: peopleLinkId } : {}),
202
- company: parentCompanyIri,
203
- people: contactPeopleIri,
204
- linkType: normalizeLinkType(registrationForm.linkType),
205
- });
191
+ // On update send only id + linkType — avoid denormalizing people IRI
192
+ // which triggered "Item not found for /people/{id}" (#688).
193
+ const linkPayload = peopleLinkId
194
+ ? {
195
+ id: peopleLinkId,
196
+ linkType: normalizeLinkType(registrationForm.linkType),
197
+ }
198
+ : {
199
+ company: parentCompanyIri,
200
+ people: contactPeopleIri,
201
+ linkType: normalizeLinkType(registrationForm.linkType),
202
+ };
203
+ const savedLink = await peopleLinkActions.save(linkPayload);
206
204
 
207
205
  const nextLinkId = String(savedLink?.id || savedLink?.['@id'] || '').replace(/\D/g, '');
208
206
  if (nextLinkId) {
@@ -210,10 +208,12 @@ const GeneralTab = ({
210
208
  }
211
209
  }
212
210
 
211
+ const peopleType = normalizePeopleType(registrationForm.peopleType);
213
212
  const payload = {
214
213
  name,
215
214
  alias,
216
215
  enable: Boolean(registrationForm.enable),
216
+ peopleType,
217
217
  };
218
218
 
219
219
  if (foundationDate) {
@@ -225,6 +225,7 @@ const GeneralTab = ({
225
225
  onUpdateClient?.('name', name);
226
226
  onUpdateClient?.('alias', alias);
227
227
  onUpdateClient?.('enable', Boolean(registrationForm.enable));
228
+ onUpdateClient?.('peopleType', peopleType);
228
229
  if (canEditLinkType) {
229
230
  onUpdateClient?.('linkType', normalizeLinkType(registrationForm.linkType));
230
231
  }
@@ -237,6 +238,7 @@ const GeneralTab = ({
237
238
  name,
238
239
  alias,
239
240
  enable: Boolean(registrationForm.enable),
241
+ peopleType,
240
242
  dateBr: foundationDate ? formatYmdToBr(foundationDate) : registrationForm.dateBr,
241
243
  linkType: normalizeLinkType(registrationForm.linkType),
242
244
  };
@@ -244,8 +246,17 @@ const GeneralTab = ({
244
246
  setRegistrationForm(updated);
245
247
  setOriginalRegistrationForm(updated);
246
248
  showSuccess?.(global.t?.t('users','success','registrationUpdated'));
247
- } catch {
248
- showError?.(global.t?.t('users','error','registrationUpdateFailed'));
249
+ } catch (error) {
250
+ const apiMessage =
251
+ error?.response?.data?.detail ||
252
+ error?.response?.data?.description ||
253
+ error?.message ||
254
+ '';
255
+ showError?.(
256
+ apiMessage
257
+ ? `${global.t?.t('users','error','registrationUpdateFailed') || 'Registration Update Failed'}\n${apiMessage}`
258
+ : global.t?.t('users','error','registrationUpdateFailed'),
259
+ );
249
260
  } finally {
250
261
  setIsSavingLinkType(false);
251
262
  setIsSavingRegistration(false);
@@ -376,6 +387,33 @@ const GeneralTab = ({
376
387
  </View>
377
388
  </View>
378
389
 
390
+ {isEditing && (
391
+ <View style={styles.fieldGroup}>
392
+ <Text style={styles.fieldLabel}>Tipo</Text>
393
+ <View style={styles.inputRow}>
394
+ <Picker
395
+ selectedValue={normalizePeopleType(registrationForm.peopleType)}
396
+ onValueChange={value =>
397
+ setRegistrationForm(prev => ({
398
+ ...prev,
399
+ peopleType: normalizePeopleType(value),
400
+ }))
401
+ }
402
+ mode={pickerMode}
403
+ accessibilityLabel="Tipo de colaborador"
404
+ style={styles.inputRowField}>
405
+ {PEOPLE_TYPE_OPTIONS.map(option => (
406
+ <Picker.Item
407
+ key={option.value}
408
+ label={option.label}
409
+ value={option.value}
410
+ />
411
+ ))}
412
+ </Picker>
413
+ </View>
414
+ </View>
415
+ )}
416
+
379
417
  {canEditLinkType && (
380
418
  <View style={styles.fieldGroup}>
381
419
  <Text style={styles.fieldLabel}>Tipo de Vinculo</Text>