diff --git a/components/dropdown.vue b/components/dropdown.vue index cfb6085..1dff597 100644 --- a/components/dropdown.vue +++ b/components/dropdown.vue @@ -17,6 +17,7 @@ margin-top: 5px; z-index: 3; border: 1px solid black; + top: 100%; } .entry { diff --git a/components/estimate-test.vue b/components/estimate-test.vue index ce1d0b4..e0117f9 100644 --- a/components/estimate-test.vue +++ b/components/estimate-test.vue @@ -1,5 +1,6 @@ +Actual costs may vary from estimates after approval. Get an official quote before choosing a loan. @@ -11,14 +12,18 @@ {{user.firstName + " " + user.lastName}} {{user.email}} {{user.phone}} -{{user.phone}} +{{user.address.street}} + +{{`${user.address.city}, ${user.address.region} ${user.address.zip}`}} + -Generate +Generate +download @@ -30,6 +35,7 @@ const doc = ref(null) const props = defineProps(['token', 'estimate', 'user']) const estimate = ref(null) const estimates = ref(null) +const pdfLink = ref('') const letterhead = computed(() => { if (!props.user.letterhead) return null @@ -43,7 +49,11 @@ const avatar = computed(() => { }) function makePDF() { - html2pdf(doc.value) + var opt = { + image: { type: 'png', quality: 1 }, + } + + html2pdf(doc.value, opt) } @@ -65,18 +75,62 @@ function getEstimates() { }) } +function getPdf() { + fetch(`/api/pdf`, + {method: 'GET', + headers: { + "Accept": "application/json", + "Authorization": `Bearer ${props.token}`, + }, + }).then(response => { + if (response.ok) { return response.blob() } + else { + return null + } + }).then (result => { + if (!result) return + pdfLink.value = URL.createObjectURL(result) + }) +} + onMounted(() => { getEstimates().then(() => estimate.value = estimates.value[0]) }) diff --git a/components/settings.vue b/components/settings.vue index fc48171..b966e7f 100644 --- a/components/settings.vue +++ b/components/settings.vue @@ -31,7 +31,7 @@ NMLS ID Branch ID - + USA @@ -288,5 +288,6 @@ watch(props.user, (u) => { div.address-entry { display: flex; flex-flow: column; + position: relative; } diff --git a/skouter.go b/skouter.go index 56d22a2..753f521 100644 --- a/skouter.go +++ b/skouter.go @@ -2,6 +2,7 @@ package main import ( "os" + "os/exec" "net/http" "net/mail" "log" @@ -12,6 +13,7 @@ import ( _ "github.com/go-sql-driver/mysql" "fmt" "encoding/json" + "encoding/base64" "strconv" "bytes" "time" @@ -811,7 +813,8 @@ func queryUsers(db *sql.DB, id int) ( []User, error ) { u.status, u.verified, u.role, - u.address + u.address, + u.phone FROM user u WHERE u.id = CASE @e := ? WHEN 0 THEN u.id ELSE @e END ` rows, err = db.Query(query, id) @@ -838,6 +841,7 @@ func queryUsers(db *sql.DB, id int) ( []User, error ) { &user.Verified, &user.Role, &user.Address.Id, + &user.Phone, ) err != nil { return users, err @@ -1807,7 +1811,7 @@ func showPDF(w http.ResponseWriter, r *http.Request) { // p := r.URL.Path db, err := sql.Open("mysql", - fmt.Sprintf("%s:%s@tcp(127.0.0.1:3306)/skouter", + fmt.Sprintf("%s:%s@tcp(127.0.0.1:3306)/skouter_dev", os.Getenv("DBUser"), os.Getenv("DBPass"))) @@ -1829,18 +1833,102 @@ func showPDF(w http.ResponseWriter, r *http.Request) { info := struct { Title string Name string + Avatar string + Letterhead string User User }{ Title: "test PDF", Name: "idk-random-name", User: users[0], } + avatar, err := fetchAvatar(db, info.User.Id) + letterhead, err := fetchLetterhead(db, info.User.Id) + info.Avatar = + base64.StdEncoding.EncodeToString(avatar) + info.Letterhead = + base64.StdEncoding.EncodeToString(letterhead) err = pa.Execute(w, info) if err != nil {fmt.Println(err)} } +func getPdf(w http.ResponseWriter, db *sql.DB, r *http.Request) { + var err error + cmd := exec.Command("wkhtmltopdf", "-", "-") + + stdout, err := cmd.StdoutPipe() + if err != nil { + w.WriteHeader(500); + log.Println(err) + return + } + + stdin, err := cmd.StdinPipe() + if err != nil { + w.WriteHeader(500); + log.Println(err) + return + } + + if err := cmd.Start(); err != nil { + log.Fatal(err) + } + + var pa = template.Must(template.ParseFiles("views/pdf.tpl", + "views/test.tpl")) + + // claims, err := getClaims(r) + if err != nil { + w.WriteHeader(500); + log.Println(err) + return + } + users, err := queryUsers(db, 1) + + info := struct { + Title string + Name string + Avatar string + Letterhead string + User User + }{ + Title: "test PDF", + Name: "idk-random-name", + User: users[0], + } + avatar, err := fetchAvatar(db, info.User.Id) + letterhead, err := fetchLetterhead(db, info.User.Id) + info.Avatar = + base64.StdEncoding.EncodeToString(avatar) + info.Letterhead = + base64.StdEncoding.EncodeToString(letterhead) + + + err = pa.Execute(stdin, info) + if err != nil { + w.WriteHeader(500); + log.Println(err) + return + } + stdin.Close() + + buf, err := io.ReadAll(stdout) + + if _, err := w.Write(buf); err != nil { + w.WriteHeader(500); + log.Println(err) + return + } + + if err := cmd.Wait(); err != nil { + // w.WriteHeader(500) + log.Println(err) + return + } + +} + func clipLetterhead(w http.ResponseWriter, db *sql.DB, r *http.Request) { var validTypes []string = []string{"image/png", "image/jpeg"} var isValidType bool @@ -1966,6 +2054,10 @@ func api(w http.ResponseWriter, r *http.Request) { r.Method == http.MethodPost && guard(r, 1): summarize(w, db, r) + case match(p, "/api/pdf", &args) && + r.Method == http.MethodGet && + guard(r, 1): + getPdf(w, db, r) default: http.Error(w, "Invalid route or token", 404) } diff --git a/views/pdf.tpl b/views/pdf.tpl new file mode 100644 index 0000000..cc695d4 --- /dev/null +++ b/views/pdf.tpl @@ -0,0 +1,14 @@ + + + + + + + + +{{block "header" .}} +{{end}} + +{{template "main" .}} + diff --git a/views/test.tpl b/views/test.tpl index 2daecca..55cbe25 100644 --- a/views/test.tpl +++ b/views/test.tpl @@ -4,8 +4,67 @@ {{end}} {{define "main"}} - -hello world {{.User.Title}} -TESTING - + +Actual costs may vary from estimates after approval. Get an official quote before choosing a loan. + + + + + + + +{{.User.FirstName}} {{.User.LastName}} +{{.User.Email}} +{{.User.Phone}} +{{.User.Address.Street}} + +{{.User.Address.City}}, {{.User.Address.Region}} {{.User.Address.Zip}} + + + + + + + + {{end}} + +
Actual costs may vary from estimates after approval. Get an official quote before choosing a loan.