Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions react/Contacts/AddModal/ContactForm/FieldInputWrapper.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,22 @@ import { FieldInputWrapperPropTypes } from '../types'
// between Field from react-final-form and TextField from Mui
const FieldInputWrapper = ({
input,
attributes,
attributes: { component, ...restAttributes },
variant,
fullWidth,
...props
}) => {
const Component = attributes.customLabelOptions
? TextFieldCustomLabelSelect
: attributes?.select
? TextFieldSelect
: TextField
const Component =
component ||
(restAttributes.customLabelOptions
? TextFieldCustomLabelSelect
: restAttributes?.select
? TextFieldSelect
: TextField)

return (
<Component
{...attributes}
{...restAttributes}
{...input}
{...props}
variant={variant}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { getFormattedAddress } from 'cozy-client/dist/models/contact'
import { fields } from './fieldsConfig'
import { makeItemLabel, makeRelatedContact, movePrimaryToHead } from './helpers'

const contactToFormValues = (contact, t) => {
const contactToFormValues = ({ contact, makeCustomContactValues, t }) => {
// initialize the form values, required so that array fields start with at least one editable field
const initialFieldValues = fields.reduce(
(initialValues, { name, layout }) => {
Expand Down Expand Up @@ -79,7 +79,10 @@ const contactToFormValues = (contact, t) => {

const relatedContactValue = makeRelatedContact(contact)

const customValues = makeCustomContactValues?.(contact) || {}

return {
...customValues,
gender,
givenName: name?.givenName,
additionalName: name?.additionalName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ describe('contactToFormValues function', () => {
relatedContact: [undefined]
}

const result = contactToFormValues(null, tSpy)
const result = contactToFormValues({ contact: null, t: tSpy })
expect(result).toEqual(expected)
})

Expand All @@ -34,7 +34,7 @@ describe('contactToFormValues function', () => {
'426 Runolfsson Knolls 84573 Port Easter Cocos (Keeling) Islands'
)

const result = contactToFormValues(johnDoeContact, tSpy)
const result = contactToFormValues({ contact: johnDoeContact, t: tSpy })
expect(result).toEqual(expected)
expect(tSpy).toHaveBeenCalledWith('formatted.address', {
street: '426 Runolfsson Knolls',
Expand Down Expand Up @@ -86,7 +86,7 @@ describe('contactToFormValues function', () => {
relatedContact: [undefined]
}

const result = contactToFormValues(contact, tSpy)
const result = contactToFormValues({ contact, t: tSpy })
expect(result).toEqual(expected)
})

Expand Down Expand Up @@ -127,7 +127,7 @@ describe('contactToFormValues function', () => {
relatedContact: [undefined]
}

const result = contactToFormValues(contact, tSpy)
const result = contactToFormValues({ contact, t: tSpy })
expect(result).toEqual(expected)
})
})
2 changes: 1 addition & 1 deletion react/Contacts/AddModal/ContactForm/fieldsConfig.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import TelephoneIcon from '../../../Icons/Telephone'
import InputAdornment from '../../../InputAdornment'

/**
* @type {import('../../../types').Field[]}
* @type {import('../types').Field[]}
*/
export const fields = [
{
Expand Down
10 changes: 9 additions & 1 deletion react/Contacts/AddModal/ContactForm/formValuesToContact.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ import {
makeTypeAndLabel
} from './helpers'

const formValuesToContact = ({ formValues, oldContact, t }) => {
const formValuesToContact = ({
formValues,
oldContact,
makeCustomFieldsFormValues,
t
}) => {
const {
gender,
givenName,
Expand Down Expand Up @@ -45,8 +50,11 @@ const formValuesToContact = ({ formValues, oldContact, t }) => {
}
}

const customFieldsFormValues = makeCustomFieldsFormValues?.(formValues) || {}

const contactWithFormValues = {
...oldContactCleaned,
...customFieldsFormValues,
gender: gender || '',
name: {
...oldContactCleaned?.name,
Expand Down
31 changes: 27 additions & 4 deletions react/Contacts/AddModal/ContactForm/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,10 @@ export const createAddress = ({ address, oldContact, t }) => {
.filter(val => val && val.address)
.map((addressField, index) => {
const oldContactAddress = oldContact?.address?.[index]
const oldContactFormValues = contactToFormValues(oldContact, t)
?.address?.[index]
const oldContactFormValues = contactToFormValues({
contact: oldContact,
t
})?.address?.[index]

const addressHasBeenModified = !isEqual(
addressField,
Expand Down Expand Up @@ -138,7 +140,7 @@ export const createAddress = ({ address, oldContact, t }) => {
}

/**
* @param {(import('../../../types').RelatedContact|undefined)[]} relatedContact - The related contacts array
* @param {(import('../types').RelatedContact|undefined)[]} relatedContact - The related contacts array
* @returns {Record<string, { data: { _id: string, _type: string }[] }>} - The related contacts relationships
*/
export const getRelatedContactRelationships = relatedContact => {
Expand Down Expand Up @@ -218,7 +220,7 @@ export const removeAsscociatedData = contact => {

/**
* @param {import('cozy-client/types/types').IOCozyContact} contact
* @returns {import('../../../types').RelatedContact[]}
* @returns {import('../types').RelatedContact[]}
*/
export const makeRelatedContact = contact => {
if (
Expand Down Expand Up @@ -368,3 +370,24 @@ export const makeInitialCustomValue = (name, value) => {
return JSON.stringify({ type: valueObj.type, label: valueObj.label })
}
}

/**
* @param {(import('../types').Field)[]|undefined} customFields
* @param {(import('../types').Field)[]} defaultFields
* @returns {(import('../types').Field)[]}
*/
export const makeFields = (customFields, defaultFields) => {
if (!customFields) {
return defaultFields
}

const fields = [...defaultFields]

customFields.map(customField => {
if (customField.position) {
fields.splice(customField.position, 0, customField)
}
})

return fields
}
66 changes: 66 additions & 0 deletions react/Contacts/AddModal/ContactForm/helpers.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
makeTypeAndLabel,
makeImppValues,
makeCustomLabel,
makeFields,
makeInitialCustomValue
} from './helpers'
import { locales } from './locales'
Expand Down Expand Up @@ -323,3 +324,68 @@ describe('makeInitialCustomValue', () => {
})
})
})

describe('makeFields', () => {
it('should return custom fields at custom position', () => {
const customFields = [
{ name: 'middlename', position: 1 },
{ name: 'birthday', position: 3 }
]
const defaultFields = [{ name: 'firstname' }, { name: 'lastname' }]

const res = makeFields(customFields, defaultFields)

expect(res).toStrictEqual([
{ name: 'firstname' },
{ name: 'middlename', position: 1 },
{ name: 'lastname' },
{ name: 'birthday', position: 3 }
])
})

it('should ignore custom fields without position value', () => {
const customFields = [
{ name: 'middlename', position: 1 },
{ name: 'field-with-no-position' }
]
const defaultFields = [{ name: 'firstname' }, { name: 'lastname' }]

const res = makeFields(customFields, defaultFields)

expect(res).toStrictEqual([
{ name: 'firstname' },
{ name: 'middlename', position: 1 },
{ name: 'lastname' }
])
})

it('should not mutate the original arrays', () => {
const customFields = [
{ name: 'middlename', position: 1 },
{ name: 'field-with-no-position' },
{ name: 'birthday', position: 3 }
]
const defaultFields = [{ name: 'firstname' }, { name: 'lastname' }]

makeFields(customFields, defaultFields)

expect(defaultFields).toStrictEqual([
{ name: 'firstname' },
{ name: 'lastname' }
])

expect(customFields).toStrictEqual([
{ name: 'middlename', position: 1 },
{ name: 'field-with-no-position' },
{ name: 'birthday', position: 3 }
])
})

it('should handle undefined custom fields', () => {
const defaultFields = [{ name: 'firstname' }, { name: 'lastname' }]

const res = makeFields(undefined, defaultFields)

expect(res).toStrictEqual(defaultFields)
})
})
37 changes: 29 additions & 8 deletions react/Contacts/AddModal/ContactForm/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import { getHasManyItems } from 'cozy-client/dist/associations/HasMany'

import FieldInputLayout from './FieldInputLayout'
import contactToFormValues from './contactToFormValues'
import { fields } from './fieldsConfig'
import { fields as defaultFields } from './fieldsConfig'
import formValuesToContact from './formValuesToContact'
import { validateFields } from './helpers'
import { validateFields, makeFields } from './helpers'
import { locales } from './locales'
import Button from '../../../Buttons'
import { useI18n, useExtendI18n } from '../../../providers/I18n'
Expand All @@ -31,24 +31,41 @@ export function getSubmitContactForm() {
/**
*
* @param {object} params
* @param {{ data: Array<object> }} params.contacts
* @param {import('cozy-client/types/types').IOCozyContact} params.contact
* @param {Object} params.customFieldsProps
* @param {func} params.onSubmit
* @param {{ data: Array<object> }} params.contacts
* @returns
*/
const ContactForm = ({ contact, onSubmit, contacts }) => {
const ContactForm = ({ contacts, contact, customFieldsProps, onSubmit }) => {
const [showSecondaryFields, setShowSecondaryFields] = useState(false)
useExtendI18n(locales)
const { t } = useI18n()
const { fields, makeCustomFieldsFormValues, makeCustomContactValues } =
customFieldsProps

const _fields = makeFields(fields, defaultFields)
const hasSecondaryFields = _fields.some(el => el.isSecondary)

return (
<Form
mutators={{ ...arrayMutators }}
initialValues={contactToFormValues({
contact,
makeCustomContactValues,
t
})}
validate={values => validateFields(values, t)}
onSubmit={formValues =>
onSubmit(formValuesToContact({ formValues, oldContact: contact, t }))
onSubmit(
formValuesToContact({
formValues,
oldContact: contact,
makeCustomFieldsFormValues,
t
})
)
}
initialValues={contactToFormValues(contact, t)}
render={({ handleSubmit, valid, submitFailed, errors }) => {
setSubmitContactForm(handleSubmit)
return (
Expand All @@ -57,7 +74,7 @@ const ContactForm = ({ contact, onSubmit, contacts }) => {
onSubmit={handleSubmit}
className="u-flex u-flex-column"
>
{fields.map((attributes, index) => (
{_fields.map((attributes, index) => (
<FieldInputLayout
key={index}
attributes={attributes}
Expand All @@ -70,7 +87,7 @@ const ContactForm = ({ contact, onSubmit, contacts }) => {
}}
/>
))}
{!showSecondaryFields && (
{hasSecondaryFields && !showSecondaryFields && (
<div>
<Button
className="u-db u-ml-2 u-mt-1"
Expand All @@ -87,6 +104,10 @@ const ContactForm = ({ contact, onSubmit, contacts }) => {
)
}

ContactForm.defaultProps = {
customFieldsProps: {}
}

// Used to avoid unnecessary multiple rendering of ContactForm when creating a new contact in another way.
// These unnecessary renderings prevented the addition of a newly created linked contact. (Creation of a contact when selecting a linked contact)
export const isSameContactProp = (prevProps, nextProps) => {
Expand Down
17 changes: 13 additions & 4 deletions react/Contacts/AddModal/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ Works with `final-form`, `final-form-arrays`, `react-final-form` and `react-fina

```jsx
import { useState } from 'react'
import StarIcon from 'cozy-ui/transpiled/react/Icons/Star'
import TextField from 'cozy-ui/transpiled/react/TextField'
import ContactsAddModal from 'cozy-ui/transpiled/react/Contacts/AddModal'
import DemoProvider from 'cozy-ui/docs/components/DemoProvider'
import AlertProvider from 'cozy-ui/transpiled/react/providers/Alert'
Expand All @@ -13,7 +15,7 @@ import contacts from 'cozy-ui/transpiled/react/ContactsList/_mockContacts.json'
import Variants from 'cozy-ui/docs/components/Variants'

initialState = { showModal: isTesting() }
initialVariants = [{ withContact: false }]
initialVariants = [{ withContact: false, withCustomFields: false }]

const open = () => setState({ showModal: true })
const close = () => setState({ showModal: false })
Expand All @@ -22,18 +24,25 @@ const handleSubmit = async formData => {
console.info('formData :', formData)
}

const customFields = [{ name: 'customField', icon: StarIcon, type: 'text', position: 5, component: TextField }]

;

<DemoProvider>
<DemoProvider dictRequire={() => ({ Contacts: {AddModal: {ContactForm: {fields: {customField: 'Custom field'}}}} })}>
<AlertProvider>
<Variants initialVariants={initialVariants} screenshotAllVariants>
<Variants initialVariants={initialVariants}>
{variant => (
<>
<Button onClick={open} label="Open Modal" />
{state.showModal && (
<ContactsAddModal
contacts={{ data: contacts }}
contact={variant.withContact ? johnDoeContact : undefined}
contact={variant.withContact ? {...johnDoeContact, customField: "Custom field value"} : undefined}
customFieldsProps={variant.withCustomFields && {
fields: customFields,
makeCustomFieldsFormValues: formValues => ({ customField: formValues.customField }),
makeCustomContactValues: contact => ({ customField: contact.customField })
}}
onSubmit={handleSubmit}
onClose={close}
/>
Expand Down
Loading
Loading