Skip to content

Commit

Permalink
Merge branch 'allow-challenge-deprecation-language-card' into allow-c…
Browse files Browse the repository at this point in the history
…hallenge-deprecation-profile
  • Loading branch information
libmartinito committed Jun 10, 2024
2 parents d0c0a0f + 90cd6d0 commit 4999a66
Show file tree
Hide file tree
Showing 9 changed files with 168 additions and 85 deletions.
148 changes: 75 additions & 73 deletions app/components/course-card.hbs
Original file line number Diff line number Diff line change
@@ -1,87 +1,89 @@
{{! template-lint-disable no-invalid-interactive }}
<LinkTo
class="group bg-white p-5 rounded-md shadow hover:shadow-md transition-all cursor-pointer flex flex-col justify-between border relative"
@route={{this.linkToRoute.name}}
@model={{this.linkToRoute.model}}
@query={{this.linkToRoute.query}}
data-test-course-card={{not this.isSkeleton}}
>
{{! Logo }}
<div class="w-8 transform scale-100 group-hover:scale-105 flex-shrink-0 transition-all absolute top-5 right-5">
{{#if this.isSkeleton}}
<div class="bg-gray-100 w-8 h-8 rounded-full" />
{{else}}
<CourseLogo @course={{@course}} />
{{/if}}
</div>

{{! Text }}
<div class="mb-6">
<div class="flex items-center mb-3 flex-wrap gap-y-2 pr-10">
<div class="text-lg font-semibold text-gray-600 mr-2" data-test-course-name>
{{#if this.isSkeleton}}
<span class="inline-block bg-gray-100 rounded">{{#each (repeat 30)}}&nbsp;{{/each}}</span>
{{else}}
<span>{{@course.name}}</span>
{{/if}}
</div>
</div>

<div class="text-sm leading-relaxed text-gray-500 pr-10" data-test-course-description>
{{#if this.shouldShowCourseCard}}
{{! template-lint-disable no-invalid-interactive }}
<LinkTo
class="group bg-white p-5 rounded-md shadow hover:shadow-md transition-all cursor-pointer flex flex-col justify-between border relative"
@route={{this.linkToRoute.name}}
@model={{this.linkToRoute.model}}
@query={{this.linkToRoute.query}}
data-test-course-card={{not this.isSkeleton}}
>
{{! Logo }}
<div class="w-8 transform scale-100 group-hover:scale-105 flex-shrink-0 transition-all absolute top-5 right-5">
{{#if this.isSkeleton}}
<div>
<div class="relative inline-block w-full">{{#each (repeat 15)}}&nbsp;{{/each}}
<div class="absolute left-0 right-0 top-[2px] bottom-[2px] bg-gray-100 rounded"></div>
</div>
<div class="relative inline-block w-full">{{#each (repeat 15)}}&nbsp;{{/each}}
<div class="absolute left-0 right-0 top-[2px] bottom-[2px] bg-gray-100 rounded"></div>
</div>
</div>
<div class="bg-gray-100 w-8 h-8 rounded-full" />
{{else}}
<span>{{@course.shortDescription}}</span>
<CourseLogo @course={{@course}} />
{{/if}}
</div>
</div>

{{! Footer }}
<div class="flex items-center justify-between">
<div class="flex items-center gap-3">
{{#if this.isSkeleton}}
<div class="bg-gray-100 rounded h-4 w-24"></div>
{{else}}
{{#if this.lastUsedRepository}}
<CourseCard::ProgressBar @course={{@course}} @lastUsedRepository={{this.lastUsedRepository}} class="flex-shrink-0" />
{{else}}
{{#if @course.releaseStatusIsAlpha}}
<div class="text-xs text-gray-400 font-semibold border border-gray-300 rounded px-1 py-0.25 mr-3" data-test-course-alpha-label>
ALPHA
</div>
{{else if @course.releaseStatusIsBeta}}
<BetaCourseLabel class="mr-3" />
{{else if (and @course.isFree (not this.currentUser.canAccessMembershipBenefits))}}
<FreeCourseLabel @course={{@course}} />
{{! Text }}
<div class="mb-6">
<div class="flex items-center mb-3 flex-wrap gap-y-2 pr-10">
<div class="text-lg font-semibold text-gray-600 mr-2" data-test-course-name>
{{#if this.isSkeleton}}
<span class="inline-block bg-gray-100 rounded">{{#each (repeat 30)}}&nbsp;{{/each}}</span>
{{else}}
<div class="flex items-center">
{{svg-jar "academic-cap" class="w-4 mr-1 fill-current text-gray-300"}}
<span class="text-xs text-gray-400">{{@course.stages.length}} stages</span>
</div>
<span>{{@course.name}}</span>
{{/if}}
</div>
</div>

<div class="text-sm leading-relaxed text-gray-500 pr-10" data-test-course-description>
{{#if this.isSkeleton}}
<div>
<div class="relative inline-block w-full">{{#each (repeat 15)}}&nbsp;{{/each}}
<div class="absolute left-0 right-0 top-[2px] bottom-[2px] bg-gray-100 rounded"></div>
</div>
<div class="relative inline-block w-full">{{#each (repeat 15)}}&nbsp;{{/each}}
<div class="absolute left-0 right-0 top-[2px] bottom-[2px] bg-gray-100 rounded"></div>
</div>
</div>
{{else}}
<span>{{@course.shortDescription}}</span>
{{/if}}
{{/if}}
</div>
</div>

<div class="flex items-center">
<span class="font-bold text-teal-500 text-xs mr-2 opacity-0 group-hover:opacity-100 transition-opacity" data-test-action-text>
{{#if this.lastUsedRepository.allStagesAreComplete}}
Start Again
{{else if this.lastUsedRepository}}
Resume
{{! Footer }}
<div class="flex items-center justify-between">
<div class="flex items-center gap-3">
{{#if this.isSkeleton}}
<div class="bg-gray-100 rounded h-4 w-24"></div>
{{else}}
Start
{{#if this.lastUsedRepository}}
<CourseCard::ProgressBar @course={{@course}} @lastUsedRepository={{this.lastUsedRepository}} class="flex-shrink-0" />
{{else}}
{{#if @course.releaseStatusIsAlpha}}
<div class="text-xs text-gray-400 font-semibold border border-gray-300 rounded px-1 py-0.25 mr-3" data-test-course-alpha-label>
ALPHA
</div>
{{else if @course.releaseStatusIsBeta}}
<BetaCourseLabel class="mr-3" />
{{else if (and @course.isFree (not this.currentUser.canAccessMembershipBenefits))}}
<FreeCourseLabel @course={{@course}} />
{{else}}
<div class="flex items-center">
{{svg-jar "academic-cap" class="w-4 mr-1 fill-current text-gray-300"}}
<span class="text-xs text-gray-400">{{@course.stages.length}} stages</span>
</div>
{{/if}}
{{/if}}
{{/if}}
</span>
</div>

{{svg-jar "arrow-right" class="w-4 fill-current text-gray-300 group-hover:text-teal-500 transition-colors"}}
<div class="flex items-center">
<span class="font-bold text-teal-500 text-xs mr-2 opacity-0 group-hover:opacity-100 transition-opacity" data-test-action-text>
{{#if this.lastUsedRepository.allStagesAreComplete}}
Start Again
{{else if this.lastUsedRepository}}
Resume
{{else}}
Start
{{/if}}
</span>

{{svg-jar "arrow-right" class="w-4 fill-current text-gray-300 group-hover:text-teal-500 transition-colors"}}
</div>
</div>
</div>
</LinkTo>
</LinkTo>
{{/if}}
12 changes: 12 additions & 0 deletions app/components/course-card.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,16 @@ export default class CourseCardComponent extends Component {
};
}
}

get shouldShowCourseCard() {
if (this.lastUsedRepository) {
return true;
}

if (this.args.course?.releaseStatusIsDeprecated) {
return false;
}

return true;
}
}
1 change: 1 addition & 0 deletions app/components/tracks-page/track-card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export default class TrackCardComponent extends Component<Signature> {
return this.store
.peekAll('course')
.rejectBy('releaseStatusIsAlpha')
.rejectBy('releaseStatusIsDeprecated')
.filter((course) => course.betaOrLiveLanguages.includes(this.args.language))
.mapBy('stages.length')
.reduce((a, b) => a + b, 0);
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/track.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export default class TrackController extends Controller {
return this.model.courses;
}

return this.model.courses.rejectBy('releaseStatusIsAlpha');
return this.model.courses.rejectBy('releaseStatusIsAlpha').rejectBy('releaseStatusIsDeprecated');
}

get sortedCourses() {
Expand Down
3 changes: 2 additions & 1 deletion app/models/course-language-configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ export default class CourseLanguageConfigurationModel extends Model {
@equal('releaseStatus', 'alpha') declare releaseStatusIsAlpha: boolean;
@equal('releaseStatus', 'beta') declare releaseStatusIsBeta: boolean;
@equal('releaseStatus', 'live') declare releaseStatusIsLive: boolean;
@equal('releaseStatus', 'deprecated') declare releaseStatusIsDeprecated: boolean;

isAvailableForUser(user: UserModel) {
if (this.releaseStatusIsAlpha) {
if (this.releaseStatusIsAlpha || this.releaseStatusIsDeprecated) {
return user.isStaff || this.alphaTesterUsernames.includes(user.username) || user.isCourseAuthor(this.course);
} else {
return true;
Expand Down
3 changes: 2 additions & 1 deletion app/models/course.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ export default class CourseModel extends Model {
@equal('releaseStatus', 'alpha') declare releaseStatusIsAlpha: boolean;
@equal('releaseStatus', 'beta') declare releaseStatusIsBeta: boolean;
@equal('releaseStatus', 'live') declare releaseStatusIsLive: boolean;
@equal('releaseStatus', 'deprecated') declare releaseStatusIsDeprecated: boolean;

@service declare date: DateService;

Expand All @@ -79,7 +80,7 @@ export default class CourseModel extends Model {
}

get betaOrLiveLanguages() {
return this.languageConfigurations.rejectBy('releaseStatusIsAlpha').mapBy('language');
return this.languageConfigurations.rejectBy('releaseStatusIsAlpha').rejectBy('releaseStatusIsDeprecated').mapBy('language');
}

get concepts() {
Expand Down
20 changes: 20 additions & 0 deletions tests/acceptance/track-page/view-track-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,4 +106,24 @@ module('Acceptance | view-track', function (hooks) {
await trackPage.visit({ track_slug: 'javascript' });
assert.notOk(trackPage.cards.mapBy('title').includes('Build your own React'));
});

test('it does not show a challenge if it is deprecated', async function (assert) {
testScenario(this.server);
signIn(this.owner, this.server);
createTrackLeaderboardEntries(this.server, 'go', 'redis');

let currentUser = this.server.schema.users.first();
let go = this.server.schema.languages.findBy({ slug: 'go' });
let docker = this.server.schema.courses.findBy({ slug: 'docker' });
docker.update({ releaseStatus: 'deprecated' });

this.server.create('repository', 'withFirstStageCompleted', {
course: docker,
language: go,
user: currentUser,
});

await visit('/tracks/go');
assert.notOk(trackPage.cards.mapBy('title').includes('Build your own Docker'));
});
});
43 changes: 38 additions & 5 deletions tests/acceptance/view-courses-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ module('Acceptance | view-courses', function (hooks) {
});

await catalogPage.visit();
assert.strictEqual(catalogPage.courseCards.length, 5, 'expected 4 course cards to be present');
assert.strictEqual(catalogPage.courseCards.length, 5, 'expected 5 course cards to be present');

assert.strictEqual(catalogPage.courseCards[0].actionText, 'Resume');
assert.strictEqual(catalogPage.courseCards[1].actionText, 'Start');
Expand Down Expand Up @@ -118,7 +118,7 @@ module('Acceptance | view-courses', function (hooks) {
});

await catalogPage.visit();
assert.strictEqual(catalogPage.courseCards.length, 5, 'expected 4 course cards to be present');
assert.strictEqual(catalogPage.courseCards.length, 5, 'expected 5 course cards to be present');

await percySnapshot('Courses Page - Courses in progress');

Expand Down Expand Up @@ -223,7 +223,7 @@ module('Acceptance | view-courses', function (hooks) {

assert.ok(find('[data-test-loading]'), 'loader should be present');
await settled();
assert.strictEqual(catalogPage.courseCards.length, 5, 'expected 4 course cards to be present');
assert.strictEqual(catalogPage.courseCards.length, 5, 'expected 5 course cards to be present');
});

test('second time visit with local repository data has no loading page', async function (assert) {
Expand Down Expand Up @@ -253,7 +253,7 @@ module('Acceptance | view-courses', function (hooks) {
});

assert.notOk(loadingIndicatorWasRendered, 'loading indicator was not rendered');
assert.strictEqual(catalogPage.courseCards.length, 5, 'expected 4 course cards to be present');
assert.strictEqual(catalogPage.courseCards.length, 5, 'expected 5 course cards to be present');
});

test('second time visit without local repository data has no loading page ', async function (assert) {
Expand All @@ -275,6 +275,39 @@ module('Acceptance | view-courses', function (hooks) {
});

assert.notOk(loadingIndicatorWasRendered, 'loading indicator was not rendered');
assert.strictEqual(catalogPage.courseCards.length, 5, 'expected 4 course cards to be present');
assert.strictEqual(catalogPage.courseCards.length, 5, 'expected 5 course cards to be present');
});

test('it should show deprecated courses if user already has progress', async function (assert) {
testScenario(this.server);
signIn(this.owner, this.server);

let currentUser = this.server.schema.users.first();
let python = this.server.schema.languages.findBy({ name: 'Python' });
let docker = this.server.schema.courses.findBy({ slug: 'docker' });
docker.update({ releaseStatus: 'deprecated' });

this.server.create('repository', {
course: docker,
language: python,
user: currentUser,
});

await catalogPage.visit();

assert.strictEqual(catalogPage.courseCards[0].name, 'Build your own Docker');
});

test('it should not show deprecated courses if user has no progress', async function (assert) {
testScenario(this.server);
signIn(this.owner, this.server);

let docker = this.server.schema.courses.findBy({ slug: 'docker' });
docker.update({ releaseStatus: 'deprecated' });

await catalogPage.visit();

assert.strictEqual(catalogPage.courseCards.length, 4, 'expected 4 course cards to be present');
assert.notOk(catalogPage.courseCards.mapBy('name').includes('Build your own Docker'), 'docker should not be included');
});
});
21 changes: 17 additions & 4 deletions tests/acceptance/view-tracks-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,14 @@ module('Acceptance | view-tracks', function (hooks) {
let redis = this.server.schema.courses.findBy({ slug: 'redis' });

this.server.create('repository', 'withFirstStageCompleted', {
createdAt: new Date('2022-01-01'),
createdAt: new Date('1922-01-01'),
course: redis,
language: go,
user: currentUser,
});

this.server.create('repository', 'withFirstStageCompleted', {
createdAt: new Date('2022-02-02'),
createdAt: new Date('1922-02-02'),
course: redis,
language: python,
user: currentUser,
Expand Down Expand Up @@ -99,14 +99,14 @@ module('Acceptance | view-tracks', function (hooks) {
dummy.update({ releaseStatus: 'live' });

this.server.create('repository', 'withAllStagesCompleted', {
createdAt: new Date('2022-01-01'),
createdAt: new Date('1922-01-01'),
course: dummy,
language: go,
user: currentUser,
});

this.server.create('repository', 'withAllStagesCompleted', {
createdAt: new Date('2022-02-02'),
createdAt: new Date('1922-02-02'),
course: sqlite,
language: go,
user: currentUser,
Expand Down Expand Up @@ -201,4 +201,17 @@ module('Acceptance | view-tracks', function (hooks) {
assert.notOk(loadingIndicatorWasRendered, 'loading indicator was not rendered');
assert.strictEqual(catalogPage.trackCards.length, 19, 'expected 19 track cards to be present');
});

test('deprecated challenges do not count towards the number of stages on a language card', async function (assert) {
testScenario(this.server);
signIn(this.owner, this.server);

const docker = this.server.schema.courses.findBy({ slug: 'docker' });
docker.update({ releaseStatus: 'deprecated' });

await catalogPage.visit();

assert.ok(catalogPage.trackCards[0].hasPopularLabel, 'go should have popular label');
assert.ok(catalogPage.trackCards[0].text.includes('75 stages'), 'number of stages should not include deprecated stages count');
});
});

0 comments on commit 4999a66

Please sign in to comment.