339 lines
7.2 KiB
Go
339 lines
7.2 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/sha256"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"time"
|
|
|
|
"dutchellie.nl/DutchEllie/proper-website-2/entity"
|
|
"github.com/maxence-charriere/go-app/v9/pkg/app"
|
|
)
|
|
|
|
type guestbook struct {
|
|
app.Compo
|
|
|
|
comments []entity.Comment
|
|
|
|
name string
|
|
email string
|
|
website string
|
|
message string
|
|
|
|
lastHash [32]byte
|
|
gbModalOpen bool
|
|
OnSubmit func(
|
|
ctx app.Context,
|
|
name string,
|
|
email string,
|
|
website string,
|
|
message string,
|
|
) // Handler to implement which calls the api
|
|
}
|
|
|
|
// TODO: The comments are loaded like 2 or 3 times every time the page is loaded...
|
|
func (g *guestbook) OnMount(ctx app.Context) {
|
|
ctx.Handle("guestbook-loadcomments", g.onHandleLoadComments)
|
|
ctx.NewAction("guestbook-loadcomments")
|
|
}
|
|
|
|
/*
|
|
func (g *guestbook) OnNav(ctx app.Context) {
|
|
g.LoadComments(ctx)
|
|
}
|
|
|
|
func (g *guestbook) OnUpdate(ctx app.Context) {
|
|
g.LoadComments(ctx)
|
|
}*/
|
|
|
|
func (g guestbook) Render() app.UI {
|
|
return app.Div().Body(
|
|
app.Form().
|
|
Class("guestbook-form").
|
|
Body(
|
|
app.Div().
|
|
Class("input-groups").
|
|
Body(
|
|
app.Div().
|
|
Class("fr").
|
|
Body(
|
|
app.Div().
|
|
Class("input-group").
|
|
Class("input-group-name").
|
|
Body(
|
|
app.Label().
|
|
For("name").
|
|
Text("Name:"),
|
|
app.Input().
|
|
Type("text").
|
|
Name("name").
|
|
Class("input").
|
|
Required(true).
|
|
OnChange(g.ValueTo(&g.name)),
|
|
),
|
|
app.Div().
|
|
Class("input-group").
|
|
Class("input-group-email").
|
|
Body(
|
|
app.Label().
|
|
For("email").
|
|
Text("Email: (optional)"),
|
|
app.Input().
|
|
Type("text").
|
|
Name("email").
|
|
Class("input").
|
|
Required(false).
|
|
OnChange(g.ValueTo(&g.email)),
|
|
),
|
|
),
|
|
app.Div().
|
|
Class("input-group").
|
|
Class("input-group-website").
|
|
Body(
|
|
app.Label().
|
|
For("website").
|
|
Text("Website: (optional)"),
|
|
app.Input().
|
|
Type("text").
|
|
Name("website").
|
|
Class("input").
|
|
Required(false).
|
|
OnChange(g.ValueTo(&g.website)),
|
|
),
|
|
app.Div().
|
|
Class("input-group").
|
|
Class("input-group-message").
|
|
Body(
|
|
app.Label().
|
|
For("message").
|
|
Text("Message:"),
|
|
app.Textarea().
|
|
Name("message").
|
|
Class("input").
|
|
Rows(5).
|
|
Cols(30).
|
|
Required(true).
|
|
OnChange(g.ValueTo(&g.message)),
|
|
),
|
|
app.Div().
|
|
Class("submit-field").
|
|
Body(
|
|
app.Input().
|
|
Type("submit").
|
|
Value("Send!"),
|
|
),
|
|
),
|
|
).OnSubmit(func(ctx app.Context, e app.Event) {
|
|
// This was to prevent the page from reloading
|
|
e.PreventDefault()
|
|
if g.name == "" || g.message == "" {
|
|
fmt.Printf("Error: one or more field(s) are empty. For now unhandled\n")
|
|
return
|
|
}
|
|
if len(g.name) > 40 || len(g.message) > 360 {
|
|
fmt.Printf("Error: Your message is too long fucker\n")
|
|
g.gbModalOpen = true
|
|
return
|
|
}
|
|
g.OnSubmit(ctx, g.name, g.email, g.website, g.message)
|
|
g.clear()
|
|
ctx.NewAction("guestbook-loadcomments")
|
|
//g.LoadComments(ctx)
|
|
}),
|
|
app.If(
|
|
g.gbModalOpen,
|
|
&guestbookAlertModal{
|
|
OnClose: func() {
|
|
g.gbModalOpen = false
|
|
g.Update()
|
|
},
|
|
},
|
|
),
|
|
app.Div().Body(
|
|
app.Range(g.comments).Slice(func(i int) app.UI {
|
|
return &guestbookComment{
|
|
Comment: g.comments[i],
|
|
}
|
|
},
|
|
),
|
|
),
|
|
)
|
|
}
|
|
|
|
func (g *guestbook) SmartLoadComments(ctx app.Context) {
|
|
{
|
|
// Get the comments quickly to at least render something
|
|
tmpjsondata := make([]byte, 0)
|
|
err := ctx.LocalStorage().Get("comments", &tmpjsondata)
|
|
if err != nil {
|
|
app.Log(err)
|
|
return
|
|
}
|
|
ctx.Dispatch(func(ctx app.Context) {
|
|
err = json.Unmarshal(tmpjsondata, &g.comments)
|
|
if err != nil {
|
|
app.Log(err)
|
|
return
|
|
}
|
|
})
|
|
g.Update()
|
|
}
|
|
var lasthash []byte
|
|
err := ctx.LocalStorage().Get("lasthash", &lasthash)
|
|
if err != nil {
|
|
app.Log(err)
|
|
return
|
|
}
|
|
|
|
if lasthash == nil {
|
|
fmt.Printf("Program thinks lasthash is empty\n")
|
|
g.LoadComments(ctx)
|
|
return
|
|
}
|
|
url := ApiURL + "/commenthash"
|
|
ctx.Async(func() {
|
|
res, err := http.Get(url)
|
|
if err != nil {
|
|
app.Log(err)
|
|
return
|
|
}
|
|
defer res.Body.Close()
|
|
|
|
hash, err := io.ReadAll(res.Body)
|
|
if err != nil {
|
|
app.Log(err)
|
|
return
|
|
}
|
|
|
|
fmt.Printf("hash: %v\n", hash)
|
|
fmt.Printf("lasthash: %v\n", lasthash)
|
|
|
|
// If the hash is different, aka there was an update in the comments
|
|
if !bytes.Equal(hash, lasthash) {
|
|
fmt.Printf("Hash calculation is different\n")
|
|
g.LoadComments(ctx)
|
|
return
|
|
}
|
|
|
|
// if the hash is not different, then there is no need to load new comments
|
|
jsondata := make([]byte, 0)
|
|
err = ctx.LocalStorage().Get("comments", &jsondata)
|
|
if err != nil {
|
|
app.Log(err)
|
|
return
|
|
}
|
|
fmt.Printf("jsondata: %v\n", jsondata)
|
|
ctx.Dispatch(func(ctx app.Context) {
|
|
err = json.Unmarshal(jsondata, &g.comments)
|
|
if err != nil {
|
|
app.Log(err)
|
|
return
|
|
}
|
|
})
|
|
return
|
|
})
|
|
}
|
|
|
|
func (g *guestbook) LoadComments(ctx app.Context) {
|
|
// TODO: maybe you can put this in a localbrowser storage?
|
|
fmt.Printf("Called LoadComments()\n")
|
|
url := ApiURL + "/comment"
|
|
ctx.Async(func() {
|
|
res, err := http.Get(url)
|
|
if err != nil {
|
|
app.Log(err)
|
|
return
|
|
}
|
|
defer res.Body.Close()
|
|
jsondata, err := io.ReadAll(res.Body)
|
|
if err != nil {
|
|
app.Log(err)
|
|
return
|
|
}
|
|
|
|
ctx.Dispatch(func(ctx app.Context) {
|
|
err = json.Unmarshal(jsondata, &g.comments)
|
|
if err != nil {
|
|
app.Log(err)
|
|
return
|
|
}
|
|
})
|
|
|
|
ctx.LocalStorage().Set("comments", jsondata)
|
|
// Calculating the hash
|
|
fmt.Printf("Calculating the hash from LoadComments\n")
|
|
hash := sha256.Sum256(jsondata)
|
|
fmt.Printf("hash fresh from calculation: %v\n", hash)
|
|
//g.lastHash = hash
|
|
err = ctx.LocalStorage().Set("lasthash", []byte(fmt.Sprintf("%x\n", hash)))
|
|
if err != nil {
|
|
app.Log(err)
|
|
return
|
|
}
|
|
})
|
|
}
|
|
|
|
func (g *guestbook) clear() {
|
|
g.name = ""
|
|
g.message = ""
|
|
g.website = ""
|
|
g.email = ""
|
|
}
|
|
|
|
func (g *guestbook) onHandleLoadComments(ctx app.Context, a app.Action) {
|
|
g.SmartLoadComments(ctx)
|
|
g.Update()
|
|
}
|
|
|
|
type guestbookAlertModal struct {
|
|
app.Compo
|
|
|
|
PreviousAttempts int
|
|
OnClose func() // For when we close the modal
|
|
}
|
|
|
|
func (g *guestbookAlertModal) Render() app.UI {
|
|
return app.Div().
|
|
Class("gb-modal").
|
|
ID("gbModal").
|
|
OnClick(func(ctx app.Context, e app.Event) {
|
|
g.OnClose()
|
|
}).
|
|
Body(
|
|
app.Div().
|
|
Class("gb-modal-content").
|
|
Body(
|
|
app.Span().Class("close").Text("X").
|
|
OnClick(func(ctx app.Context, e app.Event) {
|
|
//modal := app.Window().GetElementByID("gbModal")
|
|
//modal.Set("style", "none")
|
|
g.OnClose()
|
|
}),
|
|
app.P().Text("Your name must be <= 40 and your message must be <= 360 characters"),
|
|
),
|
|
)
|
|
}
|
|
|
|
type guestbookComment struct {
|
|
app.Compo
|
|
|
|
Comment entity.Comment
|
|
time string
|
|
}
|
|
|
|
func (c *guestbookComment) Render() app.UI {
|
|
c.time = c.Comment.PostDate.Format(time.RFC1123)
|
|
return app.Div().Body(
|
|
app.Div().Class().Body(
|
|
app.P().Text(c.Comment.Name).Class("name"),
|
|
app.P().Text(c.time).Class("date"),
|
|
).Class("comment-header"),
|
|
app.Div().Class("comment-message").Body(
|
|
app.P().Text(c.Comment.Message),
|
|
),
|
|
).Class("comment")
|
|
}
|