From 66993dc231e146e85132943513e2aefc8cb91016 Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Thu, 22 Apr 2021 15:19:15 +0200 Subject: [PATCH] MOBILE-3641 feedback: Migrate other pages --- .../mod/feedback/feedback-lazy.module.ts | 42 ++- .../mod/feedback/pages/attempt/attempt.html | 58 ++++ .../feedback/pages/attempt/attempt.module.ts | 37 +++ .../mod/feedback/pages/attempt/attempt.ts | 125 +++++++++ .../pages/nonrespondents/nonrespondents.html | 52 ++++ .../nonrespondents/nonrespondents.module.ts | 37 +++ .../pages/nonrespondents/nonrespondents.ts | 165 ++++++++++++ .../pages/respondents/respondents.html | 79 ++++++ .../feedback/pages/respondents/respondents.ts | 248 ++++++++++++++++++ 9 files changed, 842 insertions(+), 1 deletion(-) create mode 100644 src/addons/mod/feedback/pages/attempt/attempt.html create mode 100644 src/addons/mod/feedback/pages/attempt/attempt.module.ts create mode 100644 src/addons/mod/feedback/pages/attempt/attempt.ts create mode 100644 src/addons/mod/feedback/pages/nonrespondents/nonrespondents.html create mode 100644 src/addons/mod/feedback/pages/nonrespondents/nonrespondents.module.ts create mode 100644 src/addons/mod/feedback/pages/nonrespondents/nonrespondents.ts create mode 100644 src/addons/mod/feedback/pages/respondents/respondents.html create mode 100644 src/addons/mod/feedback/pages/respondents/respondents.ts diff --git a/src/addons/mod/feedback/feedback-lazy.module.ts b/src/addons/mod/feedback/feedback-lazy.module.ts index c083bea13..9c15c101a 100644 --- a/src/addons/mod/feedback/feedback-lazy.module.ts +++ b/src/addons/mod/feedback/feedback-lazy.module.ts @@ -17,8 +17,11 @@ import { RouterModule, Routes } from '@angular/router'; import { CoreSharedModule } from '@/core/shared.module'; import { AddonModFeedbackComponentsModule } from './components/components.module'; import { AddonModFeedbackIndexPage } from './pages/index/index'; +import { AddonModFeedbackRespondentsPage } from './pages/respondents/respondents'; +import { conditionalRoutes } from '@/app/app-routing.module'; +import { CoreScreen } from '@services/screen'; -const routes: Routes = [ +const commonRoutes: Routes = [ { path: ':courseId/:cmId', component: AddonModFeedbackIndexPage, @@ -27,6 +30,42 @@ const routes: Routes = [ path: ':courseId/:cmId/form', loadChildren: () => import('./pages/form/form.module').then(m => m.AddonModFeedbackFormPageModule), }, + { + path: ':courseId/:cmId/nonrespondents', + loadChildren: () => import('./pages/nonrespondents/nonrespondents.module') + .then(m => m.AddonModFeedbackNonRespondentsPageModule), + }, +]; + +const mobileRoutes: Routes = [ + ...commonRoutes, + { + path: ':courseId/:cmId/respondents', + component: AddonModFeedbackRespondentsPage, + }, + { + path: ':courseId/:cmId/attempt/:attemptId', + loadChildren: () => import('./pages/attempt/attempt.module').then(m => m.AddonModFeedbackAttemptPageModule), + }, +]; + +const tabletRoutes: Routes = [ + ...commonRoutes, + { + path: ':courseId/:cmId/respondents', + component: AddonModFeedbackRespondentsPage, + children: [ + { + path: 'attempt/:attemptId', + loadChildren: () => import('./pages/attempt/attempt.module').then(m => m.AddonModFeedbackAttemptPageModule), + }, + ], + }, +]; + +const routes: Routes = [ + ...conditionalRoutes(mobileRoutes, () => CoreScreen.isMobile), + ...conditionalRoutes(tabletRoutes, () => CoreScreen.isTablet), ]; @NgModule({ @@ -37,6 +76,7 @@ const routes: Routes = [ ], declarations: [ AddonModFeedbackIndexPage, + AddonModFeedbackRespondentsPage, ], }) export class AddonModFeedbackLazyModule {} diff --git a/src/addons/mod/feedback/pages/attempt/attempt.html b/src/addons/mod/feedback/pages/attempt/attempt.html new file mode 100644 index 000000000..aa1c35db7 --- /dev/null +++ b/src/addons/mod/feedback/pages/attempt/attempt.html @@ -0,0 +1,58 @@ + + + + + + + {{ attempt.fullname }} + + {{ 'addon.mod_feedback.response_nr' |translate }}: {{anonAttempt.number}} + + + + + + + + + + +

{{attempt.fullname}}

+

{{attempt.timemodified * 1000 | coreFormatDate }}

+
+
+ + + +

+ {{ 'addon.mod_feedback.response_nr' |translate }}: {{anonAttempt.number}} + ({{ 'addon.mod_feedback.anonymous' |translate }}) +

+
+
+ + + + + + + +

+ {{item.itemnumber}}. + + +

+

+ + +

+
+
+
+
+
+
+
diff --git a/src/addons/mod/feedback/pages/attempt/attempt.module.ts b/src/addons/mod/feedback/pages/attempt/attempt.module.ts new file mode 100644 index 000000000..788d1664a --- /dev/null +++ b/src/addons/mod/feedback/pages/attempt/attempt.module.ts @@ -0,0 +1,37 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { CoreSharedModule } from '@/core/shared.module'; +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { AddonModFeedbackAttemptPage } from './attempt'; + +const routes: Routes = [ + { + path: '', + component: AddonModFeedbackAttemptPage, + }, +]; + +@NgModule({ + declarations: [ + AddonModFeedbackAttemptPage, + ], + imports: [ + RouterModule.forChild(routes), + CoreSharedModule, + ], + exports: [RouterModule], +}) +export class AddonModFeedbackAttemptPageModule {} diff --git a/src/addons/mod/feedback/pages/attempt/attempt.ts b/src/addons/mod/feedback/pages/attempt/attempt.ts new file mode 100644 index 000000000..52e9736fe --- /dev/null +++ b/src/addons/mod/feedback/pages/attempt/attempt.ts @@ -0,0 +1,125 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Component, OnInit } from '@angular/core'; +import { CoreNavigator } from '@services/navigator'; +import { CoreDomUtils } from '@services/utils/dom'; +import { CoreTextUtils } from '@services/utils/text'; +import { + AddonModFeedback, + AddonModFeedbackProvider, + AddonModFeedbackWSAnonAttempt, + AddonModFeedbackWSAttempt, + AddonModFeedbackWSFeedback, +} from '../../services/feedback'; +import { AddonModFeedbackFormItem, AddonModFeedbackHelper } from '../../services/feedback-helper'; + +/** + * Page that displays a feedback attempt review. + */ +@Component({ + selector: 'page-addon-mod-feedback-attempt', + templateUrl: 'attempt.html', +}) +export class AddonModFeedbackAttemptPage implements OnInit { + + protected attemptId!: number; + + cmId!: number; + courseId!: number; + feedback?: AddonModFeedbackWSFeedback; + attempt?: AddonModFeedbackWSAttempt; + anonAttempt?: AddonModFeedbackWSAnonAttempt; + items: AddonModFeedbackAttemptItem[] = []; + component = AddonModFeedbackProvider.COMPONENT; + loaded = false; + + /** + * @inheritdoc + */ + ngOnInit(): void { + this.cmId = CoreNavigator.getRouteNumberParam('cmId')!; + this.courseId = CoreNavigator.getRouteNumberParam('courseId')!; + this.attemptId = CoreNavigator.getRouteNumberParam('attemptId')!; + + this.fetchData(); + } + + /** + * Fetch all the data required for the view. + * + * @return Promise resolved when done. + */ + protected async fetchData(): Promise { + try { + this.feedback = await AddonModFeedback.getFeedback(this.courseId, this.cmId); + + const attempt = await AddonModFeedback.getAttempt(this.feedback.id, this.attemptId, { cmId: this.cmId }); + + if (this.isAnonAttempt(attempt)) { + this.anonAttempt = attempt; + delete this.attempt; + } else { + this.attempt = attempt; + delete this.anonAttempt; + } + + const items = await AddonModFeedback.getItems(this.feedback.id, { cmId: this.cmId }); + + // Add responses and format items. + this.items = items.items.map((item) => { + const formItem = AddonModFeedbackHelper.getItemForm(item, true); + if (!formItem) { + return; + } + + const attemptItem = formItem; + + if (item.typ == 'label') { + attemptItem.submittedValue = CoreTextUtils.replacePluginfileUrls(item.presentation, item.itemfiles); + } else { + for (const x in attempt.responses) { + if (attempt.responses[x].id == item.id) { + attemptItem.submittedValue = attempt.responses[x].printval; + break; + } + } + } + + return attemptItem; + }).filter((itemData) => itemData); // Filter items with errors. + + } catch (message) { + // Some call failed on fetch, go back. + CoreDomUtils.showErrorModalDefault(message, 'core.course.errorgetmodule', true); + CoreNavigator.back(); + } finally { + this.loaded = true; + } + } + + /** + * Check if an attempt is anonymous or not. + * + * @param attempt Attempt to check. + */ + isAnonAttempt(attempt: AddonModFeedbackWSAttempt | AddonModFeedbackWSAnonAttempt): attempt is AddonModFeedbackWSAnonAttempt { + return !('fullname' in attempt); + } + +} + +type AddonModFeedbackAttemptItem = AddonModFeedbackFormItem & { + submittedValue?: string; +}; diff --git a/src/addons/mod/feedback/pages/nonrespondents/nonrespondents.html b/src/addons/mod/feedback/pages/nonrespondents/nonrespondents.html new file mode 100644 index 000000000..3a83b44c2 --- /dev/null +++ b/src/addons/mod/feedback/pages/nonrespondents/nonrespondents.html @@ -0,0 +1,52 @@ + + + + + + {{ 'addon.mod_feedback.responses' |translate }} + + + + + + + + + + + {{'core.groupsseparate' | translate }} + {{'core.groupsvisible' | translate }} + + + + {{groupOpt.name}} + + + + + + {{ 'addon.mod_feedback.non_respondents_students' | translate : {$a: total } }} + + + + + +

{{ user.fullname }}

+

+ + {{ 'addon.mod_feedback.started' | translate}} + + + {{ 'addon.mod_feedback.not_started' | translate}} + +

+
+
+
+ + + +
+
+
diff --git a/src/addons/mod/feedback/pages/nonrespondents/nonrespondents.module.ts b/src/addons/mod/feedback/pages/nonrespondents/nonrespondents.module.ts new file mode 100644 index 000000000..654d85141 --- /dev/null +++ b/src/addons/mod/feedback/pages/nonrespondents/nonrespondents.module.ts @@ -0,0 +1,37 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { CoreSharedModule } from '@/core/shared.module'; +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { AddonModFeedbackNonRespondentsPage } from './nonrespondents'; + +const routes: Routes = [ + { + path: '', + component: AddonModFeedbackNonRespondentsPage, + }, +]; + +@NgModule({ + declarations: [ + AddonModFeedbackNonRespondentsPage, + ], + imports: [ + RouterModule.forChild(routes), + CoreSharedModule, + ], + exports: [RouterModule], +}) +export class AddonModFeedbackNonRespondentsPageModule {} diff --git a/src/addons/mod/feedback/pages/nonrespondents/nonrespondents.ts b/src/addons/mod/feedback/pages/nonrespondents/nonrespondents.ts new file mode 100644 index 000000000..d95111480 --- /dev/null +++ b/src/addons/mod/feedback/pages/nonrespondents/nonrespondents.ts @@ -0,0 +1,165 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Component, OnInit } from '@angular/core'; +import { IonRefresher } from '@ionic/angular'; +import { CoreGroupInfo, CoreGroups } from '@services/groups'; +import { CoreNavigator } from '@services/navigator'; +import { CoreDomUtils } from '@services/utils/dom'; +import { CoreUtils } from '@services/utils/utils'; +import { AddonModFeedback, AddonModFeedbackWSFeedback } from '../../services/feedback'; +import { AddonModFeedbackHelper, AddonModFeedbackNonRespondent } from '../../services/feedback-helper'; + +/** + * Page that displays feedback non respondents. + */ +@Component({ + selector: 'page-addon-mod-feedback-nonrespondents', + templateUrl: 'nonrespondents.html', +}) +export class AddonModFeedbackNonRespondentsPage implements OnInit { + + protected cmId!: number; + protected courseId!: number; + protected feedback?: AddonModFeedbackWSFeedback; + protected page = 0; + + selectedGroup!: number; + groupInfo?: CoreGroupInfo; + users: AddonModFeedbackNonRespondent[] = []; + total = 0; + canLoadMore = false; + loaded = false; + loadMoreError = false; + + /** + * @inheritdoc + */ + ngOnInit(): void { + this.cmId = CoreNavigator.getRouteNumberParam('cmId')!; + this.courseId = CoreNavigator.getRouteNumberParam('courseId')!; + this.selectedGroup = CoreNavigator.getRouteNumberParam('group') || 0; + + this.fetchData(); + } + + /** + * Fetch all the data required for the view. + * + * @param refresh Empty events array first. + * @return Promise resolved when done. + */ + protected async fetchData(refresh: boolean = false): Promise { + this.page = 0; + this.total = 0; + this.users = []; + + try { + this.feedback = await AddonModFeedback.getFeedback(this.courseId, this.cmId); + + this.groupInfo = await CoreGroups.getActivityGroupInfo(this.cmId); + + this.selectedGroup = CoreGroups.validateGroupId(this.selectedGroup, this.groupInfo); + + await this.loadGroupUsers(this.selectedGroup); + } catch (message) { + CoreDomUtils.showErrorModalDefault(message, 'core.course.errorgetmodule', true); + + if (!refresh) { + // Some call failed on first fetch, go back. + CoreNavigator.back(); + } + } + } + + /** + * Load Group responses. + * + * @param groupId If defined it will change group if not, it will load more users for the same group. + * @return Promise resolved when done. + */ + protected async loadGroupUsers(groupId?: number): Promise { + this.loadMoreError = false; + + if (typeof groupId == 'undefined') { + this.page++; + } else { + this.selectedGroup = groupId; + this.page = 0; + this.total = 0; + this.users = []; + this.loaded = false; + } + + try { + const response = await AddonModFeedbackHelper.getNonRespondents(this.feedback!.id, { + groupId: this.selectedGroup, + page: this.page, + cmId: this.cmId, + }); + + this.total = response.total; + if (this.users.length < response.total) { + this.users = this.users.concat(response.users); + } + + this.canLoadMore = this.users.length < response.total; + } catch (error) { + this.loadMoreError = true; + + throw error; + } finally { + this.loaded = true; + } + } + + /** + * Change selected group or load more users. + * + * @param groupId Group ID selected. If not defined, it will load more users. + * @param infiniteComplete Infinite scroll complete function. Only used from core-infinite-loading. + */ + async loadAttempts(groupId?: number, infiniteComplete?: () => void): Promise { + try { + await this.loadGroupUsers(groupId); + } catch (error) { + CoreDomUtils.showErrorModalDefault(error, 'core.course.errorgetmodule', true); + } finally { + infiniteComplete && infiniteComplete(); + } + } + + /** + * Refresh the attempts. + * + * @param refresher Refresher. + */ + async refreshFeedback(refresher: IonRefresher): Promise { + try { + const promises: Promise[] = []; + + promises.push(CoreGroups.invalidateActivityGroupInfo(this.cmId)); + if (this.feedback) { + promises.push(AddonModFeedback.invalidateNonRespondentsData(this.feedback.id)); + } + + await CoreUtils.ignoreErrors(Promise.all(promises)); + + await this.fetchData(true); + } finally { + refresher.complete(); + } + } + +} diff --git a/src/addons/mod/feedback/pages/respondents/respondents.html b/src/addons/mod/feedback/pages/respondents/respondents.html new file mode 100644 index 000000000..33b20567b --- /dev/null +++ b/src/addons/mod/feedback/pages/respondents/respondents.html @@ -0,0 +1,79 @@ + + + + + + {{ 'addon.mod_feedback.responses' |translate }} + + + + + + + + + + + + {{'core.groupsseparate' | translate }} + {{'core.groupsvisible' | translate }} + + + + {{groupOpt.name}} + + + + + + + + {{ 'addon.mod_feedback.non_anonymous_entries' | translate : {$a: responses.responses.total } }} + + + + + +

{{ attempt.fullname }}

+

{{attempt.timemodified * 1000 | coreFormatDate }}

+
+
+ + + + {{ 'core.loadmore' | translate }} + + + + +
+ + + + + {{ 'addon.mod_feedback.anonymous_entries' |translate : {$a: responses.anonResponses.total } }} + + + + +

{{ 'addon.mod_feedback.response_nr' |translate }}: {{attempt.number}}

+
+
+ + + + {{ 'core.loadmore' | translate }} + + + + +
+
+
+
+
diff --git a/src/addons/mod/feedback/pages/respondents/respondents.ts b/src/addons/mod/feedback/pages/respondents/respondents.ts new file mode 100644 index 000000000..8539b2cb2 --- /dev/null +++ b/src/addons/mod/feedback/pages/respondents/respondents.ts @@ -0,0 +1,248 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { AfterViewInit, Component, ViewChild } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { CorePageItemsListManager } from '@classes/page-items-list-manager'; +import { CoreSplitViewComponent } from '@components/split-view/split-view'; +import { IonRefresher } from '@ionic/angular'; +import { CoreGroupInfo, CoreGroups } from '@services/groups'; +import { CoreNavigator } from '@services/navigator'; +import { CoreDomUtils } from '@services/utils/dom'; +import { CoreUtils } from '@services/utils/utils'; +import { + AddonModFeedback, + AddonModFeedbackWSAnonAttempt, + AddonModFeedbackWSAttempt, + AddonModFeedbackWSFeedback, +} from '../../services/feedback'; +import { AddonModFeedbackHelper, AddonModFeedbackResponsesAnalysis } from '../../services/feedback-helper'; + +/** + * Page that displays feedback respondents. + */ +@Component({ + selector: 'page-addon-mod-feedback-respondents', + templateUrl: 'respondents.html', +}) +export class AddonModFeedbackRespondentsPage implements AfterViewInit { + + @ViewChild(CoreSplitViewComponent) splitView!: CoreSplitViewComponent; + + protected cmId!: number; + protected courseId!: number; + protected page = 0; + protected feedback?: AddonModFeedbackWSFeedback; + + responses: AddonModFeedbackResponsesManager; + selectedGroup!: number; + groupInfo?: CoreGroupInfo; + loaded = false; + loadingMore = false; + + constructor( + route: ActivatedRoute, + ) { + this.responses = new AddonModFeedbackResponsesManager( + route.component, + ); + } + + /** + * @inheritdoc + */ + async ngAfterViewInit(): Promise { + this.cmId = CoreNavigator.getRouteNumberParam('cmId')!; + this.courseId = CoreNavigator.getRouteNumberParam('courseId')!; + this.selectedGroup = CoreNavigator.getRouteNumberParam('group') || 0; + + await this.fetchData(); + + this.responses.start(this.splitView); + } + + /** + * Fetch all the data required for the view. + * + * @param refresh Empty events array first. + * @return Promise resolved when done. + */ + async fetchData(refresh: boolean = false): Promise { + this.page = 0; + this.responses.resetItems(); + + try { + this.feedback = await AddonModFeedback.getFeedback(this.courseId, this.cmId); + + this.groupInfo = await CoreGroups.getActivityGroupInfo(this.cmId); + + this.selectedGroup = CoreGroups.validateGroupId(this.selectedGroup, this.groupInfo); + + await this.loadGroupAttempts(this.selectedGroup); + } catch (error) { + CoreDomUtils.showErrorModalDefault(error, 'core.course.errorgetmodule', true); + + if (!refresh) { + // Some call failed on first fetch, go back. + CoreNavigator.back(); + } + } + } + + /** + * Load Group attempts. + * + * @param groupId If defined it will change group if not, it will load more attempts for the same group. + * @return Resolved with the attempts loaded. + */ + protected async loadGroupAttempts(groupId?: number): Promise { + if (typeof groupId == 'undefined') { + this.page++; + this.loadingMore = true; + } else { + this.selectedGroup = groupId; + this.page = 0; + this.responses.resetItems(); + } + + try { + const responses = await AddonModFeedbackHelper.getResponsesAnalysis(this.feedback!.id, { + groupId: this.selectedGroup, + page: this.page, + cmId: this.cmId, + }); + + this.responses.setResponses(responses); + } finally { + this.loadingMore = false; + this.loaded = true; + } + } + + /** + * Change selected group or load more attempts. + * + * @param groupId Group ID selected. If not defined, it will load more attempts. + */ + async loadAttempts(groupId?: number): Promise { + try { + await this.loadGroupAttempts(groupId); + } catch (error) { + CoreDomUtils.showErrorModalDefault(error, 'core.course.errorgetmodule', true); + } + } + + /** + * Refresh the attempts. + * + * @param refresher Refresher. + */ + async refreshFeedback(refresher: IonRefresher): Promise { + const promises: Promise[] = []; + + promises.push(CoreGroups.invalidateActivityGroupInfo(this.cmId)); + if (this.feedback) { + promises.push(AddonModFeedback.invalidateResponsesAnalysisData(this.feedback.id)); + } + + try { + await CoreUtils.ignoreErrors(Promise.all(promises)); + + await this.fetchData(true); + } finally { + refresher.complete(); + } + } + +} + +/** + * Type of items that can be held by the entries manager. + */ +type EntryItem = AddonModFeedbackWSAttempt | AddonModFeedbackWSAnonAttempt; + +/** + * Entries manager. + */ +class AddonModFeedbackResponsesManager extends CorePageItemsListManager { + + responses: AddonModFeedbackResponses = { + attempts: [], + total: 0, + canLoadMore: false, + }; + + anonResponses: AddonModFeedbackAnonResponses = { + attempts: [], + total: 0, + canLoadMore: false, + }; + + constructor(pageComponent: unknown) { + super(pageComponent); + } + + /** + * Update responses. + * + * @param responses Responses. + */ + setResponses(responses: AddonModFeedbackResponsesAnalysis): void { + this.responses.total = responses.totalattempts; + this.anonResponses.total = responses.totalanonattempts; + + if (this.anonResponses.attempts.length < responses.totalanonattempts) { + this.anonResponses.attempts = this.anonResponses.attempts.concat(responses.anonattempts); + } + if (this.responses.attempts.length < responses.totalattempts) { + this.responses.attempts = this.responses.attempts.concat(responses.attempts); + } + + this.anonResponses.canLoadMore = this.anonResponses.attempts.length < responses.totalanonattempts; + this.responses.canLoadMore = this.responses.attempts.length < responses.totalattempts; + + this.setItems(( this.responses.attempts).concat(this.anonResponses.attempts)); + } + + /** + * @inheritdoc + */ + resetItems(): void { + super.resetItems(); + this.responses.total = 0; + this.responses.attempts = []; + this.anonResponses.total = 0; + this.anonResponses.attempts = []; + } + + /** + * @inheritdoc + */ + protected getItemPath(entry: EntryItem): string { + return `attempt/${entry.id}`; + } + +} + +type AddonModFeedbackResponses = { + attempts: AddonModFeedbackWSAttempt[]; + total: number; + canLoadMore: boolean; +}; + +type AddonModFeedbackAnonResponses = { + attempts: AddonModFeedbackWSAnonAttempt[]; + total: number; + canLoadMore: boolean; +};