Skouter mortgage estimates. Web application with view written in PHP and Vue, but controller and models in Go.
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 
 
 
 
 

153 řádky
3.1 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. />
  25. <summary v-if="hash == '#new/summary'"/>
  26. </div>
  27. </template>
  28. <script>
  29. import LoanDetails from "./details.vue"
  30. import Summary from "./summary.vue"
  31. // The default values of a new estimate
  32. const example = {
  33. title: "Example",
  34. type: "",
  35. term: 0,
  36. ltv: 0, // Loan to home value ratio
  37. dti: 0,
  38. housingDti: 0,
  39. amount: 0,
  40. interest: 0,
  41. interestDays: 0,
  42. hazard: 0, // Hazard insurance monthly payment
  43. hazardEscrow: 0, // Hazard insurance escrow in months (0 is none)
  44. tax: 0, // Real Estate taxes monthly payment
  45. taxEscrow: 0, // Months to escrow (0 is none)
  46. hoa: 100, // Home owner's association monthly fee
  47. program: "",
  48. pud: true, // Property under development
  49. zip: '',
  50. fees: [],
  51. mi: {}
  52. }
  53. // The default loans on a new estimate
  54. const loans = [
  55. Object.assign({}, example,),
  56. Object.assign(
  57. Object.assign({}, example),
  58. {title: "Another One",}
  59. ),
  60. ]
  61. // Default estimate fields
  62. const estimate = {
  63. property: "",
  64. transaction: 0,
  65. price: 0,
  66. borrowers: 0,
  67. creditScore: 0,
  68. mIncome: 0,
  69. loans: loans,
  70. }
  71. // Clone loan from initial example as a new loan
  72. function create() {
  73. this.estimate.loans.push(
  74. Object.assign({}, example, {fees: this.createFees()})
  75. )
  76. }
  77. function createFees() {
  78. return this.fees.map(f => Object.assign({}, f))
  79. }
  80. function del() {
  81. if (this.loans.length > 1) {
  82. let x = this.sel
  83. this.sel = 0
  84. this.loans.splice(x, 1)
  85. }
  86. }
  87. // Updates the property price for all loans and their fee amounts.
  88. function setPrice(value) {
  89. this.estimate.price = value
  90. this.estimate.loans[this.sel].fees.forEach(fee => {
  91. if (fee.perc) fee.amount = (fee.perc / 100 * value).toFixed(2)
  92. })
  93. }
  94. function generate() {
  95. this.errors = this.validate()
  96. if (this.errors.length) return
  97. fetch(`/api/estimate`,
  98. {
  99. method: 'POST',
  100. body: JSON.stringify( this.estimate ),
  101. headers: {
  102. "Accept": "application/json",
  103. "Authorization": `Bearer ${token}`,
  104. },
  105. }
  106. )
  107. return errors
  108. }
  109. // Percentage values of fees always takek precedent over amounts. The conversion
  110. // happens in setPrice()
  111. export default {
  112. components: { Summary, LoanDetails },
  113. methods: {
  114. generate, createFees, del, create, setPrice
  115. },
  116. props: ['user', 'fees'],
  117. data() {
  118. return {
  119. estimate: estimate,
  120. loans: estimate.loans,
  121. sel: 0,
  122. errors: [],
  123. hash: window.location.hash
  124. }
  125. },
  126. created() {
  127. this.estimate.loans.forEach(l => l.fees = this.createFees())
  128. window.addEventListener("hashchange", () => this.hash = window.location.hash)
  129. }
  130. }
  131. </script>