Skip to content

Commit

Permalink
feat: enable allocation of restricted runs
Browse files Browse the repository at this point in the history
ENT-9411
  • Loading branch information
pwnage101 committed Nov 26, 2024
1 parent 3bb7650 commit ab2a50c
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import {
Badge, breakpoints, Card, Stack, useMediaQuery,
Badge, breakpoints, Card, Skeleton, Stack, useMediaQuery,
} from '@openedx/paragon';
import { camelCaseObject } from '@edx/frontend-platform/utils';

Expand Down Expand Up @@ -35,7 +35,11 @@ const BaseCourseCard = ({
formattedPrice,
isExecEdCourseType,
footerText,
isLoadingRestrictedRuns,
} = courseCardMetadata;
const runPrice = formatPrice(courseRun.contentPrice);
const coursePrice = isLoadingRestrictedRuns ? <Skeleton /> : formattedPrice;
const cardPrice = courseRun ? runPrice : coursePrice;
return (
<Card orientation={isSmall ? 'vertical' : 'horizontal'} className={cardClassName}>
<Card.ImageCap
Expand All @@ -50,7 +54,7 @@ const BaseCourseCard = ({
subtitle={subtitle}
actions={(
<Stack gap={1} className="text-right">
<div className="h4 mt-2.5 mb-0">{courseRun ? formatPrice(courseRun.contentPrice) : formattedPrice}</div>
<div className="h4 mt-2.5 mb-0">{cardPrice}</div>
<span className="micro">
<FormattedMessage
id="lcm.budget.detail.page.catalog.tab.course.card.price.per.learner"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
getAssignableCourseRuns,
getEnrollmentDeadline,
useBudgetId,
useCatalogContainsContentItemsMultipleQueries,
useSubsidyAccessPolicy,
} from '../../data';
import { pluralText } from '../../../../utils';
Expand Down Expand Up @@ -54,10 +55,19 @@ const useCourseCardMetadata = ({
title,
courseRuns,
} = course;
const {
data: catalogContainsRestrictedRunsData,
isLoading: isLoadingcatalogContainsRestrictedRuns,
} = useCatalogContainsContentItemsMultipleQueries(
// Pass only restricted runs.
courseRuns.filter(run => run.restrictionType === 'custom-e2e-enterprise'), // TODO: replace with constant
);

const assignableCourseRuns = getAssignableCourseRuns({
courseRuns,
subsidyExpirationDatetime: subsidyAccessPolicy.subsidyExpirationDatetime,
isLateRedemptionAllowed: subsidyAccessPolicy.isLateRedemptionAllowed,
catalogContainsRestrictedRunsData,
});

// Extracts the content price from assignable course runs
Expand Down Expand Up @@ -98,6 +108,7 @@ const useCourseCardMetadata = ({
linkToCourse,
isExecEdCourseType,
footerText,
isLoading: isLoadingcatalogContainsRestrictedRuns,
};
};

Expand Down
6 changes: 6 additions & 0 deletions src/components/learner-credit-management/data/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,12 @@ export const learnerCreditManagementQueryKeys = {
budgetGroupLearners: (budgetId) => [...learnerCreditManagementQueryKeys.budget(budgetId), 'group learners'],
enterpriseCustomer: (enterpriseId) => [...learnerCreditManagementQueryKeys.all, 'enterpriseCustomer', enterpriseId],
flexGroup: (enterpriseId) => [...learnerCreditManagementQueryKeys.enterpriseCustomer(enterpriseId), 'flexGroup'],
catalog: (catalog) => [...learnerCreditManagementQueryKeys.all, 'catalog', catalog],
catalogContainsContentItem: (catalogUuid, contentKey) => [
...learnerCreditManagementQueryKeys.catalog(catalogUuid),
'containsContentItem',
contentKey,
],
};

// Route to learner credit
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ export { default as useContentMetadata } from './useContentMetadata';
export { default as useEnterpriseRemovedGroupMembers } from './useEnterpriseRemovedGroupMembers';
export { default as useEnterpriseFlexGroups } from './useEnterpriseFlexGroups';
export { default as useGroupDropdownToggle } from './useGroupDropdownToggle';
export { default as useCatalogContainsContentItemsMultipleQueries } from './useCatalogContainsContentItemsMultipleQueries';
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { useQueries } from '@tanstack/react-query';
import { camelCaseObject } from '@edx/frontend-platform/utils';

import EnterpriseCatalogApiServiceV2 from '../../../../data/services/EnterpriseCatalogApiServiceV2';
import { learnerCreditManagementQueryKeys } from '../constants';

/**
* Retrieves a response from the following enterprise-catalog endpoint for a SINGLE content key:
*
* /api/v2/enterprise-catalogs/{uuid}/contains_content_items/?course_run_ids={content_key}
*
* @param {*} queryKey The queryKey from the associated `useQuery` call.
* @returns The contains_content_items response.
*/
const getCatalogContainsContentItem = async ({ queryKey }) => {
const catalogUuid = queryKey[2];
const contentKey = queryKey[4];
const response = await EnterpriseCatalogApiServiceV2.retrieveContainsContentItems(catalogUuid, contentKey);
return camelCaseObject(response.data);
};

const useCatalogContainsContentItemsMultipleQueries = (catalogUuid, contentKeys, { queryOptions } = {}) => {
const multipleResults = useQueries({
queries: contentKeys.map((contentKey) => ({
queryKey: learnerCreditManagementQueryKeys.catalogContainsContentItem(catalogUuid, contentKey),
queryFn: getCatalogContainsContentItem,
...queryOptions,
})),
});
return {
data: multipleResults,
// If at least one query is still loading, then this whole hook is considered to be still loading.
isLoading: multipleResults.some(result => result.isLoading),
};
};

export default useCatalogContainsContentItemsMultipleQueries;
34 changes: 34 additions & 0 deletions src/data/services/EnterpriseCatalogApiServiceV2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';

import { configuration } from '../../config';

class EnterpriseCatalogApiServiceV2 {
static baseUrl = `${configuration.ENTERPRISE_CATALOG_BASE_URL}/api/v2`;

static apiClient = getAuthenticatedHttpClient;

static enterpriseCatalogsUrl = `${EnterpriseCatalogApiServiceV2.baseUrl}/enterprise-catalogs/`;

/**
* Retrieves the enterprise-catalog based contains_content_items endpoint for
* ONE content key:
*
* /api/v2/enterprise-catalogs/{uuid}/contains_content_items/?course_run_ids={content_key}
*
* This endpoint technically supports an arbitrary number of content keys,
* but this function only supports one.
*
* @param {*} catalogUuid The catalog to check for content inclusion.
* @param {*} contentKey The content to check for inclusion in the requested catalog.
*/
static retrieveContainsContentItems(catalogUuid, contentKey) {
const queryParams = new URLSearchParams();
queryParams.append('course_run_ids', contentKey);
const baseCatalogUrl = `${EnterpriseCatalogApiServiceV2.enterpriseCatalogsUrl}${catalogUuid}`;
return EnterpriseCatalogApiServiceV2.apiClient().get(
`${baseCatalogUrl}/contains_content_items/?${queryParams.toString()}`,
);
}
}

export default EnterpriseCatalogApiServiceV2;

0 comments on commit ab2a50c

Please sign in to comment.