diff --git a/api/handlers/cart.go b/api/handlers/cart.go index dd6140b..94fd58c 100644 --- a/api/handlers/cart.go +++ b/api/handlers/cart.go @@ -50,14 +50,13 @@ func cartResponse(cart *models.Cart) map[string]interface{} { subtotal := 0 itemsData := make([]map[string]interface{}, 0, len(items)) for _, item := range items { - priceInCents := int(item.Coffee.Price * 100) - lineTotal := priceInCents * item.Quantity + lineTotal := item.Coffee.Price * item.Quantity subtotal += lineTotal itemsData = append(itemsData, map[string]interface{}{ "id": item.ID, "coffee_id": item.CoffeeID, "quantity": item.Quantity, - "subtotal": lineTotal, + "subtotal": lineTotal, // already in cents "coffee": item.Coffee, }) } @@ -296,13 +295,12 @@ func (h *CartHandler) ConvertCart(w http.ResponseWriter, r *http.Request) { var subtotal int var orderItems []models.OrderItem for _, item := range items { - priceInCents := int(item.Coffee.Price * 100) - lineTotal := priceInCents * item.Quantity + lineTotal := item.Coffee.Price * item.Quantity subtotal += lineTotal orderItems = append(orderItems, models.OrderItem{ CoffeeID: item.CoffeeID, Name: item.Coffee.Name, - Price: priceInCents, + Price: item.Coffee.Price, Quantity: item.Quantity, }) } diff --git a/model.go.old b/model.go.old deleted file mode 100644 index 36826d3..0000000 --- a/model.go.old +++ /dev/null @@ -1,710 +0,0 @@ -package main - -import ( - "fmt" - - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" -) - - -// Account menu items struct. -var accountMenuItems = []string { - "order history", - "faq", - "about", -} - -// Coffee represents a coffee product -type Coffee struct { - Name string - RoastType string - Ounces int - BeanType string - Price float64 - Color string // Hex color for background - Description string -} - -// CartItem represents an item in the cart -type CartItem struct { - Coffee Coffee - Quantity int -} - -type model struct { - username string - coffees []Coffee - cursor int - cart map[int]*CartItem // maps coffee index to cart item - cartCursor int // cursor position in cart view - accountCursor int - accountPage string - windowWidth int - windowHeight int - viewingCart bool // true when viewing cart details - viewingAccount bool -} - -func (m model) Init() tea.Cmd { - return nil -} - -func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { - switch msg := msg.(type) { - case tea.WindowSizeMsg: - m.windowWidth = msg.Width - m.windowHeight = msg.Height - return m, nil - - case tea.KeyMsg: - switch msg.String() { - case "ctrl+c", "q": - return m, tea.Quit - - case "s": - m.viewingCart = false - m.viewingAccount = false - m.accountPage = "" - - case "c": - m.viewingCart = true - m.viewingAccount = false - m.accountPage = "" - - case "a": - m.viewingCart = false - m.viewingAccount = true - - case "up", "k": - if m.viewingAccount && m.accountPage == "" { - if m.accountCursor > 0 { - m.accountCursor-- - } - } else if !m.viewingCart && !m.viewingAccount && m.cursor > 0 { - m.cursor-- - } else if m.viewingCart && m.cartCursor > 0 { - m.cartCursor-- - } - - case "down", "j": - if m.viewingAccount && m.accountPage == "" { - if m.accountCursor < len(accountMenuItems)-1 { - m.accountCursor++ - } - } else if !m.viewingCart && !m.viewingAccount && m.cursor < len(m.coffees)-1 { - m.cursor++ - } else if m.viewingCart && m.cartCursor < len(m.cart)-1 { - m.cartCursor++ - } - - case "+", "=": - if !m.viewingCart { - // Increment quantity in shop view - if item, exists := m.cart[m.cursor]; exists { - item.Quantity++ - } else { - m.cart[m.cursor] = &CartItem{ - Coffee: m.coffees[m.cursor], - Quantity: 1, - } - } - } else { - // Increment quantity in cart view - cartItems := m.getCartItemsSlice() - if m.cartCursor >= 0 && m.cartCursor < len(cartItems) { - cartItems[m.cartCursor].Quantity++ - } - } - - case "enter": - if m.viewingAccount && m.accountPage == "" { - switch accountMenuItems[m.accountCursor]{ - case "order history": - m.accountPage = "orders" - case "faq": - m.accountPage = "faq" - case "about": - m.accountPage = "about" - } - } - - case "esc": - if m.viewingAccount && m.accountPage != "" { - m.accountPage = "" - } - - case "-", "_": - if !m.viewingCart { - // Decrement quantity in shop view - if item, exists := m.cart[m.cursor]; exists { - item.Quantity-- - if item.Quantity <= 0 { - delete(m.cart, m.cursor) - // Reset cart cursor if we deleted the last item - if len(m.cart) == 0 { - m.cartCursor = 0 - } else if m.cartCursor >= len(m.cart) { - m.cartCursor = len(m.cart) - 1 - } - } - } - } else { - // Decrement quantity in cart view - cartItems := m.getCartItemsSlice() - if m.cartCursor >= 0 && m.cartCursor < len(cartItems) { - cartItems[m.cartCursor].Quantity-- - if cartItems[m.cartCursor].Quantity <= 0 { - // Find and delete this item from the cart - for idx, item := range m.cart { - if item == cartItems[m.cartCursor] { - delete(m.cart, idx) - break - } - } - // Reset cart cursor - if len(m.cart) == 0 { - m.cartCursor = 0 - } else if m.cartCursor >= len(m.cart) { - m.cartCursor = len(m.cart) - 1 - } - } - } - } - } - } - return m, nil -} - -func (m model) View() string { - if m.windowWidth == 0 { - m.windowWidth = 120 - m.windowHeight = 30 - } - - // Build header with cart tab - header := m.buildHeader() - - // Build main content based on view - var content string - if m.viewingAccount { - content = m.buildAccountView() - } else if m.viewingCart { - content = m.buildCartView() - } else { - content = m.buildShopView() - } - - // Add vertical spacing around content - contentWithPadding := lipgloss.NewStyle(). - MarginTop(1). - MarginBottom(4). - Render(content) - - // Build footer - footer := m.buildFooter() - - // Combine all app content - appContent := lipgloss.JoinVertical( - lipgloss.Left, - header, - contentWithPadding, - footer, - ) - - // Calculate vertical centering - appHeight := lipgloss.Height(appContent) - verticalPadding := 2 // Minimum padding from top and bottom - availableSpace := m.windowHeight - appHeight - (verticalPadding * 2) - - if availableSpace < 0 { - availableSpace = 0 - verticalPadding = 0 - } - - // Split remaining space between top and bottom - topPadding := verticalPadding + (availableSpace / 2) - - // Create top spacing - topSpacing := "" - for i := 0; i < topPadding; i++ { - topSpacing += "\n" - } - - return topSpacing + appContent -} - -func (m model) buildHeader() string { - // Calculate cart total and item count - total := 0.0 - itemCount := 0 - for _, item := range m.cart { - total += float64(item.Quantity) * item.Coffee.Price - itemCount += item.Quantity - } - - // Define colors - whiteStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("#FFFFFF")) - grayStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("#AAAAAA")) - boldWhiteStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("#FFFFFF")).Bold(true) - - // Build shop tab - var shopKeybind, shopName string - if !m.viewingCart { - // Active: bold white keybind and name - shopKeybind = boldWhiteStyle.Render("s") - shopName = boldWhiteStyle.Render("shop") - } else { - // Inactive: bold gray keybind, gray name - shopKeybind = lipgloss.NewStyle().Foreground(lipgloss.Color("#AAAAAA")).Bold(true).Render("s") - shopName = grayStyle.Render("shop") - } - - // Build cart tab - var cartKeybind, cartName, cartInfo string - itemCountText := grayStyle.Render(fmt.Sprintf("[%d]", itemCount)) - - if m.viewingCart { - // Active: bold white keybind and name - cartKeybind = boldWhiteStyle.Render("c") - cartName = boldWhiteStyle.Render("cart") - cartInfo = fmt.Sprintf(" %s %s", - boldWhiteStyle.Render(fmt.Sprintf("$%.2f", total)), - itemCountText) - } else { - // Inactive: bold gray keybind, gray name - boldGrayStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("#AAAAAA")).Bold(true) - boldWhitePriceStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("#FFFFFF")).Bold(true) - cartKeybind = boldGrayStyle.Render("c") - cartName = grayStyle.Render("cart") - cartInfo = fmt.Sprintf(" %s %s", - boldWhitePriceStyle.Render(fmt.Sprintf("$%.2f", total)), - itemCountText) - } - - // Build Account Tabs - var accountKeybind, accountName string - if m.viewingAccount { - accountKeybind = boldWhiteStyle.Render("a") - accountName = boldWhiteStyle.Render("account") - } else { - accountKeybind = lipgloss.NewStyle().Foreground(lipgloss.Color("#AAAAAA")).Bold(true).Render("a") - accountName = grayStyle.Render("account") - } - - // Build the tabs with separator only in the middle - separator := whiteStyle.Render("|") - tabsContent := fmt.Sprintf("%s %s %s %s %s%s %s %s %s", - shopKeybind, - shopName, - separator, - cartKeybind, - cartName, - cartInfo, - separator, - accountKeybind, - accountName, - ) - - // Add box with padding (no vertical padding, just horizontal) - tabBox := lipgloss.NewStyle(). - Border(lipgloss.NormalBorder()). - Padding(0, 2). - MarginBottom(1) - - // Center the whole thing - centered := lipgloss.NewStyle(). - Width(m.windowWidth). - Align(lipgloss.Center) - - return centered.Render(tabBox.Render(tabsContent)) -} - -func (m model) buildShopView() string { - leftWidth := 18 // Narrower list - leftMargin := 4 // Minimal left margin - rightWidth := m.windowWidth - leftWidth - leftMargin - 4 - - // Build the left panel (coffee list) - leftPanel := "" - for i, coffee := range m.coffees { - // Apply background color when selected, white text - if m.cursor == i { - style := lipgloss.NewStyle(). - Background(lipgloss.Color(coffee.Color)). - Foreground(lipgloss.Color("#FFFFFF")). - Padding(0, 1). - Width(leftWidth - 2). - Align(lipgloss.Left) - leftPanel += style.Render(coffee.Name) + "\n" - } else { - style := lipgloss.NewStyle(). - Foreground(lipgloss.Color("#AAAAAA")). - Padding(0, 1). - Width(leftWidth - 2). - Align(lipgloss.Left) - leftPanel += style.Render(coffee.Name) + "\n" - } - } - - // Add left margin to the list - leftContainer := lipgloss.NewStyle(). - Width(leftWidth). - MarginLeft(leftMargin) - - // Build the detail view (right panel) - detailView := "" - if m.cursor >= 0 && m.cursor < len(m.coffees) { - selectedCoffee := m.coffees[m.cursor] - - nameStyle := lipgloss.NewStyle(). - Bold(true). - Foreground(lipgloss.Color("#FFFFFF")) - - infoStyle := lipgloss.NewStyle(). - Foreground(lipgloss.Color("#AAAAAA")) - - priceStyle := lipgloss.NewStyle(). - Foreground(lipgloss.Color(selectedCoffee.Color)). - Bold(true) - - descStyle := lipgloss.NewStyle(). - Foreground(lipgloss.Color("#FFFFFF")). - Width(rightWidth - 4) - - quantityStyle := lipgloss.NewStyle(). - Foreground(lipgloss.Color("#FFFFFF")). - Bold(true) - - // Get current quantity - quantity := 0 - if item, exists := m.cart[m.cursor]; exists { - quantity = item.Quantity - } - - detailView += nameStyle.Render(selectedCoffee.Name) + "\n" - detailView += infoStyle.Render(fmt.Sprintf("%s | %doz | %s", - selectedCoffee.RoastType, - selectedCoffee.Ounces, - selectedCoffee.BeanType)) + "\n\n" - detailView += priceStyle.Render(fmt.Sprintf("$%.2f", selectedCoffee.Price)) + "\n\n" - detailView += descStyle.Render(selectedCoffee.Description) + "\n\n" - detailView += quantityStyle.Render(fmt.Sprintf("- %d +", quantity)) + "\n" - } - - detailContainer := lipgloss.NewStyle(). - Width(rightWidth) - - // Layout the panels side by side - mainContent := lipgloss.JoinHorizontal( - lipgloss.Top, - leftContainer.Render(leftPanel), - detailContainer.Render(detailView), - ) - - return mainContent -} - -func (m model) buildCartView() string { - if len(m.cart) == 0 { - emptyStyle := lipgloss.NewStyle(). - Foreground(lipgloss.Color("#666666")). - Align(lipgloss.Center). - Width(m.windowWidth). - Padding(4, 0) - return emptyStyle.Render("Your cart is empty\n\nPress s to go back to shop") - } - - cartItems := "" - boxWidth := m.windowWidth - 20 // Leave some margin - itemSlice := m.getCartItemsSlice() - - for idx, item := range itemSlice { - itemTotal := float64(item.Quantity) * item.Coffee.Price - - // Left side: name and info - nameStyle := lipgloss.NewStyle(). - Bold(true). - Foreground(lipgloss.Color("#FFFFFF")) - - infoStyle := lipgloss.NewStyle(). - Foreground(lipgloss.Color("#AAAAAA")) - - // Right side: quantity controls and price - quantityStyle := lipgloss.NewStyle(). - Foreground(lipgloss.Color("#FFFFFF")) - - priceStyle := lipgloss.NewStyle(). - Foreground(lipgloss.Color("#FFFFFF")). - Bold(true) - - // Build content with proper spacing - nameText := nameStyle.Render(item.Coffee.Name) - infoText := infoStyle.Render(fmt.Sprintf("%s | %doz | %s", - item.Coffee.RoastType, - item.Coffee.Ounces, - item.Coffee.BeanType)) - quantityText := quantityStyle.Render(fmt.Sprintf("- %d +", item.Quantity)) - priceText := priceStyle.Render(fmt.Sprintf("$%.2f", itemTotal)) - - // Calculate spacing - nameWidth := lipgloss.Width(nameText) - quantityWidth := lipgloss.Width(quantityText) - priceWidth := lipgloss.Width(priceText) - spacing := boxWidth - nameWidth - quantityWidth - priceWidth - 8 // 8 for padding and gaps - - if spacing < 1 { - spacing = 1 - } - - contentLine1 := nameText + - lipgloss.NewStyle().Width(spacing).Render("") + - quantityText + " " + priceText - - contentLine2 := infoText - - boxContent := contentLine1 + "\n" + contentLine2 - - // Create box for this item - itemBox := lipgloss.NewStyle(). - Border(lipgloss.NormalBorder()). - Padding(0, 2). - Width(boxWidth). - Foreground(lipgloss.Color("#FFFFFF")) - - // Center the box - centered := lipgloss.NewStyle(). - Width(m.windowWidth). - Align(lipgloss.Center) - - cartItems += centered.Render(itemBox.Render(boxContent)) - - // Add spacing between items - if idx < len(itemSlice)-1 { - cartItems += "\n\n" - } - } - - return cartItems -} - -func (m model) buildAccountView() string { - // If we're on a subpage, show that content - if m.accountPage != "" { - return m.buildAccountSubpage() - } - - // Otherwise show the account menu - leftWidth := 18 - leftMargin := 4 - - leftPanel := "" - for i, item := range accountMenuItems { - // Apply background color when selected, white text - if m.accountCursor == i { - style := lipgloss.NewStyle(). - Background(lipgloss.Color("#4682B4")). - Foreground(lipgloss.Color("#FFFFFF")). - Padding(0, 1). - Width(leftWidth - 2). - Align(lipgloss.Left) - leftPanel += style.Render(item) + "\n" - } else { - style := lipgloss.NewStyle(). - Foreground(lipgloss.Color("#AAAAAA")). - Padding(0, 1). - Width(leftWidth - 2). - Align(lipgloss.Left) - leftPanel += style.Render(item) + "\n" - } - } - - leftContainer := lipgloss.NewStyle(). - Width(leftWidth). - MarginLeft(leftMargin) - - return leftContainer.Render(leftPanel) -} - -func (m model) buildAccountSubpage() string { - titleStyle := lipgloss.NewStyle(). - Bold(true). - Foreground(lipgloss.Color("#FFFFFF")). - MarginBottom(2) - - contentStyle := lipgloss.NewStyle(). - Foreground(lipgloss.Color("#AAAAAA")). - Width(m.windowWidth - 20). - MarginLeft(4) - - var content string - switch m.accountPage { - case "orders": - content = titleStyle.Render("Order History") + "\n\n" + - contentStyle.Render("No orders yet. Your order history will appear here once you make a purchase.") - case "faq": - content = titleStyle.Render("FAQ") + "\n\n" + - contentStyle.Render("Q: How do I place an order?\nA: Browse products with j/k, adjust quantity with +/-, and checkout via the cart.\n\nQ: What payment methods do you accept?\nA: We accept all major credit cards via Stripe.\n\nPress ESC to go back.") - case "about": - content = titleStyle.Render("About Terminal Coffee Shop") + "\n\n" + - contentStyle.Render("A terminal-based coffee ordering experience.\nBuilt with Go and Bubbletea.\n\nPress ESC to go back.") - default: - content = "Unknown page" - } - - return content -} - -// getCartItemsSlice converts the cart map to a sorted slice for consistent iteration -func (m model) getCartItemsSlice() []*CartItem { - items := make([]*CartItem, 0, len(m.cart)) - for _, item := range m.cart { - items = append(items, item) - } - return items -} - -func (m model) buildFooter() string { - // Style for keybinds (bold) - keybindStyle := lipgloss.NewStyle(). - Foreground(lipgloss.Color("#666666")). - Bold(true) - - // Style for descriptions (normal) - descStyle := lipgloss.NewStyle(). - Foreground(lipgloss.Color("#666666")) - - var footerText string - if m.viewingAccount { - if m.accountPage != "" { - // In a subpage - footerText = fmt.Sprintf("%s %s %s %s %s %s %s %s", - keybindStyle.Render("esc"), - descStyle.Render("back"), - keybindStyle.Render("s"), - descStyle.Render("shop"), - keybindStyle.Render("c"), - descStyle.Render("cart"), - keybindStyle.Render("q"), - descStyle.Render("quit"), - ) - } else { - // In account menu - footerText = fmt.Sprintf("%s %s %s %s %s %s %s %s %s %s", - keybindStyle.Render("j/k"), - descStyle.Render("menu"), - keybindStyle.Render("enter"), - descStyle.Render("select"), - keybindStyle.Render("s"), - descStyle.Render("shop"), - keybindStyle.Render("c"), - descStyle.Render("cart"), - keybindStyle.Render("q"), - descStyle.Render("quit"), - ) - } - } else if m.viewingCart { - footerText = fmt.Sprintf("%s %s %s %s %s %s %s %s %s %s", - keybindStyle.Render("j/k"), - descStyle.Render("items"), - keybindStyle.Render("+/-"), - descStyle.Render("qty"), - keybindStyle.Render("s"), - descStyle.Render("shop"), - keybindStyle.Render("a"), - descStyle.Render("account"), - keybindStyle.Render("q"), - descStyle.Render("quit"), - ) - } else { - footerText = fmt.Sprintf("%s %s %s %s %s %s %s %s %s %s", - keybindStyle.Render("j/k"), - descStyle.Render("products"), - keybindStyle.Render("+/-"), - descStyle.Render("qty"), - keybindStyle.Render("c"), - descStyle.Render("cart"), - keybindStyle.Render("a"), - descStyle.Render("account"), - keybindStyle.Render("q"), - descStyle.Render("quit"), - ) - } - - return lipgloss.NewStyle(). - Align(lipgloss.Center). - Width(m.windowWidth). - Render(footerText) -} - -// InitialModel creates a new model with default coffee options -func InitialModel(username string) model { - return model{ - username: username, - coffees: []Coffee{ - { - Name: "Espresso", - RoastType: "Dark Roast", - Ounces: 2, - BeanType: "Arabica", - Price: 3.50, - Color: "#8B4513", - Description: "A bold, concentrated shot of pure coffee bliss. Perfect for those who need an immediate caffeine injection to survive the day.", - }, - { - Name: "Latte", - RoastType: "Medium Roast", - Ounces: 12, - BeanType: "Arabica Blend", - Price: 5.00, - Color: "#D2691E", - Description: "Smooth espresso paired with steamed milk and a light layer of foam. For when you want coffee but also want to feel fancy about it.", - }, - { - Name: "Cappuccino", - RoastType: "Medium Roast", - Ounces: 8, - BeanType: "Italian Blend", - Price: 4.50, - Color: "#CD853F", - Description: "Equal parts espresso, steamed milk, and foam. The classic Italian choice for people who know what they're doing.", - }, - { - Name: "Americano", - RoastType: "Dark Roast", - Ounces: 16, - BeanType: "Arabica", - Price: 4.00, - Color: "#A0522D", - Description: "Espresso with hot water. Simple, strong, and no-nonsense. This is coffee for people who actually like the taste of coffee.", - }, - { - Name: "Cold Brew", - RoastType: "Medium Roast", - Ounces: 16, - BeanType: "Colombian", - Price: 5.50, - Color: "#4682B4", - Description: "Steeped for 12 hours to create a smooth, less acidic coffee experience. Served cold because sometimes hot coffee is just too much effort.", - }, - { - Name: "Macchiato", - RoastType: "Dark Roast", - Ounces: 3, - BeanType: "Robusta Blend", - Price: 4.25, - Color: "#DAA520", - Description: "Espresso 'marked' with a dollop of foamed milk. Small but mighty, like a tiny caffeinated warrior.", - }, - }, - cursor: 0, - cart: make(map[int]*CartItem), - cartCursor: 0, - accountCursor: 0, - accountPage: "", - windowWidth: 120, - windowHeight: 30, - viewingCart: false, - viewingAccount: false, - } -} diff --git a/pkg/database/db_test.go b/pkg/database/db_test.go index 7fe6e49..94f511f 100644 --- a/pkg/database/db_test.go +++ b/pkg/database/db_test.go @@ -108,7 +108,7 @@ func TestSeed(t *testing.T) { t.Errorf("Unexpected product name: %s", p.Name) } if p.Price <= 0 { - t.Errorf("Product %s has invalid price: %f", p.Name, p.Price) + t.Errorf("Product %s has invalid price: %d", p.Name, p.Price) } } } diff --git a/pkg/database/seed.go b/pkg/database/seed.go index 1b1102e..812e3d0 100644 --- a/pkg/database/seed.go +++ b/pkg/database/seed.go @@ -27,7 +27,7 @@ func Seed(db *gorm.DB) error { RoastType: "Dark Roast", Ounces: 2, BeanType: "Arabica", - Price: 3.50, + Price: 350, // $3.50 Color: "#8B4513", Description: "Bold and intense coffee with a rich crema", }, @@ -36,7 +36,7 @@ func Seed(db *gorm.DB) error { RoastType: "Medium Roast", Ounces: 8, BeanType: "Arabica", - Price: 4.00, + Price: 400, // $4.00 Color: "#A0522D", Description: "Smooth and balanced espresso diluted with hot water", }, @@ -45,7 +45,7 @@ func Seed(db *gorm.DB) error { RoastType: "Medium Roast", Ounces: 6, BeanType: "Arabica", - Price: 4.50, + Price: 450, // $4.50 Color: "#C4A574", Description: "Espresso with steamed milk and a thick layer of foam", }, @@ -54,7 +54,7 @@ func Seed(db *gorm.DB) error { RoastType: "Medium Roast", Ounces: 12, BeanType: "Arabica", - Price: 5.00, + Price: 500, // $5.00 Color: "#D2B48C", Description: "Creamy espresso with plenty of steamed milk and a touch of foam", }, @@ -63,7 +63,7 @@ func Seed(db *gorm.DB) error { RoastType: "Dark Roast", Ounces: 12, BeanType: "Arabica", - Price: 5.50, + Price: 550, // $5.50 Color: "#8B4513", Description: "Chocolate and espresso combined with steamed milk. Sweet and indulgent.", }, @@ -72,7 +72,7 @@ func Seed(db *gorm.DB) error { RoastType: "Dark Roast", Ounces: 3, BeanType: "Robusta Blend", - Price: 4.25, + Price: 425, // $4.25 Color: "#DAA520", Description: "Espresso 'marked' with a dollop of foamed milk. Small but mighty, like a tiny caffeinated warrior.", }, diff --git a/pkg/models/coffee.go b/pkg/models/coffee.go index 63e1996..0d5a350 100644 --- a/pkg/models/coffee.go +++ b/pkg/models/coffee.go @@ -13,7 +13,7 @@ type Coffee struct { RoastType string `gorm:"size:100" json:"roast_type"` Ounces int `json:"ounces"` BeanType string `gorm:"size:100" json:"bean_type"` - Price float64 `gorm:"not null" json:"price"` + Price int `gorm:"not null" json:"price"` Color string `gorm:"size:7" json:"color"` // Hex color for background Description string `gorm:"type:text" json:"description"` CreatedAt time.Time `json:"created_at"` @@ -26,7 +26,6 @@ func (Coffee) TableName() string { return "coffees" } - // AccountMenuItems something var AccountMenuItems = []string{ "order history", diff --git a/pkg/tui/cart.go b/pkg/tui/cart.go index 086cca2..bf9cc7f 100644 --- a/pkg/tui/cart.go +++ b/pkg/tui/cart.go @@ -27,7 +27,7 @@ func (m Model) BuildCartView() string { } for idx, item := range itemSlice { - itemTotal := float64(item.Quantity) * item.Coffee.Price + itemTotal := item.Quantity * item.Coffee.Price // Left side: name and individual price nameStyle := lipgloss.NewStyle(). @@ -51,13 +51,13 @@ func (m Model) BuildCartView() string { // Build content with proper spacing nameText := nameStyle.Render(item.Coffee.Name) - individualPriceText := individualPriceStyle.Render(fmt.Sprintf(" $%.2f", item.Coffee.Price)) + individualPriceText := individualPriceStyle.Render(fmt.Sprintf(" $%.2f", float64(item.Coffee.Price)/100)) infoText := infoStyle.Render(fmt.Sprintf("%s | %doz | %s", item.Coffee.RoastType, item.Coffee.Ounces, item.Coffee.BeanType)) quantityText := quantityStyle.Render(fmt.Sprintf("- %d +", item.Quantity)) - totalPriceText := totalPriceStyle.Render(fmt.Sprintf("$%.2f", itemTotal)) + totalPriceText := totalPriceStyle.Render(fmt.Sprintf("$%.2f", float64(itemTotal)/100)) // Calculate spacing nameAndPriceWidth := lipgloss.Width(nameText) + lipgloss.Width(individualPriceText) diff --git a/pkg/tui/confirmation.go b/pkg/tui/confirmation.go index 984f5ee..d055d79 100644 --- a/pkg/tui/confirmation.go +++ b/pkg/tui/confirmation.go @@ -45,15 +45,15 @@ func (m Model) RenderConfirmation() string { // Cart summary cartSection := "" - total := 0.0 + total := 0 items := m.GetCartItemsSlice() for _, item := range items { - line := fmt.Sprintf(" %s x%d $%.2f", item.Coffee.Name, item.Quantity, item.Coffee.Price*float64(item.Quantity)) + line := fmt.Sprintf(" %s x%d $%.2f", item.Coffee.Name, item.Quantity, float64(item.Coffee.Price * item.Quantity)/100) cartSection += sectionStyle.Render(line) + "\n" - total += item.Coffee.Price * float64(item.Quantity) + total += item.Coffee.Price * item.Quantity } cartSection += sectionStyle.Render( - labelStyle.Render("Total: ") + valueStyle.Render(fmt.Sprintf("$%.2f", total)), + labelStyle.Render("Total: ") + valueStyle.Render(fmt.Sprintf("$%.2f", float64(total)/100)), ) success := successStyle.Render("Order placed successfully!") diff --git a/pkg/tui/header.go b/pkg/tui/header.go index 9062227..93ab651 100644 --- a/pkg/tui/header.go +++ b/pkg/tui/header.go @@ -8,10 +8,10 @@ import ( func (m Model) BuildHeader() string { // Calculate cart total and item count - total := 0.0 + total := 0 itemCount := 0 for _, item := range m.Cart { - total += float64(item.Quantity) * item.Coffee.Price + total += item.Quantity * item.Coffee.Price itemCount += item.Quantity } @@ -29,14 +29,14 @@ func (m Model) BuildHeader() string { cartKeybind = boldWhiteStyle.Render("c") cartName = boldWhiteStyle.Render("cart") cartInfo = fmt.Sprintf(" %s %s", - boldWhiteStyle.Render(fmt.Sprintf("$%.2f", total)), + boldWhiteStyle.Render(fmt.Sprintf("$%.2f", float64(total)/100)), itemCountText) } else { // Inactive: bold gray keybind, gray name cartKeybind = boldGrayStyle.Render("c") cartName = grayStyle.Render("cart") cartInfo = fmt.Sprintf(" %s %s", - boldWhiteStyle.Render(fmt.Sprintf("$%.2f", total)), + boldWhiteStyle.Render(fmt.Sprintf("$%.2f", float64(total)/100)), itemCountText) } cartTab := cartKeybind + " " + cartName + cartInfo diff --git a/pkg/tui/menu.go b/pkg/tui/menu.go index 01065cd..02a61c6 100644 --- a/pkg/tui/menu.go +++ b/pkg/tui/menu.go @@ -35,13 +35,13 @@ func (m Model) BuildMenuView() string { hint := base.Render("press esc to close") itemCount := 0 - total := 0.0 + total := 0 for _, item := range m.Cart { - total += float64(item.Quantity) * item.Coffee.Price + total += item.Quantity * item.Coffee.Price itemCount += item.Quantity } - cartHint := base.Render(fmt.Sprintf("cart $%.2f [%d]", total, itemCount)) + cartHint := base.Render(fmt.Sprintf("cart $%.2f [%d]", float64(total)/100, itemCount)) assembled := lipgloss.JoinVertical( lipgloss.Center, diff --git a/pkg/tui/model.go b/pkg/tui/model.go index ce328b1..c3f10c4 100644 --- a/pkg/tui/model.go +++ b/pkg/tui/model.go @@ -1433,7 +1433,7 @@ func NewModel(username string) Model { RoastType: "Dark Roast", Ounces: 2, BeanType: "Arabica", - Price: 3.50, + Price: 350, // $3.50 Color: "#8B4513", Description: "A bold, concentrated shot of pure coffee bliss. Perfect for those who need an immediate caffeine injection to survive the day.", }, @@ -1442,7 +1442,7 @@ func NewModel(username string) Model { RoastType: "Medium Roast", Ounces: 12, BeanType: "Arabica Blend", - Price: 5.00, + Price: 500, // $5.00 Color: "#D2691E", Description: "Smooth espresso paired with steamed milk and a light layer of foam. For when you want coffee but also want to feel fancy about it.", }, @@ -1451,7 +1451,7 @@ func NewModel(username string) Model { RoastType: "Medium Roast", Ounces: 8, BeanType: "Italian Blend", - Price: 4.50, + Price: 450, // $4.50 Color: "#CD853F", Description: "Equal parts espresso, steamed milk, and foam. The classic Italian choice for people who know what they're doing.", }, @@ -1460,7 +1460,7 @@ func NewModel(username string) Model { RoastType: "Dark Roast", Ounces: 16, BeanType: "Arabica", - Price: 4.00, + Price: 400, // $4.00 Color: "#A0522D", Description: "Espresso with hot water. Simple, strong, and no-nonsense. This is coffee for people who actually like the taste of coffee.", }, @@ -1469,7 +1469,7 @@ func NewModel(username string) Model { RoastType: "Medium Roast", Ounces: 16, BeanType: "Colombian", - Price: 5.50, + Price: 550, // $5.50 Color: "#4682B4", Description: "Some really good Mocha", }, @@ -1478,7 +1478,7 @@ func NewModel(username string) Model { RoastType: "Dark Roast", Ounces: 3, BeanType: "Robusta Blend", - Price: 4.25, + Price: 425, // $4.25 Color: "#DAA520", Description: "Espresso 'marked' with a dollop of foamed milk. Small but mighty, like a tiny caffeinated warrior.", }, diff --git a/pkg/tui/shop.go b/pkg/tui/shop.go index 0814102..6ebeb39 100644 --- a/pkg/tui/shop.go +++ b/pkg/tui/shop.go @@ -88,7 +88,7 @@ func (m Model) BuildShopView() string { selectedCoffee.RoastType, selectedCoffee.Ounces, selectedCoffee.BeanType)) + "\n\n" - detailView += priceStyle.Render(fmt.Sprintf("$%.2f", selectedCoffee.Price)) + "\n\n" + detailView += priceStyle.Render(fmt.Sprintf("$%.2f", float64(selectedCoffee.Price)/100)) + "\n\n" detailView += descStyle.Render(selectedCoffee.Description) + "\n\n" detailView += quantityStyle.Render(fmt.Sprintf("- %d +", quantity)) + "\n" }