Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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 deletions site/src/api/api.ts
Original file line number Diff line number Diff 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 deletion site/src/components/ScrollArea/ScrollArea.tsx
Original file line number Diff line number Diff 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 />
<ScrollBar className="z-10" />
Copy link
Collaborator Author

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
Original file line number Diff line number Diff 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
Collaborator Author

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
Collaborator Author

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 Down Expand 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
Original file line number Diff line number Diff 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 Down Expand 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 that notifications isn't empty. Otherwise, lastNotification.id will throw an error on the next line

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
Collaborator Author

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 the useInfiniteQuery and its pages abstraction. Mostly when trying to update the previous query data.

const markAllAsReadMutation = useMutation({
mutationFn: markAllAsRead,
onSuccess: () => {
Expand Down Expand 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
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy