Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ final class DashboardViewController: UIViewController {
observeStatsVersionForDashboardUIUpdates()
observeAnnouncements()
observeShowWebViewSheet()
observeAddProductTrigger()
viewModel.syncAnnouncements(for: siteID)
Task { @MainActor in
await reloadDashboardUIStatsVersion(forced: true)
Expand Down Expand Up @@ -303,6 +304,28 @@ private extension DashboardViewController {
present(hostingController, animated: true, completion: nil)
}

/// Subscribes to the trigger to start the Add Product flow for products onboarding
///
private func observeAddProductTrigger() {
viewModel.addProductTrigger.sink { [weak self] _ in
self?.startAddProductFlow()
}
.store(in: &subscriptions)
}

/// Starts the Add Product flow (without switching tabs)
///
private func startAddProductFlow() {
guard let announcementView, let navigationController else { return }
let coordinator = AddProductCoordinator(siteID: siteID, sourceView: announcementView, sourceNavigationController: navigationController)
coordinator.onProductCreated = { [weak self] in
guard let self else { return }
self.viewModel.announcementViewModel = nil // Remove the products onboarding banner
self.viewModel.syncAnnouncements(for: self.siteID)
}
coordinator.start()
}

// This is used so we have a specific type for the view while applying modifiers.
struct AnnouncementCardWrapper: View {
let cardView: FeatureAnnouncementCardView
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Yosemite
import Combine
import enum Networking.DotcomError
import enum Storage.StatsVersion
import protocol Experiments.FeatureFlagService
Expand All @@ -13,6 +14,10 @@ final class DashboardViewModel {

@Published private(set) var showWebViewSheet: WebViewSheetViewModel? = nil

/// Trigger to start the Add Product flow
///
let addProductTrigger = PassthroughSubject<Void, Never>()

private let stores: StoresManager
private let featureFlagService: FeatureFlagService
private let analytics: Analytics
Expand Down Expand Up @@ -154,8 +159,7 @@ final class DashboardViewModel {
guard let self else { return }
if case let .success(isVisible) = result, isVisible {
let viewModel = ProductsOnboardingAnnouncementCardViewModel(onCTATapped: { [weak self] in
self?.announcementViewModel = nil // Dismiss announcement
MainTabBarController.presentAddProductFlow()
self?.addProductTrigger.send()
})
self.announcementViewModel = viewModel
}
Expand Down
13 changes: 0 additions & 13 deletions WooCommerce/Classes/ViewRelated/MainTabBarController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -414,19 +414,6 @@ extension MainTabBarController {
}
}

static func presentAddProductFlow() {
navigateTo(.products)

guard let productsViewController: ProductsViewController = childViewController() else {
return
}

// We give some time for the products tab transition to finish, so the add product button is present to start the flow
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
productsViewController.addProduct()
}
}

static func presentPayments() {
switchToHubMenuTab()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ final class AddProductCoordinator: Coordinator {
return controller
}()

/// Assign this closure to be notified when a new product is saved remotely
///
var onProductCreated: () -> Void = {}

init(siteID: Int64,
sourceBarButtonItem: UIBarButtonItem,
sourceNavigationController: UINavigationController,
Expand Down Expand Up @@ -211,6 +215,7 @@ private extension AddProductCoordinator {
let viewModel = ProductFormViewModel(product: model,
formType: .add,
productImageActionHandler: productImageActionHandler)
viewModel.onProductCreated = onProductCreated
let viewController = ProductFormViewController(viewModel: viewModel,
eventLogger: ProductFormEventLogger(),
productImageActionHandler: productImageActionHandler,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,10 @@ final class ProductFormViewModel: ProductFormViewModelProtocol {

private let featureFlagService: FeatureFlagService

/// Assign this closure to be notified when a new product is saved remotely
///
var onProductCreated: () -> Void = {}

init(product: EditableProductModel,
formType: ProductFormType,
productImageActionHandler: ProductImageActionHandler,
Expand Down Expand Up @@ -432,7 +436,7 @@ extension ProductFormViewModel {
let productWithStatusUpdated = product.product.copy(statusKey: status.rawValue)
return EditableProductModel(product: productWithStatusUpdated)
}()
let remoteActionUseCase = ProductFormRemoteActionUseCase()
let remoteActionUseCase = ProductFormRemoteActionUseCase(stores: stores)
switch formType {
case .add:
let productIDBeforeSave = productModel.productID
Expand All @@ -449,6 +453,7 @@ extension ProductFormViewModel {
onCompletion(.success(data.product))
self.replaceProductID(productIDBeforeSave: productIDBeforeSave)
self.saveProductImagesWhenNoneIsPendingUploadAnymore()
self.onProductCreated()
}
}
case .edit:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,16 +220,6 @@ final class ProductsViewController: UIViewController, GhostableViewController {
}
}

// MARK: - Public API
//
extension ProductsViewController {
/// Adds a new product using the "Add Product" navigation bar button as the source
///
func addProduct() {
addProduct(addProductButton)
}
}

// MARK: - Navigation Bar Actions
//
private extension ProductsViewController {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,30 @@ final class ProductFormViewModelTests: XCTestCase {
let hasLinkedProducts = try XCTUnwrap(analyticsProvider.receivedProperties.first?["has_linked_products"] as? Bool)
XCTAssertTrue(hasLinkedProducts)
}

func test_onProductCreated_called_when_new_product_saved_remotely() {
// Given
var isCallbackCalled = false
let stores = MockStoresManager(sessionManager: .testingInstance)
let viewModel = createViewModel(product: Product.fake(), formType: .add, stores: stores)
viewModel.onProductCreated = {
isCallbackCalled = true
}

// When
stores.whenReceivingAction(ofType: ProductAction.self) { action in
switch action {
case let .addProduct(product, onCompletion):
onCompletion(.success(product))
default:
XCTFail("Received unsupported action: \(action)")
}
}
viewModel.saveProductRemotely(status: .draft) { _ in }

// Then
XCTAssertTrue(isCallbackCalled)
}
}

private extension ProductFormViewModelTests {
Expand Down