mirror of
https://github.com/cheeaun/phanpy.git
synced 2025-03-21 13:19:22 +01:00
MVP-ish filtered notifications UI
This commit is contained in:
parent
da909e4084
commit
4c2210c68b
4 changed files with 520 additions and 2 deletions
|
@ -104,4 +104,5 @@ export const ICONS = {
|
||||||
code: () => import('@iconify-icons/mingcute/code-line'),
|
code: () => import('@iconify-icons/mingcute/code-line'),
|
||||||
copy: () => import('@iconify-icons/mingcute/copy-2-line'),
|
copy: () => import('@iconify-icons/mingcute/copy-2-line'),
|
||||||
quote: () => import('@iconify-icons/mingcute/quote-left-line'),
|
quote: () => import('@iconify-icons/mingcute/quote-left-line'),
|
||||||
|
settings: () => import('@iconify-icons/mingcute/settings-6-line'),
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
{
|
{
|
||||||
"@mastodon/edit-media-attributes": ">=4.1",
|
"@mastodon/edit-media-attributes": ">=4.1",
|
||||||
"@mastodon/list-exclusive": ">=4.2"
|
"@mastodon/list-exclusive": ">=4.2",
|
||||||
|
"@mastodon/filtered-notifications": "~4.3 || >=4.3"
|
||||||
}
|
}
|
||||||
|
|
|
@ -421,3 +421,130 @@
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
background-color: var(--link-faded-color);
|
background-color: var(--link-faded-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* FILTERED NOTIFICATIONS */
|
||||||
|
|
||||||
|
.filtered-notifications {
|
||||||
|
padding-block-end: 16px;
|
||||||
|
|
||||||
|
summary {
|
||||||
|
padding: 8px 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: 600;
|
||||||
|
user-select: none;
|
||||||
|
margin: 16px 0 0;
|
||||||
|
color: var(--text-insignificant-color);
|
||||||
|
|
||||||
|
&::marker,
|
||||||
|
&::-webkit-details-marker {
|
||||||
|
color: var(--text-insignificant-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
details[open] summary {
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
summary + ul {
|
||||||
|
}
|
||||||
|
ul {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
max-height: 50vh;
|
||||||
|
max-height: 50dvh;
|
||||||
|
overflow: auto;
|
||||||
|
border-top: 1px solid var(--outline-color);
|
||||||
|
border-bottom: 1px solid var(--outline-color);
|
||||||
|
background-color: var(--bg-faded-color);
|
||||||
|
|
||||||
|
@media (min-width: 40em) {
|
||||||
|
background-color: var(--bg-color);
|
||||||
|
border-radius: 16px;
|
||||||
|
border-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
display: flex;
|
||||||
|
padding: 16px;
|
||||||
|
row-gap: 8px;
|
||||||
|
column-gap: 16px;
|
||||||
|
border-bottom: 1px solid var(--outline-color);
|
||||||
|
}
|
||||||
|
li:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.request-notifcations {
|
||||||
|
flex-grow: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
.last-post {
|
||||||
|
> .status-link {
|
||||||
|
border-radius: 8px;
|
||||||
|
overflow: hidden;
|
||||||
|
--max-height: 160px;
|
||||||
|
max-height: var(--max-height);
|
||||||
|
border: 1px solid var(--outline-color);
|
||||||
|
|
||||||
|
&:is(:hover, :focus-visible) {
|
||||||
|
border-color: var(--outline-hover-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.status {
|
||||||
|
mask-image: linear-gradient(
|
||||||
|
to bottom,
|
||||||
|
black calc(var(--max-height) / 2),
|
||||||
|
transparent calc(var(--max-height) - 8px)
|
||||||
|
);
|
||||||
|
font-size: calc(var(--text-size) * 0.9);
|
||||||
|
|
||||||
|
.content-container {
|
||||||
|
pointer-events: none;
|
||||||
|
filter: saturate(0.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.request-notifications-account {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-request-buttons {
|
||||||
|
grid-area: buttons;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
|
||||||
|
button {
|
||||||
|
max-width: 30vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-request-states {
|
||||||
|
min-height: 32px;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: middle;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
margin-inline: 8px;
|
||||||
|
|
||||||
|
&.notification-accepted {
|
||||||
|
color: var(--green-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.notification-dismissed {
|
||||||
|
color: var(--red-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -14,8 +14,10 @@ import FollowRequestButtons from '../components/follow-request-buttons';
|
||||||
import Icon from '../components/icon';
|
import Icon from '../components/icon';
|
||||||
import Link from '../components/link';
|
import Link from '../components/link';
|
||||||
import Loader from '../components/loader';
|
import Loader from '../components/loader';
|
||||||
|
import Modal from '../components/modal';
|
||||||
import NavMenu from '../components/nav-menu';
|
import NavMenu from '../components/nav-menu';
|
||||||
import Notification from '../components/notification';
|
import Notification from '../components/notification';
|
||||||
|
import Status from '../components/status';
|
||||||
import { api } from '../utils/api';
|
import { api } from '../utils/api';
|
||||||
import enhanceContent from '../utils/enhance-content';
|
import enhanceContent from '../utils/enhance-content';
|
||||||
import groupNotifications from '../utils/group-notifications';
|
import groupNotifications from '../utils/group-notifications';
|
||||||
|
@ -23,8 +25,10 @@ import handleContentLinks from '../utils/handle-content-links';
|
||||||
import niceDateTime from '../utils/nice-date-time';
|
import niceDateTime from '../utils/nice-date-time';
|
||||||
import { getRegistration } from '../utils/push-notifications';
|
import { getRegistration } from '../utils/push-notifications';
|
||||||
import shortenNumber from '../utils/shorten-number';
|
import shortenNumber from '../utils/shorten-number';
|
||||||
|
import showToast from '../utils/show-toast';
|
||||||
import states, { saveStatus } from '../utils/states';
|
import states, { saveStatus } from '../utils/states';
|
||||||
import { getCurrentInstance } from '../utils/store-utils';
|
import { getCurrentInstance } from '../utils/store-utils';
|
||||||
|
import supports from '../utils/supports';
|
||||||
import usePageVisibility from '../utils/usePageVisibility';
|
import usePageVisibility from '../utils/usePageVisibility';
|
||||||
import useScroll from '../utils/useScroll';
|
import useScroll from '../utils/useScroll';
|
||||||
import useTitle from '../utils/useTitle';
|
import useTitle from '../utils/useTitle';
|
||||||
|
@ -136,6 +140,28 @@ function Notifications({ columnMode }) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const supportsFilteredNotifications = supports(
|
||||||
|
'@mastodon/filtered-notifications',
|
||||||
|
);
|
||||||
|
const [showNotificationsSettings, setShowNotificationsSettings] =
|
||||||
|
useState(false);
|
||||||
|
const [notificationsPolicy, setNotificationsPolicy] = useState({});
|
||||||
|
function fetchNotificationsPolicy() {
|
||||||
|
return masto.v1.notifications.policy.fetch().catch(() => {});
|
||||||
|
}
|
||||||
|
function loadNotificationsPolicy() {
|
||||||
|
fetchNotificationsPolicy()
|
||||||
|
.then((policy) => {
|
||||||
|
console.log('✨ Notifications policy', policy);
|
||||||
|
setNotificationsPolicy(policy);
|
||||||
|
})
|
||||||
|
.catch(() => {});
|
||||||
|
}
|
||||||
|
const [notificationsRequests, setNotificationsRequests] = useState(null);
|
||||||
|
function fetchNotificationsRequest() {
|
||||||
|
return masto.v1.notifications.requests.list();
|
||||||
|
}
|
||||||
|
|
||||||
const loadNotifications = (firstLoad) => {
|
const loadNotifications = (firstLoad) => {
|
||||||
setShowNew(false);
|
setShowNew(false);
|
||||||
setUIState('loading');
|
setUIState('loading');
|
||||||
|
@ -161,6 +187,10 @@ function Notifications({ columnMode }) {
|
||||||
setFollowRequests(requests);
|
setFollowRequests(requests);
|
||||||
})
|
})
|
||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
|
|
||||||
|
if (supportsFilteredNotifications) {
|
||||||
|
loadNotificationsPolicy();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const { done } = await fetchNotificationsPromise;
|
const { done } = await fetchNotificationsPromise;
|
||||||
|
@ -384,7 +414,17 @@ function Notifications({ columnMode }) {
|
||||||
</div>
|
</div>
|
||||||
<h1>Notifications</h1>
|
<h1>Notifications</h1>
|
||||||
<div class="header-side">
|
<div class="header-side">
|
||||||
{/* <Loader hidden={uiState !== 'loading'} /> */}
|
{supportsFilteredNotifications && (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="button plain"
|
||||||
|
onClick={() => {
|
||||||
|
setShowNotificationsSettings(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Icon icon="settings" size="l" alt="Notifications settings" />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{showNew && uiState !== 'loading' && (
|
{showNew && uiState !== 'loading' && (
|
||||||
|
@ -489,6 +529,70 @@ function Notifications({ columnMode }) {
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{supportsFilteredNotifications &&
|
||||||
|
notificationsPolicy?.summary?.pendingRequestsCount > 0 && (
|
||||||
|
<div class="filtered-notifications">
|
||||||
|
<details
|
||||||
|
onToggle={async (e) => {
|
||||||
|
const { open } = e.target;
|
||||||
|
if (open) {
|
||||||
|
const requests = await fetchNotificationsRequest();
|
||||||
|
setNotificationsRequests(requests);
|
||||||
|
console.log({ open, requests });
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<summary>
|
||||||
|
Filtered notifications from{' '}
|
||||||
|
{notificationsPolicy.summary.pendingRequestsCount} people
|
||||||
|
</summary>
|
||||||
|
{!notificationsRequests ? (
|
||||||
|
<p class="ui-state">
|
||||||
|
<Loader abrupt />
|
||||||
|
</p>
|
||||||
|
) : (
|
||||||
|
notificationsRequests?.length > 0 && (
|
||||||
|
<ul>
|
||||||
|
{notificationsRequests.map((request) => (
|
||||||
|
<li key={request.id}>
|
||||||
|
<div class="request-notifcations">
|
||||||
|
{!request.lastStatus?.id && (
|
||||||
|
<AccountBlock
|
||||||
|
useAvatarStatic
|
||||||
|
showStats
|
||||||
|
account={request.account}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{request.lastStatus?.id && (
|
||||||
|
<div class="last-post">
|
||||||
|
<Link
|
||||||
|
class="status-link"
|
||||||
|
to={`/${instance}/s/${request.lastStatus.id}`}
|
||||||
|
>
|
||||||
|
<Status
|
||||||
|
status={request.lastStatus}
|
||||||
|
size="s"
|
||||||
|
readOnly
|
||||||
|
/>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<NotificationRequestModalButton request={request} />
|
||||||
|
</div>
|
||||||
|
<NotificationRequestButtons
|
||||||
|
request={request}
|
||||||
|
onChange={() => {
|
||||||
|
loadNotifications(true);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</details>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<div id="mentions-option">
|
<div id="mentions-option">
|
||||||
<label>
|
<label>
|
||||||
<input
|
<input
|
||||||
|
@ -597,6 +701,109 @@ function Notifications({ columnMode }) {
|
||||||
</InView>
|
</InView>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
{supportsFilteredNotifications && showNotificationsSettings && (
|
||||||
|
<Modal
|
||||||
|
onClick={(e) => {
|
||||||
|
if (e.target === e.currentTarget) {
|
||||||
|
setShowNotificationsSettings(false);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div class="sheet" tabIndex="-1">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="sheet-close"
|
||||||
|
onClick={() => setShowNotificationsSettings(false)}
|
||||||
|
>
|
||||||
|
<Icon icon="x" />
|
||||||
|
</button>
|
||||||
|
<header>
|
||||||
|
<h2>Notifications settings</h2>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<form
|
||||||
|
onSubmit={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const {
|
||||||
|
filterNotFollowing,
|
||||||
|
filterNotFollowers,
|
||||||
|
filterNewAccounts,
|
||||||
|
filterPrivateMentions,
|
||||||
|
} = e.target;
|
||||||
|
const allFilters = {
|
||||||
|
filterNotFollowing: filterNotFollowing.checked,
|
||||||
|
filterNotFollowers: filterNotFollowers.checked,
|
||||||
|
filterNewAccounts: filterNewAccounts.checked,
|
||||||
|
filterPrivateMentions: filterPrivateMentions.checked,
|
||||||
|
};
|
||||||
|
setNotificationsPolicy({
|
||||||
|
...notificationsPolicy,
|
||||||
|
...allFilters,
|
||||||
|
});
|
||||||
|
setShowNotificationsSettings(false);
|
||||||
|
(async () => {
|
||||||
|
try {
|
||||||
|
await masto.v1.notifications.policy.update(allFilters);
|
||||||
|
showToast('Notifications settings updated');
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<p>Filter out notifications from people:</p>
|
||||||
|
<p>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
switch
|
||||||
|
defaultChecked={notificationsPolicy.filterNotFollowing}
|
||||||
|
name="filterNotFollowing"
|
||||||
|
/>{' '}
|
||||||
|
You don't follow
|
||||||
|
</label>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
switch
|
||||||
|
defaultChecked={notificationsPolicy.filterNotFollowers}
|
||||||
|
name="filterNotFollowers"
|
||||||
|
/>{' '}
|
||||||
|
Who don't follow you
|
||||||
|
</label>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
switch
|
||||||
|
defaultChecked={notificationsPolicy.filterNewAccounts}
|
||||||
|
name="filterNewAccounts"
|
||||||
|
/>{' '}
|
||||||
|
With a new account
|
||||||
|
</label>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
switch
|
||||||
|
defaultChecked={notificationsPolicy.filterPrivateMentions}
|
||||||
|
name="filterPrivateMentions"
|
||||||
|
/>{' '}
|
||||||
|
Who unsolicitedly private mention you
|
||||||
|
</label>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<button type="submit">Save</button>
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -679,4 +886,186 @@ function AnnouncementBlock({ announcement }) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function fetchNotficationsByAccount(accountID) {
|
||||||
|
const { masto } = api();
|
||||||
|
return masto.v1.notifications.list({
|
||||||
|
accountID,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function NotificationRequestModalButton({ request }) {
|
||||||
|
const { instance } = api();
|
||||||
|
const [uiState, setUIState] = useState('loading');
|
||||||
|
const { account, lastStatus } = request;
|
||||||
|
const [showModal, setShowModal] = useState(false);
|
||||||
|
const [notifications, setNotifications] = useState([]);
|
||||||
|
|
||||||
|
function onClose() {
|
||||||
|
setShowModal(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!request?.account?.id) return;
|
||||||
|
if (!showModal) return;
|
||||||
|
setUIState('loading');
|
||||||
|
(async () => {
|
||||||
|
const notifs = await fetchNotficationsByAccount(request.account.id);
|
||||||
|
setNotifications(notifs || []);
|
||||||
|
setUIState('default');
|
||||||
|
})();
|
||||||
|
}, [showModal, request?.account?.id]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="plain4 request-notifications-account"
|
||||||
|
onClick={() => {
|
||||||
|
setShowModal(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Icon icon="notification" class="more-insignificant" />{' '}
|
||||||
|
<small>View notifications from @{account.username}</small>{' '}
|
||||||
|
<Icon icon="chevron-down" />
|
||||||
|
</button>
|
||||||
|
{showModal && (
|
||||||
|
<Modal
|
||||||
|
onClick={(e) => {
|
||||||
|
if (e.target === e.currentTarget) {
|
||||||
|
onClose();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div class="sheet" tabIndex="-1">
|
||||||
|
<button type="button" class="sheet-close" onClick={onClose}>
|
||||||
|
<Icon icon="x" />
|
||||||
|
</button>
|
||||||
|
<header>
|
||||||
|
<b>Notifications from @{account.username}</b>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
{uiState === 'loading' ? (
|
||||||
|
<p class="ui-state">
|
||||||
|
<Loader abrupt />
|
||||||
|
</p>
|
||||||
|
) : (
|
||||||
|
notifications.map((notification) => (
|
||||||
|
<div
|
||||||
|
class="notification-peek"
|
||||||
|
onClick={(e) => {
|
||||||
|
const { target } = e;
|
||||||
|
// If button or links
|
||||||
|
if (
|
||||||
|
e.target.tagName === 'BUTTON' ||
|
||||||
|
e.target.tagName === 'A'
|
||||||
|
) {
|
||||||
|
onClose();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Notification
|
||||||
|
instance={instance}
|
||||||
|
notification={notification}
|
||||||
|
isStatic
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function NotificationRequestButtons({ request, onChange }) {
|
||||||
|
const { masto } = api();
|
||||||
|
const [uiState, setUIState] = useState('default');
|
||||||
|
const [requestState, setRequestState] = useState(null); // accept, dismiss
|
||||||
|
const hasRequestState = requestState !== null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<p class="notification-request-buttons">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
disabled={uiState === 'loading' || hasRequestState}
|
||||||
|
onClick={() => {
|
||||||
|
setUIState('loading');
|
||||||
|
(async () => {
|
||||||
|
try {
|
||||||
|
await masto.v1.notifications.requests
|
||||||
|
.$select(request.id)
|
||||||
|
.accept();
|
||||||
|
setRequestState('accept');
|
||||||
|
setUIState('default');
|
||||||
|
onChange({
|
||||||
|
request,
|
||||||
|
state: 'accept',
|
||||||
|
});
|
||||||
|
showToast(
|
||||||
|
`Notifications from @${request.account.username} will not be filtered from now on.`,
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
setUIState('error');
|
||||||
|
console.error(error);
|
||||||
|
showToast(`Unable to accept notification request`);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Allow
|
||||||
|
</button>{' '}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
disabled={uiState === 'loading' || hasRequestState}
|
||||||
|
class="light danger"
|
||||||
|
onClick={() => {
|
||||||
|
setUIState('loading');
|
||||||
|
(async () => {
|
||||||
|
try {
|
||||||
|
await masto.v1.notifications.requests
|
||||||
|
.$select(request.id)
|
||||||
|
.dismiss();
|
||||||
|
setRequestState('dismiss');
|
||||||
|
setUIState('default');
|
||||||
|
onChange({
|
||||||
|
request,
|
||||||
|
state: 'dismiss',
|
||||||
|
});
|
||||||
|
showToast(
|
||||||
|
`Notifications from @${request.account.username} will not show up in Filtered notifications from now on.`,
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
setUIState('error');
|
||||||
|
console.error(error);
|
||||||
|
showToast(`Unable to dismiss notification request`);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Dismiss
|
||||||
|
</button>
|
||||||
|
<span class="notification-request-states">
|
||||||
|
{uiState === 'loading' ? (
|
||||||
|
<Loader abrupt />
|
||||||
|
) : requestState === 'accept' ? (
|
||||||
|
<Icon
|
||||||
|
icon="check-circle"
|
||||||
|
alt="Accepted"
|
||||||
|
class="notification-accepted"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
requestState === 'dismiss' && (
|
||||||
|
<Icon
|
||||||
|
icon="x-circle"
|
||||||
|
alt="Dismissed"
|
||||||
|
class="notification-dismissed"
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export default memo(Notifications);
|
export default memo(Notifications);
|
||||||
|
|
Loading…
Reference in a new issue