From c1e0bd83b05997dda02800279e119c1d3473acf1 Mon Sep 17 00:00:00 2001 From: andreas-unleash <104830839+andreas-unleash@users.noreply.github.com> Date: Fri, 4 Nov 2022 11:33:07 +0200 Subject: [PATCH] Frontend - Suggest change copy strategy (#2312) * Suggest change copy strategy * Fix merge conflicts * Copy strategies from other environment added to draft * Copy strategies from other environment added to draft * Copy strategies from other environment added to draft * Copy strategies from other environment added to draft * fmt * PR comments * PR comments * PR comments * PR comments * Fix: Conditionally hide Change Requests tab --- .../ChangeRequest/ChangeRequest.tsx | 37 +++- .../ChangeRequestConfirmDialog.tsx | 31 +-- .../CopyStrategiesMessage.tsx | 33 ++++ .../CopyStrategyMessage.tsx | 23 +++ .../UpdateEnabledMessage.tsx | 18 ++ .../changeRequest/changeRequest.types.ts | 93 ++++++--- .../FeatureStrategyEmpty.tsx | 186 +++++++++++------- .../FeatureOverviewEnvSwitch.tsx | 10 +- .../CopyStrategyIconMenu.tsx | 53 ++++- .../StrategyItem/StrategyItem.tsx | 1 + .../ProjectFeatureToggles.tsx | 10 +- .../useChangeRequestApi.ts | 2 +- .../useChangeRequestOpen.ts | 5 +- .../src/hooks/useChangeRequestAddStrategy.ts | 131 ++++++++++++ 14 files changed, 500 insertions(+), 133 deletions(-) create mode 100644 frontend/src/component/changeRequest/ChangeRequestConfirmDialog/ChangeRequestMessages/CopyStrategiesMessage.tsx create mode 100644 frontend/src/component/changeRequest/ChangeRequestConfirmDialog/ChangeRequestMessages/CopyStrategyMessage.tsx create mode 100644 frontend/src/component/changeRequest/ChangeRequestConfirmDialog/ChangeRequestMessages/UpdateEnabledMessage.tsx create mode 100644 frontend/src/hooks/useChangeRequestAddStrategy.ts diff --git a/frontend/src/component/changeRequest/ChangeRequest/ChangeRequest.tsx b/frontend/src/component/changeRequest/ChangeRequest/ChangeRequest.tsx index f5ea7bc3be..6cfc2fe13f 100644 --- a/frontend/src/component/changeRequest/ChangeRequest/ChangeRequest.tsx +++ b/frontend/src/component/changeRequest/ChangeRequest/ChangeRequest.tsx @@ -7,7 +7,20 @@ import { ToggleStatusChange } from '../ChangeRequestOverview/ChangeRequestFeatur import { useChangeRequestApi } from 'hooks/api/actions/useChangeRequestApi/useChangeRequestApi'; import { formatUnknownError } from 'utils/formatUnknownError'; import useToast from 'hooks/useToast'; -import type { IChangeRequest } from '../changeRequest.types'; +import type { + IChangeRequest, + IChangeRequestAddStrategy, +} from '../changeRequest.types'; +import { + StrategyAddedChange, + StrategyDeletedChange, + StrategyEditedChange, +} from '../ChangeRequestOverview/ChangeRequestFeatureToggleChange/StrategyChange'; +import { + formatStrategyName, + GetFeatureStrategyIcon, +} from '../../../utils/strategyNames'; +import { IChangeRequestEnabled } from '../changeRequest.types'; interface IChangeRequestProps { changeRequest: IChangeRequest; @@ -54,21 +67,29 @@ export const ChangeRequest: VFC = ({ condition={change.action === 'updateEnabled'} show={ } /> - {/* {formatStrategyName( - change.payload.name + ( + change as IChangeRequestAddStrategy + )?.payload.name! )} } @@ -80,7 +101,7 @@ export const ChangeRequest: VFC = ({ } - /> */} + /> ))} diff --git a/frontend/src/component/changeRequest/ChangeRequestConfirmDialog/ChangeRequestConfirmDialog.tsx b/frontend/src/component/changeRequest/ChangeRequestConfirmDialog/ChangeRequestConfirmDialog.tsx index 94486da395..54bc3bd4ca 100644 --- a/frontend/src/component/changeRequest/ChangeRequestConfirmDialog/ChangeRequestConfirmDialog.tsx +++ b/frontend/src/component/changeRequest/ChangeRequestConfirmDialog/ChangeRequestConfirmDialog.tsx @@ -6,38 +6,39 @@ interface IChangeRequestDialogueProps { isOpen: boolean; onConfirm: () => void; onClose: () => void; - featureName?: string; environment?: string; - enabled?: boolean; + showBanner?: boolean; + messageComponent: JSX.Element; } export const ChangeRequestDialogue: FC = ({ isOpen, onConfirm, onClose, - enabled, - featureName, + showBanner, environment, + messageComponent, }) => ( - - Change requests is enabled for {environment}. Your changes needs to - be approved before they will be live. All the changes you do now - will be added into a draft that you can submit for review. - + {showBanner && ( + + Change requests feature is enabled for {environment}. Your + changes needs to be approved before they will be live. All the + changes you do now will be added into a draft that you can + submit for review. + + )} - Change requests: - - - {enabled ? 'Disable' : 'Enable'} feature toggle{' '} - {featureName} in {environment} + Your suggestion: + {messageComponent} ); diff --git a/frontend/src/component/changeRequest/ChangeRequestConfirmDialog/ChangeRequestMessages/CopyStrategiesMessage.tsx b/frontend/src/component/changeRequest/ChangeRequestConfirmDialog/ChangeRequestMessages/CopyStrategiesMessage.tsx new file mode 100644 index 0000000000..f99b9fddb7 --- /dev/null +++ b/frontend/src/component/changeRequest/ChangeRequestConfirmDialog/ChangeRequestMessages/CopyStrategiesMessage.tsx @@ -0,0 +1,33 @@ +import { styled, Typography } from '@mui/material'; +import { formatStrategyName } from '../../../../utils/strategyNames'; +import { IFeatureStrategy } from '../../../../interfaces/strategy'; +import { CopyStrategyMsg } from './CopyStrategyMessage'; + +const MsgContainer = styled('div')(({ theme }) => ({ + '&>*:nth-child(n)': { + margin: theme.spacing(1, 0), + }, +})); + +export const CopyStrategiesMessage = ({ + payload, + fromEnvironment, + environment, +}: CopyStrategyMsg) => ( + + + Copy: + + {(payload as IFeatureStrategy[])?.map(strategy => ( + + + {formatStrategyName((strategy as IFeatureStrategy)?.name)}{' '} + strategy{' '} + {' '} + + ))} + + from {fromEnvironment} to {environment} + + +); diff --git a/frontend/src/component/changeRequest/ChangeRequestConfirmDialog/ChangeRequestMessages/CopyStrategyMessage.tsx b/frontend/src/component/changeRequest/ChangeRequestConfirmDialog/ChangeRequestMessages/CopyStrategyMessage.tsx new file mode 100644 index 0000000000..d7bfb3ea7e --- /dev/null +++ b/frontend/src/component/changeRequest/ChangeRequestConfirmDialog/ChangeRequestMessages/CopyStrategyMessage.tsx @@ -0,0 +1,23 @@ +import { Typography } from '@mui/material'; +import { formatStrategyName } from '../../../../utils/strategyNames'; +import { IFeatureStrategy } from '../../../../interfaces/strategy'; + +export interface CopyStrategyMsg { + payload: IFeatureStrategy | IFeatureStrategy[]; + fromEnvironment?: string; + environment?: string; +} + +export const CopyStrategyMessage = ({ + payload, + fromEnvironment, + environment, +}: CopyStrategyMsg) => ( + + + Copy {formatStrategyName((payload as IFeatureStrategy)?.name)}{' '} + strategy{' '} + {' '} + from {fromEnvironment} to {environment} + +); diff --git a/frontend/src/component/changeRequest/ChangeRequestConfirmDialog/ChangeRequestMessages/UpdateEnabledMessage.tsx b/frontend/src/component/changeRequest/ChangeRequestConfirmDialog/ChangeRequestMessages/UpdateEnabledMessage.tsx new file mode 100644 index 0000000000..0eeb9156bb --- /dev/null +++ b/frontend/src/component/changeRequest/ChangeRequestConfirmDialog/ChangeRequestMessages/UpdateEnabledMessage.tsx @@ -0,0 +1,18 @@ +import { Typography } from '@mui/material'; + +interface UpdateEnabledMsg { + enabled: boolean; + featureName: string; + environment: string; +} + +export const UpdateEnabledMessage = ({ + enabled, + featureName, + environment, +}: UpdateEnabledMsg) => ( + + {enabled ? 'Disable' : 'Enable'} feature toggle{' '} + {featureName} in {environment} + +); diff --git a/frontend/src/component/changeRequest/changeRequest.types.ts b/frontend/src/component/changeRequest/changeRequest.types.ts index fe302dcb7f..a3049f4d21 100644 --- a/frontend/src/component/changeRequest/changeRequest.types.ts +++ b/frontend/src/component/changeRequest/changeRequest.types.ts @@ -1,3 +1,31 @@ +import { IFeatureStrategy } from '../../interfaces/strategy'; +import { IUser } from '../../interfaces/user'; + +export interface IChangeRequest { + id: number; + state: ChangeRequestState; + project: string; + environment: string; + createdBy: Pick; + createdAt: Date; + features: IChangeRequestFeature[]; +} + +export interface IChangeRequestFeature { + name: string; + conflict?: string; + changes: IChangeRequestEvent[]; +} + +export interface IChangeRequestBase { + id?: number; + action: ChangeRequestAction; + payload: ChangeRequestPayload; + conflict?: string; + createdBy?: Pick; + createdAt?: Date; +} + export type ChangeRequestState = | 'Draft' | 'Approved' @@ -5,32 +33,53 @@ export type ChangeRequestState = | 'Applied' | 'Cancelled'; -export interface IChangeRequest { - id: number; - environment: string; - state: ChangeRequestState; - project: string; - createdBy: ICreatedBy; - createdAt: string; - features: IChangeRequestFeatures[]; +type ChangeRequestPayload = + | ChangeRequestEnabled + | ChangeRequestAddStrategy + | ChangeRequestEditStrategy + | ChangeRequestDeleteStrategy; + +export interface IChangeRequestAddStrategy extends IChangeRequestBase { + action: 'addStrategy'; + payload: ChangeRequestAddStrategy; } -interface ICreatedBy { - id: number; - username: string; - imageUrl: string; +export interface IChangeRequestDeleteStrategy extends IChangeRequestBase { + action: 'deleteStrategy'; + payload: ChangeRequestDeleteStrategy; } -interface IChangeRequestFeatures { - name: string; - changes: IChangeRequestFeatureChanges[]; +export interface IChangeRequestUpdateStrategy extends IChangeRequestBase { + action: 'updateStrategy'; + payload: ChangeRequestEditStrategy; } -interface IChangeRequestFeatureChanges { - id: number; - action: string; - payload: unknown; - createdAt: string; - createdBy: ICreatedBy; - warning?: string; +export interface IChangeRequestEnabled extends IChangeRequestBase { + action: 'updateEnabled'; + payload: ChangeRequestEnabled; } + +export type IChangeRequestEvent = + | IChangeRequestAddStrategy + | IChangeRequestDeleteStrategy + | IChangeRequestUpdateStrategy + | IChangeRequestEnabled; + +type ChangeRequestEnabled = { enabled: boolean }; + +type ChangeRequestAddStrategy = Pick< + IFeatureStrategy, + 'parameters' | 'constraints' +> & { name: string }; + +type ChangeRequestEditStrategy = ChangeRequestAddStrategy & { id: string }; + +type ChangeRequestDeleteStrategy = { + id: string; +}; + +export type ChangeRequestAction = + | 'updateEnabled' + | 'addStrategy' + | 'updateStrategy' + | 'deleteStrategy'; diff --git a/frontend/src/component/feature/FeatureStrategy/FeatureStrategyEmpty/FeatureStrategyEmpty.tsx b/frontend/src/component/feature/FeatureStrategy/FeatureStrategyEmpty/FeatureStrategyEmpty.tsx index 8b372e4c9f..81993c2a0b 100644 --- a/frontend/src/component/feature/FeatureStrategy/FeatureStrategyEmpty/FeatureStrategyEmpty.tsx +++ b/frontend/src/component/feature/FeatureStrategy/FeatureStrategyEmpty/FeatureStrategyEmpty.tsx @@ -12,8 +12,10 @@ import { useFeatureImmutable } from 'hooks/api/getters/useFeature/useFeatureImmu import { getFeatureStrategyIcon } from 'utils/strategyNames'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { CopyButton } from './CopyButton/CopyButton'; -import { useSegments } from '../../../../hooks/api/getters/useSegments/useSegments'; -import { IFeatureStrategyPayload } from '../../../../interfaces/strategy'; +import useUiConfig from '../../../../hooks/api/getters/useUiConfig/useUiConfig'; +import { useChangeRequestAddStrategy } from '../../../../hooks/useChangeRequestAddStrategy'; +import { ChangeRequestDialogue } from '../../../changeRequest/ChangeRequestConfirmDialog/ChangeRequestConfirmDialog'; +import { CopyStrategiesMessage } from '../../../changeRequest/ChangeRequestConfirmDialog/ChangeRequestMessages/CopyStrategiesMessage'; interface IFeatureStrategyEmptyProps { projectId: string; @@ -42,6 +44,16 @@ export const FeatureStrategyEmpty = ({ environment.strategies.length > 0 ); + const { uiConfig } = useUiConfig(); + const changeRequestsEnabled = uiConfig?.flags?.changeRequests; + + const { + changeRequestDialogDetails, + onChangeRequestAddStrategies, + onChangeRequestAddStrategiesConfirm, + onChangeRequestAddStrategyClose, + } = useChangeRequestAddStrategy(projectId, featureId, 'addStrategy'); + const onAfterAddStrategy = (multiple = false) => { refetchFeature(); refetchFeatureImmutable(); @@ -61,6 +73,15 @@ export const FeatureStrategyEmpty = ({ environment => environment.name === fromEnvironmentName )?.strategies || []; + if (changeRequestsEnabled) { + await onChangeRequestAddStrategies( + environmentId, + strategies, + fromEnvironmentName + ); + return; + } + try { await Promise.all( strategies.map(strategy => { @@ -118,77 +139,96 @@ export const FeatureStrategyEmpty = ({ otherAvailableEnvironments && otherAvailableEnvironments.length > 0; return ( -
-
- You have not defined any strategies yet. + <> + + } + /> + +
+
+ You have not defined any strategies yet. +
+

+ Strategies added in this environment will only be executed + if the SDK is using an{' '} + API key configured for this + environment. +

+ + + environment.name + )} + onClick={onCopyStrategies} + /> + } + /> + + + + Or use a strategy template + + + + + The standard strategy is strictly on/off for your entire + userbase. + + + Roll out to a percentage of your userbase. + +
-

- Strategies added in this environment will only be executed if - the SDK is using an{' '} - API key configured for this - environment. -

- - - environment.name - )} - onClick={onCopyStrategies} - /> - } - /> - - - Or use a strategy template - - - - The standard strategy is strictly on/off for your entire - userbase. - - - Roll out to a percentage of your userbase. - - -
+ ); }; diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvSwitches/FeatureOverviewEnvSwitch/FeatureOverviewEnvSwitch.tsx b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvSwitches/FeatureOverviewEnvSwitch/FeatureOverviewEnvSwitch.tsx index ae0beb45ca..8e48a595d4 100644 --- a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvSwitches/FeatureOverviewEnvSwitch/FeatureOverviewEnvSwitch.tsx +++ b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvSwitches/FeatureOverviewEnvSwitch/FeatureOverviewEnvSwitch.tsx @@ -10,9 +10,9 @@ import React from 'react'; import { formatUnknownError } from 'utils/formatUnknownError'; import { useStyles } from './FeatureOverviewEnvSwitch.styles'; import { useRequiredPathParam } from 'hooks/useRequiredPathParam'; -import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; import { useChangeRequestToggle } from 'hooks/useChangeRequestToggle'; import { ChangeRequestDialogue } from 'component/changeRequest/ChangeRequestConfirmDialog/ChangeRequestConfirmDialog'; +import { UpdateEnabledMessage } from '../../../../../changeRequest/ChangeRequestConfirmDialog/ChangeRequestMessages/UpdateEnabledMessage'; import { useChangeRequestsEnabled } from 'hooks/useChangeRequestsEnabled'; interface IFeatureOverviewEnvSwitchProps { @@ -123,9 +123,15 @@ const FeatureOverviewEnvSwitch = ({ + } />
); diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/CopyStrategyIconMenu/CopyStrategyIconMenu.tsx b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/CopyStrategyIconMenu/CopyStrategyIconMenu.tsx index 6207a2e762..edde046a42 100644 --- a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/CopyStrategyIconMenu/CopyStrategyIconMenu.tsx +++ b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/CopyStrategyIconMenu/CopyStrategyIconMenu.tsx @@ -8,7 +8,7 @@ import { Tooltip, } from '@mui/material'; import { AddToPhotos as CopyIcon, Lock } from '@mui/icons-material'; -import { IFeatureStrategy, IFeatureStrategyPayload } from 'interfaces/strategy'; +import { IFeatureStrategy } from 'interfaces/strategy'; import { useRequiredPathParam } from 'hooks/useRequiredPathParam'; import { IFeatureEnvironment } from 'interfaces/featureToggle'; import AccessContext from 'contexts/AccessContext'; @@ -19,20 +19,24 @@ import useFeatureStrategyApi from 'hooks/api/actions/useFeatureStrategyApi/useFe import useToast from 'hooks/useToast'; import { useFeatureImmutable } from 'hooks/api/getters/useFeature/useFeatureImmutable'; import { formatUnknownError } from 'utils/formatUnknownError'; -import { useSegments } from '../../../../../../../../../../hooks/api/getters/useSegments/useSegments'; +import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; +import { useChangeRequestAddStrategy } from 'hooks/useChangeRequestAddStrategy'; +import { ChangeRequestDialogue } from '../../../../../../../../../changeRequest/ChangeRequestConfirmDialog/ChangeRequestConfirmDialog'; +import { CopyStrategyMessage } from '../../../../../../../../../changeRequest/ChangeRequestConfirmDialog/ChangeRequestMessages/CopyStrategyMessage'; interface ICopyStrategyIconMenuProps { + environmentId: string; environments: IFeatureEnvironment['name'][]; strategy: IFeatureStrategy; } export const CopyStrategyIconMenu: VFC = ({ + environmentId, environments, strategy, }) => { const projectId = useRequiredPathParam('projectId'); const featureId = useRequiredPathParam('featureId'); - const { segments } = useSegments(strategy.id); const [anchorEl, setAnchorEl] = useState(null); const open = Boolean(anchorEl); @@ -47,19 +51,40 @@ export const CopyStrategyIconMenu: VFC = ({ setAnchorEl(null); }; const { hasAccess } = useContext(AccessContext); - const onClick = async (environmentId: string) => { + const { uiConfig } = useUiConfig(); + const changeRequestsEnabled = uiConfig?.flags?.changeRequests; + + const { + changeRequestDialogDetails, + onChangeRequestAddStrategyClose, + onChangeRequestAddStrategy, + onChangeRequestAddStrategyConfirm, + } = useChangeRequestAddStrategy(projectId, featureId, 'addStrategy'); + + const onCopyStrategy = async (environment: string) => { const { id, ...strategyCopy } = { ...strategy, - environment: environmentId, + environment, copyOf: strategy.id, }; + if (changeRequestsEnabled) { + await onChangeRequestAddStrategy( + environment, + { + id, + ...strategyCopy, + }, + environmentId + ); + return; + } try { await addStrategyToFeature( projectId, featureId, environmentId, - strategyCopy + strategy ); refetchFeature(); refetchFeatureImmutable(); @@ -80,6 +105,20 @@ export const CopyStrategyIconMenu: VFC = ({ return (
+ + } + /> = ({ >
onClick(environment)} + onClick={() => onCopyStrategy(environment)} disabled={!access} > = ({ )} show={() => ( diff --git a/frontend/src/component/project/Project/ProjectFeatureToggles/ProjectFeatureToggles.tsx b/frontend/src/component/project/Project/ProjectFeatureToggles/ProjectFeatureToggles.tsx index 868d763882..e1806a73e6 100644 --- a/frontend/src/component/project/Project/ProjectFeatureToggles/ProjectFeatureToggles.tsx +++ b/frontend/src/component/project/Project/ProjectFeatureToggles/ProjectFeatureToggles.tsx @@ -38,6 +38,8 @@ import { useMediaQuery } from '@mui/material'; import { Search } from 'component/common/Search/Search'; import { useChangeRequestToggle } from 'hooks/useChangeRequestToggle'; import { ChangeRequestDialogue } from 'component/changeRequest/ChangeRequestConfirmDialog/ChangeRequestConfirmDialog'; +import { CopyStrategyMessage } from '../../../changeRequest/ChangeRequestConfirmDialog/ChangeRequestMessages/CopyStrategyMessage'; +import { UpdateEnabledMessage } from '../../../changeRequest/ChangeRequestConfirmDialog/ChangeRequestMessages/UpdateEnabledMessage'; import { useChangeRequestsEnabled } from 'hooks/useChangeRequestsEnabled'; interface IProjectFeatureTogglesProps { @@ -524,9 +526,15 @@ export const ProjectFeatureToggles = ({ + } /> ); diff --git a/frontend/src/hooks/api/actions/useChangeRequestApi/useChangeRequestApi.ts b/frontend/src/hooks/api/actions/useChangeRequestApi/useChangeRequestApi.ts index d4c30a5d03..f527cd219f 100644 --- a/frontend/src/hooks/api/actions/useChangeRequestApi/useChangeRequestApi.ts +++ b/frontend/src/hooks/api/actions/useChangeRequestApi/useChangeRequestApi.ts @@ -1,6 +1,6 @@ import useAPI from '../useApi/useApi'; -interface IChangeRequestsSchema { +export interface IChangeRequestsSchema { feature: string; action: | 'updateEnabled' diff --git a/frontend/src/hooks/api/getters/useChangeRequestOpen/useChangeRequestOpen.ts b/frontend/src/hooks/api/getters/useChangeRequestOpen/useChangeRequestOpen.ts index 89698eea68..4969aa6a04 100644 --- a/frontend/src/hooks/api/getters/useChangeRequestOpen/useChangeRequestOpen.ts +++ b/frontend/src/hooks/api/getters/useChangeRequestOpen/useChangeRequestOpen.ts @@ -2,10 +2,7 @@ import useSWR from 'swr'; import { useMemo } from 'react'; import { formatApiPath } from 'utils/formatPath'; import handleErrorResponses from '../httpErrorResponseHandler'; -import { - ChangeRequestState, - IChangeRequest, -} from 'component/changeRequest/changeRequest.types'; +import { IChangeRequest } from 'component/changeRequest/changeRequest.types'; const fetcher = (path: string) => { return fetch(path) diff --git a/frontend/src/hooks/useChangeRequestAddStrategy.ts b/frontend/src/hooks/useChangeRequestAddStrategy.ts new file mode 100644 index 0000000000..09eac6f486 --- /dev/null +++ b/frontend/src/hooks/useChangeRequestAddStrategy.ts @@ -0,0 +1,131 @@ +import { useCallback, useState } from 'react'; +import useToast from 'hooks/useToast'; +import { formatUnknownError } from 'utils/formatUnknownError'; +import { + IFeatureStrategy, + IFeatureStrategyPayload, +} from '../interfaces/strategy'; +import { useChangeRequestApi } from './api/actions/useChangeRequestApi/useChangeRequestApi'; +import { useChangeRequestOpen } from './api/getters/useChangeRequestOpen/useChangeRequestOpen'; + +export type ChangeRequestStrategyAction = + | 'addStrategy' + | 'updateStrategy' + | 'deleteStrategy'; + +export const useChangeRequestAddStrategy = ( + project: string, + featureName: string, + action: ChangeRequestStrategyAction +) => { + const { setToastData, setToastApiError } = useToast(); + const { addChangeRequest } = useChangeRequestApi(); + const { refetch } = useChangeRequestOpen(project); + + const [changeRequestDialogDetails, setChangeRequestDialogDetails] = + useState<{ + strategy?: IFeatureStrategy; + strategies?: IFeatureStrategy[]; + featureName?: string; + environment?: string; + fromEnvironment?: string; + isOpen: boolean; + }>({ isOpen: false }); + + const onChangeRequestAddStrategy = useCallback( + ( + environment: string, + strategy: IFeatureStrategy, + fromEnvironment?: string + ) => { + setChangeRequestDialogDetails({ + featureName, + environment, + fromEnvironment, + strategy, + isOpen: true, + }); + }, + [] + ); + + const onChangeRequestAddStrategies = useCallback( + ( + environment: string, + strategies: IFeatureStrategy[], + fromEnvironment: string + ) => { + setChangeRequestDialogDetails({ + featureName, + environment, + fromEnvironment, + strategies, + isOpen: true, + }); + }, + [] + ); + + const onChangeRequestAddStrategyClose = useCallback(() => { + setChangeRequestDialogDetails({ isOpen: false }); + }, []); + + const onChangeRequestAddStrategyConfirm = useCallback(async () => { + try { + await addChangeRequest( + project, + changeRequestDialogDetails.environment!, + { + feature: changeRequestDialogDetails.featureName!, + action: action, + payload: changeRequestDialogDetails.strategy!, + } + ); + refetch(); + setChangeRequestDialogDetails({ isOpen: false }); + setToastData({ + type: 'success', + title: 'Changes added to the draft!', + }); + } catch (error) { + setToastApiError(formatUnknownError(error)); + setChangeRequestDialogDetails({ isOpen: false }); + } + }, [addChangeRequest]); + + const onChangeRequestAddStrategiesConfirm = useCallback(async () => { + try { + await Promise.all( + changeRequestDialogDetails.strategies!.map(strategy => { + return addChangeRequest( + project, + changeRequestDialogDetails.environment!, + { + feature: changeRequestDialogDetails.featureName!, + action: action, + payload: strategy, + } + ); + }) + ); + refetch(); + setChangeRequestDialogDetails({ isOpen: false }); + setToastData({ + type: 'success', + title: 'Changes added to the draft!', + }); + } catch (error) { + setToastApiError(formatUnknownError(error)); + setChangeRequestDialogDetails({ isOpen: false }); + } + }, [addChangeRequest]); + + return { + onChangeRequestAddStrategy, + onChangeRequestAddStrategies, + onChangeRequestAddStrategyClose, + onChangeRequestAddStrategyConfirm, + onChangeRequestAddStrategiesConfirm, + changeRequestDialogDetails, + }; +};