diff --git a/packages/components/src/api/ApiConfig.ts b/packages/components/src/api/ApiConfig.ts index 2a8ddd8c46..8bcd6f3344 100644 --- a/packages/components/src/api/ApiConfig.ts +++ b/packages/components/src/api/ApiConfig.ts @@ -58,6 +58,9 @@ class ApiConfig { } else if (!useSsl && (domain === Domain.Localhost || domain === Domain.JungleHorse)) { // NB: Lack of SSL means use local development. v2ApiHost = "api.jungle.horse"; + } else if (domain === Domain.JungleHorse) { + // TODO: Clean up these branches + v2ApiHost = "api.jungle.horse"; } this.domain = domain; @@ -373,6 +376,12 @@ class ApiConfig { return `${this.getScheme()}://${this.getNewApiHost()}/twitch/event_rule/${eventRuleToken}/delete`; } + // =============== Twitch OAuth =============== + + checkTwitchOauthStatus() : string { + return `${this.getScheme()}://${this.getNewApiHost()}/twitch/oauth/check`; + } + obsEventsWebsocket(twitchUsername: string) : string { if (this.domain === Domain.Localhost) { return `ws://localhost:54321/obs/${twitchUsername}`; diff --git a/packages/components/src/api/storyteller/twitch_oauth/CheckTwitchOauth.ts b/packages/components/src/api/storyteller/twitch_oauth/CheckTwitchOauth.ts new file mode 100644 index 0000000000..aa6a19718f --- /dev/null +++ b/packages/components/src/api/storyteller/twitch_oauth/CheckTwitchOauth.ts @@ -0,0 +1,48 @@ +import { ApiConfig } from "../../ApiConfig"; + +export interface CheckTwitchOauthSuccessResponse { + success: boolean, + oauth_token_found: boolean, +} + +export interface CheckTwitchOauthErrorResponse { + success: boolean, +} + +type CheckTwitchOauthResponse = CheckTwitchOauthSuccessResponse | CheckTwitchOauthErrorResponse; + +export function CheckTwitchOauthIsOk(response: CheckTwitchOauthResponse): response is CheckTwitchOauthSuccessResponse { + return response?.success === true; +} + +export function CheckTwitchOauthIsError(response: CheckTwitchOauthResponse): response is CheckTwitchOauthErrorResponse { + return response?.success === false; +} + +export async function CheckTwitchOauth() : Promise +{ + const endpoint = new ApiConfig().checkTwitchOauthStatus(); + + return await fetch(endpoint, { + method: 'GET', + headers: { + 'Accept': 'application/json', + }, + credentials: 'include', + }) + .then(res => res.json()) + .then(res => { + if (!res) { + return { success : false }; // TODO: This loses error semantics and is deprecated + } + + if (res && 'success' in res) { + return res; + } else { + return { success : false }; + } + }) + .catch(e => { + return { success : false }; + }); +} diff --git a/packages/components/src/urls/StorytellerUrlConfig.ts b/packages/components/src/urls/StorytellerUrlConfig.ts index e2e7de24e7..2ad0eea037 100644 --- a/packages/components/src/urls/StorytellerUrlConfig.ts +++ b/packages/components/src/urls/StorytellerUrlConfig.ts @@ -25,7 +25,7 @@ export class StorytellerUrlConfig { } twitchOauthEnrollRedirect() : string { - return `${this.getScheme()}://${this.getApiHost()}/twitch/oauth_enroll_redirect`; + return `${this.getScheme()}://${this.getApiHost()}/twitch/oauth/enroll_redirect_begin`; } // =============== API HOSTS =============== diff --git a/packages/storyteller/src/pages/index/subpages/LoggedInIndex.tsx b/packages/storyteller/src/pages/index/subpages/LoggedInIndex.tsx index 4c4d35646b..4bc13012ff 100644 --- a/packages/storyteller/src/pages/index/subpages/LoggedInIndex.tsx +++ b/packages/storyteller/src/pages/index/subpages/LoggedInIndex.tsx @@ -1,17 +1,39 @@ -import React from 'react'; +import React, { useCallback, useEffect, useState } from 'react'; import { Link } from 'react-router-dom'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faCogs, faVideo } from '@fortawesome/free-solid-svg-icons'; import { faDiscord, faTwitch } from '@fortawesome/free-brands-svg-icons'; import { DiscordLink } from '@storyteller/components/src/elements/DiscordLink'; import { StorytellerUrlConfig } from '@storyteller/components/src/urls/StorytellerUrlConfig'; +import { CheckTwitchOauth, CheckTwitchOauthIsError, CheckTwitchOauthIsOk } from '@storyteller/components/src/api/storyteller/twitch_oauth/CheckTwitchOauth'; function LoggedInIndex() { const oauthUrl = new StorytellerUrlConfig().twitchOauthEnrollRedirect(); + const [oauthTokenFound, setOauthTokenFound] = useState(false); + + const checkTwitchOauth = useCallback(async () => { + const result = await CheckTwitchOauth(); + + if (CheckTwitchOauthIsOk(result)) { + setOauthTokenFound(result.oauth_token_found); + } else if (CheckTwitchOauthIsError(result)) { + } + }, []); + + useEffect(() => { + checkTwitchOauth(); + }, []) + + let linkText = <>Link Your Twitch   ; + + if (oauthTokenFound) { + linkText = <>Re-link Your Twitch   ; + } + + return (
-
@@ -19,7 +41,7 @@ function LoggedInIndex() { href={oauthUrl} className="button is-large is-info is-fullwidth" > - Link to Your Twitch  + {linkText}