Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
1816b32
Enable animation on item lists
joshheald Nov 28, 2025
c89c7e3
Rename Identifier<T> to POSItemIdentifier and remove siteID
joshheald Nov 28, 2025
ea8f0b5
Update item mappers to use POSItemIdentifier
joshheald Nov 28, 2025
f064c79
Add posItemIdentifier to CartItem protocol
joshheald Nov 28, 2025
c0c7707
Enable coupon duplicate detection using posItemIdentifier
joshheald Nov 28, 2025
5a83e8a
Update preview helpers and mocks for POSItemIdentifier
joshheald Nov 28, 2025
68616cc
Fix hardcoded itemID and update test mocks for POSItemIdentifier
joshheald Nov 28, 2025
08732bf
Update all test files to use POSItemIdentifier
joshheald Nov 28, 2025
4db8129
Add .error case to POSItemIdentifier.UnderlyingType
joshheald Nov 28, 2025
7c10049
Update preview helpers and views to use POSItemIdentifier
joshheald Nov 28, 2025
0f7018b
Make identifier copyable and fakable
joshheald Nov 28, 2025
6b34d33
Update MockPOSOrderableItem to use POSItemIdentifier
joshheald Nov 28, 2025
93810fb
Update MockPointOfSaleCouponService to use POSItemIdentifier
joshheald Nov 28, 2025
fe6d2ff
Update POSCartItemTests.makeCartItem to use POSItemIdentifier
joshheald Nov 28, 2025
6abb8be
Fix POSItemActionHandlerFactoryTests helper functions
joshheald Nov 28, 2025
9e25821
Fix CartViewHelperTests to use correct Cart item constructors
joshheald Nov 28, 2025
3aa8ceb
Add POSItemIdentifier import to POSItemActionHandlerTests
joshheald Nov 28, 2025
3741ea4
Fix TotalsViewHelperTests to use POSItemIdentifier
joshheald Nov 28, 2025
33569f4
Add POSItemIdentifier imports to test files
joshheald Nov 28, 2025
a02954c
Fix PointOfSaleOrderControllerTests to use dual-identifier architecture
joshheald Nov 28, 2025
bfd4b2d
Add missing POSItemIdentifier import to TotalsViewHelperTests
joshheald Nov 28, 2025
c5362dd
Fix test helper functions in PointOfSaleObservableItemsControllerTests
joshheald Nov 28, 2025
ca33409
Add missing POSItemIdentifier import to PointOfSaleItemsControllerTests
joshheald Nov 28, 2025
f076409
Fix import in aggregate model tests
joshheald Nov 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions Modules/Sources/Fakes/Yosemite.generated.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,23 @@ extension Yosemite.JustInTimeMessageTemplate {
.banner
}
}
extension Yosemite.POSItemIdentifier {
/// Returns a "ready to use" type filled with fake values.
///
public static func fake() -> Yosemite.POSItemIdentifier {
.init(
underlyingType: .fake(),
itemID: .fake()
)
}
}
extension Yosemite.POSItemIdentifier.UnderlyingType {
/// Returns a "ready to use" type filled with fake values.
///
public static func fake() -> Yosemite.POSItemIdentifier.UnderlyingType {
.product
}
}
extension Yosemite.POSSimpleProduct {
/// Returns a "ready to use" type filled with fake values.
///
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ private extension POSCart {
guard case let .loaded(item) = purchasableItem.state else { return nil }
return POSCartItem(item: item, quantity: Decimal(purchasableItem.quantity))
}
let coupons = cart.coupons.map { POSCoupon(id: $0.id, code: $0.code, summary: $0.summary) }
let coupons = cart.coupons.map { POSCoupon(id: $0.posItemIdentifier, code: $0.code, summary: $0.summary) }
self.init(items: items, coupons: coupons)
}
}
Expand Down
16 changes: 15 additions & 1 deletion Modules/Sources/PointOfSale/Models/Cart.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import Foundation
import protocol Yosemite.POSOrderableItem
import enum Yosemite.POSItem
import enum Yosemite.PointOfSaleBarcodeScanError
import struct Yosemite.POSItemIdentifier

struct Cart {
var purchasableItems: [Cart.PurchasableItem] = []
Expand All @@ -12,6 +13,7 @@ struct Cart {

protocol CartItem {
var id: UUID { get }
var posItemIdentifier: POSItemIdentifier { get }
var type: CartItemType { get }
}

Expand All @@ -36,6 +38,17 @@ extension Cart {
case error
}

var posItemIdentifier: POSItemIdentifier {
switch state {
case .loaded(let item):
return item.id
case .loading:
return POSItemIdentifier(underlyingType: .loading, itemID: 0)
case .error:
return POSItemIdentifier(underlyingType: .error, itemID: 0)
}
}

var formattedPrice: String? {
switch state {
case .loaded(let item):
Expand Down Expand Up @@ -76,6 +89,7 @@ extension Cart {

struct CouponItem: CartItem {
let id: UUID
let posItemIdentifier: POSItemIdentifier
let code: String
let summary: String
let type: CartItemType = .coupon
Expand All @@ -89,7 +103,7 @@ extension Cart {
if let purchasableItem = createPurchasableItem(from: posItem) {
purchasableItems.insert(purchasableItem, at: purchasableItems.startIndex)
} else if case .coupon(let coupon) = posItem {
let couponItem = Cart.CouponItem(id: coupon.id, code: coupon.code, summary: coupon.summary)
let couponItem = Cart.CouponItem(id: UUID(), posItemIdentifier: coupon.id, code: coupon.code, summary: coupon.summary)
coupons.insert(couponItem, at: coupons.startIndex)
}
}
Expand Down
2 changes: 1 addition & 1 deletion Modules/Sources/PointOfSale/Presentation/CartView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,7 @@ private extension CartView {

#Preview("Cart with one item") {
let posModel = POSPreviewHelpers.makePreviewAggregateModel()
posModel.addToCart(.simpleProduct(.init(id: UUID(),
posModel.addToCart(.simpleProduct(.init(id: .init(underlyingType: .product, itemID: 6),
name: "Sample Product",
formattedPrice: "$10.00",
productID: 6,
Expand Down
5 changes: 4 additions & 1 deletion Modules/Sources/PointOfSale/Presentation/CouponRowView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ private extension CouponRowView {

#if DEBUG
#Preview(traits: .sizeThatFitsLayout) {
CouponRowView(couponItem: Cart.CouponItem(id: UUID(), code: "10-Discount", summary: "$10 Off · All products"), couponRowState: .idle) {}
CouponRowView(couponItem: Cart.CouponItem(id: UUID(),
posItemIdentifier: .init(underlyingType: .coupon, itemID: 123),
code: "10-Discount",
summary: "$10 Off · All products"), couponRowState: .idle) {}
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import SwiftUI
import class WooFoundation.CurrencySettings
import struct Yosemite.Coupon
import enum Yosemite.POSItem
import struct Yosemite.POSItemIdentifier
import struct Yosemite.POSCoupon

extension View {
Expand Down Expand Up @@ -31,7 +32,8 @@ private struct POSCouponCreationSheetModifier: ViewModifier {
discountType: posDiscountType.discountType,
showTypeSelection: $showCouponSelectionSheet,
onSuccess: { coupon in
addedCouponItem = .coupon(.init(id: UUID(), code: coupon.code, summary: coupon.summary(currencySettings: currencySettings)))
let id = POSItemIdentifier(underlyingType: .coupon, itemID: coupon.couponID)
addedCouponItem = .coupon(.init(id: id, code: coupon.code, summary: coupon.summary(currencySettings: currencySettings)))
Comment on lines +35 to +36
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This hints that we could create the POSItemIdentifier internally within the POSItem rather than injecting it, have you had the chance to explore it, and if makes sense to do so?

},
dismissHandler: {
selectedType = nil
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ private extension ChildItemList {

#Preview("Variable product child items") {
let parentProduct = POSVariableParentProduct(
id: .init(),
id: .init(underlyingType: .product, itemID: 1),
name: "Variable latte",
productImageSource: nil,
productID: 1
Expand All @@ -134,7 +134,7 @@ private extension ChildItemList {
[
.variation(
POSVariation(
id: .init(),
id: .init(underlyingType: .variation, itemID: 256),
name: "Cinamon chestnut latte",
formattedPrice: "$5.75",
price: "5.75",
Expand All @@ -145,12 +145,12 @@ private extension ChildItemList {
),
.variation(
POSVariation(
id: .init(),
id: .init(underlyingType: .variation, itemID: 2567),
name: "Choco latte",
formattedPrice: "$6.5",
price: "6.5",
productID: 134,
variationID: 256,
variationID: 2567,
parentProductName: parentProduct.name
)
)
Expand All @@ -170,7 +170,7 @@ private extension ChildItemList {

#Preview("Variable items load error") {
let parentProduct = POSVariableParentProduct(
id: .init(),
id: .init(underlyingType: .product, itemID: 1),
name: "Variable latte",
productImageSource: nil,
productID: 1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ private extension CouponCardView {
.font(.caption)
.foregroundStyle(.secondary)
CouponCardView(coupon: .init(
id: .init(),
id: .init(underlyingType: .coupon, itemID: 1),
code: "Coupon-123",
summary: "10% off - All Products"
))
Expand All @@ -101,7 +101,7 @@ private extension CouponCardView {
.font(.caption)
.foregroundStyle(.secondary)
CouponCardView(coupon: .init(
id: .init(),
id: .init(underlyingType: .coupon, itemID: 2),
code: "Old-Coupon-123",
summary: "10% off - All Products",
dateExpires: Calendar.current.date(byAdding: .month, value: -1, to: Date())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ struct ItemList<HeaderView: View>: View {
.frame(maxWidth: .infinity)
.padding(.horizontal, Constants.itemListPadding)
.padding(.bottom, keyboardObserver.isFullSizeKeyboardVisible ? Constants.itemListPadding : floatingControlAreaSize.height)
.animation(.default, value: state?.items)
}
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ extension POSItemActionHandler {
func shouldSkipDuplicate(_ item: POSItem, posModel: PointOfSaleAggregateModelProtocol) -> Bool {
switch item {
case .coupon:
return posModel.cart.coupons.contains(where: { $0.id == item.id })
return posModel.cart.coupons.contains(where: { $0.posItemIdentifier == item.id })
default:
return false
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ private extension SimpleProductCardView {

#if DEBUG
#Preview {
SimpleProductCardView(product: POSSimpleProduct(id: UUID(),
SimpleProductCardView(product: POSSimpleProduct(id: .init(underlyingType: .product, itemID: 123),
name: "Product name",
formattedPrice: "$3.00",
productID: 123,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ private extension VariationCardView {
}

#Preview("Variation without image") {
let variation = POSVariation(id: .init(),
let variation = POSVariation(id: .init(underlyingType: .variation, itemID: 256),
name: "500ml, double shot",
formattedPrice: "$5.00",
price: "5.00",
Expand All @@ -59,13 +59,13 @@ private extension VariationCardView {
}

#Preview("Variation with image") {
let variation = POSVariation(id: .init(),
let variation = POSVariation(id: .init(underlyingType: .variation, itemID: 257),
name: "500ml, double shot",
formattedPrice: "$5.00",
price: "5.00",
productImageSource: "https://pd.w.org/2024/12/986762d0d4d4cf17.82435881-scaled.jpeg",
productID: 134,
variationID: 256,
variationID: 257,
parentProductName: "Coffee")
VariationCardView(variation: variation)
}
15 changes: 8 additions & 7 deletions Modules/Sources/PointOfSale/Utils/PreviewHelpers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,12 @@ import protocol Yosemite.POSItemFetchAnalyticsTracking
import protocol Yosemite.POSOrderListFetchStrategyFactoryProtocol
import protocol Yosemite.POSOrderListFetchStrategy
import protocol Yosemite.PointOfSaleCouponFetchStrategyFactoryProtocol
import struct Yosemite.POSItemIdentifier

// MARK: - PreviewProvider helpers
//
struct POSProductPreview: POSOrderableItem, Equatable {
let id: UUID
let id: POSItemIdentifier
let name: String
let formattedPrice: String
var productImageSource: String?
Expand Down Expand Up @@ -86,7 +87,7 @@ final class PointOfSalePreviewItemService: PointOfSaleItemServiceProtocol {
}

func providePointOfSaleItem() -> POSOrderableItem {
POSProductPreview(id: UUID(),
POSProductPreview(id: POSItemIdentifier(underlyingType: .product, itemID: 1),
name: "Product 1",
formattedPrice: "$1.00")
}
Expand Down Expand Up @@ -168,7 +169,7 @@ private var mockItems: [POSItem] {
mockSimpleProductItem(id: 3, price: "3.00"),
.variableParentProduct(
.init(
id: .init(),
id: POSItemIdentifier(underlyingType: .product, itemID: 5),
name: "Variable product 1",
productImageSource: nil,
productID: 5
Expand All @@ -179,7 +180,7 @@ private var mockItems: [POSItem] {
}

private func mockSimpleProductItem(id: Int, price: String) -> POSItem {
.simpleProduct(POSSimpleProduct(id: UUID(),
.simpleProduct(POSSimpleProduct(id: POSItemIdentifier(underlyingType: .product, itemID: Int64(id)),
name: "Product \(id)",
formattedPrice: "$\(price)",
productID: Int64(id),
Expand All @@ -191,19 +192,19 @@ private func mockSimpleProductItem(id: Int, price: String) -> POSItem {

private var mockVariationItems: [POSItem] {
[
.variation(.init(id: UUID(),
.variation(.init(id: POSItemIdentifier(underlyingType: .variation, itemID: 256),
name: "Variation 1",
formattedPrice: "$1.00",
price: "1.00",
productID: 134,
variationID: 256,
parentProductName: "Variable product")),
.variation(.init(id: UUID(),
.variation(.init(id: POSItemIdentifier(underlyingType: .variation, itemID: 257),
name: "Variation 2",
formattedPrice: "$2.00",
price: "2.00",
productID: 134,
variationID: 256,
variationID: 257,
parentProductName: "Variable product")),
]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import Foundation
import Networking
import WooFoundation
import enum NetworkingCore.OrderStatusEnum
import struct Networking.PagedItems
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one can be removed, we're already importing Networking.

import struct NetworkingCore.Address
import struct NetworkingCore.MetaData
import struct NetworkingCore.Order
Expand Down Expand Up @@ -58,6 +59,21 @@ extension Yosemite.JustInTimeMessage {
}
}

extension Yosemite.POSItemIdentifier {
public func copy(
underlyingType: CopiableProp<POSItemIdentifier.UnderlyingType> = .copy,
itemID: CopiableProp<Int64> = .copy
) -> Yosemite.POSItemIdentifier {
let underlyingType = underlyingType ?? self.underlyingType
let itemID = itemID ?? self.itemID

return Yosemite.POSItemIdentifier(
underlyingType: underlyingType,
itemID: itemID
)
}
}

extension Yosemite.POSOrder {
public func copy(
id: CopiableProp<Int64> = .copy,
Expand Down Expand Up @@ -111,7 +127,7 @@ extension Yosemite.POSOrder {

extension Yosemite.POSSimpleProduct {
public func copy(
id: CopiableProp<UUID> = .copy,
id: CopiableProp<POSItemIdentifier> = .copy,
name: CopiableProp<String> = .copy,
formattedPrice: CopiableProp<String> = .copy,
productImageSource: NullableCopiableProp<String> = .copy,
Expand Down
4 changes: 2 additions & 2 deletions Modules/Sources/Yosemite/PointOfSale/Coupons/POSCoupon.swift
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import Foundation

public struct POSCoupon: Equatable, Hashable {
public let id: UUID
public let id: POSItemIdentifier
public let code: String
public let summary: String
public var dateExpires: Date?

public init(id: UUID, code: String, summary: String = "", dateExpires: Date? = nil) {
public init(id: POSItemIdentifier, code: String, summary: String = "", dateExpires: Date? = nil) {
self.id = id
self.code = code
self.summary = summary
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ private struct CouponResultsControllerAdapter {
private func mapCouponsToPOSItems(coupons: [Coupon]) -> [POSItem] {
coupons.compactMap { coupon in
.coupon(POSCoupon(
id: UUID(),
id: POSItemIdentifier(underlyingType: .coupon, itemID: coupon.couponID),
code: coupon.code,
summary: coupon.summary(currencySettings: currencySettings),
dateExpires: coupon.dateExpires
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Networking

public struct POSSimpleProduct: POSOrderableItem, OrderSyncProductTypeProtocol {
// POSOrderableItem
public let id: UUID
public let id: POSItemIdentifier
public let name: String
public let formattedPrice: String
public var productImageSource: String?
Expand All @@ -24,7 +24,7 @@ public struct POSSimpleProduct: POSOrderableItem, OrderSyncProductTypeProtocol {
return ProductStockStatus(rawValue: stockStatusKey)
}

public init(id: UUID,
public init(id: POSItemIdentifier,
name: String,
formattedPrice: String,
productImageSource: String? = nil,
Expand Down
Loading
Loading