瀏覽代碼

List and display template details in view

master
Immanuel Onyeka 1 年之前
父節點
當前提交
94390b1aa3
共有 4 個文件被更改,包括 152 次插入5 次删除
  1. +2
    -0
      components/app.vue
  2. +93
    -3
      components/estimates.vue
  3. +56
    -2
      skouter.go
  4. +1
    -0
      views/report/header.tpl

+ 2
- 0
components/app.vue 查看文件

@@ -110,6 +110,7 @@ function getUser() {
return getAvatar(token)
}).then(b => {
if (!b) return // Exit if token is invalid
const validTypes = ['image/jpeg', 'image/png']
if (!b || !validTypes.includes(b.type) || b.size <= 1) {
@@ -120,6 +121,7 @@ function getUser() {
this.user.avatar = b
return getLetterhead(token)
}).then(b => {
if (!b) return // Exit if token is invalid
const validTypes = ['image/jpeg', 'image/png']
this.user.letterhead = b
})


+ 93
- 3
components/estimates.vue 查看文件

@@ -27,6 +27,41 @@
@save="newFee"
/>

<section class="inputs estimates">
<h3>Templates</h3>

<div class="entry" v-for="t in templates" v-if="!template"
@click="() => template = t" key="t.id">
<span>
{{t.estimate.id}} - {{t.estimate.property}} - ${{(t.estimate.price/100).toLocaleString()}}
</span>
</div>

<div class="details" v-if="template">
<label>
#{{template.estimate.id}} -


{{template.estimate.transaction}} -
{{template.estimate.property}} -
${{(template.estimate.price / 100).toLocaleString()}}
</label>
<label>Borrowers: {{template.estimate.borrower.num}}</label>
<label>Credit: {{template.estimate.borrower.credit}}</label>
<label>Income: {{(template.estimate.borrower.income/100).toLocaleString()}}</label>

<div v-for="l in template.estimate.loans" class="details">
<h4>{{l.title}}</h4>
<label>{{l.type.name}}</label>
<label>Total monthly: ${{format(l.result.totalMonthly)}}</label>
<label>Cash to close: ${{format(l.result.cashToClose)}}</label>
</div>
<button @click="() => download(template.estimate)">Generate PDF</button>
<button @click="() => deleting = true">Remove</button>
<button @click="() => template = null">Cancel</button>
</div>
</section>

<section class="inputs estimates">
<h3>Saved Estimates</h3>

@@ -55,7 +90,8 @@ ${{(estimate.price / 100).toLocaleString()}}
<label>Cash to close: ${{format(l.result.cashToClose)}}</label>
</div>
<button @click="() => download(estimate)">Generate PDF</button>
<button @click="() => deleting = true">Delete</button>
<button @click="() => saveTemplate(estimate)">Save As Template</button>
<button @click="() => deleting = true" :disabled="isTemplate()">Delete</button>
<button @click="() => estimate = null">Cancel</button>
</div>

@@ -67,7 +103,7 @@ ${{(estimate.price / 100).toLocaleString()}}

<Dialog v-if="deleting" @close="() => deleting = false">
<h3>Are you sure you want to delete this estimate?</h3>
<button @click="() => del(estimate)">Confirm</button>
<button @click="() => del(estimate ?? template.estimate)">Confirm</button>
</Dialog>

</div>
@@ -84,7 +120,9 @@ const props = defineProps(['user', 'fees', 'token'])
const emit = defineEmits(['addFeeTemp', 'removeFeeTemp', 'preview'])
let edit = ref(null)
let estimates = ref([])
let templates = ref([])
let estimate = ref()
let template = ref()
let dlink = ref("")
let deleting = ref()

@@ -146,7 +184,37 @@ function getEstimates() {
}).then (result => {
if (!result || !result.length) return // Exit if token is invalid or no fees are saved
estimates.value = result
// console.log(result)
})
}

function getTemplates() {
fetch(`/api/estimate/templates`,
{method: 'GET',
headers: {
"Accept": "application/json",
"Authorization": `Bearer ${props.token}`,
},
}).then(response => {
if (response.ok) { return response.json() } else {
response.text().then(t => console.log(t))
}
}).then (result => {
if (!result || !result.length) return // Exit if token is invalid or no fees are saved
templates.value = result
console.log(result)
})
}

function saveTemplate(e) {
fetch(`/api/estimate/templates`,
{method: 'POST',
body: JSON.stringify(e),
headers: {
"Accept": "application/json",
"Authorization": `Bearer ${props.token}`,
},
}).then(response => {
if (response.ok) { getTemplates() }
})
}

@@ -167,6 +235,23 @@ function del(e) {
})
}

function remove(t) {
fetch(`/api/estimate/template/remove`,
{method: 'DELETE',
body: JSON.stringify(t),
headers: {
"Accept": "application/json",
"Authorization": `Bearer ${props.token}`,
},
}).then(response => {
if (response.ok) {
estimates.value = estimates.value.filter(e => e.id != estimate.value.id)
estimate.value = null
deleting.value = false
}
})
}

function download(estimate) {
fetch(`/api/pdf`,
{method: 'POST',
@@ -183,8 +268,13 @@ function download(estimate) {
})
}

function isTemplate() {
return templates.value.some( t => t.estimate.id == estimate.value.id )
}

onMounted(() => {
getEstimates()
getTemplates()
})
</script>



+ 56
- 2
skouter.go 查看文件

@@ -1827,7 +1827,7 @@ func getEstimates(db *sql.DB, id int, user int) ( []Estimate, error ) {
return estimates, nil
}

func getETemplate(db *sql.DB, id int, user int) ( []ETemplate, error ) {
func queryETemplates(db *sql.DB, id int, user int) ( []ETemplate, error ) {
var eTemplates []ETemplate
var query string
var rows *sql.Rows
@@ -1837,7 +1837,7 @@ func getETemplate(db *sql.DB, id int, user int) ( []ETemplate, error ) {
id,
estimate_id,
user_id,
branch_id,
branch_id
FROM estimate_template WHERE id = CASE @e := ? WHEN 0 THEN id ELSE @e END AND
user_id = CASE @e := ? WHEN 0 THEN user_id ELSE @e END
`
@@ -1873,6 +1873,31 @@ func getETemplate(db *sql.DB, id int, user int) ( []ETemplate, error ) {
return eTemplates, nil
}

// Accepts a borrower struct and returns the id of the inserted borrower and
// any related error.
func (estimate *Estimate) insertETemplate(db *sql.DB, user int, branch int) error {
var query string
var err error

query = `INSERT INTO estimate_template
(
estimate_id,
user_id,
branch_id
)
VALUES (?, ?, ?)
`
_, err = db.Exec(query,
estimate.Id,
user,
branch,
)
if err != nil { return err }

return nil
}


// Accepts a borrower struct and returns the id of the inserted borrower and
// any related error.
func (estimate *Estimate) insertBorrower(db *sql.DB) error {
@@ -2301,6 +2326,27 @@ func checkPdf(w http.ResponseWriter, r *http.Request) {

}

func getETemplates(w http.ResponseWriter, db *sql.DB, r *http.Request) {
claims, err := getClaims(r)
et, err := queryETemplates(db, 0, claims.Id)
if err != nil { http.Error(w, err.Error(), 500); return }
json.NewEncoder(w).Encode(et)
}

func createETemplate(w http.ResponseWriter, db *sql.DB, r *http.Request) {
var estimate Estimate
err := json.NewDecoder(r.Body).Decode(&estimate)

if err != nil { http.Error(w, err.Error(), 422); return }
claims, err := getClaims(r)
if err != nil { http.Error(w, err.Error(), 422); return }
err = estimate.insertETemplate(db, claims.Id, 0)
if err != nil { http.Error(w, err.Error(), 500); return }
}

func getPdf(w http.ResponseWriter, db *sql.DB, r *http.Request) {
var estimate Estimate
err := json.NewDecoder(r.Body).Decode(&estimate)
@@ -2508,6 +2554,14 @@ func api(w http.ResponseWriter, r *http.Request) {
r.Method == http.MethodPost &&
guard(r, 1):
summarize(w, db, r)
case match(p, "/api/estimate/templates", &args) &&
r.Method == http.MethodGet &&
guard(r, 1):
getETemplates(w, db, r)
case match(p, "/api/estimate/templates", &args) &&
r.Method == http.MethodPost &&
guard(r, 1):
createETemplate(w, db, r)
case match(p, "/api/pdf", &args) &&
r.Method == http.MethodPost &&
guard(r, 1):


+ 1
- 0
views/report/header.tpl 查看文件

@@ -30,6 +30,7 @@ h4 {
header.heading > div {
display: flex;
text-align: right;
margin-left: auto;
}

header.heading .user-info {


Loading…
取消
儲存