From f6b85595df727b4ded71cebeff678ab334059395 Mon Sep 17 00:00:00 2001 From: HenriT Date: Wed, 25 Aug 2021 13:18:55 +0300 Subject: [PATCH] Abstract backend functionality to be able to easily switch out backend implementation. --- src/config/i18n.config.js | 30 +++++----- src/config/storage.config.js | 4 ++ src/services/adapters/http.adapter.js | 9 +++ src/services/adapters/local.adapter.js | 65 ++++++++++++++++++++++ src/services/adapters/wordpress.adapter.js | 4 ++ src/services/bank-account.service.js | 27 ++------- src/services/client.service.js | 33 ++--------- src/services/data.service.js | 40 +++++++++++++ src/services/invoice.service.js | 38 +++---------- src/services/tax.service.js | 44 ++++----------- src/services/team.service.js | 6 +- src/store/language.js | 50 ++++++++--------- 12 files changed, 196 insertions(+), 154 deletions(-) create mode 100644 src/services/adapters/http.adapter.js create mode 100644 src/services/adapters/local.adapter.js create mode 100644 src/services/adapters/wordpress.adapter.js create mode 100644 src/services/data.service.js diff --git a/src/config/i18n.config.js b/src/config/i18n.config.js index aaceac1..f96d914 100644 --- a/src/config/i18n.config.js +++ b/src/config/i18n.config.js @@ -8,28 +8,28 @@ import app from '@/main'; Vue.use(VueI18Next); i18next - .use(LanguageDetector) - .use(Backend); + .use(LanguageDetector) + .use(Backend); const initialized = i18next.init({ - fallbackLng: 'en', - whitelist: ['en', 'fr', 'et', 'fa', 'bn', 'es'], - backend: { - loadPath: `${window.location.origin}/locales/{{lng}}/{{ns}}.json`, - }, - detection: { - order: ['querystring', 'path', 'localStorage', 'navigator'], - lookupQuerystring: 'lang', - caches: ['localStorage'], - checkWhitelist: true, - }, + fallbackLng: 'en', + whitelist: ['en', 'fr', 'et', 'fa', 'bn', 'es'], + backend: { + loadPath: `${window.location.origin}/locales/{{lng}}/{{ns}}.json`, + }, + detection: { + order: ['querystring', 'path', 'localStorage', 'navigator'], + lookupQuerystring: 'lang', + caches: ['localStorage'], + checkWhitelist: true, + }, }); initialized.then(() => app.$store.dispatch('language/initLanguage', i18next.language)); const i18n = new VueI18Next(i18next, { - loadComponentNamespace: true, + loadComponentNamespace: true, }); i18n.initialized = initialized; -export default i18n; \ No newline at end of file +export default i18n; diff --git a/src/config/storage.config.js b/src/config/storage.config.js index e225e7e..dbe4d74 100644 --- a/src/config/storage.config.js +++ b/src/config/storage.config.js @@ -5,3 +5,7 @@ storage.config({ version: 1.0, storeName: 'default', }); + +export default { + type: 'local', +}; diff --git a/src/services/adapters/http.adapter.js b/src/services/adapters/http.adapter.js new file mode 100644 index 0000000..facaec0 --- /dev/null +++ b/src/services/adapters/http.adapter.js @@ -0,0 +1,9 @@ +const axios = null; + +class HttpAdapter { + async get(uri) { + return axios.get(uri); + } +} + +export default new HttpAdapter(); diff --git a/src/services/adapters/local.adapter.js b/src/services/adapters/local.adapter.js new file mode 100644 index 0000000..ccdf6af --- /dev/null +++ b/src/services/adapters/local.adapter.js @@ -0,0 +1,65 @@ +import storage from 'localforage'; +import { removeVuexORMFlags } from '@/utils/helpers'; + +class LocalAdapter { + async get(uri) { + const parts = uri.split('/'); + + if (parts.length === 1) { + return storage.getItem(parts[0]) || []; + } + + if (parts.length === 2) { + return (await storage.getItem(parts[0])) + .find(it => it.id === parts[1]); + } + + return null; + } + + async post(uri, data) { + const items = await this.get(uri); + + removeVuexORMFlags(data); + items.push(data); + + return storage.setItem(uri, items); + } + + async patch(uri, data) { + const parts = uri.split('/'); + + if (parts.length === 2) { + const items = await this.get(parts[0]); + + const index = items.findIndex(it => it.id === parts[1]); + removeVuexORMFlags(data); + items[index] = data; + + return storage.setItem(parts[0], items); + } + + return null; + } + + async put(uri, data) { + return storage.setItem(uri, data); + } + + async delete(uri) { + const parts = uri.split('/'); + + if (parts.length === 2) { + const items = await this.get(parts[0]); + + const index = items.findIndex(it => it.id === parts[1]); + items.splice(index, 1); + + return storage.setItem(parts[0], items); + } + + return null; + } +} + +export default new LocalAdapter(); diff --git a/src/services/adapters/wordpress.adapter.js b/src/services/adapters/wordpress.adapter.js new file mode 100644 index 0000000..9c5f90a --- /dev/null +++ b/src/services/adapters/wordpress.adapter.js @@ -0,0 +1,4 @@ +class WordpressAdapter { +} + +export default new WordpressAdapter(); diff --git a/src/services/bank-account.service.js b/src/services/bank-account.service.js index defa5b8..57dc186 100644 --- a/src/services/bank-account.service.js +++ b/src/services/bank-account.service.js @@ -1,37 +1,20 @@ -import storage from 'localforage'; -import { removeVuexORMFlags } from '@/utils/helpers'; +import data from '@/services/data.service'; class BankAccountService { async getBankAccounts() { - const bankAccounts = await storage.getItem('bank_accounts'); - - return bankAccounts || []; + return data.get('bank_accounts'); } async getBankAccount(bankAccountId) { - const bankAccounts = await this.getBankAccounts(); - return bankAccounts.find(bank_account => bank_account.id === bankAccountId); + return data.get(`bank_accounts/${bankAccountId}`); } async createBankAccount(bankAccount) { - return this.saveBankAccount(bankAccount); + return data.post('bank_accounts', bankAccount); } async updateBankAccount(bankAccount) { - return this.saveBankAccount(bankAccount); - } - - async saveBankAccount(bankAccount) { - const bankAccounts = await this.getBankAccounts(); - const index = bankAccounts.findIndex(item => item.id === bankAccount.id); - removeVuexORMFlags(bankAccount); - if (index === -1) { - bankAccounts.push(bankAccount); - } else { - bankAccounts[index] = bankAccount; - } - await storage.setItem('bank_accounts', bankAccounts); - return bankAccount; + return data.patch(`bank_accounts/${bankAccount.id}`, bankAccount); } } diff --git a/src/services/client.service.js b/src/services/client.service.js index f6bdddc..aeafa28 100644 --- a/src/services/client.service.js +++ b/src/services/client.service.js @@ -1,45 +1,24 @@ -import storage from 'localforage'; -import { removeVuexORMFlags } from '@/utils/helpers'; +import data from '@/services/data.service'; class ClientService { async getClients() { - const clients = await storage.getItem('clients'); - - return clients || []; + return data.get('clients'); } async getClient(clientId) { - const clients = await this.getClients(); - return clients.find(client => client.id === clientId); + return data.get(`clients/${clientId}`); } async createClient(client) { - return this.saveClient(client); + return data.post('clients', client); } async updateClient(client) { - return this.saveClient(client); + return data.patch(`clients/${client.id}`, client); } async deleteClient(clientId) { - const clients = await this.getClients(); - const index = clients.findIndex(item => item.id === clientId); - clients.splice(index, 1); - return storage.setItem('clients', clients); - } - - async saveClient(client) { - const clients = await this.getClients(); - const index = clients.findIndex(item => item.id === client.id); - removeVuexORMFlags(client); - - if (index === -1) { - clients.push(client); - } else { - clients[index] = client; - } - await storage.setItem('clients', clients); - return client; + return data.delete(`clients/${clientId}`); } } diff --git a/src/services/data.service.js b/src/services/data.service.js new file mode 100644 index 0000000..1470ebe --- /dev/null +++ b/src/services/data.service.js @@ -0,0 +1,40 @@ +import storage from '@/config/storage.config'; +import local from '@/services/adapters/local.adapter'; +import http from '@/services/adapters/http.adapter'; +import wordpress from '@/services/adapters/wordpress.adapter'; + +class DataService { + adapter = null; + + constructor() { + if (storage.type === 'local') { + this.adapter = local; + } else if (storage.type === 'http') { + this.adapter = http; + } else if (storage.type === 'wordpress') { + this.adapter = wordpress; + } + } + + get(uri) { + return this.adapter.get(uri); + } + + post(uri, data) { + return this.adapter.post(uri, data); + } + + patch(uri, data) { + return this.adapter.patch(uri, data); + } + + put(uri, data) { + return this.adapter.put(uri, data); + } + + delete(uri) { + return this.adapter.delete(uri); + } +} + +export default new DataService(); diff --git a/src/services/invoice.service.js b/src/services/invoice.service.js index 23816db..7c9ea6d 100644 --- a/src/services/invoice.service.js +++ b/src/services/invoice.service.js @@ -1,22 +1,19 @@ -import storage from 'localforage'; -import { - validate, removeVuexORMFlags, -} from '@/utils/helpers'; +import { validate } from '@/utils/helpers'; +import data from '@/services/data.service'; class InvoiceService { async getInvoices() { - const invoices = await storage.getItem('invoices'); - return invoices || []; + return data.get('invoices'); } async getInvoice(invoiceId) { - const invoices = await this.getInvoices(); - return invoices.find(invoice => invoice.id === invoiceId); + return data.get(`invoices/${invoiceId}`); } async createInvoice(invoice) { delete invoice.client; - return this.saveInvoice(invoice); + + return data.post('invoices', invoice); } async updateInvoice(invoice) { @@ -33,14 +30,11 @@ class InvoiceService { return Promise.reject(res); } - return this.saveInvoice(invoice); + return data.patch(`invoices/${invoice.id}`, invoice); } async deleteInvoice(invoiceId) { - const invoices = await this.getInvoices(); - const index = invoices.findIndex(item => item.id === invoiceId); - invoices.splice(index, 1); - return storage.setItem('invoices', invoices); + return data.delete(`invoices/${invoiceId}`); } async bookInvoice(invoice) { @@ -83,22 +77,6 @@ class InvoiceService { invoice.status = 'booked'; return this.updateInvoice(invoice); } - - async saveInvoice(invoice) { - const invoices = await this.getInvoices(); - const index = invoices.findIndex(item => item.id === invoice.id); - - delete invoice.client; - removeVuexORMFlags(invoice); - - if (index === -1) { - invoices.push(invoice); - } else { - invoices[index] = invoice; - } - await storage.setItem('invoices', invoices); - return invoice; - } } export default new InvoiceService(); diff --git a/src/services/tax.service.js b/src/services/tax.service.js index 3968b5e..ef0a3c2 100644 --- a/src/services/tax.service.js +++ b/src/services/tax.service.js @@ -1,48 +1,28 @@ -import storage from 'localforage'; -import { removeVuexORMFlags } from '@/utils/helpers'; +import data from '@/services/data.service'; class TaxService { - async getTaxes() { - const taxes = await storage.getItem('taxes'); - - return taxes || []; + getTaxes() { + return data.get('taxes'); } - async getTax(taxId) { - const taxes = await this.getTaxes(); - return taxes.find(tax => tax.id === taxId); + getTax(taxId) { + return data.get(`taxes/${taxId}`); } - async createTax(tax) { - return this.saveTax(tax); + createTax(tax) { + return data.post('taxes', tax); } - async updateTax(tax) { - return this.saveTax(tax); + updateTax(tax) { + return data.patch(`taxes/${tax.id}`, tax); } - async deleteTax(taxId) { - const taxes = await this.getTaxes(); - const index = taxes.findIndex(item => item.id === taxId); - taxes.splice(index, 1); - return this.setTaxes(taxes); - } - - async saveTax(tax) { - const taxes = await this.getTaxes(); - const index = taxes.findIndex(item => item.id === tax.id); - removeVuexORMFlags(tax); - if (index === -1) { - taxes.push(tax); - } else { - taxes[index] = tax; - } - await this.setTaxes(taxes); - return tax; + deleteTax(taxId) { + return data.delete(`taxes/${taxId}`); } setTaxes(taxes) { - return storage.setItem('taxes', taxes); + return data.put('taxes', taxes); } } diff --git a/src/services/team.service.js b/src/services/team.service.js index 8445bdc..6629ff3 100644 --- a/src/services/team.service.js +++ b/src/services/team.service.js @@ -1,8 +1,8 @@ -import storage from 'localforage'; +import data from '@/services/data.service'; class TeamService { async getTeam() { - let team = await storage.getItem('team'); + let team = await data.get('team'); if (!team) { team = { company_name: null, @@ -26,7 +26,7 @@ class TeamService { } async updateTeam(team) { - return storage.setItem('team', team); + return data.put('team', team); } } diff --git a/src/store/language.js b/src/store/language.js index c04ac2e..a1c6d68 100644 --- a/src/store/language.js +++ b/src/store/language.js @@ -1,31 +1,31 @@ import app from '../main'; export default { - namespaced: true, - state: { - lang: null, - all: [ - { name: 'English', code: 'en' }, - { name: 'French', code: 'fr' }, - { name: 'Estonian', code: 'et' }, - { name: 'Persian', code: 'fa' }, - { name: 'Spanish', code: 'es' }, - { name: 'Bangla', code: 'bn' }, - ], + namespaced: true, + state: { + lang: null, + all: [ + { name: 'English', code: 'en' }, + { name: 'French', code: 'fr' }, + { name: 'Estonian', code: 'et' }, + { name: 'Persian', code: 'fa' }, + { name: 'Spanish', code: 'es' }, + { name: 'Bangla', code: 'bn' }, + ], + }, + mutations: { + lang(state, lang) { + state.lang = lang; }, - mutations: { - lang(state, lang) { - state.lang = lang; - }, + }, + actions: { + changeLanguage({ commit }, lang) { + app.$i18n.i18next.changeLanguage(lang.code); + app.$router.push({ query: { ...app.$route.query, lang: lang.code } }); + commit('lang', lang); }, - actions: { - changeLanguage({ commit }, lang) { - app.$i18n.i18next.changeLanguage(lang.code); - app.$router.push({ query: {...app.$route.query, lang: lang.code } }); - commit('lang', lang); - }, - initLanguage({ commit, state }, code) { - commit('lang', state.all.find(lang => lang.code === code)); - }, + initLanguage({ commit, state }, code) { + commit('lang', state.all.find(lang => lang.code === code)); }, -}; \ No newline at end of file + }, +};