From 580fd9aa5a56682674347986f477de078e91fbd8 Mon Sep 17 00:00:00 2001 From: HenriT Date: Tue, 13 Apr 2021 12:07:08 +0300 Subject: [PATCH] Abstract footer to separate component. Abstract logo to separate component. Be able to edit team in modal. Add custom fields to team. Removed vat and reg no from team (replaced by custom fields). Custom fields are also stored on the invoice. When creating invoice add team custom fields to invoice as well. Be able to set default invoice due date, late fee, vat rate and currency. --- src/components/TheFooter.vue | 64 ++++++++++ .../invoices/InvoiceCompanyDetails.vue | 25 ++-- src/components/invoices/InvoiceForm.vue | 49 +------- src/components/invoices/InvoiceTeamFields.vue | 29 +++++ src/components/team/TeamFields.vue | 70 +++++++++++ src/components/team/TeamForm.vue | 111 ++++++++++++++++++ src/components/team/TeamLogo.vue | 71 +++++++++++ src/components/team/TeamModal.vue | 46 ++++++++ src/services/invoice.service.js | 23 ++-- src/services/team.service.js | 2 - src/store/invoice-team-fields.js | 31 +++++ src/store/invoices.js | 4 +- src/store/models/invoice-team-field.js | 16 +++ src/store/models/invoice.js | 4 +- src/store/models/team.js | 3 +- src/store/store.js | 6 + src/store/team-fields.js | 31 +++++ src/store/teams.js | 17 +-- src/views/dashboard/Dashboard.vue | 58 ++------- 19 files changed, 523 insertions(+), 137 deletions(-) create mode 100644 src/components/TheFooter.vue create mode 100644 src/components/invoices/InvoiceTeamFields.vue create mode 100644 src/components/team/TeamFields.vue create mode 100644 src/components/team/TeamForm.vue create mode 100644 src/components/team/TeamLogo.vue create mode 100644 src/components/team/TeamModal.vue create mode 100644 src/store/invoice-team-fields.js create mode 100644 src/store/models/invoice-team-field.js create mode 100644 src/store/team-fields.js diff --git a/src/components/TheFooter.vue b/src/components/TheFooter.vue new file mode 100644 index 0000000..48b2e4e --- /dev/null +++ b/src/components/TheFooter.vue @@ -0,0 +1,64 @@ + + + diff --git a/src/components/invoices/InvoiceCompanyDetails.vue b/src/components/invoices/InvoiceCompanyDetails.vue index 5d4a853..0ca566b 100644 --- a/src/components/invoices/InvoiceCompanyDetails.vue +++ b/src/components/invoices/InvoiceCompanyDetails.vue @@ -1,12 +1,12 @@ diff --git a/src/components/invoices/InvoiceTeamFields.vue b/src/components/invoices/InvoiceTeamFields.vue new file mode 100644 index 0000000..2526099 --- /dev/null +++ b/src/components/invoices/InvoiceTeamFields.vue @@ -0,0 +1,29 @@ + + diff --git a/src/components/team/TeamFields.vue b/src/components/team/TeamFields.vue new file mode 100644 index 0000000..dd837e6 --- /dev/null +++ b/src/components/team/TeamFields.vue @@ -0,0 +1,70 @@ + + diff --git a/src/components/team/TeamForm.vue b/src/components/team/TeamForm.vue new file mode 100644 index 0000000..909436b --- /dev/null +++ b/src/components/team/TeamForm.vue @@ -0,0 +1,111 @@ + + diff --git a/src/components/team/TeamLogo.vue b/src/components/team/TeamLogo.vue new file mode 100644 index 0000000..f35ce4f --- /dev/null +++ b/src/components/team/TeamLogo.vue @@ -0,0 +1,71 @@ + + diff --git a/src/components/team/TeamModal.vue b/src/components/team/TeamModal.vue new file mode 100644 index 0000000..4e7edfc --- /dev/null +++ b/src/components/team/TeamModal.vue @@ -0,0 +1,46 @@ + + + diff --git a/src/services/invoice.service.js b/src/services/invoice.service.js index 430bdfb..717b002 100644 --- a/src/services/invoice.service.js +++ b/src/services/invoice.service.js @@ -1,6 +1,8 @@ import storage from 'localforage'; import TeamService from '@/services/team.service'; -import { validate, generateInvoiceNumber, removeVuexORMFlags } from '@/utils/helpers'; +import { + validate, generateInvoiceNumber, removeVuexORMFlags, uuidv4, +} from '@/utils/helpers'; import dayjs from 'dayjs'; class InvoiceService { @@ -22,26 +24,33 @@ class InvoiceService { invoice.issued_at = dayjs() .format('YYYY-MM-DD'); invoice.due_at = dayjs() - .add(14, 'days') + .add(team.invoice_due_days || 14, 'days') .format('YYYY-MM-DD'); invoice.number = generateInvoiceNumber(invoices); - invoice.late_fee = 0.5; + invoice.late_fee = team.invoice_late_fee || 0.5; invoice.from_name = team.company_name; invoice.from_address = team.company_address; invoice.from_postal_code = team.company_postal_code; invoice.from_city = team.company_city; invoice.from_country = team.company_country; invoice.from_county = team.company_county; - invoice.from_reg_no = team.company_reg_no; - invoice.from_vat_no = team.company_vat_no; invoice.from_website = team.website; invoice.from_email = team.contact_email; invoice.from_phone = team.contact_phone; - invoice.vat_rate = 0; - invoice.currency = 'USD'; + invoice.vat_rate = team.vat_rate || 0; + invoice.currency = team.currency || 'USD'; + + // Add custom fields + invoice.team_fields = team.fields.map(field => ({ + id: uuidv4(), + label: field.label, + value: field.value, + invoice_id: invoice.id, + })); delete invoice.client; + return this.saveInvoice(invoice); } diff --git a/src/services/team.service.js b/src/services/team.service.js index 7abb20d..061292d 100644 --- a/src/services/team.service.js +++ b/src/services/team.service.js @@ -11,8 +11,6 @@ class TeamService { company_country: null, company_county: null, company_city: null, - company_reg_no: null, - company_vat_no: null, website: null, contact_email: null, contact_phone: null, diff --git a/src/store/invoice-team-fields.js b/src/store/invoice-team-fields.js new file mode 100644 index 0000000..88ad7ff --- /dev/null +++ b/src/store/invoice-team-fields.js @@ -0,0 +1,31 @@ +import InvoiceTeamField from '@/store/models/invoice-team-field'; + +export default { + namespaced: true, + state: {}, + mutations: {}, + actions: { + init() {}, + terminate() {}, + invoiceTeamFieldProps(store, payload) { + return InvoiceTeamField.update({ + where: payload.fieldId, + data: payload.props, + }); + }, + async updateInvoiceTeamField({ dispatch }, payload) { + await dispatch('invoiceTeamFieldProps', payload); + return dispatch('invoices/updateInvoice', null, { root: true }); + }, + async addInvoiceTeamField(store, payload) { + const field = await InvoiceTeamField.createNew(); + await field.$update({ + ...payload.props, + invoice_id: payload.invoiceId, + }); + }, + async removeInvoiceTeamField(store, fieldId) { + await InvoiceTeamField.delete(fieldId); + }, + }, +}; diff --git a/src/store/invoices.js b/src/store/invoices.js index c69b6be..796a38b 100644 --- a/src/store/invoices.js +++ b/src/store/invoices.js @@ -86,8 +86,6 @@ export default { from_city: 'company_city', from_country: 'company_country', from_county: 'company_county', - from_reg_no: 'company_reg_no', - from_vat_no: 'company_vat_no', from_website: 'website', from_email: 'contact_email', from_phone: 'contact_phone', @@ -139,7 +137,7 @@ export default { getters: { invoice(state) { return Invoice.query() - .with(['client', 'client_fields']) + .with(['client', 'client_fields', 'team_fields']) .with('rows', query => query.orderBy('order', 'asc')) .find(state.invoiceId); }, diff --git a/src/store/models/invoice-team-field.js b/src/store/models/invoice-team-field.js new file mode 100644 index 0000000..410f204 --- /dev/null +++ b/src/store/models/invoice-team-field.js @@ -0,0 +1,16 @@ +import { Model } from '@vuex-orm/core'; +import { uuidv4 } from '@/utils/helpers'; + +export default class InvoiceTeamField extends Model { + // This is the name used as module name of the Vuex Store. + static entity = 'invoice_team_fields'; + + static fields() { + return { + id: this.attr(() => uuidv4()), + invoice_id: this.attr(null), + label: this.attr(''), + value: this.attr(''), + }; + } +} diff --git a/src/store/models/invoice.js b/src/store/models/invoice.js index 14bb2f2..77110aa 100644 --- a/src/store/models/invoice.js +++ b/src/store/models/invoice.js @@ -3,6 +3,7 @@ import { uuidv4 } from '@/utils/helpers'; import Client from '@/store/models/client'; import InvoiceRow from '@/store/models/invoice-row'; import InvoiceClientField from '@/store/models/invoice-client-field'; +import InvoiceTeamField from '@/store/models/invoice-team-field'; export default class Invoice extends Model { // This is the name used as module name of the Vuex Store. @@ -24,8 +25,6 @@ export default class Invoice extends Model { from_city: this.attr(''), from_country: this.attr(''), from_county: this.attr(''), - from_reg_no: this.attr(''), - from_vat_no: this.attr(''), from_website: this.attr(''), from_email: this.attr(''), from_phone: this.attr(''), @@ -46,6 +45,7 @@ export default class Invoice extends Model { created_at: this.attr(''), total: this.attr(null), // Only used in lists. client_fields: this.hasMany(InvoiceClientField, 'invoice_id'), + team_fields: this.hasMany(InvoiceTeamField, 'invoice_id'), }; } diff --git a/src/store/models/team.js b/src/store/models/team.js index 6d60f44..c10f8ed 100644 --- a/src/store/models/team.js +++ b/src/store/models/team.js @@ -15,12 +15,11 @@ export default class Team extends Model { company_country: this.attr(''), company_county: this.attr(''), company_city: this.attr(''), - company_reg_no: this.attr(''), - company_vat_no: this.attr(''), website: this.attr(''), contact_email: this.attr(''), contact_phone: this.attr(''), vat_rate: this.attr(null), + currency: this.attr(null), invoice_late_fee: this.attr(null), invoice_due_days: this.attr(null), fields: this.hasMany(TeamField, 'team_id'), diff --git a/src/store/store.js b/src/store/store.js index 6fff037..caceaca 100644 --- a/src/store/store.js +++ b/src/store/store.js @@ -13,12 +13,15 @@ import clientFields from '@/store/client-fields'; import invoices from '@/store/invoices'; import invoiceRows from '@/store/invoice-rows'; import invoiceClientFields from '@/store/invoice-client-fields'; +import invoiceTeamFields from '@/store/invoice-team-fields'; import teams from '@/store/teams'; +import teamFields from '@/store/team-fields'; import themes from '@/store/themes'; import data from '@/store/data'; import ClientField from '@/store/models/client-field'; import TeamField from '@/store/models/team-field'; import InvoiceClientField from '@/store/models/invoice-client-field'; +import InvoiceTeamField from '@/store/models/invoice-team-field'; Vue.use(Vuex); @@ -31,6 +34,7 @@ database.register(Client); database.register(ClientField); database.register(Invoice); database.register(InvoiceClientField); +database.register(InvoiceTeamField); database.register(InvoiceRow); database.register(BankAccount); @@ -43,7 +47,9 @@ export default new Vuex.Store({ invoices, invoiceRows, invoiceClientFields, + invoiceTeamFields, teams, + teamFields, themes, data, }, diff --git a/src/store/team-fields.js b/src/store/team-fields.js new file mode 100644 index 0000000..f06ea77 --- /dev/null +++ b/src/store/team-fields.js @@ -0,0 +1,31 @@ +import TeamField from '@/store/models/team-field'; + +export default { + namespaced: true, + state: {}, + mutations: {}, + actions: { + init() {}, + terminate() {}, + async teamFieldProps(store, payload) { + return TeamField.update({ + where: payload.fieldId, + data: payload.props, + }); + }, + async updateTeamField({ dispatch }, payload) { + await dispatch('teamFieldProps', payload); + return dispatch('teams/updateTeam', null, { root: true }); + }, + async addNewField(store, teamId) { + const field = await TeamField.createNew(); + field.$update({ + team_id: teamId, + }); + }, + async deleteTeamField({ dispatch }, fieldId) { + await TeamField.delete(fieldId); + return dispatch('teams/updateTeam', null, { root: true }); + }, + }, +}; diff --git a/src/store/teams.js b/src/store/teams.js index c3c035d..df1114f 100644 --- a/src/store/teams.js +++ b/src/store/teams.js @@ -3,8 +3,14 @@ import Team from '@/store/models/team'; export default { namespaced: true, - state: {}, - mutations: {}, + state: { + isModalOpen: false, + }, + mutations: { + isModalOpen(state, isOpen) { + state.isModalOpen = isOpen; + }, + }, actions: { async init({ dispatch }) { await Promise.all([ @@ -39,12 +45,7 @@ export default { }, getters: { team() { - return Team.query().first(); - }, - all() { - return Team.query() - .where('$isNew', false) - .get(); + return Team.query().with(['fields']).first(); }, }, }; diff --git a/src/views/dashboard/Dashboard.vue b/src/views/dashboard/Dashboard.vue index c667b8c..0a365be 100644 --- a/src/views/dashboard/Dashboard.vue +++ b/src/views/dashboard/Dashboard.vue @@ -6,63 +6,33 @@ - + +