cozy-ui 128.2.0 → 128.3.1
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 +15 -0
- package/package.json +6 -2
- package/react/Contacts/AddModal/ContactAddressDialog/helpers.js +22 -0
- package/react/Contacts/AddModal/ContactAddressDialog/helpers.spec.js +64 -0
- package/react/Contacts/AddModal/ContactAddressDialog/index.jsx +84 -0
- package/react/Contacts/AddModal/ContactAddressDialog/locales/en.json +25 -0
- package/react/Contacts/AddModal/ContactAddressDialog/locales/fr.json +25 -0
- package/react/Contacts/AddModal/ContactAddressDialog/locales/index.jsx +7 -0
- package/react/Contacts/AddModal/ContactForm/FieldInput.jsx +117 -0
- package/react/Contacts/AddModal/ContactForm/FieldInputArray.jsx +80 -0
- package/react/Contacts/AddModal/ContactForm/FieldInputLayout.jsx +65 -0
- package/react/Contacts/AddModal/ContactForm/FieldInputWrapper.jsx +41 -0
- package/react/Contacts/AddModal/ContactForm/HasValueCondition.jsx +31 -0
- package/react/Contacts/AddModal/ContactForm/HasValueCondition.spec.jsx +79 -0
- package/react/Contacts/AddModal/ContactForm/RelatedContactList.jsx +37 -0
- package/react/Contacts/AddModal/ContactForm/TextFieldCustomLabelSelect.jsx +78 -0
- package/react/Contacts/AddModal/ContactForm/TextFieldSelect.jsx +39 -0
- package/react/Contacts/AddModal/ContactForm/__snapshots__/HasValueCondition.spec.jsx.snap +33 -0
- package/react/Contacts/AddModal/ContactForm/contactToFormValues.js +99 -0
- package/react/Contacts/AddModal/ContactForm/contactToFormValues.spec.js +128 -0
- package/react/Contacts/AddModal/ContactForm/fieldsConfig.jsx +341 -0
- package/react/Contacts/AddModal/ContactForm/formValuesToContact.js +100 -0
- package/react/Contacts/AddModal/ContactForm/formValuesToContact.spec.js +494 -0
- package/react/Contacts/AddModal/ContactForm/helpers.js +324 -0
- package/react/Contacts/AddModal/ContactForm/helpers.spec.js +152 -0
- package/react/Contacts/AddModal/ContactForm/index.jsx +104 -0
- package/react/Contacts/AddModal/ContactForm/index.spec.jsx +289 -0
- package/react/Contacts/AddModal/ContactForm/locales/en.json +73 -0
- package/react/Contacts/AddModal/ContactForm/locales/fr.json +73 -0
- package/react/Contacts/AddModal/ContactForm/locales/index.jsx +7 -0
- package/react/Contacts/AddModal/ContactForm/styles.styl +2 -0
- package/react/Contacts/AddModal/CustomLabelDialog/index.jsx +108 -0
- package/react/Contacts/AddModal/CustomLabelDialog/locales/en.json +15 -0
- package/react/Contacts/AddModal/CustomLabelDialog/locales/fr.json +15 -0
- package/react/Contacts/AddModal/CustomLabelDialog/locales/index.jsx +7 -0
- package/react/Contacts/AddModal/Readme.md +46 -0
- package/react/Contacts/AddModal/index.jsx +78 -0
- package/react/Contacts/AddModal/locales/en.json +13 -0
- package/react/Contacts/AddModal/locales/fr.json +13 -0
- package/react/Contacts/AddModal/locales/index.jsx +7 -0
- package/react/Contacts/AddModal/mocks.js +249 -0
- package/react/Contacts/AddModal/types.js +57 -0
- package/react/Contacts/Header/Readme.md +0 -2
- package/react/providers/DemoProvider.jsx +3 -2
- package/transpiled/react/Contacts/AddModal/ContactAddressDialog/helpers.d.ts +4 -0
- package/transpiled/react/Contacts/AddModal/ContactAddressDialog/helpers.js +20 -0
- package/transpiled/react/Contacts/AddModal/ContactAddressDialog/helpers.spec.d.ts +1 -0
- package/transpiled/react/Contacts/AddModal/ContactAddressDialog/index.d.ts +39 -0
- package/transpiled/react/Contacts/AddModal/ContactAddressDialog/index.js +87 -0
- package/transpiled/react/Contacts/AddModal/ContactAddressDialog/locales/index.d.ts +6 -0
- package/transpiled/react/Contacts/AddModal/ContactAddressDialog/locales/index.js +54 -0
- package/transpiled/react/Contacts/AddModal/ContactForm/FieldInput.d.ts +35 -0
- package/transpiled/react/Contacts/AddModal/ContactForm/FieldInput.js +126 -0
- package/transpiled/react/Contacts/AddModal/ContactForm/FieldInputArray.d.ts +14 -0
- package/transpiled/react/Contacts/AddModal/ContactForm/FieldInputArray.js +82 -0
- package/transpiled/react/Contacts/AddModal/ContactForm/FieldInputLayout.d.ts +20 -0
- package/transpiled/react/Contacts/AddModal/ContactForm/FieldInputLayout.js +70 -0
- package/transpiled/react/Contacts/AddModal/ContactForm/FieldInputWrapper.d.ts +16 -0
- package/transpiled/react/Contacts/AddModal/ContactForm/FieldInputWrapper.js +31 -0
- package/transpiled/react/Contacts/AddModal/ContactForm/HasValueCondition.d.ts +18 -0
- package/transpiled/react/Contacts/AddModal/ContactForm/HasValueCondition.js +32 -0
- package/transpiled/react/Contacts/AddModal/ContactForm/HasValueCondition.spec.d.ts +1 -0
- package/transpiled/react/Contacts/AddModal/ContactForm/RelatedContactList.d.ts +15 -0
- package/transpiled/react/Contacts/AddModal/ContactForm/RelatedContactList.js +39 -0
- package/transpiled/react/Contacts/AddModal/ContactForm/TextFieldCustomLabelSelect.d.ts +9 -0
- package/transpiled/react/Contacts/AddModal/ContactForm/TextFieldCustomLabelSelect.js +81 -0
- package/transpiled/react/Contacts/AddModal/ContactForm/TextFieldSelect.d.ts +5 -0
- package/transpiled/react/Contacts/AddModal/ContactForm/TextFieldSelect.js +42 -0
- package/transpiled/react/Contacts/AddModal/ContactForm/contactToFormValues.d.ts +2 -0
- package/transpiled/react/Contacts/AddModal/ContactForm/contactToFormValues.js +88 -0
- package/transpiled/react/Contacts/AddModal/ContactForm/contactToFormValues.spec.d.ts +1 -0
- package/transpiled/react/Contacts/AddModal/ContactForm/fieldsConfig.d.ts +4 -0
- package/transpiled/react/Contacts/AddModal/ContactForm/fieldsConfig.js +278 -0
- package/transpiled/react/Contacts/AddModal/ContactForm/formValuesToContact.d.ts +6 -0
- package/transpiled/react/Contacts/AddModal/ContactForm/formValuesToContact.js +94 -0
- package/transpiled/react/Contacts/AddModal/ContactForm/formValuesToContact.spec.d.ts +1 -0
- package/transpiled/react/Contacts/AddModal/ContactForm/helpers.d.ts +28 -0
- package/transpiled/react/Contacts/AddModal/ContactForm/helpers.js +335 -0
- package/transpiled/react/Contacts/AddModal/ContactForm/helpers.spec.d.ts +1 -0
- package/transpiled/react/Contacts/AddModal/ContactForm/index.d.ts +11 -0
- package/transpiled/react/Contacts/AddModal/ContactForm/index.js +114 -0
- package/transpiled/react/Contacts/AddModal/ContactForm/index.spec.d.ts +1 -0
- package/transpiled/react/Contacts/AddModal/ContactForm/locales/index.d.ts +6 -0
- package/transpiled/react/Contacts/AddModal/ContactForm/locales/index.js +150 -0
- package/transpiled/react/Contacts/AddModal/CustomLabelDialog/index.d.ts +22 -0
- package/transpiled/react/Contacts/AddModal/CustomLabelDialog/index.js +113 -0
- package/transpiled/react/Contacts/AddModal/CustomLabelDialog/locales/index.d.ts +6 -0
- package/transpiled/react/Contacts/AddModal/CustomLabelDialog/locales/index.js +34 -0
- package/transpiled/react/Contacts/AddModal/index.d.ts +7 -0
- package/transpiled/react/Contacts/AddModal/index.js +109 -0
- package/transpiled/react/Contacts/AddModal/locales/index.d.ts +6 -0
- package/transpiled/react/Contacts/AddModal/locales/index.js +30 -0
- package/transpiled/react/Contacts/AddModal/mocks.d.ts +270 -0
- package/transpiled/react/Contacts/AddModal/mocks.js +214 -0
- package/transpiled/react/Contacts/AddModal/types.d.ts +54 -0
- package/transpiled/react/Contacts/AddModal/types.js +49 -0
- package/transpiled/react/providers/DemoProvider.d.ts +2 -1
- package/transpiled/react/providers/DemoProvider.js +7 -3
- package/transpiled/react/stylesheet.css +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
## [128.3.1](https://github.com/cozy/cozy-ui/compare/v128.3.0...v128.3.1) (2025-09-03)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* `patch-package` wasn't a direct dep ([8085fd8](https://github.com/cozy/cozy-ui/commit/8085fd8))
|
|
7
|
+
|
|
8
|
+
# [128.3.0](https://github.com/cozy/cozy-ui/compare/v128.2.0...v128.3.0) (2025-09-03)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* Add ContactsAddModal component ([5e21445](https://github.com/cozy/cozy-ui/commit/5e21445))
|
|
14
|
+
* **DemoProvider:** Add ability to pass locales ([f6815a3](https://github.com/cozy/cozy-ui/commit/f6815a3))
|
|
15
|
+
|
|
1
16
|
# [128.2.0](https://github.com/cozy/cozy-ui/compare/v128.1.0...v128.2.0) (2025-09-03)
|
|
2
17
|
|
|
3
18
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cozy-ui",
|
|
3
|
-
"version": "128.
|
|
3
|
+
"version": "128.3.1",
|
|
4
4
|
"description": "Cozy apps UI SDK",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"bin": {
|
|
@@ -128,7 +128,6 @@
|
|
|
128
128
|
"mini-css-extract-plugin": "0.6.0",
|
|
129
129
|
"nodemon": "1.19.4",
|
|
130
130
|
"npm-run-all": "4.1.5",
|
|
131
|
-
"patch-package": "^8.0.0",
|
|
132
131
|
"postcss-cli": "6.1.3",
|
|
133
132
|
"postcss-loader": "2.1.6",
|
|
134
133
|
"prettier": "2.6.0",
|
|
@@ -171,14 +170,19 @@
|
|
|
171
170
|
"cozy-interapp": "^0.5.4",
|
|
172
171
|
"date-fns": "2.30.0",
|
|
173
172
|
"filesize": "8.0.7",
|
|
173
|
+
"final-form": "4.20.9",
|
|
174
|
+
"final-form-arrays": "3.1.0",
|
|
174
175
|
"hammerjs": "^2.0.8",
|
|
175
176
|
"intersection-observer": "0.11.0",
|
|
176
177
|
"mime-types": "2.1.35",
|
|
177
178
|
"mui-bottom-sheet": "https://github.com/cozy/mui-bottom-sheet.git#v1.0.9",
|
|
178
179
|
"node-polyglot": "^2.5.0",
|
|
179
180
|
"normalize.css": "^8.0.0",
|
|
181
|
+
"patch-package": "^8.0.0",
|
|
180
182
|
"pdf-lib": "1.17.1",
|
|
181
183
|
"react-chartjs-2": "4.1.0",
|
|
184
|
+
"react-final-form": "6.5.9",
|
|
185
|
+
"react-final-form-arrays": "3.1.4",
|
|
182
186
|
"react-markdown": "^4.0.8",
|
|
183
187
|
"react-popper": "^2.2.3",
|
|
184
188
|
"react-remove-scroll": "^2.4.0",
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { cleanFormattedAddress } from 'cozy-client/dist/models/contact'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Make formatted address
|
|
5
|
+
* @param {{ name: string, value: string }[]} subFieldsState - State of address sub fields
|
|
6
|
+
* @returns {string} - Formatted address
|
|
7
|
+
*/
|
|
8
|
+
export const makeFormattedAddressWithSubFields = (subFieldsState, t) => {
|
|
9
|
+
const normalizedAddress = subFieldsState.reduce((acc, curr) => {
|
|
10
|
+
const key = curr.name
|
|
11
|
+
.split('.')
|
|
12
|
+
.pop()
|
|
13
|
+
.replace(/address/, '')
|
|
14
|
+
|
|
15
|
+
return {
|
|
16
|
+
...acc,
|
|
17
|
+
[key]: curr.value || ''
|
|
18
|
+
}
|
|
19
|
+
}, {})
|
|
20
|
+
|
|
21
|
+
return cleanFormattedAddress(t('formatted.address', normalizedAddress))
|
|
22
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { makeFormattedAddressWithSubFields } from './helpers'
|
|
2
|
+
|
|
3
|
+
describe('makeFormattedAddressWithSubFields', () => {
|
|
4
|
+
it('should return full formatted address', () => {
|
|
5
|
+
const subFieldsStateMock = [
|
|
6
|
+
{ name: 'address[0].addressnumber', value: '10' },
|
|
7
|
+
{ name: 'address[0].addressstreet', value: 'rue du test' },
|
|
8
|
+
{ name: 'address[0].addresscode', value: '75056' },
|
|
9
|
+
{ name: 'address[0].addresscity', value: 'Paris' },
|
|
10
|
+
{ name: 'address[0].addresscountry', value: 'France' }
|
|
11
|
+
]
|
|
12
|
+
const res = makeFormattedAddressWithSubFields(
|
|
13
|
+
subFieldsStateMock,
|
|
14
|
+
jest.fn(() => '10 rue du test, 75056 Paris, France')
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
expect(res).toBe('10 rue du test, 75056 Paris, France')
|
|
18
|
+
})
|
|
19
|
+
it('should return formatted address if only "code" & "city" values are defined', () => {
|
|
20
|
+
const subFieldsStateMock = [
|
|
21
|
+
{ name: 'address[0].addressnumber', value: undefined },
|
|
22
|
+
{ name: 'address[0].addressstreet', value: undefined },
|
|
23
|
+
{ name: 'address[0].addresscode', value: '75056' },
|
|
24
|
+
{ name: 'address[0].addresscity', value: 'Paris' },
|
|
25
|
+
{ name: 'address[0].addresscountry', value: undefined }
|
|
26
|
+
]
|
|
27
|
+
const res = makeFormattedAddressWithSubFields(
|
|
28
|
+
subFieldsStateMock,
|
|
29
|
+
jest.fn(() => ' , 75056 Paris, ')
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
expect(res).toBe('75056 Paris')
|
|
33
|
+
})
|
|
34
|
+
it('should return formatted address if "code" & "city" values are undefined', () => {
|
|
35
|
+
const subFieldsStateMock = [
|
|
36
|
+
{ name: 'address[0].addressnumber', value: '10' },
|
|
37
|
+
{ name: 'address[0].addressstreet', value: 'rue du test' },
|
|
38
|
+
{ name: 'address[0].addresscode', value: undefined },
|
|
39
|
+
{ name: 'address[0].addresscity', value: undefined },
|
|
40
|
+
{ name: 'address[0].addresscountry', value: 'France' }
|
|
41
|
+
]
|
|
42
|
+
const res = makeFormattedAddressWithSubFields(
|
|
43
|
+
subFieldsStateMock,
|
|
44
|
+
jest.fn(() => '10 rue du test, , France')
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
expect(res).toBe('10 rue du test, France')
|
|
48
|
+
})
|
|
49
|
+
it('should return formatted address if all values are undefined', () => {
|
|
50
|
+
const subFieldsStateMock = [
|
|
51
|
+
{ name: 'address[0].addressnumber', value: undefined },
|
|
52
|
+
{ name: 'address[0].addressstreet', value: undefined },
|
|
53
|
+
{ name: 'address[0].addresscode', value: undefined },
|
|
54
|
+
{ name: 'address[0].addresscity', value: undefined },
|
|
55
|
+
{ name: 'address[0].addresscountry', value: undefined }
|
|
56
|
+
]
|
|
57
|
+
const res = makeFormattedAddressWithSubFields(
|
|
58
|
+
subFieldsStateMock,
|
|
59
|
+
jest.fn(() => ' , , ')
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
expect(res).toBe('')
|
|
63
|
+
})
|
|
64
|
+
})
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import PropTypes from 'prop-types'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
import { Field, useForm } from 'react-final-form'
|
|
4
|
+
|
|
5
|
+
import { makeFormattedAddressWithSubFields } from './helpers'
|
|
6
|
+
import { locales } from './locales'
|
|
7
|
+
import Button from '../../../Buttons'
|
|
8
|
+
import { FixedDialog } from '../../../CozyDialogs'
|
|
9
|
+
import { useI18n, useExtendI18n } from '../../../providers/I18n'
|
|
10
|
+
import FieldInputWrapper from '../ContactForm/FieldInputWrapper'
|
|
11
|
+
import { fieldInputAttributesTypes } from '../types'
|
|
12
|
+
|
|
13
|
+
const ContactAddressModal = ({ onClose, name, subFields }) => {
|
|
14
|
+
useExtendI18n(locales)
|
|
15
|
+
const { t } = useI18n()
|
|
16
|
+
const { getFieldState, change } = useForm()
|
|
17
|
+
|
|
18
|
+
const subFieldsState = subFields.map(subField =>
|
|
19
|
+
getFieldState(`${name}${subField.name}`)
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
const onConfirm = () => {
|
|
23
|
+
const hasBeenModified = subFieldsState.some(state => !state.pristine)
|
|
24
|
+
if (!hasBeenModified) {
|
|
25
|
+
return onClose()
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const formattedAddress = makeFormattedAddressWithSubFields(
|
|
29
|
+
subFieldsState,
|
|
30
|
+
t
|
|
31
|
+
)
|
|
32
|
+
change(name, formattedAddress)
|
|
33
|
+
|
|
34
|
+
onClose()
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const onCancel = () => {
|
|
38
|
+
subFieldsState.forEach(({ name, initial }) => change(name, initial))
|
|
39
|
+
onClose()
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<FixedDialog
|
|
44
|
+
open
|
|
45
|
+
onClose={onClose}
|
|
46
|
+
size="small"
|
|
47
|
+
title={t('Contacts.AddModal.ContactAddressDialog.fields.address')}
|
|
48
|
+
content={subFields.map(subField => (
|
|
49
|
+
<div key={subField.name} className="u-mt-1">
|
|
50
|
+
<Field
|
|
51
|
+
label={t(
|
|
52
|
+
`Contacts.AddModal.ContactAddressDialog.fields.${subField.name}`
|
|
53
|
+
)}
|
|
54
|
+
attributes={{ type: subField.type }}
|
|
55
|
+
name={`${name}${subField.name}`}
|
|
56
|
+
component={FieldInputWrapper}
|
|
57
|
+
/>
|
|
58
|
+
</div>
|
|
59
|
+
))}
|
|
60
|
+
actions={
|
|
61
|
+
<>
|
|
62
|
+
<Button
|
|
63
|
+
variant="secondary"
|
|
64
|
+
label={t('Contacts.AddModal.ContactAddressDialog.cancel')}
|
|
65
|
+
onClick={onCancel}
|
|
66
|
+
/>
|
|
67
|
+
<Button
|
|
68
|
+
className="u-ml-half"
|
|
69
|
+
label={t('Contacts.AddModal.ContactAddressDialog.ok')}
|
|
70
|
+
onClick={onConfirm}
|
|
71
|
+
/>
|
|
72
|
+
</>
|
|
73
|
+
}
|
|
74
|
+
/>
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
ContactAddressModal.propTypes = {
|
|
79
|
+
onClose: PropTypes.func.isRequired,
|
|
80
|
+
name: PropTypes.string.isRequired,
|
|
81
|
+
subFields: PropTypes.arrayOf(fieldInputAttributesTypes).isRequired
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export default ContactAddressModal
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"Contacts": {
|
|
3
|
+
"AddModal": {
|
|
4
|
+
"ContactAddressDialog": {
|
|
5
|
+
"fields": {
|
|
6
|
+
"address": "Address",
|
|
7
|
+
"number": "Lane number",
|
|
8
|
+
"street": "Postal address",
|
|
9
|
+
"code": "Postal code",
|
|
10
|
+
"city": "City",
|
|
11
|
+
"country": "Country",
|
|
12
|
+
"locality": "Locality",
|
|
13
|
+
"building": "Building",
|
|
14
|
+
"stairs": "Stairs",
|
|
15
|
+
"floor": "Floor",
|
|
16
|
+
"apartment": "Apartment",
|
|
17
|
+
"region": "Region",
|
|
18
|
+
"entrycode": "Entry code"
|
|
19
|
+
},
|
|
20
|
+
"cancel": "Cancel",
|
|
21
|
+
"ok": "Ok"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"Contacts": {
|
|
3
|
+
"AddModal": {
|
|
4
|
+
"ContactAddressDialog": {
|
|
5
|
+
"fields": {
|
|
6
|
+
"address": "Adresse",
|
|
7
|
+
"number": "Numéro de voie",
|
|
8
|
+
"street": "Adresse postal",
|
|
9
|
+
"code": "Code postal",
|
|
10
|
+
"city": "Ville",
|
|
11
|
+
"country": "Pays",
|
|
12
|
+
"locality": "Lieu-dit",
|
|
13
|
+
"building": "Bâtiment",
|
|
14
|
+
"stairs": "Escalier",
|
|
15
|
+
"floor": "Etage",
|
|
16
|
+
"apartment": "Appartement",
|
|
17
|
+
"region": "Région",
|
|
18
|
+
"entrycode": "Code d'entrée"
|
|
19
|
+
},
|
|
20
|
+
"cancel": "Annuler",
|
|
21
|
+
"ok": "Ok"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import cx from 'classnames'
|
|
2
|
+
import uniqueId from 'lodash/uniqueId'
|
|
3
|
+
import PropTypes from 'prop-types'
|
|
4
|
+
import React, { useState } from 'react'
|
|
5
|
+
import { Field } from 'react-final-form'
|
|
6
|
+
|
|
7
|
+
import FieldInputWrapper from './FieldInputWrapper'
|
|
8
|
+
import HasValueCondition from './HasValueCondition'
|
|
9
|
+
import { RelatedContactList } from './RelatedContactList'
|
|
10
|
+
import { locales } from './locales'
|
|
11
|
+
import styles from './styles.styl'
|
|
12
|
+
import { useI18n, useExtendI18n } from '../../../providers/I18n'
|
|
13
|
+
import ContactAddressDialog from '../ContactAddressDialog'
|
|
14
|
+
import { fieldInputAttributesTypes, labelPropTypes } from '../types'
|
|
15
|
+
|
|
16
|
+
const FieldInput = ({
|
|
17
|
+
name,
|
|
18
|
+
labelProps,
|
|
19
|
+
attributes: { subFields, ...restAttributes },
|
|
20
|
+
contacts,
|
|
21
|
+
error,
|
|
22
|
+
helperText,
|
|
23
|
+
label,
|
|
24
|
+
required
|
|
25
|
+
}) => {
|
|
26
|
+
const [id] = useState(uniqueId('field_')) // state only use to generate id once and not at each render
|
|
27
|
+
const [hasBeenFocused, setHasBeenFocused] = useState(false)
|
|
28
|
+
const [isAddressDialogOpen, setIsAddressDialogOpen] = useState(false)
|
|
29
|
+
const [isRelatedContactDialogOpen, setIsRelatedContactDialogOpen] =
|
|
30
|
+
useState(false)
|
|
31
|
+
useExtendI18n(locales)
|
|
32
|
+
const { t } = useI18n()
|
|
33
|
+
|
|
34
|
+
const handleClick = () => {
|
|
35
|
+
if (name.includes('address')) {
|
|
36
|
+
setIsAddressDialogOpen(true)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (name.includes('relatedContact')) {
|
|
40
|
+
setIsRelatedContactDialogOpen(true)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const onFocus = () => {
|
|
45
|
+
setHasBeenFocused(true)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<div
|
|
50
|
+
className={cx(
|
|
51
|
+
styles['contact-form-field__wrapper'],
|
|
52
|
+
'u-flex',
|
|
53
|
+
'u-flex-column-s'
|
|
54
|
+
)}
|
|
55
|
+
>
|
|
56
|
+
<Field
|
|
57
|
+
required={required}
|
|
58
|
+
error={error}
|
|
59
|
+
helperText={helperText}
|
|
60
|
+
label={label}
|
|
61
|
+
id={id}
|
|
62
|
+
attributes={restAttributes}
|
|
63
|
+
name={name}
|
|
64
|
+
component={FieldInputWrapper}
|
|
65
|
+
onFocus={onFocus}
|
|
66
|
+
onClick={handleClick}
|
|
67
|
+
/>
|
|
68
|
+
{isAddressDialogOpen && (
|
|
69
|
+
<ContactAddressDialog
|
|
70
|
+
onClose={() => setIsAddressDialogOpen(false)}
|
|
71
|
+
name={name}
|
|
72
|
+
subFields={subFields}
|
|
73
|
+
/>
|
|
74
|
+
)}
|
|
75
|
+
{isRelatedContactDialogOpen && (
|
|
76
|
+
<RelatedContactList
|
|
77
|
+
onClose={() => setIsRelatedContactDialogOpen(false)}
|
|
78
|
+
name={name}
|
|
79
|
+
contacts={contacts}
|
|
80
|
+
/>
|
|
81
|
+
)}
|
|
82
|
+
{labelProps && (
|
|
83
|
+
<HasValueCondition name={name} otherCondition={hasBeenFocused}>
|
|
84
|
+
<div className="u-mt-half-s u-ml-half u-ml-0-s u-flex-shrink-0 u-w-auto u-miw-4">
|
|
85
|
+
<Field
|
|
86
|
+
attributes={labelProps}
|
|
87
|
+
name={`${name}Label`}
|
|
88
|
+
label={t('Contacts.AddModal.ContactForm.fields.label')}
|
|
89
|
+
component={FieldInputWrapper}
|
|
90
|
+
onFocus={onFocus}
|
|
91
|
+
/>
|
|
92
|
+
</div>
|
|
93
|
+
</HasValueCondition>
|
|
94
|
+
)}
|
|
95
|
+
</div>
|
|
96
|
+
)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
FieldInput.propTypes = {
|
|
100
|
+
name: PropTypes.string.isRequired,
|
|
101
|
+
labelProps: labelPropTypes,
|
|
102
|
+
attributes: fieldInputAttributesTypes,
|
|
103
|
+
contacts: PropTypes.shape({
|
|
104
|
+
data: PropTypes.arrayOf(PropTypes.object)
|
|
105
|
+
}),
|
|
106
|
+
// Destructuring props
|
|
107
|
+
id: PropTypes.string,
|
|
108
|
+
label: PropTypes.string,
|
|
109
|
+
required: PropTypes.bool
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
FieldInput.defaultProps = {
|
|
113
|
+
labelProps: null,
|
|
114
|
+
required: false
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export default FieldInput
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import cx from 'classnames'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
import { FieldArray } from 'react-final-form-arrays'
|
|
4
|
+
|
|
5
|
+
import FieldInput from './FieldInput'
|
|
6
|
+
import { fieldsRequired, addField, removeField } from './helpers'
|
|
7
|
+
import { locales } from './locales'
|
|
8
|
+
import Button from '../../../Buttons'
|
|
9
|
+
import Icon from '../../../Icon'
|
|
10
|
+
import IconButton from '../../../IconButton'
|
|
11
|
+
import CrossCircleIcon from '../../../Icons/CrossCircle'
|
|
12
|
+
import PlusIcon from '../../../Icons/Plus'
|
|
13
|
+
import ListItemIcon from '../../../ListItemIcon'
|
|
14
|
+
import { useI18n, useExtendI18n } from '../../../providers/I18n'
|
|
15
|
+
|
|
16
|
+
const FieldInputArray = ({
|
|
17
|
+
attributes: { name, label, ...restAttributes },
|
|
18
|
+
contacts,
|
|
19
|
+
formProps: { valid, submitFailed, errors }
|
|
20
|
+
}) => {
|
|
21
|
+
useExtendI18n(locales)
|
|
22
|
+
const { t } = useI18n()
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<FieldArray name={name}>
|
|
26
|
+
{({ fields }) => {
|
|
27
|
+
return (
|
|
28
|
+
<>
|
|
29
|
+
{fields.map((nameWithIndex, index) => {
|
|
30
|
+
const key = fields.value[index]?.fieldId || nameWithIndex
|
|
31
|
+
const showRemove = fields.value[index]?.[name]
|
|
32
|
+
const inputName = `${nameWithIndex}.${name}`
|
|
33
|
+
const isError =
|
|
34
|
+
fieldsRequired.includes(inputName) && !valid && submitFailed
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<div
|
|
38
|
+
key={key}
|
|
39
|
+
className={cx('u-flex u-flex-items-center', {
|
|
40
|
+
'u-mt-1': index !== 0
|
|
41
|
+
})}
|
|
42
|
+
>
|
|
43
|
+
<FieldInput
|
|
44
|
+
attributes={restAttributes}
|
|
45
|
+
contacts={contacts}
|
|
46
|
+
error={isError}
|
|
47
|
+
helperText={isError ? errors[inputName] : null}
|
|
48
|
+
name={inputName}
|
|
49
|
+
label={t(`Contacts.AddModal.ContactForm.fields.${name}`)}
|
|
50
|
+
labelProps={label}
|
|
51
|
+
/>
|
|
52
|
+
{showRemove && (
|
|
53
|
+
<ListItemIcon className="u-ml-half">
|
|
54
|
+
<IconButton
|
|
55
|
+
aria-label="delete"
|
|
56
|
+
color="error"
|
|
57
|
+
size="medium"
|
|
58
|
+
onClick={() => removeField(fields, index)}
|
|
59
|
+
>
|
|
60
|
+
<Icon icon={CrossCircleIcon} />
|
|
61
|
+
</IconButton>
|
|
62
|
+
</ListItemIcon>
|
|
63
|
+
)}
|
|
64
|
+
</div>
|
|
65
|
+
)
|
|
66
|
+
})}
|
|
67
|
+
<Button
|
|
68
|
+
variant="text"
|
|
69
|
+
startIcon={<Icon icon={PlusIcon} />}
|
|
70
|
+
onClick={() => addField(fields)}
|
|
71
|
+
label={t(`Contacts.AddModal.ContactForm.addLabel.${name}`)}
|
|
72
|
+
/>
|
|
73
|
+
</>
|
|
74
|
+
)
|
|
75
|
+
}}
|
|
76
|
+
</FieldArray>
|
|
77
|
+
)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export default FieldInputArray
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import cx from 'classnames'
|
|
2
|
+
import PropTypes from 'prop-types'
|
|
3
|
+
import React from 'react'
|
|
4
|
+
|
|
5
|
+
import FieldInput from './FieldInput'
|
|
6
|
+
import FieldInputArray from './FieldInputArray'
|
|
7
|
+
import { fieldsRequired } from './helpers'
|
|
8
|
+
import { locales } from './locales'
|
|
9
|
+
import Icon from '../../../Icon'
|
|
10
|
+
import { useI18n, useExtendI18n } from '../../../providers/I18n'
|
|
11
|
+
|
|
12
|
+
const FieldInputLayout = ({
|
|
13
|
+
attributes: { isArray, icon, ...attributes }, // ⚠️ isArray and icon here are removed from attributes to avoid DOM propagration
|
|
14
|
+
contacts,
|
|
15
|
+
formProps
|
|
16
|
+
}) => {
|
|
17
|
+
useExtendI18n(locales)
|
|
18
|
+
const { t } = useI18n()
|
|
19
|
+
const { valid, submitFailed, errors } = formProps
|
|
20
|
+
const { name, label, ...restAttributes } = attributes
|
|
21
|
+
|
|
22
|
+
const isError = fieldsRequired.includes(name) && !valid && submitFailed
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<div
|
|
26
|
+
className={cx('u-flex u-mt-1', {
|
|
27
|
+
'u-flex-items-center': !isArray,
|
|
28
|
+
'u-flex-items-baseline': isArray
|
|
29
|
+
})}
|
|
30
|
+
>
|
|
31
|
+
<div className="u-w-2-half">
|
|
32
|
+
{icon && <Icon icon={icon} color="var(--iconTextColor)" />}
|
|
33
|
+
</div>
|
|
34
|
+
<div className="u-w-100">
|
|
35
|
+
{isArray ? (
|
|
36
|
+
<FieldInputArray
|
|
37
|
+
attributes={attributes}
|
|
38
|
+
contacts={contacts}
|
|
39
|
+
formProps={formProps}
|
|
40
|
+
/>
|
|
41
|
+
) : (
|
|
42
|
+
<FieldInput
|
|
43
|
+
attributes={restAttributes}
|
|
44
|
+
contacts={contacts}
|
|
45
|
+
error={isError}
|
|
46
|
+
helperText={isError ? errors[name] : null}
|
|
47
|
+
name={name}
|
|
48
|
+
label={t(`Contacts.AddModal.ContactForm.fields.${name}`)}
|
|
49
|
+
labelProps={label}
|
|
50
|
+
/>
|
|
51
|
+
)}
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
FieldInputLayout.propTypes = {
|
|
58
|
+
attributes: PropTypes.object,
|
|
59
|
+
contacts: PropTypes.shape({
|
|
60
|
+
data: PropTypes.arrayOf(PropTypes.object)
|
|
61
|
+
}),
|
|
62
|
+
formProps: PropTypes.object
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export default FieldInputLayout
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
|
|
3
|
+
import TextFieldCustomLabelSelect from './TextFieldCustomLabelSelect'
|
|
4
|
+
import TextFieldSelect from './TextFieldSelect'
|
|
5
|
+
import TextField from '../../../TextField'
|
|
6
|
+
import { FieldInputWrapperPropTypes } from '../types'
|
|
7
|
+
|
|
8
|
+
// component used to flatten props to ensure compatibility
|
|
9
|
+
// between Field from react-final-form and TextField from Mui
|
|
10
|
+
const FieldInputWrapper = ({
|
|
11
|
+
input,
|
|
12
|
+
attributes,
|
|
13
|
+
variant,
|
|
14
|
+
fullWidth,
|
|
15
|
+
...props
|
|
16
|
+
}) => {
|
|
17
|
+
const Component = attributes.customLabelOptions
|
|
18
|
+
? TextFieldCustomLabelSelect
|
|
19
|
+
: attributes?.select
|
|
20
|
+
? TextFieldSelect
|
|
21
|
+
: TextField
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<Component
|
|
25
|
+
{...attributes}
|
|
26
|
+
{...input}
|
|
27
|
+
{...props}
|
|
28
|
+
variant={variant}
|
|
29
|
+
fullWidth={fullWidth}
|
|
30
|
+
minRows="2"
|
|
31
|
+
/>
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
FieldInputWrapper.propTypes = FieldInputWrapperPropTypes
|
|
36
|
+
FieldInputWrapper.defaultProps = {
|
|
37
|
+
variant: 'outlined',
|
|
38
|
+
fullWidth: true
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export default FieldInputWrapper
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Wrapper for react-final-form field that renders it children only if the field
|
|
3
|
+
with the given name has a truthy value or if the other condition is fulfilled
|
|
4
|
+
*/
|
|
5
|
+
import PropTypes from 'prop-types'
|
|
6
|
+
import React from 'react'
|
|
7
|
+
import { Field } from 'react-final-form'
|
|
8
|
+
|
|
9
|
+
const HasValueCondition = ({ children, otherCondition, name }) => {
|
|
10
|
+
return (
|
|
11
|
+
<Field name={name} subscription={{ value: true }}>
|
|
12
|
+
{({ input: { value } }) =>
|
|
13
|
+
(otherCondition !== undefined && otherCondition) || value
|
|
14
|
+
? children
|
|
15
|
+
: null
|
|
16
|
+
}
|
|
17
|
+
</Field>
|
|
18
|
+
)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
HasValueCondition.defaultProps = {
|
|
22
|
+
otherCondition: undefined
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
HasValueCondition.propTypes = {
|
|
26
|
+
children: PropTypes.element.isRequired,
|
|
27
|
+
name: PropTypes.string.isRequired,
|
|
28
|
+
otherCondition: PropTypes.bool
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export default HasValueCondition
|