diff --git a/components/app.vue b/components/app.vue index 24dd9ab..3ab3205 100644 --- a/components/app.vue +++ b/components/app.vue @@ -29,10 +29,10 @@ const user = { status: 1, } -// The default fees of a new loan +// The default fees of a new loan. Percentage values take precedent over amounts const fees = [ - { name: 'Processing fee', type: 'Lender Fees', amount: 500 }, - { name: 'Underwriting fee', type: 'Lender Fees', amount: 500 }, + { name: 'Processing fee', type: 'Lender Fees', amount: 500, perc: 0 }, + { name: 'Underwriting fee', type: 'Lender Fees', amount: 500, perc: 0 }, { name: 'Credit Report', type: 'Services Required by Lender', amount: 52.50 }, { name: 'Appraisal', type: 'Services Required by Lender', amount: 52.50 }, diff --git a/components/estimates.vue b/components/estimates.vue index 201e6d7..f2c931e 100644 --- a/components/estimates.vue +++ b/components/estimates.vue @@ -8,13 +8,13 @@ :key="fee.name + indx" class="fee" > <label @click="() => edit = fee"> - ${{fee.amount ?? fee.perc + "%"}} - {{fee.name}}<br> + ${{fee.amount}}{{fee.perc && ` (${fee.perc}%)`}} - {{fee.name}}<br> {{fee.type}} </label> <img width="21" height="21" src="/assets/image/icon/x-red.svg" @click="() => remove(indx, 1)"> </div> -<button @click="newFee">New Fee</button> +<button @click="() => edit = {}">New Fee</button> </section> <Dialog v-if="edit" @close="() => edit = null"> diff --git a/components/fee-dialog.vue b/components/fee-dialog.vue new file mode 100644 index 0000000..21bb25a --- /dev/null +++ b/components/fee-dialog.vue @@ -0,0 +1,70 @@ +<template> +<Dialog @close="$emit('close')"> + +<h3>{{heading || "New Fee"}}</h3> + +<label>Name</label> +<input type="" +:value="fee.name" +@input="(e) => fee.name = stripLetters(e)"> + +<label>Amount</label> +<input +type="" +:value="fee.amount" +@input="(e) => {fee.perc = 0; fee.amount = strip(e)}"> + +<label>Percentage of price</label> +<input +type="" +:value="fee.perc" +@input="(e) => { fee.perc = stripPerc(e); +fee.amount = stripPerc(e)/100*price }"> + +<select id="" name="" v-model="fee.type"> + <option value="Title Company">Title Company</option> + <option value="Government">Government</option> + <option value="Lender">Lender</option> + <option value="Services Required by Lender">Required by Lender</option> + <option value="Other">Other</option> +</select> + +<button :disabled="!validFee" @click="() => $emit('save', fee, true)"> +Debit +</button> + +<button :disabled="!validFee" @click="() => $emit('save', fee, false)"> +Credit +</button> + +</Dialog> +</template> + +<script> +import Dialog from "./dialog.vue" +import { stripLetters, strip, stripInt, stripPerc } from "../helpers.js" + +function validFee() { + const fee = this.fee + if (!fee.name || !fee.type || !fee.amount) { + return false + } + + return true +} + +export default { + components: { Dialog }, + methods: { + stripLetters, strip, stripInt, stripPerc + }, + computed: { + validFee, + }, + props: ['initial', 'heading', 'price'], + emits: ['close', 'save'], + data() { + return { fee: Object.assign({}, this.initial) } + }, +} +</script> diff --git a/components/new.vue b/components/new.vue index 3e3d018..21e50a3 100644 --- a/components/new.vue +++ b/components/new.vue @@ -139,7 +139,7 @@ v-model="estimate.transaction"> :key="fee.name + indx" class="fee" > <label> - ${{fee.amount}} - {{fee.name}}<br> + ${{fee.amount}}{{fee.perc && ` (${fee.perc}%)`}} - {{fee.name}}<br> {{fee.type}} </label> <img width="21" height="21" src="/assets/image/icon/x-red.svg" @@ -149,31 +149,13 @@ v-model="estimate.transaction"> <button @click="createFee">New</button> </section> -<Dialog v-if="newFee" @close="() => newFee = null"> -<h3>New Fee</h3> - -<label>Name</label> -<input type="" -:value="newFee.name" -@input="(e) => newFee.name = stripLetters(e)"> - -<label>Amount</label> -<input -type="" -:value="newFee.amount" -@input="(e) => newFee.amount = strip(e)"> - -<select id="" name="" v-model="newFee.type"> - <option value="Title Company">Title Company</option> - <option value="Government">Government</option> - <option value="Lender">Lender</option> - <option value="Services Required by Lender">Required by Lender</option> - <option value="Other">Other</option> -</select> - -<button :disabled="!validFee" @click="addFee(true)">Debit</button> -<button :disabled="!validFee" @click="addFee(false)">Credit</button> -</Dialog> +<fee-dialog v-if="newFee" + :heading="'New Fee'" + :initial="{}" + :price="estimate.price" + @close="() => newFee = null" + @save="addFee" +/> <section class="form radios"> <h3>Mortgage Insurance</h3> @@ -202,6 +184,8 @@ selected="estimate.transaction == 1"> <script> import Dialog from "./dialog.vue" +import FeeDialog from "./fee-dialog.vue" +import { stripLetters, strip, stripInt, stripPerc } from "../helpers.js" // The default values of a new estimate const example = { @@ -246,7 +230,7 @@ const estimate = { } const newFee = { - name: '', type: '', amount: 0 + name: '', type: '', amount: 0, perc: 0 } // Clone loan from initial example as a new loan @@ -271,62 +255,13 @@ function resetFees() { // If valid, add the current this.newFee to the array of fees and reset // this.newFee to null -function addFee(isDebit) { - const fee = this.newFee - if (!this.validFee) { - return - } +function addFee(fee, isDebit) { if (!isDebit) fee.amount = fee.amount * -1 this.estimate.loans[this.sel].fees.push(fee) this.newFee = null } -function validFee() { - const fee = this.newFee - if (!fee.name || !fee.type || !fee.amount) { - return false - } - - return true -} - -// Strips non-digits from an input box event and returns it's rounded integer. -// It also preserves current valid entry (.) -function strip(e) { - let valid = e.target.value.match(/\d+\.?\d?\d?/)?.[0] ?? "" - e.target.value = valid - return Number(valid || 0) -} - -function stripInt(e) { - let value = parseInt(e.target.value.replace(/\D/g, '') || 0) - e.target.value = value - return value -} - -function stripPerc(e) { - let num = strip(e) - - if (num > 100) { - num = 100 - e.target.value = num - } - - if (num < 0) { - num = 0 - e.target.value = num - } - - return num -} - -function stripLetters(e) { - let value = (e.target.value.replace(/[^\w\s]/g, '').slice(0, 20) || '') - e.target.value = value - return value -} - function del() { if (this.loans.length > 1) { let x = this.sel @@ -361,10 +296,13 @@ function setAmount(e) { loan.ltv = (amount / this.estimate.price * 100).toFixed(2) } -// Updates the property price for all loans +// Updates the property price for all loans and their fee amounts. function setPrice(e) { let value = strip(e) this.estimate.price = value + this.estimate.loans[this.sel].fees.forEach(fee => { + if (fee.perc) fee.amount = (fee.perc / 100 * value).toFixed(2) + }) } function setDti(e) { @@ -422,16 +360,15 @@ function validate() { return errors } +// Percentage values of fees always takek precedent over amounts. The conversion +// happens in setPrice() export default { - components: { Dialog }, + components: { Dialog, FeeDialog }, methods: { setPrice, setLtv, setAmount, setDti, setHousingDti, strip, stripInt, - stripLetters, stripPerc, del, create, createFees, createFee, resetFees, + stripLetters, del, create, createFees, createFee, resetFees, addFee, generate, validate }, - computed: { - validFee, - }, props: ['user', 'fees'], data() { return { diff --git a/helpers.js b/helpers.js new file mode 100644 index 0000000..1ef7836 --- /dev/null +++ b/helpers.js @@ -0,0 +1,36 @@ +// Strips non-digits from an input box event and returns it's rounded integer. +// It also preserves current valid entry (.) +export function strip(e) { + let valid = e.target.value.match(/\d+\.?\d?\d?/)?.[0] ?? "" + e.target.value = valid + return Number(valid || 0) +} + +export function stripLetters(e) { + let value = (e.target.value.replace(/[^\w\s]/g, '').slice(0, 20) || '') + e.target.value = value + return value +} + +export function stripInt(e) { + let value = parseInt(e.target.value.replace(/\D/g, '') || 0) + e.target.value = value + return value +} + +export function stripPerc(e) { + let num = strip(e) + + if (num > 100) { + num = 100 + e.target.value = num + } + + if (num < 0) { + num = 0 + e.target.value = num + } + + return num +} +