Skip to content

Commit

Permalink
thuang-1840-authn-prompt
Browse files Browse the repository at this point in the history
  • Loading branch information
tihuan committed Oct 7, 2020
1 parent cf77a8d commit 5b351ad
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 41 deletions.
4 changes: 2 additions & 2 deletions client/src/components/leftSidebar/topLeftLogoAndTitle.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,9 @@ class LeftSideBar extends React.Component {
userinfo,
}}
/>
{!userinfo.is_authenticated ? (
{!userinfo.is_authenticated && (
<AuthButtons auth={auth} userinfo={userinfo} />
) : null}
)}
</div>
</div>
);
Expand Down
121 changes: 105 additions & 16 deletions client/src/components/menubar/authButtons.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,120 @@
import React from "react";
import { AnchorButton, ButtonGroup, Tooltip } from "@blueprintjs/core";
import React, { useState } from "react";
import {
AnchorButton,
ButtonGroup,
Elevation,
Tooltip,
Popover,
PopoverPosition,
Checkbox,
Card,
Button,
Classes,
} from "@blueprintjs/core";
import * as globals from "../../globals";
import styles from "./menubar.css";

import { storageGet, storageSet, KEYS } from "../util/localStorage";

const LOGIN_PROMPT_OFF = "off";

const Auth = React.memo((props) => {
const [isPromptOpen, setIsPromptOpen] = useState(shouldShowPrompt());

const { auth, userinfo } = props;

if (!auth || (auth && !auth.requires_client_login)) return null;
const isAuthenticated = userinfo && userinfo.is_authenticated;

if (shouldShowAuth()) return null;

const AuthButton = () => {
return (
<AnchorButton
type="button"
data-testid="auth-button"
href={isAuthenticated ? auth.logout : auth.login}
>
{isAuthenticated ? "Log Out" : "Log In"}
</AnchorButton>
);
};

return (
<ButtonGroup className={styles.menubarButton}>
<Tooltip
content="Log in to cellxgene"
position="bottom"
hoverOpenDelay={globals.tooltipHoverOpenDelay}
>
<AnchorButton
type="button"
data-testid="auth-button"
disabled={false}
href={!userinfo.is_authenticated ? auth.login : auth.logout}
<div style={{ position: "relative" }}>
<Tooltip
content="Log in to cellxgene"
position="bottom"
hoverOpenDelay={globals.tooltipHoverOpenDelay}
>
<AuthButton />
</Tooltip>
<Popover
position={PopoverPosition.AUTO_END}
isOpen={isPromptOpen}
content={<PopoverContent setIsPromptOpen={setIsPromptOpen} />}
onInteraction={setIsPromptOpen}
>
{!userinfo.is_authenticated ? "Log In" : "Log Out"}
</AnchorButton>
</Tooltip>
<div style={{ position: "absolute" }} />
</Popover>
</div>
</ButtonGroup>
);

function shouldShowAuth() {
return auth && auth.requires_client_login;
}

function shouldShowPrompt() {
if (storageGet(KEYS.LOGIN_PROMPT) === LOGIN_PROMPT_OFF) return false;

return shouldShowAuth && !isAuthenticated;
}
});

function PopoverContent({ setIsPromptOpen }) {
const [isChecked, setIsChecked] = useState(false);

function handleOKClick() {
if (isChecked) {
storageSet(KEYS.LOGIN_PROMPT, LOGIN_PROMPT_OFF);
}

setIsPromptOpen(false);
}

function handleCheckboxChange() {
setIsChecked(!isChecked);
}

return (
<Card style={{ width: "500px" }} elevation={Elevation.TWO}>
<p>
Log in to create your own annotations. Please note, logging in later
will refresh this page and you may lose progress.
</p>
<Checkbox
style={{ width: "230px" }}
checked={isChecked}
onChange={handleCheckboxChange}
>
Do not show me this message again
</Checkbox>
<div
style={{ display: "flex", justifyContent: "flex-end", marginTop: 15 }}
>
<Button
className={Classes.POPOVER_DISMISS}
style={{ marginRight: "5px" }}
>
Cancel
</Button>
<Button onClick={handleOKClick} intent="primary">
OK
</Button>
</div>
</Card>
);
}

export default Auth;
27 changes: 4 additions & 23 deletions client/src/components/termsPrompt/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,7 @@ import {
Colors,
Icon,
} from "@blueprintjs/core";

const CookieDecision = "cxg.cookieDecision";

function storageGet(key, defaultValue = null) {
try {
const val = window.localStorage.getItem(key);
if (val === null) return defaultValue;
return val;
} catch (e) {
return defaultValue;
}
}

function storageSet(key, value) {
try {
window.localStorage.setItem(key, value);
} catch {
// continue
}
}
import { storageGet, storageSet, KEYS } from "../util/localStorage";

@connect((state) => ({
tosURL: state.config?.parameters?.["about_legal_tos"],
Expand All @@ -37,7 +18,7 @@ class TermsPrompt extends React.PureComponent {
constructor(props) {
super(props);
const { tosURL, privacyURL } = this.props;
const cookieDecision = storageGet(CookieDecision, null);
const cookieDecision = storageGet(KEYS.COOKIE_DECISION, null);
const hasDecided = cookieDecision !== null;
this.state = {
hasDecided,
Expand All @@ -55,7 +36,7 @@ class TermsPrompt extends React.PureComponent {

handleOK = () => {
this.setState({ isOpen: false });
storageSet(CookieDecision, "yes");
storageSet(KEYS.COOKIE_DECISION, "yes");
if (window.cookieDecisionCallback instanceof Function) {
try {
window.cookieDecisionCallback();
Expand All @@ -67,7 +48,7 @@ class TermsPrompt extends React.PureComponent {

handleNo = () => {
this.setState({ isOpen: false });
storageSet(CookieDecision, "no");
storageSet(KEYS.COOKIE_DECISION, "no");
};

renderTos() {
Expand Down
22 changes: 22 additions & 0 deletions client/src/components/util/localStorage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
export const KEYS = {
COOKIE_DECISION: "cxg.cookieDecision",
LOGIN_PROMPT: "cxg.LOGIN_PROMPT",
};

export function storageGet(key, defaultValue = null) {
try {
const val = window.localStorage.getItem(key);
if (val === null) return defaultValue;
return val;
} catch (e) {
return defaultValue;
}
}

export function storageSet(key, value) {
try {
window.localStorage.setItem(key, value);
} catch {
// continue
}
}

0 comments on commit 5b351ad

Please sign in to comment.