forked from CIT/Vmeda.Online
		
	MOBILE-3641 feedback: Migrate other pages
This commit is contained in:
		
							parent
							
								
									77966d6fb4
								
							
						
					
					
						commit
						66993dc231
					
				@ -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 {}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										58
									
								
								src/addons/mod/feedback/pages/attempt/attempt.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								src/addons/mod/feedback/pages/attempt/attempt.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,58 @@
 | 
			
		||||
<ion-header>
 | 
			
		||||
    <ion-toolbar>
 | 
			
		||||
        <ion-buttons slot="start">
 | 
			
		||||
            <ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button>
 | 
			
		||||
        </ion-buttons>
 | 
			
		||||
        <ion-title>
 | 
			
		||||
            <ng-container *ngIf="attempt">{{ attempt.fullname }}</ng-container>
 | 
			
		||||
            <ng-container *ngIf="anonAttempt">
 | 
			
		||||
                {{ 'addon.mod_feedback.response_nr' |translate }}: {{anonAttempt.number}}
 | 
			
		||||
            </ng-container>
 | 
			
		||||
        </ion-title>
 | 
			
		||||
    </ion-toolbar>
 | 
			
		||||
</ion-header>
 | 
			
		||||
<ion-content>
 | 
			
		||||
    <core-loading [hideUntil]="loaded">
 | 
			
		||||
        <ion-list class="ion-no-margin" *ngIf="attempt || anonAttempt">
 | 
			
		||||
            <ion-item *ngIf="attempt" class="ion-text-wrap" core-user-link [userId]="attempt.userid"
 | 
			
		||||
                [attr.aria-label]=" 'core.user.viewprofile' | translate" [courseId]="attempt.courseid" [title]="attempt.fullname">
 | 
			
		||||
                <core-user-avatar [user]="attempt" slot="start"></core-user-avatar>
 | 
			
		||||
                <ion-label>
 | 
			
		||||
                    <h2>{{attempt.fullname}}</h2>
 | 
			
		||||
                    <p *ngIf="attempt.timemodified">{{attempt.timemodified * 1000 | coreFormatDate }}</p>
 | 
			
		||||
                </ion-label>
 | 
			
		||||
            </ion-item>
 | 
			
		||||
 | 
			
		||||
            <ion-item class="ion-text-wrap" *ngIf="anonAttempt">
 | 
			
		||||
                <ion-label>
 | 
			
		||||
                    <h2>
 | 
			
		||||
                        {{ 'addon.mod_feedback.response_nr' |translate }}: {{anonAttempt.number}}
 | 
			
		||||
                        ({{ 'addon.mod_feedback.anonymous' |translate }})
 | 
			
		||||
                    </h2>
 | 
			
		||||
                </ion-label>
 | 
			
		||||
            </ion-item >
 | 
			
		||||
            <ng-container *ngIf="items && items.length">
 | 
			
		||||
                <ng-container *ngFor="let item of items">
 | 
			
		||||
                    <ion-item-divider *ngIf="item.typ == 'pagebreak'">
 | 
			
		||||
                        <ion-label></ion-label>
 | 
			
		||||
                    </ion-item-divider>
 | 
			
		||||
                    <ion-item class="ion-text-wrap" *ngIf="item.typ != 'pagebreak'" [color]="item.dependitem > 0 ? 'light' : ''">
 | 
			
		||||
                        <ion-label>
 | 
			
		||||
                            <h2 *ngIf="item.name" [core-mark-required]="item.required">
 | 
			
		||||
                                <span *ngIf="feedback!.autonumbering && item.itemnumber">{{item.itemnumber}}. </span>
 | 
			
		||||
                                <core-format-text  [component]="component" [componentId]="cmId" [text]="item.name"
 | 
			
		||||
                                    contextLevel="module" [contextInstanceId]="cmId" [courseId]="courseId">
 | 
			
		||||
                                </core-format-text>
 | 
			
		||||
                            </h2>
 | 
			
		||||
                            <p *ngIf="item.submittedValue">
 | 
			
		||||
                                <core-format-text [component]="component" [componentId]="cmId" [text]="item.submittedValue"
 | 
			
		||||
                                    contextLevel="module" [contextInstanceId]="cmId" [courseId]="courseId">
 | 
			
		||||
                                </core-format-text>
 | 
			
		||||
                            </p>
 | 
			
		||||
                        </ion-label>
 | 
			
		||||
                    </ion-item>
 | 
			
		||||
                </ng-container>
 | 
			
		||||
            </ng-container>
 | 
			
		||||
        </ion-list>
 | 
			
		||||
    </core-loading>
 | 
			
		||||
</ion-content>
 | 
			
		||||
							
								
								
									
										37
									
								
								src/addons/mod/feedback/pages/attempt/attempt.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/addons/mod/feedback/pages/attempt/attempt.module.ts
									
									
									
									
									
										Normal file
									
								
							@ -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 {}
 | 
			
		||||
							
								
								
									
										125
									
								
								src/addons/mod/feedback/pages/attempt/attempt.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								src/addons/mod/feedback/pages/attempt/attempt.ts
									
									
									
									
									
										Normal file
									
								
							@ -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<void> {
 | 
			
		||||
        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 = <AddonModFeedbackAttemptItem[]> items.items.map((item) => {
 | 
			
		||||
                const formItem = AddonModFeedbackHelper.getItemForm(item, true);
 | 
			
		||||
                if (!formItem) {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                const attemptItem = <AddonModFeedbackAttemptItem> 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;
 | 
			
		||||
};
 | 
			
		||||
@ -0,0 +1,52 @@
 | 
			
		||||
<ion-header>
 | 
			
		||||
    <ion-toolbar>
 | 
			
		||||
        <ion-buttons slot="start">
 | 
			
		||||
            <ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button>
 | 
			
		||||
        </ion-buttons>
 | 
			
		||||
        <ion-title>{{ 'addon.mod_feedback.responses' |translate }}</ion-title>
 | 
			
		||||
    </ion-toolbar>
 | 
			
		||||
</ion-header>
 | 
			
		||||
<ion-content>
 | 
			
		||||
    <ion-refresher slot="fixed" [disabled]="!loaded" (ionRefresh)="refreshFeedback($event.target)">
 | 
			
		||||
        <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
 | 
			
		||||
    </ion-refresher>
 | 
			
		||||
    <core-loading [hideUntil]="loaded">
 | 
			
		||||
        <ion-list class="ion-no-margin">
 | 
			
		||||
            <ion-item class="ion-text-wrap" *ngIf="groupInfo && (groupInfo.separateGroups || groupInfo.visibleGroups)">
 | 
			
		||||
                <ion-label id="addon-feedback-groupslabel">
 | 
			
		||||
                    <ng-container *ngIf="groupInfo.separateGroups">{{'core.groupsseparate' | translate }}</ng-container>
 | 
			
		||||
                    <ng-container *ngIf="groupInfo.visibleGroups">{{'core.groupsvisible' | translate }}</ng-container>
 | 
			
		||||
                </ion-label>
 | 
			
		||||
                <ion-select [(ngModel)]="selectedGroup" (ionChange)="loadAttempts(selectedGroup)"
 | 
			
		||||
                    aria-labelledby="addon-feedback-groupslabel" interface="action-sheet">
 | 
			
		||||
                    <ion-select-option *ngFor="let groupOpt of groupInfo.groups" [value]="groupOpt.id">
 | 
			
		||||
                        {{groupOpt.name}}
 | 
			
		||||
                    </ion-select-option>
 | 
			
		||||
                </ion-select>
 | 
			
		||||
            </ion-item>
 | 
			
		||||
 | 
			
		||||
            <ion-item-divider>
 | 
			
		||||
                <ion-label>{{ 'addon.mod_feedback.non_respondents_students' | translate : {$a: total } }}</ion-label>
 | 
			
		||||
            </ion-item-divider>
 | 
			
		||||
            <ng-container *ngIf="total > 0">
 | 
			
		||||
                <ion-item *ngFor="let user of users" class="ion-text-wrap">
 | 
			
		||||
                    <core-user-avatar [user]="user" slot="start"></core-user-avatar>
 | 
			
		||||
                    <ion-label>
 | 
			
		||||
                        <h2>{{ user.fullname }}</h2>
 | 
			
		||||
                        <p>
 | 
			
		||||
                            <ion-badge color="success" *ngIf="user.started">
 | 
			
		||||
                                {{ 'addon.mod_feedback.started' | translate}}
 | 
			
		||||
                            </ion-badge>
 | 
			
		||||
                            <ion-badge color="danger" *ngIf="!user.started">
 | 
			
		||||
                                {{ 'addon.mod_feedback.not_started' | translate}}
 | 
			
		||||
                            </ion-badge>
 | 
			
		||||
                        </p>
 | 
			
		||||
                    </ion-label>
 | 
			
		||||
                </ion-item>
 | 
			
		||||
            </ng-container>
 | 
			
		||||
 | 
			
		||||
            <core-infinite-loading [enabled]="canLoadMore" (action)="loadAttempts(undefined, $event)" [error]="loadMoreError">
 | 
			
		||||
            </core-infinite-loading>
 | 
			
		||||
        </ion-list>
 | 
			
		||||
    </core-loading>
 | 
			
		||||
</ion-content>
 | 
			
		||||
@ -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 {}
 | 
			
		||||
							
								
								
									
										165
									
								
								src/addons/mod/feedback/pages/nonrespondents/nonrespondents.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										165
									
								
								src/addons/mod/feedback/pages/nonrespondents/nonrespondents.ts
									
									
									
									
									
										Normal file
									
								
							@ -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<void> {
 | 
			
		||||
        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<void> {
 | 
			
		||||
        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<void> {
 | 
			
		||||
        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<void> {
 | 
			
		||||
        try {
 | 
			
		||||
            const promises: Promise<void>[] = [];
 | 
			
		||||
 | 
			
		||||
            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();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										79
									
								
								src/addons/mod/feedback/pages/respondents/respondents.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								src/addons/mod/feedback/pages/respondents/respondents.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,79 @@
 | 
			
		||||
<ion-header>
 | 
			
		||||
    <ion-toolbar>
 | 
			
		||||
        <ion-buttons slot="start">
 | 
			
		||||
            <ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button>
 | 
			
		||||
        </ion-buttons>
 | 
			
		||||
        <ion-title>{{ 'addon.mod_feedback.responses' |translate }}</ion-title>
 | 
			
		||||
    </ion-toolbar>
 | 
			
		||||
</ion-header>
 | 
			
		||||
<ion-content>
 | 
			
		||||
    <core-split-view>
 | 
			
		||||
        <ion-refresher slot="fixed" [disabled]="!loaded" (ionRefresh)="refreshFeedback($event.target)">
 | 
			
		||||
            <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
 | 
			
		||||
        </ion-refresher>
 | 
			
		||||
        <core-loading [hideUntil]="loaded">
 | 
			
		||||
            <ion-list  class="ion-no-margin">
 | 
			
		||||
                <ion-item class="ion-text-wrap" *ngIf="groupInfo && (groupInfo.separateGroups || groupInfo.visibleGroups)">
 | 
			
		||||
                    <ion-label id="addon-feedback-groupslabel">
 | 
			
		||||
                        <ng-container *ngIf="groupInfo.separateGroups">{{'core.groupsseparate' | translate }}</ng-container>
 | 
			
		||||
                        <ng-container *ngIf="groupInfo.visibleGroups">{{'core.groupsvisible' | translate }}</ng-container>
 | 
			
		||||
                    </ion-label>
 | 
			
		||||
                    <ion-select [(ngModel)]="selectedGroup" (ionChange)="loadAttempts(selectedGroup)"
 | 
			
		||||
                        aria-labelledby="addon-feedback-groupslabel" interface="action-sheet">
 | 
			
		||||
                        <ion-select-option *ngFor="let groupOpt of groupInfo.groups" [value]="groupOpt.id">
 | 
			
		||||
                            {{groupOpt.name}}
 | 
			
		||||
                        </ion-select-option>
 | 
			
		||||
                    </ion-select>
 | 
			
		||||
                </ion-item>
 | 
			
		||||
 | 
			
		||||
                <ng-container *ngIf="responses.responses.total > 0">
 | 
			
		||||
                    <ion-item-divider>
 | 
			
		||||
                        <ion-label>
 | 
			
		||||
                            {{ 'addon.mod_feedback.non_anonymous_entries' | translate : {$a: responses.responses.total } }}
 | 
			
		||||
                        </ion-label>
 | 
			
		||||
                    </ion-item-divider>
 | 
			
		||||
                    <ion-item *ngFor="let attempt of responses.responses.attempts" class="ion-text-wrap" tappable detail="true"
 | 
			
		||||
                        (click)="responses.select(attempt)" [class.core-selected-item]="responses.isSelected(attempt)">
 | 
			
		||||
                        <core-user-avatar [user]="attempt" slot="start"></core-user-avatar>
 | 
			
		||||
                        <ion-label>
 | 
			
		||||
                            <h2>{{ attempt.fullname }}</h2>
 | 
			
		||||
                            <p *ngIf="attempt.timemodified">{{attempt.timemodified * 1000 | coreFormatDate }}</p>
 | 
			
		||||
                        </ion-label>
 | 
			
		||||
                    </ion-item>
 | 
			
		||||
 | 
			
		||||
                    <!-- Button and spinner to show more attempts. -->
 | 
			
		||||
                    <ion-button *ngIf="responses.responses.canLoadMore && !loadingMore" class="ion-margin" expand="block"
 | 
			
		||||
                        (click)="loadAttempts()">
 | 
			
		||||
                        {{ 'core.loadmore' | translate }}
 | 
			
		||||
                    </ion-button>
 | 
			
		||||
                    <ion-item *ngIf="responses.responses.canLoadMore && loadingMore" class="ion-text-center">
 | 
			
		||||
                        <ion-label><ion-spinner></ion-spinner></ion-label>
 | 
			
		||||
                    </ion-item>
 | 
			
		||||
                </ng-container>
 | 
			
		||||
 | 
			
		||||
                <ng-container *ngIf="responses.anonResponses.total > 0">
 | 
			
		||||
                    <ion-item-divider>
 | 
			
		||||
                        <ion-label>
 | 
			
		||||
                            {{ 'addon.mod_feedback.anonymous_entries' |translate : {$a: responses.anonResponses.total } }}
 | 
			
		||||
                        </ion-label>
 | 
			
		||||
                    </ion-item-divider>
 | 
			
		||||
                    <ion-item *ngFor="let attempt of responses.anonResponses.attempts" class="ion-text-wrap" tappable detail="true"
 | 
			
		||||
                        (click)="responses.select(attempt)" [class.core-selected-item]="responses.isSelected(attempt)">
 | 
			
		||||
                        <ion-label>
 | 
			
		||||
                            <h2>{{ 'addon.mod_feedback.response_nr' |translate }}: {{attempt.number}}</h2>
 | 
			
		||||
                        </ion-label>
 | 
			
		||||
                    </ion-item>
 | 
			
		||||
 | 
			
		||||
                    <!-- Button and spinner to show more attempts. -->
 | 
			
		||||
                    <ion-button *ngIf="responses.anonResponses.canLoadMore && !loadingMore" class="ion-margin" expand="block"
 | 
			
		||||
                        (click)="loadAttempts()">
 | 
			
		||||
                        {{ 'core.loadmore' | translate }}
 | 
			
		||||
                    </ion-button>
 | 
			
		||||
                    <ion-item *ngIf="responses.anonResponses.canLoadMore && loadingMore" class="ion-text-center">
 | 
			
		||||
                        <ion-label><ion-spinner></ion-spinner></ion-label>
 | 
			
		||||
                    </ion-item>
 | 
			
		||||
                </ng-container>
 | 
			
		||||
            </ion-list>
 | 
			
		||||
        </core-loading>
 | 
			
		||||
    </core-split-view>
 | 
			
		||||
</ion-content>
 | 
			
		||||
							
								
								
									
										248
									
								
								src/addons/mod/feedback/pages/respondents/respondents.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										248
									
								
								src/addons/mod/feedback/pages/respondents/respondents.ts
									
									
									
									
									
										Normal file
									
								
							@ -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<void> {
 | 
			
		||||
        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<void> {
 | 
			
		||||
        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<void> {
 | 
			
		||||
        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<void> {
 | 
			
		||||
        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<void> {
 | 
			
		||||
        const promises: Promise<void>[] = [];
 | 
			
		||||
 | 
			
		||||
        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<EntryItem> {
 | 
			
		||||
 | 
			
		||||
    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((<EntryItem[]> 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;
 | 
			
		||||
};
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user