mirror of
				https://github.com/crater-invoice/crater.git
				synced 2025-10-31 05:31:10 -04:00 
			
		
		
		
	build version 400
This commit is contained in:
		| @ -1,642 +1,21 @@ | ||||
| <template> | ||||
|   <div id="app" class="main-content dashboard"> | ||||
|     <div class="row"> | ||||
|       <div class="dash-item col-sm-6"> | ||||
|         <router-link slot="item-title" to="/admin/invoices"> | ||||
|           <div class="dashbox"> | ||||
|             <div class="desc"> | ||||
|               <span | ||||
|                 v-if="isLoaded" | ||||
|                 class="amount" | ||||
|               > | ||||
|                 <div v-html="$utils.formatMoney(getTotalDueAmount, defaultCurrency)"/> | ||||
|               </span> | ||||
|               <span class="title"> | ||||
|                 {{ $t('dashboard.cards.due_amount') }} | ||||
|               </span> | ||||
|             </div> | ||||
|             <div class="icon"> | ||||
|               <dollar-icon class="card-icon" /> | ||||
|             </div> | ||||
|           </div> | ||||
|         </router-link> | ||||
|       </div> | ||||
|       <div class="dash-item col-sm-6"> | ||||
|         <router-link slot="item-title" to="/admin/customers"> | ||||
|           <div class="dashbox"> | ||||
|             <div class="desc"> | ||||
|               <span v-if="isLoaded" | ||||
|                     class="amount" > | ||||
|                 {{ getContacts }} | ||||
|               </span> | ||||
|               <span class="title"> | ||||
|                 {{ $t('dashboard.cards.customers') }} | ||||
|               </span> | ||||
|             </div> | ||||
|             <div class="icon"> | ||||
|               <contact-icon class="card-icon" /> | ||||
|             </div> | ||||
|           </div> | ||||
|         </router-link> | ||||
|       </div> | ||||
|       <div class="dash-item col-sm-6"> | ||||
|         <router-link slot="item-title" to="/admin/invoices"> | ||||
|           <div class="dashbox"> | ||||
|             <div class="desc"> | ||||
|               <span v-if="isLoaded" | ||||
|                     class="amount"> | ||||
|                 {{ getInvoices }} | ||||
|               </span> | ||||
|               <span class="title"> | ||||
|                 {{ $t('dashboard.cards.invoices') }} | ||||
|               </span> | ||||
|             </div> | ||||
|             <div class="icon"> | ||||
|               <invoice-icon class="card-icon" /> | ||||
|             </div> | ||||
|           </div> | ||||
|         </router-link> | ||||
|       </div> | ||||
|       <div class="dash-item col-sm-6"> | ||||
|         <router-link slot="item-title" to="/admin/estimates"> | ||||
|           <div class="dashbox"> | ||||
|             <div class="desc"> | ||||
|               <span v-if="isLoaded" | ||||
|                     class="amount"> | ||||
|                 {{ getEstimates }} | ||||
|               </span> | ||||
|               <span class="title"> | ||||
|                 {{ $t('dashboard.cards.estimates') }} | ||||
|               </span> | ||||
|             </div> | ||||
|             <div class="icon"> | ||||
|               <estimate-icon class="card-icon" /> | ||||
|             </div> | ||||
|           </div> | ||||
|         </router-link> | ||||
|       </div> | ||||
|     </div> | ||||
|     <div class="row"> | ||||
|       <div class="col-lg-12 mt-2"> | ||||
|         <div class="card dashboard-card"> | ||||
|           <div class="graph-body"> | ||||
|             <div class="card-body col-md-12 col-lg-12 col-xl-10"> | ||||
|               <div class="card-header"> | ||||
|                 <h6><i class="fa fa-line-chart text-primary"/>{{ $t('dashboard.monthly_chart.title') }} </h6> | ||||
|                 <div class="year-selector"> | ||||
|                   <base-select | ||||
|                     v-model="selectedYear" | ||||
|                     :options="years" | ||||
|                     :allow-empty="false" | ||||
|                     :show-labels="false" | ||||
|                     :placeholder="$t('dashboard.select_year')" | ||||
|                   /> | ||||
|                 </div> | ||||
|               </div> | ||||
|               <line-chart | ||||
|                 v-if="isLoaded" | ||||
|                 :format-money="$utils.formatMoney" | ||||
|                 :format-graph-money="$utils.formatGraphMoney" | ||||
|                 :invoices="getChartInvoices" | ||||
|                 :expenses="getChartExpenses" | ||||
|                 :receipts="getReceiptTotals" | ||||
|                 :income="getNetProfits" | ||||
|                 :labels="getChartMonths" | ||||
|                 class="" | ||||
|               /> | ||||
|             </div> | ||||
|             <div class="chart-desc col-md-12 col-lg-12 col-xl-2"> | ||||
|               <div class="stats"> | ||||
|                 <div class="description"> | ||||
|                   <span class="title"> {{ $t('dashboard.chart_info.total_sales') }} </span> | ||||
|                   <br> | ||||
|                   <span v-if="isLoaded" class="total"> | ||||
|                     <div v-html="$utils.formatMoney(getTotalSales, defaultCurrency)"/> | ||||
|                   </span> | ||||
|                 </div> | ||||
|                 <div class="description"> | ||||
|                   <span class="title"> {{ $t('dashboard.chart_info.total_receipts') }} </span> | ||||
|                   <br> | ||||
|                   <span v-if="isLoaded" class="total" style="color:#00C99C;"> | ||||
|                     <div v-html="$utils.formatMoney(getTotalReceipts, defaultCurrency)"/> | ||||
|                   </span> | ||||
|                 </div> | ||||
|                 <div class="description"> | ||||
|                   <span class="title"> {{ $t('dashboard.chart_info.total_expense') }} </span> | ||||
|                   <br> | ||||
|                   <span v-if="isLoaded" class="total" style="color:#FB7178;"> | ||||
|                     <div v-html="$utils.formatMoney(getTotalExpenses, defaultCurrency)"/> | ||||
|                   </span> | ||||
|                 </div> | ||||
|                 <div class="description"> | ||||
|                   <span class="title"> {{ $t('dashboard.chart_info.net_income') }} </span> | ||||
|                   <br> | ||||
|                   <span class="total" style="color:#5851D8;"> | ||||
|                     <div v-html="$utils.formatMoney(getNetProfit, defaultCurrency)"/> | ||||
|                   </span> | ||||
|                 </div> | ||||
|               </div> | ||||
|             </div> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|     <base-loader v-if="!getLoadedData"/> | ||||
|     <div class="row table-row"> | ||||
|       <div class="col-lg-12 col-xl-6 mt-2"> | ||||
|         <div class="table-header"> | ||||
|           <h6 class="table-title"> | ||||
|             {{ $t('dashboard.recent_invoices_card.title') }} | ||||
|           </h6> | ||||
|           <router-link to="/admin/invoices"> | ||||
|             <base-button | ||||
|               :outline="true" | ||||
|               color="theme" | ||||
|               class="btn-sm" | ||||
|             > | ||||
|               {{ $t('dashboard.recent_invoices_card.view_all') }} | ||||
|             </base-button> | ||||
|           </router-link> | ||||
|         </div> | ||||
|         <div class="dashboard-table"> | ||||
|           <table-component | ||||
|             ref="inv_table" | ||||
|             :data="getDueInvoices" | ||||
|             :show-filter="false" | ||||
|             table-class="table" | ||||
|             class="dashboard" | ||||
|           > | ||||
|             <table-column :label="$t('dashboard.recent_invoices_card.due_on')" show="formattedDueDate" /> | ||||
|             <table-column :label="$t('dashboard.recent_invoices_card.customer')" show="user.name" /> | ||||
|             <table-column | ||||
|               :label="$t('invoices.status')" | ||||
|               sort-as="status" | ||||
|             > | ||||
|               <template slot-scope="row" > | ||||
|                 <span> {{ $t('invoices.status') }}</span> | ||||
|                 <span :class="'inv-status-'+row.status.toLowerCase()">{{ (row.status != 'PARTIALLY_PAID')? row.status : row.status.replace('_', ' ') }}</span> | ||||
|               </template> | ||||
|             </table-column> | ||||
|             <table-column :label="$t('dashboard.recent_invoices_card.amount_due')" show="due_amount" sort-as="due_amount"> | ||||
|               <template slot-scope="row"> | ||||
|                 <span>{{ $t('dashboard.recent_invoices_card.amount_due') }}</span> | ||||
|                 <div v-html="$utils.formatMoney(row.due_amount, row.user.currency)"/> | ||||
|               </template> | ||||
|             </table-column> | ||||
|             <table-column | ||||
|               :sortable="false" | ||||
|               :filterable="false" | ||||
|               cell-class="action-dropdown dashboard-recent-invoice-options no-click" | ||||
|             > | ||||
|               <template slot-scope="row"> | ||||
|                 <v-dropdown> | ||||
|                   <a slot="activator" href="#/"> | ||||
|                     <dot-icon /> | ||||
|                   </a> | ||||
|                   <v-dropdown-item> | ||||
|                     <router-link :to="{path: `invoices/${row.id}/edit`}" class="dropdown-item"> | ||||
|                       <font-awesome-icon :icon="['fas', 'pencil-alt']" class="dropdown-item-icon"/> | ||||
|                       {{ $t('general.edit') }} | ||||
|                     </router-link> | ||||
|                     <router-link :to="{path: `invoices/${row.id}/view`}" class="dropdown-item"> | ||||
|                       <font-awesome-icon icon="eye" class="dropdown-item-icon" /> | ||||
|                       {{ $t('invoices.view') }} | ||||
|                     </router-link> | ||||
|                   </v-dropdown-item> | ||||
|                   <v-dropdown-item v-if="row.status == 'DRAFT'"> | ||||
|                     <a class="dropdown-item" href="#/" @click="sendInvoice(row.id)" > | ||||
|                       <font-awesome-icon icon="envelope" class="dropdown-item-icon" /> | ||||
|                       {{ $t('invoices.send_invoice') }} | ||||
|                     </a> | ||||
|                   </v-dropdown-item> | ||||
|                   <v-dropdown-item v-if="row.status === 'DRAFT'"> | ||||
|                     <a class="dropdown-item" href="#/" @click="sentInvoice(row.id)"> | ||||
|                       <font-awesome-icon icon="check-circle" class="dropdown-item-icon" /> | ||||
|                       {{ $t('invoices.mark_as_sent') }} | ||||
|                     </a> | ||||
|                   </v-dropdown-item> | ||||
|                   <v-dropdown-item> | ||||
|                     <div class="dropdown-item" @click="removeInvoice(row.id)"> | ||||
|                       <font-awesome-icon :icon="['fas', 'trash']" class="dropdown-item-icon" /> | ||||
|                       {{ $t('general.delete') }} | ||||
|                     </div> | ||||
|                   </v-dropdown-item> | ||||
|                 </v-dropdown> | ||||
|               </template> | ||||
|             </table-column> | ||||
|           </table-component> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="col-lg-12 col-xl-6 mt-2 mob-table"> | ||||
|         <div class="table-header"> | ||||
|           <h6 class="table-title"> | ||||
|             {{ $t('dashboard.recent_estimate_card.title') }} | ||||
|           </h6> | ||||
|           <router-link to="/admin/estimates"> | ||||
|             <base-button | ||||
|               :outline="true" | ||||
|               color="theme" | ||||
|               class="btn-sm" | ||||
|             > | ||||
|               {{ $t('dashboard.recent_estimate_card.view_all') }} | ||||
|             </base-button> | ||||
|           </router-link> | ||||
|         </div> | ||||
|         <div class="dashboard-table"> | ||||
|           <table-component | ||||
|             ref="est_table" | ||||
|             :data="getRecentEstimates" | ||||
|             :show-filter="false" | ||||
|             table-class="table" | ||||
|           > | ||||
|             <table-column :label="$t('dashboard.recent_estimate_card.date')" show="formattedExpiryDate" /> | ||||
|             <table-column :label="$t('dashboard.recent_estimate_card.customer')" show="user.name" /> | ||||
|             <table-column | ||||
|               :label="$t('estimates.status')" | ||||
|               show="status" > | ||||
|               <template slot-scope="row" > | ||||
|                 <span> {{ $t('estimates.status') }}</span> | ||||
|                 <span :class="'est-status-'+row.status.toLowerCase()">{{ row.status }}</span> | ||||
|               </template> | ||||
|             </table-column> | ||||
|             <table-column :label="$t('dashboard.recent_estimate_card.amount_due')" show="total" sort-as="total"> | ||||
|               <template slot-scope="row"> | ||||
|                 <span>{{ $t('dashboard.recent_estimate_card.amount_due') }}</span> | ||||
|                 <div v-html="$utils.formatMoney(row.total, row.user.currency)"/> | ||||
|               </template> | ||||
|             </table-column> | ||||
|             <table-column | ||||
|               :sortable="false" | ||||
|               :filterable="false" | ||||
|               cell-class="action-dropdown no-click" | ||||
|             > | ||||
|               <template slot-scope="row"> | ||||
|                 <v-dropdown> | ||||
|                   <a slot="activator" href="#/"> | ||||
|                     <dot-icon /> | ||||
|                   </a> | ||||
|                   <v-dropdown-item> | ||||
|                     <router-link :to="{path: `estimates/${row.id}/edit`}" class="dropdown-item"> | ||||
|                       <font-awesome-icon :icon="['fas', 'pencil-alt']" class="dropdown-item-icon" /> | ||||
|                       {{ $t('general.edit') }} | ||||
|                     </router-link> | ||||
|                   </v-dropdown-item> | ||||
|                   <v-dropdown-item> | ||||
|                     <div class="dropdown-item" @click="removeEstimate(row.id)"> | ||||
|                       <font-awesome-icon :icon="['fas', 'trash']" class="dropdown-item-icon" /> | ||||
|                       {{ $t('general.delete') }} | ||||
|                     </div> | ||||
|                   </v-dropdown-item> | ||||
|                   <v-dropdown-item> | ||||
|                     <router-link :to="{path: `estimates/${row.id}/view`}" class="dropdown-item"> | ||||
|                       <font-awesome-icon icon="eye" class="dropdown-item-icon" /> | ||||
|                       {{ $t('general.view') }} | ||||
|                     </router-link> | ||||
|                   </v-dropdown-item> | ||||
|                   <v-dropdown-item> | ||||
|                     <a class="dropdown-item" href="#/" @click="convertInToinvoice(row.id)"> | ||||
|                       <font-awesome-icon icon="file-alt" class="dropdown-item-icon" /> | ||||
|                       {{ $t('estimates.convert_to_invoice') }} | ||||
|                     </a> | ||||
|                   </v-dropdown-item> | ||||
|                   <v-dropdown-item v-if="row.status === 'DRAFT'"> | ||||
|                     <a class="dropdown-item" href="#/" @click.self="onMarkAsSent(row.id)"> | ||||
|                       <font-awesome-icon icon="check-circle" class="dropdown-item-icon" /> | ||||
|                       {{ $t('estimates.mark_as_sent') }} | ||||
|                     </a> | ||||
|                   </v-dropdown-item> | ||||
|                   <v-dropdown-item v-if="row.status !== 'SENT'"> | ||||
|                     <a class="dropdown-item" href="#/" @click.self="sendEstimate(row.id)"> | ||||
|                       <font-awesome-icon icon="paper-plane" class="dropdown-item-icon" /> | ||||
|                       {{ $t('estimates.send_estimate') }} | ||||
|                     </a> | ||||
|                   </v-dropdown-item> | ||||
|                   <v-dropdown-item v-if="row.status !== 'ACCEPTED'"> | ||||
|                     <a class="dropdown-item" href="#/" @click.self="onMarkAsAccepted(row.id)"> | ||||
|                       <font-awesome-icon icon="check-circle" class="dropdown-item-icon" /> | ||||
|                       {{ $t('estimates.mark_as_accepted') }} | ||||
|                     </a> | ||||
|                   </v-dropdown-item> | ||||
|                   <v-dropdown-item v-if="row.status !== 'REJECTED'"> | ||||
|                     <a class="dropdown-item" href="#/" @click.self="onMarkAsRejected(row.id)"> | ||||
|                       <font-awesome-icon icon="times-circle" class="dropdown-item-icon" /> | ||||
|                       {{ $t('estimates.mark_as_rejected') }} | ||||
|                     </a> | ||||
|                   </v-dropdown-item> | ||||
|                 </v-dropdown> | ||||
|               </template> | ||||
|             </table-column> | ||||
|           </table-component> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|   </div> | ||||
|   <base-page> | ||||
|     <dashboard-stats /> | ||||
|     <dashboard-chart /> | ||||
|     <dashboard-table /> | ||||
|   </base-page> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import { mapGetters, mapActions } from 'vuex' | ||||
| import { SweetModal, SweetModalTab } from 'sweet-modal-vue' | ||||
| import LineChart from '../../components/chartjs/LineChart' | ||||
| import DollarIcon from '../../components/icon/DollarIcon' | ||||
| import ContactIcon from '../../components/icon/ContactIcon' | ||||
| import InvoiceIcon from '../../components/icon/InvoiceIcon' | ||||
| import EstimateIcon from '../../components/icon/EstimateIcon' | ||||
| import DashboardStats from '../dashboard/DashboardStats' | ||||
| import DashboardChart from '../dashboard/DashboardChart' | ||||
| import DashboardTable from '../dashboard/DashboardTable' | ||||
|  | ||||
| export default { | ||||
|   components: { | ||||
|     LineChart, | ||||
|     DollarIcon, | ||||
|     ContactIcon, | ||||
|     InvoiceIcon, | ||||
|     EstimateIcon | ||||
|     DashboardStats, | ||||
|     DashboardChart, | ||||
|     DashboardTable, | ||||
|   }, | ||||
|   data () { | ||||
|     return { | ||||
|       incomeTotal: null, | ||||
|       ...this.$store.state.dashboard, | ||||
|       currency: { precision: 2, thousand_separator: ',', decimal_separator: '.', symbol: '$' }, | ||||
|       isLoaded: false, | ||||
|       fetching: false, | ||||
|       years: ['This year', 'Previous year'], | ||||
|       selectedYear: 'This year' | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapGetters('user', { | ||||
|       'user': 'currentUser' | ||||
|     }), | ||||
|     ...mapGetters('dashboard', [ | ||||
|       'getChartMonths', | ||||
|       'getChartInvoices', | ||||
|       'getChartExpenses', | ||||
|       'getNetProfits', | ||||
|       'getReceiptTotals', | ||||
|       'getContacts', | ||||
|       'getInvoices', | ||||
|       'getEstimates', | ||||
|       'getTotalDueAmount', | ||||
|       'getTotalSales', | ||||
|       'getTotalReceipts', | ||||
|       'getTotalExpenses', | ||||
|       'getNetProfit', | ||||
|       'getLoadedData', | ||||
|       'getDueInvoices', | ||||
|       'getRecentEstimates' | ||||
|     ]), | ||||
|     ...mapGetters('currency', [ | ||||
|       'defaultCurrency' | ||||
|     ]) | ||||
|   }, | ||||
|   watch: { | ||||
|     selectedYear (val) { | ||||
|       if (val === 'Previous year') { | ||||
|         let params = {previous_year: true} | ||||
|         this.loadData(params) | ||||
|       } else { | ||||
|         this.loadData() | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   created () { | ||||
|     this.loadData() | ||||
|   }, | ||||
|   methods: { | ||||
|     ...mapActions('dashboard', [ | ||||
|       'getChart', | ||||
|       'loadData' | ||||
|     ]), | ||||
|     ...mapActions('invoice', [ | ||||
|       'deleteInvoice', | ||||
|       'sendEmail', | ||||
|       'markAsSent' | ||||
|     ]), | ||||
|     ...mapActions('estimate', [ | ||||
|       'deleteEstimate', | ||||
|       'markAsAccepted', | ||||
|       'markAsRejected', | ||||
|       'convertToInvoice' | ||||
|     ]), | ||||
|     ...mapActions('estimate', { | ||||
|       'sendEstimateEmail': 'sendEmail', | ||||
|       'markEstimateAsSent': 'markAsSent' | ||||
|     }), | ||||
|  | ||||
|     async loadData (params) { | ||||
|       await this.$store.dispatch('dashboard/loadData', params) | ||||
|       this.isLoaded = true | ||||
|     }, | ||||
|  | ||||
|     async removeEstimate (id) { | ||||
|       this.id = id | ||||
|       window.swal({ | ||||
|         title: this.$t('general.are_you_sure'), | ||||
|         text: this.$tc('estimates.confirm_delete', 1), | ||||
|         icon: '/assets/icon/trash-solid.svg', | ||||
|         buttons: true, | ||||
|         dangerMode: true | ||||
|       }).then(async (willDelete) => { | ||||
|         if (willDelete) { | ||||
|           let res = await this.deleteEstimate(this.id) | ||||
|           if (res.data.success) { | ||||
|             window.toastr['success'](this.$tc('estimates.deleted_message', 1)) | ||||
|             this.refreshEstTable() | ||||
|           } else if (res.data.error) { | ||||
|             window.toastr['error'](res.data.message) | ||||
|           } | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     refreshInvTable () { | ||||
|       this.$refs.inv_table.refresh() | ||||
|     }, | ||||
|  | ||||
|     refreshEstTable () { | ||||
|       this.$refs.est_table.refresh() | ||||
|     }, | ||||
|  | ||||
|     async convertInToinvoice (id) { | ||||
|       window.swal({ | ||||
|         title: this.$t('general.are_you_sure'), | ||||
|         text: this.$t('estimates.confirm_conversion'), | ||||
|         icon: '/assets/icon/file-alt-solid.svg', | ||||
|         buttons: true, | ||||
|         dangerMode: true | ||||
|       }).then(async (willDelete) => { | ||||
|         if (willDelete) { | ||||
|           let res = await this.convertToInvoice(id) | ||||
|           this.selectAllField = false | ||||
|           if (res.data) { | ||||
|             window.toastr['success'](this.$t('estimates.conversion_message')) | ||||
|             this.$router.push(`invoices/${res.data.invoice.id}/edit`) | ||||
|           } else if (res.data.error) { | ||||
|             window.toastr['error'](res.data.message) | ||||
|           } | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     async onMarkAsSent (id) { | ||||
|       window.swal({ | ||||
|         title: this.$t('general.are_you_sure'), | ||||
|         text: this.$t('estimates.confirm_mark_as_sent'), | ||||
|         icon: '/assets/icon/check-circle-solid.svg', | ||||
|         buttons: true, | ||||
|         dangerMode: true | ||||
|       }).then(async (willMarkAsSent) => { | ||||
|         if (willMarkAsSent) { | ||||
|           const data = { | ||||
|             id: id | ||||
|           } | ||||
|           let response = await this.markEstimateAsSent(data) | ||||
|           this.refreshEstTable() | ||||
|           if (response.data) { | ||||
|             window.toastr['success'](this.$tc('estimates.mark_as_sent_successfully')) | ||||
|           } | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     async removeInvoice (id) { | ||||
|       this.id = id | ||||
|       window.swal({ | ||||
|         title: this.$t('general.are_you_sure'), | ||||
|         text: this.$tc('invoices.confirm_delete'), | ||||
|         icon: '/assets/icon/trash-solid.svg', | ||||
|         buttons: true, | ||||
|         dangerMode: true | ||||
|       }).then(async (willDelete) => { | ||||
|         if (willDelete) { | ||||
|           let res = await this.deleteInvoice(this.id) | ||||
|           if (res.data.success) { | ||||
|             window.toastr['success'](this.$tc('invoices.deleted_message')) | ||||
|             this.refreshInvTable() | ||||
|           } else if (res.data.error) { | ||||
|             window.toastr['error'](res.data.message) | ||||
|           } | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     async sendInvoice (id) { | ||||
|       window.swal({ | ||||
|         title: this.$t('general.are_you_sure'), | ||||
|         text: this.$t('invoices.confirm_send'), | ||||
|         icon: '/assets/icon/paper-plane-solid.svg', | ||||
|         buttons: true, | ||||
|         dangerMode: true | ||||
|       }).then(async (willSendInvoice) => { | ||||
|         if (willSendInvoice) { | ||||
|           const data = { | ||||
|             id: id | ||||
|           } | ||||
|           let response = await this.sendEmail(data) | ||||
|           this.refreshInvTable() | ||||
|           if (response.data.success) { | ||||
|             window.toastr['success'](this.$tc('invoices.send_invoice_successfully')) | ||||
|             return true | ||||
|           } | ||||
|           if (response.data.error === 'user_email_does_not_exist') { | ||||
|             window.toastr['error'](this.$tc('invoices.user_email_does_not_exist')) | ||||
|             return false | ||||
|           } | ||||
|           window.toastr['error'](this.$tc('invoices.something_went_wrong')) | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     async sentInvoice (id) { | ||||
|       window.swal({ | ||||
|         title: this.$t('general.are_you_sure'), | ||||
|         text: this.$t('invoices.invoice_mark_as_sent'), | ||||
|         icon: '/assets/icon/check-circle-solid.svg', | ||||
|         buttons: true, | ||||
|         dangerMode: true | ||||
|       }).then(async (willMarkAsSend) => { | ||||
|         if (willMarkAsSend) { | ||||
|           const data = { | ||||
|             id: id | ||||
|           } | ||||
|           let response = await this.markAsSent(data) | ||||
|           this.refreshInvTable() | ||||
|           if (response.data) { | ||||
|             window.toastr['success'](this.$tc('invoices.mark_as_sent_successfully')) | ||||
|           } | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     async onMarkAsAccepted (id) { | ||||
|       window.swal({ | ||||
|         title: this.$t('general.are_you_sure'), | ||||
|         text: this.$t('estimates.confirm_mark_as_accepted'), | ||||
|         icon: '/assets/icon/check-circle-solid.svg', | ||||
|         buttons: true, | ||||
|         dangerMode: true | ||||
|       }).then(async (markedAsRejected) => { | ||||
|         if (markedAsRejected) { | ||||
|           const data = { | ||||
|             id: id | ||||
|           } | ||||
|           let response = await this.markAsAccepted(data) | ||||
|           this.refreshEstTable() | ||||
|           if (response.data) { | ||||
|             this.refreshEstTable() | ||||
|             window.toastr['success'](this.$tc('estimates.marked_as_accepted_message')) | ||||
|           } | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     async onMarkAsRejected (id) { | ||||
|       window.swal({ | ||||
|         title: this.$t('general.are_you_sure'), | ||||
|         text: this.$t('estimates.confirm_mark_as_rejected'), | ||||
|         icon: '/assets/icon/times-circle-solid.svg', | ||||
|         buttons: true, | ||||
|         dangerMode: true | ||||
|       }).then(async (markedAsRejected) => { | ||||
|         if (markedAsRejected) { | ||||
|           const data = { | ||||
|             id: id | ||||
|           } | ||||
|           let response = await this.markAsRejected(data) | ||||
|           this.refreshEstTable() | ||||
|           if (response.data) { | ||||
|             this.refreshEstTable() | ||||
|             window.toastr['success'](this.$tc('estimates.marked_as_rejected_message')) | ||||
|           } | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     async sendEstimate (id) { | ||||
|       window.swal({ | ||||
|         title: this.$t('general.are_you_sure'), | ||||
|         text: this.$t('estimates.confirm_send_estimate'), | ||||
|         icon: '/assets/icon/paper-plane-solid.svg', | ||||
|         buttons: true, | ||||
|         dangerMode: true | ||||
|       }).then(async (willSendEstimate) => { | ||||
|         if (willSendEstimate) { | ||||
|           const data = { | ||||
|             id: id | ||||
|           } | ||||
|           let response = await this.sendEstimateEmail(data) | ||||
|           this.refreshEstTable() | ||||
|           if (response.data.success) { | ||||
|             window.toastr['success'](this.$tc('estimates.send_estimate_successfully')) | ||||
|             return true | ||||
|           } | ||||
|           if (response.data.error === 'user_email_does_not_exist') { | ||||
|             window.toastr['error'](this.$tc('estimates.user_email_does_not_exist')) | ||||
|             return true | ||||
|           } | ||||
|           window.toastr['error'](this.$tc('estimates.something_went_wrong')) | ||||
|         } | ||||
|       }) | ||||
|     } | ||||
|  | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
							
								
								
									
										152
									
								
								resources/assets/js/views/dashboard/DashboardChart.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								resources/assets/js/views/dashboard/DashboardChart.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,152 @@ | ||||
| <template> | ||||
|   <div class="grid grid-cols-10 mt-8 bg-white rounded shadow"> | ||||
|     <!-- Chart --> | ||||
|     <div | ||||
|       class="grid grid-cols-1 col-span-10 px-4 py-5 lg:col-span-7 xl:col-span-8 sm:p-6" | ||||
|     > | ||||
|       <div class="flex justify-between mt-1 mb-6"> | ||||
|         <h6 class="flex items-center sw-section-title"> | ||||
|           <chart-square-bar-icon class="h-5 text-primary-400" />{{ $t('dashboard.monthly_chart.title') }} | ||||
|         </h6> | ||||
|         <div class="w-40 h-10" style="z-index: 0"> | ||||
|           <sw-select | ||||
|             v-model="selectedYear" | ||||
|             :options="years" | ||||
|             :allow-empty="false" | ||||
|             :show-labels="false" | ||||
|             :placeholder="$t('dashboard.select_year')" | ||||
|           /> | ||||
|         </div> | ||||
|       </div> | ||||
|       <line-chart | ||||
|         v-if="isLoaded" | ||||
|         :format-money="$utils.formatMoney" | ||||
|         :format-graph-money="$utils.formatGraphMoney" | ||||
|         :invoices="getChartInvoices" | ||||
|         :expenses="getChartExpenses" | ||||
|         :receipts="getReceiptTotals" | ||||
|         :income="getNetProfits" | ||||
|         :labels="getChartMonths" | ||||
|         class="sm:w-full" | ||||
|       /> | ||||
|     </div> | ||||
|  | ||||
|     <!-- Chart Labels --> | ||||
|     <div | ||||
|       class="grid grid-cols-1 grid-cols-3 col-span-10 text-center border-t border-l border-gray-200 border-solid lg:border-t-0 lg:text-right lg:col-span-3 xl:col-span-2 lg:grid-cols-1" | ||||
|     > | ||||
|       <div class="p-6"> | ||||
|         <span class="text-xs leading-5 lg:text-sm"> | ||||
|           {{ $t('dashboard.chart_info.total_sales') }} | ||||
|         </span> | ||||
|         <br /> | ||||
|         <span | ||||
|           v-if="isLoaded" | ||||
|           class="block mt-1 text-xl font-semibold leading-8 lg:text-2xl" | ||||
|         > | ||||
|           <div v-html="$utils.formatMoney(getTotalSales, defaultCurrency)" /> | ||||
|         </span> | ||||
|       </div> | ||||
|       <div class="p-6"> | ||||
|         <span class="text-xs leading-5 lg:text-sm"> | ||||
|           {{ $t('dashboard.chart_info.total_receipts') }} | ||||
|         </span> | ||||
|         <br /> | ||||
|         <span | ||||
|           v-if="isLoaded" | ||||
|           class="block mt-1 text-xl font-semibold leading-8 lg:text-2xl" | ||||
|           style="color: #00c99c" | ||||
|         > | ||||
|           <div v-html="$utils.formatMoney(getTotalReceipts, defaultCurrency)" /> | ||||
|         </span> | ||||
|       </div> | ||||
|       <div class="p-6"> | ||||
|         <span class="text-xs leading-5 lg:text-sm"> | ||||
|           {{ $t('dashboard.chart_info.total_expense') }} | ||||
|         </span> | ||||
|         <br /> | ||||
|         <span | ||||
|           v-if="isLoaded" | ||||
|           class="block mt-1 text-xl font-semibold leading-8 lg:text-2xl" | ||||
|           style="color: #fb7178" | ||||
|         > | ||||
|           <div v-html="$utils.formatMoney(getTotalExpenses, defaultCurrency)" /> | ||||
|         </span> | ||||
|       </div> | ||||
|       <div | ||||
|         class="col-span-3 p-6 border-t border-gray-200 border-solid lg:col-span-1" | ||||
|       > | ||||
|         <span class="text-xs leading-5 lg:text-sm"> | ||||
|           {{ $t('dashboard.chart_info.net_income') }} | ||||
|         </span> | ||||
|         <br /> | ||||
|         <span | ||||
|           class="block mt-1 text-xl font-semibold leading-8 lg:text-2xl" | ||||
|           style="color: #5851d8" | ||||
|         > | ||||
|           <div v-html="$utils.formatMoney(getNetProfit, defaultCurrency)" /> | ||||
|         </span> | ||||
|       </div> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import { mapGetters, mapActions } from 'vuex' | ||||
| import { SweetModal, SweetModalTab } from 'sweet-modal-vue' | ||||
| import LineChart from '../../components/chartjs/LineChart' | ||||
| import { ChartSquareBarIcon } from "@vue-hero-icons/outline" | ||||
|  | ||||
| export default { | ||||
|   components: { | ||||
|     LineChart, | ||||
|     ChartSquareBarIcon | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       ...this.$store.state.dashboard, | ||||
|       isLoaded: false, | ||||
|       years: ['This year', 'Previous year'], | ||||
|       selectedYear: 'This year', | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapGetters('user', { | ||||
|       user: 'currentUser', | ||||
|     }), | ||||
|     ...mapGetters('dashboard', [ | ||||
|       'getChartMonths', | ||||
|       'getChartInvoices', | ||||
|       'getChartExpenses', | ||||
|       'getNetProfits', | ||||
|       'getReceiptTotals', | ||||
|       'getTotalSales', | ||||
|       'getTotalReceipts', | ||||
|       'getTotalExpenses', | ||||
|       'getNetProfit', | ||||
|     ]), | ||||
|     ...mapGetters('company', ['defaultCurrency']), | ||||
|   }, | ||||
|   watch: { | ||||
|     selectedYear(val) { | ||||
|       if (val === 'Previous year') { | ||||
|         let params = { previous_year: true } | ||||
|         this.loadData(params) | ||||
|       } else { | ||||
|         this.loadData() | ||||
|       } | ||||
|     }, | ||||
|   }, | ||||
|   created() { | ||||
|     this.loadData() | ||||
|   }, | ||||
|   methods: { | ||||
|     ...mapActions('dashboard', ['loadData']), | ||||
|  | ||||
|     async loadData(params) { | ||||
|       await this.$store.dispatch('dashboard/loadData', params) | ||||
|       this.isLoaded = true | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
							
								
								
									
										128
									
								
								resources/assets/js/views/dashboard/DashboardStats.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								resources/assets/js/views/dashboard/DashboardStats.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,128 @@ | ||||
| <template> | ||||
|   <div class="grid gap-6 sm:grid-cols-2 lg:grid-cols-9 xl:gap-8"> | ||||
|     <!-- Amount Due --> | ||||
|     <router-link | ||||
|       slot="item-title" | ||||
|       class="relative flex justify-between p-3 bg-white rounded shadow hover:bg-gray-100 lg:col-span-3 xl:p-4" | ||||
|       to="/admin/invoices" | ||||
|     > | ||||
|       <div> | ||||
|         <span | ||||
|           v-if="getDashboardDataLoaded" | ||||
|           class="text-xl font-semibold leading-tight text-black xl:text-3xl" | ||||
|         > | ||||
|           <span | ||||
|             v-html="$utils.formatMoney(getTotalDueAmount, defaultCurrency)" | ||||
|           /> | ||||
|         </span> | ||||
|         <span class="block mt-1 text-sm leading-tight text-gray-500 xl:text-lg"> | ||||
|           {{ $t('dashboard.cards.due_amount') }} | ||||
|         </span> | ||||
|       </div> | ||||
|       <div class="flex items-center"> | ||||
|         <dollar-icon class="w-10 h-10 xl:w-12 xl:h-12" /> | ||||
|       </div> | ||||
|     </router-link> | ||||
|  | ||||
|     <!-- Customers --> | ||||
|     <router-link | ||||
|       slot="item-title" | ||||
|       class="relative flex justify-between p-3 bg-white rounded shadow hover:bg-gray-100 lg:col-span-2 xl:p-4" | ||||
|       to="/admin/customers" | ||||
|     > | ||||
|       <div> | ||||
|         <span | ||||
|           v-if="getDashboardDataLoaded" | ||||
|           class="text-xl font-semibold leading-tight text-black xl:text-3xl" | ||||
|         > | ||||
|           {{ getContacts }} | ||||
|         </span> | ||||
|         <span class="block mt-1 text-sm leading-tight text-gray-500 xl:text-lg"> | ||||
|           {{ $t('dashboard.cards.customers') }} | ||||
|         </span> | ||||
|       </div> | ||||
|       <div class="flex items-center"> | ||||
|         <contact-icon class="w-10 h-10 xl:w-12 xl:h-12" /> | ||||
|       </div> | ||||
|     </router-link> | ||||
|  | ||||
|     <!-- Invoices --> | ||||
|     <router-link | ||||
|       slot="item-title" | ||||
|       class="relative flex justify-between p-3 bg-white rounded shadow hover:bg-gray-100 lg:col-span-2 xl:p-4" | ||||
|       to="/admin/invoices" | ||||
|     > | ||||
|       <div> | ||||
|         <span | ||||
|           v-if="getDashboardDataLoaded" | ||||
|           class="text-xl font-semibold leading-tight text-black xl:text-3xl" | ||||
|         > | ||||
|           {{ getInvoices }} | ||||
|         </span> | ||||
|         <span class="block mt-1 text-sm leading-tight text-gray-500 xl:text-lg"> | ||||
|           {{ $t('dashboard.cards.invoices') }} | ||||
|         </span> | ||||
|       </div> | ||||
|       <div class="flex items-center"> | ||||
|         <invoice-icon class="w-10 h-10 xl:w-12 xl:h-12" /> | ||||
|       </div> | ||||
|     </router-link> | ||||
|  | ||||
|     <!-- Estimates --> | ||||
|     <router-link | ||||
|       slot="item-title" | ||||
|       class="relative flex justify-between p-3 bg-white rounded shadow hover:bg-gray-100 lg:col-span-2 xl:p-4" | ||||
|       to="/admin/estimates" | ||||
|     > | ||||
|       <div> | ||||
|         <span | ||||
|           v-if="getDashboardDataLoaded" | ||||
|           class="text-xl font-semibold leading-tight text-black xl:text-3xl" | ||||
|         > | ||||
|           {{ getEstimates }} | ||||
|         </span> | ||||
|         <span class="block mt-1 text-sm leading-tight text-gray-500 xl:text-lg"> | ||||
|           {{ $t('dashboard.cards.estimates') }} | ||||
|         </span> | ||||
|       </div> | ||||
|       <div class="flex items-center"> | ||||
|         <estimate-icon class="w-10 h-10 xl:w-12 xl:h-12" /> | ||||
|       </div> | ||||
|     </router-link> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import { mapGetters } from 'vuex' | ||||
| import DollarIcon from '../../components/icon/DollarIcon' | ||||
| import ContactIcon from '../../components/icon/ContactIcon' | ||||
| import InvoiceIcon from '../../components/icon/InvoiceIcon' | ||||
| import EstimateIcon from '../../components/icon/EstimateIcon' | ||||
|  | ||||
| export default { | ||||
|   components: { | ||||
|     DollarIcon, | ||||
|     ContactIcon, | ||||
|     InvoiceIcon, | ||||
|     EstimateIcon, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       ...this.$store.state.dashboard, | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapGetters('user', { | ||||
|       user: 'currentUser', | ||||
|     }), | ||||
|     ...mapGetters('dashboard', [ | ||||
|       'getContacts', | ||||
|       'getInvoices', | ||||
|       'getEstimates', | ||||
|       'getTotalDueAmount', | ||||
|       'getDashboardDataLoaded', | ||||
|     ]), | ||||
|     ...mapGetters('company', ['defaultCurrency']), | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
							
								
								
									
										619
									
								
								resources/assets/js/views/dashboard/DashboardTable.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										619
									
								
								resources/assets/js/views/dashboard/DashboardTable.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,619 @@ | ||||
| <template> | ||||
|   <div> | ||||
|     <base-loader v-if="!getDashboardDataLoaded" /> | ||||
|  | ||||
|     <div class="grid grid-cols-1 gap-6 mt-10 xl:grid-cols-2"> | ||||
|       <!-- Due Invoices --> | ||||
|       <div class="due-invoices"> | ||||
|         <div class="relative z-10 flex items-center justify-between"> | ||||
|           <h6 class="mb-0 text-xl font-semibold leading-normal"> | ||||
|             {{ $t('dashboard.recent_invoices_card.title') }} | ||||
|           </h6> | ||||
|  | ||||
|           <sw-button | ||||
|             tag-name="router-link" | ||||
|             to="/admin/invoices" | ||||
|             variant="primary-outline" | ||||
|           > | ||||
|             {{ $t('dashboard.recent_invoices_card.view_all') }} | ||||
|           </sw-button> | ||||
|         </div> | ||||
|  | ||||
|         <sw-table-component | ||||
|           ref="inv_table" | ||||
|           :data="getDueInvoices" | ||||
|           :show-filter="false" | ||||
|           table-class="table" | ||||
|         > | ||||
|           <sw-table-column | ||||
|             :sortable="true" | ||||
|             :label="$t('dashboard.recent_invoices_card.due_on')" | ||||
|             show="formattedDueDate" | ||||
|           > | ||||
|             <template slot-scope="row"> | ||||
|               <span>{{ $t('dashboard.recent_invoices_card.due_on') }}</span> | ||||
|               <span class="mt-6">{{ row.formattedDueDate }}</span> | ||||
|             </template> | ||||
|           </sw-table-column> | ||||
|  | ||||
|           <sw-table-column | ||||
|             :sortable="true" | ||||
|             :label="$t('dashboard.recent_invoices_card.customer')" | ||||
|             show="user.name" | ||||
|           > | ||||
|             <template slot-scope="row"> | ||||
|               <span>{{ $t('dashboard.recent_invoices_card.customer') }}</span> | ||||
|               <router-link | ||||
|                 :to="{ path: `invoices/${row.id}/view` }" | ||||
|                 class="font-medium text-primary-500" | ||||
|               > | ||||
|                 {{ row.user.name }} | ||||
|               </router-link> | ||||
|             </template> | ||||
|           </sw-table-column> | ||||
|  | ||||
|           <sw-table-column | ||||
|             :sortable="true" | ||||
|             :label="$t('invoices.status')" | ||||
|             sort-as="status" | ||||
|           > | ||||
|             <template slot-scope="row"> | ||||
|               <span> {{ $t('invoices.status') }}</span> | ||||
|  | ||||
|               <sw-badge | ||||
|                 :bg-color="$utils.getBadgeStatusColor(row.status).bgColor" | ||||
|                 :color="$utils.getBadgeStatusColor(row.status).color" | ||||
|               > | ||||
|                 {{ | ||||
|                   row.status != 'PARTIALLY_PAID' | ||||
|                     ? row.status | ||||
|                     : row.status.replace('_', ' ') | ||||
|                 }} | ||||
|               </sw-badge> | ||||
|             </template> | ||||
|           </sw-table-column> | ||||
|  | ||||
|           <sw-table-column | ||||
|             :sortable="true" | ||||
|             :label="$t('dashboard.recent_invoices_card.amount_due')" | ||||
|             show="due_amount" | ||||
|             sort-as="due_amount" | ||||
|           > | ||||
|             <template slot-scope="row"> | ||||
|               <span>{{ $t('dashboard.recent_invoices_card.amount_due') }}</span> | ||||
|  | ||||
|               <div | ||||
|                 v-html="$utils.formatMoney(row.due_amount, row.user.currency)" | ||||
|               /> | ||||
|             </template> | ||||
|           </sw-table-column> | ||||
|  | ||||
|           <sw-table-column | ||||
|             :sortable="false" | ||||
|             :filterable="false" | ||||
|             cell-class="action-dropdown dashboard-recent-invoice-options no-click" | ||||
|           > | ||||
|             <sw-dropdown slot-scope="row"> | ||||
|               <dot-icon slot="activator" /> | ||||
|               <sw-dropdown-item | ||||
|                 tag-name="router-link" | ||||
|                 :to="`invoices/${row.id}/edit`" | ||||
|               > | ||||
|                 <pencil-icon class="h-5 mr-3 text-gray-600" /> | ||||
|                 {{ $t('general.edit') }} | ||||
|               </sw-dropdown-item> | ||||
|  | ||||
|               <sw-dropdown-item | ||||
|                 tag-name="router-link" | ||||
|                 :to="`invoices/${row.id}/view`" | ||||
|               > | ||||
|                 <eye-icon class="h-5 mr-3 text-gray-600" /> | ||||
|                 {{ $t('invoices.view') }} | ||||
|               </sw-dropdown-item> | ||||
|  | ||||
|               <!-- <sw-dropdown-item | ||||
|                 v-if="row.status == 'DRAFT'" | ||||
|                 @click="sendInvoice(row.id)" | ||||
|               > | ||||
|                 <paper-airplane-icon class="h-5 mr-3 text-gray-600" /> | ||||
|                 {{ $t('invoices.send_invoice') }} | ||||
|               </sw-dropdown-item> --> | ||||
|  | ||||
|               <sw-dropdown-item | ||||
|                 v-if="row.status === 'DRAFT'" | ||||
|                 @click="sentInvoice(row.id)" | ||||
|               > | ||||
|                 <check-circle-icon class="h-5 mr-3 text-gray-600" /> | ||||
|                 {{ $t('invoices.mark_as_sent') }} | ||||
|               </sw-dropdown-item> | ||||
|  | ||||
|               <sw-dropdown-item @click="removeInvoice(row.id)"> | ||||
|                 <trash-icon class="h-5 mr-3 text-gray-600" /> | ||||
|                 {{ $t('general.delete') }} | ||||
|               </sw-dropdown-item> | ||||
|             </sw-dropdown> | ||||
|           </sw-table-column> | ||||
|         </sw-table-component> | ||||
|       </div> | ||||
|  | ||||
|       <!-- Recent Estimates --> | ||||
|       <div class="recent-estimates"> | ||||
|         <div class="relative z-10 flex items-center justify-between"> | ||||
|           <h6 class="mb-0 text-xl font-semibold leading-normal"> | ||||
|             {{ $t('dashboard.recent_estimate_card.title') }} | ||||
|           </h6> | ||||
|  | ||||
|           <sw-button | ||||
|             tag-name="router-link" | ||||
|             to="/admin/estimates" | ||||
|             variant="primary-outline" | ||||
|           > | ||||
|             {{ $t('dashboard.recent_estimate_card.view_all') }} | ||||
|           </sw-button> | ||||
|         </div> | ||||
|  | ||||
|         <sw-table-component | ||||
|           ref="est_table" | ||||
|           :data="getRecentEstimates" | ||||
|           :show-filter="false" | ||||
|           table-class="table" | ||||
|         > | ||||
|           <sw-table-column | ||||
|             :sortable="true" | ||||
|             :label="$t('dashboard.recent_estimate_card.date')" | ||||
|             show="formattedExpiryDate" | ||||
|           > | ||||
|             <template slot-scope="row"> | ||||
|               <span>{{ $t('dashboard.recent_estimate_card.date') }}</span> | ||||
|               <span class="mt-6">{{ row.formattedExpiryDate }}</span> | ||||
|             </template> | ||||
|           </sw-table-column> | ||||
|  | ||||
|           <sw-table-column | ||||
|             :sortable="true" | ||||
|             :label="$t('dashboard.recent_estimate_card.customer')" | ||||
|             show="user.name" | ||||
|           > | ||||
|             <template slot-scope="row"> | ||||
|               <span>{{ $t('dashboard.recent_estimate_card.customer') }}</span> | ||||
|               <router-link | ||||
|                 :to="{ path: `estimates/${row.id}/view` }" | ||||
|                 class="font-medium text-primary-500" | ||||
|               > | ||||
|                 {{ row.user.name }} | ||||
|               </router-link> | ||||
|             </template> | ||||
|           </sw-table-column> | ||||
|  | ||||
|           <sw-table-column | ||||
|             :sortable="true" | ||||
|             :label="$t('estimates.status')" | ||||
|             show="status" | ||||
|           > | ||||
|             <template slot-scope="row"> | ||||
|               <span> {{ $t('estimates.status') }}</span> | ||||
|  | ||||
|               <sw-badge | ||||
|                 :bg-color="$utils.getBadgeStatusColor(row.status).bgColor" | ||||
|                 :color="$utils.getBadgeStatusColor(row.status).color" | ||||
|                 class="px-3 py-1" | ||||
|               > | ||||
|                 {{ row.status }} | ||||
|               </sw-badge> | ||||
|             </template> | ||||
|           </sw-table-column> | ||||
|  | ||||
|           <sw-table-column | ||||
|             :sortable="true" | ||||
|             :label="$t('dashboard.recent_estimate_card.amount_due')" | ||||
|             show="total" | ||||
|             sort-as="total" | ||||
|           > | ||||
|             <template slot-scope="row"> | ||||
|               <span>{{ $t('dashboard.recent_estimate_card.amount_due') }}</span> | ||||
|  | ||||
|               <div v-html="$utils.formatMoney(row.total, row.user.currency)" /> | ||||
|             </template> | ||||
|           </sw-table-column> | ||||
|  | ||||
|           <sw-table-column | ||||
|             :sortable="false" | ||||
|             :filterable="false" | ||||
|             cell-class="action-dropdown no-click" | ||||
|           > | ||||
|             <sw-dropdown slot-scope="row"> | ||||
|               <dot-icon slot="activator" /> | ||||
|  | ||||
|               <sw-dropdown-item | ||||
|                 tag-name="router-link" | ||||
|                 :to="`estimates/${row.id}/edit`" | ||||
|               > | ||||
|                 <pencil-icon class="h-5 mr-3 text-gray-600" /> | ||||
|                 {{ $t('general.edit') }} | ||||
|               </sw-dropdown-item> | ||||
|  | ||||
|               <sw-dropdown-item | ||||
|                 tag-name="router-link" | ||||
|                 :to="`estimates/${row.id}/view`" | ||||
|               > | ||||
|                 <eye-icon class="h-5 mr-3 text-gray-600" /> | ||||
|                 {{ $t('general.view') }} | ||||
|               </sw-dropdown-item> | ||||
|  | ||||
|               <sw-dropdown-item @click="convertInToinvoice(row.id)"> | ||||
|                 <document-text-icon class="h-5 mr-3 text-gray-600" /> | ||||
|                 {{ $t('estimates.convert_to_invoice') }} | ||||
|               </sw-dropdown-item> | ||||
|  | ||||
|               <sw-dropdown-item @click="onMarkAsSent(row.id)"> | ||||
|                 <check-circle-icon class="h-5 mr-3 text-gray-600" /> | ||||
|                 {{ $t('estimates.mark_as_sent') }} | ||||
|               </sw-dropdown-item> | ||||
|               <!-- | ||||
|               <sw-dropdown-item | ||||
|                 v-if="row.status !== 'SENT'" | ||||
|                 @click="sendEstimate(row.id)" | ||||
|               > | ||||
|                 <paper-airplane-icon class="h-5 mr-3 text-gray-600" /> | ||||
|                 {{ $t('estimates.send_estimate') }} | ||||
|               </sw-dropdown-item> --> | ||||
|  | ||||
|               <sw-dropdown-item | ||||
|                 v-if="row.status !== 'ACCEPTED'" | ||||
|                 @click="onMarkAsAccepted(row.id)" | ||||
|               > | ||||
|                 <check-circle-icon class="h-5 mr-3 text-gray-600" /> | ||||
|                 {{ $t('estimates.mark_as_accepted') }} | ||||
|               </sw-dropdown-item> | ||||
|  | ||||
|               <sw-dropdown-item | ||||
|                 v-if="row.status !== 'REJECTED'" | ||||
|                 @click="onMarkAsRejected(row.id)" | ||||
|               > | ||||
|                 <x-circle-icon class="h-5 mr-3 text-gray-600" /> | ||||
|                 {{ $t('estimates.mark_as_rejected') }} | ||||
|               </sw-dropdown-item> | ||||
|  | ||||
|               <sw-dropdown-item @click="removeEstimate(row.id)"> | ||||
|                 <trash-icon class="h-5 mr-3 text-gray-600" /> | ||||
|                 {{ $t('general.delete') }} | ||||
|               </sw-dropdown-item> | ||||
|             </sw-dropdown> | ||||
|           </sw-table-column> | ||||
|         </sw-table-component> | ||||
|       </div> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import { mapGetters, mapActions } from 'vuex' | ||||
| import { SweetModal, SweetModalTab } from 'sweet-modal-vue' | ||||
| import { | ||||
|   PencilIcon, | ||||
|   EyeIcon, | ||||
|   PaperAirplaneIcon, | ||||
|   CheckCircleIcon, | ||||
|   TrashIcon, | ||||
|   DocumentTextIcon, | ||||
|   XCircleIcon, | ||||
| } from '@vue-hero-icons/solid' | ||||
|  | ||||
| export default { | ||||
|   components: { | ||||
|     PencilIcon, | ||||
|     EyeIcon, | ||||
|     PaperAirplaneIcon, | ||||
|     CheckCircleIcon, | ||||
|     TrashIcon, | ||||
|     DocumentTextIcon, | ||||
|     XCircleIcon, | ||||
|   }, | ||||
|  | ||||
|   data() { | ||||
|     return { | ||||
|       ...this.$store.state.dashboard, | ||||
|       currency: { | ||||
|         precision: 2, | ||||
|         thousand_separator: ',', | ||||
|         decimal_separator: '.', | ||||
|         symbol: '$', | ||||
|       }, | ||||
|       isLoaded: false, | ||||
|       fetching: false, | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   computed: { | ||||
|     ...mapGetters('user', { | ||||
|       user: 'currentUser', | ||||
|     }), | ||||
|  | ||||
|     ...mapGetters('dashboard', [ | ||||
|       'getDashboardDataLoaded', | ||||
|       'getDueInvoices', | ||||
|       'getRecentEstimates', | ||||
|     ]), | ||||
|   }, | ||||
|  | ||||
|   methods: { | ||||
|     ...mapActions('dashboard', ['loadData']), | ||||
|  | ||||
|     ...mapActions('invoice', ['deleteInvoice', 'sendEmail', 'markAsSent']), | ||||
|  | ||||
|     ...mapActions('estimate', [ | ||||
|       'deleteEstimate', | ||||
|       'markAsAccepted', | ||||
|       'markAsRejected', | ||||
|       'convertToInvoice', | ||||
|     ]), | ||||
|  | ||||
|     ...mapActions('estimate', { | ||||
|       sendEstimateEmail: 'sendEmail', | ||||
|       markEstimateAsSent: 'markAsSent', | ||||
|     }), | ||||
|  | ||||
|     async loadData(params) { | ||||
|       await this.$store.dispatch('dashboard/loadData', params) | ||||
|       this.isLoaded = true | ||||
|     }, | ||||
|  | ||||
|     async removeEstimate(id) { | ||||
|       this.id = id | ||||
|       window | ||||
|         .swal({ | ||||
|           title: this.$t('general.are_you_sure'), | ||||
|           text: this.$tc('estimates.confirm_delete', 1), | ||||
|           icon: '/assets/icon/trash-solid.svg', | ||||
|           buttons: true, | ||||
|           dangerMode: true, | ||||
|         }) | ||||
|         .then(async (willDelete) => { | ||||
|           if (willDelete) { | ||||
|             let res = await this.deleteEstimate({ ids: [this.id] }) | ||||
|             if (res.data.success) { | ||||
|               window.toastr['success'](this.$tc('estimates.deleted_message', 1)) | ||||
|               this.refreshEstTable() | ||||
|             } else if (res.data.error) { | ||||
|               window.toastr['error'](res.data.message) | ||||
|             } | ||||
|           } | ||||
|         }) | ||||
|     }, | ||||
|  | ||||
|     refreshInvTable() { | ||||
|       this.$refs.inv_table.refresh() | ||||
|     }, | ||||
|  | ||||
|     refreshEstTable() { | ||||
|       this.$refs.est_table.refresh() | ||||
|     }, | ||||
|  | ||||
|     async convertInToinvoice(id) { | ||||
|       window | ||||
|         .swal({ | ||||
|           title: this.$t('general.are_you_sure'), | ||||
|           text: this.$t('estimates.confirm_conversion'), | ||||
|           icon: '/assets/icon/file-alt-solid.svg', | ||||
|           buttons: true, | ||||
|           dangerMode: true, | ||||
|         }) | ||||
|         .then(async (willDelete) => { | ||||
|           if (willDelete) { | ||||
|             let res = await this.convertToInvoice(id) | ||||
|             this.selectAllField = false | ||||
|  | ||||
|             if (res.data) { | ||||
|               window.toastr['success'](this.$t('estimates.conversion_message')) | ||||
|               this.$router.push(`invoices/${res.data.invoice.id}/edit`) | ||||
|             } else if (res.data.error) { | ||||
|               window.toastr['error'](res.data.message) | ||||
|             } | ||||
|           } | ||||
|         }) | ||||
|     }, | ||||
|  | ||||
|     async onMarkAsSent(id) { | ||||
|       window | ||||
|         .swal({ | ||||
|           title: this.$t('general.are_you_sure'), | ||||
|           text: this.$t('estimates.confirm_mark_as_sent'), | ||||
|           icon: '/assets/icon/check-circle-solid.svg', | ||||
|           buttons: true, | ||||
|           dangerMode: true, | ||||
|         }) | ||||
|         .then(async (willMarkAsSent) => { | ||||
|           if (willMarkAsSent) { | ||||
|             const data = { | ||||
|               id: id, | ||||
|               status: 'SENT', | ||||
|             } | ||||
|  | ||||
|             let response = await this.markEstimateAsSent(data) | ||||
|             this.refreshEstTable() | ||||
|  | ||||
|             if (response.data) { | ||||
|               window.toastr['success']( | ||||
|                 this.$tc('estimates.mark_as_sent_successfully') | ||||
|               ) | ||||
|             } | ||||
|           } | ||||
|         }) | ||||
|     }, | ||||
|  | ||||
|     async removeInvoice(id) { | ||||
|       this.id = id | ||||
|       window | ||||
|         .swal({ | ||||
|           title: this.$t('general.are_you_sure'), | ||||
|           text: this.$tc('invoices.confirm_delete'), | ||||
|           icon: '/assets/icon/trash-solid.svg', | ||||
|           buttons: true, | ||||
|           dangerMode: true, | ||||
|         }) | ||||
|         .then(async (willDelete) => { | ||||
|           if (willDelete) { | ||||
|             let res = await this.deleteInvoice({ ids: [this.id] }) | ||||
|             if (res.data.success) { | ||||
|               window.toastr['success'](this.$tc('invoices.deleted_message')) | ||||
|               this.refreshInvTable() | ||||
|             } else if (res.data.error) { | ||||
|               window.toastr['error'](res.data.message) | ||||
|             } | ||||
|           } | ||||
|         }) | ||||
|     }, | ||||
|  | ||||
|     async sendInvoice(id) { | ||||
|       window | ||||
|         .swal({ | ||||
|           title: this.$t('general.are_you_sure'), | ||||
|           text: this.$t('invoices.confirm_send'), | ||||
|           icon: '/assets/icon/paper-plane-solid.svg', | ||||
|           buttons: true, | ||||
|           dangerMode: true, | ||||
|         }) | ||||
|         .then(async (willSendInvoice) => { | ||||
|           if (willSendInvoice) { | ||||
|             const data = { | ||||
|               id: id, | ||||
|             } | ||||
|             let response = await this.sendEmail(data) | ||||
|             this.refreshInvTable() | ||||
|  | ||||
|             if (response.data.success) { | ||||
|               window.toastr['success']( | ||||
|                 this.$tc('invoices.send_invoice_successfully') | ||||
|               ) | ||||
|               return true | ||||
|             } | ||||
|  | ||||
|             if (response.data.error === 'user_email_does_not_exist') { | ||||
|               window.toastr['error']( | ||||
|                 this.$tc('invoices.user_email_does_not_exist') | ||||
|               ) | ||||
|               return false | ||||
|             } | ||||
|             window.toastr['error'](this.$tc('invoices.something_went_wrong')) | ||||
|           } | ||||
|         }) | ||||
|     }, | ||||
|  | ||||
|     async sentInvoice(id) { | ||||
|       window | ||||
|         .swal({ | ||||
|           title: this.$t('general.are_you_sure'), | ||||
|           text: this.$t('invoices.invoice_mark_as_sent'), | ||||
|           icon: '/assets/icon/check-circle-solid.svg', | ||||
|           buttons: true, | ||||
|           dangerMode: true, | ||||
|         }) | ||||
|         .then(async (willMarkAsSend) => { | ||||
|           if (willMarkAsSend) { | ||||
|             const data = { | ||||
|               id: id, | ||||
|               status: 'SENT', | ||||
|             } | ||||
|             let response = await this.markAsSent(data) | ||||
|  | ||||
|             this.refreshInvTable() | ||||
|             if (response.data) { | ||||
|               window.toastr['success']( | ||||
|                 this.$tc('invoices.mark_as_sent_successfully') | ||||
|               ) | ||||
|             } | ||||
|           } | ||||
|         }) | ||||
|     }, | ||||
|  | ||||
|     async onMarkAsAccepted(id) { | ||||
|       window | ||||
|         .swal({ | ||||
|           title: this.$t('general.are_you_sure'), | ||||
|           text: this.$t('estimates.confirm_mark_as_accepted'), | ||||
|           icon: '/assets/icon/check-circle-solid.svg', | ||||
|           buttons: true, | ||||
|           dangerMode: true, | ||||
|         }) | ||||
|         .then(async (markedAsRejected) => { | ||||
|           if (markedAsRejected) { | ||||
|             const data = { | ||||
|               id: id, | ||||
|             } | ||||
|             let response = await this.markAsAccepted(data) | ||||
|             this.refreshEstTable() | ||||
|  | ||||
|             if (response.data) { | ||||
|               this.refreshEstTable() | ||||
|               window.toastr['success']( | ||||
|                 this.$tc('estimates.marked_as_accepted_message') | ||||
|               ) | ||||
|             } | ||||
|           } | ||||
|         }) | ||||
|     }, | ||||
|  | ||||
|     async onMarkAsRejected(id) { | ||||
|       window | ||||
|         .swal({ | ||||
|           title: this.$t('general.are_you_sure'), | ||||
|           text: this.$t('estimates.confirm_mark_as_rejected'), | ||||
|           icon: '/assets/icon/times-circle-solid.svg', | ||||
|           buttons: true, | ||||
|           dangerMode: true, | ||||
|         }) | ||||
|         .then(async (markedAsRejected) => { | ||||
|           if (markedAsRejected) { | ||||
|             const data = { | ||||
|               id: id, | ||||
|             } | ||||
|             let response = await this.markAsRejected(data) | ||||
|             this.refreshEstTable() | ||||
|  | ||||
|             if (response.data) { | ||||
|               this.refreshEstTable() | ||||
|               window.toastr['success']( | ||||
|                 this.$tc('estimates.marked_as_rejected_message') | ||||
|               ) | ||||
|             } | ||||
|           } | ||||
|         }) | ||||
|     }, | ||||
|  | ||||
|     async sendEstimate(id) { | ||||
|       window | ||||
|         .swal({ | ||||
|           title: this.$t('general.are_you_sure'), | ||||
|           text: this.$t('estimates.confirm_send_estimate'), | ||||
|           icon: '/assets/icon/paper-plane-solid.svg', | ||||
|           buttons: true, | ||||
|           dangerMode: true, | ||||
|         }) | ||||
|         .then(async (willSendEstimate) => { | ||||
|           if (willSendEstimate) { | ||||
|             const data = { | ||||
|               id: id, | ||||
|             } | ||||
|             let response = await this.sendEstimateEmail(data) | ||||
|             this.refreshEstTable() | ||||
|  | ||||
|             if (response.data.success) { | ||||
|               window.toastr['success']( | ||||
|                 this.$tc('estimates.send_estimate_successfully') | ||||
|               ) | ||||
|               return true | ||||
|             } | ||||
|  | ||||
|             if (response.data.error === 'user_email_does_not_exist') { | ||||
|               window.toastr['error']( | ||||
|                 this.$tc('estimates.user_email_does_not_exist') | ||||
|               ) | ||||
|               return true | ||||
|             } | ||||
|             window.toastr['error'](this.$tc('estimates.something_went_wrong')) | ||||
|           } | ||||
|         }) | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
		Reference in New Issue
	
	Block a user