Skip to content

Commit

Permalink
feat: create zero state for bnr (#1179)
Browse files Browse the repository at this point in the history
* feat: create zero state for bnr

* fix: PR requests
  • Loading branch information
kiram15 committed Mar 7, 2024
1 parent 853c8e3 commit 09da1ff
Show file tree
Hide file tree
Showing 8 changed files with 151 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Button, Card } from '@edx/paragon';
import {
formatDate, formatPrice, useBudgetId, usePathToCatalogTab, useSubsidyAccessPolicy,
} from './data';
import nameYourLearner from './assets/nameYourLearners.svg';
import nameYourLearner from './assets/reading.svg';

const AssignMoreCoursesEmptyStateMinimal = () => {
const { subsidyAccessPolicyId } = useBudgetId();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import { Stack, Skeleton } from '@edx/paragon';
import BudgetDetailRedemptions from './BudgetDetailRedemptions';
import BudgetDetailAssignments from './BudgetDetailAssignments';
import { useBudgetDetailActivityOverview, useBudgetId, useSubsidyAccessPolicy } from './data';
import NoBudgetActivityEmptyState from './NoBudgetActivityEmptyState';
import NoAssignableBudgetActivity from './empty-state/NoAssignableBudgetActivity';
import NoBnEBudgetActivity from './empty-state/NoBnEBudgetActivity';

const BudgetDetailActivityTabContents = ({ enterpriseUUID, enterpriseFeatures }) => {
const isTopDownAssignmentEnabled = enterpriseFeatures.topDownAssignmentRealTimeLcm;
Expand All @@ -32,19 +33,22 @@ const BudgetDetailActivityTabContents = ({ enterpriseUUID, enterpriseFeatures })
);
}

const hasSpentTransactions = budgetActivityOverview.spentTransactions?.count > 0;
const hasContentAssignments = budgetActivityOverview.contentAssignments?.count > 0;

if (!isTopDownAssignmentEnabled || !subsidyAccessPolicy?.isAssignable) {
return <BudgetDetailRedemptions />;
return (
<>
{!hasSpentTransactions && (<NoBnEBudgetActivity />)}
<BudgetDetailRedemptions />
</>
);
}

const hasContentAssignments = !!budgetActivityOverview.contentAssignments?.count > 0;
const hasSpentTransactions = !!budgetActivityOverview.spentTransactions?.count > 0;

// If there is no activity whatsoever (no assignments, no spent transactions), show the
// full empty state.
if (!hasContentAssignments && !hasSpentTransactions) {
return (
<NoBudgetActivityEmptyState />
);
return <NoAssignableBudgetActivity />;
}

// Otherwise, render the contents of the "Activity" tab.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ import { sendEnterpriseTrackEvent } from '@edx/frontend-enterprise-utils';
import { Link } from 'react-router-dom';
import { connect } from 'react-redux';

import { useIsLargeOrGreater, usePathToCatalogTab } from './data';
import nameYourLearners from './assets/nameYourLearners.svg';
import findTheRightCourse from './assets/findTheRightCourse.svg';
import confirmSpend from './assets/confirmSpend.svg';
import EVENT_NAMES from '../../eventTracking';
import { useIsLargeOrGreater, usePathToCatalogTab } from '../data';
import findTheRightCourse from '../assets/phoneScroll.svg';
import nameYourLearners from '../assets/reading.svg';
import confirmSpend from '../assets/wallet.svg';
import EVENT_NAMES from '../../../eventTracking';

const FindTheRightCourseIllustration = (props) => (
<img data-testid="find-the-right-course-illustration" src={findTheRightCourse} alt="" {...props} />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import React from 'react';
import classNames from 'classnames';
import {
Button, Card, Row, Col,
} from '@edx/paragon';
import { Link } from 'react-router-dom';

import { useIsLargeOrGreater } from '../data';
import nameYourMembers from '../assets/reading.svg';
import memberBrowse from '../assets/phoneScroll.svg';
import enrollAndSpend from '../assets/wallet.svg';

const NameYourMembersIllustration = (props) => (
<img data-testid="name-your-members-illustration" src={nameYourMembers} alt="" {...props} />
);

const MemberBrowseIllustration = (props) => (
<img data-testid="members-browse-illustration" src={memberBrowse} alt="" {...props} />
);

const EnrollAndSpendIllustration = (props) => (
<img data-testid="enroll-and-spend-illustration" src={enrollAndSpend} alt="" {...props} />
);

const NoBnEBudgetActivity = () => {
const isLargeOrGreater = useIsLargeOrGreater();

return (
<Card className="mb-4">
<Card.Section className={classNames('text-center', { 'bg-light-300': isLargeOrGreater })}>
<h3 className={classNames({ 'mb-4.5': isLargeOrGreater })}>
No budget activity yet? Invite members to browse the catalog and enroll!
</h3>
{isLargeOrGreater && (
<Row>
<Col>
<NameYourMembersIllustration />
</Col>
<Col>
<MemberBrowseIllustration />
</Col>
<Col>
<EnrollAndSpendIllustration />
</Col>
</Row>
)}
</Card.Section>
<Card.Section className="text-center">
<Row className={classNames({ 'mb-5': isLargeOrGreater })}>
<Col className="mb-5 mb-lg-0">
{!isLargeOrGreater && <NameYourMembersIllustration className="mb-5" />}
<h4>
<span className="d-block text-brand mb-2">01</span>
Name your members
</h4>
<span>
Upload or enter email addresses to invite people to browse and enroll
using this budget.
</span>
</Col>
<Col className="mb-5 mb-lg-0">
{!isLargeOrGreater && <MemberBrowseIllustration className="mb-5" />}
<h4>
<span className="d-block text-brand mb-2">02</span>
Members find the right course
</h4>
<span>
Members can then browse the catalog associated with this budget and
find a course that aligns with their interests.
</span>
</Col>
<Col className="mb-5 mb-lg-0">
{!isLargeOrGreater && <EnrollAndSpendIllustration className="mb-5" />}
<h4>
<span className="d-block text-brand mb-2">03</span>
Members can enroll and spend
</h4>
<span>
Members can enroll in courses, subject to any limits in this budget&apos;s
settings. The deducted costs from this budget will be visible right here
in your budget activity!
</span>
</Col>
</Row>
<Row>
<Col>
<Button
as={Link}
>
Get started
</Button>
</Col>
</Row>
</Card.Section>
</Card>
);
};

export default NoBnEBudgetActivity;
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ describe('<BudgetDetailPage />', () => {
it.each([
{ isLargeViewport: true },
{ isLargeViewport: false },
])('displays budget activity overview empty state', async ({ isLargeViewport }) => {
])('displays assignable budget activity overview empty state', async ({ isLargeViewport }) => {
useIsLargeOrGreater.mockReturnValue(isLargeViewport);
useParams.mockReturnValue({
enterpriseSlug: 'test-enterprise-slug',
Expand All @@ -472,6 +472,39 @@ describe('<BudgetDetailPage />', () => {
await waitFor(() => expect(sendEnterpriseTrackEvent).toHaveBeenCalledTimes(1));
});

it.each([
{ isLargeViewport: true },
{ isLargeViewport: false },
])('displays bnr budget activity overview empty state', async ({ isLargeViewport }) => {
useIsLargeOrGreater.mockReturnValue(isLargeViewport);
useParams.mockReturnValue({
enterpriseSlug: 'test-enterprise-slug',
enterpriseAppPage: 'test-enterprise-page',
budgetId: 'a52e6548-649f-4576-b73f-c5c2bee25e9c',
activeTabKey: 'activity',
});
useSubsidyAccessPolicy.mockReturnValue({
isInitialLoading: false,
data: mockPerLearnerSpendLimitSubsidyAccessPolicy,
});
useBudgetDetailActivityOverview.mockReturnValue({
isLoading: false,
data: mockEmptyStateBudgetDetailActivityOverview,
});
useBudgetRedemptions.mockReturnValue({
isLoading: false,
budgetRedemptions: mockEmptyBudgetRedemptions,
fetchBudgetRedemptions: jest.fn(),
});
renderWithRouter(<BudgetDetailPageWrapper />);

// Overview empty state (no content assignments, no spent transactions)
expect(screen.getByText('No budget activity yet? Invite members to browse the catalog and enroll!')).toBeInTheDocument();
const illustrationTestIds = ['name-your-members-illustration', 'members-browse-illustration', 'enroll-and-spend-illustration'];
illustrationTestIds.forEach(testId => expect(screen.getByTestId(testId)).toBeInTheDocument());
expect(screen.getByText('Get started', { selector: 'a' })).toBeInTheDocument();
});

it.each([
{
budgetId: mockEnterpriseOfferId,
Expand Down

0 comments on commit 09da1ff

Please sign in to comment.