import * as React from 'react'; import IconButton from 'material-ui/IconButton'; import RaisedButton from 'material-ui/RaisedButton'; import TextField from 'material-ui/TextField'; import SelectField from 'material-ui/SelectField'; import MenuItem from 'material-ui/MenuItem'; import IconAdd from 'material-ui/svg-icons/content/add'; import IconClear from 'material-ui/svg-icons/content/clear'; import * as uuid from 'uuid'; import * as ICAL from 'ical.js'; import * as EteSync from '../api/EteSync'; import { ContactType } from '../pim-types'; const telTypes = [ {type: 'Home'}, {type: 'Work'}, {type: 'Cell'}, {type: 'Other'}, ]; const emailTypes = telTypes; const addressTypes = [ {type: 'Home'}, {type: 'Work'}, {type: 'Other'}, ]; const imppTypes = [ {type: 'Jabber'}, {type: 'Hangouts'}, {type: 'Other'}, ]; const TypeSelector = (props: any) => { const types = props.types as {type: string}[]; return ( {types.map((x) => ( ))} ); }; class ValueType { type: string; value: string; constructor(type?: string, value?: string) { this.type = type ? type : 'home'; this.value = value ? value : ''; } } interface ValueTypeComponentProps { type?: string; style?: object; types: {type: string}[]; name: string; hintText: string; value: ValueType; onClearRequest: (name: string) => void; onChange: (name: string, type: string, value: string) => void; } const ValueTypeComponent = (props: ValueTypeComponentProps) => { return ( ) => props.onChange(props.name, props.value.type, event.target.value)} /> props.onClearRequest(props.name)} tooltip="Remove" > props.onChange(props.name, payload, props.value.value) } /> ); }; class ContactEdit extends React.PureComponent { state: { uid: string, fn: string; phone: ValueType[]; email: ValueType[]; address: ValueType[]; impp: ValueType[]; org: string; note: string; title: string; journalUid: string; }; props: { collections: Array, initialCollection?: string, item?: ContactType, onSave: (contact: ContactType, journalUid: string, originalContact?: ContactType) => void; }; constructor(props: any) { super(props); this.state = { uid: '', fn: '', phone: [new ValueType()], email: [new ValueType()], address: [new ValueType()], impp: [new ValueType()], org: '', note: '', title: '', journalUid: '', }; if (this.props.item !== undefined) { const contact = this.props.item; this.state.uid = contact.uid; this.state.fn = contact.fn ? contact.fn : ''; // FIXME: Am I really getting all the values this way? const propToValueType = (comp: ICAL.Component, propName: string) => ( comp.getAllProperties(propName).map((prop) => ( new ValueType( prop.toJSON()[1].type, prop.getFirstValue() ) )) ); this.state.phone = propToValueType(contact.comp, 'tel'); this.state.email = propToValueType(contact.comp, 'email'); this.state.address = propToValueType(contact.comp, 'adr'); this.state.impp = propToValueType(contact.comp, 'impp'); const propToStringType = (comp: ICAL.Component, propName: string) => { const val = comp.getFirstPropertyValue(propName); return val ? val : ''; }; this.state.org = propToStringType(contact.comp, 'org'); this.state.title = propToStringType(contact.comp, 'title'); this.state.note = propToStringType(contact.comp, 'note'); } else { this.state.uid = uuid.v4(); } if (props.initialCollection) { this.state.journalUid = props.initialCollection; } else if (props.collections[0]) { this.state.journalUid = props.collections[0].uid; } this.onSubmit = this.onSubmit.bind(this); this.handleChange = this.handleChange.bind(this); this.handleInputChange = this.handleInputChange.bind(this); this.handleValueTypeChange = this.handleValueTypeChange.bind(this); this.addValueType = this.addValueType.bind(this); this.removeValueType = this.removeValueType.bind(this); } componentWillReceiveProps(nextProps: any) { if ((this.props.collections !== nextProps.collections) || (this.props.initialCollection !== nextProps.initialCollection)) { if (nextProps.initialCollection) { this.state.journalUid = nextProps.initialCollection; } else if (nextProps.collections[0]) { this.state.journalUid = nextProps.collections[0].uid; } } } addValueType(name: string, _type?: string) { const type = _type ? _type : 'home'; this.setState((prevState, props) => { let newArray = prevState[name].slice(0); newArray.push(new ValueType(type)); return { ...prevState, [name]: newArray, }; }); } removeValueType(name: string, idx: number) { this.setState((prevState, props) => { let newArray = prevState[name].slice(0); newArray.splice(idx, 1); return { ...prevState, [name]: newArray, }; }); } handleValueTypeChange(name: string, idx: number, value: ValueType) { this.setState((prevState, props) => { let newArray = prevState[name].slice(0); newArray[idx] = value; return { ...prevState, [name]: newArray, }; }); } handleChange(name: string, value: string) { this.setState({ [name]: value }); } handleInputChange(contact: any) { const name = contact.target.name; const value = contact.target.value; this.handleChange(name, value); } onSubmit(e: React.FormEvent) { e.preventDefault(); let contact = (this.props.item) ? this.props.item.clone() : new ContactType(new ICAL.Component(['vcard', [], []])) ; let comp = contact.comp; comp.updatePropertyWithValue('prodid', '-//iCal.js EteSync Web'); comp.updatePropertyWithValue('version', '4.0'); comp.updatePropertyWithValue('uid', this.state.uid); comp.updatePropertyWithValue('fn', this.state.fn); comp.updatePropertyWithValue('rev', ICAL.Time.now()); function setProperties(name: string, source: ValueType[]) { comp.removeAllProperties(name); source.forEach((x) => { if (x.value === '') { return; } let prop = new ICAL.Property(name, comp); prop.setParameter('type', x.type); prop.setValue(x.value); comp.addProperty(prop); }); } setProperties('tel', this.state.phone); setProperties('email', this.state.email); setProperties('adr', this.state.address); setProperties('impp', this.state.impp.map((x) => ( {type: x.type, value: x.type + ':' + x.value} ))); function setProperty(name: string, value: string) { comp.removeAllProperties(name); if (value !== '') { comp.updatePropertyWithValue(name, value); } } setProperty('org', this.state.org); setProperty('title', this.state.title); setProperty('note', this.state.note); this.props.onSave(contact, this.state.journalUid, this.props.item); } render() { const styles = { form: { }, fullWidth: { width: '100%', boxSizing: 'border-box', }, submit: { marginTop: 40, textAlign: 'right', }, }; return (

{this.props.item ? 'Edit Contact' : 'New Contact'}

this.handleChange('journalUid', payload)} > {this.props.collections.map((x) => ( ))}
Phone numbers this.addValueType('phone')} tooltip="Add phone number" >
{this.state.phone.map((x, idx) => ( this.removeValueType(name, idx)} onChange={(name: string, type: string, value: string) => ( this.handleValueTypeChange(name, idx, {type, value}) )} /> ))}
Emails this.addValueType('email')} tooltip="Add email address" >
{this.state.email.map((x, idx) => ( this.removeValueType(name, idx)} onChange={(name: string, type: string, value: string) => ( this.handleValueTypeChange(name, idx, {type, value}) )} /> ))}
IMPP this.addValueType('impp', 'jabber')} tooltip="Add impp address" >
{this.state.impp.map((x, idx) => ( this.removeValueType(name, idx)} onChange={(name: string, type: string, value: string) => ( this.handleValueTypeChange(name, idx, {type, value}) )} /> ))}
Addresses this.addValueType('address')} tooltip="Add address" >
{this.state.address.map((x, idx) => ( this.removeValueType(name, idx)} onChange={(name: string, type: string, value: string) => ( this.handleValueTypeChange(name, idx, {type, value}) )} /> ))}
Not all types are supported at the moment. If you are editing a contact, the unsupported types will be copied as is.
); } } export default ContactEdit;