MOBILE-4616 feedback: Fix tab selection after submit form
parent
ce7243b1ae
commit
95756b5c13
|
@ -20,20 +20,13 @@
|
||||||
[courseId]="courseId" [hasDataToSync]="hasOffline" (completionChanged)="onCompletionChange()" />
|
[courseId]="courseId" [hasDataToSync]="hasOffline" (completionChanged)="onCompletionChange()" />
|
||||||
|
|
||||||
<core-tabs [hideUntil]="tabsReady" [selectedIndex]="firstSelectedTab">
|
<core-tabs [hideUntil]="tabsReady" [selectedIndex]="firstSelectedTab">
|
||||||
<core-tab [title]="'addon.mod_feedback.overview' | translate" id="overview" (ionSelect)="tabChanged('overview')">
|
<core-tab [title]="tabs.overview.label | translate" [id]="tabs.overview.name" (ionSelect)="tabChanged(tabs.overview.name)">
|
||||||
<ng-template>
|
<ng-template>
|
||||||
<ng-container *ngTemplateOutlet="tabOverview" />
|
<ng-container *ngTemplateOutlet="tabOverview" />
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</core-tab>
|
</core-tab>
|
||||||
<core-tab *ngIf="showAnalysis && access && access.canviewreports" id="analysis" [title]="'addon.mod_feedback.analysis' | translate"
|
<core-tab *ngIf="showAnalysis && access" [id]="tabs.analysis.name" [title]="tabs.analysis.label | translate"
|
||||||
(ionSelect)="tabChanged('analysis')">
|
(ionSelect)="tabChanged(tabs.analysis.name)">
|
||||||
<ng-template>
|
|
||||||
<ng-container *ngTemplateOutlet="tabAnalysis" />
|
|
||||||
</ng-template>
|
|
||||||
</core-tab>
|
|
||||||
|
|
||||||
<core-tab *ngIf="showAnalysis && access && !access.canviewreports" id="analysis"
|
|
||||||
[title]="'addon.mod_feedback.completed_feedbacks' | translate" (ionSelect)="tabChanged('analysis')">
|
|
||||||
<ng-template>
|
<ng-template>
|
||||||
<ng-container *ngTemplateOutlet="tabAnalysis" />
|
<ng-container *ngTemplateOutlet="tabAnalysis" />
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
@ -101,7 +94,7 @@
|
||||||
|
|
||||||
<!-- Template to render the overview. -->
|
<!-- Template to render the overview. -->
|
||||||
<ng-template #tabOverview>
|
<ng-template #tabOverview>
|
||||||
<core-loading [hideUntil]="tabsLoaded.overview">
|
<core-loading [hideUntil]="tabs.overview.loaded">
|
||||||
<ng-container *ngTemplateOutlet="basicInfo" />
|
<ng-container *ngTemplateOutlet="basicInfo" />
|
||||||
|
|
||||||
<ion-card class="core-info-card" *ngIf="access && access.cancomplete && !access.isopen">
|
<ion-card class="core-info-card" *ngIf="access && access.cancomplete && !access.isopen">
|
||||||
|
@ -153,7 +146,7 @@
|
||||||
|
|
||||||
<!-- Template to render the analysis. -->
|
<!-- Template to render the analysis. -->
|
||||||
<ng-template #tabAnalysis>
|
<ng-template #tabAnalysis>
|
||||||
<core-loading [hideUntil]="tabsLoaded.analysis">
|
<core-loading [hideUntil]="tabs.analysis.loaded">
|
||||||
<ng-container *ngTemplateOutlet="basicInfo" />
|
<ng-container *ngTemplateOutlet="basicInfo" />
|
||||||
|
|
||||||
<ng-container *ngIf="access && (access.canedititems || !access.isempty)">
|
<ng-container *ngIf="access && (access.canedititems || !access.isempty)">
|
||||||
|
|
|
@ -38,7 +38,12 @@ import {
|
||||||
AddonModFeedbackSyncResult,
|
AddonModFeedbackSyncResult,
|
||||||
} from '../../services/feedback-sync';
|
} from '../../services/feedback-sync';
|
||||||
import { AddonModFeedbackPrefetchHandler } from '../../services/handlers/prefetch';
|
import { AddonModFeedbackPrefetchHandler } from '../../services/handlers/prefetch';
|
||||||
import { ADDON_MOD_FEEDBACK_COMPONENT, ADDON_MOD_FEEDBACK_FORM_SUBMITTED, ADDON_MOD_FEEDBACK_PAGE_NAME } from '../../constants';
|
import {
|
||||||
|
ADDON_MOD_FEEDBACK_COMPONENT,
|
||||||
|
ADDON_MOD_FEEDBACK_FORM_SUBMITTED,
|
||||||
|
ADDON_MOD_FEEDBACK_PAGE_NAME,
|
||||||
|
AddonModFeedbackIndexTabName,
|
||||||
|
} from '../../constants';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component that displays a feedback index page.
|
* Component that displays a feedback index page.
|
||||||
|
@ -51,7 +56,7 @@ export class AddonModFeedbackIndexComponent extends CoreCourseModuleMainActivity
|
||||||
|
|
||||||
@ViewChild(CoreTabsComponent) tabsComponent?: CoreTabsComponent;
|
@ViewChild(CoreTabsComponent) tabsComponent?: CoreTabsComponent;
|
||||||
|
|
||||||
@Input() tab = 'overview';
|
@Input() selectedTab: AddonModFeedbackIndexTabName = AddonModFeedbackIndexTabName.OVERVIEW;
|
||||||
@Input() group = 0;
|
@Input() group = 0;
|
||||||
|
|
||||||
component = ADDON_MOD_FEEDBACK_COMPONENT;
|
component = ADDON_MOD_FEEDBACK_COMPONENT;
|
||||||
|
@ -75,9 +80,9 @@ export class AddonModFeedbackIndexComponent extends CoreCourseModuleMainActivity
|
||||||
closeTimeReadable: '',
|
closeTimeReadable: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
tabsLoaded = {
|
tabs = {
|
||||||
overview: false,
|
overview: { name: AddonModFeedbackIndexTabName.OVERVIEW, label: 'addon.mod_feedback.overview', loaded: false },
|
||||||
analysis: false,
|
analysis: { name: AddonModFeedbackIndexTabName.ANALYSIS, label: 'addon.mod_feedback.analysis', loaded: false },
|
||||||
};
|
};
|
||||||
|
|
||||||
protected submitObserver: CoreEventObserver;
|
protected submitObserver: CoreEventObserver;
|
||||||
|
@ -92,12 +97,12 @@ export class AddonModFeedbackIndexComponent extends CoreCourseModuleMainActivity
|
||||||
|
|
||||||
// Listen for form submit events.
|
// Listen for form submit events.
|
||||||
this.submitObserver = CoreEvents.on(ADDON_MOD_FEEDBACK_FORM_SUBMITTED, async (data) => {
|
this.submitObserver = CoreEvents.on(ADDON_MOD_FEEDBACK_FORM_SUBMITTED, async (data) => {
|
||||||
if (!this.feedback || data.feedbackId != this.feedback.id) {
|
if (!this.feedback || data.feedbackId !== this.feedback.id) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.tabsLoaded.analysis = false;
|
this.tabs.analysis.loaded = false;
|
||||||
this.tabsLoaded.overview = false;
|
this.tabs.overview.loaded = false;
|
||||||
this.showLoading = true;
|
this.showLoading = true;
|
||||||
|
|
||||||
// Prefetch data if needed.
|
// Prefetch data if needed.
|
||||||
|
@ -110,7 +115,7 @@ export class AddonModFeedbackIndexComponent extends CoreCourseModuleMainActivity
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the right tab.
|
// Load the right tab.
|
||||||
if (data.tab != this.tab) {
|
if (data.tab !== this.selectedTab) {
|
||||||
this.tabChanged(data.tab);
|
this.tabChanged(data.tab);
|
||||||
} else {
|
} else {
|
||||||
this.loadContent(true);
|
this.loadContent(true);
|
||||||
|
@ -149,7 +154,9 @@ export class AddonModFeedbackIndexComponent extends CoreCourseModuleMainActivity
|
||||||
*/
|
*/
|
||||||
protected callAnalyticsLogEvent(): void {
|
protected callAnalyticsLogEvent(): void {
|
||||||
this.analyticsLogEvent('mod_feedback_view_feedback', {
|
this.analyticsLogEvent('mod_feedback_view_feedback', {
|
||||||
url: this.tab === 'analysis' ? `/mod/feedback/analysis.php?id=${this.module.id}` : undefined,
|
url: this.selectedTab === AddonModFeedbackIndexTabName.ANALYSIS
|
||||||
|
? `/mod/feedback/analysis.php?id=${this.module.id}`
|
||||||
|
: undefined,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,8 +175,8 @@ export class AddonModFeedbackIndexComponent extends CoreCourseModuleMainActivity
|
||||||
promises.push(AddonModFeedback.invalidateResumePageData(this.feedback.id));
|
promises.push(AddonModFeedback.invalidateResumePageData(this.feedback.id));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.tabsLoaded.analysis = false;
|
this.tabs.analysis.loaded = false;
|
||||||
this.tabsLoaded.overview = false;
|
this.tabs.overview.loaded = false;
|
||||||
|
|
||||||
await Promise.all(promises);
|
await Promise.all(promises);
|
||||||
}
|
}
|
||||||
|
@ -178,7 +185,7 @@ export class AddonModFeedbackIndexComponent extends CoreCourseModuleMainActivity
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
protected isRefreshSyncNeeded(syncEventData: AddonModFeedbackAutoSyncData): boolean {
|
protected isRefreshSyncNeeded(syncEventData: AddonModFeedbackAutoSyncData): boolean {
|
||||||
if (this.feedback && syncEventData.feedbackId == this.feedback.id) {
|
if (syncEventData.feedbackId === this.feedback?.id) {
|
||||||
// Refresh the data.
|
// Refresh the data.
|
||||||
this.content?.scrollToTop();
|
this.content?.scrollToTop();
|
||||||
|
|
||||||
|
@ -207,12 +214,17 @@ export class AddonModFeedbackIndexComponent extends CoreCourseModuleMainActivity
|
||||||
this.access = await AddonModFeedback.getFeedbackAccessInformation(this.feedback.id, { cmId: this.module.id });
|
this.access = await AddonModFeedback.getFeedbackAccessInformation(this.feedback.id, { cmId: this.module.id });
|
||||||
|
|
||||||
this.showAnalysis = (this.access.canviewreports || this.access.canviewanalysis) && !this.access.isempty;
|
this.showAnalysis = (this.access.canviewreports || this.access.canviewanalysis) && !this.access.isempty;
|
||||||
|
|
||||||
|
this.tabs.analysis.label = this.access.canviewreports
|
||||||
|
? 'addon.mod_feedback.analysis'
|
||||||
|
: 'addon.mod_feedback.completed_feedbacks';
|
||||||
|
|
||||||
this.firstSelectedTab = 0;
|
this.firstSelectedTab = 0;
|
||||||
if (!this.showAnalysis) {
|
if (!this.showAnalysis) {
|
||||||
this.tab = 'overview';
|
this.selectedTab = AddonModFeedbackIndexTabName.OVERVIEW;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.tab == 'analysis') {
|
if (this.selectedTab === AddonModFeedbackIndexTabName.ANALYSIS) {
|
||||||
this.firstSelectedTab = 1;
|
this.firstSelectedTab = 1;
|
||||||
|
|
||||||
return await this.fetchFeedbackAnalysisData();
|
return await this.fetchFeedbackAnalysisData();
|
||||||
|
@ -227,34 +239,36 @@ export class AddonModFeedbackIndexComponent extends CoreCourseModuleMainActivity
|
||||||
|
|
||||||
if (this.tabsReady) {
|
if (this.tabsReady) {
|
||||||
// Make sure the right tab is selected.
|
// Make sure the right tab is selected.
|
||||||
this.tabsComponent?.selectTab(this.tab || 'overview');
|
this.tabsComponent?.selectTab(this.selectedTab ?? AddonModFeedbackIndexTabName.OVERVIEW);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience function to get feedback overview data.
|
* Convenience function to get feedback overview data.
|
||||||
*
|
|
||||||
* @returns Resolved when done.
|
|
||||||
*/
|
*/
|
||||||
protected async fetchFeedbackOverviewData(): Promise<void> {
|
protected async fetchFeedbackOverviewData(): Promise<void> {
|
||||||
|
if (!this.access || !this.feedback) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const promises: Promise<void>[] = [];
|
const promises: Promise<void>[] = [];
|
||||||
|
|
||||||
if (this.access!.cancomplete && this.access!.cansubmit && this.access!.isopen) {
|
if (this.access.cancomplete && this.access.cansubmit && this.access.isopen) {
|
||||||
promises.push(AddonModFeedback.getResumePage(this.feedback!.id, { cmId: this.module.id }).then((goPage) => {
|
promises.push(AddonModFeedback.getResumePage(this.feedback.id, { cmId: this.module.id }).then((goPage) => {
|
||||||
this.goPage = goPage > 0 ? goPage : undefined;
|
this.goPage = goPage > 0 ? goPage : undefined;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.access!.canedititems) {
|
if (this.access.canedititems) {
|
||||||
this.overview.timeopen = (this.feedback!.timeopen || 0) * 1000;
|
this.overview.timeopen = (this.feedback.timeopen || 0) * 1000;
|
||||||
this.overview.openTimeReadable = this.overview.timeopen ? CoreTimeUtils.userDate(this.overview.timeopen) : '';
|
this.overview.openTimeReadable = this.overview.timeopen ? CoreTimeUtils.userDate(this.overview.timeopen) : '';
|
||||||
this.overview.timeclose = (this.feedback!.timeclose || 0) * 1000;
|
this.overview.timeclose = (this.feedback.timeclose || 0) * 1000;
|
||||||
this.overview.closeTimeReadable = this.overview.timeclose ? CoreTimeUtils.userDate(this.overview.timeclose) : '';
|
this.overview.closeTimeReadable = this.overview.timeclose ? CoreTimeUtils.userDate(this.overview.timeclose) : '';
|
||||||
}
|
}
|
||||||
if (this.access!.canviewanalysis) {
|
if (this.access.canviewanalysis) {
|
||||||
// Get groups (only for teachers).
|
// Get groups (only for teachers).
|
||||||
promises.push(this.fetchGroupInfo(this.module.id));
|
promises.push(this.fetchGroupInfo(this.module.id));
|
||||||
}
|
}
|
||||||
|
@ -262,7 +276,7 @@ export class AddonModFeedbackIndexComponent extends CoreCourseModuleMainActivity
|
||||||
try {
|
try {
|
||||||
await Promise.all(promises);
|
await Promise.all(promises);
|
||||||
} finally {
|
} finally {
|
||||||
this.tabsLoaded.overview = true;
|
this.tabs.overview.loaded = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -273,15 +287,14 @@ export class AddonModFeedbackIndexComponent extends CoreCourseModuleMainActivity
|
||||||
*/
|
*/
|
||||||
protected async fetchFeedbackAnalysisData(): Promise<void> {
|
protected async fetchFeedbackAnalysisData(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
if (this.access!.canviewanalysis) {
|
if (this.access?.canviewanalysis) {
|
||||||
// Get groups (only for teachers).
|
// Get groups (only for teachers).
|
||||||
await this.fetchGroupInfo(this.module.id);
|
await this.fetchGroupInfo(this.module.id);
|
||||||
} else {
|
} else {
|
||||||
this.tabChanged('overview');
|
this.tabChanged(AddonModFeedbackIndexTabName.OVERVIEW);
|
||||||
}
|
}
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
this.tabsLoaded.analysis = true;
|
this.tabs.analysis.loaded = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -419,7 +432,7 @@ export class AddonModFeedbackIndexComponent extends CoreCourseModuleMainActivity
|
||||||
* Open attempts page.
|
* Open attempts page.
|
||||||
*/
|
*/
|
||||||
openAttempts(): void {
|
openAttempts(): void {
|
||||||
if (!this.access!.canviewreports || this.completedCount <= 0) {
|
if (!this.access || !this.access.canviewreports || this.completedCount <= 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -438,11 +451,11 @@ export class AddonModFeedbackIndexComponent extends CoreCourseModuleMainActivity
|
||||||
*
|
*
|
||||||
* @param tabName New tab name.
|
* @param tabName New tab name.
|
||||||
*/
|
*/
|
||||||
tabChanged(tabName: string): void {
|
tabChanged(tabName: AddonModFeedbackIndexTabName): void {
|
||||||
const tabHasChanged = this.tab !== undefined && this.tab !== tabName;
|
const tabHasChanged = this.selectedTab !== undefined && this.selectedTab !== tabName;
|
||||||
this.tab = tabName;
|
this.selectedTab = tabName;
|
||||||
|
|
||||||
if (!this.tabsLoaded[this.tab]) {
|
if (!this.tabs[this.selectedTab].loaded) {
|
||||||
this.loadContent(false, false, true);
|
this.loadContent(false, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -455,17 +468,20 @@ export class AddonModFeedbackIndexComponent extends CoreCourseModuleMainActivity
|
||||||
* Set group to see the analysis.
|
* Set group to see the analysis.
|
||||||
*
|
*
|
||||||
* @param groupId Group ID.
|
* @param groupId Group ID.
|
||||||
* @returns Resolved when done.
|
|
||||||
*/
|
*/
|
||||||
async setGroup(groupId: number): Promise<void> {
|
async setGroup(groupId: number): Promise<void> {
|
||||||
|
if (!this.feedback) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.group = groupId;
|
this.group = groupId;
|
||||||
|
|
||||||
const analysis = await AddonModFeedback.getAnalysis(this.feedback!.id, { groupId, cmId: this.module.id });
|
const analysis = await AddonModFeedback.getAnalysis(this.feedback.id, { groupId, cmId: this.module.id });
|
||||||
|
|
||||||
this.completedCount = analysis.completedcount;
|
this.completedCount = analysis.completedcount;
|
||||||
this.itemsCount = analysis.itemscount;
|
this.itemsCount = analysis.itemscount;
|
||||||
|
|
||||||
if (this.tab == 'analysis') {
|
if (this.selectedTab === AddonModFeedbackIndexTabName.ANALYSIS) {
|
||||||
let num = 1;
|
let num = 1;
|
||||||
|
|
||||||
this.items = <AddonModFeedbackItem[]> analysis.itemsdata.map((itemData) => {
|
this.items = <AddonModFeedbackItem[]> analysis.itemsdata.map((itemData) => {
|
||||||
|
|
|
@ -24,3 +24,11 @@ export const ADDON_MOD_FEEDBACK_MULTICHOICE_HIDENOSELECT = 'h';
|
||||||
export const ADDON_MOD_FEEDBACK_MULTICHOICERATED_VALUE_SEP = '####';
|
export const ADDON_MOD_FEEDBACK_MULTICHOICERATED_VALUE_SEP = '####';
|
||||||
|
|
||||||
export const ADDON_MOD_FEEDBACK_PER_PAGE = 20;
|
export const ADDON_MOD_FEEDBACK_PER_PAGE = 20;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Index Tabs.
|
||||||
|
*/
|
||||||
|
export enum AddonModFeedbackIndexTabName {
|
||||||
|
OVERVIEW = 'overview',
|
||||||
|
ANALYSIS = 'analysis',
|
||||||
|
}
|
||||||
|
|
|
@ -36,8 +36,14 @@ import {
|
||||||
import { AddonModFeedbackFormItem, AddonModFeedbackHelper } from '../../services/feedback-helper';
|
import { AddonModFeedbackFormItem, AddonModFeedbackHelper } from '../../services/feedback-helper';
|
||||||
import { AddonModFeedbackSync } from '../../services/feedback-sync';
|
import { AddonModFeedbackSync } from '../../services/feedback-sync';
|
||||||
import { CoreAnalytics, CoreAnalyticsEventType } from '@services/analytics';
|
import { CoreAnalytics, CoreAnalyticsEventType } from '@services/analytics';
|
||||||
import { ADDON_MOD_FEEDBACK_COMPONENT, ADDON_MOD_FEEDBACK_FORM_SUBMITTED, ADDON_MOD_FEEDBACK_PAGE_NAME } from '../../constants';
|
import {
|
||||||
|
ADDON_MOD_FEEDBACK_COMPONENT,
|
||||||
|
ADDON_MOD_FEEDBACK_FORM_SUBMITTED,
|
||||||
|
ADDON_MOD_FEEDBACK_PAGE_NAME,
|
||||||
|
AddonModFeedbackIndexTabName,
|
||||||
|
} from '../../constants';
|
||||||
import { CoreLoadings } from '@services/loadings';
|
import { CoreLoadings } from '@services/loadings';
|
||||||
|
import { CoreError } from '@classes/errors/error';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Page that displays feedback form.
|
* Page that displays feedback form.
|
||||||
|
@ -117,14 +123,14 @@ export class AddonModFeedbackFormPage implements OnInit, OnDestroy, CanLeave {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.feedback) {
|
if (!this.feedback || !this.module) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await AddonModFeedback.logView(this.feedback.id, true);
|
await AddonModFeedback.logView(this.feedback.id, true);
|
||||||
|
|
||||||
CoreCourse.checkModuleCompletion(this.courseId, this.module!.completiondata);
|
CoreCourse.checkModuleCompletion(this.courseId, this.module.completiondata);
|
||||||
} catch {
|
} catch {
|
||||||
// Ignore errors.
|
// Ignore errors.
|
||||||
}
|
}
|
||||||
|
@ -183,7 +189,7 @@ export class AddonModFeedbackFormPage implements OnInit, OnDestroy, CanLeave {
|
||||||
|
|
||||||
let page = 0;
|
let page = 0;
|
||||||
|
|
||||||
if (!this.preview && this.access!.cansubmit && !this.access!.isempty) {
|
if (!this.preview && this.access?.cansubmit && !this.access?.isempty) {
|
||||||
page = this.currentPage ?? await this.fetchResumePage(options);
|
page = this.currentPage ?? await this.fetchResumePage(options);
|
||||||
} else {
|
} else {
|
||||||
this.preview = true;
|
this.preview = true;
|
||||||
|
@ -203,11 +209,14 @@ export class AddonModFeedbackFormPage implements OnInit, OnDestroy, CanLeave {
|
||||||
* Fetch access information.
|
* Fetch access information.
|
||||||
*
|
*
|
||||||
* @param options Options.
|
* @param options Options.
|
||||||
* @returns Promise resolved when done.
|
|
||||||
*/
|
*/
|
||||||
protected async fetchAccessData(options: CoreCourseCommonModWSOptions): Promise<void> {
|
protected async fetchAccessData(options: CoreCourseCommonModWSOptions): Promise<void> {
|
||||||
|
if (!this.feedback) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.access = await AddonModFeedback.getFeedbackAccessInformation(this.feedback!.id, options);
|
this.access = await AddonModFeedback.getFeedbackAccessInformation(this.feedback.id, options);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (this.offline || CoreUtils.isWebServiceError(error)) {
|
if (this.offline || CoreUtils.isWebServiceError(error)) {
|
||||||
// Already offline or shouldn't go offline, fail.
|
// Already offline or shouldn't go offline, fail.
|
||||||
|
@ -218,7 +227,7 @@ export class AddonModFeedbackFormPage implements OnInit, OnDestroy, CanLeave {
|
||||||
this.offline = true;
|
this.offline = true;
|
||||||
options.readingStrategy = CoreSitesReadingStrategy.PREFER_CACHE;
|
options.readingStrategy = CoreSitesReadingStrategy.PREFER_CACHE;
|
||||||
|
|
||||||
this.access = await AddonModFeedback.getFeedbackAccessInformation(this.feedback!.id, options);
|
this.access = await AddonModFeedback.getFeedbackAccessInformation(this.feedback.id, options);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,8 +238,12 @@ export class AddonModFeedbackFormPage implements OnInit, OnDestroy, CanLeave {
|
||||||
* @returns Promise resolved with the page to resume.
|
* @returns Promise resolved with the page to resume.
|
||||||
*/
|
*/
|
||||||
protected async fetchResumePage(options: CoreCourseCommonModWSOptions): Promise<number> {
|
protected async fetchResumePage(options: CoreCourseCommonModWSOptions): Promise<number> {
|
||||||
|
if (!this.feedback) {
|
||||||
|
throw new CoreError('Cannot fetch resume page: missing feedback');
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return await AddonModFeedback.getResumePage(this.feedback!.id, options);
|
return await AddonModFeedback.getResumePage(this.feedback.id, options);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (this.offline || CoreUtils.isWebServiceError(error)) {
|
if (this.offline || CoreUtils.isWebServiceError(error)) {
|
||||||
// Already offline or shouldn't go offline, fail.
|
// Already offline or shouldn't go offline, fail.
|
||||||
|
@ -241,7 +254,7 @@ export class AddonModFeedbackFormPage implements OnInit, OnDestroy, CanLeave {
|
||||||
this.offline = true;
|
this.offline = true;
|
||||||
options.readingStrategy = CoreSitesReadingStrategy.PREFER_CACHE;
|
options.readingStrategy = CoreSitesReadingStrategy.PREFER_CACHE;
|
||||||
|
|
||||||
return AddonModFeedback.getResumePage(this.feedback!.id, options);
|
return AddonModFeedback.getResumePage(this.feedback.id, options);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,7 +262,6 @@ export class AddonModFeedbackFormPage implements OnInit, OnDestroy, CanLeave {
|
||||||
* Fetch page data.
|
* Fetch page data.
|
||||||
*
|
*
|
||||||
* @param page Page to load.
|
* @param page Page to load.
|
||||||
* @returns Promise resolved when done.
|
|
||||||
*/
|
*/
|
||||||
protected async fetchFeedbackPageData(page: number = 0): Promise<void> {
|
protected async fetchFeedbackPageData(page: number = 0): Promise<void> {
|
||||||
this.items = [];
|
this.items = [];
|
||||||
|
@ -274,6 +286,10 @@ export class AddonModFeedbackFormPage implements OnInit, OnDestroy, CanLeave {
|
||||||
* @returns Promise resolved with WS response.
|
* @returns Promise resolved with WS response.
|
||||||
*/
|
*/
|
||||||
protected async fetchPageItems(page: number): Promise<AddonModFeedbackPageItems> {
|
protected async fetchPageItems(page: number): Promise<AddonModFeedbackPageItems> {
|
||||||
|
if (!this.feedback) {
|
||||||
|
throw new CoreError('Cannot fetch page items: missing feedback');
|
||||||
|
}
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
cmId: this.cmId,
|
cmId: this.cmId,
|
||||||
readingStrategy: this.offline ? CoreSitesReadingStrategy.PREFER_CACHE : CoreSitesReadingStrategy.ONLY_NETWORK,
|
readingStrategy: this.offline ? CoreSitesReadingStrategy.PREFER_CACHE : CoreSitesReadingStrategy.ONLY_NETWORK,
|
||||||
|
@ -281,7 +297,7 @@ export class AddonModFeedbackFormPage implements OnInit, OnDestroy, CanLeave {
|
||||||
};
|
};
|
||||||
|
|
||||||
if (this.preview) {
|
if (this.preview) {
|
||||||
const response = await AddonModFeedback.getItems(this.feedback!.id, options);
|
const response = await AddonModFeedback.getItems(this.feedback.id, options);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
items: response.items,
|
items: response.items,
|
||||||
|
@ -295,7 +311,7 @@ export class AddonModFeedbackFormPage implements OnInit, OnDestroy, CanLeave {
|
||||||
let response: AddonModFeedbackPageItems;
|
let response: AddonModFeedbackPageItems;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
response = await AddonModFeedback.getPageItemsWithValues(this.feedback!.id, page, options);
|
response = await AddonModFeedback.getPageItemsWithValues(this.feedback.id, page, options);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (this.offline || CoreUtils.isWebServiceError(error)) {
|
if (this.offline || CoreUtils.isWebServiceError(error)) {
|
||||||
// Already offline or shouldn't go offline, fail.
|
// Already offline or shouldn't go offline, fail.
|
||||||
|
@ -306,7 +322,7 @@ export class AddonModFeedbackFormPage implements OnInit, OnDestroy, CanLeave {
|
||||||
this.offline = true;
|
this.offline = true;
|
||||||
options.readingStrategy = CoreSitesReadingStrategy.PREFER_CACHE;
|
options.readingStrategy = CoreSitesReadingStrategy.PREFER_CACHE;
|
||||||
|
|
||||||
response = await AddonModFeedback.getPageItemsWithValues(this.feedback!.id, page, options);
|
response = await AddonModFeedback.getPageItemsWithValues(this.feedback.id, page, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.hasPrevPage = !!response.hasprevpage;
|
this.hasPrevPage = !!response.hasprevpage;
|
||||||
|
@ -319,9 +335,12 @@ export class AddonModFeedbackFormPage implements OnInit, OnDestroy, CanLeave {
|
||||||
* Function to allow page navigation through the questions form.
|
* Function to allow page navigation through the questions form.
|
||||||
*
|
*
|
||||||
* @param goPrevious If true it will go back to the previous page, if false, it will go forward.
|
* @param goPrevious If true it will go back to the previous page, if false, it will go forward.
|
||||||
* @returns Resolved when done.
|
|
||||||
*/
|
*/
|
||||||
async gotoPage(goPrevious: boolean): Promise<void> {
|
async gotoPage(goPrevious: boolean): Promise<void> {
|
||||||
|
if (!this.feedback || this.currentPage === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.content?.scrollToTop();
|
this.content?.scrollToTop();
|
||||||
this.feedbackLoaded = false;
|
this.feedbackLoaded = false;
|
||||||
|
|
||||||
|
@ -330,9 +349,9 @@ export class AddonModFeedbackFormPage implements OnInit, OnDestroy, CanLeave {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Sync other pages first.
|
// Sync other pages first.
|
||||||
await CoreUtils.ignoreErrors(AddonModFeedbackSync.syncFeedback(this.feedback!.id));
|
await CoreUtils.ignoreErrors(AddonModFeedbackSync.syncFeedback(this.feedback.id));
|
||||||
|
|
||||||
const response = await AddonModFeedback.processPage(this.feedback!.id, this.currentPage!, responses, {
|
const response = await AddonModFeedback.processPage(this.feedback.id, this.currentPage, responses, {
|
||||||
goPrevious,
|
goPrevious,
|
||||||
formHasErrors,
|
formHasErrors,
|
||||||
courseId: this.courseId,
|
courseId: this.courseId,
|
||||||
|
@ -351,14 +370,14 @@ export class AddonModFeedbackFormPage implements OnInit, OnDestroy, CanLeave {
|
||||||
|
|
||||||
// Invalidate access information so user will see home page updated (continue form or completion messages).
|
// Invalidate access information so user will see home page updated (continue form or completion messages).
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
AddonModFeedback.invalidateFeedbackAccessInformationData(this.feedback!.id),
|
AddonModFeedback.invalidateFeedbackAccessInformationData(this.feedback.id),
|
||||||
AddonModFeedback.invalidateResumePageData(this.feedback!.id),
|
AddonModFeedback.invalidateResumePageData(this.feedback.id),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// If form has been submitted, the info has been already invalidated but we should update index view.
|
// If form has been submitted, the info has been already invalidated but we should update index view.
|
||||||
CoreEvents.trigger(ADDON_MOD_FEEDBACK_FORM_SUBMITTED, {
|
CoreEvents.trigger(ADDON_MOD_FEEDBACK_FORM_SUBMITTED, {
|
||||||
feedbackId: this.feedback!.id,
|
feedbackId: this.feedback.id,
|
||||||
tab: 'overview',
|
tab: AddonModFeedbackIndexTabName.OVERVIEW,
|
||||||
offline: this.completedOffline,
|
offline: this.completedOffline,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -371,11 +390,11 @@ export class AddonModFeedbackFormPage implements OnInit, OnDestroy, CanLeave {
|
||||||
// Errors on questions, stay in page.
|
// Errors on questions, stay in page.
|
||||||
} else {
|
} else {
|
||||||
// Invalidate access information so user will see home page updated (continue form).
|
// Invalidate access information so user will see home page updated (continue form).
|
||||||
await AddonModFeedback.invalidateResumePageData(this.feedback!.id);
|
await AddonModFeedback.invalidateResumePageData(this.feedback.id);
|
||||||
|
|
||||||
CoreEvents.trigger(ADDON_MOD_FEEDBACK_FORM_SUBMITTED, {
|
CoreEvents.trigger(ADDON_MOD_FEEDBACK_FORM_SUBMITTED, {
|
||||||
feedbackId: this.feedback!.id,
|
feedbackId: this.feedback.id,
|
||||||
tab: 'overview',
|
tab: AddonModFeedbackIndexTabName.OVERVIEW,
|
||||||
offline: this.completedOffline,
|
offline: this.completedOffline,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -393,11 +412,15 @@ export class AddonModFeedbackFormPage implements OnInit, OnDestroy, CanLeave {
|
||||||
* Function to link implemented features.
|
* Function to link implemented features.
|
||||||
*/
|
*/
|
||||||
showAnalysis(): void {
|
showAnalysis(): void {
|
||||||
|
if (!this.feedback) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.fromIndex) {
|
if (this.fromIndex) {
|
||||||
// Previous page is the index page, go back.
|
// Previous page is the index page, go back.
|
||||||
CoreEvents.trigger(ADDON_MOD_FEEDBACK_FORM_SUBMITTED, {
|
CoreEvents.trigger(ADDON_MOD_FEEDBACK_FORM_SUBMITTED, {
|
||||||
feedbackId: this.feedback!.id,
|
feedbackId: this.feedback.id,
|
||||||
tab: 'analysis',
|
tab: AddonModFeedbackIndexTabName.ANALYSIS,
|
||||||
offline: this.completedOffline,
|
offline: this.completedOffline,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -409,7 +432,7 @@ export class AddonModFeedbackFormPage implements OnInit, OnDestroy, CanLeave {
|
||||||
CoreNavigator.navigateToSitePath(ADDON_MOD_FEEDBACK_PAGE_NAME + `/${this.courseId}/${this.cmId}`, {
|
CoreNavigator.navigateToSitePath(ADDON_MOD_FEEDBACK_PAGE_NAME + `/${this.courseId}/${this.cmId}`, {
|
||||||
params: {
|
params: {
|
||||||
module: this.module,
|
module: this.module,
|
||||||
tab: 'analysis',
|
tab: AddonModFeedbackIndexTabName.ANALYSIS,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,6 @@
|
||||||
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" />
|
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" />
|
||||||
</ion-refresher>
|
</ion-refresher>
|
||||||
|
|
||||||
<addon-mod-feedback-index [module]="module" [courseId]="courseId" [group]="selectedGroup" [tab]="selectedTab"
|
<addon-mod-feedback-index [module]="module" [courseId]="courseId" [group]="selectedGroup" [selectedTab]="selectedTab"
|
||||||
(dataRetrieved)="updateData($event)" />
|
(dataRetrieved)="updateData($event)" />
|
||||||
</ion-content>
|
</ion-content>
|
||||||
|
|
|
@ -16,6 +16,7 @@ import { Component, OnInit, ViewChild } from '@angular/core';
|
||||||
import { CoreCourseModuleMainActivityPage } from '@features/course/classes/main-activity-page';
|
import { CoreCourseModuleMainActivityPage } from '@features/course/classes/main-activity-page';
|
||||||
import { CoreNavigator } from '@services/navigator';
|
import { CoreNavigator } from '@services/navigator';
|
||||||
import { AddonModFeedbackIndexComponent } from '../../components/index/index';
|
import { AddonModFeedbackIndexComponent } from '../../components/index/index';
|
||||||
|
import { AddonModFeedbackIndexTabName } from '../../constants';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Page that displays a feedback.
|
* Page that displays a feedback.
|
||||||
|
@ -28,7 +29,7 @@ export class AddonModFeedbackIndexPage extends CoreCourseModuleMainActivityPage<
|
||||||
|
|
||||||
@ViewChild(AddonModFeedbackIndexComponent) activityComponent?: AddonModFeedbackIndexComponent;
|
@ViewChild(AddonModFeedbackIndexComponent) activityComponent?: AddonModFeedbackIndexComponent;
|
||||||
|
|
||||||
selectedTab?: string;
|
selectedTab?: AddonModFeedbackIndexTabName;
|
||||||
selectedGroup?: number;
|
selectedGroup?: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -34,6 +34,7 @@ import {
|
||||||
ADDON_MOD_FEEDBACK_MULTICHOICE_TYPE_SEP,
|
ADDON_MOD_FEEDBACK_MULTICHOICE_TYPE_SEP,
|
||||||
ADDON_MOD_FEEDBACK_MULTICHOICERATED_VALUE_SEP,
|
ADDON_MOD_FEEDBACK_MULTICHOICERATED_VALUE_SEP,
|
||||||
ADDON_MOD_FEEDBACK_PER_PAGE,
|
ADDON_MOD_FEEDBACK_PER_PAGE,
|
||||||
|
AddonModFeedbackIndexTabName,
|
||||||
} from '../constants';
|
} from '../constants';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1263,7 +1264,7 @@ declare module '@singletons/events' {
|
||||||
*/
|
*/
|
||||||
export type AddonModFeedbackFormSubmittedData = {
|
export type AddonModFeedbackFormSubmittedData = {
|
||||||
feedbackId: number;
|
feedbackId: number;
|
||||||
tab: string;
|
tab: AddonModFeedbackIndexTabName;
|
||||||
offline: boolean;
|
offline: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ import { CoreCourse } from '@features/course/services/course';
|
||||||
import { CoreNavigator } from '@services/navigator';
|
import { CoreNavigator } from '@services/navigator';
|
||||||
import { CoreDomUtils } from '@services/utils/dom';
|
import { CoreDomUtils } from '@services/utils/dom';
|
||||||
import { makeSingleton } from '@singletons';
|
import { makeSingleton } from '@singletons';
|
||||||
import { ADDON_MOD_FEEDBACK_PAGE_NAME } from '../../constants';
|
import { ADDON_MOD_FEEDBACK_PAGE_NAME, AddonModFeedbackIndexTabName } from '../../constants';
|
||||||
import { CoreLoadings } from '@services/loadings';
|
import { CoreLoadings } from '@services/loadings';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -59,7 +59,7 @@ export class AddonModFeedbackAnalysisLinkHandlerService extends CoreContentLinks
|
||||||
{
|
{
|
||||||
params: {
|
params: {
|
||||||
module,
|
module,
|
||||||
tab: 'analysis',
|
tab: AddonModFeedbackIndexTabName.ANALYSIS,
|
||||||
},
|
},
|
||||||
siteId,
|
siteId,
|
||||||
},
|
},
|
||||||
|
|
|
@ -221,7 +221,7 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements AfterViewIn
|
||||||
this.swiper.update();
|
this.swiper.update();
|
||||||
await CoreWait.nextTick();
|
await CoreWait.nextTick();
|
||||||
|
|
||||||
if (!this.hasSliddenToInitial && this.selectedIndex && this.selectedIndex >= this.swiper.slidesPerViewDynamic()) {
|
if (!this.hasSliddenToInitial && this.selectedIndex >= this.swiper.slidesPerViewDynamic()) {
|
||||||
this.hasSliddenToInitial = true;
|
this.hasSliddenToInitial = true;
|
||||||
this.shouldSlideToInitial = true;
|
this.shouldSlideToInitial = true;
|
||||||
|
|
||||||
|
@ -233,7 +233,7 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements AfterViewIn
|
||||||
}, 400);
|
}, 400);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
} else if (this.selectedIndex) {
|
} else {
|
||||||
this.hasSliddenToInitial = true;
|
this.hasSliddenToInitial = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -301,21 +301,21 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements AfterViewIn
|
||||||
* @returns Initial tab, undefined if no valid tab found.
|
* @returns Initial tab, undefined if no valid tab found.
|
||||||
*/
|
*/
|
||||||
protected calculateInitialTab(): T | undefined {
|
protected calculateInitialTab(): T | undefined {
|
||||||
const selectedTab: T | undefined = this.tabs[this.selectedIndex || 0] || undefined;
|
const selectedTab: T | undefined = this.tabs[this.selectedIndex] || undefined;
|
||||||
|
|
||||||
if (selectedTab && selectedTab.enabled) {
|
if (selectedTab?.enabled) {
|
||||||
return selectedTab;
|
return selectedTab;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The tab is not enabled or not shown. Get the first tab that is enabled.
|
// The tab is not enabled or not shown. Get the first tab that is enabled.
|
||||||
return this.tabs.find((tab) => tab.enabled) || undefined;
|
return this.tabs.find((tab) => tab.enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method executed when the slides are changed.
|
* Method executed when the slides are changed.
|
||||||
*/
|
*/
|
||||||
slideChanged(): void {
|
slideChanged(): void {
|
||||||
if (!this.swiper) {
|
if (!this.swiper || this.swiper.destroyed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,7 +340,7 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements AfterViewIn
|
||||||
* Calculate the number of slides that can fit on the screen.
|
* Calculate the number of slides that can fit on the screen.
|
||||||
*/
|
*/
|
||||||
protected async calculateMaxSlides(): Promise<void> {
|
protected async calculateMaxSlides(): Promise<void> {
|
||||||
if (!this.swiper) {
|
if (!this.swiper || this.swiper.destroyed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -456,7 +456,7 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements AfterViewIn
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.selected && this.swiper) {
|
if (this.selected && this.swiper && !this.swiper.destroyed) {
|
||||||
// Check if we need to slide to the tab because it's not visible.
|
// Check if we need to slide to the tab because it's not visible.
|
||||||
const firstVisibleTab = this.swiper.activeIndex;
|
const firstVisibleTab = this.swiper.activeIndex;
|
||||||
const lastVisibleTab = firstVisibleTab + this.swiper.slidesPerViewDynamic() - 1;
|
const lastVisibleTab = firstVisibleTab + this.swiper.slidesPerViewDynamic() - 1;
|
||||||
|
|
Loading…
Reference in New Issue