manifold/web/components/referrals-button.tsx
2022-07-26 15:24:16 -07:00

178 lines
6.1 KiB
TypeScript

import clsx from 'clsx'
import { User } from 'common/user'
import { useEffect, useState } from 'react'
import { prefetchUsers, useUserById } from 'web/hooks/use-user'
import { Col } from './layout/col'
import { Modal } from './layout/modal'
import { Tabs } from './layout/tabs'
import { Row } from 'web/components/layout/row'
import { Avatar } from 'web/components/avatar'
import { UserLink } from 'web/components/user-page'
import { useReferrals } from 'web/hooks/use-referrals'
import { FilterSelectUsers } from 'web/components/filter-select-users'
import { getUser, updateUser } from 'web/lib/firebase/users'
import { TextButton } from 'web/components/text-button'
export function ReferralsButton(props: { user: User; currentUser?: User }) {
const { user, currentUser } = props
const [isOpen, setIsOpen] = useState(false)
const referralIds = useReferrals(user.id)
return (
<>
<TextButton onClick={() => setIsOpen(true)}>
<span className="font-semibold">{referralIds?.length ?? ''}</span>{' '}
Referrals
</TextButton>
<ReferralsDialog
user={user}
referralIds={referralIds ?? []}
isOpen={isOpen}
setIsOpen={setIsOpen}
currentUser={currentUser}
/>
</>
)
}
function ReferralsDialog(props: {
user: User
referralIds: string[]
isOpen: boolean
setIsOpen: (isOpen: boolean) => void
currentUser?: User
}) {
const { user, referralIds, isOpen, setIsOpen, currentUser } = props
const [referredBy, setReferredBy] = useState<User[]>([])
const [isSubmitting, setIsSubmitting] = useState(false)
const [errorText, setErrorText] = useState('')
const [referredByUser, setReferredByUser] = useState<User | null>()
useEffect(() => {
if (isOpen && !referredByUser && user?.referredByUserId) {
getUser(user.referredByUserId).then((user) => {
setReferredByUser(user)
})
}
}, [isOpen, referredByUser, user.referredByUserId])
useEffect(() => {
prefetchUsers(referralIds)
}, [referralIds])
return (
<Modal open={isOpen} setOpen={setIsOpen}>
<Col className="rounded bg-white p-6">
<div className="p-2 pb-1 text-xl">{user.name}</div>
<div className="p-2 pt-0 text-sm text-gray-500">@{user.username}</div>
<Tabs
tabs={[
{
title: 'Referrals',
content: <ReferralsList userIds={referralIds} />,
},
{
title: 'Referred by',
content: (
<>
{user.id === currentUser?.id && !referredByUser ? (
<>
<FilterSelectUsers
setSelectedUsers={setReferredBy}
selectedUsers={referredBy}
ignoreUserIds={[currentUser.id]}
showSelectedUsersTitle={false}
selectedUsersClassName={'grid-cols-2 '}
maxUsers={1}
/>
<Row className={'mt-0 justify-end'}>
<button
className={
referredBy.length === 0
? 'hidden'
: 'btn btn-primary btn-md my-2 w-24 normal-case'
}
disabled={referredBy.length === 0 || isSubmitting}
onClick={() => {
setIsSubmitting(true)
updateUser(currentUser.id, {
referredByUserId: referredBy[0].id,
})
.then(async () => {
setErrorText('')
setIsSubmitting(false)
setReferredBy([])
setIsOpen(false)
})
.catch((error) => {
setIsSubmitting(false)
setErrorText(error.message)
})
}}
>
Save
</button>
</Row>
<span className={'text-warning'}>
{referredBy.length > 0 &&
'Careful: you can only set who referred you once!'}
</span>
<span className={'text-error'}>{errorText}</span>
</>
) : (
<div className="justify-center text-gray-700">
{referredByUser ? (
<Row className={'items-center gap-2 p-2'}>
<Avatar
username={referredByUser.username}
avatarUrl={referredByUser.avatarUrl}
/>
<UserLink
username={referredByUser.username}
name={referredByUser.name}
/>
</Row>
) : (
<span className={'text-gray-500'}>No one...</span>
)}
</div>
)}
</>
),
},
]}
/>
</Col>
</Modal>
)
}
function ReferralsList(props: { userIds: string[] }) {
const { userIds } = props
return (
<Col className="gap-2">
{userIds.length === 0 && (
<div className="text-gray-500">No users yet...</div>
)}
{userIds.map((userId) => (
<UserReferralItem key={userId} userId={userId} />
))}
</Col>
)
}
function UserReferralItem(props: { userId: string; className?: string }) {
const { userId, className } = props
const user = useUserById(userId)
return (
<Row className={clsx('items-center justify-between gap-2 p-2', className)}>
<Row className="items-center gap-2">
<Avatar username={user?.username} avatarUrl={user?.avatarUrl} />
{user && <UserLink name={user.name} username={user.username} />}
</Row>
</Row>
)
}