cozy-ui-plus 4.0.0 → 4.2.0
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/CHANGELOG.md +14 -0
- package/dist/Contacts/AddModal/ContactForm/FieldInput.js +3 -7
- package/dist/Contacts/AddModal/ContactForm/FieldInputArray.js +3 -5
- package/dist/Contacts/AddModal/ContactForm/FieldInputLayout.js +2 -4
- package/dist/Contacts/AddModal/ContactForm/FieldInputWrapper.js +1 -1
- package/dist/Contacts/AddModal/ContactForm/contactToFormValues.js +75 -90
- package/dist/Contacts/AddModal/ContactForm/helpers.js +104 -34
- package/dist/Contacts/AddModal/ContactForm/index.js +7 -2
- package/dist/Contacts/AddModal/ContactForm/locales/index.js +4 -4
- package/dist/src/Contacts/AddModal/ContactForm/FieldInput.d.ts +2 -6
- package/dist/src/Contacts/AddModal/ContactForm/FieldInputArray.d.ts +2 -6
- package/dist/src/Contacts/AddModal/ContactForm/helpers.d.ts +5 -2
- package/package.json +2 -2
- package/src/Contacts/AddModal/ContactForm/FieldInput.jsx +3 -7
- package/src/Contacts/AddModal/ContactForm/FieldInputArray.jsx +7 -4
- package/src/Contacts/AddModal/ContactForm/FieldInputLayout.jsx +3 -3
- package/src/Contacts/AddModal/ContactForm/FieldInputWrapper.jsx +1 -1
- package/src/Contacts/AddModal/ContactForm/contactToFormValues.js +79 -94
- package/src/Contacts/AddModal/ContactForm/contactToFormValues.spec.js +0 -23
- package/src/Contacts/AddModal/ContactForm/helpers.js +77 -17
- package/src/Contacts/AddModal/ContactForm/helpers.spec.js +344 -1
- package/src/Contacts/AddModal/ContactForm/index.jsx +24 -10
- package/src/Contacts/AddModal/ContactForm/locales/en.json +1 -1
- package/src/Contacts/AddModal/ContactForm/locales/fr.json +1 -1
- package/src/Contacts/AddModal/ContactForm/locales/ru.json +1 -1
- package/src/Contacts/AddModal/ContactForm/locales/vi.json +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cozy-ui-plus",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.2.0",
|
|
4
4
|
"description": "Cozy-ui-plus is an extension of cozy-ui and provides components based on cozy-client",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"license": "MIT",
|
|
@@ -74,5 +74,5 @@
|
|
|
74
74
|
"react-dom": "^16 || ^17 || ^18",
|
|
75
75
|
"twake-i18n": ">=0.3.0"
|
|
76
76
|
},
|
|
77
|
-
"gitHead": "
|
|
77
|
+
"gitHead": "1fe28398fc8315ebb5eba401731f8e318c00f05a"
|
|
78
78
|
}
|
|
@@ -22,8 +22,7 @@ const FieldInput = ({
|
|
|
22
22
|
error,
|
|
23
23
|
helperText,
|
|
24
24
|
label,
|
|
25
|
-
isInvisible
|
|
26
|
-
required
|
|
25
|
+
isInvisible
|
|
27
26
|
}) => {
|
|
28
27
|
const [id] = useState(uniqueId('field_')) // state only use to generate id once and not at each render
|
|
29
28
|
const [hasBeenFocused, setHasBeenFocused] = useState(false)
|
|
@@ -57,7 +56,6 @@ const FieldInput = ({
|
|
|
57
56
|
)}
|
|
58
57
|
>
|
|
59
58
|
<Field
|
|
60
|
-
required={required}
|
|
61
59
|
error={error}
|
|
62
60
|
helperText={helperText}
|
|
63
61
|
label={label}
|
|
@@ -111,13 +109,11 @@ FieldInput.propTypes = {
|
|
|
111
109
|
}),
|
|
112
110
|
// Destructuring props
|
|
113
111
|
id: PropTypes.string,
|
|
114
|
-
label: PropTypes.string
|
|
115
|
-
required: PropTypes.bool
|
|
112
|
+
label: PropTypes.string
|
|
116
113
|
}
|
|
117
114
|
|
|
118
115
|
FieldInput.defaultProps = {
|
|
119
|
-
labelProps: null
|
|
120
|
-
required: false
|
|
116
|
+
labelProps: null
|
|
121
117
|
}
|
|
122
118
|
|
|
123
119
|
export default FieldInput
|
|
@@ -11,16 +11,17 @@ import PlusIcon from 'cozy-ui/transpiled/react/Icons/Plus'
|
|
|
11
11
|
import ListItemIcon from 'cozy-ui/transpiled/react/ListItemIcon'
|
|
12
12
|
|
|
13
13
|
import FieldInput from './FieldInput'
|
|
14
|
-
import {
|
|
14
|
+
import { addField, removeField, makeIsRequiredError } from './helpers'
|
|
15
15
|
import { locales } from './locales'
|
|
16
16
|
|
|
17
17
|
const FieldInputArray = ({
|
|
18
18
|
attributes: { name, label, ...restAttributes },
|
|
19
19
|
contacts,
|
|
20
|
-
formProps
|
|
20
|
+
formProps
|
|
21
21
|
}) => {
|
|
22
22
|
useExtendI18n(locales)
|
|
23
23
|
const { t } = useI18n()
|
|
24
|
+
const { errors } = formProps
|
|
24
25
|
|
|
25
26
|
return (
|
|
26
27
|
<FieldArray name={name}>
|
|
@@ -31,8 +32,10 @@ const FieldInputArray = ({
|
|
|
31
32
|
const key = fields.value[index]?.fieldId || nameWithIndex
|
|
32
33
|
const showRemove = fields.value[index]?.[name]
|
|
33
34
|
const inputName = `${nameWithIndex}.${name}`
|
|
34
|
-
const isError =
|
|
35
|
-
|
|
35
|
+
const isError = makeIsRequiredError(
|
|
36
|
+
restAttributes.required,
|
|
37
|
+
formProps
|
|
38
|
+
)
|
|
36
39
|
|
|
37
40
|
return (
|
|
38
41
|
<div
|
|
@@ -8,7 +8,7 @@ import Icon from 'cozy-ui/transpiled/react/Icon'
|
|
|
8
8
|
import FieldInput from './FieldInput'
|
|
9
9
|
import FieldInputAccordion from './FieldInputAccordion'
|
|
10
10
|
import FieldInputArray from './FieldInputArray'
|
|
11
|
-
import {
|
|
11
|
+
import { makeIsRequiredError } from './helpers'
|
|
12
12
|
import { locales } from './locales'
|
|
13
13
|
|
|
14
14
|
const FieldInputLayout = ({
|
|
@@ -19,10 +19,10 @@ const FieldInputLayout = ({
|
|
|
19
19
|
}) => {
|
|
20
20
|
useExtendI18n(locales)
|
|
21
21
|
const { t } = useI18n()
|
|
22
|
-
const {
|
|
22
|
+
const { errors } = formProps
|
|
23
23
|
const { name, label, ...restAttributes } = attributes
|
|
24
24
|
|
|
25
|
-
const isError =
|
|
25
|
+
const isError = makeIsRequiredError(restAttributes.required, formProps)
|
|
26
26
|
|
|
27
27
|
return (
|
|
28
28
|
<div
|
|
@@ -2,108 +2,93 @@ import uniqueId from 'lodash/uniqueId'
|
|
|
2
2
|
|
|
3
3
|
import { getFormattedAddress } from 'cozy-client/dist/models/contact'
|
|
4
4
|
|
|
5
|
-
import { fields } from './fieldsConfig'
|
|
6
5
|
import { makeItemLabel, makeRelatedContact, movePrimaryToHead } from './helpers'
|
|
7
6
|
|
|
8
7
|
const contactToFormValues = ({ contact, makeCustomContactValues, t }) => {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
8
|
+
const {
|
|
9
|
+
gender,
|
|
10
|
+
address,
|
|
11
|
+
birthday,
|
|
12
|
+
birthplace,
|
|
13
|
+
company,
|
|
14
|
+
jobTitle,
|
|
15
|
+
cozy,
|
|
16
|
+
email,
|
|
17
|
+
impp,
|
|
18
|
+
name,
|
|
19
|
+
note,
|
|
20
|
+
phone
|
|
21
|
+
} = contact
|
|
17
22
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
23
|
+
const addressValue =
|
|
24
|
+
address && address.length > 0
|
|
25
|
+
? movePrimaryToHead(address).map(addressInfo => ({
|
|
26
|
+
fieldId: uniqueId('fieldId_'),
|
|
27
|
+
address: getFormattedAddress(addressInfo, t),
|
|
28
|
+
addressnumber: addressInfo.number,
|
|
29
|
+
addressstreet:
|
|
30
|
+
addressInfo.street || getFormattedAddress(addressInfo, t),
|
|
31
|
+
addresscode: addressInfo.postcode || addressInfo.code,
|
|
32
|
+
addresscity: addressInfo.city,
|
|
33
|
+
addressregion: addressInfo.region,
|
|
34
|
+
addresscountry: addressInfo.country,
|
|
35
|
+
addresslocality: addressInfo.extendedAddress?.locality,
|
|
36
|
+
addressbuilding: addressInfo.extendedAddress?.building,
|
|
37
|
+
addressstairs: addressInfo.extendedAddress?.stairs,
|
|
38
|
+
addressfloor: addressInfo.extendedAddress?.floor,
|
|
39
|
+
addressapartment: addressInfo.extendedAddress?.apartment,
|
|
40
|
+
addressentrycode: addressInfo.extendedAddress?.entrycode,
|
|
41
|
+
addressLabel: makeItemLabel(addressInfo)
|
|
42
|
+
}))
|
|
43
|
+
: [undefined]
|
|
44
|
+
const cozyValue = cozy && cozy.length > 0 ? cozy[0].url : undefined
|
|
45
|
+
const cozyLabel = cozy && cozy.length > 0 ? makeItemLabel(cozy[0]) : undefined
|
|
46
|
+
const emailValue =
|
|
47
|
+
email && email.length > 0
|
|
48
|
+
? movePrimaryToHead(email).map(item => ({
|
|
49
|
+
fieldId: uniqueId('fieldId_'),
|
|
50
|
+
email: item?.address,
|
|
51
|
+
emailLabel: makeItemLabel(item)
|
|
52
|
+
}))
|
|
53
|
+
: [undefined]
|
|
54
|
+
const matrixValue =
|
|
55
|
+
impp && impp.length > 0
|
|
56
|
+
? impp.find(item => item.label === 'work' && item.protocol === 'matrix')
|
|
57
|
+
?.uri || undefined
|
|
58
|
+
: undefined
|
|
59
|
+
const phoneValue =
|
|
60
|
+
phone && phone.length > 0
|
|
61
|
+
? movePrimaryToHead(phone).map(item => ({
|
|
62
|
+
fieldId: uniqueId('fieldId_'),
|
|
63
|
+
phone: item?.number,
|
|
64
|
+
phoneLabel: makeItemLabel(item)
|
|
65
|
+
}))
|
|
66
|
+
: [undefined]
|
|
33
67
|
|
|
34
|
-
|
|
35
|
-
address && address.length > 0
|
|
36
|
-
? movePrimaryToHead(address).map(addressInfo => ({
|
|
37
|
-
fieldId: uniqueId('fieldId_'),
|
|
38
|
-
address: getFormattedAddress(addressInfo, t),
|
|
39
|
-
addressnumber: addressInfo.number,
|
|
40
|
-
addressstreet:
|
|
41
|
-
addressInfo.street || getFormattedAddress(addressInfo, t),
|
|
42
|
-
addresscode: addressInfo.postcode || addressInfo.code,
|
|
43
|
-
addresscity: addressInfo.city,
|
|
44
|
-
addressregion: addressInfo.region,
|
|
45
|
-
addresscountry: addressInfo.country,
|
|
46
|
-
addresslocality: addressInfo.extendedAddress?.locality,
|
|
47
|
-
addressbuilding: addressInfo.extendedAddress?.building,
|
|
48
|
-
addressstairs: addressInfo.extendedAddress?.stairs,
|
|
49
|
-
addressfloor: addressInfo.extendedAddress?.floor,
|
|
50
|
-
addressapartment: addressInfo.extendedAddress?.apartment,
|
|
51
|
-
addressentrycode: addressInfo.extendedAddress?.entrycode,
|
|
52
|
-
addressLabel: makeItemLabel(addressInfo)
|
|
53
|
-
}))
|
|
54
|
-
: [undefined]
|
|
55
|
-
const cozyValue = cozy && cozy.length > 0 ? cozy[0].url : undefined
|
|
56
|
-
const cozyLabel =
|
|
57
|
-
cozy && cozy.length > 0 ? makeItemLabel(cozy[0]) : undefined
|
|
58
|
-
const emailValue =
|
|
59
|
-
email && email.length > 0
|
|
60
|
-
? movePrimaryToHead(email).map(item => ({
|
|
61
|
-
fieldId: uniqueId('fieldId_'),
|
|
62
|
-
email: item?.address,
|
|
63
|
-
emailLabel: makeItemLabel(item)
|
|
64
|
-
}))
|
|
65
|
-
: [undefined]
|
|
66
|
-
const matrixValue =
|
|
67
|
-
impp && impp.length > 0
|
|
68
|
-
? impp.find(item => item.label === 'work' && item.protocol === 'matrix')
|
|
69
|
-
?.uri || undefined
|
|
70
|
-
: undefined
|
|
71
|
-
const phoneValue =
|
|
72
|
-
phone && phone.length > 0
|
|
73
|
-
? movePrimaryToHead(phone).map(item => ({
|
|
74
|
-
fieldId: uniqueId('fieldId_'),
|
|
75
|
-
phone: item?.number,
|
|
76
|
-
phoneLabel: makeItemLabel(item)
|
|
77
|
-
}))
|
|
78
|
-
: [undefined]
|
|
68
|
+
const relatedContactValue = makeRelatedContact(contact)
|
|
79
69
|
|
|
80
|
-
|
|
70
|
+
const customValues = makeCustomContactValues?.(contact) || {}
|
|
81
71
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
note,
|
|
102
|
-
relatedContact: relatedContactValue
|
|
103
|
-
}
|
|
72
|
+
return {
|
|
73
|
+
...customValues,
|
|
74
|
+
gender,
|
|
75
|
+
givenName: name?.givenName,
|
|
76
|
+
additionalName: name?.additionalName,
|
|
77
|
+
surname: name?.surname,
|
|
78
|
+
familyName: name?.familyName,
|
|
79
|
+
phone: phoneValue,
|
|
80
|
+
email: emailValue,
|
|
81
|
+
matrix: matrixValue,
|
|
82
|
+
address: addressValue,
|
|
83
|
+
cozy: cozyValue,
|
|
84
|
+
cozyLabel: cozyLabel,
|
|
85
|
+
company,
|
|
86
|
+
jobTitle,
|
|
87
|
+
birthday,
|
|
88
|
+
birthplace,
|
|
89
|
+
note,
|
|
90
|
+
relatedContact: relatedContactValue
|
|
104
91
|
}
|
|
105
|
-
|
|
106
|
-
return initialFieldValues
|
|
107
92
|
}
|
|
108
93
|
|
|
109
94
|
export default contactToFormValues
|
|
@@ -5,29 +5,6 @@ import { johnDoeContact, johnDoeFormValues } from '../mocks'
|
|
|
5
5
|
describe('contactToFormValues function', () => {
|
|
6
6
|
const tSpy = jest.fn()
|
|
7
7
|
|
|
8
|
-
it('should return default initial values', () => {
|
|
9
|
-
const expected = {
|
|
10
|
-
address: [undefined],
|
|
11
|
-
birthday: undefined,
|
|
12
|
-
birthplace: undefined,
|
|
13
|
-
gender: undefined,
|
|
14
|
-
company: undefined,
|
|
15
|
-
jobTitle: undefined,
|
|
16
|
-
cozy: undefined,
|
|
17
|
-
cozyLabel: undefined,
|
|
18
|
-
email: [undefined],
|
|
19
|
-
matrix: undefined,
|
|
20
|
-
familyName: undefined,
|
|
21
|
-
givenName: undefined,
|
|
22
|
-
note: undefined,
|
|
23
|
-
phone: [undefined],
|
|
24
|
-
relatedContact: [undefined]
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const result = contactToFormValues({ contact: null, t: tSpy })
|
|
28
|
-
expect(result).toEqual(expected)
|
|
29
|
-
})
|
|
30
|
-
|
|
31
8
|
it('should return initial values when a contact is given (edit)', () => {
|
|
32
9
|
const expected = { ...johnDoeFormValues, relatedContact: [undefined] }
|
|
33
10
|
tSpy.mockReturnValue(
|
|
@@ -9,26 +9,63 @@ import { CONTACTS_DOCTYPE } from 'cozy-client/dist/models/contact'
|
|
|
9
9
|
|
|
10
10
|
import contactToFormValues from './contactToFormValues'
|
|
11
11
|
|
|
12
|
-
export const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
export const getFirstValueIfArray = values => {
|
|
13
|
+
return Object.keys(values).reduce((acc, key) => {
|
|
14
|
+
const val = values[key]
|
|
15
|
+
acc[key] = Array.isArray(val) ? val[0] : val
|
|
16
|
+
return acc
|
|
17
|
+
}, {})
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Returns true if all fields have no values
|
|
22
|
+
* @param {object} values - Fields values
|
|
23
|
+
* @param {import('../types').Field[]} fields - Fields configuration
|
|
24
|
+
* @returns {boolean} True if all fields have no values
|
|
25
|
+
*/
|
|
26
|
+
export const hasNoValues = (values, fields) => {
|
|
27
|
+
const _values = getFirstValueIfArray(values)
|
|
28
|
+
|
|
29
|
+
return fields.every(field => !get(_values, field.name))
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Returns true if the input is required and the form is invalid
|
|
34
|
+
* @param {boolean} required - Whether the input is required
|
|
35
|
+
* @param {object} formProps - The form props
|
|
36
|
+
* @returns {boolean} True if the input is required and the form is invalid
|
|
37
|
+
*/
|
|
38
|
+
export const makeIsRequiredError = (required, formProps) => {
|
|
39
|
+
const { valid, submitFailed } = formProps
|
|
40
|
+
|
|
41
|
+
return required && !valid && submitFailed
|
|
42
|
+
}
|
|
18
43
|
|
|
19
44
|
/**
|
|
20
|
-
* Returns errors
|
|
45
|
+
* Returns errors for required fields that are empty
|
|
21
46
|
* @param {object} values - Fields values
|
|
22
|
-
* @param {
|
|
47
|
+
* @param {import('../types').Field[]} fields - Fields configuration
|
|
48
|
+
* @param {Function} t - Translation function
|
|
23
49
|
* @returns {object} Errors
|
|
24
50
|
*/
|
|
25
|
-
export const validateFields = (values, t) => {
|
|
51
|
+
export const validateFields = (values, fields, t) => {
|
|
26
52
|
const errors = {}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
53
|
+
const fieldsRequired = fields.filter(field => field.required)
|
|
54
|
+
const _values = getFirstValueIfArray(values)
|
|
55
|
+
|
|
56
|
+
fieldsRequired.forEach(field => {
|
|
57
|
+
if (!get(_values, field.name)) {
|
|
58
|
+
errors[field.name] =
|
|
59
|
+
field.layout === 'array'
|
|
60
|
+
? [
|
|
61
|
+
{
|
|
62
|
+
[field.name]: t('Contacts.AddModal.ContactForm.fields.required')
|
|
63
|
+
}
|
|
64
|
+
]
|
|
65
|
+
: t('Contacts.AddModal.ContactForm.fields.required')
|
|
66
|
+
}
|
|
67
|
+
})
|
|
68
|
+
|
|
32
69
|
return errors
|
|
33
70
|
}
|
|
34
71
|
|
|
@@ -329,6 +366,18 @@ export const makeImppValues = (oldContact, value) => {
|
|
|
329
366
|
)
|
|
330
367
|
}
|
|
331
368
|
|
|
369
|
+
export const initializationFieldValues = fields => {
|
|
370
|
+
const initialFieldValues = fields.reduce(
|
|
371
|
+
(initialValues, { name, layout, defaultValue }) => {
|
|
372
|
+
initialValues[name] = layout === 'array' ? [undefined] : defaultValue
|
|
373
|
+
return initialValues
|
|
374
|
+
},
|
|
375
|
+
{}
|
|
376
|
+
)
|
|
377
|
+
|
|
378
|
+
return initialFieldValues
|
|
379
|
+
}
|
|
380
|
+
|
|
332
381
|
/**
|
|
333
382
|
*
|
|
334
383
|
* @param {string} name
|
|
@@ -384,9 +433,20 @@ export const makeFields = (customFields, defaultFields) => {
|
|
|
384
433
|
|
|
385
434
|
const fields = [...defaultFields]
|
|
386
435
|
|
|
387
|
-
customFields.
|
|
388
|
-
|
|
389
|
-
|
|
436
|
+
customFields.forEach(customField => {
|
|
437
|
+
const defaultField = fields.find(field => field.name === customField.name)
|
|
438
|
+
const _field = defaultField || customField
|
|
439
|
+
|
|
440
|
+
if (defaultField) {
|
|
441
|
+
Object.assign(_field, customField)
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
if (_field.position) {
|
|
445
|
+
if (defaultField) {
|
|
446
|
+
const fieldIndex = fields.indexOf(defaultField)
|
|
447
|
+
fields.splice(fieldIndex, 1)
|
|
448
|
+
}
|
|
449
|
+
fields.splice(_field.position, 0, _field)
|
|
390
450
|
}
|
|
391
451
|
})
|
|
392
452
|
|