diff --git a/scripts/langindex.json b/scripts/langindex.json
index 5b18e0fbf..e9d1ac227 100644
--- a/scripts/langindex.json
+++ b/scripts/langindex.json
@@ -914,6 +914,8 @@
"addon.mod_quiz.mustbesubmittedby": "quiz",
"addon.mod_quiz.noquestions": "quiz",
"addon.mod_quiz.noreviewattempt": "quiz",
+ "addon.mod_quiz.noreviewuntil": "quiz",
+ "addon.mod_quiz.noreviewuntilshort": "quiz",
"addon.mod_quiz.notyetgraded": "quiz",
"addon.mod_quiz.opentoc": "local_moodlemobileapp",
"addon.mod_quiz.outof": "quiz",
diff --git a/src/addons/mod/quiz/components/index/addon-mod-quiz-index.html b/src/addons/mod/quiz/components/index/addon-mod-quiz-index.html
index 61e5cd8ba..db9d74c29 100644
--- a/src/addons/mod/quiz/components/index/addon-mod-quiz-index.html
+++ b/src/addons/mod/quiz/components/index/addon-mod-quiz-index.html
@@ -82,14 +82,13 @@
{{ 'addon.mod_quiz.review' | translate }}
- } @else if (attempt.completed) {
+ } @else if (attempt.completed && attempt.cannotReviewMessage) {
- {{ 'addon.mod_quiz.noreviewattempt' | translate }}
-
+ {{ attempt.cannotReviewMessage }}
diff --git a/src/addons/mod/quiz/components/index/index.ts b/src/addons/mod/quiz/components/index/index.ts
index f0b27e252..21df59c34 100644
--- a/src/addons/mod/quiz/components/index/index.ts
+++ b/src/addons/mod/quiz/components/index/index.ts
@@ -622,6 +622,9 @@ export class AddonModQuizIndexComponent extends CoreCourseModuleMainActivityComp
]);
formattedAttempt.canReview = canReview;
+ if (!canReview) {
+ formattedAttempt.cannotReviewMessage = AddonModQuizHelper.getCannotReviewMessage(quiz, attempt, true);
+ }
if (quiz.showFeedback && attempt.state === AddonModQuizAttemptStates.FINISHED &&
options.someoptions.overallfeedback && isSafeNumber(formattedAttempt.rescaledGrade)) {
@@ -698,5 +701,6 @@ export class AddonModQuizIndexComponent extends CoreCourseModuleMainActivityComp
type QuizAttempt = AddonModQuizAttempt & {
canReview?: boolean;
+ cannotReviewMessage?: string;
additionalData?: AddonModQuizWSAdditionalData[]; // Additional data to display for the attempt.
};
diff --git a/src/addons/mod/quiz/lang.json b/src/addons/mod/quiz/lang.json
index 44e232d1e..135e71f37 100644
--- a/src/addons/mod/quiz/lang.json
+++ b/src/addons/mod/quiz/lang.json
@@ -42,6 +42,8 @@
"mustbesubmittedby": "This attempt must be submitted by {{$a}}.",
"noquestions": "No questions have been added yet",
"noreviewattempt": "You are not allowed to review this attempt.",
+ "noreviewuntil": "You are not allowed to review this quiz until {{$a}}",
+ "noreviewuntilshort": "Available {{$a}}",
"notyetgraded": "Not yet graded",
"opentoc": "Open navigation popover",
"outof": "{{$a.grade}} out of {{$a.maxgrade}}",
diff --git a/src/addons/mod/quiz/services/quiz-helper.ts b/src/addons/mod/quiz/services/quiz-helper.ts
index 209e190c7..b5bf2f317 100644
--- a/src/addons/mod/quiz/services/quiz-helper.ts
+++ b/src/addons/mod/quiz/services/quiz-helper.ts
@@ -33,9 +33,14 @@ import {
AddonModQuizQuizWSData,
} from './quiz';
import { AddonModQuizOffline } from './quiz-offline';
-import { AddonModQuizAttemptStates, AddonModQuizDisplayOptionsAttemptStates } from '../constants';
+import {
+ ADDON_MOD_QUIZ_IMMEDIATELY_AFTER_PERIOD,
+ AddonModQuizAttemptStates,
+ AddonModQuizDisplayOptionsAttemptStates,
+} from '../constants';
import { QuestionDisplayOptionsMarks } from '@features/question/constants';
import { CoreGroups } from '@services/groups';
+import { CoreTimeUtils } from '@services/utils/time';
/**
* Helper service that provides some features for quiz.
@@ -121,6 +126,47 @@ export class AddonModQuizHelperProvider {
}
}
+ /**
+ * Get cannot review message.
+ *
+ * @param quiz Quiz.
+ * @param attempt Attempt.
+ * @param short Whether to use a short message or not.
+ * @returns Cannot review message, or empty string if no message to display.
+ */
+ getCannotReviewMessage(quiz: AddonModQuizQuizWSData, attempt: AddonModQuizAttemptWSData, short = false): string {
+ const displayOption = AddonModQuiz.getAttemptStateDisplayOption(quiz, attempt);
+
+ let reviewFrom = 0;
+ switch (displayOption) {
+ case AddonModQuizDisplayOptionsAttemptStates.DURING:
+ return '';
+
+ case AddonModQuizDisplayOptionsAttemptStates.IMMEDIATELY_AFTER:
+ // eslint-disable-next-line no-bitwise
+ if ((quiz.reviewattempt ?? 0) & AddonModQuizDisplayOptionsAttemptStates.LATER_WHILE_OPEN) {
+ reviewFrom = (attempt.timefinish ?? Date.now()) + ADDON_MOD_QUIZ_IMMEDIATELY_AFTER_PERIOD;
+ break;
+ }
+ // Fall through.
+
+ case AddonModQuizDisplayOptionsAttemptStates.LATER_WHILE_OPEN:
+ // eslint-disable-next-line no-bitwise
+ if (quiz.timeclose && ((quiz.reviewattempt ?? 0) & AddonModQuizDisplayOptionsAttemptStates.AFTER_CLOSE)) {
+ reviewFrom = quiz.timeclose;
+ break;
+ }
+ }
+
+ if (reviewFrom) {
+ return Translate.instant('addon.mod_quiz.noreviewuntil' + (short ? 'short' : ''), {
+ $a: CoreTimeUtils.userDate(reviewFrom * 1000, short ? 'core.strftimedatetimeshort': undefined),
+ });
+ } else {
+ return Translate.instant('addon.mod_quiz.noreviewattempt');
+ }
+ }
+
/**
* Validate a preflight data or show a modal to input the preflight data if required.
* It calls AddonModQuizProvider.startAttempt if a new attempt is needed.