Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Only show previous steps incomplete modal for instructions & setup #2331

Merged
merged 6 commits into from
Oct 17, 2024
17 changes: 17 additions & 0 deletions app/components/course-page/previous-steps-incomplete-overlay.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<BlurredOverlay
@isBlurred={{this.shouldShowModal}}
{{did-update this.handleStepIdUpdated @currentStep.id}}
@overlayClass="bg-gray-200 bg-opacity-20 dark:bg-gray-800 dark:bg-opacity-20"
...attributes
>
<:content>
{{yield}}
</:content>
<:overlay>
<CoursePage::PreviousStepsIncompleteModal
class="mt-8 mx-3 md:mx-6"
@onClose={{this.handleModalDismissed}}
@activeStep={{this.coursePageState.activeStep}}
/>
</:overlay>
</BlurredOverlay>
55 changes: 55 additions & 0 deletions app/components/course-page/previous-steps-incomplete-overlay.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { action } from '@ember/object';
import { tracked } from '@glimmer/tracking';
import { service } from '@ember/service';
import Component from '@glimmer/component';
import type CoursePageStateService from 'codecrafters-frontend/services/course-page-state';
import { Step } from 'codecrafters-frontend/utils/course-page-step-list';

interface Signature {
Element: HTMLDivElement;

Args: {
currentStep: Step;
};

Blocks: {
default: [];
};
}

export default class PreviousStepsIncompleteOverlayComponent extends Component<Signature> {
@tracked modalWasDismissed = false;
@tracked lastSeenStepId: string | null = null;

@service declare coursePageState: CoursePageStateService;

get shouldShowModal(): boolean {
// This _shouldn't_ happen as long as we're always rendered in the course page, but let's be safe
if (!this.coursePageState.activeStep) {
return false;
}

Check warning on line 30 in app/components/course-page/previous-steps-incomplete-overlay.ts

View check run for this annotation

Codecov / codecov/patch

app/components/course-page/previous-steps-incomplete-overlay.ts#L30

Added line #L30 was not covered by tests

return !this.modalWasDismissed && this.args.currentStep.status === 'locked';
}

@action
handleModalDismissed() {
this.modalWasDismissed = true;
}

@action
handleStepIdUpdated() {
if (this.args.currentStep.id === this.lastSeenStepId) {
return;
}

this.lastSeenStepId = this.args.currentStep.id;
this.modalWasDismissed = false;
}
}

declare module '@glint/environment-ember-loose/registry' {
export default interface Registry {
'CoursePage::PreviousStepsIncompleteOverlay': typeof PreviousStepsIncompleteOverlayComponent;
}
}
18 changes: 1 addition & 17 deletions app/components/course-page/step-content.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,5 @@
/>
{{/if}}

<BlurredOverlay
@isBlurred={{this.shouldShowPreviousStepsIncompleteModal}}
@overlayClass="bg-gray-200 bg-opacity-20 dark:bg-gray-800 dark:bg-opacity-20"
class="px-3 md:px-6 lg:px-10"
{{did-update this.handleStepIdUpdated @step.id}}
>
<:content>
{{yield}}
</:content>
<:overlay>
<CoursePage::PreviousStepsIncompleteModal
class="mt-8 mx-3 md:mx-6"
@onClose={{this.handlePreviousStepsIncompleteModalDismissed}}
@activeStep={{this.coursePageState.activeStep}}
/>
</:overlay>
</BlurredOverlay>
{{yield}}
</div>
2 changes: 1 addition & 1 deletion app/templates/course/base-stages-completed.hbs
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<div class="pt-8 pb-16">
<div class="pt-8 pb-16 px-3 md:px-6 lg:px-10">
<CoursePage::BaseStagesCompletedCard @repository={{@model.activeRepository}} />
</div>
2 changes: 1 addition & 1 deletion app/templates/course/completed.hbs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{{! @glint-nocheck: not typesafe yet !}}
<div class="pt-8 pb-16">
<div class="pt-8 pb-16 px-3 md:px-6 lg:px-10">
<CoursePage::CourseCompletedCard @repository={{@model.activeRepository}} />
</div>
2 changes: 1 addition & 1 deletion app/templates/course/extension-completed.hbs
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<div class="pt-8 pb-16">
<div class="pt-8 pb-16 px-3 md:px-6 lg:px-10">
<CoursePage::ExtensionCompletedCard @repository={{@model.activeRepository}} @extension={{@model.extension}} />
</div>
2 changes: 1 addition & 1 deletion app/templates/course/introduction.hbs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<div class="w-full pt-8 pb-32">
<div class="w-full pt-8 pb-32 px-3 md:px-6 lg:px-10">
{{#if this.authenticator.currentUser.pendingProductWalkthroughFeatureSuggestion}}
<ProductWalkthroughFeatureSuggestion
@featureSuggestion={{this.authenticator.currentUser.pendingProductWalkthroughFeatureSuggestion}}
Expand Down
2 changes: 1 addition & 1 deletion app/templates/course/setup.hbs
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<div class="w-full pt-8 pb-32">
<div class="w-full pt-8 pb-32 px-3 md:px-6 lg:px-10">
<CoursePage::SetupStep::RepositorySetupCard @repository={{@model.activeRepository}} />
</div>
2 changes: 1 addition & 1 deletion app/templates/course/stage/code-examples.hbs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<div
class="pt-8 pb-32"
class="pt-8 pb-32 px-3 md:px-6 lg:px-10"
{{did-update (fn (mut this.stageIncompleteModalWasDismissed) false) this.courseStage}}
{{did-update this.loadSolutions this.courseStage}}
{{did-insert this.loadSolutions}}
Expand Down
2 changes: 1 addition & 1 deletion app/templates/course/stage/concepts.hbs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<div class="pt-8 pb-32" data-test-concepts-tab>
<div class="pt-8 pb-32 px-3 md:px-6 lg:px-10" data-test-concepts-tab>
<AlertWithIcon class="mb-6">
Concepts are interactive tutorials that teach you fundamental concepts related to this challenge.
<br />
Expand Down
174 changes: 88 additions & 86 deletions app/templates/course/stage/instructions.hbs
Original file line number Diff line number Diff line change
@@ -1,101 +1,103 @@
<div class="pt-6 pb-32">
{{#if this.shouldShowUpgradePrompt}}
<CoursePage::CourseStageStep::UpgradePrompt @featureSlugToHighlight="content" class="mb-6" />
{{/if}}
<CoursePage::PreviousStepsIncompleteOverlay @currentStep={{this.currentStep}}>
<div class="pt-6 pb-32 px-3 md:px-6 lg:px-10">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Missing Tests for PreviousStepsIncompleteOverlay Component

No associated tests were found for the PreviousStepsIncompleteOverlay component. It's recommended to add tests to verify its functionality and ensure reliability.

🔗 Analysis chain

Approve the addition of PreviousStepsIncompleteOverlay component

The addition of the <CoursePage::PreviousStepsIncompleteOverlay> component is a good approach to manage the visibility of content based on the completion status of previous steps. This can help ensure that users follow the intended learning path.

Could you provide more information about how this overlay behaves? Specifically:

  1. How does it determine which steps are incomplete?
  2. What exactly does it display to the user when previous steps are incomplete?
  3. Are there any accessibility considerations for this overlay?

To verify the implementation, please run the following script:

Also applies to: 103-103

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the implementation of PreviousStepsIncompleteOverlay component

# Test 1: Check if the component file exists
echo "Checking if the component file exists:"
fd -t f "previous-steps-incomplete-overlay.hbs" app/components

# Test 2: Check the component's template for key elements
echo "Checking the component's template for key elements:"
rg -i "blur|overlay|incomplete" app/components/course-page/previous-steps-incomplete-overlay.hbs

# Test 3: Check for any associated tests
echo "Checking for associated tests:"
rg -i "previousstepsincompleteoverlay" app/tests

Length of output: 824


Script:

#!/bin/bash
# Description: Search for associated tests of PreviousStepsIncompleteOverlay component across the entire codebase

# Test 1: Check if the component file exists
echo "Checking if the component file exists:"
fd -t f "previous-steps-incomplete-overlay.hbs" app/components

# Test 2: Check the component's template for key elements
echo "Checking the component's template for key elements:"
rg -i "blur|overlay|incomplete" app/components/course-page/previous-steps-incomplete-overlay.hbs

# Test 3: Search for associated tests in the entire codebase
echo "Searching for associated tests in the entire codebase:"
rg -i "PreviousStepsIncompleteOverlay" --type-test

Length of output: 1264


Script:

#!/bin/bash
# Description: Search for associated tests of PreviousStepsIncompleteOverlay component across the entire codebase

# Test 1: Check if the component file exists
echo "Checking if the component file exists:"
fd -t f "previous-steps-incomplete-overlay.hbs" app/components

# Test 2: Check the component's template for key elements
echo "Checking the component's template for key elements:"
rg -i "blur|overlay|incomplete" app/components/course-page/previous-steps-incomplete-overlay.hbs

# Test 3: Search for associated tests in common test directories and files
echo "Searching for associated tests in the entire codebase:"
rg -i "PreviousStepsIncompleteOverlay" $(fd -t f -e test.js -e spec.js -e test.ts -e spec.ts)

Length of output: 1398

{{#if this.shouldShowUpgradePrompt}}
<CoursePage::CourseStageStep::UpgradePrompt @featureSlugToHighlight="content" class="mb-6" />
{{/if}}

{{#if this.shouldShowFeedbackPrompt}}
<CoursePage::CourseStageStep::FeedbackPrompt
@courseStage={{@model.courseStage}}
@repository={{@model.activeRepository}}
@onSubmit={{this.handleStageFeedbackSubmitted}}
class="mb-6"
/>
{{/if}}

{{#if (gt this.badgeAwards.length 0)}}
<CoursePage::CourseStageStep::EarnedBadgeNotice @badgeAwards={{this.badgeAwards}} class="mb-6" />
{{/if}}
{{#if this.shouldShowFeedbackPrompt}}
<CoursePage::CourseStageStep::FeedbackPrompt
@courseStage={{@model.courseStage}}
@repository={{@model.activeRepository}}
@onSubmit={{this.handleStageFeedbackSubmitted}}
class="mb-6"
/>
{{/if}}

{{#if @model.courseStage.isFirst}}
<CoursePage::CourseStageStep::FirstStageTutorialCard @repository={{@model.activeRepository}} @courseStage={{@model.courseStage}} class="mb-6" />
{{/if}}
{{#if (gt this.badgeAwards.length 0)}}
<CoursePage::CourseStageStep::EarnedBadgeNotice @badgeAwards={{this.badgeAwards}} class="mb-6" />
{{/if}}

{{#if @model.courseStage.isSecond}}
<CoursePage::CourseStageStep::SecondStageInstructionsCard
@repository={{@model.activeRepository}}
@courseStage={{@model.courseStage}}
class="mb-6"
/>
{{/if}}
{{#if @model.courseStage.isFirst}}
<CoursePage::CourseStageStep::FirstStageTutorialCard @repository={{@model.activeRepository}} @courseStage={{@model.courseStage}} class="mb-6" />
{{/if}}

{{#if this.shouldShowTestRunnerCard}}
<div class="mb-6">
<CoursePage::CourseStageStep::TestRunnerCard
@isCollapsible={{or this.shouldSuppressTestRunnerCardExpands (not-eq this.currentStep.testsStatus "passed")}}
{{#if @model.courseStage.isSecond}}
<CoursePage::CourseStageStep::SecondStageInstructionsCard
@repository={{@model.activeRepository}}
@stage={{@model.courseStage}}
@onExpand={{if this.shouldSuppressTestRunnerCardExpands this.handleTestRunnerCardExpandedOnFirstStage undefined}}
@courseStage={{@model.courseStage}}
class="mb-6"
/>
{{/if}}

{{#if this.shouldSuppressTestRunnerCardExpands}}
<EmberPopover @popperContainer="body">
<div class="prose prose-sm prose-invert text-white">
{{#if (eq this.currentStep.testsStatus "failed")}}
<p>
This failure is expected! Check the
<a href="#first-stage-tutorial-card">How to pass this stage</a>
section for instructions.
</p>
{{else}}
<p>
Check the
<a href="#first-stage-tutorial-card">How to pass this stage</a>
section for instructions.
</p>
{{/if}}
</div>
</EmberPopover>
{{/if}}
</div>
{{/if}}
{{#if this.shouldShowTestRunnerCard}}
<div class="mb-6">
<CoursePage::CourseStageStep::TestRunnerCard
@isCollapsible={{or this.shouldSuppressTestRunnerCardExpands (not-eq this.currentStep.testsStatus "passed")}}
@repository={{@model.activeRepository}}
@stage={{@model.courseStage}}
@onExpand={{if this.shouldSuppressTestRunnerCardExpands this.handleTestRunnerCardExpandedOnFirstStage undefined}}
/>

{{! TODO: Bring this back? }}
{{!-- {{#if this.shouldShowPrerequisites}}
<CoursePage::CourseStageStep::PrerequisitesCard @repository={{@model.activeRepository}} @courseStage={{@model.courseStage}} class="mb-6" />
{{/if}} --}}
{{#if this.shouldSuppressTestRunnerCardExpands}}
<EmberPopover @popperContainer="body">
<div class="prose prose-sm prose-invert text-white">
{{#if (eq this.currentStep.testsStatus "failed")}}
<p>
This failure is expected! Check the
<a href="#first-stage-tutorial-card">How to pass this stage</a>
section for instructions.
</p>
{{else}}
<p>
Check the
<a href="#first-stage-tutorial-card">How to pass this stage</a>
section for instructions.
</p>
{{/if}}
</div>
</EmberPopover>
{{/if}}
</div>
{{/if}}

<CoursePage::CourseStageStep::YourTaskCard @repository={{@model.activeRepository}} @courseStage={{@model.courseStage}} />
{{! TODO: Bring this back? }}
{{!-- {{#if this.shouldShowPrerequisites}}
<CoursePage::CourseStageStep::PrerequisitesCard @repository={{@model.activeRepository}} @courseStage={{@model.courseStage}} class="mb-6" />
{{/if}} --}}

{{#if this.shouldShowLanguageGuide}}
<CoursePage::CourseStageStep::LanguageGuideCard @repository={{@model.activeRepository}} @courseStage={{@model.courseStage}} class="mt-6" />
{{/if}}
<CoursePage::CourseStageStep::YourTaskCard @repository={{@model.activeRepository}} @courseStage={{@model.courseStage}} />

<div data-percy-hints-section>
<div class="border-b dark:border-white/5 pb-2 mb-6 mt-8 flex items-center justify-between">
<h2 class="font-semibold text-lg text-gray-800 dark:text-gray-200">Hints</h2>
{{#if this.shouldShowLanguageGuide}}
<CoursePage::CourseStageStep::LanguageGuideCard @repository={{@model.activeRepository}} @courseStage={{@model.courseStage}} class="mt-6" />
{{/if}}

{{#if @model.activeRepository.language}}
<div class="flex items-center gap-1">
<span class="text-xs text-gray-500 mr-2">Filter by {{@model.activeRepository.language.name}}</span>
<Toggle @isOn={{this.commentListIsFilteredByLanguage}} {{on "click" this.handleCommentListFilterToggled}} />
<div data-percy-hints-section>
<div class="border-b dark:border-white/5 pb-2 mb-6 mt-8 flex items-center justify-between">
<h2 class="font-semibold text-lg text-gray-800 dark:text-gray-200">Hints</h2>

<EmberTooltip>
{{#if this.commentListIsFilteredByLanguage}}
You're currently viewing hints that are relevant to
{{@model.activeRepository.language.name}}. Turn this off to view hints for all languages.
{{else}}
You're currently viewing hints for all languages. Turn this on to filter hints that are relevant to
{{@model.activeRepository.language.name}}.
{{/if}}
</EmberTooltip>
</div>
{{/if}}
</div>
{{#if @model.activeRepository.language}}
<div class="flex items-center gap-1">
<span class="text-xs text-gray-500 mr-2">Filter by {{@model.activeRepository.language.name}}</span>
<Toggle @isOn={{this.commentListIsFilteredByLanguage}} {{on "click" this.handleCommentListFilterToggled}} />

<EmberTooltip>
{{#if this.commentListIsFilteredByLanguage}}
You're currently viewing hints that are relevant to
{{@model.activeRepository.language.name}}. Turn this off to view hints for all languages.
{{else}}
You're currently viewing hints for all languages. Turn this on to filter hints that are relevant to
{{@model.activeRepository.language.name}}.
{{/if}}
</EmberTooltip>
</div>
{{/if}}
</div>

<CoursePage::CommentList
@courseStage={{@model.courseStage}}
@language={{@model.activeRepository.language}}
@shouldFilterByLanguage={{this.commentListIsFilteredByLanguage}}
/>
<CoursePage::CommentList
@courseStage={{@model.courseStage}}
@language={{@model.activeRepository.language}}
@shouldFilterByLanguage={{this.commentListIsFilteredByLanguage}}
/>
</div>
</div>
</div>
</CoursePage::PreviousStepsIncompleteOverlay>
2 changes: 1 addition & 1 deletion app/templates/course/stage/screencasts.hbs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<div class="pt-8 pb-16" data-test-screencasts-tab>
<div class="pt-8 pb-16 px-3 md:px-6 lg:px-10" data-test-screencasts-tab>
<AlertWithIcon class="mb-6">
Screencasts are recordings of CodeCrafters users passing this stage. This is a beta feature, please send us
<div class="inline-flex">
Expand Down
Loading