<template> <div class="page"> <h2>Estimates</h2> <section class="form inputs"> <h3>Default Fees</h3> <div v-for="(fee, indx) in fees" :key="fee.name + indx" class="fee" > <label @click="() => edit = fee"> ${{fee.amount/100}}{{ fee.perc ? ` ${fee.perc}%` : ''}} - {{fee.name}}<br> {{fee.type}} </label> <img width="21" height="21" src="/assets/image/icon/x-red.svg" @click="() => remove(fee)"> </div> <button @click="() => edit = {}">New Fee</button> </section> <fee-dialog v-if="edit" :heading="'Fee'" :initial="edit" :price="0" @close="() => edit = null" @save="newFee" /> <section class="inputs estimates"> <h3>Templates</h3> <div class="entry" v-for="t in templates" v-if="!template" @click="() => template = t" key="t.id"> <span> {{t.estimate.id}} - {{t.estimate.property}} - ${{(t.estimate.price/100).toLocaleString()}} </span> </div> <div class="details" v-if="template"> <label> #{{template.estimate.id}} - {{template.estimate.transaction}} - {{template.estimate.property}} - ${{(template.estimate.price / 100).toLocaleString()}} </label> <label>Borrowers: {{template.estimate.borrower.num}}</label> <label>Credit: {{template.estimate.borrower.credit}}</label> <label>Income: {{(template.estimate.borrower.income/100).toLocaleString()}}</label> <div v-for="l in template.estimate.loans" class="details"> <h4>{{l.title}}</h4> <label>{{l.type.name}}</label> <label>Total monthly: ${{format(l.result.totalMonthly)}}</label> <label>Cash to close: ${{format(l.result.cashToClose)}}</label> </div> <button @click="() => download(template.estimate)">Generate PDF</button> <button @click="() => deleting = true">Remove</button> <button @click="() => template = null">Cancel</button> </div> </section> <section class="inputs estimates"> <h3>Saved Estimates</h3> <div class="entry" v-for="e in estimates" v-if="!estimate" @click="() => estimate = e" key="e.id"> <span> {{e.id}} - {{e.property}} - ${{(e.price/100).toLocaleString()}} </span> </div> <div class="details" v-if="estimate"> <label> #{{estimate.id}} - {{estimate.transaction}} - {{estimate.property}} - ${{(estimate.price / 100).toLocaleString()}} </label> <label>Borrowers: {{estimate.borrower.num}}</label> <label>Credit: {{estimate.borrower.credit}}</label> <label>Income: {{(estimate.borrower.income/100).toLocaleString()}}</label> <div v-for="l in estimate.loans" class="details"> <h4>{{l.title}}</h4> <label>{{l.type.name}}</label> <label>Total monthly: ${{format(l.result.totalMonthly)}}</label> <label>Cash to close: ${{format(l.result.cashToClose)}}</label> </div> <button @click="() => download(estimate)">Generate PDF</button> <button @click="() => saveTemplate(estimate)">Save As Template</button> <button @click="() => deleting = true" :disabled="isTemplate()">Delete</button> <button @click="() => estimate = null">Cancel</button> </div> </section> <DDialog v-if="dlink" @close="() => dlink = ''" :fileName="`estimate-${estimate.id}.pdf`" :url="dlink"> </DDialog> <Dialog v-if="deleting" @close="() => deleting = false"> <h3>Are you sure you want to delete this estimate?</h3> <button @click="() => del(estimate ?? template.estimate)">Confirm</button> </Dialog> </div> </template> <script setup> import { ref, computed, onMounted } from 'vue' import FeeDialog from "./fee-dialog.vue" import DDialog from "./download-dialog.vue" import Dialog from "./dialog.vue" import { format } from "../helpers.js" const props = defineProps(['user', 'fees', 'token']) const emit = defineEmits(['addFeeTemp', 'removeFeeTemp', 'preview']) let edit = ref(null) let estimates = ref([]) let templates = ref([]) let estimate = ref() let template = ref() let dlink = ref("") let deleting = ref() function newFee(fee, isDebit) { if (!isDebit) { fee.amount = -1 * fee.amount || 0 fee.perc = -1 * fee.perc || 0 } fetch(`/api/fee`, {method: 'POST', body: JSON.stringify(fee), headers: { "Accept": "application/json", "Authorization": `Bearer ${props.token}`, }, }).then(resp => { if (resp.ok && resp.status == 200) { resp.json().then(r => emit('addFeeTemp', r)) } else { // resp.text().then(t => this.errors = [t]) // window.location.hash = 'new' resp.text().then(t => console.log(t)) } }) edit.value = null } function newType() { } function remove(fee) { fetch(`/api/fee`, {method: 'DELETE', headers: { "Accept": "application/json", "Authorization": `Bearer ${props.token}`, }, body: JSON.stringify(fee) }).then(response => { if (response.ok) { emit('removeFeeTemp', fee) } else { response.text().then(t => console.log(t)) } }) } function getEstimates() { fetch(`/api/estimates`, {method: 'GET', headers: { "Accept": "application/json", "Authorization": `Bearer ${props.token}`, }, }).then(response => { if (response.ok) { return response.json() } else { response.text().then(t => console.log(t)) } }).then (result => { if (!result || !result.length) return // Exit if token is invalid or no fees are saved estimates.value = result }) } function getTemplates() { fetch(`/api/estimate/templates`, {method: 'GET', headers: { "Accept": "application/json", "Authorization": `Bearer ${props.token}`, }, }).then(response => { if (response.ok) { return response.json() } else { response.text().then(t => console.log(t)) } }).then (result => { if (!result || !result.length) return // Exit if token is invalid or no fees are saved templates.value = result console.log(result) }) } function saveTemplate(e) { fetch(`/api/estimate/templates`, {method: 'POST', body: JSON.stringify(e), headers: { "Accept": "application/json", "Authorization": `Bearer ${props.token}`, }, }).then(response => { if (response.ok) { getTemplates() } }) } function del(e) { fetch(`/api/estimate`, {method: 'DELETE', body: JSON.stringify(e), headers: { "Accept": "application/json", "Authorization": `Bearer ${props.token}`, }, }).then(response => { if (response.ok) { estimates.value = estimates.value.filter(e => e.id != estimate.value.id) estimate.value = null deleting.value = false } }) } function remove(t) { fetch(`/api/estimate/template/remove`, {method: 'DELETE', body: JSON.stringify(t), headers: { "Accept": "application/json", "Authorization": `Bearer ${props.token}`, }, }).then(response => { if (response.ok) { estimates.value = estimates.value.filter(e => e.id != estimate.value.id) estimate.value = null deleting.value = false } }) } function download(estimate) { fetch(`/api/pdf`, {method: 'POST', body: JSON.stringify(estimate), headers: { "Accept": "application/json", "Authorization": `Bearer ${props.token}`, }, }).then(response => { if (response.ok) { return response.blob() } }).then (result => { if (!result) return // Exit if token is invalid or blank file returned dlink.value = URL.createObjectURL(result) }) } function isTemplate() { return templates.value.some( t => t.estimate.id == estimate.value.id ) } onMounted(() => { getEstimates() getTemplates() }) </script> <style scoped> .modal a.button { margin: auto; margin-top: 30px; } </style>