Skip to content

Commit

Permalink
feat: add experiment and eventing to recommendations painted door exp (
Browse files Browse the repository at this point in the history
  • Loading branch information
syedsajjadkazmii committed Aug 18, 2023
2 parents 30fadad + 05bdf4e commit 736abb4
Show file tree
Hide file tree
Showing 23 changed files with 391 additions and 142 deletions.
9 changes: 9 additions & 0 deletions public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="<%=htmlWebpackPlugin.options.FAVICON_URL%>" type="image/x-icon" />
<% if (process.env.OPTIMIZELY_URL) { %>
<script
src="<%= process.env.OPTIMIZELY_URL %>"
></script>
<% } else if (process.env.OPTIMIZELY_PROJECT_ID) { %>
<script
src="<%= process.env.MARKETING_SITE_BASE_URL %>/optimizelyjs/<%= process.env.OPTIMIZELY_PROJECT_ID %>.js"
></script>
<% } %>
</head>
<body>
<div id="root"></div>
Expand Down
33 changes: 18 additions & 15 deletions src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import LearnerDashboardHeader from './containers/LearnerDashboardHeader';
import messages from './messages';

import './App.scss';
import { PaintedDoorExperimentProvider } from './RecsPaintedDoorExpContext';

export const App = () => {
const { authenticatedUser } = React.useContext(AppContext);
Expand Down Expand Up @@ -78,21 +79,23 @@ export const App = () => {
<title>{formatMessage(messages.pageTitle)}</title>
</Helmet>
<div>
<LearnerDashboardHeader />
<main>
{hasNetworkFailure
? (
<Alert variant="danger">
<ErrorPage message={formatMessage(messages.errorMessage, { supportEmail })} />
</Alert>
) : (
<ExperimentProvider>
<Dashboard />
</ExperimentProvider>
)}
</main>
<Footer logo={process.env.LOGO_POWERED_BY_OPEN_EDX_URL_SVG} />
<ZendeskFab />
<PaintedDoorExperimentProvider>
<LearnerDashboardHeader />
<main>
{hasNetworkFailure
? (
<Alert variant="danger">
<ErrorPage message={formatMessage(messages.errorMessage, { supportEmail })} />
</Alert>
) : (
<ExperimentProvider>
<Dashboard />
</ExperimentProvider>
)}
</main>
<Footer logo={process.env.LOGO_POWERED_BY_OPEN_EDX_URL_SVG} />
<ZendeskFab />
</PaintedDoorExperimentProvider>
</div>
</Router>
);
Expand Down
3 changes: 3 additions & 0 deletions src/App.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ jest.mock('components/ZendeskFab', () => 'ZendeskFab');
jest.mock('ExperimentContext', () => ({
ExperimentProvider: 'ExperimentProvider',
}));
jest.mock('RecsPaintedDoorExpContext', () => ({
PaintedDoorExperimentProvider: 'PaintedDoorExperimentProvider',
}));
jest.mock('data/redux', () => ({
selectors: 'redux.selectors',
actions: 'redux.actions',
Expand Down
120 changes: 120 additions & 0 deletions src/RecsPaintedDoorExpContext.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import React from 'react';
import PropTypes from 'prop-types';
import { StrictDict } from 'utils';
import * as module from './RecsPaintedDoorExpContext';
import {
useEmailConfirmationData,
useHasAvailableDashboards,
useRequestIsPending,
} from './data/redux/hooks';
import { RequestKeys } from './data/constants/requests';
import { trackPaintedDoorVariationGroup } from './widgets/RecommendationsPanel/recsPaintedDoorExpTrack';

export const state = StrictDict({
enterpriseUser: (val) => React.useState(val), // eslint-disable-line
experimentData: (val) => React.useState(val), // eslint-disable-line
});

const PAINTED_DOOR_RECOMMENDATIONS_EXP_ID = 25116810832;
const PAINTED_DOOR_RECOMMENDATIONS_PAGE = 'url_targeting_for_van1604_recommendations_painted_door_exp';
const PAINTED_DOOR_RECS_EXP_NAVBAR_BTN_VARIATION = 'btn_navbar';
const PAINTED_DOOR_RECS_EXP_WIDGET_BTN_VARIATION = 'btn_widget';

export function getPaintedDoorRecommendationsExperimentVariation() {
try {

Check warning on line 24 in src/RecsPaintedDoorExpContext.jsx

View check run for this annotation

Codecov / codecov/patch

src/RecsPaintedDoorExpContext.jsx#L23-L24

Added lines #L23 - L24 were not covered by tests
if (window.optimizely && window.optimizely.get('data').experiments[PAINTED_DOOR_RECOMMENDATIONS_EXP_ID]) {
const selectedVariant = window.optimizely.get('state').getVariationMap()[PAINTED_DOOR_RECOMMENDATIONS_EXP_ID];
return selectedVariant?.name;

Check warning on line 27 in src/RecsPaintedDoorExpContext.jsx

View check run for this annotation

Codecov / codecov/patch

src/RecsPaintedDoorExpContext.jsx#L26-L27

Added lines #L26 - L27 were not covered by tests
}
} catch (e) { /* empty */ }
return '';

Check warning on line 30 in src/RecsPaintedDoorExpContext.jsx

View check run for this annotation

Codecov / codecov/patch

src/RecsPaintedDoorExpContext.jsx#L30

Added line #L30 was not covered by tests
}

export function activatePaintedDoorRecommendationsExperiment() {
window.optimizely = window.optimizely || [];
window.optimizely.push({
type: 'page',
pageName: PAINTED_DOOR_RECOMMENDATIONS_PAGE,
});
}

const useIsEnterpriseUser = () => {
const [enterpriseUser, setEnterpriseUser] = module.state.enterpriseUser({
isEnterpriseUser: false,
isLoading: true,
});

const initIsPending = useRequestIsPending(RequestKeys.initialize);
const hasAvailableDashboards = useHasAvailableDashboards();
const confirmationData = useEmailConfirmationData();

React.useEffect(() => {
if (!initIsPending && Object.keys(confirmationData).length && hasAvailableDashboards) {
setEnterpriseUser(prev => ({

Check warning on line 53 in src/RecsPaintedDoorExpContext.jsx

View check run for this annotation

Codecov / codecov/patch

src/RecsPaintedDoorExpContext.jsx#L53

Added line #L53 was not covered by tests
...prev,
isEnterpriseUser: true,
isLoading: false,
}));
} else if (!initIsPending && Object.keys(confirmationData).length && !hasAvailableDashboards) {
setEnterpriseUser(prev => ({
...prev,
isEnterpriseUser: false,
isLoading: false,
}));
}
}, [initIsPending]); // eslint-disable-line react-hooks/exhaustive-deps

return enterpriseUser;
};

export const PaintedDoorExperimentContext = React.createContext();

export const PaintedDoorExperimentProvider = ({ children }) => {
const [experimentData, setExperimentData] = module.state.experimentData({
experimentVariation: '',
isPaintedDoorNavbarBtnVariation: false,
isPaintedDoorWidgetBtnVariation: false,
experimentLoading: true,
});
const enterpriseUser = useIsEnterpriseUser();

const contextValue = React.useMemo(
() => ({
...experimentData,
}),
[experimentData],
);

React.useEffect(() => {
let timer = null;
if (!enterpriseUser.isLoading && !enterpriseUser.isEnterpriseUser) {
activatePaintedDoorRecommendationsExperiment();
timer = setTimeout(() => {
const variation = getPaintedDoorRecommendationsExperimentVariation();
setExperimentData(prev => ({

Check warning on line 94 in src/RecsPaintedDoorExpContext.jsx

View check run for this annotation

Codecov / codecov/patch

src/RecsPaintedDoorExpContext.jsx#L93-L94

Added lines #L93 - L94 were not covered by tests
...prev,
experimentVariation: variation,
isPaintedDoorNavbarBtnVariation: variation === PAINTED_DOOR_RECS_EXP_NAVBAR_BTN_VARIATION,
isPaintedDoorWidgetBtnVariation: variation === PAINTED_DOOR_RECS_EXP_WIDGET_BTN_VARIATION,
experimentLoading: false,
}));
trackPaintedDoorVariationGroup(variation);

Check warning on line 101 in src/RecsPaintedDoorExpContext.jsx

View check run for this annotation

Codecov / codecov/patch

src/RecsPaintedDoorExpContext.jsx#L101

Added line #L101 was not covered by tests
}, 500);
}
return () => clearTimeout(timer);
}, [enterpriseUser]); // eslint-disable-line react-hooks/exhaustive-deps

return (
<PaintedDoorExperimentContext.Provider value={contextValue}>
{children}
</PaintedDoorExperimentContext.Provider>
);
};

export const usePaintedDoorExperimentContext = () => React.useContext(PaintedDoorExperimentContext);

PaintedDoorExperimentProvider.propTypes = {
children: PropTypes.node.isRequired,
};

export default usePaintedDoorExperimentContext;
82 changes: 44 additions & 38 deletions src/__snapshots__/App.test.jsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,22 @@ exports[`App router component component initialize failure snapshot 1`] = `
</title>
</HelmetWrapper>
<div>
<LearnerDashboardHeader />
<main>
<Alert
variant="danger"
>
<ErrorPage
message="If you experience repeated failures, please email support at test-support-url"
/>
</Alert>
</main>
<Footer
logo="fakeLogo.png"
/>
<ZendeskFab />
<PaintedDoorExperimentProvider>
<LearnerDashboardHeader />
<main>
<Alert
variant="danger"
>
<ErrorPage
message="If you experience repeated failures, please email support at test-support-url"
/>
</Alert>
</main>
<Footer
logo="fakeLogo.png"
/>
<ZendeskFab />
</PaintedDoorExperimentProvider>
</div>
</BrowserRouter>
`;
Expand All @@ -40,16 +42,18 @@ exports[`App router component component no network failure snapshot 1`] = `
</title>
</HelmetWrapper>
<div>
<LearnerDashboardHeader />
<main>
<ExperimentProvider>
<Dashboard />
</ExperimentProvider>
</main>
<Footer
logo="fakeLogo.png"
/>
<ZendeskFab />
<PaintedDoorExperimentProvider>
<LearnerDashboardHeader />
<main>
<ExperimentProvider>
<Dashboard />
</ExperimentProvider>
</main>
<Footer
logo="fakeLogo.png"
/>
<ZendeskFab />
</PaintedDoorExperimentProvider>
</div>
</BrowserRouter>
`;
Expand All @@ -65,20 +69,22 @@ exports[`App router component component refresh failure snapshot 1`] = `
</title>
</HelmetWrapper>
<div>
<LearnerDashboardHeader />
<main>
<Alert
variant="danger"
>
<ErrorPage
message="If you experience repeated failures, please email support at test-support-url"
/>
</Alert>
</main>
<Footer
logo="fakeLogo.png"
/>
<ZendeskFab />
<PaintedDoorExperimentProvider>
<LearnerDashboardHeader />
<main>
<Alert
variant="danger"
>
<ErrorPage
message="If you experience repeated failures, please email support at test-support-url"
/>
</Alert>
</main>
<Footer
logo="fakeLogo.png"
/>
<ZendeskFab />
</PaintedDoorExperimentProvider>
</div>
</BrowserRouter>
`;
6 changes: 4 additions & 2 deletions src/components/ModalView/__snapshots__/index.test.jsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,17 @@ exports[`ModalView snapshot should renders default ModalView 1`] = `
<Component>
<ActionRow>
<Component
onClick={[Function]}
variant="tertiary"
>
Skip for now
</Component>
<Button
<Component
onClick={[Function]}
variant="primary"
>
Count me in!
</Button>
</Component>
</ActionRow>
</Component>
</ModalDialog>
Expand Down
17 changes: 14 additions & 3 deletions src/components/ModalView/index.jsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,26 @@
import React from 'react';
import PropTypes from 'prop-types';

import { ModalDialog, ActionRow, Button } from '@edx/paragon';
import { ModalDialog, ActionRow } from '@edx/paragon';
import { useIntl } from '@edx/frontend-platform/i18n';
import messages from './messages';

import './index.scss';
import {
trackPaintedDoorRecommendationHomeInterestBtnClicked,
trackPaintedDoorRecommendationHomeSkipBtnClicked,
} from '../../widgets/RecommendationsPanel/recsPaintedDoorExpTrack';

export const ModalView = ({
isOpen,
onClose,
variation,
}) => {
const { formatMessage } = useIntl();

const handleSkipBtnClick = () => trackPaintedDoorRecommendationHomeSkipBtnClicked(variation);
const handleInterestBtnClick = () => trackPaintedDoorRecommendationHomeInterestBtnClicked(variation);

return (
<div className="containers">
<ModalDialog
Expand All @@ -35,10 +43,12 @@ export const ModalView = ({
</ModalDialog.Body>
<ModalDialog.Footer>
<ActionRow>
<ModalDialog.CloseButton variant="tertiary">
<ModalDialog.CloseButton variant="tertiary" onClick={handleSkipBtnClick}>
{formatMessage(messages.modalSkipButton)}
</ModalDialog.CloseButton>
<Button variant="primary">{formatMessage(messages.modalCountMeButton)}</Button>
<ModalDialog.CloseButton variant="primary" onClick={handleInterestBtnClick}>
{formatMessage(messages.modalCountMeButton)}
</ModalDialog.CloseButton>
</ActionRow>
</ModalDialog.Footer>
</ModalDialog>
Expand All @@ -53,6 +63,7 @@ ModalView.defaultProps = {
ModalView.propTypes = {
onClose: PropTypes.func.isRequired,
isOpen: PropTypes.bool,
variation: PropTypes.string.isRequired,
};

export default ModalView;
Loading

0 comments on commit 736abb4

Please sign in to comment.