Skip to content

Commit 2e8eed7

Browse files
feat: Created Course Team (openedx#564)
1 parent d768bfc commit 2e8eed7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+2925
-12
lines changed

src/CourseAuthoringRoutes.jsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import FilesAndUploads from './files-and-uploads';
1313
import { AdvancedSettings } from './advanced-settings';
1414
import ScheduleAndDetails from './schedule-and-details';
1515
import { GradingSettings } from './grading-settings';
16+
import CourseTeam from './course-team/CourseTeam';
1617

1718
/**
1819
* As of this writing, these routes are mounted at a path prefixed with the following:
@@ -94,10 +95,7 @@ const CourseAuthoringRoutes = ({ courseId }) => {
9495
<GradingSettings courseId={courseId} />
9596
</PageRoute>
9697
<PageRoute path={`${path}/course_team`}>
97-
{process.env.ENABLE_NEW_COURSE_TEAM_PAGE === 'true'
98-
&& (
99-
<Placeholder />
100-
)}
98+
<CourseTeam courseId={courseId} />
10199
</PageRoute>
102100
<PageRoute path={`${path}/settings/advanced`}>
103101
<AdvancedSettings courseId={courseId} />

src/constants.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,13 @@ export const STATEFUL_BUTTON_STATES = {
77
pending: 'pending',
88
default: 'default',
99
};
10+
11+
export const USER_ROLES = {
12+
admin: 'instructor',
13+
staff: 'staff',
14+
};
15+
16+
export const BADGE_STATES = {
17+
danger: 'danger',
18+
secondary: 'secondary',
19+
};

src/course-team/CourseTeam.jsx

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
import { useIntl, injectIntl } from '@edx/frontend-platform/i18n';
4+
import {
5+
Button,
6+
Container,
7+
Layout,
8+
} from '@edx/paragon';
9+
import { Add as IconAdd } from '@edx/paragon/icons';
10+
11+
import InternetConnectionAlert from '../generic/internet-connection-alert';
12+
import SubHeader from '../generic/sub-header/SubHeader';
13+
import { USER_ROLES } from '../constants';
14+
import messages from './messages';
15+
import CourseTeamSideBar from './course-team-sidebar/CourseTeamSidebar';
16+
import AddUserForm from './add-user-form/AddUserForm';
17+
import AddTeamMember from './add-team-member/AddTeamMember';
18+
import CourseTeamMember from './course-team-member/CourseTeamMember';
19+
import InfoModal from './info-modal/InfoModal';
20+
import { useCourseTeam } from './hooks';
21+
22+
const CourseTeam = ({ courseId }) => {
23+
const intl = useIntl();
24+
25+
const {
26+
modalType,
27+
errorMessage,
28+
courseName,
29+
currentEmail,
30+
courseTeamUsers,
31+
currentUserEmail,
32+
isLoading,
33+
isSingleAdmin,
34+
isFormVisible,
35+
isQueryPending,
36+
isAllowActions,
37+
isInfoModalOpen,
38+
isOwnershipHint,
39+
isShowAddTeamMember,
40+
isShowInitialSidebar,
41+
isShowUserFilledSidebar,
42+
isInternetConnectionAlertFailed,
43+
openForm,
44+
hideForm,
45+
closeInfoModal,
46+
handleAddUserSubmit,
47+
handleOpenDeleteModal,
48+
handleDeleteUserSubmit,
49+
handleChangeRoleUserSubmit,
50+
handleInternetConnectionFailed,
51+
} = useCourseTeam({ intl, courseId });
52+
53+
if (isLoading) {
54+
// eslint-disable-next-line react/jsx-no-useless-fragment
55+
return <></>;
56+
}
57+
58+
return (
59+
<>
60+
<Container size="xl" className="m-4">
61+
<section className="course-team-container mb-4">
62+
<Layout
63+
lg={[{ span: 9 }, { span: 3 }]}
64+
md={[{ span: 9 }, { span: 3 }]}
65+
sm={[{ span: 9 }, { span: 3 }]}
66+
xs={[{ span: 9 }, { span: 3 }]}
67+
xl={[{ span: 9 }, { span: 3 }]}
68+
>
69+
<Layout.Element>
70+
<article>
71+
<div>
72+
<SubHeader
73+
title={intl.formatMessage(messages.headingTitle)}
74+
subtitle={intl.formatMessage(messages.headingSubtitle)}
75+
headerActions={isAllowActions && (
76+
<Button
77+
variant="outline-success"
78+
iconBefore={IconAdd}
79+
size="sm"
80+
onClick={openForm}
81+
disabled={isFormVisible}
82+
>
83+
{intl.formatMessage(messages.addNewMemberButton)}
84+
</Button>
85+
)}
86+
/>
87+
<section className="course-team-section">
88+
<div className="members-container">
89+
{isFormVisible && (
90+
<AddUserForm
91+
onSubmit={handleAddUserSubmit}
92+
onCancel={hideForm}
93+
/>
94+
)}
95+
{courseTeamUsers.length ? courseTeamUsers.map(({ username, role, email }) => (
96+
<CourseTeamMember
97+
key={email}
98+
userName={username}
99+
role={role}
100+
email={email}
101+
currentUserEmail={currentUserEmail || ''}
102+
isAllowActions={isAllowActions}
103+
isHideActions={role === USER_ROLES.admin && isSingleAdmin}
104+
onChangeRole={handleChangeRoleUserSubmit}
105+
onDelete={handleOpenDeleteModal}
106+
/>
107+
)) : null}
108+
{isShowAddTeamMember && (
109+
<AddTeamMember
110+
onFormOpen={openForm}
111+
isButtonDisable={isFormVisible}
112+
/>
113+
)}
114+
</div>
115+
{isShowInitialSidebar && (
116+
<div className="sidebar-container">
117+
<CourseTeamSideBar
118+
courseId={courseId}
119+
isOwnershipHint={isOwnershipHint}
120+
isShowInitialSidebar={isShowInitialSidebar}
121+
/>
122+
</div>
123+
)}
124+
<InfoModal
125+
isOpen={isInfoModalOpen}
126+
close={closeInfoModal}
127+
currentEmail={currentEmail}
128+
errorMessage={errorMessage}
129+
courseName={courseName}
130+
modalType={modalType}
131+
onDeleteSubmit={handleDeleteUserSubmit}
132+
/>
133+
</section>
134+
</div>
135+
</article>
136+
</Layout.Element>
137+
<Layout.Element>
138+
{isShowUserFilledSidebar && (
139+
<CourseTeamSideBar
140+
courseId={courseId}
141+
isOwnershipHint={isOwnershipHint}
142+
/>
143+
)}
144+
</Layout.Element>
145+
</Layout>
146+
</section>
147+
</Container>
148+
<div className="alert-toast">
149+
<InternetConnectionAlert
150+
isFailed={isInternetConnectionAlertFailed}
151+
isQueryPending={isQueryPending}
152+
onInternetConnectionFailed={handleInternetConnectionFailed}
153+
/>
154+
</div>
155+
</>
156+
);
157+
};
158+
159+
CourseTeam.propTypes = {
160+
courseId: PropTypes.string.isRequired,
161+
};
162+
163+
export default injectIntl(CourseTeam);

src/course-team/CourseTeam.scss

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
@import "./course-team-sidebar/CourseTeamSidebar";
2+
@import "./add-user-form/AddUserForm";
3+
@import "./add-team-member/AddTeamMember";
4+
@import "./course-team-member/CourseTeamMember";
5+
6+
.course-team-section {
7+
.sidebar-container {
8+
width: 30%;
9+
10+
.help-sidebar {
11+
margin-top: 0;
12+
13+
hr {
14+
display: none;
15+
}
16+
}
17+
}
18+
19+
.members-container {
20+
flex-grow: 1;
21+
padding-top: 1.25rem;
22+
}
23+
}

0 commit comments

Comments
 (0)