Files
wg-admin/internal/tui/components/delete-confirm.go

174 lines
4.5 KiB
Go

package components
import (
"fmt"
"github.com/calmcacil/wg-admin/internal/tui/theme"
"github.com/charmbracelet/bubbles/textinput"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
)
// DeleteConfirmModel represents a deletion confirmation modal with name verification
type DeleteConfirmModel struct {
clientName string
input textinput.Model
Visible bool
Width int
Height int
showErrorMessage bool
}
// Local styles for modal
var (
modalBaseStyle = lipgloss.NewStyle().Border(lipgloss.RoundedBorder()).BorderForeground(lipgloss.Color("196")).Background(lipgloss.Color("235"))
modalTitleStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("226")).Bold(true)
modalMessageStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("255"))
modalHelpStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("241"))
)
// NewDeleteConfirm creates a new deletion confirmation modal
func NewDeleteConfirm(clientName string, width, height int) *DeleteConfirmModel {
ti := textinput.New()
ti.Placeholder = "Type client name to confirm"
ti.Focus()
ti.CharLimit = 100
ti.Width = 40
return &DeleteConfirmModel{
clientName: clientName,
input: ti,
Visible: true,
Width: width,
Height: height,
showErrorMessage: false,
}
}
// Init initializes the deletion confirmation modal
func (m *DeleteConfirmModel) Init() tea.Cmd {
return textinput.Blink
}
// Update handles messages for the deletion confirmation modal
func (m *DeleteConfirmModel) Update(msg tea.Msg) (*DeleteConfirmModel, tea.Cmd) {
var cmd tea.Cmd
switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.String() {
case "esc":
m.Visible = false
return m, nil
case "enter":
if m.input.Value() == m.clientName {
m.Visible = false
return m, nil
}
m.showErrorMessage = true
return m, nil
}
}
m.input, cmd = m.input.Update(msg)
return m, cmd
}
// View renders the deletion confirmation modal
func (m *DeleteConfirmModel) View() string {
if !m.Visible {
return ""
}
// Check if input matches client name
matches := m.input.Value() == m.clientName
// Build warning section
warningText := theme.StyleError.Bold(true).MarginTop(1).Render(
fmt.Sprintf("⚠️ This will permanently delete client '%s'", m.clientName),
)
// Build message section
messageText := modalMessageStyle.Width(60).Render(
fmt.Sprintf("This action cannot be undone. Please type the client name to confirm deletion."),
)
// Build input section
inputSection := lipgloss.JoinVertical(
lipgloss.Left,
"",
theme.StyleValue.Width(60).Render("Client name:"),
m.input.View(),
)
// Build status section
var statusText string
if matches {
statusText = theme.StyleSuccess.Bold(true).MarginTop(1).Render("✓ Client name matches. Press Enter to confirm deletion.")
} else if m.showErrorMessage {
statusText = theme.StyleError.Bold(true).MarginTop(1).Render("✗ Client name does not match. Please try again.")
} else if m.input.Value() != "" {
statusText = modalHelpStyle.Render("Client name does not match yet...")
} else {
statusText = modalHelpStyle.Render("Type the client name to enable confirmation.")
}
// Build help section
helpText := modalHelpStyle.Render("Esc to cancel • Enter to confirm (when name matches)")
// Build modal content
content := lipgloss.JoinVertical(
lipgloss.Left,
modalTitleStyle.Render("🗑️ Delete Client"),
"",
warningText,
"",
messageText,
inputSection,
statusText,
"",
helpText,
)
// Apply modal style
modal := modalBaseStyle.Padding(1, 3).Render(content)
// Center modal on screen
modalWidth := lipgloss.Width(modal)
modalHeight := lipgloss.Height(modal)
x := (m.Width - modalWidth) / 2
if x < 0 {
x = 0
}
y := (m.Height - modalHeight) / 2
if y < 0 {
y = 0
}
return lipgloss.Place(m.Width, m.Height,
lipgloss.Left, lipgloss.Top,
modal,
lipgloss.WithWhitespaceChars(" "),
lipgloss.WithWhitespaceForeground(theme.StyleBackground),
)
}
// IsConfirmed returns true if user confirmed the deletion
func (m *DeleteConfirmModel) IsConfirmed() bool {
return !m.Visible && m.input.Value() == m.clientName
}
// IsCancelled returns true if user cancelled
func (m *DeleteConfirmModel) IsCancelled() bool {
return !m.Visible && m.input.Value() != m.clientName
}
// Reset resets the modal for reuse
func (m *DeleteConfirmModel) Reset() {
m.input.SetValue("")
m.input.Reset()
m.Visible = true
m.showErrorMessage = false
}