Optimistically join groups
This commit is contained in:
parent
8daf1b2ba8
commit
27a544205f
|
@ -1,6 +1,6 @@
|
||||||
import clsx from 'clsx'
|
import clsx from 'clsx'
|
||||||
import { User } from 'common/user'
|
import { User } from 'common/user'
|
||||||
import { useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { useUser } from 'web/hooks/use-user'
|
import { useUser } from 'web/hooks/use-user'
|
||||||
import { withTracking } from 'web/lib/service/analytics'
|
import { withTracking } from 'web/lib/service/analytics'
|
||||||
import { Row } from 'web/components/layout/row'
|
import { Row } from 'web/components/layout/row'
|
||||||
|
@ -9,9 +9,10 @@ import { TextButton } from 'web/components/text-button'
|
||||||
import { Group } from 'common/group'
|
import { Group } from 'common/group'
|
||||||
import { Modal } from 'web/components/layout/modal'
|
import { Modal } from 'web/components/layout/modal'
|
||||||
import { Col } from 'web/components/layout/col'
|
import { Col } from 'web/components/layout/col'
|
||||||
import { addUserToGroup, leaveGroup } from 'web/lib/firebase/groups'
|
import { joinGroup, leaveGroup } from 'web/lib/firebase/groups'
|
||||||
import { firebaseLogin } from 'web/lib/firebase/users'
|
import { firebaseLogin } from 'web/lib/firebase/users'
|
||||||
import { GroupLink } from 'web/pages/groups'
|
import { GroupLink } from 'web/pages/groups'
|
||||||
|
import toast from 'react-hot-toast'
|
||||||
|
|
||||||
export function GroupsButton(props: { user: User }) {
|
export function GroupsButton(props: { user: User }) {
|
||||||
const { user } = props
|
const { user } = props
|
||||||
|
@ -88,22 +89,34 @@ export function JoinOrLeaveGroupButton(props: {
|
||||||
}) {
|
}) {
|
||||||
const { group, small, className } = props
|
const { group, small, className } = props
|
||||||
const currentUser = useUser()
|
const currentUser = useUser()
|
||||||
const isFollowing = currentUser
|
const [isMember, setIsMember] = useState<boolean>(false)
|
||||||
? group.memberIds.includes(currentUser.id)
|
useEffect(() => {
|
||||||
: false
|
if (currentUser && group.memberIds.includes(currentUser.id)) {
|
||||||
|
setIsMember(group.memberIds.includes(currentUser.id))
|
||||||
|
}
|
||||||
|
}, [currentUser, group])
|
||||||
|
|
||||||
const onJoinGroup = () => {
|
const onJoinGroup = () => {
|
||||||
if (!currentUser) return
|
if (!currentUser) return
|
||||||
addUserToGroup(group, currentUser.id)
|
setIsMember(true)
|
||||||
|
joinGroup(group, currentUser.id).catch(() => {
|
||||||
|
setIsMember(false)
|
||||||
|
toast.error('Failed to join group')
|
||||||
|
})
|
||||||
}
|
}
|
||||||
const onLeaveGroup = () => {
|
const onLeaveGroup = () => {
|
||||||
if (!currentUser) return
|
if (!currentUser) return
|
||||||
leaveGroup(group, currentUser.id)
|
setIsMember(false)
|
||||||
|
leaveGroup(group, currentUser.id).catch(() => {
|
||||||
|
setIsMember(true)
|
||||||
|
toast.error('Failed to leave group')
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const smallStyle =
|
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'
|
'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'
|
||||||
|
|
||||||
if (!currentUser || isFollowing === undefined) {
|
if (!currentUser || isMember === undefined) {
|
||||||
if (!group.anyoneCanJoin)
|
if (!group.anyoneCanJoin)
|
||||||
return <div className={clsx(className, 'text-gray-500')}>Closed</div>
|
return <div className={clsx(className, 'text-gray-500')}>Closed</div>
|
||||||
return (
|
return (
|
||||||
|
@ -116,7 +129,7 @@ export function JoinOrLeaveGroupButton(props: {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isFollowing) {
|
if (isMember) {
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
className={clsx(
|
className={clsx(
|
||||||
|
|
|
@ -87,32 +87,23 @@ export async function addUserToGroupViaSlug(groupSlug: string, userId: string) {
|
||||||
console.error(`Group not found: ${groupSlug}`)
|
console.error(`Group not found: ${groupSlug}`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return await addUserToGroup(group, userId)
|
return await joinGroup(group, userId)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function addUserToGroup(
|
export async function joinGroup(group: Group, userId: string): Promise<void> {
|
||||||
group: Group,
|
|
||||||
userId: string
|
|
||||||
): Promise<Group> {
|
|
||||||
const { memberIds } = group
|
const { memberIds } = group
|
||||||
if (memberIds.includes(userId)) {
|
if (memberIds.includes(userId)) return // already a member
|
||||||
return group
|
|
||||||
}
|
|
||||||
const newMemberIds = [...memberIds, userId]
|
const newMemberIds = [...memberIds, userId]
|
||||||
const newGroup = { ...group, memberIds: newMemberIds }
|
return await updateGroup(group, { memberIds: uniq(newMemberIds) })
|
||||||
await updateGroup(newGroup, { memberIds: uniq(newMemberIds) })
|
|
||||||
return newGroup
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function leaveGroup(group: Group, userId: string): Promise<Group> {
|
export async function leaveGroup(group: Group, userId: string): Promise<void> {
|
||||||
const { memberIds } = group
|
const { memberIds } = group
|
||||||
if (!memberIds.includes(userId)) {
|
if (!memberIds.includes(userId)) return // not a member
|
||||||
return group
|
|
||||||
}
|
|
||||||
const newMemberIds = memberIds.filter((id) => id !== userId)
|
const newMemberIds = memberIds.filter((id) => id !== userId)
|
||||||
const newGroup = { ...group, memberIds: newMemberIds }
|
return await updateGroup(group, { memberIds: uniq(newMemberIds) })
|
||||||
await updateGroup(newGroup, { memberIds: uniq(newMemberIds) })
|
|
||||||
return newGroup
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function addContractToGroup(group: Group, contract: Contract) {
|
export async function addContractToGroup(group: Group, contract: Contract) {
|
||||||
|
|
|
@ -8,7 +8,7 @@ import {
|
||||||
groupPath,
|
groupPath,
|
||||||
getGroupBySlug,
|
getGroupBySlug,
|
||||||
updateGroup,
|
updateGroup,
|
||||||
addUserToGroup,
|
joinGroup,
|
||||||
addContractToGroup,
|
addContractToGroup,
|
||||||
} from 'web/lib/firebase/groups'
|
} from 'web/lib/firebase/groups'
|
||||||
import { Row } from 'web/components/layout/row'
|
import { Row } from 'web/components/layout/row'
|
||||||
|
@ -604,19 +604,19 @@ function JoinGroupButton(props: {
|
||||||
user: User | null | undefined
|
user: User | null | undefined
|
||||||
}) {
|
}) {
|
||||||
const { group, user } = props
|
const { group, user } = props
|
||||||
function joinGroup() {
|
function addUserToGroup() {
|
||||||
if (user && !group.memberIds.includes(user.id)) {
|
if (user && !group.memberIds.includes(user.id)) {
|
||||||
toast.promise(addUserToGroup(group, user.id), {
|
toast.promise(joinGroup(group, user.id), {
|
||||||
loading: 'Joining group...',
|
loading: 'Joining group...',
|
||||||
success: 'Joined group!',
|
success: 'Joined group!',
|
||||||
error: "Couldn't join group",
|
error: "Couldn't join group, try again?",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<button
|
<button
|
||||||
onClick={user ? joinGroup : firebaseLogin}
|
onClick={user ? addUserToGroup : firebaseLogin}
|
||||||
className={'btn-md btn-outline btn whitespace-nowrap normal-case'}
|
className={'btn-md btn-outline btn whitespace-nowrap normal-case'}
|
||||||
>
|
>
|
||||||
{user ? 'Join group' : 'Login to join group'}
|
{user ? 'Join group' : 'Login to join group'}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user