Skip to content
1 change: 1 addition & 0 deletions Modules/Sources/Yosemite/Model/Model.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public typealias FallibleCancelable = Hardware.FallibleCancelable
public typealias CommentStatus = Networking.CommentStatus
public typealias CompositeComponentOptionType = Networking.CompositeComponentOptionType
public typealias Coupon = Networking.Coupon
public typealias CouponDiscountType = Networking.Coupon.DiscountType
public typealias CouponReport = Networking.CouponReport
public typealias Country = Networking.Country
public typealias CreateAccountResult = Networking.CreateAccountResult
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ import class Networking.AlamofireNetwork
import struct Combine.AnyPublisher
import struct NetworkingCore.JetpackSite

public struct PointOfSaleCouponFetchStrategyFactory {
public protocol PointOfSaleCouponFetchStrategyFactoryProtocol {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Note: a protocol was created so that StorageManagerType, a dependency of PointOfSaleCouponFetchStrategyFactory, does not need to be known in the future POS module.

var defaultStrategy: PointOfSaleCouponFetchStrategy { get }
func searchStrategy(searchTerm: String, analytics: POSItemFetchAnalyticsTracking) -> PointOfSaleCouponFetchStrategy
}

public struct PointOfSaleCouponFetchStrategyFactory: PointOfSaleCouponFetchStrategyFactoryProtocol {
private let siteID: Int64
private let currencySettings: CurrencySettings
private let storage: StorageManagerType
Expand All @@ -28,14 +33,14 @@ public struct PointOfSaleCouponFetchStrategyFactory {
self.couponStoreMethods = CouponStoreMethods(storageManager: storage, remote: remote)
}

public var defaultStrategy: PointOfSaleDefaultCouponFetchStrategy {
public var defaultStrategy: PointOfSaleCouponFetchStrategy {
PointOfSaleDefaultCouponFetchStrategy(siteID: siteID,
currencySettings: currencySettings,
storage: storage,
couponStoreMethods: couponStoreMethods)
}

public func searchStrategy(searchTerm: String, analytics: POSItemFetchAnalyticsTracking) -> PointOfSaleSearchCouponFetchStrategy {
public func searchStrategy(searchTerm: String, analytics: POSItemFetchAnalyticsTracking) -> PointOfSaleCouponFetchStrategy {
PointOfSaleSearchCouponFetchStrategy(siteID: siteID,
currencySettings: currencySettings,
storage: storage,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
protocol POSCollectOrderPaymentAnalyticsTracking {
public protocol POSCollectOrderPaymentAnalyticsTracking {
func trackCustomerInteractionStarted()
func trackOrderSyncSuccess()
func trackCardReaderReady()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

struct CardPresentPaymentCardReader: Equatable {
public struct CardPresentPaymentCardReader: Equatable {
let name: String

/// The reader's battery level, if available.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

enum CardPresentPaymentEvent {
public enum CardPresentPaymentEvent {
case idle
case show(eventDetails: CardPresentPaymentEventDetails)
case showOnboarding(factory: CardPresentPaymentOnboardingViewContainer, onCancel: () -> Void)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Foundation
import struct Yosemite.CardReaderInput

enum CardPresentPaymentEventDetails {
public enum CardPresentPaymentEventDetails {
case scanningForReaders(endSearch: () -> Void)
case scanningFailed(error: Error,
endSearch: () -> Void)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import enum Yosemite.PaymentChannel
import struct Yosemite.Order
import Combine

protocol CardPresentPaymentFacade {
public protocol CardPresentPaymentFacade {
/// `paymentEventPublisher` provides a stream of events relating to a payment, including their view models,
/// for subscribers to display to the user. e.g. onboarding screens, connection progress, payment progress, card reader messages.
/// This is a long lasting stream, and will not finish during the life of the façade, instead it will publish events for each payment attempt.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

enum CardPresentPaymentReaderConnectionResult {
public enum CardPresentPaymentReaderConnectionResult {
case connected(CardPresentPaymentCardReader)
case canceled
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

enum CardPresentPaymentReaderConnectionStatus: Equatable {
public enum CardPresentPaymentReaderConnectionStatus: Equatable {
case disconnected
case connected(CardPresentPaymentCardReader)
case cancellingConnection
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

enum CardPresentPaymentResult {
public enum CardPresentPaymentResult {
case success(CardPresentPaymentTransaction)
case cancellation
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

/// A completed, paid transaction.
struct CardPresentPaymentTransaction {
public struct CardPresentPaymentTransaction {
let receiptURL: URL
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Foundation
import enum Yosemite.CardReaderServiceError
import enum Yosemite.CardReaderServiceUnderlyingError

enum CardPresentPaymentRetryApproach {
public enum CardPresentPaymentRetryApproach {
case dontRetry
case tryAgain(retryAction: () -> Void)
case tryAnotherPaymentMethod(retryAction: () -> Void)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

enum CardReaderConnectionMethod {
public enum CardReaderConnectionMethod {
case bluetooth
case tapToPay
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import SwiftUI

protocol POSEntryPointEligibilityCheckerProtocol {
public protocol POSEntryPointEligibilityCheckerProtocol {
/// Determines whether the site is eligible for POS.
func checkEligibility() async -> POSEligibilityState
/// Refreshes the eligibility state based on the provided ineligible reason.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import Observation
import enum Yosemite.POSItem
import enum Yosemite.PointOfSaleCouponServiceError
import protocol Yosemite.PointOfSaleItemServiceProtocol
import protocol Yosemite.PointOfSaleCouponFetchStrategyFactoryProtocol
import protocol Yosemite.PointOfSaleCouponServiceProtocol
import struct Yosemite.PointOfSaleCouponFetchStrategyFactory
import protocol Yosemite.PointOfSaleCouponFetchStrategy
Expand All @@ -19,12 +20,12 @@ protocol PointOfSaleCouponsControllerProtocol: PointOfSaleSearchingItemsControll
private let paginationTracker: AsyncPaginationTracker
private var childPaginationTrackers: [POSItem: AsyncPaginationTracker] = [:]
private let couponProvider: PointOfSaleCouponServiceProtocol
private let fetchStrategyFactory: PointOfSaleCouponFetchStrategyFactory
private let fetchStrategyFactory: PointOfSaleCouponFetchStrategyFactoryProtocol
private var fetchStrategy: PointOfSaleCouponFetchStrategy
private let analyticsProvider: POSAnalyticsProviding

init(itemProvider: PointOfSaleCouponServiceProtocol,
fetchStrategyFactory: PointOfSaleCouponFetchStrategyFactory,
fetchStrategyFactory: PointOfSaleCouponFetchStrategyFactoryProtocol,
analyticsProvider: POSAnalyticsProviding) {
self.couponProvider = itemProvider
self.fetchStrategyFactory = fetchStrategyFactory
Expand Down
4 changes: 2 additions & 2 deletions WooCommerce/Classes/POS/Models/POSIneligibleReason.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import enum WooFoundation.CountryCode
import enum WooFoundation.CurrencyCode

/// Represents the reasons why a site may be ineligible for POS.
enum POSIneligibleReason: Equatable {
public enum POSIneligibleReason: Equatable {
case unsupportedIOSVersion
case unsupportedWooCommerceVersion(minimumVersion: String)
case siteSettingsNotAvailable
Expand All @@ -15,7 +15,7 @@ enum POSIneligibleReason: Equatable {
}

/// Represents the eligibility state for POS.
enum POSEligibilityState: Equatable {
public enum POSEligibilityState: Equatable {
case eligible
case ineligible(reason: POSIneligibleReason)
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ protocol CardPresentPaymentsOnboardingViewConfiguration: ObservableObject {
var state: CardPresentPaymentOnboardingState { get }
}

final class CardPresentPaymentOnboardingViewContainer: ObservableObject, Equatable, Identifiable {
public class CardPresentPaymentOnboardingViewContainer: ObservableObject, Equatable, Identifiable {
@Published var configuration: any CardPresentPaymentsOnboardingViewConfiguration
@Published var view: any View

Expand All @@ -17,7 +17,7 @@ final class CardPresentPaymentOnboardingViewContainer: ObservableObject, Equatab
self.view = view
}

static func == (lhs: CardPresentPaymentOnboardingViewContainer, rhs: CardPresentPaymentOnboardingViewContainer) -> Bool {
public static func == (lhs: CardPresentPaymentOnboardingViewContainer, rhs: CardPresentPaymentOnboardingViewContainer) -> Bool {
lhs.configuration.state == rhs.configuration.state
}
}
Expand Down
121 changes: 87 additions & 34 deletions WooCommerce/Classes/POS/Presentation/PointOfSaleEntryPointView.swift
Original file line number Diff line number Diff line change
@@ -1,8 +1,20 @@
import SwiftUI
import protocol Yosemite.POSOrderListFetchStrategyFactoryProtocol
import protocol Yosemite.POSOrderServiceProtocol
import protocol Yosemite.POSReceiptServiceProtocol
import protocol Yosemite.POSSearchHistoryProviding
import protocol Yosemite.PluginsServiceProtocol
import class Yosemite.PointOfSaleFixedItemFetchStrategyFactory
import protocol Yosemite.PointOfSaleBarcodeScanServiceProtocol
import struct Yosemite.PointOfSaleCouponFetchStrategyFactory
import protocol Yosemite.PointOfSaleCouponServiceProtocol
import protocol Yosemite.PointOfSaleItemFetchStrategyFactoryProtocol
import class Yosemite.PointOfSaleItemService
import protocol Yosemite.PointOfSaleSettingsServiceProtocol
import struct Yosemite.SiteSetting
import protocol Yosemite.PointOfSaleCouponFetchStrategyFactoryProtocol

struct PointOfSaleEntryPointView: View {
public struct PointOfSaleEntryPointView: View {
@State private var posModel: PointOfSaleAggregateModel?
@StateObject private var posModalManager = POSModalManager()
@StateObject private var posSheetManager = POSSheetManager()
Expand All @@ -26,43 +38,79 @@ struct PointOfSaleEntryPointView: View {
private let siteTimezone: TimeZone
private let services: POSDependencyProviding

init(itemsController: PointOfSaleItemsControllerProtocol,
purchasableItemsSearchController: PointOfSaleSearchingItemsControllerProtocol,
couponsController: PointOfSaleCouponsControllerProtocol,
couponsSearchController: PointOfSaleSearchingItemsControllerProtocol,
ordersController: POSSearchingOrderListControllerProtocol,
public init(siteID: Int64,
itemFetchStrategyFactory: PointOfSaleItemFetchStrategyFactoryProtocol,
popularItemFetchStrategyFactory: PointOfSaleItemFetchStrategyFactoryProtocol,
couponProvider: PointOfSaleCouponServiceProtocol,
couponFetchStrategyFactory: PointOfSaleCouponFetchStrategyFactoryProtocol,
orderListFetchStrategyFactory: POSOrderListFetchStrategyFactoryProtocol,
orderService: POSOrderServiceProtocol,
onPointOfSaleModeActiveStateChange: @escaping ((Bool) -> Void),
cardPresentPaymentService: CardPresentPaymentFacade,
orderController: PointOfSaleOrderControllerProtocol,
receiptSender: POSReceiptSending,
settingsController: PointOfSaleSettingsControllerProtocol,
receiptService: POSReceiptServiceProtocol,
pluginsService: PluginsServiceProtocol,
settingsService: PointOfSaleSettingsServiceProtocol,
collectOrderPaymentAnalyticsTracker: POSCollectOrderPaymentAnalyticsTracking,
searchHistoryService: POSSearchHistoryProviding,
popularPurchasableItemsController: PointOfSaleItemsControllerProtocol,
barcodeScanService: PointOfSaleBarcodeScanServiceProtocol,
posEligibilityChecker: POSEntryPointEligibilityCheckerProtocol,
siteTimezone: TimeZone = .current,
defaultSiteName: String?,
siteSettings: [SiteSetting],
services: POSDependencyProviding) {
self.onPointOfSaleModeActiveStateChange = onPointOfSaleModeActiveStateChange

self.itemsController = itemsController
self.purchasableItemsSearchController = purchasableItemsSearchController
self.couponsController = couponsController
self.couponsSearchController = couponsSearchController
self.itemsController = PointOfSaleItemsController(
itemProvider: PointOfSaleItemService(currencySettings: services.currency.currencySettings),
itemFetchStrategyFactory: itemFetchStrategyFactory,
analyticsProvider: services.analytics
)
self.purchasableItemsSearchController = PointOfSaleItemsController(
itemProvider: PointOfSaleItemService(currencySettings: services.currency.currencySettings),
itemFetchStrategyFactory: itemFetchStrategyFactory,
initialState: .init(containerState: .content,
itemsStack: .init(root: .loaded([], hasMoreItems: true), itemStates: [:])),
analyticsProvider: services.analytics
)
self.couponsController = PointOfSaleCouponsController(itemProvider: couponProvider,
fetchStrategyFactory: couponFetchStrategyFactory,
analyticsProvider: services.analytics)
self.couponsSearchController = PointOfSaleCouponsController(itemProvider: couponProvider,
fetchStrategyFactory: couponFetchStrategyFactory,
analyticsProvider: services.analytics)
self.cardPresentPaymentService = cardPresentPaymentService
self.orderController = orderController
self.settingsController = settingsController
let receiptSender = POSReceiptSender(siteID: siteID,
orderService: orderService,
receiptService: receiptService,
analytics: services.analytics,
featureFlagService: services.featureFlags,
pluginsService: pluginsService)
self.orderController = PointOfSaleOrderController(orderService: orderService,
receiptSender: receiptSender,
currencySettingsProvider: services.currency,
analytics: services.analytics)
self.settingsController = PointOfSaleSettingsController(siteID: siteID,
settingsService: settingsService,
cardPresentPaymentService: cardPresentPaymentService,
pluginsService: pluginsService,
defaultSiteName: defaultSiteName,
siteSettings: siteSettings)
self.collectOrderPaymentAnalyticsTracker = collectOrderPaymentAnalyticsTracker
self.searchHistoryService = searchHistoryService
self.popularPurchasableItemsController = popularPurchasableItemsController
self.popularPurchasableItemsController = PointOfSaleItemsController(
itemProvider: PointOfSaleItemService(currencySettings: services.currency.currencySettings),
itemFetchStrategyFactory: popularItemFetchStrategyFactory,
analyticsProvider: services.analytics
)
self.barcodeScanService = barcodeScanService
self.posEntryPointController = POSEntryPointController(eligibilityChecker: posEligibilityChecker)
let ordersController = POSOrderListController(orderListFetchStrategyFactory: orderListFetchStrategyFactory)
self.orderListModel = POSOrderListModel(ordersController: ordersController, receiptSender: receiptSender)
self.siteTimezone = siteTimezone
self.services = services
}

var body: some View {
public var body: some View {
Group {
if let posModel {
PointOfSaleDashboardView()
Expand Down Expand Up @@ -115,22 +163,27 @@ struct PointOfSaleEntryPointView: View {

#if DEBUG
#Preview {
PointOfSaleEntryPointView(itemsController: PointOfSalePreviewItemsController(),
purchasableItemsSearchController: PointOfSalePreviewItemsController(),
couponsController: PointOfSalePreviewCouponsController(),
couponsSearchController: PointOfSalePreviewCouponsController(),
ordersController: POSConfigurablePreviewOrderListController(),
onPointOfSaleModeActiveStateChange: { _ in },
cardPresentPaymentService: CardPresentPaymentPreviewService(),
orderController: PointOfSalePreviewOrderController(),
receiptSender: POSReceiptSenderPreview(),
settingsController: PointOfSaleSettingsPreviewController(),
collectOrderPaymentAnalyticsTracker: POSCollectOrderPaymentPreviewAnalytics(),
searchHistoryService: PointOfSalePreviewHistoryService(),
popularPurchasableItemsController: PointOfSalePreviewItemsController(),
barcodeScanService: PointOfSalePreviewBarcodeScanService(),
posEligibilityChecker: POSTabEligibilityChecker(siteID: 1),
services: POSPreviewServices())
PointOfSaleEntryPointView(
siteID: 1,
itemFetchStrategyFactory: PointOfSaleItemFetchStrategyFactoryPreview(),
popularItemFetchStrategyFactory: PointOfSaleItemFetchStrategyFactoryPreview(),
couponProvider: PointOfSaleCouponServicePreview(),
couponFetchStrategyFactory: PointOfSaleCouponFetchStrategyFactoryPreview(),
orderListFetchStrategyFactory: POSOrderListFetchStrategyFactoryPreview(),
orderService: POSOrderServicePreview(),
onPointOfSaleModeActiveStateChange: { _ in },
cardPresentPaymentService: CardPresentPaymentPreviewService(),
receiptService: POSReceiptServicePreview(),
pluginsService: PluginsServicePreview(),
settingsService: PointOfSaleSettingsServicePreview(),
collectOrderPaymentAnalyticsTracker: POSCollectOrderPaymentPreviewAnalytics(),
searchHistoryService: PointOfSalePreviewHistoryService(),
barcodeScanService: PointOfSalePreviewBarcodeScanService(),
posEligibilityChecker: PointOfSalePreviewTabEligibilityChecker(),
defaultSiteName: "Demo Store",
siteSettings: [],
services: POSPreviewServices()
)
}

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import SwiftUI
struct PointOfSaleSettingsView: View {
@Environment(\.dismiss) private var dismiss
@Environment(\.posAnalytics) private var analytics
@Environment(\.posFeatureFlags) private var featureFlags
@State private var selection: SidebarNavigation? = .store

let settingsController: PointOfSaleSettingsControllerProtocol
Expand Down Expand Up @@ -55,7 +56,7 @@ extension PointOfSaleSettingsView {
)

// TODO: WOOMOB-1287 - integrate with local catalog feature eligibility
if ServiceLocator.featureFlagService.isFeatureFlagEnabled(.pointOfSaleLocalCatalogi1) {
if featureFlags.isFeatureFlagEnabled(.pointOfSaleLocalCatalogi1) {
PointOfSaleSettingsCard(
item: .localCatalog,
isSelected: selection == .localCatalog,
Expand Down
Loading
Loading