147 lines
3.6 KiB
Plaintext
147 lines
3.6 KiB
Plaintext
import { useRef, useState, useEffect } from 'react';
|
|
import { toast } from 'react-toastify';
|
|
|
|
function useNotificationCenter(params) {
|
|
if (params === void 0) {
|
|
params = {};
|
|
}
|
|
|
|
const sortFn = useRef(params.sort || defaultSort);
|
|
const filterFn = useRef(params.filter || null);
|
|
const [notifications, setNotifications] = useState(() => {
|
|
if (params.data) {
|
|
return filterFn.current ? params.data.filter(filterFn.current).sort(sortFn.current) : [...params.data].sort(sortFn.current);
|
|
}
|
|
|
|
return [];
|
|
});
|
|
useEffect(() => {
|
|
return toast.onChange(item => {
|
|
if (item.status === 'added' || item.status === 'updated') {
|
|
const newItem = decorate(item);
|
|
if (filterFn.current && !filterFn.current(newItem)) return;
|
|
setNotifications(prev => {
|
|
let nextState = [];
|
|
const updateIdx = prev.findIndex(v => v.id === newItem.id);
|
|
|
|
if (updateIdx !== -1) {
|
|
nextState = prev.slice();
|
|
Object.assign(nextState[updateIdx], newItem, {
|
|
createdAt: Date.now()
|
|
});
|
|
} else if (prev.length === 0) {
|
|
nextState = [newItem];
|
|
} else {
|
|
nextState = [newItem, ...prev];
|
|
}
|
|
|
|
return nextState.sort(sortFn.current);
|
|
});
|
|
}
|
|
});
|
|
}, []);
|
|
|
|
const remove = id => {
|
|
setNotifications(prev => prev.filter(Array.isArray(id) ? v => !id.includes(v.id) : v => v.id !== id));
|
|
};
|
|
|
|
const clear = () => {
|
|
setNotifications([]);
|
|
};
|
|
|
|
const markAllAsRead = function (read) {
|
|
if (read === void 0) {
|
|
read = true;
|
|
}
|
|
|
|
setNotifications(prev => prev.map(v => {
|
|
v.read = read;
|
|
return v;
|
|
}));
|
|
};
|
|
|
|
const markAsRead = function (id, read) {
|
|
if (read === void 0) {
|
|
read = true;
|
|
}
|
|
|
|
let map = v => {
|
|
if (v.id === id) v.read = read;
|
|
return v;
|
|
};
|
|
|
|
if (Array.isArray(id)) {
|
|
map = v => {
|
|
if (id.includes(v.id)) v.read = read;
|
|
return v;
|
|
};
|
|
}
|
|
|
|
setNotifications(prev => prev.map(map));
|
|
};
|
|
|
|
const find = id => {
|
|
return Array.isArray(id) ? notifications.filter(v => id.includes(v.id)) : notifications.find(v => v.id === id);
|
|
};
|
|
|
|
const add = item => {
|
|
if (notifications.find(v => v.id === item.id)) return null;
|
|
const newItem = decorate(item);
|
|
setNotifications(prev => [...prev, newItem].sort(sortFn.current));
|
|
return newItem.id;
|
|
};
|
|
|
|
const update = (id, item) => {
|
|
const index = notifications.findIndex(v => v.id === id);
|
|
|
|
if (index !== -1) {
|
|
setNotifications(prev => {
|
|
const nextState = [...prev];
|
|
Object.assign(nextState[index], item, {
|
|
createdAt: item.createdAt || Date.now()
|
|
});
|
|
return nextState.sort(sortFn.current);
|
|
});
|
|
return item.id;
|
|
}
|
|
|
|
return null;
|
|
};
|
|
|
|
const sort = compareFn => {
|
|
sortFn.current = compareFn;
|
|
setNotifications(prev => prev.slice().sort(compareFn));
|
|
};
|
|
|
|
return {
|
|
notifications,
|
|
clear,
|
|
markAllAsRead,
|
|
markAsRead,
|
|
add,
|
|
update,
|
|
remove,
|
|
// @ts-ignore fixme: overloading issue
|
|
find,
|
|
sort,
|
|
|
|
get unreadCount() {
|
|
return notifications.reduce((prev, cur) => !cur.read ? prev + 1 : prev, 0);
|
|
}
|
|
|
|
};
|
|
}
|
|
function decorate(item) {
|
|
if (item.id == null) item.id = Date.now().toString(36).substring(2, 9);
|
|
if (!item.createdAt) item.createdAt = Date.now();
|
|
if (item.read == null) item.read = false;
|
|
return item;
|
|
} // newest to oldest
|
|
|
|
function defaultSort(l, r) {
|
|
return r.createdAt - l.createdAt;
|
|
}
|
|
|
|
export { decorate, useNotificationCenter };
|
|
//# sourceMappingURL=index.esm.mjs.map
|