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 @@ - + +