@@ -57,238 +57,31 @@ public final class CouponStore: Store {
5757 pageSize: pageSize,
5858 onCompletion: onCompletion)
5959 case . deleteCoupon( let siteID, let couponID, let onCompletion) :
60- deleteCoupon ( siteID: siteID, couponID: couponID, onCompletion: onCompletion)
60+ methods . deleteCoupon ( siteID: siteID, couponID: couponID, onCompletion: onCompletion)
6161 case . updateCoupon( let coupon, let siteTimezone, let onCompletion) :
62- updateCoupon ( coupon, siteTimezone: siteTimezone, onCompletion: onCompletion)
62+ methods . updateCoupon ( coupon, siteTimezone: siteTimezone, onCompletion: onCompletion)
6363 case . createCoupon( let coupon, let siteTimezone, let onCompletion) :
64- createCoupon ( coupon, siteTimezone: siteTimezone, onCompletion: onCompletion)
64+ methods . createCoupon ( coupon, siteTimezone: siteTimezone, onCompletion: onCompletion)
6565 case . loadCouponReport( let siteID, let couponID, let startDate, let onCompletion) :
66- loadCouponReport ( siteID: siteID, couponID: couponID, startDate: startDate, onCompletion: onCompletion)
66+ methods . loadCouponReport ( siteID: siteID, couponID: couponID, startDate: startDate, onCompletion: onCompletion)
6767 case . loadMostActiveCoupons( let siteID, let numberOfCouponsToLoad, let timeRange, let siteTimezone, let onCompletion) :
68- loadMostActiveCoupons ( siteID: siteID,
69- numberOfCouponsToLoad: numberOfCouponsToLoad,
70- timeRange: timeRange,
71- siteTimezone: siteTimezone,
72- onCompletion: onCompletion)
68+ methods . loadMostActiveCoupons ( siteID: siteID,
69+ numberOfCouponsToLoad: numberOfCouponsToLoad,
70+ timeRange: timeRange,
71+ siteTimezone: siteTimezone,
72+ onCompletion: onCompletion)
7373 case . searchCoupons( let siteID, let keyword, let pageNumber, let pageSize, let onCompletion) :
74- searchCoupons ( siteID: siteID,
75- keyword: keyword,
76- pageNumber: pageNumber,
77- pageSize: pageSize,
78- onCompletion: onCompletion)
74+ methods . searchCoupons ( siteID: siteID,
75+ keyword: keyword,
76+ pageNumber: pageNumber,
77+ pageSize: pageSize,
78+ onCompletion: onCompletion)
7979 case . retrieveCoupon( let siteID, let couponID, let onCompletion) :
80- retrieveCoupon ( siteID: siteID, couponID: couponID, onCompletion: onCompletion)
80+ methods . retrieveCoupon ( siteID: siteID, couponID: couponID, onCompletion: onCompletion)
8181 case . validateCouponCode( let code, let siteID, let onCompletion) :
82- validateCouponCode ( code: code, siteID: siteID, onCompletion: onCompletion)
82+ methods . validateCouponCode ( code: code, siteID: siteID, onCompletion: onCompletion)
8383 case . loadCoupons( let siteID, let couponIDs, let onCompletion) :
84- loadCoupons ( siteID: siteID, couponIDs: couponIDs, onCompletion: onCompletion)
84+ methods . loadCoupons ( siteID: siteID, couponIDs: couponIDs, onCompletion: onCompletion)
8585 }
8686 }
8787}
88-
89- // MARK: - Services
90- //
91- private extension CouponStore {
92- /// Deletes a coupon from a Site with what is persisted in the storage layer.
93- /// After the API request succeeds, the stored coupon should be removed from the local storage.
94- /// - Parameters:
95- /// - siteID: The site that the deleted coupon belongs to.
96- /// - couponID: The ID of the coupon to be deleted.
97- /// - onCompletion: Closure to call after deletion is complete. Called on the main thread.
98- ///
99- func deleteCoupon( siteID: Int64 , couponID: Int64 , onCompletion: @escaping ( Result < Void , Error > ) -> Void ) {
100- remote. deleteCoupon ( for: siteID, couponID: couponID) { [ weak self] result in
101- guard let self = self else { return }
102- switch result {
103- case . failure( let error) :
104- onCompletion ( . failure( error) )
105- case . success( let coupon) :
106- // This is unlikely to happen, but worth checking
107- guard coupon. siteID == siteID, coupon. couponID == couponID else {
108- onCompletion ( . failure( CouponError . unexpectedCouponDeleted) )
109- DDLogError ( " ⛔️ Unexpected coupon: Deleted couponID \( coupon. couponID) for site \( coupon. siteID) " +
110- " while expecting couponID \( couponID) and site \( siteID) " )
111- return
112- }
113- self . methods. deleteStoredCoupon ( siteID: siteID, couponID: couponID) {
114- onCompletion ( . success( ( ) ) )
115- }
116- }
117- }
118- }
119-
120- /// Updates a coupon given its details.
121- /// After the API request succeeds, the stored coupon should be updated accordingly.
122- /// - Parameters:
123- /// - coupon: The coupon to be updated
124- /// - siteTimezone: the timezone configured on the site (also know as local time of the site).
125- /// - onCompletion: Closure to call after update is complete. Called on the main thread.
126- ///
127- func updateCoupon( _ coupon: Coupon ,
128- siteTimezone: TimeZone ? = nil ,
129- onCompletion: @escaping ( Result < Coupon , Error > ) -> Void ) {
130- remote. updateCoupon ( coupon, siteTimezone: siteTimezone) { [ weak self] result in
131- guard let self = self else { return }
132- switch result {
133- case . failure( let error) :
134- onCompletion ( . failure( error) )
135- case . success( let updatedCoupon) :
136- self . methods. upsertStoredCouponsInBackground ( readOnlyCoupons: [ updatedCoupon] , siteID: updatedCoupon. siteID) {
137- onCompletion ( . success( updatedCoupon) )
138- }
139- }
140- }
141- }
142-
143- /// Creates a coupon given its details.
144- /// After the API request succeeds, a new stored coupon should be inserted into the local storage.
145- /// - Parameters:
146- /// - coupon: The coupon to be created
147- /// - siteTimezone: the timezone configured on the site (also know as local time of the site).
148- /// - onCompletion: Closure to call after creation is complete. Called on the main thread.
149- ///
150- func createCoupon( _ coupon: Coupon ,
151- siteTimezone: TimeZone ? = nil ,
152- onCompletion: @escaping ( Result < Coupon , Error > ) -> Void ) {
153- remote. createCoupon ( coupon, siteTimezone: siteTimezone) { [ weak self] result in
154- guard let self = self else { return }
155- switch result {
156- case . failure( let error) :
157- onCompletion ( . failure( error) )
158- case . success( let createdCoupon) :
159- self . methods. upsertStoredCouponsInBackground ( readOnlyCoupons: [ createdCoupon] , siteID: createdCoupon. siteID) {
160- onCompletion ( . success( createdCoupon) )
161- }
162- }
163- }
164- }
165-
166- /// Loads analytics report for a coupon with the specified coupon ID and site ID.
167- ///
168- /// - Parameters:
169- /// - siteID: ID of the site that the coupon belongs to.
170- /// - couponID: ID of the coupon to load the analytics report for.
171- /// - startDate: the start of the date range to load the analytics report for.
172- /// - onCompletion: invoked when the creation finishes.
173- ///
174- func loadCouponReport( siteID: Int64 , couponID: Int64 , startDate: Date , onCompletion: @escaping ( Result < CouponReport , Error > ) -> Void ) {
175- remote. loadCouponReport ( for: siteID, couponID: couponID, from: startDate, completion: onCompletion)
176- }
177-
178- /// Loads top 3 most active coupons report within the specified time range and site ID.
179- ///
180- /// - `siteID`: site ID.
181- /// - `numberOfCouponsToLoad`: Number of coupons to load.
182- /// - `timeRange`: Time range to fetch report for.
183- /// - `siteTimezone`: site's timezone
184- /// - `onCompletion`: invoked when the reports are fetched.
185- ///
186- func loadMostActiveCoupons( siteID: Int64 ,
187- numberOfCouponsToLoad: Int ,
188- timeRange: StatsTimeRangeV4 ,
189- siteTimezone: TimeZone ,
190- onCompletion: @escaping ( Result < [ CouponReport ] , Error > ) -> Void ) {
191- let to = timeRange. latestDate ( currentDate: Date ( ) , siteTimezone: siteTimezone)
192- let from = timeRange. earliestDate ( latestDate: to, siteTimezone: siteTimezone)
193- remote. loadMostActiveCoupons ( for: siteID,
194- numberOfCouponsToLoad: numberOfCouponsToLoad,
195- from: from,
196- to: to,
197- completion: onCompletion)
198- }
199-
200- /// Search coupons from a Site that match a specified keyword.
201- /// Search results are persisted in the local storage to ensure
202- /// good performance for future search of the same keyword.
203- ///
204- /// - Parameters:
205- /// - siteId: The site to search coupons for.
206- /// - keyword: The string to match the results with.
207- /// - pageNumber: Page number of coupons to fetch from the API
208- /// - pageSize: Number of coupons per page to fetch from the API
209- /// - onCompletion: Closure to call after the search is complete. Called on the main thread.
210- ///
211- func searchCoupons( siteID: Int64 ,
212- keyword: String ,
213- pageNumber: Int ,
214- pageSize: Int ,
215- onCompletion: @escaping ( _ result: Result < Void , Error > ) -> Void ) {
216- remote. searchCoupons ( for: siteID,
217- keyword: keyword,
218- pageNumber: pageNumber,
219- pageSize: pageSize) { [ weak self] result in
220- guard let self = self else { return }
221- switch result {
222- case . failure( let error) :
223- onCompletion ( . failure( error) )
224- case . success( let coupons) :
225- self . methods. upsertSearchResultsInBackground ( siteID: siteID,
226- keyword: keyword,
227- readOnlyCoupons: coupons) {
228- onCompletion ( . success( ( ) ) )
229- }
230- }
231- }
232- }
233-
234- /// Retrieve a coupon from a Site given.
235- /// The fetched coupon is persisted to the local storage.
236- ///
237- /// - Parameters:
238- /// - siteID: The site to retrieve the coupon for.
239- /// - couponID: ID of the coupon to be retrieved.
240- /// - onCompletion: Closure to call upon completion. Called on the main thread.
241- ///
242- func retrieveCoupon( siteID: Int64 ,
243- couponID: Int64 ,
244- onCompletion: @escaping ( _ result: Result < Coupon , Error > ) -> Void ) {
245- remote. retrieveCoupon ( for: siteID,
246- couponID: couponID) { [ weak self] result in
247- guard let self = self else { return }
248- switch result {
249- case . failure( let error) :
250- onCompletion ( . failure( error) )
251- case . success( let coupon) :
252- self . methods. upsertStoredCouponsInBackground ( readOnlyCoupons: [ coupon] , siteID: siteID) {
253- onCompletion ( . success( coupon) )
254- }
255- }
256- }
257- }
258- /// Loads the coupons for a site given all the coupon IDs
259- ///
260- /// - `siteID`: the site for which coupons should be fetched.
261- /// - `couponIDs`: IDs of the coupons to be retrieved.
262- /// - `onCompletion`: invoked upon completion.
263- ///
264- func loadCoupons( siteID: Int64 ,
265- couponIDs: [ Int64 ] ,
266- onCompletion: @escaping ( _ result: Result < [ Coupon ] , Error > ) -> Void ) {
267- remote. loadCoupons ( for: siteID, by: couponIDs) { [ weak self] result in
268- guard let self = self else { return }
269- switch result {
270- case . failure( let error) :
271- onCompletion ( . failure( error) )
272- case . success( let coupons) :
273- self . methods. upsertStoredCouponsInBackground ( readOnlyCoupons: coupons, siteID: siteID) {
274- onCompletion ( . success( coupons) )
275- }
276- }
277- }
278- }
279-
280- func validateCouponCode( code: String , siteID: Int64 , onCompletion: @escaping ( Result < Bool , Error > ) -> Void ) {
281- remote. searchCoupons ( for: siteID, keyword: code, pageNumber: Remote . Default. firstPageNumber, pageSize: 25 ) { result in
282- switch result {
283- case let . success( coupons) :
284- onCompletion ( . success( coupons. contains ( where: { $0. code == code } ) ) )
285- case let . failure( error) :
286- onCompletion ( . failure( error) )
287- }
288- }
289- }
290- }
291-
292- public enum CouponError : Error {
293- case unexpectedCouponDeleted
294- }
0 commit comments