feat: refactor and improve notifications implementation

This commit is contained in:
Anoop M D 2024-03-12 02:50:06 +05:30
parent b0f4491cd2
commit 6a2754d4fb
15 changed files with 301 additions and 392 deletions

183
package-lock.json generated
View File

@ -47,6 +47,7 @@
}, },
"node_modules/@ampproject/remapping": { "node_modules/@ampproject/remapping": {
"version": "2.2.1", "version": "2.2.1",
"dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@jridgewell/gen-mapping": "^0.3.0", "@jridgewell/gen-mapping": "^0.3.0",
@ -745,6 +746,7 @@
}, },
"node_modules/@babel/compat-data": { "node_modules/@babel/compat-data": {
"version": "7.23.5", "version": "7.23.5",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@ -752,6 +754,7 @@
}, },
"node_modules/@babel/core": { "node_modules/@babel/core": {
"version": "7.23.9", "version": "7.23.9",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@ampproject/remapping": "^2.2.0", "@ampproject/remapping": "^2.2.0",
@ -814,6 +817,7 @@
}, },
"node_modules/@babel/helper-compilation-targets": { "node_modules/@babel/helper-compilation-targets": {
"version": "7.23.6", "version": "7.23.6",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/compat-data": "^7.23.5", "@babel/compat-data": "^7.23.5",
@ -828,6 +832,7 @@
}, },
"node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": {
"version": "5.1.1", "version": "5.1.1",
"dev": true,
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"yallist": "^3.0.2" "yallist": "^3.0.2"
@ -835,6 +840,7 @@
}, },
"node_modules/@babel/helper-compilation-targets/node_modules/yallist": { "node_modules/@babel/helper-compilation-targets/node_modules/yallist": {
"version": "3.1.1", "version": "3.1.1",
"dev": true,
"license": "ISC" "license": "ISC"
}, },
"node_modules/@babel/helper-create-class-features-plugin": { "node_modules/@babel/helper-create-class-features-plugin": {
@ -941,6 +947,7 @@
}, },
"node_modules/@babel/helper-module-transforms": { "node_modules/@babel/helper-module-transforms": {
"version": "7.23.3", "version": "7.23.3",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-environment-visitor": "^7.22.20",
@ -1008,6 +1015,7 @@
}, },
"node_modules/@babel/helper-simple-access": { "node_modules/@babel/helper-simple-access": {
"version": "7.22.5", "version": "7.22.5",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/types": "^7.22.5" "@babel/types": "^7.22.5"
@ -1053,6 +1061,7 @@
}, },
"node_modules/@babel/helper-validator-option": { "node_modules/@babel/helper-validator-option": {
"version": "7.23.5", "version": "7.23.5",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@ -1073,6 +1082,7 @@
}, },
"node_modules/@babel/helpers": { "node_modules/@babel/helpers": {
"version": "7.23.9", "version": "7.23.9",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/template": "^7.23.9", "@babel/template": "^7.23.9",
@ -4205,23 +4215,6 @@
"node": ">=12" "node": ">=12"
} }
}, },
"node_modules/@n8n/vm2": {
"version": "3.9.23",
"resolved": "https://registry.npmjs.org/@n8n/vm2/-/vm2-3.9.23.tgz",
"integrity": "sha512-yu+It+L89uljQsCJ2e9cQaXzoXJe9bU69QQIoWUOcUw0u5Zon37DuB7bdNNsjKS1ZdFD+fBWCQpq/FkqHsSjXQ==",
"peer": true,
"dependencies": {
"acorn": "^8.7.0",
"acorn-walk": "^8.2.0"
},
"bin": {
"vm2": "bin/vm2"
},
"engines": {
"node": ">=18.10",
"pnpm": ">=8.6.12"
}
},
"node_modules/@next/env": { "node_modules/@next/env": {
"version": "12.3.3", "version": "12.3.3",
"license": "MIT" "license": "MIT"
@ -6715,6 +6708,7 @@
}, },
"node_modules/browserslist": { "node_modules/browserslist": {
"version": "4.22.3", "version": "4.22.3",
"dev": true,
"funding": [ "funding": [
{ {
"type": "opencollective", "type": "opencollective",
@ -7652,6 +7646,7 @@
}, },
"node_modules/convert-source-map": { "node_modules/convert-source-map": {
"version": "2.0.0", "version": "2.0.0",
"dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/cookie": { "node_modules/cookie": {
@ -8809,6 +8804,7 @@
}, },
"node_modules/electron-to-chromium": { "node_modules/electron-to-chromium": {
"version": "1.4.667", "version": "1.4.667",
"dev": true,
"license": "ISC" "license": "ISC"
}, },
"node_modules/electron-util": { "node_modules/electron-util": {
@ -9812,6 +9808,7 @@
}, },
"node_modules/gensync": { "node_modules/gensync": {
"version": "1.0.0-beta.2", "version": "1.0.0-beta.2",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@ -13434,6 +13431,7 @@
}, },
"node_modules/node-releases": { "node_modules/node-releases": {
"version": "2.0.14", "version": "2.0.14",
"dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/node-vault": { "node_modules/node-vault": {
@ -16387,6 +16385,7 @@
}, },
"node_modules/semver": { "node_modules/semver": {
"version": "6.3.1", "version": "6.3.1",
"devOptional": true,
"license": "ISC", "license": "ISC",
"bin": { "bin": {
"semver": "bin/semver.js" "semver": "bin/semver.js"
@ -17995,6 +17994,7 @@
}, },
"node_modules/update-browserslist-db": { "node_modules/update-browserslist-db": {
"version": "1.0.13", "version": "1.0.13",
"dev": true,
"funding": [ "funding": [
{ {
"type": "opencollective", "type": "opencollective",
@ -19009,6 +19009,7 @@
"http-proxy-agent": "^7.0.0", "http-proxy-agent": "^7.0.0",
"https-proxy-agent": "^7.0.2", "https-proxy-agent": "^7.0.2",
"inquirer": "^9.1.4", "inquirer": "^9.1.4",
"json-bigint": "^1.0.0",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"mustache": "^4.2.0", "mustache": "^4.2.0",
"qs": "^6.11.0", "qs": "^6.11.0",
@ -19252,6 +19253,7 @@
}, },
"@ampproject/remapping": { "@ampproject/remapping": {
"version": "2.2.1", "version": "2.2.1",
"dev": true,
"requires": { "requires": {
"@jridgewell/gen-mapping": "^0.3.0", "@jridgewell/gen-mapping": "^0.3.0",
"@jridgewell/trace-mapping": "^0.3.9" "@jridgewell/trace-mapping": "^0.3.9"
@ -19805,10 +19807,12 @@
} }
}, },
"@babel/compat-data": { "@babel/compat-data": {
"version": "7.23.5" "version": "7.23.5",
"dev": true
}, },
"@babel/core": { "@babel/core": {
"version": "7.23.9", "version": "7.23.9",
"dev": true,
"requires": { "requires": {
"@ampproject/remapping": "^2.2.0", "@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.23.5", "@babel/code-frame": "^7.23.5",
@ -19851,6 +19855,7 @@
}, },
"@babel/helper-compilation-targets": { "@babel/helper-compilation-targets": {
"version": "7.23.6", "version": "7.23.6",
"dev": true,
"requires": { "requires": {
"@babel/compat-data": "^7.23.5", "@babel/compat-data": "^7.23.5",
"@babel/helper-validator-option": "^7.23.5", "@babel/helper-validator-option": "^7.23.5",
@ -19861,12 +19866,14 @@
"dependencies": { "dependencies": {
"lru-cache": { "lru-cache": {
"version": "5.1.1", "version": "5.1.1",
"dev": true,
"requires": { "requires": {
"yallist": "^3.0.2" "yallist": "^3.0.2"
} }
}, },
"yallist": { "yallist": {
"version": "3.1.1" "version": "3.1.1",
"dev": true
} }
} }
}, },
@ -19936,6 +19943,7 @@
}, },
"@babel/helper-module-transforms": { "@babel/helper-module-transforms": {
"version": "7.23.3", "version": "7.23.3",
"dev": true,
"requires": { "requires": {
"@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-environment-visitor": "^7.22.20",
"@babel/helper-module-imports": "^7.22.15", "@babel/helper-module-imports": "^7.22.15",
@ -19974,6 +19982,7 @@
}, },
"@babel/helper-simple-access": { "@babel/helper-simple-access": {
"version": "7.22.5", "version": "7.22.5",
"dev": true,
"requires": { "requires": {
"@babel/types": "^7.22.5" "@babel/types": "^7.22.5"
} }
@ -19998,7 +20007,8 @@
"version": "7.22.20" "version": "7.22.20"
}, },
"@babel/helper-validator-option": { "@babel/helper-validator-option": {
"version": "7.23.5" "version": "7.23.5",
"dev": true
}, },
"@babel/helper-wrap-function": { "@babel/helper-wrap-function": {
"version": "7.22.20", "version": "7.22.20",
@ -20011,6 +20021,7 @@
}, },
"@babel/helpers": { "@babel/helpers": {
"version": "7.23.9", "version": "7.23.9",
"dev": true,
"requires": { "requires": {
"@babel/template": "^7.23.9", "@babel/template": "^7.23.9",
"@babel/traverse": "^7.23.9", "@babel/traverse": "^7.23.9",
@ -20088,8 +20099,7 @@
}, },
"@babel/plugin-proposal-private-property-in-object": { "@babel/plugin-proposal-private-property-in-object": {
"version": "7.21.0-placeholder-for-preset-env.2", "version": "7.21.0-placeholder-for-preset-env.2",
"dev": true, "dev": true
"requires": {}
}, },
"@babel/plugin-syntax-async-generators": { "@babel/plugin-syntax-async-generators": {
"version": "7.8.4", "version": "7.8.4",
@ -21102,8 +21112,7 @@
"version": "3.0.4" "version": "3.0.4"
}, },
"ws": { "ws": {
"version": "8.13.0", "version": "8.13.0"
"requires": {}
} }
} }
}, },
@ -21131,8 +21140,7 @@
}, },
"dependencies": { "dependencies": {
"ws": { "ws": {
"version": "8.13.0", "version": "8.13.0"
"requires": {}
} }
} }
}, },
@ -21256,8 +21264,7 @@
} }
}, },
"@graphql-typed-document-node/core": { "@graphql-typed-document-node/core": {
"version": "3.2.0", "version": "3.2.0"
"requires": {}
}, },
"@iarna/toml": { "@iarna/toml": {
"version": "2.2.5" "version": "2.2.5"
@ -22016,16 +22023,6 @@
"@n1ru4l/push-pull-async-iterable-iterator": { "@n1ru4l/push-pull-async-iterable-iterator": {
"version": "3.2.0" "version": "3.2.0"
}, },
"@n8n/vm2": {
"version": "3.9.23",
"resolved": "https://registry.npmjs.org/@n8n/vm2/-/vm2-3.9.23.tgz",
"integrity": "sha512-yu+It+L89uljQsCJ2e9cQaXzoXJe9bU69QQIoWUOcUw0u5Zon37DuB7bdNNsjKS1ZdFD+fBWCQpq/FkqHsSjXQ==",
"peer": true,
"requires": {
"acorn": "^8.7.0",
"acorn-walk": "^8.2.0"
}
},
"@next/env": { "@next/env": {
"version": "12.3.3" "version": "12.3.3"
}, },
@ -22597,8 +22594,7 @@
} }
}, },
"@tabler/icons": { "@tabler/icons": {
"version": "1.119.0", "version": "1.119.0"
"requires": {}
}, },
"@tippyjs/react": { "@tippyjs/react": {
"version": "4.2.6", "version": "4.2.6",
@ -23026,6 +23022,7 @@
"http-proxy-agent": "^7.0.0", "http-proxy-agent": "^7.0.0",
"https-proxy-agent": "^7.0.2", "https-proxy-agent": "^7.0.2",
"inquirer": "^9.1.4", "inquirer": "^9.1.4",
"json-bigint": "^1.0.0",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"mustache": "^4.2.0", "mustache": "^4.2.0",
"qs": "^6.11.0", "qs": "^6.11.0",
@ -23138,8 +23135,7 @@
} }
}, },
"@usebruno/schema": { "@usebruno/schema": {
"version": "file:packages/bruno-schema", "version": "file:packages/bruno-schema"
"requires": {}
}, },
"@usebruno/tests": { "@usebruno/tests": {
"version": "file:packages/bruno-tests", "version": "file:packages/bruno-tests",
@ -23283,8 +23279,7 @@
}, },
"@webpack-cli/configtest": { "@webpack-cli/configtest": {
"version": "1.2.0", "version": "1.2.0",
"dev": true, "dev": true
"requires": {}
}, },
"@webpack-cli/info": { "@webpack-cli/info": {
"version": "1.5.0", "version": "1.5.0",
@ -23295,8 +23290,7 @@
}, },
"@webpack-cli/serve": { "@webpack-cli/serve": {
"version": "1.7.0", "version": "1.7.0",
"dev": true, "dev": true
"requires": {}
}, },
"@whatwg-node/events": { "@whatwg-node/events": {
"version": "0.0.3" "version": "0.0.3"
@ -23356,8 +23350,7 @@
}, },
"acorn-import-assertions": { "acorn-import-assertions": {
"version": "1.9.0", "version": "1.9.0",
"dev": true, "dev": true
"requires": {}
}, },
"acorn-walk": { "acorn-walk": {
"version": "8.3.2" "version": "8.3.2"
@ -23399,8 +23392,7 @@
}, },
"ajv-keywords": { "ajv-keywords": {
"version": "3.5.2", "version": "3.5.2",
"dev": true, "dev": true
"requires": {}
}, },
"amdefine": { "amdefine": {
"version": "0.0.8" "version": "0.0.8"
@ -24005,6 +23997,7 @@
}, },
"browserslist": { "browserslist": {
"version": "4.22.3", "version": "4.22.3",
"dev": true,
"requires": { "requires": {
"caniuse-lite": "^1.0.30001580", "caniuse-lite": "^1.0.30001580",
"electron-to-chromium": "^1.4.648", "electron-to-chromium": "^1.4.648",
@ -24043,7 +24036,7 @@
"https-proxy-agent": "^7.0.2", "https-proxy-agent": "^7.0.2",
"is-valid-path": "^0.1.1", "is-valid-path": "^0.1.1",
"js-yaml": "^4.1.0", "js-yaml": "^4.1.0",
"json-bigint": "*", "json-bigint": "^1.0.0",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"mime-types": "^2.1.35", "mime-types": "^2.1.35",
"mustache": "^4.2.0", "mustache": "^4.2.0",
@ -24297,8 +24290,7 @@
} }
}, },
"chai-string": { "chai-string": {
"version": "1.5.0", "version": "1.5.0"
"requires": {}
}, },
"chalk": { "chalk": {
"version": "3.0.0", "version": "3.0.0",
@ -24641,7 +24633,8 @@
"version": "1.0.5" "version": "1.0.5"
}, },
"convert-source-map": { "convert-source-map": {
"version": "2.0.0" "version": "2.0.0",
"dev": true
}, },
"cookie": { "cookie": {
"version": "0.6.0" "version": "0.6.0"
@ -24759,8 +24752,7 @@
}, },
"css-declaration-sorter": { "css-declaration-sorter": {
"version": "6.4.1", "version": "6.4.1",
"dev": true, "dev": true
"requires": {}
}, },
"css-loader": { "css-loader": {
"version": "6.10.0", "version": "6.10.0",
@ -24897,8 +24889,7 @@
}, },
"cssnano-utils": { "cssnano-utils": {
"version": "3.1.0", "version": "3.1.0",
"dev": true, "dev": true
"requires": {}
}, },
"csso": { "csso": {
"version": "4.2.0", "version": "4.2.0",
@ -24956,8 +24947,7 @@
}, },
"dedent": { "dedent": {
"version": "1.5.1", "version": "1.5.1",
"dev": true, "dev": true
"requires": {}
}, },
"deep-eql": { "deep-eql": {
"version": "4.1.3", "version": "4.1.3",
@ -25390,7 +25380,8 @@
} }
}, },
"electron-to-chromium": { "electron-to-chromium": {
"version": "1.4.667" "version": "1.4.667",
"dev": true
}, },
"electron-util": { "electron-util": {
"version": "0.17.2", "version": "0.17.2",
@ -26021,7 +26012,8 @@
} }
}, },
"gensync": { "gensync": {
"version": "1.0.0-beta.2" "version": "1.0.0-beta.2",
"dev": true
}, },
"get-caller-file": { "get-caller-file": {
"version": "2.0.5" "version": "2.0.5"
@ -26178,8 +26170,7 @@
} }
}, },
"goober": { "goober": {
"version": "2.1.14", "version": "2.1.14"
"requires": {}
}, },
"gopd": { "gopd": {
"version": "1.0.1", "version": "1.0.1",
@ -26347,8 +26338,7 @@
} }
}, },
"graphql-ws": { "graphql-ws": {
"version": "5.12.1", "version": "5.12.1"
"requires": {}
}, },
"handlebars": { "handlebars": {
"version": "4.7.8", "version": "4.7.8",
@ -26620,8 +26610,7 @@
}, },
"icss-utils": { "icss-utils": {
"version": "5.1.0", "version": "5.1.0",
"dev": true, "dev": true
"requires": {}
}, },
"idb": { "idb": {
"version": "7.1.1" "version": "7.1.1"
@ -26924,8 +26913,7 @@
"version": "3.0.1" "version": "3.0.1"
}, },
"isomorphic-ws": { "isomorphic-ws": {
"version": "5.0.0", "version": "5.0.0"
"requires": {}
}, },
"isstream": { "isstream": {
"version": "0.1.2" "version": "0.1.2"
@ -27298,8 +27286,7 @@
}, },
"jest-pnp-resolver": { "jest-pnp-resolver": {
"version": "1.2.3", "version": "1.2.3",
"dev": true, "dev": true
"requires": {}
}, },
"jest-regex-util": { "jest-regex-util": {
"version": "29.6.3", "version": "29.6.3",
@ -28038,8 +28025,7 @@
"version": "1.0.1" "version": "1.0.1"
}, },
"merge-refs": { "merge-refs": {
"version": "1.2.2", "version": "1.2.2"
"requires": {}
}, },
"merge-stream": { "merge-stream": {
"version": "2.0.0", "version": "2.0.0",
@ -28049,8 +28035,7 @@
"version": "1.4.1" "version": "1.4.1"
}, },
"meros": { "meros": {
"version": "1.3.0", "version": "1.3.0"
"requires": {}
}, },
"methods": { "methods": {
"version": "1.1.2" "version": "1.1.2"
@ -28297,7 +28282,8 @@
"version": "1.1.12" "version": "1.1.12"
}, },
"node-releases": { "node-releases": {
"version": "2.0.14" "version": "2.0.14",
"dev": true
}, },
"node-vault": { "node-vault": {
"version": "0.10.2", "version": "0.10.2",
@ -28910,23 +28896,19 @@
}, },
"postcss-discard-comments": { "postcss-discard-comments": {
"version": "5.1.2", "version": "5.1.2",
"dev": true, "dev": true
"requires": {}
}, },
"postcss-discard-duplicates": { "postcss-discard-duplicates": {
"version": "5.1.0", "version": "5.1.0",
"dev": true, "dev": true
"requires": {}
}, },
"postcss-discard-empty": { "postcss-discard-empty": {
"version": "5.1.1", "version": "5.1.1",
"dev": true, "dev": true
"requires": {}
}, },
"postcss-discard-overridden": { "postcss-discard-overridden": {
"version": "5.1.0", "version": "5.1.0",
"dev": true, "dev": true
"requires": {}
}, },
"postcss-import": { "postcss-import": {
"version": "15.1.0", "version": "15.1.0",
@ -29011,8 +28993,7 @@
}, },
"postcss-modules-extract-imports": { "postcss-modules-extract-imports": {
"version": "3.0.0", "version": "3.0.0",
"dev": true, "dev": true
"requires": {}
}, },
"postcss-modules-local-by-default": { "postcss-modules-local-by-default": {
"version": "4.0.4", "version": "4.0.4",
@ -29039,8 +29020,7 @@
}, },
"postcss-normalize-charset": { "postcss-normalize-charset": {
"version": "5.1.0", "version": "5.1.0",
"dev": true, "dev": true
"requires": {}
}, },
"postcss-normalize-display-values": { "postcss-normalize-display-values": {
"version": "5.1.0", "version": "5.1.0",
@ -29479,8 +29459,7 @@
} }
}, },
"react-inspector": { "react-inspector": {
"version": "6.0.2", "version": "6.0.2"
"requires": {}
}, },
"react-is": { "react-is": {
"version": "16.13.1" "version": "16.13.1"
@ -29630,8 +29609,7 @@
} }
}, },
"redux-thunk": { "redux-thunk": {
"version": "2.4.2", "version": "2.4.2"
"requires": {}
}, },
"regenerate": { "regenerate": {
"version": "1.4.2", "version": "1.4.2",
@ -29950,8 +29928,7 @@
}, },
"rollup-plugin-peer-deps-external": { "rollup-plugin-peer-deps-external": {
"version": "2.2.4", "version": "2.2.4",
"dev": true, "dev": true
"requires": {}
}, },
"rollup-plugin-postcss": { "rollup-plugin-postcss": {
"version": "4.0.2", "version": "4.0.2",
@ -30093,7 +30070,8 @@
} }
}, },
"semver": { "semver": {
"version": "6.3.1" "version": "6.3.1",
"devOptional": true
}, },
"semver-compare": { "semver-compare": {
"version": "1.0.0", "version": "1.0.0",
@ -30509,8 +30487,7 @@
}, },
"style-loader": { "style-loader": {
"version": "3.3.4", "version": "3.3.4",
"dev": true, "dev": true
"requires": {}
}, },
"style-mod": { "style-mod": {
"version": "4.1.0" "version": "4.1.0"
@ -30542,8 +30519,7 @@
} }
}, },
"styled-jsx": { "styled-jsx": {
"version": "5.0.7", "version": "5.0.7"
"requires": {}
}, },
"stylehacks": { "stylehacks": {
"version": "5.1.1", "version": "5.1.1",
@ -31094,6 +31070,7 @@
}, },
"update-browserslist-db": { "update-browserslist-db": {
"version": "1.0.13", "version": "1.0.13",
"dev": true,
"requires": { "requires": {
"escalade": "^3.1.1", "escalade": "^3.1.1",
"picocolors": "^1.0.0" "picocolors": "^1.0.0"
@ -31183,8 +31160,7 @@
"version": "8.0.2" "version": "8.0.2"
}, },
"use-sync-external-store": { "use-sync-external-store": {
"version": "1.2.0", "version": "1.2.0"
"requires": {}
}, },
"utf8-byte-length": { "utf8-byte-length": {
"version": "1.0.4", "version": "1.0.4",
@ -31465,8 +31441,7 @@
} }
}, },
"ws": { "ws": {
"version": "8.16.0", "version": "8.16.0"
"requires": {}
}, },
"xdg-basedir": { "xdg-basedir": {
"version": "4.0.0", "version": "4.0.0",

View File

@ -1,5 +1,3 @@
ENV=production ENV=production
NEXT_PUBLIC_ENV=prod NEXT_PUBLIC_ENV=prod
NEXT_PUBLIC_BRUNO_SERVER_API=https://ada.grafnode.com/api

View File

@ -1,13 +1,9 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import StyledWrapper from './StyledWrapper'; import StyledWrapper from './StyledWrapper';
const ModalHeader = ({ title, handleCancel, headerContentComponent }) => ( const ModalHeader = ({ title, handleCancel, customHeader }) => (
<div className="bruno-modal-header"> <div className="bruno-modal-header">
{headerContentComponent ? ( {customHeader ? customHeader : <>{title ? <div className="bruno-modal-header-title">{title}</div> : null}</>}
headerContentComponent
) : (
<>{title ? <div className="bruno-modal-header-title">{title}</div> : null}</>
)}
{handleCancel ? ( {handleCancel ? (
<div className="close cursor-pointer" onClick={handleCancel ? () => handleCancel() : null}> <div className="close cursor-pointer" onClick={handleCancel ? () => handleCancel() : null}>
× ×
@ -58,7 +54,7 @@ const ModalFooter = ({
const Modal = ({ const Modal = ({
size, size,
title, title,
headerContentComponent, customHeader,
confirmText, confirmText,
cancelText, cancelText,
handleCancel, handleCancel,
@ -104,11 +100,7 @@ const Modal = ({
return ( return (
<StyledWrapper className={classes} onClick={onClick ? (e) => onClick(e) : null}> <StyledWrapper className={classes} onClick={onClick ? (e) => onClick(e) : null}>
<div className={`bruno-modal-card modal-${size}`}> <div className={`bruno-modal-card modal-${size}`}>
<ModalHeader <ModalHeader title={title} handleCancel={() => closeModal({ type: 'icon' })} customHeader={customHeader} />
title={title}
handleCancel={() => closeModal({ type: 'icon' })}
headerContentComponent={headerContentComponent}
/>
<ModalContent>{children}</ModalContent> <ModalContent>{children}</ModalContent>
<ModalFooter <ModalFooter
confirmText={confirmText} confirmText={confirmText}

View File

@ -4,73 +4,67 @@ const StyledWrapper = styled.div`
.notifications-modal { .notifications-modal {
margin-inline: -1rem; margin-inline: -1rem;
margin-block: -1.5rem; margin-block: -1.5rem;
background-color: ${(props) => props.theme.notifications.settings.bg}; background-color: ${(props) => props.theme.notifications.bg};
} }
.notification-count { .notification-count {
position: absolute;
right: -10px;
top: -15px;
z-index: 10;
margin-right: 0.5rem;
background-color: ${(props) => props.theme.notifications.bell.count};
border-radius: 50%;
padding: 2px 1px;
min-width: 20px;
display: flex; display: flex;
color: white;
position: absolute;
top: -0.625rem;
right: -0.5rem;
margin-right: 0.5rem;
justify-content: center; justify-content: center;
font-size: 10px; font-size: 0.625rem;
border-radius: 50%;
background-color: ${(props) => props.theme.colors.text.yellow};
border: solid 2px ${(props) => props.theme.sidebar.bg};
min-width: 1.25rem;
} }
.bell { button.mark-as-read {
animation: fade-and-pulse 1s ease-in-out 1s forwards; font-weight: 400 !important;
} }
ul { ul.notifications {
background-color: ${(props) => props.theme.notifications.settings.sidebar.bg}; background-color: ${(props) => props.theme.notifications.list.bg};
border-right: solid 1px ${(props) => props.theme.notifications.settings.sidebar.borderRight}; border-right: solid 1px ${(props) => props.theme.notifications.list.borderRight};
min-height: 400px; min-height: 400px;
height: 100%; height: 100%;
max-height: 85vh; max-height: 85vh;
overflow-y: auto; overflow-y: auto;
}
li { li {
min-width: 150px; min-width: 150px;
min-height: 5rem; cursor: pointer;
display: block; padding: 0.5rem 0.625rem;
position: relative; border-left: solid 2px transparent;
cursor: pointer; color: ${(props) => props.theme.textLink};
padding: 8px 10px; border-bottom: solid 1px ${(props) => props.theme.notifications.list.borderBottom};
border-left: solid 2px transparent; &:hover {
border-bottom: solid 1px ${(props) => props.theme.notifications.settings.item.borderBottom}; background-color: ${(props) => props.theme.notifications.list.hoverBg};
font-weight: 600; }
&:hover {
background-color: ${(props) => props.theme.notifications.settings.item.hoverBg};
}
}
.active { &.active {
font-weight: normal; color: ${(props) => props.theme.text} !important;
background-color: ${(props) => props.theme.notifications.settings.item.active.bg} !important; background-color: ${(props) => props.theme.notifications.list.active.bg} !important;
border-left: solid 2px ${(props) => props.theme.notifications.settings.item.border}; border-left: solid 2px ${(props) => props.theme.notifications.list.active.border};
&:hover { &:hover {
background-color: ${(props) => props.theme.notifications.settings.item.active.hoverBg} !important; background-color: ${(props) => props.theme.notifications.list.active.hoverBg} !important;
} }
} }
.read { &.read {
opacity: 0.7; color: ${(props) => props.theme.text} !important;
font-weight: normal; }
background-color: ${(props) => props.theme.notifications.settings.item.read.bg} !important;
&:hover { .notification-date {
background-color: ${(props) => props.theme.notifications.settings.item.read.hoverBg} !important; font-size: 0.6875rem;
}
} }
} }
.notification-title { .notification-title {
// text ellipses 2 lines
// white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
display: -webkit-box; display: -webkit-box;
@ -79,12 +73,12 @@ const StyledWrapper = styled.div`
} }
.notification-date { .notification-date {
color: ${(props) => props.theme.notifications.settings.item.date.color} !important; color: ${(props) => props.theme.colors.text.muted};
} }
.pagination { .pagination {
background-color: ${(props) => props.theme.notifications.settings.sidebar.bg}; background-color: ${(props) => props.theme.notifications.list.bg};
border-right: solid 1px ${(props) => props.theme.notifications.settings.sidebar.borderRight}; border-right: solid 1px ${(props) => props.theme.notifications.list.borderRight};
} }
`; `;

View File

@ -5,25 +5,26 @@ import Modal from 'components/Modal/index';
import { useEffect } from 'react'; import { useEffect } from 'react';
import { import {
fetchNotifications, fetchNotifications,
markMultipleNotificationsAsRead, markAllNotificationsAsRead,
markNotificationAsRead markNotificationAsRead
} from 'providers/ReduxStore/slices/app'; } from 'providers/ReduxStore/slices/notifications';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import { humanizeDate, relativeDate } from 'utils/common/index'; import { humanizeDate, relativeDate } from 'utils/common';
const PAGE_SIZE = 5;
const Notifications = () => { const Notifications = () => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const notificationsById = useSelector((state) => state.app.notifications); const notifications = useSelector((state) => state.notifications.notifications);
const notifications = [...notificationsById].reverse();
const [showNotificationsModal, toggleNotificationsModal] = useState(false); const [showNotificationsModal, setShowNotificationsModal] = useState(false);
const [selectedNotification, setSelectedNotification] = useState(null); const [selectedNotification, setSelectedNotification] = useState(null);
const [pageSize, setPageSize] = useState(5);
const [pageNumber, setPageNumber] = useState(1); const [pageNumber, setPageNumber] = useState(1);
const notificationsStartIndex = (pageNumber - 1) * pageSize; const notificationsStartIndex = (pageNumber - 1) * PAGE_SIZE;
const notificationsEndIndex = pageNumber * pageSize; const notificationsEndIndex = pageNumber * PAGE_SIZE;
const totalPages = Math.ceil(notifications.length / pageSize); const totalPages = Math.ceil(notifications.length / PAGE_SIZE);
const unreadNotifications = notifications.filter((notification) => !notification.read);
useEffect(() => { useEffect(() => {
dispatch(fetchNotifications()); dispatch(fetchNotifications());
@ -62,22 +63,17 @@ const Notifications = () => {
dispatch(markNotificationAsRead({ notificationId: notification?.id })); dispatch(markNotificationAsRead({ notificationId: notification?.id }));
}; };
const unreadNotifications = notifications.filter((notification) => !notification.read); const modalCustomHeader = (
const modalHeaderContentComponent = (
<div className="flex flex-row gap-8"> <div className="flex flex-row gap-8">
<div>NOTIFICATIONS</div> <div>NOTIFICATIONS</div>
{unreadNotifications.length > 0 && ( {unreadNotifications.length > 0 && (
<> <>
<div className="normal-case font-normal"> <div className="normal-case font-normal">
{unreadNotifications.length} <i>unread notifications</i> {unreadNotifications.length} <span>unread notifications</span>
</div> </div>
<button <button
className={`select-none ${1 == 2 ? 'opacity-50' : 'text-link cursor-pointer hover:underline'}`} className={`select-none ${1 == 2 ? 'opacity-50' : 'text-link mark-as-read cursor-pointer hover:underline'}`}
onClick={() => { onClick={() => dispatch(markAllNotificationsAsRead())}
let allNotificationIds = notifications.map((notification) => notification.id);
dispatch(markMultipleNotificationsAsRead({ notificationIds: allNotificationIds }));
}}
> >
{'Mark all as read'} {'Mark all as read'}
</button> </button>
@ -92,7 +88,7 @@ const Notifications = () => {
className="relative" className="relative"
onClick={() => { onClick={() => {
dispatch(fetchNotifications()); dispatch(fetchNotifications());
toggleNotificationsModal(true); setShowNotificationsModal(true);
}} }}
> >
<IconBell <IconBell
@ -104,51 +100,52 @@ const Notifications = () => {
<div className="notification-count text-xs">{unreadNotifications.length}</div> <div className="notification-count text-xs">{unreadNotifications.length}</div>
)} )}
</div> </div>
{showNotificationsModal && ( {showNotificationsModal && (
<Modal <Modal
size="lg" size="lg"
title="Notifications" title="Notifications"
confirmText={'Close'} confirmText={'Close'}
handleConfirm={() => { handleConfirm={() => {
toggleNotificationsModal(false); setShowNotificationsModal(false);
}} }}
handleCancel={() => { handleCancel={() => {
toggleNotificationsModal(false); setShowNotificationsModal(false);
}} }}
hideFooter={true} hideFooter={true}
headerContentComponent={modalHeaderContentComponent} customHeader={modalCustomHeader}
disableCloseOnOutsideClick={true}
disableEscapeKey={true}
> >
<div className="notifications-modal"> <div className="notifications-modal">
{notifications?.length > 0 ? ( {notifications?.length > 0 ? (
<div className="grid grid-cols-4 flex flex-row text-sm"> <div className="grid grid-cols-4 flex flex-row text-sm">
<div className="col-span-1 flex flex-col"> <div className="col-span-1 flex flex-col">
<ul <ul
className="w-full flex flex-col h-[50vh] max-h-[50vh] overflow-y-auto" className="notifications w-full flex flex-col h-[50vh] max-h-[50vh] overflow-y-auto"
style={{ maxHeight: '50vh', height: '46vh' }} style={{ maxHeight: '50vh', height: '46vh' }}
> >
{notifications?.slice(notificationsStartIndex, notificationsEndIndex)?.map((notification) => ( {notifications?.slice(notificationsStartIndex, notificationsEndIndex)?.map((notification) => (
<li <li
className={`p-4 flex flex-col gap-2 ${ key={notification.id}
selectedNotification?.id == notification?.id ? 'active' : notification?.read ? 'read' : '' className={`p-4 flex flex-col justify-center ${
selectedNotification?.id == notification.id ? 'active' : notification.read ? 'read' : ''
}`} }`}
onClick={handleNotificationItemClick(notification)} onClick={handleNotificationItemClick(notification)}
> >
<div className="notification-title w-full">{notification?.title}</div> <div className="notification-title w-full">{notification?.title}</div>
{/* human readable relative date */} <div className="notification-date text-xs py-2">{relativeDate(notification?.date)}</div>
<div className="notification-date w-full flex justify-start font-normal text-xs py-2">
{relativeDate(notification?.date)}
</div>
</li> </li>
))} ))}
</ul> </ul>
<div className="w-full pagination flex flex-row gap-4 justify-center py-4 items-center"> <div className="w-full pagination flex flex-row gap-4 justify-center p-2 items-center text-xs">
<button <button
className={`pl-2 pr-2 py-3 select-none ${ className={`pl-2 pr-2 py-3 select-none ${
pageNumber <= 1 ? 'opacity-50' : 'text-link cursor-pointer hover:underline' pageNumber <= 1 ? 'opacity-50' : 'text-link cursor-pointer hover:underline'
}`} }`}
onClick={handlePrev} onClick={handlePrev}
> >
{'Previous'} {'Prev'}
</button> </button>
<div className="flex flex-row items-center justify-center gap-1"> <div className="flex flex-row items-center justify-center gap-1">
Page Page
@ -170,9 +167,11 @@ const Notifications = () => {
</button> </button>
</div> </div>
</div> </div>
<div className="flex w-full col-span-3 p-4 flex-col gap-2"> <div className="flex w-full col-span-3 p-4 flex-col">
<div className="w-full text-lg flex flex-wrap h-fit">{selectedNotification?.title}</div> <div className="w-full text-lg flex flex-wrap h-fit mb-1">{selectedNotification?.title}</div>
<div className="w-full notification-date">{humanizeDate(selectedNotification?.date)}</div> <div className="w-full notification-date text-xs mb-4">
{humanizeDate(selectedNotification?.date)}
</div>
<div <div
className="flex w-full flex-col flex-wrap h-fit" className="flex w-full flex-col flex-wrap h-fit"
dangerouslySetInnerHTML={{ __html: selectedNotification?.description }} dangerouslySetInnerHTML={{ __html: selectedNotification?.description }}

View File

@ -11,7 +11,7 @@ import { useSelector, useDispatch } from 'react-redux';
import { IconSettings, IconCookie, IconHeart } from '@tabler/icons'; import { IconSettings, IconCookie, IconHeart } from '@tabler/icons';
import { updateLeftSidebarWidth, updateIsDragging, showPreferences } from 'providers/ReduxStore/slices/app'; import { updateLeftSidebarWidth, updateIsDragging, showPreferences } from 'providers/ReduxStore/slices/app';
import { useTheme } from 'providers/Theme'; import { useTheme } from 'providers/Theme';
import Notifications from 'components/Notifications/index'; import Notifications from 'components/Notifications';
const MIN_LEFT_SIDEBAR_WIDTH = 221; const MIN_LEFT_SIDEBAR_WIDTH = 221;
const MAX_LEFT_SIDEBAR_WIDTH = 600; const MAX_LEFT_SIDEBAR_WIDTH = 600;

View File

@ -141,18 +141,6 @@ const GlobalStyle = createGlobalStyle`
} }
} }
@keyframes fade-and-pulse {
0% {
scale: 1;
}
20% {
scale: 1.5;
}
100% {
scale: 1;
}
}
@keyframes rotateClockwise { @keyframes rotateClockwise {
0% { 0% {
transform: scaleY(-1) rotate(0deg); transform: scaleY(-1) rotate(0deg);

View File

@ -5,6 +5,7 @@ import debugMiddleware from './middlewares/debug/middleware';
import appReducer from './slices/app'; import appReducer from './slices/app';
import collectionsReducer from './slices/collections'; import collectionsReducer from './slices/collections';
import tabsReducer from './slices/tabs'; import tabsReducer from './slices/tabs';
import notificationsReducer from './slices/notifications';
const { publicRuntimeConfig } = getConfig(); const { publicRuntimeConfig } = getConfig();
const isDevEnv = () => { const isDevEnv = () => {
@ -20,7 +21,8 @@ export const store = configureStore({
reducer: { reducer: {
app: appReducer, app: appReducer,
collections: collectionsReducer, collections: collectionsReducer,
tabs: tabsReducer tabs: tabsReducer,
notifications: notificationsReducer
}, },
middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(middleware) middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(middleware)
}); });

View File

@ -1,8 +1,6 @@
import { createSlice } from '@reduxjs/toolkit'; import { createSlice } from '@reduxjs/toolkit';
import filter from 'lodash/filter'; import filter from 'lodash/filter';
import toast from 'react-hot-toast'; import toast from 'react-hot-toast';
import { getReadNotificationIds, setReadNotificationsIds } from 'utils/common/notifications';
import { getAppInstallDate } from 'utils/common/platform';
const initialState = { const initialState = {
isDragging: false, isDragging: false,
@ -26,10 +24,7 @@ const initialState = {
} }
}, },
cookies: [], cookies: [],
taskQueue: [], taskQueue: []
notifications: [],
fetchingNotifications: false,
readNotificationIds: getReadNotificationIds() || []
}; };
export const appSlice = createSlice({ export const appSlice = createSlice({
@ -74,70 +69,6 @@ export const appSlice = createSlice({
}, },
removeAllTasksFromQueue: (state) => { removeAllTasksFromQueue: (state) => {
state.taskQueue = []; state.taskQueue = [];
},
fetchingNotifications: (state, action) => {
state.fetchingNotifications = action.payload.fetching;
},
updateNotifications: (state, action) => {
let notifications = action.payload.notifications || [];
let readNotificationIds = state.readNotificationIds;
// App installed date
let appInstalledOnDate = getAppInstallDate();
// date 5 days before
let dateFiveDaysBefore = new Date();
dateFiveDaysBefore.setDate(dateFiveDaysBefore.getDate() - 5);
// check if app was installed in the last 5 days
if (appInstalledOnDate > dateFiveDaysBefore) {
// filter out notifications that were sent before the app was installed
notifications = notifications.filter(
(notification) => new Date(notification.date) > new Date(appInstalledOnDate)
);
} else {
// filter out notifications that sent within the last 5 days
notifications = notifications.filter(
(notification) => new Date(notification.date) > new Date(dateFiveDaysBefore)
);
}
state.notifications = notifications.map((notification) => {
return {
...notification,
read: readNotificationIds.includes(notification.id)
};
});
},
markNotificationAsRead: (state, action) => {
let readNotificationIds = state.readNotificationIds;
readNotificationIds.push(action.payload.notificationId);
state.readNotificationIds = readNotificationIds;
// set the read notification ids in the localstorage
setReadNotificationsIds(readNotificationIds);
state.notifications = state.notifications.map((notification) => {
return {
...notification,
read: readNotificationIds.includes(notification.id)
};
});
},
markMultipleNotificationsAsRead: (state, action) => {
let readNotificationIds = state.readNotificationIds;
readNotificationIds.push(...action.payload.notificationIds);
state.readNotificationIds = readNotificationIds;
// set the read notification ids in the localstorage
setReadNotificationsIds(readNotificationIds);
state.notifications = state.notifications.map((notification) => {
return {
...notification,
read: readNotificationIds.includes(notification.id)
};
});
} }
} }
}); });
@ -155,12 +86,7 @@ export const {
updateCookies, updateCookies,
insertTaskIntoQueue, insertTaskIntoQueue,
removeTaskFromQueue, removeTaskFromQueue,
removeAllTasksFromQueue, removeAllTasksFromQueue
updateNotifications,
fetchingNotifications,
mergeNotifications,
markNotificationAsRead,
markMultipleNotificationsAsRead
} = appSlice.actions; } = appSlice.actions;
export const savePreferences = (preferences) => (dispatch, getState) => { export const savePreferences = (preferences) => (dispatch, getState) => {
@ -188,26 +114,6 @@ export const deleteCookiesForDomain = (domain) => (dispatch, getState) => {
}); });
}; };
export const fetchNotifications = () => (dispatch, getState) => {
return new Promise((resolve, reject) => {
const { ipcRenderer } = window;
dispatch(fetchingNotifications({ fetching: true }));
ipcRenderer
.invoke('renderer:fetch-notifications')
.then((notifications) => {
dispatch(updateNotifications({ notifications }));
dispatch(fetchingNotifications({ fetching: false }));
})
.then(resolve)
.catch((err) => {
toast.error('An error occurred while fetching notifications');
dispatch(fetchingNotifications({ fetching: false }));
console.error(err);
resolve();
});
});
};
export const completeQuitFlow = () => (dispatch, getState) => { export const completeQuitFlow = () => (dispatch, getState) => {
const { ipcRenderer } = window; const { ipcRenderer } = window;
return ipcRenderer.invoke('main:complete-quit-flow'); return ipcRenderer.invoke('main:complete-quit-flow');

View File

@ -0,0 +1,106 @@
import toast from 'react-hot-toast';
import { createSlice } from '@reduxjs/toolkit';
import { getAppInstallDate } from 'utils/common/platform';
const getReadNotificationIds = () => {
try {
let readNotificationIdsString = window.localStorage.getItem('bruno.notifications.read');
let readNotificationIds = readNotificationIdsString ? JSON.parse(readNotificationIdsString) : [];
return readNotificationIds;
} catch (err) {
toast.error('An error occurred while fetching read notifications');
}
};
const setReadNotificationsIds = (val) => {
try {
window.localStorage.setItem('bruno.notifications.read', JSON.stringify(val));
} catch (err) {
toast.error('An error occurred while setting read notifications');
}
};
const initialState = {
loading: false,
notifications: [],
readNotificationIds: getReadNotificationIds() || []
};
export const notificationSlice = createSlice({
name: 'notifications',
initialState,
reducers: {
setFetchingStatus: (state, action) => {
state.loading = action.payload.fetching;
},
setNotifications: (state, action) => {
console.log('notifications', notifications);
let notifications = action.payload.notifications || [];
let readNotificationIds = state.readNotificationIds;
// Ignore notifications sent before the app was installed
let appInstalledOnDate = getAppInstallDate();
notifications = notifications.filter((notification) => {
const notificationDate = new Date(notification.date);
const appInstalledOn = new Date(appInstalledOnDate);
notificationDate.setHours(0, 0, 0, 0);
appInstalledOn.setHours(0, 0, 0, 0);
return notificationDate >= appInstalledOn;
});
state.notifications = notifications.map((notification) => {
return {
...notification,
read: readNotificationIds.includes(notification.id)
};
});
},
markNotificationAsRead: (state, action) => {
if (state.readNotificationIds.includes(action.payload.notificationId)) return;
const notification = state.notifications.find(
(notification) => notification.id === action.payload.notificationId
);
if (!notification) return;
state.readNotificationIds.push(action.payload.notificationId);
setReadNotificationsIds(state.readNotificationIds);
notification.read = true;
},
markAllNotificationsAsRead: (state) => {
let readNotificationIds = state.notifications.map((notification) => notification.id);
state.readNotificationIds = readNotificationIds;
setReadNotificationsIds(readNotificationIds);
state.notifications.forEach((notification) => {
notification.read = true;
});
}
}
});
export const { setNotifications, setFetchingStatus, markNotificationAsRead, markAllNotificationsAsRead } =
notificationSlice.actions;
export const fetchNotifications = () => (dispatch, getState) => {
return new Promise((resolve) => {
const { ipcRenderer } = window;
dispatch(setFetchingStatus(true));
ipcRenderer
.invoke('renderer:fetch-notifications')
.then((notifications) => {
dispatch(setNotifications({ notifications }));
dispatch(setFetchingStatus(false));
resolve(notifications);
})
.catch((err) => {
dispatch(setFetchingStatus(false));
console.error(err);
resolve([]);
});
});
};
export default notificationSlice.reducer;

View File

@ -138,32 +138,16 @@ const darkTheme = {
notifications: { notifications: {
bg: '#3D3D3D', bg: '#3D3D3D',
settings: { list: {
bg: '#3D3D3D', bg: '3D3D3D',
sidebar: { borderRight: '#4f4f4f',
bg: '#3D3D3D', borderBottom: '#545454',
borderRight: '#4f4f4f' hoverBg: '#434343',
}, active: {
item: {
border: '#569cd6', border: '#569cd6',
hoverBg: 'transparent', bg: '#4f4f4f',
borderBottom: '#4f4f4f99', hoverBg: '#4f4f4f'
active: { }
bg: '#4f4f4f',
hoverBg: '#4f4f4f'
},
read: {
bg: '#4f4f4f55',
hoverBg: '#4f4f4f'
},
date: {
color: '#ccc9'
}
},
gridBorder: '#4f4f4f'
},
bell: {
count: '#cc7b1b55'
} }
}, },

View File

@ -141,36 +141,17 @@ const lightTheme = {
}, },
notifications: { notifications: {
bg: '#efefef', bg: 'white',
settings: { list: {
bg: 'white', bg: '#eaeaea',
sidebar: { borderRight: 'transparent',
bg: '#eaeaea', borderBottom: '#d3d3d3',
borderRight: 'transparent' hoverBg: '#e4e4e4',
}, active: {
item: {
border: '#546de5', border: '#546de5',
borderBottom: '#4f4f4f44', bg: '#dcdcdc',
hoverBg: '#e4e4e4', hoverBg: '#dcdcdc'
active: { }
bg: '#dcdcdc',
hoverBg: '#dcdcdc'
},
read: {
bg: '#dcdcdc55',
hoverBg: '#dcdcdc'
},
date: {
color: '#5f5f5f'
}
},
gridBorder: '#f4f4f4'
},
sidebar: {
bg: '#eaeaea'
},
bell: {
count: '#cc7b1b55'
} }
}, },

View File

@ -153,9 +153,6 @@ export const humanizeDate = (dateString) => {
return date.toLocaleDateString('en-US', { return date.toLocaleDateString('en-US', {
year: 'numeric', year: 'numeric',
month: 'long', month: 'long',
day: 'numeric', day: 'numeric'
hour: 'numeric',
minute: 'numeric',
second: 'numeric'
}); });
}; };

View File

@ -1,19 +0,0 @@
import toast from 'react-hot-toast';
export const getReadNotificationIds = () => {
try {
let readNotificationIdsString = window.localStorage.getItem('bruno.notifications.read');
let readNotificationIds = readNotificationIdsString ? JSON.parse(readNotificationIdsString) : [];
return readNotificationIds;
} catch (err) {
toast.error('An error occurred while fetching read notifications');
}
};
export const setReadNotificationsIds = (val) => {
try {
window.localStorage.setItem('bruno.notifications.read', JSON.stringify(val));
} catch (err) {
toast.error('An error occurred while setting read notifications');
}
};

View File

@ -30,7 +30,13 @@ const template = [
} }
}, },
{ type: 'separator' }, { type: 'separator' },
{ role: 'quit' } { role: 'quit' },
{
label: 'Force Quit',
click() {
process.exit();
}
}
] ]
}, },
{ {