import { createSlice } from "@reduxjs/toolkit"; import DOMPurify from "dompurify"; import _ from "lodash"; const defaultCloseDelay = 45; // in min const addUrlAbsolutePath = (content) => { const url = new URL(process.env.BACKEND_URL); content = content.replaceAll(/src="/g, `src="${url.origin}`); content = content.replaceAll(/url\("/g, `url("${url.origin}`); return content; }; const replaceHtmlTag = (content) => { return content.replaceAll(/body/g, "div"); }; const prepareContent = (content) => { content = addUrlAbsolutePath(content); content = replaceHtmlTag(content); return DOMPurify.sanitize(content); }; const parseTitle = (content) => { const re = /(?<=<title>).*?(?=<\/title>)/; const match = content.match(re); if (match) return match[0]; return ""; }; export const informingSlice = createSlice({ name: "informing", initialState: { notificationId: undefined, content: undefined, needConfirmation: false, closeDelay: defaultCloseDelay, closeTimer: defaultCloseDelay, isOverlay: false, title: "Notification", queue: [], }, reducers: { newNotification: (state, action) => { if (action.payload && !_.isEmpty(action.payload)) { const { text } = action.payload; const { notification_id: notificationId, content, need_confirmation: needConfirmation, close_delay: closeDelay, is_overlay: isOverlay, } = JSON.parse(text); const title = parseTitle(content); const prepared = prepareContent(content); // if notification is showing now and is'nt overlay, pu`t in queue if (state.notificationId && !state.isOverlay) { const n = _.find(state.queue, { notificationId }); if (!n && state.notificationId !== notificationId && !isOverlay) state.queue.push({ title, content: prepared, notificationId, needConfirmation, closeDelay, isOverlay, }); } else { state.title = title; state.content = prepared; state.notificationId = notificationId; state.needConfirmation = needConfirmation; state.closeDelay = closeDelay; state.closeTimer = closeDelay; state.isOverlay = isOverlay; } } }, clearNotification: (state) => { // get next notification from queue or clear if (!_.isEmpty(state.queue)) { const n = state.queue.shift(); state.notificationId = n.notificationId; state.content = n.content; state.needConfirmation = n.needConfirmation; state.closeDelay = n.closeDelay; state.closeTimer = n.closeDelay; state.isOverlay = n.isOverlay; state.title = n.title; } else { state.notificationId = undefined; state.content = undefined; state.needConfirmation = false; state.closeDelay = defaultCloseDelay; state.closeTimer = defaultCloseDelay; state.isOverlay = false; state.title = ""; } }, decrementCloseTimer: (state, { payload }) => { if (state.closeTimer > 0) state.closeTimer -= payload; }, }, }); export const { newNotification, clearNotification, decrementCloseTimer } = informingSlice.actions; export default informingSlice.reducer;