refactor: extract changePinModel into its own sub-model
The Change PIN screen was the only screen with its state (pinInput, pinStage, pinMessage) stored directly on the top-level model. Extract it into a changePinModel in screen_changepin.go to match the pattern used by all other screens. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -43,9 +43,7 @@ type model struct {
|
|||||||
history historyModel
|
history historyModel
|
||||||
messages messagesModel
|
messages messagesModel
|
||||||
admin adminModel
|
admin adminModel
|
||||||
pinInput string
|
changePin changePinModel
|
||||||
pinStage int // 0=old, 1=new, 2=confirm, 3=done
|
|
||||||
pinMessage string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func newModel(sess *shell.SessionContext, bankName, terminalID, region string) *model {
|
func newModel(sess *shell.SessionContext, bankName, terminalID, region string) *model {
|
||||||
@@ -130,7 +128,7 @@ func (m *model) View() string {
|
|||||||
case screenMessages:
|
case screenMessages:
|
||||||
content = m.messages.View()
|
content = m.messages.View()
|
||||||
case screenChangePin:
|
case screenChangePin:
|
||||||
content = m.viewChangePin()
|
content = m.changePin.View()
|
||||||
case screenAdmin:
|
case screenAdmin:
|
||||||
content = m.admin.View()
|
content = m.admin.View()
|
||||||
}
|
}
|
||||||
@@ -182,9 +180,7 @@ func (m *model) updateMenu(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
return m, tea.Batch(tea.ClearScreen, logAction(m.sess, "MENU 5", "SECURE MESSAGES"))
|
return m, tea.Batch(tea.ClearScreen, logAction(m.sess, "MENU 5", "SECURE MESSAGES"))
|
||||||
case "6":
|
case "6":
|
||||||
m.screen = screenChangePin
|
m.screen = screenChangePin
|
||||||
m.pinInput = ""
|
m.changePin = newChangePinModel()
|
||||||
m.pinStage = 0
|
|
||||||
m.pinMessage = ""
|
|
||||||
return m, tea.Batch(tea.ClearScreen, logAction(m.sess, "MENU 6", "CHANGE PIN"))
|
return m, tea.Batch(tea.ClearScreen, logAction(m.sess, "MENU 6", "CHANGE PIN"))
|
||||||
case "7":
|
case "7":
|
||||||
m.quitting = true
|
m.quitting = true
|
||||||
@@ -278,95 +274,19 @@ func (m *model) updateMessages(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *model) updateChangePin(msg tea.Msg) (tea.Model, tea.Cmd) {
|
func (m *model) updateChangePin(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
keyMsg, ok := msg.(tea.KeyMsg)
|
prevStage := m.changePin.stage
|
||||||
if !ok {
|
var cmd tea.Cmd
|
||||||
return m, nil
|
m.changePin, cmd = m.changePin.Update(msg)
|
||||||
|
|
||||||
|
// Log successful PIN change.
|
||||||
|
if m.changePin.stage == 3 && prevStage != 3 {
|
||||||
|
cmd = tea.Batch(cmd, logAction(m.sess, "CHANGE PIN", "PIN CHANGED SUCCESSFULLY"))
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.pinStage == 3 {
|
if m.changePin.done {
|
||||||
return m, m.goToMenu()
|
return m, tea.Batch(cmd, m.goToMenu())
|
||||||
}
|
}
|
||||||
|
return m, cmd
|
||||||
switch keyMsg.Type {
|
|
||||||
case tea.KeyEnter:
|
|
||||||
switch m.pinStage {
|
|
||||||
case 0:
|
|
||||||
if m.pinInput != "" {
|
|
||||||
m.pinStage = 1
|
|
||||||
m.pinInput = ""
|
|
||||||
}
|
|
||||||
case 1:
|
|
||||||
if len(m.pinInput) >= 4 {
|
|
||||||
m.pinMessage = m.pinInput
|
|
||||||
m.pinStage = 2
|
|
||||||
m.pinInput = ""
|
|
||||||
}
|
|
||||||
case 2:
|
|
||||||
if m.pinInput == m.pinMessage {
|
|
||||||
m.pinStage = 3
|
|
||||||
return m, logAction(m.sess, "CHANGE PIN", "PIN CHANGED SUCCESSFULLY")
|
|
||||||
}
|
|
||||||
m.pinInput = ""
|
|
||||||
m.pinMessage = ""
|
|
||||||
m.pinStage = 1
|
|
||||||
}
|
|
||||||
case tea.KeyEscape:
|
|
||||||
return m, m.goToMenu()
|
|
||||||
case tea.KeyBackspace:
|
|
||||||
if len(m.pinInput) > 0 {
|
|
||||||
m.pinInput = m.pinInput[:len(m.pinInput)-1]
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
ch := keyMsg.String()
|
|
||||||
if len(ch) == 1 && ch[0] >= 32 && ch[0] < 127 && len(m.pinInput) < 12 {
|
|
||||||
m.pinInput += ch
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return m, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *model) viewChangePin() string {
|
|
||||||
var b strings.Builder
|
|
||||||
|
|
||||||
b.WriteString("\n")
|
|
||||||
b.WriteString(centerText("CHANGE PIN"))
|
|
||||||
b.WriteString("\n\n")
|
|
||||||
b.WriteString(thinDivider())
|
|
||||||
b.WriteString("\n\n")
|
|
||||||
|
|
||||||
if m.pinStage == 3 {
|
|
||||||
b.WriteString(titleStyle.Render(" PIN CHANGED SUCCESSFULLY"))
|
|
||||||
b.WriteString("\n\n")
|
|
||||||
b.WriteString(baseStyle.Render(" YOUR NEW PIN IS NOW ACTIVE."))
|
|
||||||
b.WriteString("\n")
|
|
||||||
b.WriteString(baseStyle.Render(" PLEASE USE YOUR NEW PIN FOR ALL FUTURE TRANSACTIONS."))
|
|
||||||
b.WriteString("\n\n")
|
|
||||||
b.WriteString(dimStyle.Render(" PRESS ANY KEY TO RETURN TO MAIN MENU"))
|
|
||||||
} else {
|
|
||||||
prompts := []string{" CURRENT PIN: ", " NEW PIN: ", " CONFIRM PIN: "}
|
|
||||||
for i := 0; i < m.pinStage; i++ {
|
|
||||||
b.WriteString(baseStyle.Render(prompts[i]))
|
|
||||||
b.WriteString(baseStyle.Render(strings.Repeat("*", 4)))
|
|
||||||
b.WriteString("\n")
|
|
||||||
}
|
|
||||||
if m.pinStage < 3 {
|
|
||||||
b.WriteString(titleStyle.Render(prompts[m.pinStage]))
|
|
||||||
masked := strings.Repeat("*", len(m.pinInput))
|
|
||||||
b.WriteString(inputStyle.Render(masked))
|
|
||||||
b.WriteString(inputStyle.Render("_"))
|
|
||||||
b.WriteString("\n")
|
|
||||||
}
|
|
||||||
b.WriteString("\n")
|
|
||||||
if m.pinStage == 1 {
|
|
||||||
b.WriteString(dimStyle.Render(" PIN MUST BE AT LEAST 4 CHARACTERS"))
|
|
||||||
b.WriteString("\n")
|
|
||||||
}
|
|
||||||
b.WriteString("\n")
|
|
||||||
b.WriteString(dimStyle.Render(" PRESS ESC TO RETURN TO MAIN MENU"))
|
|
||||||
}
|
|
||||||
b.WriteString("\n")
|
|
||||||
|
|
||||||
return b.String()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *model) updateAdmin(msg tea.Msg) (tea.Model, tea.Cmd) {
|
func (m *model) updateAdmin(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
|
|||||||
111
internal/shell/banking/screen_changepin.go
Normal file
111
internal/shell/banking/screen_changepin.go
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
package banking
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
|
)
|
||||||
|
|
||||||
|
type changePinModel struct {
|
||||||
|
input string
|
||||||
|
stage int // 0=old, 1=new, 2=confirm, 3=done
|
||||||
|
newPin string
|
||||||
|
done bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func newChangePinModel() changePinModel {
|
||||||
|
return changePinModel{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m changePinModel) Update(msg tea.Msg) (changePinModel, tea.Cmd) {
|
||||||
|
keyMsg, ok := msg.(tea.KeyMsg)
|
||||||
|
if !ok {
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.stage == 3 {
|
||||||
|
m.done = true
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch keyMsg.Type {
|
||||||
|
case tea.KeyEnter:
|
||||||
|
switch m.stage {
|
||||||
|
case 0:
|
||||||
|
if m.input != "" {
|
||||||
|
m.stage = 1
|
||||||
|
m.input = ""
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
if len(m.input) >= 4 {
|
||||||
|
m.newPin = m.input
|
||||||
|
m.stage = 2
|
||||||
|
m.input = ""
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
if m.input == m.newPin {
|
||||||
|
m.stage = 3
|
||||||
|
} else {
|
||||||
|
m.input = ""
|
||||||
|
m.newPin = ""
|
||||||
|
m.stage = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case tea.KeyEscape:
|
||||||
|
m.done = true
|
||||||
|
case tea.KeyBackspace:
|
||||||
|
if len(m.input) > 0 {
|
||||||
|
m.input = m.input[:len(m.input)-1]
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
ch := keyMsg.String()
|
||||||
|
if len(ch) == 1 && ch[0] >= 32 && ch[0] < 127 && len(m.input) < 12 {
|
||||||
|
m.input += ch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m changePinModel) View() string {
|
||||||
|
var b strings.Builder
|
||||||
|
|
||||||
|
b.WriteString("\n")
|
||||||
|
b.WriteString(centerText("CHANGE PIN"))
|
||||||
|
b.WriteString("\n\n")
|
||||||
|
b.WriteString(thinDivider())
|
||||||
|
b.WriteString("\n\n")
|
||||||
|
|
||||||
|
if m.stage == 3 {
|
||||||
|
b.WriteString(titleStyle.Render(" PIN CHANGED SUCCESSFULLY"))
|
||||||
|
b.WriteString("\n\n")
|
||||||
|
b.WriteString(baseStyle.Render(" YOUR NEW PIN IS NOW ACTIVE."))
|
||||||
|
b.WriteString("\n")
|
||||||
|
b.WriteString(baseStyle.Render(" PLEASE USE YOUR NEW PIN FOR ALL FUTURE TRANSACTIONS."))
|
||||||
|
b.WriteString("\n\n")
|
||||||
|
b.WriteString(dimStyle.Render(" PRESS ANY KEY TO RETURN TO MAIN MENU"))
|
||||||
|
} else {
|
||||||
|
prompts := []string{" CURRENT PIN: ", " NEW PIN: ", " CONFIRM PIN: "}
|
||||||
|
for i := 0; i < m.stage; i++ {
|
||||||
|
b.WriteString(baseStyle.Render(prompts[i]))
|
||||||
|
b.WriteString(baseStyle.Render(strings.Repeat("*", 4)))
|
||||||
|
b.WriteString("\n")
|
||||||
|
}
|
||||||
|
if m.stage < 3 {
|
||||||
|
b.WriteString(titleStyle.Render(prompts[m.stage]))
|
||||||
|
masked := strings.Repeat("*", len(m.input))
|
||||||
|
b.WriteString(inputStyle.Render(masked))
|
||||||
|
b.WriteString(inputStyle.Render("_"))
|
||||||
|
b.WriteString("\n")
|
||||||
|
}
|
||||||
|
b.WriteString("\n")
|
||||||
|
if m.stage == 1 {
|
||||||
|
b.WriteString(dimStyle.Render(" PIN MUST BE AT LEAST 4 CHARACTERS"))
|
||||||
|
b.WriteString("\n")
|
||||||
|
}
|
||||||
|
b.WriteString("\n")
|
||||||
|
b.WriteString(dimStyle.Render(" PRESS ESC TO RETURN TO MAIN MENU"))
|
||||||
|
}
|
||||||
|
b.WriteString("\n")
|
||||||
|
|
||||||
|
return b.String()
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user