NotificationIcon.tsx 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. import { useEffect, useState } from "react";
  2. import { NotificationIcon } from "../../assets/icon";
  3. import { Badge, Popover } from "antd";
  4. import { get } from "../../request";
  5. import type { INotificationListResponse } from "../../api/notification";
  6. import NotificationList from "./NotificationList";
  7. import { useAppSelector } from "../../hooks";
  8. import { currentUser } from "../../reducers/current-user";
  9. import type { IUser } from "../auth/User";
  10. const NotificationIconWidget = () => {
  11. const [count, setCount] = useState<number>();
  12. const currUser = useAppSelector(currentUser);
  13. const [mute, setMute] = useState(false);
  14. const queryNotification = (user?: IUser) => {
  15. if (!user) {
  16. console.debug("未登录 不查询 notification");
  17. return;
  18. }
  19. const isMute = localStorage.getItem("notification/mute");
  20. if (isMute && isMute === "true") {
  21. setMute(true);
  22. } else {
  23. setMute(false);
  24. }
  25. const now = new Date();
  26. const notificationUpdatedAt = localStorage.getItem(
  27. "notification/updatedAt"
  28. );
  29. if (notificationUpdatedAt) {
  30. if (now.getTime() - parseInt(notificationUpdatedAt) < 59000) {
  31. const notificationCount = localStorage.getItem("notification/count");
  32. if (notificationCount !== null) {
  33. setCount(parseInt(notificationCount));
  34. console.debug("has notification count");
  35. return;
  36. }
  37. }
  38. }
  39. const url = `/v2/notification?view=to&limit=1`;
  40. console.info("notification api request", url);
  41. get<INotificationListResponse>(url).then((json) => {
  42. if (json.ok) {
  43. console.debug("notification fetch ok ", json.data.unread);
  44. localStorage.setItem(
  45. "notification/updatedAt",
  46. now.getTime().toString()
  47. );
  48. localStorage.setItem("notification/count", json.data.unread.toString());
  49. setCount(json.data.unread);
  50. if (json.data.count > 0) {
  51. const newMessageTime = json.data.rows[0].created_at;
  52. const lastTime = localStorage.getItem("notification/new");
  53. if (lastTime === null || lastTime !== newMessageTime) {
  54. localStorage.setItem("notification/new", newMessageTime);
  55. const title = json.data.rows[0].res_type;
  56. const content = json.data.rows[0].content;
  57. localStorage.setItem(
  58. "notification/message",
  59. JSON.stringify({ title: title, content: content })
  60. );
  61. //发送通知
  62. console.debug("notification isMute", isMute, mute);
  63. if (!isMute || isMute !== "true") {
  64. if (window.Notification && Notification.permission !== "denied") {
  65. Notification.requestPermission(function (_status) {
  66. const notification = new Notification(title, {
  67. body: content,
  68. icon:
  69. import.meta.env.VITE_REACT_APP_API_BASE +
  70. "/assets/images/wikipali_logo.png",
  71. tag: json.data.rows[0].id,
  72. });
  73. notification.onclick = (event) => {
  74. event.preventDefault(); // 阻止浏览器聚焦于 Notification 的标签页
  75. window.open(json.data.rows[0].url, "_blank");
  76. };
  77. });
  78. }
  79. }
  80. }
  81. }
  82. } else {
  83. console.error(json.message);
  84. }
  85. });
  86. };
  87. useEffect(() => {
  88. const timer = setInterval(queryNotification, 1000 * 60, currUser);
  89. return () => {
  90. clearInterval(timer);
  91. };
  92. }, [currUser]);
  93. return (
  94. <>
  95. {currUser ? (
  96. <Popover
  97. placement="bottomLeft"
  98. arrowPointAtCenter
  99. destroyTooltipOnHide
  100. content={
  101. <div style={{ width: 600 }}>
  102. <NotificationList
  103. onChange={(unread: number) => setCount(unread)}
  104. />
  105. </div>
  106. }
  107. trigger="click"
  108. >
  109. <Badge count={count} size="small" dot={mute}>
  110. <span style={{ color: "white", cursor: "pointer" }}>
  111. <NotificationIcon />
  112. </span>
  113. </Badge>
  114. </Popover>
  115. ) : (
  116. <></>
  117. )}
  118. </>
  119. );
  120. };
  121. export default NotificationIconWidget;