revite/src/lib/ContextMenus.tsx

1070 lines
42 KiB
TypeScript
Raw Normal View History

2021-07-05 06:23:23 -04:00
import {
2021-07-05 06:25:20 -04:00
At,
Bell,
BellOff,
Check,
CheckSquare,
ChevronRight,
Block,
Square,
LeftArrowAlt,
Trash,
2021-07-05 06:23:23 -04:00
} from "@styled-icons/boxicons-regular";
2021-07-08 15:01:21 -04:00
import { Cog, UserVoice } from "@styled-icons/boxicons-solid";
2021-06-19 15:24:11 -04:00
import { useHistory } from "react-router-dom";
import { Attachment } from "revolt-api/types/Autumn";
import { Presence, RelationshipStatus } from "revolt-api/types/Users";
2021-07-05 06:23:23 -04:00
import {
2021-07-05 06:25:20 -04:00
ChannelPermission,
ServerPermission,
UserPermission,
2021-07-05 06:23:23 -04:00
} from "revolt.js/dist/api/permissions";
import { Channel } from "revolt.js/dist/maps/Channels";
import { Message } from "revolt.js/dist/maps/Messages";
import { Server } from "revolt.js/dist/maps/Servers";
import { User } from "revolt.js/dist/maps/Users";
2021-07-05 06:23:23 -04:00
import {
2021-07-05 06:25:20 -04:00
ContextMenuWithData,
MenuItem,
openContextMenu,
2021-06-19 15:24:11 -04:00
} from "preact-context-menu";
2021-07-05 06:23:23 -04:00
import { Text } from "preact-i18n";
import { useContext } from "preact/hooks";
import { dispatch } from "../redux";
import { connectState } from "../redux/connector";
import {
2021-07-05 06:25:20 -04:00
getNotificationState,
Notifications,
NotificationState,
2021-07-05 06:23:23 -04:00
} from "../redux/reducers/notifications";
2021-06-19 15:24:11 -04:00
import { QueuedMessage } from "../redux/reducers/queue";
2021-07-05 06:23:23 -04:00
2021-08-05 09:47:00 -04:00
import { Screen, useIntermediate } from "../context/intermediate/Intermediate";
2021-07-05 06:23:23 -04:00
import {
2021-07-05 06:25:20 -04:00
AppContext,
ClientStatus,
StatusContext,
2021-07-05 06:23:23 -04:00
} from "../context/revoltjs/RevoltClient";
2021-06-19 15:24:11 -04:00
import { takeError } from "../context/revoltjs/util";
2021-07-05 06:23:23 -04:00
import Tooltip from "../components/common/Tooltip";
import UserStatus from "../components/common/user/UserStatus";
import IconButton from "../components/ui/IconButton";
2021-07-05 06:23:23 -04:00
import LineDivider from "../components/ui/LineDivider";
import { Children } from "../types/Preact";
import { internalEmit } from "./eventEmitter";
2021-06-19 15:24:11 -04:00
interface ContextMenuData {
2021-07-05 06:25:20 -04:00
user?: string;
server?: string;
server_list?: string;
channel?: string;
message?: Message;
unread?: boolean;
queued?: QueuedMessage;
contextualChannel?: string;
2021-06-19 15:24:11 -04:00
}
type Action =
2021-07-05 06:25:20 -04:00
| { action: "copy_id"; id: string }
| { action: "copy_message_link"; message: Message }
2021-07-05 06:25:20 -04:00
| { action: "copy_selection" }
| { action: "copy_text"; content: string }
2021-07-29 13:41:01 -04:00
| { action: "mark_as_read"; channel: Channel }
| { action: "mark_server_as_read"; server: Server }
2021-07-05 06:25:20 -04:00
| { action: "retry_message"; message: QueuedMessage }
| { action: "cancel_message"; message: QueuedMessage }
| { action: "mention"; user: string }
| { action: "reply_message"; id: string }
| { action: "quote_message"; content: string }
| { action: "edit_message"; id: string }
| { action: "delete_message"; target: Message }
2021-07-05 06:25:20 -04:00
| { action: "open_file"; attachment: Attachment }
| { action: "save_file"; attachment: Attachment }
| { action: "copy_file_link"; attachment: Attachment }
| { action: "open_link"; link: string }
| { action: "copy_link"; link: string }
| { action: "remove_member"; channel: Channel; user: User }
2021-07-29 14:01:40 -04:00
| { action: "kick_member"; target: Server; user: User }
| { action: "ban_member"; target: Server; user: User }
2021-07-29 10:11:21 -04:00
| { action: "view_profile"; user: User }
| { action: "message_user"; user: User }
| { action: "block_user"; user: User }
| { action: "unblock_user"; user: User }
| { action: "add_friend"; user: User }
| { action: "remove_friend"; user: User }
| { action: "cancel_friend"; user: User }
| { action: "set_presence"; presence: Presence }
2021-07-05 06:25:20 -04:00
| { action: "set_status" }
| { action: "clear_status" }
2021-07-29 14:01:40 -04:00
| { action: "create_channel"; target: Server }
2021-07-05 06:25:20 -04:00
| {
action: "create_invite";
2021-07-29 13:41:01 -04:00
target: Channel;
2021-07-05 06:25:20 -04:00
}
2021-07-29 13:41:01 -04:00
| { action: "leave_group"; target: Channel }
2021-07-05 06:25:20 -04:00
| {
action: "delete_channel";
2021-07-29 13:41:01 -04:00
target: Channel;
2021-07-05 06:25:20 -04:00
}
2021-07-29 13:41:01 -04:00
| { action: "close_dm"; target: Channel }
2021-07-29 14:01:40 -04:00
| { action: "leave_server"; target: Server }
| { action: "delete_server"; target: Server }
2021-07-29 13:41:01 -04:00
| { action: "open_notification_options"; channel: Channel }
2021-07-05 06:25:20 -04:00
| { action: "open_settings" }
| { action: "open_channel_settings"; id: string }
| { action: "open_server_settings"; id: string }
| { action: "open_server_channel_settings"; server: string; id: string }
| {
action: "set_notification_state";
key: string;
state?: NotificationState;
};
2021-06-19 15:24:11 -04:00
type Props = {
2021-07-05 06:25:20 -04:00
notifications: Notifications;
};
2021-07-29 14:01:40 -04:00
// ! FIXME: I dare someone to re-write this
// Tip: This should just be split into separate context menus per logical area.
function ContextMenus(props: Props) {
2021-07-05 06:25:20 -04:00
const { openScreen, writeClipboard } = useIntermediate();
const client = useContext(AppContext);
const userId = client.user!._id;
const status = useContext(StatusContext);
const isOnline = status === ClientStatus.ONLINE;
const history = useHistory();
function contextClick(data?: Action) {
if (typeof data === "undefined") return;
(async () => {
switch (data.action) {
case "copy_id":
writeClipboard(data.id);
break;
case "copy_message_link":
{
let pathname = `/channel/${data.message.channel_id}/${data.message._id}`;
const channel = data.message.channel;
if (channel?.channel_type === "TextChannel")
pathname = `/server/${channel.server_id}${pathname}`;
writeClipboard(window.origin + pathname);
}
break;
2021-07-05 06:25:20 -04:00
case "copy_selection":
writeClipboard(document.getSelection()?.toString() ?? "");
break;
case "mark_as_read":
{
if (
data.channel.channel_type === "SavedMessages" ||
data.channel.channel_type === "VoiceChannel"
)
return;
const message =
2021-07-29 13:41:01 -04:00
typeof data.channel.last_message === "string"
2021-07-05 06:25:20 -04:00
? data.channel.last_message
2021-07-29 13:41:01 -04:00
: data.channel.last_message!._id;
2021-07-05 06:25:20 -04:00
dispatch({
type: "UNREADS_MARK_READ",
channel: data.channel._id,
message,
});
data.channel.ack(message);
}
break;
case "mark_server_as_read":
{
dispatch({
type: "UNREADS_MARK_MULTIPLE_READ",
channels: data.server.channel_ids,
});
data.server.ack();
2021-07-05 06:25:20 -04:00
}
break;
case "retry_message":
{
const nonce = data.message.id;
2021-08-05 09:47:00 -04:00
const fail = (error: string) =>
2021-07-05 06:25:20 -04:00
dispatch({
type: "QUEUE_FAIL",
nonce,
error,
});
client.channels
.get(data.message.channel)!
.sendMessage({
2021-07-05 06:25:20 -04:00
nonce: data.message.id,
content: data.message.data.content as string,
replies: data.message.data.replies,
})
.catch(fail);
dispatch({
type: "QUEUE_START",
nonce,
});
}
break;
case "cancel_message":
{
dispatch({
type: "QUEUE_REMOVE",
nonce: data.message.id,
});
}
break;
case "mention":
{
internalEmit(
"MessageBox",
"append",
`<@${data.user}>`,
"mention",
);
}
break;
case "copy_text":
writeClipboard(data.content);
break;
case "reply_message":
{
internalEmit("ReplyBar", "add", data.id);
}
break;
case "quote_message":
{
internalEmit(
"MessageBox",
"append",
data.content,
"quote",
);
}
break;
case "edit_message":
{
internalEmit(
"MessageRenderer",
"edit_message",
data.id,
);
}
break;
case "open_file":
{
window
.open(
client.generateFileURL(data.attachment),
"_blank",
)
?.focus();
}
break;
case "save_file":
{
window.open(
// ! FIXME: do this from revolt.js
client
.generateFileURL(data.attachment)
?.replace(
"attachments",
"attachments/download",
),
"_blank",
);
}
break;
case "copy_file_link":
{
const { filename } = data.attachment;
writeClipboard(
// ! FIXME: do from r.js
`${client.generateFileURL(
data.attachment,
)}/${encodeURI(filename)}`,
2021-07-05 06:25:20 -04:00
);
}
break;
case "open_link":
{
window.open(data.link, "_blank")?.focus();
}
break;
case "copy_link":
{
writeClipboard(data.link);
}
break;
case "remove_member":
{
data.channel.removeMember(data.user._id);
2021-07-05 06:25:20 -04:00
}
break;
case "view_profile":
2021-07-29 10:11:21 -04:00
openScreen({ id: "profile", user_id: data.user._id });
2021-07-05 06:25:20 -04:00
break;
case "message_user":
{
const channel = await data.user.openDM();
2021-07-05 06:25:20 -04:00
if (channel) {
history.push(`/channel/${channel._id}`);
}
}
break;
case "add_friend":
{
await data.user.addFriend();
2021-07-05 06:25:20 -04:00
}
break;
case "block_user":
openScreen({
id: "special_prompt",
type: "block_user",
target: data.user,
});
break;
case "unblock_user":
await data.user.unblockUser();
2021-07-05 06:25:20 -04:00
break;
case "remove_friend":
openScreen({
id: "special_prompt",
type: "unfriend_user",
target: data.user,
});
break;
case "cancel_friend":
await data.user.removeFriend();
2021-07-05 06:25:20 -04:00
break;
case "set_presence":
{
await client.users.edit({
2021-07-05 06:25:20 -04:00
status: {
...client.user?.status,
presence: data.presence,
},
});
}
break;
case "set_status":
openScreen({
id: "special_input",
type: "set_custom_status",
});
break;
case "clear_status":
{
2021-08-05 09:47:00 -04:00
const { text: _text, ...status } =
client.user?.status ?? {};
await client.users.edit({ status });
2021-07-05 06:25:20 -04:00
}
break;
case "leave_group":
case "close_dm":
case "leave_server":
case "delete_channel":
case "delete_server":
case "delete_message":
case "create_channel":
case "create_invite":
2021-08-05 09:47:00 -04:00
// Typescript flattens the case types into a single type and type structure and specifity is lost
2021-07-05 06:25:20 -04:00
openScreen({
id: "special_prompt",
type: data.action,
2021-08-05 09:47:00 -04:00
target: data.target,
} as unknown as Screen);
2021-07-05 06:25:20 -04:00
break;
case "ban_member":
case "kick_member":
openScreen({
id: "special_prompt",
type: data.action,
target: data.target,
user: data.user,
});
break;
case "open_notification_options": {
openContextMenu("NotificationOptions", {
channel: data.channel,
});
break;
}
case "open_settings":
history.push("/settings");
break;
case "open_channel_settings":
history.push(`/channel/${data.id}/settings`);
break;
case "open_server_channel_settings":
history.push(
`/server/${data.server}/channel/${data.id}/settings`,
);
break;
case "open_server_settings":
history.push(`/server/${data.id}/settings`);
break;
case "set_notification_state": {
const { key, state } = data;
if (state) {
dispatch({ type: "NOTIFICATIONS_SET", key, state });
} else {
dispatch({ type: "NOTIFICATIONS_REMOVE", key });
}
break;
}
}
})().catch((err) => {
openScreen({ id: "error", error: takeError(err) });
});
}
return (
<>
<ContextMenuWithData id="Menu" onClose={contextClick}>
{({
user: uid,
channel: cid,
server: sid,
message,
server_list,
queued,
unread,
contextualChannel: cxid,
}: ContextMenuData) => {
const elements: Children[] = [];
let lastDivider = false;
2021-07-05 06:25:20 -04:00
function generateAction(
action: Action,
locale?: string,
disabled?: boolean,
tip?: Children,
) {
lastDivider = false;
elements.push(
<MenuItem data={action} disabled={disabled}>
<Text
id={`app.context_menu.${
locale ?? action.action
}`}
/>
{tip && <div className="tip">{tip}</div>}
</MenuItem>,
);
}
function pushDivider() {
if (lastDivider || elements.length === 0) return;
lastDivider = true;
elements.push(<LineDivider />);
}
if (server_list) {
const server = client.servers.get(server_list)!;
const permissions = server.permission;
2021-07-05 06:25:20 -04:00
if (server) {
if (permissions & ServerPermission.ManageChannels)
generateAction({
action: "create_channel",
target: server,
});
if (permissions & ServerPermission.ManageServer)
generateAction({
action: "open_server_settings",
id: server_list,
});
}
return elements;
}
if (document.getSelection()?.toString().length ?? 0 > 0) {
generateAction(
{ action: "copy_selection" },
undefined,
undefined,
<Text id="shortcuts.ctrlc" />,
);
pushDivider();
}
const channel = cid ? client.channels.get(cid) : undefined;
2021-07-29 13:41:01 -04:00
const contextualChannel = cxid
? client.channels.get(cxid)
2021-07-29 13:41:01 -04:00
: undefined;
2021-07-05 06:25:20 -04:00
const targetChannel = channel ?? contextualChannel;
const user = uid ? client.users.get(uid) : undefined;
2021-07-05 06:25:20 -04:00
const serverChannel =
targetChannel &&
(targetChannel.channel_type === "TextChannel" ||
targetChannel.channel_type === "VoiceChannel")
? targetChannel
: undefined;
2021-07-29 14:01:40 -04:00
const s = serverChannel ? serverChannel.server_id! : sid;
const server = s ? client.servers.get(s) : undefined;
const channelPermissions = targetChannel?.permission || 0;
const serverPermissions =
(server
? server.permission
: serverChannel
? serverChannel.server?.permission
: 0) || 0;
const userPermissions = (user ? user.permission : 0) || 0;
2021-07-05 06:25:20 -04:00
if (channel && unread) {
generateAction({ action: "mark_as_read", channel });
}
if (server && unread) {
generateAction(
{
action: "mark_server_as_read",
server,
},
"mark_as_read",
);
}
2021-07-05 06:25:20 -04:00
if (contextualChannel) {
if (user && user._id !== userId) {
generateAction({
action: "mention",
user: user._id,
});
pushDivider();
}
}
if (user) {
let actions: Action["action"][];
switch (user.relationship) {
case RelationshipStatus.User:
2021-07-05 06:25:20 -04:00
actions = [];
break;
case RelationshipStatus.Friend:
2021-07-05 06:25:20 -04:00
actions = ["remove_friend", "block_user"];
break;
case RelationshipStatus.Incoming:
2021-07-05 06:25:20 -04:00
actions = [
"add_friend",
"cancel_friend",
"block_user",
];
break;
case RelationshipStatus.Outgoing:
2021-07-05 06:25:20 -04:00
actions = ["cancel_friend", "block_user"];
break;
case RelationshipStatus.Blocked:
2021-07-05 06:25:20 -04:00
actions = ["unblock_user"];
break;
case RelationshipStatus.BlockedOther:
2021-07-05 06:25:20 -04:00
actions = ["block_user"];
break;
case RelationshipStatus.None:
2021-07-05 06:25:20 -04:00
default:
actions = ["add_friend", "block_user"];
}
if (userPermissions & UserPermission.ViewProfile) {
generateAction({
action: "view_profile",
2021-07-29 10:11:21 -04:00
user,
2021-07-05 06:25:20 -04:00
});
}
if (
user._id !== userId &&
userPermissions & UserPermission.SendMessage
) {
generateAction({
action: "message_user",
2021-07-29 10:11:21 -04:00
user,
2021-07-05 06:25:20 -04:00
});
}
for (let i = 0; i < actions.length; i++) {
2021-08-05 09:47:00 -04:00
// Typescript can't determine that user the actions are linked together correctly
generateAction({
action: actions[i],
user,
} as unknown as Action);
2021-07-05 06:25:20 -04:00
}
}
if (contextualChannel) {
if (contextualChannel.channel_type === "Group" && uid) {
if (
contextualChannel.owner_id === userId &&
2021-07-05 06:25:20 -04:00
userId !== uid
) {
generateAction({
action: "remove_member",
channel: contextualChannel,
2021-07-29 10:11:21 -04:00
user: user!,
2021-07-05 06:25:20 -04:00
});
}
}
if (
server &&
uid &&
userId !== uid &&
uid !== server.owner
) {
if (
serverPermissions & ServerPermission.KickMembers
)
generateAction({
action: "kick_member",
target: server,
2021-07-29 10:11:21 -04:00
user: user!,
2021-07-05 06:25:20 -04:00
});
if (serverPermissions & ServerPermission.BanMembers)
generateAction({
action: "ban_member",
target: server,
2021-07-29 10:11:21 -04:00
user: user!,
2021-07-05 06:25:20 -04:00
});
}
}
if (queued) {
generateAction({
action: "retry_message",
message: queued,
});
generateAction({
action: "cancel_message",
message: queued,
});
}
if (message && !queued) {
generateAction({
action: "reply_message",
id: message._id,
});
if (
typeof message.content === "string" &&
message.content.length > 0
) {
generateAction({
action: "quote_message",
content: message.content,
});
generateAction({
action: "copy_text",
content: message.content,
});
}
if (message.author_id === userId) {
2021-07-05 06:25:20 -04:00
generateAction({
action: "edit_message",
id: message._id,
});
}
if (
message.author_id === userId ||
2021-07-05 06:25:20 -04:00
channelPermissions &
ChannelPermission.ManageMessages
) {
generateAction({
action: "delete_message",
target: message,
});
}
if (message.attachments) {
pushDivider();
const { metadata } = message.attachments[0];
const { type } = metadata;
generateAction(
{
action: "open_file",
attachment: message.attachments[0],
},
type === "Image"
? "open_image"
: type === "Video"
? "open_video"
: "open_file",
);
generateAction(
{
action: "save_file",
attachment: message.attachments[0],
},
type === "Image"
? "save_image"
: type === "Video"
? "save_video"
: "save_file",
);
generateAction(
{
action: "copy_file_link",
attachment: message.attachments[0],
},
"copy_link",
);
}
if (document.activeElement?.tagName === "A") {
const link =
2021-07-05 06:25:20 -04:00
document.activeElement.getAttribute("href");
if (link) {
pushDivider();
generateAction({ action: "open_link", link });
generateAction({ action: "copy_link", link });
}
}
}
const id = sid ?? cid ?? uid ?? message?._id;
2021-07-05 06:25:20 -04:00
if (id) {
pushDivider();
if (channel) {
if (channel.channel_type !== "VoiceChannel") {
generateAction(
{
action: "open_notification_options",
channel,
},
undefined,
undefined,
<ChevronRight size={24} />,
);
}
switch (channel.channel_type) {
case "Group":
// ! generateAction({ action: "create_invite", target: channel }); FIXME: add support for group invites
generateAction(
{
action: "open_channel_settings",
id: channel._id,
},
"open_group_settings",
);
generateAction(
{
action: "leave_group",
target: channel,
},
"leave_group",
);
break;
case "DirectMessage":
generateAction({
action: "close_dm",
target: channel,
});
break;
case "TextChannel":
case "VoiceChannel":
if (
channelPermissions &
ChannelPermission.InviteOthers
) {
generateAction({
action: "create_invite",
target: channel,
});
}
2021-07-05 06:25:20 -04:00
if (
serverPermissions &
ServerPermission.ManageServer
)
generateAction(
{
action: "open_server_channel_settings",
server: channel.server_id!,
2021-07-05 06:25:20 -04:00
id: channel._id,
},
"open_channel_settings",
);
if (
serverPermissions &
ServerPermission.ManageChannels
)
generateAction({
action: "delete_channel",
target: channel,
});
break;
}
}
if (sid && server) {
if (
serverPermissions &
ServerPermission.ManageServer
)
generateAction(
{
action: "open_server_settings",
id: server._id,
},
"open_server_settings",
);
if (userId === server.owner) {
generateAction(
{ action: "delete_server", target: server },
"delete_server",
);
} else {
generateAction(
{ action: "leave_server", target: server },
"leave_server",
);
}
}
if (message) {
generateAction({
action: "copy_message_link",
message,
});
}
2021-07-05 06:25:20 -04:00
generateAction(
{ action: "copy_id", id },
sid
? "copy_sid"
: cid
? "copy_cid"
: message
? "copy_mid"
: "copy_uid",
);
}
return elements;
}}
</ContextMenuWithData>
<ContextMenuWithData
id="Status"
onClose={contextClick}
className="Status">
2021-07-29 10:11:21 -04:00
{() => {
const user = client.user!;
2021-07-29 10:11:21 -04:00
return (
<>
<div className="header">
<div className="main">
<div
className="username"
onClick={() =>
writeClipboard(
client.user!.username,
)
}>
2021-07-29 10:11:21 -04:00
<Tooltip
content={
<Text id="app.special.copy_username" />
}>
@{user.username}
</Tooltip>
</div>
<div
className="status"
onClick={() =>
contextClick({
action: "set_status",
})
}>
<UserStatus user={user} />
</div>
2021-07-05 06:25:20 -04:00
</div>
<IconButton>
2021-07-29 10:11:21 -04:00
<MenuItem
data={{ action: "open_settings" }}>
<Cog size={22} />
2021-07-05 06:25:20 -04:00
</MenuItem>
</IconButton>
2021-07-29 10:11:21 -04:00
</div>
<LineDivider />
<MenuItem
data={{
action: "set_presence",
presence: Presence.Online,
2021-07-29 10:11:21 -04:00
}}
disabled={!isOnline}>
<div className="indicator online" />
<Text id={`app.status.online`} />
</MenuItem>
<MenuItem
data={{
action: "set_presence",
presence: Presence.Idle,
2021-07-29 10:11:21 -04:00
}}
disabled={!isOnline}>
<div className="indicator idle" />
<Text id={`app.status.idle`} />
</MenuItem>
<MenuItem
data={{
action: "set_presence",
presence: Presence.Busy,
2021-07-29 10:11:21 -04:00
}}
disabled={!isOnline}>
<div className="indicator busy" />
<Text id={`app.status.busy`} />
</MenuItem>
<MenuItem
data={{
action: "set_presence",
presence: Presence.Invisible,
2021-07-29 10:11:21 -04:00
}}
disabled={!isOnline}>
<div className="indicator invisible" />
<Text id={`app.status.invisible`} />
</MenuItem>
<LineDivider />
<MenuItem
data={{ action: "set_status" }}
disabled={!isOnline}>
<UserVoice size={18} />
<Text id={`app.context_menu.custom_status`} />
{client.user!.status?.text && (
<IconButton>
<MenuItem
data={{ action: "clear_status" }}>
<Trash size={18} />
</MenuItem>
</IconButton>
)}
</MenuItem>
</>
);
}}
2021-07-05 06:25:20 -04:00
</ContextMenuWithData>
<ContextMenuWithData
id="NotificationOptions"
onClose={contextClick}>
{({ channel }: { channel: Channel }) => {
2021-07-05 06:25:20 -04:00
const state = props.notifications[channel._id];
const actual = getNotificationState(
props.notifications,
channel,
);
const elements: Children[] = [
2021-07-05 06:25:20 -04:00
<MenuItem
2021-08-05 09:47:00 -04:00
key="notif"
2021-07-05 06:25:20 -04:00
data={{
action: "set_notification_state",
key: channel._id,
}}>
<Text
id={`app.main.channel.notifications.default`}
/>
<div className="tip">
{state !== undefined && <Square size={20} />}
{state === undefined && (
<CheckSquare size={20} />
)}
</div>
</MenuItem>,
];
function generate(key: string, icon: Children) {
elements.push(
<MenuItem
2021-08-05 09:47:00 -04:00
key={key}
2021-07-05 06:25:20 -04:00
data={{
action: "set_notification_state",
key: channel._id,
state: key,
}}>
{icon}
<Text
id={`app.main.channel.notifications.${key}`}
/>
{state === undefined && actual === key && (
<div className="tip">
<LeftArrowAlt size={20} />
</div>
)}
{state === key && (
<div className="tip">
<Check size={20} />
</div>
)}
</MenuItem>,
);
}
generate("all", <Bell size={24} />);
generate("mention", <At size={24} />);
generate("muted", <BellOff size={24} />);
generate("none", <Block size={24} />);
return elements;
}}
</ContextMenuWithData>
</>
);
2021-06-19 15:24:11 -04:00
}
2021-07-05 06:23:23 -04:00
export default connectState(ContextMenus, (state) => {
2021-07-05 06:25:20 -04:00
return {
notifications: state.notifications,
};
2021-07-05 06:23:23 -04:00
});