From c01a2c72b6334b21240df898a8a9543e78e74dad Mon Sep 17 00:00:00 2001 From: Timmy Huang Date: Thu, 8 Oct 2020 16:57:53 -0700 Subject: [PATCH] thuang-1840-authn-prompt (#1911) --- client/src/components/menubar/authButtons.js | 96 +++++++++++++++++++- client/src/components/termsPrompt/index.js | 27 +----- client/src/components/util/localStorage.js | 22 +++++ 3 files changed, 117 insertions(+), 28 deletions(-) create mode 100644 client/src/components/util/localStorage.js diff --git a/client/src/components/menubar/authButtons.js b/client/src/components/menubar/authButtons.js index a9ad8176..91729679 100644 --- a/client/src/components/menubar/authButtons.js +++ b/client/src/components/menubar/authButtons.js @@ -1,4 +1,5 @@ -import React from "react"; +import React, { useState } from "react"; + import { AnchorButton, Button, @@ -6,20 +7,36 @@ import { Tooltip, Popover, Menu, + Elevation, + PopoverPosition, + Checkbox, + Card, } from "@blueprintjs/core"; + import { IconNames } from "@blueprintjs/icons"; import * as globals from "../../globals"; + import styles from "./menubar.css"; +import { storageGet, storageSet, KEYS } from "../util/localStorage"; + const BASE_EMOJI = [0x1f9d1, 0x1f468, 0x1f469]; const SKIN_TONES = [0x1f3fb, 0x1f3fc, 0x1f3fd, 0x1f3fe, 0x1f3ff]; const MICROSCOPE = 0x1f52c; const ZERO_WIDTH_JOINER = 0x0200d; +const LOGIN_PROMPT_OFF = "off"; + const Auth = React.memo((props) => { + const [isPromptOpen, setIsPromptOpen] = useState(shouldShowPrompt()); + const { auth, userinfo } = props; + const isAuthenticated = userinfo && userinfo.is_authenticated; + + window.userinfo = userinfo; + const randomInt = Math.random() * 15; const sexIndex = Math.floor(randomInt / 5); const skinToneIndex = Math.floor(randomInt % 5); @@ -31,9 +48,9 @@ const Auth = React.memo((props) => { MICROSCOPE ); - if (!auth?.["requires_client_login"]) return null; + if (!shouldShowAuth()) return null; - if (userinfo?.["is_authenticated"]) { + if (isAuthenticated) { const PopoverContent = ( { ); } - return ( + const LoginButton = ( { @@ -84,6 +100,76 @@ const Auth = React.memo((props) => { ); + + if (isPromptOpen) { + return ( + } + onInteraction={setIsPromptOpen} + > + {LoginButton} + + ); + } + + return LoginButton; + + function shouldShowAuth() { + return auth && auth.requires_client_login; + } + + function shouldShowPrompt() { + if (storageGet(KEYS.LOGIN_PROMPT) === LOGIN_PROMPT_OFF) return false; + + return shouldShowAuth && !isAuthenticated; + } }); +function PromptContent({ setIsPromptOpen }) { + const [isChecked, setIsChecked] = useState(false); + + function handleOKClick() { + if (isChecked) { + storageSet(KEYS.LOGIN_PROMPT, LOGIN_PROMPT_OFF); + } + + setIsPromptOpen(false); + } + + function handleCheckboxChange() { + setIsChecked(!isChecked); + } + + return ( + +

+ Logging in will enable you to create your own categories and labels. + Logging in later will reset cellxgene to the default view and cause you + to lose progress. +

+ + Do not show me this message again + +
+ +
+
+ ); +} + export default Auth; diff --git a/client/src/components/termsPrompt/index.js b/client/src/components/termsPrompt/index.js index c6209a00..9aef013c 100644 --- a/client/src/components/termsPrompt/index.js +++ b/client/src/components/termsPrompt/index.js @@ -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"], @@ -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, @@ -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(); @@ -67,7 +48,7 @@ class TermsPrompt extends React.PureComponent { handleNo = () => { this.setState({ isOpen: false }); - storageSet(CookieDecision, "no"); + storageSet(KEYS.COOKIE_DECISION, "no"); }; renderTos() { diff --git a/client/src/components/util/localStorage.js b/client/src/components/util/localStorage.js new file mode 100644 index 00000000..5766d9f9 --- /dev/null +++ b/client/src/components/util/localStorage.js @@ -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 + } +}