repos / pico

pico services mono repo
git clone https://github.com/picosh/pico.git

pico / pkg / tui
Antonio Mika  ·  2025-04-30

signup.go

  1package tui
  2
  3import (
  4	"fmt"
  5
  6	"git.sr.ht/~rockorager/vaxis"
  7	"git.sr.ht/~rockorager/vaxis/vxfw"
  8	"git.sr.ht/~rockorager/vaxis/vxfw/button"
  9	"git.sr.ht/~rockorager/vaxis/vxfw/richtext"
 10	"git.sr.ht/~rockorager/vaxis/vxfw/text"
 11	"github.com/picosh/pico/pkg/db"
 12	"github.com/picosh/pico/pkg/pssh"
 13	"github.com/picosh/utils"
 14	"golang.org/x/crypto/ssh"
 15)
 16
 17type SignupPage struct {
 18	shared *SharedModel
 19	focus  string
 20	err    error
 21
 22	input *TextInput
 23	btn   *button.Button
 24}
 25
 26func NewSignupPage(shrd *SharedModel) *SignupPage {
 27	btn := button.New("SIGNUP", func() (vxfw.Command, error) { return nil, nil })
 28	btn.Style = button.StyleSet{
 29		Default: vaxis.Style{Background: grey},
 30		Focus:   vaxis.Style{Background: oj, Foreground: black},
 31	}
 32	input := NewTextInput("signup")
 33	return &SignupPage{shared: shrd, btn: btn, input: input}
 34}
 35
 36func (m *SignupPage) Footer() []Shortcut {
 37	return []Shortcut{
 38		{Shortcut: "tab", Text: "focus"},
 39		{Shortcut: "enter", Text: "create user"},
 40	}
 41}
 42
 43func (m *SignupPage) createAccount(name string) (*db.User, error) {
 44	if name == "" {
 45		return nil, fmt.Errorf("name cannot be empty")
 46	}
 47	key := utils.KeyForKeyText(m.shared.Session.PublicKey())
 48	return m.shared.Dbpool.RegisterUser(name, key, "")
 49}
 50
 51func (m *SignupPage) CaptureEvent(ev vaxis.Event) (vxfw.Command, error) {
 52	switch msg := ev.(type) {
 53	case vaxis.Key:
 54		if msg.Matches(vaxis.KeyEnter) {
 55			user, err := m.createAccount(m.input.GetValue())
 56			if err != nil {
 57				m.err = err
 58				return vxfw.RedrawCmd{}, nil
 59			}
 60
 61			m.shared.User = user
 62
 63			pssh.SetUser(m.shared.Session, user)
 64
 65			m.shared.Logger = m.shared.Logger.With(
 66				"user", user.Name,
 67				"userId", user.ID,
 68			)
 69
 70			pssh.SetLogger(m.shared.Session, m.shared.Logger)
 71
 72			m.shared.App.PostEvent(Navigate{To: HOME})
 73		}
 74	}
 75	return nil, nil
 76}
 77
 78func (m *SignupPage) HandleEvent(ev vaxis.Event, phase vxfw.EventPhase) (vxfw.Command, error) {
 79	switch msg := ev.(type) {
 80	case PageIn:
 81		return m.input.FocusIn()
 82	case vaxis.Key:
 83		if msg.Matches(vaxis.KeyTab) {
 84			if m.focus == "button" {
 85				m.focus = "input"
 86				return m.input.FocusIn()
 87			}
 88			m.focus = "button"
 89			cmd, _ := m.input.FocusOut()
 90			return vxfw.BatchCmd([]vxfw.Command{
 91				cmd,
 92				vxfw.FocusWidgetCmd(m.btn),
 93			}), nil
 94		}
 95	}
 96
 97	return nil, nil
 98}
 99
100func (m *SignupPage) Draw(ctx vxfw.DrawContext) (vxfw.Surface, error) {
101	w := ctx.Max.Width
102	h := ctx.Max.Height
103
104	root := vxfw.NewSurface(w, h, m)
105
106	fp := ssh.FingerprintSHA256(m.shared.Session.PublicKey())
107	intro := richtext.New([]vaxis.Segment{
108		{Text: "Welcome to pico.sh's management TUI!\n\n"},
109		{Text: "By creating an account you get access to our pico services.  We have free and paid services."},
110		{Text: "  After you create an account, you can go to our docs site to get started:\n\n  "},
111		{Text: "https://pico.sh/getting-started\n\n", Style: vaxis.Style{Hyperlink: "https://pico.sh/getting-started"}},
112		{Text: fmt.Sprintf("pubkey: %s\n\n", fp), Style: vaxis.Style{Foreground: purp}},
113	})
114	introSurf, _ := intro.Draw(ctx)
115	ah := 0
116	root.AddChild(0, ah, introSurf)
117	ah += int(introSurf.Size.Height)
118
119	inpSurf, _ := m.input.Draw(vxfw.DrawContext{
120		Characters: ctx.Characters,
121		Max:        vxfw.Size{Width: ctx.Max.Width, Height: 4},
122	})
123	root.AddChild(0, ah, inpSurf)
124	ah += int(inpSurf.Size.Height)
125
126	btnSurf, _ := m.btn.Draw(vxfw.DrawContext{
127		Characters: ctx.Characters,
128		Max:        vxfw.Size{Width: 10, Height: 1},
129	})
130	root.AddChild(0, ah, btnSurf)
131	ah += int(btnSurf.Size.Height)
132
133	if m.err != nil {
134		errTxt := text.New(m.err.Error())
135		errTxt.Style = vaxis.Style{Foreground: red}
136		errSurf, _ := errTxt.Draw(ctx)
137		root.AddChild(0, ah, errSurf)
138	}
139
140	return root, nil
141}