Skip to content

Commit

Permalink
Merge pull request #1757 from France-ioi/item-content-cleanup
Browse files Browse the repository at this point in the history
Item-content cleanup
  • Loading branch information
smadbe authored Aug 23, 2024
2 parents 6dd3a5f + eac25e3 commit da133c1
Show file tree
Hide file tree
Showing 4 changed files with 191 additions and 120 deletions.
237 changes: 128 additions & 109 deletions src/app/items/containers/item-content/item-content.component.html
Original file line number Diff line number Diff line change
@@ -1,24 +1,67 @@
<ng-container *ngIf="itemData">

<ng-container *ngIf="itemData.item.type !== 'Task' && itemData.item.string.description">
<ng-container
*algHasHTML="itemData.item.string.description; else textContent"
@if (description(); as description) {
<ng-container
*algHasHTML="description; else textContent"
>
<div
class="html-container"
data-testid="item-description"
[innerHTML]="itemData.item.string.description"
></div>
</ng-container>
<ng-template #textContent>
<p class="description alg-text-base" data-testid="item-description">{{ itemData.item.string.description }}</p>
</ng-template>
<div
class="html-container"
data-testid="item-description"
[innerHTML]="description"
></div>
</ng-container>

<ng-container *ngIf="(itemData.item.permissions | allowsViewingContent) && !(itemData.item.requiresExplicitEntry && itemData.results !== undefined && !itemData.currentResult)">

<ng-container *ngIf="['Chapter', 'Skill'].includes(itemData.item.type) && itemData.currentResult">
<div class="edit" *ngIf="['all','all_with_grant', 'children'].includes(itemData.item.permissions.canEdit) || editModeEnabled">
<ng-template #textContent>
<p class="description alg-text-base" data-testid="item-description">{{ description }}</p>
</ng-template>
}

@let item = itemData().item;
@let perms = item.permissions;
@let canViewContent = perms | allowsViewingContent;
@let resultsFetched = itemData().results !== undefined;
@let hasCurentResult = !!itemData().currentResult;
@let userHasToEnterExplicitely = item.requiresExplicitEntry && ((canViewContent && resultsFetched && !hasCurentResult) || !canViewContent);

@if (userHasToEnterExplicitely) {
<p class="validation-text">
<span>
<ng-container i18n>This activity requires explicit entry</ng-container>&nbsp;
<ng-container i18n="@@notImplemented">(not implemented)</ng-container>.
</span>
</p>
}

@else if (!canViewContent) {
<div class="no-access-message alg-flex-1">
<span class="no-access-message-icon-container">
<i class="ph-duotone ph-lock-key no-access-message-icon"></i>
<span class="no-access-message-icon-bg"></span>
</span>
@if (item | isAChapter) {
<span class="no-access-message-text alg-text-secondary" i18n>
Your current access rights do not allow you to list<br> the content of this chapter.
</span>
}
@else if (item | isASkill) {
<span class="no-access-message-text alg-text-secondary" i18n>
Your current access rights do not allow you to list<br> the content of this skill.
</span>
}
@else { <!-- task -->
<span class="no-access-message-text alg-text-secondary" i18n>
Your current access rights do not allow you to start<br> the activity.
</span>
}
</div>
<alg-item-unlock-access class="alg-flex-1" [itemData]="itemData()"></alg-item-unlock-access>
}

@else if ((item | isAChapter) || (item | isASkill)) { <!-- with canViewContent, results may not be fetched yet-->

@if (!hasCurentResult) {
<!-- waiting for the results to load, do not show anything -->
}
@else {
@if ((perms | allowsEditingChildren) || editModeEnabled) {
<div class="edit">
<label class="edit-label">
<span class="alg-base-text-color" i18n>Edit content</span>
<alg-switch
Expand All @@ -30,96 +73,72 @@
></alg-switch>
</label>
</div>

}
@if (editModeEnabled) {
<alg-item-children-edit-form
[itemData]="itemData"
*ngIf="editModeEnabled"
[itemData]="itemData()"
></alg-item-children-edit-form>

<alg-chapter-children
}
@else { <!-- !editModeEnabled -->
@if (item | isAChapter) {
<alg-chapter-children class="alg-flex-1" [itemData]="itemData()"></alg-chapter-children>
}
@else { <!-- skill -->
<alg-sub-skills class="alg-flex-1" [itemData]="itemData()"></alg-sub-skills>
}
}
@if (item | isASkill) {
<alg-parent-skills class="alg-flex-1" [itemData]="itemData()"></alg-parent-skills>
}
}
}

@else { <!-- task with canViewContent, results may not be fetched yet -->

@let url = item.url;
@if (!url) {
<alg-error class="alg-flex-1" icon="ph-duotone ph-wrench">
<p i18n>
This activity has not been correctly configured.
</p>
@if (perms | allowsEditingAll) {
<p i18n>
You need to set a url in editing mode.
</p>
}
</alg-error>
}
@else { <!-- url set -->

@if (taskConfig) {
<alg-item-display
class="alg-flex-1"
[itemData]="itemData"
*ngIf="itemData.item.type === 'Chapter' && !editModeEnabled"
></alg-chapter-children>

<alg-sub-skills class="alg-flex-1" [itemData]="itemData" *ngIf="itemData.item.type === 'Skill' && !editModeEnabled"></alg-sub-skills>
<alg-parent-skills class="alg-flex-1" [itemData]="itemData" *ngIf="itemData.item.type === 'Skill'"></alg-parent-skills>
</ng-container>

<ng-container *ngIf="taskConfig">
<ng-container *ngIf="itemData.item.url; else noUrl">
<alg-item-display
class="alg-flex-1"
[ngClass]="{ 'alg-opacity-0': !(isTaskLoaded$ | async) }"
[route]="itemData.route"
[editingPermission]="itemData.item.permissions"
[url]="itemData.item.url"
[attemptId]="itemData.currentResult ? itemData.currentResult.attemptId : undefined"
[view]="taskView"
[taskConfig]="taskConfig"
[savingAnswer]="savingAnswer"
(viewChange)="taskViewChange.emit($event)"
(tabsChange)="taskTabsChange.emit($event)"
(scoreChange)="onScoreChange($event)"
(skipSave)="skipSave.emit()"
(refresh)="refresh.emit()"
(editorUrl)="editorUrl.emit($event)"
(disablePlatformProgress)="disablePlatformProgress.emit($event)"
(fullFrame)="fullFrameTask.emit($event)"
(loadingComplete)="isTaskLoaded$.next($event)"
></alg-item-display>
</ng-container>

<ng-template #noUrl>
<alg-error class="alg-flex-1" icon="ph-duotone ph-wrench">
<p i18n>
This activity has not been correctly configured.
</p>
<p *ngIf="itemData.item.permissions | allowsEditingChildren" i18n>
You need to set a url in editing mode.
</p>
</alg-error>
</ng-template>
</ng-container>
</ng-container>

<ng-container *ngIf="!(itemData.item.permissions | allowsViewingContent) && !itemData.item.requiresExplicitEntry">
<div class="no-access-message alg-flex-1">
<span class="no-access-message-icon-container">
<i class="ph-duotone ph-lock-key no-access-message-icon"></i>
<span class="no-access-message-icon-bg"></span>
</span>

<span class="no-access-message-text alg-text-secondary" *ngIf="itemData.item.type === 'Chapter'" i18n>
Your current access rights do not allow you to list<br> the content of this chapter.
</span>

<span class="no-access-message-text alg-text-secondary" *ngIf="itemData.item.type === 'Skill'" i18n>
Your current access rights do not allow you to list<br> the content of this skill.
</span>

<span class="no-access-message-text alg-text-secondary" *ngIf="itemData.item.type === 'Task'" i18n>
Your current access rights do not allow you to start<br> the activity.
</span>
</div>

<alg-item-unlock-access class="alg-flex-1" [itemData]="itemData"></alg-item-unlock-access>
</ng-container>

<alg-task-loader
class="alg-flex-1 task-loader"
*ngIf="(itemData.item.permissions | allowsViewingContent) && (!itemData.item.requiresExplicitEntry && (itemData.item.type === 'Task' && itemData.item.url && !(isTaskLoaded$ | async)) || (itemData.item.requiresExplicitEntry && (itemData.results === undefined || (itemData.results !== undefined && itemData.currentResult && itemData.item.type === 'Task' && itemData.item.url && !(isTaskLoaded$ | async)))) )"
i18n-label label="Loading the content"
i18n-delayedLabel delayedLabel="The content is taking an unexpected long time to load... please wait..."
></alg-task-loader>

<ng-container *ngIf="itemData.item.requiresExplicitEntry && (!(itemData.item.permissions | allowsViewingContent) || ((itemData.item.permissions | allowsViewingContent) && itemData.results !== undefined && !itemData.currentResult))">
<p class="validation-text">
<span>
<ng-container i18n>This activity requires explicit entry</ng-container>&nbsp;
<ng-container i18n="@@notImplemented">(not implemented)</ng-container>.
</span>
</p>
</ng-container>

</ng-container>
[ngClass]="{ 'alg-opacity-0': !isTaskLoaded() }"
[route]="itemData().route"
[editingPermission]="itemData().item.permissions"
[url]="url"
[attemptId]="itemData().currentResult ? itemData().currentResult?.attemptId : undefined"
[view]="taskView"
[taskConfig]="taskConfig"
[savingAnswer]="savingAnswer"
(viewChange)="taskViewChange.emit($event)"
(tabsChange)="taskTabsChange.emit($event)"
(scoreChange)="onScoreChange($event)"
(skipSave)="skipSave.emit()"
(refresh)="refresh.emit()"
(editorUrl)="editorUrl.emit($event)"
(disablePlatformProgress)="disablePlatformProgress.emit($event)"
(fullFrame)="fullFrameTask.emit($event)"
(loadingComplete)="onTaskLoadChange($event)"
></alg-item-display>
}
@if (!isTaskLoaded()) {
<alg-task-loader
class="alg-flex-1 task-loader"
i18n-label label="Loading the content"
i18n-delayedLabel delayedLabel="The content is taking an unexpected long time to load... please wait..."
></alg-task-loader>
}

}
}
31 changes: 21 additions & 10 deletions src/app/items/containers/item-content/item-content.component.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, EventEmitter, Input, Output, ViewChild } from '@angular/core';
import { Component, EventEmitter, Input, Output, ViewChild, computed, input, signal } from '@angular/core';
import { ItemData } from '../../models/item-data';
import { TaskConfig } from '../../services/item-task.service';
import { ItemDisplayComponent, TaskTab } from '../item-display/item-display.component';
Expand All @@ -8,28 +8,26 @@ import {
} from '../../containers/item-children-edit-form/item-children-edit-form.component';
import { PendingChangesComponent } from 'src/app/guards/pending-changes-guard';
import { SwitchComponent } from 'src/app/ui-components/switch/switch.component';
import { BehaviorSubject } from 'rxjs';
import { AllowsEditingChildrenItemPipe } from 'src/app/items/models/item-edit-permission';
import { AllowsEditingAllItemPipe, AllowsEditingChildrenItemPipe } from 'src/app/items/models/item-edit-permission';
import { AllowsViewingItemContentPipe } from 'src/app/items/models/item-view-permission';
import { TaskLoaderComponent } from '../../containers/task-loader/task-loader.component';
import { ItemUnlockAccessComponent } from '../../containers/item-unlock-access/item-unlock-access.component';
import { MessageInfoComponent } from 'src/app/ui-components/message-info/message-info.component';
import { ParentSkillsComponent } from '../../containers/parent-skills/parent-skills.component';
import { SubSkillsComponent } from '../../containers/sub-skills/sub-skills.component';
import { ChapterChildrenComponent } from '../../containers/chapter-children/chapter-children.component';
import { HasHTMLDirective } from 'src/app/directives/has-html.directive';
import { NgIf, NgClass, AsyncPipe } from '@angular/common';
import { NgClass } from '@angular/common';
import { Store } from '@ngrx/store';
import { fromForum } from 'src/app/forum/store';
import { ErrorComponent } from '../../../ui-components/error/error.component';
import { IsAChapterPipe, IsASkillPipe, isATask } from '../../models/item-type';

@Component({
selector: 'alg-item-content',
templateUrl: './item-content.component.html',
styleUrls: [ './item-content.component.scss' ],
standalone: true,
imports: [
NgIf,
HasHTMLDirective,
SwitchComponent,
ItemChildrenEditFormComponent,
Expand All @@ -38,21 +36,31 @@ import { ErrorComponent } from '../../../ui-components/error/error.component';
ParentSkillsComponent,
ItemDisplayComponent,
NgClass,
MessageInfoComponent,
ItemUnlockAccessComponent,
TaskLoaderComponent,
AsyncPipe,
AllowsViewingItemContentPipe,
AllowsEditingChildrenItemPipe,
AllowsEditingAllItemPipe,
ErrorComponent,
IsAChapterPipe,
IsASkillPipe,
],
})
export class ItemContentComponent implements PendingChangesComponent {
@ViewChild(ItemDisplayComponent) itemDisplayComponent?: ItemDisplayComponent;
@ViewChild(ItemChildrenEditFormComponent) itemChildrenEditFormComponent?: ItemChildrenEditFormComponent;
@ViewChild(SwitchComponent) switchComponent?: SwitchComponent;

@Input() itemData?: ItemData;
itemData = input.required<ItemData>();
private item = computed(() => this.itemData().item);
/**
* Item description, only if it should be shown
*/
description = computed(() => {
const description = this.item().string.description;
return (!isATask(this.item()) && description /* not null, undefined or empty */) ? description : null;
});

@Input() taskView?: TaskTab['view'];
@Input() taskConfig: TaskConfig|null = null;
@Input() savingAnswer = false;
Expand All @@ -67,7 +75,7 @@ export class ItemContentComponent implements PendingChangesComponent {
@Output() disablePlatformProgress = new EventEmitter<boolean>();
@Output() fullFrameTask = new EventEmitter<boolean>();

isTaskLoaded$ = new BehaviorSubject(false); // whether the task has finished loading, i.e. is ready or in error
isTaskLoaded = signal(false); // whether the task has finished loading, i.e. is ready or in error

isDirty(): boolean {
return !!this.itemChildrenEditFormComponent?.dirty;
Expand All @@ -94,4 +102,7 @@ export class ItemContentComponent implements PendingChangesComponent {
this.store.dispatch(fromForum.itemPageEventSyncActions.forceSyncCurrentThreadEvents());
}

onTaskLoadChange(loadingComplete: boolean): void {
this.isTaskLoaded.set(loadingComplete);
}
}
2 changes: 1 addition & 1 deletion src/app/items/item-by-id.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
#contentContainer
*ngrxLet="currentTab$ as currentTab"
>
<ng-container *ngIf="currentTab?.isTaskTab || (itemContentComponent?.isTaskLoaded$ | async) || currentTab?.tag === 'alg-content' || currentTab?.tag === 'alg-children-edit'">
<ng-container *ngIf="currentTab?.isTaskTab || itemContentComponent?.isTaskLoaded() || currentTab?.tag === 'alg-content' || currentTab?.tag === 'alg-children-edit'">
<alg-error *ngIf="answerLoadingError$ | async as error; else noAnswerLoadingError">
<ng-container *ngIf="!error.fallbackLink; else fallback" i18n>Unable to load the answer</ng-container>
<ng-template #fallback>
Expand Down
Loading

0 comments on commit da133c1

Please sign in to comment.