Skip to content

Conversation

@iamgabrielma
Copy link
Contributor

@iamgabrielma iamgabrielma commented Mar 14, 2025

Closes: #15346

Description

This PR hooks the item provider with the UI, allowing the item list to either display a list of Products/Variations or Coupons on tapping a button, so it provides a basic interface to access those coupons and add them to the cart (future PR) from the dashboard.

Screen.Recording.2025-03-14.at.10.24.18.mov

Changes

  • Switched the feature flag off to not bother development in trunk, since now we have some dummy UI
  • Created a POSItemType
  • Make the items controller to switch between fetching products/variations or coupons from storage based on the POSItemType state.
  • Added dummy buttons to the dashboard, which only render under feature flag, so different types can be loaded as a list.
  • Updated the coupons returning type from [POSItem] to PagedItems<POSItem> so these can be listed.

Testing

  • Set enableCouponsInPointOfSale flag to true
  • Using a store with coupons enabled in WC settings, assure that we have coupons in local storage by going to Menu > Coupons
  • Run the app, load POS, observe that products are loaded normally and variations still work as expected.
  • Tap the "Coupons" button and observe how these are shown in a list. Trying to add to cart will just display a debug log to the console.
  • Switching back to products should load product list normally after a second or two, the loading state and transitions haven't been implemented yet.

  • I have considered if this change warrants user-facing release notes and have added them to RELEASE-NOTES.txt if necessary.

Reviewer (or Author, in the case of optional code reviews):

Please make sure these conditions are met before approving the PR, or request changes if the PR needs improvement:

  • The PR is small and has a clear, single focus, or a valid explanation is provided in the description. If needed, please request to split it into smaller PRs.
  • Ensure Adequate Unit Test Coverage: The changes are reasonably covered by unit tests or an explanation is provided in the PR description.
  • Manual Testing: The author listed all the tests they ran, including smoke tests when needed (e.g., for refactorings). The reviewer confirmed that the PR works as expected on all devices (phone/tablet) and no regressions are added.

@coderabbitai
Copy link

coderabbitai bot commented Mar 14, 2025

Important

Review skipped

Auto reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

📝 Walkthrough

Walkthrough

This pull request disables the coupons feature flag by hardcoding its value to false. It adds functionality to toggle between product and coupon item types by introducing a new enum and asynchronous methods in the point-of-sale controllers and aggregate model. The UI is updated with a new SwiftUI view for displaying coupon details and a toggle interface in the item list view. Additionally, several data-fetching methods have been updated to return paged results and to throw errors, and corresponding test mocks and service protocols have been modified accordingly.

Changes

File(s) Change Summary
Experiments/.../DefaultFeatureFlagService.swift Modified enableCouponsInPointOfSale to always return false, disabling the feature in all build configurations.
WooCommerce/.../Controllers/PointOfSaleItemsController.swift Introduced POSItemType enum with .products and .coupons, added async toggleItemType() method, updated fetchItems to conditionally retrieve products or coupons, and removed the private coupon loader.
WooCommerce/.../Models/PointOfSaleAggregateModel.swift Added async toggleItemType() method that calls the controller method, and included a debug print in the coupon handling logic.
WooCommerce/.../Item Selector/CouponCardView.swift, WooCommerce/.../Item Selector/ItemList.swift Added new SwiftUI view CouponCardView for coupon details; updated ItemList to render a button with CouponCardView for coupon cases, triggering addToCart.
WooCommerce/.../ItemListView.swift Added a computed property (shouldShowCoupons) that checks the coupons feature flag and introduced an HStack with "Products" and "Coupons" buttons that call toggleItemType().
WooCommerce/.../Utils/PreviewHelpers.swift Updated providePointOfSaleCoupons to return a PagedItems<POSItem> with pagination info and added an async toggleItemType() method in the preview items controller.
WooCommerce/xcodeproj/project.pbxproj Added file reference entries for CouponCardView.swift to include it in the Xcode project’s build phases and group structure.
WooCommerceTests/.../MockPOSItemProvider.swift Updated providePointOfSaleCoupons to return paginated items (PagedItems<POSItem>) and modified the method to be throwable for error handling.
Yosemite/.../PointOfSaleItemService.swift,
Yosemite/.../PointOfSaleItemServiceProtocol.swift
Changed providePointOfSaleCoupons to throw errors and return PagedItems<POSItem>, and added a new error case (storageFailure) to the service’s error enum.

Sequence Diagram(s)

sequenceDiagram
    participant U as User
    participant ILV as ItemListView
    participant PM as PointOfSaleAggregateModel
    participant PIC as PointOfSaleItemsController
    participant DS as DataService

    U->>ILV: Tap "Products"/"Coupons" button
    ILV->>PM: toggleItemType()
    PM->>PIC: toggleItemType()
    PIC->>PIC: Toggle itemType (.products ↔ .coupons)
    PIC->>DS: fetchItems(pageNumber, based on itemType)
    DS-->>PIC: Return paged items
    PIC-->>PM: Updated item list
    PM-->>ILV: Refresh UI with new items
Loading
sequenceDiagram
    participant U as User
    participant IL as ItemList
    participant PM as PointOfSaleAggregateModel
    participant Cart as CartManager

    U->>IL: Tap coupon button (CouponCardView)
    IL->>PM: addToCart(coupon)
    PM->>Cart: Process coupon addition to cart
Loading

Suggested labels

feature: shipping labels

Suggested reviewers

  • joshheald
  • pmusolino

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@wpmobilebot
Copy link
Collaborator

wpmobilebot commented Mar 14, 2025

WooCommerce iOS📲 You can test the changes from this Pull Request in WooCommerce iOS by scanning the QR code below to install the corresponding build.

App NameWooCommerce iOS WooCommerce iOS
Build Numberpr15366-249f75f
Version22.0
Bundle IDcom.automattic.alpha.woocommerce
Commit249f75f
App Center BuildWooCommerce - Prototype Builds #13400
Automatticians: You can use our internal self-serve MC tool to give yourself access to App Center if needed.

Fetching from storage can fail, also we can reuse the error handling from items controller
Now that we have dummy UI updates we should keep the flag off in trunk
@iamgabrielma iamgabrielma added feature: coupons Related to basic fulfillment such as order tracking. feature: POS labels Mar 14, 2025
@iamgabrielma iamgabrielma added this to the 22.0 milestone Mar 14, 2025
@iamgabrielma iamgabrielma added the type: task An internally driven task. label Mar 14, 2025
@iamgabrielma iamgabrielma marked this pull request as ready for review March 14, 2025 05:35
@iamgabrielma
Copy link
Contributor Author

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Mar 14, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@iamgabrielma iamgabrielma requested a review from staskus March 14, 2025 05:38
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (4)
WooCommerce/Classes/POS/Presentation/Item Selector/CouponCardView.swift (1)

4-17: Simple CouponCardView implementation needs enhancement

The implementation is functional but quite basic. Consider the following improvements:

  1. Add proper styling to match the app's design language
  2. Display more user-friendly coupon information (e.g., code, amount, description) rather than just technical IDs
  3. Include accessibility labels and hints for VoiceOver support
struct CouponCardView: View {
    private let coupon: POSCoupon

    init(coupon: POSCoupon) {
        self.coupon = coupon
    }

    var body: some View {
-        HStack {
-            Text(coupon.id.uuidString)
-            Text(coupon.couponID.description)
-        }
+        VStack(alignment: .leading, spacing: 4) {
+            Text(coupon.code ?? "Coupon")
+                .font(.headline)
+            HStack {
+                Text("Discount: ")
+                    .font(.subheadline)
+                    .foregroundColor(.secondary)
+                Text(coupon.formattedAmount ?? "Unknown amount")
+                    .font(.subheadline)
+            }
+            if let description = coupon.description, !description.isEmpty {
+                Text(description)
+                    .font(.caption)
+                    .foregroundColor(.secondary)
+                    .lineLimit(2)
+            }
+        }
+        .padding()
+        .accessibilityLabel("\(coupon.code ?? "Coupon"), \(coupon.formattedAmount ?? "Unknown amount")")
    }
}
WooCommerce/Classes/POS/Presentation/ItemListView.swift (1)

163-167: Function implementation is correct but lacks state tracking.

The function correctly calls the model's toggleItemType() method asynchronously, but there's no way to track or update the UI state based on the current item type.

Consider enhancing the implementation to track the current state:

func toggleItemType() {
    Task {
+        // Update local state before or after the toggle
+        currentItemType = currentItemType == .product ? .coupon : .product
        await posModel.toggleItemType()
    }
}

Or better yet, retrieve the current state from the model:

func toggleItemType() {
    Task {
        await posModel.toggleItemType()
+        // Update local state after the toggle
+        currentItemType = await posModel.itemsController.currentItemType
    }
}
WooCommerce/Classes/POS/Presentation/Item Selector/ItemList.swift (1)

119-124:

❓ Verification inconclusive

Good implementation for coupon handling, but missing analytics tracking.

The implementation allows users to add coupons to the cart, but unlike the product and variation cases, it doesn't track this action for analytics.

case let .coupon(coupon):
    Button(action: {
        posModel.addToCart(item)
+       analytics.track(event: .PointOfSale.addItemToCart(type: .coupon))
    }, label: {
        CouponCardView(coupon: coupon)
    })

Make sure the PointOfSale.addItemToCart event supports a .coupon type.


🏁 Script executed:

#!/bin/bash
# Check if the addItemToCart analytics event supports coupon type
rg "addItemToCart.*coupon" --type swift

Length of output: 41


Attention: Missing Analytics Tracking for Coupons

The coupon-handling code correctly adds the coupon to the cart, but it lacks the corresponding analytics tracking call. Please add the following tracking call after adding the coupon to the cart:

case let .coupon(coupon):
    Button(action: {
        posModel.addToCart(item)
+       analytics.track(event: .PointOfSale.addItemToCart(type: .coupon))
    }, label: {
        CouponCardView(coupon: coupon)
    })

Before merging, verify manually that the PointOfSale.addItemToCart event in the analytics system supports a .coupon type. Our automated search did not return conclusive evidence of coupon support, so please review the analytics event definitions to ensure compatibility.

WooCommerce/Classes/POS/Utils/PreviewHelpers.swift (1)

94-97: Empty implementation of toggleItemType()

While the method satisfies the protocol requirement, it currently lacks implementation. This is acceptable for preview purposes but consider adding a basic implementation to toggle between mock products and coupons for more comprehensive previews.

func toggleItemType() async {
-    //
+    // For preview purposes, we could toggle between mock products and coupons
+    // by updating the itemsViewState with different mock data
}
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ae0994e and b39973e.

📒 Files selected for processing (11)
  • Experiments/Experiments/DefaultFeatureFlagService.swift (1 hunks)
  • WooCommerce/Classes/POS/Controllers/PointOfSaleItemsController.swift (5 hunks)
  • WooCommerce/Classes/POS/Models/PointOfSaleAggregateModel.swift (2 hunks)
  • WooCommerce/Classes/POS/Presentation/Item Selector/CouponCardView.swift (1 hunks)
  • WooCommerce/Classes/POS/Presentation/Item Selector/ItemList.swift (1 hunks)
  • WooCommerce/Classes/POS/Presentation/ItemListView.swift (4 hunks)
  • WooCommerce/Classes/POS/Utils/PreviewHelpers.swift (2 hunks)
  • WooCommerce/WooCommerce.xcodeproj/project.pbxproj (4 hunks)
  • WooCommerce/WooCommerceTests/POS/Mocks/MockPOSItemProvider.swift (1 hunks)
  • Yosemite/Yosemite/PointOfSale/PointOfSaleItemService.swift (3 hunks)
  • Yosemite/Yosemite/PointOfSale/PointOfSaleItemServiceProtocol.swift (1 hunks)
🔇 Additional comments (18)
Experiments/Experiments/DefaultFeatureFlagService.swift (1)

75-75: Temporary Feature Flag Disablement Confirmed

You've hardcoded the enableCouponsInPointOfSale flag to false as mentioned in the PR description. This effectively prevents the new coupon functionality from being accessible in all build configurations during development.

Remember to revisit this when the coupon feature is ready for testing, so it can be conditionally enabled again.

WooCommerce/Classes/POS/Presentation/Item Selector/CouponCardView.swift (1)

13-14:

❓ Verification inconclusive

Replace raw identifiers with user-friendly information

Displaying raw UUIDs and numerical IDs doesn't provide a good user experience. Users need to see meaningful information like coupon code, discount amount, and expiration date.

- Text(coupon.id.uuidString)
- Text(coupon.couponID.description)
+ Text(coupon.code ?? "Coupon")
+ Text(coupon.formattedAmount ?? "")

🏁 Script executed:

#!/bin/bash
# Check what properties POSCoupon has that would be more useful to display
grep -A 20 "struct POSCoupon" $(find . -name "*.swift" | grep -v "build" | grep -v "DerivedData")

Length of output: 69698


Action Required: Verify Display Fields for Coupon Information

The updated code replaces raw identifiers with more user-friendly properties. However, our verification script did not yield output for the POSCoupon structure, so it's unclear if coupon.code and coupon.formattedAmount are valid properties to display. Please manually verify that the coupon model exposes these properties (or suitable alternatives like coupon code, discount amount, or expiration date) before merging.

  • Confirm that the coupon instance has a code property for displaying the coupon code.
  • Confirm that a property like formattedAmount (or another equivalent) is available for rendering the discount amount or other meaningful details.
  • If these properties are not present, update the diff accordingly with the correct user-friendly fields.
- Text(coupon.id.uuidString)
- Text(coupon.couponID.description)
+ Text(coupon.code ?? "Coupon")
+ Text(coupon.formattedAmount ?? "")
WooCommerce/WooCommerce.xcodeproj/project.pbxproj (4)

1593-1593: LGTM: New file added to build sources.

The file reference for CouponCardView.swift has been properly added to the build sources.


4756-4756: LGTM: File reference properly configured.

The file reference for CouponCardView.swift is correctly set up with the proper file type and path.


7518-7518: LGTM: File correctly added to Item Selector group.

CouponCardView.swift has been properly added to the Item Selector group, which aligns with the PR objective of allowing toggling between products and coupons.


16212-16212: LGTM: Build phase entry correct.

The file has been correctly added to the compilation phase.

WooCommerce/Classes/POS/Models/PointOfSaleAggregateModel.swift (1)

95-98: Clean implementation of the toggle functionality.

The @MainActor attribute is correctly applied to ensure UI updates happen on the main thread. This implementation follows the established pattern in this file for other asynchronous methods.

Yosemite/Yosemite/PointOfSale/PointOfSaleItemServiceProtocol.swift (1)

61-61:

✅ Verification successful

Good change to the return type for better consistency.

Changing the return type from [POSItem] to PagedItems<POSItem> aligns with other methods in this protocol. Adding error handling with throws is also a good practice.

Make sure all implementations of this protocol have been updated to match this new signature.


🏁 Script executed:

#!/bin/bash
# Check for all implementations of providePointOfSaleCoupons
rg "func providePointOfSaleCoupons\(\)" --type swift

Length of output: 577


Review Verified: All implementations match the updated signature.

The changes in the return type and error handling have been confirmed across the codebase:

  • Yosemite/Yosemite/PointOfSale/PointOfSaleItemServiceProtocol.swift
  • Yosemite/Yosemite/PointOfSale/PointOfSaleItemService.swift
  • WooCommerce/WooCommerceTests/POS/Mocks/MockPOSItemProvider.swift
  • WooCommerce/Classes/POS/Utils/PreviewHelpers.swift

The method signature func providePointOfSaleCoupons() throws -> PagedItems<POSItem> is consistently applied, and no further changes are needed.

WooCommerce/Classes/POS/Presentation/ItemListView.swift (2)

4-4: Appropriate import for the new feature.

The import of Yosemite.POSCoupon is necessary for the coupon functionality being added.


20-22: Good use of feature flag to conditionally enable the coupons feature.

This approach allows for controlled rollout of the feature and easy disabling if issues are found.

WooCommerce/Classes/POS/Utils/PreviewHelpers.swift (1)

60-61: Method signature update looks good

The update to return PagedItems<POSItem> and to throw errors aligns with the changes in the main implementation. This ensures preview consistency with the actual service.

WooCommerce/WooCommerceTests/POS/Mocks/MockPOSItemProvider.swift (1)

49-50: Method signature update is correct

The updated method signature properly aligns with the protocol changes, ensuring test mocks remain consistent with the actual implementation.

Yosemite/Yosemite/PointOfSale/PointOfSaleItemService.swift (2)

15-15: Good addition of storage failure error case

Adding the storageFailure case enhances error handling capabilities and provides more specific error information.


103-119: Improved error handling and paging support

The updated method now properly throws errors when storage is unavailable and returns a paged result structure. The implementation is more robust with explicit error handling.

WooCommerce/Classes/POS/Controllers/PointOfSaleItemsController.swift (4)

9-12: Good addition of POSItemType enum

The enum provides a clean way to manage different item types in the controller, making the toggle functionality more maintainable.


24-24: Protocol extension with toggleItemType method

The protocol extension appropriately adds the toggle functionality requirement to the interface.


35-35: Default item type initialization

Good default initialization to .products to ensure the controller starts with the expected state.


53-56: Implementation of toggleItemType is clean and effective

The implementation efficiently toggles between item types and reloads the view with the new type of items.

@staskus
Copy link
Contributor

staskus commented Mar 17, 2025

@iamgabrielma This got away from my radar. I'll review this PR tomorrow!

Copy link
Contributor

@staskus staskus left a comment

Choose a reason for hiding this comment

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

Thanks!

I think this is important first step so I'll delay approving it since we could structure it differently based on our discussions. 👍

private let paginationTracker: AsyncPaginationTracker
private var childPaginationTrackers: [POSItem: AsyncPaginationTracker] = [:]
private let itemProvider: PointOfSaleItemServiceProtocol
private var itemType: POSItemType = .products
Copy link
Contributor

Choose a reason for hiding this comment

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

Based on a discussion p1742206171389629/1741916795.290219-slack-C070SJRA8DP, we could also consider how ItemListState could be used to represent the Products | Coupons data structure.

Maybe something like this? 🤔

image

The current selection could be tracked on a state or separately.

@wpmobilebot wpmobilebot modified the milestones: 22.0, 22.1 Mar 21, 2025
@wpmobilebot
Copy link
Collaborator

Version 22.0 has now entered code-freeze, so the milestone of this PR has been updated to 22.1.

@iamgabrielma
Copy link
Contributor Author

Sounds good! I've spent some time today experimenting with a new approach from what I've gathered from our conversation in slack: trunk...experiment/pos-coupon-service

This is not ready for review yet, but just a draft so we can sync. Let me know what do you think in general:

  • We have a separate PointOfSaleCouponsController
  • We have a separate PointOfSaleCouponService
  • We have a currentController in the aggregate model, which can be either product or coupon one, both have their respective items loaded in memory, from the UI we just switch what we load based on ItemListState
  • ItemListState and a separation of ItemType by product and coupons
  • ItemsStackState becomes more complex, as needs to handle both types, so we may need to modify this structure.

There's also a blocker which I haven't figured out yet as I ran out of time: The app crashes when we switch between products/coupons, I'm guessing because miss-referencing storage when we switch services, I'll continue tomorrow with this.

@staskus
Copy link
Contributor

staskus commented Mar 24, 2025

Thanks, @iamgabrielma!

We have a separate PointOfSaleCouponsController
We have a separate PointOfSaleCouponService

Sounds good! If you prefer, you could make PR with just of creation of the service and controller, which could be reviewed while we figure out the rest.

We have a currentController in the aggregate model, which can be either product or coupon one, both have their respective items loaded in memory, from the UI we just switch what we load based on ItemListState

We have a currentController in the aggregate model, which can be either product or coupon one, both have their respective items loaded in memory, from the UI we just switch what we load based on ItemListState

Another option would be to have an enum that represents the current selection which then could be used to select an appropriate controller. However, it doesn't change the approach, and currentController may be the best option. Likely currentController could be computer var that will return a controller based on itemType, which would hold the state of the current selection. This selection may be important to represent current selection in the UI.

ItemListState and a separation of ItemType by product and coupons
ItemsStackState becomes more complex, as needs to handle both types, so we may need to modify this structure.

I can imagine. Without actually doing it and seeing how it all works it's hard to advice something tangible. I'm not 100% sure what's the most comfortable way to represent it all.

@staskus
Copy link
Contributor

staskus commented Mar 24, 2025

There's also a blocker which I haven't figured out yet as I ran out of time: The app crashes when we switch between products/coupons, I'm guessing because miss-referencing storage when we switch services, I'll continue tomorrow with this.

I think some storage code only expects to be called from the main actor. It's enough to make PointOfSaleCouponService providePointOfSaleCoupons and public func providePointOfSaleItems(pageNumber: Int) async throws -> PagedItems<POSItem> to @MainActor to avoid the crash 👍

I pushed the fix into the branch.

@staskus
Copy link
Contributor

staskus commented Mar 24, 2025

@iamgabrielma

Overall, I think the approach is good 👍

Since we switch between currentController, we could maybe even avoid creating SectionState in the first PR, and just return the old ItemListState. This PR could focus on Service + Controller + Basic Switching.

Then we could move on to the required changes to the item state to support our needs. I don't want to put too many changes in one place. We may not even need SectionState, since currentSectionState simply returns ItemListState.SectionState which is of the same type.

WDYT?

@iamgabrielma
Copy link
Contributor Author

That sounds good, thanks for the tips @staskus ! This PR is updated, and ready for review. I've limited the scope to:

  • Created a new PointOfSaleCouponsController
  • Created a new PointOfSaleCouponService
  • Handle switch between different controllers in the aggregate model based on product type when we tap the button.
  • Kept the SectionState as it is
  • I've removed the coupon rendering and "add to cart" to handle later, but we can see in the console that the right path was taken when switching controllers, for now we'll just get an empty list of coupons. Eg:
"🍍 CouponsController::refreshItems called"
Screen.Recording.2025-03-25.at.11.33.53.mov

@iamgabrielma iamgabrielma requested a review from staskus March 25, 2025 04:49
self.siteID = siteID
self.currencyFormatter = CurrencyFormatter(currencySettings: currencySettings)
self.productsRemote = ProductsRemote(network: network)
self.variationRemote = ProductVariationsRemote(network: network)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've kept this as it is for now, but we will need to split the PointOfSaleItemServiceProtocol, as coupons do not need to know about some of these dependencies.

Copy link
Contributor

Choose a reason for hiding this comment

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

No need for splitting.

A separate PointOfSaleCouponServiceProtocol is enough. We don't need the ability to interchangeably use PointOfSaleCouponService and PointOfSaleItemService. So we can safely remove all those methods and have:

public protocol PointOfSaleCouponServiceProtocol {
    func providePointOfSaleCoupons(pageNumber: Int) async throws -> PagedItems<POSItem>
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Gotcha! I'll take a look into this in the next PR as I start to implement those.

Copy link
Contributor

@staskus staskus left a comment

Choose a reason for hiding this comment

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

🚢 Looks good! Lets goooo


@available(iOS 17.0, *)
@Observable final class PointOfSaleCouponsController: PointOfSaleItemsControllerProtocol {
let itemType: ItemType = .coupons
Copy link
Contributor

Choose a reason for hiding this comment

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

Is ItemType supposed to be used in Controllers?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It doesn't seem necessary, nope. Removed! 249f75f

case .variableParentProduct:
return nil
case .coupon:
debugPrint("Not implemented. TODO: Make POSCoupon POSOrderable")
Copy link
Contributor

Choose a reason for hiding this comment

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

Note: May not need to be POSOrderable, since for coupons it's enough to pass code to the API.

self.siteID = siteID
self.currencyFormatter = CurrencyFormatter(currencySettings: currencySettings)
self.productsRemote = ProductsRemote(network: network)
self.variationRemote = ProductVariationsRemote(network: network)
Copy link
Contributor

Choose a reason for hiding this comment

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

No need for splitting.

A separate PointOfSaleCouponServiceProtocol is enough. We don't need the ability to interchangeably use PointOfSaleCouponService and PointOfSaleItemService. So we can safely remove all those methods and have:

public protocol PointOfSaleCouponServiceProtocol {
    func providePointOfSaleCoupons(pageNumber: Int) async throws -> PagedItems<POSItem>
}

…on-list

# Conflicts:
#	WooCommerce/Classes/POS/Models/PointOfSaleAggregateModel.swift
#	WooCommerce/Classes/POS/Presentation/ItemListView.swift
#	Yosemite/Yosemite/PointOfSale/PointOfSaleItemService.swift
@iamgabrielma iamgabrielma merged commit 638baa4 into trunk Mar 25, 2025
13 checks passed
@iamgabrielma iamgabrielma deleted the task/15346-pos-allow-switch-product-vs-coupon-list branch March 25, 2025 11:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature: coupons Related to basic fulfillment such as order tracking. feature: POS type: task An internally driven task.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Woo POS] Coupons: Allow switching between Products and Coupons lists

4 participants