Skip to content

Commit 06fcadc

Browse files
authored
fix: fixing bug in learning budgets flow (#1689)
* fix: fixing bug in learning budgets flow * fix: PR requests
1 parent ad46e00 commit 06fcadc

File tree

10 files changed

+107
-26
lines changed

10 files changed

+107
-26
lines changed

src/components/ProductTours/AdminOnboardingTours/constants.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ export const ALLOCATE_LEARNING_BUDGETS_TARGETS = {
5353
INVITE_MEMBERS_BUDGET_BUTTON: 'invite-members-button',
5454
TRACK_BUDGET_ACTIVITY: 'track-budget-activity',
5555
BUDGET_TABLE: 'budget-table',
56+
ZERO_STATE_ASSIGN_CARD: 'zero-state-assign-card',
5657
BUDGET_SPENT_TABLE: 'spent-budget-table',
5758
BUDGET_CATALOG_TAB: 'budget-catalog-tab',
5859
BUDGET_MEMBERS_TAB: 'budget-members-tab',

src/components/ProductTours/AdminOnboardingTours/flows/AdminOnboardingTour.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,9 @@ const AdminOnboardingTour = (
7676
const administerSubscriptionsFlow = AdministerSubscriptionsFlow({
7777
currentStep, enterpriseSlug, handleEndTour, handleBackTour, setCurrentStep, targetSelector,
7878
});
79-
const analyticsFlow = AnalyticsFlow({ handleAdvanceTour, handleBackTour, handleEndTour });
79+
const analyticsFlow = AnalyticsFlow({
80+
handleAdvanceTour, handleBackTour, handleEndTour,
81+
});
8082
const customizeReportsFlow = CustomizeReportsFlow({ handleEndTour });
8183
const learnerProgressFlow = LearnerProgressFlow({
8284
handleAdvanceTour, handleBackTour, handleEndTour,
@@ -95,7 +97,6 @@ const AdminOnboardingTour = (
9597
setCurrentStep,
9698
targetSelector,
9799
});
98-
99100
const setUpPreferencesFlow = SetUpPreferencesFlow({ handleEndTour });
100101

101102
// Map target selectors to their respective flows

src/components/ProductTours/AdminOnboardingTours/flows/AllocateLearningBudgetsFlow.tsx

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { useIntl } from '@edx/frontend-platform/i18n';
22
import { sendEnterpriseTrackEvent } from '@edx/frontend-enterprise-utils';
33
import { useParams } from 'react-router';
4+
45
import { ALLOCATE_LEARNING_BUDGETS_TARGETS, ADMIN_TOUR_EVENT_NAMES } from '../constants';
56
import messages from '../messages';
67
import { TourStep } from '../../types';
@@ -67,8 +68,8 @@ const AllocateLearningBudgetsFlow = ({
6768

6869
if (isOnBudgetPage) {
6970
if (policyType === 'Assignment') {
70-
// Assignment budget with spend or assignment activity
71-
if (isOnBudgetPage && (hasSpentTransactions || hasContentAssignments)) {
71+
// Assignment budget with spend and assignment activity
72+
if (hasSpentTransactions && hasContentAssignments) {
7273
return [
7374
{
7475
target: `#${ALLOCATE_LEARNING_BUDGETS_TARGETS.BUDGET_DETAIL_CARD}`,
@@ -113,6 +114,51 @@ const AllocateLearningBudgetsFlow = ({
113114
onEnd: onAllocateEnd,
114115
},
115116
];
117+
} if (hasSpentTransactions && !hasContentAssignments) {
118+
return [
119+
{
120+
target: `#${ALLOCATE_LEARNING_BUDGETS_TARGETS.BUDGET_DETAIL_CARD}`,
121+
placement: 'top',
122+
body: intl.formatMessage(messages.allocateLearningBudgetStepThreeAssignment),
123+
onAdvance: onAllocateAdvance,
124+
}, {
125+
target: `#${ALLOCATE_LEARNING_BUDGETS_TARGETS.NEW_ASSIGNMENT_BUDGET_BUTTON}`,
126+
placement: 'bottom',
127+
body: intl.formatMessage(messages.allocateLearningBudgetStepFourAssignment),
128+
onAdvance: onAllocateAdvance,
129+
onBack: onAllocateBack,
130+
}, {
131+
target: `#${ALLOCATE_LEARNING_BUDGETS_TARGETS.TRACK_BUDGET_ACTIVITY}`,
132+
placement: 'top',
133+
body: intl.formatMessage(messages.allocateLearningBudgetStepFiveAssignment),
134+
onAdvance: onAllocateAdvance,
135+
onBack: onAllocateBack,
136+
}, {
137+
target: `#${ALLOCATE_LEARNING_BUDGETS_TARGETS.ZERO_STATE_ASSIGN_CARD}`,
138+
placement: 'top',
139+
body: intl.formatMessage(messages.allocateLearningBudgetStepSixSpendNoAssignment),
140+
onAdvance: onAllocateAdvance,
141+
onBack: onAllocateBack,
142+
}, {
143+
target: `#${ALLOCATE_LEARNING_BUDGETS_TARGETS.BUDGET_SPENT_TABLE}`,
144+
placement: 'top',
145+
body: intl.formatMessage(messages.allocateLearningBudgetStepSevenAssignment),
146+
onAdvance: onAllocateAdvance,
147+
onBack: onAllocateBack,
148+
}, {
149+
target: `#${ALLOCATE_LEARNING_BUDGETS_TARGETS.BUDGET_CATALOG_TAB}`,
150+
placement: 'top',
151+
body: intl.formatMessage(messages.allocateLearningBudgetStepEightAssignment),
152+
onAdvance: onAllocateAdvance,
153+
onBack: onAllocateBack,
154+
}, {
155+
target: `#${ALLOCATE_LEARNING_BUDGETS_TARGETS.LEARNER_CREDIT_MANAGEMENT_BREADCRUMBS}`,
156+
placement: 'top',
157+
body: intl.formatMessage(messages.allocateLearningBudgetStepNine),
158+
onBack: onAllocateBack,
159+
onEnd: onAllocateEnd,
160+
},
161+
];
116162
// Zero state assignment budget
117163
} if (!hasSpentTransactions && !hasContentAssignments) {
118164
return [
@@ -131,8 +177,7 @@ const AllocateLearningBudgetsFlow = ({
131177
placement: 'top',
132178
body: intl.formatMessage(messages.allocateLearningBudgetStepFiveAssignmentZeroState),
133179
onAdvance: onAllocateAdvance,
134-
},
135-
{
180+
}, {
136181
target: `#${ALLOCATE_LEARNING_BUDGETS_TARGETS.BUDGET_CATALOG_TAB}`,
137182
placement: 'top',
138183
body: intl.formatMessage(messages.allocateLearningBudgetStepSixAssignmentZeroState),

src/components/ProductTours/AdminOnboardingTours/flows/LearnerProgressFlow.tsx

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,6 @@ const LearnerProgressFlow = ({
4343
body: intl.formatMessage(messages.trackLearnerProgressStepFourBody),
4444
onAdvance: onLearnerAdvance,
4545
onBack: onLearnerBack,
46-
}, {
47-
target: `#${TRACK_LEARNER_PROGRESS_TARGETS.MODULE_ACTIVITY}`,
48-
placement: 'top',
49-
body: intl.formatMessage(messages.trackLearnerProgressStepFiveBody),
50-
onBack: onLearnerBack,
51-
onAdvance: onLearnerAdvance,
5246
}, {
5347
target: `#${TRACK_LEARNER_PROGRESS_TARGETS.FILTER}`,
5448
placement: 'top',

src/components/ProductTours/AdminOnboardingTours/messages.js

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -282,9 +282,9 @@ const messages = defineMessages({
282282
description: 'Description for the allocate learning budgets invite-only bne flow step four',
283283
},
284284
allocateLearningBudgetStepFiveAssignment: {
285-
id: 'adminPortal.productTours.adminOnboarding.allocateLearningBudget.body.6.assignment',
285+
id: 'adminPortal.productTours.adminOnboarding.allocateLearningBudget.body.5.assignment',
286286
defaultMessage: 'Track all budget activity, including pending assignments and enrollment spending.',
287-
description: 'Description for the allocate learning budgets assignments flow step six',
287+
description: 'Description for the allocate learning budgets assignments flow step five',
288288
},
289289
allocateLearningBudgetStepFiveAssignmentZeroState: {
290290
id: 'adminPortal.productTours.adminOnboarding.allocateLearningBudget.body.5.assignment.zeroState',
@@ -309,9 +309,14 @@ const messages = defineMessages({
309309
description: 'Description for the allocate learning budgets invite only Browse and Enroll flow step six',
310310
},
311311
allocateLearningBudgetStepSixAssignment: {
312-
id: 'adminPortal.productTours.adminOnboarding.allocateLearningBudget.body.7.assignment',
312+
id: 'adminPortal.productTours.adminOnboarding.allocateLearningBudget.body.6.assignment',
313313
defaultMessage: 'The Assigned table helps you monitor learner assignments, send reminders, or cancel as needed.',
314-
description: 'Description for the allocate learning budgets flow step seven',
314+
description: 'Description for the allocate learning budgets flow step six',
315+
},
316+
allocateLearningBudgetStepSixSpendNoAssignment: {
317+
id: 'adminPortal.productTours.adminOnboarding.allocateLearningBudget.body.6.spendNoAssignment',
318+
defaultMessage: 'Once you assign courses, you can monitor learner assignments, send reminders, or cancel as needed.',
319+
description: 'Description for the allocate learning budgets flow step six for customers that have spend but no assignments.',
315320
},
316321
allocateLearningBudgetStepSevenAssignment: {
317322
id: 'adminPortal.productTours.adminOnboarding.allocateLearningBudget.body.8.assignment',

src/components/ProductTours/AdminOnboardingTours/tests/AllocateLearningBudgetsFlow.test.jsx

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,42 @@ describe('useAllocateLearningBudgetsFlow', () => {
196196
expect(result.current[6].target).toBe('#learner-credit-management-breadcrumbs');
197197
});
198198

199+
it('should return learner credit detail page flow when on detail page with spent transactions and no content assignments', () => {
200+
useBudgetDetailActivityOverview.mockReturnValue({
201+
isLoading: false,
202+
isFetching: false,
203+
data: {
204+
spentTransactions: { count: 1 },
205+
contentAssignments: { count: 0 },
206+
},
207+
});
208+
209+
const props = {
210+
currentStep: 0,
211+
enablePortalLearnerCreditManagementScreen: true,
212+
enterpriseFeatures: {
213+
topDownAssignmentRealTimeLcm: true,
214+
},
215+
enterpriseId: 'test-enterprise-uuid',
216+
enterpriseSlug: 'test-enterprise-slug',
217+
handleBackTour: mockHandleBackTour,
218+
handleEndTour: mockHandleEndTour,
219+
setCurrentStep: mockSetCurrentStep,
220+
targetSelector: '',
221+
};
222+
223+
const { result } = renderHookWithProviders(() => useAllocateLearningBudgetsFlow(props));
224+
225+
expect(result.current).toHaveLength(7);
226+
expect(result.current[0].target).toBe('#budget-detail-card');
227+
expect(result.current[1].target).toBe('#new-assignment-button');
228+
expect(result.current[2].target).toBe('#track-budget-activity');
229+
expect(result.current[3].target).toBe('#zero-state-assign-card');
230+
expect(result.current[4].target).toBe('#spent-budget-table');
231+
expect(result.current[5].target).toBe('#budget-catalog-tab');
232+
expect(result.current[6].target).toBe('#learner-credit-management-breadcrumbs');
233+
});
234+
199235
it('should return learner credit detail page flow when on detail page with no spent transactions and no content assignments', () => {
200236
useBudgetDetailActivityOverview.mockReturnValue({
201237
isLoading: false,

src/components/ProductTours/AdminOnboardingTours/tests/LearnerProgressFlow.test.jsx

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ describe('tourFlows', () => {
3939

4040
const flow = result.current;
4141

42-
expect(flow).toHaveLength(7);
42+
expect(flow).toHaveLength(6);
4343
// can't test equality of onAdvance since it's an anonymous function
4444
expect(flow[0]).toMatchObject({
4545
target: `#${TRACK_LEARNER_PROGRESS_TARGETS.LEARNER_PROGRESS_SIDEBAR}`,
@@ -67,18 +67,12 @@ describe('tourFlows', () => {
6767
});
6868

6969
expect(flow[4]).toMatchObject({
70-
target: `#${TRACK_LEARNER_PROGRESS_TARGETS.MODULE_ACTIVITY}`,
71-
placement: 'top',
72-
body: messages.trackLearnerProgressStepFiveBody.defaultMessage,
73-
});
74-
75-
expect(flow[5]).toMatchObject({
7670
target: `#${TRACK_LEARNER_PROGRESS_TARGETS.FILTER}`,
7771
placement: 'top',
7872
body: messages.trackLearnerProgressStepSixBody.defaultMessage,
7973
});
8074

81-
expect(flow[6]).toMatchObject({
75+
expect(flow[5]).toMatchObject({
8276
target: `#${TRACK_LEARNER_PROGRESS_TARGETS.CSV_DOWNLOAD}`,
8377
placement: 'top',
8478
body: messages.trackLearnerProgressStepSevenBody.defaultMessage,
@@ -99,7 +93,6 @@ describe('tourFlows', () => {
9993
expect(mockFormatMessage).toHaveBeenCalledWith(messages.trackLearnerProgressStepTwoBody);
10094
expect(mockFormatMessage).toHaveBeenCalledWith(messages.trackLearnerProgressStepThreeBody);
10195
expect(mockFormatMessage).toHaveBeenCalledWith(messages.trackLearnerProgressStepFourBody);
102-
expect(mockFormatMessage).toHaveBeenCalledWith(messages.trackLearnerProgressStepFiveBody);
10396
expect(mockFormatMessage).toHaveBeenCalledWith(messages.trackLearnerProgressStepSixBody);
10497
expect(mockFormatMessage).toHaveBeenCalledWith(messages.trackLearnerProgressStepSevenBody);
10598
});

src/components/ProductTours/TourCollapsible.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ const TourCollapsible: FC<Props> = (
7272
const [onboardingSteps, setOnboardingSteps] = useState<StepDefinition[] | undefined>();
7373
const [showCompletedModal, setShowCompletedModal] = useState(false);
7474
const { data: onboardingTourData } = useFetchCompletedOnboardingFlows(adminUuid);
75+
const { canManageLearnerCredit } = useContext(EnterpriseSubsidiesContext);
7576
const { isLoadingCustomerAgreement, customerAgreement } = useContext(EnterpriseSubsidiesContext);
7677

7778
const handleDismiss = () => {
@@ -146,6 +147,8 @@ const TourCollapsible: FC<Props> = (
146147
&& (!isLoadingCustomerAgreement && !isEmpty(customerAgreement?.subscriptions));
147148
case CUSTOMIZE_REPORTS_TITLE:
148149
return enableReportingConfigScreen;
150+
case ALLOCATE_LEARNING_BUDGET_TITLE:
151+
return canManageLearnerCredit;
149152
default:
150153
return true;
151154
}
@@ -166,6 +169,7 @@ const TourCollapsible: FC<Props> = (
166169
}
167170
setOnboardingSteps(steps);
168171
}, [
172+
canManageLearnerCredit,
169173
onboardingTourData?.completedTourFlows,
170174
onboardingTourData?.onboardingTourCompleted,
171175
enableReportingConfigScreen,

src/components/ProductTours/tests/TourCollapsible.test.jsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ const defaultState = {
7070

7171
const defaultEnterpriseSubsidiesContextValue = {
7272
isLoadingCustomerAgreement: false,
73+
canManageLearnerCredit: true,
7374
customerAgreement: {
7475
subscriptions: [{ contents: 'unimportant' }],
7576
},

src/components/learner-credit-management/AssignMoreCoursesEmptyStateMinimal.jsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
formatDate, formatPrice, useBudgetId, usePathToCatalogTab, useSubsidyAccessPolicy,
88
} from './data';
99
import nameYourLearner from './assets/reading.svg';
10+
import { ALLOCATE_LEARNING_BUDGETS_TARGETS } from '../ProductTours/AdminOnboardingTours/constants';
1011

1112
const AssignMoreCoursesEmptyStateMinimal = () => {
1213
const { subsidyAccessPolicyId } = useBudgetId();
@@ -21,7 +22,7 @@ const AssignMoreCoursesEmptyStateMinimal = () => {
2122
const subsidyExpirationDate = subsidyAccessPolicy.subsidyExpirationDatetime;
2223

2324
return (
24-
<Card className="assign-more-courses-empty-state-minimal" orientation="horizontal">
25+
<Card id={ALLOCATE_LEARNING_BUDGETS_TARGETS.ZERO_STATE_ASSIGN_CARD} className="assign-more-courses-empty-state-minimal" orientation="horizontal">
2526
<Card.ImageCap
2627
src={nameYourLearner}
2728
className="bg-light-300 d-flex justify-content-center py-3"

0 commit comments

Comments
 (0)