mirror of
https://github.com/marcusDenslow/terminalShop.git
synced 2026-10-25 18:08:45 +01:00
the checkout flow was a bit wonky because it would display the same info twice which looked weird and confusing. this is now changed to only show once and update one of the pages independantly. Now added the possibility to modify card and address list in the account page and not in the checkout flow
234 lines
5.8 KiB
Go
234 lines
5.8 KiB
Go
package tui
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"terminalShop/pkg/models"
|
|
|
|
"github.com/charmbracelet/bubbles/viewport"
|
|
tea "github.com/charmbracelet/bubbletea"
|
|
"github.com/charmbracelet/lipgloss"
|
|
)
|
|
|
|
// RenderConfirmation renders the order confirmation view
|
|
func (m Model) RenderConfirmation() string {
|
|
titleStyle := m.theme.TextAccent().Bold(true).Padding(0, 0, 1, 0)
|
|
|
|
sectionStyle := m.theme.TextBody().Padding(0, 0, 1, 2)
|
|
|
|
labelStyle := m.theme.TextDim()
|
|
|
|
valueStyle := m.theme.TextAccent()
|
|
|
|
successStyle := m.theme.TextSuccess().Bold(true).Padding(1, 0)
|
|
|
|
title := titleStyle.Render("Order Confirmation")
|
|
|
|
// Shipping summary
|
|
shippingSection := ""
|
|
if m.ConfirmShipping != nil {
|
|
shippingSection = sectionStyle.Render(
|
|
labelStyle.Render("Ship to: ") +
|
|
valueStyle.Render(m.ConfirmShipping.Name) + "\n" +
|
|
labelStyle.Render(" ") +
|
|
valueStyle.Render(m.ConfirmShipping.Street) + "\n" +
|
|
labelStyle.Render(" ") +
|
|
valueStyle.Render(fmt.Sprintf("%s, %s %s, %s", m.ConfirmShipping.City, m.ConfirmShipping.State, m.ConfirmShipping.Zip, m.ConfirmShipping.Country)),
|
|
)
|
|
}
|
|
|
|
// Items summary
|
|
cartSection := ""
|
|
for _, item := range m.ConfirmItems {
|
|
line := fmt.Sprintf(" %s x%d $%.2f", item.Coffee.Name, item.Quantity, float64(item.Coffee.Price*item.Quantity)/100)
|
|
cartSection += sectionStyle.Render(line) + "\n"
|
|
}
|
|
cartSection += sectionStyle.Render(
|
|
labelStyle.Render("Shipping: ")+valueStyle.Render("$0.00"),
|
|
) + "\n"
|
|
cartSection += sectionStyle.Render(
|
|
labelStyle.Render("Total: ") + valueStyle.Render(fmt.Sprintf("$%.2f", float64(m.ConfirmTotal)/100)),
|
|
)
|
|
|
|
success := successStyle.Render("Order placed successfully!")
|
|
|
|
return lipgloss.JoinVertical(
|
|
lipgloss.Left,
|
|
title,
|
|
"",
|
|
shippingSection,
|
|
"",
|
|
cartSection,
|
|
"",
|
|
success,
|
|
)
|
|
}
|
|
|
|
func (m Model) updateConfirmViewport() Model {
|
|
headerH := lipgloss.Height(m.BuildHeader())
|
|
breadH := lipgloss.Height(m.BuildBreadcrumbs())
|
|
footerH := lipgloss.Height(m.BuildFooter())
|
|
availH := m.heightContainer - headerH - footerH - breadH
|
|
if availH < 1 {
|
|
availH = 1
|
|
}
|
|
if !m.confirmVPReady {
|
|
m.confirmVP = viewport.New(m.widthContent, availH)
|
|
m.confirmVP.KeyMap = viewport.DefaultKeyMap()
|
|
m.confirmVPReady = true
|
|
} else {
|
|
m.confirmVP.Width = m.widthContent
|
|
m.confirmVP.Height = availH
|
|
}
|
|
return m
|
|
}
|
|
|
|
func (m Model) ConfirmView() string {
|
|
if !m.confirmVPReady {
|
|
m = m.updateConfirmViewport()
|
|
}
|
|
m.confirmVP.SetContent(m.RenderConfirmation())
|
|
return lipgloss.Place(
|
|
m.widthContainer,
|
|
lipgloss.Height(m.confirmVP.View()),
|
|
lipgloss.Center, lipgloss.Center,
|
|
m.confirmVP.View(),
|
|
)
|
|
}
|
|
|
|
func (m Model) ConfirmUpdate(msg tea.Msg) (Model, tea.Cmd) {
|
|
var cmd tea.Cmd
|
|
if m.confirmVPReady {
|
|
m.confirmVP, cmd = m.confirmVP.Update(msg)
|
|
}
|
|
|
|
keyMsg, ok := msg.(tea.KeyMsg)
|
|
if !ok {
|
|
return m, cmd
|
|
}
|
|
|
|
if keyMsg.String() != "esc" && keyMsg.String() != "s" {
|
|
return m, cmd
|
|
}
|
|
|
|
m = m.SwitchPage(shopPage)
|
|
m.CheckingOut = false
|
|
m.ConfirmTotal = 0
|
|
m.ConfirmItems = nil
|
|
m.ConfirmShipping = nil
|
|
m = m.resetPageState()
|
|
return m, func() tea.Msg {
|
|
if m.APIClient != nil {
|
|
_ = m.APIClient.ClearCart()
|
|
}
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func formatUSD(cents int) string {
|
|
return fmt.Sprintf("$%d.%02d", cents/100, cents%100)
|
|
}
|
|
|
|
func (m Model) generateReviewContent() string {
|
|
view := strings.Builder{}
|
|
|
|
if m.CardJustAdded {
|
|
view.WriteString(m.theme.TextSuccess().Bold(true).Render("card added successfully") + "\n\n")
|
|
}
|
|
|
|
if m.ShippingInfo != nil {
|
|
view.WriteString(m.ShippingInfo.Name + "\n")
|
|
view.WriteString(m.ShippingInfo.Street + "\n")
|
|
if m.ShippingInfo.Street2 != "" {
|
|
view.WriteString(m.ShippingInfo.Street2 + "\n")
|
|
}
|
|
view.WriteString(fmt.Sprintf("%s, %s %s, %s\n", m.ShippingInfo.City, m.ShippingInfo.State, m.ShippingInfo.Zip, m.ShippingInfo.Country))
|
|
}
|
|
view.WriteString("\n")
|
|
|
|
if m.SelectedCard != nil {
|
|
view.WriteString(fmt.Sprintf("cc: **** **** **** %s\n", m.SelectedCard.Last4))
|
|
}
|
|
view.WriteString("\n")
|
|
|
|
subtotal := 0
|
|
for _, item := range m.GetCartItemsSlice() {
|
|
subtotal += item.Coffee.Price * item.Quantity
|
|
}
|
|
view.WriteString(fmt.Sprintf("subtotal: %s\n", formatUSD(subtotal)))
|
|
view.WriteString(m.theme.TextAccent().Render(fmt.Sprintf("total: %s", formatUSD(subtotal))) + "\n")
|
|
view.WriteString("\n")
|
|
view.WriteString(m.theme.TextDim().Render("press enter to confirm") + "\n")
|
|
|
|
return m.theme.Base().Padding(0, 1).Render(view.String())
|
|
}
|
|
|
|
func (m Model) ReviewView() string {
|
|
if m.CheckingOut {
|
|
return m.theme.TextAccent().Bold(true).Padding(1).Render(" submitting order...")
|
|
}
|
|
if m.ReviewSuccess {
|
|
content := m.theme.TextSuccess().Bold(true).Padding(1).Render("order placed successfully!")
|
|
return lipgloss.Place(
|
|
m.widthContainer,
|
|
lipgloss.Height(content),
|
|
lipgloss.Center, lipgloss.Center,
|
|
content,
|
|
)
|
|
}
|
|
content := m.generateReviewContent()
|
|
return lipgloss.Place(
|
|
m.widthContainer,
|
|
lipgloss.Height(content),
|
|
lipgloss.Center, lipgloss.Center,
|
|
content,
|
|
)
|
|
}
|
|
|
|
func (m Model) ReviewUpdate(msg tea.Msg) (Model, tea.Cmd) {
|
|
switch msg := msg.(type) {
|
|
case CheckoutResultMsg:
|
|
m.CheckingOut = false
|
|
if msg.Err != nil {
|
|
m.ErrorMsg = fmt.Sprintf("checkout failed: %v", msg.Err)
|
|
m = m.SwitchPage(paymentPage)
|
|
m.PaymentView = 0
|
|
m.PaymentForm = nil
|
|
return m, nil
|
|
}
|
|
m.Cart = make(map[uint]*models.CartItem)
|
|
m.CartCursor = 0
|
|
m.ShippingInfo = nil
|
|
m.OrdersLoaded = false
|
|
m.ReviewSuccess = true
|
|
return m, nil
|
|
|
|
case tea.KeyMsg:
|
|
if m.CheckingOut {
|
|
return m, nil
|
|
}
|
|
if m.ReviewSuccess {
|
|
m = m.SwitchPage(shopPage)
|
|
m.ReviewSuccess = false
|
|
m.CardJustAdded = false
|
|
m = m.resetPageState()
|
|
return m, func() tea.Msg {
|
|
if m.APIClient != nil {
|
|
_ = m.APIClient.ClearCart()
|
|
}
|
|
return nil
|
|
}
|
|
}
|
|
switch msg.String() {
|
|
case "esc":
|
|
m = m.SwitchPage(paymentPage)
|
|
return m, nil
|
|
|
|
case "enter":
|
|
m.CheckingOut = true
|
|
return m, m.checkoutWithSavedCard()
|
|
}
|
|
}
|
|
return m, nil
|
|
}
|