From 1ac9dc12ff55fa894c8322f0d2eb4623f90ace4b Mon Sep 17 00:00:00 2001
From: jeronimoalbi <jeronimo.albi@gmail.com>
Date: Fri, 14 Mar 2025 18:02:01 +0100
Subject: [PATCH 1/2] feat: initial render support to `commondao` realm

---
 .../gno.land/r/gnoland/commondao/render.gno   | 86 ++++++++++++++++++-
 1 file changed, 83 insertions(+), 3 deletions(-)

diff --git a/examples/gno.land/r/gnoland/commondao/render.gno b/examples/gno.land/r/gnoland/commondao/render.gno
index 74448939671..4292ac1fca0 100644
--- a/examples/gno.land/r/gnoland/commondao/render.gno
+++ b/examples/gno.land/r/gnoland/commondao/render.gno
@@ -1,6 +1,86 @@
 package commondao
 
-func Render(string) string {
-	// TODO: Implement Render support
-	return ""
+import (
+	"std"
+	"strconv"
+
+	"gno.land/p/demo/mux"
+	"gno.land/p/gnoland/commondao"
+)
+
+func Render(path string) string {
+	router := mux.NewRouter()
+	router.HandleFunc("", renderHome)
+	router.HandleFunc("{daoID}", renderDAO)
+	return router.Render(path)
+}
+
+func renderHome(res *mux.ResponseWriter, _ *mux.Request) {
+	res.Write("# Common DAO\n")
+
+	// TODO: Render a header text for users
+	// TODO: Render generic links to vote or execute proposals
+}
+
+func renderDAO(res *mux.ResponseWriter, req *mux.Request) {
+	rawID := req.GetVar("daoID")
+	daoID, err := strconv.ParseUint(rawID, 10, 64)
+	if err != nil {
+		res.Write("Value is an invalid DAO ID")
+		return
+	}
+
+	dao := getDAO(daoID)
+	if dao == nil {
+		res.Write("DAO not found")
+		return
+	}
+
+	res.Write("# ")
+	res.Write(dao.Name())
+	res.Write("\n")
+
+	if s := dao.Description(); s != "" {
+		res.Write(s)
+		res.Write("\n\n")
+	}
+
+	// TODO: Add link to DAO's proposals view
+
+	res.Write("## Members\n")
+
+	members := dao.Members()
+	if members.Size() == 0 {
+		res.Write("The DAO has no members\n\n")
+	} else {
+		// TODO: Allow members pagination
+		members.IterateByOffset(0, members.Size(), func(addr std.Address) bool {
+			res.Write("- ")
+			res.Write(addr.String())
+			res.Write("\n")
+			return false
+		})
+	}
+
+	if dao.Children().Len() > 0 {
+		res.Write("## Tree\n")
+		renderTree(res, dao, "")
+	}
+}
+
+func renderTree(res *mux.ResponseWriter, dao *commondao.CommonDAO, indent string) {
+	// TODO: Use bold and no DAO link for the current DAO (requires req.Query support)
+	// TODO: Render a link to the DAO page
+	res.Write(indent)
+	res.Write("- ")
+	res.Write(dao.Name())
+	res.Write("\n")
+
+	indent += "  "
+	dao.Children().ForEach(func(_ int, v any) bool {
+		if subDAO, ok := v.(*commondao.CommonDAO); ok {
+			renderTree(res, subDAO, indent)
+		}
+		return false
+	})
 }

From 22e0b60dcf81b2accb84877faa7ea371e748cd3d Mon Sep 17 00:00:00 2001
From: jeronimoalbi <jeronimo.albi@gmail.com>
Date: Fri, 14 Mar 2025 18:24:32 +0100
Subject: [PATCH 2/2] feat: add members pagination to DAO view

---
 .../gno.land/r/gnoland/commondao/render.gno   | 54 +++++++++++++------
 1 file changed, 39 insertions(+), 15 deletions(-)

diff --git a/examples/gno.land/r/gnoland/commondao/render.gno b/examples/gno.land/r/gnoland/commondao/render.gno
index 4292ac1fca0..11d2e54e1b1 100644
--- a/examples/gno.land/r/gnoland/commondao/render.gno
+++ b/examples/gno.land/r/gnoland/commondao/render.gno
@@ -6,9 +6,13 @@ import (
 
 	"gno.land/p/demo/mux"
 	"gno.land/p/gnoland/commondao"
+	"gno.land/p/jeronimoalbi/pager"
 )
 
 func Render(path string) string {
+	// TODO: Add view to list proposals of a DAO
+	// TODO: Add view to render a single proposal (allow/disallow must be configurable)
+	// TODO: Add view to render a SubDAO (use query "?path=...")
 	router := mux.NewRouter()
 	router.HandleFunc("", renderHome)
 	router.HandleFunc("{daoID}", renderDAO)
@@ -16,13 +20,13 @@ func Render(path string) string {
 }
 
 func renderHome(res *mux.ResponseWriter, _ *mux.Request) {
-	res.Write("# Common DAO\n")
-
 	// TODO: Render a header text for users
 	// TODO: Render generic links to vote or execute proposals
+	res.Write("# Common DAO\n")
 }
 
 func renderDAO(res *mux.ResponseWriter, req *mux.Request) {
+	// TODO: Support config option to allow/disallow rendering a DAO
 	rawID := req.GetVar("daoID")
 	daoID, err := strconv.ParseUint(rawID, 10, 64)
 	if err != nil {
@@ -45,27 +49,47 @@ func renderDAO(res *mux.ResponseWriter, req *mux.Request) {
 		res.Write("\n\n")
 	}
 
-	// TODO: Add link to DAO's proposals view
+	// TODO: Add link to DAO's proposals list view
 
 	res.Write("## Members\n")
+	renderMembers(res, dao, req.RawPath)
+
+	if dao.Children().Len() > 0 {
+		res.Write("## Tree\n")
+		renderTree(res, dao, "")
+	}
+
+	// TODO: List latest 10 proposals
+}
 
+func renderMembers(res *mux.ResponseWriter, dao *commondao.CommonDAO, path string) {
 	members := dao.Members()
-	if members.Size() == 0 {
+	membersCount := members.Size()
+	if membersCount == 0 {
 		res.Write("The DAO has no members\n\n")
-	} else {
-		// TODO: Allow members pagination
-		members.IterateByOffset(0, members.Size(), func(addr std.Address) bool {
-			res.Write("- ")
-			res.Write(addr.String())
-			res.Write("\n")
-			return false
-		})
+		return
 	}
 
-	if dao.Children().Len() > 0 {
-		res.Write("## Tree\n")
-		renderTree(res, dao, "")
+	p, err := pager.New(path, membersCount, pager.WithPageQueryParam("members"), pager.WithPageSize(10))
+	if err != nil {
+		res.Write(err.Error())
+		return
 	}
+
+	members.IterateByOffset(p.Offset(), p.PageSize(), func(addr std.Address) bool {
+		res.Write("- ")
+		res.Write(addr.String())
+		res.Write("\n")
+		return false
+	})
+
+	if p.HasPages() {
+		res.Write("\n")
+		res.Write(pager.Picker(p))
+		res.Write("\n")
+	}
+
+	res.Write("\n")
 }
 
 func renderTree(res *mux.ResponseWriter, dao *commondao.CommonDAO, indent string) {