Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

feat: add load more notifications on inbox#17030

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
BrunoQuaresma merged 3 commits intomainfrombq/infinite-scroll-inbox
Mar 21, 2025
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletionssite/src/api/api.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -2434,9 +2434,13 @@ class ApiMethods {
return res.data;
};

getInboxNotifications = async () => {
getInboxNotifications = async (startingBeforeId?: string) => {
const params = new URLSearchParams();
if (startingBeforeId) {
params.append("starting_before", startingBeforeId);
}
const res = await this.axios.get<TypesGen.ListInboxNotificationsResponse>(
"/api/v2/notifications/inbox",
`/api/v2/notifications/inbox?${params.toString()}`,
);
return res.data;
};
Expand Down
2 changes: 1 addition & 1 deletionsite/src/components/ScrollArea/ScrollArea.tsx
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -18,7 +18,7 @@ export const ScrollArea = React.forwardRef<
<ScrollAreaPrimitive.Viewport className="h-full w-full rounded-[inherit]">
{children}
</ScrollAreaPrimitive.Viewport>
<ScrollBar />
<ScrollBarclassName="z-10"/>
Copy link
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

It was getting behind the sticky header.

<ScrollAreaPrimitive.Corner />
</ScrollAreaPrimitive.Root>
));
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,9 +19,12 @@ type InboxPopoverProps = {
notifications: readonly InboxNotification[] | undefined;
unreadCount: number;
error: unknown;
isLoadingMoreNotifications: boolean;
hasMoreNotifications: boolean;
onRetry: () => void;
onMarkAllAsRead: () => void;
onMarkNotificationAsRead: (notificationId: string) => void;
onLoadMoreNotifications: () => void;
defaultOpen?: boolean;
};

Expand All@@ -30,9 +33,12 @@ export const InboxPopover: FC<InboxPopoverProps> = ({
unreadCount,
notifications,
error,
isLoadingMoreNotifications,
hasMoreNotifications,
onRetry,
onMarkAllAsRead,
onMarkNotificationAsRead,
onLoadMoreNotifications,
}) => {
const [isOpen, setIsOpen] = useState(defaultOpen);

Expand All@@ -41,12 +47,21 @@ export const InboxPopover: FC<InboxPopoverProps> = ({
<PopoverTrigger asChild>
<InboxButton unreadCount={unreadCount} />
</PopoverTrigger>
<PopoverContent className="w-[466px]" align="end">
<PopoverContent
className="w-[var(--radix-popper-available-width)] max-w-[466px]"
align="end"
>
{/*
* data-radix-scroll-area-viewport is used to set the max-height of the ScrollArea
* https://github.com/shadcn-ui/ui/issues/542#issuecomment-2339361283
*/}
<ScrollArea className="[&>[data-radix-scroll-area-viewport]]:max-h-[calc(var(--radix-popover-content-available-height)-24px)]">
<ScrollArea
className={cn([
"[--bottom-offset:48px]",
"[--max-height:calc(var(--radix-popover-content-available-height)-var(--bottom-offset))]",
"[&>[data-radix-scroll-area-viewport]]:max-h-[var(--max-height)]",
Copy link
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Tried to make it easier to read the classes and reasoning about their values.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Do you know what happens if the result of--max-height falls below 0? We're always subtracting 48 no matter what, so I don't know if it makes sense to do a CSS clamp to make sure it can't fall below 0

Copy link
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

To make that happen, the screen height would be 48px or less than that. Since this is not a real scenario, even it is possible, I think it is ok to not care about that. Makes sense?

])}
>
<div
className={cn([
"flex items-center justify-between p-3 border-0 border-b border-solid border-border",
Expand DownExpand Up@@ -94,6 +109,18 @@ export const InboxPopover: FC<InboxPopoverProps> = ({
onMarkNotificationAsRead={onMarkNotificationAsRead}
/>
))}
{hasMoreNotifications && (
<Button
variant="subtle"
size="sm"
disabled={isLoadingMoreNotifications}
onClick={onLoadMoreNotifications}
className="w-full"
>
<Spinner loading={isLoadingMoreNotifications} size="sm" />
Load more
</Button>
)}
</div>
) : (
<div className="p-6 flex items-center justify-center min-h-48">
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
import {API,watchInboxNotifications } from "api/api";
import { watchInboxNotifications } from "api/api";
import { getErrorDetail, getErrorMessage } from "api/errors";
import type {
ListInboxNotificationsResponse,
Expand All@@ -11,10 +11,13 @@ import { useMutation, useQuery, useQueryClient } from "react-query";
import { InboxPopover } from "./InboxPopover";

const NOTIFICATIONS_QUERY_KEY = ["notifications"];
const NOTIFICATIONS_LIMIT = 25; // This is hard set in the API

type NotificationsInboxProps = {
defaultOpen?: boolean;
fetchNotifications: () => Promise<ListInboxNotificationsResponse>;
fetchNotifications: (
startingBeforeId?: string,
) => Promise<ListInboxNotificationsResponse>;
markAllAsRead: () => Promise<void>;
markNotificationAsRead: (
notificationId: string,
Expand All@@ -30,12 +33,12 @@ export const NotificationsInbox: FC<NotificationsInboxProps> = ({
const queryClient = useQueryClient();

const {
data:res,
data:inboxRes,
error,
refetch,
} = useQuery({
queryKey: NOTIFICATIONS_QUERY_KEY,
queryFn: fetchNotifications,
queryFn:() =>fetchNotifications(),
});

const updateNotificationsCache = useEffectEvent(
Expand DownExpand Up@@ -75,6 +78,32 @@ export const NotificationsInbox: FC<NotificationsInboxProps> = ({
};
}, [updateNotificationsCache]);

const {
mutate: loadMoreNotifications,
isLoading: isLoadingMoreNotifications,
} = useMutation({
mutationFn: async () => {
if (!inboxRes || inboxRes.notifications.length === 0) {
return;
}
const lastNotification =
inboxRes.notifications[inboxRes.notifications.length - 1];
const newRes = await fetchNotifications(lastNotification.id);
Comment on lines +89 to +90
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

We want to make sure thatnotifications isn't empty. Otherwise,lastNotification.id will throw an error on the next line

BrunoQuaresma reacted with thumbs up emoji
updateNotificationsCache((prev) => {
return {
unread_count: newRes.unread_count,
notifications: [...prev.notifications, ...newRes.notifications],
};
});
},
onError: (error) => {
displayError(
getErrorMessage(error, "Error loading more notifications"),
getErrorDetail(error),
);
},
});

Copy link
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I just found way easier to use a mutation to update the data than use theuseInfiniteQuery and its pages abstraction. Mostly when trying to update the previous query data.

const markAllAsReadMutation = useMutation({
mutationFn: markAllAsRead,
onSuccess: () => {
Expand DownExpand Up@@ -122,12 +151,17 @@ export const NotificationsInbox: FC<NotificationsInboxProps> = ({
return (
<InboxPopover
defaultOpen={defaultOpen}
notifications={res?.notifications}
unreadCount={res?.unread_count ?? 0}
notifications={inboxRes?.notifications}
unreadCount={inboxRes?.unread_count ?? 0}
error={error}
isLoadingMoreNotifications={isLoadingMoreNotifications}
hasMoreNotifications={Boolean(
inboxRes && inboxRes.notifications.length === NOTIFICATIONS_LIMIT,
)}
onRetry={refetch}
onMarkAllAsRead={markAllAsReadMutation.mutate}
onMarkNotificationAsRead={markNotificationAsReadMutation.mutate}
onLoadMoreNotifications={loadMoreNotifications}
/>
);
};
Loading

[8]ページ先頭

©2009-2025 Movatter.jp