diff --git a/handlers/admin/page.go b/handlers/admin/page.go
index 79cd34b1..7bc50a4f 100644
--- a/handlers/admin/page.go
+++ b/handlers/admin/page.go
@@ -12,9 +12,12 @@ import (
"oj/handlers/admin/quizzes"
"oj/handlers/layout"
"oj/handlers/render"
+ "oj/internal/link"
"github.com/go-chi/chi/v5"
"github.com/jackc/pgx/v5/pgxpool"
+ g "maragu.dev/gomponents"
+ h "maragu.dev/gomponents/html"
)
type service struct {
@@ -37,12 +40,6 @@ func (s *service) Routes() chi.Router {
return r
}
-var (
- //go:embed page.gohtml
- pageContent string
- pageTemplate = layout.MustParse(pageContent, pageContent)
-)
-
func (s *service) page(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
@@ -54,11 +51,25 @@ func (s *service) page(w http.ResponseWriter, r *http.Request) {
return
}
- render.Execute(w, pageTemplate, struct {
- Layout layout.Data
- Users []api.User
- }{
- Layout: l,
- Users: allUsers,
- })
+ layout.Layout(l, "admin", g.Group{
+ h.Div(h.Style("display:flex; gap:1em"),
+ h.A(
+ h.Href("/admin/quizzes"),
+ g.Text("quizzes"),
+ ),
+ h.A(
+ h.Href("/admin/messages"),
+ g.Text("messages"),
+ ),
+ ),
+ h.Hr(),
+ g.Map(allUsers, func(user api.User) g.Node {
+ return h.Div(
+ h.A(
+ h.Href(link.User(user.ID)),
+ g.Text(user.Username),
+ ),
+ )
+ }),
+ }).Render(w)
}
diff --git a/handlers/admin/page.gohtml b/handlers/admin/page.gohtml
deleted file mode 100644
index 6cbb9214..00000000
--- a/handlers/admin/page.gohtml
+++ /dev/null
@@ -1,12 +0,0 @@
-{{define "main"}}
- quizzes
- messages
-
-
-
- {{range .Users}}
-
- {{end}}
-{{end}}
diff --git a/handlers/admin/quizzes/page.go b/handlers/admin/quizzes/page.go
index c486ac60..abe4eb64 100644
--- a/handlers/admin/quizzes/page.go
+++ b/handlers/admin/quizzes/page.go
@@ -7,9 +7,12 @@ import (
"oj/api"
"oj/handlers/layout"
"oj/handlers/render"
+ "oj/internal/link"
"github.com/go-chi/chi/v5"
"github.com/jackc/pgx/v5"
+ g "maragu.dev/gomponents"
+ h "maragu.dev/gomponents/html"
)
type service struct {
@@ -24,12 +27,6 @@ func (s *service) Router(r chi.Router) {
r.Get("/", s.page)
}
-var (
- //go:embed page.gohtml
- pageContent string
- pageTemplate = layout.MustParse(pageContent, pageContent)
-)
-
func (s *service) page(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
l := layout.FromContext(ctx)
@@ -40,11 +37,23 @@ func (s *service) page(w http.ResponseWriter, r *http.Request) {
return
}
- render.Execute(w, pageTemplate, struct {
- Layout layout.Data
- Quizzes []api.Quiz
- }{
- Layout: l,
- Quizzes: allQuizzes,
- })
+ layout.Layout(l, "quizzes",
+ h.Div(
+ h.Div(
+ h.Style("display:flex; justify-content:space-between; align-items:center"),
+ h.H1(
+ g.Text("quizzes"),
+ ),
+ ),
+ g.Map(allQuizzes, func(q api.Quiz) g.Node {
+ return h.Div(
+ h.Class("nes-container ghost"),
+ h.A(
+ h.Href(link.Quiz(q)),
+ g.Text(q.Name),
+ ),
+ )
+ }),
+ ),
+ ).Render(w)
}
diff --git a/handlers/admin/quizzes/page.gohtml b/handlers/admin/quizzes/page.gohtml
deleted file mode 100644
index 178a020f..00000000
--- a/handlers/admin/quizzes/page.gohtml
+++ /dev/null
@@ -1,11 +0,0 @@
-{{define "main"}}
-
- {{range .Quizzes}}
-
- {{end}}
-{{end}}
diff --git a/handlers/deliveries/page.go b/handlers/deliveries/page.go
index a70cd444..ebe75233 100644
--- a/handlers/deliveries/page.go
+++ b/handlers/deliveries/page.go
@@ -12,6 +12,8 @@ import (
"github.com/go-chi/chi/v5"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgxpool"
+ g "maragu.dev/gomponents"
+ h "maragu.dev/gomponents/html"
)
type service struct {
@@ -23,12 +25,6 @@ func NewService(q *api.Queries, conn *pgxpool.Pool) *service {
return &service{Queries: q, Conn: conn}
}
-var (
- //go:embed "page.gohtml"
- pageContent string
- pageTemplate = layout.MustParse(pageContent)
-)
-
func (s *service) Page(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
l := layout.FromContext(r.Context())
@@ -50,15 +46,34 @@ func (s *service) Page(w http.ResponseWriter, r *http.Request) {
return
}
- render.Execute(w, pageTemplate, struct {
- Layout layout.Data
- LogoutActionURL string
- Delivery api.Delivery
- }{
- Layout: l,
- LogoutActionURL: fmt.Sprintf("%d/logout", delivery.ID),
- Delivery: delivery,
- })
+ logoutActionURL := fmt.Sprintf("%d/logout", delivery.ID)
+
+ layout.Layout(l, "Delivery",
+ h.Dialog(
+ g.Attr("open"),
+ h.Class("nes-dialog"),
+ h.Form(
+ h.Method("post"),
+ h.Action(logoutActionURL),
+ h.P(
+ g.Text(fmt.Sprintf("You are currently logged in as %s.", l.User.Username)),
+ ),
+ h.P(
+ g.Text("This content is for a different user!"),
+ ),
+ h.Div(
+ h.Style("display:flex; justify-content: space-between"),
+ h.Button(
+ h.Class("nes-btn is-primary"),
+ g.Text("Switch User"),
+ ),
+ h.A(
+ h.Href("/"),
+ h.Class("nes-btn"),
+ g.Text("Cancel"),
+ ),
+ ),
+ ))).Render(w)
}
// Logout and redirect back to delivery page to recheck current user
diff --git a/handlers/deliveries/page.gohtml b/handlers/deliveries/page.gohtml
deleted file mode 100644
index 552fdb2c..00000000
--- a/handlers/deliveries/page.gohtml
+++ /dev/null
@@ -1,13 +0,0 @@
-{{define "main"}}
-
-
-{{end}}
diff --git a/internal/link/link.go b/internal/link/link.go
index 94fdaead..ddcab7c3 100644
--- a/internal/link/link.go
+++ b/internal/link/link.go
@@ -2,6 +2,7 @@ package link
import (
"fmt"
+ "oj/api"
"strings"
)
@@ -20,3 +21,11 @@ func ChessMatch(id int64, rest ...string) string {
func ConnectFriend(id int64) string {
return Link("connectkids/friend", id)
}
+
+func Quiz(quiz api.Quiz, rest ...string) string {
+ return fmt.Sprintf("/u/%d/quizzes/%d", quiz.UserID, quiz.ID)
+}
+
+func ParentKid(id int64, rest ...string) string {
+ return Link("parent/kids", id, rest...)
+}
diff --git a/internal/resources/parent/parent.go b/internal/resources/parent/parent.go
index fa36aab6..f8eef90f 100644
--- a/internal/resources/parent/parent.go
+++ b/internal/resources/parent/parent.go
@@ -9,12 +9,16 @@ import (
"oj/api"
"oj/handlers/layout"
"oj/handlers/render"
+ "oj/internal/link"
"oj/internal/middleware/auth"
"oj/services/family"
+ "time"
"github.com/go-chi/chi/v5"
"github.com/jackc/pgx/v5"
"github.com/jmoiron/sqlx"
+ g "maragu.dev/gomponents"
+ h "maragu.dev/gomponents/html"
)
type Resource struct {
@@ -31,16 +35,9 @@ func (rs Resource) Routes() chi.Router {
return r
}
-var (
- //go:embed parent.gohtml
- pageContent string
-
- t = layout.MustParse(pageContent)
-)
-
func (rs Resource) index(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
- l := layout.FromContext(r.Context())
+ l := layout.FromContext(ctx)
kids, err := rs.Queries.KidsByParentID(ctx, l.User.ID)
if err != nil {
@@ -48,18 +45,87 @@ func (rs Resource) index(w http.ResponseWriter, r *http.Request) {
return
}
- err = t.Execute(w, struct {
- Layout layout.Data
- User api.User
- Kids []api.User
- }{
- Layout: l,
- User: l.User,
- Kids: kids,
- })
- if err != nil {
- render.Error(w, fmt.Errorf("Execute: %w", err), 500)
- }
+ layout.Layout(l, "parent",
+ h.Div(
+ h.Style("display:flex; flex-direction: column; gap:1em; margin-bottom: 50%"),
+ h.Div(
+ h.Class("nes-container is-dark"),
+ h.Style("display:flex; flex-direction:column; gap:1em"),
+ h.H1(
+ g.Text("Hello parent!"),
+ h.Small(
+ g.Text(l.User.Email.String),
+ ),
+ ),
+ h.P(
+ g.Text("Here you can add managed accounts for your kids."),
+ ),
+ h.P(
+ g.Text("You are the manager for these accounts. You can remove them and\n all associated data at any time."),
+ ),
+ h.P(
+ g.Text("Choose a unique username for your child. It can contain their name, but doesn't have to. They will be able to change it to whatever they want when they login."),
+ ),
+ h.Div(
+ h.Class("nes-container is-dark"),
+ h.Form(
+ h.Action("/parent/kids"),
+ h.Method("post"),
+ h.Label(
+ g.Text("Child's Username"),
+ h.Input(
+ h.Class("nes-input"),
+ h.Type("text"),
+ h.Name("username"),
+ ),
+ ),
+ h.Button(
+ h.Class("nes-btn is-primary"),
+ g.Text("Add Kid"),
+ ),
+ ),
+ ),
+ h.P(
+ g.Text(fmt.Sprintf("Kids login with their username and a one time code that will be emailed to %s.",
+ l.User.Email)),
+ ),
+ ),
+ g.Map(kids, func(kid api.User) g.Node {
+ return h.Div(
+ h.Class("nes-container ghost kid"),
+ h.Div(
+ h.Style("display:flex; justify-content:space-between"),
+ h.A(
+ h.Href(link.User(l.User.ID)),
+ h.Style("display: flex; gap:1em"),
+ h.Img(
+ h.Width("100"),
+ h.Src(kid.Avatar.URL()),
+ ),
+ h.Div(
+ h.Style("display:flex; flex-direction: column"),
+ h.H2(
+ g.Text(fmt.Sprintf("username: %s", kid.Username)),
+ ),
+ h.Div(
+ g.Text(fmt.Sprintf("Joined %s", kid.CreatedAt.Time.Format(time.DateOnly))),
+ ),
+ ),
+ ),
+ h.Div(
+ h.Button(
+ h.Class("nes-btn is-error"),
+ g.Attr("hx-delete", link.ParentKid(kid.ID)),
+ g.Attr("hx-confirm", fmt.Sprintf("Permanently delete %s and all associated data?", kid.Username)),
+ g.Attr("hx-target", "closest .kid"),
+ g.Attr("hx-swap", "outerHTML"),
+ g.Text("delete"),
+ ),
+ ),
+ ),
+ )
+ }),
+ )).Render(w)
}
func (rs Resource) createKid(w http.ResponseWriter, r *http.Request) {
diff --git a/internal/resources/parent/parent.gohtml b/internal/resources/parent/parent.gohtml
deleted file mode 100644
index f470ef34..00000000
--- a/internal/resources/parent/parent.gohtml
+++ /dev/null
@@ -1,69 +0,0 @@
-{{define "main"}}
-
-
-
Hello parent! {{.User.Email.String}}
-
-
- Here you can add managed accounts for your kids.
-
-
-
- You are the manager for these accounts. You can remove them and
- all associated data at any time.
-
-
-
- Choose a unique username for your child. It can contain their
- name, but doesn't have to. They will be able to
- change it to whatever they want when they login.
-
-
-
-
-
-
-
- Kids login with their username and a one time code that will
- be emailed to {{.User.Email}}.
-
-
-
- {{range .Kids}}
- {{template "kid" .}}
- {{end}}
-
-{{end}}
-
-{{define "kid"}}
-
-{{end}}