Fix twitch onboarding (#910)

* don't show welcome dialog for twitch users

* handle sign up race conditions with more hooks

* content organization and copy tweaks

* lint

* fix import
This commit is contained in:
mantikoros 2022-09-20 19:23:18 -05:00 committed by GitHub
parent 8870f0d356
commit 54778ec1b1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 79 additions and 49 deletions

View File

@ -1,6 +1,9 @@
import { ChevronLeftIcon, ChevronRightIcon } from '@heroicons/react/solid'
import clsx from 'clsx'
import { useState } from 'react'
import { useRouter } from 'next/router'
import { useEffect, useState } from 'react'
import { ChevronLeftIcon, ChevronRightIcon } from '@heroicons/react/solid'
import { User } from 'common/user'
import { useUser } from 'web/hooks/use-user'
import { updateUser } from 'web/lib/firebase/users'
import { Col } from '../layout/col'
@ -27,16 +30,12 @@ export default function Welcome() {
}
}
async function setUserHasSeenWelcome() {
if (user) {
await updateUser(user.id, { ['shouldShowWelcome']: false })
}
const setUserHasSeenWelcome = async () => {
if (user) await updateUser(user.id, { ['shouldShowWelcome']: false })
}
const [groupSelectorOpen, setGroupSelectorOpen] = useState(false)
if (!user || (!user.shouldShowWelcome && !groupSelectorOpen)) return <></>
const toggleOpen = (isOpen: boolean) => {
setUserHasSeenWelcome()
setOpen(isOpen)
@ -45,6 +44,12 @@ export default function Welcome() {
setGroupSelectorOpen(true)
}
}
const isTwitch = useIsTwitch(user)
if (isTwitch || !user || (!user.shouldShowWelcome && !groupSelectorOpen))
return <></>
return (
<>
<GroupSelectorDialog
@ -89,6 +94,21 @@ export default function Welcome() {
)
}
const useIsTwitch = (user: User | null | undefined) => {
const router = useRouter()
const isTwitch = router.pathname === '/twitch'
useEffect(() => {
console.log('twich?', isTwitch)
if (isTwitch && user?.shouldShowWelcome) {
updateUser(user.id, { ['shouldShowWelcome']: false })
}
}, [isTwitch, user])
return isTwitch
}
function PageIndicator(props: { page: number; totalpages: number }) {
const { page, totalpages } = props
return (

View File

@ -1,8 +1,7 @@
import { LinkIcon } from '@heroicons/react/solid'
import clsx from 'clsx'
import { PrivateUser, User } from 'common/user'
import Link from 'next/link'
import { MouseEventHandler, ReactNode, useState } from 'react'
import { MouseEventHandler, ReactNode, useEffect, useState } from 'react'
import toast from 'react-hot-toast'
import { Button } from 'web/components/button'
@ -17,11 +16,7 @@ import { Title } from 'web/components/title'
import { useSaveReferral } from 'web/hooks/use-save-referral'
import { useTracking } from 'web/hooks/use-tracking'
import { usePrivateUser, useUser } from 'web/hooks/use-user'
import {
firebaseLogin,
getUserAndPrivateUser,
updatePrivateUser,
} from 'web/lib/firebase/users'
import { firebaseLogin, updatePrivateUser } from 'web/lib/firebase/users'
import { track } from 'web/lib/service/analytics'
import {
getDockURLForUser,
@ -40,23 +35,32 @@ function ButtonGetStarted(props: {
const { user, privateUser, buttonClass, spinnerClass } = props
const [isLoading, setLoading] = useState(false)
const needsRelink =
privateUser?.twitchInfo?.twitchName &&
privateUser?.twitchInfo?.needsRelinking
const [waitingForUser, setWaitingForUser] = useState(false)
useEffect(() => {
if (waitingForUser && user && privateUser) {
setWaitingForUser(false)
if (privateUser.twitchInfo?.twitchName) return // If we've already linked Twitch, no need to do so again
setLoading(true)
linkTwitchAccountRedirect(user, privateUser).then(() => {
setLoading(false)
})
}
}, [user, privateUser, waitingForUser])
const callback =
user && privateUser
? () => linkTwitchAccountRedirect(user, privateUser)
: async () => {
const result = await firebaseLogin()
const userId = result.user.uid
const { user, privateUser } = await getUserAndPrivateUser(userId)
if (!user || !privateUser) return
if (privateUser.twitchInfo?.twitchName) return // If we've already linked Twitch, no need to do so again
await linkTwitchAccountRedirect(user, privateUser)
await firebaseLogin()
setWaitingForUser(true)
}
const getStarted = async () => {
@ -110,20 +114,9 @@ function TwitchPlaysManifoldMarkets(props: {
className={'!-my-0 md:block'}
/>
</Row>
<Col className="gap-4">
<div>
Similar to Twitch channel point predictions, Manifold Markets allows
you to create and feature on stream any question you like with users
predicting to earn play money.
</div>
<div>
The key difference is that Manifold's questions function more like a
stock market and viewers can buy and sell shares over the course of
the event and not just at the start. The market will eventually
resolve to yes or no at which point the winning shareholders will
receive their profit.
</div>
Start playing now by logging in with Google and typing commands in chat!
<Col className="mb-4 gap-4">
Start betting on Twitch now by linking your account and typing commands
in chat!
{twitchUser && !twitchInfo.needsRelinking ? (
<Button
size="xl"
@ -135,13 +128,25 @@ function TwitchPlaysManifoldMarkets(props: {
) : (
<ButtonGetStarted user={user} privateUser={privateUser} />
)}
</Col>
<Col className="gap-4">
<Subtitle text="How it works" />
<div>
Instead of Twitch channel points we use our play money, Mana (M$). All
viewers start with M$1000 and more can be earned for free and then{' '}
<Link href="/charity">
<a className="underline">donated to a charity</a>
</Link>{' '}
of their choice at no cost!
Similar to Twitch channel point predictions, Manifold Markets allows
you to create a play-money betting market on any question you like and
feature it in your stream.
</div>
<div>
The key difference is that Manifold's questions function more like a
stock market and viewers can buy and sell shares over the course of
the event and not just at the start. The market will eventually
resolve to yes or no at which point the winning shareholders will
receive their profit.
</div>
<div>
Instead of Twitch channel points we use our own play money, mana (M$).
All viewers start with M$1,000 and can earn more for free by betting
well.
</div>
</Col>
</div>
@ -170,21 +175,26 @@ function TwitchChatCommands() {
<Title text="Twitch Chat Commands" className="md:block" />
<Col className="gap-4">
<Subtitle text="For Chat" />
<Command command="bet yes#" desc="Bets a # of Mana on yes." />
<Command command="bet no#" desc="Bets a # of Mana on no." />
<Command
command="bet yes #"
desc="Bets an amount of M$ on yes, for example !bet yes 20"
/>
<Command command="bet no #" desc="Bets an amount of M$ on no." />
<Command
command="sell"
desc="Sells all shares you own. Using this command causes you to
cash out early before the market resolves. This could be profitable
(if the probability has moved towards the direction you bet) or cause
a loss, although at least you keep some Mana. For maximum profit (but
a loss, although at least you keep some mana. For maximum profit (but
also risk) it is better to not sell and wait for a favourable
resolution."
/>
<Command command="balance" desc="Shows how much Mana you own." />
<Command command="balance" desc="Shows how much M$ you have." />
<Command command="allin yes" desc="Bets your entire balance on yes." />
<Command command="allin no" desc="Bets your entire balance on no." />
<div className="mb-4" />
<Subtitle text="For Mods/Streamer" />
<Command
command="create <question>"
@ -194,7 +204,7 @@ function TwitchChatCommands() {
<Command command="resolve no" desc="Resolves the market as 'No'." />
<Command
command="resolve n/a"
desc="Resolves the market as 'N/A' and refunds everyone their Mana."
desc="Resolves the market as 'N/A' and refunds everyone their mana."
/>
</Col>
</div>