/ client.go
client.go
  1  package main
  2  
  3  import (
  4  	"encoding/json"
  5  	"log"
  6  	"strconv"
  7  
  8  	"github.com/maxence-charriere/go-app/v10/pkg/app"
  9  	shell "github.com/stateless-minds/go-ipfs-api"
 10  )
 11  
 12  // client is a component that holds cyber-gubi. A component is a
 13  // customizable, independent, and reusable UI element. It is created by
 14  // embedding app.Compo into a struct.
 15  type client struct {
 16  	app.Compo
 17  	sh            *shell.Shell
 18  	loggedIn      bool
 19  	businessName  string
 20  	wallet        Wallet
 21  	plan          Plan
 22  	subscriptions []Subscription
 23  	totalIncome   int
 24  	observer      app.Value
 25  	callback      app.Func
 26  	lastIndex     int
 27  	indexStep     int
 28  }
 29  
 30  func (c *client) OnMount(ctx app.Context) {
 31  	sh := shell.NewShell("localhost:5001")
 32  	c.sh = sh
 33  	c.indexStep = 99
 34  
 35  	ctx.GetState("loggedIn", &c.loggedIn)
 36  	if !c.loggedIn {
 37  		ctx.Navigate("/auth")
 38  	}
 39  
 40  	c.callback = app.FuncOf(func(this app.Value, args []app.Value) interface{} {
 41  		entries := args[0]
 42  		for i := 0; i < entries.Length(); i++ {
 43  			entry := entries.Index(i)
 44  			if entry.Get("isIntersecting").Bool() {
 45  				// Element is visible - do something
 46  				c.getSubscriptions(ctx)
 47  			}
 48  		}
 49  		return nil
 50  	})
 51  
 52  	// Select the root element by class name
 53  	rootElement := app.Window().Get("document").Call("querySelector", ".list")
 54  
 55  	options := map[string]interface{}{
 56  		"root":       rootElement,
 57  		"rootMargin": "0px",
 58  		"threshold":  1,
 59  	}
 60  
 61  	observerConstructor := app.Window().Get("IntersectionObserver")
 62  	c.observer = observerConstructor.New(c.callback, options)
 63  
 64  	ctx.GetState("businessName", &c.businessName)
 65  
 66  	ctx.GetState("balance", &c.wallet)
 67  
 68  	ctx.GetState("plan", &c.plan)
 69  
 70  	c.getSubscriptions(ctx)
 71  }
 72  
 73  func (c *client) OnUpdate(ctx app.Context) {
 74  	// Wrap your observation logic in a Go function
 75  	callback := func() {
 76  		target := app.Window().GetElementByID("last-item")
 77  		if !target.IsNull() && !target.IsUndefined() {
 78  			c.observer.Call("disconnect")
 79  			c.observer.Call("observe", target)
 80  		}
 81  	}
 82  
 83  	var goFunc app.Func
 84  
 85  	// Wrap callback as JS function
 86  	goFunc = app.FuncOf(func(this app.Value, args []app.Value) interface{} {
 87  		callback()
 88  		goFunc.Release() // release after call to avoid leaks
 89  		return nil
 90  	})
 91  
 92  	// Call JS setTimeout with delay 10ms
 93  	app.Window().Call("goAppSetTimeout", goFunc, 100)
 94  }
 95  
 96  func (c *client) OnDismount(ctx app.Context) {
 97  	c.observer.Call("disconnect")
 98  	c.callback.Release()
 99  }
100  
101  func (c *client) getSubscriptions(ctx app.Context) {
102  	ctx.Async(func() {
103  		rangeStart := strconv.Itoa(c.lastIndex)
104  		rangeEnd := strconv.Itoa(c.lastIndex + c.indexStep)
105  		subs, err := c.sh.OrbitDocsQuery(dbSubscription, "plan_id", c.plan.ID+",range="+rangeStart+"-"+rangeEnd)
106  		if err != nil {
107  			log.Fatal(err)
108  		}
109  
110  		subscriptions := []Subscription{}
111  		var totalIncome int
112  
113  		if len(subs) != 0 {
114  			err = json.Unmarshal(subs, &subscriptions) // Unmarshal the byte slice directly
115  			if err != nil {
116  				log.Fatal(err)
117  			}
118  
119  			for _, sub := range subscriptions {
120  				totalIncome += sub.Price
121  			}
122  		} else {
123  			c.OnDismount(ctx)
124  		}
125  
126  		ctx.Dispatch(func(ctx app.Context) {
127  			c.subscriptions = append(c.subscriptions, subscriptions...)
128  			c.totalIncome = totalIncome
129  			c.lastIndex = c.lastIndex + 1 + c.indexStep
130  			c.OnUpdate(ctx)
131  		})
132  	})
133  }
134  
135  // The Render method is where the component appearance is defined. Here, a
136  // client is displayed.
137  func (c *client) Render() app.UI {
138  	return app.Div().Class("container").Body(
139  		app.Div().Class("mobile").Body(
140  			app.Div().Class("header").Body(
141  				newNav(),
142  				app.Div().Class("header-summary").Body(
143  					app.Span().Class("logo").Text("cyber-gubi"),
144  					app.Div().Class("summary-text").Body(
145  						app.Span().Text("Recurring"),
146  					),
147  					app.Div().Class("summary-balance").Body(
148  						app.Span().Text(strconv.Itoa(c.totalIncome/100)+" GUBI"),
149  					),
150  				),
151  			),
152  			app.Div().ID("content").Body(
153  				app.Div().Class("card").Body(
154  					app.Div().Class("upper-row single").Body(
155  						app.Div().Class("card-item").Body(
156  							app.Span().Class("span-header-sub").Text("Clients"),
157  						),
158  					),
159  				),
160  				app.Div().Class("list").Body(
161  					app.If(len(c.subscriptions) == 0, func() app.UI {
162  						return app.Div().Class("list-item").Body(
163  							app.Span().Class("empty").Text("No subscriptions yet"),
164  						).Style("pointer-events", "none")
165  					}),
166  					app.Range(c.subscriptions).Slice(func(i int) app.UI {
167  						return app.If(i == len(c.subscriptions)-1 && len(c.subscriptions)%5 == 0, func() app.UI {
168  							return app.Div().ID("last-item").Class("list-item").Body(
169  								app.Div().Class("s-details").Body(
170  									app.Div().Class("c-title").Body(
171  										app.Span().Text("User ID: "+c.subscriptions[i].UserID),
172  									),
173  									app.Div().Class("s-time").Body(
174  										app.Span().Text(c.subscriptions[i].StartDate.Format("2006-01-02 15:04")),
175  										app.Span().Text(c.subscriptions[i].EndDate.Format("2006-01-02 15:04")),
176  									),
177  								),
178  								app.Div().Class("s-price").Body(
179  									app.Span().Text(strconv.Itoa(c.subscriptions[i].Price/100)+" GUBI"),
180  								),
181  							)
182  						}).Else(func() app.UI {
183  							return app.Div().Class("list-item").Body(
184  								app.Div().Class("s-details").Body(
185  									app.Div().Class("c-title").Body(
186  										app.Span().Text("User ID: "+c.subscriptions[i].UserID),
187  									),
188  									app.Div().Class("s-time").Body(
189  										app.Span().Text(c.subscriptions[i].StartDate.Format("2006-01-02 15:04")),
190  										app.Span().Text(c.subscriptions[i].EndDate.Format("2006-01-02 15:04")),
191  									),
192  								),
193  								app.Div().Class("s-price").Body(
194  									app.Span().Text(strconv.Itoa(c.subscriptions[i].Price/100)+" GUBI"),
195  								),
196  							)
197  						})
198  					}),
199  				),
200  			),
201  		),
202  	)
203  }