Import data.

This commit is contained in:
HenriT
2021-02-16 18:34:04 +02:00
parent 6cadfed54c
commit 26ccd9365e
7 changed files with 167 additions and 30 deletions

View 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>

View 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
View 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: {},
};

View File

@ -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: {},
});

View File

@ -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 });

View File

@ -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,
},

View File

@ -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);
},
},
};