-
Notifications
You must be signed in to change notification settings - Fork 324
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add notifications for mention in reflections and show kudos pre…
…view (#9354) * feat: add notifications for mention in reflections and show kudos preview * Fix types * chore(kudos): track kudos type and meeting type in kudosSent event (#9373) * senderName senderPicture * Fix tests * Add TODO comment to use single Mentioned notification everywhere
- Loading branch information
1 parent
d991532
commit a7f9b5d
Showing
16 changed files
with
402 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
import graphql from 'babel-plugin-relay/macro' | ||
import React, {useEffect} from 'react' | ||
import {useFragment} from 'react-relay' | ||
import NotificationAction from '~/components/NotificationAction' | ||
import useRouter from '../hooks/useRouter' | ||
import {Mentioned_notification$key} from '../__generated__/Mentioned_notification.graphql' | ||
import NotificationTemplate from './NotificationTemplate' | ||
import SendClientSideEvent from '../utils/SendClientSideEvent' | ||
import useAtmosphere from '~/hooks/useAtmosphere' | ||
import anonymousAvatar from '~/styles/theme/images/anonymous-avatar.svg' | ||
import useEditorState from '../hooks/useEditorState' | ||
import {Editor} from 'draft-js' | ||
|
||
interface Props { | ||
notification: Mentioned_notification$key | ||
} | ||
|
||
const Mentioned = (props: Props) => { | ||
const {notification: notificationRef} = props | ||
const notification = useFragment( | ||
graphql` | ||
fragment Mentioned_notification on NotifyMentioned { | ||
...NotificationTemplate_notification | ||
type | ||
status | ||
senderName | ||
senderPicture | ||
kudosEmojiUnicode | ||
createdAt | ||
meetingId | ||
meetingName | ||
retroReflection { | ||
content | ||
} | ||
retroDiscussStageIdx | ||
} | ||
`, | ||
notificationRef | ||
) | ||
const {history} = useRouter() | ||
const atmosphere = useAtmosphere() | ||
|
||
const { | ||
senderName, | ||
senderPicture, | ||
meetingId, | ||
meetingName, | ||
kudosEmojiUnicode, | ||
type, | ||
status, | ||
retroReflection, | ||
retroDiscussStageIdx | ||
} = notification | ||
const isAnonymous = !senderName | ||
const authorName = isAnonymous ? 'Someone' : senderName | ||
|
||
useEffect(() => { | ||
SendClientSideEvent(atmosphere, 'Notification Viewed', { | ||
notificationType: type, | ||
notificationStatus: status, | ||
kudosEmojiUnicode | ||
}) | ||
}, []) | ||
|
||
let locationType = 'their response' | ||
let actionLabel = 'See their response' | ||
let actionUrl = `/meet/${meetingId}` | ||
let previewContent = null | ||
|
||
if (retroReflection) { | ||
actionLabel = 'See their reflection' | ||
locationType = 'their reflection' | ||
previewContent = retroReflection.content | ||
if (retroDiscussStageIdx) { | ||
actionUrl = `/meet/${meetingId}/discuss/${retroDiscussStageIdx}` | ||
} | ||
} | ||
|
||
const message = !kudosEmojiUnicode | ||
? `${authorName} mentioned you in ${locationType} in ${meetingName}` | ||
: `${kudosEmojiUnicode} ${authorName} gave you kudos in ${locationType} in ${meetingName}` | ||
|
||
const goThere = () => { | ||
history.push(actionUrl) | ||
} | ||
|
||
const [editorState] = useEditorState(previewContent) | ||
|
||
return ( | ||
<NotificationTemplate | ||
avatar={!isAnonymous ? senderPicture : anonymousAvatar} | ||
message={message} | ||
notification={notification} | ||
action={<NotificationAction label={actionLabel} onClick={goThere} />} | ||
> | ||
{previewContent && ( | ||
<div className='my-1 mx-0 mt-4 rounded bg-white p-2 text-sm leading-5 shadow-card'> | ||
<Editor | ||
readOnly | ||
editorState={editorState} | ||
onChange={() => { | ||
/*noop*/ | ||
}} | ||
/> | ||
</div> | ||
)} | ||
</NotificationTemplate> | ||
) | ||
} | ||
|
||
export default Mentioned |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
import graphql from 'babel-plugin-relay/macro' | ||
import {Snack} from '../../components/Snackbar' | ||
import {OnNextHistoryContext} from '../../types/relayMutations' | ||
import {mapMentionedToToast_notification$data} from '../../__generated__/mapMentionedToToast_notification.graphql' | ||
import SendClientSideEvent from '../../utils/SendClientSideEvent' | ||
import makeNotificationToastKey from './makeNotificationToastKey' | ||
|
||
graphql` | ||
fragment mapMentionedToToast_notification on NotifyMentioned { | ||
id | ||
kudosEmojiUnicode | ||
senderName | ||
meetingId | ||
meetingName | ||
retroReflection { | ||
content | ||
} | ||
retroDiscussStageIdx | ||
} | ||
` | ||
|
||
const mapMentionedToToast = ( | ||
notification: mapMentionedToToast_notification$data, | ||
{atmosphere, history}: OnNextHistoryContext | ||
): Snack | null => { | ||
if (!notification) return null | ||
const { | ||
id: notificationId, | ||
senderName, | ||
meetingName, | ||
kudosEmojiUnicode, | ||
retroReflection, | ||
retroDiscussStageIdx, | ||
meetingId | ||
} = notification | ||
const isAnonymous = !senderName | ||
const authorName = isAnonymous ? 'Someone' : senderName | ||
|
||
let locationType = 'their response' | ||
let actionLabel = 'See their response' | ||
let snackbarType = 'responseMentioned' | ||
let actionUrl = `/meet/${meetingId}` | ||
|
||
if (retroReflection) { | ||
actionLabel = 'See their reflection' | ||
locationType = 'their reflection' | ||
snackbarType = 'reflectionMentioned' | ||
if (retroDiscussStageIdx) { | ||
actionUrl = `/meet/${meetingId}/discuss/${retroDiscussStageIdx}` | ||
} | ||
} | ||
|
||
const message = !kudosEmojiUnicode | ||
? `${authorName} mentioned you in ${locationType} in ${meetingName}` | ||
: `${kudosEmojiUnicode} ${authorName} gave you kudos in ${locationType} in ${meetingName}` | ||
|
||
const goThere = () => { | ||
history.push(actionUrl) | ||
} | ||
|
||
return { | ||
key: makeNotificationToastKey(notificationId), | ||
autoDismiss: 5, | ||
message, | ||
action: { | ||
label: actionLabel, | ||
callback: goThere | ||
}, | ||
onShow: () => { | ||
SendClientSideEvent(atmosphere, 'Snackbar Viewed', { | ||
snackbarType, | ||
kudosEmojiUnicode | ||
}) | ||
}, | ||
onManualDismiss: () => { | ||
SendClientSideEvent(atmosphere, 'Snackbar Clicked', { | ||
snackbarType, | ||
kudosEmojiUnicode | ||
}) | ||
} | ||
} | ||
} | ||
|
||
export default mapMentionedToToast |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import Notification from './Notification' | ||
|
||
interface Input { | ||
userId: string | ||
senderName: string | null | ||
senderPicture: string | null | ||
senderUserId: string | ||
meetingName: string | ||
meetingId: string | ||
retroReflectionId?: string | null | ||
retroDiscussStageIdx?: number | null | ||
kudosEmoji?: string | null | ||
kudosEmojiUnicode?: string | null | ||
} | ||
|
||
// TODO: replace NotificationResponseMentioned and NotificationResponseReplied with NotificationMentioned | ||
export default class NotificationMentioned extends Notification { | ||
readonly type = 'MENTIONED' | ||
senderName: string | null | ||
senderPicture: string | null | ||
senderUserId: string | ||
meetingName: string | ||
meetingId: string | ||
retroReflectionId?: string | null | ||
retroDiscussStageIdx?: number | null | ||
kudosEmoji?: string | null | ||
kudosEmojiUnicode?: string | null | ||
|
||
constructor(input: Input) { | ||
const { | ||
userId, | ||
senderName, | ||
senderPicture, | ||
senderUserId, | ||
meetingName, | ||
meetingId, | ||
retroReflectionId, | ||
retroDiscussStageIdx, | ||
kudosEmoji, | ||
kudosEmojiUnicode | ||
} = input | ||
super({userId, type: 'MENTIONED'}) | ||
this.senderName = senderName | ||
this.senderPicture = senderPicture | ||
this.senderUserId = senderUserId | ||
this.meetingName = meetingName | ||
this.meetingId = meetingId | ||
this.retroReflectionId = retroReflectionId | ||
this.kudosEmoji = kudosEmoji | ||
this.kudosEmojiUnicode = kudosEmojiUnicode | ||
this.retroDiscussStageIdx = retroDiscussStageIdx | ||
} | ||
} |
Oops, something went wrong.