diff --git a/src/actions/__tests__/app-install.ts b/src/actions/__tests__/app-install.ts deleted file mode 100644 index aa573981d3..0000000000 --- a/src/actions/__tests__/app-install.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { - appInstallRequestSuccess, - appInstallRequestDataFailure, - appInstallRequestData, - appInstallLoading, - appInstallDone -} from '../app-install' -import ActionTypes from '@/constants/action-types' - -describe('app install actions', () => { - it('should create a appInstallRequestData action', () => { - expect(appInstallDone.type).toEqual(ActionTypes.APP_INSTALL_DONE) - }) - it('should create a appInstallRequestData action', () => { - expect(appInstallRequestData.type).toEqual(ActionTypes.APP_INSTALL_REQUEST_DATA) - }) - - it('should create a appInstallRequestData action', () => { - expect(appInstallRequestSuccess.type).toEqual(ActionTypes.APP_INSTALL_REQUEST_DATA_SUCCESS) - }) - it('should create a appInstallRequestDataFailure action', () => { - expect(appInstallRequestDataFailure.type).toEqual(ActionTypes.APP_INSTALL_REQUEST_DATA_FAILURE) - }) - - it('should create a appInstallLoading action', () => { - expect(appInstallLoading.type).toEqual(ActionTypes.APP_INSTALL_LOADING) - }) -}) diff --git a/src/actions/__tests__/app-installations.ts b/src/actions/__tests__/app-installations.ts new file mode 100644 index 0000000000..b28255da7f --- /dev/null +++ b/src/actions/__tests__/app-installations.ts @@ -0,0 +1,39 @@ +import { + appInstallationsReceiveData, + appInstallationsRequestData, + appInstallationsRequestDataFailure, + appInstallationsRequestInstall, + appInstallationsRequestUninstall, + appInstallationsSetFormState +} from '../app-installations' +import ActionTypes from '@/constants/action-types' +import { installationsStub } from '@/sagas/__stubs__/installations' + +describe('app install actions', () => { + it('should create a appInstallationsReceiveData action', () => { + expect(appInstallationsReceiveData.type).toEqual(ActionTypes.APP_INSTALLATIONS_RECEIVE_DATA) + expect(appInstallationsReceiveData(installationsStub).data).toEqual(installationsStub) + }) + it('should create a appInstallationsRequestData action', () => { + expect(appInstallationsRequestData.type).toEqual(ActionTypes.APP_INSTALLATIONS_REQUEST_DATA) + expect(appInstallationsRequestData({ appId: ['1'] }).data).toEqual({ appId: ['1'] }) + }) + it('should create a appInstallationsRequestDataFailure action', () => { + expect(appInstallationsRequestDataFailure.type).toEqual(ActionTypes.APP_INSTALLATIONS_REQUEST_DATA_FAILURE) + }) + it('should create a appInstallationsRequestInstall action', () => { + expect(appInstallationsRequestInstall.type).toEqual(ActionTypes.APP_INSTALLATIONS_REQUEST_INSTALL) + expect(appInstallationsRequestInstall({ appId: '1' }).data).toEqual({ appId: '1' }) + }) + it('should create a appInstallationsRequestUninstall action', () => { + expect(appInstallationsRequestUninstall.type).toEqual(ActionTypes.APP_INSTALLATIONS_REQUEST_UNINSTALL) + expect(appInstallationsRequestUninstall({ appId: '1', installationId: '1' }).data).toEqual({ + appId: '1', + installationId: '1' + }) + }) + it('should create a appInstallationsSetFormState action', () => { + expect(appInstallationsSetFormState.type).toEqual(ActionTypes.APP_INSTALLATIONS_SET_FORM_STATE) + expect(appInstallationsSetFormState('PENDING').data).toEqual('PENDING') + }) +}) diff --git a/src/actions/__tests__/app-uninstall.ts b/src/actions/__tests__/app-uninstall.ts deleted file mode 100644 index 3dedebf13d..0000000000 --- a/src/actions/__tests__/app-uninstall.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { - appUninstallRequestSuccess, - appUninstallRequestDataFailure, - appUninstallRequestData, - appUninstallLoading, - appUninstallDone -} from '../app-uninstall' -import ActionTypes from '@/constants/action-types' - -describe('app install actions', () => { - it('should create a appUninstallRequestData action', () => { - expect(appUninstallDone.type).toEqual(ActionTypes.APP_UNINSTALL_DONE) - }) - it('should create a appUninstallRequestData action', () => { - expect(appUninstallRequestData.type).toEqual(ActionTypes.APP_UNINSTALL_REQUEST_DATA) - }) - - it('should create a appUninstallRequestData action', () => { - expect(appUninstallRequestSuccess.type).toEqual(ActionTypes.APP_UNINSTALL_REQUEST_DATA_SUCCESS) - }) - it('should create a appUninstallRequestDataFailure action', () => { - expect(appUninstallRequestDataFailure.type).toEqual(ActionTypes.APP_UNINSTALL_REQUEST_DATA_FAILURE) - }) - - it('should create a appUninstallLoading action', () => { - expect(appUninstallLoading.type).toEqual(ActionTypes.APP_UNINSTALL_LOADING) - }) -}) diff --git a/src/actions/app-install.ts b/src/actions/app-install.ts deleted file mode 100644 index d3d11b27df..0000000000 --- a/src/actions/app-install.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { actionCreator } from '../utils/actions' -import ActionTypes from '../constants/action-types' - -export const appInstallRequestData = actionCreator(ActionTypes.APP_INSTALL_REQUEST_DATA) -export const appInstallLoading = actionCreator(ActionTypes.APP_INSTALL_LOADING) -export const appInstallRequestDataFailure = actionCreator(ActionTypes.APP_INSTALL_REQUEST_DATA_FAILURE) -export const appInstallRequestSuccess = actionCreator(ActionTypes.APP_INSTALL_REQUEST_DATA_SUCCESS) -export const appInstallDone = actionCreator(ActionTypes.APP_INSTALL_DONE) diff --git a/src/actions/app-installations.ts b/src/actions/app-installations.ts new file mode 100644 index 0000000000..43ca40068f --- /dev/null +++ b/src/actions/app-installations.ts @@ -0,0 +1,39 @@ +import { actionCreator } from '../utils/actions' +import ActionTypes from '../constants/action-types' +import { FormState } from '../types/core' +import { + PagedResultInstallationModel_, + TerminateInstallationModel, + CreateInstallationModel +} from '@/types/marketplace-api-schema' + +export interface InstallationParams { + appId?: string[] + developerId?: string[] + clientId?: string[] + externalAppId?: string[] + showTerminated?: boolean + pageSize?: number + pageNumber?: number +} + +export type InstallParams = CreateInstallationModel + +export type UninstallParams = { + installationId: string +} & TerminateInstallationModel + +export const appInstallationsRequestData = actionCreator(ActionTypes.APP_INSTALLATIONS_REQUEST_DATA) +export const appInstallationsReceiveData = actionCreator( + ActionTypes.APP_INSTALLATIONS_RECEIVE_DATA +) +export const appInstallationsRequestDataFailure = actionCreator( + ActionTypes.APP_INSTALLATIONS_REQUEST_DATA_FAILURE +) +export const appInstallationsRequestInstall = actionCreator( + ActionTypes.APP_INSTALLATIONS_REQUEST_INSTALL +) +export const appInstallationsRequestUninstall = actionCreator( + ActionTypes.APP_INSTALLATIONS_REQUEST_UNINSTALL +) +export const appInstallationsSetFormState = actionCreator(ActionTypes.APP_INSTALLATIONS_SET_FORM_STATE) diff --git a/src/actions/app-uninstall.ts b/src/actions/app-uninstall.ts deleted file mode 100644 index 2929521902..0000000000 --- a/src/actions/app-uninstall.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { actionCreator } from '../utils/actions' -import ActionTypes from '../constants/action-types' - -export const appUninstallRequestData = actionCreator(ActionTypes.APP_UNINSTALL_REQUEST_DATA) -export const appUninstallLoading = actionCreator(ActionTypes.APP_UNINSTALL_LOADING) -export const appUninstallRequestDataFailure = actionCreator(ActionTypes.APP_UNINSTALL_REQUEST_DATA_FAILURE) -export const appUninstallRequestSuccess = actionCreator(ActionTypes.APP_UNINSTALL_REQUEST_DATA_SUCCESS) -export const appUninstallDone = actionCreator(ActionTypes.APP_UNINSTALL_DONE) diff --git a/src/components/pages/__tests__/__snapshots__/client.tsx.snap b/src/components/pages/__tests__/__snapshots__/client.tsx.snap index 4c5e865d42..cb8a78407e 100644 --- a/src/components/pages/__tests__/__snapshots__/client.tsx.snap +++ b/src/components/pages/__tests__/__snapshots__/client.tsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Client should match a snapshot 1`] = ` +exports[`Client should match a snapshot when LOADING false 1`] = `
@@ -80,7 +80,7 @@ exports[`Client should match a snapshot 1`] = ` `; -exports[`Client should match a snapshot 2`] = ` +exports[`Client should match a snapshot when LOADING true 1`] = `
diff --git a/src/components/pages/__tests__/client.tsx b/src/components/pages/__tests__/client.tsx index a79752c594..56d31e499c 100644 --- a/src/components/pages/__tests__/client.tsx +++ b/src/components/pages/__tests__/client.tsx @@ -3,7 +3,6 @@ import { shallow } from 'enzyme' import toJson from 'enzyme-to-json' import { appsDataStub, featuredAppsDataStub } from '@/sagas/__stubs__/apps' import { ReduxState } from '@/types/core' -import routes from '@/constants/routes' import { ClientItem } from '@/reducers/client' import { Client, @@ -18,53 +17,46 @@ import { import { addQuery } from '@/utils/client-url-params' import { AppSummaryModel } from '@/types/marketplace-api-schema' import { RouteComponentProps, StaticContext } from 'react-router' -import { AppDetailState } from '@/reducers/app-detail' +import { appDetailDataStub } from '@/sagas/__stubs__/app-detail' -describe('Client', () => { - it('should match a snapshot', () => { - const props: ClientProps = { - clientState: { - loading: false, - clientData: { - featuredApps: featuredAppsDataStub.data, - apps: appsDataStub - } as ClientItem - }, - // @ts-ignore: just pick the needed props for the test - match: { - params: { - page: '2' - } - }, - // @ts-ignore: just pick the needed props for the test - location: { - search: 'page=1' - } +const routerProps = { + match: { + params: { + page: '2' } - expect(toJson(shallow())).toMatchSnapshot() + }, + location: { + search: 'page=1' + } +} as RouteComponentProps + +const props = (loading: boolean): ClientProps => ({ + clientState: { + loading: loading, + clientData: { + featuredApps: featuredAppsDataStub.data, + apps: appsDataStub + } as ClientItem + }, + appDetail: { + appDetailData: appDetailDataStub, + loading: false, + error: false + }, + clientId: '1', + installationsFormState: 'PENDING', + installationsSetFormState: jest.fn(), + fetchAppDetail: jest.fn(), + ...routerProps +}) + +describe('Client', () => { + it('should match a snapshot when LOADING false', () => { + expect(toJson(shallow())).toMatchSnapshot() }) - it('should match a snapshot', () => { - const props: ClientProps = { - clientState: { - loading: true, - clientData: { - featuredApps: featuredAppsDataStub.data, - apps: appsDataStub - } as ClientItem - }, - // @ts-ignore: just pick the needed props for the test - match: { - params: { - page: '2' - } - }, - // @ts-ignore: just pick the needed props for the test - location: { - search: 'page=1' - } - } - expect(toJson(shallow())).toMatchSnapshot() + it('should match a snapshot when LOADING true', () => { + expect(toJson(shallow())).toMatchSnapshot() }) it('should match a snapshot when featured apps is empty []', () => { @@ -87,26 +79,22 @@ describe('Client', () => { apps: appsDataStub } as ClientItem }, + appDetail: { + appDetailData: appDetailDataStub, + loading: false, + error: false + }, + clientId: '1', + installationsFormState: 'PENDING', + installationsSetFormState: jest.fn(), fetchAppDetail: jest.fn(), - appDetail: {} as AppDetailState, - clientId: 'ABC', ...routerProps } + expect(toJson(shallow())).toMatchSnapshot() }) it('should match a snapshot when featured apps is undefined', () => { - const routerProps = { - match: { - params: { - page: '2' - } - }, - location: { - search: 'page=1' - } - } as RouteComponentProps - const props: ClientProps = { clientState: { loading: false, @@ -115,31 +103,51 @@ describe('Client', () => { apps: appsDataStub } as ClientItem }, + appDetail: { + appDetailData: appDetailDataStub, + loading: false, + error: false + }, + clientId: '1', + installationsFormState: 'PENDING', + installationsSetFormState: jest.fn(), fetchAppDetail: jest.fn(), - appDetail: {} as AppDetailState, - clientId: 'ABC', ...routerProps } + expect(toJson(shallow())).toMatchSnapshot() }) describe('mapStateToProps', () => { it('should return correctly', () => { const mockState = { - client: {}, - appDetail: {}, + client: { + clientData: { + featuredApps: featuredAppsDataStub.data, + apps: appsDataStub + } + }, + appDetail: { + appDetailData: appDetailDataStub, + error: false, + loading: false + }, auth: { loginSession: { loginIdentity: { clientId: 'ABC' } } + }, + installations: { + formState: 'PENDING' } } as ReduxState const output = { clientState: mockState.client, appDetail: mockState.appDetail, - clientId: 'ABC' + clientId: 'ABC', + installationsFormState: 'PENDING' } const result = mapStateToProps(mockState) expect(result).toEqual(output) @@ -147,12 +155,18 @@ describe('Client', () => { }) describe('mapDispatchToProps', () => { - it('should call dispatch correctly', () => { + it('should call fetchAppDetail correctly', () => { const mockDispatch = jest.fn() const { fetchAppDetail } = mapDispatchToProps(mockDispatch) fetchAppDetail('123', 'ABC') expect(mockDispatch).toBeCalled() }) + it('should call installationsSetFormState correctly', () => { + const mockDispatch = jest.fn() + const { installationsSetFormState } = mapDispatchToProps(mockDispatch) + installationsSetFormState('SUCCESS') + expect(mockDispatch).toBeCalled() + }) }) describe('handleOnChange', () => { diff --git a/src/components/pages/__tests__/my-apps.tsx b/src/components/pages/__tests__/my-apps.tsx index 6c5aa7cb4a..670612d900 100644 --- a/src/components/pages/__tests__/my-apps.tsx +++ b/src/components/pages/__tests__/my-apps.tsx @@ -40,15 +40,15 @@ describe('MyApps', () => { it('handleUseEffect', () => { const mockProps = { - isSuccess: true, - appUninstallDone: jest.fn(), + isDone: true, + installationsSetFormState: jest.fn(), fetchMyApp: jest.fn(), pageNumber: 1 } const fn = handleUseEffect(mockProps) fn() + expect(mockProps.installationsSetFormState).toBeCalled() expect(mockProps.fetchMyApp).toBeCalledWith(mockProps.pageNumber) - expect(mockProps.appUninstallDone).toBeCalled() }) it('mapStateToProps', () => { @@ -62,7 +62,7 @@ describe('MyApps', () => { } } }, - appUninstall: { + installations: { formState: 'PENDING' } } as ReduxState @@ -71,7 +71,7 @@ describe('MyApps', () => { myAppsState: {}, appDetail: {}, clientId: '', - appUninstallFormState: 'PENDING' + installationsFormState: 'PENDING' } expect(result).toEqual(output) }) @@ -91,10 +91,10 @@ describe('MyApps', () => { expect(mockDispatch).toBeCalled() }) - it('appUninstallDone', () => { + it('installationsSetFormState', () => { const mockDispatch = jest.fn() - const { appUninstallDone } = mapDispatchToProps(mockDispatch) - appUninstallDone() + const { installationsSetFormState } = mapDispatchToProps(mockDispatch) + installationsSetFormState('PENDING') expect(mockDispatch).toBeCalled() }) }) diff --git a/src/components/pages/client.tsx b/src/components/pages/client.tsx index 70f6023de2..75c7d77fae 100644 --- a/src/components/pages/client.tsx +++ b/src/components/pages/client.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import { connect } from 'react-redux' -import { ReduxState } from '@/types/core' +import { ReduxState, FormState } from '@/types/core' import { ClientState } from '@/reducers/client' import { Loader } from '@reapit/elements' import ErrorBoundary from '@/components/hocs/error-boundary' @@ -13,17 +13,20 @@ import AppDetailModal from '@/components/ui/app-detail-modal' import { selectClientId } from '@/selector/client' import { AppSummaryModel } from '@/types/marketplace-api-schema' import styles from '@/styles/pages/client.scss?mod' +import { appInstallationsSetFormState } from '@/actions/app-installations' import { addQuery, getParamValueFromPath, hasFilterParams } from '@/utils/client-url-params' export interface ClientMappedActions { fetchAppDetail: (id: string, clientId: string) => void + installationsSetFormState: (formState: FormState) => void } export interface ClientMappedProps { clientState: ClientState appDetail: AppDetailState clientId: string + installationsFormState: FormState } export const handleAfterClose = ({ setVisible }) => () => setVisible(false) @@ -36,6 +39,20 @@ export const handleOnCardClick = ({ setVisible, appDetail, fetchAppDetail, clien fetchAppDetail(app.id, clientId) } } + +export const handleInstallationDone = ({ + isDone, + installationsSetFormState, + fetchAppDetail, + appDetail, + clientId +}) => () => { + if (isDone) { + installationsSetFormState('PENDING') + fetchAppDetail(appDetail.appDetailData.data.id, clientId) + } +} + export type ClientProps = ClientMappedActions & ClientMappedProps & RouteComponentProps<{ page?: any }> export const Client: React.FunctionComponent = ({ @@ -44,7 +61,9 @@ export const Client: React.FunctionComponent = ({ location, fetchAppDetail, appDetail, - clientId + clientId, + installationsFormState, + installationsSetFormState }) => { const pageNumber = !isNaN(Number(getParamValueFromPath(location.search, 'page'))) && @@ -59,6 +78,12 @@ export const Client: React.FunctionComponent = ({ const { totalCount, pageSize } = clientState?.clientData?.apps || {} const [visible, setVisible] = React.useState(false) + const isDone = installationsFormState === 'DONE' + + React.useEffect(handleInstallationDone({ isDone, installationsSetFormState, fetchAppDetail, appDetail, clientId }), [ + isDone + ]) + return (
@@ -104,11 +129,13 @@ export const Client: React.FunctionComponent = ({ export const mapStateToProps = (state: ReduxState): ClientMappedProps => ({ clientState: state.client, appDetail: state.appDetail, - clientId: selectClientId(state) + clientId: selectClientId(state), + installationsFormState: state.installations.formState }) export const mapDispatchToProps = (dispatch: any): ClientMappedActions => ({ - fetchAppDetail: (id: string, clientId: string) => dispatch(appDetailRequestData({ id, clientId })) + fetchAppDetail: (id: string, clientId: string) => dispatch(appDetailRequestData({ id, clientId })), + installationsSetFormState: (formState: FormState) => dispatch(appInstallationsSetFormState(formState)) }) export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Client)) diff --git a/src/components/pages/my-apps.tsx b/src/components/pages/my-apps.tsx index 4a8cbf8b31..2ac5f4f154 100644 --- a/src/components/pages/my-apps.tsx +++ b/src/components/pages/my-apps.tsx @@ -11,21 +11,21 @@ import { appDetailRequestData } from '@/actions/app-detail' import { AppDetailState } from '@/reducers/app-detail' import AppDetailModal from '../ui/app-detail-modal' import { myAppsRequestData } from '@/actions/my-apps' -import { appUninstallDone } from '@/actions/app-uninstall' import { selectClientId } from '@/selector/client' import { AppSummaryModel } from '@/types/marketplace-api-schema' import { handleLaunchApp } from '../../utils/launch-app' +import { appInstallationsSetFormState } from '@/actions/app-installations' export interface MyAppsMappedActions { fetchAppDetail: (id: string, clientId: string) => void fetchMyApp: (page: number) => void - appUninstallDone: () => void + installationsSetFormState: (formState: FormState) => void } export interface MyAppsMappedProps { myAppsState: MyAppsState appDetail: AppDetailState - appUninstallFormState: FormState + installationsFormState: FormState clientId: string } @@ -33,9 +33,9 @@ export type MyAppsProps = MyAppsMappedActions & MyAppsMappedProps & RouteCompone export const handleOnChange = history => (page: number) => history.push(`${routes.MY_APPS}/${page}`) -export const handleUseEffect = ({ isSuccess, appUninstallDone, fetchMyApp, pageNumber }) => () => { - if (isSuccess) { - appUninstallDone() +export const handleUseEffect = ({ isDone, installationsSetFormState, fetchMyApp, pageNumber }) => () => { + if (isDone) { + installationsSetFormState('PENDING') fetchMyApp(pageNumber) } } @@ -47,8 +47,8 @@ export const MyApps: React.FunctionComponent = ({ fetchMyApp, fetchAppDetail, appDetail, - appUninstallDone, - appUninstallFormState, + installationsFormState, + installationsSetFormState, history }) => { const pageNumber = match.params && !isNaN(match.params.page) ? Number(match.params.page) : 1 @@ -57,9 +57,9 @@ export const MyApps: React.FunctionComponent = ({ const list = myAppsState?.myAppsData?.data?.data || [] const { totalCount, pageSize } = myAppsState?.myAppsData?.data || {} const [visible, setVisible] = React.useState(false) - const isSuccess = appUninstallFormState === 'SUCCESS' + const isDone = installationsFormState === 'DONE' - React.useEffect(handleUseEffect({ isSuccess, appUninstallDone, fetchMyApp, pageNumber }), [isSuccess]) + React.useEffect(handleUseEffect({ isDone, installationsSetFormState, fetchMyApp, pageNumber }), [isDone]) if (unfetched || loading) { return @@ -95,13 +95,13 @@ export const mapStateToProps = (state: ReduxState): MyAppsMappedProps => ({ myAppsState: state.myApps, appDetail: state.appDetail, clientId: selectClientId(state), - appUninstallFormState: state.appUninstall.formState + installationsFormState: state.installations.formState }) export const mapDispatchToProps = (dispatch: any): MyAppsMappedActions => ({ fetchAppDetail: (id: string, clientId: string) => dispatch(appDetailRequestData({ id, clientId })), fetchMyApp: (page: number) => dispatch(myAppsRequestData(page)), - appUninstallDone: () => dispatch(appUninstallDone()) + installationsSetFormState: (formState: FormState) => dispatch(appInstallationsSetFormState(formState)) }) export default withRouter(connect(mapStateToProps, mapDispatchToProps)(MyApps)) diff --git a/src/components/ui/__tests__/__snapshots__/app-confirm-install.tsx.snap b/src/components/ui/__tests__/__snapshots__/app-confirm-install.tsx.snap index aa90ddfb35..77e8d438c1 100644 --- a/src/components/ui/__tests__/__snapshots__/app-confirm-install.tsx.snap +++ b/src/components/ui/__tests__/__snapshots__/app-confirm-install.tsx.snap @@ -5,7 +5,7 @@ exports[`AppConfirmInstallContent render correctly 1`] = ` This action will install the app for ALL platform users.
- mockAppName + Peter's Properties requires the permissions below. By installing you are granting permission to your data.
  • Read data about developers
  • +
  • + Write data about developers +
} @@ -32,7 +35,6 @@ exports[`AppConfirmInstallContent render correctly 1`] = ` + + + } + /> + +`; diff --git a/src/components/ui/__tests__/__snapshots__/app-confirm-uninstall.tsx.snap b/src/components/ui/__tests__/__snapshots__/app-confirm-uninstall.tsx.snap index f2cad8cc32..4cc5a1e988 100644 --- a/src/components/ui/__tests__/__snapshots__/app-confirm-uninstall.tsx.snap +++ b/src/components/ui/__tests__/__snapshots__/app-confirm-uninstall.tsx.snap @@ -5,7 +5,7 @@ exports[`AppConfirmUninstall render correctly 1`] = ` Are you sure you wish to uninstall - mockAppName + Peter's Properties ? This action will uninstall the app for ALL platform users. } @@ -26,7 +26,6 @@ exports[`AppConfirmUninstall render correctly 1`] = ` dataTest="agree-btn" fullWidth={true} loading={false} - onClick={[MockFunction]} type="button" variant="primary" > @@ -54,7 +53,7 @@ exports[`AppConfirmUninstall render correctly 2`] = ` Are you sure you wish to uninstall - mockAppName + Peter's Properties ? This action will uninstall the app for ALL platform users. } @@ -75,7 +74,6 @@ exports[`AppConfirmUninstall render correctly 2`] = ` dataTest="agree-btn" fullWidth={true} loading={false} - onClick={[MockFunction]} type="button" variant="primary" > @@ -103,7 +101,7 @@ exports[`AppConfirmUninstall render correctly 3`] = ` Are you sure you wish to uninstall - mockAppName + Peter's Properties ? This action will uninstall the app for ALL platform users. } @@ -124,7 +122,6 @@ exports[`AppConfirmUninstall render correctly 3`] = ` dataTest="agree-btn" fullWidth={true} loading={true} - onClick={[MockFunction]} type="button" variant="primary" > @@ -152,7 +149,7 @@ exports[`AppConfirmUninstall render correctly 4`] = ` Are you sure you wish to uninstall - mockAppName + Peter's Properties ? This action will uninstall the app for ALL platform users. } @@ -173,7 +170,6 @@ exports[`AppConfirmUninstall render correctly 4`] = ` dataTest="agree-btn" fullWidth={true} loading={false} - onClick={[MockFunction]} type="button" variant="primary" > @@ -196,4 +192,50 @@ exports[`AppConfirmUninstall render correctly 4`] = ` `; -exports[`AppConfirmUninstall render correctly 5`] = `""`; +exports[`AppConfirmUninstall render correctly 5`] = ` + + + + Are you sure you wish to uninstall + Peter's Properties + ? This action will uninstall the app for ALL platform users. + + } + /> + + + + + } + /> + +`; diff --git a/src/components/ui/__tests__/__snapshots__/developer-app-modal.tsx.snap b/src/components/ui/__tests__/__snapshots__/developer-app-modal.tsx.snap index 977aa85c1e..e6358d9056 100644 --- a/src/components/ui/__tests__/__snapshots__/developer-app-modal.tsx.snap +++ b/src/components/ui/__tests__/__snapshots__/developer-app-modal.tsx.snap @@ -73,24 +73,36 @@ exports[`DeveloperAppModalInner should match a snapshot when LOADING false 1`] = } data-test="app-detail-modal" footerItems={ - - - - + + + + + + + + + } /> + `; diff --git a/src/components/ui/__tests__/app-confirm-install.tsx b/src/components/ui/__tests__/app-confirm-install.tsx index 69c4845622..649b5c07d9 100644 --- a/src/components/ui/__tests__/app-confirm-install.tsx +++ b/src/components/ui/__tests__/app-confirm-install.tsx @@ -4,83 +4,47 @@ import toJson from 'enzyme-to-json' import { FormState, ReduxState } from '@/types/core' import { AppConfirmInstallContent, handleCloseModal, mapDispatchToProps, mapStateToProps } from '../app-confirm-install' import { appDetailDataStub } from '@/sagas/__stubs__/app-detail' -import { appPermissionStub } from '@/sagas/__stubs__/app-permission' + +const mockProps = { + appDetailData: appDetailDataStub.data, + installationsFormState: 'PENDING' as FormState, + afterClose: jest.fn(), + installApp: jest.fn(), + setAppDetailModalStateView: jest.fn(), + setAppDetailModalStateSuccess: jest.fn() +} describe('AppConfirmInstallContent', () => { it('render correctly', () => { - const mockProps = { - permissions: [{ name: 'Marketplace/developers.read', description: 'Read data about developers' }], - requestInstall: jest.fn(), - installDone: jest.fn(), - appName: 'mockAppName', - afterClose: jest.fn(), - setAppDetailModalStateView: jest.fn() - } - const wrapper = shallow() + const wrapper = shallow() expect(toJson(wrapper)).toMatchSnapshot() - const wrapper1 = shallow() + const wrapper1 = shallow() expect(toJson(wrapper1)).toMatchSnapshot() - const wrapper2 = shallow() + const wrapper2 = shallow() expect(toJson(wrapper2)).toMatchSnapshot() - const wrapper3 = shallow() + const wrapper3 = shallow() expect(toJson(wrapper3)).toMatchSnapshot() - const wrapper4 = shallow() + const wrapper4 = shallow() expect(toJson(wrapper4)).toMatchSnapshot() }) it('should return null when formState SUCCESS', () => { - const mockProps = { - permissions: [{ name: 'Marketplace/developers.read', description: 'Read data about developers' }], - requestInstall: jest.fn(), - installDone: jest.fn(), - appName: 'mockAppName', - afterClose: jest.fn(), - setAppDetailModalStateView: jest.fn(), - appInstallFormState: 'SUCCESS' as FormState - } - const wrapper = shallow() + const wrapper = shallow() expect(wrapper).toEqual({}) }) it('show confirm content', () => { - const mockProps = { - permissions: [{ name: 'Marketplace/developers.read', description: 'Read data about developers' }], - requestInstall: jest.fn(), - installDone: jest.fn(), - appName: 'mockAppName', - afterClose: jest.fn(), - setAppDetailModalStateView: jest.fn(), - appInstallFormState: 'PENDING' as FormState - } const wrapper = shallow() expect(wrapper.find('[data-test="confirm-content"]')).toHaveLength(1) }) it('button agree show loading when agree install', () => { - const mockProps = { - permissions: [{ name: 'Marketplace/developers.read', description: 'Read data about developers' }], - requestInstall: jest.fn(), - installDone: jest.fn(), - appName: 'mockAppName', - afterClose: jest.fn(), - setAppDetailModalStateView: jest.fn(), - appInstallFormState: 'SUBMITTING' as FormState - } - const wrapper = mount() + const wrapper = mount() expect(wrapper.find('[dataTest="agree-btn"]').prop('loading')).toEqual(true) }) it('button disagree show loading when agree install', () => { - const mockProps = { - permissions: [{ name: 'Marketplace/developers.read', description: 'Read data about developers' }], - requestInstall: jest.fn(), - installDone: jest.fn(), - appName: 'mockAppName', - afterClose: jest.fn(), - setAppDetailModalStateView: jest.fn(), - appInstallFormState: 'SUBMITTING' as FormState - } - const wrapper = mount() + const wrapper = mount() expect(wrapper.find('[dataTest="agree-btn"]').prop('loading')).toEqual(true) }) it('handleCloseModal', () => { @@ -94,17 +58,19 @@ describe('AppConfirmInstallContent', () => { describe('mapDispatchToProps', () => { const dispatch = jest.fn() - const afterClose = jest.fn() - const setAppDetailModalStateView = jest.fn() const fn = mapDispatchToProps(dispatch) it('should call dispatch when involke request install', () => { - fn.requestInstall() + fn.installApp({ appId: '1' })() expect(dispatch).toBeCalled() }) - it('should call dispatch when involke request install', () => { + it('should call dispatch when involke setAppDetailModalStateView', () => { fn.setAppDetailModalStateView() expect(dispatch).toBeCalled() }) + it('should call dispatch when involke setAppDetailModalStateSuccess', () => { + fn.setAppDetailModalStateSuccess() + expect(dispatch).toBeCalled() + }) }) describe('mapStateToProps', () => { @@ -113,31 +79,15 @@ describe('AppConfirmInstallContent', () => { appDetail: { appDetailData: appDetailDataStub }, - appInstall: { - formState: 'PENDING' - } - } - const expected = { - permissions: appPermissionStub, - appName: `Peter's Properties`, - appInstallFormState: 'PENDING' - } - const result = mapStateToProps(mockState as ReduxState) - expect(result).toEqual(expected) - }) - - it('should return correct Props when no data', () => { - const mockState = { - appInstall: { + installations: { formState: 'PENDING' } - } + } as ReduxState const expected = { - permissions: [], - appName: '', - appInstallFormState: 'PENDING' + appDetailData: appDetailDataStub.data, + installationsFormState: 'PENDING' } - const result = mapStateToProps(mockState as ReduxState) + const result = mapStateToProps(mockState) expect(result).toEqual(expected) }) }) diff --git a/src/components/ui/__tests__/app-confirm-uninstall.tsx b/src/components/ui/__tests__/app-confirm-uninstall.tsx index 6d7f0e44f3..64a60232db 100644 --- a/src/components/ui/__tests__/app-confirm-uninstall.tsx +++ b/src/components/ui/__tests__/app-confirm-uninstall.tsx @@ -5,76 +5,46 @@ import { FormState, ReduxState } from '@/types/core' import { AppConfirmUninstall, handleCloseModal, mapDispatchToProps, mapStateToProps } from '../app-confirm-uninstall' import { appDetailDataStub } from '@/sagas/__stubs__/app-detail' +const mockProps = { + appDetailData: appDetailDataStub.data, + installationsFormState: 'PENDING' as FormState, + afterClose: jest.fn(), + uninstallApp: jest.fn(), + setAppDetailModalStateView: jest.fn(), + setAppDetailModalStateSuccess: jest.fn() +} + describe('AppConfirmUninstall', () => { it('render correctly', () => { - const mockProps = { - requestUninstall: jest.fn(), - uninstallDone: jest.fn(), - appName: 'mockAppName', - afterClose: jest.fn(), - setAppDetailModalStateView: jest.fn() - } - const wrapper = shallow() + const wrapper = shallow() expect(toJson(wrapper)).toMatchSnapshot() - const wrapper1 = shallow() + const wrapper1 = shallow() expect(toJson(wrapper1)).toMatchSnapshot() - const wrapper2 = shallow() + const wrapper2 = shallow() expect(toJson(wrapper2)).toMatchSnapshot() - const wrapper3 = shallow() + const wrapper3 = shallow() expect(toJson(wrapper3)).toMatchSnapshot() - const wrapper4 = shallow() + const wrapper4 = shallow() expect(toJson(wrapper4)).toMatchSnapshot() }) it('should return null when appUninstallFormState SUCCESS', () => { - const mockProps = { - requestUninstall: jest.fn(), - uninstallDone: jest.fn(), - appName: 'mockAppName', - afterClose: jest.fn(), - setAppDetailModalStateView: jest.fn(), - appUninstallFormState: 'SUCCESS' as FormState - } - const wrapper = shallow() + const wrapper = shallow() expect(wrapper).toEqual({}) }) it('show confirm content', () => { - const mockProps = { - requestUninstall: jest.fn(), - uninstallDone: jest.fn(), - appName: 'mockAppName', - afterClose: jest.fn(), - setAppDetailModalStateView: jest.fn(), - appUninstallFormState: 'PENDING' as FormState - } const wrapper = shallow() expect(wrapper.find('[data-test="confirm-content"]')).toHaveLength(1) }) it('button agree show loading when agree install', () => { - const mockProps = { - requestUninstall: jest.fn(), - uninstallDone: jest.fn(), - appName: 'mockAppName', - afterClose: jest.fn(), - setAppDetailModalStateView: jest.fn(), - appUninstallFormState: 'SUBMITTING' as FormState - } - const wrapper = mount() + const wrapper = mount() expect(wrapper.find('[dataTest="agree-btn"]').prop('loading')).toEqual(true) }) it('button disagree show loading when agree install', () => { - const mockProps = { - requestUninstall: jest.fn(), - uninstallDone: jest.fn(), - appName: 'mockAppName', - afterClose: jest.fn(), - setAppDetailModalStateView: jest.fn(), - appUninstallFormState: 'SUBMITTING' as FormState - } - const wrapper = mount() + const wrapper = mount() expect(wrapper.find('[dataTest="agree-btn"]').prop('loading')).toEqual(true) }) it('handleCloseModal', () => { @@ -88,17 +58,19 @@ describe('AppConfirmUninstall', () => { describe('mapDispatchToProps', () => { const dispatch = jest.fn() - const afterClose = jest.fn() - const setAppDetailModalStateView = jest.fn() const fn = mapDispatchToProps(dispatch) it('should call dispatch when involke request install', () => { - fn.requestUninstall() + fn.uninstallApp({ appId: '1', installationId: '1' })() expect(dispatch).toBeCalled() }) - it('should call dispatch when involke request install', () => { + it('should call dispatch when involke setAppDetailModalStateView', () => { fn.setAppDetailModalStateView() expect(dispatch).toBeCalled() }) + it('should call dispatch when involke setAppDetailModalStateSuccess', () => { + fn.setAppDetailModalStateSuccess() + expect(dispatch).toBeCalled() + }) }) describe('mapStateToProps', () => { @@ -107,29 +79,15 @@ describe('AppConfirmUninstall', () => { appDetail: { appDetailData: appDetailDataStub }, - appUninstall: { - formState: 'PENDING' - } - } - const expected = { - appName: `Peter's Properties`, - appUninstallFormState: 'PENDING' - } - const result = mapStateToProps(mockState as ReduxState) - expect(result).toEqual(expected) - }) - - it('should return correct Props when no data', () => { - const mockState = { - appUninstall: { + installations: { formState: 'PENDING' } - } + } as ReduxState const expected = { - appName: '', - appUninstallFormState: 'PENDING' + appDetailData: appDetailDataStub.data, + installationsFormState: 'PENDING' } - const result = mapStateToProps(mockState as ReduxState) + const result = mapStateToProps(mockState) expect(result).toEqual(expected) }) }) diff --git a/src/components/ui/__tests__/app-detail.tsx b/src/components/ui/__tests__/app-detail.tsx index 0d124e63cb..06f5939869 100644 --- a/src/components/ui/__tests__/app-detail.tsx +++ b/src/components/ui/__tests__/app-detail.tsx @@ -8,7 +8,6 @@ const props: AppDetailProps = { setDeveloperAppModalStateDelete: jest.fn(), setAppDetailModalStateViewConfirm: jest.fn(), setAppDetailModalStateUninstall: jest.fn(), - appUninstallFormState: 'PENDING', isCurrentLoggedUserDeveloper: true, isCurrentLoggedUserClient: false, data: {}, diff --git a/src/components/ui/app-confirm-install.tsx b/src/components/ui/app-confirm-install.tsx index 9612af58c9..20271dc83f 100644 --- a/src/components/ui/app-confirm-install.tsx +++ b/src/components/ui/app-confirm-install.tsx @@ -1,27 +1,25 @@ import * as React from 'react' import { connect } from 'react-redux' import { FormState, ReduxState } from '@/types/core' -import { ScopeModel } from '@/types/marketplace-api-schema' +import { ScopeModel, AppDetailModel } from '@/types/marketplace-api-schema' import appPermissionContentStyles from '@/styles/pages/app-permission-content.scss?mod' import { Button, SubTitleH6, ModalHeader, ModalBody, ModalFooter } from '@reapit/elements' -import { appInstallRequestData, appInstallDone } from '@/actions/app-install' -import { setAppDetailModalStateView } from '@/actions/app-detail-modal' +import { setAppDetailModalStateView, setAppDetailModalStateSuccess } from '@/actions/app-detail-modal' +import { InstallParams, appInstallationsRequestInstall } from '@/actions/app-installations' export type AppConfirmInstallContentMappedProps = { - permissions: ScopeModel[] - appInstallFormState: FormState - appName: string + installationsFormState: FormState + appDetailData?: AppDetailModel } export interface AppConfirmInstallContentMappedActions { setAppDetailModalStateView: () => void - requestInstall: () => void - installDone: () => void + setAppDetailModalStateSuccess: () => void + installApp: (params: InstallParams) => () => void } export type AppConfirmInstallContentInnerProps = AppConfirmInstallContentMappedProps & AppConfirmInstallContentMappedActions & { - setAppDetailModalStateView: () => void afterClose?: () => void } @@ -30,41 +28,45 @@ export const handleCloseModal = (setAppDetailModalStateView: () => void, afterCl setAppDetailModalStateView() } +export const handleInstallSuccess = ({ isSuccessed, setAppDetailModalStateSuccess }) => () => { + if (isSuccessed) { + setAppDetailModalStateSuccess() + } +} + export const AppConfirmInstallContent = ({ - permissions, - requestInstall, - installDone, - appInstallFormState, - appName, + installApp, + installationsFormState, + appDetailData, afterClose, - setAppDetailModalStateView + setAppDetailModalStateView, + setAppDetailModalStateSuccess }: AppConfirmInstallContentInnerProps) => { - const isLoading = appInstallFormState === 'SUBMITTING' - const isSuccessed = appInstallFormState === 'SUCCESS' + const isLoading = installationsFormState === 'SUBMITTING' + const isSuccessed = installationsFormState === 'SUCCESS' - if (isSuccessed) { - installDone() - return null - } + const { name, id, scopes = [] } = appDetailData || {} + + React.useEffect(handleInstallSuccess({ isSuccessed, setAppDetailModalStateSuccess }), [isSuccessed]) return ( <> void} data-test="confirm-content" /> This action will install the app for ALL platform users.
- {appName} requires the permissions below. By installing you are granting permission to your data. + {name} requires the permissions below. By installing you are granting permission to your data.
    - {permissions.map(({ description, name }) => ( + {scopes.map(({ description, name }) => (
  • {description}
  • @@ -85,7 +87,7 @@ export const AppConfirmInstallContent = ({ className={appPermissionContentStyles.installButton} type="button" variant="primary" - onClick={requestInstall} + onClick={installApp({ appId: id })} > Confirm @@ -107,15 +109,14 @@ export const AppConfirmInstallContent = ({ } export const mapStateToProps = (state: ReduxState): AppConfirmInstallContentMappedProps => ({ - permissions: state?.appDetail?.appDetailData?.data?.scopes || [], - appName: state?.appDetail?.appDetailData?.data?.name || '', - appInstallFormState: state.appInstall.formState + appDetailData: state?.appDetail?.appDetailData?.data, + installationsFormState: state.installations.formState }) export const mapDispatchToProps = (dispatch: any): AppConfirmInstallContentMappedActions => ({ setAppDetailModalStateView: () => dispatch(setAppDetailModalStateView()), - requestInstall: () => dispatch(appInstallRequestData()), - installDone: () => dispatch(appInstallDone()) + setAppDetailModalStateSuccess: () => dispatch(setAppDetailModalStateSuccess()), + installApp: (params: InstallParams) => () => dispatch(appInstallationsRequestInstall(params)) }) const AppConfirmInstallContentInnerWithConnect = connect(mapStateToProps, mapDispatchToProps)(AppConfirmInstallContent) diff --git a/src/components/ui/app-confirm-uninstall.tsx b/src/components/ui/app-confirm-uninstall.tsx index b3742603e0..1f32331cf3 100644 --- a/src/components/ui/app-confirm-uninstall.tsx +++ b/src/components/ui/app-confirm-uninstall.tsx @@ -2,58 +2,75 @@ import * as React from 'react' import { connect } from 'react-redux' import { FormState, ReduxState } from '@/types/core' import { Button, SubTitleH6, ModalFooter, ModalBody, ModalHeader } from '@reapit/elements' -import { appUninstallRequestData, appUninstallDone } from '@/actions/app-uninstall' -import { setAppDetailModalStateView } from '@/actions/app-detail-modal' +import { setAppDetailModalStateView, setAppDetailModalStateSuccess } from '@/actions/app-detail-modal' +import { AppDetailModel } from '@/types/marketplace-api-schema' +import { appInstallationsRequestUninstall, UninstallParams } from '@/actions/app-installations' -export type AppConfirmUninstallMappedProps = { - appUninstallFormState: FormState - appName: string +export interface AppConfirmUninstallInnerProps { + afterClose?: () => void +} + +export interface AppConfirmUninstallMappedProps { + appDetailData?: AppDetailModel + installationsFormState: FormState } export interface AppConfirmUninstallMappedActions { setAppDetailModalStateView: () => void - requestUninstall: () => void - uninstallDone: () => void + setAppDetailModalStateSuccess: () => void + uninstallApp: (params: UninstallParams) => () => void } -export type AppConfirmUninstallInnerProps = AppConfirmUninstallMappedProps & - AppConfirmUninstallMappedActions & { - setAppDetailModalStateView: () => void - afterClose?: () => void - } +export type AppConfirmUninstallProps = AppConfirmUninstallInnerProps & + AppConfirmUninstallMappedProps & + AppConfirmUninstallMappedActions export const handleCloseModal = (setAppDetailModalStateView: () => void, afterClose?: () => void) => () => { if (afterClose) afterClose() setAppDetailModalStateView() } +export const handleUninstallSuccess = ({ isSuccessed, setAppDetailModalStateSuccess }) => () => { + if (isSuccessed) { + setAppDetailModalStateSuccess() + } +} + +export const generateUninstallParams = ({ id, installationId }) => () => { + return { + appId: id, + installationId, + terminatedReason: 'User uninstall' + } as UninstallParams +} + export const AppConfirmUninstall = ({ - requestUninstall, - uninstallDone, - appUninstallFormState, - appName, + appDetailData, + uninstallApp, + installationsFormState, afterClose, - setAppDetailModalStateView -}: AppConfirmUninstallInnerProps) => { - const isLoading = appUninstallFormState === 'SUBMITTING' - const isSuccessed = appUninstallFormState === 'SUCCESS' + setAppDetailModalStateView, + setAppDetailModalStateSuccess +}: AppConfirmUninstallProps) => { + const isLoading = installationsFormState === 'SUBMITTING' + const isSuccessed = installationsFormState === 'SUCCESS' + const { id, installationId, name } = appDetailData || {} - if (isSuccessed) { - uninstallDone() - return null - } + React.useEffect(handleUninstallSuccess({ isSuccessed, setAppDetailModalStateSuccess }), [isSuccessed]) + + const uninstallParams = React.useMemo(generateUninstallParams({ id, installationId }), [appDetailData]) return ( <> void} data-test="confirm-content" /> - Are you sure you wish to uninstall {appName}? This action will uninstall the app for ALL platform users. + Are you sure you wish to uninstall {name}? This action will uninstall the app for ALL platform users. } /> @@ -67,7 +84,7 @@ export const AppConfirmUninstall = ({ fullWidth type="button" variant="primary" - onClick={requestUninstall} + onClick={uninstallApp(uninstallParams)} > Agree @@ -90,14 +107,14 @@ export const AppConfirmUninstall = ({ } export const mapStateToProps = (state: ReduxState): AppConfirmUninstallMappedProps => ({ - appName: state?.appDetail?.appDetailData?.data?.name || '', - appUninstallFormState: state.appUninstall.formState + appDetailData: state.appDetail.appDetailData?.data, + installationsFormState: state.installations.formState }) export const mapDispatchToProps = (dispatch: any): AppConfirmUninstallMappedActions => ({ setAppDetailModalStateView: () => dispatch(setAppDetailModalStateView()), - requestUninstall: () => dispatch(appUninstallRequestData()), - uninstallDone: () => dispatch(appUninstallDone()) + setAppDetailModalStateSuccess: () => dispatch(setAppDetailModalStateSuccess()), + uninstallApp: (params: UninstallParams) => () => dispatch(appInstallationsRequestUninstall(params)) }) const AppConfirmUninstallInnerWithConnect = connect(mapStateToProps, mapDispatchToProps)(AppConfirmUninstall) diff --git a/src/components/ui/app-detail-modal/__tests__/app-detail-inner.tsx b/src/components/ui/app-detail-modal/__tests__/app-detail-inner.tsx index 4516a31b3a..00351c100a 100644 --- a/src/components/ui/app-detail-modal/__tests__/app-detail-inner.tsx +++ b/src/components/ui/app-detail-modal/__tests__/app-detail-inner.tsx @@ -4,60 +4,42 @@ import toJson from 'enzyme-to-json' import { AppDetailInner, AppDetailInnerProps } from '../app-detail-inner' import { appDetailDataStub } from '@/sagas/__stubs__/app-detail' +const mockProps: AppDetailInnerProps = { + appDetailModalState: 'VIEW_DETAIL', + appDetailState: { loading: false, error: false, appDetailData: appDetailDataStub }, + setAppDetailModalStateView: jest.fn(), + installationsSetFormState: jest.fn() +} + describe('AppDetailInner', () => { it('should match a snapshot when appDetailModalState = VIEW_DETAIL', () => { - const props: AppDetailInnerProps = { - appDetailModalState: 'VIEW_DETAIL', - appDetailState: { loading: false, error: false, appDetailData: appDetailDataStub }, - setAppDetailModalStateView: jest.fn() - } - expect(toJson(shallow())).toMatchSnapshot() + expect(shallow()).toMatchSnapshot() }) it('should match a snapshot when appDetailModalState = VIEW_CONFIRM_INSTALL', () => { - const props: AppDetailInnerProps = { - appDetailModalState: 'VIEW_CONFIRM_INSTALL', - appDetailState: { loading: false, error: false, appDetailData: appDetailDataStub }, - setAppDetailModalStateView: jest.fn() - } - expect(toJson(shallow())).toMatchSnapshot() + const props: AppDetailInnerProps = { ...mockProps, appDetailModalState: 'VIEW_CONFIRM_INSTALL' } + expect(shallow()).toMatchSnapshot() }) it('should render AppDetail when appDetailModalState = VIEW_DETAIL', () => { - const props: AppDetailInnerProps = { - appDetailModalState: 'VIEW_DETAIL', - appDetailState: { loading: false, error: false, appDetailData: appDetailDataStub }, - setAppDetailModalStateView: jest.fn() - } - const wrapper = shallow() + const wrapper = shallow() expect(wrapper.find('AppDetailWithConnect')).toHaveLength(1) }) it('should render AppInstallConfirm when appDetailModalState = VIEW_CONFIRM_INSTALL', () => { - const props: AppDetailInnerProps = { - appDetailModalState: 'VIEW_CONFIRM_INSTALL', - appDetailState: { loading: false, error: false, appDetailData: appDetailDataStub }, - setAppDetailModalStateView: jest.fn() - } + const props: AppDetailInnerProps = { ...mockProps, appDetailModalState: 'VIEW_CONFIRM_INSTALL' } const wrapper = shallow() expect(wrapper.find('AppConfirmInstallContentInnerWithConnect')).toHaveLength(1) }) it('should render CallToAction when appDetailModalState = VIEW_DETAIL_ACTION_SUCCESS', () => { - const props: AppDetailInnerProps = { - appDetailModalState: 'VIEW_DETAIL_ACTION_SUCCESS', - appDetailState: { loading: false, error: false, appDetailData: appDetailDataStub }, - setAppDetailModalStateView: jest.fn() - } + const props: AppDetailInnerProps = { ...mockProps, appDetailModalState: 'VIEW_DETAIL_ACTION_SUCCESS' } const wrapper = mount() expect(wrapper.find('CallToAction')).toHaveLength(1) }) it('should render null when !appDetailState.appDetailData || !appDetailState.appDetailData.data', () => { - const props = { - appDetailModalState: 'VIEW_CONFIRM_INSTALL', - appDetailState: { loading: false, error: false } - } as AppDetailInnerProps + const props: AppDetailInnerProps = { ...mockProps, appDetailModalState: 'VIEW_CONFIRM_INSTALL' } const wrapper = shallow() expect(wrapper.find('AppInstallConfirm')).toHaveLength(0) expect(wrapper.find('AppPermission')).toHaveLength(0) diff --git a/src/components/ui/app-detail-modal/app-detail-inner.tsx b/src/components/ui/app-detail-modal/app-detail-inner.tsx index 77719f5bce..5dcfc3baa8 100644 --- a/src/components/ui/app-detail-modal/app-detail-inner.tsx +++ b/src/components/ui/app-detail-modal/app-detail-inner.tsx @@ -1,14 +1,15 @@ import * as React from 'react' import { connect } from 'react-redux' import { AppDetailModalState } from '@/reducers/app-detail-modal' -import { ReduxState } from '@/types/core' +import { ReduxState, FormState } from '@/types/core' import AppDetail from '@/components/ui/app-detail' import { AppDetailState } from '@/reducers/app-detail' import AppInstallConfirm from '@/components/ui/app-confirm-install' import AppUninstallConfirm from '@/components/ui/app-confirm-uninstall' import CallToAction from '../call-to-action' -import { handleCloseModal, mapDispatchToProps } from '../app-confirm-install' import { ModalBody } from '@reapit/elements' +import { setAppDetailModalStateView } from '@/actions/app-detail-modal' +import { appInstallationsSetFormState } from '@/actions/app-installations' export interface AppDetailInnerMappedProps { appDetailModalState: AppDetailModalState @@ -17,6 +18,7 @@ export interface AppDetailInnerMappedProps { export interface AppDetailInnerMappedActions { setAppDetailModalStateView: () => void + installationsSetFormState: (formState: FormState) => void } export const mapStateToProps = (state: ReduxState): AppDetailInnerMappedProps => ({ @@ -24,16 +26,32 @@ export const mapStateToProps = (state: ReduxState): AppDetailInnerMappedProps => appDetailState: state.appDetail }) +export const mapDispatchToProps = (dispatch: any): AppDetailInnerMappedActions => ({ + setAppDetailModalStateView: () => dispatch(setAppDetailModalStateView()), + installationsSetFormState: (formState: FormState) => dispatch(appInstallationsSetFormState(formState)) +}) + export type AppDetailInnerProps = AppDetailInnerMappedProps & AppDetailInnerMappedActions & { afterClose?: () => void } +export const handleCloseModal = ( + setAppDetailModalStateView: () => void, + afterClose?: () => void, + installationsSetFormState?: (formState: FormState) => void +) => () => { + afterClose && afterClose() + installationsSetFormState && installationsSetFormState('DONE') + setAppDetailModalStateView() +} + export const AppDetailInner: React.FunctionComponent = ({ appDetailModalState, appDetailState, afterClose, - setAppDetailModalStateView + setAppDetailModalStateView, + installationsSetFormState }) => { if (appDetailModalState === 'VIEW_DETAIL') { if (!appDetailState.appDetailData || !appDetailState.appDetailData.data) { @@ -60,7 +78,7 @@ export const AppDetailInner: React.FunctionComponent = ({ title="Success!" buttonText="Back to List" dataTest="alertInstalledSuccess" - onButtonClick={handleCloseModal(setAppDetailModalStateView, afterClose)} + onButtonClick={handleCloseModal(setAppDetailModalStateView, afterClose, installationsSetFormState)} isCenter > {appName} has been successfully {isInstalled ? 'installed' : 'uninstalled'} diff --git a/src/components/ui/app-detail-modal/app-detail-modal.tsx b/src/components/ui/app-detail-modal/app-detail-modal.tsx index aae1621188..d2f3f95085 100644 --- a/src/components/ui/app-detail-modal/app-detail-modal.tsx +++ b/src/components/ui/app-detail-modal/app-detail-modal.tsx @@ -4,11 +4,6 @@ import { connect } from 'react-redux' import { setAppDetailModalStateView } from '@/actions/app-detail-modal' import AppDetailInner from './app-detail-inner' import AppDetailAsyncContainer from './app-detail-async-container' -import { FormState, ReduxState } from '@/types/core' - -export interface ActionDetailModalMappedState { - appInstallFormState: FormState -} export interface ActionDetailModalMappedAction { setAppDetailModalStateView: () => void @@ -20,10 +15,6 @@ const mapDispatchToProps = (dispatch: any): ActionDetailModalMappedAction => ({ setAppDetailModalStateView: () => dispatch(setAppDetailModalStateView()) }) -const mapStateToProps = (state: ReduxState): ActionDetailModalMappedState => ({ - appInstallFormState: state.appInstall.formState -}) - export const handleAfterClose = (setAppDetailModalStateView: () => void, afterClose?: () => void) => () => { if (afterClose) { afterClose() @@ -45,6 +36,6 @@ export const AppDetailModal: React.FunctionComponent = ({ ) } -const AppDetailModalWithConnect = connect(mapStateToProps, mapDispatchToProps)(AppDetailModal) +const AppDetailModalWithConnect = connect(null, mapDispatchToProps)(AppDetailModal) export default AppDetailModalWithConnect diff --git a/src/components/ui/app-detail.tsx b/src/components/ui/app-detail.tsx index 575978f204..3b53133a72 100644 --- a/src/components/ui/app-detail.tsx +++ b/src/components/ui/app-detail.tsx @@ -20,7 +20,6 @@ export interface AppDetailModalInnerProps { export interface AppDetailModalMappedProps { isCurrentLoggedUserClient: boolean isCurrentLoggedUserDeveloper: boolean - appUninstallFormState: FormState } export interface AppDetailModalMappedActions { @@ -39,7 +38,6 @@ export const AppDetail: React.FunctionComponent = ({ data, setAppDetailModalStateViewConfirm, setAppDetailModalStateUninstall, - appUninstallFormState, isCurrentLoggedUserClient, isCurrentLoggedUserDeveloper, afterClose, @@ -49,12 +47,10 @@ export const AppDetail: React.FunctionComponent = ({ return null } - const { id, media = [], description, name, summary, developer, installedOn, scopes } = data + const { id, media = [], description, name, summary, developer, installedOn, scopes = [] } = data const icon = media.filter(({ type }) => type === 'icon')[0] const carouselImages = media.filter(({ type }) => type === 'image') - const isLoadingUninstall = appUninstallFormState === 'SUBMITTING' - const settings: Settings = { dots: false, speed: 500, @@ -106,17 +102,18 @@ export const AppDetail: React.FunctionComponent = ({

    {description}


    -

    Permission

    +

    Permissions

    {isCurrentLoggedUserDeveloper && You have requested the following permissions for this App:} - {isCurrentLoggedUserClient && installedOn ? ( - This app has been granted the following permissions to your data: - ) : ( - This App requires the following permissions in order to access your data: - )} + {isCurrentLoggedUserClient && + (installedOn ? ( + This app has been granted the following permissions to your data: + ) : ( + This App requires the following permissions in order to access your data: + ))}
      - {scopes?.map(item => ( + {scopes.map(item => (
    • {item.description}
    • ))}
    @@ -133,8 +130,6 @@ export const AppDetail: React.FunctionComponent = ({ type="button" variant="primary" dataTest="btnAppDetailUninstallApp" - loading={Boolean(isLoadingUninstall)} - disabled={Boolean(isLoadingUninstall)} onClick={setAppDetailModalStateUninstall} > Uninstall App @@ -144,8 +139,6 @@ export const AppDetail: React.FunctionComponent = ({ type="button" variant="primary" dataTest="btnAppDetailInstallApp" - loading={false} - disabled={false} onClick={() => { if (!id) { return @@ -165,8 +158,7 @@ export const AppDetail: React.FunctionComponent = ({ export const mapStateToProps = (state: ReduxState): AppDetailModalMappedProps => { return { isCurrentLoggedUserClient: state.auth.loginType === 'CLIENT', - isCurrentLoggedUserDeveloper: state.auth.loginType === 'DEVELOPER', - appUninstallFormState: state.appUninstall.formState + isCurrentLoggedUserDeveloper: state.auth.loginType === 'DEVELOPER' } } diff --git a/src/components/ui/app-installations/__tests__/__snapshots__/app-installations-modal.tsx.snap b/src/components/ui/app-installations/__tests__/__snapshots__/app-installations-modal.tsx.snap new file mode 100644 index 0000000000..08fb0c1a7c --- /dev/null +++ b/src/components/ui/app-installations/__tests__/__snapshots__/app-installations-modal.tsx.snap @@ -0,0 +1,15 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`AppInstallationsModal should match a snapshot 1`] = ` + + + +`; diff --git a/src/components/ui/app-installations/__tests__/__snapshots__/confirm-uninstall.tsx.snap b/src/components/ui/app-installations/__tests__/__snapshots__/confirm-uninstall.tsx.snap new file mode 100644 index 0000000000..afd23378f6 --- /dev/null +++ b/src/components/ui/app-installations/__tests__/__snapshots__/confirm-uninstall.tsx.snap @@ -0,0 +1,119 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ConfirmUninstall should match a snapshot when FORMSTATE is PENDING 1`] = ` + + + +
    + Are you sure you wish to uninstall ' + 1 + ' from ‘ + DXX + ’? +
    +