You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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 "../components/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;