working linking logic
This commit is contained in:
parent
6b05561517
commit
bfef873b53
|
@ -62,6 +62,10 @@ export type PrivateUser = {
|
||||||
initialIpAddress?: string
|
initialIpAddress?: string
|
||||||
apiKey?: string
|
apiKey?: string
|
||||||
notificationPreferences?: notification_subscribe_types
|
notificationPreferences?: notification_subscribe_types
|
||||||
|
twitchInfo?: {
|
||||||
|
twitchName: string
|
||||||
|
controlToken: string
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type notification_subscribe_types = 'all' | 'less' | 'none'
|
export type notification_subscribe_types = 'all' | 'less' | 'none'
|
||||||
|
|
|
@ -70,7 +70,7 @@ service cloud.firestore {
|
||||||
allow read: if userId == request.auth.uid || isAdmin();
|
allow read: if userId == request.auth.uid || isAdmin();
|
||||||
allow update: if (userId == request.auth.uid || isAdmin())
|
allow update: if (userId == request.auth.uid || isAdmin())
|
||||||
&& request.resource.data.diff(resource.data).affectedKeys()
|
&& request.resource.data.diff(resource.data).affectedKeys()
|
||||||
.hasOnly(['apiKey', 'unsubscribedFromResolutionEmails', 'unsubscribedFromCommentEmails', 'unsubscribedFromAnswerEmails', 'notificationPreferences', 'unsubscribedFromWeeklyTrendingEmails' ]);
|
.hasOnly(['apiKey', 'twitchInfo', 'unsubscribedFromResolutionEmails', 'unsubscribedFromCommentEmails', 'unsubscribedFromAnswerEmails', 'notificationPreferences', 'unsubscribedFromWeeklyTrendingEmails' ]);
|
||||||
}
|
}
|
||||||
|
|
||||||
match /private-users/{userId}/views/{viewId} {
|
match /private-users/{userId}/views/{viewId} {
|
||||||
|
|
|
@ -13,7 +13,6 @@ import { createUser } from 'web/lib/firebase/api'
|
||||||
import { randomString } from 'common/util/random'
|
import { randomString } from 'common/util/random'
|
||||||
import { identifyUser, setUserProperty } from 'web/lib/service/analytics'
|
import { identifyUser, setUserProperty } from 'web/lib/service/analytics'
|
||||||
import { useStateCheckEquality } from 'web/hooks/use-state-check-equality'
|
import { useStateCheckEquality } from 'web/hooks/use-state-check-equality'
|
||||||
import { handleRedirectAfterSignup } from 'web/hooks/use-redirect-after-signup'
|
|
||||||
|
|
||||||
// Either we haven't looked up the logged in user yet (undefined), or we know
|
// Either we haven't looked up the logged in user yet (undefined), or we know
|
||||||
// the user is not logged in (null), or we know the user is logged in.
|
// the user is not logged in (null), or we know the user is logged in.
|
||||||
|
@ -64,13 +63,11 @@ export function AuthProvider(props: {
|
||||||
// Note: Cap on localStorage size is ~5mb
|
// Note: Cap on localStorage size is ~5mb
|
||||||
localStorage.setItem(CACHED_USER_KEY, JSON.stringify(current))
|
localStorage.setItem(CACHED_USER_KEY, JSON.stringify(current))
|
||||||
setCachedReferralInfoForUser(current.user)
|
setCachedReferralInfoForUser(current.user)
|
||||||
handleRedirectAfterSignup(current.user)
|
|
||||||
} else {
|
} else {
|
||||||
// User logged out; reset to null
|
// User logged out; reset to null
|
||||||
deleteTokenCookies()
|
deleteTokenCookies()
|
||||||
setAuthUser(null)
|
setAuthUser(null)
|
||||||
localStorage.removeItem(CACHED_USER_KEY)
|
localStorage.removeItem(CACHED_USER_KEY)
|
||||||
handleRedirectAfterSignup(null)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}, [setAuthUser])
|
}, [setAuthUser])
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
import { User, PrivateUser } from 'common/lib/user'
|
||||||
|
import { generateNewApiKey } from '../api/api-key'
|
||||||
|
import { updatePrivateUser } from '../firebase/users'
|
||||||
|
|
||||||
const TWITCH_BOT_PUBLIC_URL = 'https://king-prawn-app-5btyw.ondigitalocean.app'
|
const TWITCH_BOT_PUBLIC_URL = 'https://king-prawn-app-5btyw.ondigitalocean.app'
|
||||||
|
|
||||||
export async function initLinkTwitchAccount(
|
export async function initLinkTwitchAccount(
|
||||||
|
@ -23,3 +27,21 @@ export async function initLinkTwitchAccount(
|
||||||
)
|
)
|
||||||
return [responseData.twitchAuthURL, responseFetch.then((r) => r.json())]
|
return [responseData.twitchAuthURL, responseFetch.then((r) => r.json())]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function linkTwitchAccount(user: User, privateUser: PrivateUser) {
|
||||||
|
const apiKey = privateUser.apiKey ?? (await generateNewApiKey(user.id))
|
||||||
|
if (!apiKey) throw new Error("Couldn't retrieve or create Manifold api key")
|
||||||
|
|
||||||
|
const [twitchAuthURL, linkSuccessPromise] = await initLinkTwitchAccount(
|
||||||
|
user.id,
|
||||||
|
apiKey
|
||||||
|
)
|
||||||
|
|
||||||
|
console.log('opening twitch link', twitchAuthURL)
|
||||||
|
window.open(twitchAuthURL)
|
||||||
|
|
||||||
|
const twitchInfo = await linkSuccessPromise
|
||||||
|
await updatePrivateUser(user.id, { twitchInfo })
|
||||||
|
|
||||||
|
console.log(`Successfully linked Twitch account '${twitchInfo.twitchName}'`)
|
||||||
|
}
|
||||||
|
|
|
@ -1,21 +1,53 @@
|
||||||
|
import { useState } from 'react'
|
||||||
|
|
||||||
import { Page } from 'web/components/page'
|
import { Page } from 'web/components/page'
|
||||||
import { Col } from 'web/components/layout/col'
|
import { Col } from 'web/components/layout/col'
|
||||||
import { ManifoldLogo } from 'web/components/nav/manifold-logo'
|
import { ManifoldLogo } from 'web/components/nav/manifold-logo'
|
||||||
import { useSaveReferral } from 'web/hooks/use-save-referral'
|
import { useSaveReferral } from 'web/hooks/use-save-referral'
|
||||||
import { SEO } from 'web/components/SEO'
|
import { SEO } from 'web/components/SEO'
|
||||||
import { Spacer } from 'web/components/layout/spacer'
|
import { Spacer } from 'web/components/layout/spacer'
|
||||||
import { firebaseLogin } from 'web/lib/firebase/users'
|
import { firebaseLogin, getUserAndPrivateUser } from 'web/lib/firebase/users'
|
||||||
import { withTracking } from 'web/lib/service/analytics'
|
import { track } from 'web/lib/service/analytics'
|
||||||
import { Row } from 'web/components/layout/row'
|
import { Row } from 'web/components/layout/row'
|
||||||
import { Button } from 'web/components/button'
|
import { Button } from 'web/components/button'
|
||||||
import { useTracking } from 'web/hooks/use-tracking'
|
import { useTracking } from 'web/hooks/use-tracking'
|
||||||
import { useRedirectAfterSignup } from 'web/hooks/use-redirect-after-signup'
|
import { linkTwitchAccount } from 'web/lib/twitch/link-twitch-account'
|
||||||
|
import { usePrivateUser, useUser } from 'web/hooks/use-user'
|
||||||
|
import { LoadingIndicator } from 'web/components/loading-indicator'
|
||||||
|
|
||||||
export default function TwitchLandingPage() {
|
export default function TwitchLandingPage() {
|
||||||
useRedirectAfterSignup('twitch')
|
|
||||||
useSaveReferral()
|
useSaveReferral()
|
||||||
useTracking('view twitch landing page')
|
useTracking('view twitch landing page')
|
||||||
|
|
||||||
|
const user = useUser()
|
||||||
|
const privateUser = usePrivateUser()
|
||||||
|
const twitchUser = privateUser?.twitchInfo?.twitchName
|
||||||
|
|
||||||
|
const callback =
|
||||||
|
user && privateUser
|
||||||
|
? () => linkTwitchAccount(user, privateUser)
|
||||||
|
: async () => {
|
||||||
|
const result = await firebaseLogin()
|
||||||
|
|
||||||
|
const userId = result.user.uid
|
||||||
|
const { user, privateUser } = await getUserAndPrivateUser(userId)
|
||||||
|
if (!user || !privateUser) return
|
||||||
|
|
||||||
|
await linkTwitchAccount(user, privateUser)
|
||||||
|
}
|
||||||
|
|
||||||
|
const [isLoading, setLoading] = useState(false)
|
||||||
|
|
||||||
|
const getStarted = async () => {
|
||||||
|
setLoading(true)
|
||||||
|
|
||||||
|
const promise = callback()
|
||||||
|
track('twitch page button click')
|
||||||
|
await promise
|
||||||
|
|
||||||
|
setLoading(false)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page>
|
<Page>
|
||||||
<SEO
|
<SEO
|
||||||
|
@ -48,15 +80,32 @@ export default function TwitchLandingPage() {
|
||||||
<br />
|
<br />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Spacer h={6} />
|
<Spacer h={6} />
|
||||||
<Button
|
|
||||||
size="2xl"
|
{twitchUser ? (
|
||||||
color="gradient"
|
<div className="mt-3 self-center rounded-lg bg-gradient-to-r from-pink-300 via-purple-300 to-indigo-400 p-4 ">
|
||||||
className="self-center"
|
<div className="overflow-hidden rounded-lg bg-white px-4 py-5 shadow sm:p-6">
|
||||||
onClick={withTracking(firebaseLogin, 'twitch page button click')}
|
<div className="truncate text-sm font-medium text-gray-500">
|
||||||
>
|
Twitch account linked
|
||||||
Get started
|
</div>
|
||||||
</Button>
|
<div className="mt-1 text-2xl font-semibold text-gray-900">
|
||||||
|
{twitchUser}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : isLoading ? (
|
||||||
|
<LoadingIndicator spinnerClassName="w-16 h-16" />
|
||||||
|
) : (
|
||||||
|
<Button
|
||||||
|
size="2xl"
|
||||||
|
color="gradient"
|
||||||
|
className="self-center"
|
||||||
|
onClick={getStarted}
|
||||||
|
>
|
||||||
|
Get started
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
</Col>
|
</Col>
|
||||||
</Col>
|
</Col>
|
||||||
</Col>
|
</Col>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user