mirror of
https://github.com/docmost/docmost.git
synced 2026-05-20 08:34:04 +08:00
feat: group notifications
This commit is contained in:
@@ -690,6 +690,8 @@
|
||||
"Get notified when your comment is resolved.": "Get notified when your comment is resolved.",
|
||||
"You are now watching this page": "You are now watching this page",
|
||||
"You are no longer watching this page": "You are no longer watching this page",
|
||||
"Direct": "Direct",
|
||||
"Updates": "Updates",
|
||||
"Today": "Today",
|
||||
"Yesterday": "Yesterday",
|
||||
"This week": "This week",
|
||||
|
||||
@@ -294,6 +294,7 @@ const MentionList = forwardRef<any, MentionListProps>((props, ref) => {
|
||||
w={popupWidth}
|
||||
scrollbars={"y"}
|
||||
scrollbarSize={6}
|
||||
overscrollBehavior={"contain"}
|
||||
styles={{ content: { minWidth: 0 } }}
|
||||
>
|
||||
{renderItems?.map((item, index) => {
|
||||
|
||||
@@ -87,7 +87,13 @@ const CommandList = ({
|
||||
|
||||
return flatItems.length > 0 ? (
|
||||
<Paper id="slash-command" shadow="md" p="xs" withBorder>
|
||||
<ScrollArea viewportRef={viewportRef} h={350} w={270} scrollbarSize={8}>
|
||||
<ScrollArea
|
||||
viewportRef={viewportRef}
|
||||
h={350}
|
||||
w={270}
|
||||
scrollbarSize={8}
|
||||
overscrollBehavior="contain"
|
||||
>
|
||||
{Object.entries(items).map(([category, categoryItems]) => (
|
||||
<div key={category}>
|
||||
<Text c="dimmed" mb={4} fw={500} tt="capitalize">
|
||||
@@ -103,10 +109,7 @@ const CommandList = ({
|
||||
})}
|
||||
>
|
||||
<Group>
|
||||
<ActionIcon
|
||||
variant="default"
|
||||
component="div"
|
||||
>
|
||||
<ActionIcon variant="default" component="div">
|
||||
<item.icon size={18} />
|
||||
</ActionIcon>
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ const renderItems = () => {
|
||||
getReferenceClientRect = props.clientRect;
|
||||
|
||||
popup = document.createElement("div");
|
||||
popup.style.zIndex = "9999";
|
||||
popup.style.zIndex = "199";
|
||||
popup.style.position = "absolute";
|
||||
popup.style.top = "0";
|
||||
popup.style.left = "0";
|
||||
|
||||
@@ -77,6 +77,7 @@ export function NotificationItem({
|
||||
};
|
||||
|
||||
const handleMarkRead = (e: React.MouseEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
markReadIfNeeded();
|
||||
};
|
||||
|
||||
@@ -3,17 +3,23 @@ import { IconBellOff } from "@tabler/icons-react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useEffect, useRef } from "react";
|
||||
import { NotificationItem } from "./notification-item";
|
||||
import { INotification, NotificationFilter } from "../types/notification.types";
|
||||
import {
|
||||
INotification,
|
||||
NotificationFilter,
|
||||
NotificationTab,
|
||||
} from "../types/notification.types";
|
||||
import { groupNotificationsByTime } from "../notification.utils";
|
||||
import { useNotificationsQuery } from "../queries/notification-query";
|
||||
import classes from "../notification.module.css";
|
||||
|
||||
type NotificationListProps = {
|
||||
tab: NotificationTab;
|
||||
filter: NotificationFilter;
|
||||
onNavigate: () => void;
|
||||
};
|
||||
|
||||
export function NotificationList({
|
||||
tab,
|
||||
filter,
|
||||
onNavigate,
|
||||
}: NotificationListProps) {
|
||||
@@ -24,7 +30,7 @@ export function NotificationList({
|
||||
hasNextPage,
|
||||
fetchNextPage,
|
||||
isFetchingNextPage,
|
||||
} = useNotificationsQuery();
|
||||
} = useNotificationsQuery(tab as string);
|
||||
|
||||
const sentinelRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
Menu,
|
||||
Popover,
|
||||
ScrollArea,
|
||||
Tabs,
|
||||
Text,
|
||||
Tooltip,
|
||||
} from "@mantine/core";
|
||||
@@ -18,15 +19,20 @@ import {
|
||||
} from "@tabler/icons-react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { NotificationList } from "./notification-list";
|
||||
import { NotificationFilter } from "../types/notification.types";
|
||||
import {
|
||||
NotificationFilter,
|
||||
NotificationTab,
|
||||
} from "../types/notification.types";
|
||||
import {
|
||||
useMarkAllReadMutation,
|
||||
useUnreadCountQuery,
|
||||
} from "../queries/notification-query";
|
||||
import classes from "../notification.module.css";
|
||||
|
||||
export function NotificationPopover() {
|
||||
const { t } = useTranslation();
|
||||
const [opened, setOpened] = useState(false);
|
||||
const [tab, setTab] = useState<NotificationTab>("direct");
|
||||
const [filter, setFilter] = useState<NotificationFilter>("all");
|
||||
|
||||
const { data: unreadData } = useUnreadCountQuery();
|
||||
@@ -125,13 +131,27 @@ export function NotificationPopover() {
|
||||
</Group>
|
||||
</Group>
|
||||
|
||||
<Tabs
|
||||
value={tab}
|
||||
onChange={(value) => setTab(value as NotificationTab)}
|
||||
variant="default"
|
||||
color="dark"
|
||||
>
|
||||
<Tabs.List px="md">
|
||||
<Tabs.Tab value="direct">{t("Direct")}</Tabs.Tab>
|
||||
<Tabs.Tab value="updates">{t("Updates")}</Tabs.Tab>
|
||||
</Tabs.List>
|
||||
</Tabs>
|
||||
|
||||
<ScrollArea.Autosize
|
||||
mah={500}
|
||||
type="auto"
|
||||
offsetScrollbars
|
||||
scrollbarSize={6}
|
||||
style={{ overscrollBehavior: "contain" }}
|
||||
>
|
||||
<NotificationList
|
||||
tab={tab}
|
||||
filter={filter}
|
||||
onNavigate={() => setOpened(false)}
|
||||
/>
|
||||
|
||||
@@ -13,3 +13,4 @@
|
||||
.divider {
|
||||
border-color: light-dark(var(--mantine-color-gray-2), var(--mantine-color-dark-5));
|
||||
}
|
||||
|
||||
|
||||
@@ -15,10 +15,10 @@ import {
|
||||
export const NOTIFICATION_KEY = ["notifications"];
|
||||
export const UNREAD_COUNT_KEY = ["notifications", "unread-count"];
|
||||
|
||||
export function useNotificationsQuery() {
|
||||
export function useNotificationsQuery(type?: string) {
|
||||
return useInfiniteQuery({
|
||||
queryKey: NOTIFICATION_KEY,
|
||||
queryFn: ({ pageParam }) => getNotifications({ cursor: pageParam }),
|
||||
queryKey: [...NOTIFICATION_KEY, type],
|
||||
queryFn: ({ pageParam }) => getNotifications({ cursor: pageParam, type }),
|
||||
initialPageParam: undefined as string | undefined,
|
||||
getNextPageParam: (lastPage) =>
|
||||
lastPage.meta.hasNextPage ? lastPage.meta.nextCursor : undefined,
|
||||
|
||||
@@ -5,6 +5,7 @@ import { IPagination } from "@/lib/types";
|
||||
export async function getNotifications(params: {
|
||||
limit?: number;
|
||||
cursor?: string;
|
||||
type?: string;
|
||||
}): Promise<IPagination<INotification>> {
|
||||
const req = await api.post<IPagination<INotification>>(
|
||||
"/notifications",
|
||||
|
||||
@@ -39,3 +39,5 @@ export type INotification = {
|
||||
};
|
||||
|
||||
export type NotificationFilter = "all" | "unread";
|
||||
|
||||
export type NotificationTab = "direct" | "updates" | "all";
|
||||
|
||||
Reference in New Issue
Block a user