Skip to content

Commit

Permalink
Merge pull request #16983 from code-dot-org/redux-roster-dialog
Browse files Browse the repository at this point in the history
Fully reduxify third-party import logic.
  • Loading branch information
islemaster committed Aug 14, 2017
2 parents e1c72d7 + b3c6617 commit 1397917
Show file tree
Hide file tree
Showing 12 changed files with 516 additions and 257 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import teacherSections, {
setOAuthProvider,
asyncLoadSectionData,
} from '@cdo/apps/templates/teacherDashboard/teacherSectionsRedux';
import oauthClassroom from '@cdo/apps/templates/teacherDashboard/oauthClassroomRedux';
import SectionsPage from '@cdo/apps/templates/teacherDashboard/SectionsPage';

/**
Expand All @@ -25,7 +24,7 @@ import SectionsPage from '@cdo/apps/templates/teacherDashboard/SectionsPage';
*/
export function renderSectionsPage(data) {
const element = document.getElementById('sections-page');
registerReducers({teacherSections, oauthClassroom});
registerReducers({teacherSections});
const store = getStore();

store.dispatch(setStudioUrl(data.studiourlprefix));
Expand Down
3 changes: 1 addition & 2 deletions apps/src/sites/studio/pages/home/_homepage.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import UiTips from '@cdo/apps/templates/studioHomepages/UiTips';
import i18n from "@cdo/locale";
import {Provider} from 'react-redux';
import {getStore, registerReducers} from '@cdo/apps/redux';
import oauthClassroom from '@cdo/apps/templates/teacherDashboard/oauthClassroomRedux';
import teacherSections, {
setValidGrades,
setOAuthProvider
Expand All @@ -27,7 +26,7 @@ function showHomepage() {
const showInitialTips = !homepageData.initialtipsdismissed;
const query = queryString.parse(window.location.search);

registerReducers({teacherSections, oauthClassroom});
registerReducers({teacherSections});
const store = getStore();
store.dispatch(setValidGrades(homepageData.valid_grades));
store.dispatch(setOAuthProvider(homepageData.provider));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import {Provider} from 'react-redux';
import sinon from 'sinon';
import {createStoreWithReducers, registerReducers} from '@cdo/apps/redux';
import teacherSections, {serverSectionFromSection} from '../teacherDashboard/teacherSectionsRedux';
import oauthClassroom from '../teacherDashboard/oauthClassroomRedux';
import TeacherSections from './TeacherSections';

const sections = [
Expand Down Expand Up @@ -46,7 +45,7 @@ export default [
description: 'shows a table of sections on the teacher homepage',
story: () => {
withFakeServer({sections: serverSections});
registerReducers({teacherSections, oauthClassroom});
registerReducers({teacherSections});
const store = createStoreWithReducers();
return (
<Provider store={store}>
Expand All @@ -65,7 +64,7 @@ export default [
description: 'shows a set up message if the teacher does not have any sections yet',
story: () => {
withFakeServer();
registerReducers({teacherSections, oauthClassroom});
registerReducers({teacherSections});
const store = createStoreWithReducers();
return (
<Provider store={store}>
Expand Down
15 changes: 10 additions & 5 deletions apps/src/templates/teacherDashboard/AddSectionDialog.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,25 @@ import LoginTypePicker from './LoginTypePicker';
import EditSectionForm from "./EditSectionForm";
import PadAndCenter from './PadAndCenter';
import {sectionShape} from './shapes';
import {isAddingSection} from './teacherSectionsRedux';
import {
isAddingSection,
beginImportRosterFlow
} from './teacherSectionsRedux';

/**
* UI for a teacher to add a new class section. For editing a section see
* EditSectionDialog.
*/
class AddSectionDialog extends Component {
static propTypes = {
handleImportOpen: PropTypes.func.isRequired,
// Provided by Redux
isOpen: PropTypes.bool.isRequired,
section: sectionShape,
beginImportRosterFlow: PropTypes.func.isRequired,
};

render() {
const {isOpen, section, handleImportOpen} = this.props;
const {isOpen, section, beginImportRosterFlow} = this.props;
const {loginType} = section || {};
const title = i18n.newSection();
return (
Expand All @@ -36,7 +39,7 @@ class AddSectionDialog extends Component {
{!loginType &&
<LoginTypePicker
title={title}
handleImportOpen={handleImportOpen}
handleImportOpen={beginImportRosterFlow}
/>
}
{loginType &&
Expand All @@ -51,4 +54,6 @@ class AddSectionDialog extends Component {
export default connect(state => ({
isOpen: isAddingSection(state.teacherSections),
section: state.teacherSections.sectionBeingEdited,
}))(AddSectionDialog);
}), {
beginImportRosterFlow
})(AddSectionDialog);
80 changes: 16 additions & 64 deletions apps/src/templates/teacherDashboard/OwnedSections.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,22 @@
* current user. */
import React, {PropTypes} from 'react';
import {connect} from 'react-redux';
import $ from 'jquery';
import SectionTable from './SectionTable';
import RosterDialog from './RosterDialog';
import Button from '@cdo/apps/templates/Button';
import {
newSection,
beginEditingNewSection,
beginEditingSection,
asyncLoadSectionData,
beginImportRosterFlow,
} from './teacherSectionsRedux';
import {loadClassroomList, importClassroomStarted} from './oauthClassroomRedux';
import {classroomShape, loadErrorShape, OAuthSectionTypes} from './shapes';
import {OAuthSectionTypes} from './shapes';
import i18n from '@cdo/locale';
import experiments, {SECTION_FLOW_2017} from '@cdo/apps/util/experiments';
import AddSectionDialog from "./AddSectionDialog";
import EditSectionDialog from "./EditSectionDialog";
import SetUpSections from '../studioHomepages/SetUpSections';

const urlByProvider = {
[OAuthSectionTypes.google_classroom]: '/dashboardapi/import_google_classroom',
[OAuthSectionTypes.clever]: '/dashboardapi/import_clever_classroom',
};

const styles = {
button: {
marginBottom: 20,
Expand All @@ -41,21 +34,12 @@ class OwnedSections extends React.Component {

// redux provided
numSections: PropTypes.number.isRequired,
studioUrl: PropTypes.string.isRequired,
provider: PropTypes.string,
classrooms: PropTypes.arrayOf(classroomShape),
loadError: loadErrorShape,
asyncLoadComplete: PropTypes.bool.isRequired,
newSection: PropTypes.func.isRequired,
loadClassroomList: PropTypes.func.isRequired,
importClassroomStarted: PropTypes.func.isRequired,
beginEditingNewSection: PropTypes.func.isRequired,
beginEditingSection: PropTypes.func.isRequired,
asyncLoadSectionData: PropTypes.func.isRequired,
};

state = {
rosterDialogOpen: false,
beginImportRosterFlow: PropTypes.func.isRequired,
};

componentWillMount() {
Expand All @@ -69,6 +53,7 @@ class OwnedSections extends React.Component {
defaultCourseId,
defaultScriptId,
queryStringOpen,
beginImportRosterFlow,
} = this.props;

// If we have a default courseId and/or scriptId, we want to start with our
Expand All @@ -79,36 +64,11 @@ class OwnedSections extends React.Component {

if (experiments.isEnabled('importClassroom')) {
if (queryStringOpen === 'rosterDialog') {
this.handleImportOpen();
beginImportRosterFlow();
}
}
}

handleImportOpen = () => {
this.setState({rosterDialogOpen: true});
this.props.loadClassroomList(this.provider);
};

handleImportCancel = () => {
this.setState({rosterDialogOpen: false});
};

handleImport = courseId => {
const {
importClassroomStarted,
asyncLoadSectionData,
beginEditingSection,
} = this.props;

importClassroomStarted();
const url = urlByProvider[this.provider];
$.getJSON(url, { courseId }).then(importedSection => {
this.setState({rosterDialogOpen: false});
asyncLoadSectionData()
.then(() => beginEditingSection(importedSection.id));
});
};

addSection = () => {
const { defaultCourseId, defaultScriptId } = this.props;
if (experiments.isEnabled(SECTION_FLOW_2017)) {
Expand All @@ -127,7 +87,12 @@ class OwnedSections extends React.Component {
};

render() {
const { isRtl, numSections, asyncLoadComplete } = this.props;
const {
isRtl,
numSections,
asyncLoadComplete,
beginImportRosterFlow
} = this.props;
if (!asyncLoadComplete) {
return null;
}
Expand All @@ -152,15 +117,15 @@ class OwnedSections extends React.Component {
<Button
text={i18n.importFromGoogleClassroom()}
style={styles.button}
onClick={this.handleImportOpen}
onClick={beginImportRosterFlow}
color={Button.ButtonColor.gray}
/>
}
{showCleverClassroom &&
<Button
text={i18n.importFromClever()}
style={styles.button}
onClick={this.handleImportOpen}
onClick={beginImportRosterFlow}
color={Button.ButtonColor.gray}
/>
}
Expand All @@ -174,16 +139,8 @@ class OwnedSections extends React.Component {
}
</div>
)}
<RosterDialog
isOpen={this.state.rosterDialogOpen}
handleImport={this.handleImport}
handleCancel={this.handleImportCancel}
classrooms={this.props.classrooms}
loadError={this.props.loadError}
studioUrl={this.props.studioUrl}
provider={this.provider}
/>
<AddSectionDialog handleImportOpen={this.handleImportOpen}/>
<RosterDialog/>
<AddSectionDialog/>
<EditSectionDialog/>
</div>
);
Expand All @@ -193,16 +150,11 @@ export const UnconnectedOwnedSections = OwnedSections;

export default connect(state => ({
numSections: state.teacherSections.sectionIds.length,
studioUrl: state.teacherSections.studioUrl,
provider: state.teacherSections.provider,
classrooms: state.oauthClassroom.classrooms,
loadError: state.oauthClassroom.loadError,
asyncLoadComplete: state.teacherSections.asyncLoadComplete,
}), {
newSection,
beginEditingNewSection,
beginEditingSection,
loadClassroomList,
importClassroomStarted,
asyncLoadSectionData,
beginImportRosterFlow,
})(OwnedSections);
27 changes: 21 additions & 6 deletions apps/src/templates/teacherDashboard/RosterDialog.jsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import React from 'react';
import {connect} from 'react-redux';
import BaseDialog from '../BaseDialog';
import { classroomShape, loadErrorShape, OAuthSectionTypes } from './shapes';
import color from '../../util/color';
import locale from '@cdo/locale';
import {
cancelImportRosterFlow,
importRoster,
isRosterDialogOpen,
} from './teacherSectionsRedux';

const styles = {
title: {
Expand Down Expand Up @@ -134,21 +140,19 @@ LoadError.propTypes = {
studioUrl: React.PropTypes.string.isRequired,
};

export default class RosterDialog extends React.Component {
class RosterDialog extends React.Component {
static propTypes = {
// Provided by Redux
handleImport: React.PropTypes.func,
handleCancel: React.PropTypes.func,
isOpen: React.PropTypes.bool,
classrooms: React.PropTypes.arrayOf(classroomShape),
loadError: loadErrorShape,
studioUrl: React.PropTypes.string.isRequired,
provider: React.PropTypes.oneOf(Object.keys(OAuthSectionTypes)),
}
};

constructor(props) {
super(props);
this.state = {};
}
state = {selectedId: null};

importClassroom = () => {
this.props.handleImport(this.state.selectedId);
Expand Down Expand Up @@ -224,3 +228,14 @@ export default class RosterDialog extends React.Component {
);
}
}
export const UnconnectedRosterDialog = RosterDialog;
export default connect(state => ({
isOpen: isRosterDialogOpen(state),
classrooms: state.teacherSections.classrooms,
loadError: state.teacherSections.loadError,
studioUrl: state.teacherSections.studioUrl,
provider: state.teacherSections.provider,
}), {
handleImport: importRoster,
handleCancel: cancelImportRosterFlow,
})(RosterDialog);
2 changes: 1 addition & 1 deletion apps/src/templates/teacherDashboard/RosterDialog.story.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import RosterDialog from './RosterDialog';
import {UnconnectedRosterDialog as RosterDialog} from './RosterDialog';
import { OAuthSectionTypes } from './shapes';

const ExampleDialogButton = React.createClass({
Expand Down

0 comments on commit 1397917

Please sign in to comment.