Add referrals list to user profile
This commit is contained in:
parent
bd3b1d5952
commit
6786c13bad
119
web/components/referrals-button.tsx
Normal file
119
web/components/referrals-button.tsx
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
import clsx from 'clsx'
|
||||||
|
import { PencilIcon } from '@heroicons/react/outline'
|
||||||
|
|
||||||
|
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 { TextButton } from './text-button'
|
||||||
|
import { track } from 'web/lib/service/analytics'
|
||||||
|
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'
|
||||||
|
|
||||||
|
export function EditReferredByButton(props: {
|
||||||
|
user: User
|
||||||
|
className?: string
|
||||||
|
}) {
|
||||||
|
const { user, className } = props
|
||||||
|
const [isOpen, setIsOpen] = useState(false)
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={clsx(
|
||||||
|
className,
|
||||||
|
'btn btn-sm btn-ghost cursor-pointer gap-2 whitespace-nowrap text-sm normal-case text-gray-700'
|
||||||
|
)}
|
||||||
|
onClick={() => {
|
||||||
|
setIsOpen(true)
|
||||||
|
track('edit referred by button')
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<PencilIcon className="inline h-4 w-4" />
|
||||||
|
Referred By {user.referredByUserId ?? 'No one'}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ReferralsButton(props: { user: User }) {
|
||||||
|
const { user } = 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}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function ReferralsDialog(props: {
|
||||||
|
user: User
|
||||||
|
referralIds: string[]
|
||||||
|
isOpen: boolean
|
||||||
|
setIsOpen: (isOpen: boolean) => void
|
||||||
|
}) {
|
||||||
|
const { user, referralIds, isOpen, setIsOpen } = props
|
||||||
|
|
||||||
|
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} />,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</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>
|
||||||
|
)
|
||||||
|
}
|
|
@ -36,6 +36,7 @@ import { FollowersButton, FollowingButton } from './following-button'
|
||||||
import { useFollows } from 'web/hooks/use-follows'
|
import { useFollows } from 'web/hooks/use-follows'
|
||||||
import { FollowButton } from './follow-button'
|
import { FollowButton } from './follow-button'
|
||||||
import { PortfolioMetrics } from 'common/user'
|
import { PortfolioMetrics } from 'common/user'
|
||||||
|
import { ReferralsButton } from 'web/components/referrals-button'
|
||||||
|
|
||||||
export function UserLink(props: {
|
export function UserLink(props: {
|
||||||
name: string
|
name: string
|
||||||
|
@ -197,6 +198,7 @@ export function UserPage(props: {
|
||||||
<Row className="gap-4">
|
<Row className="gap-4">
|
||||||
<FollowingButton user={user} />
|
<FollowingButton user={user} />
|
||||||
<FollowersButton user={user} />
|
<FollowersButton user={user} />
|
||||||
|
<ReferralsButton user={user} />
|
||||||
</Row>
|
</Row>
|
||||||
|
|
||||||
{user.website && (
|
{user.website && (
|
||||||
|
|
12
web/hooks/use-referrals.ts
Normal file
12
web/hooks/use-referrals.ts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
import { listenForReferrals } from 'web/lib/firebase/users'
|
||||||
|
|
||||||
|
export const useReferrals = (userId: string | null | undefined) => {
|
||||||
|
const [referralIds, setReferralIds] = useState<string[] | undefined>()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (userId) return listenForReferrals(userId, setReferralIds)
|
||||||
|
}, [userId])
|
||||||
|
|
||||||
|
return referralIds
|
||||||
|
}
|
|
@ -154,9 +154,9 @@ async function setCachedReferralInfoForUser(user: User | null) {
|
||||||
? cachedReferralContractId
|
? cachedReferralContractId
|
||||||
: undefined,
|
: undefined,
|
||||||
})
|
})
|
||||||
)
|
).catch((err) => {
|
||||||
.then((data) => console.log('done!', data))
|
console.log('error setting referral details', err)
|
||||||
.catch(console.error)
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
if (cachedReferralGroupSlug)
|
if (cachedReferralGroupSlug)
|
||||||
|
@ -359,3 +359,22 @@ export function listenForFollowers(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
export function listenForReferrals(
|
||||||
|
userId: string,
|
||||||
|
setReferralIds: (referralIds: string[]) => void
|
||||||
|
) {
|
||||||
|
const referralsQuery = query(
|
||||||
|
collection(db, 'users'),
|
||||||
|
where('referredByUserId', '==', userId)
|
||||||
|
)
|
||||||
|
return onSnapshot(
|
||||||
|
referralsQuery,
|
||||||
|
{ includeMetadataChanges: true },
|
||||||
|
(snapshot) => {
|
||||||
|
if (snapshot.metadata.fromCache) return
|
||||||
|
|
||||||
|
const values = snapshot.docs.map((doc) => doc.ref.id)
|
||||||
|
setReferralIds(filterDefined(values))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user