diff --git a/src/addons/block/timeline/services/block-handler.ts b/src/addons/block/timeline/services/block-handler.ts index d05574786..0675654c3 100644 --- a/src/addons/block/timeline/services/block-handler.ts +++ b/src/addons/block/timeline/services/block-handler.ts @@ -19,7 +19,7 @@ import { CoreCourses } from '@features/courses/services/courses'; import { AddonBlockTimelineComponent } from '@addons/block/timeline/components/timeline/timeline'; import { CoreBlockBaseHandler } from '@features/block/classes/base-block-handler'; import { makeSingleton } from '@singletons'; -import { AddonBlockTimeline } from './timeline'; +import { CoreCoursesDashboard } from '@features/courses/services/dashboard'; /** * Block handler. @@ -36,7 +36,7 @@ export class AddonBlockTimelineHandlerService extends CoreBlockBaseHandler { * @return Whether or not the handler is enabled on a site level. */ async isEnabled(): Promise { - const enabled = await AddonBlockTimeline.isAvailable(); + const enabled = !CoreCoursesDashboard.isDisabledInSite(); const currentSite = CoreSites.getCurrentSite(); return enabled && ((currentSite && currentSite.isVersionGreaterEqualThan('3.6')) || diff --git a/src/addons/block/timeline/services/timeline.ts b/src/addons/block/timeline/services/timeline.ts index 0dbddde01..fe06a1aa6 100644 --- a/src/addons/block/timeline/services/timeline.ts +++ b/src/addons/block/timeline/services/timeline.ts @@ -14,7 +14,6 @@ import { Injectable } from '@angular/core'; import { CoreSites } from '@services/sites'; -import { CoreCoursesDashboard } from '@features/courses/services/dashboard'; import { AddonCalendarEvents, AddonCalendarEventsGroupedByCourse, @@ -251,19 +250,6 @@ export class AddonBlockTimelineProvider { await site.invalidateWsCacheForKeyStartingWith(this.getActionEventsByTimesortPrefixCacheKey()); } - /** - * Returns whether or not My Overview is available for a certain site. - * - * @param siteId Site ID. If not defined, current site. - * @return Promise resolved with true if available, resolved with false or rejected otherwise. - */ - async isAvailable(siteId?: string): Promise { - const site = await CoreSites.getSite(siteId); - - // Check if dashboard is disabled. - return !CoreCoursesDashboard.isDisabledInSite(site); - } - /** * Handles course events, filtering and treating if more can be loaded. * diff --git a/src/core/features/courses/pages/dashboard/dashboard.ts b/src/core/features/courses/pages/dashboard/dashboard.ts index e86d2d72a..739b75755 100644 --- a/src/core/features/courses/pages/dashboard/dashboard.ts +++ b/src/core/features/courses/pages/dashboard/dashboard.ts @@ -85,8 +85,9 @@ export class CoreCoursesDashboardPage implements OnInit, OnDestroy { */ protected async loadContent(): Promise { const available = await CoreCoursesDashboard.isAvailable(); + const disabled = await CoreCoursesDashboard.isDisabled(); - if (available) { + if (available && !disabled) { this.userId = CoreSites.getCurrentSiteUserId(); try { @@ -101,7 +102,7 @@ export class CoreCoursesDashboardPage implements OnInit, OnDestroy { // Cannot get the blocks, just show dashboard if needed. this.loadFallbackBlocks(); } - } else if (!CoreCoursesDashboard.isDisabledInSite()) { + } else if (!available) { // Not available, but not disabled either. Use fallback. this.loadFallbackBlocks(); } else { diff --git a/src/core/features/courses/pages/my/my.html b/src/core/features/courses/pages/my/my.html index af8a8f2fa..bdd93c60b 100644 --- a/src/core/features/courses/pages/my/my.html +++ b/src/core/features/courses/pages/my/my.html @@ -26,13 +26,16 @@ - + - - - - - + + + + + + + + diff --git a/src/core/features/courses/pages/my/my.ts b/src/core/features/courses/pages/my/my.ts index 9c98a25a4..45365fd23 100644 --- a/src/core/features/courses/pages/my/my.ts +++ b/src/core/features/courses/pages/my/my.ts @@ -15,6 +15,8 @@ import { AddonBlockMyOverviewComponent } from '@addons/block/myoverview/components/myoverview/myoverview'; import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { CoreBlockComponent } from '@features/block/components/block/block'; +import { CoreCourseBlock } from '@features/course/services/course'; +import { CoreCoursesDashboard, CoreCoursesDashboardProvider } from '@features/courses/services/dashboard'; import { IonRefresher } from '@ionic/angular'; import { CoreNavigator } from '@services/navigator'; import { CoreSites } from '@services/sites'; @@ -37,7 +39,9 @@ export class CoreCoursesMyCoursesPage implements OnInit, OnDestroy { searchEnabled = false; downloadCoursesEnabled = false; userId: number; + loadedBlock?: Partial; myOverviewBlock?: AddonBlockMyOverviewComponent; + loaded = false; protected updateSiteObserver: CoreEventObserver; @@ -58,21 +62,49 @@ export class CoreCoursesMyCoursesPage implements OnInit, OnDestroy { this.searchEnabled = !CoreCourses.isSearchCoursesDisabledInSite(); this.downloadCoursesEnabled = !CoreCourses.isDownloadCoursesDisabledInSite(); - this.loadBlock(); + this.loadContent(); } /** * Load my overview block instance. */ - protected loadBlock(): void { - setTimeout(() => { - if (!this.block) { - return this.loadBlock(); - } + protected async loadContent(): Promise { + const available = await CoreCoursesDashboard.isAvailable(); + const disabled = await CoreCourses.isMyCoursesDisabled(); - this.myOverviewBlock = this.block?.dynamicComponent?.instance as AddonBlockMyOverviewComponent; - }, 500); + if (available && !disabled) { + try { + const blocks = await CoreCoursesDashboard.getDashboardBlocksFromWS(CoreCoursesDashboardProvider.MY_PAGE_COURSES); + + this.loadedBlock = blocks.find((block) => block.name == 'myoverview'); + + await CoreUtils.nextTicks(2); + + this.myOverviewBlock = this.block?.dynamicComponent?.instance as AddonBlockMyOverviewComponent; + } catch { + // Cannot get the blocks, just show the block if needed. + this.loadFallbackBlock(); + } + } else if (!available) { + // WS not available, or my courses page not available. show fallback block. + this.loadFallbackBlock(); + } else { + // Disabled. + this.loadedBlock = undefined; + } + + this.loaded = true; + } + + /** + * Load fallback blocks. + */ + protected loadFallbackBlock(): void { + this.loadedBlock = { + name: 'myoverview', + visible: true, + }; } /** @@ -95,11 +127,21 @@ export class CoreCoursesMyCoursesPage implements OnInit, OnDestroy { * @param refresher Refresher. */ async refresh(refresher?: IonRefresher): Promise { - if (this.block) { - await CoreUtils.ignoreErrors(this.block.doRefresh()); + + const promises: Promise[] = []; + + promises.push(CoreCoursesDashboard.invalidateDashboardBlocks(CoreCoursesDashboardProvider.MY_PAGE_COURSES)); + + // Invalidate the blocks. + if (this.myOverviewBlock) { + promises.push(CoreUtils.ignoreErrors(this.myOverviewBlock.doRefresh())); } - refresher?.complete(); + Promise.all(promises).finally(() => { + this.loadContent().finally(() => { + refresher?.complete(); + }); + }); } /** diff --git a/src/core/features/courses/services/dashboard.ts b/src/core/features/courses/services/dashboard.ts index 76823a0b2..97e86c2d2 100644 --- a/src/core/features/courses/services/dashboard.ts +++ b/src/core/features/courses/services/dashboard.ts @@ -18,6 +18,7 @@ import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; import { CoreCourseBlock } from '@features/course/services/course'; import { CoreStatusWithWarningsWSResponse } from '@services/ws'; import { makeSingleton } from '@singletons'; +import { CoreError } from '@classes/errors/error'; const ROOT_CACHE_KEY = 'CoreCoursesDashboard:'; @@ -27,32 +28,47 @@ const ROOT_CACHE_KEY = 'CoreCoursesDashboard:'; @Injectable({ providedIn: 'root' }) export class CoreCoursesDashboardProvider { + static readonly MY_PAGE_DEFAULT = '__default'; + static readonly MY_PAGE_COURSES = '__courses'; + /** * Get cache key for dashboard blocks WS calls. * + * @param myPage What my page to return blocks of. Default MY_PAGE_DEFAULT. * @param userId User ID. Default, 0 means current user. * @return Cache key. */ - protected getDashboardBlocksCacheKey(userId: number = 0): string { - return ROOT_CACHE_KEY + 'blocks:' + userId; + protected getDashboardBlocksCacheKey(myPage = CoreCoursesDashboardProvider.MY_PAGE_DEFAULT, userId: number = 0): string { + return ROOT_CACHE_KEY + 'blocks:' + myPage + ':' + userId; } /** * Get dashboard blocks from WS. * + * @param myPage What my page to return blocks of. Default MY_PAGE_DEFAULT. * @param userId User ID. Default, current user. * @param siteId Site ID. If not defined, current site. * @return Promise resolved with the list of blocks. * @since 3.6 */ - protected async getDashboardBlocksFromWS(userId?: number, siteId?: string): Promise { + async getDashboardBlocksFromWS( + myPage = CoreCoursesDashboardProvider.MY_PAGE_DEFAULT, + userId?: number, + siteId?: string, + ): Promise { const site = await CoreSites.getSite(siteId); const params: CoreBlockGetDashboardBlocksWSParams = { returncontents: true, }; + if (CoreSites.getRequiredCurrentSite().isVersionGreaterEqualThan('4.0')) { + params.mypage = myPage; + } else if (myPage != CoreCoursesDashboardProvider.MY_PAGE_DEFAULT) { + throw new CoreError('mypage param is no accessible on core_block_get_dashboard_blocks'); + } + const preSets: CoreSiteWSPreSets = { - cacheKey: this.getDashboardBlocksCacheKey(userId), + cacheKey: this.getDashboardBlocksCacheKey(myPage, userId), updateFrequency: CoreSite.FREQUENCY_RARELY, }; if (userId) { @@ -71,7 +87,7 @@ export class CoreCoursesDashboardProvider { * @return Promise resolved with the list of blocks. */ async getDashboardBlocks(userId?: number, siteId?: string): Promise { - const blocks = await CoreCoursesDashboard.getDashboardBlocksFromWS(userId, siteId); + const blocks = await this.getDashboardBlocksFromWS(CoreCoursesDashboardProvider.MY_PAGE_DEFAULT, userId, siteId); let mainBlocks: CoreCourseBlock[] = []; let sideBlocks: CoreCourseBlock[] = []; @@ -104,14 +120,19 @@ export class CoreCoursesDashboardProvider { /** * Invalidates dashboard blocks WS call. * + * @param myPage What my page to return blocks of. Default MY_PAGE_DEFAULT. * @param userId User ID. Default, current user. * @param siteId Site ID. If not defined, current site. * @return Promise resolved when the data is invalidated. */ - async invalidateDashboardBlocks(userId?: number, siteId?: string): Promise { + async invalidateDashboardBlocks( + myPage = CoreCoursesDashboardProvider.MY_PAGE_DEFAULT, + userId?: number, + siteId?: string, + ): Promise { const site = await CoreSites.getSite(siteId); - return await site.invalidateWsCacheForKey(this.getDashboardBlocksCacheKey(userId)); + return await site.invalidateWsCacheForKey(this.getDashboardBlocksCacheKey(myPage, userId)); } /** @@ -124,11 +145,6 @@ export class CoreCoursesDashboardProvider { async isAvailable(siteId?: string): Promise { const site = await CoreSites.getSite(siteId); - // First check if it's disabled. - if (this.isDisabledInSite(site)) { - return false; - } - return site.wsAvailable('core_block_get_dashboard_blocks'); } @@ -171,6 +187,7 @@ export type CoreCoursesDashboardBlocks = { type CoreBlockGetDashboardBlocksWSParams = { userid?: number; // User id (optional), default is current user. returncontents?: boolean; // Whether to return the block contents. + mypage?: string; // @since 4.0. What my page to return blocks of. Default MY_PAGE_DEFAULT. }; /** diff --git a/src/core/features/courses/services/handlers/dashboard-home.ts b/src/core/features/courses/services/handlers/dashboard-home.ts index 0076031a8..c06582993 100644 --- a/src/core/features/courses/services/handlers/dashboard-home.ts +++ b/src/core/features/courses/services/handlers/dashboard-home.ts @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { AddonBlockTimeline } from '@addons/block/timeline/services/timeline'; import { Injectable } from '@angular/core'; import { CoreBlockDelegate } from '@features/block/services/block-delegate'; import { CoreMainMenuHomeHandler, CoreMainMenuHomeHandlerToDisplay } from '@features/mainmenu/services/home-delegate'; @@ -49,6 +48,7 @@ export class CoreDashboardHomeHandlerService implements CoreMainMenuHomeHandler const promises: Promise[] = []; let blocksEnabled = false; let dashboardAvailable = false; + let dashboardEnabled = false; // Check if blocks and 3.6 dashboard is enabled. promises.push(CoreBlockDelegate.areBlocksDisabled(siteId).then((disabled) => { @@ -57,7 +57,13 @@ export class CoreDashboardHomeHandlerService implements CoreMainMenuHomeHandler return; })); - promises.push(CoreCoursesDashboard.isAvailable().then((available) => { + promises.push(CoreCoursesDashboard.isDisabled(siteId).then((disabled) => { + dashboardEnabled = !disabled; + + return; + })); + + promises.push(CoreCoursesDashboard.isAvailable(siteId).then((available) => { dashboardAvailable = available; return; @@ -65,16 +71,14 @@ export class CoreDashboardHomeHandlerService implements CoreMainMenuHomeHandler await Promise.all(promises); - if (dashboardAvailable && blocksEnabled) { + if (dashboardAvailable && dashboardEnabled && blocksEnabled) { const blocks = await CoreCoursesDashboard.getDashboardBlocks(undefined, siteId); return CoreBlockDelegate.hasSupportedBlock(blocks.mainBlocks) || CoreBlockDelegate.hasSupportedBlock(blocks.sideBlocks); } - // Check if my overview is enabled. If it's enabled we will fake enabled blocks. - const timelineEnabled = await AddonBlockTimeline.isAvailable(); - - return timelineEnabled && blocksEnabled; + // Dashboard is enabled but not available, we will fake blocks. + return dashboardEnabled && blocksEnabled; } /**