diff --git a/.env b/.env
index 2b2bf477..7619bc6b 100644
--- a/.env
+++ b/.env
@@ -32,3 +32,4 @@ TERMS_OF_SERVICE_URL=''
TWITTER_HASHTAG=''
TWITTER_URL=''
USER_INFO_COOKIE_NAME=''
+SESSION_COOKIE_DOMAIN=''
\ No newline at end of file
diff --git a/.env.development b/.env.development
index f0b2b655..cf763714 100644
--- a/.env.development
+++ b/.env.development
@@ -32,3 +32,4 @@ TERMS_OF_SERVICE_URL='https://www.edx.org/edx-terms-service'
TWITTER_HASHTAG='myedxjourney'
TWITTER_URL='https://twitter.com/edXOnline'
USER_INFO_COOKIE_NAME='edx-user-info'
+SESSION_COOKIE_DOMAIN='localhost'
\ No newline at end of file
diff --git a/src/alerts/logistration-alert/AccountActivationAlert.jsx b/src/alerts/logistration-alert/AccountActivationAlert.jsx
new file mode 100644
index 00000000..effc43b6
--- /dev/null
+++ b/src/alerts/logistration-alert/AccountActivationAlert.jsx
@@ -0,0 +1,135 @@
+import React, { useState } from 'react';
+import Cookies from 'js-cookie';
+import { getConfig } from '@edx/frontend-platform';
+import { getAuthenticatedUser } from '@edx/frontend-platform/auth';
+import {
+ AlertModal,
+ Button,
+ Spinner,
+ Icon,
+} from '@edx/paragon';
+import { Check, ArrowForward } from '@edx/paragon/icons';
+import { FormattedMessage, injectIntl } from '@edx/frontend-platform/i18n';
+import { sendActivationEmail } from '../../courseware/data';
+
+function AccountActivationAlert() {
+ const [showModal, setShowModal] = useState(false);
+ const [showSpinner, setShowSpinner] = useState(false);
+ const [showCheck, setShowCheck] = useState(false);
+ const handleOnClick = () => {
+ setShowSpinner(true);
+ setShowCheck(false);
+ sendActivationEmail().then(() => {
+ setShowSpinner(false);
+ setShowCheck(true);
+ });
+ };
+
+ const showAccountActivationAlert = Cookies.get('show-account-activation-popup');
+ if (showAccountActivationAlert !== undefined) {
+ Cookies.remove('show-account-activation-popup', { path: '/', domain: process.env.SESSION_COOKIE_DOMAIN });
+ // extra check to make sure cookie was removed before updating the state. Updating the state without removal
+ // of cookie would make it infinit rendering
+ if (Cookies.get('show-account-activation-popup') === undefined) {
+ setShowModal(true);
+ }
+ }
+
+ const title = (
+
+
+
+ );
+
+ const button = (
+
+ );
+
+ const children = () => {
+ let bodyContent = null;
+ const message = (
+ {getAuthenticatedUser().email},
+ sendEmailTag: (
+ // eslint-disable-next-line jsx-a11y/anchor-is-valid
+
+
+
+ ),
+ }}
+ />
+ );
+ bodyContent = (
+
+ {message}
+
+ );
+
+ if (!showCheck && showSpinner) {
+ bodyContent = (
+
+ {message}
+
+
+ );
+ }
+
+ if (showCheck && !showSpinner) {
+ bodyContent = (
+
+ {message}
+
+
+ );
+ }
+ return bodyContent;
+ };
+
+ return (
+ ({})}
+ >
+ {children()}
+
+ );
+}
+
+export default injectIntl(AccountActivationAlert);
diff --git a/src/course-home/outline-tab/OutlineTab.jsx b/src/course-home/outline-tab/OutlineTab.jsx
index ac6eaa7a..15da2938 100644
--- a/src/course-home/outline-tab/OutlineTab.jsx
+++ b/src/course-home/outline-tab/OutlineTab.jsx
@@ -26,6 +26,7 @@ import usePrivateCourseAlert from './alerts/private-course-alert';
import { useModel } from '../../generic/model-store';
import WelcomeMessage from './widgets/WelcomeMessage';
import ProctoringInfoPanel from './widgets/ProctoringInfoPanel';
+import AccountActivationAlert from '../../alerts/logistration-alert/AccountActivationAlert';
/** [MM-P2P] Experiment */
import { initHomeMMP2P, MMP2PFlyover } from '../../experiments/mm-p2p';
@@ -131,6 +132,7 @@ function OutlineTab({ intl }) {
{/** [MM-P2P] Experiment (className for optimizely trigger) */}
+
{
});
});
});
+
+ describe('Accont Activation Alert', () => {
+ beforeEach(() => {
+ const intersectionObserverMock = () => ({
+ observe: () => null,
+ disconnect: () => null,
+ });
+ window.IntersectionObserver = jest.fn().mockImplementation(intersectionObserverMock);
+ });
+ it('displays account activation alert if cookie is set true', async () => {
+ Cookies.set = jest.fn();
+ Cookies.get = jest.fn().mockImplementation(() => 'true');
+ Cookies.remove = jest.fn().mockImplementation(() => { Cookies.get = jest.fn(); });
+
+ await fetchAndRender();
+ expect(screen.queryByText('Activate your account so you can log back in')).toBeInTheDocument();
+ expect(screen.queryByRole('button', { name: 'resend the email' })).toBeInTheDocument();
+ });
+
+ it('do not displays account activation alert if cookie is not set true', async () => {
+ Cookies.set = jest.fn();
+ Cookies.get = jest.fn();
+ Cookies.remove = jest.fn().mockImplementation(() => { Cookies.get = jest.fn(); });
+
+ await fetchAndRender();
+ expect(screen.queryByText('Activate your account so you can log back in')).not.toBeInTheDocument();
+ expect(screen.queryByRole('button', { name: 'resend the email' })).not.toBeInTheDocument();
+ });
+
+ it('sends account activation email on clicking the resened email in account activation alert', async () => {
+ Cookies.set = jest.fn();
+ Cookies.get = jest.fn().mockImplementation(() => 'true');
+ Cookies.remove = jest.fn().mockImplementation(() => { Cookies.get = jest.fn(); });
+
+ await fetchAndRender();
+
+ axiosMock = new MockAdapter(getAuthenticatedHttpClient());
+ const resendEmailUrl = `${getConfig().LMS_BASE_URL}/api/send_account_activation_email`;
+ axiosMock.onPost(resendEmailUrl).reply(200, {});
+
+ const resendLink = screen.getByRole('button', { name: 'resend the email' });
+ fireEvent.click(resendLink);
+
+ await waitFor(() => expect(axiosMock.history.post).toHaveLength(1));
+ expect(axiosMock.history.post[0].url).toEqual(resendEmailUrl);
+ });
+ });
});
diff --git a/src/courseware/data/api.js b/src/courseware/data/api.js
index c0670620..c66b0ec3 100644
--- a/src/courseware/data/api.js
+++ b/src/courseware/data/api.js
@@ -239,3 +239,8 @@ export async function postIntegritySignature(courseId) {
);
return camelCaseObject(data);
}
+export async function sendActivationEmail() {
+ const url = new URL(`${getConfig().LMS_BASE_URL}/api/send_account_activation_email`);
+ const { data } = await getAuthenticatedHttpClient().post(url.href, {});
+ return data;
+}
diff --git a/src/courseware/data/index.js b/src/courseware/data/index.js
index 5961756d..72fe2bc4 100644
--- a/src/courseware/data/index.js
+++ b/src/courseware/data/index.js
@@ -7,6 +7,7 @@ export {
} from './thunks';
export {
getResumeBlock,
+ sendActivationEmail,
} from './api';
export {
sequenceIdsSelector,