Skouter mortgage estimates. Web application with view written in PHP and Vue, but controller and models in Go.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

134 lines
3.3 KiB

  1. <template>
  2. <div v-if="valid">
  3. <section class="form inputs">
  4. <h3>Monthly Payment - ${{format(totalMonthly)}}</h3>
  5. <label>Loan payment: ${{format(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(cashToClose)}}</h3>
  17. <label>Closing costs: ${{format(fees)}}</label>
  18. <label v-if="credits">Credits: ${{credits}}</label>
  19. <label>Down payment: ${{format(downpayment)}}</label>
  20. <label v-if="!loan.mi.monthly">
  21. Mortgage insurance: ${{format(loan.amount*loan.mi.rate/100)}}
  22. </label>
  23. </section>
  24. <section class="form inputs">
  25. <button :disabled="saved" @click="create">Save Estimate</button>
  26. <button>Generate PDF</button>
  27. </section>
  28. </div>
  29. </template>
  30. <script setup>
  31. import { ref, computed, onMounted } from 'vue'
  32. import { format } from '../../helpers.js'
  33. let valid = ref(false)
  34. let saved = ref(false)
  35. const props = defineProps(['downpayment', 'loan', 'token', 'estimate'])
  36. function amortize(principle, rate, periods) {
  37. return principle * rate*(1+rate)**periods / ((1+rate)**periods - 1)
  38. }
  39. const loanPayment = computed(() => {
  40. return amortize(props.loan.amount,
  41. props.loan.interest / 100 / 12,
  42. props.loan.term*12)
  43. })
  44. const totalMonthly = computed (() => {
  45. let total = loanPayment.value +
  46. props.loan.tax +
  47. props.loan.hoi +
  48. props.loan.hazard
  49. if (props.loan.mi.monthly) {
  50. total = total + props.loan.mi.rate/100*(props.loan.amount)
  51. }
  52. return total
  53. })
  54. // Closing costs
  55. const fees = computed(() => {
  56. return props.loan.fees.reduce((total, x) => {
  57. return x.amount > 0 ? total + x.amount : 0
  58. }, 0
  59. )
  60. })
  61. const credits = computed(() => {
  62. return props.loan.fees.reduce((total, x) => {
  63. return x.amount < 0 ? total + x.amount : 0
  64. }, 0
  65. )
  66. })
  67. const cashToClose = computed(() => {
  68. let total = fees.value + credits.value + props.downpayment
  69. if (!props.loan.mi.monthly) {
  70. total = total + props.loan.mi.rate/100*(props.loan.amount)
  71. }
  72. return total
  73. })
  74. function validate() {
  75. fetch(`/api/estimate/validate`,
  76. {method: 'POST',
  77. body: JSON.stringify(props.estimate),
  78. headers: {
  79. "Accept": "application/json",
  80. "Authorization": `Bearer ${props.token}`,
  81. },
  82. }).then(resp => {
  83. if (resp.ok && resp.status == 200) {
  84. valid.value = true
  85. return
  86. } else {
  87. // resp.text().then(t => this.errors = [t])
  88. // window.location.hash = 'new'
  89. }
  90. })
  91. }
  92. function create() {
  93. saved.value = true
  94. fetch(`/api/estimate`,
  95. {method: 'POST',
  96. body: JSON.stringify(props.estimate),
  97. headers: {
  98. "Accept": "application/json",
  99. "Authorization": `Bearer ${props.token}`,
  100. },
  101. }).then(resp => {
  102. if (resp.ok && resp.status == 200) {
  103. saved.value = true
  104. return
  105. } else {
  106. // resp.text().then(t => this.errors = [t])
  107. // window.location.hash = 'new'
  108. resp.text().then(t => console.log(t))
  109. saved.value = false
  110. }
  111. })
  112. }
  113. onMounted(() => {validate()})
  114. </script>