Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions example/onboarding-example/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Button, Container, useToggle } from '@openedx/paragon';

import getAllPossibleQueryParams from '../../src/data/utils';
import {
ResetPasswordComponent, SignInComponent, SignUpComponent,
ResetPasswordComponent, SignInComponent, SignUpComponent, WelcomePageComponent,
} from '../../src/onboarding-component';

import './index.scss';
Expand All @@ -16,6 +16,7 @@ import './index.scss';
const OnBoardingExampleContainer = () => {
const [isSignUpFormOpen, setSignUpFormOpen, setSignUpFormClose] = useToggle(false);
const [isSignInFormOpen, setSignInFormOpen, setSignInFormClose] = useToggle(false);
const [isWelcomeFormOpen, setWelcomeFormOpen, setWelcomeFormClose] = useToggle(false);
const [isResetPasswordFormOpen, setResetPasswordFormOpen, setResetPasswordFormClose] = useToggle(false);

const queryParam = getAllPossibleQueryParams();
Expand All @@ -24,13 +25,18 @@ const OnBoardingExampleContainer = () => {
const url = new URL(window.location.href);
const path = url.pathname;

if (path === '/login' || path === '/register' || path.startsWith('/password_reset_confirm')) {
if (path === '/login'
|| path === '/register'
|| path === '/welcome'
|| path.startsWith('/password_reset_confirm')) {
const searchParams = new URLSearchParams(url.search);

if (path === '/login') {
searchParams.set('authMode', 'Login');
} else if (path === '/register') {
searchParams.set('authMode', 'Register');
} else if (path === '/welcome') {
searchParams.set('authMode', 'Welcome');
} else if (path.startsWith('/password_reset_confirm')) {
searchParams.set('authMode', 'PasswordResetConfirm');

Expand All @@ -50,10 +56,12 @@ const OnBoardingExampleContainer = () => {
setSignInFormOpen();
} else if (queryParam?.authMode === 'Register') {
setSignUpFormOpen();
} else if (queryParam?.authMode === 'Welcome') {
setWelcomeFormOpen();
} else if (queryParam?.authMode === 'PasswordResetConfirm') {
setResetPasswordFormOpen();
}
}, [setSignInFormOpen, setSignUpFormOpen, setResetPasswordFormOpen, queryParam?.authMode]);
}, [setSignInFormOpen, setSignUpFormOpen, setResetPasswordFormOpen, queryParam?.authMode, setWelcomeFormOpen]);

return (
<>
Expand Down Expand Up @@ -83,6 +91,10 @@ const OnBoardingExampleContainer = () => {
isOpen={isSignInFormOpen}
context={{}}
/>
<WelcomePageComponent
close={setWelcomeFormClose}
isOpen={isWelcomeFormOpen}
/>
<ResetPasswordComponent
close={setResetPasswordFormClose}
isOpen={isResetPasswordFormOpen}
Expand Down
4 changes: 3 additions & 1 deletion src/base-container/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ const BaseContainer = ({
&& currentForm === FORGOT_PASSWORD_FORM) {
window.location.href = loginErrorResult.redirectUrl;
}
deleteQueryParams(['authMode', 'tpa_hint', 'password_reset_token', 'track']);
deleteQueryParams(
['authMode', 'tpa_hint', 'password_reset_token', 'track', 'from_tpa_pipeline'],
);
dispatch(forgotPasswordClearStatus());
dispatch(loginErrorClear());
dispatch(clearAllRegistrationErrors());
Expand Down
22 changes: 21 additions & 1 deletion src/common-ui/SocialAuthButtons/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,24 @@ export const SocialAuthButton = forwardRef(({

const registrationFields = useSelector(state => state.register.registrationFields);

// temporary code for testing
const registrationParams = {
// ...registrationFields,
totalRegistrationTime: 0,
app_name: 'onboarding-component',
marketing_emails_opt_in: false,
};

if (!provider) {
return null;
}

const prepareFinalUrl = (url, paramKey, paramValue) => {
const urlObj = new URL(url, getConfig().LMS_BASE_URL);
urlObj.searchParams.set(paramKey, paramValue);
return urlObj.toString();
};

const {
id: providerId,
name: providerName,
Expand All @@ -52,8 +66,14 @@ export const SocialAuthButton = forwardRef(({
if (!isLoginForm) {
setCookie('marketingEmailsOptIn', registrationFields?.marketingEmailsOptIn);
}
// const url = updateNextQueryParam(e.currentTarget.dataset.providerUrl);
const url = e.currentTarget.dataset.providerUrl;
window.location.href = getConfig().LMS_BASE_URL + url;
// eslint-disable-next-line max-len
// const finalUrl = prepareFinalUrl(url, 'marketing_emails_opt_in', registrationFields?.marketingEmailsOptIn.toString());

const finalUrl = prepareFinalUrl(url, 'registration_params', JSON.stringify(registrationParams));
console.log('final url = ', finalUrl);
window.location.href = finalUrl;
};

return (
Expand Down
3 changes: 2 additions & 1 deletion src/data/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export const FORGOT_PASSWORD_FORM = 'forgot-password';
export const RESET_PASSWORD_FORM = 'reset-password';
export const PROGRESSIVE_PROFILING_FORM = 'progressive-profiling';
export const ENTERPRISE_LOGIN = 'enterprise-login';
export const VALID_FORMS = [LOGIN_FORM, REGISTRATION_FORM, RESET_PASSWORD_FORM];
export const VALID_FORMS = [LOGIN_FORM, REGISTRATION_FORM, RESET_PASSWORD_FORM, PROGRESSIVE_PROFILING_FORM];

// Common States
export const DEFAULT_STATE = 'default';
Expand All @@ -30,6 +30,7 @@ export const ENTERPRISE_LOGIN_URL = '/enterprise/login';
export const VALID_AUTH_PARAMS = [
'course_id', 'enrollment_action', 'course_mode', 'email_opt_in', 'purchase_workflow',
'next', 'tpa_hint', 'account_activation_status', 'authMode', 'password_reset_token',
'from_tpa_pipeline',
];

export const AUTH_MODE = 'authMode';
Expand Down
7 changes: 5 additions & 2 deletions src/forms/common-components/AuthenticatedRedirection.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,17 @@ const AuthenticatedRedirection = ({
redirectToProgressiveProfilingForm = false,
success = false,
isLinkTracked = false,
shouldUseRedirectUrl = false,
}) => {
const dispatch = useDispatch();

if (success) {
let finalRedirectUrl = '';

// If we're in a third party auth pipeline, we must complete the pipeline
// once user has successfully logged in. Otherwise, redirect to the specified redirect url.
// Note: For multiple enterprise use case, we need to make sure that user first visits the
// enterprise selection page and then complete the auth workflow
if (finishAuthUrl && !redirectUrl.includes(finishAuthUrl)) {
if (!shouldUseRedirectUrl && finishAuthUrl && !redirectUrl.includes(finishAuthUrl)) {
finalRedirectUrl = getConfig().LMS_BASE_URL + finishAuthUrl;
} else {
finalRedirectUrl = redirectUrl;
Expand All @@ -58,8 +58,10 @@ const AuthenticatedRedirection = ({
}

if (isLinkTracked) {
console.log('oct1 before redirect', { finalRedirectUrl });
setTimeout(() => { window.location.href = finalRedirectUrl; }, LINK_TIMEOUT);
} else {
console.log('oct2 before redirect', { finalRedirectUrl });
window.location.href = finalRedirectUrl;
}
}
Expand All @@ -73,6 +75,7 @@ AuthenticatedRedirection.propTypes = {
redirectUrl: PropTypes.string,
redirectToProgressiveProfilingForm: PropTypes.bool,
isLinkTracked: PropTypes.bool,
shouldUseRedirectUrl: PropTypes.bool,
};

export default AuthenticatedRedirection;
102 changes: 80 additions & 22 deletions src/forms/progressive-profiling-popup/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ import React, {
} from 'react';

import { getConfig, snakeCaseObject } from '@edx/frontend-platform';
import { identifyAuthenticatedUser } from '@edx/frontend-platform/analytics';
import {
AxiosJwtAuthService,
configure as configureAuth,
configure as configureAuth, fetchAuthenticatedUser,
getAuthenticatedUser,
} from '@edx/frontend-platform/auth';
import { getCountryList, getLocale, useIntl } from '@edx/frontend-platform/i18n';
import { getLoggingService } from '@edx/frontend-platform/logging';
Expand All @@ -26,7 +28,7 @@ import {
} from '../../data/constants';
import { getCountryCookieValue } from '../../data/cookies';
import { useDispatch, useSelector } from '../../data/storeHooks';
import { moveScrollToTop } from '../../data/utils';
import getAllPossibleQueryParams, { moveScrollToTop } from '../../data/utils';
import { setCurrentOpenedForm } from '../../onboarding-component/data/reducers';
import {
trackProgressiveProfilingPageViewed,
Expand All @@ -47,6 +49,7 @@ import './index.scss';
const ProgressiveProfilingForm = () => {
const { formatMessage } = useIntl();
const dispatch = useDispatch();
const queryParams = useMemo(() => getAllPossibleQueryParams(), []);

const countryFieldRef = useRef(null);

Expand All @@ -55,15 +58,39 @@ const ProgressiveProfilingForm = () => {

const submitState = useSelector(state => state.progressiveProfiling.submitState);
const subjectsList = useSelector(state => state.progressiveProfiling.subjectsList);
const redirectUrl = useSelector(state => state.progressiveProfiling.redirectUrl);
const redirectURL = useSelector(state => state.progressiveProfiling.redirectUrl);
const authContextCountryCode = useSelector(state => state.commonData.thirdPartyAuthContext.countryCode);
const finishAuthUrl = useSelector(state => state.commonData.thirdPartyAuthContext.finishAuthUrl);
const authenticatedUser = useSelector(state => state.register.registrationResult.authenticatedUser);
const authUser = useSelector(state => state.register.registrationResult.authenticatedUser);

const [redirectUrl, setRedirectUrl] = React.useState(redirectURL);
const [formData, setFormData] = useState({});
const [formErrors, setFormErrors] = useState({});
const [autoFilledCountry, setAutoFilledCountry] = useState({ value: '', displayText: '' });
const [skipButtonState, setSkipButtonState] = useState(DEFAULT_STATE);
const [authConfigured, setAuthConfigured] = useState(false);
const [authenticatedUser, setAuthenticatedUser] = useState(authUser);
const [isUserFetchingCompleted, setIsUserFetchingCompleted] = useState(false);
const isRedirectedFromSSOPipeline = !!queryParams?.from_tpa_pipeline && !!queryParams?.next;

// const loadAuthenticatedUser = () => {
// if (queryParams?.from_tpa_pipeline) {
// return getAuthenticatedUser();
// }
// return authUser;
// };
// const authenticatedUser = loadAuthenticatedUser();

useEffect(() => {
if (isRedirectedFromSSOPipeline) {
console.log({ queryParams, url: `${getConfig().LMS_BASE_URL}${queryParams?.next}` });
setRedirectUrl(`${getConfig().LMS_BASE_URL}${queryParams?.next}`);
}
}, [queryParams]);

console.log('authUser = ', authUser);
console.log('getAuthenticatedUser = ', getAuthenticatedUser());
// console.log('authenticatedUser = ', loadAuthenticatedUser());

useEffect(() => {
let countryCode = null;
Expand All @@ -85,14 +112,41 @@ const ProgressiveProfilingForm = () => {
}, [authContextCountryCode, autoFilledCountry, countryCookieValue, countryList, formatMessage]);

useEffect(() => {
if (authenticatedUser === null) {
dispatch(setCurrentOpenedForm(LOGIN_FORM));
console.log('1. inside configure auth useEffect', { authConfigured });
if (!authConfigured) {
console.log('1.1 inside configure auth useEffect INSIDE', { authConfigured });
configureAuth(AxiosJwtAuthService, { loggingService: getLoggingService(), config: getConfig() });
setAuthConfigured(true);
}
}, [authConfigured]);

useEffect(() => {
console.log('2. inside fetch user useEffect', { authConfigured });
if (authConfigured) {
console.log('2.1 inside fetch user useEffect INSIDE', { authConfigured });
fetchAuthenticatedUser({ forceRefresh: !!getAuthenticatedUser() }).then((user) => {
console.log('inside fetchAuthenticatedUser success', { user });
setAuthenticatedUser(user);
setIsUserFetchingCompleted(true);
}).catch(() => setIsUserFetchingCompleted(true));
}
}, [authConfigured]);

useEffect(() => {
if (authenticatedUser?.userId) {
configureAuth(AxiosJwtAuthService, { loggingService: getLoggingService(), config: getConfig() });
setAuthConfigured(true);
identifyAuthenticatedUser(authenticatedUser?.userId);
trackProgressiveProfilingPageViewed();
}
}, [authenticatedUser, dispatch]);
}, [authenticatedUser]);

useEffect(() => {
console.log('EXIT inside returning to Login useEffect', { isUserFetchingCompleted, authenticatedUser });
if (isUserFetchingCompleted && !authenticatedUser) {
console.log('EXIT inside returning to Login useEffect inside if', { isUserFetchingCompleted, authenticatedUser });
dispatch(setCurrentOpenedForm(LOGIN_FORM));
}
}, [isUserFetchingCompleted, authenticatedUser, dispatch]);

const hasFormErrors = () => {
let error = false;
Expand Down Expand Up @@ -185,8 +239,11 @@ const ProgressiveProfilingForm = () => {
setSkipButtonState(FAILURE_STATE);
moveScrollToTop(countryFieldRef);
} else if (hasCountry) {
// link tracker
trackProgressiveProfilingSkipLinkClick(redirectUrl)(e);
let finalRedirectUrl = redirectUrl;
if (!isRedirectedFromSSOPipeline && finishAuthUrl && !redirectUrl.includes(finishAuthUrl)) {
finalRedirectUrl = getConfig().LMS_BASE_URL + finishAuthUrl;
}
trackProgressiveProfilingSkipLinkClick(finalRedirectUrl)(e);
}
};

Expand All @@ -197,6 +254,7 @@ const ProgressiveProfilingForm = () => {
redirectUrl={redirectUrl}
finishAuthUrl={finishAuthUrl}
isLinkTracked
// shouldUseRedirectUrl={isRedirectedFromSSOPipeline}
/>
<h1
className="display-1 font-italic text-center mb-4"
Expand Down Expand Up @@ -232,18 +290,18 @@ const ProgressiveProfilingForm = () => {
onBlurHandler={onFieldBlur}
/>
</Form.Group>
<h3 className="mb-2.5">
{formatMessage(messages.progressiveProfilingDataCollectionTitle)}
</h3>
<Form.Group controlId="subject" className="mb-4">
<AutoSuggestField
name="subject"
placeholder={formatMessage(messages.progressiveProfilingSubjectFieldPlaceholder)}
label={formatMessage(messages.progressiveProfilingSubjectFieldLabel)}
options={subjectsList?.options}
onChangeHandler={handleSelect}
/>
</Form.Group>
{/* <h3 className="mb-2.5"> */}
{/* {formatMessage(messages.progressiveProfilingDataCollectionTitle)} */}
{/* </h3> */}
{/* <Form.Group controlId="subject" className="mb-4"> */}
{/* <AutoSuggestField */}
{/* name="subject" */}
{/* placeholder={formatMessage(messages.progressiveProfilingSubjectFieldPlaceholder)} */}
{/* label={formatMessage(messages.progressiveProfilingSubjectFieldLabel)} */}
{/* options={subjectsList?.options} */}
{/* onChangeHandler={handleSelect} */}
{/* /> */}
{/* </Form.Group> */}
<Form.Group controlId="levelOfEducation" className="mb-4">
<AutoSuggestField
name="levelOfEducation"
Expand Down
5 changes: 4 additions & 1 deletion src/forms/registration-popup/data/reducers.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,10 @@ export const registerSlice = createSlice({
state.validations = null;
},
setRegistrationFields: (state, { payload }) => {
state.registrationFields = payload;
state.registrationFields = {
...state.registrationFields,
...payload,
};
},
backupRegistrationForm: (state, { payload }) => {
state.registrationFormData = payload;
Expand Down
3 changes: 3 additions & 0 deletions src/forms/registration-popup/data/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,7 @@ const isFormValid = (
return { isValid, fieldErrors, emailSuggestion };
};

// const preparePayload = (formFields, totalRegistrationTime, currentProvider, isLoginSSOIntent, backendCountryCode, ) => {
//
// }
export default isFormValid;
7 changes: 6 additions & 1 deletion src/onboarding-component/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ export const OnBoardingComponent = ({
if (context) {
validatedContext = validateContextData(context);
}
if (isAuthenticatedUser) {
if (isAuthenticatedUser && [REGISTRATION_FORM, LOGIN_FORM].includes(formToRender)) {
const queryParamString = objectToQueryString({ ...validatedContext, ...queryParams });
const formUrl = formToRender === REGISTRATION_FORM ? 'register' : formToRender;
window.location.href = `${getConfig().LMS_BASE_URL}/${formUrl}?${queryParamString}`;
Expand All @@ -133,6 +133,7 @@ export const OnBoardingComponent = ({
return <LoginForm />;
}
if (currentForm === PROGRESSIVE_PROFILING_FORM) {
console.log('getForm');
return <ProgressiveProfilingForm />;
}
if (currentForm === REGISTRATION_FORM) {
Expand Down Expand Up @@ -232,3 +233,7 @@ export const SignUpComponent = (props) => (
export const ResetPasswordComponent = (props) => (
<OnBoardingComponentWithProvider {...props} formToRender={RESET_PASSWORD_FORM} />
);

export const WelcomePageComponent = (props) => (
<OnBoardingComponentWithProvider {...props} formToRender={PROGRESSIVE_PROFILING_FORM} />
);