Skip to content

Commit 1fca718

Browse files
author
katrinan029
committed
chore: rebase
2 parents 87ab48a + 6b3bb62 commit 1fca718

20 files changed

+829
-52
lines changed

src/Configuration/Customers/CustomerDataTable/CustomerDetailSubComponent.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { FormattedMessage } from '@edx/frontend-platform/i18n';
77
import useActiveAssociatedPlans from '../data/hooks/useActiveAssociatedPlans';
88

99
const SubscriptionCheckIcon = ({ row }) => {
10-
if (row.original.hasActiveAgreements) {
10+
if (row.original.hasActiveSubscriptions) {
1111
return <Icon src={Check} screenReaderText="subscription check" />;
1212
}
1313
return null;
@@ -100,7 +100,7 @@ CustomerDetailRowSubComponent.propTypes = {
100100
SubscriptionCheckIcon.propTypes = {
101101
row: PropTypes.shape({
102102
original: PropTypes.shape({
103-
hasActiveAgreements: PropTypes.bool,
103+
hasActiveSubscriptions: PropTypes.bool,
104104
}),
105105
}).isRequired,
106106
};

src/Configuration/Customers/CustomerDataTable/tests/CustomerDetailSubComponent.test.jsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ describe('CustomerDetailRowSubComponent', () => {
3030
useActiveAssociatedPlans.mockReturnValue({
3131
isLoading: false,
3232
data: {
33-
hasActiveAgreements: true,
33+
hasActiveSubscriptions: true,
3434
hasActivePolicies: true,
3535
hasActiveOtherSubsidies: true,
3636
},
@@ -52,7 +52,7 @@ describe('CustomerDetailRowSubComponent', () => {
5252
useActiveAssociatedPlans.mockReturnValue({
5353
isLoading: false,
5454
data: {
55-
hasActiveAgreements: false,
55+
hasActiveSubscriptions: false,
5656
hasActivePolicies: true,
5757
hasActiveOtherSubsidies: true,
5858
},
@@ -74,7 +74,7 @@ describe('CustomerDetailRowSubComponent', () => {
7474
useActiveAssociatedPlans.mockReturnValue({
7575
isLoading: false,
7676
data: {
77-
hasActiveAgreements: true,
77+
hasActiveSubscriptions: true,
7878
hasActivePolicies: false,
7979
hasActiveOtherSubsidies: true,
8080
},
@@ -96,7 +96,7 @@ describe('CustomerDetailRowSubComponent', () => {
9696
useActiveAssociatedPlans.mockReturnValue({
9797
isLoading: false,
9898
data: {
99-
hasActiveAgreements: true,
99+
hasActiveSubscriptions: true,
100100
hasActivePolicies: true,
101101
hasActiveOtherSubsidies: false,
102102
},

src/Configuration/Customers/CustomerDetailView/CustomerCard.jsx

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,30 @@
11
import PropTypes from 'prop-types';
22
import {
3-
ActionRow,
4-
Button,
5-
Card,
6-
Icon,
7-
Hyperlink,
8-
Toast,
3+
ActionRow, Button, Card, Icon, Hyperlink, Toast, useToggle,
94
} from '@openedx/paragon';
105
import { Launch, ContentCopy } from '@openedx/paragon/icons';
116
import { getConfig } from '@edx/frontend-platform';
127
import { formatDate, useCopyToClipboard } from '../data/utils';
138
import DJANGO_ADMIN_BASE_URL from '../data/constants';
9+
import CustomerDetailModal from './CustomerDetailModal';
1410

1511
const CustomerCard = ({ enterpriseCustomer }) => {
1612
const { ADMIN_PORTAL_BASE_URL } = getConfig();
17-
const { showToast, copyToClipboard, setShowToast } = useCopyToClipboard(enterpriseCustomer.uuid);
13+
const { showToast, copyToClipboard, setShowToast } = useCopyToClipboard();
14+
const [isDetailsOpen, openDetails, closeDetails] = useToggle(false);
1815

1916
return (
2017
<div>
18+
<CustomerDetailModal
19+
customer={enterpriseCustomer}
20+
isOpen={isDetailsOpen}
21+
close={closeDetails}
22+
/>
2123
<Card variant="dark" className="mb-0">
2224
<Card.Section
2325
actions={(
2426
<ActionRow>
25-
<Button>View Details</Button>
27+
<Button onClick={openDetails}>View Details</Button>
2628
<Button
2729
className="text-dark-500"
2830
as="a"
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
import PropTypes from 'prop-types';
2+
import {
3+
ActionRow, Badge, Button, Icon, ModalDialog,
4+
} from '@openedx/paragon';
5+
import { Check, Launch } from '@openedx/paragon/icons';
6+
import { getConfig } from '@edx/frontend-platform';
7+
import classNames from 'classnames';
8+
9+
const CustomerDetailModal = ({ customer, isOpen, close }) => {
10+
const { DJANGO_ADMIN_LMS_BASE_URL } = getConfig();
11+
const DATA_SHARING_CONSENT = {
12+
at_enrollment: 'At enrollment',
13+
externally_managed: 'Externally managed',
14+
};
15+
return (
16+
<ModalDialog
17+
title="Enterprise customer details"
18+
isOpen={isOpen}
19+
onClose={close}
20+
size="lg"
21+
hasCloseButton
22+
isFullscreenOnMobile
23+
>
24+
<ModalDialog.Header>
25+
<h1>
26+
{customer.name}
27+
</h1>
28+
</ModalDialog.Header>
29+
30+
<ModalDialog.Body>
31+
<Badge variant="light" style={{ width: 'fit-content' }}>View only</Badge>
32+
<h3 className="mb-3">Enterprise info</h3>
33+
<h4 className="mb-0">Name</h4>
34+
<p>{customer.name || '--'}</p>
35+
<p className="d-flex">
36+
<Icon
37+
className={classNames(
38+
'mr-3',
39+
{ 'text-white': !customer.active },
40+
)}
41+
src={Check}
42+
/>
43+
Active Admin Portal
44+
</p>
45+
<h4 className="mb-0">Slug</h4>
46+
<p>/{customer.slug || '--'}/</p>
47+
<h4 className="mb-0">Auth org id</h4>
48+
<p>{customer.authOrgId || '--'}</p>
49+
<h4 className="mb-0">Country</h4>
50+
<p>{customer.country || '--'}</p>
51+
<h3 className="mt-4 mb-3">Data sharing consent</h3>
52+
<p className="d-flex">
53+
<Icon
54+
className={classNames(
55+
'mr-3',
56+
{ 'text-white': !customer.enableDataSharingConsent },
57+
)}
58+
src={Check}
59+
/>
60+
Activate data sharing consent prompt
61+
</p>
62+
<h4 className="mb-0">Data sharing consent enforcement</h4>
63+
<p>{DATA_SHARING_CONSENT[customer.enforceDataSharingConsent]}</p>
64+
<h3 className="mt-4 mb-3">Email and language</h3>
65+
<h4 className="mb-0">Customer admin contact email</h4>
66+
<p>{customer.contactEmail || '--'}</p>
67+
<h4 className="mb-0">Customer reply-to email</h4>
68+
<p>{customer.replyTo || '--'}</p>
69+
<h4 className="mb-0">Automated email sender alias</h4>
70+
<p>{customer.senderAlias || '--'}</p>
71+
<h4 className="mb-0">Learner default language</h4>
72+
<p>{customer.defaultLanguage || '--'}</p>
73+
<p className="d-flex">
74+
<Icon
75+
className={classNames(
76+
'mr-3',
77+
{ 'text-white': !customer.hideLaborMarketData },
78+
)}
79+
src={Check}
80+
/>
81+
Hide labor market data
82+
</p>
83+
<h3 className="mt-4 mb-3">Integration and learner platform settings</h3>
84+
<p className="d-flex">
85+
<Icon
86+
className={classNames(
87+
'mr-3',
88+
{ 'text-white': !customer.enablePortalReportingConfigScreen },
89+
)}
90+
src={Check}
91+
/>
92+
Display learning platform configuration screen
93+
</p>
94+
<p className="d-flex">
95+
<Icon
96+
className={classNames(
97+
'mr-3',
98+
{ 'text-white': !customer.enablePortalSamlConfigurationScreen },
99+
)}
100+
src={Check}
101+
/>
102+
Display SSO configuration screen
103+
</p>
104+
<p className="d-flex">
105+
<Icon
106+
className={classNames(
107+
'mr-3',
108+
{ 'text-white': !customer.enableSlugLogin },
109+
)}
110+
src={Check}
111+
/>
112+
Allow slug login for SSO
113+
</p>
114+
<p className="d-flex">
115+
<Icon
116+
className={classNames(
117+
'mr-3',
118+
{ 'text-white': !customer.replaceSensitiveSsoUsername },
119+
)}
120+
src={Check}
121+
/>
122+
Replace sensitive SSO username
123+
</p>
124+
<p className="d-flex">
125+
<Icon
126+
className={classNames(
127+
'mr-3',
128+
{ 'text-white': !customer.hideCourseOriginalPrice },
129+
)}
130+
src={Check}
131+
/>
132+
Hide course price on learning platform
133+
</p>
134+
<p className="d-flex">
135+
<Icon
136+
className={classNames(
137+
'mr-3',
138+
{ 'text-white': !customer.hideCourseOriginalPrice },
139+
)}
140+
src={Check}
141+
/>
142+
Hide course price on learning platform
143+
</p>
144+
<p className="d-flex">
145+
<Icon
146+
className={classNames(
147+
'mr-3',
148+
{ 'text-white': !customer.enableGenerationOfApiCredentials },
149+
)}
150+
src={Check}
151+
/>
152+
Allow generation of API credentials
153+
</p>
154+
</ModalDialog.Body>
155+
156+
<ModalDialog.Footer>
157+
<ActionRow>
158+
<ModalDialog.CloseButton variant="tertiary" onClick={close}>
159+
Close
160+
</ModalDialog.CloseButton>
161+
<Button
162+
as="a"
163+
href={`${DJANGO_ADMIN_LMS_BASE_URL}/admin/enterprise/enterprisecustomer/${customer.uuid}/change`}
164+
target="_blank"
165+
rel="noopener noreferrer"
166+
iconAfter={Launch}
167+
>
168+
Open in Django
169+
</Button>
170+
</ActionRow>
171+
</ModalDialog.Footer>
172+
</ModalDialog>
173+
);
174+
};
175+
176+
CustomerDetailModal.propTypes = {
177+
isOpen: PropTypes.bool.isRequired,
178+
close: PropTypes.func.isRequired,
179+
customer: PropTypes.shape({
180+
active: PropTypes.bool,
181+
authOrgId: PropTypes.string,
182+
contactEmail: PropTypes.string,
183+
country: PropTypes.string,
184+
defaultLanguage: PropTypes.string,
185+
enableDataSharingConsent: PropTypes.bool,
186+
enableGenerationOfApiCredentials: PropTypes.bool,
187+
enablePortalReportingConfigScreen: PropTypes.bool,
188+
enablePortalSamlConfigurationScreen: PropTypes.bool,
189+
enableSlugLogin: PropTypes.bool,
190+
enforceDataSharingConsent: PropTypes.string,
191+
hideCourseOriginalPrice: PropTypes.bool,
192+
hideLaborMarketData: PropTypes.bool,
193+
modified: PropTypes.string,
194+
name: PropTypes.string,
195+
replaceSensitiveSsoUsername: PropTypes.bool,
196+
replyTo: PropTypes.string,
197+
senderAlias: PropTypes.string,
198+
slug: PropTypes.string,
199+
uuid: PropTypes.string,
200+
}).isRequired,
201+
};
202+
203+
export default CustomerDetailModal;

src/Configuration/Customers/CustomerDetailView/CustomerIntegrations.jsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { Container } from '@openedx/paragon';
21
import { getConfig } from '@edx/frontend-platform';
32
import PropTypes from 'prop-types';
43

@@ -14,10 +13,10 @@ const CustomerIntegrations = ({
1413
const configDateText = ({ config }) => (`Created ${formatDate(config?.created)} • Last modified ${formatDate(config?.lastModifiedAt)}`);
1514

1615
return (
17-
<Container className="mt-3 pr-6 mb-5">
16+
<div>
1817
{(activeSSO || activeIntegrations || apiCredentialsEnabled) && (
1918
<div>
20-
<h2 className="pt-4">Associated Integrations</h2>
19+
<h2>Associated Integrations</h2>
2120
{activeSSO && activeSSO.map((sso) => (
2221
<CustomerViewCard
2322
slug={slug}
@@ -49,7 +48,7 @@ const CustomerIntegrations = ({
4948
)}
5049
</div>
5150
)}
52-
</Container>
51+
</div>
5352
);
5453
};
5554

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { useState } from 'react';
2+
import { useParams } from 'react-router-dom';
3+
import PropTypes from 'prop-types';
4+
import { Form, Skeleton } from '@openedx/paragon';
5+
import useAllAssociatedPlans from '../data/hooks/useAllAssociatedPlans';
6+
import LearnerCreditPlanCard from './LearnerCreditPlanCard';
7+
import SubscriptionPlanCard from './SubscriptionPlanCard';
8+
9+
const CustomerPlanContainer = ({ slug }) => {
10+
const { id } = useParams();
11+
const {
12+
activePolicies,
13+
activeSubscriptions,
14+
countOfActivePlans,
15+
countOfAllPlans,
16+
inactivePolicies,
17+
inactiveSubscriptions,
18+
isLoading,
19+
} = useAllAssociatedPlans(id);
20+
const [showInactive, setShowInactive] = useState(false);
21+
const renderActivePoliciesCard = activePolicies.map(policy => (
22+
<LearnerCreditPlanCard key={policy.uuid} isActive slug={slug} policy={policy} />
23+
));
24+
const renderInactivePoliciesCard = inactivePolicies.map(policy => (
25+
<LearnerCreditPlanCard key={policy.uuid} isActive={false} slug={slug} policy={policy} />
26+
));
27+
const renderActiveSubscriptions = activeSubscriptions.map(subscription => (
28+
<SubscriptionPlanCard key={subscription.uuid} isActive slug={slug} subscription={subscription} />
29+
));
30+
const renderInActiveSubscriptions = inactiveSubscriptions.map(subscription => (
31+
<SubscriptionPlanCard key={subscription.uuid} isActive={false} slug={slug} subscription={subscription} />
32+
));
33+
return (
34+
<div>
35+
{!isLoading ? (
36+
<div>
37+
<div className="d-flex justify-content-between">
38+
<h2>Associated subsidy plans ({showInactive ? countOfAllPlans : countOfActivePlans})</h2>
39+
<Form.Switch
40+
className="ml-2.5 mt-2.5"
41+
checked={showInactive}
42+
disabled={countOfAllPlans === countOfActivePlans}
43+
onChange={() => {
44+
setShowInactive(prevState => !prevState);
45+
}}
46+
data-testid="show-removed-toggle"
47+
>
48+
Show inactive
49+
</Form.Switch>
50+
</div>
51+
{renderActivePoliciesCard}
52+
{renderActiveSubscriptions}
53+
{showInactive ? (
54+
<div>
55+
{renderInactivePoliciesCard}
56+
{renderInActiveSubscriptions}
57+
</div>
58+
) : null}
59+
</div>
60+
) : <Skeleton height={230} />}
61+
</div>
62+
);
63+
};
64+
65+
CustomerPlanContainer.propTypes = {
66+
slug: PropTypes.string.isRequired,
67+
};
68+
69+
export default CustomerPlanContainer;

0 commit comments

Comments
 (0)