Skouter mortgage estimates. Web application with view written in PHP and Vue, but controller and models in Go.
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

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