Skouter mortgage estimates. Web application with view written in PHP and Vue, but controller and models in Go.
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

153 lines
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>