Absorbing work from douglashall/learning_sequence
This commit is contained in:
119
src/learning-sequence/LearningSequencePage.jsx
Normal file
119
src/learning-sequence/LearningSequencePage.jsx
Normal file
@@ -0,0 +1,119 @@
|
||||
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, {
|
||||
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;
|
||||
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
|
||||
// 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=course-v1%3AedX%2BDemoX%2BDemo_Course&username=staff&depth=all&block_types_filter=sequential&requested_fields=children`, {}),
|
||||
{
|
||||
keepDataIfFailed: false,
|
||||
refreshParams: [
|
||||
props.match.params.courseRunId,
|
||||
props.match.params.sequenceBlockId,
|
||||
],
|
||||
},
|
||||
);
|
||||
|
||||
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>
|
||||
<p>Hello world!</p>
|
||||
Params: {props.match.params.courseRunId}/{props.match.params.sequenceBlockId}
|
||||
State:
|
||||
{loaded && data.blocks ? (
|
||||
<iframe
|
||||
title="yus"
|
||||
ref={iframeRef}
|
||||
src={Object.values(data.blocks)[0].studentViewUrl}
|
||||
onLoad={handleResizeIframe}
|
||||
height={500}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
LearningSequencePage.propTypes = {
|
||||
match: PropTypes.shape({
|
||||
params: PropTypes.shape({
|
||||
courseRunId: PropTypes.string.isRequired,
|
||||
sequenceBlockId: PropTypes.string.isRequired,
|
||||
}).isRequired,
|
||||
}).isRequired,
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
export default injectIntl(LearningSequencePage);
|
||||
37
src/learning-sequence/PageLoading.jsx
Normal file
37
src/learning-sequence/PageLoading.jsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import React, { Component } from 'react';
|
||||
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
src/learning-sequence/index.scss
Normal file
4
src/learning-sequence/index.scss
Normal file
@@ -0,0 +1,4 @@
|
||||
iframe {
|
||||
border: 0;
|
||||
width: 100%;
|
||||
}
|
||||
16
src/learning-sequence/messages.js
Normal file
16
src/learning-sequence/messages.js
Normal file
@@ -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;
|
||||
Reference in New Issue
Block a user