Skip to content

Commit

Permalink
feat: add enterprise customer list view
Browse files Browse the repository at this point in the history
  • Loading branch information
katrinan029 committed Aug 2, 2024
1 parent 3798d97 commit 1c7f1dd
Show file tree
Hide file tree
Showing 27 changed files with 1,121 additions and 9 deletions.
2 changes: 2 additions & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ BASE_URL=null
FEATURE_CONFIGURATION_MANAGEMENT=''
FEATURE_CONFIGURATION_ENTERPRISE_PROVISION=''
FEATURE_CONFIGURATION_EDIT_ENTERPRISE_PROVISION=''
FEATURE_CUSTOMER_SUPPORT_VIEW=''
ADMIN_PORTAL_BASE_URL=''
COMMERCE_COORDINATOR_ORDER_DETAILS_URL=''
CREDENTIALS_BASE_URL=null
CSRF_TOKEN_API_PATH=null
Expand Down
2 changes: 2 additions & 0 deletions .env.development
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ BASE_URL='http://localhost:18450'
FEATURE_CONFIGURATION_MANAGEMENT='true'
FEATURE_CONFIGURATION_ENTERPRISE_PROVISION='true'
FEATURE_CONFIGURATION_EDIT_ENTERPRISE_PROVISION='true'
FEATURE_CUSTOMER_SUPPORT_VIEW='true'
ADMIN_PORTAL_BASE_URL='http://localhost:1991'
COMMERCE_COORDINATOR_ORDER_DETAILS_URL='http://localhost:8140/lms/order_details_page_redirect'
CREDENTIALS_BASE_URL='http://localhost:18150'
CSRF_TOKEN_API_PATH='/csrf/api/v1/token'
Expand Down
6 changes: 3 additions & 3 deletions src/Configuration/ConfigurationPage.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {
Container,
Hyperlink,
Stack,
// Stack,
} from '@edx/paragon';
import { v4 as uuidv4 } from 'uuid';
import ROUTES from '../data/constants/routes';
Expand All @@ -14,13 +14,13 @@ const ConfigurationPage = () => {
return (
<Container className="mt-3">
<h1>{CONFIGURATION_PAGE_TEXT.HEADER}</h1>
<Stack>
{/* <Stack> */}
{Object.keys(SUB_DIRECTORY).map((route) => (
<Hyperlink destination={SUB_DIRECTORY[route].HOME} key={uuidv4()}>
{titleCase(route)}
</Hyperlink>
))}
</Stack>
{/* </Stack> */}
</Container>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import PropTypes from 'prop-types';
import {
DataTable, Icon, OverlayTrigger, Stack, Tooltip,
} from '@edx/paragon';
import { Check, InfoOutline } from '@edx/paragon/icons';
import { FormattedMessage } from '@edx/frontend-platform/i18n';
import useActiveAssociatedPlans from '../data/hooks/useActiveAssociatedPlans';

const SubscriptionCheckIcon = ({ row }) => {
if (row.original.hasActiveAgreements) {
return <Icon src={Check} screenReaderText="subscription check" />;
}
return null;
};

const PolicyCheckIcon = ({ row }) => {
if (row.original.hasActivePolicies) {
return <Icon src={Check} screenReaderText="policy check" />;
}
return null;
};

const OtherSubsidiesCheckIcon = ({ row }) => {
if (row.original.hasActiveOtherSubsidies) {
return <Icon src={Check} screenReaderText="other subsidies check" />;
}
return null;
};

export const OtherSubsidies = () => (
<Stack gap={1} direction="horizontal">
<span data-testid="members-table-status-column-header">
<FormattedMessage
id="configuration.customersPage.otherSubsidiesColumn"
defaultMessage="Other Subsidies"
description="Other subsidies column header in the Customers table"
/>
</span>
<OverlayTrigger
key="other-subsidies-tooltip"
placement="top"
overlay={(
<Tooltip id="other-subsidies-tooltip">
<div>
<FormattedMessage
id="configuration.customersPage.otherSubsidiesColumn.tooltip"
defaultMessage="Includes Offers and Codes"
description="Tooltip for the Other Subsidies column header in the Customers table"
/>
</div>
</Tooltip>
)}
>
<Icon size="xs" src={InfoOutline} className="ml-1 d-inline-flex" />
</OverlayTrigger>
</Stack>
);

const CustomerDetailRowSubComponent = ({ row }) => {
const enterpriseId = row.original.uuid;
const { data, isLoading } = useActiveAssociatedPlans(enterpriseId);
return (
<div className="sub-component w-50">
<DataTable
itemCount={1}
data={[data] || []}
isLoading={isLoading}
columns={[
{
Header: 'Subscription',
accessor: 'hasActiveSubscription',
Cell: SubscriptionCheckIcon,
},
{
Header: 'Learner Credit',
accessor: 'hasActivePolicies',
Cell: PolicyCheckIcon,
},
{
Header: OtherSubsidies,
accessor: 'hasActiveOtherSubsidies',
Cell: OtherSubsidiesCheckIcon,
},
]}
>
<DataTable.Table />
</DataTable>
</div>
);
};

CustomerDetailRowSubComponent.propTypes = {
row: PropTypes.shape({
original: PropTypes.shape({
uuid: PropTypes.string,
}),
}).isRequired,
};

SubscriptionCheckIcon.propTypes = {
row: PropTypes.shape({
original: PropTypes.shape({
hasActiveAgreements: PropTypes.bool,
}),
}).isRequired,
};

PolicyCheckIcon.propTypes = {
row: PropTypes.shape({
original: PropTypes.shape({
hasActivePolicies: PropTypes.bool,
}),
}).isRequired,
};

OtherSubsidiesCheckIcon.propTypes = {
row: PropTypes.shape({
original: PropTypes.shape({
hasActiveOtherSubsidies: PropTypes.bool,
}),
}).isRequired,
};

export default CustomerDetailRowSubComponent;
140 changes: 140 additions & 0 deletions src/Configuration/Customers/CustomerDataTable/CustomerDetails.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import { useState } from 'react';
import {
Hyperlink,
Icon,
Toast,
} from '@edx/paragon';
import { getConfig } from '@edx/frontend-platform';
import { Check, ContentCopy } from '@edx/paragon/icons';
import PropTypes from 'prop-types';
import ROUTES from '../../../data/constants/routes';

const { HOME } = ROUTES.CONFIGURATION.SUB_DIRECTORY.CUSTOMERS;

export const CustomerDetailLink = ({ row }) => {
const [showToast, setShowToast] = useState(false);
const copyToClipboard = (id) => {
navigator.clipboard.writeText(id);
setShowToast(true);
};
const { ADMIN_PORTAL_BASE_URL } = getConfig();

return (
<div>
<div>
<Hyperlink
destination={`${HOME}/${row.original.slug}/view`}
key={row.original.uuid}
variant="muted"
target="_blank"
showLaunchIcon={false}
className="customer-name"
>
{row.original.name}
</Hyperlink>
</div>
<div>
<Hyperlink
destination={`${ADMIN_PORTAL_BASE_URL}/${row.original.slug}/admin/learners`}
key={row.original.uuid}
variant="muted"
target="_blank"
showLaunchIcon
>
/{row.original.slug}/
</Hyperlink>
<div
role="presentation"
className="pgn-doc__icons-table__preview-footer"
>
<div>{row.original.uuid}</div>
<Icon
key="ContentCopy"
src={ContentCopy}
data-testid="copy"
onClick={() => copyToClipboard(row.original.uuid)}
/>
</div>
</div>
<Toast
onClose={() => setShowToast(false)}
show={showToast}
delay={2000}
>
Copied to clipboard!
</Toast>
</div>
);
};

export const LmsCheck = ({ row }) => {
if (row.original.activeIntegrations.length) {
return (
<Icon src={Check} screenReaderText="Lms Check" />
);
}
return null;
};

export const SSOCheck = ({ row }) => {
if (row.original.activeSsoConfigurations.length) {
return (
<Icon src={Check} screenReaderText="SSO Check" />
);
}
return null;
};

export const ApiCheck = ({ row }) => {
if (row.original.enableGenerationOfApiCredentials) {
return (
<Icon src={Check} screenReaderText="API Check" />
);
}
return null;
};

LmsCheck.propTypes = {
row: PropTypes.shape({
original: PropTypes.shape({
activeIntegrations: PropTypes.arrayOf(PropTypes.shape({
channelCode: PropTypes.string,
created: PropTypes.string,
modified: PropTypes.string,
displayName: PropTypes.string,
active: PropTypes.bool,
})),
}),
}).isRequired,
};

SSOCheck.propTypes = {
row: PropTypes.shape({
original: PropTypes.shape({
activeSsoConfigurations: PropTypes.arrayOf(PropTypes.shape({
created: PropTypes.string,
modified: PropTypes.string,
active: PropTypes.bool,
displayName: PropTypes.string,
})),
}),
}).isRequired,
};

ApiCheck.propTypes = {
row: PropTypes.shape({
original: PropTypes.shape({
enableGenerationOfApiCredentials: PropTypes.bool,
}),
}).isRequired,
};

CustomerDetailLink.propTypes = {
row: PropTypes.shape({
original: PropTypes.shape({
name: PropTypes.string,
uuid: PropTypes.string,
slug: PropTypes.string,
}),
}).isRequired,
};
Loading

0 comments on commit 1c7f1dd

Please sign in to comment.