Skip to content

Commit

Permalink
Merged in r2-2632-pwa-logout (pull request #6519)
Browse files Browse the repository at this point in the history
R2-2632: Fixing offline logout, disabling login if offline

Approved-by: Alberto Espinoza
  • Loading branch information
jtoliver-quoin committed Sep 27, 2023
2 parents 6d7c3b2 + 1669fd9 commit a706665
Show file tree
Hide file tree
Showing 9 changed files with 96 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ import { NAME } from "./constants";
const Component = ({ text, id, ...options }) => {
const { rest, ...remainder } = options;

if (rest.disabled) {
return <div className={options.className}>{text}</div>;
}

return (
<Link id={id} underline="hover" {...rest} {...remainder}>
{text}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ import { useApp } from "../../../application";

import css from "./styles.css";

const Component = ({ text }) => {
const Component = ({ text, noMargin }) => {
const { online } = useApp();

if (online) return null;

return (
<div className={css.alert}>
<div className={noMargin || css.alert}>
<Alert icon={<SignalWifiOff />} severity="warning" variant="outlined">
{text}
</Alert>
Expand All @@ -23,6 +23,7 @@ const Component = ({ text }) => {
Component.displayName = "OfflineAlert";

Component.propTypes = {
noMargin: PropTypes.bool,
text: PropTypes.string
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@ import { useHistory } from "react-router-dom";
import { PRIMERO_IDP } from "../constants";
import { attemptIDPLogin } from "../action-creators";
import { signIn } from "../auth-provider";
import { useApp } from "../../../../application";
import DisableOffline from "../../../../disable-offline";

const PrimeroIdpLink = ({ identityProviders, i18n, dispatch, css }) => {
const history = useHistory();
const { online } = useApp();

const primeroIdp = identityProviders.find(idp => idp.get("unique_id") === PRIMERO_IDP);
const onlyPrimeroIDP = primeroIdp && identityProviders?.size === 1;
Expand All @@ -26,12 +29,20 @@ const PrimeroIdpLink = ({ identityProviders, i18n, dispatch, css }) => {
return null;
}

const linkText = i18n.t("log_in_primero_idp", { idp_name: primeroIdp.get("name") });

return (
<div className={classes}>
{!onlyPrimeroIDP && <span>{i18n.t("or_label")}</span>}
<Link component="a" variant="body2" onClick={handleOnClick}>
{i18n.t("log_in_primero_idp", { idp_name: primeroIdp.get("name") })}
</Link>
{online ? (
<Link component="a" variant="body2" onClick={handleOnClick}>
{linkText}
</Link>
) : (
<DisableOffline offlineTextKey="unavailable_offline">
<div className={css.linkDisabled}>{linkText}</div>
</DisableOffline>
)}
</div>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,15 @@ import { signIn } from "../auth-provider";
import { PRIMERO_IDP, FORM_ID } from "../constants";
import { SELECT_FIELD } from "../../../../form/constants";
import Form, { FormAction, FieldRecord, FormSectionRecord } from "../../../../form";
import { useApp } from "../../../../application";
import { ConditionalWrapper } from "../../../../../libs";
import disableOffline from "../../../../disable-offline";

const Component = ({ identityProviders, css }) => {
const i18n = useI18n();
const dispatch = useDispatch();
const history = useHistory();
const { online } = useApp();

const primeroIdp = identityProviders.find(idp => idp.get("unique_id") === PRIMERO_IDP);

Expand Down Expand Up @@ -46,6 +50,7 @@ const Component = ({ identityProviders, css }) => {
FieldRecord({
name: "idp",
type: SELECT_FIELD,
disabled: !online,
option_strings_text: {
[i18n.locale]: options
}
Expand All @@ -65,7 +70,9 @@ const Component = ({ identityProviders, css }) => {
submitAllFields
errorMessage={i18n.t("select_idp_error")}
/>
<FormAction options={{ form: FORM_ID, type: "submit" }} text={i18n.t("go")} />
<ConditionalWrapper wrapper={disableOffline} condition={!online} offlineTextKey="unavailable_offline">
<FormAction options={{ form: FORM_ID, type: "submit" }} text={i18n.t("go")} />
</ConditionalWrapper>
</div>
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@

}

.linkDisabled {
cursor: not-allowed;
user-select: none;
}

.selectProvider {
margin: 0;
}
Expand Down
58 changes: 34 additions & 24 deletions app/javascript/components/login/components/login-form/component.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useEffect } from "react";
import { useDispatch } from "react-redux";
import PropTypes from "prop-types";

import { useMemoizedSelector, useThemeHelper } from "../../../../libs";
import { ConditionalWrapper, useMemoizedSelector, useThemeHelper } from "../../../../libs";
import Form from "../../../form";
import { useI18n } from "../../../i18n";
import { enqueueSnackbar } from "../../../notifier";
Expand All @@ -15,6 +15,7 @@ import { NAME as PASSWORD_RESET_DIALOG_NAME } from "../password-reset-dialog/con
import PasswordResetDialog from "../password-reset-dialog";
import { getUseIdentityProvider } from "../../selectors";
import utils from "../../utils";
import DisableOffline, { OfflineAlert } from "../../../disable-offline";

import { NAME, FORM_ID } from "./constants";
import css from "./styles.css";
Expand All @@ -25,7 +26,7 @@ import { form, validationSchema } from "./form";
const Container = ({ modal }) => {
const i18n = useI18n();
const dispatch = useDispatch();
const { demo } = useApp();
const { demo, online } = useApp();
const { mobileDisplay } = useThemeHelper();
const { setDialog, dialogOpen, dialogClose } = useDialog(PASSWORD_RESET_DIALOG_NAME);

Expand All @@ -50,35 +51,44 @@ const Container = ({ modal }) => {
const { title, actionButton } = utils.loginComponentText(i18n, demo);

const renderForgotPassword = !useIdentityProvider && (
<>
<ActionButton
className={css.forgotPaswordLink}
onClick={onClickForgotLink}
text="login.forgot_password"
type={ACTION_BUTTON_TYPES.link}
/>
{dialogOpen && <PasswordResetDialog open={dialogOpen} handleCancel={dialogClose} />}
</>
<ConditionalWrapper condition={!online} wrapper={DisableOffline} offlineTextKey="unavailable_offline">
<>
<ActionButton
className={css.forgotPaswordLink}
onClick={onClickForgotLink}
text="login.forgot_password"
type={ACTION_BUTTON_TYPES.link}
disabled={!online}
/>
{dialogOpen && <PasswordResetDialog open={dialogOpen} handleCancel={dialogClose} />}
</>
</ConditionalWrapper>
);

return (
<>
<div className={css.loginContainer}>
<OfflineAlert text={i18n.t("connection_lost")} noMargin />
{modal || <PageHeading title={title} noPadding noElevation />}
<Form formSections={formSections} validations={validations} onSubmit={handleSubmit} formID={FORM_ID} />
<ConditionalWrapper condition={!online} wrapper={DisableOffline} offlineTextKey="unavailable_offline">
<Form formSections={formSections} validations={validations} onSubmit={handleSubmit} formID={FORM_ID} />
</ConditionalWrapper>
{modal || (
<ActionButton
id={`${FORM_ID}-button`}
text={actionButton}
type={ACTION_BUTTON_TYPES.default}
size="large"
noTranslate
rest={{
fullWidth: mobileDisplay,
form: FORM_ID,
type: "submit"
}}
/>
<ConditionalWrapper condition={!online} wrapper={DisableOffline} offlineTextKey="unavailable_offline">
<ActionButton
id={`${FORM_ID}-button`}
text={actionButton}
type={ACTION_BUTTON_TYPES.default}
size="large"
noTranslate
rest={{
fullWidth: mobileDisplay,
form: FORM_ID,
type: "submit"
}}
disabled={!online}
/>
</ConditionalWrapper>
)}
</div>
{renderForgotPassword}
Expand Down
29 changes: 19 additions & 10 deletions app/javascript/middleware/utils/start-signout.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,33 @@
import { setPendingUserLogin } from "../../components/connectivity/action-creators";
import { signOut } from "../../components/login/components/idp-selection";
import { attemptSignout, showLoginDialog } from "../../components/user";
import { Actions, attemptSignout, showLoginDialog } from "../../components/user";
import { IS_AUTHENTICATED_PATH } from "../constants";

import isOnline from "./is-online";

export default (store, logout = false) => {
const state = store.getState();
const usingIdp = state.getIn(["idp", "use_identity_provider"], false);
const isAuthenticated = state.getIn(IS_AUTHENTICATED_PATH, false);
const appLoading = state.getIn(["application", "loading"], false);
const online = isOnline(store);

if (isAuthenticated && !logout && !appLoading) {
store.dispatch(setPendingUserLogin(true));
store.dispatch(showLoginDialog());
}

if (logout || appLoading) {
if (usingIdp) {
signOut();
if (online) {
if (isAuthenticated && !logout && !appLoading) {
store.dispatch(setPendingUserLogin(true));
store.dispatch(showLoginDialog());
}

store.dispatch(attemptSignout());
if (logout || appLoading) {
if (usingIdp) {
signOut();
}

store.dispatch(attemptSignout());
}
} else {
localStorage.clear();
sessionStorage.clear();
store.dispatch({ type: Actions.LOGOUT_SUCCESS });
}
};
3 changes: 3 additions & 0 deletions app/javascript/middleware/utils/start-signout.unit.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ describe("middleware/utils/start-signout.js", () => {
const store = (userProvider = true) =>
configureStore()(
fromJS({
connectivity: {
online: true
},
idp: {
use_identity_provider: userProvider
}
Expand Down
7 changes: 6 additions & 1 deletion app/javascript/test/globals.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ global.IDBCursor = global.window.IDBCursor;
global.window.IDBIndex = IDBIndex;
global.IDBIndex = global.window.IDBIndex;

const storage = {};
let storage = {};

global.localStorage = {
setItem: (key, value) => {
Expand All @@ -50,5 +50,10 @@ global.localStorage = {
},
removeItem: key => {
delete storage[key];
},
clear: () => {
storage = {}
}
};

global.sessionStorage = global.localStorage

0 comments on commit a706665

Please sign in to comment.