ImportDialog: change to be a function component.

master
Tom Hacohen 4 years ago
parent 749d9de581
commit cd7739a3d1

@ -33,89 +33,20 @@ interface PropsType {
onClose?: () => void; onClose?: () => void;
} }
class ImportDialog extends React.Component<PropsType> { export default function ImportDialog(props: PropsType) {
public state = { const [loading, setLoading] = React.useState(false);
loading: false,
};
constructor(props: PropsType) {
super(props);
this.onFileDropCommon = this.onFileDropCommon.bind(this);
this.onFileDropEvent = this.onFileDropEvent.bind(this);
this.onFileDropTask = this.onFileDropTask.bind(this);
this.onFileDropContact = this.onFileDropContact.bind(this);
this.onClose = this.onClose.bind(this);
}
public render() {
const { syncJournal } = this.props;
const { loading } = this.state;
const collectionInfo = syncJournal.collection;
let acceptTypes;
let dropFunction;
if (collectionInfo.type === "ADDRESS_BOOK") {
acceptTypes = ["text/vcard", "text/directory", "text/x-vcard", ".vcf"];
dropFunction = this.onFileDropContact;
} else if (collectionInfo.type === "CALENDAR") {
acceptTypes = ["text/calendar", ".ics", ".ical"];
dropFunction = this.onFileDropEvent;
} else if (collectionInfo.type === "TASKS") {
acceptTypes = ["text/calendar", ".ics", ".ical"];
dropFunction = this.onFileDropTask;
}
return (
<React.Fragment>
<Dialog
open={this.props.open}
onClose={this.onClose}
>
<DialogTitle>Import entries from file?</DialogTitle>
<DialogContent>
{loading ?
<LoadingIndicator style={{ display: "block", margin: "auto" }} />
:
<Dropzone
onDrop={dropFunction}
multiple={false}
accept={acceptTypes}
>
{({ getRootProps, getInputProps }) => (
<section>
<div {...getRootProps()}>
<input {...getInputProps()} />
<DialogContentText id="alert-dialog-description">
To import entries from a file, drag 'n' drop it here, or click to open the file selector.
</DialogContentText>
</div>
</section>
)}
</Dropzone>
}
</DialogContent>
<DialogActions>
<Button disabled={loading} onClick={this.onClose} color="primary">
Cancel
</Button>
</DialogActions>
</Dialog>
</React.Fragment>
);
}
private onFileDropCommon(itemsCreator: (fileText: string) => PimType[], acceptedFiles: File[], rejectedFiles: File[]) { function onFileDropCommon(itemsCreator: (fileText: string) => PimType[], acceptedFiles: File[], rejectedFiles: File[]) {
// XXX: implement handling of rejectedFiles // XXX: implement handling of rejectedFiles
const reader = new FileReader(); const reader = new FileReader();
reader.onabort = () => { reader.onabort = () => {
this.setState({ loading: false }); setLoading(false);
console.error("Import Aborted"); console.error("Import Aborted");
alert("file reading was aborted"); alert("file reading was aborted");
}; };
reader.onerror = (e) => { reader.onerror = (e) => {
this.setState({ loading: false }); setLoading(false);
console.error(e); console.error(e);
alert("file reading has failed"); alert("file reading has failed");
}; };
@ -124,7 +55,7 @@ class ImportDialog extends React.Component<PropsType> {
const fileText = reader.result as string; const fileText = reader.result as string;
const items = itemsCreator(fileText); const items = itemsCreator(fileText);
const { syncJournal } = this.props; const { syncJournal } = props;
const last = syncJournal.journalEntries.last() as EteSync.Entry; const last = syncJournal.journalEntries.last() as EteSync.Entry;
const lastUid = last ? last.uid : null; const lastUid = last ? last.uid : null;
@ -132,7 +63,7 @@ class ImportDialog extends React.Component<PropsType> {
let prevUid = lastUid; let prevUid = lastUid;
const journalItems = items.map((item) => { const journalItems = items.map((item) => {
const ret = createJournalEntry( const ret = createJournalEntry(
this.props.etesync, this.props.userInfo, syncJournal.journal, props.etesync, props.userInfo, syncJournal.journal,
prevUid, EteSync.SyncEntryAction.Add, item.toIcal()); prevUid, EteSync.SyncEntryAction.Add, item.toIcal());
prevUid = ret.uid; prevUid = ret.uid;
@ -140,22 +71,22 @@ class ImportDialog extends React.Component<PropsType> {
}); });
await store.dispatch<any>( await store.dispatch<any>(
addEntries(this.props.etesync, syncJournal.journal.uid, journalItems, lastUid) addEntries(props.etesync, syncJournal.journal.uid, journalItems, lastUid)
); );
} catch (e) { } catch (e) {
console.error(e); console.error(e);
alert("An error has occurred, please contact developers."); alert("An error has occurred, please contact developers.");
throw e; throw e;
} finally { } finally {
if (this.props.onClose) { if (props.onClose) {
this.setState({ loading: false }); setLoading(false);
this.props.onClose(); props.onClose();
} }
} }
}; };
if (acceptedFiles.length > 0) { if (acceptedFiles.length > 0) {
this.setState({ loading: true }); setLoading(true);
acceptedFiles.forEach((file) => { acceptedFiles.forEach((file) => {
reader.readAsText(file); reader.readAsText(file);
}); });
@ -165,7 +96,7 @@ class ImportDialog extends React.Component<PropsType> {
} }
} }
private onFileDropContact(acceptedFiles: File[], rejectedFiles: File[]) { function onFileDropContact(acceptedFiles: File[], rejectedFiles: File[]) {
const itemsCreator = (fileText: string) => { const itemsCreator = (fileText: string) => {
const mainComp = ICAL.parse(fileText); const mainComp = ICAL.parse(fileText);
return mainComp.map((comp) => { return mainComp.map((comp) => {
@ -177,10 +108,10 @@ class ImportDialog extends React.Component<PropsType> {
}); });
}; };
this.onFileDropCommon(itemsCreator, acceptedFiles, rejectedFiles); onFileDropCommon(itemsCreator, acceptedFiles, rejectedFiles);
} }
private onFileDropEvent(acceptedFiles: File[], rejectedFiles: File[]) { function onFileDropEvent(acceptedFiles: File[], rejectedFiles: File[]) {
const itemsCreator = (fileText: string) => { const itemsCreator = (fileText: string) => {
const calendarComp = new ICAL.Component(ICAL.parse(fileText)); const calendarComp = new ICAL.Component(ICAL.parse(fileText));
return calendarComp.getAllSubcomponents("vevent").map((comp) => { return calendarComp.getAllSubcomponents("vevent").map((comp) => {
@ -192,10 +123,10 @@ class ImportDialog extends React.Component<PropsType> {
}); });
}; };
this.onFileDropCommon(itemsCreator, acceptedFiles, rejectedFiles); onFileDropCommon(itemsCreator, acceptedFiles, rejectedFiles);
} }
private onFileDropTask(acceptedFiles: File[], rejectedFiles: File[]) { function onFileDropTask(acceptedFiles: File[], rejectedFiles: File[]) {
const itemsCreator = (fileText: string) => { const itemsCreator = (fileText: string) => {
const calendarComp = new ICAL.Component(ICAL.parse(fileText)); const calendarComp = new ICAL.Component(ICAL.parse(fileText));
return calendarComp.getAllSubcomponents("vtodo").map((comp) => { return calendarComp.getAllSubcomponents("vtodo").map((comp) => {
@ -207,19 +138,70 @@ class ImportDialog extends React.Component<PropsType> {
}); });
}; };
this.onFileDropCommon(itemsCreator, acceptedFiles, rejectedFiles); onFileDropCommon(itemsCreator, acceptedFiles, rejectedFiles);
} }
private onClose() { function onClose() {
if (this.state.loading) { if (loading) {
return; return;
} }
if (this.props.onClose) { if (props.onClose) {
this.props.onClose(); props.onClose();
} }
} }
}
export default ImportDialog; const { syncJournal } = props;
const collectionInfo = syncJournal.collection;
let acceptTypes;
let dropFunction;
if (collectionInfo.type === "ADDRESS_BOOK") {
acceptTypes = ["text/vcard", "text/directory", "text/x-vcard", ".vcf"];
dropFunction = onFileDropContact;
} else if (collectionInfo.type === "CALENDAR") {
acceptTypes = ["text/calendar", ".ics", ".ical"];
dropFunction = onFileDropEvent;
} else if (collectionInfo.type === "TASKS") {
acceptTypes = ["text/calendar", ".ics", ".ical"];
dropFunction = onFileDropTask;
}
return (
<React.Fragment>
<Dialog
open={props.open}
onClose={onClose}
>
<DialogTitle>Import entries from file?</DialogTitle>
<DialogContent>
{loading ?
<LoadingIndicator style={{ display: "block", margin: "auto" }} />
:
<Dropzone
onDrop={dropFunction}
multiple={false}
accept={acceptTypes}
>
{({ getRootProps, getInputProps }) => (
<section>
<div {...getRootProps()}>
<input {...getInputProps()} />
<DialogContentText id="alert-dialog-description">
To import entries from a file, drag 'n' drop it here, or click to open the file selector.
</DialogContentText>
</div>
</section>
)}
</Dropzone>
}
</DialogContent>
<DialogActions>
<Button disabled={loading} onClick={onClose} color="primary">
Cancel
</Button>
</DialogActions>
</Dialog>
</React.Fragment>
);
}

Loading…
Cancel
Save