Skip to content

Commit

Permalink
Merge pull request #2367 from codecrafters-io/highlight-language-guid…
Browse files Browse the repository at this point in the history
…es-in-stage-2

CC-1480: Highlight language guides in stage 2 tutorial card
  • Loading branch information
andy1li authored Oct 29, 2024
2 parents 8e2bbfe + 190fca8 commit 6475112
Show file tree
Hide file tree
Showing 14 changed files with 101 additions and 79 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@
@repository={{@repository}}
@courseStage={{@courseStage}}
@isComplete={{this.readInstructionsStepIsComplete}}
@shouldRecommendLanguageGuide={{@shouldRecommendLanguageGuide}}
/>
{{else if (eq stepList.expandedStep.id "implement-solution")}}
<CoursePage::CourseStageStep::SecondStageInstructionsCard::ImplementSolutionStep
@repository={{@repository}}
@courseStage={{@courseStage}}
@isComplete={{this.implementSolutionStepIsComplete}}
@shouldRecommendLanguageGuide={{@shouldRecommendLanguageGuide}}
/>
{{else if (eq stepList.expandedStep.id "run-tests")}}
<CoursePage::CourseStageStep::SecondStageInstructionsCard::RunTestsStep
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ interface Signature {
Args: {
repository: RepositoryModel;
courseStage: CourseStageModel;
shouldRecommendLanguageGuide: boolean;
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,16 @@
Head over to your editor / IDE and implement your solution.
</p>
<p>
If you want a quick look at what functions to use or how to structure your code, we recommend looking at
<LinkTo @route="course.stage.code-examples">Code Examples</LinkTo>.
{{#if @shouldRecommendLanguageGuide}}
If you want a quick look at what functions to use or how to structure your code, we recommend looking at
<LinkTo @route="course.stage.code-examples">Code Examples</LinkTo>
tab or the
<a href="#language-guide-card">{{@repository.language.name}} Guide</a>
card.
{{else}}
If you want a quick look at what functions to use or how to structure your code, we recommend looking at
<LinkTo @route="course.stage.code-examples">Code Examples</LinkTo>
tab.
{{/if}}
</p>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ interface Signature {
repository: RepositoryModel;
courseStage: CourseStageModel;
isComplete: boolean;
shouldRecommendLanguageGuide: boolean;
};
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<div class="prose dark:prose-invert prose-compact">
<p>
The
<a href="#your-task-card">"Your Task"</a>
<a href="#your-task-card">Your Task</a>
card below contains a description of what you need to implement to pass tests.
</p>
<p>
Expand All @@ -14,6 +14,15 @@
tab, which contains code examples from other users.
</li>

{{#if @shouldRecommendLanguageGuide}}
<li>
The
<a href="#language-guide-card">{{@repository.language.name}} Guide</a>
card, which contains
{{@repository.language.name}}-specific instructions for this stage.
</li>
{{/if}}

{{! Let's limit to 2 suggestions for now so that we don't overwhelm the user.}}
{{#if (gt @courseStage.screencasts.length 0)}}
<li>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ interface Signature {
repository: RepositoryModel;
courseStage: CourseStageModel;
isComplete: boolean;
shouldRecommendLanguageGuide: boolean;
};
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,45 +1,41 @@
<div {{did-update this.loadLanguageGuides @courseStage}} {{did-insert this.loadLanguageGuides}}>
{{#if this.languageGuide}}
<CoursePage::InstructionsCard
@contentIdentifier={{@courseStage.id}}
@isCollapsedByDefault={{true}}
@onExpand={{this.handleExpand}}
id="language-guide-card"
data-test-language-guide-card
...attributes
>
<:header>
<div class="flex items-center justify-between border-b dark:border-white/5 pb-2 mb-5 w-full">
<div class="flex items-center gap-x-3">
<h2 class="font-semibold text-lg text-gray-700 dark:text-gray-200 flex items-center">
{{@language.name}}&nbsp;Guide
</h2>
<CoursePage::InstructionsCard
@contentIdentifier={{@languageGuide.id}}
@isCollapsedByDefault={{true}}
@onExpand={{this.handleExpand}}
id="language-guide-card"
data-test-language-guide-card
...attributes
>
<:header>
<div class="flex items-center justify-between border-b dark:border-white/5 pb-2 mb-5 w-full">
<div class="flex items-center gap-x-3">
<h2 class="font-semibold text-lg text-gray-700 dark:text-gray-200 flex items-center">
{{@languageGuide.language.name}}&nbsp;Guide
</h2>

<Pill @color="green" class="text-xs">
BETA
<EmberTooltip @text="This is a beta feature, please send us feedback!" @side="top" />
</Pill>
</div>
<Pill @color="green" class="text-xs">
BETA
<EmberTooltip @text="This is a beta feature, please send us feedback!" @side="top" />
</Pill>
</div>

<FeedbackButton
@source="course_stage_language_guide"
@sourceMetadata={{hash language_slug=@language.slug}}
class="inline-flex"
@dropdownPosition="right"
data-test-feedback-button
>
<TertiaryButton @size="small">
Share Feedback
</TertiaryButton>
</FeedbackButton>
</div>
</:header>
<FeedbackButton
@source="course_stage_language_guide"
@sourceMetadata={{hash language_slug=@languageGuide.language.slug}}
class="inline-flex"
@dropdownPosition="right"
data-test-feedback-button
>
<TertiaryButton @size="small">
Share Feedback
</TertiaryButton>
</FeedbackButton>
</div>
</:header>

<:content>
<div class="prose dark:prose-invert has-prism-highlighting" {{highlight-code-blocks this.languageGuide.markdownForBeginner}}>
{{markdown-to-html this.languageGuide.markdownForBeginner}}
</div>
</:content>
</CoursePage::InstructionsCard>
{{/if}}
</div>
<:content>
<div class="prose dark:prose-invert has-prism-highlighting" {{highlight-code-blocks @languageGuide.markdownForBeginner}}>
{{markdown-to-html @languageGuide.markdownForBeginner}}
</div>
</:content>
</CoursePage::InstructionsCard>
Original file line number Diff line number Diff line change
@@ -1,45 +1,24 @@
import Component from '@glimmer/component';
import CourseStageModel from 'codecrafters-frontend/models/course-stage';
import LanguageModel from 'codecrafters-frontend/models/language';
import Store from '@ember-data/store';
import { action } from '@ember/object';
import { inject as service } from '@ember/service';
import { task } from 'ember-concurrency';
import type CourseStageLanguageGuideModel from 'codecrafters-frontend/models/course-stage-language-guide';

interface Signature {
Element: HTMLDivElement;

Args: {
courseStage: CourseStageModel;
language?: LanguageModel;
languageGuide: CourseStageLanguageGuideModel;
};
}

export default class SimpleLanguageGuideCardComponent extends Component<Signature> {
@service declare store: Store;

get languageGuide() {
return this.args.courseStage.languageGuides.findBy('language', this.args.language);
}

@action
handleExpand(): void {
if (this.languageGuide) {
this.languageGuide.createView();
}
}

@action
loadLanguageGuides(): void {
this.loadLanguageGuidesTask.perform();
this.args.languageGuide.createView();
}

loadLanguageGuidesTask = task({ keepLatest: true }, async (): Promise<void> => {
await this.store.query('course-stage-language-guide', {
course_stage_id: this.args.courseStage.id,
include: 'course-stage,language',
});
});
}

declare module '@glint/environment-ember-loose/registry' {
Expand Down
21 changes: 20 additions & 1 deletion app/controllers/course/stage/instructions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@ import type CourseStageStep from 'codecrafters-frontend/utils/course-page-step-l
import { action } from '@ember/object';
import type RouterService from '@ember/routing/router-service';
import { next } from '@ember/runloop';
import { task } from 'ember-concurrency';
import type Store from '@ember-data/store';

export default class CourseStageInstructionsController extends Controller {
@service declare authenticator: AuthenticatorService;
@service declare coursePageState: CoursePageStateService;
@service declare featureFlags: FeatureFlagsService;
@service declare router: RouterService;
@service declare store: Store;

@tracked commentListIsFilteredByLanguage = true;

Expand All @@ -38,6 +41,10 @@ export default class CourseStageInstructionsController extends Controller {
return this.model.activeRepository.currentStage === this.model.courseStage;
}

get languageGuide() {
return this.model.courseStage.languageGuides.findBy('language', this.model.activeRepository.language);
}

get prerequisiteInstructionsMarkdown() {
return this.model.courseStage.prerequisiteInstructionsMarkdownFor(this.model.activeRepository);
}
Expand All @@ -47,7 +54,7 @@ export default class CourseStageInstructionsController extends Controller {
}

get shouldShowLanguageGuide() {
return !this.model.courseStage.isFirst && (this.featureFlags.canSeeLanguageGuidesForStage2 || this.authenticator.currentUser?.isStaff);
return !this.model.courseStage.isFirst && !!this.languageGuide && this.featureFlags.canSeeLanguageGuidesForStage2;
}

get shouldShowPrerequisites() {
Expand Down Expand Up @@ -109,4 +116,16 @@ export default class CourseStageInstructionsController extends Controller {
handleTestRunnerCardExpandedOnFirstStage() {
document.getElementById('first-stage-tutorial-card')?.scrollIntoView({ behavior: 'smooth' });
}

@action
loadLanguageGuides(): void {
this.loadLanguageGuidesTask.perform();
}

loadLanguageGuidesTask = task({ keepLatest: true }, async (): Promise<void> => {
await this.store.query('course-stage-language-guide', {
course_stage_id: this.model.courseStage.id,
include: 'course-stage,language',
});
});
}
16 changes: 10 additions & 6 deletions app/templates/course/stage/instructions.hbs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
<CoursePage::PreviousStepsIncompleteOverlay @currentStep={{this.currentStep}}>
<CoursePage::PreviousStepsIncompleteOverlay
@currentStep={{this.currentStep}}
{{did-update this.loadLanguageGuides @model.courseStage}}
{{did-insert this.loadLanguageGuides}}
>
<div class="pt-6 pb-32 px-3 md:px-6 lg:px-10" {{did-update this.handleDidUpdateTestsStatus this.currentStep.testsStatus}}>
{{#if this.shouldShowUpgradePrompt}}
<CoursePage::CourseStageStep::UpgradePrompt @featureSlugToHighlight="content" class="mb-6" />
Expand Down Expand Up @@ -36,6 +40,7 @@
<CoursePage::CourseStageStep::SecondStageInstructionsCard
@repository={{@model.activeRepository}}
@courseStage={{@model.courseStage}}
@shouldRecommendLanguageGuide={{this.shouldShowLanguageGuide}}
class="mb-6"
/>
{{/if}}
Expand Down Expand Up @@ -81,11 +86,10 @@
<CoursePage::CourseStageStep::YourTaskCard @repository={{@model.activeRepository}} @courseStage={{@model.courseStage}} />

{{#if this.shouldShowLanguageGuide}}
<CoursePage::CourseStageStep::SimpleLanguageGuideCard
@courseStage={{@model.courseStage}}
@language={{@model.activeRepository.language}}
class="mt-6"
/>
{{! Extra if condition convinces typescript that languageGuide isn't null }}
{{#if this.languageGuide}}
<CoursePage::CourseStageStep::SimpleLanguageGuideCard @languageGuide={{this.languageGuide}} class="mt-6" />
{{/if}}
{{/if}}

<div data-percy-hints-section>
Expand Down
2 changes: 1 addition & 1 deletion tests/acceptance/course-page/attempt-course-stage-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ module('Acceptance | course-page | attempt-course-stage', function (hooks) {
'fetch repositories (course page)',
'fetch leaderboard entries (course page)',
'fetch hints (course page)',
// 'fetch language guide (course page)',
'fetch language guide (course page)',
].length,
);

Expand Down
2 changes: 1 addition & 1 deletion tests/acceptance/course-page/resume-course-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ module('Acceptance | course-page | resume-course-test', function (hooks) {
'fetch repositories (course page)',
'fetch leaderboard entries (course page)',
'fetch hints (course page)',
// 'fetch language guide (course page)',
'fetch language guide (course page)',
].length,
);
});
Expand Down
1 change: 1 addition & 0 deletions tests/acceptance/course-page/switch-repository-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ module('Acceptance | course-page | switch-repository', function (hooks) {
'fetch repositories (course page)',
'fetch leaderboard entries (course page)',
'fetch hints (course page)',
'fetch language guides (course page)',
].length;

assert.strictEqual(coursePage.repositoryDropdown.activeRepositoryName, goRepository.name, 'repository with last push should be active');
Expand Down
2 changes: 1 addition & 1 deletion tests/acceptance/course-page/try-other-language-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ module('Acceptance | course-page | try-other-language', function (hooks) {
'fetch repositories (course page)',
'fetch leaderboard entries (course page)',
'fetch hints (course page)',
// 'fetch language guide (course page)',
'fetch language guides (course page)',
].length;

await catalogPage.visit();
Expand Down

0 comments on commit 6475112

Please sign in to comment.