Create masquerade widget component

on the Staff Instructor Toolbar
This commit is contained in:
stvn
2020-05-07 14:08:43 -07:00
parent 5ffc1bc599
commit dee5128448
6 changed files with 181 additions and 2 deletions

View File

@@ -4,6 +4,8 @@ import { connect } from 'react-redux';
import { getConfig } from '@edx/frontend-platform';
import MasqueradeWidget from './masquerade-widget';
function getInsightsUrl(courseId) {
const urlBase = getConfig().INSIGHTS_BASE_URL;
let urlFull;
@@ -44,7 +46,7 @@ function InstructorToolbar(props) {
<div className="bg-primary text-light">
<div className="container-fluid py-3 d-md-flex justify-content-end align-items-center">
<div className="flex-grow-1">
&nbsp;
<MasqueradeWidget courseId={courseId} />
</div>
{urlLms && (
<div className="flex-shrink-0">

View File

@@ -0,0 +1,73 @@
import React, {
Component,
} from 'react';
import PropTypes from 'prop-types';
import { Dropdown } from '@edx/paragon';
import { getMasqueradeOptions } from '../../../data/api';
import MasqueradeWidgetOption from './MasqueradeWidgetOption';
class MasqueradeWidget extends Component {
constructor(props) {
super(props);
this.courseId = props.courseId;
this.state = {
options: [],
};
}
componentDidMount() {
getMasqueradeOptions(this.courseId).then((data) => {
if (data.success) {
const options = this.parseAvailableOptions(data);
this.setState({
options,
});
} else {
console.warn('Unable to get masquerade options', data);
}
}).catch((response) => {
console.error('Unable to get masquerade options', response);
});
}
parseAvailableOptions(payload) {
const data = payload || {};
const active = data.active || {};
const available = data.available || [];
const options = available.map((group) => (
<MasqueradeWidgetOption
courseId={this.courseId}
groupId={group.groupId}
groupName={group.name}
key={group.name}
role={group.role}
selected={active}
userName={group.userName}
userPartitionId={group.userPartitionId}
/>
));
return options;
}
render() {
const {
options,
} = this.state;
return (
<Dropdown>
<Dropdown.Button>
View this course as
</Dropdown.Button>
<Dropdown.Menu>
{options}
</Dropdown.Menu>
</Dropdown>
);
}
}
MasqueradeWidget.propTypes = {
courseId: PropTypes.string.isRequired,
};
export default MasqueradeWidget;

View File

@@ -0,0 +1,90 @@
import React, {
Component,
} from 'react';
import PropTypes from 'prop-types';
import { Dropdown } from '@edx/paragon';
import { postMasqueradeOptions } from '../../../data/api';
class MasqueradeWidgetOption extends Component {
handleClick() {
const {
courseId,
groupId,
role,
userName,
userPartitionId,
} = this.props;
const payload = {};
if (role) {
payload.role = role;
}
if (groupId) {
payload.group_id = parseInt(groupId, 10);
payload.user_partition_id = parseInt(userPartitionId, 10);
}
if (userName) {
payload.user_name = userName;
}
postMasqueradeOptions(courseId, payload).then(() => {
global.location.reload();
});
}
isSelected() {
const selected = this.props.selected || {};
const isEqual = (
selected.userPartitionId === (this.props.userPartitionId || null)
&& selected.groupId === (this.props.groupId || null)
&& selected.role === this.props.role
);
return isEqual;
}
render() {
const {
groupName,
} = this.props;
if (!groupName) {
return null;
}
const selected = this.isSelected();
let className;
if (selected) {
className = 'active';
}
return (
<Dropdown.Item
className={className}
href="#"
onClick={(event) => this.handleClick(event)}
>
{groupName}
</Dropdown.Item>
);
}
}
MasqueradeWidgetOption.propTypes = {
courseId: PropTypes.string.isRequired,
groupId: PropTypes.number,
groupName: PropTypes.string.isRequired,
role: PropTypes.string,
selected: PropTypes.shape({
courseKey: PropTypes.string.isRequired,
groupId: PropTypes.number,
role: PropTypes.string,
userName: PropTypes.string,
userPartitionId: PropTypes.number,
}),
userName: PropTypes.string,
userPartitionId: PropTypes.number,
};
MasqueradeWidgetOption.defaultProps = {
groupId: null,
role: null,
selected: null,
userName: null,
userPartitionId: null,
};
export default MasqueradeWidgetOption;

View File

@@ -0,0 +1,3 @@
import MasqueradeWidget from './MasqueradeWidget';
export default MasqueradeWidget;

View File

@@ -62,7 +62,6 @@ function Unit({
const course = useModel('courses', courseId);
const {
contentTypeGatingEnabled,
enrollmentMode,
} = course;
// Do not remove this hook. See function description.

View File

@@ -227,6 +227,18 @@ export async function getResumeBlock(courseId) {
return camelCaseObject(data);
}
export async function getMasqueradeOptions(courseId) {
const url = new URL(`${getConfig().LMS_BASE_URL}/courses/${courseId}/masquerade`);
const { data } = await getAuthenticatedHttpClient().get(url.href, {});
return camelCaseObject(data);
}
export async function postMasqueradeOptions(courseId, data) {
const url = new URL(`${getConfig().LMS_BASE_URL}/courses/${courseId}/masquerade`);
const { response } = await getAuthenticatedHttpClient().post(url.href, data);
return camelCaseObject(response);
}
export async function updateCourseDeadlines(courseId) {
const url = new URL(`${getConfig().LMS_BASE_URL}/api/course_experience/v1/reset_course_deadlines`);
await getAuthenticatedHttpClient().post(url.href, { course_key: courseId });