From dad0995ffd4e428878f6767d9f1b687a04cd8893 Mon Sep 17 00:00:00 2001 From: urwithat Date: Tue, 29 Jun 2021 14:40:41 +0530 Subject: [PATCH 1/9] npm audit --- package-lock.json | 148 +++++++++++++++++++--------------------------- 1 file changed, 61 insertions(+), 87 deletions(-) diff --git a/package-lock.json b/package-lock.json index 82e5885..0b73009 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5569,9 +5569,9 @@ "dev": true }, "postcss": { - "version": "7.0.35", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", - "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "dev": true, "requires": { "chalk": "^2.4.2", @@ -5727,15 +5727,16 @@ } }, "css-select": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", - "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz", + "integrity": "sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA==", "dev": true, "requires": { "boolbase": "^1.0.0", - "css-what": "^3.2.1", - "domutils": "^1.7.0", - "nth-check": "^1.0.2" + "css-what": "^5.0.0", + "domhandler": "^4.2.0", + "domutils": "^2.6.0", + "nth-check": "^2.0.0" } }, "css-selector-tokenizer": { @@ -5749,9 +5750,9 @@ } }, "css-what": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz", - "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.0.1.tgz", + "integrity": "sha512-FYDTSHb/7KXsWICVsxdmiExPjCfRC4qRFBdVwv7Ax9hMnvMmEjP9RfxTEZ3qPZGmADDn2vAKSo9UcN1jKVYscg==", "dev": true }, "css.escape": { @@ -6098,9 +6099,9 @@ "dev": true }, "dns-packet": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz", - "integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.4.tgz", + "integrity": "sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA==", "dev": true, "requires": { "ip": "^1.1.0", @@ -6157,21 +6158,14 @@ } }, "dom-serializer": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", - "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", + "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", "dev": true, "requires": { "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", "entities": "^2.0.0" - }, - "dependencies": { - "domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", - "dev": true - } } }, "domain-browser": { @@ -6181,9 +6175,9 @@ "dev": true }, "domelementtype": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", + "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", "dev": true }, "domexception": { @@ -6196,22 +6190,23 @@ } }, "domhandler": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", - "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.2.0.tgz", + "integrity": "sha512-zk7sgt970kzPks2Bf+dwT/PLzghLnsivb9CcxkvR8Mzr66Olr0Ofd8neSbglHJHaHa2MadfoSdNlKYAaafmWfA==", "dev": true, "requires": { - "domelementtype": "1" + "domelementtype": "^2.2.0" } }, "domutils": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", - "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.7.0.tgz", + "integrity": "sha512-8eaHa17IwJUPAiB+SoTYBo5mCdeMgdcAoXJ59m6DT1vw+5iLS3gNoqYaRowaBKtGVrOF1Jz4yDTgYKLK2kvfJg==", "dev": true, "requires": { - "dom-serializer": "0", - "domelementtype": "1" + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" } }, "dot-case": { @@ -8414,36 +8409,15 @@ } }, "htmlparser2": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", - "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", "dev": true, "requires": { - "domelementtype": "^1.3.1", - "domhandler": "^2.3.0", - "domutils": "^1.5.1", - "entities": "^1.1.1", - "inherits": "^2.0.1", - "readable-stream": "^3.1.1" - }, - "dependencies": { - "entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", - "dev": true - }, - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" } }, "http-deceiver": { @@ -8553,9 +8527,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.35", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", - "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "dev": true, "requires": { "chalk": "^2.4.2", @@ -13570,12 +13544,12 @@ } }, "nth-check": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", - "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.0.tgz", + "integrity": "sha512-i4sc/Kj8htBrAiH1viZ0TgU8Y5XqCaV/FziYK6TBczxmeKm3AEFWqqF3195yKudrarqy7Zu80Ra5dobFjn9X/Q==", "dev": true, "requires": { - "boolbase": "~1.0.0" + "boolbase": "^1.0.0" } }, "num2fraction": { @@ -14345,9 +14319,9 @@ } }, "postcss": { - "version": "7.0.35", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", - "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "dev": true, "requires": { "chalk": "^2.4.2", @@ -15396,16 +15370,16 @@ "dev": true }, "renderkid": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.5.tgz", - "integrity": "sha512-ccqoLg+HLOHq1vdfYNm4TBeaCDIi1FLt3wGojTDSvdewUv65oTmI3cnT2E4hRjl1gzKZIPK+KZrXzlUYKnR+vQ==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.7.tgz", + "integrity": "sha512-oCcFyxaMrKsKcTY59qnCAtmDVSLfPbrv6A3tVbPdFMMrv5jaK10V6m40cKsoPNhAqN6rmHW9sswW4o3ruSrwUQ==", "dev": true, "requires": { - "css-select": "^2.0.2", - "dom-converter": "^0.2", - "htmlparser2": "^3.10.1", - "lodash": "^4.17.20", - "strip-ansi": "^3.0.0" + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^3.0.1" } }, "repeat-element": { @@ -18606,9 +18580,9 @@ } }, "ws": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.5.tgz", - "integrity": "sha512-xzyu3hFvomRfXKH8vOFMU3OguG6oOvhXMo3xsGy3xWExqaM2dxBbVxuD99O7m3ZUFMvvscsZDqxfgMaRr/Nr1g==", + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.1.tgz", + "integrity": "sha512-2c6faOUH/nhoQN6abwMloF7Iyl0ZS2E9HGtsiLrWn0zOOMWlhtDmdf/uihDt6jnuCxgtwGBNy6Onsoy2s2O2Ow==", "dev": true }, "xml-name-validator": { From dc556636dd0cef6517cc7824dbf18e1e87345109 Mon Sep 17 00:00:00 2001 From: Cagdas U Date: Tue, 27 Jul 2021 14:01:17 +0300 Subject: [PATCH 2/9] feat: add businessLogin function * Add `businessLogin` function, which redirects user to customer login flow. Addresses https://github.com/topcoder-platform/taas-app/issues/401 --- README.md | 3 +++ src/topcoder-micro-frontends-navbar-app.js | 3 ++- src/utils/index.js | 17 +++++++++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2cd51e4..d4cd21d 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,7 @@ Make sure you have [Heroky CLI](https://devcenter.heroku.com/articles/heroku-cli This app exports functions to be imported by other microapps. - `login` - redirects to login page +- `businessLogin` - redirects to business (i.e. customer) login page - `logout` - clears session storage and redirects to logout page - `setAppMenu` - sets sidebar menu for the app by app's `path` - `getAuthUserTokens` - returns a promise which resolves to object with user tokens `{ tokenV3, tokenV2 }` @@ -95,6 +96,7 @@ For example see https://github.com/topcoder-platform/micro-frontends-react-app ```js module.exports = { login: () => {}, + businessLogin: () => {}, logout: () => {}, setAppMenu: () => {}, getAuthUserTokens: () => new Promise(() => {}), @@ -121,6 +123,7 @@ For example see https://github.com/topcoder-platform/micro-frontends-angular-app ```js declare module '@topcoder/micro-frontends-navbar-app' { export const login: any; + export const businessLogin: any; export const logout: any; export const setAppMenu: any; export const getAuthUserTokens: any; diff --git a/src/topcoder-micro-frontends-navbar-app.js b/src/topcoder-micro-frontends-navbar-app.js index 5e146bd..f60723b 100644 --- a/src/topcoder-micro-frontends-navbar-app.js +++ b/src/topcoder-micro-frontends-navbar-app.js @@ -19,7 +19,7 @@ import { setNotificationPlatform, } from "./utils/exports"; -import { login, logout } from "./utils"; +import { login, businessLogin, logout } from "./utils"; import { PLATFORM } from "./constants/notifications"; const lifecycles = singleSpaReact({ @@ -37,6 +37,7 @@ export const { bootstrap, mount, unmount } = lifecycles; // list everything we want to export for other microapps here export { login, + businessLogin, logout, setAppMenu, getAuthUserTokens, diff --git a/src/utils/index.js b/src/utils/index.js index 5f37fa2..66be7c6 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -16,6 +16,16 @@ export const getLoginUrl = () => window.location.href.match(/[^?]*/)[0] )}`; +/** + * Generate Business Login URL + */ +export const getBusinessLoginUrl = () => + `${ + config.URL.AUTH + }?regSource=tcBusiness&mode=login&retUrl=${encodeURIComponent( + window.location.href.match(/[^?]*/)[0] + )}`; + /** * Logout user from Topcoder */ @@ -30,3 +40,10 @@ export const logout = () => { export const login = () => { window.location = getLoginUrl(); }; + +/** + * Forward user to business login page + */ +export const businessLogin = () => { + window.location = getBusinessLoginUrl(); +}; From cc1d3cdde98102572e7b85dede1c78517f603521 Mon Sep 17 00:00:00 2001 From: yoution Date: Wed, 11 Aug 2021 14:29:03 +0800 Subject: [PATCH 3/9] fix: tass issue #435 --- src/utils/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/index.js b/src/utils/index.js index 66be7c6..c827f83 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -22,7 +22,7 @@ export const getLoginUrl = () => export const getBusinessLoginUrl = () => `${ config.URL.AUTH - }?regSource=tcBusiness&mode=login&retUrl=${encodeURIComponent( + }?regSource=taasApp&mode=login&retUrl=${encodeURIComponent( window.location.href.match(/[^?]*/)[0] )}`; From 163bbfda4d01a445b009e6d071f3fbcca0d8499c Mon Sep 17 00:00:00 2001 From: Nguyen Viet Date: Thu, 12 Aug 2021 15:24:43 +0700 Subject: [PATCH 4/9] implements issue 477 --- config/dev.js | 1 + config/prod.js | 1 + src/actions/notifications.js | 25 ++- .../NotificationsEmpty/index.jsx | 2 +- src/constants/notifications.js | 54 ++++++- .../NotificationsContainer/index.jsx | 4 +- .../NotificationsDropdownContainer/index.jsx | 30 ++-- src/reducers/notifications.js | 9 +- src/services/notifications.js | 10 ++ src/utils/notifications.js | 143 ++++++------------ 10 files changed, 146 insertions(+), 133 deletions(-) diff --git a/config/dev.js b/config/dev.js index 68dd4ca..c0320e9 100644 --- a/config/dev.js +++ b/config/dev.js @@ -5,6 +5,7 @@ module.exports = { TC_NOTIFICATION_URL: "https://api.topcoder-dev.com/v5/notifications", CONNECT_DOMAIN: "https://connect.topcoder-dev.com", COMMUNITY_DOMAIN: "https://www.topcoder-dev.com", + TAAS_APP: "https://platform.topcoder-dev.com/taas/myteams", }, API: { V3: "https://api.topcoder-dev.com/v3", diff --git a/config/prod.js b/config/prod.js index 8054083..ee7b020 100644 --- a/config/prod.js +++ b/config/prod.js @@ -5,6 +5,7 @@ module.exports = { TC_NOTIFICATION_URL: "https://api.topcoder.com/v5/notifications", CONNECT_DOMAIN: "https://connect.topcoder.com", COMMUNITY_DOMAIN: "https://www.topcoder.com", + TAAS_APP: "https://platform.topcoder.com/taas/myteams", }, API: { V3: "https://api.topcoder.com/v3", diff --git a/src/actions/notifications.js b/src/actions/notifications.js index ca1bab3..073d4da 100644 --- a/src/actions/notifications.js +++ b/src/actions/notifications.js @@ -19,7 +19,6 @@ import { NOTIFICATIONS_PENDING, SET_NOTIFICATION_PLATFORM, RESET_NOTIFICATIONS, - RESET_COMMUNITY_NOTIFICATIONS, } from "../constants/notifications"; import notificationsService from "../services/notifications"; import { @@ -83,6 +82,25 @@ export const getNotifications = () => (dispatch) => { }); }; +export const getTaaSNotifications = () => (dispatch) => { + dispatch({ type: GET_NOTIFICATIONS_PENDING }); + notificationsService + .getTaaSNotifications() + .then((notifications) => { + dispatch({ + type: GET_NOTIFICATIONS_SUCCESS, + payload: notifications, + }); + }) + .catch((err) => { + dispatch({ + type: GET_NOTIFICATIONS_FAILURE, + payload: err, + }); + console.error(`Failed to load notifications. ${err.message}`); + }); +}; + export const getCommunityNotifications = () => (dispatch) => { dispatch({ type: GET_COMMUNITY_NOTIFICATIONS_PENDING }); notificationsService @@ -243,10 +261,6 @@ export const resetNotifications = () => (dispatch) => { dispatch({ type: RESET_NOTIFICATIONS }); }; -export const resetCommunityNotifications = () => (dispatch) => { - dispatch({ type: RESET_COMMUNITY_NOTIFICATIONS }); -}; - export default { getNotifications, getCommunityNotifications, @@ -262,5 +276,4 @@ export default { markNotificationsRead, setNotificationPlatform, resetNotifications, - resetCommunityNotifications, }; diff --git a/src/components/Notifications/NotificationsEmpty/index.jsx b/src/components/Notifications/NotificationsEmpty/index.jsx index ea7a6cd..ffd204a 100644 --- a/src/components/Notifications/NotificationsEmpty/index.jsx +++ b/src/components/Notifications/NotificationsEmpty/index.jsx @@ -8,7 +8,7 @@ import Bell from "../../../assets/icons/bell.svg"; const NotificationsEmpty = ({ children, - message = "Good job! You�re all caught up", + message = "Good job! You’re all caught up", }) => (
diff --git a/src/constants/notifications.js b/src/constants/notifications.js index 4b39ebd..6867758 100644 --- a/src/constants/notifications.js +++ b/src/constants/notifications.js @@ -23,7 +23,6 @@ export const NOTIFICATIONS_PENDING = "NOTIFICATIONS_PENDING"; export const MARK_NOTIFICATIONS_READ = "MARK_NOTIFICATIONS_READ"; export const SET_NOTIFICATION_PLATFORM = "SET_NOTIFICATION_PLATFORM"; export const RESET_NOTIFICATIONS = "RESET_NOTIFICATIONS"; -export const RESET_COMMUNITY_NOTIFICATIONS = "RESET_COMMUNITY_NOTIFICATIONS"; /* * Project member role @@ -76,7 +75,7 @@ export const NOTIFICATIONS_LIMIT = 1000; export const PLATFORM = { CONNECT: "connect", COMMUNITY: "community", - BOTH: "connect+community", + TAAS: "taas", }; // Notifications event types @@ -141,6 +140,11 @@ export const EVENT_TYPE = { COMPLETED: "challenge.notification.completed", }, BROADCAST: "admin.notification.broadcast", + TAAS: { + POST_INTERVIEW_ACTION_REQUIRED: 'taas.notification.post-interview-action-required', + RESOURCE_BOOKING_EXPIRATION: 'taas.notification.resource-booking-expiration', + RESOURCE_BOOKING_PLACED: 'taas.notification.resource-booking-placed', + }, }; export const NOTIFICATION_TYPE = { @@ -152,6 +156,7 @@ export const NOTIFICATION_TYPE = { MEMBER_ADDED: "member-added", CHALLENGE: "challenge", BROADCAST: "broadcast", + TAAS: "taas", }; /* @@ -169,6 +174,8 @@ export const GOTO = { PHASE: `${config.URL.CONNECT_DOMAIN}/projects/{{projectId}}/plan#phase-{{phaseId}}`, TOPCODER_TEAM: `${config.URL.CONNECT_DOMAIN}/projects/{{projectId}}#manageTopcoderTeam`, CHALLENGE: `${config.URL.COMMUNITY_DOMAIN}/challenges/{{id}}`, + TAAS_CANDIDATES_INTERVIEWS: `${config.URL.TAAS_APP}/{{projectId}}/positions/{{jobId}}/candidates/interviews`, + TAAS_PROJECT: `${config.URL.TAAS_APP}/{{projectId}}` }; // each notification can be displayed differently depend on WHO see them @@ -1226,6 +1233,8 @@ export const NOTIFICATIONS = [ ], }, + /// Community notification rules + { eventType: EVENT_TYPE.CHALLENGE.ACTIVE, type: NOTIFICATION_TYPE.CHALLENGE, @@ -1258,6 +1267,47 @@ export const NOTIFICATIONS = [ }, ], }, + + /// TaaS notification rules + + { + version: 1, + eventType: EVENT_TYPE.TAAS.POST_INTERVIEW_ACTION_REQUIRED, + type: NOTIFICATION_TYPE.TAAS, + rules: [ + { + text: "Candidate action required for {{userHandle}} in job {{jobTitle}} of the team {{teamName}}", + shouldBundle: false, + goTo: GOTO.TAAS_CANDIDATES_INTERVIEWS, + } + ], + }, + + { + version: 1, + eventType: EVENT_TYPE.TAAS.RESOURCE_BOOKING_EXPIRATION, + type: NOTIFICATION_TYPE.TAAS, + rules: [ + { + text: "{{numOfExpiringResourceBookings}} resource booking{{s}} {{be}} expiring in the team {{teamName}}", + shouldBundle: false, + goTo: GOTO.TAAS_PROJECT, + } + ], + }, + + { + version: 1, + eventType: EVENT_TYPE.TAAS.RESOURCE_BOOKING_PLACED, + type: NOTIFICATION_TYPE.TAAS, + rules: [ + { + text: "Resource {{userHandle}} is placed for the job {{jobTitle}} of the team {{teamName}}", + shouldBundle: false, + goTo: GOTO.TAAS_PROJECT, + } + ], + }, ]; // list of ignored notifications diff --git a/src/containers/NotificationsContainer/index.jsx b/src/containers/NotificationsContainer/index.jsx index 93f2278..2e52611 100644 --- a/src/containers/NotificationsContainer/index.jsx +++ b/src/containers/NotificationsContainer/index.jsx @@ -279,7 +279,7 @@ class NotificationsContainer extends Component { render() { const { notifications, communityNotifications, ...restProps } = this.props; const preRenderedNotifications = preRenderNotifications(notifications); - const preRenderedNotifications2 = preRenderCommunityNotifications( + const preRenderedCommunityNotifications = preRenderCommunityNotifications( communityNotifications ); @@ -288,7 +288,7 @@ class NotificationsContainer extends Component { {...{ ...restProps, notifications: preRenderedNotifications, - communityNotifications: preRenderedNotifications2, + communityNotifications: preRenderedCommunityNotifications, }} /> ); diff --git a/src/containers/NotificationsDropdownContainer/index.jsx b/src/containers/NotificationsDropdownContainer/index.jsx index f580b5a..5f38966 100644 --- a/src/containers/NotificationsDropdownContainer/index.jsx +++ b/src/containers/NotificationsDropdownContainer/index.jsx @@ -11,6 +11,7 @@ import { TransitionGroup, Transition } from "react-transition-group"; import { getNotifications, getCommunityNotifications, + getTaaSNotifications, toggleNotificationSeen, markAllNotificationsRead, markAllNotificationsSeen, @@ -19,7 +20,6 @@ import { viewOlderNotifications, hideOlderNotifications, resetNotifications, - resetCommunityNotifications, } from "../../actions/notifications"; import { splitNotificationsBySources, @@ -70,6 +70,7 @@ const NotificationsDropdownContainerView = (props) => { toggleNotificationsDropdownMobile, toggleNotificationsDropdownWeb, markAllNotificationsSeen, + platform, } = props; if ( (!initialized && isLoading) || @@ -154,8 +155,9 @@ const NotificationsDropdownContainerView = (props) => { ); if ( - (!isLoading && !initialized) || - (!isCommunityLoading && !communityInitialized) + (!isLoading && !initialized && platform == PLATFORM.CONNECT) || + (!isLoading && !initialized && platform == PLATFORM.TAAS) || + (!isCommunityLoading && !communityInitialized && platform == PLATFORM.COMMUNITY) ) { notificationsEmpty = ( @@ -543,10 +545,14 @@ class NotificationsDropdownContainer extends React.Component { } componentWillReceiveProps(nextProps) { - const { platform: oldPlatform } = this.props; + const { + platform: oldPlatform, + resetNotifications, + } = this.props; const { platform } = nextProps; if (platform !== oldPlatform) { + resetNotifications(); this.getPlatformNotifications(platform); } } @@ -555,23 +561,17 @@ class NotificationsDropdownContainer extends React.Component { const { getNotifications, getCommunityNotifications, + getTaaSNotifications, platform, - resetNotifications, - resetCommunityNotifications, } = this.props; p = p || platform; - if (p === PLATFORM.BOTH) { - resetNotifications(); - resetCommunityNotifications(); - getNotifications(); - getCommunityNotifications(); - } else if (p === PLATFORM.CONNECT) { - resetCommunityNotifications(); + if (p === PLATFORM.CONNECT) { getNotifications(); + } else if (p === PLATFORM.TAAS) { + getTaaSNotifications(); } else { - resetNotifications(); getCommunityNotifications(); } } @@ -619,6 +619,7 @@ const mapStateToProps = ({ notifications }) => notifications; const mapDispatchToProps = { getNotifications, getCommunityNotifications, + getTaaSNotifications, toggleNotificationSeen, markAllNotificationsRead, markAllNotificationsSeen, @@ -627,7 +628,6 @@ const mapDispatchToProps = { viewOlderNotifications, hideOlderNotifications, resetNotifications, - resetCommunityNotifications, }; export default connect( diff --git a/src/reducers/notifications.js b/src/reducers/notifications.js index f638f3e..7033fa0 100644 --- a/src/reducers/notifications.js +++ b/src/reducers/notifications.js @@ -20,7 +20,6 @@ import { SET_NOTIFICATION_PLATFORM, PLATFORM, RESET_NOTIFICATIONS, - RESET_COMMUNITY_NOTIFICATIONS, } from "../constants/notifications"; import _ from "lodash"; import { getActiveAndBroadcastNotifications } from "../utils/notifications"; @@ -266,14 +265,10 @@ export default (state = initialState, action) => { case RESET_NOTIFICATIONS: return { ...state, + filterBy: "", notifications: [], - sources: [], - }; - - case RESET_COMMUNITY_NOTIFICATIONS: - return { - ...state, communityNotifications: [], + sources: [], communitySources: [], }; diff --git a/src/services/notifications.js b/src/services/notifications.js index 93e10d6..3cd0f84 100644 --- a/src/services/notifications.js +++ b/src/services/notifications.js @@ -5,6 +5,7 @@ import { URL } from "../../config"; import { prepareNotifications, prepareCommunityNotifications, + prepareTaaSNotifications, } from "../utils/notifications"; const logger = console; @@ -51,6 +52,14 @@ const getNotifications = () => { .then((resp) => prepareNotifications(resp.data.items)); }; +const getTaaSNotifications = () => { + return axiosInstance + .get( + `${URL.TC_NOTIFICATION_URL}/list?read=false&platform=taas&per_page=${NOTIFICATIONS_LIMIT}` + ) + .then((resp) => prepareTaaSNotifications(resp.data.items)); +}; + const getCommunityNotifications = () => { return axiosInstance .get( @@ -64,4 +73,5 @@ export default { getCommunityNotifications, markNotificationsRead, markNotificationsSeen, + getTaaSNotifications, }; diff --git a/src/utils/notifications.js b/src/utils/notifications.js index c382379..c9e26b1 100644 --- a/src/utils/notifications.js +++ b/src/utils/notifications.js @@ -244,105 +244,6 @@ export const filterReadNotifications = (notifications) => export const filterSeenNotifications = (notifications) => _.filter(notifications, { seen: false }); -/** - * Filter notifications that belongs to project:projectId - * - * @param {Array} notifications list of notifications - * - * @param {Number} projectId - * - * @return {Array} notifications list filtered of notifications - */ -export const filterNotificationsByProjectId = (notifications, projectId) => - _.filter(notifications, (notification) => { - return notification.sourceId === `${projectId}`; - }); - -/** - * Filter notifications about Topic and Post changed - * - * @param {Array} notifications list of notifications - * @param {RegExp} [tagRegExp] regexp to filter notification by tags - * - * @return {Array} notifications list filtered of notifications - */ -export const filterTopicAndPostChangedNotifications = ( - notifications, - tagRegExp -) => { - let topicAndPostNotifications = _.filter( - notifications, - (notification) => - notification.eventType === EVENT_TYPE.TOPIC.CREATED || - notification.eventType === EVENT_TYPE.POST.CREATED || - notification.eventType === EVENT_TYPE.POST.UPDATED || - notification.eventType === EVENT_TYPE.POST.MENTION - ); - - // filter messages using `tags` - if (tagRegExp) { - topicAndPostNotifications = _.filter( - topicAndPostNotifications, - (notification) => { - const tags = _.get(notification, "contents.tags", []); - - return _.some(tags, (tag) => tagRegExp.test(tag)); - } - ); - } - - return topicAndPostNotifications; -}; - -/** - * Filter notifications about Link and File changed - * - * @param {Array} notifications list of notifications - * - * @return {Array} notifications list filtered of notifications - */ -export const filterFileAndLinkChangedNotifications = (notifications) => { - return _.filter( - notifications, - (notification) => - notification.eventType === EVENT_TYPE.PROJECT.FILE_UPLOADED || - notification.eventType === EVENT_TYPE.PROJECT.LINK_CREATED - ); -}; - -/** - * Filter notification about post mentions - * @param {Array} notifications list of notifications - * - * @return {Array} notifications list filtered by post mention event type - */ -export const filterPostsMentionNotifications = (notifications) => - _.filter(notifications, (notification) => { - return notification.eventType === EVENT_TYPE.POST.MENTION; - }); - -/** - * Filter notifications about the project - * - * @param {Array} notifications list of notifications - * - * @return {Array} notifications list filtered of notifications - */ -export const filterProjectNotifications = (notifications) => - _.filter(notifications, (notification) => { - return ( - notification.eventType === EVENT_TYPE.PROJECT.CREATED || - notification.eventType === EVENT_TYPE.PROJECT.APPROVED || - notification.eventType === EVENT_TYPE.PROJECT.PAUSED || - notification.eventType === EVENT_TYPE.PROJECT.COMPLETED || - notification.eventType === EVENT_TYPE.PROJECT.SPECIFICATION_MODIFIED || - notification.eventType === EVENT_TYPE.PROJECT.SUBMITTED_FOR_REVIEW || - notification.eventType === EVENT_TYPE.PROJECT.FILE_UPLOADED || - notification.eventType === EVENT_TYPE.PROJECT.CANCELED || - notification.eventType === EVENT_TYPE.PROJECT.LINK_CREATED - ); - }); - /** * Limits notifications quantity per source * @@ -669,7 +570,49 @@ export const preRenderNotifications = (notifications) => { return preRenderedNotifications; }; -//----- // +// --- TaaS --- // + +export const prepareTaaSNotifications = (rawNotifications) => { + const notifications = rawNotifications.map((rawNotification) => ({ + id: `${rawNotification.id}`, + sourceId: rawNotification.contents.projectId + ? `${rawNotification.contents.projectId}` + : "team", + sourceName: rawNotification.contents.projectId + ? rawNotification.contents.teamName || "Team" + : "Global", + eventType: rawNotification.type, + date: rawNotification.createdAt, + isRead: rawNotification.read, + seen: rawNotification.seen, + contents: rawNotification.contents, + version: rawNotification.version, + })); + + notifications.forEach((notification) => { + const notificationRule = getNotificationRule(notification); + + if (notificationRule) { + notification.type = notificationRule.type; + if (notificationRule.goTo) { + notification.goto = renderGoTo( + notificationRule.goTo, + notification.contents + ); + } + notification.rule = notificationRule; + } else { + console.warn( + `Cannot find notification rule for eventType '${notification.eventType}' version '${notification.version}'.` + ); + } + }); + + return notifications; +} + +// --- Community --- // + const getCommunityNotificationRule = (notification) => { const notificationRule = _.find(NOTIFICATION_RULES, (_notificationRule) => { return _notificationRule.eventType === notification.eventType; From 5ad49e91b4dcc95271a62b191229ca9275c8b20e Mon Sep 17 00:00:00 2001 From: Nguyen Viet Date: Thu, 12 Aug 2021 23:33:50 +0700 Subject: [PATCH 5/9] lint-fix --- jest.config.js | 2 +- server.js | 10 ++--- src/components/Menu/index.jsx | 18 ++++----- src/constants/apps.js | 38 +++++++++---------- src/constants/notifications.js | 16 ++++---- .../NotificationsDropdownContainer/index.jsx | 9 ++--- src/utils/index.js | 4 +- src/utils/notifications.js | 2 +- webpack.config.js | 3 ++ 9 files changed, 52 insertions(+), 50 deletions(-) diff --git a/jest.config.js b/jest.config.js index add373e..0b2e6e7 100644 --- a/jest.config.js +++ b/jest.config.js @@ -6,7 +6,7 @@ module.exports = { transformIgnorePatterns: ["node_modules/?!(tc-auth-lib)"], moduleNameMapper: { "\\.(css|scss)$": "identity-obj-proxy", - "\\.svg$": "/__mocks__/fileMock.js", + "\\.(png|eot|otf|ttf|woff|woff2|svg)$": "/__mocks__/fileMock.js", }, setupFilesAfterEnv: [ "../node_modules/@testing-library/jest-dom/dist/index.js", diff --git a/server.js b/server.js index e3e2927..1e44b08 100644 --- a/server.js +++ b/server.js @@ -1,5 +1,5 @@ /* global process */ -const express = require('express'); +const express = require("express"); const app = express(); @@ -7,11 +7,11 @@ app.use( "/navbar", express.static("./dist", { setHeaders: function setHeaders(res) { - res.header('Access-Control-Allow-Origin', '*'); - res.header('Access-Control-Allow-Methods', 'GET'); + res.header("Access-Control-Allow-Origin", "*"); + res.header("Access-Control-Allow-Methods", "GET"); res.header( - 'Access-Control-Allow-Headers', - 'Origin, X-Requested-With, Content-Type, Accept' + "Access-Control-Allow-Headers", + "Origin, X-Requested-With, Content-Type, Accept" ); }, }) diff --git a/src/components/Menu/index.jsx b/src/components/Menu/index.jsx index 408758c..c941bb0 100644 --- a/src/components/Menu/index.jsx +++ b/src/components/Menu/index.jsx @@ -3,18 +3,18 @@ * * General component to show menu with submenu. */ -import React, { Fragment, useCallback, useState } from 'react'; -import { useLocation } from '@reach/router'; -import cn from 'classnames'; -import { includes, map } from 'lodash'; -import NavLink from '../NavLink'; -import './styles.css'; +import React, { Fragment, useCallback, useState } from "react"; +import { useLocation } from "@reach/router"; +import cn from "classnames"; +import { includes, map } from "lodash"; +import NavLink from "../NavLink"; +import "./styles.css"; const SubMenu = ({ option }) => { const location = useLocation(); const [isOpen, setIsOpen] = useState( - includes(map(option.children, 'path'), location.pathname) + includes(map(option.children, "path"), location.pathname) ); const toggleOpen = useCallback(() => { @@ -24,8 +24,8 @@ const SubMenu = ({ option }) => { return ( <> {{userHandle}} in job {{jobTitle}} of the team {{teamName}}", shouldBundle: false, goTo: GOTO.TAAS_CANDIDATES_INTERVIEWS, - } + }, ], }, @@ -1292,7 +1294,7 @@ export const NOTIFICATIONS = [ text: "{{numOfExpiringResourceBookings}} resource booking{{s}} {{be}} expiring in the team {{teamName}}", shouldBundle: false, goTo: GOTO.TAAS_PROJECT, - } + }, ], }, @@ -1305,7 +1307,7 @@ export const NOTIFICATIONS = [ text: "Resource {{userHandle}} is placed for the job {{jobTitle}} of the team {{teamName}}", shouldBundle: false, goTo: GOTO.TAAS_PROJECT, - } + }, ], }, ]; diff --git a/src/containers/NotificationsDropdownContainer/index.jsx b/src/containers/NotificationsDropdownContainer/index.jsx index 5f38966..f41f607 100644 --- a/src/containers/NotificationsDropdownContainer/index.jsx +++ b/src/containers/NotificationsDropdownContainer/index.jsx @@ -157,7 +157,9 @@ const NotificationsDropdownContainerView = (props) => { if ( (!isLoading && !initialized && platform == PLATFORM.CONNECT) || (!isLoading && !initialized && platform == PLATFORM.TAAS) || - (!isCommunityLoading && !communityInitialized && platform == PLATFORM.COMMUNITY) + (!isCommunityLoading && + !communityInitialized && + platform == PLATFORM.COMMUNITY) ) { notificationsEmpty = ( @@ -545,10 +547,7 @@ class NotificationsDropdownContainer extends React.Component { } componentWillReceiveProps(nextProps) { - const { - platform: oldPlatform, - resetNotifications, - } = this.props; + const { platform: oldPlatform, resetNotifications } = this.props; const { platform } = nextProps; if (platform !== oldPlatform) { diff --git a/src/utils/index.js b/src/utils/index.js index c827f83..30e94c6 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -20,9 +20,7 @@ export const getLoginUrl = () => * Generate Business Login URL */ export const getBusinessLoginUrl = () => - `${ - config.URL.AUTH - }?regSource=taasApp&mode=login&retUrl=${encodeURIComponent( + `${config.URL.AUTH}?regSource=taasApp&mode=login&retUrl=${encodeURIComponent( window.location.href.match(/[^?]*/)[0] )}`; diff --git a/src/utils/notifications.js b/src/utils/notifications.js index c9e26b1..9d312f3 100644 --- a/src/utils/notifications.js +++ b/src/utils/notifications.js @@ -609,7 +609,7 @@ export const prepareTaaSNotifications = (rawNotifications) => { }); return notifications; -} +}; // --- Community --- // diff --git a/webpack.config.js b/webpack.config.js index 4b31b48..fa827be 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -14,6 +14,9 @@ module.exports = (webpackConfigEnv, options) => { disableHtmlGeneration: true, }); + const unusedFilesWebpackPlugin = defaultConfig.plugins.find(p => p.constructor.name === "UnusedFilesWebpackPlugin"); + unusedFilesWebpackPlugin.globOptions.ignore.push("**/assets/icons/*.svg", "**/__mocks__/**"); + let cssLocalIdent; if (options.mode === "production") { cssLocalIdent = "[hash:base64:6]"; From cd5cbfbf6e9d2ec090391ddfd91f89aedfa50c9a Mon Sep 17 00:00:00 2001 From: Nguyen Viet Date: Thu, 12 Aug 2021 23:36:42 +0700 Subject: [PATCH 6/9] fix for plural notification text --- src/constants/notifications.js | 9 ++++++++- src/utils/notifications.js | 22 +++++++++++++++++++++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/constants/notifications.js b/src/constants/notifications.js index fc73395..7351877 100644 --- a/src/constants/notifications.js +++ b/src/constants/notifications.js @@ -1291,7 +1291,14 @@ export const NOTIFICATIONS = [ type: NOTIFICATION_TYPE.TAAS, rules: [ { - text: "{{numOfExpiringResourceBookings}} resource booking{{s}} {{be}} expiring in the team {{teamName}}", + textIsPlural: true, + text: "{{numOfExpiringResourceBookings}} resource bookings are expiring in the team {{teamName}}", + shouldBundle: false, + goTo: GOTO.TAAS_PROJECT, + }, + { + textIsPlural: false, + text: "{{numOfExpiringResourceBookings}} resource booking is expiring in the team {{teamName}}", shouldBundle: false, goTo: GOTO.TAAS_PROJECT, }, diff --git a/src/utils/notifications.js b/src/utils/notifications.js index 9d312f3..1de5e9a 100644 --- a/src/utils/notifications.js +++ b/src/utils/notifications.js @@ -319,6 +319,12 @@ const getNotificationRule = (notification) => { ); } + if (notification.contents.textIsPlural != null) { + match = + match && + notification.contents.textIsPlural === _notificationRule.textIsPlural; + } + return match; }); @@ -572,6 +578,17 @@ export const preRenderNotifications = (notifications) => { // --- TaaS --- // +const prepareTaaSNotificationContents = (eventType, contents) => { + if (eventType === EVENT_TYPE.TAAS.RESOURCE_BOOKING_EXPIRATION) { + return { + ...contents, + textIsPlural: contents.numOfExpiringResourceBookings > 1, + }; + } + + return contents; +}; + export const prepareTaaSNotifications = (rawNotifications) => { const notifications = rawNotifications.map((rawNotification) => ({ id: `${rawNotification.id}`, @@ -585,7 +602,10 @@ export const prepareTaaSNotifications = (rawNotifications) => { date: rawNotification.createdAt, isRead: rawNotification.read, seen: rawNotification.seen, - contents: rawNotification.contents, + contents: prepareTaaSNotificationContents( + rawNotification.type, + rawNotification.contents + ), version: rawNotification.version, })); From a551663a69e2e475405137ba509eda0b68885320 Mon Sep 17 00:00:00 2001 From: Nguyen Viet Date: Fri, 13 Aug 2021 00:08:07 +0700 Subject: [PATCH 7/9] fix for bundling taas notifications --- src/utils/notifications.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utils/notifications.js b/src/utils/notifications.js index 1de5e9a..8ab05ef 100644 --- a/src/utils/notifications.js +++ b/src/utils/notifications.js @@ -352,6 +352,7 @@ const isNotificationRuleEqual = (rule1, rule2) => { "projectRole", "topcoderRole", "originator", + "textIsPlural", ]; const essentialRule1 = _.pick(rule1, ESSENTIAL_RULE_PROPERTIES); const essentialRule2 = _.pick(rule2, ESSENTIAL_RULE_PROPERTIES); From d1d4ebff91576309f045fef04f7bff5b7e7c12ce Mon Sep 17 00:00:00 2001 From: Nguyen Viet Date: Fri, 13 Aug 2021 16:12:35 +0700 Subject: [PATCH 8/9] proper fix for notification's plural text --- src/constants/notifications.js | 9 +------- src/utils/notifications.js | 41 ++++++++++++++++------------------ 2 files changed, 20 insertions(+), 30 deletions(-) diff --git a/src/constants/notifications.js b/src/constants/notifications.js index 7351877..ade9978 100644 --- a/src/constants/notifications.js +++ b/src/constants/notifications.js @@ -1291,14 +1291,7 @@ export const NOTIFICATIONS = [ type: NOTIFICATION_TYPE.TAAS, rules: [ { - textIsPlural: true, - text: "{{numOfExpiringResourceBookings}} resource bookings are expiring in the team {{teamName}}", - shouldBundle: false, - goTo: GOTO.TAAS_PROJECT, - }, - { - textIsPlural: false, - text: "{{numOfExpiringResourceBookings}} resource booking is expiring in the team {{teamName}}", + text: "{{numOfExpiringResourceBookings}} resource booking{{pluralize numOfExpiringResourceBookings '' 's'}} {{pluralize numOfExpiringResourceBookings 'is' 'are'}} expiring in the team {{teamName}}", shouldBundle: false, goTo: GOTO.TAAS_PROJECT, }, diff --git a/src/utils/notifications.js b/src/utils/notifications.js index 8ab05ef..38d2cf0 100644 --- a/src/utils/notifications.js +++ b/src/utils/notifications.js @@ -59,9 +59,27 @@ const handlebarsFallbackHelper = (value, fallbackValue) => { return new Handlebars.SafeString(out); }; +/** + * Handlebars helper which displays single or plural noun + * + * Example: + * ``` + * {{pluralize count resource resources}} + * ``` + * Will output `resource` if `count` equals or less than 1; otherwise `resources` + * + * @param {Number} count quantity + * @param {String} single noun + * @param {String} plural nouns + */ +const handlebarsPluralizeHelper = (number, single, plural) => { + return number > 1 ? plural : single; +}; + // register handlebars helpers Handlebars.registerHelper("showMore", handlebarsShowMoreHelper); Handlebars.registerHelper("fallback", handlebarsFallbackHelper); +Handlebars.registerHelper("pluralize", handlebarsPluralizeHelper); export const renderGoTo = (goTo, contents) => { let goToHandlebars = ""; @@ -319,12 +337,6 @@ const getNotificationRule = (notification) => { ); } - if (notification.contents.textIsPlural != null) { - match = - match && - notification.contents.textIsPlural === _notificationRule.textIsPlural; - } - return match; }); @@ -352,7 +364,6 @@ const isNotificationRuleEqual = (rule1, rule2) => { "projectRole", "topcoderRole", "originator", - "textIsPlural", ]; const essentialRule1 = _.pick(rule1, ESSENTIAL_RULE_PROPERTIES); const essentialRule2 = _.pick(rule2, ESSENTIAL_RULE_PROPERTIES); @@ -579,17 +590,6 @@ export const preRenderNotifications = (notifications) => { // --- TaaS --- // -const prepareTaaSNotificationContents = (eventType, contents) => { - if (eventType === EVENT_TYPE.TAAS.RESOURCE_BOOKING_EXPIRATION) { - return { - ...contents, - textIsPlural: contents.numOfExpiringResourceBookings > 1, - }; - } - - return contents; -}; - export const prepareTaaSNotifications = (rawNotifications) => { const notifications = rawNotifications.map((rawNotification) => ({ id: `${rawNotification.id}`, @@ -603,10 +603,7 @@ export const prepareTaaSNotifications = (rawNotifications) => { date: rawNotification.createdAt, isRead: rawNotification.read, seen: rawNotification.seen, - contents: prepareTaaSNotificationContents( - rawNotification.type, - rawNotification.contents - ), + contents: rawNotification.contents, version: rawNotification.version, })); From 9b0d8dc396e1c350568666a70f9b1cba45e2512d Mon Sep 17 00:00:00 2001 From: Nguyen Viet Date: Fri, 13 Aug 2021 16:22:37 +0700 Subject: [PATCH 9/9] fix plural text with negative value --- src/utils/notifications.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils/notifications.js b/src/utils/notifications.js index 38d2cf0..ff49cb7 100644 --- a/src/utils/notifications.js +++ b/src/utils/notifications.js @@ -66,14 +66,14 @@ const handlebarsFallbackHelper = (value, fallbackValue) => { * ``` * {{pluralize count resource resources}} * ``` - * Will output `resource` if `count` equals or less than 1; otherwise `resources` + * Will output `resource` if `count` equals 0 or 1; otherwise `resources` * * @param {Number} count quantity * @param {String} single noun * @param {String} plural nouns */ const handlebarsPluralizeHelper = (number, single, plural) => { - return number > 1 ? plural : single; + return Math.abs(number) > 1 ? plural : single; }; // register handlebars helpers