mirror of
https://github.com/mokuappio/serverless-invoices.git
synced 2025-10-27 16:01:07 -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 invoices from '@/store/invoices';
|
||||||
import teams from '@/store/teams';
|
import teams from '@/store/teams';
|
||||||
import themes from '@/store/themes';
|
import themes from '@/store/themes';
|
||||||
import localForage from 'localforage';
|
import data from '@/store/data';
|
||||||
import { download } from '../utils/helpers';
|
|
||||||
|
|
||||||
Vue.use(Vuex);
|
Vue.use(Vuex);
|
||||||
|
|
||||||
@ -34,27 +33,9 @@ export default new Vuex.Store({
|
|||||||
invoices,
|
invoices,
|
||||||
teams,
|
teams,
|
||||||
themes,
|
themes,
|
||||||
|
data,
|
||||||
},
|
},
|
||||||
state: {},
|
state: {},
|
||||||
mutations: {},
|
mutations: {},
|
||||||
actions: {
|
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() {
|
|
||||||
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|||||||
@ -7,9 +7,11 @@ export default {
|
|||||||
mutations: {},
|
mutations: {},
|
||||||
actions: {
|
actions: {
|
||||||
async init({ dispatch }) {
|
async init({ dispatch }) {
|
||||||
dispatch('clients/terminate', null, { root: true });
|
await Promise.all([
|
||||||
dispatch('bankAccounts/terminate', null, { root: true });
|
dispatch('clients/terminate', null, { root: true }),
|
||||||
dispatch('invoices/terminate', null, { root: true });
|
dispatch('bankAccounts/terminate', null, { root: true }),
|
||||||
|
dispatch('invoices/terminate', null, { root: true }),
|
||||||
|
]);
|
||||||
|
|
||||||
await dispatch('getTeam');
|
await dispatch('getTeam');
|
||||||
|
|
||||||
@ -17,6 +19,9 @@ export default {
|
|||||||
dispatch('bankAccounts/init', null, { root: true });
|
dispatch('bankAccounts/init', null, { root: true });
|
||||||
dispatch('invoices/init', null, { root: true });
|
dispatch('invoices/init', null, { root: true });
|
||||||
},
|
},
|
||||||
|
async terminate() {
|
||||||
|
return Team.deleteAll();
|
||||||
|
},
|
||||||
async getTeam() {
|
async getTeam() {
|
||||||
const team = await TeamService.getTeam();
|
const team = await TeamService.getTeam();
|
||||||
await Team.create({ data: team });
|
await Team.create({ data: team });
|
||||||
|
|||||||
@ -16,7 +16,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<small v-b-tooltip.hover
|
<small v-b-tooltip.hover
|
||||||
title="All your data is saved in your browser and not on any server.
|
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">
|
class="pointer">
|
||||||
What about my data?
|
What about my data?
|
||||||
</small>
|
</small>
|
||||||
@ -46,6 +46,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<ClientModal v-if="team"/>
|
<ClientModal v-if="team"/>
|
||||||
<BankAccountModal v-if="team"/>
|
<BankAccountModal v-if="team"/>
|
||||||
|
<ImportModal/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -54,6 +55,7 @@ import { mapGetters, mapState } from 'vuex';
|
|||||||
import ClientModal from '@/components/clients/ClientModal';
|
import ClientModal from '@/components/clients/ClientModal';
|
||||||
import BankAccountModal from '@/components/bank-accounts/BankAccountModal';
|
import BankAccountModal from '@/components/bank-accounts/BankAccountModal';
|
||||||
import { VBTooltip } from 'bootstrap-vue';
|
import { VBTooltip } from 'bootstrap-vue';
|
||||||
|
import ImportModal from '../../components/ImportModal';
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -61,6 +63,7 @@ export default {
|
|||||||
'b-tooltip': VBTooltip,
|
'b-tooltip': VBTooltip,
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
ImportModal,
|
||||||
BankAccountModal,
|
BankAccountModal,
|
||||||
ClientModal,
|
ClientModal,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
<i class="material-icons">more_vert</i>
|
<i class="material-icons">more_vert</i>
|
||||||
</template>
|
</template>
|
||||||
<b-dropdown-item @click="exportJson">Export</b-dropdown-item>
|
<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>
|
</b-dropdown>
|
||||||
<button class="btn btn-sm btn-outline-dark" @click="createNewInvoice">New invoice</button>
|
<button class="btn btn-sm btn-outline-dark" @click="createNewInvoice">New invoice</button>
|
||||||
</div>
|
</div>
|
||||||
@ -46,10 +46,10 @@ export default {
|
|||||||
.then(id => this.$router.push({ name: 'invoice', params: { id } }));
|
.then(id => this.$router.push({ name: 'invoice', params: { id } }));
|
||||||
},
|
},
|
||||||
exportJson() {
|
exportJson() {
|
||||||
this.$store.dispatch('exportJson');
|
this.$store.dispatch('data/exportJson');
|
||||||
},
|
},
|
||||||
importJson() {
|
openImportModal() {
|
||||||
this.$store.dispatch('importJson');
|
this.$store.commit('data/isImportModalOpen', true);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user