From a04902e3a6694b6bb2b1c6a4e2ecccbce02a70f4 Mon Sep 17 00:00:00 2001 From: "Leon.kov" Date: Mon, 8 Apr 2024 12:28:37 +0300 Subject: [PATCH] feat: add feature flags --- json-server/db.json | 132 +++++++++--------- src/entities/User/model/slice/userSlice.ts | 6 +- src/entities/User/model/types/user.ts | 2 + .../ArticlesDetailsPage.tsx | 7 +- src/shared/lib/features/index.ts | 1 + src/shared/lib/features/setGetFeatures.ts | 14 ++ src/shared/types/featureFlags.ts | 4 + 7 files changed, 99 insertions(+), 67 deletions(-) create mode 100644 src/shared/lib/features/index.ts create mode 100644 src/shared/lib/features/setGetFeatures.ts create mode 100644 src/shared/types/featureFlags.ts diff --git a/json-server/db.json b/json-server/db.json index 82e4663..04f936d 100644 --- a/json-server/db.json +++ b/json-server/db.json @@ -38,7 +38,7 @@ "id": "1", "title": "Javascript news СВЕЖАЯ", "subtitle": "Что нового в JS за 2022 год?", - "img": "https://teknotower.com/wp-content/uploads/2020/11/js.png", + "img": "https://upload.wikimedia.org/wikipedia/commons/thumb/9/99/Unofficial_JavaScript_logo_2.svg/1024px-Unofficial_JavaScript_logo_2.svg.png", "views": 1022, "createdAt": "26.04.2022", "userId": "1", @@ -110,7 +110,7 @@ "id": "2", "title": "Python news", "subtitle": "Что нового в JS за 2022 год?", - "img": "https://zsfond.ru/wp-content/uploads/2021/03/piton-1-1024x578.jpg", + "img": "https://fiverr-res.cloudinary.com/images/t_main1,q_auto,f_auto,q_auto,f_auto/gigs2/113415626/original/a17667d573bf34559bf0d35993ed76e57d43ad00/program-python-scripts-for-automation-and-data-mining.png", "views": 5204, "createdAt": "26.02.2022", "userId": "1", @@ -158,7 +158,7 @@ "id": "4", "title": "Scala news", "subtitle": "Что нового в JS за 2022 год?", - "img": "https://coursefreedl.com/wp-content/uploads/2020/01/Scala-Zero-To-Hero-Complete-Guide.jpg", + "img": "https://pluspng.com/img-png/scala-logo-png-scala-logo-1200x675.png", "views": 10222, "createdAt": "24.01.2022", "userId": "1", @@ -182,7 +182,7 @@ "id": "5", "title": "Golang news", "subtitle": "Что нового в JS за 2022 год?", - "img": "https://cdn-front.kwork.ru/pics/t3/88/16350941-1630390388.jpg", + "img": "https://www.itsec.ru/hs-fs/hubfs/ISR/Golang.png?width=750&name=Golang.png", "views": 10222, "createdAt": "26.02.2020", "userId": "1", @@ -302,7 +302,7 @@ "id": "10", "title": "Python news", "subtitle": "Что нового в JS за 2022 год?", - "img": "https://zsfond.ru/wp-content/uploads/2021/03/piton-1-1024x578.jpg", + "img": "https://fiverr-res.cloudinary.com/images/t_main1,q_auto,f_auto,q_auto,f_auto/gigs2/113415626/original/a17667d573bf34559bf0d35993ed76e57d43ad00/program-python-scripts-for-automation-and-data-mining.png", "views": 1022, "createdAt": "26.02.2022", "userId": "1", @@ -350,7 +350,7 @@ "id": "12", "title": "Python news", "subtitle": "Что нового в JS за 2022 год?", - "img": "https://zsfond.ru/wp-content/uploads/2021/03/piton-1-1024x578.jpg", + "img": "https://fiverr-res.cloudinary.com/images/t_main1,q_auto,f_auto,q_auto,f_auto/gigs2/113415626/original/a17667d573bf34559bf0d35993ed76e57d43ad00/program-python-scripts-for-automation-and-data-mining.png", "views": 1022, "createdAt": "26.02.2022", "userId": "1", @@ -398,7 +398,7 @@ "id": "14", "title": "Python news", "subtitle": "Что нового в JS за 2022 год?", - "img": "https://zsfond.ru/wp-content/uploads/2021/03/piton-1-1024x578.jpg", + "img": "https://fiverr-res.cloudinary.com/images/t_main1,q_auto,f_auto,q_auto,f_auto/gigs2/113415626/original/a17667d573bf34559bf0d35993ed76e57d43ad00/program-python-scripts-for-automation-and-data-mining.png", "views": 1022, "createdAt": "26.02.2022", "userId": "1", @@ -446,7 +446,7 @@ "id": "16", "title": "Python news", "subtitle": "Что нового в JS за 2022 год?", - "img": "https://zsfond.ru/wp-content/uploads/2021/03/piton-1-1024x578.jpg", + "img": "https://fiverr-res.cloudinary.com/images/t_main1,q_auto,f_auto,q_auto,f_auto/gigs2/113415626/original/a17667d573bf34559bf0d35993ed76e57d43ad00/program-python-scripts-for-automation-and-data-mining.png", "views": 1022, "createdAt": "26.02.2022", "userId": "1", @@ -518,7 +518,7 @@ "id": "18", "title": "Научная статья - Биология", "subtitle": "БиологиЯ", - "img": "https://avatars.mds.yandex.net/get-zen_doc/2746556/pub_5f50dd7e1a1ddf4776aa5569_5f50decd2506f211d1de6284/scale_1200", + "img": "https://kartinkin.net/uploads/posts/2022-05/1652214942_9-kartinkin-net-p-biologiya-krasivie-kartinki-10.jpg", "views": 1022, "createdAt": "26.02.2022", "userId": "1", @@ -541,7 +541,7 @@ { "title": "Научная статья - Биология", "subtitle": "БиологиЯ", - "img": "https://avatars.mds.yandex.net/get-zen_doc/2746556/pub_5f50dd7e1a1ddf4776aa5569_5f50decd2506f211d1de6284/scale_1200", + "img": "https://kartinkin.net/uploads/posts/2022-05/1652214942_9-kartinkin-net-p-biologiya-krasivie-kartinki-10.jpg", "views": 1022, "createdAt": "26.02.2022", "userId": "1", @@ -554,7 +554,7 @@ { "title": "Научная статья - Биология", "subtitle": "БиологиЯ", - "img": "https://avatars.mds.yandex.net/get-zen_doc/2746556/pub_5f50dd7e1a1ddf4776aa5569_5f50decd2506f211d1de6284/scale_1200", + "img": "https://i.ebayimg.com/00/s/NjE0WDc2OA==/z/PhIAAOSw~oFZvBcK/$_57.JPG?set_id=8800005007", "views": 1022, "createdAt": "26.02.2022", "userId": "1", @@ -563,45 +563,6 @@ ], "blocks": [], "id": "6f91vPH" - }, - { - "title": "TESTING ARTICLE", - "subtitle": "Subtitle text", - "img": "https://avatars.mds.yandex.net/get-zen_doc/2746556/pub_5f50dd7e1a1ddf4776aa5569_5f50decd2506f211d1de6284/scale_1200", - "views": 1022, - "createdAt": "26.02.2022", - "userId": "1", - "type": [ - "SCIENCE" - ], - "blocks": [], - "id": "y1D5B71" - }, - { - "title": "TESTING ARTICLE", - "subtitle": "Subtitle text", - "img": "https://avatars.mds.yandex.net/get-zen_doc/2746556/pub_5f50dd7e1a1ddf4776aa5569_5f50decd2506f211d1de6284/scale_1200", - "views": 1022, - "createdAt": "26.02.2022", - "userId": "1", - "type": [ - "SCIENCE" - ], - "blocks": [], - "id": "3u59urr" - }, - { - "title": "TESTING ARTICLE", - "subtitle": "Subtitle text", - "img": "https://avatars.mds.yandex.net/get-zen_doc/2746556/pub_5f50dd7e1a1ddf4776aa5569_5f50decd2506f211d1de6284/scale_1200", - "views": 1022, - "createdAt": "26.02.2022", - "userId": "1", - "type": [ - "SCIENCE" - ], - "blocks": [], - "id": "PhhG_hW" } ], "comments": [ @@ -760,6 +721,24 @@ "userId": "1", "text": "123", "id": "KmtWJR_" + }, + { + "articleId": "8", + "userId": "2", + "text": "asdasd", + "id": "eB1A-7c" + }, + { + "articleId": "2", + "userId": "1", + "text": "class", + "id": "wAZ_hJM" + }, + { + "articleId": "2", + "userId": "1", + "text": "asfasf", + "id": "SygCNYE" } ], "users": [ @@ -770,7 +749,11 @@ "roles": [ "ADMIN" ], - "avatar": "https://yakutsk.ru/wp-content/uploads/2022/07/12/bystrov_haker.jpeg" + "features": { + "isArticleRatingEnabled": true, + "isCounterEnabled": false + }, + "avatar": "https://mobimg.b-cdn.net/v3/fetch/22/2207633df03a819cd72889249c8361a8.jpeg?w=1470&r=0.5625" }, { "id": "2", @@ -779,7 +762,11 @@ "roles": [ "USER" ], - "avatar": "https://xakep.ru/wp-content/uploads/2018/05/171485/KuroiSH-hacker.jpg" + "features": { + "isArticleRatingEnabled": false, + "isCounterEnabled": false + }, + "avatar": "https://i.pinimg.com/originals/9a/e0/2d/9ae02d4b4288396108ef77830a59e060.jpg" }, { "id": "3", @@ -788,7 +775,11 @@ "roles": [ "MANAGER" ], - "avatar": "https://xakep.ru/wp-content/uploads/2018/05/171485/KuroiSH-hacker.jpg" + "features": { + "isArticleRatingEnabled": false, + "isCounterEnabled": true + }, + "avatar": "https://s1.1zoom.ru/big3/992/367659-alexfas01.jpg" }, { "id": "4", @@ -797,20 +788,24 @@ "roles": [ "ADMIN" ], - "avatar": "https://xakep.ru/wp-content/uploads/2018/05/171485/KuroiSH-hacker.jpg" + "features": { + "isArticleRatingEnabled": true, + "isCounterEnabled": true + }, + "avatar": "https://s1.1zoom.ru/big3/992/367659-alexfas01.jpg" } ], "profile": [ { "id": "1", - "first": "timur", + "first": "timurasdasd", "lastname": "ulbi", "age": 465, "currency": "RUB", "country": "Belarus", "city": "Moscow", "username": "admin213", - "avatar": "https://yt3.ggpht.com/ytc/AKedOLTYUJxG8Hu036PQ_TXpMLq2fG8Kj8NZI4h0lbn_3g=s900-c-k-c0x00ffffff-no-rj" + "avatar": "https://mobimg.b-cdn.net/v3/fetch/22/2207633df03a819cd72889249c8361a8.jpeg?w=1470&r=0.5625" }, { "id": "2", @@ -821,7 +816,7 @@ "country": "Ukraine", "city": "Moscow", "username": "ulbi tv", - "avatar": "https://xakep.ru/wp-content/uploads/2018/05/171485/KuroiSH-hacker.jpg" + "avatar": "https://i.pinimg.com/originals/9a/e0/2d/9ae02d4b4288396108ef77830a59e060.jpg" }, { "id": "4", @@ -843,13 +838,6 @@ "userId": "1", "articleId": "1" }, - { - "id": "2", - "rate": 4, - "feedback": "Хорошая статья", - "userId": "1", - "articleId": "2" - }, { "userId": "1", "articleId": "3", @@ -877,6 +865,20 @@ "rate": 3, "feedback": "", "id": "bcPnbbZ" + }, + { + "userId": "2", + "articleId": "1", + "rate": 4, + "feedback": "asdasdasdad", + "id": "1I3E5gT" + }, + { + "userId": "1", + "articleId": "2", + "rate": 2, + "feedback": "asdasdasd", + "id": "xbwnNBF" } ], "profile-ratings": [ @@ -895,4 +897,4 @@ "profileId": "2" } ] -} \ No newline at end of file +} diff --git a/src/entities/User/model/slice/userSlice.ts b/src/entities/User/model/slice/userSlice.ts index 1cd8737..d3dbe6c 100644 --- a/src/entities/User/model/slice/userSlice.ts +++ b/src/entities/User/model/slice/userSlice.ts @@ -1,6 +1,7 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit'; import { USER_LOCALSTORAGE_KEY } from '@/shared/const/localstorage'; import { User, UserSchema } from '../types/user'; +import { setFeatureFlags } from '@/shared/lib/features'; const initialState: UserSchema = { _inited: false, @@ -12,11 +13,14 @@ export const userSlice = createSlice({ reducers: { setAuthData: (state, action: PayloadAction) => { state.authData = action.payload; + setFeatureFlags(action.payload.features); }, initAuthData: (state) => { const user = localStorage.getItem(USER_LOCALSTORAGE_KEY); if (user) { - state.authData = JSON.parse(user); + const json = JSON.parse(user) as User; + state.authData = json; + setFeatureFlags(json.features); } state._inited = true; }, diff --git a/src/entities/User/model/types/user.ts b/src/entities/User/model/types/user.ts index 8780df2..19859c0 100644 --- a/src/entities/User/model/types/user.ts +++ b/src/entities/User/model/types/user.ts @@ -1,10 +1,12 @@ import { UserRole } from '../../model/consts/consts'; +import { FeatureFlags } from '@/shared/types/featureFlags'; export interface User { id: string; username: string; avatar?: string; roles?: UserRole[]; + features?: FeatureFlags; } export interface UserSchema { diff --git a/src/pages/ArticlesDetailsPage/ui/ArticlesDetailsPage/ArticlesDetailsPage.tsx b/src/pages/ArticlesDetailsPage/ui/ArticlesDetailsPage/ArticlesDetailsPage.tsx index d2cca0f..2f6f017 100644 --- a/src/pages/ArticlesDetailsPage/ui/ArticlesDetailsPage/ArticlesDetailsPage.tsx +++ b/src/pages/ArticlesDetailsPage/ui/ArticlesDetailsPage/ArticlesDetailsPage.tsx @@ -13,6 +13,8 @@ import { articleDetailsPageReducer } from '../../model/slices'; import { ArticleDetails } from '../../../../entities/Article'; import { ArticleRating } from '@/features/articleRating'; import { Page } from '@/widgets/Page'; +import { getFeatureFlag } from '@/shared/lib/features'; +import { Counter } from '@/entities/Counter'; const reducers: ReducersList = { articleDetailsPage: articleDetailsPageReducer, @@ -20,6 +22,8 @@ const reducers: ReducersList = { const ArticlesDetailsPage = (props: any) => { const { id } = useParams<{ id: string }>(); + const isArticleRatingEnabled = getFeatureFlag('isArticleRatingEnabled'); + const isCounterEnabled = getFeatureFlag('isCounterEnabled'); if (!id) { return null; @@ -31,7 +35,8 @@ const ArticlesDetailsPage = (props: any) => { - + {isCounterEnabled && } + {isArticleRatingEnabled && } diff --git a/src/shared/lib/features/index.ts b/src/shared/lib/features/index.ts new file mode 100644 index 0000000..f9ced00 --- /dev/null +++ b/src/shared/lib/features/index.ts @@ -0,0 +1 @@ +export { setFeatureFlags, getFeatureFlag } from './setGetFeatures'; diff --git a/src/shared/lib/features/setGetFeatures.ts b/src/shared/lib/features/setGetFeatures.ts new file mode 100644 index 0000000..847d538 --- /dev/null +++ b/src/shared/lib/features/setGetFeatures.ts @@ -0,0 +1,14 @@ +import { FeatureFlags } from '@/shared/types/featureFlags'; + +// features does not change on session, only after +let featureFlags: FeatureFlags; + +export function setFeatureFlags(newFeatureFlags?: FeatureFlags) { + if (newFeatureFlags) { + featureFlags = newFeatureFlags; + } +} + +export function getFeatureFlag(flag: keyof FeatureFlags) { + return featureFlags[flag] ?? false; +} diff --git a/src/shared/types/featureFlags.ts b/src/shared/types/featureFlags.ts new file mode 100644 index 0000000..2b38b40 --- /dev/null +++ b/src/shared/types/featureFlags.ts @@ -0,0 +1,4 @@ +export interface FeatureFlags { + isArticleRatingEnabled?: boolean; + isCounterEnabled?: boolean; +}