/ associate.go
associate.go
1 package main 2 3 import ( 4 "encoding/json" 5 "log" 6 "slices" 7 8 "github.com/maxence-charriere/go-app/v10/pkg/app" 9 shell "github.com/stateless-minds/go-ipfs-api" 10 ) 11 12 // supplier 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 associate struct { 16 app.Compo 17 sh *shell.Shell 18 loggedIn bool 19 userID string 20 associateName string 21 newAssociateName string 22 associates []string 23 currentUser User 24 } 25 26 func (a *associate) OnMount(ctx app.Context) { 27 sh := shell.NewShell("localhost:5001") 28 a.sh = sh 29 30 ctx.GetState("loggedIn", &a.loggedIn) 31 if !a.loggedIn { 32 ctx.Navigate("/auth") 33 } 34 35 ctx.GetState("userID", &a.userID) 36 37 ctx.GetState("associateName", &a.associateName) 38 39 ctx.GetState("currentUser", &a.currentUser) 40 41 a.getAssociates() 42 } 43 44 func (a *associate) getAssociates() { 45 46 associateNames := []string{} 47 48 var descriptor map[string]map[string][]string 49 50 err := json.Unmarshal(a.currentUser.Descriptor, &descriptor) 51 if err != nil { 52 log.Fatal(err) 53 } 54 55 for name := range descriptor { 56 if name != a.associateName { 57 associateNames = append(associateNames, name) 58 } 59 } 60 a.associates = associateNames 61 } 62 63 func (a *associate) addAssociate(ctx app.Context, e app.Event) { 64 e.PreventDefault() 65 valid := app.Window().GetElementByID("associate-form").Call("reportValidity").Bool() 66 if valid { 67 ctx.SetState("newAssociateName", a.newAssociateName).Persist() 68 69 ctx.Notifications().New(app.Notification{ 70 Title: "Action required", 71 Body: "Associate " + a.newAssociateName + " needs to sit in front of the web camera. Click this notification when ready.", 72 Path: "auth", 73 }) 74 } 75 } 76 77 func (a *associate) removeAssociate(ctx app.Context, e app.Event) { 78 e.PreventDefault() 79 name := ctx.JSSrc().Get("value").String() 80 81 var descriptor map[string]map[string][]string 82 83 err := json.Unmarshal(a.currentUser.Descriptor, &descriptor) 84 if err != nil { 85 log.Fatal(err) 86 } 87 88 for associate := range descriptor { 89 if name == associate { 90 a.updateUser(ctx, name) 91 } 92 } 93 94 } 95 96 func (a *associate) updateUser(ctx app.Context, name string) { 97 ctx.Async(func() { 98 user := a.currentUser 99 100 var descriptor map[string]map[string][]string 101 102 err := json.Unmarshal(a.currentUser.Descriptor, &descriptor) 103 if err != nil { 104 log.Fatal(err) 105 } 106 107 delete(descriptor, name) 108 userJSON, err := json.Marshal(user) 109 if err != nil { 110 log.Fatal(err) 111 } 112 113 err = a.sh.OrbitDocsPut(dbUser, userJSON) 114 if err != nil { 115 log.Fatal(err) 116 } 117 118 ctx.Dispatch(func(ctx app.Context) { 119 delete(descriptor, name) 120 for i, associate := range a.associates { 121 if associate == name { 122 a.associates = slices.Delete(a.associates, i, i+1) 123 } 124 } 125 ctx.Notifications().New(app.Notification{ 126 Title: "Success", 127 Body: "Associate " + a.newAssociateName + " has been deleted.", 128 }) 129 }) 130 }) 131 } 132 133 // The Render method is where the component appearance is defined. Here, a 134 // payment form is displayed. 135 func (a *associate) Render() app.UI { 136 return app.Div().Class("container").Body( 137 app.Div().Class("mobile").Body( 138 app.Div().Class("header").Body( 139 newNav(), 140 app.Div().Class("header-summary").Body( 141 app.Span().Class("logo").Text("cyber-gubi"), 142 app.Div().Class("summary-text").Body( 143 app.Span().Text("Associates"), 144 ), 145 ), 146 ), 147 app.Div().ID("content").Body( 148 app.Div().Class("card").Body( 149 app.Div().Class("upper-row").Body( 150 app.Div().Class("card-item").Body( 151 app.Span().Class("span-header").Text("Add Associate"), 152 app.Form().ID("associate-form").Body( 153 app.Div().ID("associate").Body( 154 app.Input().ID("associate-name").Type("text").Name("associate-name").Placeholder("Associate name").Required(true).OnChange(a.ValueTo(&a.newAssociateName)), 155 ), 156 app.Div().Class("drawer drawer-pay").Body( 157 app.Div().Class("menu-btn").Body( 158 app.Button().Class("submit").Type("submit").Text("Submit").OnClick(a.addAssociate), 159 ), 160 ), 161 ), 162 ), 163 ), 164 ), 165 app.Div().Class("list associates").Body( 166 app.Span().Class("a-desc").Text("Manage Associates"), 167 app.If(len(a.associates) == 0, func() app.UI { 168 return app.Div().Class("list-item").Body( 169 app.Span().Class("empty").Text("No associates yet"), 170 ).Style("pointer-events", "none") 171 }), 172 app.Range(a.associates).Slice(func(i int) app.UI { 173 return app.Div().Class("list-item").Body( 174 app.Div().Class("a-details").Body( 175 app.Div().Class("a-title").Body( 176 app.Span().Text(a.associates[i]), 177 ), 178 ), 179 app.Div().Class("a-price").Body( 180 app.Div().Class("menu-btn menu-assoc").Body( 181 app.Button().Class("submit submit-sub").Type("submit").Text("Remove").Value(a.associates[i]).OnClick(a.removeAssociate), 182 ), 183 ), 184 ) 185 }), 186 ), 187 ), 188 ), 189 ) 190 }