import { action, IReactionDisposer, makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Opt } from '../../fields/Doc'; import { Networking } from '../Network'; import { ScriptingGlobals } from '../util/ScriptingGlobals'; import { MainViewModal } from '../views/MainViewModal'; import './GoogleAuthenticationManager.scss'; import { ObservableReactComponent } from '../views/ObservableReactComponent'; const prompt = 'Paste authorization code here...'; @observer export class GoogleAuthenticationManager extends ObservableReactComponent { // eslint-disable-next-line no-use-before-define public static Instance: GoogleAuthenticationManager; private authenticationLink: Opt = undefined; @observable private openState = false; @observable private authenticationCode: Opt = undefined; @observable private showPasteTargetState = false; @observable private success: Opt = undefined; @observable private displayLauncher = true; @observable private credentials: { user_info: { name: string; picture: string }; access_token: string } | undefined = undefined; private disposer: Opt; constructor(props: object) { super(props); makeObservable(this); GoogleAuthenticationManager.Instance = this; } 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 fetchOrGenerateAccessToken = async (): Promise => { const response = await Networking.FetchFromServer('/readGoogleAccessToken'); // This will return a JSON object with { access_token, user_info } if already linked try { const parsed = JSON.parse(response) as { access_token: string; user_info: { name: string; picture: string } }; runInAction(() => { this.success = true; this.credentials = parsed; }); return parsed.access_token; } catch { console.warn('Not linked yet or invalid JSON. open auth...'); // This is an auth URL — redirect the user to /refreshGoogle if (typeof response === 'string' && response.startsWith('http')) { if (window.confirm('Authorize Dash to access your Google account?')) { window.open(response)?.focus(); return undefined; } } throw new Error('Unable to fetch Google access token.'); } }; public fetchAccessTokenSilently = async (): Promise => { const response = await Networking.FetchFromServer('/readGoogleAccessToken'); try { const parsed = JSON.parse(response) as { access_token: string; user_info: { name: string; picture: string } }; runInAction(() => { this.success = true; this.credentials = parsed; }); return parsed.access_token; } catch { // Do nothing — just return undefined silently return undefined; } }; resetState = action((visibleForMS: number = 3000, fadesOutInMS: number = 500) => { if (!visibleForMS && !fadesOutInMS) { runInAction(() => { this.isOpen = false; this.success = undefined; this.displayLauncher = true; this.credentials = undefined; 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 = undefined; }), fadesOutInMS ); }), visibleForMS ); } }); private get renderPrompt() { return (
{this.displayLauncher ? ( ) : null} {this.showPasteTargetState ? (this.authenticationCode = e.currentTarget.value))} placeholder={prompt} /> : null} {this.credentials?.user_info?.picture ? ( <> Welcome to Dash, {this.credentials.user_info.name}
{ await Networking.FetchFromServer('/revokeGoogleAccessToken'); this.resetState(0, 0); }}> Disconnect Account
) : null}
); } private get dialogueBoxStyle() { const borderColor = this.success === undefined ? 'black' : this.success ? 'green' : 'red'; return { borderColor, transition: '0.2s borderColor ease', zIndex: 1002 }; } render() { return (this.isOpen = false))} />; } } ScriptingGlobals.add('GoogleAuthenticationManager', GoogleAuthenticationManager);