mirror of
https://github.com/mokuappio/serverless-invoices.git
synced 2025-10-27 07:51:08 -04:00
Import data.
This commit is contained in:
63
src/components/ImportModal.vue
Normal file
63
src/components/ImportModal.vue
Normal file
@ -0,0 +1,63 @@
|
||||
<template>
|
||||
<BModal v-model="isOpen"
|
||||
centered
|
||||
hide-footer
|
||||
title="Import data"
|
||||
size="md"
|
||||
content-class="bg-base dp--24 text-center">
|
||||
<p>
|
||||
<AppFileInput @selected="onSelected" button-text="Select import file"/>
|
||||
<AppError :errors="errors" field="file"/>
|
||||
</p>
|
||||
<p>
|
||||
<small>Your current data will be erased and overwritten with the imported data!</small>
|
||||
</p>
|
||||
</BModal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { BModal } from 'bootstrap-vue';
|
||||
import AppFileInput from './form/AppFileInput';
|
||||
import Errors from '../utils/errors';
|
||||
import AppError from './form/AppError';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
AppError,
|
||||
AppFileInput,
|
||||
BModal,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
errors: new Errors(),
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
isOpen: {
|
||||
get() {
|
||||
return this.$store.state.data.isImportModalOpen;
|
||||
},
|
||||
set(val) {
|
||||
this.$store.commit('data/isImportModalOpen', val);
|
||||
},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
close() {
|
||||
this.isOpen = false;
|
||||
},
|
||||
onSelected(content) {
|
||||
try {
|
||||
const data = JSON.parse(content);
|
||||
|
||||
this.$store.dispatch('data/importJson', data);
|
||||
this.close();
|
||||
} catch (e) {
|
||||
return this.errors.set({
|
||||
file: ['Invalid JSON format'],
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
44
src/components/form/AppFileInput.vue
Normal file
44
src/components/form/AppFileInput.vue
Normal file
@ -0,0 +1,44 @@
|
||||
<template>
|
||||
<div>
|
||||
<label :for="inputRef" class="btn btn-sm btn-link pointer mb-0">
|
||||
<i class="material-icons md-18 mr-2 va-tt">cloud_upload</i>{{ buttonText }}
|
||||
</label>
|
||||
<input v-if="ready" class="d-none" type="file" :id="inputRef" :ref="inputRef" @change="handleFileUpload()"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { uuidv4 } from '@/utils/helpers';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
buttonText: {
|
||||
default: 'Select file',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
inputRef: uuidv4(),
|
||||
ready: true,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
handleFileUpload() {
|
||||
const file = this.$refs[this.inputRef].files[0];
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
this.$emit('selected', e.target.result);
|
||||
this.reset();
|
||||
};
|
||||
reader.readAsText(file);
|
||||
},
|
||||
reset() {
|
||||
this.ready = false;
|
||||
this.$nextTick(() => {
|
||||
this.ready = true;
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
41
src/store/data.js
Normal file
41
src/store/data.js
Normal file
@ -0,0 +1,41 @@
|
||||
import localForage from 'localforage';
|
||||
import { download } from '../utils/helpers';
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
state: {
|
||||
isImportModalOpen: false,
|
||||
},
|
||||
mutations: {
|
||||
isImportModalOpen(state, isOpen) {
|
||||
state.isImportModalOpen = isOpen;
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
async exportJson() {
|
||||
let results = [];
|
||||
const keys = await localForage.keys();
|
||||
keys.forEach((key) => {
|
||||
results.push(localForage.getItem(key));
|
||||
});
|
||||
results = await Promise.all(results);
|
||||
|
||||
const data = {};
|
||||
keys.forEach((key, index) => {
|
||||
data[key] = results[index];
|
||||
});
|
||||
|
||||
download(JSON.stringify(data), 'serverless-invoices.json', 'application/json');
|
||||
},
|
||||
async importJson({ dispatch }, data) {
|
||||
const results = [];
|
||||
Object.keys(data).forEach((key) => {
|
||||
results.push(localForage.setItem(key, data[key]));
|
||||
});
|
||||
await Promise.all(results);
|
||||
await dispatch('teams/terminate', null, { root: true });
|
||||
return dispatch('teams/init', null, { root: true });
|
||||
},
|
||||
},
|
||||
getters: {},
|
||||
};
|
||||
@ -12,8 +12,7 @@ import clients from '@/store/clients';
|
||||
import invoices from '@/store/invoices';
|
||||
import teams from '@/store/teams';
|
||||
import themes from '@/store/themes';
|
||||
import localForage from 'localforage';
|
||||
import { download } from '../utils/helpers';
|
||||
import data from '@/store/data';
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
@ -34,27 +33,9 @@ export default new Vuex.Store({
|
||||
invoices,
|
||||
teams,
|
||||
themes,
|
||||
data,
|
||||
},
|
||||
state: {},
|
||||
mutations: {},
|
||||
actions: {
|
||||
async exportJson() {
|
||||
let results = [];
|
||||
const keys = await localForage.keys();
|
||||
keys.forEach((key) => {
|
||||
results.push(localForage.getItem(key));
|
||||
});
|
||||
results = await Promise.all(results);
|
||||
|
||||
const data = {};
|
||||
keys.forEach((key, index) => {
|
||||
data[key] = results[index];
|
||||
});
|
||||
|
||||
download(JSON.stringify(data), 'serverless-invoices.json', 'application/json');
|
||||
},
|
||||
importJson() {
|
||||
|
||||
},
|
||||
},
|
||||
actions: {},
|
||||
});
|
||||
|
||||
@ -7,9 +7,11 @@ export default {
|
||||
mutations: {},
|
||||
actions: {
|
||||
async init({ dispatch }) {
|
||||
dispatch('clients/terminate', null, { root: true });
|
||||
dispatch('bankAccounts/terminate', null, { root: true });
|
||||
dispatch('invoices/terminate', null, { root: true });
|
||||
await Promise.all([
|
||||
dispatch('clients/terminate', null, { root: true }),
|
||||
dispatch('bankAccounts/terminate', null, { root: true }),
|
||||
dispatch('invoices/terminate', null, { root: true }),
|
||||
]);
|
||||
|
||||
await dispatch('getTeam');
|
||||
|
||||
@ -17,6 +19,9 @@ export default {
|
||||
dispatch('bankAccounts/init', null, { root: true });
|
||||
dispatch('invoices/init', null, { root: true });
|
||||
},
|
||||
async terminate() {
|
||||
return Team.deleteAll();
|
||||
},
|
||||
async getTeam() {
|
||||
const team = await TeamService.getTeam();
|
||||
await Team.create({ data: team });
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
<div>
|
||||
<small v-b-tooltip.hover
|
||||
title="All your data is saved in your browser and not on any server.
|
||||
This application is truly serverless and we do not have access to any of your data."
|
||||
This application is truly serverless and only you have access to your data."
|
||||
class="pointer">
|
||||
What about my data?
|
||||
</small>
|
||||
@ -46,6 +46,7 @@
|
||||
</div>
|
||||
<ClientModal v-if="team"/>
|
||||
<BankAccountModal v-if="team"/>
|
||||
<ImportModal/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -54,6 +55,7 @@ import { mapGetters, mapState } from 'vuex';
|
||||
import ClientModal from '@/components/clients/ClientModal';
|
||||
import BankAccountModal from '@/components/bank-accounts/BankAccountModal';
|
||||
import { VBTooltip } from 'bootstrap-vue';
|
||||
import ImportModal from '../../components/ImportModal';
|
||||
|
||||
|
||||
export default {
|
||||
@ -61,6 +63,7 @@ export default {
|
||||
'b-tooltip': VBTooltip,
|
||||
},
|
||||
components: {
|
||||
ImportModal,
|
||||
BankAccountModal,
|
||||
ClientModal,
|
||||
},
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
<i class="material-icons">more_vert</i>
|
||||
</template>
|
||||
<b-dropdown-item @click="exportJson">Export</b-dropdown-item>
|
||||
<b-dropdown-item @click="importJson">Import</b-dropdown-item>
|
||||
<b-dropdown-item @click="openImportModal">Import</b-dropdown-item>
|
||||
</b-dropdown>
|
||||
<button class="btn btn-sm btn-outline-dark" @click="createNewInvoice">New invoice</button>
|
||||
</div>
|
||||
@ -46,10 +46,10 @@ export default {
|
||||
.then(id => this.$router.push({ name: 'invoice', params: { id } }));
|
||||
},
|
||||
exportJson() {
|
||||
this.$store.dispatch('exportJson');
|
||||
this.$store.dispatch('data/exportJson');
|
||||
},
|
||||
importJson() {
|
||||
this.$store.dispatch('importJson');
|
||||
openImportModal() {
|
||||
this.$store.commit('data/isImportModalOpen', true);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user