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.
 
 
 
 
 
 

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