202 lines
5.3 KiB
TypeScript
202 lines
5.3 KiB
TypeScript
// SPDX-FileCopyrightText: © 2017 EteSync Authors
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
import * as React from 'react';
|
|
import moment from 'moment';
|
|
|
|
import { List, ListItem, ListDivider as Divider } from '../widgets/List';
|
|
import IconHome from '@material-ui/icons/Home';
|
|
import IconDate from '@material-ui/icons/DateRange';
|
|
import CommunicationCall from '@material-ui/icons/Call';
|
|
import CommunicationChatBubble from '@material-ui/icons/ChatBubble';
|
|
import CommunicationEmail from '@material-ui/icons/Email';
|
|
import CopyIcon from '../icons/Copy';
|
|
|
|
import PimItemHeader from './PimItemHeader';
|
|
|
|
import { ContactType } from '../pim-types';
|
|
import { IconButton, Avatar } from '@material-ui/core';
|
|
|
|
class Contact extends React.PureComponent {
|
|
public props: {
|
|
item?: ContactType;
|
|
};
|
|
|
|
public render() {
|
|
if (this.props.item === undefined) {
|
|
throw Error('Contact should be defined!');
|
|
}
|
|
|
|
const contact = this.props.item;
|
|
const name = contact.fn;
|
|
|
|
const revProp = contact.comp.getFirstProperty('rev');
|
|
const lastModified = (revProp) ?
|
|
'Modified: ' + moment(revProp.getFirstValue().toJSDate()).format('LLLL') : undefined;
|
|
|
|
const lists = [];
|
|
|
|
function getAllType(
|
|
propName: string,
|
|
props: any,
|
|
valueToHref?: (value: string, type: string) => string,
|
|
primaryTransform?: (value: string, type: string) => string,
|
|
secondaryTransform?: (value: string, type: string) => string) {
|
|
|
|
return contact.comp.getAllProperties(propName).map((prop, idx) => {
|
|
const type = prop.toJSON()[1].type;
|
|
const values = prop.getValues().map((val) => {
|
|
const primaryText = primaryTransform ? primaryTransform(val, type) : val;
|
|
const clipboardButton = (
|
|
<IconButton
|
|
onClick={(e) => {
|
|
e.preventDefault();
|
|
(window as any).navigator.clipboard.writeText(primaryText);
|
|
}}
|
|
>
|
|
<CopyIcon />
|
|
</IconButton>
|
|
);
|
|
|
|
return (
|
|
<ListItem
|
|
key={idx}
|
|
href={valueToHref ? valueToHref(val, type) : undefined}
|
|
primaryText={primaryText}
|
|
rightIcon={clipboardButton}
|
|
secondaryText={secondaryTransform ? secondaryTransform(val, type) : type}
|
|
{...props}
|
|
/>
|
|
);
|
|
});
|
|
return values;
|
|
});
|
|
}
|
|
|
|
lists.push(getAllType(
|
|
'tel',
|
|
{
|
|
leftIcon: <CommunicationCall />,
|
|
},
|
|
(x) => ('tel:' + x)
|
|
));
|
|
|
|
lists.push(getAllType(
|
|
'email',
|
|
{
|
|
leftIcon: <CommunicationEmail />,
|
|
},
|
|
(x) => ('mailto:' + x)
|
|
));
|
|
|
|
lists.push(getAllType(
|
|
'impp',
|
|
{
|
|
leftIcon: <CommunicationChatBubble />,
|
|
},
|
|
(x) => x,
|
|
(x) => (x.substring(x.indexOf(':') + 1)),
|
|
(x) => (x.substring(0, x.indexOf(':')))
|
|
));
|
|
|
|
lists.push(getAllType(
|
|
'adr',
|
|
{
|
|
leftIcon: <IconHome />,
|
|
}
|
|
));
|
|
|
|
lists.push(getAllType(
|
|
'bday',
|
|
{
|
|
leftIcon: <IconDate />,
|
|
},
|
|
undefined,
|
|
((x: any) => moment(x.toJSDate()).format('dddd, LL')),
|
|
() => 'Birthday'
|
|
));
|
|
|
|
lists.push(getAllType(
|
|
'anniversary',
|
|
{
|
|
leftIcon: <IconDate />,
|
|
},
|
|
undefined,
|
|
((x: any) => moment(x.toJSDate()).format('dddd, LL')),
|
|
() => 'Anniversary'
|
|
));
|
|
|
|
const skips = ['tel', 'email', 'impp', 'adr', 'bday', 'anniversary', 'rev',
|
|
'prodid', 'uid', 'fn', 'n', 'version', 'photo', 'note'];
|
|
const theRest = contact.comp.getAllProperties().filter((prop) => (
|
|
skips.indexOf(prop.name) === -1
|
|
)).map((prop, idx) => {
|
|
const values = prop.getValues().map((_val) => {
|
|
const val = (_val instanceof String) ? _val : _val.toString();
|
|
return (
|
|
<ListItem
|
|
key={idx}
|
|
insetChildren
|
|
primaryText={val}
|
|
secondaryText={prop.name}
|
|
/>
|
|
);
|
|
});
|
|
return values;
|
|
});
|
|
|
|
{
|
|
const note = contact.comp.getFirstPropertyValue('note');
|
|
const item = (
|
|
<ListItem
|
|
key="note"
|
|
insetChildren
|
|
secondaryText="note"
|
|
>
|
|
<pre style={{ wordWrap: 'break-word', whiteSpace: 'pre-wrap', overflowX: 'auto' }}>{note}</pre>
|
|
</ListItem>
|
|
);
|
|
theRest.push([item]);
|
|
}
|
|
|
|
function listIfNotEmpty(items: JSX.Element[][]) {
|
|
if (items.length > 0) {
|
|
return (
|
|
<React.Fragment>
|
|
<List>
|
|
{items}
|
|
</List>
|
|
<List>
|
|
<Divider inset />
|
|
</List>
|
|
</React.Fragment>
|
|
);
|
|
} else {
|
|
return undefined;
|
|
}
|
|
}
|
|
|
|
const contactImageSrc = contact.comp.getFirstProperty('photo')?.getFirstValue();
|
|
|
|
return (
|
|
<div>
|
|
<PimItemHeader text={name} rightItem={contactImageSrc && (<Avatar style={{ width: '3em', height: '3em' }} src={contactImageSrc} />)}>
|
|
{lastModified && (
|
|
<span style={{ fontSize: '90%' }}>{lastModified}</span>
|
|
)}
|
|
</PimItemHeader>
|
|
{lists.map((list, idx) => (
|
|
<React.Fragment key={idx}>
|
|
{listIfNotEmpty(list)}
|
|
</React.Fragment>
|
|
))}
|
|
<List>
|
|
{theRest}
|
|
</List>
|
|
</div>
|
|
);
|
|
}
|
|
}
|
|
|
|
export default Contact;
|