From e5e67af6d1e16183be2c4af1cd8eff83fc1358bc Mon Sep 17 00:00:00 2001 From: mosin74 Date: Thu, 3 Sep 2026 21:06:15 +0530 Subject: [PATCH 1/5] Remove topic recommendations from intro card, update instruction panel legend layout, and switch certificates tab icon to fa-award --- assets/i18n/en.json | 8 +- assets/i18n/fr.json | 4 + assets/i18n/ko.json | 1 - assets/i18n/nl.json | 5 +- assets/i18n/qqq.json | 8 +- assets/i18n/sk.json | 5 +- assets/i18n/tr.json | 5 +- ...assessment-instruction-panel.component.css | 66 ++++++++++ ...ssessment-instruction-panel.component.html | 23 ++++ ...ssment-instruction-panel.component.spec.ts | 24 ++++ .../assessment-instruction-panel.component.ts | 10 ++ ...assessment-introduction-card.component.css | 70 ---------- ...ssessment-introduction-card.component.html | 26 ---- ...ssment-introduction-card.component.spec.ts | 122 +----------------- .../assessment-introduction-card.component.ts | 36 +----- ...assessment-conversation-skin.component.css | 88 ++++++++++--- ...ssessment-conversation-skin.component.html | 33 +++-- ...ssment-conversation-skin.component.spec.ts | 16 +++ ...-assessment-conversation-skin.component.ts | 27 +++- ...cate-assessment-player-page.component.html | 4 +- ...e-assessment-player-page.component.spec.ts | 51 ++++++-- ...ficate-assessment-player-page.component.ts | 29 +++-- .../learner-dashboard-page.component.html | 2 +- 23 files changed, 353 insertions(+), 310 deletions(-) diff --git a/assets/i18n/en.json b/assets/i18n/en.json index b3a24dd0057db..66681dc74a5cb 100644 --- a/assets/i18n/en.json +++ b/assets/i18n/en.json @@ -183,6 +183,13 @@ "I18N_ASSESSMENT_INSTRUCTIONS_HEADING": "Before you begin, here's what to expect:", "I18N_ASSESSMENT_INSTRUCTION_AUTO_SUBMIT": "If the timer runs out, your assessment will be auto-submitted.", "I18N_ASSESSMENT_INSTRUCTION_FINAL_SUBMISSION": "Your answers are final only when you click \"Submit Assessment\" at the end of the assessment.", + "I18N_ASSESSMENT_INSTRUCTION_INDEX_LEGEND_ATTEMPTED": "Attempted", + "I18N_ASSESSMENT_INSTRUCTION_INDEX_LEGEND_NOT_ATTEMPTED": "Not attempted", + "I18N_ASSESSMENT_INSTRUCTION_INDEX_LEGEND_UNANSWERED": "Unanswered/visited", + "I18N_ASSESSMENT_INSTRUCTION_INDEX_LEGEND_NOT_VISITED": "Not visited", + "I18N_ASSESSMENT_INSTRUCTION_INDEX_LEGEND_ANSWERED": "Answered", + "I18N_ASSESSMENT_INSTRUCTION_INDEX_PREVIEW_DESCRIPTION": "A row of numbers sits above every question. Tap any number to jump straight to that question. The colours tell you where you stand:", + "I18N_ASSESSMENT_INSTRUCTION_INDEX_NAVIGATION": "Each question has a numbered box at the top. Click any numbered box to jump directly to that question.", "I18N_ASSESSMENT_INSTRUCTION_MULTIPLE_ATTEMPTS": "You may take the assessment multiple times. If you don't pass, we recommend reviewing the lessons before trying again.", "I18N_ASSESSMENT_INSTRUCTION_NAVIGATION": "Use the Back (←) and Next (→) arrows to move between questions.", "I18N_ASSESSMENT_INSTRUCTION_NEW_ATTEMPT": "In that case, you can start the assessment again later, which will begin a new attempt.", @@ -280,7 +287,6 @@ "I18N_CERTIFICATE_ASSESSMENT_BACK_BUTTON": "Back", "I18N_CERTIFICATE_ASSESSMENT_CONTINUE_BUTTON": "Continue to assessment", "I18N_CERTIFICATE_ASSESSMENT_CONVERSATION_SKIN_BACK_BUTTON": "Back", - "I18N_CERTIFICATE_ASSESSMENT_CONVERSATION_SKIN_CURRENT_PROGRESS": "Current Progress: <[progressPercentage]>%", "I18N_CERTIFICATE_ASSESSMENT_CONVERSATION_SKIN_NEXT_BUTTON": "Next", "I18N_CERTIFICATE_ASSESSMENT_CONVERSATION_SKIN_SUBMIT_ASSESSMENT_BUTTON": "Submit Assessment", "I18N_CERTIFICATE_ASSESSMENT_COOLDOWN_ERROR": "You just started an assessment before this time. Please try again in <[remainingMinutes]> minute(s).", diff --git a/assets/i18n/fr.json b/assets/i18n/fr.json index d98a2b819090a..28c70bc31b045 100644 --- a/assets/i18n/fr.json +++ b/assets/i18n/fr.json @@ -174,6 +174,10 @@ "I18N_ASSESSMENT_INSTRUCTIONS_HEADING": "Avant de commencer, voici ce à quoi vous pouvez vous attendre:", "I18N_ASSESSMENT_INSTRUCTION_AUTO_SUBMIT": "Si le temps imparti est écoulé, votre évaluation sera automatiquement soumise.", "I18N_ASSESSMENT_INSTRUCTION_FINAL_SUBMISSION": "Vos réponses ne seront définitives que lorsque vous cliquerez sur « Soumettre l’évaluation » à la fin de l’évaluation.", + "I18N_ASSESSMENT_INSTRUCTION_INDEX_LEGEND_ATTEMPTED": "Attempted", + "I18N_ASSESSMENT_INSTRUCTION_INDEX_LEGEND_NOT_ATTEMPTED": "Not attempted", + "I18N_ASSESSMENT_INSTRUCTION_INDEX_LEGEND_UNANSWERED": "Unanswered/visited", + "I18N_ASSESSMENT_INSTRUCTION_INDEX_NAVIGATION": "Each question has a numbered box at the top. Click any numbered box to jump directly to that question.", "I18N_ASSESSMENT_INSTRUCTION_MULTIPLE_ATTEMPTS": "Vous pouvez passer l'évaluation plusieurs fois. Si vous ne réussissez pas, nous vous recommandons de revoir les leçons avant de recommencer.", "I18N_ASSESSMENT_INSTRUCTION_NAVIGATION": "Utilisez les flèches Retour (←) et Suivant (→) pour passer d'une question à l'autre.", "I18N_ASSESSMENT_INSTRUCTION_NEW_ATTEMPT": "Dans ce cas, vous pourrez recommencer l'évaluation plus tard, ce qui constituera une nouvelle tentative.", diff --git a/assets/i18n/ko.json b/assets/i18n/ko.json index cd7912b983ef1..82e5dc54fec45 100644 --- a/assets/i18n/ko.json +++ b/assets/i18n/ko.json @@ -252,7 +252,6 @@ "I18N_CARD_CONTENT_LIMIT_ERROR_MESSAGE": "카드 내용이 너무 깁니다. 저장하려면 4500자 이내로 작성해 주세요.", "I18N_CARD_HEIGHT_LIMIT_WARNING_MESSAGE": "이 카드는 너무 길어서 학생들이 흥미를 잃을 수 있습니다. 길이를 줄이거나 두 장으로 나누는 것을 고려해 보세요.", "I18N_CERTIFICATE_ASSESSMENT_CONVERSATION_SKIN_BACK_BUTTON": "뒤로", - "I18N_CERTIFICATE_ASSESSMENT_CONVERSATION_SKIN_CURRENT_PROGRESS": "현재 진행 상황: <[progressPercentage]>%", "I18N_CERTIFICATE_ASSESSMENT_CONVERSATION_SKIN_NEXT_BUTTON": "다음", "I18N_CHAPTER_COMPLETION": "챕터 완료를 축하합니다!", "I18N_CLASSROOM_FOUNDATION_TEXT": "<[classroomName]>에서 시작하기 위한 기초 수업입니다.", diff --git a/assets/i18n/nl.json b/assets/i18n/nl.json index 0d4d675bebb66..2307ee26ebbed 100644 --- a/assets/i18n/nl.json +++ b/assets/i18n/nl.json @@ -183,6 +183,10 @@ "I18N_ASSESSMENT_INSTRUCTIONS_HEADING": "Voordat u begint, volgt hier wat u kunt verwachten:", "I18N_ASSESSMENT_INSTRUCTION_AUTO_SUBMIT": "Als de timer afloopt, wordt uw toets automatisch ingediend.", "I18N_ASSESSMENT_INSTRUCTION_FINAL_SUBMISSION": "Uw antwoorden zijn pas definitief als u aan het einde van de toets op 'Toets indienen' klikt.", + "I18N_ASSESSMENT_INSTRUCTION_INDEX_LEGEND_ATTEMPTED": "Attempted", + "I18N_ASSESSMENT_INSTRUCTION_INDEX_LEGEND_NOT_ATTEMPTED": "Not attempted", + "I18N_ASSESSMENT_INSTRUCTION_INDEX_LEGEND_UNANSWERED": "Unanswered/visited", + "I18N_ASSESSMENT_INSTRUCTION_INDEX_NAVIGATION": "Each question has a numbered box at the top. Click any numbered box to jump directly to that question.", "I18N_ASSESSMENT_INSTRUCTION_MULTIPLE_ATTEMPTS": "U mag de toets meerdere keren maken. Als u niet slaagt, raden we u aan de lessen nog eens door te nemen voordat u het opnieuw probeert.", "I18N_ASSESSMENT_INSTRUCTION_NAVIGATION": "Gebruik de pijltoetsen Terug (←) en Volgende (→) om tussen de vragen te navigeren.", "I18N_ASSESSMENT_INSTRUCTION_NEW_ATTEMPT": "In dat geval kunt u de toets later opnieuw starten, waarmee een nieuwe poging begint.", @@ -274,7 +278,6 @@ "I18N_CERTIFICATE_ASSESSMENT_BACK_BUTTON": "Terug", "I18N_CERTIFICATE_ASSESSMENT_CONTINUE_BUTTON": "Doorgaan naar de toets", "I18N_CERTIFICATE_ASSESSMENT_CONVERSATION_SKIN_BACK_BUTTON": "Terug", - "I18N_CERTIFICATE_ASSESSMENT_CONVERSATION_SKIN_CURRENT_PROGRESS": "Huidige voortgang: <[progressPercentage]>%", "I18N_CERTIFICATE_ASSESSMENT_CONVERSATION_SKIN_NEXT_BUTTON": "Volgende", "I18N_CERTIFICATE_ASSESSMENT_CONVERSATION_SKIN_SUBMIT_ASSESSMENT_BUTTON": "Toets indienen", "I18N_CERTIFICATE_ASSESSMENT_DEMONSTRATES_HEADING": "Wat dit certificaat aantoont", diff --git a/assets/i18n/qqq.json b/assets/i18n/qqq.json index 2e7af694db15c..0b70b6df066b1 100644 --- a/assets/i18n/qqq.json +++ b/assets/i18n/qqq.json @@ -183,6 +183,13 @@ "I18N_ASSESSMENT_INSTRUCTIONS_HEADING": "Heading shown above the list of assessment instructions on the instruction panel.", "I18N_ASSESSMENT_INSTRUCTION_AUTO_SUBMIT": "Instruction telling the learner their assessment is auto-submitted when the timer runs out.", "I18N_ASSESSMENT_INSTRUCTION_FINAL_SUBMISSION": "Instruction telling the learner their answers are only final once they click Submit Assessment.", + "I18N_ASSESSMENT_INSTRUCTION_INDEX_LEGEND_ATTEMPTED": "Legend label describing a question that has been attempted by the learner.", + "I18N_ASSESSMENT_INSTRUCTION_INDEX_LEGEND_NOT_ATTEMPTED": "Legend label describing a question that has not yet been attempted by the learner.", + "I18N_ASSESSMENT_INSTRUCTION_INDEX_LEGEND_UNANSWERED": "Legend label describing a question the learner has visited but not yet answered.", + "I18N_ASSESSMENT_INSTRUCTION_INDEX_LEGEND_NOT_VISITED": "Legend label describing a question the learner has not yet visited.", + "I18N_ASSESSMENT_INSTRUCTION_INDEX_LEGEND_ANSWERED": "Legend label describing a question the learner has answered.", + "I18N_ASSESSMENT_INSTRUCTION_INDEX_PREVIEW_DESCRIPTION": "Explanatory text above the numbered index grid on the instruction panel, describing how the number navigation works and what the colours mean.", + "I18N_ASSESSMENT_INSTRUCTION_INDEX_NAVIGATION": "Instruction explaining that each question has a numbered box at the top which can be clicked to jump to that question.", "I18N_ASSESSMENT_INSTRUCTION_MULTIPLE_ATTEMPTS": "Instruction telling the learner they may retake the assessment.", "I18N_ASSESSMENT_INSTRUCTION_NAVIGATION": "Instruction explaining how to navigate between questions using the Back (←) and Next (→) arrows.", "I18N_ASSESSMENT_INSTRUCTION_NEW_ATTEMPT": "Instruction explaining that restarting the assessment begins a new attempt.", @@ -280,7 +287,6 @@ "I18N_CERTIFICATE_ASSESSMENT_BACK_BUTTON": "Text displayed on the back button in the certificate assessment header. Clicking the button navigate back in the certificate assessment flow.", "I18N_CERTIFICATE_ASSESSMENT_CONTINUE_BUTTON": "Text displayed on the button that allows the learner to proceed from the certificate introduction card to the certificate assessment.", "I18N_CERTIFICATE_ASSESSMENT_CONVERSATION_SKIN_BACK_BUTTON": "Label for the back button in the certificate assessment question view.", - "I18N_CERTIFICATE_ASSESSMENT_CONVERSATION_SKIN_CURRENT_PROGRESS": "Text showing the learner's progress through the certificate assessment questions.", "I18N_CERTIFICATE_ASSESSMENT_CONVERSATION_SKIN_NEXT_BUTTON": "Label for the next button in the certificate assessment question view.", "I18N_CERTIFICATE_ASSESSMENT_CONVERSATION_SKIN_SUBMIT_ASSESSMENT_BUTTON": "Label for the button that submits the certificate assessment.", "I18N_CERTIFICATE_ASSESSMENT_COOLDOWN_ERROR": "Warning message shown when the learner tries to start a new certificate assessment attempt before the cooldown window after their previous attempt has elapsed. <[remainingMinutes]> is replaced with the whole number of minutes they must wait; it is always at least one.", diff --git a/assets/i18n/sk.json b/assets/i18n/sk.json index 5ff49afd4a45b..45109127d08e4 100644 --- a/assets/i18n/sk.json +++ b/assets/i18n/sk.json @@ -183,6 +183,10 @@ "I18N_ASSESSMENT_INSTRUCTIONS_HEADING": "Skôr než začnete, tu je, čo vás čaká:", "I18N_ASSESSMENT_INSTRUCTION_AUTO_SUBMIT": "Ak vyprší časový limit, vaša skúška sa odošle automaticky.", "I18N_ASSESSMENT_INSTRUCTION_FINAL_SUBMISSION": "Vaše odpovede sú konečné až vtedy, keď na konci skúšky kliknete na „Odoslať skúšku“.", + "I18N_ASSESSMENT_INSTRUCTION_INDEX_LEGEND_ATTEMPTED": "Attempted", + "I18N_ASSESSMENT_INSTRUCTION_INDEX_LEGEND_NOT_ATTEMPTED": "Not attempted", + "I18N_ASSESSMENT_INSTRUCTION_INDEX_LEGEND_UNANSWERED": "Unanswered/visited", + "I18N_ASSESSMENT_INSTRUCTION_INDEX_NAVIGATION": "Each question has a numbered box at the top. Click any numbered box to jump directly to that question.", "I18N_ASSESSMENT_INSTRUCTION_MULTIPLE_ATTEMPTS": "Skúšku môžete absolvovať viackrát. Ak neuspejete, odporúčame si pred ďalším pokusom zopakovať lekcie.", "I18N_ASSESSMENT_INSTRUCTION_NAVIGATION": "Medzi otázkami sa pohybujte šípkami Späť (←) a Ďalej (→).", "I18N_ASSESSMENT_INSTRUCTION_NEW_ATTEMPT": "V takom prípade môžete skúšku neskôr spustiť znova, čím sa začne nový pokus.", @@ -273,7 +277,6 @@ "I18N_CERTIFICATE_ASSESSMENT_BACK_BUTTON": "Späť", "I18N_CERTIFICATE_ASSESSMENT_CONTINUE_BUTTON": "Pokračovať na skúšku", "I18N_CERTIFICATE_ASSESSMENT_CONVERSATION_SKIN_BACK_BUTTON": "Späť", - "I18N_CERTIFICATE_ASSESSMENT_CONVERSATION_SKIN_CURRENT_PROGRESS": "Aktuálny postup: <[progressPercentage]> %", "I18N_CERTIFICATE_ASSESSMENT_CONVERSATION_SKIN_NEXT_BUTTON": "Ďalej", "I18N_CERTIFICATE_ASSESSMENT_CONVERSATION_SKIN_SUBMIT_ASSESSMENT_BUTTON": "Odoslať skúšku", "I18N_CERTIFICATE_ASSESSMENT_DEMONSTRATES_HEADING": "Čo tento certifikát dokazuje", diff --git a/assets/i18n/tr.json b/assets/i18n/tr.json index 6f517136b33e9..586b374753c74 100644 --- a/assets/i18n/tr.json +++ b/assets/i18n/tr.json @@ -183,6 +183,10 @@ "I18N_ASSESSMENT_INSTRUCTIONS_HEADING": "Başlamadan önce sizi nelerin beklediğine bir göz atalım:", "I18N_ASSESSMENT_INSTRUCTION_AUTO_SUBMIT": "Süre dolduğunda değerlendirmeniz otomatik olarak gönderilecektir.", "I18N_ASSESSMENT_INSTRUCTION_FINAL_SUBMISSION": "Yanıtlarınız, yalnızca değerlendirmenin sonunda \"Değerlendirmeyi Gönder\" düğmesine tıkladığınızda kesinleşir.", + "I18N_ASSESSMENT_INSTRUCTION_INDEX_LEGEND_ATTEMPTED": "Attempted", + "I18N_ASSESSMENT_INSTRUCTION_INDEX_LEGEND_NOT_ATTEMPTED": "Not attempted", + "I18N_ASSESSMENT_INSTRUCTION_INDEX_LEGEND_UNANSWERED": "Unanswered/visited", + "I18N_ASSESSMENT_INSTRUCTION_INDEX_NAVIGATION": "Each question has a numbered box at the top. Click any numbered box to jump directly to that question.", "I18N_ASSESSMENT_INSTRUCTION_MULTIPLE_ATTEMPTS": "Değerlendirmeye birden fazla kez katılabilirsiniz. Başarılı olamazsanız tekrar denemeden önce dersleri gözden geçirmenizi öneririz.", "I18N_ASSESSMENT_INSTRUCTION_NAVIGATION": "Sorular arasında geçiş yapmak için Geri (←) ve İleri (→) oklarını kullanın.", "I18N_ASSESSMENT_INSTRUCTION_NEW_ATTEMPT": "Bu durumda, değerlendirmeye daha sonra yeniden başlayabilirsiniz. Böylece yeni bir deneme başlatmış olursunuz.", @@ -274,7 +278,6 @@ "I18N_CERTIFICATE_ASSESSMENT_BACK_BUTTON": "Geri", "I18N_CERTIFICATE_ASSESSMENT_CONTINUE_BUTTON": "Değerlendirmeye devam edin", "I18N_CERTIFICATE_ASSESSMENT_CONVERSATION_SKIN_BACK_BUTTON": "Geri", - "I18N_CERTIFICATE_ASSESSMENT_CONVERSATION_SKIN_CURRENT_PROGRESS": "Mevcut İlerleme: <[progressPercentage]>%", "I18N_CERTIFICATE_ASSESSMENT_CONVERSATION_SKIN_NEXT_BUTTON": "İleri", "I18N_CERTIFICATE_ASSESSMENT_CONVERSATION_SKIN_SUBMIT_ASSESSMENT_BUTTON": "Değerlendirmeyi Gönder", "I18N_CERTIFICATE_ASSESSMENT_DEMONSTRATES_HEADING": "Bu sertifika neleri gösterir", diff --git a/core/templates/pages/certificate-assessment-player-page/assessment-instruction-panel.component.css b/core/templates/pages/certificate-assessment-player-page/assessment-instruction-panel.component.css index a1b26067c0672..8019f6b028b0f 100644 --- a/core/templates/pages/certificate-assessment-player-page/assessment-instruction-panel.component.css +++ b/core/templates/pages/certificate-assessment-player-page/assessment-instruction-panel.component.css @@ -41,6 +41,72 @@ margin-bottom: 8px; } +.index-preview-section { + background: #f8fafc; + border: 1px solid #e2e8f0; + border-radius: 6px; + margin-bottom: 32px; + padding: 16px; +} + +.index-preview-description { + color: #333; + font-size: 15px; + line-height: 1.5; + margin-bottom: 16px; + text-align: center; +} + +.index-preview-rows { + display: flex; + flex-wrap: wrap; + gap: 16px; + justify-content: center; +} + +.index-preview-row { + align-items: center; + display: flex; + gap: 12px; +} + +.index-preview-box { + align-items: center; + border-radius: 6px; + color: #333; + display: flex; + font-family: 'Roboto', sans-serif; + font-size: 14px; + font-weight: 600; + height: 36px; + justify-content: center; + min-width: 36px; + width: 36px; +} + +.index-preview-box.unvisited { + background-color: #fff; + border: 2px solid #ccc; +} + +.index-preview-box.visited { + background-color: #fff3cd; + border: 2px solid #ffc107; + color: #856404; +} + +.index-preview-box.attempted { + background-color: #d4edda; + border: 2px solid #28a745; + color: #155724; +} + +.index-preview-label { + color: #333; + font-family: 'Roboto', sans-serif; + font-size: 15px; +} + .cta-row { display: flex; justify-content: center; diff --git a/core/templates/pages/certificate-assessment-player-page/assessment-instruction-panel.component.html b/core/templates/pages/certificate-assessment-player-page/assessment-instruction-panel.component.html index e26c072f54e1e..7f545e7601f79 100644 --- a/core/templates/pages/certificate-assessment-player-page/assessment-instruction-panel.component.html +++ b/core/templates/pages/certificate-assessment-player-page/assessment-instruction-panel.component.html @@ -17,11 +17,34 @@

{{ certificateTitle | titlecase }}

  • {{ questionCountInstructionI18nKey | translate: { questions: totalQuestions } }}
  • +
  • + {{ indexNavigationInstructionI18nKey | translate }} +
  • {{ instructionKey | translate }}
  • +
    +
    + {{ indexPreviewDescriptionI18nKey | translate }} +
    +
    +
    +
    1
    + {{ indexAttemptedLegendI18nKey | translate }} +
    +
    +
    2
    + {{ indexNotVisitedLegendI18nKey | translate }} +
    +
    +
    3
    + {{ indexAnsweredLegendI18nKey | translate }} +
    +
    +
    +
    -

    {{ topicsHeadingI18nKey | translate }}

    -

    - {{ topicsSubtextI18nKey | translate }} -

    - -
    -
    - -
    -
    -
    -
    - - {{ - 'I18N_CERTIFICATE_ASSESSMENT_CONVERSATION_SKIN_CURRENT_PROGRESS' - | translate: {progressPercentage: progressPercentage} - }} - +
    +
    + + {{ indexAttemptedLegendI18nKey | translate }} +
    +
    + + {{ indexNotVisitedLegendI18nKey | translate }} +
    +
    + + {{ indexAnsweredLegendI18nKey | translate }} +
    diff --git a/core/templates/pages/certificate-assessment-player-page/certificate-assessment-conversation-skin.component.spec.ts b/core/templates/pages/certificate-assessment-player-page/certificate-assessment-conversation-skin.component.spec.ts index 7345594462f3b..0138e3e3241c9 100644 --- a/core/templates/pages/certificate-assessment-player-page/certificate-assessment-conversation-skin.component.spec.ts +++ b/core/templates/pages/certificate-assessment-player-page/certificate-assessment-conversation-skin.component.spec.ts @@ -153,4 +153,20 @@ describe('CertificateAssessmentConversationSkinComponent', () => { expect(() => component.onSubmitAssessment()).toThrowError('submit failed'); expect(component.submitAssessment.emit).not.toHaveBeenCalled(); }); + + it('should emit navigateToQuestion with correct index', () => { + spyOn(component.navigateToQuestion, 'emit'); + + component.onNavigateToQuestion(2); + + expect(component.navigateToQuestion.emit).toHaveBeenCalledWith(2); + }); + + it('should return correct question status', () => { + component.questionStatuses = {0: 'visited', 1: 'attempted'}; + + expect(component.getQuestionStatus(0)).toBe('visited'); + expect(component.getQuestionStatus(1)).toBe('attempted'); + expect(component.getQuestionStatus(2)).toBe('unvisited'); + }); }); diff --git a/core/templates/pages/certificate-assessment-player-page/certificate-assessment-conversation-skin.component.ts b/core/templates/pages/certificate-assessment-player-page/certificate-assessment-conversation-skin.component.ts index 0ee71c1c94313..20579d0776eb0 100644 --- a/core/templates/pages/certificate-assessment-player-page/certificate-assessment-conversation-skin.component.ts +++ b/core/templates/pages/certificate-assessment-player-page/certificate-assessment-conversation-skin.component.ts @@ -14,8 +14,8 @@ /** * @fileoverview Component for the certificate assessment conversation skin, - * i.e. the question-by-question player screen (progress bar, question card, - * and navigation actions). + * i.e. the question-by-question player screen (question index grid, + * question card, and navigation actions). */ import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; @@ -33,14 +33,27 @@ export class CertificateAssessmentConversationSkinComponent implements OnInit { @Input() currentQuestion!: AssessmentQuestion; @Input() currentQuestionIndex = 0; @Input() totalQuestions = 0; - @Input() progressPercentage = 0; @Input() isLastQuestion = false; @Input() interactionHtml = ''; + @Input() questionStatuses: {[index: number]: string} = {}; + @Input() questionIndexes: number[] = []; @Output() previousQuestion = new EventEmitter(); @Output() nextQuestion = new EventEmitter(); + @Output() navigateToQuestion = new EventEmitter(); @Output() submitAssessment = new EventEmitter(); + indexNotAttemptedLegendI18nKey = + 'I18N_ASSESSMENT_INSTRUCTION_INDEX_LEGEND_NOT_ATTEMPTED'; + indexUnansweredLegendI18nKey = + 'I18N_ASSESSMENT_INSTRUCTION_INDEX_LEGEND_UNANSWERED'; + indexAttemptedLegendI18nKey = + 'I18N_ASSESSMENT_INSTRUCTION_INDEX_LEGEND_ATTEMPTED'; + indexNotVisitedLegendI18nKey = + 'I18N_ASSESSMENT_INSTRUCTION_INDEX_LEGEND_NOT_VISITED'; + indexAnsweredLegendI18nKey = + 'I18N_ASSESSMENT_INSTRUCTION_INDEX_LEGEND_ANSWERED'; + OPPIA_AVATAR_IMAGE_URL!: string; constructor( @@ -68,6 +81,14 @@ export class CertificateAssessmentConversationSkinComponent implements OnInit { this.nextQuestion.emit(); } + onNavigateToQuestion(index: number): void { + this.navigateToQuestion.emit(index); + } + + getQuestionStatus(index: number): string { + return this.questionStatuses[index] || 'unvisited'; + } + onSubmitAssessment(): void { if (this.currentInteractionService.isSubmitAnswerFnRegistered()) { this.currentInteractionService.submitAnswer(); diff --git a/core/templates/pages/certificate-assessment-player-page/certificate-assessment-player-page.component.html b/core/templates/pages/certificate-assessment-player-page/certificate-assessment-player-page.component.html index 3c0a54f630ec3..64432efeb964c 100644 --- a/core/templates/pages/certificate-assessment-player-page/certificate-assessment-player-page.component.html +++ b/core/templates/pages/certificate-assessment-player-page/certificate-assessment-player-page.component.html @@ -7,11 +7,13 @@ [currentQuestion]="currentQuestion" [currentQuestionIndex]="currentQuestionIndex" [totalQuestions]="totalQuestionCount" - [progressPercentage]="progressPercentage" [isLastQuestion]="isLastQuestion" [interactionHtml]="getInteractionHtml()" + [questionStatuses]="questionStatuses" + [questionIndexes]="getQuestionIndexes()" (previousQuestion)="previousQuestion()" (nextQuestion)="nextQuestion()" + (navigateToQuestion)="navigateToQuestion($event)" (submitAssessment)="submitAssessment()"> diff --git a/core/templates/pages/certificate-assessment-player-page/certificate-assessment-player-page.component.spec.ts b/core/templates/pages/certificate-assessment-player-page/certificate-assessment-player-page.component.spec.ts index 7c98f42ea9f3c..aa9c31cade272 100644 --- a/core/templates/pages/certificate-assessment-player-page/certificate-assessment-player-page.component.spec.ts +++ b/core/templates/pages/certificate-assessment-player-page/certificate-assessment-player-page.component.spec.ts @@ -338,12 +338,46 @@ describe('CertificateAssessmentPlayerPageComponent', () => { expect(component.currentQuestionIndex).toBe(0); }); + it('should navigate directly to a specific question', fakeAsync(() => { + load(); + component.navigateToQuestion(2); + expect(component.currentQuestionIndex).toBe(2); + expect(component.questionStatuses[2]).toBe('visited'); + })); + + it('should not navigate to invalid question index', fakeAsync(() => { + load(); + component.navigateToQuestion(-1); + expect(component.currentQuestionIndex).toBe(0); + component.navigateToQuestion(10); + expect(component.currentQuestionIndex).toBe(0); + })); + + it('should return correct question indexes', fakeAsync(() => { + load(); + expect(component.getQuestionIndexes()).toEqual([0, 1, 2]); + })); + + it('should initialize all question statuses as unvisited', fakeAsync(() => { + load(); + expect(component.questionStatuses[0]).toBe('visited'); + expect(component.questionStatuses[1]).toBe('unvisited'); + expect(component.questionStatuses[2]).toBe('unvisited'); + })); + + it('should mark question as attempted on answer submit', fakeAsync(() => { + load(); + component.currentQuestionIndex = 0; + component.handleInteractionSubmit(1); + expect(component.questionStatuses[0]).toBe('attempted'); + })); + it('should recompute derived fields on first load', fakeAsync(() => { expect(component.currentQuestion).toBeNull(); loadQ1(); expect(component.currentQuestion).toEqual(component.questions[0]); expect(component.totalQuestionCount).toBe(3); - expect(component.progressPercentage).toBe(Math.round((1 / 3) * 100)); + expect(component.questionStatuses[0]).toBe('visited'); expect(component.isLastQuestion).toBe(false); })); @@ -352,9 +386,11 @@ describe('CertificateAssessmentPlayerPageComponent', () => { component.currentQuestionIndex = 0; component.nextQuestion(); expect(component.isLastQuestion).toBe(false); + expect(component.questionStatuses[0]).toBe('visited'); + expect(component.questionStatuses[1]).toBe('visited'); component.nextQuestion(); expect(component.isLastQuestion).toBe(true); - expect(component.progressPercentage).toBe(100); + expect(component.questionStatuses[2]).toBe('visited'); component.previousQuestion(); expect(component.isLastQuestion).toBe(false); })); @@ -397,18 +433,15 @@ describe('CertificateAssessmentPlayerPageComponent', () => { expect(component.isCurrentQuestionLast()).toBe(true); })); - it('should return 0 when no questions', async () => { + it('should return empty indexes when no questions', async () => { await setup(null); fixture.detectChanges(); - expect(component.getProgressPercentage()).toBe(0); + expect(component.getQuestionIndexes()).toEqual([]); }); - it('should compute progress percentage', fakeAsync(() => { + it('should return indexes matching question count', fakeAsync(() => { load(); - component.currentQuestionIndex = 0; - expect(component.getProgressPercentage()).toBe(Math.round((1 / 3) * 100)); - component.currentQuestionIndex = 2; - expect(component.getProgressPercentage()).toBe(100); + expect(component.getQuestionIndexes()).toEqual([0, 1, 2]); })); it('should open time-expired modal on desktop when time expires', fakeAsync(() => { diff --git a/core/templates/pages/certificate-assessment-player-page/certificate-assessment-player-page.component.ts b/core/templates/pages/certificate-assessment-player-page/certificate-assessment-player-page.component.ts index 6c6dc0a222ec2..cd4acdb55a83d 100644 --- a/core/templates/pages/certificate-assessment-player-page/certificate-assessment-player-page.component.ts +++ b/core/templates/pages/certificate-assessment-player-page/certificate-assessment-player-page.component.ts @@ -82,10 +82,10 @@ export class CertificateAssessmentPlayerPageComponent answers: {[questionId: string]: InteractionAnswer | null} = {}; interactions: {[questionId: string]: Interaction} = {}; interactionHtmls: {[questionId: string]: string} = {}; + questionStatuses: {[index: number]: string} = {}; focusLabel = ''; currentQuestion: AssessmentQuestion | null = null; totalQuestionCount = 0; - progressPercentage = 0; isLastQuestion = false; hasHandledTimeExpiry = false; private handleSubmitFn: OnSubmitFn; @@ -135,6 +135,7 @@ export class CertificateAssessmentPlayerPageComponent attemptQuestion.questionId, attemptQuestion.questionStateData ); + this.questionStatuses[index] = 'unvisited'; }); } @@ -256,6 +257,18 @@ export class CertificateAssessmentPlayerPageComponent this.refreshComputedFields(); } + navigateToQuestion(index: number): void { + if (index < 0 || index >= this.getTotalQuestionCount()) { + return; + } + this.currentQuestionIndex = index; + this.refreshComputedFields(); + } + + getQuestionIndexes(): number[] { + return Array.from({length: this.getTotalQuestionCount()}, (_, i) => i); + } + private collectAnswers(): SubmitCertificateAssessmentAnswerBackendDict[] { const loadedQuestions = this.questions.filter( (question): question is AssessmentQuestion => question !== undefined @@ -332,6 +345,7 @@ export class CertificateAssessmentPlayerPageComponent return; } this.answers[question.id] = answer; + this.questionStatuses[this.currentQuestionIndex] = 'attempted'; this.refreshComputedFields(); } @@ -350,15 +364,6 @@ export class CertificateAssessmentPlayerPageComponent return JSON.stringify(answer); } - getProgressPercentage(): number { - if (this.getTotalQuestionCount() === 0) { - return 0; - } - return Math.round( - ((this.currentQuestionIndex + 1) / this.getTotalQuestionCount()) * 100 - ); - } - getCurrentQuestion(): AssessmentQuestion | null { if (this.questions.length === 0) { return null; @@ -380,7 +385,9 @@ export class CertificateAssessmentPlayerPageComponent private refreshComputedFields(): void { this.currentQuestion = this.getCurrentQuestion(); this.totalQuestionCount = this.getTotalQuestionCount(); - this.progressPercentage = this.getProgressPercentage(); this.isLastQuestion = this.isCurrentQuestionLast(); + if (this.questionStatuses[this.currentQuestionIndex] !== 'attempted') { + this.questionStatuses[this.currentQuestionIndex] = 'visited'; + } } } diff --git a/core/templates/pages/learner-dashboard-page/learner-dashboard-page.component.html b/core/templates/pages/learner-dashboard-page/learner-dashboard-page.component.html index 5fb20573f1ab2..6ff39f0035784 100644 --- a/core/templates/pages/learner-dashboard-page/learner-dashboard-page.component.html +++ b/core/templates/pages/learner-dashboard-page/learner-dashboard-page.component.html @@ -89,7 +89,7 @@ [ngClass]="{'oppia-learner-dash-sidebar_btn--active': activeSection === LEARNER_DASHBOARD_SECTION_I18N_IDS.MY_CERTIFICATES}" (click)="setActiveSection(LEARNER_DASHBOARD_SECTION_I18N_IDS.MY_CERTIFICATES)" (keyup.enter)="setActiveSection(LEARNER_DASHBOARD_SECTION_I18N_IDS.MY_CERTIFICATES)"> - + {{ LEARNER_DASHBOARD_SECTION_I18N_IDS.MY_CERTIFICATES | translate }} From 629264f05d1d6031e0d4544c4b255b7751157dd4 Mon Sep 17 00:00:00 2001 From: mosin74 Date: Fri, 4 Sep 2026 17:22:33 +0530 Subject: [PATCH 2/5] fix: mobile responsiveness and badge image updates --- .../certificate badge.png | Bin 0 -> 7546 bytes ...led-shared-background-banner.component.css | 15 +++++++++-- .../time-expired-modal.component.css | 1 + .../unanswered-question-modal.component.css | 23 +++++++++++++++++ ...assessment-introduction-card.component.css | 1 + ...assessment-conversation-skin.component.css | 2 +- ...cate-offering-available-page.component.css | 24 +++++++++++++++++- ...ate-offering-available-page.component.html | 10 ++------ 8 files changed, 64 insertions(+), 12 deletions(-) create mode 100644 assets/images/certificate-assessment/certificate badge.png diff --git a/assets/images/certificate-assessment/certificate badge.png b/assets/images/certificate-assessment/certificate badge.png new file mode 100644 index 0000000000000000000000000000000000000000..ff6e7f7136939e7938998b0393c163e4cd6a9c35 GIT binary patch literal 7546 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' *ngFor="let certificate of availableCertificates">
    -

    {{ certificate.title }}

    From 510499328c3ff86c471bb1a22c6d3ae74fe7e42e Mon Sep 17 00:00:00 2001 From: mosin74 Date: Fri, 4 Sep 2026 17:25:28 +0530 Subject: [PATCH 3/5] fix: result card styling for fail screen and mobile --- .../certificate-assessment-result-card.component.css | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/templates/pages/certificate-assessment-result-page/certificate-assessment-result-card.component.css b/core/templates/pages/certificate-assessment-result-page/certificate-assessment-result-card.component.css index bc9fd0a9dd5a0..cd2e9744e22e7 100644 --- a/core/templates/pages/certificate-assessment-result-page/certificate-assessment-result-card.component.css +++ b/core/templates/pages/certificate-assessment-result-page/certificate-assessment-result-card.component.css @@ -26,6 +26,10 @@ --oppia-result-accent: #b3261e; } +.result-card--failed .result-card-heading { + font-weight: 400; +} + .result-card-heading { color: var(--oppia-result-accent); font-family: 'Capriola', 'Roboto', Arial, sans-serif; @@ -105,6 +109,7 @@ .result-card { margin: -120px 16px 32px; padding: 28px 20px 24px; + top: 125px; } .result-card-summary { From 9c25b0608381d4673bd40e25fefb11c05b7035a0 Mon Sep 17 00:00:00 2001 From: mosin74 Date: Fri, 4 Sep 2026 19:36:05 +0530 Subject: [PATCH 4/5] Fixed lint checks --- ...sessment-titled-shared-background-banner.component.css | 2 +- .../unanswered-question-modal.component.css | 2 +- .../certificate-assessment-result-card.component.css | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/core/templates/components/certificate-assessment-offering-helper/certificate-assessment-titled-shared-background-banner.component.css b/core/templates/components/certificate-assessment-offering-helper/certificate-assessment-titled-shared-background-banner.component.css index bbc6231bb0d95..383cce5a235b8 100644 --- a/core/templates/components/certificate-assessment-offering-helper/certificate-assessment-titled-shared-background-banner.component.css +++ b/core/templates/components/certificate-assessment-offering-helper/certificate-assessment-titled-shared-background-banner.component.css @@ -86,8 +86,8 @@ } .oppia-titled-background-banner-button.btn-primary { + font-size: 1.6rem; margin-left: 0; width: 120px; - font-size: 1.6rem; } } diff --git a/core/templates/components/certificate-assessment-offering-helper/unanswered-question-modal.component.css b/core/templates/components/certificate-assessment-offering-helper/unanswered-question-modal.component.css index 15613f4b1d762..54c94fe0565b1 100644 --- a/core/templates/components/certificate-assessment-offering-helper/unanswered-question-modal.component.css +++ b/core/templates/components/certificate-assessment-offering-helper/unanswered-question-modal.component.css @@ -98,8 +98,8 @@ } .assessment-modal-actions { - margin-left: 0; justify-content: center; + margin-left: 0; } .assessment-modal-action-button { diff --git a/core/templates/pages/certificate-assessment-result-page/certificate-assessment-result-card.component.css b/core/templates/pages/certificate-assessment-result-page/certificate-assessment-result-card.component.css index cd2e9744e22e7..9782af1b80779 100644 --- a/core/templates/pages/certificate-assessment-result-page/certificate-assessment-result-card.component.css +++ b/core/templates/pages/certificate-assessment-result-page/certificate-assessment-result-card.component.css @@ -26,10 +26,6 @@ --oppia-result-accent: #b3261e; } -.result-card--failed .result-card-heading { - font-weight: 400; -} - .result-card-heading { color: var(--oppia-result-accent); font-family: 'Capriola', 'Roboto', Arial, sans-serif; @@ -39,6 +35,10 @@ text-align: center; } +.result-card--failed .result-card-heading { + font-weight: 400; +} + .result-card-earned-banner { border-radius: 6px; margin-bottom: 24px; From 5f9d4794370c15ad021fcd98215509a2b0fe4c8b Mon Sep 17 00:00:00 2001 From: mosin74 Date: Fri, 4 Sep 2026 21:02:38 +0530 Subject: [PATCH 5/5] Fixed failling test --- .../assessment-introduction-card.component.spec.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/core/templates/pages/certificate-assessment-player-page/assessment-introduction-card.component.spec.ts b/core/templates/pages/certificate-assessment-player-page/assessment-introduction-card.component.spec.ts index 06c010494b121..1a22e043a7457 100644 --- a/core/templates/pages/certificate-assessment-player-page/assessment-introduction-card.component.spec.ts +++ b/core/templates/pages/certificate-assessment-player-page/assessment-introduction-card.component.spec.ts @@ -95,10 +95,6 @@ describe('AssessmentIntroductionCardComponent', () => { }); it('should stop loading topics after the classroom data is fetched', async () => { - expect(component.isLoadingTopics).toBe(true); - - await fixture.whenStable(); - expect(component.isLoadingTopics).toBe(false); });