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 @@ -64,7 +64,8 @@ extension Storage.GeneralAppSettings {
featureAnnouncementCampaignSettings: CopiableProp<[FeatureAnnouncementCampaign: FeatureAnnouncementCampaignSettings]> = .copy,
sitesWithAtLeastOneIPPTransactionFinished: CopiableProp<Set<Int64>> = .copy,
isEUShippingNoticeDismissed: CopiableProp<Bool> = .copy,
isCustomFieldsTopBannerDismissed: CopiableProp<Bool> = .copy
isCustomFieldsTopBannerDismissed: CopiableProp<Bool> = .copy,
isPOSSurveyNotificationScheduled: CopiableProp<Bool> = .copy
) -> Storage.GeneralAppSettings {
let installationDate = installationDate ?? self.installationDate
let feedbacks = feedbacks ?? self.feedbacks
Expand All @@ -77,6 +78,7 @@ extension Storage.GeneralAppSettings {
let sitesWithAtLeastOneIPPTransactionFinished = sitesWithAtLeastOneIPPTransactionFinished ?? self.sitesWithAtLeastOneIPPTransactionFinished
let isEUShippingNoticeDismissed = isEUShippingNoticeDismissed ?? self.isEUShippingNoticeDismissed
let isCustomFieldsTopBannerDismissed = isCustomFieldsTopBannerDismissed ?? self.isCustomFieldsTopBannerDismissed
let isPOSSurveyNotificationScheduled = isPOSSurveyNotificationScheduled ?? self.isPOSSurveyNotificationScheduled

return Storage.GeneralAppSettings(
installationDate: installationDate,
Expand All @@ -89,7 +91,8 @@ extension Storage.GeneralAppSettings {
featureAnnouncementCampaignSettings: featureAnnouncementCampaignSettings,
sitesWithAtLeastOneIPPTransactionFinished: sitesWithAtLeastOneIPPTransactionFinished,
isEUShippingNoticeDismissed: isEUShippingNoticeDismissed,
isCustomFieldsTopBannerDismissed: isCustomFieldsTopBannerDismissed
isCustomFieldsTopBannerDismissed: isCustomFieldsTopBannerDismissed,
isPOSSurveyNotificationScheduled: isPOSSurveyNotificationScheduled
)
}
}
Expand Down
19 changes: 14 additions & 5 deletions Modules/Sources/Storage/Model/GeneralAppSettings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ public struct GeneralAppSettings: Codable, Equatable, GeneratedCopiable {
///
public var isCustomFieldsTopBannerDismissed: Bool

/// Whether the Point of Sale survey notification has been scheduled
///
public var isPOSSurveyNotificationScheduled: Bool

public init(installationDate: Date?,
feedbacks: [FeedbackType: FeedbackSettings],
isViewAddOnsSwitchEnabled: Bool,
Expand All @@ -66,7 +70,8 @@ public struct GeneralAppSettings: Codable, Equatable, GeneratedCopiable {
featureAnnouncementCampaignSettings: [FeatureAnnouncementCampaign: FeatureAnnouncementCampaignSettings],
sitesWithAtLeastOneIPPTransactionFinished: Set<Int64>,
isEUShippingNoticeDismissed: Bool,
isCustomFieldsTopBannerDismissed: Bool) {
isCustomFieldsTopBannerDismissed: Bool,
isPOSSurveyNotificationScheduled: Bool) {
self.installationDate = installationDate
self.feedbacks = feedbacks
self.isViewAddOnsSwitchEnabled = isViewAddOnsSwitchEnabled
Expand All @@ -78,6 +83,7 @@ public struct GeneralAppSettings: Codable, Equatable, GeneratedCopiable {
self.sitesWithAtLeastOneIPPTransactionFinished = sitesWithAtLeastOneIPPTransactionFinished
self.isEUShippingNoticeDismissed = isEUShippingNoticeDismissed
self.isCustomFieldsTopBannerDismissed = isCustomFieldsTopBannerDismissed
self.isPOSSurveyNotificationScheduled = isPOSSurveyNotificationScheduled
}

public static var `default`: Self {
Expand All @@ -90,7 +96,8 @@ public struct GeneralAppSettings: Codable, Equatable, GeneratedCopiable {
featureAnnouncementCampaignSettings: [:],
sitesWithAtLeastOneIPPTransactionFinished: [],
isEUShippingNoticeDismissed: false,
isCustomFieldsTopBannerDismissed: false)
isCustomFieldsTopBannerDismissed: false,
isPOSSurveyNotificationScheduled: false)
}

/// Returns the status of a given feedback type. If the feedback is not stored in the feedback array. it is assumed that it has a pending status.
Expand Down Expand Up @@ -120,7 +127,8 @@ public struct GeneralAppSettings: Codable, Equatable, GeneratedCopiable {
featureAnnouncementCampaignSettings: featureAnnouncementCampaignSettings,
sitesWithAtLeastOneIPPTransactionFinished: sitesWithAtLeastOneIPPTransactionFinished,
isEUShippingNoticeDismissed: isEUShippingNoticeDismissed,
isCustomFieldsTopBannerDismissed: isCustomFieldsTopBannerDismissed
isCustomFieldsTopBannerDismissed: isCustomFieldsTopBannerDismissed,
isPOSSurveyNotificationScheduled: isPOSSurveyNotificationScheduled
)
}

Expand All @@ -141,7 +149,8 @@ public struct GeneralAppSettings: Codable, Equatable, GeneratedCopiable {
featureAnnouncementCampaignSettings: updatedSettings,
sitesWithAtLeastOneIPPTransactionFinished: sitesWithAtLeastOneIPPTransactionFinished,
isEUShippingNoticeDismissed: isEUShippingNoticeDismissed,
isCustomFieldsTopBannerDismissed: isCustomFieldsTopBannerDismissed
isCustomFieldsTopBannerDismissed: isCustomFieldsTopBannerDismissed,
isPOSSurveyNotificationScheduled: isPOSSurveyNotificationScheduled
)
}
}
Expand All @@ -167,7 +176,7 @@ extension GeneralAppSettings {
forKey: .sitesWithAtLeastOneIPPTransactionFinished) ?? Set<Int64>([])
self.isEUShippingNoticeDismissed = try container.decodeIfPresent(Bool.self, forKey: .isEUShippingNoticeDismissed) ?? false
self.isCustomFieldsTopBannerDismissed = try container.decodeIfPresent(Bool.self, forKey: .isCustomFieldsTopBannerDismissed) ?? false

self.isPOSSurveyNotificationScheduled = try container.decodeIfPresent(Bool.self, forKey: .isPOSSurveyNotificationScheduled) ?? false
// Decode new properties with `decodeIfPresent` and provide a default value if necessary.
}
}
14 changes: 14 additions & 0 deletions Modules/Sources/Yosemite/Actions/AppSettingsAction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -366,4 +366,18 @@ public enum AppSettingsAction: Action {
/// Loads Loads the state of the App Passwords Experiment feature
///
case getAppPasswordsExperimentSettingState(onCompletion: (Bool) -> Void)

// MARK: - Point of Sale Surveys

/// Sets the POS survey notification as scheduled
///
case setPOSSurveyNotificationScheduled(onCompletion: (Result<Void, Error>) -> Void)

/// Gets whether the POS survey notification has been scheduled
///
case getPOSSurveyNotificationScheduled(onCompletion: (Bool) -> Void)

/// Resets the POS survey notification scheduled state
/// At the moment this one is used for testing only. To remove in WOOMOB-1480
case resetPOSSurveyNotificationScheduled(onCompletion: (Result<Void, Error>) -> Void)
}
32 changes: 32 additions & 0 deletions Modules/Sources/Yosemite/Stores/AppSettingsStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,12 @@ public class AppSettingsStore: Store {
setAppPasswordsExperimentSettingEnabled(isOn: value, onCompletion: onCompletion)
case .getAppPasswordsExperimentSettingState(let onCompletion):
getAppPasswordsExperimentSettingEnabled(onCompletion: onCompletion)
case .setPOSSurveyNotificationScheduled(onCompletion: let onCompletion):
setPOSSurveyNotificationScheduled(onCompletion: onCompletion)
case .getPOSSurveyNotificationScheduled(onCompletion: let onCompletion):
getPOSSurveyNotificationScheduled(onCompletion: onCompletion)
case .resetPOSSurveyNotificationScheduled(onCompletion: let onCompletion):
resetPOSSurveyNotificationScheduled(onCompletion: onCompletion)
}
}
}
Expand Down Expand Up @@ -1290,6 +1296,32 @@ private extension AppSettingsStore {
}
}

// MARK: - Point of Sale surveys
//
private extension AppSettingsStore {
func setPOSSurveyNotificationScheduled(onCompletion: (Result<Void, Error>) -> Void) {
do {
try generalAppSettings.setValue(true, for: \.isPOSSurveyNotificationScheduled)
onCompletion(.success(()))
} catch {
onCompletion(.failure(error))
}
}

func getPOSSurveyNotificationScheduled(onCompletion: (Bool) -> Void) {
onCompletion(generalAppSettings.value(for: \.isPOSSurveyNotificationScheduled))
}

func resetPOSSurveyNotificationScheduled(onCompletion: (Result<Void, Error>) -> Void) {
do {
try generalAppSettings.setValue(false, for: \.isPOSSurveyNotificationScheduled)
onCompletion(.success(()))
} catch {
onCompletion(.failure(error))
}
}
}

// MARK: - Errors

/// Errors
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ final class GeneralAppSettingsTests: XCTestCase {
XCTAssertEqual(newSettings.feedbacks[.general], newFeedback)
}

func test_isPOSSurveyNotificationScheduled_defaults_to_false() {
// Given
let settings = createGeneralAppSettings()

// Then
XCTAssertFalse(settings.isPOSSurveyNotificationScheduled)
}

func test_updating_properties_to_generalAppSettings_does_not_breaks_decoding() throws {
// Given
let installationDate = Date(timeIntervalSince1970: 1630314000) // Mon Aug 30 2021 09:00:00 UTC+0000
Expand All @@ -63,6 +71,7 @@ final class GeneralAppSettingsTests: XCTestCase {
FeatureAnnouncementCampaignSettings(dismissedDate: Date(), remindAfter: nil)]
let sitesWithAtLeastOneIPPTransactionFinished: Set<Int64> = [1234, 123, 12, 1]
let isCustomFieldsTopBannerDismissed = true
let isPOSSurveyNotificationScheduled = true
let previousSettings = GeneralAppSettings(installationDate: installationDate,
feedbacks: feedbackSettings,
isViewAddOnsSwitchEnabled: true,
Expand All @@ -73,13 +82,15 @@ final class GeneralAppSettingsTests: XCTestCase {
featureAnnouncementCampaignSettings: featureAnnouncementCampaignSettings,
sitesWithAtLeastOneIPPTransactionFinished: sitesWithAtLeastOneIPPTransactionFinished,
isEUShippingNoticeDismissed: false,
isCustomFieldsTopBannerDismissed: isCustomFieldsTopBannerDismissed)
isCustomFieldsTopBannerDismissed: isCustomFieldsTopBannerDismissed,
isPOSSurveyNotificationScheduled: isPOSSurveyNotificationScheduled)

let previousEncodedSettings = try JSONEncoder().encode(previousSettings)
var previousSettingsJson = try JSONSerialization.jsonObject(with: previousEncodedSettings, options: .allowFragments) as? [String: Any]

// When
previousSettingsJson?.removeValue(forKey: "isViewAddOnsSwitchEnabled")
previousSettingsJson?.removeValue(forKey: "isPOSSurveyNotificationScheduled")
let newEncodedSettings = try JSONSerialization.data(withJSONObject: previousSettingsJson as Any, options: .fragmentsAllowed)
let newSettings = try JSONDecoder().decode(GeneralAppSettings.self, from: newEncodedSettings)

Expand All @@ -93,6 +104,7 @@ final class GeneralAppSettingsTests: XCTestCase {
assertEqual(newSettings.featureAnnouncementCampaignSettings, featureAnnouncementCampaignSettings)
assertEqual(newSettings.sitesWithAtLeastOneIPPTransactionFinished, sitesWithAtLeastOneIPPTransactionFinished)
assertEqual(newSettings.isCustomFieldsTopBannerDismissed, isCustomFieldsTopBannerDismissed)
assertEqual(newSettings.isPOSSurveyNotificationScheduled, false)
}
}

Expand Down Expand Up @@ -122,6 +134,7 @@ private extension GeneralAppSettingsTests {
featureAnnouncementCampaignSettings: featureAnnouncementCampaignSettings,
sitesWithAtLeastOneIPPTransactionFinished: sitesWithAtLeastOneIPPTransactionFinished,
isEUShippingNoticeDismissed: isEUShippingNoticeDismissed,
isCustomFieldsTopBannerDismissed: isCustomFieldsTopBannerDismissed)
isCustomFieldsTopBannerDismissed: isCustomFieldsTopBannerDismissed,
isPOSSurveyNotificationScheduled: false)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,8 @@ private extension InAppFeedbackCardVisibilityUseCaseTests {
featureAnnouncementCampaignSettings: [:],
sitesWithAtLeastOneIPPTransactionFinished: [],
isEUShippingNoticeDismissed: false,
isCustomFieldsTopBannerDismissed: false)
isCustomFieldsTopBannerDismissed: false,
isPOSSurveyNotificationScheduled: false)
return settings
}
}
96 changes: 94 additions & 2 deletions Modules/Tests/YosemiteTests/Stores/AppSettingsStoreTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1506,6 +1506,96 @@ extension AppSettingsStoreTests {
// Then
XCTAssertNil(loadedOrderStatus)
}

// MARK: - Point of Sale Survey Notification

func test_getPOSSurveyNotificationScheduled_returns_false_on_new_generalAppSettings() throws {
// Given
try fileStorage?.deleteFile(at: expectedGeneralAppSettingsFileURL)

// When
let result: Bool = waitFor { promise in
let action = AppSettingsAction.getPOSSurveyNotificationScheduled { isScheduled in
promise(isScheduled)
}
self.subject?.onAction(action)
}

// Then
XCTAssertFalse(result)
}

func test_getPOSSurveyNotificationScheduled_returns_true_after_setting_as_scheduled() throws {
// Given
try fileStorage?.deleteFile(at: expectedGeneralAppSettingsFileURL)
let setAction = AppSettingsAction.setPOSSurveyNotificationScheduled { _ in }
subject?.onAction(setAction)

// When
let result: Bool = waitFor { promise in
let action = AppSettingsAction.getPOSSurveyNotificationScheduled { isScheduled in
promise(isScheduled)
}
self.subject?.onAction(action)
}

// Then
XCTAssertTrue(result)
}

func test_setPOSSurveyNotificationScheduled_stores_value_correctly() throws {
// Given
try fileStorage?.deleteFile(at: expectedGeneralAppSettingsFileURL)

// When
var result: Result<Void, Error>?
let action = AppSettingsAction.setPOSSurveyNotificationScheduled { aResult in
result = aResult
}
subject?.onAction(action)

// Then
XCTAssertTrue(try XCTUnwrap(result).isSuccess)

let savedSettings: GeneralAppSettings = try XCTUnwrap(fileStorage?.data(for: expectedGeneralAppSettingsFileURL))
XCTAssertTrue(savedSettings.isPOSSurveyNotificationScheduled)
}

func test_resetPOSSurveyNotificationScheduled_resets_to_false_after_being_set_to_true() throws {
// Given
try fileStorage?.deleteFile(at: expectedGeneralAppSettingsFileURL)

// 1. Set to true
let setAction = AppSettingsAction.setPOSSurveyNotificationScheduled { _ in }
subject?.onAction(setAction)

// 2. Verify it's true
let checkBeforeReset: Bool = waitFor { promise in
let action = AppSettingsAction.getPOSSurveyNotificationScheduled { isScheduled in
promise(isScheduled)
}
self.subject?.onAction(action)
}
XCTAssertTrue(checkBeforeReset)

// When - 3. Reset it
var resetResult: Result<Void, Error>?
let resetAction = AppSettingsAction.resetPOSSurveyNotificationScheduled { aResult in
resetResult = aResult
}
subject?.onAction(resetAction)

// Then - 4. Verify it's false
XCTAssertTrue(try XCTUnwrap(resetResult).isSuccess)

let checkAfterReset: Bool = waitFor { promise in
let action = AppSettingsAction.getPOSSurveyNotificationScheduled { isScheduled in
promise(isScheduled)
}
self.subject?.onAction(action)
}
XCTAssertFalse(checkAfterReset)
}
}

// MARK: - Utils
Expand All @@ -1527,7 +1617,8 @@ private extension AppSettingsStoreTests {
featureAnnouncementCampaignSettings: [:],
sitesWithAtLeastOneIPPTransactionFinished: [],
isEUShippingNoticeDismissed: false,
isCustomFieldsTopBannerDismissed: false
isCustomFieldsTopBannerDismissed: false,
isPOSSurveyNotificationScheduled: false
)
return (settings, feedback)
}
Expand All @@ -1542,7 +1633,8 @@ private extension AppSettingsStoreTests {
featureAnnouncementCampaignSettings: featureAnnouncementCampaignSettings,
sitesWithAtLeastOneIPPTransactionFinished: [],
isEUShippingNoticeDismissed: false,
isCustomFieldsTopBannerDismissed: false
isCustomFieldsTopBannerDismissed: false,
isPOSSurveyNotificationScheduled: false
)
return settings
}
Expand Down
Loading