manifold/web/components/groups/groups-button.tsx

151 lines
4.0 KiB
TypeScript
Raw Normal View History

import clsx from 'clsx'
import { User } from 'common/user'
import { useState } from 'react'
import { useUser } from 'web/hooks/use-user'
import { withTracking } from 'web/lib/service/analytics'
import { Row } from 'web/components/layout/row'
import { useMemberGroups, useMemberIds } from 'web/hooks/use-group'
import { TextButton } from 'web/components/text-button'
import { Group } from 'common/group'
import { Modal } from 'web/components/layout/modal'
import { Col } from 'web/components/layout/col'
2022-07-14 17:09:28 +00:00
import { joinGroup, leaveGroup } from 'web/lib/firebase/groups'
import { firebaseLogin } from 'web/lib/firebase/users'
import { GroupLinkItem } from 'web/pages/groups'
2022-07-14 17:09:28 +00:00
import toast from 'react-hot-toast'
export function GroupsButton(props: { user: User }) {
const { user } = props
const [isOpen, setIsOpen] = useState(false)
const groups = useMemberGroups(user.id)
return (
<>
<TextButton onClick={() => setIsOpen(true)}>
<span className="font-semibold">{groups?.length ?? ''}</span> Groups
</TextButton>
<GroupsDialog
user={user}
groups={groups ?? []}
isOpen={isOpen}
setIsOpen={setIsOpen}
/>
</>
)
}
function GroupsDialog(props: {
user: User
groups: Group[]
isOpen: boolean
setIsOpen: (isOpen: boolean) => void
}) {
const { user, groups, isOpen, setIsOpen } = props
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>
<GroupsList groups={groups} />
</Col>
</Modal>
)
}
function GroupsList(props: { groups: Group[] }) {
const { groups } = props
return (
<Col className="gap-2">
{groups.length === 0 && (
<div className="text-gray-500">No groups yet...</div>
)}
{groups
.sort((group1, group2) => group2.createdTime - group1.createdTime)
.map((group) => (
<GroupItem key={group.id} group={group} />
))}
</Col>
)
}
function GroupItem(props: { group: Group; className?: string }) {
const { group, className } = props
2022-09-03 01:36:49 +00:00
const user = useUser()
const memberIds = useMemberIds(group.id)
return (
<Row className={clsx('items-center justify-between gap-2 p-2', className)}>
<Row className="line-clamp-1 items-center gap-2">
<GroupLinkItem group={group} />
</Row>
2022-09-03 01:36:49 +00:00
<JoinOrLeaveGroupButton
group={group}
user={user}
isMember={user ? memberIds?.includes(user.id) : false}
/>
</Row>
)
}
export function JoinOrLeaveGroupButton(props: {
group: Group
2022-09-03 01:36:49 +00:00
isMember: boolean
user: User | undefined | null
small?: boolean
className?: string
}) {
2022-09-03 01:36:49 +00:00
const { group, small, className, isMember, user } = props
const smallStyle =
'btn !btn-xs border-2 border-gray-500 bg-white normal-case text-gray-500 hover:border-gray-500 hover:bg-white hover:text-gray-500'
2022-09-03 01:36:49 +00:00
if (!user) {
if (!group.anyoneCanJoin)
return <div className={clsx(className, 'text-gray-500')}>Closed</div>
return (
<button
onClick={firebaseLogin}
className={clsx('btn btn-sm', small && smallStyle, className)}
>
2022-09-05 21:51:09 +00:00
Login to follow
</button>
)
}
const onJoinGroup = () => {
2022-09-03 01:36:49 +00:00
joinGroup(group, user.id).catch(() => {
toast.error('Failed to join group')
})
}
const onLeaveGroup = () => {
2022-09-03 01:36:49 +00:00
leaveGroup(group, user.id).catch(() => {
toast.error('Failed to leave group')
})
}
2022-07-14 17:09:28 +00:00
if (isMember) {
return (
<button
className={clsx(
'btn btn-outline btn-xs',
small && smallStyle,
className
)}
onClick={withTracking(onLeaveGroup, 'leave group')}
>
2022-09-05 21:51:09 +00:00
Unfollow
</button>
)
}
if (!group.anyoneCanJoin)
return <div className={clsx(className, 'text-gray-500')}>Closed</div>
return (
<button
className={clsx('btn btn-sm', small && smallStyle, className)}
onClick={withTracking(onJoinGroup, 'join group')}
>
2022-09-05 21:51:09 +00:00
Follow
</button>
)
}