Skip to content
Merged
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
4 changes: 2 additions & 2 deletions .env.development
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
NODE_ENV='development'
PORT=8080
PORT=2000

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I mean, why not?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎈

ACCESS_TOKEN_COOKIE_NAME='edx-jwt-cookie-header-payload'
BASE_URL='localhost:8080'
BASE_URL='localhost:2000'
CREDENTIALS_BASE_URL='http://localhost:18150'
CSRF_TOKEN_API_PATH='/csrf/api/v1/token'
ECOMMERCE_BASE_URL='http://localhost:18130'
Expand Down
12 changes: 0 additions & 12 deletions src/example/ExamplePage.jsx

This file was deleted.

5 changes: 0 additions & 5 deletions src/example/ExamplePage.test.jsx

This file was deleted.

Empty file removed src/example/data/.gitkeep
Empty file.
4 changes: 0 additions & 4 deletions src/example/data/README.rst

This file was deleted.

Empty file removed src/example/index.scss
Empty file.
12 changes: 10 additions & 2 deletions src/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ import { APP_INIT_ERROR, APP_READY, subscribe, initialize } from '@edx/frontend-
import { AppProvider, ErrorPage } from '@edx/frontend-platform/react';
import React from 'react';
import ReactDOM from 'react-dom';
import { Route, Switch, Link } from 'react-router-dom';

import Header, { messages as headerMessages } from '@edx/frontend-component-header';
import Footer, { messages as footerMessages } from '@edx/frontend-component-footer';

import appMessages from './i18n';
import ExamplePage from './example/ExamplePage';
import LearningSequencePage from './learning-sequence/LearningSequencePage';

import './index.scss';
import './assets/favicon.ico';
Expand All @@ -18,7 +19,14 @@ subscribe(APP_READY, () => {
ReactDOM.render(
<AppProvider>
<Header />
<ExamplePage />
<Switch>
<Route

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This route is a temporary helper for developers to help them find a useful URL.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Good thinking

exact
path="/"
render={() => <Link to="/course/course-v1%3AedX%2BDemoX%2BDemo_Course/0">Visit Demo Course</Link>}
/>
<Route path="/course/:courseId/:blockIndex" component={LearningSequencePage} />
</Switch>
<Footer />
</AppProvider>,
document.getElementById('root'),
Expand Down
2 changes: 1 addition & 1 deletion src/index.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
@import '~@edx/paragon/scss/edx/theme.scss';

@import './example/index.scss';
@import './learning-sequence/index';

@import "~@edx/frontend-component-header/dist/index";
@import "~@edx/frontend-component-footer/dist/footer";
116 changes: 116 additions & 0 deletions src/learning-sequence/LearningSequencePage.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import React, { useState, useEffect, useCallback, useRef } from 'react';
import PropTypes from 'prop-types';
import { camelCaseObject, getConfig } from '@edx/frontend-platform';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';

import PageLoading from './PageLoading';

import messages from './messages';

function useApi(apiFunction, {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I intend that this useApi hook - or something like it - could be moved into frontend-platform/react.

format = true, keepDataIfFailed = false, loadedIfFailed = false, refreshParams = [],
}) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(false);
const [loaded, setLoaded] = useState(false);
const [failed, setFailed] = useState(false);
const [error, setError] = useState(null);

useEffect(() => {
setLoading(true);
apiFunction().then((response) => {
const result = format ? camelCaseObject(response.data) : response.data;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nice

setData(result);
setLoaded(true);
setLoading(false);
setError(null);
setFailed(false);
})
.catch((e) => {
if (keepDataIfFailed) {
setData(null);
}
setFailed(true);
setLoading(false);
if (loadedIfFailed) {
setLoaded(true);
}
setError(e);
});
}, refreshParams);

return {
data,
loading,
loaded,
failed,
error,
};
}

function LearningSequencePage(props) {
const iframeRef = useRef(null);

const handleResizeIframe = useCallback(() => {
// TODO: This won't work because of crossdomain issues. Leaving here for reference once we're

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Note this TODO.

// able to have the iFrame content publish resize events through postMessage
console.log('**** Resizing iframe...');
const iframe = iframeRef.current;
const contentHeight = iframe.contentWindow.document.body.scrollHeight;
console.log(`**** Height is: ${contentHeight}`);
iframe.height = contentHeight + 20;
});

const {
data,
loading,
loaded,
} = useApi(
async () => getAuthenticatedHttpClient().get(`${getConfig().LMS_BASE_URL}/api/courses/v1/blocks/?course_id=${props.match.params.courseId}&username=staff&depth=all&block_types_filter=sequential&requested_fields=children`, {}),
{
keepDataIfFailed: false,
refreshParams: [
props.match.params.courseId,
props.match.params.blockIndex,
],
},
);

console.log(data);

if (loading) {
return (
<PageLoading srMessage={props.intl.formatMessage(messages['learn.loading.learning.sequence'])} />
);
}

return (
<main>
<div className="container-fluid">
<h1>Learning Sequence Page</h1>
{loaded && data.blocks ? (
<iframe
title="yus"
ref={iframeRef}
src={Object.values(data.blocks)[parseInt(props.match.params.blockIndex, 10)].studentViewUrl}
onLoad={handleResizeIframe}
height={500}
/>
) : null}
</div>
</main>
);
}

LearningSequencePage.propTypes = {
match: PropTypes.shape({
params: PropTypes.shape({
courseId: PropTypes.string.isRequired,
blockIndex: PropTypes.number.isRequired,
}).isRequired,
}).isRequired,
intl: intlShape.isRequired,
};

export default injectIntl(LearningSequencePage);
37 changes: 37 additions & 0 deletions src/learning-sequence/PageLoading.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React, { Component } from 'react';

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I just snagged this component from a different MFE. We should have one of these in Paragon.

import PropTypes from 'prop-types';

export default class PageLoading extends Component {
renderSrMessage() {
if (!this.props.srMessage) {
return null;
}

return (
<span className="sr-only">
{this.props.srMessage}
</span>
);
}

render() {
return (
<div>
<div
className="d-flex justify-content-center align-items-center flex-column"
style={{
height: '50vh',
}}
>
<div className="spinner-border text-primary" role="status">
{this.renderSrMessage()}
</div>
</div>
</div>
);
}
}

PageLoading.propTypes = {
srMessage: PropTypes.string.isRequired,
};
4 changes: 4 additions & 0 deletions src/learning-sequence/index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
iframe {
border: 0;
width: 100%;
}
16 changes: 16 additions & 0 deletions src/learning-sequence/messages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { defineMessages } from '@edx/frontend-platform/i18n';

const messages = defineMessages({
'learn.loading.learning.sequence': {
id: 'learn.loading.learning.sequence',
defaultMessage: 'Loading learning sequence...',
description: 'Message when learning sequence is being loaded',
},
'learn.loading.error': {
id: 'learn.loading.error',
defaultMessage: 'Error: {error}',
description: 'Message when learning sequence fails to load',
},
});

export default messages;