Files
ThreadNet-Web/src/components/views/settings/notifications/NotificationSettings2.tsx
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

392 lines
17 KiB
TypeScript
Raw Normal View History

2023-06-29 17:46:31 +02:00
/*
Copyright 2023 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React, { useState } from "react";
import NewAndImprovedIcon from "../../../../../res/img/element-icons/new-and-improved.svg";
import { useMatrixClientContext } from "../../../../contexts/MatrixClientContext";
import { useNotificationSettings } from "../../../../hooks/useNotificationSettings";
import { useSettingValue } from "../../../../hooks/useSettings";
import { _t } from "../../../../languageHandler";
import {
DefaultNotificationSettings,
NotificationSettings,
} from "../../../../models/notificationsettings/NotificationSettings";
import { RoomNotifState } from "../../../../RoomNotifs";
import { SettingLevel } from "../../../../settings/SettingLevel";
import SettingsStore from "../../../../settings/SettingsStore";
import { NotificationLevel } from "../../../../stores/notifications/NotificationLevel";
2023-06-29 17:46:31 +02:00
import { clearAllNotifications } from "../../../../utils/notifications";
import AccessibleButton from "../../elements/AccessibleButton";
2023-07-11 12:38:14 +02:00
import ExternalLink from "../../elements/ExternalLink";
2023-06-29 17:46:31 +02:00
import LabelledCheckbox from "../../elements/LabelledCheckbox";
import LabelledToggleSwitch from "../../elements/LabelledToggleSwitch";
import StyledRadioGroup from "../../elements/StyledRadioGroup";
import TagComposer from "../../elements/TagComposer";
import { StatelessNotificationBadge } from "../../rooms/NotificationBadge/StatelessNotificationBadge";
import { SettingsBanner } from "../shared/SettingsBanner";
import { SettingsSection } from "../shared/SettingsSection";
import SettingsSubsection from "../shared/SettingsSubsection";
import { NotificationPusherSettings } from "./NotificationPusherSettings";
2024-04-12 14:18:09 +01:00
import SettingsFlag from "../../elements/SettingsFlag";
2023-06-29 17:46:31 +02:00
enum NotificationDefaultLevels {
AllMessages = "all_messages",
PeopleMentionsKeywords = "people_mentions_keywords",
MentionsKeywords = "mentions_keywords",
}
function toDefaultLevels(levels: NotificationSettings["defaultLevels"]): NotificationDefaultLevels {
if (levels.room === RoomNotifState.AllMessages) {
return NotificationDefaultLevels.AllMessages;
} else if (levels.dm === RoomNotifState.AllMessages) {
return NotificationDefaultLevels.PeopleMentionsKeywords;
} else {
return NotificationDefaultLevels.MentionsKeywords;
}
}
function boldText(text: string): JSX.Element {
return <strong>{text}</strong>;
}
2023-07-11 12:38:14 +02:00
function helpLink(sub: string): JSX.Element {
return <ExternalLink href="https://element.io/help#settings2">{sub}</ExternalLink>;
}
2023-06-29 17:46:31 +02:00
function useHasUnreadNotifications(): boolean {
const cli = useMatrixClientContext();
return cli.getRooms().some((room) => room.getUnreadNotificationCount() > 0);
}
2024-04-12 14:18:09 +01:00
/**
* The new notification settings tab view, only displayed if the user has Features.NotificationSettings2 enabled
*/
2023-06-29 17:46:31 +02:00
export default function NotificationSettings2(): JSX.Element {
const cli = useMatrixClientContext();
const desktopNotifications = useSettingValue<boolean>("notificationsEnabled");
const desktopShowBody = useSettingValue<boolean>("notificationBodyEnabled");
const audioNotifications = useSettingValue<boolean>("audioNotificationsEnabled");
const { model, hasPendingChanges, reconcile } = useNotificationSettings(cli);
const disabled = model === null || hasPendingChanges;
const settings = model ?? DefaultNotificationSettings;
const [updatingUnread, setUpdatingUnread] = useState<boolean>(false);
const hasUnreadNotifications = useHasUnreadNotifications();
const NotificationOptions = [
{
value: NotificationDefaultLevels.AllMessages,
label: _t("notifications|all_messages"),
},
{
value: NotificationDefaultLevels.PeopleMentionsKeywords,
label: _t("settings|notifications|people_mentions_keywords"),
},
{
value: NotificationDefaultLevels.MentionsKeywords,
label: _t("settings|notifications|mentions_keywords_only"),
},
];
2023-06-29 17:46:31 +02:00
return (
<div className="mx_NotificationSettings2">
{hasPendingChanges && model !== null && (
<SettingsBanner
icon={<img src={NewAndImprovedIcon} alt="" width={12} />}
action={_t("action|proceed")}
2023-06-29 17:46:31 +02:00
onAction={() => reconcile(model!)}
>
{_t(
"settings|notifications|labs_notice_prompt",
2023-06-29 17:46:31 +02:00
{},
2023-07-11 12:38:14 +02:00
{
strong: boldText,
a: helpLink,
},
2023-06-29 17:46:31 +02:00
)}
</SettingsBanner>
)}
<SettingsSection>
2023-06-29 17:46:31 +02:00
<div className="mx_SettingsSubsection_content mx_NotificationSettings2_flags">
<LabelledToggleSwitch
label={_t("settings|notifications|enable_notifications_account")}
2023-06-29 17:46:31 +02:00
value={!settings.globalMute}
disabled={disabled}
onChange={(value) => {
reconcile({
...model!,
globalMute: !value,
});
}}
/>
<LabelledToggleSwitch
label={_t("settings|notifications|enable_desktop_notifications_session")}
2023-06-29 17:46:31 +02:00
value={desktopNotifications}
onChange={(value) =>
SettingsStore.setValue("notificationsEnabled", null, SettingLevel.DEVICE, value)
}
/>
<LabelledToggleSwitch
label={_t("settings|notifications|desktop_notification_message_preview")}
2023-06-29 17:46:31 +02:00
value={desktopShowBody}
onChange={(value) =>
SettingsStore.setValue("notificationBodyEnabled", null, SettingLevel.DEVICE, value)
}
/>
<LabelledToggleSwitch
label={_t("settings|notifications|enable_audible_notifications_session")}
2023-06-29 17:46:31 +02:00
value={audioNotifications}
onChange={(value) =>
SettingsStore.setValue("audioNotificationsEnabled", null, SettingLevel.DEVICE, value)
}
/>
</div>
<SettingsSubsection
heading={_t("settings|notifications|default_setting_section")}
description={_t("settings|notifications|default_setting_description")}
2023-06-29 17:46:31 +02:00
>
<StyledRadioGroup
name="defaultNotificationLevel"
value={toDefaultLevels(settings.defaultLevels)}
disabled={disabled}
definitions={NotificationOptions}
onChange={(value) => {
reconcile({
...model!,
defaultLevels: {
...model!.defaultLevels,
dm:
value !== NotificationDefaultLevels.MentionsKeywords
? RoomNotifState.AllMessages
: RoomNotifState.MentionsOnly,
room:
value === NotificationDefaultLevels.AllMessages
? RoomNotifState.AllMessages
: RoomNotifState.MentionsOnly,
},
});
}}
/>
</SettingsSubsection>
<SettingsSubsection
heading={_t("settings|notifications|play_sound_for_section")}
description={_t("settings|notifications|play_sound_for_description")}
2023-06-29 17:46:31 +02:00
>
<LabelledCheckbox
label="People"
value={settings.sound.people !== undefined}
disabled={disabled || settings.defaultLevels.dm === RoomNotifState.MentionsOnly}
2023-06-29 17:46:31 +02:00
onChange={(value) => {
reconcile({
...model!,
sound: {
...model!.sound,
people: value ? "default" : undefined,
},
});
}}
/>
<LabelledCheckbox
label={_t("settings|notifications|mentions_keywords")}
2023-06-29 17:46:31 +02:00
value={settings.sound.mentions !== undefined}
disabled={disabled}
onChange={(value) => {
reconcile({
...model!,
sound: {
...model!.sound,
mentions: value ? "default" : undefined,
},
});
}}
/>
<LabelledCheckbox
label={_t("settings|notifications|voip")}
2023-06-29 17:46:31 +02:00
value={settings.sound.calls !== undefined}
disabled={disabled}
onChange={(value) => {
reconcile({
...model!,
sound: {
...model!.sound,
calls: value ? "ring" : undefined,
},
});
}}
/>
</SettingsSubsection>
<SettingsSubsection heading={_t("settings|notifications|other_section")}>
2023-06-29 17:46:31 +02:00
<LabelledCheckbox
label={_t("settings|notifications|invites")}
2023-06-29 17:46:31 +02:00
value={settings.activity.invite}
disabled={disabled}
onChange={(value) => {
reconcile({
...model!,
activity: {
...model!.activity,
invite: value,
},
});
}}
/>
<LabelledCheckbox
label={_t("settings|notifications|room_activity")}
2023-06-29 17:46:31 +02:00
value={settings.activity.status_event}
disabled={disabled}
onChange={(value) => {
reconcile({
...model!,
activity: {
...model!.activity,
status_event: value,
},
});
}}
/>
<LabelledCheckbox
label={_t("settings|notifications|notices")}
2023-06-29 17:46:31 +02:00
value={settings.activity.bot_notices}
disabled={disabled}
onChange={(value) => {
reconcile({
...model!,
activity: {
...model!.activity,
bot_notices: value,
},
});
}}
/>
</SettingsSubsection>
<SettingsSubsection
heading={_t("settings|notifications|mentions_keywords")}
2023-06-29 17:46:31 +02:00
description={_t(
"settings|notifications|keywords",
2023-06-29 17:46:31 +02:00
{},
{
badge: (
<StatelessNotificationBadge
symbol="1"
count={1}
level={NotificationLevel.Notification}
/>
),
2023-06-29 17:46:31 +02:00
},
)}
>
<LabelledCheckbox
label={_t("settings|notifications|notify_at_room")}
2023-06-29 17:46:31 +02:00
value={settings.mentions.room}
disabled={disabled}
onChange={(value) => {
reconcile({
...model!,
mentions: {
...model!.mentions,
room: value,
},
});
}}
/>
<LabelledCheckbox
label={_t("settings|notifications|notify_mention", {
2023-06-29 17:46:31 +02:00
mxid: cli.getUserId()!,
})}
value={settings.mentions.user}
disabled={disabled}
onChange={(value) => {
reconcile({
...model!,
mentions: {
...model!.mentions,
user: value,
},
});
}}
/>
<LabelledCheckbox
label={_t("settings|notifications|notify_keyword")}
byline={_t("settings|notifications|keywords_prompt")}
2023-06-29 17:46:31 +02:00
value={settings.mentions.keywords}
disabled={disabled}
onChange={(value) => {
reconcile({
...model!,
mentions: {
...model!.mentions,
keywords: value,
},
});
}}
/>
<TagComposer
id="mx_NotificationSettings2_Keywords"
tags={model?.keywords ?? []}
disabled={disabled}
onAdd={(keyword) => {
reconcile({
...model!,
keywords: [keyword, ...model!.keywords],
});
}}
onRemove={(keyword) => {
reconcile({
...model!,
keywords: model!.keywords.filter((it) => it !== keyword),
});
}}
label={_t("notifications|keyword")}
placeholder={_t("notifications|keyword_new")}
2023-06-29 17:46:31 +02:00
/>
2024-04-12 14:18:09 +01:00
<SettingsFlag name="Notifications.showbold" level={SettingLevel.DEVICE} />
<SettingsFlag name="Notifications.tac_only_notifications" level={SettingLevel.DEVICE} />
2023-06-29 17:46:31 +02:00
</SettingsSubsection>
<NotificationPusherSettings />
<SettingsSubsection heading={_t("settings|notifications|quick_actions_section")}>
2023-06-29 17:46:31 +02:00
{hasUnreadNotifications && (
<AccessibleButton
kind="primary_outline"
disabled={updatingUnread}
onClick={async () => {
setUpdatingUnread(true);
await clearAllNotifications(cli);
setUpdatingUnread(false);
}}
>
{_t("settings|notifications|quick_actions_mark_all_read")}
2023-06-29 17:46:31 +02:00
</AccessibleButton>
)}
<AccessibleButton
kind="danger_outline"
disabled={model === null}
onClick={() => {
reconcile(DefaultNotificationSettings);
}}
>
{_t("settings|notifications|quick_actions_reset")}
2023-06-29 17:46:31 +02:00
</AccessibleButton>
</SettingsSubsection>
</SettingsSection>
</div>
);
}