feat: add browser-based card collection via Stripe Checkout Session
adds a /pay/{token} redirect endpoint that generates a short URL
pointing to a stripe checkout sessions in setup mode. The TUI shows a QR
code and URL on the payment page so users can add a card via the browser
instead of entering raw card data over SSH.
the checkout.session.completed webhook saves the card to the database.
the TUI polls GET /api/v1/cards every second and auto-proceeds to
confirmation once the new card is detected.
also adds a dev.sh startup script that runs all four required processes.
(SSH server, API server, Stripe CLI listener, ngrok) in a single
terminal
This commit is contained in:
@@ -116,33 +116,25 @@ func (m Model) View() string {
|
||||
}
|
||||
content = strings.Join(contentLines, "\n")
|
||||
|
||||
// Add vertical spacing around content with fixed height
|
||||
contentWithPadding := lipgloss.NewStyle().
|
||||
MarginTop(marginTop).
|
||||
MarginBottom(marginBottom).
|
||||
Height(availableContentHeight).
|
||||
Render(content)
|
||||
|
||||
// Build footer
|
||||
footer := m.BuildFooter()
|
||||
|
||||
// Assemble all layers vertically within the container
|
||||
isViewportPage := m.currentPage == shopPage || m.currentPage == cartPage ||
|
||||
m.currentPage == shippingPage || m.currentPage == paymentPage ||
|
||||
m.currentPage == confirmPage
|
||||
|
||||
var child string
|
||||
if breadcrumbs != "" {
|
||||
child = lipgloss.JoinVertical(
|
||||
lipgloss.Left,
|
||||
header,
|
||||
breadcrumbs,
|
||||
contentWithPadding,
|
||||
footer,
|
||||
)
|
||||
if isViewportPage {
|
||||
if breadcrumbs != "" {
|
||||
child = lipgloss.JoinVertical(lipgloss.Left, header, breadcrumbs, content, footer)
|
||||
} else {
|
||||
child = lipgloss.JoinVertical(lipgloss.Left, header, content, footer)
|
||||
}
|
||||
} else if breadcrumbs != "" {
|
||||
ccontentWithPadding := lipgloss.NewStyle().MarginTop(marginTop).MarginBottom(marginBottom).Height(availableContentHeight).Render(content)
|
||||
child = lipgloss.JoinVertical(lipgloss.Left, header, breadcrumbs, ccontentWithPadding, footer)
|
||||
} else {
|
||||
child = lipgloss.JoinVertical(
|
||||
lipgloss.Left,
|
||||
header,
|
||||
contentWithPadding,
|
||||
footer,
|
||||
)
|
||||
ccontentWithPadding := lipgloss.NewStyle().MarginTop(marginTop).MarginBottom(marginBottom).Height(availableContentHeight).Render(content)
|
||||
child = lipgloss.JoinVertical(lipgloss.Left, header, ccontentWithPadding, footer)
|
||||
}
|
||||
|
||||
// Constrain the assembled layout to the container dimensions
|
||||
@@ -166,23 +158,16 @@ func (m Model) buildPageContent(height int) string {
|
||||
case accountPage:
|
||||
return m.BuildAccountView(height)
|
||||
case shippingPage:
|
||||
if m.ShippingView == 0 && m.ShippingForm == nil {
|
||||
return m.RenderAddressList()
|
||||
}
|
||||
return m.RenderShippingForm(m.ShippingForm)
|
||||
return m.ShippingPageView()
|
||||
case paymentPage:
|
||||
if m.CheckingOut {
|
||||
return " submitting order..."
|
||||
}
|
||||
if m.PaymentView == 0 && m.PaymentForm == nil {
|
||||
return m.RenderCardList()
|
||||
}
|
||||
return m.RenderPaymentForm(m.PaymentForm)
|
||||
return m.PaymentPageView()
|
||||
case confirmPage:
|
||||
return m.RenderConfirmation()
|
||||
return m.ConfirmView()
|
||||
case cartPage:
|
||||
return m.BuildCartView()
|
||||
return m.CartView()
|
||||
case shopPage:
|
||||
return m.ShopView()
|
||||
default:
|
||||
return m.BuildShopView()
|
||||
return m.ShopView()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user