mirror of
https://github.com/marcusDenslow/terminalShop.git
synced 2026-10-25 02:52:20 +02:00
feat(models): derive order state from status + tracking
This commit is contained in:
25
cog.toml
Normal file
25
cog.toml
Normal file
@@ -0,0 +1,25 @@
|
||||
from_latest_tag = false
|
||||
ignore_merge_commits = false
|
||||
ignore_fixup_commits = false
|
||||
disable_changelog = false
|
||||
disable_bump_commit = false
|
||||
generate_mono_repository_global_tag = true
|
||||
generate_mono_repository_package_tags = true
|
||||
branch_whitelist = []
|
||||
pre = "alpha.*"
|
||||
skip_ci = "[skip ci]"
|
||||
skip_untracked = false
|
||||
pre_bump_hooks = []
|
||||
post_bump_hooks = []
|
||||
pre_package_bump_hooks = []
|
||||
post_package_bump_hooks = []
|
||||
|
||||
[git_hooks]
|
||||
|
||||
[commit_types]
|
||||
|
||||
[changelog]
|
||||
path = "CHANGELOG.md"
|
||||
authors = []
|
||||
|
||||
[bump_profiles]
|
||||
76
pkg/models/order_display.go
Normal file
76
pkg/models/order_display.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package models
|
||||
|
||||
// DisplayKind is a ui agnostic color/severity token.
|
||||
// The TUI (or any other renderer) maps this to a concrete style
|
||||
// the model stays free of UI deps.
|
||||
type DisplayKind string
|
||||
|
||||
const (
|
||||
DisplayKindNeutral DisplayKind = "neutral" // pending, default
|
||||
DisplayKindAccent DisplayKind = "accent" // paid, awaiting fulfillment
|
||||
DisplayKindBrand DisplayKind = "brand" // shipped / in transit
|
||||
DisplayKindSuccess DisplayKind = "success" // delivered
|
||||
DisplayKindError DisplayKind = "error" // cancelled, failed, refunded
|
||||
DisplayKindWarning DisplayKind = "warning" // refund pending, delivery issue
|
||||
)
|
||||
|
||||
func (order *Order) DisplayState() string {
|
||||
switch order.Status {
|
||||
case OrderStatusPending:
|
||||
return "Awaiting payment"
|
||||
case OrderStatusPaid:
|
||||
if order.TrackingNumber == "" {
|
||||
return "Paid * awaiting label"
|
||||
}
|
||||
// !IMPORTANT
|
||||
// Reachable only if UpdateTracking auto-promote is removed later
|
||||
if order.TrackingStatus == TrackingStatusPreTransit {
|
||||
return "Paid * ready to ship"
|
||||
}
|
||||
return "Paid"
|
||||
case OrderStatusShipped:
|
||||
switch order.TrackingStatus {
|
||||
case TrackingStatusTransit:
|
||||
return "Shipped * in transit"
|
||||
case TrackingStatusFailure:
|
||||
return "Shipped * delivery issue"
|
||||
case TrackingStatusReturned:
|
||||
return "Shipped * returned to sender"
|
||||
case TrackingStatusDelivered:
|
||||
// Webhook hasn't promoted Status yet, trust tracking
|
||||
return "Delivered"
|
||||
}
|
||||
return "Shipped"
|
||||
case OrderStatusDelivered:
|
||||
return "Delivered"
|
||||
case OrderStatusCancelled:
|
||||
return "Cancelled"
|
||||
case OrderStatusRefunded:
|
||||
return "Refunded"
|
||||
case OrderStatusFailed:
|
||||
return "Payment failed"
|
||||
}
|
||||
return string(order.Status)
|
||||
}
|
||||
|
||||
func (order *Order) DisplayKind() DisplayKind {
|
||||
switch order.Status {
|
||||
case OrderStatusPending:
|
||||
return DisplayKindNeutral
|
||||
case OrderStatusPaid:
|
||||
return DisplayKindAccent
|
||||
case OrderStatusShipped:
|
||||
switch order.TrackingStatus {
|
||||
case TrackingStatusFailure, TrackingStatusReturned:
|
||||
return DisplayKindWarning
|
||||
case TrackingStatusDelivered:
|
||||
return DisplayKindSuccess
|
||||
}
|
||||
return DisplayKindBrand
|
||||
case OrderStatusDelivered:
|
||||
return DisplayKindSuccess
|
||||
case OrderStatusCancelled, OrderStatusRefunded, OrderStatusFailed:
|
||||
return DisplayKindError
|
||||
}
|
||||
return DisplayKindNeutral
|
||||
}
|
||||
36
pkg/models/order_display_test.go
Normal file
36
pkg/models/order_display_test.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package models
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestOrderDisplayState(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
order Order
|
||||
want string
|
||||
kind DisplayKind
|
||||
}{
|
||||
{"pending", Order{Status: OrderStatusPending}, "Awaiting payment", DisplayKindNeutral},
|
||||
{"paid no tracking", Order{Status: OrderStatusPaid}, "Paid * awaiting label", DisplayKindAccent},
|
||||
{"paid with tracking, no event", Order{Status: OrderStatusPaid, TrackingNumber: "12999"}, "Paid", DisplayKindAccent},
|
||||
{"Paid pre-transit", Order{Status: OrderStatusPaid, TrackingNumber: "12999", TrackingStatus: TrackingStatusPreTransit}, "Paid * ready to ship", DisplayKindAccent},
|
||||
{"shipped no tracking event", Order{Status: OrderStatusShipped}, "Shipped", DisplayKindBrand},
|
||||
{"shipped in transit", Order{Status: OrderStatusShipped, TrackingStatus: TrackingStatusTransit}, "Shipped * in transit", DisplayKindBrand},
|
||||
{"shipped failure", Order{Status: OrderStatusShipped, TrackingStatus: TrackingStatusFailure}, "Shipped * delivery issue", DisplayKindWarning},
|
||||
{"shipped returned", Order{Status: OrderStatusShipped, TrackingStatus: TrackingStatusReturned}, "Shipped * returned to sender", DisplayKindWarning},
|
||||
{"shipped tracking-delivered (webhook lag)", Order{Status: OrderStatusShipped, TrackingStatus: TrackingStatusDelivered}, "Delivered", DisplayKindSuccess},
|
||||
{"delivered", Order{Status: OrderStatusDelivered}, "Delivered", DisplayKindSuccess},
|
||||
{"cancelled", Order{Status: OrderStatusCancelled}, "Cancelled", DisplayKindError},
|
||||
{"refunded", Order{Status: OrderStatusRefunded}, "Refunded", DisplayKindError},
|
||||
{"failed", Order{Status: OrderStatusFailed}, "Payment failed", DisplayKindError},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
if got := tc.order.DisplayState(); got != tc.want {
|
||||
t.Errorf("DisplayState() = %q, want %q", got, tc.want)
|
||||
}
|
||||
if got := tc.order.DisplayKind(); got != tc.kind {
|
||||
t.Errorf("DisplayKind() = %q, want %q", got, tc.kind)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -74,9 +74,9 @@ func (m Model) buildOrderCard(order models.Order, boxWidth int, isSelected bool)
|
||||
}
|
||||
line1 := orderLabel + lipgloss.NewStyle().Width(spacing).Render("") + total
|
||||
|
||||
// Line 2: date + status
|
||||
// Line 2: date + derived status
|
||||
date := dimStyle.Render(order.CreatedAt.Format("Jan 02 2006"))
|
||||
status := m.statusStyle(order.Status).Bold(true).Render(strings.ToUpper(string(order.Status)))
|
||||
status := m.displayStyle(order.DisplayKind()).Bold(true).Render(order.DisplayState())
|
||||
line2 := date + " " + status
|
||||
|
||||
boxContent := line1 + "\n" + line2
|
||||
@@ -102,7 +102,7 @@ func (m Model) buildOrderDetailView(order models.Order, _ int) string {
|
||||
|
||||
// Status and date
|
||||
b.WriteString(labelStyle.Render("Status: "))
|
||||
b.WriteString(m.statusStyle(order.Status).Render(strings.ToUpper(string(order.Status))))
|
||||
b.WriteString(m.displayStyle(order.DisplayKind()).Render(order.DisplayState()))
|
||||
b.WriteString("\n")
|
||||
b.WriteString(labelStyle.Render("Date: "))
|
||||
b.WriteString(valueStyle.Render(order.CreatedAt.Format("Jan 02 2006 3:04 PM")))
|
||||
@@ -183,15 +183,23 @@ func (m Model) buildOrderDetailView(order models.Order, _ int) string {
|
||||
return b.String()
|
||||
}
|
||||
|
||||
func (m Model) statusStyle(s models.OrderStatus) lipgloss.Style {
|
||||
switch s {
|
||||
case models.OrderStatusDelivered:
|
||||
// displayStyle maps a model-layer DisplayKind token to a themed lipgloss style.
|
||||
// Keeps pkg/models free of UI deps.
|
||||
func (m Model) displayStyle(k models.DisplayKind) lipgloss.Style {
|
||||
switch k {
|
||||
case models.DisplayKindSuccess:
|
||||
return m.theme.TextSuccess()
|
||||
case models.OrderStatusShipped:
|
||||
case models.DisplayKindBrand:
|
||||
return m.theme.TextBrand()
|
||||
case models.OrderStatusFailed, models.OrderStatusCancelled, models.OrderStatusRefunded:
|
||||
case models.DisplayKindAccent:
|
||||
return m.theme.TextAccent()
|
||||
case models.DisplayKindError:
|
||||
return m.theme.TextError()
|
||||
|
||||
case models.DisplayKindWarning:
|
||||
// !TODO add refunds and change this
|
||||
// No warning color in theme yet, reuse loading pink as visual flag
|
||||
// for now
|
||||
return m.theme.TextLoading()
|
||||
}
|
||||
return m.theme.TextHighlight()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user