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

Commit1593861

Browse files
feat: add load more notifications on inbox (#17030)
Users need to see older notifications, so to make that happen, we addeda load more button at the end of the notifications list.**Demo:**https://github.com/user-attachments/assets/bd3d7964-a8f5-4164-8da0-9ba89ae88c9c**What is missing?**As you can notice, I didn't add tests for this feature. I tried, but Ididn't find a good solution for testing scroll events. However I wasable to get it working, but it was too cumbersome that I decided toremove because of its maintenence burden.
1 parent82e3773 commit1593861

File tree

4 files changed

+76
-11
lines changed

4 files changed

+76
-11
lines changed

‎site/src/api/api.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2434,9 +2434,13 @@ class ApiMethods {
24342434
returnres.data;
24352435
};
24362436

2437-
getInboxNotifications=async()=>{
2437+
getInboxNotifications=async(startingBeforeId?:string)=>{
2438+
constparams=newURLSearchParams();
2439+
if(startingBeforeId){
2440+
params.append("starting_before",startingBeforeId);
2441+
}
24382442
constres=awaitthis.axios.get<TypesGen.ListInboxNotificationsResponse>(
2439-
"/api/v2/notifications/inbox",
2443+
`/api/v2/notifications/inbox?${params.toString()}`,
24402444
);
24412445
returnres.data;
24422446
};

‎site/src/components/ScrollArea/ScrollArea.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export const ScrollArea = React.forwardRef<
1818
<ScrollAreaPrimitive.ViewportclassName="h-full w-full rounded-[inherit]">
1919
{children}
2020
</ScrollAreaPrimitive.Viewport>
21-
<ScrollBar/>
21+
<ScrollBarclassName="z-10"/>
2222
<ScrollAreaPrimitive.Corner/>
2323
</ScrollAreaPrimitive.Root>
2424
));

‎site/src/modules/notifications/NotificationsInbox/InboxPopover.tsx

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,12 @@ type InboxPopoverProps = {
1919
notifications:readonlyInboxNotification[]|undefined;
2020
unreadCount:number;
2121
error:unknown;
22+
isLoadingMoreNotifications:boolean;
23+
hasMoreNotifications:boolean;
2224
onRetry:()=>void;
2325
onMarkAllAsRead:()=>void;
2426
onMarkNotificationAsRead:(notificationId:string)=>void;
27+
onLoadMoreNotifications:()=>void;
2528
defaultOpen?:boolean;
2629
};
2730

@@ -30,9 +33,12 @@ export const InboxPopover: FC<InboxPopoverProps> = ({
3033
unreadCount,
3134
notifications,
3235
error,
36+
isLoadingMoreNotifications,
37+
hasMoreNotifications,
3338
onRetry,
3439
onMarkAllAsRead,
3540
onMarkNotificationAsRead,
41+
onLoadMoreNotifications,
3642
})=>{
3743
const[isOpen,setIsOpen]=useState(defaultOpen);
3844

@@ -41,12 +47,21 @@ export const InboxPopover: FC<InboxPopoverProps> = ({
4147
<PopoverTriggerasChild>
4248
<InboxButtonunreadCount={unreadCount}/>
4349
</PopoverTrigger>
44-
<PopoverContentclassName="w-[466px]"align="end">
50+
<PopoverContent
51+
className="w-[var(--radix-popper-available-width)] max-w-[466px]"
52+
align="end"
53+
>
4554
{/*
4655
* data-radix-scroll-area-viewport is used to set the max-height of the ScrollArea
4756
* https://github.com/shadcn-ui/ui/issues/542#issuecomment-2339361283
4857
*/}
49-
<ScrollAreaclassName="[&>[data-radix-scroll-area-viewport]]:max-h-[calc(var(--radix-popover-content-available-height)-24px)]">
58+
<ScrollArea
59+
className={cn([
60+
"[--bottom-offset:48px]",
61+
"[--max-height:calc(var(--radix-popover-content-available-height)-var(--bottom-offset))]",
62+
"[&>[data-radix-scroll-area-viewport]]:max-h-[var(--max-height)]",
63+
])}
64+
>
5065
<div
5166
className={cn([
5267
"flex items-center justify-between p-3 border-0 border-b border-solid border-border",
@@ -94,6 +109,18 @@ export const InboxPopover: FC<InboxPopoverProps> = ({
94109
onMarkNotificationAsRead={onMarkNotificationAsRead}
95110
/>
96111
))}
112+
{hasMoreNotifications&&(
113+
<Button
114+
variant="subtle"
115+
size="sm"
116+
disabled={isLoadingMoreNotifications}
117+
onClick={onLoadMoreNotifications}
118+
className="w-full"
119+
>
120+
<Spinnerloading={isLoadingMoreNotifications}size="sm"/>
121+
Load more
122+
</Button>
123+
)}
97124
</div>
98125
) :(
99126
<divclassName="p-6 flex items-center justify-center min-h-48">

‎site/src/modules/notifications/NotificationsInbox/NotificationsInbox.tsx

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import{API,watchInboxNotifications}from"api/api";
1+
import{watchInboxNotifications}from"api/api";
22
import{getErrorDetail,getErrorMessage}from"api/errors";
33
importtype{
44
ListInboxNotificationsResponse,
@@ -11,10 +11,13 @@ import { useMutation, useQuery, useQueryClient } from "react-query";
1111
import{InboxPopover}from"./InboxPopover";
1212

1313
constNOTIFICATIONS_QUERY_KEY=["notifications"];
14+
constNOTIFICATIONS_LIMIT=25;// This is hard set in the API
1415

1516
typeNotificationsInboxProps={
1617
defaultOpen?:boolean;
17-
fetchNotifications:()=>Promise<ListInboxNotificationsResponse>;
18+
fetchNotifications:(
19+
startingBeforeId?:string,
20+
)=>Promise<ListInboxNotificationsResponse>;
1821
markAllAsRead:()=>Promise<void>;
1922
markNotificationAsRead:(
2023
notificationId:string,
@@ -30,12 +33,12 @@ export const NotificationsInbox: FC<NotificationsInboxProps> = ({
3033
constqueryClient=useQueryClient();
3134

3235
const{
33-
data:res,
36+
data:inboxRes,
3437
error,
3538
refetch,
3639
}=useQuery({
3740
queryKey:NOTIFICATIONS_QUERY_KEY,
38-
queryFn:fetchNotifications,
41+
queryFn:()=>fetchNotifications(),
3942
});
4043

4144
constupdateNotificationsCache=useEffectEvent(
@@ -75,6 +78,32 @@ export const NotificationsInbox: FC<NotificationsInboxProps> = ({
7578
};
7679
},[updateNotificationsCache]);
7780

81+
const{
82+
mutate:loadMoreNotifications,
83+
isLoading:isLoadingMoreNotifications,
84+
}=useMutation({
85+
mutationFn:async()=>{
86+
if(!inboxRes||inboxRes.notifications.length===0){
87+
return;
88+
}
89+
constlastNotification=
90+
inboxRes.notifications[inboxRes.notifications.length-1];
91+
constnewRes=awaitfetchNotifications(lastNotification.id);
92+
updateNotificationsCache((prev)=>{
93+
return{
94+
unread_count:newRes.unread_count,
95+
notifications:[...prev.notifications, ...newRes.notifications],
96+
};
97+
});
98+
},
99+
onError:(error)=>{
100+
displayError(
101+
getErrorMessage(error,"Error loading more notifications"),
102+
getErrorDetail(error),
103+
);
104+
},
105+
});
106+
78107
constmarkAllAsReadMutation=useMutation({
79108
mutationFn:markAllAsRead,
80109
onSuccess:()=>{
@@ -122,12 +151,17 @@ export const NotificationsInbox: FC<NotificationsInboxProps> = ({
122151
return(
123152
<InboxPopover
124153
defaultOpen={defaultOpen}
125-
notifications={res?.notifications}
126-
unreadCount={res?.unread_count??0}
154+
notifications={inboxRes?.notifications}
155+
unreadCount={inboxRes?.unread_count??0}
127156
error={error}
157+
isLoadingMoreNotifications={isLoadingMoreNotifications}
158+
hasMoreNotifications={Boolean(
159+
inboxRes&&inboxRes.notifications.length===NOTIFICATIONS_LIMIT,
160+
)}
128161
onRetry={refetch}
129162
onMarkAllAsRead={markAllAsReadMutation.mutate}
130163
onMarkNotificationAsRead={markNotificationAsReadMutation.mutate}
164+
onLoadMoreNotifications={loadMoreNotifications}
131165
/>
132166
);
133167
};

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp