Skip to content
Draft
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
3 changes: 3 additions & 0 deletions src/components/EnterpriseApp/EnterpriseAppContent.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const EnterpriseAppContent = ({
enableReportingPage,
enableSubscriptionManagementPage,
enableAnalyticsPage,
enterpriseGroupsV2,
}) => {
const { FEATURE_CONTENT_HIGHLIGHTS } = getConfig();
const enterpriseAppContext = useContext(EnterpriseAppContext);
Expand All @@ -32,6 +33,7 @@ const EnterpriseAppContent = ({
enableSubscriptionManagementPage={enableSubscriptionManagementPage}
enableAnalyticsPage={enableAnalyticsPage}
enableContentHighlightsPage={isContentHighlightsEnabled}
enterpriseGroupsV2={enterpriseGroupsV2}
/>
);
};
Expand All @@ -44,6 +46,7 @@ EnterpriseAppContent.propTypes = {
enableReportingPage: PropTypes.bool.isRequired,
enableSubscriptionManagementPage: PropTypes.bool.isRequired,
enableAnalyticsPage: PropTypes.bool.isRequired,
enterpriseGroupsV2: PropTypes.bool.isRequired,
};

export default EnterpriseAppContent;
12 changes: 11 additions & 1 deletion src/components/EnterpriseApp/EnterpriseAppRoutes.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import BulkEnrollmentResultsDownloadPage from '../BulkEnrollmentResultsDownloadP
import { EnterpriseSubsidiesContext } from '../EnterpriseSubsidiesContext';
import ContentHighlights from '../ContentHighlights';
import LearnerCreditManagementRoutes from '../learner-credit-management';
import PeopleManagementPage from '../PeopleManagement';

const EnterpriseAppRoutes = ({
email,
Expand All @@ -27,10 +28,11 @@ const EnterpriseAppRoutes = ({
enableSubscriptionManagementPage,
enableAnalyticsPage,
enableContentHighlightsPage,
enterpriseGroupsV2,
}) => {
const { canManageLearnerCredit } = useContext(EnterpriseSubsidiesContext);
const { enterpriseAppPage } = useParams();

console.log(enterpriseGroupsV2)
return (
<Routes>
{enterpriseAppPage === ROUTE_NAMES.learners && (
Expand Down Expand Up @@ -115,6 +117,13 @@ const EnterpriseAppRoutes = ({
/>
)}

{enterpriseGroupsV2 && enterpriseAppPage === ROUTE_NAMES.peopleManagement && (
<Route
path="/*"
element={<PeopleManagementPage />}
/>
)}

{enableContentHighlightsPage && enterpriseAppPage === ROUTE_NAMES.contentHighlights && (
<Route
path="/*"
Expand All @@ -136,6 +145,7 @@ EnterpriseAppRoutes.propTypes = {
enableSubscriptionManagementPage: PropTypes.bool.isRequired,
enableAnalyticsPage: PropTypes.bool.isRequired,
enableContentHighlightsPage: PropTypes.bool.isRequired,
enterpriseGroupsV2: PropTypes.bool.isRequired,
};

export default EnterpriseAppRoutes;
5 changes: 3 additions & 2 deletions src/components/EnterpriseApp/data/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@
export const ROUTE_NAMES = {
analytics: 'analytics',
analyticsv2: 'analyticsv2',
appearance: 'appearance',
bulkEnrollment: 'enrollment',
bulkEnrollmentResults: 'bulk-enrollment-results',
codeManagement: 'coupons',
contentHighlights: 'content-highlights',
learners: 'learners',
learnerCredit: 'learner-credit',
peopleManagement: 'people-management',
reporting: 'reporting',
appearance: 'appearance',
settings: 'settings',
subscriptionManagement: 'subscriptions',
contentHighlights: 'content-highlights',
};

export const BUDGET_STATUSES = {
Expand Down
3 changes: 3 additions & 0 deletions src/components/EnterpriseApp/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ class EnterpriseApp extends React.Component {
enableReportingPage={features.REPORTING_CONFIGURATIONS && enableReportingConfigurationsScreen}
enableSubscriptionManagementPage={enableSubscriptionManagementScreen}
enableAnalyticsPage={features.ANALYTICS && enableAnalyticsScreen}
enterpriseGroupsV2={enterpriseFeatures.enterpriseGroupsV2}
>
<FeatureAnnouncementBanner enterpriseSlug={enterpriseSlug} />
</EnterpriseAppContent>
Expand Down Expand Up @@ -195,6 +196,7 @@ EnterpriseApp.propTypes = {
enterpriseName: PropTypes.string,
enterpriseFeatures: PropTypes.shape({
topDownAssignmentRealTimeLcm: PropTypes.bool,
enterpriseGroupsV2: PropTypes.bool,
}),
enterpriseBranding: PropTypes.shape({
primary_color: PropTypes.string,
Expand All @@ -212,6 +214,7 @@ EnterpriseApp.propTypes = {
enableAnalyticsScreen: PropTypes.bool,
enableReportingConfigurationsScreen: PropTypes.bool,
enablePortalLearnerCreditManagementScreen: PropTypes.bool,
enterpriseGroupsV2: PropTypes.bool,
error: PropTypes.instanceOf(Error),
loading: PropTypes.bool,
};
Expand Down
111 changes: 111 additions & 0 deletions src/components/PeopleManagement/CreateGroupModal.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import React, {
useCallback, useEffect, useMemo, useState,
} from 'react';
import PropTypes from 'prop-types';
import debounce from 'lodash.debounce';
import {
Col, Container, Form, Row,
} from '@openedx/paragon';

import InviteModalSummary from '../learner-credit-management/invite-modal/InviteModalSummary';
import { EMAIL_ADDRESSES_INPUT_VALUE_DEBOUNCE_DELAY, INPUT_TYPE, isInviteEmailAddressesInputValueValid } from '../learner-credit-management/cards/data';
import FileUpload from '../learner-credit-management/invite-modal/FileUpload';
import { MAX_LENGTH_GROUP_NAME } from './constants';

const CreateGroupModal = ({ onEmailAddressesChange }) => {
const [learnerEmails, setLearnerEmails] = useState([]);
const [emailAddressesInputValue, setEmailAddressesInputValue] = useState('');
const [memberInviteMetadata, setMemberInviteMetadata] = useState({
isValidInput: null,
lowerCasedEmails: [],
duplicateEmails: null,
});
const [groupNameLength, setGroupNameLength] = useState(0);
const [groupName, setGroupName] = useState('');


const handleGroupNameChange = (e) => {
const { value } = e.target;
if (value.length > MAX_LENGTH_GROUP_NAME) {
return;
}
setGroupNameLength(value.length);
setGroupName(value);
};

const handleEmailAddressesChanged = useCallback((value) => {
if (!value) {
setLearnerEmails([]);
onEmailAddressesChange([]);
return;
}
const emails = value.split('\n').map((email) => email.trim()).filter((email) => email.length > 0);
console.log(emails)
setLearnerEmails(emails);
}, [onEmailAddressesChange]);

const debouncedHandleEmailAddressesChanged = useMemo(
() => debounce(handleEmailAddressesChanged, EMAIL_ADDRESSES_INPUT_VALUE_DEBOUNCE_DELAY),
[handleEmailAddressesChanged],
);

useEffect(() => {
debouncedHandleEmailAddressesChanged(emailAddressesInputValue);
}, [emailAddressesInputValue, debouncedHandleEmailAddressesChanged]);

useEffect(() => {
const inviteMetadata = isInviteEmailAddressesInputValueValid({
learnerEmails,
});
setMemberInviteMetadata(inviteMetadata);
if (inviteMetadata.canInvite) {
onEmailAddressesChange(learnerEmails, { canInvite: true });
} else {
onEmailAddressesChange([]);
}
console.log(inviteMetadata)
}, [onEmailAddressesChange, learnerEmails]);

return (
<Container size="lg" className="py-3">
<h3>Create a custom group of members</h3>
<Row>
<Col>
<h4 className="mt-4">Name your group</h4>
<Form.Control
value={groupName}
onChange={handleGroupNameChange}
label="Name"
data-testid="group-name"
placeholder="Name"
/>
<Form.Control.Feedback className="mb-4">
{groupNameLength} / {MAX_LENGTH_GROUP_NAME}
</Form.Control.Feedback>
</Col>
<Col />
</Row>
<Row>
<Col>
<h4>Select group members</h4>
<p>Upload a CSV or select members from the table below.</p>
<FileUpload
memberInviteMetadata={memberInviteMetadata}
setEmailAddressesInputValue={setEmailAddressesInputValue}
/>
</Col>
<Col>
<h4>Details</h4>
<InviteModalSummary isGroupsInvite memberInviteMetadata={memberInviteMetadata} />
<hr className="my-4" />
</Col>
</Row>
</Container>
);
};

CreateGroupModal.propTypes = {
onEmailAddressesChange: PropTypes.func.isRequired,
};

export default CreateGroupModal;
Loading