Skip to content

Commit

Permalink
Display notification when someone tips one of your messages (#4530)
Browse files Browse the repository at this point in the history
  • Loading branch information
hpeebles authored Oct 9, 2023
1 parent 782206b commit 7855091
Show file tree
Hide file tree
Showing 4 changed files with 206 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ import {
ChannelReactionAddedNotification,
DirectReactionAddedNotification,
GroupReactionAddedNotification,
ChannelMessageTippedNotification,
DirectMessageTippedNotification,
GroupMessageTippedNotification,
NotificationCryptoTransferDetails,
SubscriptionExistsResponse,
} from "./types";
Expand All @@ -22,6 +25,9 @@ export {
ChannelReactionAddedNotification as ApiChannelReactionAddedNotification,
DirectReactionAddedNotification as ApiDirectReactionAddedNotification,
GroupReactionAddedNotification as ApiGroupReactionAddedNotification,
ChannelMessageTippedNotification as ApiChannelMessageTippedNotification,
DirectMessageTippedNotification as ApiDirectMessageTippedNotification,
GroupMessageTippedNotification as ApiGroupMessageTippedNotification,
NotificationCryptoTransferDetails as ApiNotificationCryptoTransferDetails,
SubscriptionExistsResponse as ApiSubscriptionExistsResponse,
};
Expand Down
106 changes: 98 additions & 8 deletions frontend/openchat-agent/src/services/notifications/mappers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ import type {
ChannelReaction,
GroupReaction,
DirectReaction,
ChannelMessageTipped,
GroupMessageTipped,
DirectMessageTipped,
CryptoTransferDetails,
} from "openchat-shared";
import { UnsupportedValueError } from "openchat-shared";
Expand All @@ -27,6 +30,9 @@ import type {
ApiChannelReactionAddedNotification,
ApiGroupReactionAddedNotification,
ApiDirectReactionAddedNotification,
ApiChannelMessageTippedNotification,
ApiGroupMessageTippedNotification,
ApiDirectMessageTippedNotification,
ApiNotificationCryptoTransferDetails,
} from "./candid/idl";
import type { ApiToggleMuteChannelNotificationsResponse } from "../community/candid/idl";
Expand All @@ -35,7 +41,7 @@ export function muteNotificationsResponse(
candid:
| ApiMuteNotificationsResponse
| ApiUnmuteNotificationsResponse
| ApiToggleMuteChannelNotificationsResponse
| ApiToggleMuteChannelNotificationsResponse,
): ToggleMuteNotificationResponse {
if ("Success" in candid) {
return "success";
Expand All @@ -46,7 +52,7 @@ export function muteNotificationsResponse(
}

export function subscriptionExistsResponse(
candid: ApiSubscriptionExistsResponse
candid: ApiSubscriptionExistsResponse,
): SubscriptionExistsResponse {
if ("Yes" in candid) {
return true;
Expand All @@ -56,7 +62,7 @@ export function subscriptionExistsResponse(
}
throw new UnsupportedValueError(
`Unexpected ApiSubscriptionExistsResponse type received`,
candid
candid,
);
}

Expand All @@ -82,16 +88,29 @@ export function notification(candid: ApiNotification, timestamp: bigint): Notifi
if ("DirectReactionAdded" in candid) {
return directReactionNotification(candid.DirectReactionAdded, timestamp);
}
if ("ChannelMessageTipped" in candid) {
return channelMessageTipped(candid.ChannelMessageTipped, timestamp);
}
if ("GroupMessageTipped" in candid) {
return groupMessageTipped(candid.GroupMessageTipped, timestamp);
}
if ("DirectMessageTipped" in candid) {
return directMessageTipped(candid.DirectMessageTipped, timestamp);
}
throw new Error(`Unexpected ApiNotification type received, ${candid}`);
}

export function addedToChannelNotification(
candid: ApiAddedToChannelNotification,
timestamp : bigint,
timestamp: bigint,
): AddedToChannelNotification {
return {
kind: "added_to_channel_notification",
chatId: { kind: "channel", communityId: candid.community_id.toString(), channelId: candid.channel_id.toString() },
chatId: {
kind: "channel",
communityId: candid.community_id.toString(),
channelId: candid.channel_id.toString(),
},
communityName: candid.community_name,
channelName: candid.channel_name,
addedBy: candid.added_by.toString(),
Expand All @@ -105,7 +124,7 @@ export function addedToChannelNotification(

export function channelNotification(
candid: ApiChannelMessageNotification,
timestamp : bigint,
timestamp: bigint,
): ChannelNotification {
return {
kind: "channel_notification",
Expand All @@ -115,7 +134,11 @@ export function channelNotification(
eventIndex: candid.event_index,
senderName: candid.sender_name,
senderDisplayName: optional(candid.sender_display_name, identity),
chatId: { kind: "channel", communityId: candid.community_id.toString(), channelId: candid.channel_id.toString() },
chatId: {
kind: "channel",
communityId: candid.community_id.toString(),
channelId: candid.channel_id.toString(),
},
communityName: candid.community_name,
channelName: candid.channel_name,
messageType: candid.message_type,
Expand Down Expand Up @@ -177,7 +200,11 @@ function channelReactionNotification(
): ChannelReaction {
return {
kind: "channel_reaction",
chatId: { kind: "channel", communityId: candid.community_id.toString(), channelId: candid.channel_id.toString() },
chatId: {
kind: "channel",
communityId: candid.community_id.toString(),
channelId: candid.channel_id.toString(),
},
communityName: candid.community_name,
channelName: candid.channel_name,
threadRootMessageIndex: optional(candid.thread_root_message_index, identity),
Expand Down Expand Up @@ -230,6 +257,69 @@ function directReactionNotification(
};
}

function channelMessageTipped(
candid: ApiChannelMessageTippedNotification,
timestamp: bigint,
): ChannelMessageTipped {
return {
kind: "channel_message_tipped",
chatId: {
kind: "channel",
communityId: candid.community_id.toString(),
channelId: candid.channel_id.toString(),
},
communityName: candid.community_name,
channelName: candid.channel_name,
threadRootMessageIndex: optional(candid.thread_root_message_index, identity),
messageIndex: candid.message_index,
messageEventIndex: candid.message_event_index,
tippedBy: candid.tipped_by.toString(),
tippedByName: candid.tipped_by_name,
tippedByDisplayName: optional(candid.tipped_by_display_name, identity),
tip: candid.tip,
communityAvatarId: optional(candid.community_avatar_id, identity),
channelAvatarId: optional(candid.channel_avatar_id, identity),
timestamp,
};
}

function groupMessageTipped(
candid: ApiGroupMessageTippedNotification,
timestamp: bigint,
): GroupMessageTipped {
return {
kind: "group_message_tipped",
chatId: { kind: "group_chat", groupId: candid.chat_id.toString() },
threadRootMessageIndex: optional(candid.thread_root_message_index, identity),
messageIndex: candid.message_index,
messageEventIndex: candid.message_event_index,
groupName: candid.group_name,
tippedBy: candid.tipped_by.toString(),
tippedByName: candid.tipped_by_name,
tippedByDisplayName: optional(candid.tipped_by_display_name, identity),
tip: candid.tip,
groupAvatarId: optional(candid.group_avatar_id, identity),
timestamp,
};
}

function directMessageTipped(
candid: ApiDirectMessageTippedNotification,
timestamp: bigint,
): DirectMessageTipped {
return {
kind: "direct_message_tipped",
them: { kind: "direct_chat", userId: candid.them.toString() },
messageIndex: candid.message_index,
messageEventIndex: candid.message_event_index,
username: candid.username,
displayName: optional(candid.display_name, identity),
tip: candid.tip,
userAvatarId: optional(candid.user_avatar_id, identity),
timestamp,
};
}

function cryptoTransfer(candid: ApiNotificationCryptoTransferDetails): CryptoTransferDetails {
return {
recipient: candid.recipient.toString(),
Expand Down
65 changes: 53 additions & 12 deletions frontend/openchat-push/src/push_sw.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { IDL } from "@dfinity/candid";
import { type ApiNotification, NotificationIdl, notification as toNotification } from "openchat-agent";
import {
type ApiNotification,
NotificationIdl,
notification as toNotification,
} from "openchat-agent";
import type {
Notification,
DirectChatIdentifier,
Expand Down Expand Up @@ -133,11 +137,7 @@ async function showNotification(n: Notification, id: string): Promise<void> {
userId: n.sender.userId,
};
title = n.senderDisplayName ?? n.senderName;
body = messageText(
n.messageText,
n.messageType,
n.cryptoTransfer,
);
body = messageText(n.messageText, n.messageType, n.cryptoTransfer);
if (n.senderAvatarId !== undefined) {
icon = avatarUrl(n.sender.userId, n.senderAvatarId);
} else if (n.messageType === "File") {
Expand Down Expand Up @@ -202,11 +202,7 @@ async function showNotification(n: Notification, id: string): Promise<void> {
if (n.userAvatarId !== undefined) {
icon = avatarUrl(n.them.userId, n.userAvatarId);
}
path = routeForMessage(
"direct_chat",
{ chatId: n.them },
n.messageIndex,
);
path = routeForMessage("direct_chat", { chatId: n.them }, n.messageIndex);
tag = path;
timestamp = Number(n.timestamp);
} else if (n.kind === "channel_reaction") {
Expand Down Expand Up @@ -243,10 +239,55 @@ async function showNotification(n: Notification, id: string): Promise<void> {
);
tag = path;
timestamp = Number(n.timestamp);
} else if (n.kind === "direct_message_tipped") {
title = n.username;
body = `${n.displayName ?? n.username} tipped your message ${n.tip}`;
if (n.userAvatarId !== undefined) {
icon = avatarUrl(n.them.userId, n.userAvatarId);
}
path = routeForMessage("direct_chat", { chatId: n.them }, n.messageIndex);
tag = path;
timestamp = Number(n.timestamp);
} else if (n.kind === "channel_message_tipped") {
title = `${n.communityName} / ${n.channelName}`;
body = `${n.tippedByDisplayName ?? n.tippedByName} tipped your message ${n.tip}`;
if (n.channelAvatarId !== undefined) {
icon = channelAvatarUrl(n.chatId, n.channelAvatarId);
} else if (n.communityAvatarId !== undefined) {
icon = avatarUrl(n.chatId.communityId, n.communityAvatarId);
}
path = routeForMessage(
"community",
{
chatId: n.chatId,
threadRootMessageIndex: n.threadRootMessageIndex,
},
n.messageIndex,
);
tag = path;
timestamp = Number(n.timestamp);
} else if (n.kind === "group_message_tipped") {
title = n.groupName;
body = `${n.tippedByDisplayName ?? n.tippedByName} tipped your message ${n.tip}`;
if (n.groupAvatarId !== undefined) {
icon = avatarUrl(n.chatId.groupId, n.groupAvatarId);
}
path = routeForMessage(
"group_chat",
{
chatId: n.chatId,
threadRootMessageIndex: n.threadRootMessageIndex,
},
n.messageIndex,
);
tag = path;
timestamp = Number(n.timestamp);
} else if (n.kind === "added_to_channel_notification") {
// TODO Multi language support
title = `${n.communityName} / ${n.channelName}`;
body = `${n.addedByDisplayName ?? n.addedByUsername} added you to the channel "${n.channelName}" in the community "${n.communityName}"`;
body = `${n.addedByDisplayName ?? n.addedByUsername} added you to the channel "${
n.channelName
}" in the community "${n.communityName}"`;
if (n.channelAvatarId !== undefined) {
icon = channelAvatarUrl(n.chatId, n.channelAvatarId);
} else if (n.communityAvatarId !== undefined) {
Expand Down
55 changes: 49 additions & 6 deletions frontend/openchat-shared/src/domain/notifications/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
import type {
ChannelIdentifier,
DirectChatIdentifier,
GroupChatIdentifier,
} from "../chat/chat";
import type { ChannelIdentifier, DirectChatIdentifier, GroupChatIdentifier } from "../chat/chat";

export type Notification =
| AddedToChannelNotification
Expand All @@ -11,7 +7,10 @@ export type Notification =
| GroupNotification
| ChannelReaction
| DirectReaction
| GroupReaction;
| GroupReaction
| ChannelMessageTipped
| DirectMessageTipped
| GroupMessageTipped;

export type AddedToChannelNotification = {
kind: "added_to_channel_notification";
Expand Down Expand Up @@ -123,6 +122,50 @@ export type GroupReaction = {
timestamp: bigint;
};

export type ChannelMessageTipped = {
kind: "channel_message_tipped";
chatId: ChannelIdentifier;
threadRootMessageIndex: number | undefined;
messageIndex: number;
messageEventIndex: number;
communityName: string;
channelName: string;
tippedBy: string;
tippedByName: string;
tippedByDisplayName: string | undefined;
tip: string;
communityAvatarId: bigint | undefined;
channelAvatarId: bigint | undefined;
timestamp: bigint;
};

export type DirectMessageTipped = {
kind: "direct_message_tipped";
messageIndex: number;
messageEventIndex: number;
them: DirectChatIdentifier;
username: string;
displayName: string | undefined;
tip: string;
userAvatarId: bigint | undefined;
timestamp: bigint;
};

export type GroupMessageTipped = {
kind: "group_message_tipped";
chatId: GroupChatIdentifier;
threadRootMessageIndex: number | undefined;
messageIndex: number;
messageEventIndex: number;
groupName: string;
tippedBy: string;
tippedByName: string;
tippedByDisplayName: string | undefined;
tip: string;
groupAvatarId: bigint | undefined;
timestamp: bigint;
};

export type CryptoTransferDetails = {
recipient: string;
recipientUsername: string | undefined;
Expand Down

0 comments on commit 7855091

Please sign in to comment.