diff --git a/packages/marketplace/src/components/pages/client-app-detail/__test__/__snapshots__/app-content.test.tsx.snap b/packages/marketplace/src/components/pages/client-app-detail/__test__/__snapshots__/app-content.test.tsx.snap
new file mode 100644
index 0000000000..8ccf4af89d
--- /dev/null
+++ b/packages/marketplace/src/components/pages/client-app-detail/__test__/__snapshots__/app-content.test.tsx.snap
@@ -0,0 +1,211 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`AppContent AppContent - should match snapshot 1`] = `
+
+
+
+
+ Description
+
+
+
+
+
+ Permission Required
+
+
+
+
+
+ Destop Integration
+
+
+ Identity Check
+
+
+ Property Marketing Information
+
+
+ Vendor Marketing Report
+
+
+ Property Details Generation
+
+
+ Applicant Export
+
+
+ Property
+
+
+ Applicant
+
+
+
+ TBC
+
+
+
+ Lorem ipsum, dolor sit amet consectetur adipisicing elit. Magnam aliquid culpa saepe asperiores debitis illo dolorum dolore incidunt officiis praesentium, nemo similique veritatis exercitationem perferendis non mollitia animi laboriosam perspiciatis.
+
+
+
+
+ NEED HELP?
+
+
+
+`;
+
+exports[`AppContent RenderWithHeader - should match snapshot 1`] = `
+
+
+ test
+
+ some text
+
+`;
+
+exports[`AppContent Tag - should match snapshot 1`] = `
+
+ Test
+
+`;
+
+exports[`AppContent renderCategory - should match snapshot 1`] = ``;
+
+exports[`AppContent renderDescripion - should match snapshot 1`] = `
+
+
+
+ Description
+
+
+
+
+`;
+
+exports[`AppContent renderDesktopIntegrationTypes - should match snapshot 1`] = `
+
+
+
+ Destop Integration
+
+
+ Identity Check
+
+
+ Property Marketing Information
+
+
+ Vendor Marketing Report
+
+
+ Property Details Generation
+
+
+ Applicant Export
+
+
+ Property
+
+
+ Applicant
+
+
+
+`;
+
+exports[`AppContent renderExtraMedia - should match snapshot 1`] = `
+
+`;
+
+exports[`AppContent renderPermissions - should match snapshot 1`] = `
+
+
+
+ Permission Required
+
+
+ -
+ Read data about developers
+
+ -
+ Write data about developers
+
+
+
+
+`;
diff --git a/packages/marketplace/src/components/pages/client-app-detail/__test__/__snapshots__/client-app-detail.test.tsx.snap b/packages/marketplace/src/components/pages/client-app-detail/__test__/__snapshots__/client-app-detail.test.tsx.snap
index 5cb1726154..ce3f472e52 100644
--- a/packages/marketplace/src/components/pages/client-app-detail/__test__/__snapshots__/client-app-detail.test.tsx.snap
+++ b/packages/marketplace/src/components/pages/client-app-detail/__test__/__snapshots__/client-app-detail.test.tsx.snap
@@ -2,15 +2,17 @@
exports[`ClientAppDetail renderAppHeaderButtonGroup should match snapshot 1`] = `
-
-
+
-
-
- Installed
-
-
+ Uninstall App
+
`;
@@ -71,7 +73,9 @@ exports[`ClientAppDetail should match a snapshot 1`] = `
}
>
-
+
}
>
-
+
+
+
-
+
+
+
+
+
+
+
+
+
+ Verified by Reapit
+
-
-
-
-
-
-
-
-
-
+
+
-
+
+
-
-
-
-
+
+
+
+
+
+ Description
+
-
+
+
-
+
+
+
+ Permission Required
+
+
+
+
+
+
+
+
+ Developer
+
+
+ TBC
+
+
+
+
+
+
+ About Developer
+
+
+
+ Lorem ipsum, dolor sit amet consectetur adipisicing elit. Magnam aliquid culpa saepe asperiores debitis illo dolorum dolore incidunt officiis praesentium, nemo similique veritatis exercitationem perferendis non mollitia animi laboriosam perspiciatis.
+
+
+
+
+
+
+
+ Contact Developer
+
+
+
+
+
+
+
+
diff --git a/packages/marketplace/src/components/pages/client-app-detail/__test__/app-content.test.tsx b/packages/marketplace/src/components/pages/client-app-detail/__test__/app-content.test.tsx
new file mode 100644
index 0000000000..714d76e7c6
--- /dev/null
+++ b/packages/marketplace/src/components/pages/client-app-detail/__test__/app-content.test.tsx
@@ -0,0 +1,62 @@
+import React from 'react'
+import AppContent, {
+ renderCategory,
+ renderDescripion,
+ renderDesktopIntegrationTypes,
+ renderExtraMedia,
+ renderPermissions,
+ RenderWithHeader,
+ Tag,
+} from '../app-content'
+
+import { appDetailDataStub } from '@/sagas/__stubs__/app-detail'
+import { integrationTypesStub } from '@/sagas/__stubs__/integration-types'
+
+import { shallow } from 'enzyme'
+import { DesktopIntegrationTypeModel } from '@reapit/foundations-ts-definitions'
+import { AppDetailDataNotNull } from '@/reducers/client/app-detail'
+
+describe('AppContent', () => {
+ test('renderCategory - should match snapshot', () => {
+ const result = renderCategory(appDetailDataStub.data.category)
+ const wrapper = shallow({result}
)
+ expect(wrapper).toMatchSnapshot()
+ })
+ test('renderDescripion - should match snapshot', () => {
+ const result = renderDescripion(appDetailDataStub.data.description as string)
+ const wrapper = shallow({result}
)
+ expect(wrapper).toMatchSnapshot()
+ })
+ test('renderDesktopIntegrationTypes - should match snapshot', () => {
+ const result = renderDesktopIntegrationTypes(integrationTypesStub.data as DesktopIntegrationTypeModel[])
+ const wrapper = shallow({result}
)
+ expect(wrapper).toMatchSnapshot()
+ })
+ test('renderExtraMedia - should match snapshot', () => {
+ const result = renderExtraMedia(appDetailDataStub.data.media)
+ const wrapper = shallow({result}
)
+ expect(wrapper).toMatchSnapshot()
+ })
+ test('renderPermissions - should match snapshot', () => {
+ const result = renderPermissions(appDetailDataStub.data.scopes)
+ const wrapper = shallow({result}
)
+ expect(wrapper).toMatchSnapshot()
+ })
+ test('RenderWithHeader - should match snapshot', () => {
+ const wrapper = shallow(some text)
+ expect(wrapper).toMatchSnapshot()
+ })
+ test('Tag - should match snapshot', () => {
+ const wrapper = shallow(Test)
+ expect(wrapper).toMatchSnapshot()
+ })
+ test('AppContent - should match snapshot', () => {
+ const wrapper = shallow(
+ ,
+ )
+ expect(wrapper).toMatchSnapshot()
+ })
+})
diff --git a/packages/marketplace/src/components/pages/client-app-detail/__test__/app-header.text.tsx b/packages/marketplace/src/components/pages/client-app-detail/__test__/app-header.text.tsx
new file mode 100644
index 0000000000..5f5e5b64e2
--- /dev/null
+++ b/packages/marketplace/src/components/pages/client-app-detail/__test__/app-header.text.tsx
@@ -0,0 +1,17 @@
+import React from 'react'
+import AppHeader, { VerifiedByReapit } from '../app-header'
+
+import { appDetailDataStub } from '@/sagas/__stubs__/app-detail'
+import { shallow } from 'enzyme'
+import { AppDetailModel } from '@reapit/foundations-ts-definitions'
+
+describe('AppHeader', () => {
+ test('VerifiedByReapit - should match snapshot', () => {
+ const wrapper = shallow()
+ expect(wrapper).toMatchSnapshot()
+ })
+ test('AppHeader - should match snapshot', () => {
+ const wrapper = shallow()
+ expect(wrapper).toMatchSnapshot()
+ })
+})
diff --git a/packages/marketplace/src/components/pages/client-app-detail/__test__/client-app-detail.test.tsx b/packages/marketplace/src/components/pages/client-app-detail/__test__/client-app-detail.test.tsx
index 77027721bc..92d9aca2cf 100644
--- a/packages/marketplace/src/components/pages/client-app-detail/__test__/client-app-detail.test.tsx
+++ b/packages/marketplace/src/components/pages/client-app-detail/__test__/client-app-detail.test.tsx
@@ -36,30 +36,28 @@ describe('ClientAppDetail', () => {
const mockAppId = 'test'
const mockInstalledOn = '2020-2-20'
it('should match snapshot', () => {
- const wrapper = shallow({renderAppHeaderButtonGroup(mockAppId, mockInstalledOn, jest.fn())}
)
+ const wrapper = shallow({renderAppHeaderButtonGroup(mockAppId, mockInstalledOn, jest.fn(), jest.fn())}
)
expect(wrapper).toMatchSnapshot()
})
it('should render header button group when appId is existed', () => {
- const testRenderer = TestRenderer.create(renderAppHeaderButtonGroup(mockAppId, mockInstalledOn, jest.fn()))
+ const testRenderer = TestRenderer.create(
+ renderAppHeaderButtonGroup(mockAppId, mockInstalledOn, jest.fn(), jest.fn()),
+ )
const testInstance = testRenderer.root
expect(testInstance.children.length).toBe(1)
})
it('should render install app button if installedOn is empty', () => {
- const testRenderer = TestRenderer.create(renderAppHeaderButtonGroup(mockAppId, '', jest.fn()))
+ const testRenderer = TestRenderer.create(renderAppHeaderButtonGroup(mockAppId, '', jest.fn(), jest.fn()))
const testInstance = testRenderer.root
expect(testInstance.findByType(Button).props.children).toBe('Install App')
})
- it('should render installed label if installedOn is existed', () => {
- const testRenderer = TestRenderer.create(renderAppHeaderButtonGroup(mockAppId, mockInstalledOn, jest.fn()))
+ it('should render uninstall app button if installedOn is existed', () => {
+ const testRenderer = TestRenderer.create(renderAppHeaderButtonGroup(mockAppId, 'exist', jest.fn(), jest.fn()))
const testInstance = testRenderer.root
- expect(
- testInstance.findByProps({
- id: 'installed-label-container',
- }).children.length,
- ).toBeGreaterThan(0)
+ expect(testInstance.findByType(Button).props.children).toBe('Uninstall App')
})
it('should not render header button group when appId is empty', () => {
- const testRenderer = TestRenderer.create(renderAppHeaderButtonGroup('', mockInstalledOn, jest.fn()))
+ const testRenderer = TestRenderer.create(renderAppHeaderButtonGroup('', mockInstalledOn, jest.fn(), jest.fn()))
const testInstance = testRenderer.getInstance
expect(testInstance).toHaveLength(0)
})
diff --git a/packages/marketplace/src/components/pages/client-app-detail/app-content.tsx b/packages/marketplace/src/components/pages/client-app-detail/app-content.tsx
new file mode 100644
index 0000000000..057a701bc5
--- /dev/null
+++ b/packages/marketplace/src/components/pages/client-app-detail/app-content.tsx
@@ -0,0 +1,118 @@
+import * as React from 'react'
+import { H5, HTMLRender, Button } from '@reapit/elements'
+import { CategoryModel, DesktopIntegrationTypeModel } from '@reapit/foundations-ts-definitions'
+import styles from '@/styles/blocks/app-detail.scss?mod'
+import { ScopeModel, MediaModel } from '@reapit/foundations-ts-definitions'
+import '@/styles/vendor/slick.scss'
+import clientAppDetailStyles from '@/styles/pages/client-app-detail.scss?mod'
+
+import { AppDetailDataNotNull } from '@/reducers/client/app-detail'
+
+export type AppContentProps = {
+ appDetailData: AppDetailDataNotNull
+ desktopIntegrationTypes: DesktopIntegrationTypeModel[]
+}
+
+export const Tag = ({ children }) => {children}
+
+export const renderDescripion = (description: string) => (
+
+
Description
+
+
+)
+
+export const renderPermissions = (scopes: ScopeModel[] = []) => (
+
+
Permission Required
+
+ {scopes.map(scope => (
+ - {scope?.description}
+ ))}
+
+
+)
+
+export const renderCategory = (category: CategoryModel | undefined) => {
+ if (!category) {
+ return undefined
+ }
+
+ return (
+
+
Category
+ {category.name}
+
+ )
+}
+
+export const renderDesktopIntegrationTypes = (desktopIntegrationTypes: DesktopIntegrationTypeModel[]) => {
+ if (desktopIntegrationTypes.length === 0) {
+ return undefined
+ }
+
+ return (
+
+
Destop Integration
+ {desktopIntegrationTypes.map(({ name }) => (
+ {name}
+ ))}
+
+ )
+}
+
+export const RenderWithHeader: React.FC<{ header: string }> = ({ header, children }) => (
+
+
{header}
+ {children}
+
+)
+
+export const renderExtraMedia = (media: MediaModel[] = []) =>
+ media.map(({ uri }) => (
+
+
+
+ ))
+
+const AppContent: React.FC = ({ appDetailData, desktopIntegrationTypes = [] }) => {
+ const { summary = '', description = '', category, scopes = [], media = [] } = appDetailData
+ /**
+ * 0 = icon
+ * 1 = featured media
+ * 2 -> nth: extra media
+ */
+ const extraMedia = media.filter((_, index) => index > 1)
+ console.log({
+ extraMedia,
+ media,
+ })
+
+ return (
+
+
{summary}
+ {renderDescripion(description)}
+ {summary &&
{summary}
}
+ {media[0] &&
}
+ {renderPermissions(scopes)}
+ {renderExtraMedia(extraMedia)}
+ {renderCategory(category)}
+ {renderDesktopIntegrationTypes(desktopIntegrationTypes)}
+
TBC
+
+
+ Lorem ipsum, dolor sit amet consectetur adipisicing elit. Magnam aliquid culpa saepe asperiores debitis illo
+ dolorum dolore incidunt officiis praesentium, nemo similique veritatis exercitationem perferendis non mollitia
+ animi laboriosam perspiciatis.
+
+
+
+
+
+
+ )
+}
+
+export default AppContent
diff --git a/packages/marketplace/src/components/pages/client-app-detail/app-header.tsx b/packages/marketplace/src/components/pages/client-app-detail/app-header.tsx
new file mode 100644
index 0000000000..db76acf5aa
--- /dev/null
+++ b/packages/marketplace/src/components/pages/client-app-detail/app-header.tsx
@@ -0,0 +1,57 @@
+import * as React from 'react'
+import { H2 } from '@reapit/elements'
+import { FaCheck } from 'react-icons/fa'
+import developerAppDetailstyles from '@/styles/pages/developer-app-detail.scss?mod'
+import { AppDetailModel } from '@reapit/foundations-ts-definitions'
+import clientAppDetailStyles from '@/styles/pages/client-app-detail.scss?mod'
+
+export type AppHeaderProps = {
+ appDetailData: AppDetailModel & {
+ apiKey?: string | undefined
+ }
+ buttonGroup?: React.ReactNode
+}
+
+const appIconContainerClassName = [
+ developerAppDetailstyles.appIconContainer,
+ clientAppDetailStyles.appIconContainer,
+].join(' ')
+
+const appIconClassName = ['images', clientAppDetailStyles.appIcon].join(' ')
+
+const placeHolderUrl = 'https://bulma.io/images/placeholders/48x48.png'
+
+export const VerifiedByReapit: React.FC<{ appName: string }> = ({ appName }) => (
+
+
{appName}
+
+ Verified by Reapit
+
+
+)
+
+const AppHeader: React.FC = ({ appDetailData, buttonGroup }) => {
+ const { media, name = '' } = appDetailData
+ const appIcon = media?.filter(({ type }) => type === 'icon')[0]
+
+ return (
+
+
+
+
+
+
+
+ {buttonGroup}
+
+
+
+
+
+ )
+}
+
+export default AppHeader
diff --git a/packages/marketplace/src/components/pages/client-app-detail/client-app-detail.tsx b/packages/marketplace/src/components/pages/client-app-detail/client-app-detail.tsx
index 68f8d44a56..d9a9cf4d6f 100644
--- a/packages/marketplace/src/components/pages/client-app-detail/client-app-detail.tsx
+++ b/packages/marketplace/src/components/pages/client-app-detail/client-app-detail.tsx
@@ -1,17 +1,29 @@
import * as React from 'react'
-import { FaCheck } from 'react-icons/fa'
+import {
+ handleUninstallAppButtonClick,
+ handleCloseUninstallConfirmationModal,
+} from '../client-app-detail-manage/client-app-detail-manage'
+import ClientAppUninstallConfirmation from '@/components/ui/client-app-detail/client-app-uninstall-confirmation'
+import { DesktopIntegrationTypeModel } from '@/actions/app-integration-types'
+import { AppDetailDataNotNull } from '@/reducers/client/app-detail'
+import { selectIntegrationTypes } from '@/selector/integration-types'
import { useSelector } from 'react-redux'
import { selectAppDetailData, selectAppDetailLoading } from '@/selector/client-app-detail'
-import { selectLoginType } from '@/selector/auth'
-import AppHeader from '@/components/ui/app-detail/app-header'
-import AppContent from '@/components/ui/app-detail/app-content'
+import AppHeader from './app-header'
+import AppContent from './app-content'
import { Loader, Button } from '@reapit/elements'
-import styles from '@/styles/pages/developer-app-detail.scss?mod'
+import developerAppDetailStyles from '@/styles/pages/developer-app-detail.scss?mod'
+import clientAppDetailStyles from '@/styles/pages/client-app-detail.scss?mod'
import ClientAppInstallConfirmation from '@/components/ui/client-app-detail/client-app-install-confirmation'
export type ClientAppDetailProps = {}
+const appDetailContainerClassNames = [
+ clientAppDetailStyles.appDetailContainer,
+ developerAppDetailStyles.appDetailContainer,
+].join(' ')
+
export const handleCloseInstallConfirmationModal = (setIsVisibleInstallConfirmation: (isVisible: boolean) => void) => {
return () => {
setIsVisibleInstallConfirmation(false)
@@ -24,16 +36,25 @@ export const handleInstallAppButtonClick = (setIsVisibleInstallConfirmation: (is
}
}
-export const renderAppHeaderButtonGroup = (id: string, installedOn: string, onInstallConfirmationModal: () => void) => {
+export const renderAppHeaderButtonGroup = (
+ id: string,
+ installedOn: string,
+ onUninstallConfirmationModal: () => void,
+ onInstallConfirmationModal: () => void,
+) => {
return (
<>
{id && (
-
+
{installedOn ? (
-
-
- Installed
-
+
) : (