Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP]add export Invoices and Contacts to CSV #143

Closed
wants to merge 13 commits into from
13 changes: 13 additions & 0 deletions app/components/settings/General.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import PropTypes from 'prop-types';

// Custom Libs
import _withFadeInAnimation from '../shared/hoc/_withFadeInAnimation';
import Button from '../shared/Button';

// Export and Import PouchDB
import { exportDB, importDB } from '../../helpers/import-export.js';

// Component
class General extends Component {
Expand Down Expand Up @@ -57,6 +61,15 @@ class General extends Component {
</div>
</div>
</div>
<div className="row">
<div className="col-md-6">
<div className="pageItem">
<label className="itemLabel">Export / Import</label>
<Button onClick={exportDB}>Export</Button>
<Button onClick={importDB}>Import</Button>
</div>
</div>
</div>
<div className="row">
<div className="col-md-6">
<div className="pageItem">
Expand Down
133 changes: 133 additions & 0 deletions app/helpers/import-export.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
// Node Libs
const fs = require('fs');
const path = require('path');

// Electron Libs
const { dialog } = require('electron').remote;

const openDialog = require('../renderers/dialog'); // Dialog on errors, warnings, info, etc...
const { pouchDBInvoices, pouchDBContacts } = require('./pouchDB'); // PouchDB helpers
const csvjson = require('csvjson'); // CSV to JSON and JSON to CSV

// Export PouchDB
const exportDB = () => {
// Save PouchDB as CSV
const saveFile = () => {
dialog.showSaveDialog(
{ filters: [{ name: 'CSV', extensions: ['csv'] }] },
savePath => {
if (path) {
// Get Directory from path
const dir = path.parse(savePath).dir;
// Check whether you have write permission for directory
fs.access(dir, fs.constants.W_OK, err => {
if (err) {
openDialog({
type: 'warning',
title: 'No Write Permission',
message: `No write permission to ${dir}, please choose a different directory!`,
});
} else {
writeFile(savePath);
}
});
}
}
);
};

async function writeFile(savePath) {
const file = fs.createWriteStream(savePath);
const data = await getData(); // PouchDB JSON Data
// console.log(data) // TO see how the PouchDB JSON looks like

if (data) {
// csvjson options
const options = {
delimiter: ',',
wrap: false,
headers: 'full',
objectDenote: '.',
arrayDenote: '[]',
};

file.write(csvjson.toCSV(data, options));
file.close(); // Close when done
}
}

// Get PouchDB Invoices
async function getData() {
let Invoices;
let Contacts;

try {
await pouchDBInvoices().then(invoices => (Invoices = invoices));
await pouchDBContacts().then(contacts => (Contacts = contacts));
} catch (err) {
openDialog({
type: 'error',
title: 'PouchDB Error',
message: 'Exporting PouchDB to CSV failed!',
});
}

if ((Invoices, Contacts)) {
return { Invoices, Contacts };
}
}

saveFile();
};

// Import PouchDB
const importDB = () => {
const openFile = () => {
dialog.showOpenDialog(
{
filters: [{ name: 'CSV', extensions: ['csv'] }],
properties: ['openFile'],
},
openPath => {
if (openPath) {
fs.access(openPath[0], fs.constants.R_OK, err => {
if (err) {
openDialog({
type: 'warning',
title: 'No Read Permission',
message: `No read permission on ${
openPath[0]
}, please make sure you have read permission!`,
});
} else {
// DBLoad()
}
});
}
}
);
};

// const DBLoad = () => {
// // Read the CSV file
// const data = fs.readFileSync(path, 'utf8');

// if (data) {
// const options = {
// delimiter: ',',
// quote: '"',
// };

// // TODO: This does not output the correct JSON as of now!
// const j = csvjson.toSchemaObject(data);
// console.log(j);
// }
// }
//
// openFile();
};

module.exports = {
exportDB,
importDB,
};
80 changes: 79 additions & 1 deletion app/helpers/pouchDB.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@ const PouchDB = require('pouchdb-browser');
const contactsDB = new PouchDB('contacts');
const invoicesDB = new PouchDB('invoices');

// Used for Export and Import PouchDB
const MemoryStream = require('memorystream');
const replicationStream = require('pouchdb-replication-stream');

// CSV to JSON and JSON to CSV
const csvjson = require('csvjson');

PouchDB.plugin(replicationStream.plugin);
PouchDB.adapter('writableStream', replicationStream.adapters.writableStream);

// Utility
import { omit } from 'lodash';

Expand Down Expand Up @@ -79,6 +89,67 @@ runMigration(
}
);

// Get PouchDB Invoices (Used for Exporting)
const pouchDBInvoices = () => {
Copy link
Owner

@hql287 hql287 Jan 20, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't we use getAllDocs instead? 🧐

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like you need this to return different kind of doc than getAllDocs?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once again I didn't do enough testing 😞 I tried to use it in the beginning and saw the end result being different, so I just assumed it would be wrong to use. But now that I can compare getAllDocs('invoices') and pouchDBInvoices I see the only difference is that I have to wrap getAllDocs with an array and that it is missing the _revisions object wich is not important.

I will use getAllDocs instead 🙂 And remove the extra pouchDBInvoices and pouchDBContacts helpers which will reduce dependencies!

Thank you!

const invoices = new Promise((resolve, reject) => {
const invoicesStream = new MemoryStream();
let invoicesStreamObject;

invoicesStream.on('data', chunk => {
const json = JSON.parse(chunk.toString());
if (json.docs) {
invoicesStreamObject = json;
}
});

invoicesStream.on('end', () => {
resolve(invoicesStreamObject);
});

// Dump invoices to memoryStream
invoicesDB.dump(invoicesStream).then(res => {
if (res.ok !== true) {
reject(new Error('Exporting PouchDB to CSV failed!'));
}
});
});

return invoices;
};

// Get PouchDB Contacts (Used for Exporting)
const pouchDBContacts = () => {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above, why don't we use getAllDocs instead?

const contacts = new Promise((resolve, reject) => {
const contactsStream = new MemoryStream();
let contactsStreamObject;

contactsStream.on('data', chunk => {
const json = JSON.parse(chunk.toString());
if (json.docs) {
contactsStreamObject = json;
}
});

contactsStream.on('end', () => {
resolve(contactsStreamObject);
});

// Dump contacts to memoryStream
contactsDB.dump(contactsStream).then(res => {
if (res.ok !== true) {
reject(new Error('Importing PouchDB from CSV failed!'));
}
});
});

return contacts;
};

// Import PouchDB from CSV file
const DBLoad = load => {
// TODO: load invoices and contacts to PouchDB
};

// Set DB via dbName
const setDB = dbName =>
new Promise((resolve, reject) => {
Expand Down Expand Up @@ -157,4 +228,11 @@ const updateDoc = (dbName, docId, updatedDoc) =>
.catch(err => reject(err));
});

export { getAllDocs, deleteDoc, saveDoc, updateDoc };
export {
getAllDocs,
deleteDoc,
saveDoc,
updateDoc,
pouchDBInvoices,
pouchDBContacts,
};
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"lint-staged": "lint-staged"
},
"dependencies": {
"csvjson": "^5.0.0",
"date-fns": "^1.28.5",
"dotenv": "^4.0.0",
"electron-is-dev": "^0.3.0",
Expand All @@ -36,8 +37,10 @@
"glob": "^7.1.2",
"is-svg": "^2.1.0",
"jimp": "^0.2.28",
"memorystream": "^0.3.1",
"moment": "^2.20.1",
"pouchdb-browser": "6.2.0",
"pouchdb-replication-stream": "^1.2.9",
"rc-progress": "^2.2.5",
"react": "^16.2.0",
"react-addons-shallow-compare": "^15.6.2",
Expand Down
Loading