diff --git a/common/group.ts b/common/group.ts
index e367ded7..15348d5a 100644
--- a/common/group.ts
+++ b/common/group.ts
@@ -11,11 +11,8 @@ export type Group = {
contractIds: string[]
chatDisabled?: boolean
- mostRecentChatActivityTime?: number
- mostRecentContractAddedTime?: number
}
export const MAX_GROUP_NAME_LENGTH = 75
export const MAX_ABOUT_LENGTH = 140
export const MAX_ID_LENGTH = 60
export const NEW_USER_GROUP_SLUGS = ['updates', 'bugs', 'welcome']
-export const GROUP_CHAT_SLUG = 'chat'
diff --git a/functions/src/create-notification.ts b/functions/src/create-notification.ts
index 4c42b00e..1fb6c3af 100644
--- a/functions/src/create-notification.ts
+++ b/functions/src/create-notification.ts
@@ -15,11 +15,11 @@ import { Answer } from '../../common/answer'
import { getContractBetMetrics } from '../../common/calculate'
import { removeUndefinedProps } from '../../common/util/object'
import { TipTxn } from '../../common/txn'
-import { Group, GROUP_CHAT_SLUG } from '../../common/group'
+import { Group } from '../../common/group'
const firestore = admin.firestore()
type user_to_reason_texts = {
- [userId: string]: { reason: notification_reason_types }
+ [userId: string]: { reason: notification_reason_types; isSeeOnHref?: string }
}
export const createNotification = async (
@@ -72,6 +72,7 @@ export const createNotification = async (
sourceContractSlug: sourceContract?.slug,
sourceSlug: sourceSlug ? sourceSlug : sourceContract?.slug,
sourceTitle: sourceTitle ? sourceTitle : sourceContract?.question,
+ isSeenOnHref: userToReasonTexts[userId].isSeeOnHref,
}
await notificationRef.set(removeUndefinedProps(notification))
})
@@ -276,6 +277,17 @@ export const createNotification = async (
}
}
+ const notifyOtherGroupMembersOfComment = async (
+ userToReasons: user_to_reason_texts,
+ userId: string
+ ) => {
+ if (shouldGetNotification(userId, userToReasons))
+ userToReasons[userId] = {
+ reason: 'on_group_you_are_member_of',
+ isSeeOnHref: sourceSlug,
+ }
+ }
+
const getUsersToNotify = async () => {
const userToReasonTexts: user_to_reason_texts = {}
// The following functions modify the userToReasonTexts object in place.
@@ -286,6 +298,8 @@ export const createNotification = async (
await notifyUserAddedToGroup(userToReasonTexts, relatedUserId)
} else if (sourceType === 'user' && relatedUserId) {
await notifyUserReceivedReferralBonus(userToReasonTexts, relatedUserId)
+ } else if (sourceType === 'comment' && !sourceContract && relatedUserId) {
+ await notifyOtherGroupMembersOfComment(userToReasonTexts, relatedUserId)
}
// The following functions need sourceContract to be defined.
@@ -403,34 +417,3 @@ export const createBetFillNotification = async (
}
return await notificationRef.set(removeUndefinedProps(notification))
}
-
-export const createGroupCommentNotification = async (
- fromUser: User,
- toUserId: string,
- comment: Comment,
- group: Group,
- idempotencyKey: string
-) => {
- const notificationRef = firestore
- .collection(`/users/${toUserId}/notifications`)
- .doc(idempotencyKey)
- const sourceSlug = `/group/${group.slug}/${GROUP_CHAT_SLUG}`
- const notification: Notification = {
- id: idempotencyKey,
- userId: toUserId,
- reason: 'on_group_you_are_member_of',
- createdTime: Date.now(),
- isSeen: false,
- sourceId: comment.id,
- sourceType: 'comment',
- sourceUpdateType: 'created',
- sourceUserName: fromUser.name,
- sourceUserUsername: fromUser.username,
- sourceUserAvatarUrl: fromUser.avatarUrl,
- sourceText: comment.text,
- sourceSlug,
- sourceTitle: `${group.name}`,
- isSeenOnHref: sourceSlug,
- }
- await notificationRef.set(removeUndefinedProps(notification))
-}
diff --git a/functions/src/on-create-comment-on-group.ts b/functions/src/on-create-comment-on-group.ts
index 0064480f..7217e602 100644
--- a/functions/src/on-create-comment-on-group.ts
+++ b/functions/src/on-create-comment-on-group.ts
@@ -3,7 +3,7 @@ import { Comment } from '../../common/comment'
import * as admin from 'firebase-admin'
import { Group } from '../../common/group'
import { User } from '../../common/user'
-import { createGroupCommentNotification } from './create-notification'
+import { createNotification } from './create-notification'
const firestore = admin.firestore()
export const onCreateCommentOnGroup = functions.firestore
@@ -29,17 +29,23 @@ export const onCreateCommentOnGroup = functions.firestore
const group = groupSnapshot.data() as Group
await firestore.collection('groups').doc(groupId).update({
- mostRecentChatActivityTime: comment.createdTime,
+ mostRecentActivityTime: comment.createdTime,
})
await Promise.all(
group.memberIds.map(async (memberId) => {
- return await createGroupCommentNotification(
+ return await createNotification(
+ comment.id,
+ 'comment',
+ 'created',
creatorSnapshot.data() as User,
+ eventId,
+ comment.text,
+ undefined,
+ undefined,
memberId,
- comment,
- group,
- eventId
+ `/group/${group.slug}`,
+ `${group.name}`
)
})
)
diff --git a/functions/src/on-update-group.ts b/functions/src/on-update-group.ts
index 3ab2a249..feaa6443 100644
--- a/functions/src/on-update-group.ts
+++ b/functions/src/on-update-group.ts
@@ -12,15 +12,7 @@ export const onUpdateGroup = functions.firestore
// ignore the update we just made
if (prevGroup.mostRecentActivityTime !== group.mostRecentActivityTime)
return
-
- if (prevGroup.contractIds.length < group.contractIds.length) {
- await firestore
- .collection('groups')
- .doc(group.id)
- .update({ mostRecentContractAddedTime: Date.now() })
- //TODO: create notification with isSeeOnHref set to the group's /group/slug/questions url
- // but first, let the new /group/slug/chat notification permeate so that we can differentiate between the two
- }
+ // TODO: create notification with isSeeOnHref set to the group's /group/questions url
await firestore
.collection('groups')
diff --git a/web/components/groups/groups-button.tsx b/web/components/groups/groups-button.tsx
index b510f44d..f3ae77a2 100644
--- a/web/components/groups/groups-button.tsx
+++ b/web/components/groups/groups-button.tsx
@@ -17,9 +17,7 @@ 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, undefined, {
- by: 'mostRecentChatActivityTime',
- })
+ const groups = useMemberGroups(user.id)
return (
<>
diff --git a/web/components/nav/sidebar.tsx b/web/components/nav/sidebar.tsx
index 8553b506..f4abc6c7 100644
--- a/web/components/nav/sidebar.tsx
+++ b/web/components/nav/sidebar.tsx
@@ -24,7 +24,7 @@ import { CreateQuestionButton } from 'web/components/create-question-button'
import { useMemberGroups } from 'web/hooks/use-group'
import { groupPath } from 'web/lib/firebase/groups'
import { trackCallback, withTracking } from 'web/lib/service/analytics'
-import { Group, GROUP_CHAT_SLUG } from 'common/group'
+import { Group } from 'common/group'
import { Spacer } from '../layout/spacer'
import { useUnseenPreferredNotifications } from 'web/hooks/use-notifications'
import { setNotificationsAsSeen } from 'web/pages/notifications'
@@ -194,14 +194,10 @@ export default function Sidebar(props: { className?: string }) {
? signedOutMobileNavigation
: signedInMobileNavigation
const memberItems = (
- useMemberGroups(
- user?.id,
- { withChatEnabled: true },
- { by: 'mostRecentChatActivityTime' }
- ) ?? []
+ useMemberGroups(user?.id, { withChatEnabled: true }) ?? []
).map((group: Group) => ({
name: group.name,
- href: `${groupPath(group.slug)}/${GROUP_CHAT_SLUG}`,
+ href: groupPath(group.slug),
}))
return (
@@ -282,16 +278,8 @@ function GroupsList(props: {
// Set notification as seen if our current page is equal to the isSeenOnHref property
useEffect(() => {
- const currentPageGroupSlug = currentPage.split('/')[2]
preferredNotifications.forEach((notification) => {
- if (
- notification.isSeenOnHref === currentPage ||
- // Old chat style group chat notif ended just with the group slug
- notification.isSeenOnHref?.endsWith(currentPageGroupSlug) ||
- // They're on the home page, so if they've a chat notif, they're seeing the chat
- (notification.isSeenOnHref?.endsWith(GROUP_CHAT_SLUG) &&
- currentPage.endsWith(currentPageGroupSlug))
- ) {
+ if (notification.isSeenOnHref === currentPage) {
setNotificationsAsSeen([notification])
}
})
diff --git a/web/components/user-page.tsx b/web/components/user-page.tsx
index 85d70e86..be3f3ac4 100644
--- a/web/components/user-page.tsx
+++ b/web/components/user-page.tsx
@@ -38,7 +38,6 @@ import { GroupsButton } from 'web/components/groups/groups-button'
import { PortfolioValueSection } from './portfolio/portfolio-value-section'
import { filterDefined } from 'common/util/array'
import { useUserBets } from 'web/hooks/use-user-bets'
-import { ReferralsButton } from 'web/components/referrals-button'
export function UserLink(props: {
name: string
@@ -203,9 +202,7 @@ export function UserPage(props: {
- {currentUser?.username === 'Ian' && (
-
- )}
+ {/* */}
diff --git a/web/hooks/use-group.ts b/web/hooks/use-group.ts
index 4f968005..c3098ba4 100644
--- a/web/hooks/use-group.ts
+++ b/web/hooks/use-group.ts
@@ -32,26 +32,19 @@ export const useGroups = () => {
export const useMemberGroups = (
userId: string | null | undefined,
- options?: { withChatEnabled: boolean },
- sort?: { by: 'mostRecentChatActivityTime' | 'mostRecentContractAddedTime' }
+ options?: { withChatEnabled: boolean }
) => {
const [memberGroups, setMemberGroups] = useState()
useEffect(() => {
if (userId)
- return listenForMemberGroups(
- userId,
- (groups) => {
- if (options?.withChatEnabled)
- return setMemberGroups(
- filterDefined(
- groups.filter((group) => group.chatDisabled !== true)
- )
- )
- return setMemberGroups(groups)
- },
- sort
- )
- }, [options?.withChatEnabled, sort, userId])
+ return listenForMemberGroups(userId, (groups) => {
+ if (options?.withChatEnabled)
+ return setMemberGroups(
+ filterDefined(groups.filter((group) => group.chatDisabled !== true))
+ )
+ return setMemberGroups(groups)
+ })
+ }, [options?.withChatEnabled, userId])
return memberGroups
}
@@ -95,7 +88,7 @@ export async function listMembers(group: Group, max?: number) {
const { memberIds } = group
const numToRetrieve = max ?? memberIds.length
if (memberIds.length === 0) return []
- if (numToRetrieve > 100)
+ if (numToRetrieve)
return (await getUsers()).filter((user) =>
group.memberIds.includes(user.id)
)
diff --git a/web/lib/firebase/groups.ts b/web/lib/firebase/groups.ts
index e49b012a..6d695b7f 100644
--- a/web/lib/firebase/groups.ts
+++ b/web/lib/firebase/groups.ts
@@ -7,7 +7,7 @@ import {
where,
} from 'firebase/firestore'
import { sortBy, uniq } from 'lodash'
-import { Group, GROUP_CHAT_SLUG } from 'common/group'
+import { Group } from 'common/group'
import { updateContract } from './contracts'
import {
coll,
@@ -22,7 +22,7 @@ export const groups = coll('groups')
export function groupPath(
groupSlug: string,
- subpath?: 'edit' | 'questions' | 'about' | typeof GROUP_CHAT_SLUG | 'rankings'
+ subpath?: 'edit' | 'questions' | 'about' | 'chat' | 'rankings'
) {
return `/group/${groupSlug}${subpath ? `/${subpath}` : ''}`
}
@@ -62,21 +62,12 @@ export function listenForGroup(
export function listenForMemberGroups(
userId: string,
- setGroups: (groups: Group[]) => void,
- sort?: { by: 'mostRecentChatActivityTime' | 'mostRecentContractAddedTime' }
+ setGroups: (groups: Group[]) => void
) {
const q = query(groups, where('memberIds', 'array-contains', userId))
- const sorter = (group: Group) => {
- if (sort?.by === 'mostRecentChatActivityTime') {
- return group.mostRecentChatActivityTime ?? group.mostRecentActivityTime
- }
- if (sort?.by === 'mostRecentContractAddedTime') {
- return group.mostRecentContractAddedTime ?? group.mostRecentActivityTime
- }
- return group.mostRecentActivityTime
- }
+
return listenForValues(q, (groups) => {
- const sorted = sortBy(groups, [(group) => -sorter(group)])
+ const sorted = sortBy(groups, [(group) => -group.mostRecentActivityTime])
setGroups(sorted)
})
}
diff --git a/web/pages/group/[...slugs]/index.tsx b/web/pages/group/[...slugs]/index.tsx
index 3fa64964..a364de43 100644
--- a/web/pages/group/[...slugs]/index.tsx
+++ b/web/pages/group/[...slugs]/index.tsx
@@ -1,6 +1,6 @@
import { take, sortBy, debounce } from 'lodash'
-import { Group, GROUP_CHAT_SLUG } from 'common/group'
+import { Group } from 'common/group'
import { Page } from 'web/components/page'
import { listAllBets } from 'web/lib/firebase/bets'
import { Contract, listContractsByGroupSlug } from 'web/lib/firebase/contracts'
@@ -21,7 +21,7 @@ import {
} from 'web/lib/firebase/users'
import { Col } from 'web/components/layout/col'
import { useUser } from 'web/hooks/use-user'
-import { listMembers, useGroup, useMembers } from 'web/hooks/use-group'
+import { listMembers, useGroup } from 'web/hooks/use-group'
import { useRouter } from 'next/router'
import { scoreCreators, scoreTraders } from 'common/scoring'
import { Leaderboard } from 'web/components/leaderboard'
@@ -114,7 +114,7 @@ export async function getStaticPaths() {
}
const groupSubpages = [
undefined,
- GROUP_CHAT_SLUG,
+ 'chat',
'questions',
'rankings',
'about',
@@ -218,7 +218,7 @@ export default function GroupPage(props: {
) : (
),
- href: groupPath(group.slug, GROUP_CHAT_SLUG),
+ href: groupPath(group.slug, 'chat'),
},
]),
{
@@ -246,7 +246,7 @@ export default function GroupPage(props: {
href: groupPath(group.slug, 'about'),
},
]
- const tabIndex = tabs.map((t) => t.title).indexOf(page ?? GROUP_CHAT_SLUG)
+ const tabIndex = tabs.map((t) => t.title).indexOf(page ?? 'chat')
return (
)}
-
+
>
@@ -426,16 +426,9 @@ function SearchBar(props: { setQuery: (query: string) => void }) {
)
}
-function GroupMemberSearch(props: { members: User[]; group: Group }) {
+function GroupMemberSearch(props: { members: User[] }) {
const [query, setQuery] = useState('')
- const { group } = props
- let { members } = props
-
- // Use static members on load, but also listen to member changes:
- const listenToMembers = useMembers(group)
- if (listenToMembers) {
- members = listenToMembers
- }
+ const { members } = props
// TODO use find-active-contracts to sort by?
const matches = sortBy(members, [(member) => member.name]).filter(
diff --git a/web/pages/groups.tsx b/web/pages/groups.tsx
index 87ac1501..2523b789 100644
--- a/web/pages/groups.tsx
+++ b/web/pages/groups.tsx
@@ -79,11 +79,7 @@ export default function Groups(props: {
)
const matchesOrderedByRecentActivity = sortBy(groups, [
- (group) =>
- -1 *
- (group.mostRecentChatActivityTime ??
- group.mostRecentContractAddedTime ??
- group.mostRecentActivityTime),
+ (group) => -1 * group.mostRecentActivityTime,
]).filter(
(g) =>
checkAgainstQuery(query, g.name) ||