import { useCallback , useMemo , forwardRef , Ref } from 'react' ; import { c } from 'ttag' ; import { move } from '@proton/shared/lib/helpers/array' ; import { OTHER_INFORMATION_FIELDS } from '@proton/shared/lib/contacts/constants' ; import { ContactPropertyChange , ContactProperties , ContactEmailModel } from '@proton/shared/lib/interfaces/contacts' ; import { EXACTLY_ONE_MAY_BE_PRESENT , PROPERTIES } from '@proton/shared/lib/contacts/vcard' ; import { SimpleMap } from '@proton/shared/lib/interfaces' ; import { Button , Icon , OrderableContainer , OrderableElement } from '../../components' ; import ContactModalRow from './ContactModalRow' ; import EncryptedIcon from './EncryptedIcon' ; const ICONS = { fn : 'user' , email : 'envelope' , tel : 'phone-rotary' , adr : 'map-marker' , other : 'circle-info' , } ; interface Props { field ? : string ; properties : ContactProperties ; isSignatureVerified : boolean ; onChange : ( payload : ContactPropertyChange ) => void ; onOrderChange ? : ( field : string , orderedProperties : ContactProperties ) => void ; onAdd ? : ( ) => void ; onRemove : ( value : string ) => void ; isSubmitted ? : boolean ; contactEmails ? : SimpleMap < ContactEmailModel > ; onContactEmailChange ? : ( contactEmail : ContactEmailModel ) => void ; } const ContactModalProperties = ( { properties : allProperties , isSignatureVerified , field , onChange , onOrderChange , onAdd , onRemove , isSubmitted = false , contactEmails , onContactEmailChange , } , ref ) => { const TITLES = { fn : c ( 'Title' ) . t `Other names` , email : c ( 'Title' ) . t `Email addresses` , tel : c ( 'Title' ) . t `Phone numbers` , adr : c ( 'Title' ) . t `Addresses` , other : c ( 'Title' ) . t `Other information` , } ; const title = field ? TITLES [ field ] : TITLES . other ; const iconName = field ? ICONS [ field ] : ICONS . other ; const fields = field ? [ field ] : OTHER_INFORMATION_FIELDS ; const properties = allProperties . filter ( ( { field } ) => fields . includes ( field ) ) ; const canAdd = ! fields . includes ( 'fn' ) ; const rows = useMemo ( ( ) => { const isOtherFields = fields === OTHER_INFORMATION_FIELDS ; const filteredTypes = isOtherFields ? properties . filter ( ( property ) => PROPERTIES [ property . field ] . cardinality === EXACTLY_ONE_MAY_BE_PRESENT ) . map ( ( property ) => property . field ) : [ ] ; return properties . map ( ( property ) => ( < ContactModalRow key = { property . uid } ref = { ref } isSubmitted = { isSubmitted } property = { property } onChange = { onChange } onRemove = { onRemove } isOrderable = { ! ! onOrderChange } filteredTypes = { filteredTypes . filter ( ( type ) => property . field !== type ) } contactEmail = { contactEmails ?. [ property . value as string ] } onContactEmailChange = { onContactEmailChange } / > ) ) ; } , [ properties , onChange , onRemove , onAdd , ! ! onOrderChange ] ) ; const handleSortEnd = useCallback ( ( { newIndex , oldIndex } ) => { const orderedProperties = move ( properties , oldIndex , newIndex ) ; if ( onOrderChange && field ) { onOrderChange ( field , orderedProperties ) ; } } , [ properties , field ] ) ; if ( field === 'fn' && ! properties . length ) { return null ; } return ( < div className = "border-bottom mb1" > < h3 className = "mb1 flex flex-nowrap flex-align-items-center flex-item-noshrink" > < Icon className = "mr0-25 flex-item-noshrink" name = { iconName } / > < span className = "ml0-1 mr0-5" > { title } < /span> { ( ( field && ! [ 'fn' , 'email' ] . includes ( field ) ) || field === undefined ) && ( < EncryptedIcon className = "flex flex-item-centered-vert flex-item-noshrink" isSignatureVerified = { isSignatureVerified } / > ) } < /h3> { field && [ 'email' ] . includes ( field ) && ( < span className = "text-semibold ml1-5 pl0-25 mb0-5" > { c ( 'Info' ) . t `Primary` } < /span>)} { onOrderChange ? ( < OrderableContainer helperClass = "row--orderable" onSortEnd = { handleSortEnd } useDragHandle > < div className = "mt0-5" > { rows . map ( ( row , index ) => ( < OrderableElement key = { row . key || `row${ index }` } index = { index } > { row } < /OrderableElement>))} < /div> < /OrderableContainer>) : (<div>{rows}</div > ) } { canAdd && ( < div className = "flex flex-nowrap flex-item-noshrink" > < div className = "mr0-5 flex flex-align-items-center flex-item-noshrink" > < Icon name = "align-justify visibility-hidden" / > < /div> < div className = "flex flex-nowrap w95" > < Button color = "norm" shape = "outline" className = "mb1" onClick = { onAdd } data - testid = { field ? `add-${ field }` : 'add-other' } > { c ( 'Action' ) . t `Add` } < /Button> < /div> < /div>)} < /div>); } ; export default forwardRef ( ContactModalProperties ) ;