Bw/responsive api actions (#20)
This commit is contained in:
@@ -2,8 +2,6 @@
|
||||
|
||||
.course-card {
|
||||
.card {
|
||||
overflow: hidden;
|
||||
|
||||
.pgn__card-image-cap {
|
||||
border-bottom-left-radius: 0 !important;
|
||||
}
|
||||
|
||||
@@ -11,10 +11,12 @@ exports[`CourseCard component snapshot: collapsed 1`] = `
|
||||
<div
|
||||
className="d-flex flex-column w-100"
|
||||
>
|
||||
<CourseCardContent
|
||||
cardId="test-card-id"
|
||||
orientation="vertical"
|
||||
/>
|
||||
<div>
|
||||
<CourseCardContent
|
||||
cardId="test-card-id"
|
||||
orientation="vertical"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="course-card-banners"
|
||||
data-testid="CourseCardBanners"
|
||||
|
||||
@@ -19,14 +19,9 @@ export const CourseCard = ({
|
||||
<div className="mb-4.5 course-card" data-testid="CourseCard">
|
||||
<Card orientation={orientation}>
|
||||
<div className="d-flex flex-column w-100">
|
||||
{isCollapsed
|
||||
? (
|
||||
<CourseCardContent cardId={cardId} orientation={orientation} />
|
||||
) : (
|
||||
<div className="d-flex">
|
||||
<CourseCardContent cardId={cardId} orientation={orientation} />
|
||||
</div>
|
||||
)}
|
||||
<div {...(!isCollapsed && { className: 'd-flex' })}>
|
||||
<CourseCardContent cardId={cardId} orientation={orientation} />
|
||||
</div>
|
||||
<div className="course-card-banners" data-testid="CourseCardBanners">
|
||||
<CourseCardBanners cardId={cardId} />
|
||||
</div>
|
||||
|
||||
@@ -3,11 +3,16 @@ import PropTypes from 'prop-types';
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import {
|
||||
Form,
|
||||
Button,
|
||||
Form,
|
||||
Icon,
|
||||
ModalPopup,
|
||||
Sheet,
|
||||
breakpoints,
|
||||
useWindowSize,
|
||||
ModalCloseButton,
|
||||
} from '@edx/paragon';
|
||||
import { Tune } from '@edx/paragon/icons';
|
||||
import { Close, Tune } from '@edx/paragon/icons';
|
||||
|
||||
import FilterForm from './components/FilterForm';
|
||||
import SortForm from './components/SortForm';
|
||||
@@ -35,6 +40,9 @@ export const CourseFilterControls = ({
|
||||
setFilters,
|
||||
setSortBy,
|
||||
});
|
||||
const { width } = useWindowSize();
|
||||
const isMobile = width < breakpoints.small.minWidth;
|
||||
|
||||
return (
|
||||
<div id="course-filter-controls">
|
||||
<Button
|
||||
@@ -45,27 +53,53 @@ export const CourseFilterControls = ({
|
||||
>
|
||||
{formatMessage(messages.refine)}
|
||||
</Button>
|
||||
<ModalPopup
|
||||
positionRef={target}
|
||||
isOpen={isOpen}
|
||||
onClose={close}
|
||||
placement="bottom-end"
|
||||
>
|
||||
<Form>
|
||||
<div
|
||||
id="course-filter-controls-card"
|
||||
className="bg-white p-3 rounded shadow d-flex flex-row"
|
||||
>
|
||||
<div className="filter-form-col">
|
||||
<FilterForm {...{ filters, handleFilterChange }} />
|
||||
</div>
|
||||
<hr className="h-100 bg-primary-200 m-1" />
|
||||
<div className="filter-form-col text-left m-1">
|
||||
<SortForm {...{ sortBy, handleSortChange }} />
|
||||
</div>
|
||||
</div>
|
||||
</Form>
|
||||
</ModalPopup>
|
||||
<Form>
|
||||
{isMobile
|
||||
? (
|
||||
<Sheet
|
||||
className="w-75"
|
||||
position="left"
|
||||
show={isOpen}
|
||||
onClose={close}
|
||||
>
|
||||
<div className="p-1 mr-3">
|
||||
<b>Refine</b>
|
||||
</div>
|
||||
<hr />
|
||||
<div className="filter-form-row">
|
||||
<FilterForm {...{ filters, handleFilterChange }} />
|
||||
</div>
|
||||
<div className="filter-form-row text-left m-1">
|
||||
<SortForm {...{ sortBy, handleSortChange }} />
|
||||
</div>
|
||||
<div className="pgn__modal-close-container">
|
||||
<ModalCloseButton variant="tertiary" onClick={close}>
|
||||
<Icon src={Close} />
|
||||
</ModalCloseButton>
|
||||
</div>
|
||||
</Sheet>
|
||||
) : (
|
||||
<ModalPopup
|
||||
positionRef={target}
|
||||
isOpen={isOpen}
|
||||
onClose={close}
|
||||
placement="bottom-end"
|
||||
>
|
||||
<div
|
||||
id="course-filter-controls-card"
|
||||
className="bg-white p-3 rounded shadow d-flex flex-row"
|
||||
>
|
||||
<div className="filter-form-col">
|
||||
<FilterForm {...{ filters, handleFilterChange }} />
|
||||
</div>
|
||||
<hr className="h-100 bg-primary-200 m-1" />
|
||||
<div className="filter-form-col text-left m-1">
|
||||
<SortForm {...{ sortBy, handleSortChange }} />
|
||||
</div>
|
||||
</div>
|
||||
</ModalPopup>
|
||||
)}
|
||||
</Form>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
.pgn__sheet-component {
|
||||
max-width: 75% !important;
|
||||
width: 75% !important;
|
||||
|
||||
.filter-form-heading {
|
||||
font-weight: bold;
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
#course-filter-controls-card {
|
||||
width: 512px;
|
||||
height: 288px;
|
||||
|
||||
@@ -4,6 +4,7 @@ exports[`SelectSessionModal snapshot empty modal with leave option 1`] = `
|
||||
<ModalDialog
|
||||
className="p-4 px-4.5"
|
||||
hasCloseButton={false}
|
||||
isFullscreenOnMobile={true}
|
||||
isOpen={true}
|
||||
onClose={[MockFunction hooks.nullMethod]}
|
||||
size="md"
|
||||
@@ -47,6 +48,7 @@ exports[`SelectSessionModal snapshot modal with leave option 1`] = `
|
||||
<ModalDialog
|
||||
className="p-4 px-4.5"
|
||||
hasCloseButton={false}
|
||||
isFullscreenOnMobile={true}
|
||||
isOpen={true}
|
||||
onClose={[MockFunction hooks.nullMethod]}
|
||||
size="md"
|
||||
@@ -114,6 +116,7 @@ exports[`SelectSessionModal snapshot modal without leave option 1`] = `
|
||||
<ModalDialog
|
||||
className="p-4 px-4.5"
|
||||
hasCloseButton={false}
|
||||
isFullscreenOnMobile={true}
|
||||
isOpen={true}
|
||||
onClose={[MockFunction hooks.nullMethod]}
|
||||
size="md"
|
||||
|
||||
@@ -35,6 +35,7 @@ export const SelectSessionModal = () => {
|
||||
isOpen={showModal}
|
||||
onClose={nullMethod}
|
||||
hasCloseButton={false}
|
||||
isFullscreenOnMobile
|
||||
size="md"
|
||||
className="p-4 px-4.5"
|
||||
title={header}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
exports[`UnenrollConfirmModal component snapshot: modalStates.confirm 1`] = `
|
||||
<ModalDialog
|
||||
hasCloseButton={false}
|
||||
isFullscreenOnMobile={false}
|
||||
isOpen={true}
|
||||
onClose={[MockFunction hooks.nullMethod]}
|
||||
title=""
|
||||
@@ -26,6 +27,7 @@ exports[`UnenrollConfirmModal component snapshot: modalStates.confirm 1`] = `
|
||||
exports[`UnenrollConfirmModal component snapshot: modalStates.finished, reason given 1`] = `
|
||||
<ModalDialog
|
||||
hasCloseButton={false}
|
||||
isFullscreenOnMobile={false}
|
||||
isOpen={true}
|
||||
onClose={[MockFunction hooks.nullMethod]}
|
||||
title=""
|
||||
@@ -49,6 +51,7 @@ exports[`UnenrollConfirmModal component snapshot: modalStates.finished, reason g
|
||||
exports[`UnenrollConfirmModal component snapshot: modalStates.finished, reason skipped 1`] = `
|
||||
<ModalDialog
|
||||
hasCloseButton={false}
|
||||
isFullscreenOnMobile={false}
|
||||
isOpen={true}
|
||||
onClose={[MockFunction hooks.nullMethod]}
|
||||
title=""
|
||||
@@ -69,15 +72,16 @@ exports[`UnenrollConfirmModal component snapshot: modalStates.finished, reason s
|
||||
</ModalDialog>
|
||||
`;
|
||||
|
||||
exports[`UnenrollConfirmModal component snapshot: modalStates.reason 1`] = `
|
||||
exports[`UnenrollConfirmModal component snapshot: modalStates.reason, should be fullscreen with no shadow 1`] = `
|
||||
<ModalDialog
|
||||
hasCloseButton={false}
|
||||
isFullscreenOnMobile={true}
|
||||
isOpen={true}
|
||||
onClose={[MockFunction hooks.nullMethod]}
|
||||
title=""
|
||||
>
|
||||
<div
|
||||
className="bg-white p-3 rounded shadow"
|
||||
className="bg-white p-3 rounded"
|
||||
style={
|
||||
Object {
|
||||
"textAlign": "start",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
@@ -26,14 +27,19 @@ export const UnenrollConfirmModal = ({
|
||||
close,
|
||||
modalState,
|
||||
} = useUnenrollData({ dispatch, closeModal });
|
||||
const showFullscreen = modalState === modalStates.reason;
|
||||
return (
|
||||
<ModalDialog
|
||||
isOpen={show}
|
||||
onClose={nullMethod}
|
||||
hasCloseButton={false}
|
||||
isFullscreenOnMobile={showFullscreen}
|
||||
title=""
|
||||
>
|
||||
<div className="bg-white p-3 rounded shadow" style={{ textAlign: 'start' }}>
|
||||
<div
|
||||
className={classNames('bg-white p-3 rounded', { shadow: !showFullscreen })}
|
||||
style={{ textAlign: 'start' }}
|
||||
>
|
||||
{(modalState === modalStates.confirm) && (
|
||||
<ConfirmPane handleClose={close} handleConfirm={confirm} />
|
||||
)}
|
||||
|
||||
@@ -51,7 +51,7 @@ describe('UnenrollConfirmModal component', () => {
|
||||
});
|
||||
expect(shallow(<UnenrollConfirmModal {...{ closeModal, show }} />)).toMatchSnapshot();
|
||||
});
|
||||
test('snapshot: modalStates.reason', () => {
|
||||
test('snapshot: modalStates.reason, should be fullscreen with no shadow', () => {
|
||||
hooks.useUnenrollData.mockReturnValueOnce({ ...hookProps, modalState: hooks.modalStates.reason });
|
||||
expect(shallow(<UnenrollConfirmModal {...{ closeModal, show }} />)).toMatchSnapshot();
|
||||
});
|
||||
|
||||
@@ -10,8 +10,11 @@ export const RequestStates = StrictDict({
|
||||
export const RequestKeys = StrictDict({
|
||||
initialize: 'initialize',
|
||||
refreshList: 'refreshList',
|
||||
enrollEntitlementSession: 'enrollEntitlementSession',
|
||||
leaveEntitlementSession: 'leaveEntitlementSession',
|
||||
newEntitlementEnrollment: 'newEntitlementEnrollment',
|
||||
leaveEntitlementEnrollment: 'leaveEntitlementEnrollment',
|
||||
switchEntitlementSession: 'switchEntitlementSession',
|
||||
unenrollFromCourse: 'unenrollFromCourse',
|
||||
updateEmailSettings: 'updateEmailSettings',
|
||||
});
|
||||
|
||||
export const ErrorCodes = StrictDict({
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { StrictDict } from 'utils';
|
||||
import { handleEvent } from 'data/services/segment/utils';
|
||||
import { eventNames } from 'data/services/segment/constants';
|
||||
import { actions, selectors } from 'data/redux';
|
||||
import { post } from 'data/services/lms/utils';
|
||||
|
||||
@@ -36,25 +38,54 @@ export const sendConfirmEmail = () => (dispatch, getState) => post(
|
||||
selectors.app.emailConfirmation(getState()).sendEmailUrl,
|
||||
);
|
||||
|
||||
export const updateEntitlementSession = (cardId, selection) => (dispatch, getState) => {
|
||||
const entitlement = selectors.app.courseCard.entitlement(getState(), cardId);
|
||||
const { uuid } = entitlement;
|
||||
console.log({
|
||||
cardId,
|
||||
selection,
|
||||
entitlement,
|
||||
uuid,
|
||||
export const newEntitlementEnrollment = (cardId, selection) => (dispatch, getState) => {
|
||||
const { uuid } = selectors.app.courseCard.entitlement(getState(), cardId);
|
||||
handleEvent(eventNames.sessionChange({ action: 'new' }), {
|
||||
fromCourseRun: null,
|
||||
toCourseRun: selection,
|
||||
});
|
||||
return dispatch(requests.newEntitlementEnrollment({ uuid, courseId: selection }));
|
||||
};
|
||||
|
||||
export const unenroll = (courseId) => (dispatch, getState) => post(
|
||||
selectors.app.courseCard.courseRun(getState(), courseId),
|
||||
).then(() => dispatch(module.refreshList()));
|
||||
export const switchEntitlementEnrollment = (cardId, selection) => (dispatch, getState) => {
|
||||
const { courseId } = selectors.app.courseCard.courseRun(getState(), cardId);
|
||||
const { uuid } = selectors.app.courseCard.entitlement(getState(), cardId);
|
||||
handleEvent(eventNames.sessionChange({ action: 'switch' }), {
|
||||
fromCourseRun: courseId,
|
||||
toCourseRun: selection,
|
||||
});
|
||||
return dispatch(requests.switchEntitlementEnrollment({ uuid, courseId: selection }));
|
||||
};
|
||||
|
||||
export const leaveEntitlementSession = (cardId) => (dispatch, getState) => {
|
||||
const { courseId } = selectors.app.courseCard.courseRun(getState(), cardId);
|
||||
const { uuid } = selectors.app.courseCard.entitlement(getState(), cardId);
|
||||
handleEvent(eventNames.entitlementUnenroll({ action: 'leave' }), {
|
||||
fromCourseRun: courseId,
|
||||
toCourseRun: null,
|
||||
});
|
||||
return dispatch(requests.leaveEntitlementSession({ uuid }));
|
||||
};
|
||||
|
||||
export const unenrollFromCourse = (courseId, reason) => (dispatch) => {
|
||||
handleEvent(eventNames.unenrollReason, {
|
||||
category: 'user-engagement',
|
||||
displayName: 'v1',
|
||||
label: reason,
|
||||
course_id: courseId,
|
||||
});
|
||||
dispatch(requests.unenrollFromCourse({
|
||||
courseId,
|
||||
onSuccess: () => dispatch(module.refreshList()),
|
||||
}));
|
||||
};
|
||||
|
||||
export default StrictDict({
|
||||
initialize,
|
||||
refreshList,
|
||||
sendConfirmEmail,
|
||||
updateEntitlementSession,
|
||||
unenroll,
|
||||
newEntitlementEnrollment,
|
||||
switchEntitlementEnrollment,
|
||||
leaveEntitlementSession,
|
||||
unenrollFromCourse,
|
||||
});
|
||||
|
||||
@@ -4,7 +4,7 @@ import { RequestKeys } from 'data/constants/requests';
|
||||
import { actions } from 'data/redux';
|
||||
import api from 'data/services/lms/api';
|
||||
|
||||
// import * as module from './requests';
|
||||
import * as module from './requests';
|
||||
|
||||
/**
|
||||
* Wrapper around a network request promise, that sends actions to the redux store to
|
||||
@@ -33,44 +33,62 @@ export const networkRequest = ({
|
||||
});
|
||||
};
|
||||
|
||||
export const initializeList = ({ onSuccess, onFailure }) => (dispatch) => {
|
||||
dispatch(networkRequest({
|
||||
requestKey: RequestKeys.initialize,
|
||||
onFailure,
|
||||
onSuccess,
|
||||
promise: api.initializeList(),
|
||||
}));
|
||||
};
|
||||
export const networkAction = (requestKey, promise, options) => (dispatch) => (
|
||||
dispatch(module.networkRequest({
|
||||
requestKey,
|
||||
promise,
|
||||
...options,
|
||||
})));
|
||||
|
||||
export const updateEntitlementEnrollment = ({
|
||||
export const initializeList = (options) => module.networkAction(
|
||||
RequestKeys.initialize,
|
||||
api.initializeList(),
|
||||
options,
|
||||
);
|
||||
|
||||
export const newEntitlementEnrollment = ({
|
||||
uuid,
|
||||
courseId,
|
||||
onSuccess,
|
||||
onFailure,
|
||||
}) => (dispatch) => {
|
||||
dispatch(networkRequest({
|
||||
requestKey: RequestKeys.enrollEntitlementSession,
|
||||
onFailure,
|
||||
onSuccess,
|
||||
promise: api.updateEntitlementEnrollment({ uuid, courseId }),
|
||||
}));
|
||||
};
|
||||
...options
|
||||
}) => module.networkAction(
|
||||
RequestKeys.newEntitlementEnrollment,
|
||||
api.updateEntitlementEnrollment({ uuid, courseId }),
|
||||
options,
|
||||
);
|
||||
|
||||
export const leaveEntitlementSession = ({
|
||||
export const switchEntitlementEnrollment = ({
|
||||
uuid,
|
||||
onSuccess,
|
||||
onFailure,
|
||||
}) => (dispatch) => {
|
||||
dispatch(networkRequest({
|
||||
requestKey: RequestKeys.leaveEntitlementSession,
|
||||
onFailure,
|
||||
onSuccess,
|
||||
promise: api.leaveEntitlementEnrollment({ uuid }),
|
||||
}));
|
||||
};
|
||||
courseId,
|
||||
...options
|
||||
}) => module.networkAction(
|
||||
RequestKeys.switchEntitlementSession,
|
||||
api.updateEntitlementEnrollment({ uuid, courseId }),
|
||||
options,
|
||||
);
|
||||
|
||||
export const leaveEntitlementSession = ({ uuid, ...options }) => module.networkAction(
|
||||
RequestKeys.leaveEntitlementSession,
|
||||
api.leaveEntitlementEnrollment({ uuid }),
|
||||
options,
|
||||
);
|
||||
|
||||
export const unenrollFromCourse = ({ courseId, ...options }) => module.networkAction(
|
||||
RequestKeys.unenrollFromCourse,
|
||||
api.unenrollFromCourse({ courseId }),
|
||||
options,
|
||||
);
|
||||
|
||||
export const updateEmailSettings = ({ courseId, enable, ...options }) => module.networkAction(
|
||||
RequestKeys.updateEmailSettings,
|
||||
api.updateEmailSettings({ courseId, enable }),
|
||||
options,
|
||||
);
|
||||
|
||||
export default StrictDict({
|
||||
initializeList,
|
||||
updateEntitlementEnrollment,
|
||||
leaveEntitlementSession,
|
||||
newEntitlementEnrollment,
|
||||
switchEntitlementEnrollment,
|
||||
unenrollFromCourse,
|
||||
updateEmailSettings,
|
||||
});
|
||||
|
||||
@@ -21,8 +21,20 @@ const deleteEntitlementEnrollment = ({ uuid }) => client().delete(stringifyUrl(
|
||||
{ course_run_id: null },
|
||||
));
|
||||
|
||||
const updateEmailSettings = ({ courseId, enable }) => post(stringifyUrl(
|
||||
urls.updateEmailSettings,
|
||||
{ course_id: courseId, ...(enable && { receive_emails: 'on' }) },
|
||||
));
|
||||
|
||||
const unenrollFromCourse = ({ courseId }) => post(stringifyUrl(
|
||||
urls.unenrollFromCourse,
|
||||
{ course_id: courseId, enrollment_action: 'unenroll' },
|
||||
));
|
||||
|
||||
export default {
|
||||
initializeList,
|
||||
unenrollFromCourse,
|
||||
updateEmailSettings,
|
||||
updateEntitlementEnrollment,
|
||||
deleteEntitlementEnrollment,
|
||||
};
|
||||
|
||||
@@ -6,10 +6,14 @@ const baseUrl = `${configuration.LMS_BASE_URL}`;
|
||||
const api = `${baseUrl}/api/`;
|
||||
const init = `${api}learner_home/mock/init`;
|
||||
|
||||
const courseUnenroll = `${api}/courses/unenroll`; // TODO: Fix
|
||||
const updateEmailSettings = `${api}/change_email_settings`;
|
||||
const entitlementEnrollment = (uuid) => `${api}/entitlements/v1/entitlements/${uuid}/enrollments`;
|
||||
|
||||
export default StrictDict({
|
||||
api,
|
||||
init,
|
||||
courseUnenroll,
|
||||
updateEmailSettings,
|
||||
entitlementEnrollment,
|
||||
});
|
||||
|
||||
19
src/data/services/segment/constants.js
Normal file
19
src/data/services/segment/constants.js
Normal file
@@ -0,0 +1,19 @@
|
||||
import { StrictDict } from 'utils';
|
||||
|
||||
export const events = StrictDict({
|
||||
courseEnroll: 'courseEnroll',
|
||||
entitlementUnenroll: 'entitlementUnenroll',
|
||||
sessionChange: 'sessionChange',
|
||||
unenrollReason: 'unenrollReason',
|
||||
});
|
||||
|
||||
export const eventNames = StrictDict({
|
||||
[events.courseEnroll]: 'edx.bi.user.program-details.enrollment',
|
||||
[events.entitlementUnenroll]: 'entitlement_unenrollment_reason.selected',
|
||||
[events.sessionChange]: ({ action }) => `course-dashboard.${action}-session`, // 'switch', 'new', 'leave'
|
||||
[events.unenrollReason]: 'unenrollment_reason.selected',
|
||||
});
|
||||
|
||||
export const trackingCategory = 'learner-home';
|
||||
|
||||
export const pageViewEvent = { category: trackingCategory };
|
||||
18
src/data/services/segment/utils.js
Executable file
18
src/data/services/segment/utils.js
Executable file
@@ -0,0 +1,18 @@
|
||||
/* eslint-disable import/prefer-default-export */
|
||||
import { trackEvent } from '@redux-beacon/segment';
|
||||
import { trackingCategory as category } from './constants';
|
||||
|
||||
export const handleEvent = (name, options = {}) => trackEvent(
|
||||
(event = {}) => {
|
||||
const { payload } = event;
|
||||
const { propsFn, extrasFn } = options;
|
||||
return {
|
||||
name,
|
||||
...(extrasFn && extrasFn(payload)),
|
||||
properties: {
|
||||
category,
|
||||
...(propsFn && propsFn(payload)),
|
||||
},
|
||||
};
|
||||
},
|
||||
);
|
||||
49
src/data/services/segment/utils.test.js
Normal file
49
src/data/services/segment/utils.test.js
Normal file
@@ -0,0 +1,49 @@
|
||||
import * as constants from './constants';
|
||||
import { handleEvent } from './utils';
|
||||
|
||||
jest.mock('@redux-beacon/segment', () => ({
|
||||
trackEvent: (handleFn) => ({ trackEvent: handleFn }),
|
||||
}));
|
||||
|
||||
const category = 'AFakeCategory';
|
||||
describe('segment service utils', () => {
|
||||
beforeAll(() => {
|
||||
global.window = Object.create(window);
|
||||
constants.trackingCategory = category;
|
||||
});
|
||||
|
||||
describe('handleEvent', () => {
|
||||
const name = 'aName';
|
||||
const payload = { field1: 'some data', field2: 'other data' };
|
||||
describe('when called with just a name', () => {
|
||||
it('returns a TrackEvent call with the name and tracking category', () => {
|
||||
const handler = handleEvent(name).trackEvent;
|
||||
expect(handler(payload)).toEqual({
|
||||
name,
|
||||
properties: { category },
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('when a propsFn is provided', () => {
|
||||
it('adds the output of propsFn(event.payload) to properties', () => {
|
||||
const propsFn = ({ field1 }) => ({ field1 });
|
||||
const handler = handleEvent(name, { propsFn }).trackEvent;
|
||||
expect(handler({ payload })).toEqual({
|
||||
name,
|
||||
properties: { category, field1: payload.field1 },
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('when an extrasFn object is provided', () => {
|
||||
it('adds the output of extrasFn(event.payload) to top-level object', () => {
|
||||
const extrasFn = ({ field2 }) => ({ field2 });
|
||||
const handler = handleEvent(name, { extrasFn }).trackEvent;
|
||||
expect(handler({ payload })).toEqual({
|
||||
name,
|
||||
field2: payload.field2,
|
||||
properties: { category },
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user