Skip to content

Conversation

@iamgabrielma
Copy link
Contributor

@iamgabrielma iamgabrielma commented Jan 17, 2023

Closes: #8589
Part of #8530

Description

This PR adds the logic to dismiss the IPP feedback banner.

TODO

  • Dismisses the IPP banner upon tapping
  • Presents confirmation screen upon dismissal
  • Dismisses the IPP banner upon survey completion.

Changes

  • Updates the setFeatureAnnouncementDismissed AppSettingsStore/AppSettingsAction to accept a new remindAfter parameter, this allows us to specify a number of days for the reminder to be triggered (previous default to 14)
  • Adds an UIAlertController to be shown when the IPP banner is dismissed, with 2 buttons: "Remind me later", and "Don't show again".
  • Once the IPP banner is dismissed, we update the feedback status to .dismissed, and the feedback visibility to be reminded later or never.
  • Updated, and added Unit Tests

Testing instructions

  • Go to My Store > Orders and see the IPP feedback banner appear
  • Tap on "x" and see a confirmation alert with 2 options: "remind me later", and "Don't show again"
  • Confirm that the banner dismisses no matter the option you tap
  • Note: If Order Creation feedback banner should appear in your store, this will show after we've dismissed the IPP banner.

Simulator Screen Recording - iPhone 11 Pro - 2023-01-19 at 10 19 40

Screenshots


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

@iamgabrielma iamgabrielma added the feature: mobile payments Related to mobile payments / card present payments / Woo Payments. label Jan 17, 2023
@iamgabrielma iamgabrielma added this to the 12.0 milestone Jan 17, 2023
@wpmobilebot
Copy link
Collaborator

wpmobilebot commented Jan 17, 2023

You can test the changes from this Pull Request by:
  • Clicking here or scanning the QR code below to access App Center
  • Then installing the build number pr8657-914d62c on your iPhone

If you need access to App Center, please ask a maintainer to add you.

Base automatically changed from issue/8636-orders-view-ippiaf-banner to trunk January 18, 2023 11:43
# Conflicts:
#	WooCommerce/Classes/ViewRelated/Orders/OrderListViewController.swift
#	WooCommerce/Classes/ViewRelated/Orders/OrderListViewModel.swift
@iamgabrielma iamgabrielma marked this pull request as ready for review January 19, 2023 02:23
@iamgabrielma iamgabrielma requested a review from toupper January 19, 2023 03:28
@iamgabrielma
Copy link
Contributor Author

iamgabrielma commented Jan 19, 2023

👋 @toupper I'd appreciate an "early" review on this one before is fully ready for review, as I'm unsure how to deal with the case of "Dismisses the IPP banner upon survey completion", happy to get any pointer on what would work for this case. For context:

  • If I use the existing SurveyCoordinatingController (current solution), we get the WooCommerce navigation flow, but we can't access to any completion handler to work with when the survey is submitted.
  • If I use the existing SurveyViewController we get a completion handler that is effectively called when the survey is submitted, but we lose the WooCommerce flow and get the Crowdsignal one instead.

We seem to use the first option across other surveys, but I'm failing to understand how are we dealing with the logic that needs to happen when a user submits the survey from the modal view. This will be needed for tracking FeedbackStatus as well.

Edit: This is resolved with 523fe0a (Reference: p1674118095143339?thread_ts=1674101250.398509&cid=CGPNUU63E-slack-CGPNUU63E). We'll be dismissing the banner right away upon tapping, and then we'll figure out if we need to show it again or not via checking the FeedbackStatus


private func createIPPFeedbackTopBanner() -> TopBannerView {
let shareIPPFeedbackAction = TopBannerViewModel.ActionButton(title: Localization.shareFeedbackButton, action: { _ in
self.displayIPPFeedbackBannerSurvey()
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need to add [weak self] for these references? Also for other self usage within a block in this PR

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We definitely do 🙇 , added both on 70d9cbd

self.present(surveyNavigation, animated: true, completion: nil)
}

private func dismissIPPFeedbackBannerSurvey() {
Copy link
Contributor

Choose a reason for hiding this comment

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

In order to be more precise, I would rename this function to actually reflect what's happening inside. Perhaps something like func showIPPFeedbackDismissAlert() ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, the method internals changed but I didn't change the name. Modified on 909bea5

static let estimatedHeaderHeight = CGFloat(43)
static let estimatedRowHeight = CGFloat(86)
static let placeholderRowsPerSection = [3]
static let remindAfterDays = 7
Copy link
Contributor

Choose a reason for hiding this comment

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

I would be more specific here, what is it that we are using this value for? IPP Feedback or something else? Also, this pertains to view model logic, as mentioned before.

}

private func remindMeLaterTapped() {
viewModel.dismissIPPFeedbackBanner(remindLater: true, remindAfter: Settings.remindAfterDays)
Copy link
Contributor

Choose a reason for hiding this comment

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

The remindLater and remindAfter logic seem to fit better in the view model logic, I would move that there while keeping the UI actions here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That makes sense, moved to the view model on 80a1b1b

stores.dispatch(action)
}

func dismissIPPFeedbackBanner(remindLater: Bool, remindAfter: Int?) {
Copy link
Contributor

@toupper toupper Jan 19, 2023

Choose a reason for hiding this comment

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

As mentioned before, remindLater and remindAfter shouldn't be exposed to the view, but kept here inside the view model logic. We can also test it that way.

loadCouponManagementFeatureSwitchState(onCompletion: onCompletion)
case .setFeatureAnnouncementDismissed(campaign: let campaign, remindLater: let remindLater, onCompletion: let completion):
setFeatureAnnouncementDismissed(campaign: campaign, remindLater: remindLater, onCompletion: completion)
case .setFeatureAnnouncementDismissed(campaign: let campaign, remindLater: let remindLater, remindAfter: let remindAfter, onCompletion: let completion):
Copy link
Contributor

Choose a reason for hiding this comment

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

I would encapsulate remindLater and remindLater in one value, I don't think we need both here. If we have both we can give place to inconsistent states, e.g., remindLater false and remindAfter to 5 days. For instance, we can solve this as follows:

  • We can have only remindAfter, where 0 means it shouldn't be reminded. Or,
  • remindAfter can be an optional, being nil meaning it shouldn't be reminded. I prefer this one.

Copy link
Contributor Author

@iamgabrielma iamgabrielma Jan 20, 2023

Choose a reason for hiding this comment

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

Much cleaner indeed, changes here: 2177584 Now we have a unique Optional parameter remindAfterDays rather than two.

loadCouponManagementFeatureSwitchState(onCompletion: onCompletion)
case .setFeatureAnnouncementDismissed(campaign: let campaign, remindLater: let remindLater, onCompletion: let completion):
setFeatureAnnouncementDismissed(campaign: campaign, remindLater: remindLater, onCompletion: completion)
case .setFeatureAnnouncementDismissed(campaign: let campaign, remindLater: let remindLater, remindAfter: let remindAfter, onCompletion: let completion):
Copy link
Contributor

Choose a reason for hiding this comment

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

If keep remindAfter, it would be valuable to specify what time unit are we expecting: remindAfterDays

@toupper
Copy link
Contributor

toupper commented Jan 19, 2023

Great job @iamgabrielma! I left some comments there, let me know what you think of that. Once we are done with that, I will test the flow 👍

XCTAssert(Calendar.current.isDate(actualRemindAfter, inSameDayAs: twoWeeksTime))
}

func test_setFeatureAnnouncementDismissed_with_remindAfter_seven_days_stores_reminder_date_in_one_week() throws {
Copy link
Contributor

Choose a reason for hiding this comment

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

It would be great to use the agreed test function naming syntax here as well:

test_setFeatureAnnouncementDismissed_when_remindAfter_is_seven_days_stores_reminder_then_date_saved_date_is_one_week

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, you're right! Changed f8a2586

@iamgabrielma iamgabrielma modified the milestones: 12.0, 12.1 Jan 19, 2023
We’re modifying the action by removing the parameters remindLater, and remindAfter in favor of an unique remindAfterDays parameter. If this is nil, no reminder is set. Otherwise the number of days will be set.
By making remindAfterDays an Optional Int, we need to edit storeDismissedSetting as well to either save the current date if is true (by passing 0, so adds 0 days to the current date) or nil if is false
}

func test_setFeatureAnnouncementDismissed_with_remindLater_true_stores_reminder_date_in_two_weeks() throws {
func test_setFeatureAnnouncementDismissed_with_remindAfterDays_two_weeks_stores_reminder_date_in_two_weeks() throws {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Suggested change
func test_setFeatureAnnouncementDismissed_with_remindAfterDays_two_weeks_stores_reminder_date_in_two_weeks() throws {
func test_setFeatureAnnouncementDismissed_when_remindAfterDays_two_weeks_then_stores_reminder_date_in_two_weeks() throws {

Copy link
Contributor

Choose a reason for hiding this comment

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

test_setFeatureAnnouncementDismissed_when_remindAfterDays_is_two_weeks_then_stores_reminder_date_is_two_weeks()

@iamgabrielma
Copy link
Contributor Author

Thanks for the review @toupper ! I made the changes and this is ready for review 🙇

@iamgabrielma iamgabrielma requested a review from toupper January 20, 2023 05:42
// MARK: - In-Person Payments Feedback Banner

extension OrderListViewModel {
func dismissIPPFeedbackBanner(remindAfterDays: Int?) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice change moving the logic to the view model! However, the remindAfterDays logic can be contained in the view model; the view doesn't need to know about when are we going to show it again. With that, we can remove this parameter remindAfterDays from this function.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed here the remaining use of remindAfterDays: d5e02a2 to a new method, so this is entirely contained in the view model now 👍

}

func test_setFeatureAnnouncementDismissed_with_remindLater_true_stores_reminder_date_in_two_weeks() throws {
func test_setFeatureAnnouncementDismissed_with_remindAfterDays_two_weeks_stores_reminder_date_in_two_weeks() throws {
Copy link
Contributor

Choose a reason for hiding this comment

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

test_setFeatureAnnouncementDismissed_when_remindAfterDays_is_two_weeks_then_stores_reminder_date_is_two_weeks()

stores.dispatch(updateBannerVisibility)
}

func remindMeLaterTapped() {
Copy link
Contributor

Choose a reason for hiding this comment

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

We can name this function more specifically for the IPP Feedback Banner.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Renamed on 9884f22

@toupper toupper self-assigned this Jan 20, 2023
@toupper
Copy link
Contributor

toupper commented Jan 20, 2023

Great job! LGTM :shipit:

@iamgabrielma iamgabrielma merged commit c487172 into trunk Jan 20, 2023
@iamgabrielma iamgabrielma deleted the issue/8589-ipp-banner-dismiss branch January 20, 2023 11:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature: mobile payments Related to mobile payments / card present payments / Woo Payments.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[IPPInAppFeedback] Dismiss logic

4 participants