Skouter mortgage estimates. Web application with view written in PHP and Vue, but controller and models in Go.
 
 
 
 
 
 

131 lines
3.4 KiB

  1. <template>
  2. <div v-if="valid && props.loan.result">
  3. <section class="form inputs">
  4. <h3>Monthly Payment - ${{format(loan.result.totalMonthly)}}</h3>
  5. <label>Loan payment: ${{format(loan.result.loanPayment)}}</label>
  6. <label v-if="loan.mi.monthly">
  7. Mortgage insurance: ${{format(loan.amount*loan.mi.rate/100/12)}}
  8. </label>
  9. <label>Property taxes: ${{format(loan.tax)}}</label>
  10. <label>Homeowner's Insurance: ${{format(loan.hoi)}}</label>
  11. <label v-if="loan.hazard">
  12. Hazard insurance: ${{format(loan.hazard)}}
  13. </label>
  14. </section>
  15. <section class="form inputs">
  16. <h3>Cash to Close - ${{format(loan.result.cashToClose)}}</h3>
  17. <label>Closing costs: ${{format(loan.result.totalFees)}}</label>
  18. <label v-if="loan.result.totalCredits">
  19. Credits: ${{format(loan.result.totalCredits)}}
  20. </label>
  21. <label>Down payment: ${{format(downpayment)}}</label>
  22. <label v-if="!loan.mi.monthly">
  23. Mortgage insurance: ${{format(loan.amount*loan.mi.rate/100)}}
  24. </label>
  25. </section>
  26. <section class="form inputs">
  27. <button :disabled="saved" @click="create">Save Estimate</button>
  28. <button @click="() => download(props.estimate)">Generate PDF</button>
  29. </section>
  30. <DDialog v-if="dlink" @close="() => dlink = ''"
  31. :fileName="`estimate-${props.estimate.id}.pdf`" :url="dlink">
  32. </DDialog>
  33. </div>
  34. </template>
  35. <script setup>
  36. import { ref, computed, onMounted } from 'vue'
  37. import { format } from '../../helpers.js'
  38. import DDialog from "../download-dialog.vue"
  39. const props = defineProps(['downpayment', 'loan', 'token', 'estimate'])
  40. const emit = defineEmits(['update'])
  41. let valid = ref(false)
  42. let saved = ref(false)
  43. let dlink = ref('')
  44. function amortize(principle, rate, periods) {
  45. return principle * rate*(1+rate)**periods / ((1+rate)**periods - 1)
  46. }
  47. function validate() {
  48. fetch(`/api/estimate/validate`,
  49. {method: 'POST',
  50. body: JSON.stringify(props.estimate),
  51. headers: {
  52. "Accept": "application/json",
  53. "Authorization": `Bearer ${props.token}`,
  54. },
  55. }).then(resp => {
  56. if (resp.ok && resp.status == 200) {
  57. valid.value = true
  58. summarize()
  59. }
  60. })
  61. }
  62. function summarize() {
  63. fetch(`/api/estimate/summarize`,
  64. {method: 'POST',
  65. body: JSON.stringify(props.estimate),
  66. headers: {
  67. "Accept": "application/json",
  68. "Authorization": `Bearer ${props.token}`,
  69. },
  70. }).then(resp => {
  71. if (resp.ok && resp.status == 200) return resp.json()
  72. }).then(e => {
  73. console.log(e)
  74. emit('update', e)
  75. })
  76. }
  77. function create() {
  78. saved.value = true
  79. fetch(`/api/estimate`,
  80. {method: 'POST',
  81. body: JSON.stringify(props.estimate),
  82. headers: {
  83. "Accept": "application/json",
  84. "Authorization": `Bearer ${props.token}`,
  85. },
  86. }).then(resp => {
  87. if (resp.ok && resp.status == 200) {
  88. saved.value = true
  89. return
  90. } else {
  91. // resp.text().then(t => this.errors = [t])
  92. // window.location.hash = 'new'
  93. resp.text().then(t => console.log(t))
  94. saved.value = false
  95. }
  96. })
  97. }
  98. function download(estimate) {
  99. fetch(`/api/pdf`,
  100. {method: 'POST',
  101. body: JSON.stringify(estimate),
  102. headers: {
  103. "Accept": "application/json",
  104. "Authorization": `Bearer ${props.token}`,
  105. },
  106. }).then(response => {
  107. if (response.ok) { return response.blob() }
  108. }).then (result => {
  109. if (!result) return // Exit if token is invalid or blank file returned
  110. dlink.value = URL.createObjectURL(result)
  111. })
  112. }
  113. onMounted(() => {validate()})
  114. </script>