diff --git a/pkg/web/components/issuelist.templ b/pkg/web/components/issuelist.templ
new file mode 100644
index 0000000..cc97491
--- /dev/null
+++ b/pkg/web/components/issuelist.templ
@@ -0,0 +1,19 @@
+package components
+
+import "github.com/LazyBachelor/LazyPM/internal/models"
+
+type IssueListProps struct {
+ Issues []*models.Issue
+}
+
+templ IssueList(props IssueListProps) {
+
+ for _, issue := range props.Issues {
+ @IssueListItem(issue)
+ }
+
+}
+
+templ IssueListItem(issue *models.Issue) {
+ Issue ID: { issue.ID }, Title: { issue.Title }
+}
diff --git a/pkg/web/components/issuelist_templ.go b/pkg/web/components/issuelist_templ.go
new file mode 100644
index 0000000..860dc69
--- /dev/null
+++ b/pkg/web/components/issuelist_templ.go
@@ -0,0 +1,111 @@
+// Code generated by templ - DO NOT EDIT.
+
+// templ: version: v0.3.977
+package components
+
+//lint:file-ignore SA4006 This context is only used if a nested component is present.
+
+import "github.com/a-h/templ"
+import templruntime "github.com/a-h/templ/runtime"
+
+import "github.com/LazyBachelor/LazyPM/internal/models"
+
+type IssueListProps struct {
+ Issues []*models.Issue
+}
+
+func IssueList(props IssueListProps) templ.Component {
+ return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
+ if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
+ return templ_7745c5c3_CtxErr
+ }
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
+ if !templ_7745c5c3_IsBuffer {
+ defer func() {
+ templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err == nil {
+ templ_7745c5c3_Err = templ_7745c5c3_BufErr
+ }
+ }()
+ }
+ ctx = templ.InitializeContext(ctx)
+ templ_7745c5c3_Var1 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var1 == nil {
+ templ_7745c5c3_Var1 = templ.NopComponent
+ }
+ ctx = templ.ClearChildren(ctx)
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ for _, issue := range props.Issues {
+ templ_7745c5c3_Err = IssueListItem(issue).Render(ctx, templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ return nil
+ })
+}
+
+func IssueListItem(issue *models.Issue) templ.Component {
+ return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
+ if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
+ return templ_7745c5c3_CtxErr
+ }
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
+ if !templ_7745c5c3_IsBuffer {
+ defer func() {
+ templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err == nil {
+ templ_7745c5c3_Err = templ_7745c5c3_BufErr
+ }
+ }()
+ }
+ ctx = templ.InitializeContext(ctx)
+ templ_7745c5c3_Var2 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var2 == nil {
+ templ_7745c5c3_Var2 = templ.NopComponent
+ }
+ ctx = templ.ClearChildren(ctx)
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "Issue ID: ")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ var templ_7745c5c3_Var3 string
+ templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(issue.ID)
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/web/components/issuelist.templ`, Line: 18, Col: 25}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, ", Title: ")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ var templ_7745c5c3_Var4 string
+ templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(issue.Title)
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/web/components/issuelist.templ`, Line: 18, Col: 49}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ return nil
+ })
+}
+
+var _ = templruntime.GeneratedTemplate
diff --git a/pkg/web/handler/handler.go b/pkg/web/handler/handler.go
new file mode 100644
index 0000000..597333c
--- /dev/null
+++ b/pkg/web/handler/handler.go
@@ -0,0 +1,21 @@
+package handler
+
+import (
+ "net/http"
+
+ "github.com/LazyBachelor/LazyPM/internal/service"
+)
+
+type Route struct {
+ Pattern string
+ Handler http.Handler
+}
+
+func GetRoutes(svc *service.Services) []Route {
+ var routes []Route
+
+ routes = append(routes, PagesRoutes(svc)...)
+ routes = append(routes, IssuesRoutes(svc)...)
+
+ return routes
+}
diff --git a/pkg/web/handler/issues.go b/pkg/web/handler/issues.go
index d89e213..6beff6a 100644
--- a/pkg/web/handler/issues.go
+++ b/pkg/web/handler/issues.go
@@ -1,22 +1,66 @@
package handler
import (
- "github.com/LazyBachelor/LazyPM/internal/service"
+ "encoding/json"
"net/http"
+
+ "github.com/LazyBachelor/LazyPM/internal/models"
+ "github.com/LazyBachelor/LazyPM/internal/service"
)
-type IssuesHandler struct {
- Services *service.Services
-}
-
-func NewIssuesHandler(services *service.Services) *IssuesHandler {
- return &IssuesHandler{
- Services: services,
+func IssuesRoutes(svc *service.Services) []Route {
+ return []Route{
+ {Pattern: "/issues", Handler: GetAllIssues(svc)},
+ {Pattern: "POST /create-issue", Handler: CreateIssue(svc)},
}
}
-func (h *IssuesHandler) HandleGetAllIssues() http.Handler {
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+func CreateIssue(svc *service.Services) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ if r.Method != http.MethodPost {
+ http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
+ return
+ }
- })
+ var issue models.Issue
+
+ err := json.NewDecoder(r.Body).Decode(&issue)
+ if err != nil {
+ http.Error(w, "Invalid request payload", http.StatusBadRequest)
+ return
+ }
+
+ defer r.Body.Close()
+
+ err = svc.Beads.CreateIssue(r.Context(), &issue, "")
+ if err != nil {
+ http.Error(w, "Failed to create issue: "+err.Error(), http.StatusBadRequest)
+ return
+ }
+
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusCreated)
+ json.NewEncoder(w).Encode(issue)
+ }
+}
+
+func GetAllIssues(svc *service.Services) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ issues, err := svc.Beads.AllIssues(r.Context())
+
+ if err != nil {
+ http.Error(w, "Failed to retrieve issues", http.StatusInternalServerError)
+ return
+ }
+
+ jsonData, err := json.Marshal(issues)
+
+ if err != nil {
+ http.Error(w, "Failed to marshal issues", http.StatusInternalServerError)
+ return
+ }
+
+ w.Header().Set("Content-Type", "application/json")
+ w.Write(jsonData)
+ }
}
diff --git a/pkg/web/handler/pages.go b/pkg/web/handler/pages.go
new file mode 100644
index 0000000..0eea015
--- /dev/null
+++ b/pkg/web/handler/pages.go
@@ -0,0 +1,46 @@
+package handler
+
+import (
+ "net/http"
+
+ "github.com/LazyBachelor/LazyPM/internal/service"
+ "github.com/LazyBachelor/LazyPM/pkg/web/components"
+ "github.com/LazyBachelor/LazyPM/pkg/web/routes"
+)
+
+func PagesRoutes(svc *service.Services) []Route {
+ return []Route{
+ {Pattern: "/", Handler: IndexHandler(svc)},
+ }
+}
+
+func IndexHandler(svc *service.Services) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+
+ if r.URL.Path != "/" {
+ handleNotFound(w, r)
+ return
+ }
+
+ issues, err := svc.Beads.AllIssues(r.Context())
+
+ if err != nil {
+ http.Error(w, "Failed to retrieve issues",
+ http.StatusInternalServerError)
+ return
+ }
+
+ props := routes.IndexProps{
+ Issues: issues,
+ IssueList: components.IssueListProps{
+ Issues: issues,
+ },
+ }
+
+ routes.Index(props).Render(r.Context(), w)
+ }
+}
+
+func handleNotFound(w http.ResponseWriter, _ *http.Request) {
+ http.Error(w, "Page not found", http.StatusNotFound)
+}
diff --git a/pkg/web/routes/index.templ b/pkg/web/routes/index.templ
index 2216e9c..73423e2 100644
--- a/pkg/web/routes/index.templ
+++ b/pkg/web/routes/index.templ
@@ -1,8 +1,19 @@
package routes
-templ Index() {
+import (
+ "github.com/LazyBachelor/LazyPM/internal/models"
+ "github.com/LazyBachelor/LazyPM/pkg/web/components"
+)
+
+type IndexProps struct {
+ Issues []*models.Issue
+ IssueList components.IssueListProps
+}
+
+templ Index(props IndexProps) {
@BaseLayout() {
Welcome to the Beads Test Application
Here are current issues:
+ @components.IssueList(props.IssueList)
}
}
diff --git a/pkg/web/routes/index_templ.go b/pkg/web/routes/index_templ.go
index 1103fc6..0600679 100644
--- a/pkg/web/routes/index_templ.go
+++ b/pkg/web/routes/index_templ.go
@@ -8,7 +8,17 @@ package routes
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
-func Index() templ.Component {
+import (
+ "github.com/LazyBachelor/LazyPM/internal/models"
+ "github.com/LazyBachelor/LazyPM/pkg/web/components"
+)
+
+type IndexProps struct {
+ Issues []*models.Issue
+ IssueList components.IssueListProps
+}
+
+func Index(props IndexProps) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
@@ -45,6 +55,10 @@ func Index() templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
+ templ_7745c5c3_Err = components.IssueList(props.IssueList).Render(ctx, templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
return nil
})
templ_7745c5c3_Err = BaseLayout().Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
diff --git a/pkg/web/server/routes.go b/pkg/web/server/routes.go
index bf02c5f..94e439a 100644
--- a/pkg/web/server/routes.go
+++ b/pkg/web/server/routes.go
@@ -6,22 +6,18 @@ import (
"strings"
"time"
+ "github.com/LazyBachelor/LazyPM/pkg/web/handler"
"github.com/NYTimes/gziphandler"
"github.com/rs/cors"
)
-type Route struct {
- Pattern string
- Handeler http.Handler
-}
-
-func (s *Server) RegisterRoutes(assets embed.FS, routes []Route) http.Handler {
+func (s *Server) RegisterRoutes(assets embed.FS) http.Handler {
mux := http.NewServeMux()
s.handleAssets(mux, assets)
- for _, route := range routes {
- mux.Handle(route.Pattern, route.Handeler)
+ for _, route := range handler.GetRoutes(s.Services) {
+ mux.Handle(route.Pattern, route.Handler)
}
handler := cors.Default().Handler(mux)
diff --git a/pkg/web/server/server.go b/pkg/web/server/server.go
index b473ca9..9a5553b 100644
--- a/pkg/web/server/server.go
+++ b/pkg/web/server/server.go
@@ -1,16 +1,16 @@
package server
import (
- "github.com/LazyBachelor/LazyPM/internal/service"
"embed"
"net/http"
"time"
+
+ "github.com/LazyBachelor/LazyPM/internal/service"
)
type Server struct {
Address string
Assets embed.FS
- Routes []Route
Services *service.Services
}
@@ -20,9 +20,11 @@ func NewServer(props Server) *http.Server {
props.Address = "localhost:8080"
}
+ handler := props.RegisterRoutes(props.Assets)
+
return &http.Server{
Addr: props.Address,
- Handler: props.RegisterRoutes(props.Assets, props.Routes),
+ Handler: handler,
IdleTimeout: time.Minute,
ReadTimeout: time.Second * 10,
WriteTimeout: time.Second * 10,
diff --git a/pkg/web/web.go b/pkg/web/web.go
index b62360d..0670da8 100644
--- a/pkg/web/web.go
+++ b/pkg/web/web.go
@@ -1,15 +1,12 @@
package web
import (
- "github.com/LazyBachelor/LazyPM/internal/service"
- "github.com/LazyBachelor/LazyPM/pkg/web/handler"
- "github.com/LazyBachelor/LazyPM/pkg/web/routes"
- "github.com/LazyBachelor/LazyPM/pkg/web/server"
"context"
"embed"
"fmt"
- "github.com/a-h/templ"
+ "github.com/LazyBachelor/LazyPM/internal/service"
+ "github.com/LazyBachelor/LazyPM/pkg/web/server"
)
type WebConfig = service.Config
@@ -25,16 +22,10 @@ func Run(ctx context.Context, config WebConfig) error {
defer cleanup()
- handler := handler.NewIssuesHandler(svc)
-
server := server.NewServer(server.Server{
Address: config.WebAddress,
Assets: assets,
Services: svc,
- Routes: []server.Route{
- {Pattern: "/", Handeler: templ.Handler(routes.Index())},
- {Pattern: "/issues", Handeler: handler.HandleGetAllIssues()},
- },
})
fmt.Printf("Starting web server on %s...\n", config.WebAddress)