Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"react-router-dom": "5.3.0",
"react-share": "4.4.1",
"redux": "4.1.2",
"lodash": "4.17.21",
"regenerator-runtime": "0.13.11",
"reselect": "4.1.7",
"truncate-html": "1.0.4",
Expand Down
53 changes: 53 additions & 0 deletions src/course-home/athena-tab/AthenaTab.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import {
Card, Button,
} from '@edx/paragon';

const colorVariants = ['brand', 'outline-brand', 'primary', 'outline-primary', 'tertiary'];

const CardComponent = () => {
const randomIndex = Math.floor(Math.random() * colorVariants.length);
const variant = colorVariants[randomIndex];

return (
<Card className="col col-3 mx-5 my-5">
<Card.ImageCap
src="fakeURL"
fallbackSrc="https://picsum.photos/360/200/"
srcAlt="Card image"
logoSrc="fakeURL"
fallbackLogoSrc="https://www.edx.org/images/logos/edx-logo-elm.svg"
logoAlt="Card logo"
/>
<Card.Header title="Title" subtitle="Subtitle" />
<Card.Section title="Section title">
This is a card section. It can contain anything but usually text, a list, or list of links.
Multiple sections have a card divider between them.
</Card.Section>
<Card.Footer>
<Button variant={variant}>Action 1</Button>
</Card.Footer>
</Card>
);
};

const generateRandomId = () => {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let id = '';
for (let i = 0; i < 10; i++) {
id += chars.charAt(Math.floor(Math.random() * chars.length));
}
return id;
};

const data = Array.from({ length: 10 }).map(() => ({ id: generateRandomId() }));

const AthenaTab = () => (
<>
<div className="row">
{data.map(({ id }) => <CardComponent key={id} />)}
</div>

</>
);

export default AthenaTab;
15 changes: 14 additions & 1 deletion src/course-home/data/thunks.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { logError } from '@edx/frontend-platform/logging';
import { camelCaseObject } from '@edx/frontend-platform';
import { cloneDeep } from 'lodash';
import {
executePostFromPostEvent,
getCourseHomeCourseMetadata,
Expand Down Expand Up @@ -35,11 +36,23 @@ export function fetchTab(courseId, tab, getTabData, targetUserId) {
dispatch(fetchTabRequest({ courseId }));
try {
const courseHomeCourseMetadata = await getCourseHomeCourseMetadata(courseId, 'outline');
const formatCourseHomeCourseMetadata = cloneDeep(courseHomeCourseMetadata);
const { tabs: [homeTab] } = formatCourseHomeCourseMetadata;
const { url } = homeTab;
const newTab = {
slug: 'newtab',
title: 'New Tab',
url: url.replace('/home', '/newtab'),
};

const { tabs: currentTabs } = formatCourseHomeCourseMetadata;

formatCourseHomeCourseMetadata.tabs = [...currentTabs, newTab];
dispatch(addModel({
modelType: 'courseHomeMeta',
model: {
id: courseId,
...courseHomeCourseMetadata,
...formatCourseHomeCourseMetadata,
},
}));
const tabDataResult = getTabData && await getTabData(courseId, targetUserId);
Expand Down
2 changes: 1 addition & 1 deletion src/course-home/outline-tab/Section.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ const Section = ({
return (
<li>
<Collapsible
className="mb-2"
className="mb-2 bg-dark-100"
styling="card-lg"
title={sectionTitle}
open={open}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ const StartOrResumeCourseCard = ({ intl }) => {
title={hasVisitedCourse ? intl.formatMessage(messages.resumeBlurb) : intl.formatMessage(messages.startBlurb)}
actions={(
<Button
variant="brand"
variant="primary"
block
href={resumeCourseUrl}
onClick={() => logResumeCourseClick()}
Expand Down
15 changes: 14 additions & 1 deletion src/courseware/data/thunks.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { logError, logInfo } from '@edx/frontend-platform/logging';
import { cloneDeep } from 'lodash';
import { getCourseHomeCourseMetadata } from '../../course-home/data/api';
import {
addModel, addModelsMap, updateModel, updateModels, updateModelsMap,
Expand Down Expand Up @@ -42,11 +43,23 @@ export function fetchCourse(courseId) {
}

if (courseHomeMetadataResult.status === 'fulfilled') {
const formatCourseHomeCourseMetadata = cloneDeep(courseHomeMetadataResult.value);
const { tabs: [homeTab] } = formatCourseHomeCourseMetadata;
const { url } = homeTab;
const newTab = {
slug: 'newtab',
title: 'New Tab',
url: url.replace('/home', '/newtab'),
};

const { tabs: currentTabs } = formatCourseHomeCourseMetadata;
formatCourseHomeCourseMetadata.tabs = [...currentTabs, newTab];

dispatch(addModel({
modelType: 'courseHomeMeta',
model: {
id: courseId,
...courseHomeMetadataResult.value,
...formatCourseHomeCourseMetadata,
},
}));
}
Expand Down
6 changes: 6 additions & 0 deletions src/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { CourseExit } from './courseware/course/course-exit';
import CoursewareContainer from './courseware';
import CoursewareRedirectLandingPage from './courseware/CoursewareRedirectLandingPage';
import DatesTab from './course-home/dates-tab';
import AthenaTab from './course-home/athena-tab/AthenaTab';
import GoalUnsubscribe from './course-home/goal-unsubscribe';
import ProgressTab from './course-home/progress-tab/ProgressTab';
import { TabContainer } from './tab-page';
Expand All @@ -50,6 +51,11 @@ subscribe(APP_READY, () => {
<PageRoute exact path="/goal-unsubscribe/:token" component={GoalUnsubscribe} />
<PageRoute path="/redirect" component={CoursewareRedirectLandingPage} />
<DecodePageRoute path="/course/:courseId/access-denied" component={CourseAccessErrorPage} />
<DecodePageRoute path="/course/:courseId/newtab">
<TabContainer tab="newtab" fetch={fetchOutlineTab} slice="courseHome">
<AthenaTab />
</TabContainer>
</DecodePageRoute>
<DecodePageRoute path="/course/:courseId/home">
<TabContainer tab="outline" fetch={fetchOutlineTab} slice="courseHome">
<OutlineTab />
Expand Down
2 changes: 1 addition & 1 deletion src/instructor-toolbar/InstructorToolbar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ const InstructorToolbar = (props) => {

return (!didMount ? null : (
<div data-testid="instructor-toolbar">
<div className="bg-primary text-white">
<div className="bg-dark text-white">
<div className="container-xl py-3 d-md-flex justify-content-end align-items-start">
<div className="align-items-center flex-grow-1 d-md-flex mx-1 my-1">
<MasqueradeWidget courseId={courseId} onError={showMasqueradeError} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ class MasqueradeWidget extends Component {
<div className="row">
<span className="col-auto col-form-label pl-3">View this course as:</span>
<Dropdown className="flex-shrink-1 mx-1">
<Dropdown.Toggle variant="inverse-outline-primary">
<Dropdown.Toggle variant="inverse-outline-brand">
{masquerade}
</Dropdown.Toggle>
<Dropdown.Menu>
Expand Down
Empty file added webpack.dev-tutor.config.js
Empty file.