Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(examples): Credit Card Example Now Displays User Input Errors #660

Closed
wants to merge 8 commits into from
74 changes: 66 additions & 8 deletions examples/credit-card-form/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,19 @@ const (
cvv
)

var (
submitting bool
)

const (
hotPink = lipgloss.Color("#FF06B7")
darkGray = lipgloss.Color("#767676")
errorRed = lipgloss.Color("#FF2222")
)

var (
inputStyle = lipgloss.NewStyle().Foreground(hotPink)
errorStyle = lipgloss.NewStyle().Foreground(errorRed)
continueStyle = lipgloss.NewStyle().Foreground(darkGray)
)

Expand All @@ -46,11 +52,22 @@ type model struct {
}

// Validator functions to ensure valid input
// Note: Please don't mix runtime errors with your users' errors
func ccnValidator(s string) error {
// Credit Card Number should a string less than 20 digits
// It should include 16 integers and 3 spaces

if len(s) == 0 {
if submitting {
return fmt.Errorf("CCN cannot be blank")
}
return nil
}

// Since typing past 19 is intuitively disabled, we don't *really* need a msg
// This is brings ccnValidator in line with the other validators
if len(s) > 16+3 {
return fmt.Errorf("CCN is too long")
return fmt.Errorf("")
}

// The last digit should be a number unless it is a multiple of 4 in which
Expand All @@ -59,7 +76,7 @@ func ccnValidator(s string) error {
return fmt.Errorf("CCN must separate groups with spaces")
}
if len(s)%5 != 0 && (s[len(s)-1] < '0' || s[len(s)-1] > '9') {
return fmt.Errorf("CCN is invalid")
return fmt.Errorf("CCN must be numbers seperated by spaces")
}

// The remaining digits should be integers
Expand All @@ -72,26 +89,46 @@ func ccnValidator(s string) error {
func expValidator(s string) error {
// The 3 character should be a slash (/)
// The rest thould be numbers
if len(s) == 0 {
if submitting {
return fmt.Errorf("EXP cannot be blank")
}
return nil
}

if len(s) >= 2 && s[1] == '/' {
return fmt.Errorf("EXP must be two, two-digit numbers seperated by a slash (/)")
}

e := strings.ReplaceAll(s, "/", "")
_, err := strconv.ParseInt(e, 10, 64)
if err != nil {
return fmt.Errorf("EXP is invalid")
return fmt.Errorf("EXP must be two, two-digit numbers seperated by a slash (/)")
}

// There should be only one slash and it should be in the 2nd index (3rd character)
if len(s) >= 3 && (strings.Index(s, "/") != 2 || strings.LastIndex(s, "/") != 2) {
return fmt.Errorf("EXP is invalid")
return fmt.Errorf("EXP month and year must be separated by a /")
}

return nil
}

func cvvValidator(s string) error {
// The CVV should be a number of 3 digits
// Since the input will already ensure that the CVV is a string of length 3,
if len(s) == 0 {
if submitting {
return fmt.Errorf("CVV cannot be blank")
}
return nil

}
// All we need to do is check that it is a number
_, err := strconv.ParseInt(s, 10, 64)
return err
if err != nil {
return fmt.Errorf("CVV must be a number")
}
return nil
}

func initialModel() model {
Expand Down Expand Up @@ -134,11 +171,13 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {

switch msg := msg.(type) {
case tea.KeyMsg:
submitting = false
switch msg.Type {
case tea.KeyEnter:
if m.focused == len(m.inputs)-1 {
return m, tea.Quit
return m, nil
}
submitting = true
m.nextInput()
case tea.KeyCtrlC, tea.KeyEsc:
return m, tea.Quit
Expand All @@ -165,6 +204,24 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}

func (m model) View() string {
var err error
errorString := ""
err = m.inputs[m.focused].Err
if err == nil {
for i, input := range m.inputs {
if i > m.focused {
break
}
if input.Err != nil {
err = input.Err
break
}
}
}
if err != nil {
errorString = err.Error()
}

return fmt.Sprintf(
` Total: $21.50:

Expand All @@ -173,7 +230,7 @@ func (m model) View() string {

%s %s
%s %s

%s
%s
`,
inputStyle.Width(30).Render("Card Number"),
Expand All @@ -182,6 +239,7 @@ func (m model) View() string {
inputStyle.Width(6).Render("CVV"),
m.inputs[exp].View(),
m.inputs[cvv].View(),
errorStyle.Render(errorString),
continueStyle.Render("Continue ->"),
) + "\n"
}
Expand Down