diff --git a/web/components/groups/group-selector.tsx b/web/components/groups/group-selector.tsx
index 6bc943dc..ea1597f2 100644
--- a/web/components/groups/group-selector.tsx
+++ b/web/components/groups/group-selector.tsx
@@ -22,7 +22,7 @@ export function GroupSelector(props: {
const [isCreatingNewGroup, setIsCreatingNewGroup] = useState(false)
const [query, setQuery] = useState('')
- const memberGroups = useMemberGroups(creator)
+ const memberGroups = useMemberGroups(creator?.id)
const filteredGroups = memberGroups
? query === ''
? memberGroups
diff --git a/web/components/groups/groups-button.tsx b/web/components/groups/groups-button.tsx
new file mode 100644
index 00000000..e6ee217d
--- /dev/null
+++ b/web/components/groups/groups-button.tsx
@@ -0,0 +1,144 @@
+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 } 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'
+import { joinGroup, leaveGroup } from 'web/lib/firebase/groups'
+import { firebaseLogin } from 'web/lib/firebase/users'
+import { GroupLink } from 'web/pages/groups'
+
+export function GroupsButton(props: { user: User }) {
+ const { user } = props
+ const [isOpen, setIsOpen] = useState(false)
+ const groups = useMemberGroups(user.id)
+
+ return (
+ <>
+ setIsOpen(true)}>
+ {groups?.length ?? ''} Groups
+
+
+
+ >
+ )
+}
+
+function GroupsDialog(props: {
+ user: User
+ groups: Group[]
+ isOpen: boolean
+ setIsOpen: (isOpen: boolean) => void
+}) {
+ const { user, groups, isOpen, setIsOpen } = props
+
+ return (
+
+
+ {user.name}
+ @{user.username}
+
+
+
+ )
+}
+
+function GroupsList(props: { groups: Group[] }) {
+ const { groups } = props
+ return (
+
+ {groups.length === 0 && (
+ No groups yet...
+ )}
+ {groups
+ .sort((group1, group2) => group2.createdTime - group1.createdTime)
+ .map((group) => (
+
+ ))}
+
+ )
+}
+
+function GroupItem(props: { group: Group; className?: string }) {
+ const { group, className } = props
+ return (
+
+
+
+
+
+
+ )
+}
+
+export function JoinOrLeaveGroupButton(props: {
+ group: Group
+ small?: boolean
+ className?: string
+}) {
+ const { group, small, className } = props
+ const currentUser = useUser()
+ const isFollowing = currentUser
+ ? group.memberIds.includes(currentUser.id)
+ : false
+ const onJoinGroup = () => {
+ if (!currentUser) return
+ joinGroup(group, currentUser.id)
+ }
+ const onLeaveGroup = () => {
+ if (!currentUser) return
+ leaveGroup(group, currentUser.id)
+ }
+
+ 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'
+
+ if (!currentUser || isFollowing === undefined) {
+ if (!group.anyoneCanJoin)
+ return Closed
+ return (
+
+ )
+ }
+
+ if (isFollowing) {
+ return (
+
+ )
+ }
+
+ if (!group.anyoneCanJoin)
+ return Closed
+ return (
+
+ )
+}
diff --git a/web/components/nav/sidebar.tsx b/web/components/nav/sidebar.tsx
index e5f3cd5c..0b3d9393 100644
--- a/web/components/nav/sidebar.tsx
+++ b/web/components/nav/sidebar.tsx
@@ -185,7 +185,7 @@ export default function Sidebar(props: { className?: string }) {
const mobileNavigationOptions = !user
? signedOutMobileNavigation
: signedInMobileNavigation
- const memberItems = (useMemberGroups(user) ?? []).map((group: Group) => ({
+ const memberItems = (useMemberGroups(user?.id) ?? []).map((group: Group) => ({
name: group.name,
href: groupPath(group.slug),
}))
diff --git a/web/components/user-page.tsx b/web/components/user-page.tsx
index 2019a9de..246ed2aa 100644
--- a/web/components/user-page.tsx
+++ b/web/components/user-page.tsx
@@ -36,6 +36,7 @@ import { FollowersButton, FollowingButton } from './following-button'
import { useFollows } from 'web/hooks/use-follows'
import { FollowButton } from './follow-button'
import { PortfolioMetrics } from 'common/user'
+import { GroupsButton } from 'web/components/groups/groups-button'
export function UserLink(props: {
name: string
@@ -197,6 +198,7 @@ export function UserPage(props: {
+
{user.website && (
diff --git a/web/hooks/use-group.ts b/web/hooks/use-group.ts
index f73fd04e..41f84707 100644
--- a/web/hooks/use-group.ts
+++ b/web/hooks/use-group.ts
@@ -29,11 +29,11 @@ export const useGroups = () => {
return groups
}
-export const useMemberGroups = (user: User | null | undefined) => {
+export const useMemberGroups = (userId: string | null | undefined) => {
const [memberGroups, setMemberGroups] = useState()
useEffect(() => {
- if (user) return listenForMemberGroups(user.id, setMemberGroups)
- }, [user])
+ if (userId) return listenForMemberGroups(userId, setMemberGroups)
+ }, [userId])
return memberGroups
}
diff --git a/web/lib/firebase/groups.ts b/web/lib/firebase/groups.ts
index 1438dd4c..d7244f98 100644
--- a/web/lib/firebase/groups.ts
+++ b/web/lib/firebase/groups.ts
@@ -94,3 +94,24 @@ export async function getGroupsWithContractId(
const groups = await getValues(q)
setGroups(groups)
}
+
+export async function joinGroup(group: Group, userId: string): Promise {
+ const { memberIds } = group
+ if (memberIds.includes(userId)) {
+ return group
+ }
+ const newMemberIds = [...memberIds, userId]
+ const newGroup = { ...group, memberIds: newMemberIds }
+ await updateGroup(newGroup, { memberIds: newMemberIds })
+ return newGroup
+}
+export async function leaveGroup(group: Group, userId: string): Promise {
+ const { memberIds } = group
+ if (!memberIds.includes(userId)) {
+ return group
+ }
+ const newMemberIds = memberIds.filter((id) => id !== userId)
+ const newGroup = { ...group, memberIds: newMemberIds }
+ await updateGroup(newGroup, { memberIds: newMemberIds })
+ return newGroup
+}
diff --git a/web/pages/groups.tsx b/web/pages/groups.tsx
index c8f08b25..a8f99b23 100644
--- a/web/pages/groups.tsx
+++ b/web/pages/groups.tsx
@@ -15,6 +15,8 @@ import { getUser, User } from 'web/lib/firebase/users'
import { Tabs } from 'web/components/layout/tabs'
import { GroupMembersList } from 'web/pages/group/[...slugs]'
import { checkAgainstQuery } from 'web/hooks/use-sort-and-query-params'
+import { SiteLink } from 'web/components/site-link'
+import clsx from 'clsx'
export async function getStaticProps() {
const groups = await listAllGroups().catch((_) => [])
@@ -202,3 +204,16 @@ export function GroupCard(props: { group: Group; creator: User | undefined }) {
)
}
+
+export function GroupLink(props: { group: Group; className?: string }) {
+ const { group, className } = props
+
+ return (
+
+ {group.name}
+
+ )
+}