mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-09-22 19:53:48 +08:00
fix(core): fix notification list (#11423)
This commit is contained in:
@@ -138,3 +138,11 @@ export const itemNameLabelIcon = style({
|
|||||||
marginRight: '4px',
|
marginRight: '4px',
|
||||||
color: cssVarV2('icon/primary'),
|
color: cssVarV2('icon/primary'),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const loadMoreIndicator = style({
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
height: '24px',
|
||||||
|
color: cssVarV2('text/secondary'),
|
||||||
|
});
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import {
|
|||||||
Button,
|
Button,
|
||||||
IconButton,
|
IconButton,
|
||||||
notify,
|
notify,
|
||||||
|
observeIntersection,
|
||||||
Scrollable,
|
Scrollable,
|
||||||
Skeleton,
|
Skeleton,
|
||||||
} from '@affine/component';
|
} from '@affine/component';
|
||||||
@@ -35,47 +36,53 @@ import {
|
|||||||
} from '@blocksuite/icons/rc';
|
} from '@blocksuite/icons/rc';
|
||||||
import { useLiveData, useService } from '@toeverything/infra';
|
import { useLiveData, useService } from '@toeverything/infra';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
import {
|
||||||
|
useCallback,
|
||||||
|
useEffect,
|
||||||
|
useLayoutEffect,
|
||||||
|
useMemo,
|
||||||
|
useRef,
|
||||||
|
useState,
|
||||||
|
} from 'react';
|
||||||
|
|
||||||
import { useNavigateHelper } from '../hooks/use-navigate-helper';
|
import { useNavigateHelper } from '../hooks/use-navigate-helper';
|
||||||
import * as styles from './list.style.css';
|
import * as styles from './list.style.css';
|
||||||
|
|
||||||
export const NotificationList = () => {
|
export const NotificationList = () => {
|
||||||
|
const t = useI18n();
|
||||||
const notificationListService = useService(NotificationListService);
|
const notificationListService = useService(NotificationListService);
|
||||||
const notifications = useLiveData(notificationListService.notifications$);
|
const notifications = useLiveData(notificationListService.notifications$);
|
||||||
const isLoading = useLiveData(notificationListService.isLoading$);
|
const isLoading = useLiveData(notificationListService.isLoading$);
|
||||||
const error = useLiveData(notificationListService.error$);
|
const error = useLiveData(notificationListService.error$);
|
||||||
|
const hasMore = useLiveData(notificationListService.hasMore$);
|
||||||
|
const loadMoreIndicatorRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const userFriendlyError = useMemo(() => {
|
const userFriendlyError = useMemo(() => {
|
||||||
return error && UserFriendlyError.fromAny(error);
|
return error && UserFriendlyError.fromAny(error);
|
||||||
}, [error]);
|
}, [error]);
|
||||||
|
|
||||||
useEffect(() => {
|
useLayoutEffect(() => {
|
||||||
// reset the notification list when the component is mounted
|
// reset the notification list when the component is mounted
|
||||||
notificationListService.reset();
|
notificationListService.reset();
|
||||||
notificationListService.loadMore();
|
notificationListService.loadMore();
|
||||||
}, [notificationListService]);
|
}, [notificationListService]);
|
||||||
|
|
||||||
const handleScrollEnd = useCallback(() => {
|
useEffect(() => {
|
||||||
notificationListService.loadMore();
|
if (loadMoreIndicatorRef.current) {
|
||||||
}, [notificationListService]);
|
let previousIsIntersecting = false;
|
||||||
|
return observeIntersection(loadMoreIndicatorRef.current, entity => {
|
||||||
const handleScroll = useCallback(
|
if (entity.isIntersecting && !previousIsIntersecting && hasMore) {
|
||||||
(e: React.UIEvent<HTMLDivElement>) => {
|
notificationListService.loadMore();
|
||||||
const target = e.currentTarget;
|
}
|
||||||
if (target.scrollHeight - target.scrollTop <= target.clientHeight + 1) {
|
previousIsIntersecting = entity.isIntersecting;
|
||||||
handleScrollEnd();
|
});
|
||||||
}
|
}
|
||||||
},
|
return;
|
||||||
[handleScrollEnd]
|
}, [hasMore, notificationListService]);
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Scrollable.Root>
|
<Scrollable.Root>
|
||||||
<Scrollable.Viewport
|
<Scrollable.Viewport className={styles.containerScrollViewport}>
|
||||||
className={styles.containerScrollViewport}
|
|
||||||
onScroll={handleScroll}
|
|
||||||
>
|
|
||||||
{notifications.length > 0 ? (
|
{notifications.length > 0 ? (
|
||||||
<ul className={styles.itemList}>
|
<ul className={styles.itemList}>
|
||||||
{notifications.map(notification => (
|
{notifications.map(notification => (
|
||||||
@@ -94,6 +101,13 @@ export const NotificationList = () => {
|
|||||||
) : (
|
) : (
|
||||||
<NotificationListEmpty />
|
<NotificationListEmpty />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
<div
|
||||||
|
ref={loadMoreIndicatorRef}
|
||||||
|
className={hasMore ? styles.loadMoreIndicator : ''}
|
||||||
|
>
|
||||||
|
{hasMore ? t['com.affine.notification.loading-more']() : null}
|
||||||
|
</div>
|
||||||
</Scrollable.Viewport>
|
</Scrollable.Viewport>
|
||||||
<Scrollable.Scrollbar />
|
<Scrollable.Scrollbar />
|
||||||
</Scrollable.Root>
|
</Scrollable.Root>
|
||||||
|
|||||||
@@ -7229,6 +7229,10 @@ export function useAFFiNEI18N(): {
|
|||||||
* `No new notifications`
|
* `No new notifications`
|
||||||
*/
|
*/
|
||||||
["com.affine.notification.empty"](): string;
|
["com.affine.notification.empty"](): string;
|
||||||
|
/**
|
||||||
|
* `Loading more...`
|
||||||
|
*/
|
||||||
|
["com.affine.notification.loading-more"](): string;
|
||||||
/**
|
/**
|
||||||
* `You'll be notified here for @mentions and workspace invites.`
|
* `You'll be notified here for @mentions and workspace invites.`
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1797,6 +1797,7 @@
|
|||||||
"com.affine.notification.unsupported": "Unsupported message",
|
"com.affine.notification.unsupported": "Unsupported message",
|
||||||
"com.affine.notification.mention": "<1>{{username}}</1> mentioned you in <2>{{docTitle}}</2>",
|
"com.affine.notification.mention": "<1>{{username}}</1> mentioned you in <2>{{docTitle}}</2>",
|
||||||
"com.affine.notification.empty": "No new notifications",
|
"com.affine.notification.empty": "No new notifications",
|
||||||
|
"com.affine.notification.loading-more": "Loading more...",
|
||||||
"com.affine.notification.empty.description": "You'll be notified here for @mentions and workspace invites.",
|
"com.affine.notification.empty.description": "You'll be notified here for @mentions and workspace invites.",
|
||||||
"com.affine.notification.invitation-accepted": "<1>{{username}}</1> has accept your invitation",
|
"com.affine.notification.invitation-accepted": "<1>{{username}}</1> has accept your invitation",
|
||||||
"com.affine.notification.invitation-review-request": "<1>{{username}}</1> has requested to join <2>{{workspaceName}}</2>",
|
"com.affine.notification.invitation-review-request": "<1>{{username}}</1> has requested to join <2>{{workspaceName}}</2>",
|
||||||
|
|||||||
Reference in New Issue
Block a user