diff --git a/json-server/db.json b/json-server/db.json index 3c13e49..1c6d3bb 100644 --- a/json-server/db.json +++ b/json-server/db.json @@ -1196,6 +1196,10 @@ "ADMIN", "USER" ], + "features": { + "isArticleRatingEnabled": true, + "isCounterEnabled": true + }, "avatar": "https://source.boringavatars.com/pixel/120/Stefan?colors=26a653,2a1d8f,79646a" }, { @@ -1205,6 +1209,10 @@ "roles": [ "USER" ], + "features": { + "isArticleRatingEnabled": false, + "isCounterEnabled": true + }, "avatar": "https://cdn.discordapp.com/attachments/341701512155758594/1136485169189105714/Main_avatar.png" }, { @@ -1215,6 +1223,10 @@ "MANAGER", "USER" ], + "features": { + "isArticleRatingEnabled": false, + "isCounterEnabled": false + }, "avatar": "https://cdn.discordapp.com/attachments/341701512155758594/1136485169189105714/Main_avatar.png" }, { @@ -1224,6 +1236,10 @@ "roles": [ "USER" ], + "features": { + "isArticleRatingEnabled": true, + "isCounterEnabled": false + }, "avatar": "https://source.boringavatars.com/pixel/120/Stefan?colors=26a653,2a1d8f,79646a" } ], diff --git a/src/entities/User/model/slice/userSlice.ts b/src/entities/User/model/slice/userSlice.ts index f6f87cd..907ef8b 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 { AUTH_TOKEN_KEY } from '@/shared/consts/localStorage'; import { User, UserSchema } from '../types/user'; +import { setFeatureFlags } from '@/shared/lib/features'; const initialState: UserSchema = { _mounted: false, @@ -13,12 +14,15 @@ export const userSlice = createSlice({ setAuthData: (state, action: PayloadAction) => { localStorage.setItem(AUTH_TOKEN_KEY, JSON.stringify(action.payload)); state.authData = action.payload; + setFeatureFlags(action.payload?.features); }, initAuthData: (state) => { const authData = localStorage.getItem(AUTH_TOKEN_KEY); if (authData) { - state.authData = JSON.parse(authData); + const parsedUser = JSON.parse(authData) as User; + state.authData = parsedUser; + setFeatureFlags(parsedUser?.features); } state._mounted = true; diff --git a/src/entities/User/model/types/user.ts b/src/entities/User/model/types/user.ts index 29a80e8..6d2966b 100644 --- a/src/entities/User/model/types/user.ts +++ b/src/entities/User/model/types/user.ts @@ -1,3 +1,4 @@ +import { FeatureFlags } from '@/shared/types/featureFlags'; import { UserRole } from '../consts'; export interface User { @@ -5,6 +6,7 @@ export interface User { username: string; avatar?: string; roles?: UserRole[]; + features?: FeatureFlags; } export interface UserSchema { diff --git a/src/pages/ArticleDetailsPage/ui/ArticleDetailsPage/ArticleDetailsPage.tsx b/src/pages/ArticleDetailsPage/ui/ArticleDetailsPage/ArticleDetailsPage.tsx index 624952d..c21019e 100644 --- a/src/pages/ArticleDetailsPage/ui/ArticleDetailsPage/ArticleDetailsPage.tsx +++ b/src/pages/ArticleDetailsPage/ui/ArticleDetailsPage/ArticleDetailsPage.tsx @@ -2,13 +2,15 @@ import { FC, memo } from 'react'; import { useParams } from 'react-router-dom'; import { DynamicModuleWrapper, ReducersList } from '@/shared/lib/components/DynamicModuleWrapper'; import { classNames } from '@/shared/lib/classNames/classNames'; -import { PageWrapper } from '@/widgets/PageWrapper'; +import { getFeatureFlags } from '@/shared/lib/features'; import { ArticleDetails } from '@/entities/Article'; import { ArticleRating } from '@/features/ArticleRating'; import { ArticleRecommendations } from '@/features/ArticleRecommendations'; +import { PageWrapper } from '@/widgets/PageWrapper'; import { ArticleDetailsComments, articleDetailsCommentsReducer } from '../ArticleDetailsComments'; import { ArticleDetailsPageHeader } from '../ArticleDetailsPageHeader/ArticleDetailsPageHeader'; import cls from './ArticleDetailsPage.module.scss'; +import { Counter } from '@/entities/Counter'; const reducers: ReducersList = { articleDetailsComments: articleDetailsCommentsReducer, @@ -19,12 +21,16 @@ interface ArticleDetailsPageProps { const ArticleDetailsPage: FC = ({ className }) => { const { id } = useParams<{ id: string }>(); + const isArticleRatingFeatureEnabled = getFeatureFlags('isArticleRatingEnabled'); + const isCounterFeatureEnabled = getFeatureFlags('isCounterEnabled'); + return ( - + {isCounterFeatureEnabled && } + {isArticleRatingFeatureEnabled && } diff --git a/src/shared/lib/features/featureFlagsHandlers.ts b/src/shared/lib/features/featureFlagsHandlers.ts new file mode 100644 index 0000000..56cf383 --- /dev/null +++ b/src/shared/lib/features/featureFlagsHandlers.ts @@ -0,0 +1,11 @@ +import { FeatureFlags } from '@/shared/types/featureFlags'; + +let featureFlags: FeatureFlags; + +export const setFeatureFlags = (newFeatureFlags?: FeatureFlags) => { + if (newFeatureFlags) { + featureFlags = newFeatureFlags; + } +}; + +export const getFeatureFlags = (flag: keyof FeatureFlags) => featureFlags[flag]; diff --git a/src/shared/lib/features/index.ts b/src/shared/lib/features/index.ts new file mode 100644 index 0000000..de13bc0 --- /dev/null +++ b/src/shared/lib/features/index.ts @@ -0,0 +1 @@ +export * from './featureFlagsHandlers'; diff --git a/src/shared/types/featureFlags.ts b/src/shared/types/featureFlags.ts new file mode 100644 index 0000000..5c4b0f8 --- /dev/null +++ b/src/shared/types/featureFlags.ts @@ -0,0 +1,4 @@ +export interface FeatureFlags { + isArticleRatingEnabled?: boolean; + isCounterEnabled?: boolean; +}