MOBILE-3663 forum: Add ratings to forum
parent
44a03b61e7
commit
44e3c42d76
|
@ -18,6 +18,7 @@ import { CoreCourseComponentsModule } from '@features/course/components/componen
|
|||
import { CoreEditorComponentsModule } from '@features/editor/components/components.module';
|
||||
import { CoreSharedModule } from '@/core/shared.module';
|
||||
import { CoreTagComponentsModule } from '@features/tag/components/components.module';
|
||||
import { CoreRatingComponentsModule } from '@features/rating/components/components.module';
|
||||
|
||||
import { AddonModForumDiscussionOptionsMenuComponent } from './discussion-options-menu/discussion-options-menu';
|
||||
import { AddonModForumEditPostComponent } from './edit-post/edit-post';
|
||||
|
@ -40,6 +41,7 @@ import { AddonModForumSortOrderSelectorComponent } from './sort-order-selector/s
|
|||
CoreCourseComponentsModule,
|
||||
CoreTagComponentsModule,
|
||||
CoreEditorComponentsModule,
|
||||
CoreRatingComponentsModule,
|
||||
],
|
||||
exports: [
|
||||
AddonModForumIndexComponent,
|
||||
|
|
|
@ -50,6 +50,10 @@ import { CoreScreen } from '@services/screen';
|
|||
import { CoreArray } from '@singletons/array';
|
||||
import { AddonModForumPrefetchHandler } from '../../services/handlers/prefetch';
|
||||
import { AddonModForumModuleHandlerService } from '../../services/handlers/module';
|
||||
import { CoreRatingProvider } from '@features/rating/services/rating';
|
||||
import { CoreRatingSyncProvider } from '@features/rating/services/rating-sync';
|
||||
import { CoreRatingOffline } from '@features/rating/services/rating-offline';
|
||||
import { ContextLevel } from '@/core/constants';
|
||||
|
||||
/**
|
||||
* Component that displays a forum entry page.
|
||||
|
@ -88,9 +92,9 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom
|
|||
protected viewDiscObserver?: CoreEventObserver;
|
||||
protected changeDiscObserver?: CoreEventObserver;
|
||||
|
||||
hasOfflineRatings?: boolean;
|
||||
protected ratingOfflineObserver: any;
|
||||
protected ratingSyncObserver: any;
|
||||
hasOfflineRatings = false;
|
||||
protected ratingOfflineObserver?: CoreEventObserver;
|
||||
protected ratingSyncObserver?: CoreEventObserver;
|
||||
|
||||
constructor(
|
||||
route: ActivatedRoute,
|
||||
|
@ -166,7 +170,21 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom
|
|||
}
|
||||
});
|
||||
|
||||
// @todo Listen for offline ratings saved and synced.
|
||||
// Listen for offline ratings saved and synced.
|
||||
this.ratingOfflineObserver = CoreEvents.on(CoreRatingProvider.RATING_SAVED_EVENT, (data) => {
|
||||
if (this.forum && data.component == 'mod_forum' && data.ratingArea == 'post' &&
|
||||
data.contextLevel == ContextLevel.MODULE && data.instanceId == this.forum.cmid) {
|
||||
this.hasOfflineRatings = true;
|
||||
}
|
||||
});
|
||||
|
||||
this.ratingSyncObserver = CoreEvents.on(CoreRatingSyncProvider.SYNCED_EVENT, async (data) => {
|
||||
if (this.forum && data.component == 'mod_forum' && data.ratingArea == 'post' &&
|
||||
data.contextLevel == ContextLevel.MODULE && data.instanceId == this.forum.cmid) {
|
||||
this.hasOfflineRatings =
|
||||
await CoreRatingOffline.hasRatings('mod_forum', 'post', ContextLevel.MODULE, this.forum.cmid);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async ngAfterViewInit(): Promise<void> {
|
||||
|
@ -224,7 +242,11 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom
|
|||
await Promise.all([
|
||||
this.fetchOfflineDiscussions(),
|
||||
this.fetchDiscussions(refresh),
|
||||
// @todo fetch hasOfflineRatings.
|
||||
CoreRatingOffline.hasRatings('mod_forum', 'post', ContextLevel.MODULE, this.forum!.cmid).then((hasRatings) => {
|
||||
this.hasOfflineRatings = hasRatings;
|
||||
|
||||
return;
|
||||
}),
|
||||
]);
|
||||
} catch (error) {
|
||||
if (refresh) {
|
||||
|
|
|
@ -75,8 +75,7 @@
|
|||
<core-tag-list [tags]="post.tags"></core-tag-list>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
<!-- @todo -->
|
||||
<!-- <core-rating-rate *ngIf="forum && ratingInfo"
|
||||
<core-rating-rate *ngIf="forum && ratingInfo"
|
||||
[ratingInfo]="ratingInfo" contextLevel="module" [instanceId]="componentId" [itemId]="post.id"
|
||||
[itemSetId]="discussionId" [courseId]="courseId" [aggregateMethod]="forum.assessed" [scaleId]="forum.scale"
|
||||
[userId]="post.author.id" (onUpdate)="ratingUpdated()">
|
||||
|
@ -84,7 +83,7 @@
|
|||
<core-rating-aggregate *ngIf="forum && ratingInfo"
|
||||
[ratingInfo]="ratingInfo" contextLevel="module" [instanceId]="componentId" [itemId]="post.id"
|
||||
[courseId]="courseId" [aggregateMethod]="forum.assessed" [scaleId]="forum.scale">
|
||||
</core-rating-aggregate> -->
|
||||
</core-rating-aggregate>
|
||||
|
||||
<ion-item *ngIf="post.id > 0 && post.capabilities.reply && !post.isprivatereply"
|
||||
class="ion-no-padding ion-text-end addon-forum-reply-button">
|
||||
|
|
|
@ -52,6 +52,7 @@ import { AddonModForumOffline, AddonModForumReplyOptions } from '../../services/
|
|||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { AddonModForumPostOptionsMenuComponent } from '../post-options-menu/post-options-menu';
|
||||
import { AddonModForumEditPostComponent } from '../edit-post/edit-post';
|
||||
import { CoreRatingInfo } from '@features/rating/services/rating';
|
||||
|
||||
/**
|
||||
* Components that shows a discussion post, its attachments and the action buttons allowed (reply, etc.).
|
||||
|
@ -75,7 +76,7 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges
|
|||
@Input() forum!: AddonModForumData; // The forum the post belongs to. Required for attachments and offline posts.
|
||||
@Input() accessInfo!: AddonModForumAccessInformation; // Forum access information.
|
||||
@Input() parentSubject?: string; // Subject of parent post.
|
||||
@Input() ratingInfo?: any; // TODO CoreRatingInfo; // Rating info item.
|
||||
@Input() ratingInfo?: CoreRatingInfo; // Rating info item.
|
||||
@Input() leavingPage?: boolean; // Whether the page that contains this post is being left and will be destroyed.
|
||||
@Input() highlight = false;
|
||||
@Output() onPostChange: EventEmitter<void> = new EventEmitter<void>(); // Event emitted when a reply is posted or modified.
|
||||
|
|
|
@ -12,9 +12,13 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { ContextLevel } from '@/core/constants';
|
||||
import { Component, OnDestroy, ViewChild, OnInit, AfterViewInit, ElementRef, Optional } from '@angular/core';
|
||||
import { CoreSplitViewComponent } from '@components/split-view/split-view';
|
||||
import { CoreFileUploader } from '@features/fileuploader/services/fileuploader';
|
||||
import { CoreRatingInfo, CoreRatingProvider } from '@features/rating/services/rating';
|
||||
import { CoreRatingOffline } from '@features/rating/services/rating-offline';
|
||||
import { CoreRatingSyncProvider } from '@features/rating/services/rating-sync';
|
||||
import { CoreUser } from '@features/user/services/user';
|
||||
import { CanLeave } from '@guards/can-leave';
|
||||
import { IonContent } from '@ionic/angular';
|
||||
|
@ -34,7 +38,6 @@ import {
|
|||
AddonModForumDiscussion,
|
||||
AddonModForumPost,
|
||||
AddonModForumProvider,
|
||||
AddonModForumRatingInfo,
|
||||
} from '../../services/forum';
|
||||
import { AddonModForumHelper } from '../../services/helper';
|
||||
import { AddonModForumOffline } from '../../services/offline';
|
||||
|
@ -101,8 +104,8 @@ export class AddonModForumDiscussionPage implements OnInit, AfterViewInit, OnDes
|
|||
protected syncObserver?: CoreEventObserver;
|
||||
protected syncManualObserver?: CoreEventObserver;
|
||||
|
||||
ratingInfo?: AddonModForumRatingInfo;
|
||||
hasOfflineRatings!: boolean;
|
||||
ratingInfo?: CoreRatingInfo;
|
||||
hasOfflineRatings = false;
|
||||
protected ratingOfflineObserver?: CoreEventObserver;
|
||||
protected ratingSyncObserver?: CoreEventObserver;
|
||||
protected changeDiscObserver?: CoreEventObserver;
|
||||
|
@ -203,7 +206,20 @@ export class AddonModForumDiscussionPage implements OnInit, AfterViewInit, OnDes
|
|||
AddonModForum.invalidateDiscussionsList(this.forumId);
|
||||
}
|
||||
|
||||
// @todo Listen for offline ratings saved and synced.
|
||||
// Listen for offline ratings saved and synced.
|
||||
this.ratingOfflineObserver = CoreEvents.on(CoreRatingProvider.RATING_SAVED_EVENT, (data) => {
|
||||
if (data.component == 'mod_forum' && data.ratingArea == 'post' && data.contextLevel == ContextLevel.MODULE &&
|
||||
data.instanceId == this.cmId && data.itemSetId == this.discussionId) {
|
||||
this.hasOfflineRatings = true;
|
||||
}
|
||||
});
|
||||
|
||||
this.ratingSyncObserver = CoreEvents.on(CoreRatingSyncProvider.SYNCED_EVENT, async (data) => {
|
||||
if (data.component == 'mod_forum' && data.ratingArea == 'post' && data.contextLevel == ContextLevel.MODULE &&
|
||||
data.instanceId == this.cmId && data.itemSetId == this.discussionId) {
|
||||
this.hasOfflineRatings = false;
|
||||
}
|
||||
});
|
||||
|
||||
this.changeDiscObserver = CoreEvents.on(AddonModForumProvider.CHANGE_DISCUSSION_EVENT, data => {
|
||||
if ((this.forumId && this.forumId === data.forumId) || data.cmId === this.cmId) {
|
||||
|
@ -345,7 +361,8 @@ export class AddonModForumDiscussionPage implements OnInit, AfterViewInit, OnDes
|
|||
|
||||
const response = await AddonModForum.getDiscussionPosts(this.discussionId, { cmId: this.cmId });
|
||||
const replies = await AddonModForumOffline.getDiscussionReplies(this.discussionId);
|
||||
const ratingInfo = response.ratinginfo;
|
||||
this.ratingInfo = response.ratinginfo;
|
||||
|
||||
onlinePosts = response.posts;
|
||||
this.courseId = response.courseid || this.courseId;
|
||||
this.forumId = response.forumid || this.forumId;
|
||||
|
@ -462,7 +479,6 @@ export class AddonModForumDiscussionPage implements OnInit, AfterViewInit, OnDes
|
|||
}
|
||||
|
||||
this.posts = posts;
|
||||
this.ratingInfo = ratingInfo;
|
||||
this.postSubjects = this.getAllPosts().reduce(
|
||||
(postSubjects, post) => {
|
||||
postSubjects[post.id] = post.subject;
|
||||
|
@ -487,7 +503,8 @@ export class AddonModForumDiscussionPage implements OnInit, AfterViewInit, OnDes
|
|||
this.canPin = false;
|
||||
}
|
||||
|
||||
// @todo fetch hasOfflineRatings.
|
||||
this.hasOfflineRatings =
|
||||
await CoreRatingOffline.hasRatings('mod_forum', 'post', ContextLevel.MODULE, this.cmId, this.discussionId);
|
||||
} catch (error) {
|
||||
CoreDomUtils.showErrorModal(error);
|
||||
} finally {
|
||||
|
|
|
@ -17,6 +17,7 @@ import { CoreSite, CoreSiteWSPreSets } from '@classes/site';
|
|||
import { CoreCourseCommonModWSOptions } from '@features/course/services/course';
|
||||
import { CoreCourseLogHelper } from '@features/course/services/log-helper';
|
||||
import { CoreFileEntry } from '@features/fileuploader/services/fileuploader';
|
||||
import { CoreRatingInfo } from '@features/rating/services/rating';
|
||||
import { CoreUser } from '@features/user/services/user';
|
||||
import { CoreApp } from '@services/app';
|
||||
import { CoreFilepool } from '@services/filepool';
|
||||
|
@ -553,7 +554,7 @@ export class AddonModForumProvider {
|
|||
posts: AddonModForumPost[];
|
||||
courseid?: number;
|
||||
forumid?: number;
|
||||
ratinginfo?: AddonModForumRatingInfo;
|
||||
ratinginfo?: CoreRatingInfo;
|
||||
}> {
|
||||
// Convenience function to translate legacy data to new format.
|
||||
const translateLegacyPostsFormat = (posts: AddonModForumLegacyPost[]): AddonModForumPost[] => posts.map((post) => {
|
||||
|
@ -1526,40 +1527,6 @@ export type AddonModForumLegacyPost = {
|
|||
}[];
|
||||
};
|
||||
|
||||
/**
|
||||
* Forum rating info.
|
||||
*/
|
||||
export type AddonModForumRatingInfo = {
|
||||
contextid: number; // Context id.
|
||||
component: string; // Context name.
|
||||
ratingarea: string; // Rating area name.
|
||||
canviewall?: boolean; // Whether the user can view all the individual ratings.
|
||||
canviewany?: boolean; // Whether the user can view aggregate of ratings of others.
|
||||
scales?: { // Different scales used information.
|
||||
id: number; // Scale id.
|
||||
courseid?: number; // Course id.
|
||||
name?: string; // Scale name (when a real scale is used).
|
||||
max: number; // Max value for the scale.
|
||||
isnumeric: boolean; // Whether is a numeric scale.
|
||||
items?: { // Scale items. Only returned for not numerical scales.
|
||||
value: number; // Scale value/option id.
|
||||
name: string; // Scale name.
|
||||
}[];
|
||||
}[];
|
||||
ratings?: { // The ratings.
|
||||
itemid: number; // Item id.
|
||||
scaleid?: number; // Scale id.
|
||||
userid?: number; // User who rated id.
|
||||
aggregate?: number; // Aggregated ratings grade.
|
||||
aggregatestr?: string; // Aggregated ratings as string.
|
||||
aggregatelabel?: string; // The aggregation label.
|
||||
count?: number; // Ratings count (used when aggregating).
|
||||
rating?: number; // The rating the user gave.
|
||||
canrate?: boolean; // Whether the user can rate the item.
|
||||
canviewaggregate?: boolean; // Whether the user can view the aggregated grade.
|
||||
}[];
|
||||
};
|
||||
|
||||
/**
|
||||
* Options to pass to get discussions.
|
||||
*/
|
||||
|
@ -1994,7 +1961,7 @@ export type AddonModForumGetDiscussionPostsWSResponse = {
|
|||
posts: AddonModForumWSPost[];
|
||||
forumid: number; // The forum id.
|
||||
courseid: number; // The forum course id.
|
||||
ratinginfo?: AddonModForumRatingInfo; // Rating information.
|
||||
ratinginfo?: CoreRatingInfo; // Rating information.
|
||||
warnings?: CoreWSExternalWarning[];
|
||||
};
|
||||
|
||||
|
@ -2012,7 +1979,7 @@ export type AddonModForumGetForumDiscussionPostsWSParams = {
|
|||
*/
|
||||
export type AddonModForumGetForumDiscussionPostsWSResponse = {
|
||||
posts: AddonModForumLegacyPost[];
|
||||
ratinginfo?: AddonModForumRatingInfo; // Rating information.
|
||||
ratinginfo?: CoreRatingInfo; // Rating information.
|
||||
warnings?: CoreWSExternalWarning[];
|
||||
};
|
||||
|
||||
|
|
|
@ -12,11 +12,13 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { ContextLevel } from '@/core/constants';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { CoreSyncBaseProvider } from '@classes/base-sync';
|
||||
import { CoreCourse } from '@features/course/services/course';
|
||||
import { CoreCourseLogHelper } from '@features/course/services/log-helper';
|
||||
import { CoreFileUploader } from '@features/fileuploader/services/fileuploader';
|
||||
import { CoreRatingSync } from '@features/rating/services/rating-sync';
|
||||
import { CoreApp } from '@services/app';
|
||||
import { CoreGroups } from '@services/groups';
|
||||
import { CoreSites } from '@services/sites';
|
||||
|
@ -327,14 +329,44 @@ export class AddonModForumSyncProvider extends CoreSyncBaseProvider<AddonModForu
|
|||
* @param siteId Site ID. If not defined, current site.
|
||||
* @return Promise resolved if sync is successful, rejected otherwise.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
async syncRatings(cmId?: number, discussionId?: number, force?: boolean, siteId?: string): Promise<{
|
||||
updated: boolean;
|
||||
warnings: string[];
|
||||
}> {
|
||||
// @todo
|
||||
async syncRatings(cmId?: number, discussionId?: number, force?: boolean, siteId?: string): Promise<AddonModForumSyncResult> {
|
||||
siteId = siteId || CoreSites.getCurrentSiteId();
|
||||
|
||||
return { updated: true, warnings: [] };
|
||||
const results =
|
||||
await CoreRatingSync.syncRatings('mod_forum', 'post', ContextLevel.MODULE, cmId, discussionId, force, siteId);
|
||||
|
||||
let updated = false;
|
||||
const warnings: string[] = [];
|
||||
const promises: Promise<void>[] = [];
|
||||
|
||||
results.forEach((result) => {
|
||||
if (result.updated.length) {
|
||||
updated = true;
|
||||
|
||||
// Invalidate discussions of updated ratings.
|
||||
promises.push(AddonModForum.invalidateDiscussionPosts(result.itemSet!.itemSetId, undefined, siteId));
|
||||
}
|
||||
|
||||
if (result.warnings.length) {
|
||||
// Fetch forum to construct the warning message.
|
||||
promises.push(AddonModForum.getForum(result.itemSet!.courseId!, result.itemSet!.instanceId, { siteId })
|
||||
.then((forum) => {
|
||||
result.warnings.forEach((warning) => {
|
||||
warnings.push(Translate.instant('core.warningofflinedatadeleted', {
|
||||
component: this.componentTranslate,
|
||||
name: forum.name,
|
||||
error: warning,
|
||||
}));
|
||||
});
|
||||
|
||||
return;
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
await CoreUtils.allPromises(promises);
|
||||
|
||||
return { updated, warnings };
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue