index.esm.mjs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. import { useRef, useState, useEffect } from 'react';
  2. import { toast } from 'react-toastify';
  3. function useNotificationCenter(params) {
  4. if (params === void 0) {
  5. params = {};
  6. }
  7. const sortFn = useRef(params.sort || defaultSort);
  8. const filterFn = useRef(params.filter || null);
  9. const [notifications, setNotifications] = useState(() => {
  10. if (params.data) {
  11. return filterFn.current ? params.data.filter(filterFn.current).sort(sortFn.current) : [...params.data].sort(sortFn.current);
  12. }
  13. return [];
  14. }); // used to method to be used inside effect without having stale `notifications`
  15. const notificationsRef = useRef(notifications);
  16. useEffect(() => {
  17. notificationsRef.current = notifications;
  18. }, [notifications]);
  19. useEffect(() => {
  20. return toast.onChange(toast => {
  21. if (toast.status === 'added' || toast.status === 'updated') {
  22. const newItem = decorate(toast);
  23. if (filterFn.current && !filterFn.current(newItem)) return;
  24. setNotifications(prev => {
  25. let nextState = [];
  26. const updateIdx = prev.findIndex(v => v.id === newItem.id);
  27. if (updateIdx !== -1) {
  28. nextState = prev.slice();
  29. Object.assign(nextState[updateIdx], newItem, {
  30. createdAt: Date.now()
  31. });
  32. } else if (prev.length === 0) {
  33. nextState = [newItem];
  34. } else {
  35. nextState = [newItem, ...prev];
  36. }
  37. return nextState.sort(sortFn.current);
  38. });
  39. }
  40. });
  41. }, []);
  42. const remove = id => {
  43. setNotifications(prev => prev.filter(Array.isArray(id) ? v => !id.includes(v.id) : v => v.id !== id));
  44. };
  45. const clear = () => {
  46. setNotifications([]);
  47. };
  48. const markAllAsRead = function (read) {
  49. if (read === void 0) {
  50. read = true;
  51. }
  52. setNotifications(prev => prev.map(v => {
  53. v.read = read;
  54. return v;
  55. }));
  56. };
  57. const markAsRead = function (id, read) {
  58. if (read === void 0) {
  59. read = true;
  60. }
  61. let map = v => {
  62. if (v.id === id) v.read = read;
  63. return v;
  64. };
  65. if (Array.isArray(id)) {
  66. map = v => {
  67. if (id.includes(v.id)) v.read = read;
  68. return v;
  69. };
  70. }
  71. setNotifications(prev => prev.map(map));
  72. };
  73. const find = id => {
  74. return Array.isArray(id) ? notificationsRef.current.filter(v => id.includes(v.id)) : notificationsRef.current.find(v => v.id === id);
  75. };
  76. const add = item => {
  77. if (notificationsRef.current.find(v => v.id === item.id)) return null;
  78. const newItem = decorate(item);
  79. setNotifications(prev => [...prev, newItem].sort(sortFn.current));
  80. return newItem.id;
  81. };
  82. const update = (id, item) => {
  83. const index = notificationsRef.current.findIndex(v => v.id === id);
  84. if (index !== -1) {
  85. setNotifications(prev => {
  86. const nextState = [...prev];
  87. Object.assign(nextState[index], item, {
  88. createdAt: item.createdAt || Date.now()
  89. });
  90. return nextState.sort(sortFn.current);
  91. });
  92. return item.id;
  93. }
  94. return null;
  95. };
  96. const sort = compareFn => {
  97. sortFn.current = compareFn;
  98. setNotifications(prev => prev.slice().sort(compareFn));
  99. };
  100. return {
  101. notifications,
  102. clear,
  103. markAllAsRead,
  104. markAsRead,
  105. add,
  106. update,
  107. remove,
  108. // @ts-ignore fixme: overloading issue
  109. find,
  110. sort,
  111. get unreadCount() {
  112. return notifications.reduce((prev, cur) => !cur.read ? prev + 1 : prev, 0);
  113. }
  114. };
  115. }
  116. function decorate(item) {
  117. if (item.id == null) item.id = Date.now().toString(36).substring(2, 9);
  118. if (!item.createdAt) item.createdAt = Date.now();
  119. if (item.read == null) item.read = false;
  120. return item;
  121. } // newest to oldest
  122. function defaultSort(l, r) {
  123. return r.createdAt - l.createdAt;
  124. }
  125. export { useNotificationCenter };
  126. //# sourceMappingURL=index.esm.mjs.map