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

160 lines
3.4 KiB

  1. <template>
  2. <div id="new" class="page">
  3. <h2>New Loan</h2>
  4. <section class="loans-list">
  5. <h3 v-for="(l, indx) in loans"
  6. :class="sel == indx ? 'sel' : ''"
  7. @click="() => sel = indx"
  8. >
  9. {{l.title}}
  10. </h3>
  11. <div class="add">
  12. <svg @click="create"
  13. xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"
  14. class="bi bi-plus" viewBox="0 0 16 16"> <path d="M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0
  15. 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z"/> </svg>
  16. </div>
  17. </section>
  18. <loan-details v-if="hash == '#new'"
  19. :estimate="estimate"
  20. :loans="estimate.loans"
  21. :sel="sel"
  22. @update:name="(name) => loans[sel].title = name"
  23. @del="del"
  24. @update:borrowers="(b) => estimate.borrowers = b"
  25. @update:creditScore="(c) => estimate.creditScore = c"
  26. @update:mIncome="(m) => estimate.mIncome = m"
  27. @update:transaction="(t) => estimate.transaction = t"
  28. @update:property="(p) => estimate.property = p"
  29. @update:loanType="(lt) => loans[sel].type = lt"
  30. />
  31. <summary v-if="hash == '#new/summary'"/>
  32. </div>
  33. </template>
  34. <script>
  35. import LoanDetails from "./details.vue"
  36. import Summary from "./summary.vue"
  37. // The default values of a new estimate
  38. const example = {
  39. title: "Example",
  40. type: "",
  41. term: 0,
  42. ltv: 0, // Loan to home value ratio
  43. dti: 0,
  44. housingDti: 0,
  45. amount: 0,
  46. interest: 0,
  47. interestDays: 0,
  48. hazard: 0, // Hazard insurance monthly payment
  49. hazardEscrow: 0, // Hazard insurance escrow in months (0 is none)
  50. tax: 0, // Real Estate taxes monthly payment
  51. taxEscrow: 0, // Months to escrow (0 is none)
  52. hoa: 100, // Home owner's association monthly fee
  53. program: "",
  54. pud: true, // Property under development
  55. zip: '',
  56. fees: [],
  57. mi: {}
  58. }
  59. // The default loans on a new estimate
  60. const loans = [
  61. Object.assign({}, example,),
  62. Object.assign(
  63. Object.assign({}, example),
  64. {title: "Another One",}
  65. ),
  66. ]
  67. // Default estimate fields
  68. const estimate = {
  69. property: "",
  70. transaction: 0,
  71. price: 0,
  72. borrowers: 0,
  73. creditScore: 0,
  74. mIncome: 0,
  75. loans: loans,
  76. }
  77. // Clone loan from initial example as a new loan
  78. function create() {
  79. this.estimate.loans.push(
  80. Object.assign({}, example, {fees: this.createFees()})
  81. )
  82. }
  83. function createFees() {
  84. return this.fees.map(f => Object.assign({}, f))
  85. }
  86. function del() {
  87. if (this.loans.length > 1) {
  88. let x = this.sel
  89. this.sel = 0
  90. this.loans.splice(x, 1)
  91. }
  92. }
  93. // Updates the property price for all loans and their fee amounts.
  94. function setPrice(value) {
  95. this.estimate.price = value
  96. this.estimate.loans[this.sel].fees.forEach(fee => {
  97. if (fee.perc) fee.amount = (fee.perc / 100 * value).toFixed(2)
  98. })
  99. }
  100. function generate() {
  101. this.errors = this.validate()
  102. if (this.errors.length) return
  103. fetch(`/api/estimate`,
  104. {
  105. method: 'POST',
  106. body: JSON.stringify( this.estimate ),
  107. headers: {
  108. "Accept": "application/json",
  109. "Authorization": `Bearer ${token}`,
  110. },
  111. }
  112. )
  113. return errors
  114. }
  115. // Percentage values of fees always takek precedent over amounts. The conversion
  116. // happens in setPrice()
  117. export default {
  118. components: { Summary, LoanDetails },
  119. methods: {
  120. generate, createFees, del, create, setPrice
  121. },
  122. props: ['user', 'fees'],
  123. data() {
  124. return {
  125. estimate: estimate,
  126. loans: estimate.loans,
  127. sel: 0,
  128. errors: [],
  129. hash: window.location.hash
  130. }
  131. },
  132. created() {
  133. this.estimate.loans.forEach(l => l.fees = this.createFees())
  134. window.addEventListener("hashchange", () => this.hash = window.location.hash)
  135. }
  136. }
  137. </script>