Skouter mortgage estimates. Web application with view written in PHP and Vue, but controller and models in Go.
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  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:price="(p) => estimate.price = p"
  29. @update:property="(p) => estimate.property = p"
  30. @update:loanType="(lt) => loans[sel].type = lt"
  31. @update:term="(lt) => loans[sel].term = lt"
  32. @update:program="(p) => loans[sel].program = p"
  33. @update:ltv="setLtv"
  34. @update:amount="setAmount"
  35. @update:housingDti="setHousingDti"
  36. @update:dti="setDti"
  37. @update:hoa="(hoa) => loans[sel].hoa = hoa"
  38. @update:interest="(i) => loans[sel].interest = i"
  39. @update:interestDays="(d) => loans[sel].interestDays = d"
  40. @update:hazardEscrow="(h) => loans[sel].hazardEscrow = h"
  41. @update:hazard="(h) => loans[sel].hazard = h"
  42. @update:taxEscrow="(t) => loans[sel].taxEscrow = t"
  43. @update:tax="(t) => loans[sel].tax = t"
  44. @continue="generate"
  45. />
  46. <summary v-if="hash == '#new/summary'"/>
  47. </div>
  48. </template>
  49. <script>
  50. import { stripLetters, strip, stripInt, stripPerc } from "../../helpers.js"
  51. import LoanDetails from "./details.vue"
  52. import Summary from "./summary.vue"
  53. // The default values of a new estimate
  54. const example = {
  55. title: "Example",
  56. type: "",
  57. term: 0,
  58. ltv: 0, // Loan to home value ratio
  59. dti: 0,
  60. housingDti: 0,
  61. amount: 0,
  62. interest: 0,
  63. interestDays: 0,
  64. hazard: 0, // Hazard insurance monthly payment
  65. hazardEscrow: 0, // Hazard insurance escrow in months (0 is none)
  66. tax: 0, // Real Estate taxes monthly payment
  67. taxEscrow: 0, // Months to escrow (0 is none)
  68. hoa: 100, // Home owner's association monthly fee
  69. program: "",
  70. pud: true, // Property under development
  71. zip: '',
  72. fees: [],
  73. mi: {}
  74. }
  75. // The default loans on a new estimate
  76. const loans = [
  77. Object.assign({}, example,),
  78. Object.assign(
  79. Object.assign({}, example),
  80. {title: "Another One",}
  81. ),
  82. ]
  83. // Default estimate fields
  84. const estimate = {
  85. property: "",
  86. transaction: 0,
  87. price: 0,
  88. borrowers: 0,
  89. creditScore: 0,
  90. mIncome: 0,
  91. loans: loans,
  92. }
  93. // Clone loan from initial example as a new loan
  94. function create() {
  95. this.estimate.loans.push(
  96. Object.assign({}, example, {fees: this.createFees()})
  97. )
  98. }
  99. function createFees() {
  100. return this.fees.map(f => Object.assign({}, f))
  101. }
  102. function del() {
  103. if (this.loans.length > 1) {
  104. let x = this.sel
  105. this.sel = 0
  106. this.loans.splice(x, 1)
  107. }
  108. }
  109. // Updates the property price for all loans and their fee amounts.
  110. function setPrice(value) {
  111. this.estimate.price = value
  112. this.estimate.loans[this.sel].fees.forEach(fee => {
  113. if (fee.perc) fee.amount = (fee.perc / 100 * value).toFixed(2)
  114. })
  115. }
  116. // Changes loan.ltv's <input> and data() values, then syncs with data.amount
  117. function setLtv(e) {
  118. let ltv = strip(e)
  119. let loan = this.loans[this.sel]
  120. if (!this.estimate.price) return
  121. if (ltv > 100) ltv = 100
  122. if (ltv < 0) ltv = 0
  123. loan.ltv = ltv
  124. loan.amount = (ltv / 100 * this.estimate.price).toFixed(2)
  125. }
  126. // Changes loan.amount\'s <input> and data() values, then syncs with data.ltv
  127. function setAmount(e) {
  128. let amount = strip(e)
  129. let loan = this.loans[this.sel]
  130. if (!this.estimate.price) return
  131. if (amount > loan.price) amount = loan.price
  132. if (amount < 0) amount = 0
  133. loan.amount = amount
  134. loan.ltv = (amount / this.estimate.price * 100).toFixed(2)
  135. }
  136. function setDti(e) {
  137. let dti = strip(e)
  138. let loan = this.loans[this.sel]
  139. if (!loan.price) return
  140. if (dti > 100) dti = 100
  141. if (dti < 0) dti = 0
  142. e.target.value = dti
  143. loan.dti = dti
  144. }
  145. function setHousingDti(e) {
  146. let housingDti = strip(e)
  147. let loan = this.loans[this.sel]
  148. if (!loan.price) return
  149. if (housingDti > 100) housingDti = 100
  150. if (housingDti < 0) housingDti = 0
  151. e.target.value = housingDti
  152. loan.housingDti = housingDti
  153. }
  154. function generate() {
  155. window.location.hash = 'new/summary'
  156. }
  157. // Percentage values of fees always takek precedent over amounts. The conversion
  158. // happens in setPrice()
  159. export default {
  160. components: { Summary, LoanDetails },
  161. methods: {
  162. generate, createFees, del, create, setPrice, setLtv, setAmount,
  163. setDti, setHousingDti
  164. },
  165. props: ['user', 'fees'],
  166. data() {
  167. return {
  168. estimate: estimate,
  169. loans: estimate.loans,
  170. sel: 0,
  171. errors: [],
  172. hash: window.location.hash
  173. }
  174. },
  175. created() {
  176. this.estimate.loans.forEach(l => l.fees = this.createFees())
  177. window.addEventListener("hashchange", () => this.hash = window.location.hash)
  178. }
  179. }
  180. </script>