Show online users on desktop
This commit is contained in:
parent
2610f32521
commit
dd9d24e657
|
@ -38,6 +38,7 @@ export type User = {
|
|||
|
||||
referredByUserId?: string
|
||||
referredByContractId?: string
|
||||
lastPingTime?: number
|
||||
}
|
||||
|
||||
export const STARTING_BALANCE = ENV_CONFIG.startingBalance ?? 1000
|
||||
|
@ -57,7 +58,6 @@ export type PrivateUser = {
|
|||
initialIpAddress?: string
|
||||
apiKey?: string
|
||||
notificationPreferences?: notification_subscribe_types
|
||||
lastTimeCheckedBonuses?: number
|
||||
}
|
||||
|
||||
export type notification_subscribe_types = 'all' | 'less' | 'none'
|
||||
|
|
|
@ -20,16 +20,17 @@ service cloud.firestore {
|
|||
allow read;
|
||||
allow update: if resource.data.id == request.auth.uid
|
||||
&& request.resource.data.diff(resource.data).affectedKeys()
|
||||
.hasOnly(['bio', 'bannerUrl', 'website', 'twitterHandle', 'discordHandle', 'followedCategories', 'referredByContractId']);
|
||||
allow update: if resource.data.id == request.auth.uid
|
||||
&& request.resource.data.diff(resource.data).affectedKeys()
|
||||
.hasOnly(['referredByUserId'])
|
||||
// only one referral allowed per user
|
||||
&& !("referredByUserId" in resource.data)
|
||||
// user can't refer themselves
|
||||
&& !(resource.data.id == request.resource.data.referredByUserId);
|
||||
// quid pro quos enabled (only once though so nbd) - bc I can't make this work:
|
||||
// && (get(/databases/$(database)/documents/users/$(request.resource.data.referredByUserId)).referredByUserId == resource.data.id);
|
||||
.hasOnly(['bio', 'bannerUrl', 'website', 'twitterHandle', 'discordHandle', 'followedCategories', 'referredByContractId', 'lastPingTime']);
|
||||
// User referral rules
|
||||
allow update: if resource.data.id == request.auth.uid
|
||||
&& request.resource.data.diff(resource.data).affectedKeys()
|
||||
.hasOnly(['referredByUserId'])
|
||||
// only one referral allowed per user
|
||||
&& !("referredByUserId" in resource.data)
|
||||
// user can't refer themselves
|
||||
&& !(resource.data.id == request.resource.data.referredByUserId);
|
||||
// quid pro quos enabled (only once though so nbd) - bc I can't make this work:
|
||||
// && (get(/databases/$(database)/documents/users/$(request.resource.data.referredByUserId)).referredByUserId == resource.data.id);
|
||||
}
|
||||
|
||||
match /{somePath=**}/portfolioHistory/{portfolioHistoryId} {
|
||||
|
|
|
@ -7,6 +7,7 @@ import { FollowButton } from './follow-button'
|
|||
import { Col } from './layout/col'
|
||||
import { Row } from './layout/row'
|
||||
import { UserLink } from './user-page'
|
||||
import { OnlineUserAvatar } from 'web/components/online-user-list'
|
||||
|
||||
export function FollowList(props: { userIds: string[] }) {
|
||||
const { userIds } = props
|
||||
|
@ -63,10 +64,7 @@ function UserFollowItem(props: {
|
|||
|
||||
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>
|
||||
<OnlineUserAvatar user={user} />
|
||||
{!hideFollowButton && (
|
||||
<FollowButton
|
||||
isFollowing={isFollowing}
|
||||
|
|
|
@ -13,7 +13,7 @@ import clsx from 'clsx'
|
|||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/router'
|
||||
import { usePrivateUser, useUser } from 'web/hooks/use-user'
|
||||
import { firebaseLogout, User } from 'web/lib/firebase/users'
|
||||
import { firebaseLogout, updateUser, User } from 'web/lib/firebase/users'
|
||||
import { ManifoldLogo } from './manifold-logo'
|
||||
import { MenuButton } from './menu'
|
||||
import { ProfileSummary } from './profile-menu'
|
||||
|
@ -208,6 +208,17 @@ export default function Sidebar(props: { className?: string }) {
|
|||
href: `${groupPath(group.slug)}/${GROUP_CHAT_SLUG}`,
|
||||
}))
|
||||
|
||||
useEffect(() => {
|
||||
if (!user) return
|
||||
// set ping time to now every 60 seconds to indicate that the user is active
|
||||
const pingInterval = setInterval(() => {
|
||||
updateUser(user.id, {
|
||||
lastPingTime: Date.now(),
|
||||
})
|
||||
}, 1000 * 30)
|
||||
return () => clearInterval(pingInterval)
|
||||
}, [user])
|
||||
|
||||
return (
|
||||
<nav aria-label="Sidebar" className={className}>
|
||||
<ManifoldLogo className="py-6" twoLine />
|
||||
|
|
56
web/components/online-user-list.tsx
Normal file
56
web/components/online-user-list.tsx
Normal file
|
@ -0,0 +1,56 @@
|
|||
import clsx from 'clsx'
|
||||
import { Avatar } from './avatar'
|
||||
import { Col } from './layout/col'
|
||||
import { Row } from './layout/row'
|
||||
import { UserLink } from './user-page'
|
||||
import { User } from 'common/user'
|
||||
import { UserCircleIcon } from '@heroicons/react/solid'
|
||||
import { useUsers } from 'web/hooks/use-users'
|
||||
import { partition } from 'lodash'
|
||||
|
||||
const isOnline = (user?: User) =>
|
||||
user && user.lastPingTime && user.lastPingTime > Date.now() - 5 * 60 * 1000
|
||||
|
||||
export function OnlineUserList(props: { users: User[] }) {
|
||||
let { users } = props
|
||||
const liveUsers = useUsers().filter((user) =>
|
||||
users.map((u) => u.id).includes(user.id)
|
||||
)
|
||||
if (liveUsers) users = liveUsers
|
||||
const [onlineUsers, offlineUsers] = partition(users, (user) => isOnline(user))
|
||||
return (
|
||||
<Col className="mt-4 gap-1">
|
||||
{onlineUsers
|
||||
.concat(offlineUsers)
|
||||
.slice(0, 15)
|
||||
.map((user) => (
|
||||
<Row
|
||||
key={user.id}
|
||||
className={clsx('items-center justify-between gap-2 p-2')}
|
||||
>
|
||||
<OnlineUserAvatar key={user.id} user={user} />
|
||||
</Row>
|
||||
))}
|
||||
</Col>
|
||||
)
|
||||
}
|
||||
|
||||
export function OnlineUserAvatar(props: { user?: User; className?: string }) {
|
||||
const { user, className } = props
|
||||
|
||||
return (
|
||||
<Row className={clsx('relative items-center gap-2', className)}>
|
||||
<Avatar
|
||||
username={user?.username}
|
||||
avatarUrl={user?.avatarUrl}
|
||||
className={className}
|
||||
/>
|
||||
{user && <UserLink name={user.name} username={user.username} />}
|
||||
{isOnline(user) && (
|
||||
<div className="absolute left-0 top-0 ">
|
||||
<UserCircleIcon className="text-primary bg-primary h-3 w-3 rounded-full border-2 border-white" />
|
||||
</div>
|
||||
)}
|
||||
</Row>
|
||||
)
|
||||
}
|
|
@ -55,6 +55,7 @@ import { FollowList } from 'web/components/follow-list'
|
|||
import { SearchIcon } from '@heroicons/react/outline'
|
||||
import { useTipTxns } from 'web/hooks/use-tip-txns'
|
||||
import { JoinOrLeaveGroupButton } from 'web/components/groups/groups-button'
|
||||
import { OnlineUserList } from 'web/components/online-user-list'
|
||||
|
||||
export const getStaticProps = fromPropz(getStaticPropz)
|
||||
export async function getStaticPropz(props: { params: { slugs: string[] } }) {
|
||||
|
@ -174,7 +175,12 @@ export default function GroupPage(props: {
|
|||
|
||||
const rightSidebar = (
|
||||
<Col className="mt-6 hidden xl:block">
|
||||
<JoinOrCreateButton group={group} user={user} isMember={!!isMember} />
|
||||
<JoinOrAddQuestionsButtons
|
||||
group={group}
|
||||
user={user}
|
||||
isMember={!!isMember}
|
||||
/>
|
||||
<OnlineUserList users={members} />
|
||||
</Col>
|
||||
)
|
||||
const leaderboard = (
|
||||
|
@ -254,7 +260,6 @@ export default function GroupPage(props: {
|
|||
description={`Created by ${creator.name}. ${group.about}`}
|
||||
url={groupPath(group.slug)}
|
||||
/>
|
||||
|
||||
<Col className="px-3">
|
||||
<Row className={'items-center justify-between gap-4'}>
|
||||
<div className={'sm:mb-1'}>
|
||||
|
@ -270,7 +275,7 @@ export default function GroupPage(props: {
|
|||
</div>
|
||||
</div>
|
||||
<div className="hidden sm:block xl:hidden">
|
||||
<JoinOrCreateButton
|
||||
<JoinOrAddQuestionsButtons
|
||||
group={group}
|
||||
user={user}
|
||||
isMember={!!isMember}
|
||||
|
@ -278,10 +283,13 @@ export default function GroupPage(props: {
|
|||
</div>
|
||||
</Row>
|
||||
<div className="block sm:hidden">
|
||||
<JoinOrCreateButton group={group} user={user} isMember={!!isMember} />
|
||||
<JoinOrAddQuestionsButtons
|
||||
group={group}
|
||||
user={user}
|
||||
isMember={!!isMember}
|
||||
/>
|
||||
</div>
|
||||
</Col>
|
||||
|
||||
<Tabs
|
||||
currentPageForAnalytics={groupPath(group.slug)}
|
||||
className={'mb-0 sm:mb-2'}
|
||||
|
@ -292,7 +300,7 @@ export default function GroupPage(props: {
|
|||
)
|
||||
}
|
||||
|
||||
function JoinOrCreateButton(props: {
|
||||
function JoinOrAddQuestionsButtons(props: {
|
||||
group: Group
|
||||
user: User | null | undefined
|
||||
isMember: boolean
|
||||
|
|
Loading…
Reference in New Issue
Block a user