diff options
author | Andy Rickert <andrew_rickert@brown.edu> | 2020-07-31 19:04:32 -0400 |
---|---|---|
committer | Andy Rickert <andrew_rickert@brown.edu> | 2020-07-31 19:04:32 -0400 |
commit | cfa39673564b6cd12d61ebbf3778cea8c3d0eff2 (patch) | |
tree | fd43d10a62c5d8f15057af7f1d788f263194ee0d /src/client/apis/HypothesisAuthenticationManager.tsx | |
parent | a1950ec49c56f5f9e2612da7e60a1e2615209386 (diff) | |
parent | c71d7fa4f84149bcb62246d50e06bfd1481365bc (diff) |
merge
Diffstat (limited to 'src/client/apis/HypothesisAuthenticationManager.tsx')
-rw-r--r-- | src/client/apis/HypothesisAuthenticationManager.tsx | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/src/client/apis/HypothesisAuthenticationManager.tsx b/src/client/apis/HypothesisAuthenticationManager.tsx new file mode 100644 index 000000000..c3e8d2fff --- /dev/null +++ b/src/client/apis/HypothesisAuthenticationManager.tsx @@ -0,0 +1,160 @@ +import { observable, action, reaction, runInAction, IReactionDisposer } from "mobx"; +import { observer } from "mobx-react"; +import * as React from "react"; +import MainViewModal from "../views/MainViewModal"; +import { Opt } from "../../fields/Doc"; +import { Networking } from "../Network"; +import "./HypothesisAuthenticationManager.scss"; +import { Scripting } from "../util/Scripting"; + +const prompt = "Paste authorization code here..."; + +@observer +export default class HypothesisAuthenticationManager extends React.Component<{}> { + public static Instance: HypothesisAuthenticationManager; + private authenticationLink: Opt<string> = undefined; + @observable private openState = false; + @observable private authenticationCode: Opt<string> = undefined; + @observable private showPasteTargetState = false; + @observable private success: Opt<boolean> = undefined; + @observable private displayLauncher = true; + @observable private credentials: string; + private disposer: Opt<IReactionDisposer>; + + private set isOpen(value: boolean) { + runInAction(() => this.openState = value); + } + + private set shouldShowPasteTarget(value: boolean) { + runInAction(() => this.showPasteTargetState = value); + } + + public cancel() { + this.openState && this.resetState(0, 0); + } + + public fetchAccessToken = async (displayIfFound = false) => { + const response: any = await Networking.FetchFromServer("/readHypothesisAccessToken"); + // if this is an authentication url, activate the UI to register the new access token + if (!response) { // new RegExp(AuthenticationUrl).test(response)) { + this.isOpen = true; + this.authenticationLink = response; + return new Promise<string>(async resolve => { + this.disposer?.(); + this.disposer = reaction( + () => this.authenticationCode, + async authenticationCode => { + if (authenticationCode) { + this.disposer?.(); + Networking.PostToServer("/writeHypothesisAccessToken", { authenticationCode }); + runInAction(() => { + this.success = true; + this.credentials = response; + }); + this.resetState(); + resolve(authenticationCode); + } + } + ); + }); + } + + if (displayIfFound) { + runInAction(() => { + this.success = true; + this.credentials = response; + }); + this.resetState(-1, -1); + this.isOpen = true; + } + return response.access_token; + } + + resetState = action((visibleForMS: number = 3000, fadesOutInMS: number = 500) => { + if (!visibleForMS && !fadesOutInMS) { + runInAction(() => { + this.isOpen = false; + this.success = undefined; + this.displayLauncher = true; + this.credentials = ""; + this.shouldShowPasteTarget = false; + this.authenticationCode = undefined; + }); + return; + } + this.authenticationCode = undefined; + this.displayLauncher = false; + this.shouldShowPasteTarget = false; + if (visibleForMS > 0 && fadesOutInMS > 0) { + setTimeout(action(() => { + this.isOpen = false; + setTimeout(action(() => { + this.success = undefined; + this.displayLauncher = true; + this.credentials = ""; + }), fadesOutInMS); + }), visibleForMS); + } + }); + + constructor(props: {}) { + super(props); + HypothesisAuthenticationManager.Instance = this; + } + + private get renderPrompt() { + return ( + <div className={'authorize-container'}> + + {this.displayLauncher ? <button + className={"dispatch"} + onClick={() => { + this.shouldShowPasteTarget = true; + }} + style={{ marginBottom: this.showPasteTargetState ? 15 : 0 }} + >Authorize a Hypothesis account...</button> : (null)} + {this.showPasteTargetState ? <input + className={'paste-target'} + onChange={action(e => this.authenticationCode = e.currentTarget.value)} + placeholder={prompt} + /> : (null)} + {this.credentials ? + <> + <span + className={'welcome'} + >Welcome to Dash, {this.credentials} + </span> + <div + className={'disconnect'} + onClick={async () => { + await Networking.FetchFromServer("/revokeHypothesisAccessToken"); + this.resetState(0, 0); + }} + >Disconnect Account</div> + </> : (null)} + </div> + ); + } + + private get dialogueBoxStyle() { + const borderColor = this.success === undefined ? "black" : this.success ? "green" : "red"; + return { borderColor, transition: "0.2s borderColor ease", zIndex: 1002 }; + } + + render() { + return ( + <MainViewModal + isDisplayed={this.openState} + interactive={true} + contents={this.renderPrompt} + // overlayDisplayedOpacity={0.9} + dialogueBoxStyle={this.dialogueBoxStyle} + overlayStyle={{ zIndex: 1001 }} + closeOnExternalClick={action(() => this.isOpen = false)} + /> + ); + } + +} + +Scripting.addGlobal("HypothesisAuthenticationManager", HypothesisAuthenticationManager);
\ No newline at end of file |