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

Add SelfPacedProgressTable to My PL LandingPage component #57869

Merged
merged 10 commits into from
Apr 10, 2024
3 changes: 2 additions & 1 deletion apps/i18n/common/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -1936,6 +1936,7 @@
"plLandingTabRPCenter": "My Regional Partner Center",
"plLandingTabWorkshopOrganizerCenter": "My Workshop Organizer Center",
"plLandingTabInstructorCenter": "My Instructor Center",
"plLandingSelfPacedProgressHeading": "Self-Paced Professional Learning Courses",
"plLandingGettingStartedHeading": "Getting started with Professional Learning",
"plLandingGettingStartedSubHeading": "Code.org Professional Learning",
"plLandingGettingStartedDescription": "Help today's students become tomorrow's superheroes with professional learning that meets your needs. We offer different kinds of professional learning to meet your needs.",
Expand All @@ -1946,7 +1947,7 @@
"plLandingStaticPLMidHighDesc": "Our engaging workshops are for new and experienced computer science teachers! In this program, you will explore the curriculum and learning tools, experience the course as a teacher and a learner and collaborate with fellow teachers.",
"plLandingStaticPLMidHighButton": "Learn more about workshops",
"plLandingStaticPLSelfPacedOverline": "Self-paced / Online",
"plLandingStaticPLSelfPacedHeading": "Self Paced Professional Learning",
"plLandingStaticPLSelfPacedHeading": "Self-Paced Professional Learning",
"plLandingStaticPLSelfPacedDesc": "Through reading, viewing videos, completing interactive puzzles, and reflecting on your learning, you will develop your own understanding while preparing to teach computer science in your classroom.",
"plLandingStaticPLSelfPacedButton": "Start professional learning courses",
"plSectionsJoined": "Professional Learning Sections I've Joined",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ import {pegasus} from '@cdo/apps/lib/util/urlHelpers';
import {Heading2} from '@cdo/apps/componentLibrary/typography';
import ProfessionalLearningCourseProgress from './ProfessionalLearningCourseProgress';
import {EnrolledWorkshops} from './EnrolledWorkshops';
import SelfPacedProgressTable from './SelfPacedProgressTable';
import HeaderBannerNoImage from '@cdo/apps/templates/HeaderBannerNoImage';
import TwoColumnActionBlock from '@cdo/apps/templates/studioHomepages/TwoColumnActionBlock';
import ActionBlocksWrapper from '@cdo/apps/templates/studioHomepages/ActionBlocksWrapper';
import style from './landingPage.module.scss';
import './tableStyles.scss';
import Tabs from '@cdo/apps/componentLibrary/tabs';

const getAvailableTabs = () => {
Expand Down Expand Up @@ -73,6 +75,7 @@ export default function LandingPage({
text: i18n.plLandingGettingStartedButton(),
},
]}
marginBottom={'0'}
Copy link
Contributor Author

@kelbyhawn kelbyhawn Apr 9, 2024

Choose a reason for hiding this comment

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

Added this to remove the bottom margin from the Getting Started TwoColumnActionBlock component used on this page for new teachers.

/>
);

Expand All @@ -93,6 +96,10 @@ export default function LandingPage({
/>
);

const RenderSelfPacedProgressTable = () => {
return <SelfPacedProgressTable plCoursesStarted={plCoursesStarted} />;
};

const RenderStaticRecommendedPL = () => {
const actionBlocks = [
{
Expand Down Expand Up @@ -151,6 +158,12 @@ export default function LandingPage({
{showGettingStartedBanner && RenderGettingStartedBanner()}
{lastWorkshopSurveyUrl && RenderLastWorkshopSurveyBanner()}
<EnrolledWorkshops />
{plCoursesStarted?.length >= 1 && (
<section>
<Heading2>{i18n.plLandingSelfPacedProgressHeading()}</Heading2>
{RenderSelfPacedProgressTable()}
</section>
)}
{deeperLearningCourseData?.length >= 1 && (
<div>
<Heading2>Online Professional Learning Courses</Heading2>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const CourseRow = ({
{percent_completed}% {i18n.selfPacedPlCompleted()}
</BodyThreeText>
{/* Progress bar */}
<div className={styles.progressBar}>
<div className={styles.progressBar} data-testid="progress-bar">
Copy link
Contributor

Choose a reason for hiding this comment

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

Just a thought for future/followup work- it would be super cool if this had some sore of accessible readout (i.e. label) of progress! I know that isn't a focus for this page but always something to keep in mind in case it's easy to add.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I thought about adding something like that! But it says "(percent)% Completed" right above it so I thought it would be redundant 😅

Copy link
Contributor

Choose a reason for hiding this comment

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

oo does a screen reader read that out loud? I'm not sure if this is what you're referring to, but there is a way to add an aria-label that doesn't show, but a screen reader would still read

Copy link
Contributor Author

@kelbyhawn kelbyhawn Apr 10, 2024

Choose a reason for hiding this comment

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

Oh it doesn't! VoiceOver on Mac only reads links and buttons. I checked this on the Teacher homepage, and it does the same thing there too (only reads links and buttons). I'll add a ticket for this in the next AccHack.

Edit: made a ticket: https://codedotorg.atlassian.net/browse/A11Y-281

Copy link
Contributor

Choose a reason for hiding this comment

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

Okay- it should be as simple as wrapping the text in a . But yes- thanks for making a ticket!

Copy link
Contributor Author

@kelbyhawn kelbyhawn Apr 10, 2024

Choose a reason for hiding this comment

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

Neither the paragraph or progress bar is a link, so it'd need to be something else. Misread that to say "wrap in an a (link tag)" 🤦‍♀️ I'm too scattered today to look into it, but will look tomorrow! This makes me excited for the Deque training, since I assumed screen readers read all the text on a page 🥲

Copy link
Contributor

Choose a reason for hiding this comment

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

Ahh yes okay I'm following! To be clear, folks using screen readers use the tab key to scan through interactive elements (like you mentioned- buttons, links, input fields, etc), but they can also use keys to navigate by header size (and drill down into reading the text directly if they choose). This is a super interesting case because A11y-wise, really we should be treating this div as an image with an alt text. Happy to brainstorm together at some point!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

use keys to navigate by header size (and drill down into reading the text directly if they choose

A ha! That makes sense, thanks for explaining. This is an interesting case…maybe the <figure> and <figcaption> elements would work? (MDN docs)

Let's def brainstorm on this, and thanks for bringing it up!

<span
className={styles.progressBarFill}
style={{width: `${percent_completed}%`}}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,34 +1,11 @@
import React from 'react';
import SelfPacedProgressTable from './SelfPacedProgressTable';
import {selfPacedCourseConstants} from './constants';

export default {
component: SelfPacedProgressTable,
};

const plCoursesStarted = [
{
name: '#',
title: 'Course is in progress',
current_lesson_name: 'Current lesson name',
percent_completed: 10,
finish_url: '',
},
{
name: '#',
title: 'Course is in progress and has unit certificates',
current_lesson_name: 'Current lesson name',
percent_completed: 45,
finish_url: '#',
},
{
name: '#',
title: 'Course is complete',
current_lesson_name: 'Current lesson name',
percent_completed: 100,
finish_url: '#',
},
];

export const Basic = () => {
return <SelfPacedProgressTable plCoursesStarted={plCoursesStarted} />;
return <SelfPacedProgressTable plCoursesStarted={selfPacedCourseConstants} />;
};
23 changes: 23 additions & 0 deletions apps/src/code-studio/pd/professional_learning_landing/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
export const selfPacedCourseConstants = [
{
name: '#',
title: 'Course is in progress',
current_lesson_name: 'Current lesson name',
percent_completed: 10,
finish_url: '',
},
{
name: '#',
title: 'Course is in progress and has unit certificates',
current_lesson_name: 'Current lesson name',
percent_completed: 45,
finish_url: '#',
},
{
name: '#',
title: 'Course is complete',
current_lesson_name: 'Current lesson name',
percent_completed: 100,
finish_url: '#',
},
];
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@ main.wrapper {
}

section {
padding: 4rem 1rem 0 1rem !important;
padding: 4rem 0 0 !important;
}

.headerContainer {
background-color: color.$light_gray_50;
padding: 0 1rem;
Copy link
Contributor Author

@kelbyhawn kelbyhawn Apr 9, 2024

Choose a reason for hiding this comment

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

Did a little bit of refactoring here related to this PR since the inline padding was being applied to all the <section>s on the page. Here's a screenshot of the tabs showing to confirm this didn't break, but these will not show up on the page yet!

Screenshot 2024-04-09 at 11 03 02 AM

}

.headerWithoutTabsContainer {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ table.selfPacedProgressTable {
height: 0.5rem;
border-radius: 1rem;
margin-block-start: 0.25rem;
overflow: hidden;
Copy link
Contributor Author

@kelbyhawn kelbyhawn Apr 9, 2024

Choose a reason for hiding this comment

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

This fixes a little UI bug on the progress bar if it gets close to the end:

Before After
Before After

Copy link
Contributor

Choose a reason for hiding this comment

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

That attention to detail🔥


.progressBarFill {
display: block;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,23 @@ import {render, screen} from '@testing-library/react';
import i18n from '@cdo/locale';
import {expect} from '../../../../util/reconfiguredChai';
import LandingPage from '@cdo/apps/code-studio/pd/professional_learning_landing/LandingPage';
import {selfPacedCourseConstants} from '@cdo/apps/code-studio/pd/professional_learning_landing/constants.js';

const DEFAULT_PROPS = {
lastWorkshopSurveyUrl: 'url',
lastWorkshopSurveyCourse: 'CS Fundamentals',
deeperLearningCourseData: [{data: 'oh yeah'}],
currentYearApplicationId: 2024,
workshopsAsParticipant: [{data: 'workshops'}],
plCoursesStarted: [{data: 'courses'}],
plCoursesStarted: selfPacedCourseConstants,
};

describe('LandingPage', () => {
function renderDefault(propOverrides = {}) {
render(<LandingPage {...DEFAULT_PROPS} {...propOverrides} />);
}

it('page shows a getting started banner for a new teacher without an existing application, upcoming workshop, or pl course', () => {
it('page shows a getting started banner for a new teacher without an existing application, upcoming workshop, self-paced courses, or pl course', () => {
renderDefault({
lastWorkshopSurveyUrl: null,
lastWorkshopSurveyCourse: null,
Expand All @@ -30,6 +31,8 @@ describe('LandingPage', () => {
screen.getByText(i18n.plLandingGettingStartedHeading());
expect(screen.queryByText(i18n.plLandingStartSurvey())).to.not.exist;
screen.getByTestId('enrolled-workshops-loader');
expect(screen.queryByText(i18n.plLandingSelfPacedProgressHeading())).to.not
.exist;
expect(screen.queryByText('Online Professional Learning Courses')).to.not
.exist;
screen.getByText(i18n.plLandingStaticPLMidHighHeading());
Expand All @@ -41,6 +44,7 @@ describe('LandingPage', () => {
.exist;
screen.getByText(i18n.plLandingStartSurvey());
screen.getByTestId('enrolled-workshops-loader');
screen.getByText(i18n.plLandingSelfPacedProgressHeading());
screen.getByText('Online Professional Learning Courses');
screen.getByText(i18n.plLandingStaticPLMidHighHeading());
});
Expand All @@ -51,11 +55,12 @@ describe('LandingPage', () => {
.exist;
screen.getByText(i18n.plLandingStartSurvey());
screen.getByTestId('enrolled-workshops-loader');
screen.getByText(i18n.plLandingSelfPacedProgressHeading());
screen.getByText('Online Professional Learning Courses');
screen.getByText(i18n.plLandingStaticPLMidHighHeading());
});

it('page shows upcoming workshops and plc enrollments but no survey banner if no pending survey exists', () => {
it('page shows upcoming workshops, self-paced courses, and plc enrollments but no survey banner if no pending survey exists', () => {
renderDefault({
lastWorkshopSurveyUrl: null,
lastWorkshopSurveyCourse: null,
Expand All @@ -64,7 +69,21 @@ describe('LandingPage', () => {
.exist;
expect(screen.queryByText(i18n.plLandingStartSurvey())).to.not.exist;
screen.getByTestId('enrolled-workshops-loader');
screen.getByText(i18n.plLandingSelfPacedProgressHeading());
screen.getByText('Online Professional Learning Courses');
screen.getByText(i18n.plLandingStaticPLMidHighHeading());
});

it('page shows self-paced progress table if enrolled in self-paced courses', () => {
renderDefault();
screen.getByText(i18n.plLandingSelfPacedProgressHeading());
expect(screen.getAllByTestId('progress-bar').length).to.equal(2);
expect(screen.getByText(i18n.selfPacedPlCompleted()));
expect(
screen.getAllByText(i18n.selfPacedPlContinueCourse()).length
).to.equal(2);
expect(
screen.getAllByText(i18n.selfPacedPlPrintCertificates()).length
).to.equal(2);
});
});