-
Notifications
You must be signed in to change notification settings - Fork 136
[WOOMOB-1722] - Properly clean the Bookings table for Today/Upcoming tabs' first page load #15022
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
b6cd96c
98c6ec8
99c3735
5ef2be3
e19f6d1
c2cf448
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,38 +1,19 @@ | ||
| package com.woocommerce.android.ui.bookings.list | ||
|
|
||
| import org.wordpress.android.fluxc.network.rest.wpcom.wc.bookings.BookingsDateRangePresets | ||
| import org.wordpress.android.fluxc.network.rest.wpcom.wc.bookings.BookingsFilterOption | ||
| import java.time.Clock | ||
| import java.time.LocalDate | ||
| import java.time.LocalTime | ||
| import java.time.ZoneOffset | ||
| import javax.inject.Inject | ||
|
|
||
| class BookingListFiltersBuilder @Inject constructor( | ||
| private val clock: Clock | ||
| ) { | ||
| /** | ||
| * Returns a [BookingsFilterOption.DateRange] based on the selected [BookingListTab]. | ||
| * | ||
| * We use UTC for the API calls, as the API stores the dates without timezone information, which means that | ||
| * when comparing dates, they are treated as UTC times. | ||
| * See p1759398245019489-slack-C09FHQNQERG | ||
| */ | ||
| fun BookingListTab.asDateRangeFilter(): BookingsFilterOption.DateRange? { | ||
| fun todayAtMidnight() = LocalDate.now(clock).atTime(LocalTime.MIDNIGHT).atOffset(ZoneOffset.UTC).toInstant() | ||
| fun todayAtEndOfDay() = LocalDate.now(clock).atTime(LocalTime.MAX).atOffset(ZoneOffset.UTC).toInstant() | ||
|
|
||
| return when (this) { | ||
| BookingListTab.Today -> BookingsFilterOption.DateRange( | ||
| before = todayAtEndOfDay(), | ||
| after = todayAtMidnight() | ||
| ) | ||
|
|
||
| BookingListTab.Upcoming -> BookingsFilterOption.DateRange( | ||
| before = null, | ||
| after = todayAtEndOfDay() | ||
| ) | ||
|
|
||
| BookingListTab.All -> null | ||
| } | ||
| fun BookingListTab.asDateRangeFilter(): BookingsFilterOption.DateRange? = when (this) { | ||
| BookingListTab.Today -> BookingsDateRangePresets.today(clock) | ||
| BookingListTab.Upcoming -> BookingsDateRangePresets.upcoming(clock) | ||
| BookingListTab.All -> null | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| package org.wordpress.android.fluxc.network.rest.wpcom.wc.bookings | ||
|
|
||
| import java.time.Clock | ||
| import java.time.LocalDate | ||
| import java.time.LocalTime | ||
| import java.time.ZoneOffset | ||
|
|
||
| /** | ||
| * Factory for canonical booking date range presets used across app and data layers. | ||
| * | ||
| * Notes about time zone: | ||
| * The WC Bookings API stores dates without timezone information. To ensure | ||
| * consistent comparisons and filtering on both client and server, we construct | ||
| * ranges in UTC. | ||
| * See p1759398245019489-slack-C09FHQNQERG | ||
| */ | ||
| object BookingsDateRangePresets { | ||
| /** | ||
| * Returns a DateRange that spans the current day in UTC, inclusive of the | ||
| * full day when interpreted by the API (midnight to end-of-day). | ||
| */ | ||
| fun today(clock: Clock): BookingsFilterOption.DateRange { | ||
| val start = LocalDate.now(clock) | ||
| .atTime(LocalTime.MIDNIGHT) | ||
| .atOffset(ZoneOffset.UTC) | ||
| .toInstant() | ||
| val end = LocalDate.now(clock) | ||
| .atTime(LocalTime.MAX) | ||
| .atOffset(ZoneOffset.UTC) | ||
| .toInstant() | ||
| return BookingsFilterOption.DateRange(before = end, after = start) | ||
| } | ||
|
|
||
| /** | ||
| * Returns a DateRange that includes bookings strictly after the end of the | ||
| * current day in UTC (i.e., upcoming bookings from tomorrow onwards). | ||
| * | ||
| * before = null and after = end-of-today. | ||
AdamGrzybkowski marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| */ | ||
| fun upcoming(clock: Clock): BookingsFilterOption.DateRange { | ||
| val endOfToday = LocalDate.now(clock) | ||
| .atTime(LocalTime.MAX) | ||
| .atOffset(ZoneOffset.UTC) | ||
| .toInstant() | ||
| return BookingsFilterOption.DateRange(before = null, after = endOfToday) | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,6 +15,7 @@ import org.wordpress.android.fluxc.store.WCOrderStore | |
| import org.wordpress.android.fluxc.tools.CoroutineEngine | ||
| import org.wordpress.android.fluxc.utils.HeadersParser | ||
| import org.wordpress.android.util.AppLog | ||
| import java.time.Clock | ||
| import javax.inject.Inject | ||
| import javax.inject.Singleton | ||
|
|
||
|
|
@@ -26,13 +27,14 @@ class BookingsStore @Inject internal constructor( | |
| private val bookingDtoMapper: BookingDtoMapper, | ||
| private val headersParser: HeadersParser, | ||
| private val coroutineEngine: CoroutineEngine, | ||
| private val clock: Clock, | ||
| ) { | ||
| suspend fun fetchBookings( | ||
| site: SiteModel, | ||
| perPage: Int = BookingsRestClient.DEFAULT_PER_PAGE, | ||
| page: Int = 1, | ||
| query: String? = null, | ||
| filters: BookingFilters?, | ||
| filters: BookingFilters, | ||
| order: BookingsOrderOption | ||
| ): WooResult<BookingsFetchResult> { | ||
| return coroutineEngine.withDefaultContext(AppLog.T.API, this, "fetchBookings") { | ||
|
|
@@ -54,9 +56,28 @@ class BookingsStore @Inject internal constructor( | |
| ) | ||
| } | ||
| } | ||
| if (page == 1 && filters == BookingFilters.EMPTY && query.isNullOrEmpty()) { | ||
| // Clear existing bookings and insert new ones when fetching the first page | ||
| bookingsDao.replaceAllForSite(site.localId(), entities) | ||
| // Clear existing bookings when fetching the first page. | ||
| // If filters are applied, only clear entries that match the applied filters, | ||
| // otherwise (no filters) clear all entries for the site. | ||
|
Comment on lines
+59
to
+61
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The comment here is not entirely accurate. We say,
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I initially did that, but then I thought that there was a reason why we added this check in the first place, so I decided to strictly add this logic for Today and Upcoming filter. I'm open to changing that. I wonder if we had similar problems with Products or Orders, and how they were solved there?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm thinking about it, I'm not sure we need it. We can only apply other filters in the
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. True, the issue is less visible for the All tab, but the All filter is saved, and it's possible that the user prefers to always keep a certain filter enabled. In that case, it becomes the same situation as the Today and Upcoming tabs.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I've just tested the Products tab, and the issue exists there as well. |
||
| if (page == 1 && query.isNullOrEmpty()) { | ||
| when { | ||
| filters == BookingFilters.EMPTY -> { | ||
| bookingsDao.replaceAllForSite(site.localId(), entities) | ||
| } | ||
| filters.dateRange != null && isTodayOrUpcoming(filters.dateRange) -> { | ||
| // Delete only the rows that match the applied date range filter for Today/Upcoming | ||
| bookingsDao.deleteForSiteWithDateRangeFilter( | ||
| site.localId(), | ||
| filters.dateRange, | ||
| entities.map { it.id.value } | ||
| ) | ||
| bookingsDao.insertOrReplace(entities) | ||
|
||
| } | ||
AdamGrzybkowski marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| else -> { | ||
| // For any other filters, avoid deletions to prevent removing unrelated cached items | ||
| bookingsDao.insertOrReplace(entities) | ||
| } | ||
| } | ||
| } else { | ||
| bookingsDao.insertOrReplace(entities) | ||
| } | ||
|
|
@@ -77,6 +98,12 @@ class BookingsStore @Inject internal constructor( | |
| } | ||
| } | ||
|
|
||
| private fun isTodayOrUpcoming(dateRange: BookingsFilterOption.DateRange): Boolean { | ||
| val today = BookingsDateRangePresets.today(clock) | ||
| val upcoming = BookingsDateRangePresets.upcoming(clock) | ||
| return dateRange == today || dateRange == upcoming | ||
| } | ||
|
|
||
| fun observeBookings( | ||
| site: SiteModel, | ||
| limit: Int? = null, | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.