diff --git a/common/notification.ts b/common/notification.ts
index e90624a4..16444c48 100644
--- a/common/notification.ts
+++ b/common/notification.ts
@@ -22,6 +22,8 @@ export type Notification = {
sourceSlug?: string
sourceTitle?: string
+
+ isSeenOnHref?: string
}
export type notification_source_types =
| 'contract'
@@ -58,3 +60,4 @@ export type notification_reason_types =
| 'you_referred_user'
| 'user_joined_to_bet_on_your_market'
| 'unique_bettors_on_your_contract'
+ | 'on_group_you_are_member_of'
diff --git a/functions/src/create-notification.ts b/functions/src/create-notification.ts
index b63958f0..45db1c4e 100644
--- a/functions/src/create-notification.ts
+++ b/functions/src/create-notification.ts
@@ -17,7 +17,7 @@ import { removeUndefinedProps } from '../../common/util/object'
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 (
+ userToReasonTexts: user_to_reason_texts,
+ userId: string
+ ) => {
+ if (shouldGetNotification(userId, userToReasonTexts))
+ userToReasonTexts[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.
diff --git a/functions/src/index.ts b/functions/src/index.ts
index e4a30761..d9b7a255 100644
--- a/functions/src/index.ts
+++ b/functions/src/index.ts
@@ -10,7 +10,7 @@ export * from './stripe'
export * from './create-user'
export * from './create-answer'
export * from './on-create-bet'
-export * from './on-create-comment'
+export * from './on-create-comment-on-contract'
export * from './on-view'
export * from './unsubscribe'
export * from './update-metrics'
@@ -28,6 +28,7 @@ export * from './on-create-liquidity-provision'
export * from './on-update-group'
export * from './on-create-group'
export * from './on-update-user'
+export * from './on-create-comment-on-group'
// v2
export * from './health'
diff --git a/functions/src/on-create-comment.ts b/functions/src/on-create-comment-on-contract.ts
similarity index 98%
rename from functions/src/on-create-comment.ts
rename to functions/src/on-create-comment-on-contract.ts
index 8d52fd46..f7839b44 100644
--- a/functions/src/on-create-comment.ts
+++ b/functions/src/on-create-comment-on-contract.ts
@@ -11,7 +11,7 @@ import { createNotification } from './create-notification'
const firestore = admin.firestore()
-export const onCreateComment = functions
+export const onCreateCommentOnContract = functions
.runWith({ secrets: ['MAILGUN_KEY'] })
.firestore.document('contracts/{contractId}/comments/{commentId}')
.onCreate(async (change, context) => {
diff --git a/functions/src/on-create-comment-on-group.ts b/functions/src/on-create-comment-on-group.ts
new file mode 100644
index 00000000..7217e602
--- /dev/null
+++ b/functions/src/on-create-comment-on-group.ts
@@ -0,0 +1,52 @@
+import * as functions from 'firebase-functions'
+import { Comment } from '../../common/comment'
+import * as admin from 'firebase-admin'
+import { Group } from '../../common/group'
+import { User } from '../../common/user'
+import { createNotification } from './create-notification'
+const firestore = admin.firestore()
+
+export const onCreateCommentOnGroup = functions.firestore
+ .document('groups/{groupId}/comments/{commentId}')
+ .onCreate(async (change, context) => {
+ const { eventId } = context
+ const { groupId } = context.params as {
+ groupId: string
+ }
+
+ const comment = change.data() as Comment
+ const creatorSnapshot = await firestore
+ .collection('users')
+ .doc(comment.userId)
+ .get()
+ if (!creatorSnapshot.exists) throw new Error('Could not find user')
+
+ const groupSnapshot = await firestore
+ .collection('groups')
+ .doc(groupId)
+ .get()
+ if (!groupSnapshot.exists) throw new Error('Could not find group')
+
+ const group = groupSnapshot.data() as Group
+ await firestore.collection('groups').doc(groupId).update({
+ mostRecentActivityTime: comment.createdTime,
+ })
+
+ await Promise.all(
+ group.memberIds.map(async (memberId) => {
+ return await createNotification(
+ comment.id,
+ 'comment',
+ 'created',
+ creatorSnapshot.data() as User,
+ eventId,
+ comment.text,
+ undefined,
+ undefined,
+ memberId,
+ `/group/${group.slug}`,
+ `${group.name}`
+ )
+ })
+ )
+ })
diff --git a/functions/src/on-update-group.ts b/functions/src/on-update-group.ts
index bc6f6ab4..feaa6443 100644
--- a/functions/src/on-update-group.ts
+++ b/functions/src/on-update-group.ts
@@ -12,6 +12,7 @@ export const onUpdateGroup = functions.firestore
// ignore the update we just made
if (prevGroup.mostRecentActivityTime !== group.mostRecentActivityTime)
return
+ // TODO: create notification with isSeeOnHref set to the group's /group/questions url
await firestore
.collection('groups')
diff --git a/web/components/nav/sidebar.tsx b/web/components/nav/sidebar.tsx
index ba46bd80..b9449ea0 100644
--- a/web/components/nav/sidebar.tsx
+++ b/web/components/nav/sidebar.tsx
@@ -18,7 +18,7 @@ import { ManifoldLogo } from './manifold-logo'
import { MenuButton } from './menu'
import { ProfileSummary } from './profile-menu'
import NotificationsIcon from 'web/components/notifications-icon'
-import React from 'react'
+import React, { useEffect } from 'react'
import { IS_PRIVATE_MANIFOLD } from 'common/envs/constants'
import { CreateQuestionButton } from 'web/components/create-question-button'
import { useMemberGroups } from 'web/hooks/use-group'
@@ -26,6 +26,8 @@ import { groupPath } from 'web/lib/firebase/groups'
import { trackCallback, withTracking } from 'web/lib/service/analytics'
import { Group } from 'common/group'
import { Spacer } from '../layout/spacer'
+import { usePreferredNotifications } from 'web/hooks/use-notifications'
+import { setNotificationsAsSeen } from 'web/pages/notifications'
function getNavigation() {
return [
@@ -182,6 +184,7 @@ export default function Sidebar(props: { className?: string }) {
const { className } = props
const router = useRouter()
const currentPage = router.pathname
+
const user = useUser()
const navigationOptions = !user ? signedOutNavigation : getNavigation()
const mobileNavigationOptions = !user
@@ -217,7 +220,11 @@ export default function Sidebar(props: { className?: string }) {
/>
)}
-