-
+
APIs
@@ -56,7 +56,7 @@ export const Documentation = () => {
Our interactive documentation allows you to easily experiment with our APIs with a ‘Try it now’
function to quickly build requests and inspect responses. To try it yourself and to see what data is available,
click{' '}
-
+
here
.
@@ -156,7 +156,7 @@ export const Support = () => {
You are currently logged into our alpha release of Reapit Foundations and we are continuing to update, add
additional features and address any issues that may appear. In the meantime, if you would like to request a
feature or report a bug, this can be done from the{' '}
-
+
‘Help’
{' '}
section on the left.
diff --git a/packages/developer-portal/src/components/ui/__tests__/help-item-list.tsx b/packages/developer-portal/src/components/ui/__tests__/help-item-list.tsx
index b2c3780cff..33d70245c9 100644
--- a/packages/developer-portal/src/components/ui/__tests__/help-item-list.tsx
+++ b/packages/developer-portal/src/components/ui/__tests__/help-item-list.tsx
@@ -3,8 +3,7 @@ import { shallow } from 'enzyme'
import toJson from 'enzyme-to-json'
import { HelpItemList } from '../help-item-list'
-
-import { helpItems } from '@/components/pages/developer-help'
+import { helpItems } from '@/components/pages/help/help'
describe('HelpItemList', () => {
it('should match a snapshot', () => {
diff --git a/packages/developer-portal/src/components/ui/developer-edition-modal/__tests__/__snapshots__/success-content.tsx.snap b/packages/developer-portal/src/components/ui/developer-edition-modal/__tests__/__snapshots__/success-content.tsx.snap
index 112aedc5e0..c10aa6e5e3 100644
--- a/packages/developer-portal/src/components/ui/developer-edition-modal/__tests__/__snapshots__/success-content.tsx.snap
+++ b/packages/developer-portal/src/components/ui/developer-edition-modal/__tests__/__snapshots__/success-content.tsx.snap
@@ -34,13 +34,22 @@ exports[`SuccessContent should match snapshot 1`] = `
/>
- CLOSE
-
+
+
+ CLOSE
+
+
+ DOWNLOAD NOW
+
+
}
/>
diff --git a/packages/developer-portal/src/components/ui/developer-edition-modal/__tests__/success-content.tsx b/packages/developer-portal/src/components/ui/developer-edition-modal/__tests__/success-content.tsx
index 5395cef13c..a32b61fbf2 100644
--- a/packages/developer-portal/src/components/ui/developer-edition-modal/__tests__/success-content.tsx
+++ b/packages/developer-portal/src/components/ui/developer-edition-modal/__tests__/success-content.tsx
@@ -1,6 +1,6 @@
import * as React from 'react'
import { shallow } from 'enzyme'
-import { SuccessContent } from '../success-content'
+import { SuccessContent, handleDownload } from '../success-content'
import { developerStub } from '@/sagas/__stubs__/developer'
describe('SuccessContent', () => {
@@ -9,3 +9,14 @@ describe('SuccessContent', () => {
expect(wrapper).toMatchSnapshot()
})
})
+
+describe('handleDownload', () => {
+ it('should open download link', () => {
+ const downloadURL = 'downloadURL'
+ window.reapit.config.developerEditionDownloadUrl = downloadURL
+ window.open = jest.fn()
+
+ handleDownload()
+ expect(window.open).toBeCalledWith(downloadURL, '_self')
+ })
+})
diff --git a/packages/developer-portal/src/components/ui/developer-edition-modal/success-content.tsx b/packages/developer-portal/src/components/ui/developer-edition-modal/success-content.tsx
index 78daad4f0e..fd0744772a 100644
--- a/packages/developer-portal/src/components/ui/developer-edition-modal/success-content.tsx
+++ b/packages/developer-portal/src/components/ui/developer-edition-modal/success-content.tsx
@@ -8,6 +8,10 @@ export type SuccessContentProps = Pick & {
developer?: DeveloperModel
}
+export const handleDownload = () => {
+ window.open(window.reapit.config.developerEditionDownloadUrl, '_self')
+}
+
export const SuccessContent: React.FC = ({ developer, afterClose }) => {
if (!developer) return null
@@ -44,9 +48,14 @@ export const SuccessContent: React.FC = ({ developer, after
/>
- CLOSE
-
+ <>
+
+ CLOSE
+
+
+ DOWNLOAD NOW
+
+ >
}
/>
>
diff --git a/packages/developer-portal/src/components/ui/menu.tsx b/packages/developer-portal/src/components/ui/menu.tsx
index 1daef0ff67..bccc28310c 100644
--- a/packages/developer-portal/src/components/ui/menu.tsx
+++ b/packages/developer-portal/src/components/ui/menu.tsx
@@ -65,35 +65,35 @@ export const generateMenuConfig = (
{
title: 'API',
key: 'SWAGGER',
- url: Routes.DEVELOPER_SWAGGER,
+ url: Routes.SWAGGER,
type: 'PRIMARY',
icon: ,
},
{
title: 'Webhooks',
key: 'WEBHOOKS',
- url: Routes.DEVELOPER_WEBHOOKS,
+ url: Routes.WEBHOOKS,
type: 'PRIMARY',
icon: ,
},
{
title: 'Docs',
key: 'API_DOCS',
- url: Routes.DEVELOPER_API_DOCS,
+ url: Routes.API_DOCS,
type: 'PRIMARY',
icon: ,
},
{
title: 'Desktop',
key: 'DESKTOP',
- url: Routes.DEVELOPER_DESKTOP,
+ url: Routes.DESKTOP,
type: 'PRIMARY',
icon: ,
},
{
title: 'Help',
key: 'HELP',
- url: Routes.DEVELOPER_HELP,
+ url: Routes.HELP,
type: 'PRIMARY',
icon: ,
},
diff --git a/packages/developer-portal/src/components/ui/submit-app-wizard/steps/step-before-you-start.tsx b/packages/developer-portal/src/components/ui/submit-app-wizard/steps/step-before-you-start.tsx
index 54053d2756..e54180f5e1 100644
--- a/packages/developer-portal/src/components/ui/submit-app-wizard/steps/step-before-you-start.tsx
+++ b/packages/developer-portal/src/components/ui/submit-app-wizard/steps/step-before-you-start.tsx
@@ -5,8 +5,7 @@ import Routes from '@/constants/routes'
import { WizardStepComponent, SetWizardStep } from '../types'
import { wizzardSteps } from '../constant'
-export const onViewDocs = (history: History) => () =>
- history.push(`${Routes.DEVELOPER_API_DOCS}/developer-portal`)
+export const onViewDocs = (history: History) => () => history.push(`${Routes.API_DOCS}/developer-portal`)
export const onCreateNewApp = (setWizardStep: SetWizardStep) => () => {
setWizardStep(wizzardSteps.INPUT_APP_NAME)
@@ -31,7 +30,7 @@ export const StepBeforeYouStart: WizardStepComponent = ({ setWizardStep }) => {
<>
diff --git a/packages/developer-portal/src/constants/routes.ts b/packages/developer-portal/src/constants/routes.ts
index da6e41352d..4044abcc53 100644
--- a/packages/developer-portal/src/constants/routes.ts
+++ b/packages/developer-portal/src/constants/routes.ts
@@ -2,23 +2,23 @@ const Routes = {
AUTHENTICATION: '/authentication',
AUTHENTICATION_LOGIN_TYPE: '/authentication/:loginType',
DEVELOPER: '/developer',
- DEVELOPER_WELCOME: '/developer/welcome',
+ WELCOME: '/developer/welcome',
APPS: '/developer/apps',
- DEVELOPER_APP_DETAIL: '/developer/apps/:appid',
- DEVELOPER_SWAGGER: '/developer/swagger',
- DEVELOPER_DESKTOP: '/developer/desktop',
+ APP_DETAIL: '/developer/apps/:appid',
+ SWAGGER: '/developer/swagger',
+ DESKTOP: '/developer/desktop',
APPS_EDIT: '/developer/apps/:appid/edit',
- DEVELOPER_API_DOCS: '/developer/api-docs',
+ API_DOCS: '/developer/api-docs',
ANALYTICS: '/developer/analytics',
ANALYTICS_TAB: '/developer/analytics/:activeTab?',
- DEVELOPER_RESET_PASSWORD: '/developer/reset-password',
- DEVELOPER_WEBHOOKS: '/developer/webhooks',
+ RESET_PASSWORD: '/developer/reset-password',
+ WEBHOOKS: '/developer/webhooks',
SETTINGS: '/developer/settings/',
SETTINGS_ORGANISATION_TAB: '/developer/settings/organisation',
SETTINGS_BILLING_TAB: '/developer/settings/billing',
SUBMIT_APP: '/developer/submit-app',
- DEVELOPER_HELP: '/developer/help',
- DEVELOPER_APP_PREVIEW: '/developer/apps/:appId/preview',
+ HELP: '/developer/help',
+ APP_PREVIEW: '/developer/apps/:appId/preview',
DEVELOPER_EDITION_DOWNLOAD: '/developer/edition-download',
REGISTER: '/register',
REGISTER_CONFIRM: '/register/confirm',
diff --git a/packages/developer-portal/src/core/__tests__/__snapshots__/router.tsx.snap b/packages/developer-portal/src/core/__tests__/__snapshots__/router.tsx.snap
index ba67c6f73e..af4aeec8c0 100644
--- a/packages/developer-portal/src/core/__tests__/__snapshots__/router.tsx.snap
+++ b/packages/developer-portal/src/core/__tests__/__snapshots__/router.tsx.snap
@@ -302,6 +302,20 @@ exports[`Router should match a snapshot 1`] = `
fetcher={true}
path="/developer/settings/"
/>
+
catchChunkError(() => import('../compone
const Login = React.lazy(() => catchChunkError(() => import('../components/pages/login')))
const Register = React.lazy(() => catchChunkError(() => import('../components/pages/register')))
const Apps = React.lazy(() => catchChunkError(() => import('../components/pages/apps')))
-const DeveloperAppDetail = React.lazy(() => catchChunkError(() => import('../components/pages/app-detail')))
-const DeveloperEditApp = React.lazy(() => catchChunkError(() => import('../components/pages/developer-edit-app')))
+const AppDetail = React.lazy(() => catchChunkError(() => import('../components/pages/app-detail')))
+const EditApp = React.lazy(() => catchChunkError(() => import('../components/pages/edit-app')))
const ApiDocsPage = React.lazy(() => catchChunkError(() => import('../components/pages/api-docs')))
const SwaggerPage = React.lazy(() => catchChunkError(() => import('../components/pages/swagger')))
-const DeveloperDesktopPage = React.lazy(() => catchChunkError(() => import('../components/pages/developer-desktop')))
-const DeveloperWelcomePage = React.lazy(() => catchChunkError(() => import('../components/pages/developer-welcome')))
-const DeveloperHelpPage = React.lazy(() => catchChunkError(() => import('../components/pages/developer-help')))
+const DesktopPage = React.lazy(() => catchChunkError(() => import('../components/pages/desktop')))
+const WelcomePage = React.lazy(() => catchChunkError(() => import('../components/pages/welcome')))
+const HelpPage = React.lazy(() => catchChunkError(() => import('../components/pages/help')))
const AnalyticsPage = React.lazy(() => catchChunkError(() => import('@/components/pages/analytics')))
const RegisterConfirm = React.lazy(() => catchChunkError(() => import('../components/pages/register-confirm')))
const WebhooksPage = React.lazy(() => catchChunkError(() => import('../components/pages/webhooks')))
-const SettingsPage = React.lazy(() => catchChunkError(() => import('../components/pages/settings/settings')))
+const SettingsPage = React.lazy(() => catchChunkError(() => import('../components/pages/settings/')))
const SettingsOrganisationTabPage = React.lazy(() =>
catchChunkError(() => import('../components/pages/settings/settings-organisation-tab')),
@@ -33,7 +33,7 @@ const SettingsBillingTabPage = React.lazy(() =>
catchChunkError(() => import('../components/pages/settings/settings-billing-tab')),
)
-const DeveloperEditionDownloadPage = React.lazy(() =>
+const EditionDownloadPage = React.lazy(() =>
catchChunkError(() => import('../components/pages/developer-edition-download')),
)
@@ -49,7 +49,7 @@ const Router = () => {
} />
-
+
@@ -60,25 +60,15 @@ const Router = () => {
component={Authentication}
/>
-
-
-
-
-
-
+
+
+
+
+
+
+
{
fetcher
component={SettingsOrganisationTabPage}
/>
-
-
+
+
} />
diff --git a/packages/developer-portal/src/tests/badges/badge-branches.svg b/packages/developer-portal/src/tests/badges/badge-branches.svg
index 828389066b..bc9049555a 100644
--- a/packages/developer-portal/src/tests/badges/badge-branches.svg
+++ b/packages/developer-portal/src/tests/badges/badge-branches.svg
@@ -1 +1 @@
-Coverage:branches Coverage:branches 69.97% 69.97%
\ No newline at end of file
+Coverage:branches Coverage:branches 68.64% 68.64%
\ No newline at end of file
diff --git a/packages/developer-portal/src/tests/badges/badge-functions.svg b/packages/developer-portal/src/tests/badges/badge-functions.svg
index c306084d0c..c5dbd4c6b6 100644
--- a/packages/developer-portal/src/tests/badges/badge-functions.svg
+++ b/packages/developer-portal/src/tests/badges/badge-functions.svg
@@ -1 +1 @@
-Coverage:functions Coverage:functions 81.82% 81.82%
\ No newline at end of file
+Coverage:functions Coverage:functions 79.36% 79.36%
\ No newline at end of file
diff --git a/packages/developer-portal/src/tests/badges/badge-lines.svg b/packages/developer-portal/src/tests/badges/badge-lines.svg
index 2a4ce36294..ddec17d912 100644
--- a/packages/developer-portal/src/tests/badges/badge-lines.svg
+++ b/packages/developer-portal/src/tests/badges/badge-lines.svg
@@ -1 +1 @@
-Coverage:lines Coverage:lines 91.2% 91.2%
\ No newline at end of file
+Coverage:lines Coverage:lines 89.8% 89.8%
\ No newline at end of file
diff --git a/packages/developer-portal/src/tests/badges/badge-statements.svg b/packages/developer-portal/src/tests/badges/badge-statements.svg
index 5c999ee2ea..9b15b3d0ec 100644
--- a/packages/developer-portal/src/tests/badges/badge-statements.svg
+++ b/packages/developer-portal/src/tests/badges/badge-statements.svg
@@ -1 +1 @@
-Coverage:statements Coverage:statements 90.2% 90.2%
\ No newline at end of file
+Coverage:statements Coverage:statements 88.79% 88.79%
\ No newline at end of file
diff --git a/packages/developer-portal/src/tests/cypress/hooks/login.ts b/packages/developer-portal/src/tests/cypress/hooks/login.ts
index 6c2dcd9c9f..9dadaeb4b4 100644
--- a/packages/developer-portal/src/tests/cypress/hooks/login.ts
+++ b/packages/developer-portal/src/tests/cypress/hooks/login.ts
@@ -76,7 +76,7 @@ export const loginDeveloperHook = () => {
userName: developerUserName,
password: developerPassword,
loginType: 'DEVELOPER',
- loginRoute: ROUTES.DEVELOPER_LOGIN,
+ loginRoute: Routes.LOGIN,
beforeLogin: () => {
cy.setCookie(`${env}-${COOKIE_DEVELOPER_FIRST_TIME_LOGIN_COMPLETE}`, new Date().toString())
cy.setCookie(`${env}-${COOKIE_DEVELOPER_TERMS_ACCEPTED}`, new Date().toString())
diff --git a/packages/developer-portal/src/tests/cypress/pages/developer-settings-page.ts b/packages/developer-portal/src/tests/cypress/pages/developer-settings-page.ts
index 1e2e41d7b8..091e484ed6 100644
--- a/packages/developer-portal/src/tests/cypress/pages/developer-settings-page.ts
+++ b/packages/developer-portal/src/tests/cypress/pages/developer-settings-page.ts
@@ -1,7 +1,7 @@
import Routes from '@/constants/routes'
import api from '../fixtures/routes'
-const developerSettingsMetaData = {
+const SettingsMetaData = {
url: Routes.SETTINGS,
selectors: {
companyName: 'input[data-test="company-name"]',
@@ -13,8 +13,8 @@ const developerSettingsMetaData = {
apiRoute: `${api.developers}/**`,
}
-const developerSettingsAppPage = {
- ...developerSettingsMetaData,
+const SettingsAppPage = {
+ ...SettingsMetaData,
}
-export default developerSettingsAppPage
+export default SettingsAppPage
diff --git a/packages/developer-portal/src/utils/__tests__/admin-stats.ts b/packages/developer-portal/src/utils/__tests__/admin-stats.ts
deleted file mode 100644
index ce14ba02f0..0000000000
--- a/packages/developer-portal/src/utils/__tests__/admin-stats.ts
+++ /dev/null
@@ -1,62 +0,0 @@
-import MockDate from 'mockdate'
-import { Range } from '@/components/pages/admin-stats/admin-stats'
-import { getDateRange, getDataLabel, getChartConfig, numOfObjectCreatedInDate, getRangeName } from '../admin-stats'
-
-beforeEach(() => {
- MockDate.set(new Date(2020, 1, 21))
-})
-
-afterEach(() => {
- MockDate.reset()
-})
-
-describe('admin stats utils', () => {
- describe('getDataLabel', () => {
- it('should run correctly', () => {
- expect(getDataLabel('APPS')).toEqual('Apps')
- expect(getDataLabel('DEVELOPERS')).toEqual('Developers')
- expect(getDataLabel('INSTALLATIONS')).toEqual('Installations')
- })
- })
-
- describe('getDateRange', () => {
- it('should run correctly', () => {
- const weekRange = { from: new Date(2020, 1, 14), to: new Date(2020, 1, 21) }
- const monthRange = { from: new Date(2020, 0, 21), to: new Date(2020, 1, 21) }
- expect(getDateRange('WEEK')).toEqual(weekRange)
- expect(getDateRange('MONTH')).toEqual(monthRange)
- })
- })
-
- describe('numOfObjectCreatedInDate', () => {
- it('should run correctly', () => {
- const data = [
- { id: 1, created: new Date(2020, 1, 14) },
- { id: 2, created: new Date(2020, 1, 15) },
- { id: 3, created: new Date(2020, 1, 16) },
- ]
- const date = new Date(2020, 1, 14)
- expect(numOfObjectCreatedInDate(data, date)).toEqual(1)
- })
- })
-
- describe('getChartConfig', () => {
- it('should run correctly', () => {
- const labels = ['Mon', 'Tue']
- const data = [10, 20]
- const chartConfig = getChartConfig(labels, data, 'DEVELOPERS')
- expect(chartConfig.labels.length).toBe(2)
- expect(chartConfig.datasets[0].data.length).toBe(2)
- })
- })
-
- describe('getRangeName', () => {
- it('should run correctly', () => {
- const ranges: Array = ['WEEK', 'MONTH', 'ALL']
- const names: Array = ['Last Week', 'Last Month', 'All Time']
- ranges.forEach((range, index) => {
- expect(getRangeName(range)).toEqual(names[index])
- })
- })
- })
-})
diff --git a/packages/developer-portal/src/utils/__tests__/auth-route.ts b/packages/developer-portal/src/utils/__tests__/auth-route.ts
index 0bec383fc5..268c1d83f7 100644
--- a/packages/developer-portal/src/utils/__tests__/auth-route.ts
+++ b/packages/developer-portal/src/utils/__tests__/auth-route.ts
@@ -6,8 +6,8 @@ describe('getDefaultRoute', () => {
expect(getDefaultRoute(true)).toEqual(`${window.location.origin}${Routes.APPS}`)
})
- it('should return origin url + Routes.DEVELOPER_WELCOME', () => {
- expect(getDefaultRoute(false)).toEqual(`${window.location.origin}${Routes.DEVELOPER_WELCOME}`)
+ it('should return origin url + Routes.WELCOME', () => {
+ expect(getDefaultRoute(false)).toEqual(`${window.location.origin}${Routes.WELCOME}`)
})
})
@@ -20,7 +20,7 @@ describe('getDefaultPathByLoginType', () => {
expect(getDefaultPath(false, true)).toEqual(Routes.APPS)
})
- it('should return Routes.DEVELOPER_WELCOME', () => {
- expect(getDefaultPath(false, false)).toEqual(Routes.DEVELOPER_WELCOME)
+ it('should return Routes.WELCOME', () => {
+ expect(getDefaultPath(false, false)).toEqual(Routes.WELCOME)
})
})
diff --git a/packages/developer-portal/src/utils/auth-route.ts b/packages/developer-portal/src/utils/auth-route.ts
index 7af7b3ea3c..c67b765ea6 100644
--- a/packages/developer-portal/src/utils/auth-route.ts
+++ b/packages/developer-portal/src/utils/auth-route.ts
@@ -4,14 +4,12 @@ export function getDefaultRoute(isFirtTimeLogin: boolean) {
if (window.location.pathname === Routes.DEVELOPER_EDITION_DOWNLOAD) {
return `${window.location.origin}${Routes.DEVELOPER_EDITION_DOWNLOAD}`
}
- return !isFirtTimeLogin
- ? `${window.location.origin}${Routes.DEVELOPER_WELCOME}`
- : `${window.location.origin}${Routes.APPS}`
+ return !isFirtTimeLogin ? `${window.location.origin}${Routes.WELCOME}` : `${window.location.origin}${Routes.APPS}`
}
export function getDefaultPath(isDesktopMode: boolean, isFirtTimeLogin: boolean) {
if (isDesktopMode) {
return Routes.APPS
}
- return !isFirtTimeLogin ? Routes.DEVELOPER_WELCOME : Routes.APPS
+ return !isFirtTimeLogin ? Routes.WELCOME : Routes.APPS
}
diff --git a/packages/developer-portal/src/utils/form/settings-contact-information.ts b/packages/developer-portal/src/utils/form/settings-contact-information.ts
index 72b6cc0ebc..9fda227f0a 100644
--- a/packages/developer-portal/src/utils/form/settings-contact-information.ts
+++ b/packages/developer-portal/src/utils/form/settings-contact-information.ts
@@ -2,10 +2,10 @@ import { ContactInformationValues } from '@/components/pages/settings/forms/cont
import ErrorMessages from '@/constants/error-messages'
import { isValidPersonName, isValidTelephone } from '@/utils/validate'
-export type DeveloperSettingsContactInformationErrorKeys = Partial
+export type SettingsContactInformationErrorKeys = Partial
export const validate = (values: ContactInformationValues) => {
- let errors: DeveloperSettingsContactInformationErrorKeys = {}
+ let errors: SettingsContactInformationErrorKeys = {}
if (values.telephone && !isValidTelephone(values.telephone)) {
errors.telephone = ErrorMessages.FIELD_PHONE_NUMER
diff --git a/packages/developer-portal/src/utils/route-dispatcher.ts b/packages/developer-portal/src/utils/route-dispatcher.ts
index b61224a093..75913a1f03 100644
--- a/packages/developer-portal/src/utils/route-dispatcher.ts
+++ b/packages/developer-portal/src/utils/route-dispatcher.ts
@@ -32,7 +32,7 @@ const routeDispatcher = async (route: RouteValue, params?: StringMap, search?: s
}
break
}
- case Routes.DEVELOPER_APP_DETAIL: {
+ case Routes.APP_DETAIL: {
if (id) {
const clientId = selectClientId(store.state)
const developerId = selectDeveloperId(store.state) || ''
@@ -59,10 +59,10 @@ const routeDispatcher = async (route: RouteValue, params?: StringMap, search?: s
case Routes.SETTINGS:
store.dispatch(requestDeveloperData())
break
- case Routes.DEVELOPER_WEBHOOKS:
+ case Routes.WEBHOOKS:
store.dispatch(developerRequestData({ page: 1, appsPerPage: GET_ALL_PAGE_SIZE } as DeveloperRequestParams))
break
- case Routes.DEVELOPER_HELP:
+ case Routes.HELP:
// Need the fetcher to have retrieved the login session only.
break
default:
diff --git a/packages/elements/package.json b/packages/elements/package.json
index 98af1bda6e..543eec48e3 100644
--- a/packages/elements/package.json
+++ b/packages/elements/package.json
@@ -95,6 +95,7 @@
"rollup-plugin-typescript2": "^0.27.1"
},
"peerDependencies": {
+ "dayjs": "^1.8.19",
"react": "^16.11.0",
"react-dom": "^16.11.0",
"react-router": "^5.1.2",
diff --git a/packages/geo-diary-v2/manifest.json b/packages/geo-diary-v2/manifest.json
new file mode 100644
index 0000000000..f83ccae22b
--- /dev/null
+++ b/packages/geo-diary-v2/manifest.json
@@ -0,0 +1,25 @@
+{
+ "short_name": "Geo Diary",
+ "name": "Geo Diary App",
+ "icons": [
+ {
+ "src": "logo.png",
+ "sizes": "64x64 32x32 24x24 16x16",
+ "type": "image/x-icon"
+ },
+ {
+ "src": "logo.png",
+ "type": "image/png",
+ "sizes": "192x192"
+ },
+ {
+ "src": "logo.png",
+ "type": "image/png",
+ "sizes": "512x512"
+ }
+ ],
+ "start_url": ".",
+ "display": "standalone",
+ "theme_color": "#000000",
+ "background_color": "#ffffff"
+}
diff --git a/packages/geo-diary-v2/package.json b/packages/geo-diary-v2/package.json
index f620e9c61d..16be1c105e 100644
--- a/packages/geo-diary-v2/package.json
+++ b/packages/geo-diary-v2/package.json
@@ -11,7 +11,7 @@
"author": "Reapit",
"main": "./src/index.ts",
"scripts": {
- "build:prod": "rimraf public/dist && webpack --config ../../scripts/webpack/webpack.config.prod.js",
+ "build:prod": "rimraf public/dist && webpack --config ../../scripts/webpack/webpack.pwa.prod.js",
"fetch-config": "yarn config-manager fetchConfig geo-diary-v2",
"release:dev": "node ../../scripts/release/release-dev.js geo-diary-v2 reapit-geo-diary-v2-dev",
"start:dev": "webpack-dev-server --hot --progress --color --mode development --config ../../scripts/webpack/webpack.config.dev.js",
diff --git a/packages/geo-diary-v2/src/core/index.tsx b/packages/geo-diary-v2/src/core/index.tsx
index e591f430fa..9fd00545aa 100644
--- a/packages/geo-diary-v2/src/core/index.tsx
+++ b/packages/geo-diary-v2/src/core/index.tsx
@@ -1,4 +1,5 @@
import * as Sentry from '@sentry/browser'
+import { injectSwitchModeToWindow } from '@reapit/elements'
import load from 'little-loader'
import qs from 'query-string'
import React from 'react'
@@ -6,7 +7,7 @@ import { render } from 'react-dom'
import ReactGA from 'react-ga'
import { Config } from '@/types/global'
import App from './app'
-import { injectSwitchModeToWindow } from '@reapit/elements'
+import * as serviceWorker from './service-worker'
injectSwitchModeToWindow()
@@ -71,3 +72,10 @@ if (module['hot']) {
}
run()
+if (process.env.NODE_ENV === 'development') {
+ serviceWorker.unregister()
+ console.info(`UnRegister-${process.env.APP_VERSION}`)
+} else {
+ serviceWorker.register()
+ console.info(`Register-${process.env.APP_VERSION}`)
+}
diff --git a/packages/geo-diary-v2/src/core/service-worker.ts b/packages/geo-diary-v2/src/core/service-worker.ts
new file mode 100644
index 0000000000..b06a126765
--- /dev/null
+++ b/packages/geo-diary-v2/src/core/service-worker.ts
@@ -0,0 +1,140 @@
+// This optional code is used to register a service worker.
+// register() is not called by default.
+
+import { notification } from '@reapit/elements'
+
+// This lets the app load faster on subsequent visits in production, and gives
+// it offline capabilities. However, it also means that developers (and users)
+// will only see deployed updates on subsequent visits to a page, after all the
+// existing tabs open on the page have been closed, since previously cached
+// resources are updated in the background.
+
+// To learn more about the benefits of this model and instructions on how to
+// opt-in, read https://bit.ly/CRA-PWA
+
+const isLocalhost = Boolean(
+ window.location.hostname === 'localhost' ||
+ // [::1] is the IPv6 localhost address.
+ window.location.hostname === '[::1]' ||
+ // 127.0.0.0/8 are considered localhost for IPv4.
+ window.location.hostname.match(/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/),
+)
+
+type Config = {
+ onSuccess?: (registration: ServiceWorkerRegistration) => void
+ onUpdate?: (registration: ServiceWorkerRegistration) => void
+}
+
+export function register(config?: Config) {
+ if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
+ // The URL constructor is available in all browsers that support SW.
+ const publicUrl = new URL('/', window.location.href)
+ if (publicUrl.origin !== window.location.origin) {
+ // Our service worker won't work if PUBLIC_URL is on a different origin
+ // from what our page is served on. This might happen if a CDN is used to
+ // serve assets; see https://github.com/facebook/create-react-app/issues/2374
+ return
+ }
+
+ window.addEventListener('load', () => {
+ const swUrl = '/service-worker.js'
+
+ if (isLocalhost) {
+ // This is running on localhost. Let's check if a service worker still exists or not.
+ checkValidServiceWorker(swUrl, config)
+
+ // Add some additional logging to localhost, pointing developers to the
+ // service worker/PWA documentation.
+ navigator.serviceWorker.ready.then(() => {
+ console.log(
+ 'This web app is being served cache-first by a service ' +
+ 'worker. To learn more, visit https://bit.ly/CRA-PWA',
+ )
+ })
+ } else {
+ // Is not localhost. Just register service worker
+ registerValidSW(swUrl, config)
+ }
+ })
+ }
+}
+
+function registerValidSW(swUrl: string, config?: Config) {
+ navigator.serviceWorker
+ .register(swUrl)
+ .then(registration => {
+ registration.onupdatefound = () => {
+ const installingWorker = registration.installing
+ if (installingWorker == null) {
+ return
+ }
+ installingWorker.onstatechange = () => {
+ if (installingWorker.state === 'installed') {
+ if (navigator.serviceWorker.controller) {
+ notification.success({
+ message: 'New version available, please press CTRL-SHIFT-R to update',
+ duration: 0,
+ placement: 'bottomRight',
+ })
+
+ console.log(
+ 'New content is available and will be used when all ' +
+ 'tabs for this page are closed. See https://bit.ly/CRA-PWA.',
+ )
+
+ // Execute callback
+ if (config && config.onUpdate) {
+ config.onUpdate(registration)
+ }
+ } else {
+ // At this point, everything has been precached.
+ // It's the perfect time to display a
+ // "Content is cached for offline use." message.
+ console.log('Content is cached for offline use.')
+
+ // Execute callback
+ if (config && config.onSuccess) {
+ config.onSuccess(registration)
+ }
+ }
+ }
+ }
+ }
+ })
+ .catch(error => {
+ console.error('Error during service worker registration:', error)
+ })
+}
+
+function checkValidServiceWorker(swUrl: string, config?: Config) {
+ // Check if the service worker can be found. If it can't reload the page.
+ fetch(swUrl, {
+ headers: { 'Service-Worker': 'script' },
+ })
+ .then(response => {
+ // Ensure service worker exists, and that we really are getting a JS file.
+ const contentType = response.headers.get('content-type')
+ if (response.status === 404 || (contentType != null && contentType.indexOf('javascript') === -1)) {
+ // No service worker found. Probably a different app. Reload the page.
+ navigator.serviceWorker.ready.then(registration => {
+ registration.unregister().then(() => {
+ window.location.reload()
+ })
+ })
+ } else {
+ // Service worker found. Proceed as normal.
+ registerValidSW(swUrl, config)
+ }
+ })
+ .catch(() => {
+ console.log('No internet connection found. App is running in offline mode.')
+ })
+}
+
+export function unregister() {
+ if ('serviceWorker' in navigator) {
+ navigator.serviceWorker.ready.then(registration => {
+ registration.unregister()
+ })
+ }
+}
diff --git a/packages/react-app-scaffolder/README.md b/packages/react-app-scaffolder/README.md
index 96c1031493..b9184f76de 100644
--- a/packages/react-app-scaffolder/README.md
+++ b/packages/react-app-scaffolder/README.md
@@ -1,9 +1,23 @@
-# Reapit React-Redux App Scaffolder
+# Reapit React App Scaffolder
A CLI for generating React Apps, optimised for the marketplace, including Reapit Connect authentication and Elements. For usage visit [here](https://foundations-documentation.reapit.cloud/api/web#react-app-scaffolder).
-- **Tech Stack**: Yeoman, React, Redux, Jest, React, Router, Styled-Components, Sass, CSS Modules
+- **Tech Stack**: Yeoman, React, Redux, Jest, React, Router, Linaria
- **Cloud Services**: NPM
- **Production**: https://www.npmjs.com/package/@reapit/generator-react-redux-app
For detailed documentation [visit here](https://foundations-documentation.reapit.cloud/open-source/packages#react-app-scaffolder).
+
+For internal scaffolds, navigate to project folder and execute `yarn scaffold` to load the CLI.
+
+For external users first;
+
+`npm install -g yo @reapit/generator-react-app-scaffolder`
+
+Then
+
+`yo @reapit/react-app-scaffolder` to load the CLI.
+
+For internal maintainers, to build an app locally, navigate to one of the external options within the templates folder, `yarn` and `yarn start:dev` to develop the scaffold.
+
+For internal apps, scaffold a local app and copy your changes back to the main directory.
\ No newline at end of file
diff --git a/packages/react-app-scaffolder/app/index.js b/packages/react-app-scaffolder/app/index.js
index 07fc6908ba..c13dbcf2d9 100644
--- a/packages/react-app-scaffolder/app/index.js
+++ b/packages/react-app-scaffolder/app/index.js
@@ -3,26 +3,23 @@ const { promisify } = require('util')
const process = require('process')
const exec = promisify(require('child_process').exec)
const spawn = require('cross-spawn')
-const { execSync } = require('child_process')
const path = require('path')
const fs = require('fs')
const yosay = require('yosay')
-const { constantCase } = require('change-case')
module.exports = class extends Generator {
_installAndExport() {
return new Promise(async (resolve, reject) => {
- const { isFoundation } = this.answers
+ const { isFoundations } = this.answers
this.log(yosay('Installing dependencies... this may take a minute!'))
- if (!isFoundation) {
+ if (!isFoundations) {
await exec(`yarn`)
}
- const prettierConfigPath = path.resolve(__dirname, '../../../.prettierrc.js')
await exec(`yarn prettier --write ./package.json`)
- await exec(`yarn prettier "**/*.ts" "**/*.tsx" --write`)
+
this.log(yosay('App installed successfully!'))
this._pushToGithub()
@@ -58,62 +55,30 @@ module.exports = class extends Generator {
}
_addPackageJson() {
- const { isFoundation, name, author, repo, description } = this.answers
-
- if (isFoundation) {
- return
- }
+ const { isFoundations, name, author, repo, description } = this.answers
- if (this.redux) {
- this.fs.copyTpl(this.templatePath('./is-foundation-redux/**/*'), this.destinationPath('./'), {
- name, author, repo, description
- })
- }
+ const local = require(this.templatePath('./_package.json'))
+ const base = require(this.destinationPath('./package.json'))
- if (!this.redux) {
- this.fs.copyTpl(this.templatePath('./is-foundation-no-redux/**/*'), this.destinationPath('./'), {
- name, author, repo, description
- })
+ const merged = {
+ ...local,
+ ...base,
}
- }
- _addPackageJson() {
- const { isFoundation, name, author, repo, description } = this.answers
-
- if (isFoundation) {
- return
- }
-
- if (this.redux) {
- this.fs.copyTpl(this.templatePath('./is-foundation-redux/**/*'), this.destinationPath('./'), {
- name, author, repo, description
- })
- }
-
- if (!this.redux) {
- this.fs.copyTpl(this.templatePath('./is-foundation-no-redux/**/*'), this.destinationPath('./'), {
- name, author, repo, description
+ this.fs.delete(this.destinationPath('./package.json'))
+ this.fs.commit([], () => {
+ this.fs.write(this.destinationPath('./temp.package.json'), JSON.stringify(merged))
+ this.fs.commit([], () => {
+ this.fs.copyTpl(this.destinationPath('./temp.package.json'), this.destinationPath('./package.json'), {
+ name,
+ author,
+ repo,
+ description,
+ })
+ this.fs.delete(this.destinationPath('./temp.package.json'))
+ this.fs.commit([], () => {})
})
- }
- }
-
-
- _addAzure() {
- const { name, azure } = this.answers
- if (azure) {
- this.fs.copy(this.templatePath('redu'), this.destinationPath(`./azure-pipelines.yml`))
- }
- }
-
- _addStyleSolution() {
- const { sass, name, isFoundation } = this.answers
-
-
- if (sass) {
- this.fs.copyTpl(this.templatePath('./base-is-sass/**/*'), this.destinationPath('./'), { isFoundation })
- } else {
- this.fs.copyTpl(this.templatePath('./base-is-linaria/**/*'), this.destinationPath('./'), { isFoundation })
- }
+ })
}
constructor(args, opts) {
@@ -123,94 +88,35 @@ module.exports = class extends Generator {
async writeBaseFiles() {
return new Promise((resolve, reject) => {
- const { name, repo, description, author, isFoundation, stylesSolution, clientId, sass } = this.answers
- const { redux, graphql } = this
-
- /**
- * settings destination path
- * for non isFoundation: it will be the folder where the scaffolder is executed
- * for isFoundation: we have to deter
- */
-
- this.fs.copyTpl(this.templatePath('_README.md'), this.destinationPath('./README.md'), {
- name,
- })
-
- this.fs.copyTpl(this.templatePath('_gitignore'), this.destinationPath('./.gitignore'), {
- name,
- })
-
- this.fs.copyTpl(this.templatePath('_eslintrc.js'), this.destinationPath('./.eslintrc.js'), {
- name,
- })
-
- this.fs.copyTpl(this.templatePath('_prettierrc.js'), this.destinationPath('./.prettierrc.js'), {
- name,
- })
+ const { name, isFoundations, clientId } = this.answers
+ const configPath = isFoundations ? './_config.internal.json' : './_config.external.json'
- this.fs.copyTpl(this.templatePath('_config.json'), this.destinationPath('./config.json'), {
+ this.fs.copyTpl(this.templatePath(configPath), this.destinationPath('./config.json'), {
clientId,
})
- this.fs.copyTpl(this.templatePath('_config.example.json'), this.destinationPath('./config.example.json'), {
- clientId,
- })
-
- this.fs.copyTpl(this.templatePath('./base'), this.destinationPath('./'), {
+ this.fs.copyTpl(this.templatePath('_README.md'), this.destinationPath('./README.md'), {
name,
- nameInConstantCase: constantCase(name),
- redux,
- graphql,
- stylesSolution,
- isFoundation
})
- if (isFoundation) {
- // Any any additional base files specialized for non-foundation project will need to uncomment this like
- // Select recursively dot files
- // glob isn't really smart at the moment. In the future, when need to add non dot files, uncomment this
- // this.fs.copyTpl(this.templatePath('./base-is-foundation/**/.*'), this.destinationPath('./'), {
- // name,
- // repo,
- // description,
- // author,
- // })
- this.fs.copyTpl(this.templatePath('./base-is-foundation/*'), this.destinationPath('./'), {
- name,
- repo,
- description,
- author,
- })
- } else {
- this.fs.copyTpl(this.templatePath('./base-is-not-foundation/**/*'), this.destinationPath('./'), {
- name,
- nameInConstantCase: constantCase(name),
- repo,
- description,
- author,
- clientId,
- })
- }
-
- this.fs.copyTpl(this.templatePath(this.projectTypePath), this.destinationPath('./'), {
- name,
- nameInConstantCase: constantCase(name),
- redux,
- graphql,
- stylesSolution,
- graphql,
- stylesSolution,
- sass
- })
+ this.fs.copyTpl(this.templatePath(this.projectPath), this.destinationPath('./'))
this.fs.commit([], () => {
- this._addStyleSolution(),
- this._addPackageJson(),
- this._addAzure()
+
+ if (!isFoundations) {
+ this.fs.copyTpl(this.templatePath('_prettierrc.js'), this.destinationPath('./.prettierrc.js'))
+ this.fs.copyTpl(this.templatePath('_eslintrc.js'), this.destinationPath('./.eslintrc.js'))
+ this.fs.copyTpl(this.templatePath('_gitignore'), this.destinationPath('./.gitignore'))
+ }
+
this.fs.commit([], () => {
- this._installAndExport()
- .then(resolve)
- .catch(reject)
+ this._addPackageJson()
+
+ this.fs.commit([], () => {
+ this._installAndExport()
+ .then(resolve)
+ .catch(reject)
+ })
})
})
})
@@ -250,21 +156,15 @@ module.exports = class extends Generator {
},
{
type: 'confirm',
- name: 'isFoundation',
- message: 'Is this project for internal use (mono-repo)',
- default: true,
- },
- {
- name: 'sass',
- message: 'Would you like to use Sass?',
- type: 'confirm',
+ name: 'isFoundations',
+ message: 'Is this a Reapit internal project?',
default: false,
},
{
type: 'list',
name: 'stateManagementStyle',
- message: 'Pick project type',
- choices: ['Redux', 'No Redux'],
+ message: 'How do you want to manage state?',
+ choices: ['Redux', 'React Hooks & Context'],
},
{
type: 'confirm',
@@ -274,36 +174,28 @@ module.exports = class extends Generator {
},
])
- const { stateManagementStyle, stylesSolution } = this.answers
- if (stateManagementStyle === 'Redux') {
- this.projectTypePath = 'redux'
- this.redux = true
- }
-
- if (stateManagementStyle === 'No Redux') {
- this.projectTypePath = 'no-redux'
- this.redux = false
+ const { stateManagementStyle, isFoundations } = this.answers
+ if (stateManagementStyle === 'Redux' && isFoundations) {
+ this.projectPath = './redux-internal'
}
- if (stateManagementStyle === 'Apollo GraphQL') {
- this.projectTypePath = 'apollo'
- this.graphql = true
+ if (stateManagementStyle === 'Redux' && !isFoundations) {
+ this.projectPath = './redux-external'
}
- if (stylesSolution === 'Styled Components') {
- this.answers.stylesSolution = 'styledComponents'
+ if (stateManagementStyle === 'React Hooks & Context' && isFoundations) {
+ this.projectPath = './hooks-internal'
}
- if (stylesSolution === 'Sass/CSS') {
- this.answers.stylesSolution = 'sass'
+ if (stateManagementStyle === 'React Hooks & Context' && !isFoundations) {
+ this.projectPath = './hooks-external'
}
-
/**
* Destination path
- * isFoundation ->./package/{appName}
- * else current path
+ * isFoundations ->./package/{appName}
+ * else current path/{appName}
*/
- if (this.answers.isFoundation) {
+ if (isFoundations) {
this.packagePath = path.resolve(__dirname, '../..', this.answers.name)
/**
* create directory if not
diff --git a/packages/react-app-scaffolder/app/templates/_README.md b/packages/react-app-scaffolder/app/templates/_README.md
index ba91c0cfec..dd0eea6719 100644
--- a/packages/react-app-scaffolder/app/templates/_README.md
+++ b/packages/react-app-scaffolder/app/templates/_README.md
@@ -1,12 +1,5 @@
# <%= name %>
-<%= name %> for Reapit PAAS platform. Initial scaffold from [React App Boilerplate](https://github.com/reapit/react-app)
+<%= name %> an app built for Reapit Marketplace.
-## Read on:
-
-- [Getting Started](./src/docs/GETTING_STARTED.md)
-- [Api Platform](./src/docs/API_PLATFORM.md)
-- [Code Style](./src/docs/CODE_STYLE.md)
-- [Version Control](./VERSION_CONTROL.md)
-- [Definition of Done](./src/docs/DEFINITION_OF_DONE.md)
-- [Deployment](./src/docs/DEPLOYMENT.md)
+Initial scaffold using the steps from [here](https://foundations-documentation.reapit.cloud/developer-portal), using [Reapit React App Scaffolder](https://www.npmjs.com/package/@reapit/generator-react-app-scaffolder)
\ No newline at end of file
diff --git a/packages/react-app-scaffolder/app/templates/_config.external.json b/packages/react-app-scaffolder/app/templates/_config.external.json
new file mode 100644
index 0000000000..6d156b8f08
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/_config.external.json
@@ -0,0 +1,7 @@
+{
+ "appEnv": "local",
+ "cognitoClientId": "<%= clientId %>",
+ "cognitoOAuthUrl": "https://dev.connect.reapit.cloud",
+ "cognitoUserPoolId": "eu-west-2_hbt0B7yys",
+ "platformApiUrl": "https://dev.platform.reapit.cloud"
+}
diff --git a/packages/react-app-scaffolder/app/templates/_config.example.json b/packages/react-app-scaffolder/app/templates/_config.internal.json
similarity index 99%
rename from packages/react-app-scaffolder/app/templates/_config.example.json
rename to packages/react-app-scaffolder/app/templates/_config.internal.json
index 692adaf253..5d3433212c 100644
--- a/packages/react-app-scaffolder/app/templates/_config.example.json
+++ b/packages/react-app-scaffolder/app/templates/_config.internal.json
@@ -6,4 +6,4 @@
"cognitoOAuthUrl": "https://dev.connect.reapit.cloud",
"cognitoUserPoolId": "eu-west-2_hbt0B7yys",
"platformApiUrl": "https://dev.platform.reapit.cloud"
-}
+}
\ No newline at end of file
diff --git a/packages/react-app-scaffolder/app/templates/_gitignore b/packages/react-app-scaffolder/app/templates/_gitignore
index bcd5078bd8..a2e8df3890 100644
--- a/packages/react-app-scaffolder/app/templates/_gitignore
+++ b/packages/react-app-scaffolder/app/templates/_gitignore
@@ -16,3 +16,11 @@ yarn-error.log*
*.log
.cache/
+yarn.lock
+
+public/dist
+src/tests
+
+.jest-cache
+.linaria-cache
+.webpack-cache
diff --git a/packages/react-app-scaffolder/app/templates/_jest.config.js b/packages/react-app-scaffolder/app/templates/_jest.config.js
deleted file mode 100644
index e3d7b18525..0000000000
--- a/packages/react-app-scaffolder/app/templates/_jest.config.js
+++ /dev/null
@@ -1,26 +0,0 @@
-const { pathsToModuleNameMapper } = require('ts-jest/utils')
-const { compilerOptions } = require('./tsconfig')
-
-module.exports = {
- preset: 'ts-jest',
- setupFiles: ['/src/scripts/jest-setup.js'],
- collectCoverageFrom: ['/src/**/*.ts', '/src/**/*.tsx'],
- coverageDirectory: './src/tests/coverage',
- coveragePathIgnorePatterns: ['[/\\\\](node_modules|src/types|src/tests|src/scripts)[/\\\\]', 'index.tsx'],
- modulePathIgnorePatterns: ['[/\\\\](node_modules)[/\\\\]'],
- snapshotSerializers: ['enzyme-to-json/serializer'],
- moduleNameMapper: {
- '^.+.(?=.*scss|sass|css|jpg|png).*': '/src/scripts/css-stub.js',
- ...pathsToModuleNameMapper(compilerOptions.paths, {
- prefix: '/'
- })
- },
- coverageThreshold: {
- global: {
- branches: 0,
- functions: 0,
- lines: 0,
- statements: 0
- }
- }
-}
\ No newline at end of file
diff --git a/packages/react-app-scaffolder/app/templates/_package.json b/packages/react-app-scaffolder/app/templates/_package.json
new file mode 100644
index 0000000000..7c76605044
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/_package.json
@@ -0,0 +1,9 @@
+{
+ "name": "<%= name %>",
+ "description": "<%= description %>",
+ "repository": {
+ "type": "git",
+ "url": "git+<%= repo %>"
+ },
+ "author": "<%= author %>"
+}
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/components/pages/__tests__/__snapshots__/authenticated.tsx.snap b/packages/react-app-scaffolder/app/templates/apollo/src/components/pages/__tests__/__snapshots__/authenticated.tsx.snap
deleted file mode 100644
index 5b71532eb0..0000000000
--- a/packages/react-app-scaffolder/app/templates/apollo/src/components/pages/__tests__/__snapshots__/authenticated.tsx.snap
+++ /dev/null
@@ -1,20 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`Authenticated should match a snapshot 1`] = `
-
-
-
- Welcome To Reapit Elements
-
-
- You are now authenticated against our sandbox data
-
-
-
-`;
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/components/pages/__tests__/__snapshots__/home.tsx.snap b/packages/react-app-scaffolder/app/templates/apollo/src/components/pages/__tests__/__snapshots__/home.tsx.snap
deleted file mode 100644
index 903688c646..0000000000
--- a/packages/react-app-scaffolder/app/templates/apollo/src/components/pages/__tests__/__snapshots__/home.tsx.snap
+++ /dev/null
@@ -1,27 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`Home should match a snapshot 1`] = `
-
-
-
- Welcome To Reapit Elements
-
-
- Click
-
- here
-
- to login
-
-
-
-`;
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/components/pages/__tests__/__snapshots__/login.tsx.snap b/packages/react-app-scaffolder/app/templates/apollo/src/components/pages/__tests__/__snapshots__/login.tsx.snap
deleted file mode 100644
index da5a785eb6..0000000000
--- a/packages/react-app-scaffolder/app/templates/apollo/src/components/pages/__tests__/__snapshots__/login.tsx.snap
+++ /dev/null
@@ -1,37 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`Login should match a snapshot 1`] = `
-
-
-
- Sign in
-
-
- Welcome to smb
-
-
-
-
-
-
-
-`;
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/components/pages/__tests__/home.tsx b/packages/react-app-scaffolder/app/templates/apollo/src/components/pages/__tests__/home.tsx
deleted file mode 100644
index 644f30ccc3..0000000000
--- a/packages/react-app-scaffolder/app/templates/apollo/src/components/pages/__tests__/home.tsx
+++ /dev/null
@@ -1,23 +0,0 @@
-import * as React from 'react'
-import { shallow } from 'enzyme'
-import toJson from 'enzyme-to-json'
-import { Home, HomeProps } from '../home'
-
-const props: HomeProps = {
- approvalsState: {
- loading: false,
- homeData: {},
- },
- // @ts-ignore: just pick the needed props for the test
- match: {
- params: {
- page: '2',
- },
- },
-}
-
-describe('Home', () => {
- it('should match a snapshot', () => {
- expect(toJson(shallow( ))).toMatchSnapshot()
- })
-})
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/components/pages/__tests__/login.tsx b/packages/react-app-scaffolder/app/templates/apollo/src/components/pages/__tests__/login.tsx
deleted file mode 100644
index 4abbad8af0..0000000000
--- a/packages/react-app-scaffolder/app/templates/apollo/src/components/pages/__tests__/login.tsx
+++ /dev/null
@@ -1,22 +0,0 @@
-import * as React from 'react'
-import { shallow } from 'enzyme'
-import toJson from 'enzyme-to-json'
-import { Login, LoginProps } from '../login'
-
-const props: LoginProps = {
- error: false,
- isLogin: false,
- login: jest.fn(),
- authChangeLoginType: jest.fn(),
- loginType: 'CLIENT',
- // @ts-ignore: ignore to fullfil the definition of RouteComponentProps
- location: {
- pathname: '/client',
- },
-}
-
-describe('Login', () => {
- it('should match a snapshot', () => {
- expect(toJson(shallow( ))).toMatchSnapshot()
- })
-})
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/components/pages/authenticated.tsx b/packages/react-app-scaffolder/app/templates/apollo/src/components/pages/authenticated.tsx
deleted file mode 100644
index d46ac3db14..0000000000
--- a/packages/react-app-scaffolder/app/templates/apollo/src/components/pages/authenticated.tsx
+++ /dev/null
@@ -1,21 +0,0 @@
-import * as React from 'react'
-import { H3, FlexContainerBasic, FlexContainerResponsive, SubTitleH5 } from '@reapit/elements'
-
-export interface AuthenticatedMappedActions {}
-
-export interface AuthenticatedMappedProps {}
-
-export type AuthenticatedProps = AuthenticatedMappedActions & AuthenticatedMappedProps
-
-export const Authenticated: React.FunctionComponent = () => {
- return (
-
-
- Welcome To Reapit Foundations
- You are now authenticated against our sandbox data
-
-
- )
-}
-
-export default Authenticated
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/components/pages/home.tsx b/packages/react-app-scaffolder/app/templates/apollo/src/components/pages/home.tsx
deleted file mode 100644
index 6dd617ae62..0000000000
--- a/packages/react-app-scaffolder/app/templates/apollo/src/components/pages/home.tsx
+++ /dev/null
@@ -1,27 +0,0 @@
-import * as React from 'react'
-import { withRouter, RouteComponentProps } from 'react-router'
-import { Link } from 'react-router-dom'
-import { H3, FlexContainerBasic, FlexContainerResponsive, SubTitleH5 } from '@reapit/elements'
-
-export type HomeMappedActions = {}
-
-export type HomeMappedProps = {
- homeState: any
-}
-
-export type HomeProps = HomeMappedActions & HomeMappedProps & RouteComponentProps<{ page?: any }>
-
-export const Home: React.FunctionComponent = () => {
- return (
-
-
- Welcome To Reapit Foundations
-
- Click here to login
-
-
-
- )
-}
-
-export default withRouter(Home)
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/components/pages/login.tsx b/packages/react-app-scaffolder/app/templates/apollo/src/components/pages/login.tsx
deleted file mode 100644
index 536357f15e..0000000000
--- a/packages/react-app-scaffolder/app/templates/apollo/src/components/pages/login.tsx
+++ /dev/null
@@ -1,135 +0,0 @@
-import * as React from 'react'
-import { Redirect } from 'react-router-dom'
-import { withRouter, RouteComponentProps } from 'react-router'
-import Routes from '@/constants/routes'
-import { Input, Button, H1, Level, Alert, isEmail, Formik, Form } from '@reapit/elements'
-import { LoginParams } from '@reapit/cognito-auth'
-<% if (stylesSolution == 'sass') { %>import loginStyles from '@/styles/pages/login.scss?mod'<%}%>
-<% if (stylesSolution == 'styledComponents') { %>import { Container, Wrapper, ImageContainer } from './__styles__/login'<%}%>
-import logoImage from '@/assets/images/reapit-graphic.jpg'
-
-export type LoginMappedActions = {
- login: (params: LoginParams) => void
-}
-
-export type LoginMappedProps = {
- hasSession: boolean
- error: boolean
-}
-
-export type LoginFormValues = {
- email: string
- password: string
-}
-
-export type LoginFormError = {
- email?: string
- password?: string
-}
-
-export function validate(values: LoginFormValues) {
- let errors = {} as LoginFormError
-
- if (!values.email) {
- errors.email = 'Required'
- } else if (!isEmail(values.email)) {
- errors.email = 'Invalid email address'
- }
-
- if (!values.password) {
- errors.password = 'Required'
- }
-
- return errors
-}
-
-export type LoginProps = LoginMappedActions & LoginMappedProps & RouteComponentProps
-
-export const onSubmitHandler = (setIsSubmitting: any, login: any, values: LoginFormValues) => {
- const { email, password } = values
-
- setIsSubmitting(true)
- login({ userName: email, password, loginType: 'CLIENT' } as LoginParams)
-}
-
-export const Login: React.FunctionComponent = (props: LoginProps) => {
- const [isSubmitting, setIsSubmitting] = React.useState(false)
- const { hasSession, error, login } = props
- <% if (stylesSolution == 'sass') { %>const { disabled, wrapper, container, image } = loginStyles<%}%>
-
- React.useEffect(() => {
- if (error) {
- setIsSubmitting(false)
- }
- }, [error])
-
- if (hasSession) {
- return
- }
-
- return (
- <% if (stylesSolution == 'sass') { %>
-
-
Sign in
-
Welcome to <%= name %>
<%}%>
-
- <% if (stylesSolution == 'styledComponents') { %>
-
- Sign in
- Welcome to <%= name %>
<%}%>
-
- onSubmitHandler(setIsSubmitting, login, values)}
- render={() => (
-
- )}
- />
-
-
- <% if (stylesSolution == 'sass') { %>
-
-
-
-
-
-
- <%}%>
- <% if (stylesSolution == 'styledComponents') { %>
-
-
-
-
-
-
- <%}%>
- )
-}
-
-export default withRouter(Login)
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/core/__tests__/__snapshots__/app.tsx.snap b/packages/react-app-scaffolder/app/templates/apollo/src/core/__tests__/__snapshots__/app.tsx.snap
deleted file mode 100644
index 11f21ac70a..0000000000
--- a/packages/react-app-scaffolder/app/templates/apollo/src/core/__tests__/__snapshots__/app.tsx.snap
+++ /dev/null
@@ -1,1847 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`App should match a snapshot 1`] = `
-
- Object {
- "definitions": Array [
- Object {
- "kind": "OperationDefinition",
- "name": Object {
- "kind": "Name",
- "value": "GeneratedClientQuery",
- },
- "operation": "query",
- "selectionSet": Object {
- "kind": "SelectionSet",
- "selections": Array [],
- },
- },
- ],
- "kind": "Document",
- },
- Object {
- "definitions": Array [
- Object {
- "kind": "OperationDefinition",
- "name": Object {
- "kind": "Name",
- "value": "GeneratedClientQuery",
- },
- "operation": "query",
- "selectionSet": Object {
- "kind": "SelectionSet",
- "selections": Array [],
- },
- },
- ],
- "kind": "Document",
- } => Object {
- "definitions": Array [
- Object {
- "kind": "OperationDefinition",
- "name": Object {
- "kind": "Name",
- "value": "GeneratedClientQuery",
- },
- "operation": "query",
- "selectionSet": Object {
- "kind": "SelectionSet",
- "selections": Array [],
- },
- },
- ],
- "kind": "Document",
- },
- },
- "watches": Set {},
- },
- "clearStoreCallbacks": Array [],
- "defaultOptions": Object {},
- "disableNetworkFetches": false,
- "link": ApolloLink {
- "request": [Function],
- },
- "localState": LocalState {
- "cache": InMemoryCache {
- "addTypename": true,
- "cacheKeyRoot": KeyTrie {
- "weakness": true,
- },
- "config": Object {
- "addTypename": true,
- "dataIdFromObject": [Function],
- "fragmentMatcher": HeuristicFragmentMatcher {},
- "freezeResults": false,
- "resultCaching": true,
- },
- "data": DepTrackingCache {
- "data": Object {},
- "depend": [Function],
- },
- "maybeBroadcastWatch": [Function],
- "optimisticData": DepTrackingCache {
- "data": Object {},
- "depend": [Function],
- },
- "silenceBroadcast": false,
- "storeReader": StoreReader {
- "executeSelectionSet": [Function],
- "executeStoreQuery": [Function],
- "executeSubSelectedArray": [Function],
- "freezeResults": false,
- },
- "storeWriter": StoreWriter {},
- "typenameDocumentCache": Map {
- Object {
- "definitions": Array [
- Object {
- "kind": "OperationDefinition",
- "name": Object {
- "kind": "Name",
- "value": "GeneratedClientQuery",
- },
- "operation": "query",
- "selectionSet": Object {
- "kind": "SelectionSet",
- "selections": Array [],
- },
- },
- ],
- "kind": "Document",
- } => Object {
- "definitions": Array [
- Object {
- "kind": "OperationDefinition",
- "name": Object {
- "kind": "Name",
- "value": "GeneratedClientQuery",
- },
- "operation": "query",
- "selectionSet": Object {
- "kind": "SelectionSet",
- "selections": Array [],
- },
- },
- ],
- "kind": "Document",
- },
- Object {
- "definitions": Array [
- Object {
- "kind": "OperationDefinition",
- "name": Object {
- "kind": "Name",
- "value": "GeneratedClientQuery",
- },
- "operation": "query",
- "selectionSet": Object {
- "kind": "SelectionSet",
- "selections": Array [],
- },
- },
- ],
- "kind": "Document",
- } => Object {
- "definitions": Array [
- Object {
- "kind": "OperationDefinition",
- "name": Object {
- "kind": "Name",
- "value": "GeneratedClientQuery",
- },
- "operation": "query",
- "selectionSet": Object {
- "kind": "SelectionSet",
- "selections": Array [],
- },
- },
- ],
- "kind": "Document",
- },
- },
- "watches": Set {},
- },
- "client": [Circular],
- "resolvers": Object {
- "Mutation": Object {},
- "Query": Object {
- "contacts": [Function],
- },
- },
- },
- "mutate": [Function],
- "query": [Function],
- "queryDeduplication": true,
- "queryManager": QueryManager {
- "assumeImmutableResults": false,
- "clientAwareness": Object {
- "name": undefined,
- "version": undefined,
- },
- "dataStore": DataStore {
- "cache": InMemoryCache {
- "addTypename": true,
- "cacheKeyRoot": KeyTrie {
- "weakness": true,
- },
- "config": Object {
- "addTypename": true,
- "dataIdFromObject": [Function],
- "fragmentMatcher": HeuristicFragmentMatcher {},
- "freezeResults": false,
- "resultCaching": true,
- },
- "data": DepTrackingCache {
- "data": Object {},
- "depend": [Function],
- },
- "maybeBroadcastWatch": [Function],
- "optimisticData": DepTrackingCache {
- "data": Object {},
- "depend": [Function],
- },
- "silenceBroadcast": false,
- "storeReader": StoreReader {
- "executeSelectionSet": [Function],
- "executeStoreQuery": [Function],
- "executeSubSelectedArray": [Function],
- "freezeResults": false,
- },
- "storeWriter": StoreWriter {},
- "typenameDocumentCache": Map {
- Object {
- "definitions": Array [
- Object {
- "kind": "OperationDefinition",
- "name": Object {
- "kind": "Name",
- "value": "GeneratedClientQuery",
- },
- "operation": "query",
- "selectionSet": Object {
- "kind": "SelectionSet",
- "selections": Array [],
- },
- },
- ],
- "kind": "Document",
- } => Object {
- "definitions": Array [
- Object {
- "kind": "OperationDefinition",
- "name": Object {
- "kind": "Name",
- "value": "GeneratedClientQuery",
- },
- "operation": "query",
- "selectionSet": Object {
- "kind": "SelectionSet",
- "selections": Array [],
- },
- },
- ],
- "kind": "Document",
- },
- Object {
- "definitions": Array [
- Object {
- "kind": "OperationDefinition",
- "name": Object {
- "kind": "Name",
- "value": "GeneratedClientQuery",
- },
- "operation": "query",
- "selectionSet": Object {
- "kind": "SelectionSet",
- "selections": Array [],
- },
- },
- ],
- "kind": "Document",
- } => Object {
- "definitions": Array [
- Object {
- "kind": "OperationDefinition",
- "name": Object {
- "kind": "Name",
- "value": "GeneratedClientQuery",
- },
- "operation": "query",
- "selectionSet": Object {
- "kind": "SelectionSet",
- "selections": Array [],
- },
- },
- ],
- "kind": "Document",
- },
- },
- "watches": Set {},
- },
- },
- "fetchQueryRejectFns": Map {},
- "idCounter": 1,
- "inFlightLinkObservables": Map {},
- "link": ApolloLink {
- "request": [Function],
- },
- "localState": LocalState {
- "cache": InMemoryCache {
- "addTypename": true,
- "cacheKeyRoot": KeyTrie {
- "weakness": true,
- },
- "config": Object {
- "addTypename": true,
- "dataIdFromObject": [Function],
- "fragmentMatcher": HeuristicFragmentMatcher {},
- "freezeResults": false,
- "resultCaching": true,
- },
- "data": DepTrackingCache {
- "data": Object {},
- "depend": [Function],
- },
- "maybeBroadcastWatch": [Function],
- "optimisticData": DepTrackingCache {
- "data": Object {},
- "depend": [Function],
- },
- "silenceBroadcast": false,
- "storeReader": StoreReader {
- "executeSelectionSet": [Function],
- "executeStoreQuery": [Function],
- "executeSubSelectedArray": [Function],
- "freezeResults": false,
- },
- "storeWriter": StoreWriter {},
- "typenameDocumentCache": Map {
- Object {
- "definitions": Array [
- Object {
- "kind": "OperationDefinition",
- "name": Object {
- "kind": "Name",
- "value": "GeneratedClientQuery",
- },
- "operation": "query",
- "selectionSet": Object {
- "kind": "SelectionSet",
- "selections": Array [],
- },
- },
- ],
- "kind": "Document",
- } => Object {
- "definitions": Array [
- Object {
- "kind": "OperationDefinition",
- "name": Object {
- "kind": "Name",
- "value": "GeneratedClientQuery",
- },
- "operation": "query",
- "selectionSet": Object {
- "kind": "SelectionSet",
- "selections": Array [],
- },
- },
- ],
- "kind": "Document",
- },
- Object {
- "definitions": Array [
- Object {
- "kind": "OperationDefinition",
- "name": Object {
- "kind": "Name",
- "value": "GeneratedClientQuery",
- },
- "operation": "query",
- "selectionSet": Object {
- "kind": "SelectionSet",
- "selections": Array [],
- },
- },
- ],
- "kind": "Document",
- } => Object {
- "definitions": Array [
- Object {
- "kind": "OperationDefinition",
- "name": Object {
- "kind": "Name",
- "value": "GeneratedClientQuery",
- },
- "operation": "query",
- "selectionSet": Object {
- "kind": "SelectionSet",
- "selections": Array [],
- },
- },
- ],
- "kind": "Document",
- },
- },
- "watches": Set {},
- },
- "client": [Circular],
- "resolvers": Object {
- "Mutation": Object {},
- "Query": Object {
- "contacts": [Function],
- },
- },
- },
- "mutationStore": MutationStore {
- "store": Object {},
- },
- "onBroadcast": [Function],
- "pollingInfoByQueryId": Map {},
- "queries": Map {},
- "queryDeduplication": true,
- "queryStore": QueryStore {
- "store": Object {},
- },
- "ssrMode": false,
- "transformCache": WeakMap {},
- },
- "reFetchObservableQueries": [Function],
- "resetStore": [Function],
- "resetStoreCallbacks": Array [],
- "store": DataStore {
- "cache": InMemoryCache {
- "addTypename": true,
- "cacheKeyRoot": KeyTrie {
- "weakness": true,
- },
- "config": Object {
- "addTypename": true,
- "dataIdFromObject": [Function],
- "fragmentMatcher": HeuristicFragmentMatcher {},
- "freezeResults": false,
- "resultCaching": true,
- },
- "data": DepTrackingCache {
- "data": Object {},
- "depend": [Function],
- },
- "maybeBroadcastWatch": [Function],
- "optimisticData": DepTrackingCache {
- "data": Object {},
- "depend": [Function],
- },
- "silenceBroadcast": false,
- "storeReader": StoreReader {
- "executeSelectionSet": [Function],
- "executeStoreQuery": [Function],
- "executeSubSelectedArray": [Function],
- "freezeResults": false,
- },
- "storeWriter": StoreWriter {},
- "typenameDocumentCache": Map {
- Object {
- "definitions": Array [
- Object {
- "kind": "OperationDefinition",
- "name": Object {
- "kind": "Name",
- "value": "GeneratedClientQuery",
- },
- "operation": "query",
- "selectionSet": Object {
- "kind": "SelectionSet",
- "selections": Array [],
- },
- },
- ],
- "kind": "Document",
- } => Object {
- "definitions": Array [
- Object {
- "kind": "OperationDefinition",
- "name": Object {
- "kind": "Name",
- "value": "GeneratedClientQuery",
- },
- "operation": "query",
- "selectionSet": Object {
- "kind": "SelectionSet",
- "selections": Array [],
- },
- },
- ],
- "kind": "Document",
- },
- Object {
- "definitions": Array [
- Object {
- "kind": "OperationDefinition",
- "name": Object {
- "kind": "Name",
- "value": "GeneratedClientQuery",
- },
- "operation": "query",
- "selectionSet": Object {
- "kind": "SelectionSet",
- "selections": Array [],
- },
- },
- ],
- "kind": "Document",
- } => Object {
- "definitions": Array [
- Object {
- "kind": "OperationDefinition",
- "name": Object {
- "kind": "Name",
- "value": "GeneratedClientQuery",
- },
- "operation": "query",
- "selectionSet": Object {
- "kind": "SelectionSet",
- "selections": Array [],
- },
- },
- ],
- "kind": "Document",
- },
- },
- "watches": Set {},
- },
- },
- "typeDefs": Object {
- "definitions": Array [
- Object {
- "directives": Array [],
- "fields": Array [
- Object {
- "arguments": Array [
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "id",
- },
- "type": Object {
- "kind": "NonNullType",
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "String",
- },
- },
- },
- },
- ],
- "directives": Array [],
- "kind": "FieldDefinition",
- "name": Object {
- "kind": "Name",
- "value": "contact",
- },
- "type": Object {
- "kind": "NonNullType",
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "Contact",
- },
- },
- },
- },
- Object {
- "arguments": Array [
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "name",
- },
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "String",
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "address",
- },
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "String",
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "negotiatorId",
- },
- "type": Object {
- "kind": "ListType",
- "type": Object {
- "kind": "NonNullType",
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "String",
- },
- },
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "officeId",
- },
- "type": Object {
- "kind": "ListType",
- "type": Object {
- "kind": "NonNullType",
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "String",
- },
- },
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "active",
- },
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "Boolean",
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "pageNumber",
- },
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "Int",
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "pageSize",
- },
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "Int",
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "sortBy",
- },
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "String",
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "identityCheck",
- },
- "type": Object {
- "kind": "ListType",
- "type": Object {
- "kind": "NonNullType",
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "String",
- },
- },
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "marketingConsent",
- },
- "type": Object {
- "kind": "ListType",
- "type": Object {
- "kind": "NonNullType",
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "String",
- },
- },
- },
- },
- },
- ],
- "directives": Array [],
- "kind": "FieldDefinition",
- "name": Object {
- "kind": "Name",
- "value": "contacts",
- },
- "type": Object {
- "kind": "NonNullType",
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "Contacts",
- },
- },
- },
- },
- Object {
- "arguments": Array [
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "id",
- },
- "type": Object {
- "kind": "NonNullType",
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "String",
- },
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "checkId",
- },
- "type": Object {
- "kind": "NonNullType",
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "String",
- },
- },
- },
- },
- ],
- "directives": Array [],
- "kind": "FieldDefinition",
- "name": Object {
- "kind": "Name",
- "value": "contactIdentityCheck",
- },
- "type": Object {
- "kind": "NonNullType",
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "ContactIdentityCheck",
- },
- },
- },
- },
- Object {
- "arguments": Array [
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "id",
- },
- "type": Object {
- "kind": "NonNullType",
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "String",
- },
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "pageNumber",
- },
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "Int",
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "pageSize",
- },
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "Int",
- },
- },
- },
- ],
- "directives": Array [],
- "kind": "FieldDefinition",
- "name": Object {
- "kind": "Name",
- "value": "contactIdentityChecks",
- },
- "type": Object {
- "kind": "NonNullType",
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "ContactIdentityChecks",
- },
- },
- },
- },
- ],
- "interfaces": Array [],
- "kind": "ObjectTypeDefinition",
- "name": Object {
- "kind": "Name",
- "value": "Query",
- },
- },
- Object {
- "directives": Array [],
- "fields": Array [
- Object {
- "arguments": Array [
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "title",
- },
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "String",
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "forename",
- },
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "String",
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "surname",
- },
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "String",
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "dateOfBirth",
- },
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "String",
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "active",
- },
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "Boolean",
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "marketingConsent",
- },
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "String",
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "communications",
- },
- "type": Object {
- "kind": "ListType",
- "type": Object {
- "kind": "NonNullType",
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "ContactCommunicationInput",
- },
- },
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "officeIds",
- },
- "type": Object {
- "kind": "ListType",
- "type": Object {
- "kind": "NonNullType",
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "String",
- },
- },
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "negotiatorIds",
- },
- "type": Object {
- "kind": "ListType",
- "type": Object {
- "kind": "NonNullType",
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "String",
- },
- },
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "addresses",
- },
- "type": Object {
- "kind": "ListType",
- "type": Object {
- "kind": "NonNullType",
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "ContactAddressInput",
- },
- },
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "metadata",
- },
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "JSON",
- },
- },
- },
- ],
- "directives": Array [],
- "kind": "FieldDefinition",
- "name": Object {
- "kind": "Name",
- "value": "createContact",
- },
- "type": Object {
- "kind": "NonNullType",
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "Contact",
- },
- },
- },
- },
- Object {
- "arguments": Array [
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "id",
- },
- "type": Object {
- "kind": "NonNullType",
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "String",
- },
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "title",
- },
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "String",
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "forename",
- },
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "String",
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "surname",
- },
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "String",
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "dateOfBirth",
- },
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "String",
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "active",
- },
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "Boolean",
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "marketingConsent",
- },
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "String",
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "communications",
- },
- "type": Object {
- "kind": "ListType",
- "type": Object {
- "kind": "NonNullType",
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "ContactCommunicationInput",
- },
- },
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "officeIds",
- },
- "type": Object {
- "kind": "ListType",
- "type": Object {
- "kind": "NonNullType",
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "String",
- },
- },
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "negotiatorIds",
- },
- "type": Object {
- "kind": "ListType",
- "type": Object {
- "kind": "NonNullType",
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "String",
- },
- },
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "addresses",
- },
- "type": Object {
- "kind": "ListType",
- "type": Object {
- "kind": "NonNullType",
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "ContactAddressInput",
- },
- },
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "metadata",
- },
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "JSON",
- },
- },
- },
- ],
- "directives": Array [],
- "kind": "FieldDefinition",
- "name": Object {
- "kind": "Name",
- "value": "updateContact",
- },
- "type": Object {
- "kind": "NonNullType",
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "Contact",
- },
- },
- },
- },
- Object {
- "arguments": Array [
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "contactId",
- },
- "type": Object {
- "kind": "NonNullType",
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "String",
- },
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "checkDate",
- },
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "String",
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "status",
- },
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "String",
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "negotiatorId",
- },
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "String",
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "documents",
- },
- "type": Object {
- "kind": "ListType",
- "type": Object {
- "kind": "NonNullType",
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "ContactIdentityDocumentInput",
- },
- },
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "metadata",
- },
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "JSON",
- },
- },
- },
- ],
- "directives": Array [],
- "kind": "FieldDefinition",
- "name": Object {
- "kind": "Name",
- "value": "createContactIdentityCheck",
- },
- "type": Object {
- "kind": "NonNullType",
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "ContactIdentityCheck",
- },
- },
- },
- },
- Object {
- "arguments": Array [
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "id",
- },
- "type": Object {
- "kind": "NonNullType",
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "String",
- },
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "contactId",
- },
- "type": Object {
- "kind": "NonNullType",
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "String",
- },
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "checkDate",
- },
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "String",
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "status",
- },
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "String",
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "negotiatorId",
- },
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "String",
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "documents",
- },
- "type": Object {
- "kind": "ListType",
- "type": Object {
- "kind": "NonNullType",
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "ContactIdentityDocumentInput",
- },
- },
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "metadata",
- },
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "JSON",
- },
- },
- },
- ],
- "directives": Array [],
- "kind": "FieldDefinition",
- "name": Object {
- "kind": "Name",
- "value": "updateIdentityCheck",
- },
- "type": Object {
- "kind": "NonNullType",
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "ContactIdentityCheck",
- },
- },
- },
- },
- Object {
- "arguments": Array [
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "userName",
- },
- "type": Object {
- "kind": "NonNullType",
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "String",
- },
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "password",
- },
- "type": Object {
- "kind": "NonNullType",
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "String",
- },
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "loginType",
- },
- "type": Object {
- "kind": "NonNullType",
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "LoginType",
- },
- },
- },
- },
- Object {
- "directives": Array [],
- "kind": "InputValueDefinition",
- "name": Object {
- "kind": "Name",
- "value": "mode",
- },
- "type": Object {
- "kind": "NonNullType",
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "LoginMode",
- },
- },
- },
- },
- ],
- "directives": Array [],
- "kind": "FieldDefinition",
- "name": Object {
- "kind": "Name",
- "value": "login",
- },
- "type": Object {
- "kind": "NamedType",
- "name": Object {
- "kind": "Name",
- "value": "Token",
- },
- },
- },
- ],
- "interfaces": Array [],
- "kind": "ObjectTypeDefinition",
- "name": Object {
- "kind": "Name",
- "value": "Mutation",
- },
- },
- ],
- "kind": "Document",
- "loc": Object {
- "end": 1872,
- "source": Object {
- "body": "type Query {
- # contact
- contact(
- id: String!,
- ): Contact!
-
- contacts(
- name: String,
- address: String,
- negotiatorId: [String!],
- officeId: [String!],
- active: Boolean,
- pageNumber: Int,
- pageSize: Int,
- sortBy: String,
- identityCheck: [String!],
- marketingConsent: [String!],
- ): Contacts!
-
- # contact-identity-check
- contactIdentityCheck(
- id: String!,
- checkId: String!,
- ): ContactIdentityCheck!
-
- contactIdentityChecks(
- id: String!,
- pageNumber: Int,
- pageSize: Int,
- ): ContactIdentityChecks!
-
-}
-
-type Mutation {
- # contact
- createContact(
- title: String,
- forename: String,
- surname: String,
- dateOfBirth: String,
- active: Boolean,
- marketingConsent: String,
- communications: [ContactCommunicationInput!],
- officeIds: [String!],
- negotiatorIds: [String!],
- addresses: [ContactAddressInput!],
- metadata: JSON,
- ): Contact!
-
- updateContact(
- id: String!,
- title: String,
- forename: String,
- surname: String,
- dateOfBirth: String,
- active: Boolean,
- marketingConsent: String,
- communications: [ContactCommunicationInput!],
- officeIds: [String!],
- negotiatorIds: [String!],
- addresses: [ContactAddressInput!],
- metadata: JSON,
- ): Contact!
-
- # contact-identity-check
- createContactIdentityCheck(
- contactId: String!,
- checkDate: String,
- status: String,
- negotiatorId: String,
- documents: [ContactIdentityDocumentInput!],
- metadata: JSON,
- ): ContactIdentityCheck!
-
- updateIdentityCheck(
- id: String!,
- contactId: String!,
- checkDate: String,
- status: String,
- negotiatorId: String,
- documents: [ContactIdentityDocumentInput!],
- metadata: JSON,
- ): ContactIdentityCheck!
-
- login(
- userName: String!,
- password: String!,
- loginType: LoginType!,
- mode: LoginMode!,
- ): Token
-}
-",
- "locationOffset": Object {
- "column": 1,
- "line": 1,
- },
- "name": "GraphQL request",
- },
- "start": 0,
- },
- },
- "version": "2.6.8",
- "watchQuery": [Function],
- }
- }
- >
-
-
-
-
-`;
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/core/__tests__/__snapshots__/private-route-wrapper.tsx.snap b/packages/react-app-scaffolder/app/templates/apollo/src/core/__tests__/__snapshots__/private-route-wrapper.tsx.snap
deleted file mode 100644
index faa51af46d..0000000000
--- a/packages/react-app-scaffolder/app/templates/apollo/src/core/__tests__/__snapshots__/private-route-wrapper.tsx.snap
+++ /dev/null
@@ -1,835 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`PrivateRouter should match a snapshot 1`] = `
-Object {
- "asFragment": [Function],
- "baseElement":
-
- ,
- "container": ,
- "debug": [Function],
- "findAllByAltText": [Function],
- "findAllByDisplayValue": [Function],
- "findAllByLabelText": [Function],
- "findAllByPlaceholderText": [Function],
- "findAllByRole": [Function],
- "findAllByTestId": [Function],
- "findAllByText": [Function],
- "findAllByTitle": [Function],
- "findByAltText": [Function],
- "findByDisplayValue": [Function],
- "findByLabelText": [Function],
- "findByPlaceholderText": [Function],
- "findByRole": [Function],
- "findByTestId": [Function],
- "findByText": [Function],
- "findByTitle": [Function],
- "getAllByAltText": [Function],
- "getAllByDisplayValue": [Function],
- "getAllByLabelText": [Function],
- "getAllByPlaceholderText": [Function],
- "getAllByRole": [Function],
- "getAllByTestId": [Function],
- "getAllByText": [Function],
- "getAllByTitle": [Function],
- "getByAltText": [Function],
- "getByDisplayValue": [Function],
- "getByLabelText": [Function],
- "getByPlaceholderText": [Function],
- "getByRole": [Function],
- "getByTestId": [Function],
- "getByText": [Function],
- "getByTitle": [Function],
- "queryAllByAltText": [Function],
- "queryAllByDisplayValue": [Function],
- "queryAllByLabelText": [Function],
- "queryAllByPlaceholderText": [Function],
- "queryAllByRole": [Function],
- "queryAllByTestId": [Function],
- "queryAllByText": [Function],
- "queryAllByTitle": [Function],
- "queryByAltText": [Function],
- "queryByDisplayValue": [Function],
- "queryByLabelText": [Function],
- "queryByPlaceholderText": [Function],
- "queryByRole": [Function],
- "queryByTestId": [Function],
- "queryByText": [Function],
- "queryByTitle": [Function],
- "rerender": [Function],
- "unmount": [Function],
-}
-`;
-
-exports[`PrivateRouter should match a snapshot 2`] = `
-Object {
- "asFragment": [Function],
- "baseElement":
-
- ,
- "container":
,
- "debug": [Function],
- "findAllByAltText": [Function],
- "findAllByDisplayValue": [Function],
- "findAllByLabelText": [Function],
- "findAllByPlaceholderText": [Function],
- "findAllByRole": [Function],
- "findAllByTestId": [Function],
- "findAllByText": [Function],
- "findAllByTitle": [Function],
- "findByAltText": [Function],
- "findByDisplayValue": [Function],
- "findByLabelText": [Function],
- "findByPlaceholderText": [Function],
- "findByRole": [Function],
- "findByTestId": [Function],
- "findByText": [Function],
- "findByTitle": [Function],
- "getAllByAltText": [Function],
- "getAllByDisplayValue": [Function],
- "getAllByLabelText": [Function],
- "getAllByPlaceholderText": [Function],
- "getAllByRole": [Function],
- "getAllByTestId": [Function],
- "getAllByText": [Function],
- "getAllByTitle": [Function],
- "getByAltText": [Function],
- "getByDisplayValue": [Function],
- "getByLabelText": [Function],
- "getByPlaceholderText": [Function],
- "getByRole": [Function],
- "getByTestId": [Function],
- "getByText": [Function],
- "getByTitle": [Function],
- "queryAllByAltText": [Function],
- "queryAllByDisplayValue": [Function],
- "queryAllByLabelText": [Function],
- "queryAllByPlaceholderText": [Function],
- "queryAllByRole": [Function],
- "queryAllByTestId": [Function],
- "queryAllByText": [Function],
- "queryAllByTitle": [Function],
- "queryByAltText": [Function],
- "queryByDisplayValue": [Function],
- "queryByLabelText": [Function],
- "queryByPlaceholderText": [Function],
- "queryByRole": [Function],
- "queryByTestId": [Function],
- "queryByText": [Function],
- "queryByTitle": [Function],
- "rerender": [Function],
- "unmount": [Function],
-}
-`;
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/core/private-route-wrapper.tsx b/packages/react-app-scaffolder/app/templates/apollo/src/core/private-route-wrapper.tsx
deleted file mode 100644
index 58587d8930..0000000000
--- a/packages/react-app-scaffolder/app/templates/apollo/src/core/private-route-wrapper.tsx
+++ /dev/null
@@ -1,53 +0,0 @@
-import * as React from 'react'
-import { withRouter, RouteComponentProps, Redirect } from 'react-router-dom'
-import Menu from '@/components/ui/menu'
-import { Loader, AppNavContainer, Section, FlexContainerBasic } from '@reapit/elements'
-import { redirectToOAuth } from '@reapit/cognito-auth'
-import { AuthContext } from '@/context'
-import Routes from '@/constants/routes'
-
-const { Suspense } = React
-
-export type PrivateRouteWrapperProps = RouteComponentProps & {
- path: string
-}
-
-export const PrivateRouteWrapper: React.FunctionComponent = ({ children }) => {
- const { loginSession, refreshParams, getLoginSession } = React.useContext(AuthContext)
-
- if (!loginSession && !refreshParams) {
- redirectToOAuth(window.reapit.config.cognitoClientId)
- return null
- }
-
- if (!loginSession && refreshParams) {
- getLoginSession(refreshParams)
- }
-
- if (!loginSession) {
- return null
- }
-
- if (location.pathname === '/') {
- return
- }
-
- return (
-
-
-
-
-
-
- }
- >
- {children}
-
-
-
- )
-}
-
-export default withRouter(PrivateRouteWrapper)
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/graphql/__mocks__/contact.ts b/packages/react-app-scaffolder/app/templates/apollo/src/graphql/__mocks__/contact.ts
deleted file mode 100644
index 63fd063889..0000000000
--- a/packages/react-app-scaffolder/app/templates/apollo/src/graphql/__mocks__/contact.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-export const contact = {
- __typename: 'Contact',
- active: false,
- addresses: [
- {
- __typename: 'ContactAddress',
- buildingName: 'building name',
- buildingNumber: '1',
- line1: '15 Furzen Crescent',
- line2: 'line2',
- line3: 'line3',
- postcode: 'AL10 9QN',
- },
- ],
- created: '2019-11-26T11:19:23.0000000Z',
- dateOfBirth: '1986-06-29T13:00:00.0000000Z',
- forename: 'Development',
- id: 'MOD19000001',
- identityCheck: 'pass',
- marketingConsent: 'notAsked',
- modified: '2019-12-13T13:32:28.0000000Z',
- surname: 'Environment',
- title: 'Mrs',
-}
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/graphql/__mocks__/contacts.ts b/packages/react-app-scaffolder/app/templates/apollo/src/graphql/__mocks__/contacts.ts
deleted file mode 100644
index 58008eacc2..0000000000
--- a/packages/react-app-scaffolder/app/templates/apollo/src/graphql/__mocks__/contacts.ts
+++ /dev/null
@@ -1,243 +0,0 @@
-export const contacts = {
- __typename: 'Contacts',
- _embedded: [
- {
- __typename: 'Contact',
- active: false,
- addresses: [
- {
- __typename: 'ContactAddress',
- buildingName: 'building name',
- buildingNumber: '1',
- line1: '15 Furzen Crescent',
- line2: 'line2',
- line3: 'line3',
- postcode: 'AL10 9QN',
- },
- ],
- created: '2019-11-26T11:19:23.0000000Z',
- dateOfBirth: '1986-06-29T13:00:00.0000000Z',
- forename: 'Development',
- id: 'MOD19000001',
- identityCheck: 'pass',
- marketingConsent: 'notAsked',
- modified: '2019-12-13T13:32:28.0000000Z',
- surname: 'Environment',
- title: 'Mrs',
- },
- {
- __typename: 'Contact',
- active: true,
- addresses: [
- {
- __typename: 'ContactAddress',
- buildingName: '',
- buildingNumber: '38',
- line1: 'Stephen Crescent',
- line2: 'Humberston',
- line3: 'Grimsby',
- postcode: 'DN36 4DT',
- },
- ],
- created: '2019-11-05T12:47:50.0000000Z',
- dateOfBirth: '1981-03-25',
- forename: 'Paul',
- id: 'AYL19000004',
- identityCheck: 'cancelled',
- marketingConsent: 'notAsked',
- modified: '2019-11-26T13:18:04.0000000Z',
- surname: 'Rideout',
- title: 'Mr',
- },
- {
- __typename: 'Contact',
- active: false,
- addresses: [
- {
- __typename: 'ContactAddress',
- buildingName: '',
- buildingNumber: '86a',
- line1: 'Potternewton Lane',
- line2: 'Chapel Allerton',
- line3: 'Leeds',
- postcode: 'LS7 3LW',
- },
- ],
- created: '2019-11-05T12:35:44.0000000Z',
- dateOfBirth: '1981-03-25',
- forename: 'Dave',
- id: 'AYL19000003',
- identityCheck: 'pending',
- marketingConsent: 'notAsked',
- modified: '2019-11-26T13:18:04.0000000Z',
- surname: 'Gilbert',
- title: 'Mr',
- },
- {
- __typename: 'Contact',
- active: false,
- addresses: [
- {
- __typename: 'ContactAddress',
- buildingName: 'Tyto Alba',
- buildingNumber: '38',
- line1: 'Stephen Crescent',
- line2: 'Humberston',
- line3: 'Grimsby',
- postcode: 'DN36 4DT',
- },
- ],
- created: '2019-11-04T11:32:55.0000000Z',
- dateOfBirth: '1981-03-26',
- forename: 'Charles',
- id: 'AYL19000002',
- identityCheck: 'cancelled',
- marketingConsent: 'notAsked',
- modified: '2019-11-26T13:18:04.0000000Z',
- surname: 'Babbage',
- title: 'Mr',
- },
- {
- __typename: 'Contact',
- active: true,
- addresses: [
- {
- __typename: 'ContactAddress',
- buildingName: 'Name',
- buildingNumber: '38',
- line1: 'Stephen Crescent',
- line2: 'Grimsby',
- line3: 'N E Lincs',
- postcode: 'DN36 4DT',
- },
- ],
- created: '2019-11-03T19:45:29.0000000Z',
- dateOfBirth: '1981-03-24T17:00:00.0000000Z',
- forename: 'Dawson',
- id: 'RPT19000366',
- identityCheck: 'pending',
- marketingConsent: 'notAsked',
- modified: '2019-12-11T07:11:42.0000000Z',
- surname: 'Scott',
- title: 'Mr',
- },
- {
- __typename: 'Contact',
- active: true,
- addresses: [
- {
- __typename: 'ContactAddress',
- buildingName: 'Ash Lodge',
- buildingNumber: '3',
- line1: 'Northbourne Road',
- line2: 'London',
- line3: '',
- postcode: 'SE5 9RL',
- },
- ],
- created: '2019-11-03T19:09:58.0000000Z',
- dateOfBirth: '1984-09-24',
- forename: 'Katy',
- id: 'RPT19000365',
- identityCheck: 'pending',
- marketingConsent: 'notAsked',
- modified: '2019-11-04T16:16:28.0000000Z',
- surname: 'Easton',
- title: 'Ms',
- },
- {
- __typename: 'Contact',
- active: true,
- addresses: [
- {
- __typename: 'ContactAddress',
- buildingName: 'aa',
- buildingNumber: '37',
- line1: 'Kingsway Place',
- line2: 'London',
- line3: 'a',
- postcode: 'EC1R 0LU',
- },
- ],
- created: '2019-10-31T14:19:51.0000000Z',
- dateOfBirth: '2019-12-12',
- forename: 'H',
- id: 'AYL19000001',
- identityCheck: 'pass',
- marketingConsent: 'grant',
- modified: '2019-12-13T05:38:17.0000000Z',
- surname: 'Phillips',
- title: 'Mrs',
- },
- {
- __typename: 'Contact',
- active: true,
- addresses: [
- {
- __typename: 'ContactAddress',
- buildingName: '',
- buildingNumber: '46',
- line1: 'Farm Street',
- line2: 'High Wycombe',
- line3: 'Milton Keynes',
- postcode: 'MK4 4AG',
- },
- ],
- created: '2019-10-25T11:09:08.0000000Z',
- dateOfBirth: '1986-06-30',
- forename: 'Rogan',
- id: 'RPT19000363',
- identityCheck: 'pending',
- marketingConsent: 'notAsked',
- modified: '2019-12-10T10:13:44.0000000Z',
- surname: 'Johnstone',
- title: 'Mr',
- },
- {
- __typename: 'Contact',
- active: true,
- addresses: null,
- created: '2019-10-24T09:11:29.0000000Z',
- dateOfBirth: null,
- forename: 'James',
- id: 'BED19000003',
- identityCheck: 'pending',
- marketingConsent: 'notAsked',
- modified: '2019-10-24T09:14:55.0000000Z',
- surname: 'Brown',
- title: 'Mr',
- },
- {
- __typename: 'Contact',
- active: true,
- addresses: null,
- created: '2019-10-24T08:29:00.0000000Z',
- dateOfBirth: null,
- forename: '',
- id: 'RPT19000362',
- identityCheck: 'unchecked',
- marketingConsent: 'notAsked',
- modified: '2019-10-24T08:30:17.0000000Z',
- surname: '',
- title: '',
- },
- ],
- _links: {
- first: {
- href: '/contacts/?PageNumber=1&PageSize=10',
- },
- last: {
- href: '/contacts/?PageNumber=397&PageSize=10',
- },
- next: {
- href: '/contacts/?PageNumber=2&PageSize=10',
- },
- self: {
- href: '/contacts/?PageNumber=1&PageSize=10',
- },
- },
- pageCount: 10,
- pageNumber: 1,
- pageSize: 10,
- totalCount: 3966,
-}
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/graphql/__mocks__/error.ts b/packages/react-app-scaffolder/app/templates/apollo/src/graphql/__mocks__/error.ts
deleted file mode 100644
index 7d2d3432ee..0000000000
--- a/packages/react-app-scaffolder/app/templates/apollo/src/graphql/__mocks__/error.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-export const error = {
- message: 'mockError',
- graphQLErrors: [],
- networkError: { name: 'Error', message: 'Error' },
- extraInfo: [],
- name: 'Error',
-}
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/graphql/__mocks__/token.ts b/packages/react-app-scaffolder/app/templates/apollo/src/graphql/__mocks__/token.ts
deleted file mode 100644
index b24f710d1c..0000000000
--- a/packages/react-app-scaffolder/app/templates/apollo/src/graphql/__mocks__/token.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import { LoginParams } from '@reapit/cognito-auth'
-
-export const token = {
- __typename: 'Token',
- accessToken: 'mockAccessToken',
- refreshToken: 'mockRefreshToken',
-}
-
-export const loginParams = {
- userName: 'mockUsername',
- password: 'mockPassword',
- loginType: 'CLIENT',
- mode: 'WEB',
-} as LoginParams
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/graphql/__tests__/client.test.ts b/packages/react-app-scaffolder/app/templates/apollo/src/graphql/__tests__/client.test.ts
deleted file mode 100644
index 1795abcefd..0000000000
--- a/packages/react-app-scaffolder/app/templates/apollo/src/graphql/__tests__/client.test.ts
+++ /dev/null
@@ -1,72 +0,0 @@
-import { Operation, IdGetterObj } from 'apollo-boost'
-import { ErrorResponse } from 'apollo-link-error'
-import { GraphQLError } from 'graphql'
-import { getClient, generateRequest, onError, dataIdFromObject } from '@/graphql/client'
-
-describe('client', () => {
- describe('getClient', () => {
- it('should run correctly', () => {
- const mockAccessToken = 'mockAccessToken'
- const result = getClient(mockAccessToken)
- expect(result).toBeDefined()
- })
- })
- describe('generateRequest', () => {
- it('should run correctly', done => {
- // @ts-ignore
- const mockOperation = {
- setContext: jest.fn(),
- } as Operation
- generateRequest('mockToken')(mockOperation)
- setTimeout(() => {
- expect(mockOperation.setContext).toBeCalled()
- done()
- }, 1000)
- })
- })
- describe('onError', () => {
- it('should run correctly when have both', () => {
- const mockError = {
- graphQLErrors: [new GraphQLError('123')] as ReadonlyArray,
- networkError: new Error('abc'),
- } as ErrorResponse
- onError(mockError)
- })
-
- it('should run correctly when no graphQLErrors', () => {
- const mockError = {
- graphQLErrors: [] as ReadonlyArray,
- networkError: new Error('abc'),
- } as ErrorResponse
- onError(mockError)
- })
-
- it('should run correctly when no networkError', () => {
- const mockError = {
- graphQLErrors: [new GraphQLError('123')] as ReadonlyArray,
- networkError: undefined,
- } as ErrorResponse
- onError(mockError)
- })
-
- it('should run correctly when no error', () => {
- const mockError = {
- graphQLErrors: [] as ReadonlyArray,
- networkError: undefined,
- } as ErrorResponse
- onError(mockError)
- })
- })
-
- describe('dataIdFromObject', () => {
- it('should run correctly', () => {
- const mockObject = {
- __typename: 'mockType',
- id: '1',
- } as IdGetterObj
- const result = dataIdFromObject(mockObject)
- const output = `${mockObject.__typename}:${mockObject.id}`
- expect(result).toEqual(output)
- })
- })
-})
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/graphql/__tests__/resolver.test.ts b/packages/react-app-scaffolder/app/templates/apollo/src/graphql/__tests__/resolver.test.ts
deleted file mode 100644
index cb8c68a361..0000000000
--- a/packages/react-app-scaffolder/app/templates/apollo/src/graphql/__tests__/resolver.test.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import resolvers from '../resolvers'
-import { contacts } from '../__mocks__/contacts'
-
-describe('resolvers', () => {
- describe('contacts', () => {
- it('should run correctly', async done => {
- const result = await resolvers.Query.contacts()
- setTimeout(() => {
- expect(result).toEqual(contacts)
- done()
- }, 2000)
- })
- })
-})
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/graphql/client.ts b/packages/react-app-scaffolder/app/templates/apollo/src/graphql/client.ts
deleted file mode 100644
index 8d768100af..0000000000
--- a/packages/react-app-scaffolder/app/templates/apollo/src/graphql/client.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-import ApolloClient, { InMemoryCache, Operation, defaultDataIdFromObject, IdGetterObj } from 'apollo-boost'
-import { ErrorHandler, ErrorResponse } from 'apollo-link-error'
-import { ApolloCache } from 'apollo-cache'
-import typeDefs from './schema.graphql'
-import resolvers from './resolvers'
-
-export const generateRequest = (accessToken: string) => async (operation: Operation) => {
- operation.setContext({
- headers: {
- authorization: accessToken,
- },
- })
-}
-
-export const onError: ErrorHandler = ({ graphQLErrors, networkError }: ErrorResponse) => {
- if (graphQLErrors) {
- graphQLErrors.map(({ message, locations, path }) =>
- console.log(`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`),
- )
- }
- if (networkError) console.log(`[Network error]: ${networkError}`)
-}
-
-export const dataIdFromObject = (object: IdGetterObj) => {
- // Will open when custom object ID for caching
- // switch (object.__typename) {
- // // Custom keycache here!
- // default:
- // return defaultDataIdFromObject(object)
- // }
- return defaultDataIdFromObject(object)
-}
-
-const cache: ApolloCache = new InMemoryCache({
- dataIdFromObject,
-})
-
-const clientState = {
- cache,
- defaults: {},
- resolvers,
- typeDefs,
-}
-
-export const getClient = (accessToken: string, uri: string) =>
- new ApolloClient({
- uri,
- onError,
- cache,
- request: generateRequest(accessToken),
- clientState,
- })
-
-export default getClient
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/graphql/resolvers.ts b/packages/react-app-scaffolder/app/templates/apollo/src/graphql/resolvers.ts
deleted file mode 100644
index cbc9e3919e..0000000000
--- a/packages/react-app-scaffolder/app/templates/apollo/src/graphql/resolvers.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import sleep from '@/utils/sleep'
-import { contacts } from './__mocks__/contacts'
-
-const resolvers = {
- Query: {
- contacts: async () => {
- await sleep(1000)
- return contacts
- },
- },
- Mutation: {},
-}
-
-export default resolvers
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/graphql/schema.graphql b/packages/react-app-scaffolder/app/templates/apollo/src/graphql/schema.graphql
deleted file mode 100644
index 4253cc49dc..0000000000
--- a/packages/react-app-scaffolder/app/templates/apollo/src/graphql/schema.graphql
+++ /dev/null
@@ -1,3 +0,0 @@
-type Query {}
-
-type Mutation {}
diff --git a/packages/react-app-scaffolder/app/templates/base-is-linaria/src/styles/index.css b/packages/react-app-scaffolder/app/templates/base-is-linaria/src/styles/index.css
deleted file mode 100644
index 3c02e6809d..0000000000
--- a/packages/react-app-scaffolder/app/templates/base-is-linaria/src/styles/index.css
+++ /dev/null
@@ -1,9 +0,0 @@
-@import url('https://fonts.googleapis.com/css?family=Source+Code+Pro&display=swap');
-@import url('https://fonts.googleapis.com/css?family=Roboto&display=swap');
-
-
-<%if (!isFoundation) { %>
-/* need this because we import production elements. in foundation we import the code from element directly which imports the element styles */
-@import "~@reapit/elements/dist/index.css"
-<% } %>
-
diff --git a/packages/react-app-scaffolder/app/templates/base-is-sass/src/styles/base/colors.scss b/packages/react-app-scaffolder/app/templates/base-is-sass/src/styles/base/colors.scss
deleted file mode 100644
index cefdf1553b..0000000000
--- a/packages/react-app-scaffolder/app/templates/base-is-sass/src/styles/base/colors.scss
+++ /dev/null
@@ -1,27 +0,0 @@
-$white: #fff;
-$black: #12263f;
-$grey-dark: #6e84a3;
-$grey: #95aac9;
-$grey-lighter: #e3ebf6;
-$grey-lightest: #f9fbfd;
-
-$green: #5fe781;
-$green-lighter: #acf2bd;
-$green-lightest: #e6ffed;
-$red: #e96171;
-$red-lighter: #fdb8c0;
-$red-lightest: #ffeef0;
-
-$reapit-dark-blue: #262f69;
-$reapit-mid-blue: #0061a8;
-$reapit-light-blue: #23a4de;
-$reapit-lightest-blue: #7bc9eb;
-
-$reapit-orange: #ec631b;
-$reapit-lime: #cddb00;
-$reapit-teal: #006580;
-$reapit-plumb: #7a2c81;
-$reapit-purple: #a4185c;
-$reapit-gold: #ffb71b;
-$reapit-green: #a0c862;
-$reapit-red: #d3033d;
diff --git a/packages/react-app-scaffolder/app/templates/base-is-sass/src/styles/base/layout.scss b/packages/react-app-scaffolder/app/templates/base-is-sass/src/styles/base/layout.scss
deleted file mode 100644
index a21cb393db..0000000000
--- a/packages/react-app-scaffolder/app/templates/base-is-sass/src/styles/base/layout.scss
+++ /dev/null
@@ -1,14 +0,0 @@
-$layout-base: 1rem;
-// Generic layout values that scale to rem base
-$layout-quarter: calc(1rem / 4);
-$layout-third: calc(1rem / 3);
-$layout-half: calc(1rem / 2);
-$layout-two-third: calc(1rem * 0.67);
-$layout-three-quarter: calc(1rem * 0.75);
-$layout-one-quarter: calc(1rem * 1.25);
-$layout-one-half: calc(1rem * 1.5);
-$layout-double: calc(1rem * 2);
-$layout-two-half: calc(1rem * 2.5);
-$layout-triple: calc(1rem * 3);
-$layout-quadruple: calc(1rem * 4);
-$layout-sextuple: calc(1rem * 6);
diff --git a/packages/react-app-scaffolder/app/templates/base-is-sass/src/styles/index.scss b/packages/react-app-scaffolder/app/templates/base-is-sass/src/styles/index.scss
deleted file mode 100644
index 279ed39041..0000000000
--- a/packages/react-app-scaffolder/app/templates/base-is-sass/src/styles/index.scss
+++ /dev/null
@@ -1,8 +0,0 @@
-@charset "utf-8";
-@import url('https://fonts.googleapis.com/css?family=Source+Code+Pro&display=swap');
-@import url('https://fonts.googleapis.com/css?family=Roboto&display=swap');
-
-<%if (!isFoundation) { %>
-/* need this because we import production elements. in foundation we import the code from element directly which imports the element styles */
-@import "~@reapit/elements/dist/index.css"
-<% } %>
diff --git a/packages/react-app-scaffolder/app/templates/base/.npmrc b/packages/react-app-scaffolder/app/templates/base/.npmrc
deleted file mode 100644
index bd3327ab5a..0000000000
--- a/packages/react-app-scaffolder/app/templates/base/.npmrc
+++ /dev/null
@@ -1 +0,0 @@
-//registry.npmjs.org/:_authToken=${NPM_TOKEN}
\ No newline at end of file
diff --git a/packages/react-app-scaffolder/app/templates/base/public/index.js b/packages/react-app-scaffolder/app/templates/base/public/index.js
deleted file mode 100644
index d0e80f1ee1..0000000000
--- a/packages/react-app-scaffolder/app/templates/base/public/index.js
+++ /dev/null
@@ -1,38 +0,0 @@
-const http = require('http')
-const url = require('url')
-const fs = require('fs')
-const path = require('path')
-const port = 8080
-
-http
- .createServer((request, response) => {
- try {
- const requestUrl = url.parse(request.url)
- const fsPath = `${__dirname}/dist${path.normalize(requestUrl.pathname)}` // need to use path.normalize so people can't access directories underneath baseDirectory
- const fileStream = /\.(js|css|woff|gif|jpg|jpeg|tiff|png)$/i.test(fsPath)
- ? fs.createReadStream(fsPath)
- : fs.createReadStream(`${__dirname}/dist/index.html`)
-
- fileStream.pipe(response)
- fileStream.on('open', () => {
- response.writeHead(200)
- })
- fileStream.on('error', e => {
- response.writeHead(404) // assume the file doesn't exist
- response.end()
- })
- } catch (e) {
- response.writeHead(500)
- response.end() // end the response so browsers don't hang
- console.log(e.stack)
- }
- })
- .listen(port)
-
-process.title = process.argv[2]
-process.on('SIGINT', () => {
- console.log(`Gracefully shutting down ${process.title}`)
- process.exit()
-})
-
-console.log(`Listening on port ${port}`)
diff --git a/packages/react-app-scaffolder/app/templates/base/src/assets/fonts/1427936/353acc2c-88f2-4de3-83eb-6cc2c9b05af1.ttf b/packages/react-app-scaffolder/app/templates/base/src/assets/fonts/1427936/353acc2c-88f2-4de3-83eb-6cc2c9b05af1.ttf
deleted file mode 100755
index 7a2e60c6d8..0000000000
Binary files a/packages/react-app-scaffolder/app/templates/base/src/assets/fonts/1427936/353acc2c-88f2-4de3-83eb-6cc2c9b05af1.ttf and /dev/null differ
diff --git a/packages/react-app-scaffolder/app/templates/base/src/assets/fonts/1427936/9803fddf-c005-431a-92d5-0f18688f945d.woff2 b/packages/react-app-scaffolder/app/templates/base/src/assets/fonts/1427936/9803fddf-c005-431a-92d5-0f18688f945d.woff2
deleted file mode 100755
index c38d9ef1e7..0000000000
Binary files a/packages/react-app-scaffolder/app/templates/base/src/assets/fonts/1427936/9803fddf-c005-431a-92d5-0f18688f945d.woff2 and /dev/null differ
diff --git a/packages/react-app-scaffolder/app/templates/base/src/assets/fonts/1427936/ea9b8ac3-ff16-4387-a473-32a6a617329f.woff b/packages/react-app-scaffolder/app/templates/base/src/assets/fonts/1427936/ea9b8ac3-ff16-4387-a473-32a6a617329f.woff
deleted file mode 100755
index 8695bba38d..0000000000
Binary files a/packages/react-app-scaffolder/app/templates/base/src/assets/fonts/1427936/ea9b8ac3-ff16-4387-a473-32a6a617329f.woff and /dev/null differ
diff --git a/packages/react-app-scaffolder/app/templates/base/src/assets/fonts/1427936/f2cf6cf9-9ec6-4945-a525-f5873d143c2a.eot b/packages/react-app-scaffolder/app/templates/base/src/assets/fonts/1427936/f2cf6cf9-9ec6-4945-a525-f5873d143c2a.eot
deleted file mode 100755
index 3b2fb12725..0000000000
Binary files a/packages/react-app-scaffolder/app/templates/base/src/assets/fonts/1427936/f2cf6cf9-9ec6-4945-a525-f5873d143c2a.eot and /dev/null differ
diff --git a/packages/react-app-scaffolder/app/templates/base/src/assets/fonts/1427944/1c070cdb-18d8-440e-be9d-2448fa3930c4.eot b/packages/react-app-scaffolder/app/templates/base/src/assets/fonts/1427944/1c070cdb-18d8-440e-be9d-2448fa3930c4.eot
deleted file mode 100755
index 3c246ee6fb..0000000000
Binary files a/packages/react-app-scaffolder/app/templates/base/src/assets/fonts/1427944/1c070cdb-18d8-440e-be9d-2448fa3930c4.eot and /dev/null differ
diff --git a/packages/react-app-scaffolder/app/templates/base/src/assets/fonts/1427944/66c06801-da3e-4587-a89c-674cfbe39c21.woff2 b/packages/react-app-scaffolder/app/templates/base/src/assets/fonts/1427944/66c06801-da3e-4587-a89c-674cfbe39c21.woff2
deleted file mode 100755
index 0c0e23f86f..0000000000
Binary files a/packages/react-app-scaffolder/app/templates/base/src/assets/fonts/1427944/66c06801-da3e-4587-a89c-674cfbe39c21.woff2 and /dev/null differ
diff --git a/packages/react-app-scaffolder/app/templates/base/src/assets/fonts/1427944/c21bf502-6b58-4bf0-9ddd-169929c263e7.ttf b/packages/react-app-scaffolder/app/templates/base/src/assets/fonts/1427944/c21bf502-6b58-4bf0-9ddd-169929c263e7.ttf
deleted file mode 100755
index 406dc21fd0..0000000000
Binary files a/packages/react-app-scaffolder/app/templates/base/src/assets/fonts/1427944/c21bf502-6b58-4bf0-9ddd-169929c263e7.ttf and /dev/null differ
diff --git a/packages/react-app-scaffolder/app/templates/base/src/assets/fonts/1427944/f3c7f613-9728-4ed6-a383-1c8519b215d2.woff b/packages/react-app-scaffolder/app/templates/base/src/assets/fonts/1427944/f3c7f613-9728-4ed6-a383-1c8519b215d2.woff
deleted file mode 100755
index 8b3d1ec354..0000000000
Binary files a/packages/react-app-scaffolder/app/templates/base/src/assets/fonts/1427944/f3c7f613-9728-4ed6-a383-1c8519b215d2.woff and /dev/null differ
diff --git a/packages/react-app-scaffolder/app/templates/hooks-external/.eslintrc.js b/packages/react-app-scaffolder/app/templates/hooks-external/.eslintrc.js
new file mode 100644
index 0000000000..bc51f80efb
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/hooks-external/.eslintrc.js
@@ -0,0 +1,76 @@
+module.exports = {
+ env: {
+ browser: true,
+ es6: true,
+ node: true,
+ amd: true,
+ jest: true,
+ },
+ extends: [
+ 'eslint:recommended',
+ 'plugin:react/recommended',
+ 'plugin:@typescript-eslint/eslint-recommended',
+ 'prettier',
+ 'prettier/@typescript-eslint',
+ 'prettier/react',
+ 'prettier/standard',
+ ],
+ globals: {
+ Atomics: 'readonly',
+ SharedArrayBuffer: 'readonly',
+ },
+ parser: '@typescript-eslint/parser',
+ parserOptions: {
+ ecmaFeatures: {
+ jsx: true,
+ },
+ ecmaVersion: 2018,
+ sourceType: 'module',
+ },
+ plugins: ['react', '@typescript-eslint', 'prettier', 'react-hooks'],
+ ignorePatterns: [
+ '__mocks__/',
+ 'node_modules/',
+ 'setup-tests.ts',
+ 'jest.config.js',
+ '.prettierrc.js',
+ 'react-app-scaffolder/',
+ 'marketplace-api-schema.ts',
+ 'platform-schema.ts',
+ ],
+ rules: {
+ quotes: ['error', 'single', { avoidEscape: true, allowTemplateLiterals: false }],
+ semi: ['error', 'never'],
+ 'no-unused-vars': ['error', { vars: 'all', args: 'after-used' }],
+ '@typescript-eslint/no-unused-vars': [2, { args: 'none' }],
+ 'prettier/prettier': ['error', {
+ 'endOfLine': 'auto'
+ }],
+ 'max-len': ['error', { code: 120, ignoreUrls: true }],
+ 'no-confusing-arrow': ['error', { allowParens: false }],
+ 'no-mixed-operators': [
+ 'error',
+ {
+ groups: [
+ ['&', '|', '^', '~', '<<', '>>', '>>>'],
+ ['==', '!=', '===', '!==', '>', '>=', '<', '<='],
+ ['&&', '||'],
+ ['in', 'instanceof'],
+ ],
+ },
+ ],
+ 'no-tabs': ['error', { allowIndentationTabs: true }],
+ 'no-unexpected-multiline': 'error',
+ // Disabling as conflicts with Prettier
+ indent: 0,
+ // Disabling as we are validating types with TypeScript not PropTypes
+ 'react/prop-types': 0,
+ "react-hooks/rules-of-hooks": 0,
+ "react-hooks/exhaustive-deps": 0,
+ },
+ settings: {
+ react: {
+ version: 'detect',
+ },
+ },
+}
diff --git a/packages/react-app-scaffolder/app/templates/hooks-external/.gitignore b/packages/react-app-scaffolder/app/templates/hooks-external/.gitignore
new file mode 100644
index 0000000000..aeb663f439
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/hooks-external/.gitignore
@@ -0,0 +1,24 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+/src/tests/coverage
+
+# misc
+.DS_Store
+reapit-config.json
+config.json
+
+# log files
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+*.log
+
+.cache/
+yarn.lock
+
+public/dist
+src/tests
+
+.jest-cache
\ No newline at end of file
diff --git a/packages/react-app-scaffolder/app/templates/base-is-not-foundation/.prettierrc.js b/packages/react-app-scaffolder/app/templates/hooks-external/.prettierrc.js
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/base-is-not-foundation/.prettierrc.js
rename to packages/react-app-scaffolder/app/templates/hooks-external/.prettierrc.js
diff --git a/packages/react-app-scaffolder/app/templates/hooks-external/config.example.json b/packages/react-app-scaffolder/app/templates/hooks-external/config.example.json
new file mode 100644
index 0000000000..98a80ad258
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/hooks-external/config.example.json
@@ -0,0 +1,7 @@
+{
+ "appEnv": "local",
+ "cognitoClientId": "",
+ "cognitoOAuthUrl": "https://dev.connect.reapit.cloud",
+ "cognitoUserPoolId": "eu-west-2_hbt0B7yys",
+ "platformApiUrl": "https://dev.platform.reapit.cloud"
+}
diff --git a/packages/react-app-scaffolder/app/templates/hooks-external/jest.config.js b/packages/react-app-scaffolder/app/templates/hooks-external/jest.config.js
new file mode 100644
index 0000000000..92f778077a
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/hooks-external/jest.config.js
@@ -0,0 +1,42 @@
+const path = require('path')
+const { defaults } = require('jest-config')
+const { pathsToModuleNameMapper } = require('ts-jest/utils')
+const { compilerOptions } = require('./tsconfig')
+
+module.exports = {
+ preset: 'ts-jest',
+ testPathIgnorePatterns: ['/src/tests/'],
+ setupFiles: ['/src/scripts/jest/jest-setup.js'],
+ collectCoverageFrom: ['/src/**/*.ts', '/src/**/*.tsx'],
+ coverageDirectory: './src/tests/coverage',
+ coveragePathIgnorePatterns: [
+ '[/\\\\](node_modules|src/types|src/tests|src/scripts)[/\\\\]',
+ 'index.tsx',
+ '.d.ts',
+ ],
+ modulePathIgnorePatterns: ['[/\\\\](node_modules)[/\\\\]'],
+ moduleNameMapper: {
+ '^.+.(?=.*scss|sass|css|png|jpg|pdf).*': '/src/scripts/jest/css-stub.js',
+ ...pathsToModuleNameMapper(compilerOptions.paths, {
+ prefix: '/',
+ }),
+ },
+ moduleFileExtensions: [...defaults.moduleFileExtensions, 'ts', 'tsx'],
+ snapshotSerializers: ['enzyme-to-json/serializer'],
+ verbose: false,
+ projects: ['/jest.config.js'],
+ transform: {
+ '^.+\\.svg$': '/src/scripts/jest/svg-transform.js',
+ },
+ globalSetup: '/src/scripts/jest/jest-global.js',
+ coverageThreshold: {
+ global: {
+ branches: 65,
+ functions: 55,
+ lines: 85,
+ statements: 85,
+ },
+ },
+ coverageReporters: ['json-summary', 'text', 'lcov'],
+ cacheDirectory: path.join(__dirname, '.jest-cache'),
+}
diff --git a/packages/react-app-scaffolder/app/templates/hooks-external/package.json b/packages/react-app-scaffolder/app/templates/hooks-external/package.json
new file mode 100644
index 0000000000..9ea8dccb76
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/hooks-external/package.json
@@ -0,0 +1,80 @@
+{
+ "version": "0.0.1",
+ "main": "./src/index.ts",
+ "license": "MIT",
+ "private": true,
+ "scripts": {
+ "build:prod": "webpack --color --mode production --config './src/scripts/webpack-prod.js'",
+ "start:dev": "webpack-dev-server --hot --progress --color --mode development --config ./src/scripts/webpack-dev.js",
+ "lint": "concurrently \"tsc --noEmit\" \"eslint --cache --ext=ts,tsx src\"",
+ "lint:fix": "eslint --cache --ext=ts,tsx src --fix",
+ "start:prod": "serve public/dist -s -l 8080",
+ "test:ci": "cross-env TZ=UTC jest --ci --colors --coverage --silent --forceExit --detectOpenHandles --runInBand",
+ "test:dev": "cross-env TZ=UTC jest --watch --verbose"
+ },
+ "dependencies": {
+ "@reapit/cognito-auth": "2.1.7",
+ "@reapit/elements": "0.5.61",
+ "@reapit/foundations-ts-definitions": "2020-02-13",
+ "dayjs": "^1.8.19",
+ "react": "~16.12.0",
+ "react-dom": "~16.12.0",
+ "react-router": "~5.1.2",
+ "react-router-dom": "~5.1.2"
+ },
+ "devDependencies": {
+ "@babel/core": "~7.7.2",
+ "@babel/polyfill": "~7.7.0",
+ "@babel/preset-env": "~7.7.1",
+ "@testing-library/react": "~10.0.1",
+ "@testing-library/react-hooks": "~3.3.0",
+ "@types/enzyme": "~3.10.3",
+ "@types/enzyme-adapter-react-16": "~1.0.5",
+ "@types/jest": "~24.0.23",
+ "@types/node": "10.17.13",
+ "@types/react": "~16.9.0",
+ "@types/react-dom": "~16.9.0",
+ "@types/react-router": "~5.1.3",
+ "@types/react-router-dom": "~5.1.3",
+ "@typescript-eslint/eslint-plugin": "~2.23.0",
+ "@typescript-eslint/parser": "~2.23.0",
+ "autoprefixer": "~9.8.0",
+ "babel-loader": "~8.1.0",
+ "concurrently": "~5.2.0",
+ "cross-env": "~7.0.2",
+ "css-loader": "~3.6.0",
+ "enzyme": "~3.10.0",
+ "enzyme-adapter-react-16": "~1.15.1",
+ "enzyme-to-json": "~3.4.3",
+ "eslint": "~6.7.2",
+ "eslint-config-prettier": "~6.7.0",
+ "eslint-plugin-prettier": "~3.1.1",
+ "eslint-plugin-react": "~7.17.0",
+ "eslint-plugin-react-hooks": "~2.3.0",
+ "favicons-webpack-plugin": "~2.1.0",
+ "file-loader": "~3.0.1",
+ "fork-ts-checker-notifier-webpack-plugin": "~1.0.0",
+ "fork-ts-checker-webpack-plugin": "~1.3.4",
+ "hard-source-webpack-plugin": "~0.13.1",
+ "html-webpack-plugin": "~3.2.0",
+ "jest": "~25.1.0",
+ "jest-config": "~25.1.0",
+ "jest-fetch-mock": "~2.1.2",
+ "mini-css-extract-plugin": "~0.9.0",
+ "mockdate": "~3.0.2",
+ "postcss-flexbugs-fixes": "~4.2.1",
+ "postcss-loader": "~3.0.0",
+ "prettier": "~1.19.1",
+ "serve": "~11.3.2",
+ "style-loader": "~1.1.3",
+ "thread-loader": "~2.1.3",
+ "ts-jest": "~25.2.0",
+ "ts-loader": "~6.0.1",
+ "ts-paths-to-webpack-alias": "~0.3.1",
+ "typescript": "3.7.2",
+ "typescript-eslint": "~0.0.1-alpha.0",
+ "webpack": "~4.41.5",
+ "webpack-cli": "~3.3.2",
+ "webpack-dev-server": "~3.4.1"
+ }
+}
diff --git a/packages/react-app-scaffolder/app/templates/base-is-not-foundation/postcss.config.js b/packages/react-app-scaffolder/app/templates/hooks-external/postcss.config.js
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/base-is-not-foundation/postcss.config.js
rename to packages/react-app-scaffolder/app/templates/hooks-external/postcss.config.js
diff --git a/packages/react-app-scaffolder/app/templates/hooks-external/public/index.html b/packages/react-app-scaffolder/app/templates/hooks-external/public/index.html
new file mode 100644
index 0000000000..72cb6e98ef
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/hooks-external/public/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ Reapit Foundations
+
+
+ You need to enable JavaScript to run this app.
+
+
+
diff --git a/packages/react-app-scaffolder/app/templates/base/public/logo.png b/packages/react-app-scaffolder/app/templates/hooks-external/public/logo.png
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/base/public/logo.png
rename to packages/react-app-scaffolder/app/templates/hooks-external/public/logo.png
diff --git a/packages/react-app-scaffolder/app/templates/base/src/assets/images/reapit-connect.png b/packages/react-app-scaffolder/app/templates/hooks-external/src/assets/images/reapit-connect.png
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/base/src/assets/images/reapit-connect.png
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/assets/images/reapit-connect.png
diff --git a/packages/react-app-scaffolder/app/templates/base/src/assets/images/reapit-graphic.jpg b/packages/react-app-scaffolder/app/templates/hooks-external/src/assets/images/reapit-graphic.jpg
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/base/src/assets/images/reapit-graphic.jpg
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/assets/images/reapit-graphic.jpg
diff --git a/packages/react-app-scaffolder/app/templates/hooks-external/src/components/hocs/__tests__/__snapshots__/error-boundary.tsx.snap b/packages/react-app-scaffolder/app/templates/hooks-external/src/components/hocs/__tests__/__snapshots__/error-boundary.tsx.snap
new file mode 100644
index 0000000000..c971b7b33b
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/hooks-external/src/components/hocs/__tests__/__snapshots__/error-boundary.tsx.snap
@@ -0,0 +1,9 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`ErrorBoundary should match a snapshot when has an error 1`] = `
+
+ Something went wrong here, try refreshing your page.
+
+`;
+
+exports[`ErrorBoundary should match a snapshot when no error 1`] = ` `;
diff --git a/packages/react-app-scaffolder/app/templates/no-redux/src/components/hocs/__tests__/error-boundary.tsx b/packages/react-app-scaffolder/app/templates/hooks-external/src/components/hocs/__tests__/error-boundary.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/no-redux/src/components/hocs/__tests__/error-boundary.tsx
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/components/hocs/__tests__/error-boundary.tsx
diff --git a/packages/react-app-scaffolder/app/templates/no-redux/src/components/hocs/error-boundary.tsx b/packages/react-app-scaffolder/app/templates/hooks-external/src/components/hocs/error-boundary.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/no-redux/src/components/hocs/error-boundary.tsx
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/components/hocs/error-boundary.tsx
diff --git a/packages/react-app-scaffolder/app/templates/base-is-linaria/src/components/pages/__styles__/styles.ts b/packages/react-app-scaffolder/app/templates/hooks-external/src/components/pages/__styles__/styles.ts
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/base-is-linaria/src/components/pages/__styles__/styles.ts
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/components/pages/__styles__/styles.ts
diff --git a/packages/react-app-scaffolder/app/templates/hooks-external/src/components/pages/__tests__/__snapshots__/authenticated.tsx.snap b/packages/react-app-scaffolder/app/templates/hooks-external/src/components/pages/__tests__/__snapshots__/authenticated.tsx.snap
new file mode 100644
index 0000000000..6bd6fcc0cc
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/hooks-external/src/components/pages/__tests__/__snapshots__/authenticated.tsx.snap
@@ -0,0 +1,3 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Authenticated should match a snapshot 1`] = ` `;
diff --git a/packages/react-app-scaffolder/app/templates/hooks-external/src/components/pages/__tests__/__snapshots__/login.tsx.snap b/packages/react-app-scaffolder/app/templates/hooks-external/src/components/pages/__tests__/__snapshots__/login.tsx.snap
new file mode 100644
index 0000000000..0486a88694
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/hooks-external/src/components/pages/__tests__/__snapshots__/login.tsx.snap
@@ -0,0 +1,199 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Login should match a snapshot 1`] = `
+Object {
+ "asFragment": [Function],
+ "baseElement":
+
+ ,
+ "container":
,
+ "debug": [Function],
+ "findAllByAltText": [Function],
+ "findAllByDisplayValue": [Function],
+ "findAllByLabelText": [Function],
+ "findAllByPlaceholderText": [Function],
+ "findAllByRole": [Function],
+ "findAllByTestId": [Function],
+ "findAllByText": [Function],
+ "findAllByTitle": [Function],
+ "findByAltText": [Function],
+ "findByDisplayValue": [Function],
+ "findByLabelText": [Function],
+ "findByPlaceholderText": [Function],
+ "findByRole": [Function],
+ "findByTestId": [Function],
+ "findByText": [Function],
+ "findByTitle": [Function],
+ "getAllByAltText": [Function],
+ "getAllByDisplayValue": [Function],
+ "getAllByLabelText": [Function],
+ "getAllByPlaceholderText": [Function],
+ "getAllByRole": [Function],
+ "getAllByTestId": [Function],
+ "getAllByText": [Function],
+ "getAllByTitle": [Function],
+ "getByAltText": [Function],
+ "getByDisplayValue": [Function],
+ "getByLabelText": [Function],
+ "getByPlaceholderText": [Function],
+ "getByRole": [Function],
+ "getByTestId": [Function],
+ "getByText": [Function],
+ "getByTitle": [Function],
+ "queryAllByAltText": [Function],
+ "queryAllByDisplayValue": [Function],
+ "queryAllByLabelText": [Function],
+ "queryAllByPlaceholderText": [Function],
+ "queryAllByRole": [Function],
+ "queryAllByTestId": [Function],
+ "queryAllByText": [Function],
+ "queryAllByTitle": [Function],
+ "queryByAltText": [Function],
+ "queryByDisplayValue": [Function],
+ "queryByLabelText": [Function],
+ "queryByPlaceholderText": [Function],
+ "queryByRole": [Function],
+ "queryByTestId": [Function],
+ "queryByText": [Function],
+ "queryByTitle": [Function],
+ "rerender": [Function],
+ "unmount": [Function],
+}
+`;
+
+exports[`Login should match a snapshot 2`] = `
+Object {
+ "asFragment": [Function],
+ "baseElement":
+
+
+
+
+
+
+
+
+ Login
+
+
+
+
+
+
+
+
+ ,
+ "container":
+
+
+
+
+
+
+
+ Login
+
+
+
+
+
+
+
+
,
+ "debug": [Function],
+ "findAllByAltText": [Function],
+ "findAllByDisplayValue": [Function],
+ "findAllByLabelText": [Function],
+ "findAllByPlaceholderText": [Function],
+ "findAllByRole": [Function],
+ "findAllByTestId": [Function],
+ "findAllByText": [Function],
+ "findAllByTitle": [Function],
+ "findByAltText": [Function],
+ "findByDisplayValue": [Function],
+ "findByLabelText": [Function],
+ "findByPlaceholderText": [Function],
+ "findByRole": [Function],
+ "findByTestId": [Function],
+ "findByText": [Function],
+ "findByTitle": [Function],
+ "getAllByAltText": [Function],
+ "getAllByDisplayValue": [Function],
+ "getAllByLabelText": [Function],
+ "getAllByPlaceholderText": [Function],
+ "getAllByRole": [Function],
+ "getAllByTestId": [Function],
+ "getAllByText": [Function],
+ "getAllByTitle": [Function],
+ "getByAltText": [Function],
+ "getByDisplayValue": [Function],
+ "getByLabelText": [Function],
+ "getByPlaceholderText": [Function],
+ "getByRole": [Function],
+ "getByTestId": [Function],
+ "getByText": [Function],
+ "getByTitle": [Function],
+ "queryAllByAltText": [Function],
+ "queryAllByDisplayValue": [Function],
+ "queryAllByLabelText": [Function],
+ "queryAllByPlaceholderText": [Function],
+ "queryAllByRole": [Function],
+ "queryAllByTestId": [Function],
+ "queryAllByText": [Function],
+ "queryAllByTitle": [Function],
+ "queryByAltText": [Function],
+ "queryByDisplayValue": [Function],
+ "queryByLabelText": [Function],
+ "queryByPlaceholderText": [Function],
+ "queryByRole": [Function],
+ "queryByTestId": [Function],
+ "queryByText": [Function],
+ "queryByTitle": [Function],
+ "rerender": [Function],
+ "unmount": [Function],
+}
+`;
diff --git a/packages/react-app-scaffolder/app/templates/no-redux/src/components/pages/__tests__/authenticated.tsx b/packages/react-app-scaffolder/app/templates/hooks-external/src/components/pages/__tests__/authenticated.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/no-redux/src/components/pages/__tests__/authenticated.tsx
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/components/pages/__tests__/authenticated.tsx
diff --git a/packages/react-app-scaffolder/app/templates/no-redux/src/components/pages/__tests__/login.tsx b/packages/react-app-scaffolder/app/templates/hooks-external/src/components/pages/__tests__/login.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/no-redux/src/components/pages/__tests__/login.tsx
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/components/pages/__tests__/login.tsx
diff --git a/packages/react-app-scaffolder/app/templates/no-redux/src/components/pages/authenticated.tsx b/packages/react-app-scaffolder/app/templates/hooks-external/src/components/pages/authenticated.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/no-redux/src/components/pages/authenticated.tsx
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/components/pages/authenticated.tsx
diff --git a/packages/react-app-scaffolder/app/templates/no-redux/src/components/pages/login.tsx b/packages/react-app-scaffolder/app/templates/hooks-external/src/components/pages/login.tsx
similarity index 90%
rename from packages/react-app-scaffolder/app/templates/no-redux/src/components/pages/login.tsx
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/components/pages/login.tsx
index 3b40d25bd4..89ecda0ac3 100644
--- a/packages/react-app-scaffolder/app/templates/no-redux/src/components/pages/login.tsx
+++ b/packages/react-app-scaffolder/app/templates/hooks-external/src/components/pages/login.tsx
@@ -4,11 +4,9 @@ import { Redirect } from 'react-router-dom'
import Routes from '@/constants/routes'
import { Button, Level } from '@reapit/elements'
-<% if(sass){ %>
-import loginStyles from '@/styles/pages/login.scss?mod'
-<% } else { %>
+
import * as loginStyles from './__styles__/styles'
- <% } %>
+
import logoImage from '@/assets/images/reapit-graphic.jpg'
import connectImage from '@/assets/images/reapit-connect.png'
@@ -37,8 +35,6 @@ export const Login: React.FunctionComponent = () => {
- Welcome to app-name
-
Login
diff --git a/packages/react-app-scaffolder/app/templates/hooks-external/src/components/ui/__tests__/__snapshots__/menu.tsx.snap b/packages/react-app-scaffolder/app/templates/hooks-external/src/components/ui/__tests__/__snapshots__/menu.tsx.snap
new file mode 100644
index 0000000000..a80288f267
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/hooks-external/src/components/ui/__tests__/__snapshots__/menu.tsx.snap
@@ -0,0 +1,45 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Menu should match a snapshot 1`] = `
+
+`;
diff --git a/packages/react-app-scaffolder/app/templates/no-redux/src/components/ui/__tests__/menu.tsx b/packages/react-app-scaffolder/app/templates/hooks-external/src/components/ui/__tests__/menu.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/no-redux/src/components/ui/__tests__/menu.tsx
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/components/ui/__tests__/menu.tsx
diff --git a/packages/react-app-scaffolder/app/templates/no-redux/src/components/ui/menu.tsx b/packages/react-app-scaffolder/app/templates/hooks-external/src/components/ui/menu.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/no-redux/src/components/ui/menu.tsx
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/components/ui/menu.tsx
diff --git a/packages/react-app-scaffolder/app/templates/base/src/constants/api.ts b/packages/react-app-scaffolder/app/templates/hooks-external/src/constants/api.ts
similarity index 78%
rename from packages/react-app-scaffolder/app/templates/base/src/constants/api.ts
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/constants/api.ts
index b80c0a493b..5ffe5c9cb7 100644
--- a/packages/react-app-scaffolder/app/templates/base/src/constants/api.ts
+++ b/packages/react-app-scaffolder/app/templates/hooks-external/src/constants/api.ts
@@ -7,7 +7,7 @@ export const CONTACTS_HEADERS = {
export const API_VERSION = '2020-01-31'
-export const COOKIE_SESSION_KEY = `${COGNITIO_COOKIE_SESSION_KEY}-<%= name %>`
+export const COOKIE_SESSION_KEY = COGNITIO_COOKIE_SESSION_KEY
export const URLS = {
}
diff --git a/packages/react-app-scaffolder/app/templates/base/src/constants/auth.ts b/packages/react-app-scaffolder/app/templates/hooks-external/src/constants/auth.ts
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/base/src/constants/auth.ts
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/constants/auth.ts
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/constants/error-messages.ts b/packages/react-app-scaffolder/app/templates/hooks-external/src/constants/error-messages.ts
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/apollo/src/constants/error-messages.ts
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/constants/error-messages.ts
diff --git a/packages/react-app-scaffolder/app/templates/no-redux/src/constants/routes.ts b/packages/react-app-scaffolder/app/templates/hooks-external/src/constants/routes.ts
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/no-redux/src/constants/routes.ts
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/constants/routes.ts
diff --git a/packages/react-app-scaffolder/app/templates/no-redux/src/context/__mocks__/mock-context.tsx b/packages/react-app-scaffolder/app/templates/hooks-external/src/context/__mocks__/mock-context.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/no-redux/src/context/__mocks__/mock-context.tsx
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/context/__mocks__/mock-context.tsx
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/context/__tests__/__snapshots__/auth-context.test.tsx.snap b/packages/react-app-scaffolder/app/templates/hooks-external/src/context/__tests__/__snapshots__/auth-context.test.tsx.snap
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/apollo/src/context/__tests__/__snapshots__/auth-context.test.tsx.snap
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/context/__tests__/__snapshots__/auth-context.test.tsx.snap
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/context/__tests__/auth-context.test.tsx b/packages/react-app-scaffolder/app/templates/hooks-external/src/context/__tests__/auth-context.test.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/apollo/src/context/__tests__/auth-context.test.tsx
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/context/__tests__/auth-context.test.tsx
diff --git a/packages/react-app-scaffolder/app/templates/no-redux/src/context/auth-context.tsx b/packages/react-app-scaffolder/app/templates/hooks-external/src/context/auth-context.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/no-redux/src/context/auth-context.tsx
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/context/auth-context.tsx
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/context/index.tsx b/packages/react-app-scaffolder/app/templates/hooks-external/src/context/index.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/apollo/src/context/index.tsx
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/context/index.tsx
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/core/__mocks__/mock-router.tsx b/packages/react-app-scaffolder/app/templates/hooks-external/src/core/__mocks__/mock-router.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/apollo/src/core/__mocks__/mock-router.tsx
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/core/__mocks__/mock-router.tsx
diff --git a/packages/react-app-scaffolder/app/templates/no-redux/src/core/__mocks__/router.tsx b/packages/react-app-scaffolder/app/templates/hooks-external/src/core/__mocks__/router.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/no-redux/src/core/__mocks__/router.tsx
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/core/__mocks__/router.tsx
diff --git a/packages/react-app-scaffolder/app/templates/hooks-external/src/core/__tests__/__snapshots__/app.tsx.snap b/packages/react-app-scaffolder/app/templates/hooks-external/src/core/__tests__/__snapshots__/app.tsx.snap
new file mode 100644
index 0000000000..ba1842ec82
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/hooks-external/src/core/__tests__/__snapshots__/app.tsx.snap
@@ -0,0 +1,19 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`App should match a snapshot 1`] = `
+
+
+
+
+
+`;
diff --git a/packages/react-app-scaffolder/app/templates/hooks-external/src/core/__tests__/__snapshots__/private-route-wrapper.tsx.snap b/packages/react-app-scaffolder/app/templates/hooks-external/src/core/__tests__/__snapshots__/private-route-wrapper.tsx.snap
new file mode 100644
index 0000000000..8d8ddccee3
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/hooks-external/src/core/__tests__/__snapshots__/private-route-wrapper.tsx.snap
@@ -0,0 +1,359 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`PrivateRouter should match a snapshot 1`] = `
+Object {
+ "asFragment": [Function],
+ "baseElement":
+
+ ,
+ "container": ,
+ "debug": [Function],
+ "findAllByAltText": [Function],
+ "findAllByDisplayValue": [Function],
+ "findAllByLabelText": [Function],
+ "findAllByPlaceholderText": [Function],
+ "findAllByRole": [Function],
+ "findAllByTestId": [Function],
+ "findAllByText": [Function],
+ "findAllByTitle": [Function],
+ "findByAltText": [Function],
+ "findByDisplayValue": [Function],
+ "findByLabelText": [Function],
+ "findByPlaceholderText": [Function],
+ "findByRole": [Function],
+ "findByTestId": [Function],
+ "findByText": [Function],
+ "findByTitle": [Function],
+ "getAllByAltText": [Function],
+ "getAllByDisplayValue": [Function],
+ "getAllByLabelText": [Function],
+ "getAllByPlaceholderText": [Function],
+ "getAllByRole": [Function],
+ "getAllByTestId": [Function],
+ "getAllByText": [Function],
+ "getAllByTitle": [Function],
+ "getByAltText": [Function],
+ "getByDisplayValue": [Function],
+ "getByLabelText": [Function],
+ "getByPlaceholderText": [Function],
+ "getByRole": [Function],
+ "getByTestId": [Function],
+ "getByText": [Function],
+ "getByTitle": [Function],
+ "queryAllByAltText": [Function],
+ "queryAllByDisplayValue": [Function],
+ "queryAllByLabelText": [Function],
+ "queryAllByPlaceholderText": [Function],
+ "queryAllByRole": [Function],
+ "queryAllByTestId": [Function],
+ "queryAllByText": [Function],
+ "queryAllByTitle": [Function],
+ "queryByAltText": [Function],
+ "queryByDisplayValue": [Function],
+ "queryByLabelText": [Function],
+ "queryByPlaceholderText": [Function],
+ "queryByRole": [Function],
+ "queryByTestId": [Function],
+ "queryByText": [Function],
+ "queryByTitle": [Function],
+ "rerender": [Function],
+ "unmount": [Function],
+}
+`;
+
+exports[`PrivateRouter should match a snapshot 2`] = `
+Object {
+ "asFragment": [Function],
+ "baseElement":
+
+ ,
+ "container":
,
+ "debug": [Function],
+ "findAllByAltText": [Function],
+ "findAllByDisplayValue": [Function],
+ "findAllByLabelText": [Function],
+ "findAllByPlaceholderText": [Function],
+ "findAllByRole": [Function],
+ "findAllByTestId": [Function],
+ "findAllByText": [Function],
+ "findAllByTitle": [Function],
+ "findByAltText": [Function],
+ "findByDisplayValue": [Function],
+ "findByLabelText": [Function],
+ "findByPlaceholderText": [Function],
+ "findByRole": [Function],
+ "findByTestId": [Function],
+ "findByText": [Function],
+ "findByTitle": [Function],
+ "getAllByAltText": [Function],
+ "getAllByDisplayValue": [Function],
+ "getAllByLabelText": [Function],
+ "getAllByPlaceholderText": [Function],
+ "getAllByRole": [Function],
+ "getAllByTestId": [Function],
+ "getAllByText": [Function],
+ "getAllByTitle": [Function],
+ "getByAltText": [Function],
+ "getByDisplayValue": [Function],
+ "getByLabelText": [Function],
+ "getByPlaceholderText": [Function],
+ "getByRole": [Function],
+ "getByTestId": [Function],
+ "getByText": [Function],
+ "getByTitle": [Function],
+ "queryAllByAltText": [Function],
+ "queryAllByDisplayValue": [Function],
+ "queryAllByLabelText": [Function],
+ "queryAllByPlaceholderText": [Function],
+ "queryAllByRole": [Function],
+ "queryAllByTestId": [Function],
+ "queryAllByText": [Function],
+ "queryAllByTitle": [Function],
+ "queryByAltText": [Function],
+ "queryByDisplayValue": [Function],
+ "queryByLabelText": [Function],
+ "queryByPlaceholderText": [Function],
+ "queryByRole": [Function],
+ "queryByTestId": [Function],
+ "queryByText": [Function],
+ "queryByTitle": [Function],
+ "rerender": [Function],
+ "unmount": [Function],
+}
+`;
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/core/__tests__/__snapshots__/private-route.tsx.snap b/packages/react-app-scaffolder/app/templates/hooks-external/src/core/__tests__/__snapshots__/private-route.tsx.snap
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/apollo/src/core/__tests__/__snapshots__/private-route.tsx.snap
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/core/__tests__/__snapshots__/private-route.tsx.snap
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/core/__tests__/__snapshots__/router.tsx.snap b/packages/react-app-scaffolder/app/templates/hooks-external/src/core/__tests__/__snapshots__/router.tsx.snap
similarity index 56%
rename from packages/react-app-scaffolder/app/templates/apollo/src/core/__tests__/__snapshots__/router.tsx.snap
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/core/__tests__/__snapshots__/router.tsx.snap
index 9d487b1285..84a14360af 100644
--- a/packages/react-app-scaffolder/app/templates/apollo/src/core/__tests__/__snapshots__/router.tsx.snap
+++ b/packages/react-app-scaffolder/app/templates/hooks-external/src/core/__tests__/__snapshots__/router.tsx.snap
@@ -35,7 +35,6 @@ exports[`Router should match a snapshot 1`] = `
"_status": -1,
}
}
- exact={true}
path="/login"
/>
-
-
-
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/core/__tests__/app.tsx b/packages/react-app-scaffolder/app/templates/hooks-external/src/core/__tests__/app.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/apollo/src/core/__tests__/app.tsx
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/core/__tests__/app.tsx
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/core/__tests__/private-route-wrapper.tsx b/packages/react-app-scaffolder/app/templates/hooks-external/src/core/__tests__/private-route-wrapper.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/apollo/src/core/__tests__/private-route-wrapper.tsx
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/core/__tests__/private-route-wrapper.tsx
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/core/__tests__/private-route.tsx b/packages/react-app-scaffolder/app/templates/hooks-external/src/core/__tests__/private-route.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/apollo/src/core/__tests__/private-route.tsx
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/core/__tests__/private-route.tsx
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/core/__tests__/router.tsx b/packages/react-app-scaffolder/app/templates/hooks-external/src/core/__tests__/router.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/apollo/src/core/__tests__/router.tsx
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/core/__tests__/router.tsx
diff --git a/packages/react-app-scaffolder/app/templates/no-redux/src/core/app.tsx b/packages/react-app-scaffolder/app/templates/hooks-external/src/core/app.tsx
similarity index 91%
rename from packages/react-app-scaffolder/app/templates/no-redux/src/core/app.tsx
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/core/app.tsx
index dee2423f22..96e272dcc0 100644
--- a/packages/react-app-scaffolder/app/templates/no-redux/src/core/app.tsx
+++ b/packages/react-app-scaffolder/app/templates/hooks-external/src/core/app.tsx
@@ -8,11 +8,9 @@ import { injectSwitchModeToWindow } from '@reapit/elements'
injectSwitchModeToWindow()
- <% if (sass) { %>
-import '@/styles/index.scss'
-<% } else { %>
+
import '@/styles/index.css'
- <% } %>
+
const App = () => {
const { loginSession, refreshParams, getLoginSession, isFetchSession, ...rest } = useAuth()
diff --git a/packages/react-app-scaffolder/app/templates/hooks-external/src/core/index.tsx b/packages/react-app-scaffolder/app/templates/hooks-external/src/core/index.tsx
new file mode 100644
index 0000000000..134801c043
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/hooks-external/src/core/index.tsx
@@ -0,0 +1,43 @@
+import React from 'react'
+import { render } from 'react-dom'
+import { Config } from '@/types/global'
+import App from './app'
+import { getMarketplaceGlobalsByKey } from '@reapit/elements'
+import config from '../../config.json'
+
+// Init global config
+window.reapit = {
+ config: {
+ appEnv: 'local',
+ cognitoClientId: '',
+ cognitoOAuthUrl: '',
+ cognitoUserPoolId: '',
+ },
+}
+
+export const renderApp = (Component: React.ComponentType) => {
+ const rootElement = document.querySelector('#root') as Element
+ const isDesktop = getMarketplaceGlobalsByKey()
+ const html = document.querySelector('html')
+ if (isDesktop && html) {
+ html.classList.add('is-desktop')
+ }
+
+ if (rootElement) {
+ render( , rootElement)
+ }
+}
+
+const run = () => {
+ window.reapit.config = config as Config
+ renderApp(App)
+}
+
+if (module['hot']) {
+ module['hot'].accept('./app', () => {
+ const NextApp = require('./app').default
+ renderApp(NextApp)
+ })
+}
+
+run()
diff --git a/packages/react-app-scaffolder/app/templates/no-redux/src/core/private-route-wrapper.tsx b/packages/react-app-scaffolder/app/templates/hooks-external/src/core/private-route-wrapper.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/no-redux/src/core/private-route-wrapper.tsx
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/core/private-route-wrapper.tsx
diff --git a/packages/react-app-scaffolder/app/templates/no-redux/src/core/private-route.tsx b/packages/react-app-scaffolder/app/templates/hooks-external/src/core/private-route.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/no-redux/src/core/private-route.tsx
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/core/private-route.tsx
diff --git a/packages/react-app-scaffolder/app/templates/no-redux/src/core/router.tsx b/packages/react-app-scaffolder/app/templates/hooks-external/src/core/router.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/no-redux/src/core/router.tsx
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/core/router.tsx
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/hooks/__mocks__/mount-react-hook.tsx b/packages/react-app-scaffolder/app/templates/hooks-external/src/hooks/__mocks__/mount-react-hook.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/apollo/src/hooks/__mocks__/mount-react-hook.tsx
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/hooks/__mocks__/mount-react-hook.tsx
diff --git a/packages/react-app-scaffolder/app/templates/no-redux/src/hooks/__tests__/__snapshots__/use-auth.test.tsx.snap b/packages/react-app-scaffolder/app/templates/hooks-external/src/hooks/__tests__/__snapshots__/use-auth.test.tsx.snap
similarity index 92%
rename from packages/react-app-scaffolder/app/templates/no-redux/src/hooks/__tests__/__snapshots__/use-auth.test.tsx.snap
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/hooks/__tests__/__snapshots__/use-auth.test.tsx.snap
index bf04c25e0b..c23ad0cb66 100644
--- a/packages/react-app-scaffolder/app/templates/no-redux/src/hooks/__tests__/__snapshots__/use-auth.test.tsx.snap
+++ b/packages/react-app-scaffolder/app/templates/hooks-external/src/hooks/__tests__/__snapshots__/use-auth.test.tsx.snap
@@ -4,10 +4,11 @@ exports[`use-auth (pure) useAuth Hook should match snapshot 1`] = `
Object {
"componentHook": Object {
"getLoginSession": [Function],
+ "isFetchSession": false,
"loginSession": Object {
"accessToken": "123",
"accessTokenExpiry": 1583492838,
- "cognitoClientId": "ue1e0vujti1p9f133ckfkbkdh",
+ "cognitoClientId": "123",
"idToken": "123",
"idTokenExpiry": 1583492838,
"loginIdentity": Object {
@@ -27,7 +28,7 @@ Object {
"refreshParams": Object {
"accessToken": "123",
"accessTokenExpiry": 1583492838,
- "cognitoClientId": "ue1e0vujti1p9f133ckfkbkdh",
+ "cognitoClientId": "123",
"idToken": "123",
"idTokenExpiry": 1583492838,
"loginIdentity": Object {
diff --git a/packages/react-app-scaffolder/app/templates/no-redux/src/hooks/__tests__/use-auth.test.tsx b/packages/react-app-scaffolder/app/templates/hooks-external/src/hooks/__tests__/use-auth.test.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/no-redux/src/hooks/__tests__/use-auth.test.tsx
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/hooks/__tests__/use-auth.test.tsx
diff --git a/packages/react-app-scaffolder/app/templates/no-redux/src/hooks/use-auth.ts b/packages/react-app-scaffolder/app/templates/hooks-external/src/hooks/use-auth.ts
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/no-redux/src/hooks/use-auth.ts
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/hooks/use-auth.ts
diff --git a/packages/react-app-scaffolder/app/templates/base-is-not-foundation/src/scripts/constants.js b/packages/react-app-scaffolder/app/templates/hooks-external/src/scripts/constants.js
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/base-is-not-foundation/src/scripts/constants.js
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/scripts/constants.js
diff --git a/packages/react-app-scaffolder/app/templates/base-is-not-foundation/src/scripts/jest/css-stub.js b/packages/react-app-scaffolder/app/templates/hooks-external/src/scripts/jest/css-stub.js
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/base-is-not-foundation/src/scripts/jest/css-stub.js
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/scripts/jest/css-stub.js
diff --git a/packages/react-app-scaffolder/app/templates/base-is-not-foundation/src/scripts/jest/jest-global.js b/packages/react-app-scaffolder/app/templates/hooks-external/src/scripts/jest/jest-global.js
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/base-is-not-foundation/src/scripts/jest/jest-global.js
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/scripts/jest/jest-global.js
diff --git a/packages/react-app-scaffolder/app/templates/hooks-external/src/scripts/jest/jest-setup.js b/packages/react-app-scaffolder/app/templates/hooks-external/src/scripts/jest/jest-setup.js
new file mode 100644
index 0000000000..52f5176a0d
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/hooks-external/src/scripts/jest/jest-setup.js
@@ -0,0 +1,491 @@
+const Adapter = require('enzyme-adapter-react-16')
+const Enzyme = require('enzyme')
+const fetchMock = require('jest-fetch-mock')
+const MockDate = require('mockdate')
+
+Enzyme.configure({ adapter: new Adapter() })
+global.fetch = fetchMock
+
+jest.mock('linaria', () => {
+ return {
+ css: jest.fn(() => ''),
+ cx: jest.fn(() => ''),
+ }
+})
+
+/* tslint:disable */
+const createMockFuncsFromArray = (instance, names = []) => {
+ names.forEach(name => {
+ instance[name] = jest.fn().mockName(name)
+ })
+}
+
+const createGoogleMapsMock = (libraries = []) => {
+ const createMVCObject = instance => {
+ const listeners = {}
+ instance.listeners = listeners
+
+ instance.addListener = jest
+ .fn((event, fn) => {
+ listeners[event] = listeners[event] || []
+ listeners[event].push(fn)
+ return {
+ remove: () => {
+ const index = listeners[event].indexOf(fn)
+
+ if (index !== -1) {
+ listeners[event].splice(index, 1)
+ }
+ },
+ }
+ })
+ .mockName('addListener')
+
+ createMockFuncsFromArray(instance, ['bindTo', 'get', 'notify', 'set', 'setValues', 'unbind', 'unbindAll'])
+ }
+
+ const maps = {
+ Animation: {
+ BOUNCE: 1,
+ DROP: 2,
+ Lo: 3,
+ Go: 4,
+ },
+ BicyclingLayer: jest.fn().mockImplementation(function() {
+ //@ts-ignore
+ createMVCObject(this)
+ //@ts-ignore
+ createMockFuncsFromArray(this, ['setMap'])
+ }),
+ Circle: jest.fn().mockImplementation(function(opts) {
+ //@ts-ignore
+ this.opts = opts
+ //@ts-ignore
+ createMVCObject(this)
+ //@ts-ignore
+ createMockFuncsFromArray(this, [
+ 'setCenter',
+ 'setDraggable',
+ 'setEditable',
+ 'setMap',
+ 'setOptions',
+ 'setRadius',
+ 'setVisible',
+ ])
+ }),
+ ControlPosition: {
+ TOP_LEFT: 1,
+ TOP_CENTER: 2,
+ TOP: 2,
+ TOP_RIGHT: 3,
+ LEFT_CENTER: 4,
+ LEFT: 5,
+ LEFT_TOP: 5,
+ LEFT_BOTTOM: 6,
+ RIGHT: 7,
+ RIGHT_CENTER: 8,
+ RIGHT_BOTTOM: 9,
+ BOTTOM_LEFT: 10,
+ BOTTOM: 11,
+ BOTTOM_CENTER: 11,
+ BOTTOM_RIGHT: 12,
+ CENTER: 13,
+ },
+ Data: jest.fn().mockImplementation(function(options) {
+ //@ts-ignore
+ this.options = options
+ //@ts-ignore
+ createMVCObject(this)
+ //@ts-ignore
+ createMockFuncsFromArray(this, ['setControlPosition', 'setControls', 'setDrawingMode', 'setMap', 'setStyle'])
+ }),
+ DirectionsRenderer: jest.fn().mockImplementation(function(opts) {
+ //@ts-ignore
+ this.opts = opts
+ //@ts-ignore
+ createMVCObject(this)
+ //@ts-ignore
+ createMockFuncsFromArray(this, ['setDirections', 'setMap', 'setOptions', 'setPanel', 'setRouteIndex'])
+ }),
+ DirectionsService: jest.fn().mockImplementation(function(opts) {
+ //@ts-ignore
+ this.opts = opts
+ //@ts-ignore
+ createMVCObject(this)
+ //@ts-ignore
+ createMockFuncsFromArray(this, ['route'])
+ }),
+ DirectionsStatus: {
+ INVALID_REQUEST: 'INVALID_REQUEST',
+ MAX_WAYPOINTS_EXCEEDED: 'MAX_WAYPOINTS_EXCEEDED',
+ NOT_FOUND: 'NOT_FOUND',
+ OK: 'OK',
+ OVER_QUERY_LIMIT: 'OVER_QUERY_LIMIT',
+ REQUEST_DENIED: 'REQUEST_DENIED',
+ UNKNOWN_ERROR: 'UNKNOWN_ERROR',
+ ZERO_RESULTS: 'ZERO_RESULTS',
+ },
+ DirectionsTravelMode: {
+ BICYCLING: 'BICYCLING',
+ DRIVING: 'DRIVING',
+ TRANSIT: 'TRANSIT',
+ WALKING: 'WALKING',
+ },
+ DirectionsUnitSystem: {
+ IMPERIAL: 1,
+ METRIC: 0,
+ },
+ DistanceMatrixElementStatus: {
+ NOT_FOUND: 'NOT_FOUND',
+ OK: 'OK',
+ ZERO_RESULTS: 'ZERO_RESULTS',
+ },
+ DistanceMatrixService: function() {},
+ DistanceMatrixStatus: {
+ INVALID_REQUEST: 'INVALID_REQUEST',
+ MAX_DIMENSIONS_EXCEEDED: 'MAX_DIMENSIONS_EXCEEDED',
+ MAX_ELEMENTS_EXCEEDED: 'MAX_ELEMENTS_EXCEEDED',
+ OK: 'OK',
+ OVER_QUERY_LIMIT: 'OVER_QUERY_LIMIT',
+ REQUEST_DENIED: 'REQUEST_DENIED',
+ UNKNOWN_ERROR: 'UNKNOWN_ERROR',
+ },
+ ElevationService: function() {},
+ ElevationStatus: {
+ Co: 'DATA_NOT_AVAILABLE',
+ INVALID_REQUEST: 'INVALID_REQUEST',
+ OK: 'OK',
+ OVER_QUERY_LIMIT: 'OVER_QUERY_LIMIT',
+ REQUEST_DENIED: 'REQUEST_DENIED',
+ UNKNOWN_ERROR: 'UNKNOWN_ERROR',
+ },
+ FusionTablesLayer: jest.fn().mockImplementation(function(options) {
+ //@ts-ignore
+ this.options = options
+ //@ts-ignore
+ createMVCObject(this)
+ //@ts-ignore
+ createMockFuncsFromArray(this, ['setMap', 'setOptions'])
+ }),
+ Geocoder: function() {},
+ GeocoderLocationType: {
+ APPROXIMATE: 'APPROXIMATE',
+ GEOMETRIC_CENTER: 'GEOMETRIC_CENTER',
+ RANGE_INTERPOLATED: 'RANGE_INTERPOLATED',
+ ROOFTOP: 'ROOFTOP',
+ },
+ GeocoderStatus: {
+ ERROR: 'ERROR',
+ INVALID_REQUEST: 'INVALID_REQUEST',
+ OK: 'OK',
+ OVER_QUERY_LIMIT: 'OVER_QUERY_LIMIT',
+ REQUEST_DENIED: 'REQUEST_DENIED',
+ UNKNOWN_ERROR: 'UNKNOWN_ERROR',
+ ZERO_RESULTS: 'ZERO_RESULTS',
+ },
+ GroundOverlay: function() {},
+ ImageMapType: function() {},
+ InfoWindow: function(opts) {
+ //@ts-ignore
+ this.opts = opts
+ //@ts-ignore
+ createMVCObject(this)
+ //@ts-ignore
+ createMockFuncsFromArray(this, ['setContent'])
+ },
+ KmlLayer: function() {},
+ KmlLayerStatus: {
+ DOCUMENT_NOT_FOUND: 'DOCUMENT_NOT_FOUND',
+ DOCUMENT_TOO_LARGE: 'DOCUMENT_TOO_LARGE',
+ FETCH_ERROR: 'FETCH_ERROR',
+ INVALID_DOCUMENT: 'INVALID_DOCUMENT',
+ INVALID_REQUEST: 'INVALID_REQUEST',
+ LIMITS_EXCEEDED: 'LIMITS_EXECEEDED',
+ OK: 'OK',
+ TIMED_OUT: 'TIMED_OUT',
+ UNKNOWN: 'UNKNOWN',
+ },
+ //@ts-ignore
+ LatLng: function() {
+ //@ts-ignore
+ createMVCObject(this)
+ //@ts-ignore
+ createMockFuncsFromArray(this, ['setMap'])
+ },
+ LatLngBounds: function() {
+ //@ts-ignore
+ createMVCObject(this)
+ //@ts-ignore
+ createMockFuncsFromArray(this, ['getCenter', 'extend'])
+ },
+ MVCArray: function() {},
+ MVCObject: jest.fn().mockImplementation(function() {
+ //@ts-ignore
+ createMVCObject(this)
+ }),
+ Map: jest.fn().mockImplementation(function(mapDiv, opts) {
+ //@ts-ignore
+ this.mapDiv = mapDiv
+ //@ts-ignore
+ this.opts = opts
+ //@ts-ignore
+ createMVCObject(this)
+ //@ts-ignore
+ createMockFuncsFromArray(this, [
+ 'setCenter',
+ 'setClickableIcons',
+ 'setHeading',
+ 'setMapTypeId',
+ 'setOptions',
+ 'setStreetView',
+ 'setTilt',
+ 'setZoom',
+ 'fitBounds',
+ 'getBounds',
+ 'panToBounds',
+ ])
+ }),
+ MapTypeControlStyle: {
+ DEFAULT: 0,
+ DROPDOWN_MENU: 2,
+ HORIZONTAL_BAR: 1,
+ INSET: 3,
+ INSET_LARGE: 4,
+ },
+ MapTypeId: {
+ HYBRID: 'hybrid',
+ ROADMAP: 'roadmap',
+ SATELLITE: 'satellite',
+ TERRAIN: 'terrain',
+ },
+ MapTypeRegistry: function() {},
+ Marker: jest.fn().mockImplementation(function(opts) {
+ //@ts-ignore
+ this.opts = opts
+ //@ts-ignore
+ createMVCObject(this)
+ //@ts-ignore
+ createMockFuncsFromArray(this, [
+ 'setMap',
+ 'setOpacity',
+ 'setOptions',
+ 'setPosition',
+ 'setShape',
+ 'setTitle',
+ 'setVisible',
+ 'setZIndex',
+ 'getPosition',
+ ])
+ }),
+ MarkerImage: function() {},
+ MaxZoomService: function() {
+ return {
+ getMaxZoomAtLatLng: function() {},
+ }
+ },
+ MaxZoomStatus: {
+ ERROR: 'ERROR',
+ OK: 'OK',
+ },
+ NavigationControlStyle: {
+ ANDROID: 2,
+ DEFAULT: 0,
+ Mo: 4,
+ SMALL: 1,
+ ZOOM_PAN: 3,
+ ik: 5,
+ },
+ OverlayView: function() {},
+ Point: function() {},
+ Polygon: function() {},
+ Polyline: function() {},
+ Rectangle: function() {},
+ SaveWidget: function() {},
+ ScaleControlStyle: {
+ DEFAULT: 0,
+ },
+ Size: function() {},
+ StreetViewCoverageLayer: function() {},
+ StreetViewPanorama: function() {},
+ StreetViewPreference: {
+ BEST: 'best',
+ NEAREST: 'nearest',
+ },
+ StreetViewService: function() {},
+ StreetViewSource: {
+ DEFAULT: 'default',
+ OUTDOOR: 'outdoor',
+ },
+ StreetViewStatus: {
+ OK: 'OK',
+ UNKNOWN_ERROR: 'UNKNOWN_ERROR',
+ ZERO_RESULTS: 'ZERO_RESULTS',
+ },
+ StrokePosition: {
+ CENTER: 0,
+ INSIDE: 1,
+ OUTSIDE: 2,
+ },
+ StyledMapType: function() {},
+ SymbolPath: {
+ BACKWARD_CLOSED_ARROW: 3,
+ BACKWARD_OPEN_ARROW: 4,
+ CIRCLE: 0,
+ FORWARD_CLOSED_ARROW: 1,
+ FORWARD_OPEN_ARROW: 2,
+ },
+ TrafficLayer: jest.fn().mockImplementation(function(opts) {
+ //@ts-ignore
+ this.opts = opts
+ //@ts-ignore
+ createMVCObject(this)
+ //@ts-ignore
+ createMockFuncsFromArray(this, ['setMap', 'setOptions'])
+ }),
+ TrafficModel: {
+ BEST_GUESS: 'bestguess',
+ OPTIMISTIC: 'optimistic',
+ PESSIMISTIC: 'pessimistic',
+ },
+ TransitLayer: jest.fn().mockImplementation(function() {
+ //@ts-ignore
+ createMVCObject(this)
+ //@ts-ignore
+ createMockFuncsFromArray(this, ['setMap'])
+ }),
+ TransitMode: {
+ BUS: 'BUS',
+ RAIL: 'RAIL',
+ SUBWAY: 'SUBWAY',
+ TRAIN: 'TRAIN',
+ TRAM: 'TRAM',
+ },
+ TransitRoutePreference: {
+ FEWER_TRANSFERS: 'FEWER_TRANSFERS',
+ LESS_WALKING: 'LESS_WALKING',
+ },
+ TravelMode: {
+ BICYCLING: 'BICYCLING',
+ DRIVING: 'DRIVING',
+ TRANSIT: 'TRANSIT',
+ WALKING: 'WALKING',
+ },
+ UnitSystem: {
+ IMPERIAL: 1,
+ METRIC: 0,
+ },
+ ZoomControlStyle: {
+ DEFAULT: 0,
+ LARGE: 2,
+ SMALL: 1,
+ ik: 3,
+ },
+ __gjsload__: function() {},
+ event: {
+ clearInstanceListeners: jest.fn().mockName('clearInstanceListeners'),
+ addListener: jest.fn().mockName('addListener'),
+ },
+ }
+ if (libraries.includes('places')) {
+ // @ts-ignore
+ maps.places = {
+ AutocompleteService: jest.fn(() => ({
+ getPlacePredictions: jest.fn(),
+ })),
+ }
+ }
+
+ return maps
+}
+
+const mockStorage = (() => {
+ let store = {
+ __REAPIT_MARKETPLACE_GLOBALS__: null,
+ }
+ return {
+ getItem: key => {
+ return store[key]
+ },
+ setItem: (key, value) => {
+ store[key] = value.toString()
+ },
+ removeItem: key => {
+ store[key] = undefined
+ },
+ clear: () => {
+ store = {}
+ },
+ }
+})()
+
+Object.defineProperty(window, 'localStorage', {
+ value: mockStorage,
+})
+
+Object.defineProperty(document, 'execCommand', {
+ value: jest.fn(),
+})
+
+Object.defineProperty(document, 'queryCommandSupported', {
+ value: jest.fn(() => true),
+ writable: true,
+})
+window.queryCommandSupported = jest.fn()
+
+Object.defineProperty(window, 'location', {
+ value: {
+ href: '',
+ reload: jest.fn(),
+ },
+})
+
+Object.defineProperty(window, 'google', {
+ value: createGoogleMapsMock(),
+})
+
+Object.defineProperty(window, 'reapit', {
+ value: {
+ config: {
+ appEnv: 'development',
+ sentryDns: '',
+ marketplaceApiUrl: '',
+ marketplaceApiKey: '',
+ platformApiUrl: '',
+ uploadApiUrl: '',
+ swaggerUrl: '',
+ elementDocumentUrl: '',
+ cognitoClientId: '',
+ googleAnalyticsKey: '',
+ googleMapApiKey: '',
+ },
+ },
+})
+
+Object.defineProperty(window, 'getComputedStyle', {
+ value: () => ({
+ getPropertyValue: () => {
+ return ''
+ },
+ }),
+})
+
+Object.defineProperty(window, 'open', {
+ value: jest.fn(),
+})
+
+Object.defineProperty(window, 'alert', {
+ value: jest.fn(),
+})
+
+// browserMock.js
+Object.defineProperty(document, 'currentScript', {
+ value: (document.createElement('div').id = 'coordinate-0-0'),
+})
+
+global.navigator.geolocation = {
+ getCurrentPosition: jest.fn(),
+ watchPosition: jest.fn(),
+}
+
+MockDate.set(1570747191389)
+window.HTMLElement.prototype.scrollIntoView = function() {}
diff --git a/packages/react-app-scaffolder/app/templates/base-is-not-foundation/src/scripts/jest/svg-transform.js b/packages/react-app-scaffolder/app/templates/hooks-external/src/scripts/jest/svg-transform.js
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/base-is-not-foundation/src/scripts/jest/svg-transform.js
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/scripts/jest/svg-transform.js
diff --git a/packages/react-app-scaffolder/app/templates/base-is-not-foundation/src/scripts/utils.js b/packages/react-app-scaffolder/app/templates/hooks-external/src/scripts/utils.js
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/base-is-not-foundation/src/scripts/utils.js
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/scripts/utils.js
diff --git a/packages/react-app-scaffolder/app/templates/base-is-not-foundation/src/scripts/webpack-dev.js b/packages/react-app-scaffolder/app/templates/hooks-external/src/scripts/webpack-dev.js
similarity index 79%
rename from packages/react-app-scaffolder/app/templates/base-is-not-foundation/src/scripts/webpack-dev.js
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/scripts/webpack-dev.js
index 4842fb06f4..be17472a6f 100644
--- a/packages/react-app-scaffolder/app/templates/base-is-not-foundation/src/scripts/webpack-dev.js
+++ b/packages/react-app-scaffolder/app/templates/hooks-external/src/scripts/webpack-dev.js
@@ -136,59 +136,6 @@ const webpackConfig = {
test: /\.css$/,
use: ['style-loader', 'css-loader', 'postcss-loader'],
},
- {
- test: /\.(sass|scss)$/,
- oneOf: [
- {
- resourceQuery: /\?mod$/,
- use: [
- {
- loader: 'style-loader',
- },
- {
- loader: 'css-loader',
- options: {
- modules: {
- localIdentName: '[name]-[local]-[hash:base64:5]',
- },
- localsConvention: 'camelCase',
- },
- },
- 'postcss-loader',
- {
- loader: 'sass-loader',
- options: {
- sourceMap: true,
- includePaths: ['node_modules'],
- },
- },
- ],
- },
- {
- use: [
- {
- loader: 'style-loader',
- },
- {
- loader: 'css-loader',
- },
- 'postcss-loader',
- {
- loader: 'sass-loader',
- options: {
- sourceMap: true,
- includePaths: ['node_modules'],
- },
- },
- ],
- },
- ],
- },
- {
- test: /\.(graphql|gql)$/,
- exclude: /node_modules/,
- use: 'graphql-tag/loader',
- },
{
test: /\.(woff(2)?|ttf|eot|svg|png|jpg|jpeg|gif|pdf)$/,
use: {
diff --git a/packages/react-app-scaffolder/app/templates/hooks-external/src/scripts/webpack-prod.js b/packages/react-app-scaffolder/app/templates/hooks-external/src/scripts/webpack-prod.js
new file mode 100644
index 0000000000..9aafee427a
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/hooks-external/src/scripts/webpack-prod.js
@@ -0,0 +1,197 @@
+const path = require('path')
+const HtmlWebpackPlugin = require('html-webpack-plugin')
+const FaviconsWebpackPlugin = require('favicons-webpack-plugin')
+const MiniCssExtractPlugin = require('mini-css-extract-plugin')
+const ResolveTSPathsToWebpackAlias = require('ts-paths-to-webpack-alias')
+const HardSourceWebpackPlugin = require('hard-source-webpack-plugin')
+const { SourceMapDevToolPlugin, HashedModuleIdsPlugin } = require('webpack')
+const { PATHS } = require('./constants')
+const hashFiles = require('./utils')
+
+const EXCLUDE_PACKAGES = ['linaria']
+
+const generateRegexExcludePackages = () => {
+ const listPackagesString = EXCLUDE_PACKAGES.join('|')
+ return new RegExp(`node_modules/(?!(${listPackagesString})/).*`)
+}
+
+const babelLoaderOptions = {
+ presets: [
+ [
+ '@babel/preset-env',
+ {
+ useBuiltIns: 'entry',
+ corejs: '3',
+ targets: {
+ chrome: '58',
+ ie: '11',
+ },
+ },
+ ],
+ 'linaria/babel',
+ ],
+}
+
+const webpackConfig = {
+ mode: 'production',
+ bail: true,
+ context: process.cwd(),
+ entry: ['@babel/polyfill', 'core-js', 'isomorphic-fetch', 'regenerator-runtime/runtime', PATHS.entryWeb],
+ output: {
+ path: PATHS.output,
+ filename: '[name].[hash].js',
+ },
+ optimization: {
+ nodeEnv: 'production',
+ splitChunks: {
+ cacheGroups: {
+ styles: {
+ name: 'styles',
+ test: /\.css$/,
+ chunks: 'all',
+ enforce: true,
+ },
+ },
+ chunks: 'all',
+ },
+ },
+ module: {
+ rules: [
+ {
+ test: /\.js$/,
+ exclude: generateRegexExcludePackages(),
+ use: {
+ loader: 'babel-loader',
+ options: babelLoaderOptions,
+ },
+ },
+ {
+ test: /.tsx?$/,
+ exclude: generateRegexExcludePackages(),
+ use: [
+ {
+ loader: 'cache-loader',
+ options: {
+ // each package has its own .webpack-cache
+ cacheDirectory: `${PATHS.cacheWebpackDir}/cache-loader`,
+ // use yarn.lock at the root of the monorepo as hash, relative to this file
+ cacheIdentifier: hashFiles([path.join(__dirname, '../..', 'yarn.lock')]),
+ },
+ },
+ 'thread-loader',
+ {
+ loader: 'babel-loader',
+ options: babelLoaderOptions,
+ },
+ {
+ loader: 'linaria/loader',
+ options: {
+ sourceMap: process.env.NODE_ENV !== 'production',
+ },
+ },
+ { loader: 'ts-loader', options: { happyPackMode: true, transpileOnly: true } },
+ ],
+ },
+ {
+ test: /\.(css)$/,
+ use: [
+ MiniCssExtractPlugin.loader,
+ {
+ loader: 'css-loader',
+ options: {
+ importLoaders: 1,
+ },
+ },
+ 'postcss-loader',
+ ],
+ },
+ {
+ test: /\.(woff(2)?|ttf|eot|svg|png|jpg|jpeg|gif|pdf)$/,
+ use: [
+ {
+ loader: 'file-loader',
+ options: {
+ name: '[name].[ext]',
+ outputPath: '/assets',
+ },
+ },
+ ],
+ },
+ ],
+ },
+ resolve: {
+ extensions: ['.tsx', '.ts', '.js'],
+ alias: {
+ '@': `${PATHS.src}/`,
+ },
+ },
+ stats: {
+ cached: false,
+ cachedAssets: false,
+ chunks: false,
+ chunkModules: false,
+ chunkOrigins: false,
+ modules: false,
+ },
+ plugins: [
+ new ResolveTSPathsToWebpackAlias({
+ tsconfig: PATHS.tsConfig,
+ }),
+ new SourceMapDevToolPlugin({
+ filename: '[file].map',
+ }),
+ new HtmlWebpackPlugin({
+ hash: true,
+ inject: true,
+ template: PATHS.template,
+ minify: {
+ removeComments: true,
+ collapseWhitespace: true,
+ removeRedundantAttributes: true,
+ useShortDoctype: true,
+ removeEmptyAttributes: true,
+ removeStyleLinkTypeAttributes: true,
+ keepClosingSlash: true,
+ minifyJS: true,
+ minifyCSS: true,
+ minifyURLs: true,
+ },
+ }),
+ new MiniCssExtractPlugin({
+ filename: 'styles.css',
+ }),
+ new FaviconsWebpackPlugin({
+ logo: PATHS.logo,
+ emitStats: false,
+ persistentCache: true,
+ inject: true,
+ background: '#fff',
+ title: 'Reapit',
+ icons: {
+ android: true,
+ appleIcon: true,
+ appleStartup: true,
+ coast: false,
+ favicons: true,
+ firefox: true,
+ opengraph: false,
+ twitter: false,
+ yandex: false,
+ windows: false,
+ },
+ }),
+ new HashedModuleIdsPlugin(),
+ new HardSourceWebpackPlugin({
+ // each package has its own .webpack-cache
+ cacheDirectory: `${PATHS.cacheWebpackDir}/hard-source/[confighash]`,
+ environmentHash: {
+ root: path.join(__dirname, '../..'),
+ directories: [],
+ // use yarn.lock at the root of the monorepo as hash, relative to this file
+ files: ['yarn.lock'],
+ },
+ }),
+ ],
+}
+
+module.exports = webpackConfig
diff --git a/packages/react-app-scaffolder/app/templates/hooks-external/src/styles/index.css b/packages/react-app-scaffolder/app/templates/hooks-external/src/styles/index.css
new file mode 100644
index 0000000000..57180691f7
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/hooks-external/src/styles/index.css
@@ -0,0 +1,3 @@
+@import url('https://fonts.googleapis.com/css?family=Roboto&display=swap');
+
+@import "~@reapit/elements/dist/index.css"
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/types/core.ts b/packages/react-app-scaffolder/app/templates/hooks-external/src/types/core.ts
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/apollo/src/types/core.ts
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/types/core.ts
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/types/global.d.ts b/packages/react-app-scaffolder/app/templates/hooks-external/src/types/global.d.ts
similarity index 61%
rename from packages/react-app-scaffolder/app/templates/apollo/src/types/global.d.ts
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/types/global.d.ts
index b9ffb61d13..05ecceb797 100644
--- a/packages/react-app-scaffolder/app/templates/apollo/src/types/global.d.ts
+++ b/packages/react-app-scaffolder/app/templates/hooks-external/src/types/global.d.ts
@@ -1,9 +1,8 @@
+export type AppEnv = 'local' | 'development' | 'production'
+
export type Config = {
- appEnv: 'local' | 'development' | 'production'
- sentryDns: string
+ appEnv: AppEnv
cognitoClientId: string
- googleAnalyticsKey: string
- graphqlUri: string
cognitoOAuthUrl: string
cognitoUserPoolId: string
}
diff --git a/packages/react-app-scaffolder/app/templates/no-redux/src/types/index.d.ts b/packages/react-app-scaffolder/app/templates/hooks-external/src/types/index.d.ts
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/no-redux/src/types/index.d.ts
rename to packages/react-app-scaffolder/app/templates/hooks-external/src/types/index.d.ts
diff --git a/packages/react-app-scaffolder/app/templates/base-is-not-foundation/tsconfig.json b/packages/react-app-scaffolder/app/templates/hooks-external/tsconfig.json
similarity index 94%
rename from packages/react-app-scaffolder/app/templates/base-is-not-foundation/tsconfig.json
rename to packages/react-app-scaffolder/app/templates/hooks-external/tsconfig.json
index e8a6fc744d..c35f07663d 100644
--- a/packages/react-app-scaffolder/app/templates/base-is-not-foundation/tsconfig.json
+++ b/packages/react-app-scaffolder/app/templates/hooks-external/tsconfig.json
@@ -22,7 +22,9 @@
"forceConsistentCasingInFileNames": true,
"outDir": "dist",
"strict": true,
+ "skipLibCheck": true,
"target": "es2020",
+ "resolveJsonModule": true,
"typeRoots": [
"./node_modules/@types"
],
diff --git a/packages/react-app-scaffolder/app/templates/_config.json b/packages/react-app-scaffolder/app/templates/hooks-internal/config.example.json
similarity index 85%
rename from packages/react-app-scaffolder/app/templates/_config.json
rename to packages/react-app-scaffolder/app/templates/hooks-internal/config.example.json
index 692adaf253..345fab9d4b 100644
--- a/packages/react-app-scaffolder/app/templates/_config.json
+++ b/packages/react-app-scaffolder/app/templates/hooks-internal/config.example.json
@@ -1,7 +1,7 @@
{
"appEnv": "local",
"sentryDns": "",
- "cognitoClientId": "<%= clientId %>",
+ "cognitoClientId": "",
"googleAnalyticsKey": "",
"cognitoOAuthUrl": "https://dev.connect.reapit.cloud",
"cognitoUserPoolId": "eu-west-2_hbt0B7yys",
diff --git a/packages/react-app-scaffolder/app/templates/base-is-foundation/jest.config.js b/packages/react-app-scaffolder/app/templates/hooks-internal/jest.config.js
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/base-is-foundation/jest.config.js
rename to packages/react-app-scaffolder/app/templates/hooks-internal/jest.config.js
diff --git a/packages/react-app-scaffolder/app/templates/base-is-foundation/package.json b/packages/react-app-scaffolder/app/templates/hooks-internal/package.json
similarity index 82%
rename from packages/react-app-scaffolder/app/templates/base-is-foundation/package.json
rename to packages/react-app-scaffolder/app/templates/hooks-internal/package.json
index c5054de9da..f6a1390da8 100644
--- a/packages/react-app-scaffolder/app/templates/base-is-foundation/package.json
+++ b/packages/react-app-scaffolder/app/templates/hooks-internal/package.json
@@ -1,25 +1,25 @@
{
- "name": "<%= name %>",
+ "name": "app-name",
"version": "0.0.1",
- "description": "<%= description %>",
- "main": "./src/index.ts",
+ "private": true,
+ "description": "Description",
"repository": {
"type": "git",
- "url": "git+<%= repo %>"
+ "url": "git+git@github.com:reapit/app-name.git"
},
- "author": "<%= author %>",
"license": "MIT",
- "private": true,
+ "author": "Author",
+ "main": "./src/index.ts",
"scripts": {
"build:prod": "rimraf public/dist && webpack --config ../../scripts/webpack/webpack.config.prod.js",
- "start:dev": "webpack-dev-server --hot --progress --color --mode development --config ../../scripts/webpack/webpack.config.dev.js",
+ "fetch-config": "yarn config-manager fetchConfig app-name",
"lint": "concurrently \"tsc --noEmit\" \"eslint --cache --ext=ts,tsx src\"",
"lint:fix": "eslint --cache --ext=ts,tsx src --fix",
+ "start:dev": "webpack-dev-server --hot --progress --color --mode development --config ../../scripts/webpack/webpack.config.dev.js",
"start:prod": "serve public/dist -s -l 8080",
"test:ci": "cross-env TZ=UTC jest --ci --colors --coverage --silent --forceExit --detectOpenHandles --runInBand",
"test:dev": "cross-env TZ=UTC jest --watch --verbose",
- "test:update-badges": "yarn test:ci && jest-coverage-badges --input src/tests/coverage/coverage-summary.json --output src/tests/badges",
- "fetch-config": "yarn config-manager fetchConfig app-name"
+ "test:update-badges": "yarn test:ci && jest-coverage-badges --input src/tests/coverage/coverage-summary.json --output src/tests/badges"
},
"dependencies": {
"@reapit/foundations-ts-definitions": "2020-02-13"
diff --git a/packages/react-app-scaffolder/app/templates/base/public/index.html b/packages/react-app-scaffolder/app/templates/hooks-internal/public/index.html
similarity index 90%
rename from packages/react-app-scaffolder/app/templates/base/public/index.html
rename to packages/react-app-scaffolder/app/templates/hooks-internal/public/index.html
index 1f45fa1f60..e40228b119 100644
--- a/packages/react-app-scaffolder/app/templates/base/public/index.html
+++ b/packages/react-app-scaffolder/app/templates/hooks-internal/public/index.html
@@ -4,7 +4,7 @@
- <%= name %>
+ Foundations App
You need to enable JavaScript to run this app.
diff --git a/packages/react-app-scaffolder/app/templates/hooks-internal/public/logo.png b/packages/react-app-scaffolder/app/templates/hooks-internal/public/logo.png
new file mode 100644
index 0000000000..eaf5e2e1f3
Binary files /dev/null and b/packages/react-app-scaffolder/app/templates/hooks-internal/public/logo.png differ
diff --git a/packages/react-app-scaffolder/app/templates/hooks-internal/src/assets/images/reapit-connect.png b/packages/react-app-scaffolder/app/templates/hooks-internal/src/assets/images/reapit-connect.png
new file mode 100644
index 0000000000..207e7c5599
Binary files /dev/null and b/packages/react-app-scaffolder/app/templates/hooks-internal/src/assets/images/reapit-connect.png differ
diff --git a/packages/react-app-scaffolder/app/templates/hooks-internal/src/assets/images/reapit-graphic.jpg b/packages/react-app-scaffolder/app/templates/hooks-internal/src/assets/images/reapit-graphic.jpg
new file mode 100644
index 0000000000..99137577d8
Binary files /dev/null and b/packages/react-app-scaffolder/app/templates/hooks-internal/src/assets/images/reapit-graphic.jpg differ
diff --git a/packages/react-app-scaffolder/app/templates/hooks-internal/src/components/hocs/__tests__/error-boundary.tsx b/packages/react-app-scaffolder/app/templates/hooks-internal/src/components/hocs/__tests__/error-boundary.tsx
new file mode 100644
index 0000000000..064da14c56
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/hooks-internal/src/components/hocs/__tests__/error-boundary.tsx
@@ -0,0 +1,29 @@
+import * as React from 'react'
+import { shallow } from 'enzyme'
+import toJson from 'enzyme-to-json'
+import { ErrorBoundary } from '../error-boundary'
+
+const Component: React.FC = () => I am a component!
+Component.displayName = 'Component'
+
+const props = {
+ children: Component,
+}
+
+describe('ErrorBoundary', () => {
+ it('should match a snapshot when no error', () => {
+ expect(toJson(shallow( ))).toMatchSnapshot()
+ })
+
+ it('should match a snapshot when has an error', () => {
+ const component = shallow( )
+ component.setState({
+ hasFailed: true,
+ })
+ expect(toJson(component)).toMatchSnapshot()
+ })
+
+ afterEach(() => {
+ jest.restoreAllMocks()
+ })
+})
diff --git a/packages/react-app-scaffolder/app/templates/hooks-internal/src/components/hocs/error-boundary.tsx b/packages/react-app-scaffolder/app/templates/hooks-internal/src/components/hocs/error-boundary.tsx
new file mode 100644
index 0000000000..179131fd9f
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/hooks-internal/src/components/hocs/error-boundary.tsx
@@ -0,0 +1,38 @@
+import * as React from 'react'
+
+export interface ErrorState {
+ hasFailed: boolean
+}
+
+export type ErrorProps = {
+ children?: React.ReactNode
+}
+
+export class ErrorBoundary extends React.Component {
+ constructor(props: ErrorProps) {
+ super(props)
+ this.state = {
+ hasFailed: false,
+ }
+ }
+
+ static getDerivedStateFromError() {
+ return {
+ hasFailed: true,
+ }
+ }
+
+ componentDidCatch(error: Error, info: React.ErrorInfo) {
+ console.error('ERROR BOUNDARY CAUGHT', error.message, info)
+ }
+
+ render() {
+ if (this.state.hasFailed) {
+ return Something went wrong here, try refreshing your page.
+ }
+
+ return this.props.children
+ }
+}
+
+export default ErrorBoundary
diff --git a/packages/react-app-scaffolder/app/templates/base-is-sass/src/styles/pages/login.scss b/packages/react-app-scaffolder/app/templates/hooks-internal/src/components/pages/__styles__/styles.ts
similarity index 79%
rename from packages/react-app-scaffolder/app/templates/base-is-sass/src/styles/pages/login.scss
rename to packages/react-app-scaffolder/app/templates/hooks-internal/src/components/pages/__styles__/styles.ts
index 062953cea6..f1b00b614a 100644
--- a/packages/react-app-scaffolder/app/templates/base-is-sass/src/styles/pages/login.scss
+++ b/packages/react-app-scaffolder/app/templates/hooks-internal/src/components/pages/__styles__/styles.ts
@@ -1,21 +1,21 @@
-@import '../base/colors.scss';
+import { css } from 'linaria'
-.container {
+export const container = css`
min-width: 100vw;
min-height: 100vh;
display: flex;
justify-content: flex-end;
align-items: center;
flex-direction: row;
- background-color: $white;
+ background-color: #fff;
@media screen and (max-width: 900px) {
flex-direction: column-reverse;
}
-}
+`
-.wrapper {
- background-color: $white;
+export const wrapper = css`
+ background-color: #fff;
width: 33.33%;
padding: 1rem;
pointer-events: auto;
@@ -25,11 +25,12 @@
}
h1,
- p, img {
+ p,
+ img {
text-align: center;
}
- img {
+ div > img {
margin: 0 auto;
max-width: 200px;
display: block;
@@ -47,10 +48,10 @@
@media screen and (min-width: 1200px) {
padding: 0 3rem;
}
-}
+`
-.image {
- background-color: $white;
+export const image = css`
+ background-color: #fff;
width: 66.66%;
height: 100vh;
font-size: 0;
@@ -65,4 +66,4 @@
width: 100%;
height: 300px;
}
-}
+`
diff --git a/packages/react-app-scaffolder/app/templates/hooks-internal/src/components/pages/__tests__/authenticated.tsx b/packages/react-app-scaffolder/app/templates/hooks-internal/src/components/pages/__tests__/authenticated.tsx
new file mode 100644
index 0000000000..03847f835d
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/hooks-internal/src/components/pages/__tests__/authenticated.tsx
@@ -0,0 +1,20 @@
+import * as React from 'react'
+import { shallow } from 'enzyme'
+import toJson from 'enzyme-to-json'
+import Authenticated from '../authenticated'
+import { AuthContext } from '@/context'
+import { mockContext } from '@/context/__mocks__/mock-context'
+
+describe('Authenticated', () => {
+ it('should match a snapshot', () => {
+ expect(
+ toJson(
+ shallow(
+
+
+ ,
+ ),
+ ),
+ ).toMatchSnapshot()
+ })
+})
diff --git a/packages/react-app-scaffolder/app/templates/hooks-internal/src/components/pages/__tests__/login.tsx b/packages/react-app-scaffolder/app/templates/hooks-internal/src/components/pages/__tests__/login.tsx
new file mode 100644
index 0000000000..3af7b8123b
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/hooks-internal/src/components/pages/__tests__/login.tsx
@@ -0,0 +1,46 @@
+import * as React from 'react'
+import { render } from '@testing-library/react'
+import { createBrowserHistory } from 'history'
+import { AuthContext } from '@/context'
+import { mockContext } from '@/context/__mocks__/mock-context'
+import { AuthHook } from '@/hooks/use-auth'
+import * as cognito from '@reapit/cognito-auth'
+import { redirectToLoginPage, Login } from '@/components/pages/login'
+import { Router, Route } from 'react-router-dom'
+
+jest.mock('@reapit/cognito-auth', () => ({
+ redirectToLogin: jest.fn(),
+ getTokenFromQueryString: jest.fn(),
+ getSessionCookie: jest.fn(),
+}))
+
+describe('Login', () => {
+ it('should match a snapshot', () => {
+ const history = createBrowserHistory()
+ const wrapper = render(
+
+
+
+
+
+
+ ,
+ )
+ expect(wrapper).toMatchSnapshot()
+ })
+
+ it('should match a snapshot', () => {
+ const wrapper = render(
+
+
+ ,
+ )
+ expect(wrapper).toMatchSnapshot()
+ })
+
+ it('should call redirectToLogin a snapshot', () => {
+ const spy = jest.spyOn(cognito, 'redirectToLogin')
+ redirectToLoginPage()
+ expect(spy).toBeCalled()
+ })
+})
diff --git a/packages/react-app-scaffolder/app/templates/hooks-internal/src/components/pages/authenticated.tsx b/packages/react-app-scaffolder/app/templates/hooks-internal/src/components/pages/authenticated.tsx
new file mode 100644
index 0000000000..97f8d91f90
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/hooks-internal/src/components/pages/authenticated.tsx
@@ -0,0 +1,15 @@
+import * as React from 'react'
+import { H3, Section, SubTitleH5 } from '@reapit/elements'
+
+export type AuthenticatedProps = {}
+
+export const Authenticated: React.FunctionComponent = () => {
+ return (
+
+ Welcome To Reapit Foundations
+ You are now authenticated against our sandbox data
+
+ )
+}
+
+export default Authenticated
diff --git a/packages/react-app-scaffolder/app/templates/hooks-internal/src/components/pages/login.tsx b/packages/react-app-scaffolder/app/templates/hooks-internal/src/components/pages/login.tsx
new file mode 100644
index 0000000000..f531ab3c17
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/hooks-internal/src/components/pages/login.tsx
@@ -0,0 +1,50 @@
+import * as React from 'react'
+import { Redirect } from 'react-router-dom'
+
+import Routes from '@/constants/routes'
+import { Button, Level } from '@reapit/elements'
+
+import * as loginStyles from './__styles__/styles'
+
+import logoImage from '@/assets/images/reapit-graphic.jpg'
+import connectImage from '@/assets/images/reapit-connect.png'
+import { AuthContext } from '@/context'
+import { redirectToLogin } from '@reapit/cognito-auth'
+
+export const redirectToLoginPage = () => {
+ const cognitoClientId = window.reapit.config.cognitoClientId
+ redirectToLogin(cognitoClientId, `${window.location.origin}`)
+}
+
+export const Login: React.FunctionComponent = () => {
+ const loginHandler = React.useCallback(redirectToLoginPage, [])
+
+ const { wrapper, container, image } = loginStyles
+
+ const { loginSession } = React.useContext(AuthContext)
+
+ if (loginSession) {
+ return
+ }
+
+ return (
+
+
+
+
+
+
+
+ Login
+
+
+
+
+
+
+
+
+ )
+}
+
+export default Login
diff --git a/packages/react-app-scaffolder/app/templates/hooks-internal/src/components/ui/__tests__/menu.tsx b/packages/react-app-scaffolder/app/templates/hooks-internal/src/components/ui/__tests__/menu.tsx
new file mode 100644
index 0000000000..636d02aa37
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/hooks-internal/src/components/ui/__tests__/menu.tsx
@@ -0,0 +1,39 @@
+import * as React from 'react'
+import { shallow } from 'enzyme'
+import { getMockRouterProps } from '@/core/__mocks__/mock-router'
+import { AuthContext } from '@/context'
+import { mockContext } from '@/context/__mocks__/mock-context'
+import { Menu, MenuProps, generateMenuConfig, callbackAppClick } from '../menu'
+
+describe('Menu', () => {
+ it('should match a snapshot', () => {
+ const props = {
+ ...getMockRouterProps({ params: {}, search: '' }),
+ }
+ const wrapper = shallow(
+
+
+ ,
+ )
+ expect(wrapper).toMatchSnapshot()
+ })
+
+ describe('generateMenuConfig', () => {
+ it('should return config', () => {
+ const props = {
+ ...getMockRouterProps({ params: {}, search: '' }),
+ } as MenuProps
+ const logoutCallback = jest.fn()
+ const result = generateMenuConfig(logoutCallback, props.location, 'WEB')
+ expect(result).toBeDefined()
+ })
+ })
+
+ describe('callbackAppClick', () => {
+ it('should run correcly', () => {
+ window.location.href = 'dev'
+ const fn = callbackAppClick()
+ expect(fn).toEqual('https://dev.marketplace.reapit.cloud/client/installed')
+ })
+ })
+})
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/components/ui/menu.tsx b/packages/react-app-scaffolder/app/templates/hooks-internal/src/components/ui/menu.tsx
similarity index 61%
rename from packages/react-app-scaffolder/app/templates/apollo/src/components/ui/menu.tsx
rename to packages/react-app-scaffolder/app/templates/hooks-internal/src/components/ui/menu.tsx
index 0fa7f9f895..82f7a5c15a 100644
--- a/packages/react-app-scaffolder/app/templates/apollo/src/components/ui/menu.tsx
+++ b/packages/react-app-scaffolder/app/templates/hooks-internal/src/components/ui/menu.tsx
@@ -1,9 +1,10 @@
import * as React from 'react'
import { withRouter, RouteComponentProps } from 'react-router'
import { Menu as Sidebar, MenuConfig, ReapitLogo } from '@reapit/elements'
-import { LoginMode } from '@reapit/cognito-auth'
import { Location } from 'history'
import { FaSignOutAlt, FaCloud } from 'react-icons/fa'
+import { LoginMode } from '@reapit/cognito-auth'
+import { AuthContext } from '@/context'
export const generateMenuConfig = (
logoutCallback: () => void,
@@ -24,10 +25,7 @@ export const generateMenuConfig = (
title: 'Apps',
key: 'APPS',
icon: ,
- callback: () =>
- (window.location.href = window.location.href.includes('dev') || window.location.href.includes('localhost')
- ? 'https://dev.marketplace.reapit.cloud/client/installed'
- : 'https://marketplace.reapit.cloud/client/installed'),
+ callback: callbackAppClick,
type: 'PRIMARY',
},
{
@@ -41,19 +39,20 @@ export const generateMenuConfig = (
}
}
-export type DispatchProps = {
- logout: () => void
-}
+export const callbackAppClick = () =>
+ (window.location.href =
+ window.location.href.includes('dev') || window.location.href.includes('localhost')
+ ? 'https://dev.marketplace.reapit.cloud/client/installed'
+ : 'https://marketplace.reapit.cloud/client/installed')
-export type StateProps = {
- mode: LoginMode
-}
+export type MenuProps = RouteComponentProps
+
+export const Menu: React.FunctionComponent = ({ location }) => {
+ const { logout, loginSession } = React.useContext(AuthContext)
+ const mode = loginSession?.mode || 'WEB'
-export type MenuProps = DispatchProps & StateProps & RouteComponentProps & {}
+ const menuConfigs = generateMenuConfig(logout, location, mode)
-export const Menu: React.FC = ({ logout, location, mode }: MenuProps) => {
- const logoutCallback = () => logout()
- const menuConfigs = generateMenuConfig(logoutCallback, location, mode)
return
}
diff --git a/packages/react-app-scaffolder/app/templates/hooks-internal/src/constants/api.ts b/packages/react-app-scaffolder/app/templates/hooks-internal/src/constants/api.ts
new file mode 100644
index 0000000000..c737c935cb
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/hooks-internal/src/constants/api.ts
@@ -0,0 +1,12 @@
+import { StringMap } from '@/types/core'
+import { COOKIE_SESSION_KEY as COGNITIO_COOKIE_SESSION_KEY } from '@reapit/cognito-auth'
+
+export const CONTACTS_HEADERS = {
+ 'Content-Type': 'application/json',
+} as StringMap
+
+export const API_VERSION = '2020-01-31'
+
+export const COOKIE_SESSION_KEY = COGNITIO_COOKIE_SESSION_KEY
+
+export const URLS = {}
diff --git a/packages/react-app-scaffolder/app/templates/no-redux/src/constants/auth.ts b/packages/react-app-scaffolder/app/templates/hooks-internal/src/constants/auth.ts
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/no-redux/src/constants/auth.ts
rename to packages/react-app-scaffolder/app/templates/hooks-internal/src/constants/auth.ts
diff --git a/packages/react-app-scaffolder/app/templates/base/src/constants/error-messages.ts b/packages/react-app-scaffolder/app/templates/hooks-internal/src/constants/error-messages.ts
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/base/src/constants/error-messages.ts
rename to packages/react-app-scaffolder/app/templates/hooks-internal/src/constants/error-messages.ts
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/constants/routes.ts b/packages/react-app-scaffolder/app/templates/hooks-internal/src/constants/routes.ts
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/constants/routes.ts
rename to packages/react-app-scaffolder/app/templates/hooks-internal/src/constants/routes.ts
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/context/__mocks__/mock-context.tsx b/packages/react-app-scaffolder/app/templates/hooks-internal/src/context/__mocks__/mock-context.tsx
similarity index 92%
rename from packages/react-app-scaffolder/app/templates/apollo/src/context/__mocks__/mock-context.tsx
rename to packages/react-app-scaffolder/app/templates/hooks-internal/src/context/__mocks__/mock-context.tsx
index 2d737f68d2..117e7fb056 100644
--- a/packages/react-app-scaffolder/app/templates/apollo/src/context/__mocks__/mock-context.tsx
+++ b/packages/react-app-scaffolder/app/templates/hooks-internal/src/context/__mocks__/mock-context.tsx
@@ -19,9 +19,10 @@ export const mockContext = {
groups: [],
},
loginType: 'CLIENT',
- cognitoClientId: 'mockCognitoClientId',
+ cognitoClientId: '123',
refreshToken: 'mockRefreshToken',
},
+ isFetchSession: false,
logout: jest.fn(),
getLoginSession: jest.fn(),
refreshParams: null,
diff --git a/packages/react-app-scaffolder/app/templates/no-redux/src/context/__tests__/__snapshots__/auth-context.test.tsx.snap b/packages/react-app-scaffolder/app/templates/hooks-internal/src/context/__tests__/__snapshots__/auth-context.test.tsx.snap
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/no-redux/src/context/__tests__/__snapshots__/auth-context.test.tsx.snap
rename to packages/react-app-scaffolder/app/templates/hooks-internal/src/context/__tests__/__snapshots__/auth-context.test.tsx.snap
diff --git a/packages/react-app-scaffolder/app/templates/no-redux/src/context/__tests__/auth-context.test.tsx b/packages/react-app-scaffolder/app/templates/hooks-internal/src/context/__tests__/auth-context.test.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/no-redux/src/context/__tests__/auth-context.test.tsx
rename to packages/react-app-scaffolder/app/templates/hooks-internal/src/context/__tests__/auth-context.test.tsx
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/context/auth-context.tsx b/packages/react-app-scaffolder/app/templates/hooks-internal/src/context/auth-context.tsx
similarity index 76%
rename from packages/react-app-scaffolder/app/templates/apollo/src/context/auth-context.tsx
rename to packages/react-app-scaffolder/app/templates/hooks-internal/src/context/auth-context.tsx
index a7a3f5223f..26b0642902 100644
--- a/packages/react-app-scaffolder/app/templates/apollo/src/context/auth-context.tsx
+++ b/packages/react-app-scaffolder/app/templates/hooks-internal/src/context/auth-context.tsx
@@ -1,5 +1,5 @@
import React from 'react'
-import { useAuth, AuthHook } from '@/hooks/use-auth'
+import { AuthHook } from '@/hooks/use-auth'
export const AuthContext = React.createContext({} as AuthHook)
AuthContext.displayName = 'AuthContext'
diff --git a/packages/react-app-scaffolder/app/templates/no-redux/src/context/index.tsx b/packages/react-app-scaffolder/app/templates/hooks-internal/src/context/index.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/no-redux/src/context/index.tsx
rename to packages/react-app-scaffolder/app/templates/hooks-internal/src/context/index.tsx
diff --git a/packages/react-app-scaffolder/app/templates/no-redux/src/core/__mocks__/mock-router.tsx b/packages/react-app-scaffolder/app/templates/hooks-internal/src/core/__mocks__/mock-router.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/no-redux/src/core/__mocks__/mock-router.tsx
rename to packages/react-app-scaffolder/app/templates/hooks-internal/src/core/__mocks__/mock-router.tsx
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/core/__mocks__/router.tsx b/packages/react-app-scaffolder/app/templates/hooks-internal/src/core/__mocks__/router.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/core/__mocks__/router.tsx
rename to packages/react-app-scaffolder/app/templates/hooks-internal/src/core/__mocks__/router.tsx
diff --git a/packages/react-app-scaffolder/app/templates/no-redux/src/core/__tests__/app.tsx b/packages/react-app-scaffolder/app/templates/hooks-internal/src/core/__tests__/app.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/no-redux/src/core/__tests__/app.tsx
rename to packages/react-app-scaffolder/app/templates/hooks-internal/src/core/__tests__/app.tsx
diff --git a/packages/react-app-scaffolder/app/templates/no-redux/src/core/__tests__/private-route-wrapper.tsx b/packages/react-app-scaffolder/app/templates/hooks-internal/src/core/__tests__/private-route-wrapper.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/no-redux/src/core/__tests__/private-route-wrapper.tsx
rename to packages/react-app-scaffolder/app/templates/hooks-internal/src/core/__tests__/private-route-wrapper.tsx
diff --git a/packages/react-app-scaffolder/app/templates/no-redux/src/core/__tests__/private-route.tsx b/packages/react-app-scaffolder/app/templates/hooks-internal/src/core/__tests__/private-route.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/no-redux/src/core/__tests__/private-route.tsx
rename to packages/react-app-scaffolder/app/templates/hooks-internal/src/core/__tests__/private-route.tsx
diff --git a/packages/react-app-scaffolder/app/templates/no-redux/src/core/__tests__/router.tsx b/packages/react-app-scaffolder/app/templates/hooks-internal/src/core/__tests__/router.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/no-redux/src/core/__tests__/router.tsx
rename to packages/react-app-scaffolder/app/templates/hooks-internal/src/core/__tests__/router.tsx
diff --git a/packages/react-app-scaffolder/app/templates/hooks-internal/src/core/app.tsx b/packages/react-app-scaffolder/app/templates/hooks-internal/src/core/app.tsx
new file mode 100644
index 0000000000..987db1242e
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/hooks-internal/src/core/app.tsx
@@ -0,0 +1,28 @@
+import * as React from 'react'
+import Router from './router'
+import ErrorBoundary from '@/components/hocs/error-boundary'
+
+import { useAuth } from '@/hooks/use-auth'
+import { AuthContext } from '@/context'
+import { injectSwitchModeToWindow } from '@reapit/elements'
+
+injectSwitchModeToWindow()
+
+import '@/styles/index.css'
+
+const App = () => {
+ const { loginSession, refreshParams, getLoginSession, isFetchSession, ...rest } = useAuth()
+ if (!loginSession && refreshParams && !isFetchSession) {
+ getLoginSession(refreshParams)
+ }
+
+ return (
+
+
+
+
+
+ )
+}
+
+export default App
diff --git a/packages/react-app-scaffolder/app/templates/base/src/core/index.tsx b/packages/react-app-scaffolder/app/templates/hooks-internal/src/core/index.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/base/src/core/index.tsx
rename to packages/react-app-scaffolder/app/templates/hooks-internal/src/core/index.tsx
diff --git a/packages/react-app-scaffolder/app/templates/hooks-internal/src/core/private-route-wrapper.tsx b/packages/react-app-scaffolder/app/templates/hooks-internal/src/core/private-route-wrapper.tsx
new file mode 100644
index 0000000000..cc20eae5e0
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/hooks-internal/src/core/private-route-wrapper.tsx
@@ -0,0 +1,58 @@
+import * as React from 'react'
+import { Loader, Section, FlexContainerResponsive, AppNavContainer, FlexContainerBasic } from '@reapit/elements'
+import { withRouter, RouteComponentProps } from 'react-router-dom'
+import Menu from '@/components/ui/menu'
+import { redirectToOAuth } from '@reapit/cognito-auth'
+import { AuthContext } from '@/context'
+
+const { Suspense } = React
+
+export type PrivateRouteWrapperProps = RouteComponentProps & {
+ path: string
+}
+
+export const PrivateRouteWrapper: React.FunctionComponent = ({ children }) => {
+ const { loginSession, refreshParams, getLoginSession, isFetchSession } = React.useContext(AuthContext)
+
+ if (!loginSession && !refreshParams) {
+ redirectToOAuth(window.reapit.config.cognitoClientId)
+ return null
+ }
+
+ if (!loginSession && refreshParams && !isFetchSession) {
+ getLoginSession(refreshParams)
+ }
+
+ if (!loginSession) {
+ return null
+ }
+
+ if (isFetchSession) {
+ return (
+
+ )
+ }
+
+ return (
+
+
+
+
+
+
+
+ }
+ >
+ {children}
+
+
+
+
+ )
+}
+
+export default withRouter(PrivateRouteWrapper)
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/core/private-route.tsx b/packages/react-app-scaffolder/app/templates/hooks-internal/src/core/private-route.tsx
similarity index 97%
rename from packages/react-app-scaffolder/app/templates/apollo/src/core/private-route.tsx
rename to packages/react-app-scaffolder/app/templates/hooks-internal/src/core/private-route.tsx
index b97e05b820..b9b77dd07c 100644
--- a/packages/react-app-scaffolder/app/templates/apollo/src/core/private-route.tsx
+++ b/packages/react-app-scaffolder/app/templates/hooks-internal/src/core/private-route.tsx
@@ -12,6 +12,7 @@ export interface PrivateRouteProps extends PrivateRouteConnectProps {
allow: LoginType | LoginType[]
component: React.FunctionComponent
exact?: boolean
+ fetcher?: boolean
}
export const PrivateRoute = ({ component, allow, loginType = 'CLIENT', ...rest }: PrivateRouteProps & RouteProps) => {
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/core/router.tsx b/packages/react-app-scaffolder/app/templates/hooks-internal/src/core/router.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/core/router.tsx
rename to packages/react-app-scaffolder/app/templates/hooks-internal/src/core/router.tsx
diff --git a/packages/react-app-scaffolder/app/templates/no-redux/src/hooks/__mocks__/mount-react-hook.tsx b/packages/react-app-scaffolder/app/templates/hooks-internal/src/hooks/__mocks__/mount-react-hook.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/no-redux/src/hooks/__mocks__/mount-react-hook.tsx
rename to packages/react-app-scaffolder/app/templates/hooks-internal/src/hooks/__mocks__/mount-react-hook.tsx
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/hooks/__tests__/__snapshots__/use-auth.test.tsx.snap b/packages/react-app-scaffolder/app/templates/hooks-internal/src/hooks/__tests__/__snapshots__/use-auth.test.tsx.snap
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/apollo/src/hooks/__tests__/__snapshots__/use-auth.test.tsx.snap
rename to packages/react-app-scaffolder/app/templates/hooks-internal/src/hooks/__tests__/__snapshots__/use-auth.test.tsx.snap
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/hooks/__tests__/use-auth.test.tsx b/packages/react-app-scaffolder/app/templates/hooks-internal/src/hooks/__tests__/use-auth.test.tsx
similarity index 99%
rename from packages/react-app-scaffolder/app/templates/apollo/src/hooks/__tests__/use-auth.test.tsx
rename to packages/react-app-scaffolder/app/templates/hooks-internal/src/hooks/__tests__/use-auth.test.tsx
index bdefa12fd5..3f7dffa1bf 100644
--- a/packages/react-app-scaffolder/app/templates/apollo/src/hooks/__tests__/use-auth.test.tsx
+++ b/packages/react-app-scaffolder/app/templates/hooks-internal/src/hooks/__tests__/use-auth.test.tsx
@@ -4,7 +4,7 @@ import { useAuth, AuthHook } from '../use-auth'
import mountReactHook from '../__mocks__/mount-react-hook'
const refreshParams: RefreshParams = {
- cognitoClientId: '1',
+ cognitoClientId: '123',
loginType: 'CLIENT',
mode: 'WEB',
redirectUri: '1',
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/hooks/use-auth.ts b/packages/react-app-scaffolder/app/templates/hooks-internal/src/hooks/use-auth.ts
similarity index 94%
rename from packages/react-app-scaffolder/app/templates/apollo/src/hooks/use-auth.ts
rename to packages/react-app-scaffolder/app/templates/hooks-internal/src/hooks/use-auth.ts
index 004d60504a..1ecbc9e5be 100644
--- a/packages/react-app-scaffolder/app/templates/apollo/src/hooks/use-auth.ts
+++ b/packages/react-app-scaffolder/app/templates/hooks-internal/src/hooks/use-auth.ts
@@ -15,6 +15,7 @@ export type AuthHook = {
logout: () => void
getLoginSession: (refreshParams: RefreshParams | null) => Promise
refreshParams?: RefreshParams | null
+ isFetchSession: boolean
}
export const useAuth = (): AuthHook => {
@@ -22,7 +23,7 @@ export const useAuth = (): AuthHook => {
const [loginSession, setLoginSession] = React.useState(null)
const urlParams: RefreshParams | null = getTokenFromQueryString(
window.location.search,
- window.reapit.config.cognitoClientId
+ window.reapit.config.cognitoClientId,
)
const cookieParams = getSessionCookie(COOKIE_SESSION_KEY)
const refreshParams = cookieParams ? cookieParams : urlParams
@@ -51,6 +52,7 @@ export const useAuth = (): AuthHook => {
loginSession,
logout,
getLoginSession,
+ isFetchSession,
}
}
diff --git a/packages/react-app-scaffolder/app/templates/hooks-internal/src/styles/index.css b/packages/react-app-scaffolder/app/templates/hooks-internal/src/styles/index.css
new file mode 100644
index 0000000000..f1323ff4b3
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/hooks-internal/src/styles/index.css
@@ -0,0 +1,6 @@
+@import url('https://fonts.googleapis.com/css?family=Source+Code+Pro&display=swap');
+@import url('https://fonts.googleapis.com/css?family=Roboto&display=swap');
+
+
+
+
diff --git a/packages/react-app-scaffolder/app/templates/no-redux/src/types/core.ts b/packages/react-app-scaffolder/app/templates/hooks-internal/src/types/core.ts
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/no-redux/src/types/core.ts
rename to packages/react-app-scaffolder/app/templates/hooks-internal/src/types/core.ts
diff --git a/packages/react-app-scaffolder/app/templates/no-redux/src/types/global.d.ts b/packages/react-app-scaffolder/app/templates/hooks-internal/src/types/global.d.ts
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/no-redux/src/types/global.d.ts
rename to packages/react-app-scaffolder/app/templates/hooks-internal/src/types/global.d.ts
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/types/index.d.ts b/packages/react-app-scaffolder/app/templates/hooks-internal/src/types/index.d.ts
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/types/index.d.ts
rename to packages/react-app-scaffolder/app/templates/hooks-internal/src/types/index.d.ts
diff --git a/packages/react-app-scaffolder/app/templates/base-is-foundation/tsconfig.json b/packages/react-app-scaffolder/app/templates/hooks-internal/tsconfig.json
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/base-is-foundation/tsconfig.json
rename to packages/react-app-scaffolder/app/templates/hooks-internal/tsconfig.json
diff --git a/packages/react-app-scaffolder/app/templates/is-foundation-no-redux/package.json b/packages/react-app-scaffolder/app/templates/is-foundation-no-redux/package.json
deleted file mode 100644
index 575a333d24..0000000000
--- a/packages/react-app-scaffolder/app/templates/is-foundation-no-redux/package.json
+++ /dev/null
@@ -1,102 +0,0 @@
-{
- "name": "<%= name %>",
- "version": "0.0.1",
- "description": "<%= description %>",
- "main": "./src/index.ts",
- "repository": {
- "type": "git",
- "url": "git+<%= repo %>"
- },
- "author": "<%= author %>",
- "license": "MIT",
- "private": true,
- "scripts": {
- "build:prod": "webpack --color --mode production --config './src/scripts/webpack-prod.js'",
- "start:dev": "webpack-dev-server --hot --progress --color --mode development --config ./src/scripts/webpack-dev.js",
- "lint": "concurrently \"tsc --noEmit\" \"eslint --cache --ext=ts,tsx src\"",
- "lint:fix": "eslint --cache --ext=ts,tsx src --fix",
- "start:prod": "serve public/dist -s -l 8080",
- "test:ci": "cross-env TZ=UTC jest --ci --colors --coverage --silent --forceExit --detectOpenHandles --runInBand",
- "test:dev": "cross-env TZ=UTC jest --watch --verbose",
- "fetch-config": "yarn config-manager fetchConfig app-name"
- },
- "dependencies": {
- "@reapit/cognito-auth": "latest",
- "@reapit/elements": "0.5.61-alpha.1",
- "@reapit/foundations-ts-definitions": "2020-02-13",
- "@sentry/browser": "^5.11.1",
- "@testing-library/react": "^10.0.1",
- "dayjs": "latest",
- "offline-plugin": "^5.0.7",
- "react": "^16.11.0",
- "react-dom": "^16.11.0",
- "react-ga": "^2.7.0",
- "react-router": "^5.1.2",
- "react-router-dom": "^5.1.2"
- },
- "devDependencies": {
- "@babel/core": "^7.7.2",
- "@babel/polyfill": "^7.7.0",
- "@babel/preset-env": "^7.7.1",
- "@sentry/webpack-plugin": "^1.10.0",
- "@testing-library/react-hooks": "^2.0.3",
- "@types/enzyme": "^3.9.3",
- "@types/jest": "^24.0.13",
- "@types/node": "^12.0.2",
- "@types/react": "^16.8.19",
- "@types/react-dom": "^16.8.4",
- "@types/react-router": "^5.1.2",
- "@types/react-router-dom": "^5.1.2",
- "@typescript-eslint/eslint-plugin": "^2.10.0",
- "@typescript-eslint/parser": "^2.10.0",
- "babel-loader": "^8.0.6",
- "copy-webpack-plugin": "5.1.1",
- "cross-env": "^7.0.0",
- "css-loader": "^3.5.1",
- "enzyme": "^3.10.0",
- "enzyme-adapter-react-16": "^1.14.0",
- "enzyme-to-json": "^3.3.5",
- "eslint": "^6.7.2",
- "eslint-config-prettier": "^6.7.0",
- "eslint-plugin-prettier": "^3.1.1",
- "eslint-plugin-react": "^7.17.0",
- "eslint-plugin-react-hooks": "^2.3.0",
- "favicons-webpack-plugin": "^2.1.0",
- "file-loader": "^3.0.1",
- "fork-ts-checker-notifier-webpack-plugin": "^1.0.0",
- "fork-ts-checker-webpack-plugin": "^1.3.4",
- "html-webpack-plugin": "^3.2.0",
- "husky": "^2.3.0",
- "isomorphic-fetch": "^2.2.1",
- "jest": "^25.1.0",
- "jest-config": "^25.1.0",
- "jest-fetch-mock": "^2.1.2",
- "lint-staged": "^8.1.7",
- "loader-utils": "^1.2.3",
- "node-sass": "^4.12.0",
- "prettier": "^1.19.1",
- "prettier-plugin-packagejson": "^2.0.1",
- "raw-loader": "^3.1.0",
- "sass-loader": "^7.1.0",
- "serve": "^11.3.0",
- "source-map-loader": "^0.2.4",
- "style-loader": "^1.1.3",
- "ts-jest": "^25.2.0",
- "ts-loader": "^6.0.1",
- "ts-node": "^8.3.0",
- "ts-paths-to-webpack-alias": "^0.3.1",
- "typescript": "3.7.2",
- "typescript-eslint": "^0.0.1-alpha.0",
- "webpack": "^4.41.5",
- "webpack-cli": "^3.3.2",
- "webpack-dev-server": "^3.4.1",
- "mini-css-extract-plugin": "^0.9.0",
- "hard-source-webpack-plugin": "^0.13.1",
- "postcss-loader": "^3.0.0",
- "autoprefixer": "^9.8.0",
- "postcss-flexbugs-fixes": "^4.2.1",
- "thread-loader": "^2.1.3",
- "mockdate": "^3.0.2",
- "concurrently": "^5.2.0"
- }
-}
diff --git a/packages/react-app-scaffolder/app/templates/is-foundation-redux/package.json b/packages/react-app-scaffolder/app/templates/is-foundation-redux/package.json
deleted file mode 100644
index c24122d1cb..0000000000
--- a/packages/react-app-scaffolder/app/templates/is-foundation-redux/package.json
+++ /dev/null
@@ -1,106 +0,0 @@
-{
- "name": "<%= name %>",
- "version": "0.0.1",
- "description": "<%= description %>",
- "main": "./src/index.ts",
- "repository": {
- "type": "git",
- "url": "git+<%= repo %>"
- },
- "author": "<%= author %>",
- "license": "MIT",
- "private": true,
- "scripts": {
- "build:prod": "webpack --color --mode production --config './src/scripts/webpack-prod.js'",
- "start:dev": "webpack-dev-server --hot --progress --color --mode development --config ./src/scripts/webpack-dev.js",
- "lint": "concurrently \"tsc --noEmit\" \"eslint --cache --ext=ts,tsx src\"",
- "lint:fix": "eslint --cache --ext=ts,tsx src --fix",
- "start:prod": "serve public/dist -s -l 8080",
- "test:ci": "cross-env TZ=UTC jest --ci --colors --coverage --silent --forceExit --detectOpenHandles --runInBand",
- "test:dev": "cross-env TZ=UTC jest --watch --verbose",
- "fetch-config": "yarn config-manager fetchConfig app-name"
- },
- "dependencies": {
- "offline-plugin": "^5.0.7",
- "@reapit/cognito-auth": "latest",
- "@reapit/elements": "latest",
- "@reapit/foundations-ts-definitions": "2020-02-13",
- "dayjs": "latest",
- "react": "^16.11.0",
- "react-dom": "^16.11.0",
- "react-router": "^5.1.2",
- "react-router-dom": "^5.1.2",
- "@sentry/browser": "^5.11.1",
- "react-ga": "^2.7.0",
- "react-redux": "^7.1.3",
- "redux": "^4.0.4",
- "redux-saga": "^1.1.3"
- },
- "devDependencies": {
- "babel-loader": "^8.0.6",
- "@babel/core": "^7.7.2",
- "@babel/polyfill": "^7.7.0",
- "@babel/preset-env": "^7.7.1",
- "@testing-library/react-hooks": "^2.0.3",
- "@types/enzyme": "^3.9.3",
- "@types/jest": "^24.0.13",
- "@types/node": "^12.0.2",
- "@types/react": "^16.8.19",
- "@types/react-dom": "^16.8.4",
- "@types/react-router": "^5.1.2",
- "@types/react-router-dom": "^5.1.2",
- "@typescript-eslint/eslint-plugin": "^2.10.0",
- "@typescript-eslint/parser": "^2.10.0",
- "@sentry/webpack-plugin": "^1.10.0",
- "cross-env": "^7.0.0",
- "enzyme": "^3.10.0",
- "enzyme-adapter-react-16": "^1.14.0",
- "enzyme-to-json": "^3.3.5",
- "eslint": "^6.7.2",
- "eslint-config-prettier": "^6.7.0",
- "eslint-plugin-prettier": "^3.1.1",
- "eslint-plugin-react": "^7.17.0",
- "eslint-plugin-react-hooks": "^2.3.0",
- "favicons-webpack-plugin": "^2.1.0",
- "file-loader": "^3.0.1",
- "fork-ts-checker-notifier-webpack-plugin": "^1.0.0",
- "fork-ts-checker-webpack-plugin": "^1.3.4",
- "html-webpack-plugin": "^3.2.0",
- "husky": "^2.3.0",
- "isomorphic-fetch": "^2.2.1",
- "jest": "^25.1.0",
- "jest-config": "^25.1.0",
- "jest-fetch-mock": "^2.1.2",
- "lint-staged": "^8.1.7",
- "loader-utils": "^1.2.3",
- "prettier": "^1.19.1",
- "prettier-plugin-packagejson": "^2.0.1",
- "raw-loader": "^3.1.0",
- "serve": "^11.3.0",
- "source-map-loader": "^0.2.4",
- "ts-jest": "^25.2.0",
- "ts-loader": "^6.0.1",
- "ts-node": "^8.3.0",
- "ts-paths-to-webpack-alias": "^0.3.1",
- "typescript": "3.7.2",
- "typescript-eslint": "^0.0.1-alpha.0",
- "webpack": "^4.41.5",
- "webpack-cli": "^3.3.2",
- "webpack-dev-server": "^3.4.1",
- "sass-loader": "^7.1.0",
- "node-sass": "^4.12.0",
- "copy-webpack-plugin": "5.1.1",
- "style-loader": "^1.1.3",
- "css-loader": "^3.5.1",
- "@redux-saga/testing-utils": "^1.0.5",
- "@types/react-redux": "^7.0.9",
- "mini-css-extract-plugin": "^0.9.0",
- "hard-source-webpack-plugin": "^0.13.1",
- "postcss-loader": "^3.0.0",
- "autoprefixer": "^9.8.0",
- "postcss-flexbugs-fixes": "^4.2.1",
- "thread-loader": "^2.1.3",
- "mockdate": "^3.0.2",
- "concurrently": "^5.2.0"
- }
-}
diff --git a/packages/react-app-scaffolder/app/templates/redux-external/.eslintrc.js b/packages/react-app-scaffolder/app/templates/redux-external/.eslintrc.js
new file mode 100644
index 0000000000..bc51f80efb
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-external/.eslintrc.js
@@ -0,0 +1,76 @@
+module.exports = {
+ env: {
+ browser: true,
+ es6: true,
+ node: true,
+ amd: true,
+ jest: true,
+ },
+ extends: [
+ 'eslint:recommended',
+ 'plugin:react/recommended',
+ 'plugin:@typescript-eslint/eslint-recommended',
+ 'prettier',
+ 'prettier/@typescript-eslint',
+ 'prettier/react',
+ 'prettier/standard',
+ ],
+ globals: {
+ Atomics: 'readonly',
+ SharedArrayBuffer: 'readonly',
+ },
+ parser: '@typescript-eslint/parser',
+ parserOptions: {
+ ecmaFeatures: {
+ jsx: true,
+ },
+ ecmaVersion: 2018,
+ sourceType: 'module',
+ },
+ plugins: ['react', '@typescript-eslint', 'prettier', 'react-hooks'],
+ ignorePatterns: [
+ '__mocks__/',
+ 'node_modules/',
+ 'setup-tests.ts',
+ 'jest.config.js',
+ '.prettierrc.js',
+ 'react-app-scaffolder/',
+ 'marketplace-api-schema.ts',
+ 'platform-schema.ts',
+ ],
+ rules: {
+ quotes: ['error', 'single', { avoidEscape: true, allowTemplateLiterals: false }],
+ semi: ['error', 'never'],
+ 'no-unused-vars': ['error', { vars: 'all', args: 'after-used' }],
+ '@typescript-eslint/no-unused-vars': [2, { args: 'none' }],
+ 'prettier/prettier': ['error', {
+ 'endOfLine': 'auto'
+ }],
+ 'max-len': ['error', { code: 120, ignoreUrls: true }],
+ 'no-confusing-arrow': ['error', { allowParens: false }],
+ 'no-mixed-operators': [
+ 'error',
+ {
+ groups: [
+ ['&', '|', '^', '~', '<<', '>>', '>>>'],
+ ['==', '!=', '===', '!==', '>', '>=', '<', '<='],
+ ['&&', '||'],
+ ['in', 'instanceof'],
+ ],
+ },
+ ],
+ 'no-tabs': ['error', { allowIndentationTabs: true }],
+ 'no-unexpected-multiline': 'error',
+ // Disabling as conflicts with Prettier
+ indent: 0,
+ // Disabling as we are validating types with TypeScript not PropTypes
+ 'react/prop-types': 0,
+ "react-hooks/rules-of-hooks": 0,
+ "react-hooks/exhaustive-deps": 0,
+ },
+ settings: {
+ react: {
+ version: 'detect',
+ },
+ },
+}
diff --git a/packages/react-app-scaffolder/app/templates/redux-external/.gitignore b/packages/react-app-scaffolder/app/templates/redux-external/.gitignore
new file mode 100644
index 0000000000..aeb663f439
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-external/.gitignore
@@ -0,0 +1,24 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+/src/tests/coverage
+
+# misc
+.DS_Store
+reapit-config.json
+config.json
+
+# log files
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+*.log
+
+.cache/
+yarn.lock
+
+public/dist
+src/tests
+
+.jest-cache
\ No newline at end of file
diff --git a/packages/react-app-scaffolder/app/templates/redux-external/.prettierrc.js b/packages/react-app-scaffolder/app/templates/redux-external/.prettierrc.js
new file mode 100644
index 0000000000..39b61eca68
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-external/.prettierrc.js
@@ -0,0 +1,7 @@
+module.exports = {
+ semi: false,
+ trailingComma: 'all',
+ singleQuote: true,
+ printWidth: 120,
+ tabWidth: 2,
+}
diff --git a/packages/react-app-scaffolder/app/templates/redux-external/config.example.json b/packages/react-app-scaffolder/app/templates/redux-external/config.example.json
new file mode 100644
index 0000000000..98a80ad258
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-external/config.example.json
@@ -0,0 +1,7 @@
+{
+ "appEnv": "local",
+ "cognitoClientId": "",
+ "cognitoOAuthUrl": "https://dev.connect.reapit.cloud",
+ "cognitoUserPoolId": "eu-west-2_hbt0B7yys",
+ "platformApiUrl": "https://dev.platform.reapit.cloud"
+}
diff --git a/packages/react-app-scaffolder/app/templates/base-is-not-foundation/jest.config.js b/packages/react-app-scaffolder/app/templates/redux-external/jest.config.js
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/base-is-not-foundation/jest.config.js
rename to packages/react-app-scaffolder/app/templates/redux-external/jest.config.js
diff --git a/packages/react-app-scaffolder/app/templates/redux-external/package.json b/packages/react-app-scaffolder/app/templates/redux-external/package.json
new file mode 100644
index 0000000000..c1574e5caf
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-external/package.json
@@ -0,0 +1,84 @@
+{
+ "version": "0.0.1",
+ "main": "./src/index.ts",
+ "license": "MIT",
+ "private": true,
+ "scripts": {
+ "build:prod": "webpack --color --mode production --config './src/scripts/webpack-prod.js'",
+ "start:dev": "webpack-dev-server --hot --progress --color --mode development --config ./src/scripts/webpack-dev.js",
+ "lint": "concurrently \"tsc --noEmit\" \"eslint --cache --ext=ts,tsx src\"",
+ "lint:fix": "eslint --cache --ext=ts,tsx src --fix",
+ "start:prod": "serve public/dist -s -l 8080",
+ "test:ci": "cross-env TZ=UTC jest --ci --colors --coverage --silent --forceExit --detectOpenHandles --runInBand",
+ "test:dev": "cross-env TZ=UTC jest --watch --verbose"
+ },
+ "dependencies": {
+ "@reapit/cognito-auth": "2.1.7",
+ "@reapit/elements": "0.5.61",
+ "@reapit/foundations-ts-definitions": "2020-02-13",
+ "dayjs": "^1.8.19",
+ "react": "~16.12.0",
+ "react-dom": "~16.12.0",
+ "react-router": "~5.1.2",
+ "react-router-dom": "~5.1.2",
+ "react-redux": "~7.2.0",
+ "redux": "~4.0.5",
+ "redux-saga": "~1.1.3"
+ },
+ "devDependencies": {
+ "@babel/core": "~7.7.2",
+ "@babel/polyfill": "~7.7.0",
+ "@babel/preset-env": "~7.7.1",
+ "@redux-saga/testing-utils": "^1.0.5",
+ "@testing-library/react": "~10.0.1",
+ "@testing-library/react-hooks": "~3.3.0",
+ "@types/enzyme": "~3.10.3",
+ "@types/enzyme-adapter-react-16": "~1.0.5",
+ "@types/jest": "~24.0.23",
+ "@types/node": "10.17.13",
+ "@types/react": "~16.9.0",
+ "@types/react-dom": "~16.9.0",
+ "@types/react-router": "~5.1.3",
+ "@types/react-router-dom": "~5.1.3",
+ "@typescript-eslint/eslint-plugin": "~2.23.0",
+ "@typescript-eslint/parser": "~2.23.0",
+ "autoprefixer": "~9.8.0",
+ "babel-loader": "~8.1.0",
+ "concurrently": "~5.2.0",
+ "cross-env": "~7.0.2",
+ "css-loader": "~3.6.0",
+ "enzyme": "~3.10.0",
+ "enzyme-adapter-react-16": "~1.15.1",
+ "enzyme-to-json": "~3.4.3",
+ "eslint": "~6.7.2",
+ "eslint-config-prettier": "~6.7.0",
+ "eslint-plugin-prettier": "~3.1.1",
+ "eslint-plugin-react": "~7.17.0",
+ "eslint-plugin-react-hooks": "~2.3.0",
+ "favicons-webpack-plugin": "~2.1.0",
+ "file-loader": "~3.0.1",
+ "fork-ts-checker-notifier-webpack-plugin": "~1.0.0",
+ "fork-ts-checker-webpack-plugin": "~1.3.4",
+ "hard-source-webpack-plugin": "~0.13.1",
+ "html-webpack-plugin": "~3.2.0",
+ "jest": "~25.1.0",
+ "jest-config": "~25.1.0",
+ "jest-fetch-mock": "~2.1.2",
+ "mini-css-extract-plugin": "~0.9.0",
+ "mockdate": "~3.0.2",
+ "postcss-flexbugs-fixes": "~4.2.1",
+ "postcss-loader": "~3.0.0",
+ "prettier": "~1.19.1",
+ "serve": "~11.3.2",
+ "style-loader": "~1.1.3",
+ "thread-loader": "~2.1.3",
+ "ts-jest": "~25.2.0",
+ "ts-loader": "~6.0.1",
+ "ts-paths-to-webpack-alias": "~0.3.1",
+ "typescript": "3.7.2",
+ "typescript-eslint": "~0.0.1-alpha.0",
+ "webpack": "~4.41.5",
+ "webpack-cli": "~3.3.2",
+ "webpack-dev-server": "~3.4.1"
+ }
+}
diff --git a/packages/react-app-scaffolder/app/templates/redux-external/postcss.config.js b/packages/react-app-scaffolder/app/templates/redux-external/postcss.config.js
new file mode 100644
index 0000000000..ee5eb8627a
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-external/postcss.config.js
@@ -0,0 +1,3 @@
+module.exports = {
+ plugins: [require('autoprefixer'), require('postcss-flexbugs-fixes')],
+}
diff --git a/packages/react-app-scaffolder/app/templates/redux-external/public/index.html b/packages/react-app-scaffolder/app/templates/redux-external/public/index.html
new file mode 100644
index 0000000000..72cb6e98ef
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-external/public/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ Reapit Foundations
+
+
+ You need to enable JavaScript to run this app.
+
+
+
diff --git a/packages/react-app-scaffolder/app/templates/redux-external/public/logo.png b/packages/react-app-scaffolder/app/templates/redux-external/public/logo.png
new file mode 100644
index 0000000000..eaf5e2e1f3
Binary files /dev/null and b/packages/react-app-scaffolder/app/templates/redux-external/public/logo.png differ
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/actions/__tests__/auth.ts b/packages/react-app-scaffolder/app/templates/redux-external/src/actions/__tests__/auth.ts
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/actions/__tests__/auth.ts
rename to packages/react-app-scaffolder/app/templates/redux-external/src/actions/__tests__/auth.ts
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/actions/__tests__/authenticated.ts b/packages/react-app-scaffolder/app/templates/redux-external/src/actions/__tests__/authenticated.ts
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/actions/__tests__/authenticated.ts
rename to packages/react-app-scaffolder/app/templates/redux-external/src/actions/__tests__/authenticated.ts
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/actions/__tests__/error.ts b/packages/react-app-scaffolder/app/templates/redux-external/src/actions/__tests__/error.ts
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/actions/__tests__/error.ts
rename to packages/react-app-scaffolder/app/templates/redux-external/src/actions/__tests__/error.ts
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/actions/auth.ts b/packages/react-app-scaffolder/app/templates/redux-external/src/actions/auth.ts
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/actions/auth.ts
rename to packages/react-app-scaffolder/app/templates/redux-external/src/actions/auth.ts
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/actions/authenticated.ts b/packages/react-app-scaffolder/app/templates/redux-external/src/actions/authenticated.ts
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/actions/authenticated.ts
rename to packages/react-app-scaffolder/app/templates/redux-external/src/actions/authenticated.ts
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/actions/error.ts b/packages/react-app-scaffolder/app/templates/redux-external/src/actions/error.ts
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/actions/error.ts
rename to packages/react-app-scaffolder/app/templates/redux-external/src/actions/error.ts
diff --git a/packages/react-app-scaffolder/app/templates/redux-external/src/assets/images/reapit-connect.png b/packages/react-app-scaffolder/app/templates/redux-external/src/assets/images/reapit-connect.png
new file mode 100644
index 0000000000..207e7c5599
Binary files /dev/null and b/packages/react-app-scaffolder/app/templates/redux-external/src/assets/images/reapit-connect.png differ
diff --git a/packages/react-app-scaffolder/app/templates/redux-external/src/assets/images/reapit-graphic.jpg b/packages/react-app-scaffolder/app/templates/redux-external/src/assets/images/reapit-graphic.jpg
new file mode 100644
index 0000000000..99137577d8
Binary files /dev/null and b/packages/react-app-scaffolder/app/templates/redux-external/src/assets/images/reapit-graphic.jpg differ
diff --git a/packages/react-app-scaffolder/app/templates/redux-external/src/components/hocs/__tests__/__snapshots__/error-boundary.tsx.snap b/packages/react-app-scaffolder/app/templates/redux-external/src/components/hocs/__tests__/__snapshots__/error-boundary.tsx.snap
new file mode 100644
index 0000000000..c971b7b33b
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-external/src/components/hocs/__tests__/__snapshots__/error-boundary.tsx.snap
@@ -0,0 +1,9 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`ErrorBoundary should match a snapshot when has an error 1`] = `
+
+ Something went wrong here, try refreshing your page.
+
+`;
+
+exports[`ErrorBoundary should match a snapshot when no error 1`] = ` `;
diff --git a/packages/react-app-scaffolder/app/templates/redux-external/src/components/hocs/__tests__/__snapshots__/route-fetcher.tsx.snap b/packages/react-app-scaffolder/app/templates/redux-external/src/components/hocs/__tests__/__snapshots__/route-fetcher.tsx.snap
new file mode 100644
index 0000000000..aea42c8cb2
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-external/src/components/hocs/__tests__/__snapshots__/route-fetcher.tsx.snap
@@ -0,0 +1,3 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`RouteFetcher should match a snapshot 1`] = ` `;
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/components/hocs/__tests__/error-boundary.tsx b/packages/react-app-scaffolder/app/templates/redux-external/src/components/hocs/__tests__/error-boundary.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/components/hocs/__tests__/error-boundary.tsx
rename to packages/react-app-scaffolder/app/templates/redux-external/src/components/hocs/__tests__/error-boundary.tsx
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/components/hocs/__tests__/route-fetcher.tsx b/packages/react-app-scaffolder/app/templates/redux-external/src/components/hocs/__tests__/route-fetcher.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/components/hocs/__tests__/route-fetcher.tsx
rename to packages/react-app-scaffolder/app/templates/redux-external/src/components/hocs/__tests__/route-fetcher.tsx
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/components/hocs/error-boundary.tsx b/packages/react-app-scaffolder/app/templates/redux-external/src/components/hocs/error-boundary.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/components/hocs/error-boundary.tsx
rename to packages/react-app-scaffolder/app/templates/redux-external/src/components/hocs/error-boundary.tsx
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/components/hocs/route-fetcher.tsx b/packages/react-app-scaffolder/app/templates/redux-external/src/components/hocs/route-fetcher.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/components/hocs/route-fetcher.tsx
rename to packages/react-app-scaffolder/app/templates/redux-external/src/components/hocs/route-fetcher.tsx
diff --git a/packages/react-app-scaffolder/app/templates/redux-external/src/components/pages/__styles__/styles.ts b/packages/react-app-scaffolder/app/templates/redux-external/src/components/pages/__styles__/styles.ts
new file mode 100644
index 0000000000..f1b00b614a
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-external/src/components/pages/__styles__/styles.ts
@@ -0,0 +1,69 @@
+import { css } from 'linaria'
+
+export const container = css`
+ min-width: 100vw;
+ min-height: 100vh;
+ display: flex;
+ justify-content: flex-end;
+ align-items: center;
+ flex-direction: row;
+ background-color: #fff;
+
+ @media screen and (max-width: 900px) {
+ flex-direction: column-reverse;
+ }
+`
+
+export const wrapper = css`
+ background-color: #fff;
+ width: 33.33%;
+ padding: 1rem;
+ pointer-events: auto;
+
+ &.disabled {
+ pointer-events: none;
+ }
+
+ h1,
+ p,
+ img {
+ text-align: center;
+ }
+
+ div > img {
+ margin: 0 auto;
+ max-width: 200px;
+ display: block;
+ }
+
+ button {
+ margin: 0 auto;
+ max-width: 400px;
+ }
+
+ @media screen and (max-width: 900px) {
+ width: 100%;
+ }
+
+ @media screen and (min-width: 1200px) {
+ padding: 0 3rem;
+ }
+`
+
+export const image = css`
+ background-color: #fff;
+ width: 66.66%;
+ height: 100vh;
+ font-size: 0;
+
+ img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ }
+
+ @media screen and (max-width: 900px) {
+ width: 100%;
+ height: 300px;
+ }
+`
diff --git a/packages/react-app-scaffolder/app/templates/redux-external/src/components/pages/__tests__/__snapshots__/authenticated.tsx.snap b/packages/react-app-scaffolder/app/templates/redux-external/src/components/pages/__tests__/__snapshots__/authenticated.tsx.snap
new file mode 100644
index 0000000000..51209aa1bd
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-external/src/components/pages/__tests__/__snapshots__/authenticated.tsx.snap
@@ -0,0 +1,12 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Authenticated should match a snapshot 1`] = `
+
+
+ Welcome To Reapit Foundations
+
+
+ You are now authenticated against our sandbox data
+
+
+`;
diff --git a/packages/react-app-scaffolder/app/templates/redux-external/src/components/pages/__tests__/__snapshots__/login.tsx.snap b/packages/react-app-scaffolder/app/templates/redux-external/src/components/pages/__tests__/__snapshots__/login.tsx.snap
new file mode 100644
index 0000000000..dbbd7122ac
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-external/src/components/pages/__tests__/__snapshots__/login.tsx.snap
@@ -0,0 +1,44 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Login should match a snapshot 1`] = `
+
+
+
+
+
+
+
+ Login
+
+
+
+
+
+
+
+`;
+
+exports[`Login should match a snapshot when hasSession 1`] = `
+
+`;
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/components/pages/__tests__/authenticated.tsx b/packages/react-app-scaffolder/app/templates/redux-external/src/components/pages/__tests__/authenticated.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/components/pages/__tests__/authenticated.tsx
rename to packages/react-app-scaffolder/app/templates/redux-external/src/components/pages/__tests__/authenticated.tsx
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/components/pages/__tests__/login.tsx b/packages/react-app-scaffolder/app/templates/redux-external/src/components/pages/__tests__/login.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/components/pages/__tests__/login.tsx
rename to packages/react-app-scaffolder/app/templates/redux-external/src/components/pages/__tests__/login.tsx
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/components/pages/authenticated.tsx b/packages/react-app-scaffolder/app/templates/redux-external/src/components/pages/authenticated.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/components/pages/authenticated.tsx
rename to packages/react-app-scaffolder/app/templates/redux-external/src/components/pages/authenticated.tsx
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/components/pages/login.tsx b/packages/react-app-scaffolder/app/templates/redux-external/src/components/pages/login.tsx
similarity index 91%
rename from packages/react-app-scaffolder/app/templates/redux/src/components/pages/login.tsx
rename to packages/react-app-scaffolder/app/templates/redux-external/src/components/pages/login.tsx
index e132957165..bfd8a4b4f2 100644
--- a/packages/react-app-scaffolder/app/templates/redux/src/components/pages/login.tsx
+++ b/packages/react-app-scaffolder/app/templates/redux-external/src/components/pages/login.tsx
@@ -7,11 +7,9 @@ import Routes from '@/constants/routes'
import { Button, Level } from '@reapit/elements'
import connectImage from '@/assets/images/reapit-connect.png'
-<% if(sass){ %>
-import loginStyles from '@/styles/pages/login.scss?mod'
-<% } else { %>
+
import * as loginStyles from './__styles__/styles'
- <% } %>
+
import { redirectToLogin } from '@reapit/cognito-auth'
@@ -38,8 +36,6 @@ export const Login: React.FunctionComponent = (props: LoginProps) =>
- Welcome to app-name
-
Login
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/components/ui/__tests__/__snapshots__/menu.tsx.snap b/packages/react-app-scaffolder/app/templates/redux-external/src/components/ui/__tests__/__snapshots__/menu.tsx.snap
similarity index 97%
rename from packages/react-app-scaffolder/app/templates/apollo/src/components/ui/__tests__/__snapshots__/menu.tsx.snap
rename to packages/react-app-scaffolder/app/templates/redux-external/src/components/ui/__tests__/__snapshots__/menu.tsx.snap
index 3cfac0548a..cece534a0c 100644
--- a/packages/react-app-scaffolder/app/templates/apollo/src/components/ui/__tests__/__snapshots__/menu.tsx.snap
+++ b/packages/react-app-scaffolder/app/templates/redux-external/src/components/ui/__tests__/__snapshots__/menu.tsx.snap
@@ -1,7 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Menu should match a snapshot 1`] = `
- I am a router
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/core/__mocks__/store.ts b/packages/react-app-scaffolder/app/templates/redux-external/src/core/__mocks__/store.ts
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/core/__mocks__/store.ts
rename to packages/react-app-scaffolder/app/templates/redux-external/src/core/__mocks__/store.ts
diff --git a/packages/react-app-scaffolder/app/templates/redux-external/src/core/__tests__/__snapshots__/app.tsx.snap b/packages/react-app-scaffolder/app/templates/redux-external/src/core/__tests__/__snapshots__/app.tsx.snap
new file mode 100644
index 0000000000..f440d0156e
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-external/src/core/__tests__/__snapshots__/app.tsx.snap
@@ -0,0 +1,19 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`App should match a snapshot 1`] = `
+
+
+
+
+
+`;
diff --git a/packages/react-app-scaffolder/app/templates/redux-external/src/core/__tests__/__snapshots__/private-route-wrapper.tsx.snap b/packages/react-app-scaffolder/app/templates/redux-external/src/core/__tests__/__snapshots__/private-route-wrapper.tsx.snap
new file mode 100644
index 0000000000..16c1c08388
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-external/src/core/__tests__/__snapshots__/private-route-wrapper.tsx.snap
@@ -0,0 +1,3 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`PrivateRouter should match a snapshot 1`] = `""`;
diff --git a/packages/react-app-scaffolder/app/templates/redux-external/src/core/__tests__/__snapshots__/private-route.tsx.snap b/packages/react-app-scaffolder/app/templates/redux-external/src/core/__tests__/__snapshots__/private-route.tsx.snap
new file mode 100644
index 0000000000..c7befec92a
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-external/src/core/__tests__/__snapshots__/private-route.tsx.snap
@@ -0,0 +1,7 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`PrivateRouter should match a snapshot 1`] = `
+
+`;
diff --git a/packages/react-app-scaffolder/app/templates/redux-external/src/core/__tests__/__snapshots__/router.tsx.snap b/packages/react-app-scaffolder/app/templates/redux-external/src/core/__tests__/__snapshots__/router.tsx.snap
new file mode 100644
index 0000000000..3dec670e19
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-external/src/core/__tests__/__snapshots__/router.tsx.snap
@@ -0,0 +1,63 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Router should match a snapshot 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/core/__tests__/app.tsx b/packages/react-app-scaffolder/app/templates/redux-external/src/core/__tests__/app.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/core/__tests__/app.tsx
rename to packages/react-app-scaffolder/app/templates/redux-external/src/core/__tests__/app.tsx
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/core/__tests__/private-route-wrapper.tsx b/packages/react-app-scaffolder/app/templates/redux-external/src/core/__tests__/private-route-wrapper.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/core/__tests__/private-route-wrapper.tsx
rename to packages/react-app-scaffolder/app/templates/redux-external/src/core/__tests__/private-route-wrapper.tsx
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/core/__tests__/private-route.tsx b/packages/react-app-scaffolder/app/templates/redux-external/src/core/__tests__/private-route.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/core/__tests__/private-route.tsx
rename to packages/react-app-scaffolder/app/templates/redux-external/src/core/__tests__/private-route.tsx
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/core/__tests__/router.tsx b/packages/react-app-scaffolder/app/templates/redux-external/src/core/__tests__/router.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/core/__tests__/router.tsx
rename to packages/react-app-scaffolder/app/templates/redux-external/src/core/__tests__/router.tsx
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/core/__tests__/store.ts b/packages/react-app-scaffolder/app/templates/redux-external/src/core/__tests__/store.ts
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/core/__tests__/store.ts
rename to packages/react-app-scaffolder/app/templates/redux-external/src/core/__tests__/store.ts
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/core/app.tsx b/packages/react-app-scaffolder/app/templates/redux-external/src/core/app.tsx
similarity index 85%
rename from packages/react-app-scaffolder/app/templates/redux/src/core/app.tsx
rename to packages/react-app-scaffolder/app/templates/redux-external/src/core/app.tsx
index a06d23d20d..69e3783418 100644
--- a/packages/react-app-scaffolder/app/templates/redux/src/core/app.tsx
+++ b/packages/react-app-scaffolder/app/templates/redux-external/src/core/app.tsx
@@ -5,11 +5,9 @@ import ErrorBoundary from '@/components/hocs/error-boundary'
import store from './store'
import { Provider } from 'react-redux'
-<% if(sass){ %>
-import '@/styles/index.scss'
-<% } else { %>
+
import '@/styles/index.css'
- <% } %>
+
const App = () => {
return (
diff --git a/packages/react-app-scaffolder/app/templates/redux-external/src/core/index.tsx b/packages/react-app-scaffolder/app/templates/redux-external/src/core/index.tsx
new file mode 100644
index 0000000000..600ea2d9b7
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-external/src/core/index.tsx
@@ -0,0 +1,43 @@
+import React from 'react'
+import { render } from 'react-dom'
+import { Config } from '@/types/global'
+import App from './app'
+import { getMarketplaceGlobalsByKey } from '@reapit/elements'
+import config from '../../config.json'
+
+// Init global config
+window.reapit = {
+ config: {
+ appEnv: 'production',
+ cognitoClientId: '',
+ cognitoOAuthUrl: '',
+ cognitoUserPoolId: '',
+ },
+}
+
+export const renderApp = (Component: React.ComponentType) => {
+ const rootElement = document.querySelector('#root') as Element
+ const isDesktop = getMarketplaceGlobalsByKey()
+ const html = document.querySelector('html')
+ if (isDesktop && html) {
+ html.classList.add('is-desktop')
+ }
+
+ if (rootElement) {
+ render( , rootElement)
+ }
+}
+
+const run = () => {
+ window.reapit.config = config as Config
+ renderApp(App)
+}
+
+if (module['hot']) {
+ module['hot'].accept('./app', () => {
+ const NextApp = require('./app').default
+ renderApp(NextApp)
+ })
+}
+
+run()
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/core/private-route-wrapper.tsx b/packages/react-app-scaffolder/app/templates/redux-external/src/core/private-route-wrapper.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/core/private-route-wrapper.tsx
rename to packages/react-app-scaffolder/app/templates/redux-external/src/core/private-route-wrapper.tsx
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/core/private-route.tsx b/packages/react-app-scaffolder/app/templates/redux-external/src/core/private-route.tsx
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/core/private-route.tsx
rename to packages/react-app-scaffolder/app/templates/redux-external/src/core/private-route.tsx
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/core/router.tsx b/packages/react-app-scaffolder/app/templates/redux-external/src/core/router.tsx
similarity index 75%
rename from packages/react-app-scaffolder/app/templates/apollo/src/core/router.tsx
rename to packages/react-app-scaffolder/app/templates/redux-external/src/core/router.tsx
index c7e7e5fb73..75cb6d6381 100644
--- a/packages/react-app-scaffolder/app/templates/apollo/src/core/router.tsx
+++ b/packages/react-app-scaffolder/app/templates/redux-external/src/core/router.tsx
@@ -2,6 +2,8 @@ import * as React from 'react'
import { Route, Router as BrowserRouter, Switch, Redirect } from 'react-router-dom'
import { createBrowserHistory } from 'history'
import Routes from '../constants/routes'
+import PrivateRoute from './private-route'
+import PrivateRouteWrapper from './private-route-wrapper'
export const history = createBrowserHistory()
@@ -28,15 +30,18 @@ export const catchChunkError = (
}
const LoginPage = React.lazy(() => catchChunkError(() => import('../components/pages/login')))
-const HomePage = React.lazy(() => catchChunkError(() => import('../components/pages/home')))
-// const AuthenticatedPage = React.lazy(() => import('../components/pages/authenticated'))
+const AuthenticatedPage = React.lazy(() => catchChunkError(() => import('../components/pages/authenticated')))
const Router = () => (
-
+
+
+
+
+
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/core/store.ts b/packages/react-app-scaffolder/app/templates/redux-external/src/core/store.ts
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/core/store.ts
rename to packages/react-app-scaffolder/app/templates/redux-external/src/core/store.ts
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/reducers/__tests__/auth.ts b/packages/react-app-scaffolder/app/templates/redux-external/src/reducers/__tests__/auth.ts
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/reducers/__tests__/auth.ts
rename to packages/react-app-scaffolder/app/templates/redux-external/src/reducers/__tests__/auth.ts
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/reducers/__tests__/authenticated.ts b/packages/react-app-scaffolder/app/templates/redux-external/src/reducers/__tests__/authenticated.ts
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/reducers/__tests__/authenticated.ts
rename to packages/react-app-scaffolder/app/templates/redux-external/src/reducers/__tests__/authenticated.ts
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/reducers/__tests__/error.ts b/packages/react-app-scaffolder/app/templates/redux-external/src/reducers/__tests__/error.ts
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/reducers/__tests__/error.ts
rename to packages/react-app-scaffolder/app/templates/redux-external/src/reducers/__tests__/error.ts
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/reducers/auth.ts b/packages/react-app-scaffolder/app/templates/redux-external/src/reducers/auth.ts
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/reducers/auth.ts
rename to packages/react-app-scaffolder/app/templates/redux-external/src/reducers/auth.ts
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/reducers/authenticated.ts b/packages/react-app-scaffolder/app/templates/redux-external/src/reducers/authenticated.ts
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/reducers/authenticated.ts
rename to packages/react-app-scaffolder/app/templates/redux-external/src/reducers/authenticated.ts
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/reducers/error.ts b/packages/react-app-scaffolder/app/templates/redux-external/src/reducers/error.ts
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/reducers/error.ts
rename to packages/react-app-scaffolder/app/templates/redux-external/src/reducers/error.ts
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/sagas/__tests__/auth.ts b/packages/react-app-scaffolder/app/templates/redux-external/src/sagas/__tests__/auth.ts
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/sagas/__tests__/auth.ts
rename to packages/react-app-scaffolder/app/templates/redux-external/src/sagas/__tests__/auth.ts
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/sagas/__tests__/authenticated.ts b/packages/react-app-scaffolder/app/templates/redux-external/src/sagas/__tests__/authenticated.ts
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/sagas/__tests__/authenticated.ts
rename to packages/react-app-scaffolder/app/templates/redux-external/src/sagas/__tests__/authenticated.ts
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/sagas/auth.ts b/packages/react-app-scaffolder/app/templates/redux-external/src/sagas/auth.ts
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/sagas/auth.ts
rename to packages/react-app-scaffolder/app/templates/redux-external/src/sagas/auth.ts
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/sagas/authenticated.ts b/packages/react-app-scaffolder/app/templates/redux-external/src/sagas/authenticated.ts
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/sagas/authenticated.ts
rename to packages/react-app-scaffolder/app/templates/redux-external/src/sagas/authenticated.ts
diff --git a/packages/react-app-scaffolder/app/templates/redux-external/src/scripts/constants.js b/packages/react-app-scaffolder/app/templates/redux-external/src/scripts/constants.js
new file mode 100644
index 0000000000..84ff7d8748
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-external/src/scripts/constants.js
@@ -0,0 +1,15 @@
+const PATHS = {
+ src: `${process.cwd()}/src`,
+ entryWeb: `${process.cwd()}/src/core/index.tsx`,
+ template: `${process.cwd()}/public/index.html`,
+ tsConfig: `${process.cwd()}/tsconfig.json`,
+ logo: `${process.cwd()}/public/logo.png`,
+ output: `${process.cwd()}/public/dist`,
+ elementsSass: `${process.cwd()}/../elements/src/styles/**.scss`,
+ elementsIndexSass: `${process.cwd()}/../elements/src/styles/index.scss`,
+ cacheWebpackDir: `${process.cwd()}/.webpack-cache`,
+}
+
+module.exports = {
+ PATHS,
+}
diff --git a/packages/react-app-scaffolder/app/templates/redux-external/src/scripts/jest/css-stub.js b/packages/react-app-scaffolder/app/templates/redux-external/src/scripts/jest/css-stub.js
new file mode 100644
index 0000000000..b0c50903a9
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-external/src/scripts/jest/css-stub.js
@@ -0,0 +1 @@
+module.exports = ''
diff --git a/packages/react-app-scaffolder/app/templates/redux-external/src/scripts/jest/jest-global.js b/packages/react-app-scaffolder/app/templates/redux-external/src/scripts/jest/jest-global.js
new file mode 100644
index 0000000000..5c9b79e934
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-external/src/scripts/jest/jest-global.js
@@ -0,0 +1,3 @@
+module.exports = async () => {
+ process.env.TZ = 'UTC'
+}
diff --git a/packages/react-app-scaffolder/app/templates/base-is-not-foundation/src/scripts/jest/jest-setup.js b/packages/react-app-scaffolder/app/templates/redux-external/src/scripts/jest/jest-setup.js
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/base-is-not-foundation/src/scripts/jest/jest-setup.js
rename to packages/react-app-scaffolder/app/templates/redux-external/src/scripts/jest/jest-setup.js
diff --git a/packages/react-app-scaffolder/app/templates/redux-external/src/scripts/jest/svg-transform.js b/packages/react-app-scaffolder/app/templates/redux-external/src/scripts/jest/svg-transform.js
new file mode 100644
index 0000000000..2324fefdff
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-external/src/scripts/jest/svg-transform.js
@@ -0,0 +1,9 @@
+module.exports = {
+ process() {
+ return 'module.exports = {};'
+ },
+ getCacheKey() {
+ // The output is always the same.
+ return 'svgTransform'
+ },
+}
diff --git a/packages/react-app-scaffolder/app/templates/redux-external/src/scripts/utils.js b/packages/react-app-scaffolder/app/templates/redux-external/src/scripts/utils.js
new file mode 100644
index 0000000000..df3dda3754
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-external/src/scripts/utils.js
@@ -0,0 +1,15 @@
+const crypto = require('crypto')
+const fs = require('fs')
+
+function hashFile(file) {
+ const content = fs.readFileSync(file)
+ return crypto
+ .createHash('md5')
+ .update(content)
+ .digest('hex')
+}
+
+function hashFiles(filesArray) {
+ return filesArray.reduce((accumulator, file) => hashFile(file) + accumulator, '')
+}
+module.exports = hashFiles
diff --git a/packages/react-app-scaffolder/app/templates/redux-external/src/scripts/webpack-dev.js b/packages/react-app-scaffolder/app/templates/redux-external/src/scripts/webpack-dev.js
new file mode 100644
index 0000000000..be17472a6f
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-external/src/scripts/webpack-dev.js
@@ -0,0 +1,183 @@
+const path = require('path')
+const ForkTsCheckerNotifierWebpackPlugin = require('fork-ts-checker-notifier-webpack-plugin')
+const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin')
+const HtmlWebpackPlugin = require('html-webpack-plugin')
+const FaviconsWebpackPlugin = require('favicons-webpack-plugin')
+const ResolveTSPathsToWebpackAlias = require('ts-paths-to-webpack-alias')
+const { PATHS } = require('./constants')
+const hashFiles = require('./utils')
+const HardSourceWebpackPlugin = require('hard-source-webpack-plugin')
+
+const EXCLUDE_PACKAGES = ['linaria']
+
+const generateRegexExcludePackages = () => {
+ const listPackagesString = EXCLUDE_PACKAGES.join('|')
+ return new RegExp(`node_modules/(?!(${listPackagesString})/).*`)
+}
+
+const babelLoaderOptions = {
+ presets: [
+ [
+ '@babel/preset-env',
+ {
+ useBuiltIns: 'entry',
+ corejs: '3',
+ targets: {
+ chrome: '58',
+ ie: '11',
+ },
+ },
+ ],
+ 'linaria/babel',
+ ],
+}
+
+const webpackConfig = {
+ mode: 'development',
+ bail: true,
+ devtool: 'inline-source-map',
+ context: process.cwd(),
+ entry: ['@babel/polyfill', 'core-js', 'isomorphic-fetch', 'regenerator-runtime/runtime', PATHS.entryWeb],
+ output: {
+ path: PATHS.output,
+ filename: '[name].[hash].js',
+ },
+ plugins: [
+ new ResolveTSPathsToWebpackAlias({
+ tsconfig: PATHS.tsConfig,
+ }),
+ new ForkTsCheckerWebpackPlugin({
+ useTypescriptIncrementalApi: true,
+ }),
+ new ForkTsCheckerNotifierWebpackPlugin({
+ title: 'TypeScript',
+ excludeWarnings: false,
+ }),
+ new HtmlWebpackPlugin({
+ inject: true,
+ template: PATHS.template,
+ }),
+ new FaviconsWebpackPlugin({
+ logo: PATHS.logo,
+ emitStats: false,
+ persistentCache: true,
+ inject: true,
+ background: '#fff',
+ title: 'Reapit',
+ icons: {
+ android: true,
+ appleIcon: true,
+ appleStartup: true,
+ coast: false,
+ favicons: true,
+ firefox: true,
+ opengraph: false,
+ twitter: false,
+ yandex: false,
+ windows: false,
+ },
+ }),
+ new HardSourceWebpackPlugin({
+ // each package has its own .webpack-cache
+ cacheDirectory: `${PATHS.cacheWebpackDir}/hard-source/[confighash]`,
+ environmentHash: {
+ root: path.join(__dirname, '../..'),
+ directories: [],
+ // use yarn.lock at the root of the monorepo as hash, relative to this file
+ files: ['yarn.lock'],
+ },
+ }),
+ ],
+ module: {
+ rules: [
+ {
+ test: /\.js$/,
+ exclude: generateRegexExcludePackages(),
+ use: [
+ {
+ loader: 'babel-loader',
+ options: babelLoaderOptions,
+ },
+ {
+ loader: 'linaria/loader',
+ options: {
+ sourceMap: process.env.NODE_ENV !== 'production',
+ },
+ },
+ ],
+ },
+ {
+ test: /.tsx?$/,
+ exclude: generateRegexExcludePackages(),
+ use: [
+ {
+ loader: 'cache-loader',
+ options: {
+ // each package has its own .webpack-cache
+ cacheDirectory: `${PATHS.cacheWebpackDir}/cache-loader`,
+ // use yarn.lock at the root of the monorepo as hash, relative to this file
+ cacheIdentifier: hashFiles([path.join(__dirname, '../..', 'yarn.lock')]),
+ },
+ },
+ {
+ loader: 'babel-loader',
+ options: babelLoaderOptions,
+ },
+ {
+ loader: 'linaria/loader',
+ options: {
+ sourceMap: process.env.NODE_ENV !== 'production',
+ },
+ },
+ { loader: 'ts-loader', options: { happyPackMode: true, transpileOnly: true } },
+ ],
+ },
+ {
+ test: /\.css$/,
+ use: ['style-loader', 'css-loader', 'postcss-loader'],
+ },
+ {
+ test: /\.(woff(2)?|ttf|eot|svg|png|jpg|jpeg|gif|pdf)$/,
+ use: {
+ loader: 'file-loader',
+ options: {
+ name: '[name].[ext]',
+ },
+ },
+ },
+ ],
+ },
+ resolve: {
+ extensions: ['.tsx', '.ts', '.js', '.css', '.scss', '.sass'],
+ alias: {
+ '@': path.resolve(__dirname, 'src/'),
+ react: require.resolve('react'),
+ 'react-dom': require.resolve('react-dom'),
+ 'react-router': require.resolve('react-router'),
+ 'react-router-dom': require.resolve('react-router-dom'),
+ },
+ },
+ devServer: {
+ host: '0.0.0.0',
+ contentBase: [path.join(process.cwd(), 'public'), path.join(process.cwd())],
+ compress: true,
+ clientLogLevel: 'warning',
+ historyApiFallback: true,
+ stats: {
+ cached: false,
+ cachedAssets: false,
+ chunks: false,
+ chunkModules: false,
+ chunkOrigins: false,
+ modules: false,
+ },
+ },
+ optimization: {
+ nodeEnv: 'development',
+ splitChunks: {
+ chunks: 'all',
+ },
+ },
+}
+
+module.exports = webpackConfig
diff --git a/packages/react-app-scaffolder/app/templates/redux-external/src/scripts/webpack-prod.js b/packages/react-app-scaffolder/app/templates/redux-external/src/scripts/webpack-prod.js
new file mode 100644
index 0000000000..9aafee427a
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-external/src/scripts/webpack-prod.js
@@ -0,0 +1,197 @@
+const path = require('path')
+const HtmlWebpackPlugin = require('html-webpack-plugin')
+const FaviconsWebpackPlugin = require('favicons-webpack-plugin')
+const MiniCssExtractPlugin = require('mini-css-extract-plugin')
+const ResolveTSPathsToWebpackAlias = require('ts-paths-to-webpack-alias')
+const HardSourceWebpackPlugin = require('hard-source-webpack-plugin')
+const { SourceMapDevToolPlugin, HashedModuleIdsPlugin } = require('webpack')
+const { PATHS } = require('./constants')
+const hashFiles = require('./utils')
+
+const EXCLUDE_PACKAGES = ['linaria']
+
+const generateRegexExcludePackages = () => {
+ const listPackagesString = EXCLUDE_PACKAGES.join('|')
+ return new RegExp(`node_modules/(?!(${listPackagesString})/).*`)
+}
+
+const babelLoaderOptions = {
+ presets: [
+ [
+ '@babel/preset-env',
+ {
+ useBuiltIns: 'entry',
+ corejs: '3',
+ targets: {
+ chrome: '58',
+ ie: '11',
+ },
+ },
+ ],
+ 'linaria/babel',
+ ],
+}
+
+const webpackConfig = {
+ mode: 'production',
+ bail: true,
+ context: process.cwd(),
+ entry: ['@babel/polyfill', 'core-js', 'isomorphic-fetch', 'regenerator-runtime/runtime', PATHS.entryWeb],
+ output: {
+ path: PATHS.output,
+ filename: '[name].[hash].js',
+ },
+ optimization: {
+ nodeEnv: 'production',
+ splitChunks: {
+ cacheGroups: {
+ styles: {
+ name: 'styles',
+ test: /\.css$/,
+ chunks: 'all',
+ enforce: true,
+ },
+ },
+ chunks: 'all',
+ },
+ },
+ module: {
+ rules: [
+ {
+ test: /\.js$/,
+ exclude: generateRegexExcludePackages(),
+ use: {
+ loader: 'babel-loader',
+ options: babelLoaderOptions,
+ },
+ },
+ {
+ test: /.tsx?$/,
+ exclude: generateRegexExcludePackages(),
+ use: [
+ {
+ loader: 'cache-loader',
+ options: {
+ // each package has its own .webpack-cache
+ cacheDirectory: `${PATHS.cacheWebpackDir}/cache-loader`,
+ // use yarn.lock at the root of the monorepo as hash, relative to this file
+ cacheIdentifier: hashFiles([path.join(__dirname, '../..', 'yarn.lock')]),
+ },
+ },
+ 'thread-loader',
+ {
+ loader: 'babel-loader',
+ options: babelLoaderOptions,
+ },
+ {
+ loader: 'linaria/loader',
+ options: {
+ sourceMap: process.env.NODE_ENV !== 'production',
+ },
+ },
+ { loader: 'ts-loader', options: { happyPackMode: true, transpileOnly: true } },
+ ],
+ },
+ {
+ test: /\.(css)$/,
+ use: [
+ MiniCssExtractPlugin.loader,
+ {
+ loader: 'css-loader',
+ options: {
+ importLoaders: 1,
+ },
+ },
+ 'postcss-loader',
+ ],
+ },
+ {
+ test: /\.(woff(2)?|ttf|eot|svg|png|jpg|jpeg|gif|pdf)$/,
+ use: [
+ {
+ loader: 'file-loader',
+ options: {
+ name: '[name].[ext]',
+ outputPath: '/assets',
+ },
+ },
+ ],
+ },
+ ],
+ },
+ resolve: {
+ extensions: ['.tsx', '.ts', '.js'],
+ alias: {
+ '@': `${PATHS.src}/`,
+ },
+ },
+ stats: {
+ cached: false,
+ cachedAssets: false,
+ chunks: false,
+ chunkModules: false,
+ chunkOrigins: false,
+ modules: false,
+ },
+ plugins: [
+ new ResolveTSPathsToWebpackAlias({
+ tsconfig: PATHS.tsConfig,
+ }),
+ new SourceMapDevToolPlugin({
+ filename: '[file].map',
+ }),
+ new HtmlWebpackPlugin({
+ hash: true,
+ inject: true,
+ template: PATHS.template,
+ minify: {
+ removeComments: true,
+ collapseWhitespace: true,
+ removeRedundantAttributes: true,
+ useShortDoctype: true,
+ removeEmptyAttributes: true,
+ removeStyleLinkTypeAttributes: true,
+ keepClosingSlash: true,
+ minifyJS: true,
+ minifyCSS: true,
+ minifyURLs: true,
+ },
+ }),
+ new MiniCssExtractPlugin({
+ filename: 'styles.css',
+ }),
+ new FaviconsWebpackPlugin({
+ logo: PATHS.logo,
+ emitStats: false,
+ persistentCache: true,
+ inject: true,
+ background: '#fff',
+ title: 'Reapit',
+ icons: {
+ android: true,
+ appleIcon: true,
+ appleStartup: true,
+ coast: false,
+ favicons: true,
+ firefox: true,
+ opengraph: false,
+ twitter: false,
+ yandex: false,
+ windows: false,
+ },
+ }),
+ new HashedModuleIdsPlugin(),
+ new HardSourceWebpackPlugin({
+ // each package has its own .webpack-cache
+ cacheDirectory: `${PATHS.cacheWebpackDir}/hard-source/[confighash]`,
+ environmentHash: {
+ root: path.join(__dirname, '../..'),
+ directories: [],
+ // use yarn.lock at the root of the monorepo as hash, relative to this file
+ files: ['yarn.lock'],
+ },
+ }),
+ ],
+}
+
+module.exports = webpackConfig
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/selectors/auth.ts b/packages/react-app-scaffolder/app/templates/redux-external/src/selectors/auth.ts
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/selectors/auth.ts
rename to packages/react-app-scaffolder/app/templates/redux-external/src/selectors/auth.ts
diff --git a/packages/react-app-scaffolder/app/templates/redux-external/src/styles/index.css b/packages/react-app-scaffolder/app/templates/redux-external/src/styles/index.css
new file mode 100644
index 0000000000..4b0394d8a2
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-external/src/styles/index.css
@@ -0,0 +1,4 @@
+@import url('https://fonts.googleapis.com/css?family=Roboto&display=swap');
+@import "~@reapit/elements/dist/index.css";
+
+
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/types/core.ts b/packages/react-app-scaffolder/app/templates/redux-external/src/types/core.ts
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/types/core.ts
rename to packages/react-app-scaffolder/app/templates/redux-external/src/types/core.ts
diff --git a/packages/react-app-scaffolder/app/templates/redux-external/src/types/global.d.ts b/packages/react-app-scaffolder/app/templates/redux-external/src/types/global.d.ts
new file mode 100644
index 0000000000..05ecceb797
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-external/src/types/global.d.ts
@@ -0,0 +1,16 @@
+export type AppEnv = 'local' | 'development' | 'production'
+
+export type Config = {
+ appEnv: AppEnv
+ cognitoClientId: string
+ cognitoOAuthUrl: string
+ cognitoUserPoolId: string
+}
+
+declare global {
+ interface Window {
+ reapit: {
+ config: Config
+ }
+ }
+}
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/types/index.d.ts b/packages/react-app-scaffolder/app/templates/redux-external/src/types/index.d.ts
similarity index 80%
rename from packages/react-app-scaffolder/app/templates/apollo/src/types/index.d.ts
rename to packages/react-app-scaffolder/app/templates/redux-external/src/types/index.d.ts
index d2486d9651..5940037217 100644
--- a/packages/react-app-scaffolder/app/templates/apollo/src/types/index.d.ts
+++ b/packages/react-app-scaffolder/app/templates/redux-external/src/types/index.d.ts
@@ -1,5 +1,5 @@
/**
- * Global override types to make the compiler happy
+ * Gobal override types to make the compiler happy
*/
declare namespace yargs {
@@ -10,6 +10,5 @@ declare module '*.css'
declare module '*.scss'
declare module '*.scss?mod'
declare module '*.sass'
-declare module '*.png'
declare module '*.jpg'
-
+declare module '*.png'
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/utils/__mocks__/session.ts b/packages/react-app-scaffolder/app/templates/redux-external/src/utils/__mocks__/session.ts
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/utils/__mocks__/session.ts
rename to packages/react-app-scaffolder/app/templates/redux-external/src/utils/__mocks__/session.ts
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/utils/__tests__/actions.ts b/packages/react-app-scaffolder/app/templates/redux-external/src/utils/__tests__/actions.ts
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/utils/__tests__/actions.ts
rename to packages/react-app-scaffolder/app/templates/redux-external/src/utils/__tests__/actions.ts
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/utils/__tests__/route-dispatcher.ts b/packages/react-app-scaffolder/app/templates/redux-external/src/utils/__tests__/route-dispatcher.ts
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/utils/__tests__/route-dispatcher.ts
rename to packages/react-app-scaffolder/app/templates/redux-external/src/utils/__tests__/route-dispatcher.ts
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/utils/__tests__/session.ts b/packages/react-app-scaffolder/app/templates/redux-external/src/utils/__tests__/session.ts
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/utils/__tests__/session.ts
rename to packages/react-app-scaffolder/app/templates/redux-external/src/utils/__tests__/session.ts
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/utils/actions.ts b/packages/react-app-scaffolder/app/templates/redux-external/src/utils/actions.ts
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/utils/actions.ts
rename to packages/react-app-scaffolder/app/templates/redux-external/src/utils/actions.ts
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/utils/route-dispatcher.ts b/packages/react-app-scaffolder/app/templates/redux-external/src/utils/route-dispatcher.ts
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/utils/route-dispatcher.ts
rename to packages/react-app-scaffolder/app/templates/redux-external/src/utils/route-dispatcher.ts
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/utils/session.ts b/packages/react-app-scaffolder/app/templates/redux-external/src/utils/session.ts
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/utils/session.ts
rename to packages/react-app-scaffolder/app/templates/redux-external/src/utils/session.ts
diff --git a/packages/react-app-scaffolder/app/templates/redux-external/tsconfig.json b/packages/react-app-scaffolder/app/templates/redux-external/tsconfig.json
new file mode 100644
index 0000000000..14b747b005
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-external/tsconfig.json
@@ -0,0 +1,61 @@
+{
+ "compilerOptions": {
+ "allowJs": true,
+ "esModuleInterop": true,
+ "jsx": "react",
+ "lib": [
+ "dom",
+ "es2015",
+ "es2017",
+ "es2018",
+ "es2019",
+ "es2020",
+ "es5",
+ "es6",
+ "es7",
+ "esnext"
+ ],
+ "module": "esnext",
+ "moduleResolution": "node",
+ "noEmit": true,
+ "noImplicitAny": false,
+ "forceConsistentCasingInFileNames": true,
+ "skipLibCheck": true,
+ "outDir": "dist",
+ "strict": true,
+ "resolveJsonModule": true,
+ "target": "es2020",
+ "typeRoots": [
+ "./node_modules/@types"
+ ],
+ "types": [
+ "jest",
+ "node",
+ "react"
+ ],
+ "baseUrl": "./",
+ "paths": {
+ "@/*": [
+ "./src/*"
+ ]
+ }
+ },
+ "exclude": [
+ "public",
+ "dist",
+ "src/scriptsipts/scripts",
+ "node_modules",
+ "coverage",
+ "public",
+ "dist",
+ "./webpack.config.js",
+ "node_modules",
+ "src/tests/coverage"
+ ],
+ "include": [
+ "src",
+ "../base/src/scripts/constants.js",
+ "scripts",
+ "scripts"
+ ]
+}
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/config.example.json b/packages/react-app-scaffolder/app/templates/redux-internal/config.example.json
new file mode 100644
index 0000000000..345fab9d4b
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/config.example.json
@@ -0,0 +1,9 @@
+{
+ "appEnv": "local",
+ "sentryDns": "",
+ "cognitoClientId": "",
+ "googleAnalyticsKey": "",
+ "cognitoOAuthUrl": "https://dev.connect.reapit.cloud",
+ "cognitoUserPoolId": "eu-west-2_hbt0B7yys",
+ "platformApiUrl": "https://dev.platform.reapit.cloud"
+}
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/jest.config.js b/packages/react-app-scaffolder/app/templates/redux-internal/jest.config.js
new file mode 100644
index 0000000000..0c53209cd9
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/jest.config.js
@@ -0,0 +1,23 @@
+const { pathsToModuleNameMapper } = require('ts-jest/utils')
+const baseConfig = require('../../scripts/jest/jest.config')
+const { compilerOptions } = require('./tsconfig')
+
+module.exports = {
+ ...baseConfig,
+ testPathIgnorePatterns: ['/src/tests/'],
+ moduleNameMapper: {
+ ...baseConfig.moduleNameMapper,
+ ...pathsToModuleNameMapper(compilerOptions.paths, {
+ prefix: '/',
+ }),
+ },
+ coveragePathIgnorePatterns: ['/src/services', '/src/tests'],
+ coverageThreshold: {
+ global: {
+ branches: 63,
+ functions: 70,
+ lines: 88,
+ statements: 87,
+ },
+ },
+}
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/node_modules/.yarn-integrity b/packages/react-app-scaffolder/app/templates/redux-internal/node_modules/.yarn-integrity
new file mode 100644
index 0000000000..0b19981cd5
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/node_modules/.yarn-integrity
@@ -0,0 +1,19 @@
+{
+ "systemParams": "darwin-x64-72",
+ "modulesFolders": [
+ "node_modules"
+ ],
+ "flags": [],
+ "linkedModules": [
+ "@reapit/elements",
+ "@reapit/generator-react-app-scaffolder"
+ ],
+ "topLevelPatterns": [
+ "@reapit/foundations-ts-definitions@2020-02-13"
+ ],
+ "lockfileEntries": {
+ "@reapit/foundations-ts-definitions@2020-02-13": "https://registry.yarnpkg.com/@reapit/foundations-ts-definitions/-/foundations-ts-definitions-0.0.68.tgz#61331dc5552900159eb66ad5e496695b53597add"
+ },
+ "files": [],
+ "artifacts": {}
+}
\ No newline at end of file
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/node_modules/@reapit/foundations-ts-definitions/README.md b/packages/react-app-scaffolder/app/templates/redux-internal/node_modules/@reapit/foundations-ts-definitions/README.md
new file mode 100644
index 0000000000..afdb43e664
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/node_modules/@reapit/foundations-ts-definitions/README.md
@@ -0,0 +1,9 @@
+# Foundations TS Definitions:
+
+Automated TypeScript definitions for the Foundations API Platform. Automatically generates up to date TypeScript type definitions from Platform API swagger documentation. For usage visit [here](https://foundations-documentation.reapit.cloud/api/web#foundations-ts-definitions).
+
+- **Tech Stack**: NodeJS
+- **Cloud Services**: NPM
+- **Production**: https://www.npmjs.com/package/@reapit/foundations-ts-definitions
+
+For detailed documentation [visit here](https://foundations-documentation.reapit.cloud/open-source/packages#foundations-ts-definitions).
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/node_modules/@reapit/foundations-ts-definitions/package.json b/packages/react-app-scaffolder/app/templates/redux-internal/node_modules/@reapit/foundations-ts-definitions/package.json
new file mode 100644
index 0000000000..1ad9744030
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/node_modules/@reapit/foundations-ts-definitions/package.json
@@ -0,0 +1,23 @@
+{
+ "name": "@reapit/foundations-ts-definitions",
+ "version": "0.0.68",
+ "license": "MIT",
+ "files": [
+ "types/*"
+ ],
+ "main": "./types/index.ts",
+ "scripts": {
+ "fetch-definition": "node '../../scripts/foundations-ts-definitions/fetch-definition.js'",
+ "handle-cron-job": "node '../../scripts/foundations-ts-definitions/handle-cronjob.js'",
+ "release:prod": "node ../../scripts/foundations-ts-definitions/release-npm.js foundations-ts-definitions",
+ "test:update-badges": "echo 'not implmented'"
+ },
+ "lint-staged": {
+ "src/**/*.{js,jsx,ts,tsx,json,css,scss,md}": [
+ "prettier --write",
+ "git add"
+ ]
+ },
+ "dependencies": {},
+ "peerDependencies": {}
+}
\ No newline at end of file
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/node_modules/@reapit/foundations-ts-definitions/types/index.ts b/packages/react-app-scaffolder/app/templates/redux-internal/node_modules/@reapit/foundations-ts-definitions/types/index.ts
new file mode 100644
index 0000000000..f77d055630
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/node_modules/@reapit/foundations-ts-definitions/types/index.ts
@@ -0,0 +1,4 @@
+// @ts-ignore
+export * from './marketplace-api-schema'
+// @ts-ignore
+export * from './platform-schema'
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/node_modules/@reapit/foundations-ts-definitions/types/marketplace-api-schema.ts b/packages/react-app-scaffolder/app/templates/redux-internal/node_modules/@reapit/foundations-ts-definitions/types/marketplace-api-schema.ts
new file mode 100644
index 0000000000..5db55a766f
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/node_modules/@reapit/foundations-ts-definitions/types/marketplace-api-schema.ts
@@ -0,0 +1,943 @@
+/**
+ * App secret representation
+ */
+export interface AppClientSecretModel {
+ /**
+ * Gets the GUID of the app
+ */
+ id?: string // uuid
+ /**
+ * Gets the apps client secret
+ */
+ clientSecret?: string
+}
+/**
+ * App detailed representation
+ */
+export interface AppDetailModel {
+ /**
+ * Gets the GUID of the app
+ */
+ id?: string // uuid
+ /**
+ * Gets the date and time the app was originally registered on the marketplace
+ */
+ created?: string // date-time
+ /**
+ * Gets the GUID of the developer who has created the app
+ */
+ developerId?: string // uuid
+ /**
+ * Gets the GUID of the installation
+ */
+ installationId?: string // uuid
+ /**
+ * Gets client id of this application
+ */
+ externalId?: string
+ /**
+ * Gets the full name of the app
+ */
+ name?: string
+ /**
+ * Gets a short summary of the app
+ */
+ summary?: string
+ /**
+ * Gets a detailed description of the app
+ */
+ description?: string
+ /**
+ * Gets the name of the developer who created the app
+ */
+ developer?: string
+ /**
+ * Gets the email address of the developer's helpdesk responsible for providing support of the application
+ */
+ supportEmail?: string
+ /**
+ * Gets the telephone number of the developer's helpdesk responsible for providing support of the application
+ */
+ telephone?: string
+ /**
+ * Gets the home page of the developer, or the app/product specific page on the developer's website
+ */
+ homePage?: string
+ /**
+ * Gets the Uri at which the app is launched
+ */
+ launchUri?: string
+ /**
+ * Gets the app revisions redirect uri (or uris) where a user will be redirected to immediately after a successful authentication
+ */
+ redirectUris?: string[]
+ /**
+ * Gets the app revisions signout uri (or uris) where a user will be redirected to immediately after a successful logout
+ */
+ signoutUris?: string[]
+ /**
+ * Gets the date the app was installed for a specific client
+ */
+ installedOn?: string // date-time
+ /**
+ * Gets the application authorisation flow type (authorisationCode/clientCredentials)
+ */
+ authFlow?: string
+ /**
+ * Gets a flag determining whether or not the app is currently listed on the marketplace
+ */
+ isListed?: boolean
+ /**
+ * Gets a flag determining whether or not the app will appear in the marketplace
+ */
+ isDirectApi?: boolean
+ /**
+ * Gets the sandbox status of this app
+ */
+ isSandbox?: boolean
+ /**
+ * Gets a flag determining whether or not the app is featured
+ */
+ isFeatured?: boolean
+ /**
+ * Gets a flag determining whether or not the app is a web component
+ */
+ isWebComponent?: boolean
+ /**
+ * Gets the status of whether the app has pending revisions
+ */
+ pendingRevisions?: boolean
+ /**
+ * Gets the apps category
+ */
+ category?: CategoryModel
+ /**
+ * Gets the collection of scopes against the app
+ */
+ scopes?: ScopeModel[]
+ /**
+ * Gets a collection of media objects associated with the app
+ */
+ media?: MediaModel[]
+ /**
+ * Gets the links associated to this model
+ */
+ readonly links?: LinkModel[]
+}
+/**
+ * App revision detailed representation
+ */
+export interface AppRevisionModel {
+ /**
+ * Gets the unique identifier of the app revision
+ */
+ id?: string // uuid
+ /**
+ * Gets the unique identifier of the app the revision is associated with
+ */
+ appId?: string // uuid
+ /**
+ * Gets the GUID of the developer of made the app
+ */
+ developerId?: string // uuid
+ /**
+ * Gets the full name of the app revision
+ */
+ name?: string
+ /**
+ * Gets a short summary of the app revision
+ */
+ summary?: string
+ /**
+ * Gets a detailed description of the app revision
+ */
+ description?: string
+ /**
+ * Gets the name of the developer who created the app revision
+ */
+ developer?: string
+ /**
+ * Gets the email address of the developer's helpdesk responsible for providing support of the application
+ */
+ supportEmail?: string
+ /**
+ * Gets the telephone number of the developer's helpdesk responsible for providing support of the application
+ */
+ telephone?: string
+ /**
+ * Gets the home page of the developer, or the app/product specific page on the developer's website
+ */
+ homePage?: string
+ /**
+ * Gets the app revisions launch uri
+ */
+ launchUri?: string
+ /**
+ * Gets the app revisions redirect uri (or uris) where a user will be redirected to immediately after a successful authentication
+ */
+ redirectUris?: string[]
+ /**
+ * Gets the app revisions signout uri (or uris) where a user will be redirected to immediately after a successful logout
+ */
+ signoutUris?: string[]
+ /**
+ * Gets the listed status of the app revision
+ */
+ isListed?: boolean
+ /**
+ * Gets a flag determining whether or not the app will appear in the marketplace
+ */
+ isDirectApi?: boolean
+ /**
+ * Gets the app revisions category
+ */
+ category?: CategoryModel
+ /**
+ * Gets the scopes that have been associated to this revision
+ */
+ scopes?: ScopeModel[]
+ /**
+ * Gets a collection of media objects associated with the app
+ */
+ media?: MediaModel[]
+ /**
+ * Gets the links associated to this model
+ */
+ readonly links?: LinkModel[]
+}
+/**
+ * App summary representation
+ */
+export interface AppSummaryModel {
+ /**
+ * Gets the GUID of the app
+ */
+ id?: string // uuid
+ /**
+ * Gets external client id of this application
+ */
+ externalId?: string
+ /**
+ * Gets the date and time the app was originally registered on the marketplace
+ */
+ created?: string // date-time
+ /**
+ * Gets the GUID of the developer who has created the app
+ */
+ developerId?: string // uuid
+ /**
+ * Gets the full name of the app
+ */
+ name?: string
+ /**
+ * Gets a short summary of the app
+ */
+ summary?: string
+ /**
+ * Gets the name of the developer who created the app
+ */
+ developer?: string
+ /**
+ * Gets the home page of the developer, or the app/product specific page on the developer's website
+ */
+ homePage?: string
+ /**
+ * Gets a flag determining whether or not the app is currently listed on the marketplace
+ */
+ isListed?: boolean
+ /**
+ * Gets the sandbox status of this app
+ */
+ isSandbox?: boolean
+ /**
+ * Gets a flag determining whether or not the app is featured
+ */
+ isFeatured?: boolean
+ /**
+ * Gets a flag determining whether or not the app will appear in the marketplace
+ */
+ isDirectApi?: boolean
+ /**
+ * Gets the public Url for accessing this app's icon
+ */
+ iconUri?: string
+ /**
+ * Gets the time stamp of the installed date
+ */
+ installedOn?: string // date-time
+ /**
+ * Gets the application authorisation flow type (authorisationCode/clientCredentials)
+ */
+ authFlow?: string
+ /**
+ * Gets the Uri at which the app is launched
+ */
+ launchUri?: string
+ /**
+ * Gets the status of whether the app has pending revisions
+ */
+ pendingRevisions?: boolean
+ /**
+ * Gets the links associated to this model
+ */
+ readonly links?: LinkModel[]
+}
+/**
+ * Representation of app usage for a specific day
+ */
+export interface AppUsageStatsByDateModel {
+ /**
+ * The date the usage is recorded for
+ */
+ date?: string // date-time
+ /**
+ * The number of requests made by this app on this day
+ */
+ requests?: number // int64
+}
+/**
+ * Representation of a specific apps usage
+ */
+export interface AppUsageStatsModel {
+ /**
+ * The unique app identifier
+ */
+ appId?: string // uuid
+ /**
+ * The total number of requests from this app over the period given
+ */
+ requestsForPeriod?: number // int64
+ /**
+ * Daily breakdown of requests made by this app
+ */
+ usage?: AppUsageStatsByDateModel[]
+}
+/**
+ * Approval representation
+ */
+export interface ApprovalModel {
+ /**
+ * Apps unique identifier
+ */
+ appId?: string // uuid
+ /**
+ * Type of approval
+ */
+ type?: string
+ /**
+ * Description of approval
+ */
+ description?: string
+ /**
+ * App revision unique identifier
+ */
+ appRevisionId?: string // uuid
+ /**
+ * Gets the date the revision was created
+ */
+ readonly created?: string // date-time
+ /**
+ * Gets the links associated to this model
+ */
+ readonly links?: LinkModel[]
+}
+/**
+ * The model responsible for the approval of an app revision
+ */
+export interface ApproveModel {
+ /**
+ * Sets the name of the admin approving
+ */
+ name?: string
+ /**
+ * Sets the email of the admin approving
+ */
+ email?: string
+}
+/**
+ * Model to expose category info
+ */
+export interface CategoryModel {
+ /**
+ * Gets the unique identifier associated to the category
+ */
+ id?: string
+ /**
+ * Gets the name of the category
+ */
+ name?: string
+ /**
+ * Gets the description of the category
+ */
+ description?: string
+ /**
+ * Gets the links associated to this model
+ */
+ readonly links?: LinkModel[]
+}
+/**
+ * The model responsible for creation of an app definition
+ */
+export interface CreateAppModel {
+ /**
+ * Sets the full name of the app
+ */
+ name?: string
+ /**
+ * Sets the description of the app
+ */
+ description?: string
+ /**
+ * Sets a short summary of the app
+ */
+ summary?: string
+ /**
+ * Sets the email address of the developer's helpdesk responsible for providing support of the app
+ */
+ supportEmail?: string
+ /**
+ * Sets the telephone number of the developer's helpdesk responsible for providing support of the app
+ */
+ telephone?: string
+ /**
+ * Sets the home page of the developer, or the application/product specific page on the developer's website
+ */
+ homePage?: string
+ /**
+ * Sets the apps launch uri
+ */
+ launchUri?: string
+ /**
+ * Sets the apps uri where a user will be redirected to immediately after a successful authentication. Multiple URIs can be passed in the array
+ */
+ redirectUris?: string[]
+ /**
+ * Set the apps uri where a user will be redirected to immediately after a session is logged out. Multiple URIs can be passed in the array
+ */
+ signoutUris?: string[]
+ /**
+ * Sets the unique identifer of the developer registering the app
+ */
+ developerId?: string // uuid
+ /**
+ * Sets the unique identifer of the apps category
+ */
+ categoryId?: string
+ /**
+ * Sets a flag determining whether or not the app is featured
+ */
+ isFeatured?: boolean
+ /**
+ * Sets the flag determining whether or not the app will appear in the marketplace
+ */
+ isDirectApi?: boolean
+ /**
+ * Sets the flag determining whether or not the app is a web component
+ */
+ isWebComponent?: boolean
+ /**
+ * Sets the application authorisation flow type (authorisationCode/clientCredentials)
+ */
+ authFlow?: string
+ /**
+ * Sets the list of scope keys required for this app to run
+ */
+ scopes?: string[]
+ /**
+ * Sets the location url of the app icon image
+ */
+ iconImageUrl?: string
+ /**
+ * Sets the location url of the first app screenshot image
+ */
+ screen1ImageUrl?: string
+ /**
+ * Sets the location url of the second (optional) app screenshot image
+ */
+ screen2ImageUrl?: string
+ /**
+ * Sets the location url of the third (optional) app screenshot image
+ */
+ screen3ImageUrl?: string
+ /**
+ * Sets the location url of the fourth (optional) app screenshot image
+ */
+ screen4ImageUrl?: string
+ /**
+ * Sets the location url of the fifth (optional) app screenshot image
+ */
+ screen5ImageUrl?: string
+}
+/**
+ * The model responsible for creation of an app revision
+ */
+export interface CreateAppRevisionModel {
+ /**
+ * Sets the full name of the app revision
+ */
+ name?: string
+ /**
+ * Sets the description of the app revision
+ */
+ description?: string
+ /**
+ * Sets a short summary of the app revision
+ */
+ summary?: string
+ /**
+ * Sets the email address of the developer's helpdesk responsible for providing support of the app revision
+ */
+ supportEmail?: string
+ /**
+ * Sets the telephone number of the developer's helpdesk responsible for providing support of the app revision
+ */
+ telephone?: string
+ /**
+ * Sets the home page of the developer, or the application/product specific page on the developer's website
+ */
+ homePage?: string
+ /**
+ * Sets the flag determining whether or not the app will appear in the marketplace
+ */
+ isDirectApi?: boolean
+ /**
+ * Sets the unique identifier of the developer associated with this app revision
+ */
+ developerId?: string // uuid
+ /**
+ * Sets the unique identifer of the app revisions category
+ */
+ categoryId?: string
+ /**
+ * Sets location url of the app icon image
+ */
+ iconImageUrl?: string
+ /**
+ * Sets the location url of the first app screenshot image
+ */
+ screen1ImageUrl?: string
+ /**
+ * Sets the location url of the second (optional) app screenshot image
+ */
+ screen2ImageUrl?: string
+ /**
+ * Sets the location url of the third (optional) app screenshot image
+ */
+ screen3ImageUrl?: string
+ /**
+ * Sets the location url of the fourth (optional) app screenshot image
+ */
+ screen4ImageUrl?: string
+ /**
+ * Sets the location url of the fifth (optional) app screenshot image
+ */
+ screen5ImageUrl?: string
+ /**
+ * Sets the apps launch uri
+ */
+ launchUri?: string
+ /**
+ * Sets the apps uri where a user will be redirected to immediately after a successful authentication. Multiple URIs can be passed in the array
+ */
+ redirectUris?: string[]
+ /**
+ * Set the apps uri where a user will be redirected to immediately after a session is logged out. Multiple URIs can be passed in the array
+ */
+ signoutUris?: string[]
+ /**
+ * Sets the listed status of the app
+ * When false, the app will not be visible in marketplace app listings
+ */
+ isListed?: boolean
+ /**
+ * Sets the list of scope keys required for this app revision
+ */
+ scopes?: string[]
+}
+/**
+ * The model responsible for creation of a category
+ */
+export interface CreateCategoryModel {
+ /**
+ * Sets the unique identifier of the category
+ */
+ id?: string
+ /**
+ * Sets the name of the category
+ */
+ name?: string
+ /**
+ * Sets the description of the category
+ */
+ description?: string
+}
+/**
+ * The model responsible for creation of a developer
+ */
+export interface CreateDeveloperModel {
+ /**
+ * Sets the full name of this developer
+ */
+ name?: string
+ /**
+ * Sets the company to which this developer is acting on behalf of
+ */
+ companyName?: string
+ /**
+ * Sets the job title for this developer
+ */
+ jobTitle?: string
+ /**
+ * Sets the email address of the developer
+ */
+ email?: string
+ /**
+ * Sets the telephone number of the developer
+ */
+ telephone?: string
+ /**
+ * Sets the date the developer agreed to the terms
+ */
+ readonly agreedTerms?: string // date-time
+}
+/**
+ * The model responsible for creation of an installation between a specific client and app
+ */
+export interface CreateInstallationModel {
+ /**
+ * Sets the unique identifier of the app that this installation will be associated with
+ */
+ appId?: string // uuid
+ /**
+ * Sets the unique identifier of the client this installation is being created for
+ */
+ clientId?: string
+ /**
+ * Sets the email address of the user that has approved this app (and created the installation)
+ */
+ approvedBy?: string
+ /**
+ * Sets the termination date of the installation (this could be used for app trials etc)
+ */
+ terminatesOn?: string // date-time
+}
+/**
+ * Model that represents a developer
+ */
+export interface DeveloperModel {
+ /**
+ * Gets the id of this developer
+ */
+ readonly id?: string // uuid
+ /**
+ * Gets the id of this developer held in the gateway
+ */
+ readonly externalId?: string
+ /**
+ * Gets the full name of this developer
+ */
+ readonly name?: string
+ /**
+ * Gets the company to which this developer is acting on behalf of
+ */
+ readonly company?: string
+ /**
+ * Gets the job title for this developer
+ */
+ readonly jobTitle?: string
+ /**
+ * Gets the email address of the developer
+ */
+ readonly email?: string
+ /**
+ * Gets the telephone number of the developer
+ */
+ readonly telephone?: string
+ /**
+ * Gets the date the developer agreed to the terms
+ */
+ readonly agreedTerms?: string // date-time
+ /**
+ * Gets the flag determining if the developer is inactive
+ */
+ isInactive?: boolean
+ /**
+ * Gets the timestamp of entity creation
+ */
+ readonly created?: string // date-time
+ /**
+ * Gets the timestamp of entity modification
+ */
+ readonly modified?: string // date-time
+ /**
+ * Gets the links associated to this model
+ */
+ readonly links?: LinkModel[]
+}
+/**
+ * Installation representation
+ */
+export interface InstallationModel {
+ /**
+ * Gets the unique identifier of the installation
+ */
+ id?: string // uuid
+ /**
+ * Gets the unique identifier of the app the installation is associated with
+ */
+ appId?: string // uuid
+ /**
+ * Gets the date/time the installation was created
+ */
+ created?: string // date-time
+ /**
+ * Gets the id of the client that has granted access to the app (or revoked it)
+ */
+ client?: string
+ /**
+ * Gets the status of this installation
+ */
+ status?: string
+ /**
+ * Gets the authorisation flow type of the associated app
+ */
+ authFlow?: string
+ /**
+ * Gets the reason that access to associated app was removed
+ */
+ terminatedReason?: string
+ /**
+ * Gets the date that access to the associated app was terminated, or is due to terminate on
+ */
+ terminatesOn?: string // date-time
+ /**
+ * Gets the links associated to this model
+ */
+ readonly links?: LinkModel[]
+}
+/**
+ * Represents a HyperMedia Link
+ */
+export interface LinkModel {
+ /**
+ * The relationship being described
+ */
+ rel?: string
+ /**
+ * The hyperlink URI
+ */
+ href?: string
+ /**
+ * The HTTP verb to be issued
+ */
+ action?: string
+}
+/**
+ * Media representation
+ */
+export interface MediaModel {
+ /**
+ * Gets the unique identifier of the media item
+ */
+ id?: string // uuid
+ /**
+ * Gets the URI where this media is located
+ */
+ uri?: string
+ /**
+ * Gets the textual description of this media content
+ */
+ description?: string
+ /**
+ * Gets type of media this entity relates to
+ */
+ type?: string
+ /**
+ * Gets the order of this particular picture in the list of available media
+ */
+ order?: number // int32
+ /**
+ * Gets the links associated to this model
+ */
+ readonly links?: LinkModel[]
+}
+/**
+ * Model to handle paged data and information
+ */
+export interface PagedResultAppRevisionModel_ {
+ /**
+ * List of paged data
+ */
+ data?: AppRevisionModel[]
+ pageNumber?: number // int32
+ pageSize?: number // int32
+ pageCount?: number // int32
+ totalCount?: number // int32
+}
+/**
+ * Model to handle paged data and information
+ */
+export interface PagedResultAppSummaryModel_ {
+ /**
+ * List of paged data
+ */
+ data?: AppSummaryModel[]
+ pageNumber?: number // int32
+ pageSize?: number // int32
+ pageCount?: number // int32
+ totalCount?: number // int32
+}
+/**
+ * Model to handle paged data and information
+ */
+export interface PagedResultApprovalModel_ {
+ /**
+ * List of paged data
+ */
+ data?: ApprovalModel[]
+ pageNumber?: number // int32
+ pageSize?: number // int32
+ pageCount?: number // int32
+ totalCount?: number // int32
+}
+/**
+ * Model to handle paged data and information
+ */
+export interface PagedResultCategoryModel_ {
+ /**
+ * List of paged data
+ */
+ data?: CategoryModel[]
+ pageNumber?: number // int32
+ pageSize?: number // int32
+ pageCount?: number // int32
+ totalCount?: number // int32
+}
+/**
+ * Model to handle paged data and information
+ */
+export interface PagedResultDeveloperModel_ {
+ /**
+ * List of paged data
+ */
+ data?: DeveloperModel[]
+ pageNumber?: number // int32
+ pageSize?: number // int32
+ pageCount?: number // int32
+ totalCount?: number // int32
+}
+/**
+ * Model to handle paged data and information
+ */
+export interface PagedResultInstallationModel_ {
+ /**
+ * List of paged data
+ */
+ data?: InstallationModel[]
+ pageNumber?: number // int32
+ pageSize?: number // int32
+ pageCount?: number // int32
+ totalCount?: number // int32
+}
+/**
+ * The model responsible for rejection of a revision
+ */
+export interface RejectRevisionModel {
+ /**
+ * Sets the name of the admin rejecting
+ */
+ name?: string
+ /**
+ * Sets the email of the admin rejecting
+ */
+ email?: string
+ /**
+ * Sets the reason the revision is rejected
+ */
+ rejectionReason?: string
+}
+/**
+ * Model that represents a scope
+ */
+export interface ScopeModel {
+ /**
+ * Gets the name of the scope
+ */
+ name?: string
+ /**
+ * Gets the description of the scope
+ */
+ description?: string
+}
+/**
+ * The model responsible for terminating the installation between a specific client and app
+ */
+export interface TerminateInstallationModel {
+ /**
+ * Sets the unique identifier of the associated app for which the installation is being terminated
+ */
+ appId?: string // uuid
+ /**
+ * Sets the email address of the person removing access to this app for the client
+ * specified in the installation
+ */
+ terminatedBy?: string
+ /**
+ * Sets the reason that app access has been removed
+ */
+ terminatedReason?: string
+ /**
+ * Sets the date at which the app should become unavailable to the client (optional - if not passed the app will become unavailable immediately)
+ */
+ terminatesOn?: string // date-time
+}
+/**
+ * The model responsible for updating of a developer
+ */
+export interface UpdateDeveloperModel {
+ /**
+ * Sets the full name of this developer
+ */
+ name?: string
+ /**
+ * Sets the company to which this developer is acting on behalf of
+ */
+ companyName?: string
+ /**
+ * Sets the job title for this developer
+ */
+ jobTitle?: string
+ /**
+ * Sets the telephone number of the developer
+ */
+ telephone?: string
+ /**
+ * Sets the date the developer agreed to the terms
+ */
+ readonly agreedTerms?: string // date-time
+ /**
+ * Sets the flag specifying if the developer is inactive
+ */
+ isInactive?: boolean
+}
+/**
+ * Representations of an apps statistics
+ */
+export interface UsageStatsModel {
+ /**
+ * The date to retrieve app statistics from
+ */
+ dateFrom?: string // date-time
+ /**
+ * The date to retrieve app statistics until
+ */
+ dateTo?: string // date-time
+ /**
+ * The total number of requests across all apps given
+ */
+ totalRequestsForPeriod?: number // int64
+ /**
+ * Breakdown of the individual apps usage
+ */
+ appUsage?: AppUsageStatsModel[]
+}
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/node_modules/@reapit/foundations-ts-definitions/types/platform-schema.ts b/packages/react-app-scaffolder/app/templates/redux-internal/node_modules/@reapit/foundations-ts-definitions/types/platform-schema.ts
new file mode 100644
index 0000000000..22c9d134f3
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/node_modules/@reapit/foundations-ts-definitions/types/platform-schema.ts
@@ -0,0 +1,11530 @@
+/**
+ * The details specific to applicants with a marketingMode of buying
+ */
+export interface ApplicantBuyingModel {
+ /**
+ * The lower bound of the applicant's budget
+ */
+ priceFrom?: number // int32
+ /**
+ * The upper bound of the applicant's budget
+ */
+ priceTo?: number // int32
+}
+/**
+ * Representation of the physical address of a building or premise
+ */
+export interface ApplicantContactAddressModel {
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides within
+ */
+ countryId?: string
+}
+/**
+ * A summarised view of the details of a contact or company associated to an applicant
+ */
+export interface ApplicantContactModel {
+ /**
+ * The unique identifier of the contact or company
+ */
+ id?: string
+ /**
+ * The name of the contact or company
+ */
+ name?: string
+ /**
+ * The type of the contact (company/contact)
+ */
+ type?: string
+ /**
+ * The home phone number of the contact or company
+ */
+ homePhone?: string
+ /**
+ * The work phone number of the contact or company
+ */
+ workPhone?: string
+ /**
+ * The mobile phone number of the contact or company
+ */
+ mobilePhone?: string
+ /**
+ * The email address of the contact or company
+ */
+ email?: string
+ /**
+ * The primary address of the contact or company
+ */
+ primaryAddress?: {
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides within
+ */
+ countryId?: string
+ }
+}
+/**
+ * Representation of a relationship between an applicant and a contact or company
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+export interface ApplicantContactRelationshipModel {
+ /**
+ * The unique identifier of the applicant relationship
+ */
+ id?: string
+ /**
+ * The date and time when the relationship was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the relationship was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The unique identifier of the applicant
+ */
+ applicantId?: string
+ /**
+ * The type of related entity (contact/company)
+ */
+ associatedType?: string
+ /**
+ * The unique identifier of the related contact or company
+ */
+ associatedId?: string
+ /**
+ * A flag denoting whether or not this relationship should be regarded as the main relationship for the parent applicant entity
+ */
+ isMain?: boolean
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+}
+/**
+ * The applicant's outdoor space requirements
+ */
+export interface ApplicantExternalAreaModel {
+ /**
+ * The unit of area that each amount corresponds to (acres/hectares)
+ */
+ type?: string
+ /**
+ * The minimum unit value of outside space that the applicant is looking for
+ */
+ amountFrom?: number // double
+ /**
+ * The maximum unit value of outside space that the applicant is looking for
+ */
+ amountTo?: number // double
+}
+/**
+ * The applicant's indoor space requirements
+ */
+export interface ApplicantInternalAreaModel {
+ /**
+ * The unit of area that each amount corresponds to (squareFeet/squareMetres)
+ */
+ type?: string
+ /**
+ * The unit value of inside space that the applicant is looking for
+ */
+ amount?: number // double
+}
+/**
+ * Representation of an applicant
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+export interface ApplicantModel {
+ /**
+ * The unique identifier of the applicant
+ */
+ id?: string
+ /**
+ * The date and time when the applicant was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the applicant was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * Indicates whether the applicant is look to buy or rent a property (buying/renting)
+ */
+ marketingMode?: string
+ /**
+ * The ISO-4217 currency code that relates to monetary amounts specified by the applicant
+ */
+ currency?: string
+ /**
+ * A flag determining whether or not the applicant is actively looking for a property
+ */
+ active?: boolean
+ /**
+ * A free text field describing any adhoc buying or renting requirements
+ */
+ notes?: string
+ /**
+ * The date when the applicant was last contacted
+ * example:
+ * 2019-08-14
+ */
+ lastCall?: string // date
+ /**
+ * The date when the applicant is next due to be contacted
+ * example:
+ * 2019-08-14
+ */
+ nextCall?: string // date
+ /**
+ * The unique identifier of the department that the applicant requirements are associated with. The applicant will only match to properties with the same value
+ */
+ departmentId?: string
+ /**
+ * The unique identifier of the solicitor associated to the applicant
+ */
+ solicitorId?: string
+ /**
+ * A list of property type requirements taken from the full listing of the associated department
+ */
+ type?: string[]
+ /**
+ * A list of property style requirements taken from the full listing of the associated department
+ */
+ style?: string[]
+ /**
+ * A list of property situation requirements taken from the full listing of the associated department
+ */
+ situation?: string[]
+ /**
+ * A list of property parking requirements taken from the full listing of the associated department
+ */
+ parking?: string[]
+ /**
+ * A list of property age requirements taken from the full listing of the associated department
+ */
+ age?: string[]
+ /**
+ * A list of property locality requirements taken from the full listing of the associated department
+ */
+ locality?: string[]
+ /**
+ * The minimum number of bedrooms the applicant requires
+ */
+ bedroomsMin?: number // int32
+ /**
+ * The maximum number of bedrooms the applicant requires
+ */
+ bedroomsMax?: number // int32
+ /**
+ * The minimum number of reception rooms the applicant requires
+ */
+ receptionsMin?: number // int32
+ /**
+ * The maximum number of reception rooms the applicant requires
+ */
+ receptionsMax?: number // int32
+ /**
+ * The minimum number of bathrooms the applicant requires
+ */
+ bathroomsMin?: number // int32
+ /**
+ * The maximum number of bathrooms the applicant requires
+ */
+ bathroomsMax?: number // int32
+ /**
+ * The applicant's location type (areas/addresses/none)
+ */
+ locationType?: string
+ /**
+ * The applicant's location options
+ */
+ locationOptions?: string[]
+ /**
+ * The details specific to applicants with a marketingMode of buying
+ */
+ buying?: {
+ /**
+ * The lower bound of the applicant's budget
+ */
+ priceFrom?: number // int32
+ /**
+ * The upper bound of the applicant's budget
+ */
+ priceTo?: number // int32
+ }
+ /**
+ * The details specific to applicants with a marketingMode of renting
+ */
+ renting?: {
+ /**
+ * The date the applicant is looking to move to a new property
+ * example:
+ * 2019-08-14
+ */
+ moveDate?: string // date
+ /**
+ * The applicant's preferred letting term (long/short/any)
+ */
+ term?: string
+ /**
+ * The lower bound of the applicant's budget
+ */
+ rentFrom?: number // double
+ /**
+ * The upper bound of the applicant's budget
+ */
+ rentTo?: number // double
+ /**
+ * The desired rent collection frequency specified by the applicant's budget (weekly/monthly/annually)
+ */
+ rentFrequency?: string
+ /**
+ * A list of property furnishing requirements taken from the full listing of the associated department. Only applicable to applicants with a marketingMode of renting
+ */
+ furnishing?: string[]
+ }
+ /**
+ * The applicant's outdoor space requirements
+ */
+ externalArea?: {
+ /**
+ * The unit of area that each amount corresponds to (acres/hectares)
+ */
+ type?: string
+ /**
+ * The minimum unit value of outside space that the applicant is looking for
+ */
+ amountFrom?: number // double
+ /**
+ * The maximum unit value of outside space that the applicant is looking for
+ */
+ amountTo?: number // double
+ }
+ /**
+ * The applicant's indoor space requirements
+ */
+ internalArea?: {
+ /**
+ * The unit of area that each amount corresponds to (squareFeet/squareMetres)
+ */
+ type?: string
+ /**
+ * The unit value of inside space that the applicant is looking for
+ */
+ amount?: number // double
+ }
+ /**
+ * The source of the applicant
+ */
+ source?: {
+ /**
+ * The unique identifier of the applicant's source
+ */
+ id?: string
+ /**
+ * The source type (office/source)
+ */
+ type?: string
+ }
+ /**
+ * A collection of unique identifiers of offices attached to the applicant. The first item in the collection is considered the primary office
+ */
+ officeIds?: string[]
+ /**
+ * A collection of unique identifiers of negotiators attached to the applicant. The first item in the collection is considered the primary negotiator
+ */
+ negotiatorIds?: string[]
+ /**
+ * A collection of contacts and/or companies associated to the applicant. The first item in the collection is considered the primary relationship
+ */
+ related?: {
+ /**
+ * The unique identifier of the contact or company
+ */
+ id?: string
+ /**
+ * The name of the contact or company
+ */
+ name?: string
+ /**
+ * The type of the contact (company/contact)
+ */
+ type?: string
+ /**
+ * The home phone number of the contact or company
+ */
+ homePhone?: string
+ /**
+ * The work phone number of the contact or company
+ */
+ workPhone?: string
+ /**
+ * The mobile phone number of the contact or company
+ */
+ mobilePhone?: string
+ /**
+ * The email address of the contact or company
+ */
+ email?: string
+ /**
+ * The primary address of the contact or company
+ */
+ primaryAddress?: {
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides within
+ */
+ countryId?: string
+ }
+ }[]
+ /**
+ * App specific metadata that has been set against the applicant
+ */
+ metadata?: {
+ [name: string]: any
+ }
+ /**
+ * The ETag for the current version of the applicant. Used for managing update concurrency
+ */
+ readonly _eTag?: string
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+}
+/**
+ * The details specific to applicants with a marketingMode of renting
+ */
+export interface ApplicantRentingModel {
+ /**
+ * The date the applicant is looking to move to a new property
+ * example:
+ * 2019-08-14
+ */
+ moveDate?: string // date
+ /**
+ * The applicant's preferred letting term (long/short/any)
+ */
+ term?: string
+ /**
+ * The lower bound of the applicant's budget
+ */
+ rentFrom?: number // double
+ /**
+ * The upper bound of the applicant's budget
+ */
+ rentTo?: number // double
+ /**
+ * The desired rent collection frequency specified by the applicant's budget (weekly/monthly/annually)
+ */
+ rentFrequency?: string
+ /**
+ * A list of property furnishing requirements taken from the full listing of the associated department. Only applicable to applicants with a marketingMode of renting
+ */
+ furnishing?: string[]
+}
+/**
+ * An applicant's source of enquiry
+ */
+export interface ApplicantSourceModel {
+ /**
+ * The unique identifier of the applicant's source
+ */
+ id?: string
+ /**
+ * The source type (office/source)
+ */
+ type?: string
+}
+export interface Applicants {
+ PageSize?: number
+ PageNumber?: number
+ SortBy?: string
+ Id?: string[]
+ NegotiatorId?: string[]
+ OfficeId?: string[]
+ Address?: string
+ DepartmentId?: string
+ Name?: string
+ PriceFrom?: number
+ PriceTo?: number
+ RentFrom?: number
+ RentTo?: number
+ BedroomsFrom?: number
+ BedroomsTo?: number
+ CreatedFrom?: string
+ CreatedTo?: string
+ LastCallFrom?: string
+ LastCallTo?: string
+ NextCallFrom?: string
+ NextCallTo?: string
+ Embed?: ('areas' | 'department' | 'documents' | 'negotiators' | 'offers' | 'offices' | 'solicitor' | 'source')[]
+ Age?: ('period' | 'new' | 'modern')[]
+ Furnishing?: ('furnished' | 'unfurnished' | 'partFurnished')[]
+ Locality?: ('rural' | 'village' | 'townCity')[]
+ Parking?: ('residents' | 'offStreet' | 'secure' | 'underground' | 'garage' | 'doubleGarage' | 'tripleGarage')[]
+ Situation?: ('garden' | 'land' | 'patio' | 'roofTerrace' | 'conservatory' | 'balcony' | 'communalGardens')[]
+ Style?: (
+ | 'terraced'
+ | 'endTerrace'
+ | 'detached'
+ | 'semiDetached'
+ | 'linkDetached'
+ | 'mews'
+ | 'basement'
+ | 'lowerGroundFloor'
+ | 'groundFloor'
+ | 'firstFloor'
+ | 'upperFloor'
+ | 'upperFloorWithLift'
+ | 'penthouse'
+ )[]
+ Type?: (
+ | 'house'
+ | 'bungalow'
+ | 'flatApartment'
+ | 'maisonette'
+ | 'land'
+ | 'farm'
+ | 'cottage'
+ | 'studio'
+ | 'townhouse'
+ | 'developmentPlot'
+ )[]
+ MarketingMode?: ('selling' | 'letting' | 'sellingAndLetting')[]
+}
+/**
+ * An appointment attendee
+ */
+export interface AppointmentAttendeeModel {
+ /**
+ * The unique identifier of the attendee
+ */
+ id?: string
+ /**
+ * The type of attendee
+ */
+ type?: string
+ /**
+ * A collection of contacts relating to the attendee
+ */
+ contacts?: {
+ /**
+ * The unique identifier of the contact
+ */
+ id?: string
+ /**
+ * The name of the contact
+ */
+ name?: string
+ /**
+ * The home phone number of the contact
+ */
+ homePhone?: string
+ /**
+ * The work phone number of the contact
+ */
+ workPhone?: string
+ /**
+ * The mobile phone number of the contact
+ */
+ mobilePhone?: string
+ /**
+ * The email address of the contact
+ */
+ email?: string
+ }[]
+}
+/**
+ * A summarised view of the details of a contact associated to an appointment attendee
+ */
+export interface AppointmentContactModel {
+ /**
+ * The unique identifier of the contact
+ */
+ id?: string
+ /**
+ * The name of the contact
+ */
+ name?: string
+ /**
+ * The home phone number of the contact
+ */
+ homePhone?: string
+ /**
+ * The work phone number of the contact
+ */
+ workPhone?: string
+ /**
+ * The mobile phone number of the contact
+ */
+ mobilePhone?: string
+ /**
+ * The email address of the contact
+ */
+ email?: string
+}
+/**
+ * Follow up information relating to an appointment
+ */
+export interface AppointmentFollowUpModel {
+ /**
+ * The date when the appointment should be followed up
+ * example:
+ * 2019-08-14
+ */
+ due?: string // date
+ /**
+ * The unique identifier of a pre-defined follow up response type
+ */
+ responseId?: string
+ /**
+ * Free text internal follow up notes to be stored against the appointment
+ */
+ notes?: string
+}
+/**
+ * Representation of a calendar appointment
+ */
+export interface AppointmentModel {
+ /**
+ * The unique identifier of the appointment
+ */
+ id?: string
+ /**
+ * The date and time when the appointment was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the appointment was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The date and time when the appointment will start
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ start?: string // date-time
+ /**
+ * The date and time when the appointment will end
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ end?: string // date-time
+ /**
+ * The unique identifier of the appointment type
+ */
+ typeId?: string
+ /**
+ * A free text description about the appointment
+ */
+ description?: string
+ /**
+ * A flag denoting whether or not the appointment recurs
+ */
+ recurring?: boolean
+ /**
+ * A flag denoting whether or not the appointment has been cancelled
+ */
+ cancelled?: boolean
+ /**
+ * Follow up information relating to the appointment
+ */
+ followUp?: {
+ /**
+ * The date when the appointment should be followed up
+ * example:
+ * 2019-08-14
+ */
+ due?: string // date
+ /**
+ * The unique identifier of a pre-defined follow up response type
+ */
+ responseId?: string
+ /**
+ * Free text internal follow up notes to be stored against the appointment
+ */
+ notes?: string
+ }
+ /**
+ * The unique identifier of the property related to the appointment
+ */
+ propertyId?: string
+ /**
+ * The unique identifier of the negotiator that organised the appointment
+ */
+ organiserId?: string
+ /**
+ * A collection of unique identifiers of negotiators attached to the appointment
+ */
+ negotiatorIds?: string[]
+ /**
+ * A collection of unique identifiers of offices attached to the appointment
+ */
+ officeIds?: string[]
+ /**
+ * An appointment attendee
+ */
+ attendee?: {
+ /**
+ * The unique identifier of the attendee
+ */
+ id?: string
+ /**
+ * The type of attendee
+ */
+ type?: string
+ /**
+ * A collection of contacts relating to the attendee
+ */
+ contacts?: {
+ /**
+ * The unique identifier of the contact
+ */
+ id?: string
+ /**
+ * The name of the contact
+ */
+ name?: string
+ /**
+ * The home phone number of the contact
+ */
+ homePhone?: string
+ /**
+ * The work phone number of the contact
+ */
+ workPhone?: string
+ /**
+ * The mobile phone number of the contact
+ */
+ mobilePhone?: string
+ /**
+ * The email address of the contact
+ */
+ email?: string
+ }[]
+ }
+ /**
+ * A flag denoting whether or not the appointment will be accompanied by one or more negotiators
+ */
+ accompanied?: boolean
+ /**
+ * A flag denoting whether or not the main negotiator has confirmed their attendance
+ */
+ negotiatorConfirmed?: boolean
+ /**
+ * A flag denoting whether or not the attendee has confirmed their attendance
+ */
+ attendeeConfirmed?: boolean
+ /**
+ * A flag denoting whether or not the property and/or property's vendor has confirmed their attendance
+ */
+ propertyConfirmed?: boolean
+ /**
+ * App specific metadata that has been set against the appointment
+ */
+ metadata?: {
+ [name: string]: any
+ }
+ /**
+ * The ETag for the current version of the appointment. Used for managing update concurrency
+ */
+ readonly _eTag?: string
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+}
+export interface Appointments {
+ PageSize?: number
+ PageNumber?: number
+ SortBy?: string
+ Id?: string[]
+ TypeId?: string[]
+ NegotiatorId?: string[]
+ OfficeId?: string[]
+ PropertyId?: string[]
+ Start?: string
+ End?: string
+ IncludeCancelled?: boolean
+ IncludeUnconfirmed?: boolean
+ Embed?: ('negotiators' | 'offices' | 'organiser' | 'property' | 'type')[]
+}
+/**
+ * Representation of an area that properties reside in, or applicants are looking to buy/rent in
+ */
+export interface AreaModel {
+ /**
+ * The unique identifier of the area
+ */
+ id?: string
+ /**
+ * The date and time when the area was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the area was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The name of the area
+ */
+ name?: string
+ /**
+ * A flag denoting whether the area can currently be selected against properties and applicants
+ */
+ active?: boolean
+ /**
+ * The type of area (postcodes/polygon/group)
+ */
+ type?: string
+ /**
+ * The location details (comma delimited list of postcodes, group ids or lat/long coordinate groups)
+ */
+ area?: string[]
+ /**
+ * A collection of unique identifiers of departments associated to the area
+ */
+ departmentIds?: string[]
+ /**
+ * A collection of unique identifiers of offices associated to the area
+ */
+ officeIds?: string[]
+ /**
+ * The ETag for the current version of the area. Used for managing update concurrency
+ */
+ readonly _eTag?: string
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+}
+export interface Areas {
+ PageSize?: number
+ PageNumber?: number
+ SortBy?: string
+ Id?: string[]
+ DepartmentId?: string[]
+ OfficeId?: string[]
+ Name?: string
+ Active?: boolean
+}
+export interface Companies {
+ PageSize?: number
+ PageNumber?: number
+ SortBy?: string
+ Id?: string[]
+ Address?: string
+ Branch?: string
+ Name?: string
+ TypeId?: string
+ CreatedFrom?: string
+ CreatedTo?: string
+ Embed?: 'companyTypes'[]
+}
+/**
+ * Representation of the physical address of a building or premise
+ */
+export interface CompanyAddressModel {
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides within
+ */
+ country?: string
+}
+/**
+ * Representation of a company
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+export interface CompanyModel {
+ /**
+ * The unique identifier of the company
+ */
+ id?: string
+ /**
+ * The date and time when the company was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the company was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The name of the company
+ */
+ name?: string
+ /**
+ * The branch name of the company
+ */
+ branch?: string
+ /**
+ * A free text field containing notes that describe the company's business or service offering
+ */
+ notes?: string
+ /**
+ * A flag determining whether or not the company is currently active
+ */
+ active?: boolean
+ /**
+ * A flag determining whether or not the company is VAT registered
+ */
+ vatRegistered?: boolean
+ /**
+ * A collection of unique identifiers of company types that categorise the type of business the company operates
+ */
+ typeIds?: string[]
+ /**
+ * The unique identifier of a supplier type, if the company is a supplier
+ */
+ supplierTypeId?: string
+ /**
+ * The work phone number of the company
+ */
+ workPhone?: string
+ /**
+ * The mobile phone number of the company
+ */
+ mobilePhone?: string
+ /**
+ * The email address of the company
+ */
+ email?: string
+ /**
+ * The address of the company
+ */
+ address?: {
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides within
+ */
+ country?: string
+ }
+ /**
+ * App specific metadata that has been set against the company
+ */
+ metadata?: {
+ [name: string]: any
+ }
+ /**
+ * The ETag for the current version of the company. Used for managing update concurrency
+ */
+ readonly _eTag?: string
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+}
+export interface ConfigurationCompanyTypes {
+ Id?: string[]
+}
+/**
+ * Representation of the physical address of a building or premise
+ */
+export interface ContactAddressModel {
+ /**
+ * The type of address (primary/secondary/home/work/forwarding/company/previous)
+ */
+ type?: string
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides in
+ */
+ countryId?: string
+}
+/**
+ * Representation of an individual contact
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+export interface ContactModel {
+ /**
+ * The unique identifier of the contact
+ */
+ id?: string
+ /**
+ * The date and time when the contact was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the contact was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The contact's title (eg. Mr, Mrs, Miss, Dr)
+ */
+ title?: string
+ /**
+ * The contact's forename
+ */
+ forename?: string
+ /**
+ * The contact's surname
+ */
+ surname?: string
+ /**
+ * The contact's date of birth
+ * example:
+ * 2019-08-14
+ */
+ dateOfBirth?: string // date
+ /**
+ * A flag determining whether or not the contact is currently active
+ */
+ active?: boolean
+ /**
+ * The marketing consent status of the contact (grant/deny/notAsked)
+ */
+ marketingConsent?: string
+ /**
+ * The status of the last identity check performed against the contact (pass/fail/pending/cancelled/warnings/unchecked)
+ */
+ identityCheck?: string
+ /**
+ * The source of the contact
+ */
+ source?: {
+ /**
+ * The unique identifier of the source of the contact
+ */
+ id?: string
+ /**
+ * The source type (office/source)
+ */
+ type?: string
+ }
+ /**
+ * The home phone number of the contact
+ */
+ homePhone?: string
+ /**
+ * The work phone number of the contact
+ */
+ workPhone?: string
+ /**
+ * The mobile phone number of the contact
+ */
+ mobilePhone?: string
+ /**
+ * The email address of the contact
+ */
+ email?: string
+ /**
+ * The primary address of the contact
+ */
+ primaryAddress?: {
+ /**
+ * The type of address (primary/secondary/home/work/forwarding/company/previous)
+ */
+ type?: string
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides in
+ */
+ countryId?: string
+ }
+ /**
+ * The secondary address of the contact
+ */
+ secondaryAddress?: {
+ /**
+ * The type of address (primary/secondary/home/work/forwarding/company/previous)
+ */
+ type?: string
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides in
+ */
+ countryId?: string
+ }
+ /**
+ * The work address of the contact
+ */
+ workAddress?: {
+ /**
+ * The type of address (primary/secondary/home/work/forwarding/company/previous)
+ */
+ type?: string
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides in
+ */
+ countryId?: string
+ }
+ /**
+ * A collection of unique identifiers of offices attached to the contact
+ */
+ officeIds?: string[]
+ /**
+ * A collection of unique identifiers of negotiators attached to the contact
+ */
+ negotiatorIds?: string[]
+ /**
+ * App specific metadata that has been set against the contact
+ */
+ metadata?: {
+ [name: string]: any
+ }
+ /**
+ * The ETag for the current version of the contact. Used for managing update concurrency
+ */
+ readonly _eTag?: string
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+}
+/**
+ * Representation of the roles that an individual contacts possesses
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+export interface ContactRoleModel {
+ /**
+ * The unique identifier of the relationship
+ */
+ id?: string
+ /**
+ * The date and time when the relationship was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the relationship was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The unique identifier of the related contact
+ */
+ contactId?: string
+ /**
+ * The type of related entity (applicant/vendor/landlord/tenancy)
+ */
+ associatedType?: string
+ /**
+ * The unique identifier of the related entity
+ */
+ associatedId?: string
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+}
+/**
+ * Representation of a contact's source
+ */
+export interface ContactSourceModel {
+ /**
+ * The unique identifier of the source of the contact
+ */
+ id?: string
+ /**
+ * The source type (office/source)
+ */
+ type?: string
+}
+export interface Contacts {
+ PageSize?: number
+ PageNumber?: number
+ SortBy?: string
+ Id?: string[]
+ NegotiatorId?: string[]
+ OfficeId?: string[]
+ Address?: string
+ IdentityCheck?: string
+ Name?: string
+ MarketingConsent?: string
+ Active?: boolean
+ CreatedFrom?: string
+ CreatedTo?: string
+ Embed?: ('documents' | 'identityChecks' | 'negotiators' | 'offices' | 'source')[]
+}
+/**
+ * The details specific to applicants with a marketingMode of buying
+ */
+export interface CreateApplicantBuyingModel {
+ /**
+ * The lower bound of the applicant's budget
+ */
+ priceFrom?: number // int32
+ /**
+ * The upper bound of the applicant's budget
+ */
+ priceTo?: number // int32
+}
+/**
+ * Request body used to create a relationship between an applicant and a contact or company
+ */
+export interface CreateApplicantContactRelationshipModel {
+ /**
+ * The unique identifier of the contact or company to create a relationship with
+ */
+ associatedId?: string
+ /**
+ * The type of relationship to create (contact/company)
+ */
+ associatedType?: string
+}
+/**
+ * The applicant's outdoor space requirements
+ */
+export interface CreateApplicantExternalAreaModel {
+ /**
+ * The unit of area that each amount corresponds to (acres/hectares)
+ */
+ type?: string
+ /**
+ * The minimum unit value of outside space that the applicant is looking for
+ */
+ amountFrom?: number // double
+ /**
+ * The maximum unit value of outside space that the applicant is looking for
+ */
+ amountTo?: number // double
+}
+/**
+ * The applicant's indoor space requirements
+ */
+export interface CreateApplicantInternalAreaModel {
+ /**
+ * The unit of area that each amount corresponds to (squareFeet/squareMetres)
+ */
+ type?: string
+ /**
+ * The unit value of inside space that the applicant is looking for
+ */
+ amount?: number // double
+}
+/**
+ * Request body used to create a new applicant
+ * example:
+ * [object Object]
+ */
+export interface CreateApplicantModel {
+ /**
+ * Indicates whether the applicant is look to buy or rent a property (buying/renting)
+ */
+ marketingMode?: string
+ /**
+ * A flag determining whether or not the applicant is actively looking for a property
+ */
+ active?: boolean
+ /**
+ * A free text field describing any adhoc buying or renting requirements
+ */
+ notes?: string
+ /**
+ * The date when the applicant was last contacted
+ * example:
+ * 2019-08-14
+ */
+ lastCall?: string // date
+ /**
+ * The date when the applicant is next due to be contacted
+ * example:
+ * 2019-08-14
+ */
+ nextCall?: string // date
+ /**
+ * The unique identifier of the department that the applicant requirements are associated with. The applicant will only match to properties with the same value
+ */
+ departmentId?: string
+ /**
+ * The unique identifier of the solicitor associated to the applicant
+ */
+ solicitorId?: string
+ /**
+ * A list of property type requirements taken from the full listing of the associated department
+ */
+ type?: string[]
+ /**
+ * A list of property style requirements taken from the full listing of the associated department
+ */
+ style?: string[]
+ /**
+ * A list of property situation requirements taken from the full listing of the associated department
+ */
+ situation?: string[]
+ /**
+ * A list of property parking requirements taken from the full listing of the associated department
+ */
+ parking?: string[]
+ /**
+ * A list of property age requirements taken from the full listing of the associated department
+ */
+ age?: string[]
+ /**
+ * A list of property locality requirements taken from the full listing of the associated department
+ */
+ locality?: string[]
+ /**
+ * The minimum number of bedrooms the applicant requires
+ */
+ bedroomsMin?: number // int32
+ /**
+ * The maximum number of bedrooms the applicant requires
+ */
+ bedroomsMax?: number // int32
+ /**
+ * The minimum number of reception rooms the applicant requires
+ */
+ receptionsMin?: number // int32
+ /**
+ * The maximum number of reception rooms the applicant requires
+ */
+ receptionsMax?: number // int32
+ /**
+ * The minimum number of bathrooms the applicant requires
+ */
+ bathroomsMin?: number // int32
+ /**
+ * The maximum number of bathrooms the applicant requires
+ */
+ bathroomsMax?: number // int32
+ /**
+ * The applicant's location type (areas/addresses/none)
+ */
+ locationType?: string
+ /**
+ * The applicant's location options
+ */
+ locationOptions?: string[]
+ /**
+ * The details specific to applicants with a marketingMode of buying
+ */
+ buying?: {
+ /**
+ * The lower bound of the applicant's budget
+ */
+ priceFrom?: number // int32
+ /**
+ * The upper bound of the applicant's budget
+ */
+ priceTo?: number // int32
+ }
+ /**
+ * The details specific to applicants with a marketingMode of renting
+ */
+ renting?: {
+ /**
+ * The date the applicant is looking to move to a new property
+ * example:
+ * 2019-08-14
+ */
+ moveDate?: string // date
+ /**
+ * The applicant's preferred letting term (long/short/any)
+ */
+ term?: string
+ /**
+ * The lower bound of the applicant's budget
+ */
+ rentFrom?: number // double
+ /**
+ * The upper bound of the applicant's budget
+ */
+ rentTo?: number // double
+ /**
+ * The desired rent collection frequency specified by the applicant's budget (weekly/monthly/annually)
+ */
+ rentFrequency?: string
+ /**
+ * A list of property furnishing requirements taken from the full listing of the associated department
+ */
+ furnishing?: string[]
+ }
+ /**
+ * The applicant's outdoor space requirements
+ */
+ externalArea?: {
+ /**
+ * The unit of area that each amount corresponds to (acres/hectares)
+ */
+ type?: string
+ /**
+ * The minimum unit value of outside space that the applicant is looking for
+ */
+ amountFrom?: number // double
+ /**
+ * The maximum unit value of outside space that the applicant is looking for
+ */
+ amountTo?: number // double
+ }
+ /**
+ * The applicant's indoor space requirements
+ */
+ internalArea?: {
+ /**
+ * The unit of area that each amount corresponds to (squareFeet/squareMetres)
+ */
+ type?: string
+ /**
+ * The unit value of inside space that the applicant is looking for
+ */
+ amount?: number // double
+ }
+ /**
+ * The source of the applicant
+ */
+ source?: {
+ /**
+ * The unique identifier of the applicant's source
+ */
+ id?: string
+ /**
+ * The source type (office/source)
+ */
+ type?: string
+ }
+ /**
+ * A collection of unique identifiers of offices attached to the applicant. The first item in the collection is considered the primary office
+ */
+ officeIds?: string[]
+ /**
+ * A collection of unique identifiers of negotiators attached to the applicant. The first item in the collection is considered the primary negotiator
+ */
+ negotiatorIds?: string[]
+ /**
+ * A collection of contacts and/or companies associated to the applicant. The first item in the collection is considered the primary relationship
+ */
+ related?: {
+ /**
+ * The unique identifier of the contact or company to create a relationship with
+ */
+ associatedId?: string
+ /**
+ * The type of relationship to create (contact/company)
+ */
+ associatedType?: string
+ }[]
+ /**
+ * App specific metadata to set against the applicant
+ */
+ metadata?: {
+ [name: string]: any
+ }
+}
+/**
+ * The details specific to applicants with a marketingMode of renting
+ */
+export interface CreateApplicantRentingModel {
+ /**
+ * The date the applicant is looking to move to a new property
+ * example:
+ * 2019-08-14
+ */
+ moveDate?: string // date
+ /**
+ * The applicant's preferred letting term (long/short/any)
+ */
+ term?: string
+ /**
+ * The lower bound of the applicant's budget
+ */
+ rentFrom?: number // double
+ /**
+ * The upper bound of the applicant's budget
+ */
+ rentTo?: number // double
+ /**
+ * The desired rent collection frequency specified by the applicant's budget (weekly/monthly/annually)
+ */
+ rentFrequency?: string
+ /**
+ * A list of property furnishing requirements taken from the full listing of the associated department
+ */
+ furnishing?: string[]
+}
+/**
+ * An applicant's source of enquiry
+ */
+export interface CreateApplicantSourceModel {
+ /**
+ * The unique identifier of the applicant's source
+ */
+ id?: string
+ /**
+ * The source type (office/source)
+ */
+ type?: string
+}
+/**
+ * Represents an external attendee on an appointment
+ */
+export interface CreateAppointmentAttendeeModel {
+ /**
+ * The unique identifier of the attendee
+ */
+ id?: string
+ /**
+ * The type of attendee (applicant/contact/landlord/tenant)
+ */
+ type?: string
+}
+/**
+ * Request body used to create a new calendar appointment
+ * example:
+ * [object Object]
+ */
+export interface CreateAppointmentModel {
+ /**
+ * The date and time when the appointment will start
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ start?: string // date-time
+ /**
+ * The date and time when the appointment will end
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ end?: string // date-time
+ /**
+ * The date when the appointment should be followed up
+ * example:
+ * 2019-08-14
+ */
+ followUpOn?: string // date
+ /**
+ * The unique identifier of the appointment type
+ */
+ typeId?: string
+ /**
+ * A free text description about the appointment
+ */
+ description?: string
+ /**
+ * The unique identifier of the negotiator that organised the appointment
+ */
+ organiserId?: string
+ /**
+ * A collection of unique identifiers of negotiators attached to the appointment
+ */
+ negotiatorIds?: string[]
+ /**
+ * A collection of unique identifiers of offices attached to the appointment
+ */
+ officeIds?: string[]
+ /**
+ * Details of the external appointment attendee
+ */
+ attendee?: {
+ /**
+ * The unique identifier of the attendee
+ */
+ id?: string
+ /**
+ * The type of attendee (applicant/contact/landlord/tenant)
+ */
+ type?: string
+ }
+ /**
+ * The unique identifier of the property related to the appointment
+ */
+ propertyId?: string
+ /**
+ * A flag denoting whether or not the appointment will be accompanied by one or more negotiators
+ */
+ accompanied?: boolean
+ /**
+ * A flag denoting whether or not the main negotiator has confirmed their attendance
+ */
+ negotiatorConfirmed?: boolean
+ /**
+ * A flag denoting whether or not the attendee has confirmed their attendance
+ */
+ attendeeConfirmed?: boolean
+ /**
+ * A flag denoting whether or not the property and/or property's vendor has confirmed their attendance
+ */
+ propertyConfirmed?: boolean
+ /**
+ * Details of the recurrence pattern for the appointment
+ */
+ recurrence?: {
+ /**
+ * The numeric value denoting how often the appointment will recur
+ */
+ interval?: number // int32
+ /**
+ * The type of unit that the `interval` applies to
+ */
+ type?: string
+ /**
+ * The date and time when the recurrence will stop
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ until?: string // date-time
+ }
+ /**
+ * App specific metadata to set against the appointment
+ */
+ metadata?: {
+ [name: string]: any
+ }
+}
+/**
+ * Details of an appointment's recurrence pattern
+ */
+export interface CreateAppointmentRecurrenceModel {
+ /**
+ * The numeric value denoting how often the appointment will recur
+ */
+ interval?: number // int32
+ /**
+ * The type of unit that the `interval` applies to
+ */
+ type?: string
+ /**
+ * The date and time when the recurrence will stop
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ until?: string // date-time
+}
+/**
+ * Request body used to create a new area
+ * example:
+ * [object Object]
+ */
+export interface CreateAreaModel {
+ /**
+ * The name of the area
+ */
+ name?: string
+ /**
+ * The type of area (postcodes/polygon/group)
+ */
+ type?: string
+ /**
+ * The location details (comma delimited list of postcodes, group ids or lat/long coordinate groups)
+ */
+ area?: string[]
+ /**
+ * A collection of unique identifiers of departments associated to the area
+ */
+ departmentIds?: string[]
+ /**
+ * A collection of unique identifiers of offices associated to the area
+ */
+ officeIds?: string[]
+ /**
+ * The unique identifier of the parent area, if the area should be registered as a child area/group in an existing area group
+ */
+ parentId?: string
+}
+/**
+ * Request body to set the address of a new company
+ */
+export interface CreateCompanyAddressModel {
+ /**
+ * The type of address (primary/secondary/home/work/forwarding/company/previous)
+ */
+ type?: string
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides within
+ */
+ countryId?: string
+}
+/**
+ * Request body used to create a new company
+ * example:
+ * [object Object]
+ */
+export interface CreateCompanyModel {
+ /**
+ * The name of the company
+ */
+ name?: string
+ /**
+ * The branch name of the company
+ */
+ branch?: string
+ /**
+ * A free text field containing notes that describe the company's business or service offering
+ */
+ notes?: string
+ /**
+ * A flag determining whether or not the company is currently active
+ */
+ active?: boolean
+ /**
+ * A flag determining whether or not the company is VAT registered
+ */
+ vatRegistered?: boolean
+ /**
+ * A collection of unique identifiers of company types that categorise the type of business the company operates
+ */
+ typeIds?: string[]
+ /**
+ * The unique identifier of a supplier type, if the company is a supplier
+ */
+ supplierTypeId?: string
+ /**
+ * The work phone number of the company
+ */
+ workPhone?: string
+ /**
+ * The mobile phone number of the company
+ */
+ mobilePhone?: string
+ /**
+ * The email address of the company
+ */
+ email?: string
+ /**
+ * The address of the company
+ */
+ address?: {
+ /**
+ * The type of address (primary/secondary/home/work/forwarding/company/previous)
+ */
+ type?: string
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides within
+ */
+ countryId?: string
+ }
+ /**
+ * App specific metadata to set against the company
+ */
+ metadata?: {
+ [name: string]: any
+ }
+}
+/**
+ * Request body used to set an address against a new contact
+ */
+export interface CreateContactAddressModel {
+ /**
+ * The type of address (primary/secondary/home/work/forwarding/company/previous)
+ */
+ type?: string
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides in
+ */
+ countryId?: string
+}
+/**
+ * Request body used to create a new contact
+ * example:
+ * [object Object]
+ */
+export interface CreateContactModel {
+ /**
+ * The contact's title (eg. Mr, Mrs, Miss, Dr)
+ */
+ title?: string
+ /**
+ * The contact's forename
+ */
+ forename?: string
+ /**
+ * The contact's surname
+ */
+ surname?: string
+ /**
+ * The contact's date of birth
+ * example:
+ * 2019-08-14
+ */
+ dateOfBirth?: string // date
+ /**
+ * A flag determining whether or not the contact is currently active
+ */
+ active?: boolean
+ /**
+ * The marketing consent status of the contact (grant/deny/notAsked)
+ */
+ marketingConsent?: string
+ /**
+ * The source of the contact
+ */
+ source?: {
+ /**
+ * The unique identifier of the source of the contact
+ */
+ id?: string
+ /**
+ * The source type (office/source)
+ */
+ type?: string
+ }
+ /**
+ * The home phone number of the contact
+ */
+ homePhone?: string
+ /**
+ * The work phone number of the contact
+ */
+ workPhone?: string
+ /**
+ * The mobile phone number of the contact
+ */
+ mobilePhone?: string
+ /**
+ * The email address of the contact
+ */
+ email?: string
+ /**
+ * A collection of unique identifiers of offices attached to the contact
+ */
+ officeIds?: string[]
+ /**
+ * A collection of unique identifiers of negotiators attached to the contact
+ */
+ negotiatorIds?: string[]
+ /**
+ * The primary address of the contact
+ */
+ primaryAddress?: {
+ /**
+ * The type of address (primary/secondary/home/work/forwarding/company/previous)
+ */
+ type?: string
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides in
+ */
+ countryId?: string
+ }
+ /**
+ * The secondary address of the contact
+ */
+ secondaryAddress?: {
+ /**
+ * The type of address (primary/secondary/home/work/forwarding/company/previous)
+ */
+ type?: string
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides in
+ */
+ countryId?: string
+ }
+ /**
+ * The work address of the contact
+ */
+ workAddress?: {
+ /**
+ * The type of address (primary/secondary/home/work/forwarding/company/previous)
+ */
+ type?: string
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides in
+ */
+ countryId?: string
+ }
+ /**
+ * App specific metadata to set against the contact
+ */
+ metadata?: {
+ [name: string]: any
+ }
+}
+/**
+ * Request body used to set the source of a new contact
+ */
+export interface CreateContactSourceModel {
+ /**
+ * The unique identifier of the source of the contact
+ */
+ id?: string
+ /**
+ * The source type (office/source)
+ */
+ type?: string
+}
+/**
+ * Request body used to create a new document
+ * example:
+ * [object Object]
+ */
+export interface CreateDocumentModel {
+ /**
+ * The type of entity that the document is associated with (appliance/applicant/bankStatement/batch/certificate/contact/depositCertificate/estate/estateUnit/idCheck/keySet/landlord/nominalTransaction/property/tenancy/tenancyCheck/tenancyRenewal/worksOrder)
+ */
+ associatedType?: string
+ /**
+ * The unique identifier of the entity that the document is associated with
+ */
+ associatedId?: string
+ /**
+ * The unique identifier of the type of document
+ */
+ typeId?: string
+ /**
+ * The filename of the document
+ */
+ name?: string
+ /**
+ * The base64 encoded document content, prefixed with the content type (eg. data:text/plain;base64,VGVzdCBmaWxl)
+ */
+ fileData?: string
+}
+/**
+ * Request body used to create a new contact identity check
+ * example:
+ * [object Object]
+ */
+export interface CreateIdentityCheckModel {
+ /**
+ * The unique identifier of the contact associated to the identity check
+ */
+ contactId?: string
+ /**
+ * The date when the identity check was performed. This may differ to the date when the check was created
+ * example:
+ * 2019-08-14
+ */
+ checkDate?: string // date
+ /**
+ * The current status of the identity check (pass/fail/pending/cancelled/warnings/unchecked)
+ */
+ status?: string
+ /**
+ * The unique identifier of the negotiator that initiated the identity check
+ */
+ negotiatorId?: string
+ /**
+ * The details of the first document that was provided as part of the identity check
+ */
+ identityDocument1?: {
+ /**
+ * The unique identifier of the type of identity document provided
+ */
+ typeId?: string
+ /**
+ * The date when the document expires and becomes invalid
+ * example:
+ * 2019-08-14
+ */
+ expiry?: string // date
+ /**
+ * Details regarding the identity document (eg. passport number)
+ */
+ details?: string
+ /**
+ * The base64 encoded identity document content, prefixed with the content type (eg. data:text/plain;base64,VGVzdCBmaWxl)
+ */
+ fileData?: string
+ /**
+ * The filename to store the document as
+ */
+ name?: string
+ }
+ /**
+ * The details of the second document that was provided as part of the identity check
+ */
+ identityDocument2?: {
+ /**
+ * The unique identifier of the type of identity document provided
+ */
+ typeId?: string
+ /**
+ * The date when the document expires and becomes invalid
+ * example:
+ * 2019-08-14
+ */
+ expiry?: string // date
+ /**
+ * Details regarding the identity document (eg. passport number)
+ */
+ details?: string
+ /**
+ * The base64 encoded identity document content, prefixed with the content type (eg. data:text/plain;base64,VGVzdCBmaWxl)
+ */
+ fileData?: string
+ /**
+ * The filename to store the document as
+ */
+ name?: string
+ }
+ /**
+ * App specific metadata to set against the identity check
+ */
+ metadata?: {
+ [name: string]: any
+ }
+}
+/**
+ * Request body to attach an identity document to a new contact identity check
+ */
+export interface CreateIdentityDocumentModel {
+ /**
+ * The unique identifier of the type of identity document provided
+ */
+ typeId?: string
+ /**
+ * The date when the document expires and becomes invalid
+ * example:
+ * 2019-08-14
+ */
+ expiry?: string // date
+ /**
+ * Details regarding the identity document (eg. passport number)
+ */
+ details?: string
+ /**
+ * The base64 encoded identity document content, prefixed with the content type (eg. data:text/plain;base64,VGVzdCBmaWxl)
+ */
+ fileData?: string
+ /**
+ * The filename to store the document as
+ */
+ name?: string
+}
+/**
+ * Request body used to create a new relationship between a landlord and a contact or company
+ */
+export interface CreateLandlordContactRelationshipModel {
+ /**
+ * The unique identifier of the contact or company to create a relationship with
+ */
+ associatedId?: string
+ /**
+ * The type of relationship to create (contact/company)
+ */
+ associatedType?: string
+}
+/**
+ * Request body used to create a new landlord
+ * example:
+ * [object Object]
+ */
+export interface CreateLandlordModel {
+ /**
+ * A flag determining whether or not the landlord is currently active
+ */
+ active?: boolean
+ /**
+ * The unique identifier of the company acting as the landlord's solicitor
+ */
+ solicitorId?: string
+ /**
+ * The unique identifier of the office that is associated to the landlord
+ */
+ officeId?: string
+ /**
+ * The source of the landlord
+ */
+ source?: {
+ /**
+ * The unique identifier of the source of the landlord
+ */
+ id?: string
+ /**
+ * The source type (office/source)
+ */
+ type?: string
+ }
+ /**
+ * A collection of contacts and/or companies associated to the landlord. The first item in the collection is considered the primary relationship
+ */
+ related?: {
+ /**
+ * The unique identifier of the contact or company to create a relationship with
+ */
+ associatedId?: string
+ /**
+ * The type of relationship to create (contact/company)
+ */
+ associatedType?: string
+ }[]
+ /**
+ * App specific metadata that to set against the landlord
+ */
+ metadata?: {
+ [name: string]: any
+ }
+}
+/**
+ * Request body used to set the source of a new landlord
+ */
+export interface CreateLandlordSourceModel {
+ /**
+ * The unique identifier of the source of the landlord
+ */
+ id?: string
+ /**
+ * The source type (office/source)
+ */
+ type?: string
+}
+/**
+ * Request body used to create a new negotiator
+ * example:
+ * [object Object]
+ */
+export interface CreateNegotiatorModel {
+ /**
+ * The name of the negotiator
+ */
+ name?: string
+ /**
+ * The job title of the negotiator
+ */
+ jobTitle?: string
+ /**
+ * A flag determining whether or not the negotiator is active
+ */
+ active?: boolean
+ /**
+ * The unique identifier of the office that the negotiator is attached to
+ */
+ officeId?: string
+ /**
+ * The work phone number of the negotiator
+ */
+ workPhone?: string
+ /**
+ * The mobile phone number of the negotiator
+ */
+ mobilePhone?: string
+ /**
+ * The email address of the negotiator
+ */
+ email?: string
+ /**
+ * App specific metadata to set against the negotiator
+ */
+ metadata?: {
+ [name: string]: any
+ }
+}
+/**
+ * Request body used to create a new offer
+ * example:
+ * [object Object]
+ */
+export interface CreateOfferModel {
+ /**
+ * The unique identifier of the applicant associated to the offer
+ */
+ applicantId?: string
+ /**
+ * The unique identifier of the property associated to the offer
+ */
+ propertyId?: string
+ /**
+ * The unique identifier of the negotiator associated to the offer
+ */
+ negotiatorId?: string
+ /**
+ * The date when the offer was made
+ * example:
+ * 2019-08-14
+ */
+ date?: string // date
+ /**
+ * The monetary amount of the offer
+ */
+ amount?: number // double
+ /**
+ * The current status of the offer (pending/withdrawn/rejected/accepted/noteOfInterest)
+ */
+ status?: string
+ /**
+ * A free text field describing items that should be included in the sale
+ */
+ inclusions?: string
+ /**
+ * A free text field describing items that are explicitly excluded from the sale
+ */
+ exclusions?: string
+ /**
+ * A free text field describing any other conditions set by either party that relate to the sale
+ */
+ conditions?: string
+ /**
+ * App specific metadata to set against the offer
+ */
+ metadata?: {
+ [name: string]: any
+ }
+}
+/**
+ * Request body used to set the address of a new office
+ */
+export interface CreateOfficeAddressModel {
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides within
+ */
+ countryId?: string
+}
+/**
+ * Request body used to create a new office
+ * example:
+ * [object Object]
+ */
+export interface CreateOfficeModel {
+ /**
+ * The name of the office
+ */
+ name?: string
+ /**
+ * The name of the office manager
+ */
+ manager?: string
+ /**
+ * The address of the office
+ */
+ address?: {
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides within
+ */
+ countryId?: string
+ }
+ /**
+ * The work phone number of the office
+ */
+ workPhone?: string
+ /**
+ * The email address of the office
+ */
+ email?: string
+ /**
+ * App specific metadata to set against the office
+ */
+ metadata?: {
+ [name: string]: any
+ }
+}
+/**
+ * Request body used to set the address of a new property
+ */
+export interface CreatePropertyAddressModel {
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides within
+ */
+ countryId?: string
+ /**
+ * The geolocation coordinates associated with the address
+ */
+ geolocation?: {
+ /**
+ * The latitude coordinate of the coordinate pair
+ */
+ latitude?: number // double
+ /**
+ * The longitude coordinate of the coordinate pair
+ */
+ longitude?: number // double
+ }
+}
+/**
+ * Request body used to set the EPC statistic of a new property
+ */
+export interface CreatePropertyEpcModel {
+ /**
+ * A flag denoting whether or not this property is exempt from requiring an EPC certificate
+ */
+ exempt?: boolean
+ /**
+ * The current energy efficiency rating
+ */
+ eer?: number // int32
+ /**
+ * The potential energy efficiency rating
+ */
+ eerPotential?: number // int32
+ /**
+ * The current environmental impact rating
+ */
+ eir?: number // int32
+ /**
+ * The potential environmental impact rating
+ */
+ eirPotential?: number // int32
+}
+/**
+ * Request body to set the external land area of a new property
+ */
+export interface CreatePropertyExternalAreaModel {
+ /**
+ * The unit of area (acres/hectares)
+ */
+ type?: string
+ /**
+ * The minimum area bound
+ */
+ min?: number // double
+ /**
+ * The maximum area bound
+ */
+ max?: number // double
+}
+/**
+ * Request body used to set the geolocation coordinates of a new property's address
+ */
+export interface CreatePropertyGeolocationModel {
+ /**
+ * The latitude coordinate of the coordinate pair
+ */
+ latitude?: number // double
+ /**
+ * The longitude coordinate of the coordinate pair
+ */
+ longitude?: number // double
+}
+/**
+ * Request body used to create a new property image
+ * example:
+ * [object Object]
+ */
+export interface CreatePropertyImageModel {
+ /**
+ * The base64 encoded file content, prefixed with the content type (eg. data:image/jpeg;base64,VGVzdCBmaWxl)
+ */
+ data?: string
+ /**
+ * The unique identifier of the property attached to the image
+ */
+ propertyId?: string
+ /**
+ * The image caption
+ */
+ caption?: string
+ /**
+ * The type of image (picture/floorPlan/epc/map)
+ */
+ type?: string
+}
+/**
+ * Request body to set the internal dimensions of a new property
+ */
+export interface CreatePropertyInternalAreaModel {
+ /**
+ * The unit of area (squareFeet/squareMetres)
+ */
+ type?: string
+ /**
+ * The minimum area bound
+ */
+ min?: number // double
+ /**
+ * The maximum area bound
+ */
+ max?: number // double
+}
+/**
+ * Request body used to set details specific to lettings marketing on a new property
+ */
+export interface CreatePropertyLettingModel {
+ /**
+ * The date the property was marked as to let
+ * example:
+ * 2019-08-14
+ */
+ instructed?: string // date
+ /**
+ * The date the property is available from
+ * example:
+ * 2019-08-14
+ */
+ availableFrom?: string // date
+ /**
+ * The date the property is available to
+ * example:
+ * 2019-08-14
+ */
+ availableTo?: string // date
+ /**
+ * The rent being charged for the property
+ */
+ rent?: number // double
+ /**
+ * The frequency at which rent will be collected (weekly/monthly/yearly)
+ */
+ rentFrequency?: string
+ /**
+ * The acceptable letting terms (short/long/any)
+ */
+ term?: string
+ /**
+ * The current status of the let (valuation/toLet/toLetUnavailable/underOffer/underOfferUnavailable/arrangingTenancyUnavailable/arrangingTenancy/tenancyCurrentUnavailable/tenancyCurrent/tenancyFinished/tenancyCancelled/sold/letByOtherAgent/letPrivately/provisional/withdrawn)
+ */
+ status?: string
+}
+/**
+ * Request body used to create a new property
+ * example:
+ * [object Object]
+ */
+export interface CreatePropertyModel {
+ /**
+ * The marketing mode of the property (selling/letting/sellingAndLetting)
+ */
+ marketingMode?: string
+ /**
+ * The unique identifier of the department
+ */
+ departmentId?: string
+ /**
+ * The strapline description containing a short summary about the property
+ */
+ strapline?: string
+ /**
+ * The brief description of the property
+ */
+ description?: string
+ /**
+ * The summary of accommodation, typically short phrases or bullet points describing the key features of the property
+ */
+ summary?: string
+ /**
+ * The address of the property
+ */
+ address?: {
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides within
+ */
+ countryId?: string
+ /**
+ * The geolocation coordinates associated with the address
+ */
+ geolocation?: {
+ /**
+ * The latitude coordinate of the coordinate pair
+ */
+ latitude?: number // double
+ /**
+ * The longitude coordinate of the coordinate pair
+ */
+ longitude?: number // double
+ }
+ }
+ /**
+ * The total number of bedrooms in the property
+ */
+ bedrooms?: number // int32
+ /**
+ * The total number of reception rooms in the property
+ */
+ receptions?: number // int32
+ /**
+ * The total number of bathrooms in the property
+ */
+ bathrooms?: number // int32
+ /**
+ * The council tax banding of the property (A/B/C/D/E/F/G/H)
+ */
+ councilTax?: string
+ /**
+ * A flag denoting whether or not this property can be advertised on the internet
+ */
+ internetAdvertising?: boolean
+ /**
+ * The arrangements regarding viewing the property
+ */
+ viewingArrangements?: string
+ /**
+ * Details of the EPC statistics
+ */
+ epc?: {
+ /**
+ * A flag denoting whether or not this property is exempt from requiring an EPC certificate
+ */
+ exempt?: boolean
+ /**
+ * The current energy efficiency rating
+ */
+ eer?: number // int32
+ /**
+ * The potential energy efficiency rating
+ */
+ eerPotential?: number // int32
+ /**
+ * The current environmental impact rating
+ */
+ eir?: number // int32
+ /**
+ * The potential environmental impact rating
+ */
+ eirPotential?: number // int32
+ }
+ /**
+ * Details of the external land area associated to this property
+ */
+ externalArea?: {
+ /**
+ * The unit of area (acres/hectares)
+ */
+ type?: string
+ /**
+ * The minimum area bound
+ */
+ min?: number // double
+ /**
+ * The maximum area bound
+ */
+ max?: number // double
+ }
+ /**
+ * Details of the internal dimensions of the property
+ */
+ internalArea?: {
+ /**
+ * The unit of area (squareFeet/squareMetres)
+ */
+ type?: string
+ /**
+ * The minimum area bound
+ */
+ min?: number // double
+ /**
+ * The maximum area bound
+ */
+ max?: number // double
+ }
+ /**
+ * Selling specific details about the property
+ */
+ selling?: {
+ /**
+ * The date that the property was marked as for sale
+ * example:
+ * 2019-08-14
+ */
+ instructed?: string // date
+ /**
+ * The marketing price of the property
+ */
+ price?: number // int32
+ /**
+ * The price qualifier (askingPrice/priceOnApplication/guidePrice/offersInRegion/offersOver/offersInExcess/fixedPrice/priceReducedTo)
+ */
+ qualifier?: string
+ /**
+ * The current status of the sale (preAppraisal/valuation/paidValuation/forSale/forSaleUnavailable/underOffer/underOfferUnavailable/reserved/exchanged/completed/soldExternally/withdrawn)
+ */
+ status?: string
+ /**
+ * Details about the tenure of the property
+ */
+ tenure?: {
+ /**
+ * The type of tenure that applies to the property (freehold/leasehold/shareOfFreehold/commonhold/tba)
+ */
+ type?: string
+ /**
+ * The tenure expiration date
+ * example:
+ * 2019-08-14
+ */
+ expiry?: string // date
+ }
+ }
+ /**
+ * Letting specific details about the property
+ */
+ letting?: {
+ /**
+ * The date the property was marked as to let
+ * example:
+ * 2019-08-14
+ */
+ instructed?: string // date
+ /**
+ * The date the property is available from
+ * example:
+ * 2019-08-14
+ */
+ availableFrom?: string // date
+ /**
+ * The date the property is available to
+ * example:
+ * 2019-08-14
+ */
+ availableTo?: string // date
+ /**
+ * The rent being charged for the property
+ */
+ rent?: number // double
+ /**
+ * The frequency at which rent will be collected (weekly/monthly/yearly)
+ */
+ rentFrequency?: string
+ /**
+ * The acceptable letting terms (short/long/any)
+ */
+ term?: string
+ /**
+ * The current status of the let (valuation/toLet/toLetUnavailable/underOffer/underOfferUnavailable/arrangingTenancyUnavailable/arrangingTenancy/tenancyCurrentUnavailable/tenancyCurrent/tenancyFinished/tenancyCancelled/sold/letByOtherAgent/letPrivately/provisional/withdrawn)
+ */
+ status?: string
+ }
+ /**
+ * The property type attributes
+ */
+ type?: string[]
+ /**
+ * The property style attributes
+ */
+ style?: string[]
+ /**
+ * The property situation attributes
+ */
+ situation?: string[]
+ /**
+ * The property parking attributes
+ */
+ parking?: string[]
+ /**
+ * The property age attributes
+ */
+ age?: string[]
+ /**
+ * The property locality attributes
+ */
+ locality?: string[]
+ /**
+ * Details of each room in the property
+ */
+ rooms?: {
+ /**
+ * The name of the room
+ */
+ name?: string
+ /**
+ * Details about the dimensions of the room
+ */
+ dimensions?: string
+ /**
+ * Short description of the room
+ */
+ description?: string
+ }[]
+ /**
+ * The unique identifier of the negotiator managing the property
+ */
+ negotiatorId?: string
+ /**
+ * A collection of unique identifiers of offices attached to the property
+ */
+ officeIds?: string[]
+ /**
+ * The unique identifier of the area that the property resides in
+ */
+ areaId?: string
+ /**
+ * App specific metadata to set against the property
+ */
+ metadata?: {
+ [name: string]: any
+ }
+}
+/**
+ * Request body to create a room in the Rooms collection of a new property
+ */
+export interface CreatePropertyRoomModel {
+ /**
+ * The name of the room
+ */
+ name?: string
+ /**
+ * Details about the dimensions of the room
+ */
+ dimensions?: string
+ /**
+ * Short description of the room
+ */
+ description?: string
+}
+/**
+ * Request body used to set details specific to sales marketing on a new property
+ */
+export interface CreatePropertySellingModel {
+ /**
+ * The date that the property was marked as for sale
+ * example:
+ * 2019-08-14
+ */
+ instructed?: string // date
+ /**
+ * The marketing price of the property
+ */
+ price?: number // int32
+ /**
+ * The price qualifier (askingPrice/priceOnApplication/guidePrice/offersInRegion/offersOver/offersInExcess/fixedPrice/priceReducedTo)
+ */
+ qualifier?: string
+ /**
+ * The current status of the sale (preAppraisal/valuation/paidValuation/forSale/forSaleUnavailable/underOffer/underOfferUnavailable/reserved/exchanged/completed/soldExternally/withdrawn)
+ */
+ status?: string
+ /**
+ * Details about the tenure of the property
+ */
+ tenure?: {
+ /**
+ * The type of tenure that applies to the property (freehold/leasehold/shareOfFreehold/commonhold/tba)
+ */
+ type?: string
+ /**
+ * The tenure expiration date
+ * example:
+ * 2019-08-14
+ */
+ expiry?: string // date
+ }
+}
+/**
+ * Request body used to set the tenure of a new property
+ */
+export interface CreatePropertyTenureModel {
+ /**
+ * The type of tenure that applies to the property (freehold/leasehold/shareOfFreehold/commonhold/tba)
+ */
+ type?: string
+ /**
+ * The tenure expiration date
+ * example:
+ * 2019-08-14
+ */
+ expiry?: string // date
+}
+/**
+ * Request body used to create a new source of business
+ * example:
+ * [object Object]
+ */
+export interface CreateSourceModel {
+ /**
+ * The name of the source or advertising publication
+ */
+ name?: string
+ /**
+ * The type of the source (source/advertisement)
+ */
+ type?: string
+ /**
+ * A collection of the unique identifiers of offices that regularly get business from the source
+ */
+ officeIds?: string[]
+ /**
+ * A collection of unique identifiers of departments that regularly get business from the source
+ */
+ departmentIds?: string[]
+}
+/**
+ * Request body used to create a new task, which can also be an internal message
+ * example:
+ * [object Object]
+ */
+export interface CreateTaskModel {
+ /**
+ * The date the task becomes active
+ * example:
+ * 2019-08-14
+ */
+ activates?: string // date
+ /**
+ * The date the task was completed
+ * example:
+ * 2019-08-14
+ */
+ completed?: string // date
+ /**
+ * The unique identifier of the task type
+ */
+ typeId?: string
+ /**
+ * The unique identifer of the negotiator that created the task
+ */
+ senderId?: string
+ /**
+ * The textual contents of the task or message
+ */
+ text?: string
+ /**
+ * The unique identifier of the landlord the task is associated to
+ */
+ landlordId?: string
+ /**
+ * The unique identifier of the property the task is associated to
+ */
+ propertyId?: string
+ /**
+ * The unique identifier of the applicant the task is associated to
+ */
+ applicantId?: string
+ /**
+ * The unique identifier of the tenancy the task is associated to
+ */
+ tenancyId?: string
+ /**
+ * The unique identifier of the contact the task is associated to
+ */
+ contactId?: string
+ /**
+ * The unique identifier of the negotiator or office the task is being sent to
+ */
+ recipientId?: string
+ /**
+ * The type of the recipient (office/negotiator)
+ */
+ recipientType?: string
+ /**
+ * App specific metadata that has been set against the task
+ */
+ metadata?: {
+ [name: string]: any
+ }
+}
+/**
+ * Representation of a works order item
+ * example:
+ * [object Object]
+ */
+export interface CreateWorksOrderItemModel {
+ /**
+ * The notes attached to the works order item
+ */
+ notes?: string
+ /**
+ * The party to be charged for the work being carried out (landlord/tenant)
+ */
+ chargeTo?: string
+ /**
+ * The estimate of any costs associated with the work being carried out given to the party to be charged for the work
+ */
+ estimate?: number // double
+ /**
+ * The type of estimate supplied (agent/verbal/written)
+ */
+ estimateType?: string
+ /**
+ * The net cost of the work to be carried out
+ */
+ netAmount?: number // double
+ /**
+ * The cost of the vat associated with the work
+ */
+ vatAmount?: number // double
+}
+/**
+ * Request body used to create a new works order
+ * example:
+ * [object Object]
+ */
+export interface CreateWorksOrderModel {
+ /**
+ * The unique identifier of the company that has been selected to perform the work
+ */
+ companyId?: string
+ /**
+ * The unique identifier of the property where the work is to be carried out
+ */
+ propertyId?: string
+ /**
+ * The unique identifier of the tenancy that the works order originated from
+ */
+ tenancyId?: string
+ /**
+ * The unique identifier of the negotiator that booked the works order
+ */
+ negotiatorId?: string
+ /**
+ * The unique id of the type of work that needs to be carried out
+ */
+ typeId?: string
+ /**
+ * The current status of the works order (pendingApproval/pendingQuote/raised/raisedToChase/landlordToComplete/complete/cancelled)
+ */
+ status?: string
+ /**
+ * A free text description of the work required
+ */
+ description?: string
+ /**
+ * The party requesting the work to be carried out (landlord/tenant/other)
+ */
+ reporter?: string
+ /**
+ * The date when the works order was booked
+ * example:
+ * 2019-08-14
+ */
+ booked?: string // date
+ /**
+ * The date when the work is required to be completed by
+ * example:
+ * 2019-08-14
+ */
+ required?: string // date
+ /**
+ * The date when the work was completed
+ * example:
+ * 2019-08-14
+ */
+ completed?: string // date
+ /**
+ * Individual work items to attach to the works order
+ */
+ items?: {
+ /**
+ * The notes attached to the works order item
+ */
+ notes?: string
+ /**
+ * The party to be charged for the work being carried out (landlord/tenant)
+ */
+ chargeTo?: string
+ /**
+ * The estimate of any costs associated with the work being carried out given to the party to be charged for the work
+ */
+ estimate?: number // double
+ /**
+ * The type of estimate supplied (agent/verbal/written)
+ */
+ estimateType?: string
+ /**
+ * The net cost of the work to be carried out
+ */
+ netAmount?: number // double
+ /**
+ * The cost of the vat associated with the work
+ */
+ vatAmount?: number // double
+ }[]
+ /**
+ * App specific metadata to set against the works order
+ */
+ metadata?: {
+ [name: string]: any
+ }
+}
+/**
+ * Representation of a department
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+export interface DepartmentModel {
+ /**
+ * The unique identifier of the department
+ */
+ id?: string
+ /**
+ * The date and time when the department was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the department was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The name of the department
+ */
+ name?: string
+ /**
+ * A collection of property type values that will be accepted by other services
+ */
+ typeOptions?: string[]
+ /**
+ * A collection of property style values that will be accepted by other services
+ */
+ styleOptions?: string[]
+ /**
+ * A collection of property situation values that will be accepted by other services
+ */
+ situationOptions?: string[]
+ /**
+ * A collection of property parking values that will be accepted by other services
+ */
+ parkingOptions?: string[]
+ /**
+ * A collection of property age values that will be accepted by other services
+ */
+ ageOptions?: string[]
+ /**
+ * A collection of property locality values that will be accepted by other services
+ */
+ localityOptions?: string[]
+ /**
+ * The ETag for the current version of the department. Used for managing update concurrency
+ */
+ readonly _eTag?: string
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+}
+export interface Departments {
+ PageSize?: number
+ PageNumber?: number
+ Id?: string[]
+ Name?: string
+}
+/**
+ * Representation of a document
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+export interface DocumentModel {
+ /**
+ * The unique identifier of the document
+ */
+ id?: string
+ /**
+ * The date and time when the document was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the document was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The type of entity that the document is associated with
+ */
+ associatedType?: string
+ /**
+ * The unique identifier of the entity that the document is associated with
+ */
+ associatedId?: string
+ /**
+ * The unique identifier of the type of document
+ */
+ typeId?: string
+ /**
+ * The filename of the document
+ */
+ name?: string
+ /**
+ * The ETag for the current version of the document. Used for managing update concurrency
+ */
+ readonly _eTag?: string
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+}
+export interface Documents {
+ PageSize?: number
+ PageNumber?: number
+ SortBy?: string
+ Id?: string[]
+ AssociatedId?: string[]
+ TypeId?: string[]
+ Embed?: 'documentType'[]
+ AssociatedType?: (
+ | 'appliance'
+ | 'applicant'
+ | 'bankStatement'
+ | 'batch'
+ | 'certificate'
+ | 'contact'
+ | 'depositCertificate'
+ | 'estate'
+ | 'estateUnit'
+ | 'idCheck'
+ | 'keySet'
+ | 'landlord'
+ | 'nominalTransaction'
+ | 'property'
+ | 'tenancy'
+ | 'tenancyCheck'
+ | 'tenancyRenewal'
+ | 'worksOrder'
+ )[]
+}
+export interface EntityTagHeaderValue {
+ readonly tag?: {
+ readonly buffer?: string
+ readonly offset?: number // int32
+ readonly length?: number // int32
+ readonly value?: string
+ readonly hasValue?: boolean
+ }
+ readonly isWeak?: boolean
+}
+export interface FileResult {
+ readonly contentType?: string
+ fileDownloadName?: string
+ lastModified?: string // date-time
+ entityTag?: {
+ readonly tag?: {
+ readonly buffer?: string
+ readonly offset?: number // int32
+ readonly length?: number // int32
+ readonly value?: string
+ readonly hasValue?: boolean
+ }
+ readonly isWeak?: boolean
+ }
+ enableRangeProcessing?: boolean
+}
+/**
+ * Representation of a contact identity check
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+export interface IdentityCheckModel {
+ /**
+ * The unique identifier of the identity check
+ */
+ id?: string
+ /**
+ * The unique identifier of the contact associated to the identity check
+ */
+ contactId?: string
+ /**
+ * The date and time when the identity check was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the identity check was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The date when the identity check was performed. This may differ to the date when the check was created
+ * example:
+ * 2019-08-14
+ */
+ checkDate?: string // date
+ /**
+ * The current status of the identity check (pass/fail/pending/cancelled/warnings/unchecked)
+ */
+ status?: string
+ /**
+ * The unique identifier of the negotiator that initiated the identity check
+ */
+ negotiatorId?: string
+ /**
+ * The details of the first document that was provided as part of the identity check
+ */
+ identityDocument1?: {
+ /**
+ * The unique identifier of the identity document
+ */
+ documentId?: string
+ /**
+ * The unique identifier of the type of identity document provided
+ */
+ typeId?: string
+ /**
+ * The date when the document expires and becomes invalid
+ * example:
+ * 2019-08-14
+ */
+ expiry?: string // date
+ /**
+ * Details regarding the identity document (eg. passport number)
+ */
+ details?: string
+ }
+ /**
+ * The details of the second document that was provided as part of the identity check
+ */
+ identityDocument2?: {
+ /**
+ * The unique identifier of the identity document
+ */
+ documentId?: string
+ /**
+ * The unique identifier of the type of identity document provided
+ */
+ typeId?: string
+ /**
+ * The date when the document expires and becomes invalid
+ * example:
+ * 2019-08-14
+ */
+ expiry?: string // date
+ /**
+ * Details regarding the identity document (eg. passport number)
+ */
+ details?: string
+ }
+ /**
+ * App specific metadata that has been set against the identity check
+ */
+ metadata?: {
+ [name: string]: any
+ }
+ /**
+ * The ETag for the current version of the identity check. Used for managing update concurrency
+ */
+ readonly _eTag?: string
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+}
+export interface IdentityChecks {
+ PageSize?: number
+ PageNumber?: number
+ SortBy?: string
+ Id?: string[]
+ ContactId?: string[]
+ NegotiatorId?: string[]
+ CheckDateFrom?: string
+ CheckDateTo?: string
+ CreatedFrom?: string
+ CreatedTo?: string
+ Embed?: ('contact' | 'document1' | 'document2' | 'documentType1' | 'documentType2')[]
+ Status?: ('unknown' | 'unchecked' | 'pending' | 'fail' | 'cancelled' | 'warnings' | 'pass')[]
+}
+/**
+ * Representation of a single identity document that was provided as part of a contact identity check (eg. passport)
+ */
+export interface IdentityDocumentModel {
+ /**
+ * The unique identifier of the identity document
+ */
+ documentId?: string
+ /**
+ * The unique identifier of the type of identity document provided
+ */
+ typeId?: string
+ /**
+ * The date when the document expires and becomes invalid
+ * example:
+ * 2019-08-14
+ */
+ expiry?: string // date
+ /**
+ * Details regarding the identity document (eg. passport number)
+ */
+ details?: string
+}
+/**
+ * Request body used to create or update a relationship between an applicant and a contact or company
+ * example:
+ * [object Object]
+ */
+export interface InsertApplicantContactRelationshipModel {
+ /**
+ * The unique identifier of the contact or company to create a relationship with
+ */
+ associatedId?: string
+ /**
+ * The type of relationship to create (contact/company)
+ */
+ associatedType?: string
+ /**
+ * Flag denoting whether or not this relationship should be considered to be the main/primary relationship. Setting to true will automatically demote the existing primary relationship
+ */
+ isMain?: boolean
+}
+/**
+ * Request body used to create or update a relationship between a landlord and a contact or company
+ * example:
+ * [object Object]
+ */
+export interface InsertLandlordContactRelationshipModel {
+ /**
+ * The unique identifier of the contact or company to create a relationship with
+ */
+ associatedId?: string
+ /**
+ * The type of relationship to create (contact/company)
+ */
+ associatedType?: string
+ /**
+ * Flag denoting whether or not this relationship should be considered to be the main/primary relationship. Setting to true will automatically demote the existing primary relationship
+ */
+ isMain?: boolean
+}
+/**
+ * Request body used to create or update a relationship between a vendor and a contact or company
+ * example:
+ * [object Object]
+ */
+export interface InsertVendorContactRelationshipModel {
+ /**
+ * The unique identifier of the contact or company to create a relationship with
+ */
+ associatedId?: string
+ /**
+ * The type of relationship to create (contact/company)
+ */
+ associatedType?: string
+ /**
+ * Flag denoting whether or not this relationship should be considered to be the main/primary relationship. Setting to true will automatically demote the existing primary relationship
+ */
+ isMain?: boolean
+}
+/**
+ * Representation of the physical address of a building or premise
+ */
+export interface LandlordContactAddressModel {
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides within
+ */
+ countryId?: string
+}
+/**
+ * A summarised view of the details of a contact associated to a landlord
+ */
+export interface LandlordContactModel {
+ /**
+ * The unique identifier of the contact
+ */
+ id?: string
+ /**
+ * The name of the contact
+ */
+ name?: string
+ /**
+ * The type of the contact (contact/company)
+ */
+ type?: string
+ /**
+ * The home phone number of the contact
+ */
+ homePhone?: string
+ /**
+ * The work phone number of the contact
+ */
+ workPhone?: string
+ /**
+ * The mobile phone number of the contact
+ */
+ mobilePhone?: string
+ /**
+ * The email address of the contact
+ */
+ email?: string
+ /**
+ * The primary address of the contact
+ */
+ primaryAddress?: {
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides within
+ */
+ countryId?: string
+ }
+}
+/**
+ * Representation of relationship between a landlord and a contact or company
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+export interface LandlordContactRelationshipModel {
+ /**
+ * The unique identifier of the landlord relationship
+ */
+ id?: string
+ /**
+ * The unique identifier of the landlord
+ */
+ landlordId?: string
+ /**
+ * The date and time when the relationship was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the relationship was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The type of related entity (contact/company)
+ */
+ associatedType?: string
+ /**
+ * The unique identifier of the related contact or company
+ */
+ associatedId?: string
+ /**
+ * A flag denoting whether or not the relationship should be regarded as the main relationship for the parent landlord entity
+ */
+ isMain?: boolean
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+}
+/**
+ * Representation of a landlord
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+export interface LandlordModel {
+ /**
+ * The unique identifier of the landlord
+ */
+ id?: string
+ /**
+ * The date and time when the landlord was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the landlord was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * A flag determining whether or not the landlord is currently active
+ */
+ active?: boolean
+ /**
+ * The unique identifier of the company acting as the landlord's solicitor
+ */
+ solicitorId?: string
+ /**
+ * The unique identifier of the office that is associated to the landlord
+ */
+ officeId?: string
+ /**
+ * The source of the landlord
+ */
+ source?: {
+ /**
+ * The unique identifier of the source of the landlord
+ */
+ id?: string
+ /**
+ * The source type (office/source)
+ */
+ type?: string
+ }
+ /**
+ * A collection of contacts and/or companies associated to the landlord. The first item in the collection is considered the primary relationship
+ */
+ related?: {
+ /**
+ * The unique identifier of the contact
+ */
+ id?: string
+ /**
+ * The name of the contact
+ */
+ name?: string
+ /**
+ * The type of the contact (contact/company)
+ */
+ type?: string
+ /**
+ * The home phone number of the contact
+ */
+ homePhone?: string
+ /**
+ * The work phone number of the contact
+ */
+ workPhone?: string
+ /**
+ * The mobile phone number of the contact
+ */
+ mobilePhone?: string
+ /**
+ * The email address of the contact
+ */
+ email?: string
+ /**
+ * The primary address of the contact
+ */
+ primaryAddress?: {
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides within
+ */
+ countryId?: string
+ }
+ }[]
+ /**
+ * App specific metadata that has been set against the landlord
+ */
+ metadata?: {
+ [name: string]: any
+ }
+ /**
+ * The ETag for the current version of the landlord. Used for managing update concurrency
+ */
+ readonly _eTag?: string
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+}
+/**
+ * Representation of a landlord's source
+ */
+export interface LandlordSourceModel {
+ /**
+ * The unique identifier of the source of the landlord
+ */
+ id?: string
+ /**
+ * The source type (office/source)
+ */
+ type?: string
+}
+export interface Landlords {
+ PageSize?: number
+ PageNumber?: number
+ SortBy?: string
+ Id?: string[]
+ Active?: boolean
+ Address?: string
+ Name?: string
+ CreatedFrom?: string
+ CreatedTo?: string
+ Embed?: ('documents' | 'office' | 'solicitor' | 'source')[]
+}
+export interface LinkModel {
+ href?: string
+}
+/**
+ * Representation of a configuration item
+ */
+export interface ListItemModel {
+ /**
+ * The unique identifier of the list item
+ */
+ id?: string
+ /**
+ * The textual value for the list item
+ */
+ value?: string
+}
+/**
+ * Representation of a negotiator
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+export interface NegotiatorModel {
+ /**
+ * The unique identifier of the negotiator
+ */
+ id?: string
+ /**
+ * The date and time when the negotiator was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the negotiator was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The name of the negotiator
+ */
+ name?: string
+ /**
+ * The job title of the negotiator
+ */
+ jobTitle?: string
+ /**
+ * A flag determining whether or not the negotiator is active
+ */
+ active?: boolean
+ /**
+ * The unique identifier of the office that the negotiator is attached to
+ */
+ officeId?: string
+ /**
+ * The work phone number of the negotiator
+ */
+ workPhone?: string
+ /**
+ * The mobile phone number of the negotiator
+ */
+ mobilePhone?: string
+ /**
+ * The email address of the negotiator
+ */
+ email?: string
+ /**
+ * App specific metadata that has been set against the negotiator
+ */
+ metadata?: {
+ [name: string]: any
+ }
+ /**
+ * The ETag for the current version of the negotiator. Used for managing update concurrency
+ */
+ readonly _eTag?: string
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+}
+export interface Negotiators {
+ PageSize?: number
+ PageNumber?: number
+ SortBy?: string
+ Id?: string[]
+ OfficeId?: string[]
+ Name?: string
+ Embed?: 'office'[]
+}
+/**
+ * Representation of the physical address of a building or premise
+ */
+export interface OfferContactAddressModel {
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides in
+ */
+ countryId?: string
+}
+/**
+ * A summarised view of the details of a contact associated to an offer
+ */
+export interface OfferContactModel {
+ /**
+ * The unique identifier of the contact
+ */
+ id?: string
+ /**
+ * The name of the contact
+ */
+ name?: string
+ /**
+ * The type of the contact (contact/company)
+ */
+ type?: string
+ /**
+ * The home phone number of the contact
+ */
+ homePhone?: string
+ /**
+ * The work phone number of the contact
+ */
+ workPhone?: string
+ /**
+ * The mobile phone number of the contact
+ */
+ mobilePhone?: string
+ /**
+ * The email address of the contact
+ */
+ email?: string
+ /**
+ * The primary address of the contact
+ */
+ primaryAddress?: {
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides in
+ */
+ countryId?: string
+ }
+}
+/**
+ * Representation of an offer
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+export interface OfferModel {
+ /**
+ * The unique identifier of the offer
+ */
+ id?: string
+ /**
+ * The the date and time when the offer was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the offer was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The currency that applies to monetary amounts exposed in the model
+ */
+ currency?: string
+ /**
+ * The unique identifier of the applicant associated to the offer
+ */
+ applicantId?: string
+ /**
+ * The unique identifier of the property associated to the offer
+ */
+ propertyId?: string
+ /**
+ * The unique identifier of the negotiator associated to the offer
+ */
+ negotiatorId?: string
+ /**
+ * The date when the offer was made
+ * example:
+ * 2019-08-14
+ */
+ date?: string // date
+ /**
+ * The monetary amount of the offer
+ */
+ amount?: number // double
+ /**
+ * The current status of the offer (pending/withdrawn/rejected/accepted/noteOfInterest)
+ */
+ status?: string
+ /**
+ * A free text field describing items that should be included in the sale
+ */
+ inclusions?: string
+ /**
+ * A free text field describing items that are explicitly excluded from the sale
+ */
+ exclusions?: string
+ /**
+ * A free text field describing any other conditions set by either party that relate to the sale
+ */
+ conditions?: string
+ /**
+ * A collection of contacts associated to the offer
+ */
+ related?: {
+ /**
+ * The unique identifier of the contact
+ */
+ id?: string
+ /**
+ * The name of the contact
+ */
+ name?: string
+ /**
+ * The type of the contact (contact/company)
+ */
+ type?: string
+ /**
+ * The home phone number of the contact
+ */
+ homePhone?: string
+ /**
+ * The work phone number of the contact
+ */
+ workPhone?: string
+ /**
+ * The mobile phone number of the contact
+ */
+ mobilePhone?: string
+ /**
+ * The email address of the contact
+ */
+ email?: string
+ /**
+ * The primary address of the contact
+ */
+ primaryAddress?: {
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides in
+ */
+ countryId?: string
+ }
+ }[]
+ /**
+ * App specific metadata that has been set against the offer
+ */
+ metadata?: {
+ [name: string]: any
+ }
+ /**
+ * The ETag for the current version of the offer. Used for managing update concurrency
+ */
+ readonly _eTag?: string
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+}
+export interface Offers {
+ PageSize?: number
+ PageNumber?: number
+ SortBy?: string
+ Id?: string[]
+ ApplicantId?: string[]
+ PropertyId?: string[]
+ Address?: string
+ Name?: string
+ AmountFrom?: number
+ AmountTo?: number
+ DateFrom?: string
+ DateTo?: string
+ Embed?: ('applicant' | 'property' | 'negotiator')[]
+ Status?: ('pending' | 'withdrawn' | 'rejected' | 'accepted' | 'noteOfInterest' | 'noteOfInterestWithdrawn')[]
+}
+/**
+ * Representation of the physical address of a building or premise
+ */
+export interface OfficeAddressModel {
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides within
+ */
+ countryId?: string
+}
+/**
+ * Representation of an office
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+export interface OfficeModel {
+ /**
+ * The unique identifier of the office
+ */
+ id?: string
+ /**
+ * The date and time when the office was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the office was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The name of the office
+ */
+ name?: string
+ /**
+ * The name of the office manager
+ */
+ manager?: string
+ /**
+ * The address of the office
+ */
+ address?: {
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides within
+ */
+ countryId?: string
+ }
+ /**
+ * The work phone number of the office
+ */
+ workPhone?: string
+ /**
+ * The email address of the office
+ */
+ email?: string
+ /**
+ * App specific metadata that has been set against the office
+ */
+ metadata?: {
+ [name: string]: any
+ }
+ /**
+ * The ETag for the current version of the office. Used for managing update concurrency
+ */
+ readonly _eTag?: string
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+}
+export interface Offices {
+ PageSize?: number
+ PageNumber?: number
+ SortBy?: string
+ Id?: string[]
+ Address?: string
+ Name?: string
+ Embed?: 'negotiators'[]
+}
+export interface PagedResultApplicantContactRelationshipModel_ {
+ _embedded?: {
+ /**
+ * The unique identifier of the applicant relationship
+ */
+ id?: string
+ /**
+ * The date and time when the relationship was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the relationship was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The unique identifier of the applicant
+ */
+ applicantId?: string
+ /**
+ * The type of related entity (contact/company)
+ */
+ associatedType?: string
+ /**
+ * The unique identifier of the related contact or company
+ */
+ associatedId?: string
+ /**
+ * A flag denoting whether or not this relationship should be regarded as the main relationship for the parent applicant entity
+ */
+ isMain?: boolean
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+ }[]
+ pageNumber?: number // int32
+ pageSize?: number // int32
+ pageCount?: number // int32
+ totalCount?: number // int32
+ _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+}
+export interface PagedResultApplicantModel_ {
+ _embedded?: {
+ /**
+ * The unique identifier of the applicant
+ */
+ id?: string
+ /**
+ * The date and time when the applicant was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the applicant was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * Indicates whether the applicant is look to buy or rent a property (buying/renting)
+ */
+ marketingMode?: string
+ /**
+ * The ISO-4217 currency code that relates to monetary amounts specified by the applicant
+ */
+ currency?: string
+ /**
+ * A flag determining whether or not the applicant is actively looking for a property
+ */
+ active?: boolean
+ /**
+ * A free text field describing any adhoc buying or renting requirements
+ */
+ notes?: string
+ /**
+ * The date when the applicant was last contacted
+ * example:
+ * 2019-08-14
+ */
+ lastCall?: string // date
+ /**
+ * The date when the applicant is next due to be contacted
+ * example:
+ * 2019-08-14
+ */
+ nextCall?: string // date
+ /**
+ * The unique identifier of the department that the applicant requirements are associated with. The applicant will only match to properties with the same value
+ */
+ departmentId?: string
+ /**
+ * The unique identifier of the solicitor associated to the applicant
+ */
+ solicitorId?: string
+ /**
+ * A list of property type requirements taken from the full listing of the associated department
+ */
+ type?: string[]
+ /**
+ * A list of property style requirements taken from the full listing of the associated department
+ */
+ style?: string[]
+ /**
+ * A list of property situation requirements taken from the full listing of the associated department
+ */
+ situation?: string[]
+ /**
+ * A list of property parking requirements taken from the full listing of the associated department
+ */
+ parking?: string[]
+ /**
+ * A list of property age requirements taken from the full listing of the associated department
+ */
+ age?: string[]
+ /**
+ * A list of property locality requirements taken from the full listing of the associated department
+ */
+ locality?: string[]
+ /**
+ * The minimum number of bedrooms the applicant requires
+ */
+ bedroomsMin?: number // int32
+ /**
+ * The maximum number of bedrooms the applicant requires
+ */
+ bedroomsMax?: number // int32
+ /**
+ * The minimum number of reception rooms the applicant requires
+ */
+ receptionsMin?: number // int32
+ /**
+ * The maximum number of reception rooms the applicant requires
+ */
+ receptionsMax?: number // int32
+ /**
+ * The minimum number of bathrooms the applicant requires
+ */
+ bathroomsMin?: number // int32
+ /**
+ * The maximum number of bathrooms the applicant requires
+ */
+ bathroomsMax?: number // int32
+ /**
+ * The applicant's location type (areas/addresses/none)
+ */
+ locationType?: string
+ /**
+ * The applicant's location options
+ */
+ locationOptions?: string[]
+ /**
+ * The details specific to applicants with a marketingMode of buying
+ */
+ buying?: {
+ /**
+ * The lower bound of the applicant's budget
+ */
+ priceFrom?: number // int32
+ /**
+ * The upper bound of the applicant's budget
+ */
+ priceTo?: number // int32
+ }
+ /**
+ * The details specific to applicants with a marketingMode of renting
+ */
+ renting?: {
+ /**
+ * The date the applicant is looking to move to a new property
+ * example:
+ * 2019-08-14
+ */
+ moveDate?: string // date
+ /**
+ * The applicant's preferred letting term (long/short/any)
+ */
+ term?: string
+ /**
+ * The lower bound of the applicant's budget
+ */
+ rentFrom?: number // double
+ /**
+ * The upper bound of the applicant's budget
+ */
+ rentTo?: number // double
+ /**
+ * The desired rent collection frequency specified by the applicant's budget (weekly/monthly/annually)
+ */
+ rentFrequency?: string
+ /**
+ * A list of property furnishing requirements taken from the full listing of the associated department. Only applicable to applicants with a marketingMode of renting
+ */
+ furnishing?: string[]
+ }
+ /**
+ * The applicant's outdoor space requirements
+ */
+ externalArea?: {
+ /**
+ * The unit of area that each amount corresponds to (acres/hectares)
+ */
+ type?: string
+ /**
+ * The minimum unit value of outside space that the applicant is looking for
+ */
+ amountFrom?: number // double
+ /**
+ * The maximum unit value of outside space that the applicant is looking for
+ */
+ amountTo?: number // double
+ }
+ /**
+ * The applicant's indoor space requirements
+ */
+ internalArea?: {
+ /**
+ * The unit of area that each amount corresponds to (squareFeet/squareMetres)
+ */
+ type?: string
+ /**
+ * The unit value of inside space that the applicant is looking for
+ */
+ amount?: number // double
+ }
+ /**
+ * The source of the applicant
+ */
+ source?: {
+ /**
+ * The unique identifier of the applicant's source
+ */
+ id?: string
+ /**
+ * The source type (office/source)
+ */
+ type?: string
+ }
+ /**
+ * A collection of unique identifiers of offices attached to the applicant. The first item in the collection is considered the primary office
+ */
+ officeIds?: string[]
+ /**
+ * A collection of unique identifiers of negotiators attached to the applicant. The first item in the collection is considered the primary negotiator
+ */
+ negotiatorIds?: string[]
+ /**
+ * A collection of contacts and/or companies associated to the applicant. The first item in the collection is considered the primary relationship
+ */
+ related?: {
+ /**
+ * The unique identifier of the contact or company
+ */
+ id?: string
+ /**
+ * The name of the contact or company
+ */
+ name?: string
+ /**
+ * The type of the contact (company/contact)
+ */
+ type?: string
+ /**
+ * The home phone number of the contact or company
+ */
+ homePhone?: string
+ /**
+ * The work phone number of the contact or company
+ */
+ workPhone?: string
+ /**
+ * The mobile phone number of the contact or company
+ */
+ mobilePhone?: string
+ /**
+ * The email address of the contact or company
+ */
+ email?: string
+ /**
+ * The primary address of the contact or company
+ */
+ primaryAddress?: {
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides within
+ */
+ countryId?: string
+ }
+ }[]
+ /**
+ * App specific metadata that has been set against the applicant
+ */
+ metadata?: {
+ [name: string]: any
+ }
+ /**
+ * The ETag for the current version of the applicant. Used for managing update concurrency
+ */
+ readonly _eTag?: string
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+ }[]
+ pageNumber?: number // int32
+ pageSize?: number // int32
+ pageCount?: number // int32
+ totalCount?: number // int32
+ _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+}
+export interface PagedResultAppointmentModel_ {
+ _embedded?: {
+ /**
+ * The unique identifier of the appointment
+ */
+ id?: string
+ /**
+ * The date and time when the appointment was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the appointment was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The date and time when the appointment will start
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ start?: string // date-time
+ /**
+ * The date and time when the appointment will end
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ end?: string // date-time
+ /**
+ * The unique identifier of the appointment type
+ */
+ typeId?: string
+ /**
+ * A free text description about the appointment
+ */
+ description?: string
+ /**
+ * A flag denoting whether or not the appointment recurs
+ */
+ recurring?: boolean
+ /**
+ * A flag denoting whether or not the appointment has been cancelled
+ */
+ cancelled?: boolean
+ /**
+ * Follow up information relating to the appointment
+ */
+ followUp?: {
+ /**
+ * The date when the appointment should be followed up
+ * example:
+ * 2019-08-14
+ */
+ due?: string // date
+ /**
+ * The unique identifier of a pre-defined follow up response type
+ */
+ responseId?: string
+ /**
+ * Free text internal follow up notes to be stored against the appointment
+ */
+ notes?: string
+ }
+ /**
+ * The unique identifier of the property related to the appointment
+ */
+ propertyId?: string
+ /**
+ * The unique identifier of the negotiator that organised the appointment
+ */
+ organiserId?: string
+ /**
+ * A collection of unique identifiers of negotiators attached to the appointment
+ */
+ negotiatorIds?: string[]
+ /**
+ * A collection of unique identifiers of offices attached to the appointment
+ */
+ officeIds?: string[]
+ /**
+ * An appointment attendee
+ */
+ attendee?: {
+ /**
+ * The unique identifier of the attendee
+ */
+ id?: string
+ /**
+ * The type of attendee
+ */
+ type?: string
+ /**
+ * A collection of contacts relating to the attendee
+ */
+ contacts?: {
+ /**
+ * The unique identifier of the contact
+ */
+ id?: string
+ /**
+ * The name of the contact
+ */
+ name?: string
+ /**
+ * The home phone number of the contact
+ */
+ homePhone?: string
+ /**
+ * The work phone number of the contact
+ */
+ workPhone?: string
+ /**
+ * The mobile phone number of the contact
+ */
+ mobilePhone?: string
+ /**
+ * The email address of the contact
+ */
+ email?: string
+ }[]
+ }
+ /**
+ * A flag denoting whether or not the appointment will be accompanied by one or more negotiators
+ */
+ accompanied?: boolean
+ /**
+ * A flag denoting whether or not the main negotiator has confirmed their attendance
+ */
+ negotiatorConfirmed?: boolean
+ /**
+ * A flag denoting whether or not the attendee has confirmed their attendance
+ */
+ attendeeConfirmed?: boolean
+ /**
+ * A flag denoting whether or not the property and/or property's vendor has confirmed their attendance
+ */
+ propertyConfirmed?: boolean
+ /**
+ * App specific metadata that has been set against the appointment
+ */
+ metadata?: {
+ [name: string]: any
+ }
+ /**
+ * The ETag for the current version of the appointment. Used for managing update concurrency
+ */
+ readonly _eTag?: string
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+ }[]
+ pageNumber?: number // int32
+ pageSize?: number // int32
+ pageCount?: number // int32
+ totalCount?: number // int32
+ _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+}
+export interface PagedResultAreaModel_ {
+ _embedded?: {
+ /**
+ * The unique identifier of the area
+ */
+ id?: string
+ /**
+ * The date and time when the area was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the area was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The name of the area
+ */
+ name?: string
+ /**
+ * A flag denoting whether the area can currently be selected against properties and applicants
+ */
+ active?: boolean
+ /**
+ * The type of area (postcodes/polygon/group)
+ */
+ type?: string
+ /**
+ * The location details (comma delimited list of postcodes, group ids or lat/long coordinate groups)
+ */
+ area?: string[]
+ /**
+ * A collection of unique identifiers of departments associated to the area
+ */
+ departmentIds?: string[]
+ /**
+ * A collection of unique identifiers of offices associated to the area
+ */
+ officeIds?: string[]
+ /**
+ * The ETag for the current version of the area. Used for managing update concurrency
+ */
+ readonly _eTag?: string
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+ }[]
+ pageNumber?: number // int32
+ pageSize?: number // int32
+ pageCount?: number // int32
+ totalCount?: number // int32
+ _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+}
+export interface PagedResultCompanyModel_ {
+ _embedded?: {
+ /**
+ * The unique identifier of the company
+ */
+ id?: string
+ /**
+ * The date and time when the company was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the company was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The name of the company
+ */
+ name?: string
+ /**
+ * The branch name of the company
+ */
+ branch?: string
+ /**
+ * A free text field containing notes that describe the company's business or service offering
+ */
+ notes?: string
+ /**
+ * A flag determining whether or not the company is currently active
+ */
+ active?: boolean
+ /**
+ * A flag determining whether or not the company is VAT registered
+ */
+ vatRegistered?: boolean
+ /**
+ * A collection of unique identifiers of company types that categorise the type of business the company operates
+ */
+ typeIds?: string[]
+ /**
+ * The unique identifier of a supplier type, if the company is a supplier
+ */
+ supplierTypeId?: string
+ /**
+ * The work phone number of the company
+ */
+ workPhone?: string
+ /**
+ * The mobile phone number of the company
+ */
+ mobilePhone?: string
+ /**
+ * The email address of the company
+ */
+ email?: string
+ /**
+ * The address of the company
+ */
+ address?: {
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides within
+ */
+ country?: string
+ }
+ /**
+ * App specific metadata that has been set against the company
+ */
+ metadata?: {
+ [name: string]: any
+ }
+ /**
+ * The ETag for the current version of the company. Used for managing update concurrency
+ */
+ readonly _eTag?: string
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+ }[]
+ pageNumber?: number // int32
+ pageSize?: number // int32
+ pageCount?: number // int32
+ totalCount?: number // int32
+ _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+}
+export interface PagedResultContactModel_ {
+ _embedded?: {
+ /**
+ * The unique identifier of the contact
+ */
+ id?: string
+ /**
+ * The date and time when the contact was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the contact was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The contact's title (eg. Mr, Mrs, Miss, Dr)
+ */
+ title?: string
+ /**
+ * The contact's forename
+ */
+ forename?: string
+ /**
+ * The contact's surname
+ */
+ surname?: string
+ /**
+ * The contact's date of birth
+ * example:
+ * 2019-08-14
+ */
+ dateOfBirth?: string // date
+ /**
+ * A flag determining whether or not the contact is currently active
+ */
+ active?: boolean
+ /**
+ * The marketing consent status of the contact (grant/deny/notAsked)
+ */
+ marketingConsent?: string
+ /**
+ * The status of the last identity check performed against the contact (pass/fail/pending/cancelled/warnings/unchecked)
+ */
+ identityCheck?: string
+ /**
+ * The source of the contact
+ */
+ source?: {
+ /**
+ * The unique identifier of the source of the contact
+ */
+ id?: string
+ /**
+ * The source type (office/source)
+ */
+ type?: string
+ }
+ /**
+ * The home phone number of the contact
+ */
+ homePhone?: string
+ /**
+ * The work phone number of the contact
+ */
+ workPhone?: string
+ /**
+ * The mobile phone number of the contact
+ */
+ mobilePhone?: string
+ /**
+ * The email address of the contact
+ */
+ email?: string
+ /**
+ * The primary address of the contact
+ */
+ primaryAddress?: {
+ /**
+ * The type of address (primary/secondary/home/work/forwarding/company/previous)
+ */
+ type?: string
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides in
+ */
+ countryId?: string
+ }
+ /**
+ * The secondary address of the contact
+ */
+ secondaryAddress?: {
+ /**
+ * The type of address (primary/secondary/home/work/forwarding/company/previous)
+ */
+ type?: string
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides in
+ */
+ countryId?: string
+ }
+ /**
+ * The work address of the contact
+ */
+ workAddress?: {
+ /**
+ * The type of address (primary/secondary/home/work/forwarding/company/previous)
+ */
+ type?: string
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides in
+ */
+ countryId?: string
+ }
+ /**
+ * A collection of unique identifiers of offices attached to the contact
+ */
+ officeIds?: string[]
+ /**
+ * A collection of unique identifiers of negotiators attached to the contact
+ */
+ negotiatorIds?: string[]
+ /**
+ * App specific metadata that has been set against the contact
+ */
+ metadata?: {
+ [name: string]: any
+ }
+ /**
+ * The ETag for the current version of the contact. Used for managing update concurrency
+ */
+ readonly _eTag?: string
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+ }[]
+ pageNumber?: number // int32
+ pageSize?: number // int32
+ pageCount?: number // int32
+ totalCount?: number // int32
+ _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+}
+export interface PagedResultContactRoleModel_ {
+ _embedded?: {
+ /**
+ * The unique identifier of the relationship
+ */
+ id?: string
+ /**
+ * The date and time when the relationship was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the relationship was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The unique identifier of the related contact
+ */
+ contactId?: string
+ /**
+ * The type of related entity (applicant/vendor/landlord/tenancy)
+ */
+ associatedType?: string
+ /**
+ * The unique identifier of the related entity
+ */
+ associatedId?: string
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+ }[]
+ pageNumber?: number // int32
+ pageSize?: number // int32
+ pageCount?: number // int32
+ totalCount?: number // int32
+ _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+}
+export interface PagedResultDepartmentModel_ {
+ _embedded?: {
+ /**
+ * The unique identifier of the department
+ */
+ id?: string
+ /**
+ * The date and time when the department was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the department was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The name of the department
+ */
+ name?: string
+ /**
+ * A collection of property type values that will be accepted by other services
+ */
+ typeOptions?: string[]
+ /**
+ * A collection of property style values that will be accepted by other services
+ */
+ styleOptions?: string[]
+ /**
+ * A collection of property situation values that will be accepted by other services
+ */
+ situationOptions?: string[]
+ /**
+ * A collection of property parking values that will be accepted by other services
+ */
+ parkingOptions?: string[]
+ /**
+ * A collection of property age values that will be accepted by other services
+ */
+ ageOptions?: string[]
+ /**
+ * A collection of property locality values that will be accepted by other services
+ */
+ localityOptions?: string[]
+ /**
+ * The ETag for the current version of the department. Used for managing update concurrency
+ */
+ readonly _eTag?: string
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+ }[]
+ pageNumber?: number // int32
+ pageSize?: number // int32
+ pageCount?: number // int32
+ totalCount?: number // int32
+ _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+}
+export interface PagedResultDocumentModel_ {
+ _embedded?: {
+ /**
+ * The unique identifier of the document
+ */
+ id?: string
+ /**
+ * The date and time when the document was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the document was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The type of entity that the document is associated with
+ */
+ associatedType?: string
+ /**
+ * The unique identifier of the entity that the document is associated with
+ */
+ associatedId?: string
+ /**
+ * The unique identifier of the type of document
+ */
+ typeId?: string
+ /**
+ * The filename of the document
+ */
+ name?: string
+ /**
+ * The ETag for the current version of the document. Used for managing update concurrency
+ */
+ readonly _eTag?: string
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+ }[]
+ pageNumber?: number // int32
+ pageSize?: number // int32
+ pageCount?: number // int32
+ totalCount?: number // int32
+ _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+}
+export interface PagedResultIdentityCheckModel_ {
+ _embedded?: {
+ /**
+ * The unique identifier of the identity check
+ */
+ id?: string
+ /**
+ * The unique identifier of the contact associated to the identity check
+ */
+ contactId?: string
+ /**
+ * The date and time when the identity check was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the identity check was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The date when the identity check was performed. This may differ to the date when the check was created
+ * example:
+ * 2019-08-14
+ */
+ checkDate?: string // date
+ /**
+ * The current status of the identity check (pass/fail/pending/cancelled/warnings/unchecked)
+ */
+ status?: string
+ /**
+ * The unique identifier of the negotiator that initiated the identity check
+ */
+ negotiatorId?: string
+ /**
+ * The details of the first document that was provided as part of the identity check
+ */
+ identityDocument1?: {
+ /**
+ * The unique identifier of the identity document
+ */
+ documentId?: string
+ /**
+ * The unique identifier of the type of identity document provided
+ */
+ typeId?: string
+ /**
+ * The date when the document expires and becomes invalid
+ * example:
+ * 2019-08-14
+ */
+ expiry?: string // date
+ /**
+ * Details regarding the identity document (eg. passport number)
+ */
+ details?: string
+ }
+ /**
+ * The details of the second document that was provided as part of the identity check
+ */
+ identityDocument2?: {
+ /**
+ * The unique identifier of the identity document
+ */
+ documentId?: string
+ /**
+ * The unique identifier of the type of identity document provided
+ */
+ typeId?: string
+ /**
+ * The date when the document expires and becomes invalid
+ * example:
+ * 2019-08-14
+ */
+ expiry?: string // date
+ /**
+ * Details regarding the identity document (eg. passport number)
+ */
+ details?: string
+ }
+ /**
+ * App specific metadata that has been set against the identity check
+ */
+ metadata?: {
+ [name: string]: any
+ }
+ /**
+ * The ETag for the current version of the identity check. Used for managing update concurrency
+ */
+ readonly _eTag?: string
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+ }[]
+ pageNumber?: number // int32
+ pageSize?: number // int32
+ pageCount?: number // int32
+ totalCount?: number // int32
+ _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+}
+export interface PagedResultLandlordContactRelationshipModel_ {
+ _embedded?: {
+ /**
+ * The unique identifier of the landlord relationship
+ */
+ id?: string
+ /**
+ * The unique identifier of the landlord
+ */
+ landlordId?: string
+ /**
+ * The date and time when the relationship was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the relationship was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The type of related entity (contact/company)
+ */
+ associatedType?: string
+ /**
+ * The unique identifier of the related contact or company
+ */
+ associatedId?: string
+ /**
+ * A flag denoting whether or not the relationship should be regarded as the main relationship for the parent landlord entity
+ */
+ isMain?: boolean
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+ }[]
+ pageNumber?: number // int32
+ pageSize?: number // int32
+ pageCount?: number // int32
+ totalCount?: number // int32
+ _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+}
+export interface PagedResultLandlordModel_ {
+ _embedded?: {
+ /**
+ * The unique identifier of the landlord
+ */
+ id?: string
+ /**
+ * The date and time when the landlord was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the landlord was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * A flag determining whether or not the landlord is currently active
+ */
+ active?: boolean
+ /**
+ * The unique identifier of the company acting as the landlord's solicitor
+ */
+ solicitorId?: string
+ /**
+ * The unique identifier of the office that is associated to the landlord
+ */
+ officeId?: string
+ /**
+ * The source of the landlord
+ */
+ source?: {
+ /**
+ * The unique identifier of the source of the landlord
+ */
+ id?: string
+ /**
+ * The source type (office/source)
+ */
+ type?: string
+ }
+ /**
+ * A collection of contacts and/or companies associated to the landlord. The first item in the collection is considered the primary relationship
+ */
+ related?: {
+ /**
+ * The unique identifier of the contact
+ */
+ id?: string
+ /**
+ * The name of the contact
+ */
+ name?: string
+ /**
+ * The type of the contact (contact/company)
+ */
+ type?: string
+ /**
+ * The home phone number of the contact
+ */
+ homePhone?: string
+ /**
+ * The work phone number of the contact
+ */
+ workPhone?: string
+ /**
+ * The mobile phone number of the contact
+ */
+ mobilePhone?: string
+ /**
+ * The email address of the contact
+ */
+ email?: string
+ /**
+ * The primary address of the contact
+ */
+ primaryAddress?: {
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides within
+ */
+ countryId?: string
+ }
+ }[]
+ /**
+ * App specific metadata that has been set against the landlord
+ */
+ metadata?: {
+ [name: string]: any
+ }
+ /**
+ * The ETag for the current version of the landlord. Used for managing update concurrency
+ */
+ readonly _eTag?: string
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+ }[]
+ pageNumber?: number // int32
+ pageSize?: number // int32
+ pageCount?: number // int32
+ totalCount?: number // int32
+ _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+}
+export interface PagedResultNegotiatorModel_ {
+ _embedded?: {
+ /**
+ * The unique identifier of the negotiator
+ */
+ id?: string
+ /**
+ * The date and time when the negotiator was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the negotiator was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The name of the negotiator
+ */
+ name?: string
+ /**
+ * The job title of the negotiator
+ */
+ jobTitle?: string
+ /**
+ * A flag determining whether or not the negotiator is active
+ */
+ active?: boolean
+ /**
+ * The unique identifier of the office that the negotiator is attached to
+ */
+ officeId?: string
+ /**
+ * The work phone number of the negotiator
+ */
+ workPhone?: string
+ /**
+ * The mobile phone number of the negotiator
+ */
+ mobilePhone?: string
+ /**
+ * The email address of the negotiator
+ */
+ email?: string
+ /**
+ * App specific metadata that has been set against the negotiator
+ */
+ metadata?: {
+ [name: string]: any
+ }
+ /**
+ * The ETag for the current version of the negotiator. Used for managing update concurrency
+ */
+ readonly _eTag?: string
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+ }[]
+ pageNumber?: number // int32
+ pageSize?: number // int32
+ pageCount?: number // int32
+ totalCount?: number // int32
+ _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+}
+export interface PagedResultOfferModel_ {
+ _embedded?: {
+ /**
+ * The unique identifier of the offer
+ */
+ id?: string
+ /**
+ * The the date and time when the offer was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the offer was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The currency that applies to monetary amounts exposed in the model
+ */
+ currency?: string
+ /**
+ * The unique identifier of the applicant associated to the offer
+ */
+ applicantId?: string
+ /**
+ * The unique identifier of the property associated to the offer
+ */
+ propertyId?: string
+ /**
+ * The unique identifier of the negotiator associated to the offer
+ */
+ negotiatorId?: string
+ /**
+ * The date when the offer was made
+ * example:
+ * 2019-08-14
+ */
+ date?: string // date
+ /**
+ * The monetary amount of the offer
+ */
+ amount?: number // double
+ /**
+ * The current status of the offer (pending/withdrawn/rejected/accepted/noteOfInterest)
+ */
+ status?: string
+ /**
+ * A free text field describing items that should be included in the sale
+ */
+ inclusions?: string
+ /**
+ * A free text field describing items that are explicitly excluded from the sale
+ */
+ exclusions?: string
+ /**
+ * A free text field describing any other conditions set by either party that relate to the sale
+ */
+ conditions?: string
+ /**
+ * A collection of contacts associated to the offer
+ */
+ related?: {
+ /**
+ * The unique identifier of the contact
+ */
+ id?: string
+ /**
+ * The name of the contact
+ */
+ name?: string
+ /**
+ * The type of the contact (contact/company)
+ */
+ type?: string
+ /**
+ * The home phone number of the contact
+ */
+ homePhone?: string
+ /**
+ * The work phone number of the contact
+ */
+ workPhone?: string
+ /**
+ * The mobile phone number of the contact
+ */
+ mobilePhone?: string
+ /**
+ * The email address of the contact
+ */
+ email?: string
+ /**
+ * The primary address of the contact
+ */
+ primaryAddress?: {
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides in
+ */
+ countryId?: string
+ }
+ }[]
+ /**
+ * App specific metadata that has been set against the offer
+ */
+ metadata?: {
+ [name: string]: any
+ }
+ /**
+ * The ETag for the current version of the offer. Used for managing update concurrency
+ */
+ readonly _eTag?: string
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+ }[]
+ pageNumber?: number // int32
+ pageSize?: number // int32
+ pageCount?: number // int32
+ totalCount?: number // int32
+ _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+}
+export interface PagedResultOfficeModel_ {
+ _embedded?: {
+ /**
+ * The unique identifier of the office
+ */
+ id?: string
+ /**
+ * The date and time when the office was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the office was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The name of the office
+ */
+ name?: string
+ /**
+ * The name of the office manager
+ */
+ manager?: string
+ /**
+ * The address of the office
+ */
+ address?: {
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides within
+ */
+ countryId?: string
+ }
+ /**
+ * The work phone number of the office
+ */
+ workPhone?: string
+ /**
+ * The email address of the office
+ */
+ email?: string
+ /**
+ * App specific metadata that has been set against the office
+ */
+ metadata?: {
+ [name: string]: any
+ }
+ /**
+ * The ETag for the current version of the office. Used for managing update concurrency
+ */
+ readonly _eTag?: string
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+ }[]
+ pageNumber?: number // int32
+ pageSize?: number // int32
+ pageCount?: number // int32
+ totalCount?: number // int32
+ _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+}
+export interface PagedResultPropertyImageModel_ {
+ _embedded?: {
+ /**
+ * The unique identifier of the image, which is also the filename
+ */
+ id?: string
+ /**
+ * The date and time when the image was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the property image was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The unique identifier of the property attached to the image
+ */
+ propertyId?: string
+ /**
+ * The url where the image can be downloaded from
+ */
+ url?: string
+ /**
+ * The image caption
+ */
+ caption?: string
+ /**
+ * The type of image (picture/floorPlan/epc/map)
+ */
+ type?: string
+ /**
+ * The display order index of the image which can be used to correctly order the whole collection
+ */
+ order?: number // int32
+ /**
+ * The ETag for the current version of the image. Used for managing update concurrency
+ */
+ readonly _eTag?: string
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+ }[]
+ pageNumber?: number // int32
+ pageSize?: number // int32
+ pageCount?: number // int32
+ totalCount?: number // int32
+ _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+}
+export interface PagedResultPropertyModel_ {
+ _embedded?: {
+ /**
+ * The unique identifier of the property
+ */
+ id?: string
+ /**
+ * The date and time when the property was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the property was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The marketing mode of the property (selling/letting/sellingAndLetting)
+ */
+ marketingMode?: string
+ /**
+ * The currency that applies to monetary amounts exposed in the model
+ */
+ currency?: string
+ /**
+ * The address of the property
+ */
+ address?: {
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides within
+ */
+ countryId?: string
+ /**
+ * The geolocation coordinates associated with the address
+ */
+ geolocation?: {
+ /**
+ * The latitude coordinate of the coordinate pair
+ */
+ latitude?: number // double
+ /**
+ * The longitude coordinate of the coordinate pair
+ */
+ longitude?: number // double
+ }
+ }
+ /**
+ * The unique identifier of the area that the property resides in
+ */
+ areaId?: string
+ /**
+ * The strapline description containing a short summary about the property
+ */
+ strapline?: string
+ /**
+ * The brief description of the property
+ */
+ description?: string
+ /**
+ * The summary of accommodation, typically short phrases or bullet points describing the key features of the property
+ */
+ summary?: string
+ /**
+ * The unique identifier of the department
+ */
+ departmentId?: string
+ /**
+ * The unique identifier of the negotiator managing the property
+ */
+ negotiatorId?: string
+ /**
+ * The total number of bedrooms in the property
+ */
+ bedrooms?: number // int32
+ /**
+ * The total number of reception rooms in the property
+ */
+ receptions?: number // int32
+ /**
+ * The total number of bathrooms in the property
+ */
+ bathrooms?: number // int32
+ /**
+ * The council tax banding of the property (A/B/C/D/E/F/G/H)
+ */
+ councilTax?: string
+ /**
+ * A flag denoting whether or not this property can be advertised on the internet
+ */
+ internetAdvertising?: boolean
+ /**
+ * The arrangements regarding viewing the property
+ */
+ viewingArrangements?: string
+ /**
+ * Details of the external land area associated to this property
+ */
+ externalArea?: {
+ /**
+ * The unit of area (acres/hectares)
+ */
+ type?: string
+ /**
+ * The minimum area bound
+ */
+ min?: number // double
+ /**
+ * The maximum area bound
+ */
+ max?: number // double
+ }
+ /**
+ * Details of the internal dimensions of the property
+ */
+ internalArea?: {
+ /**
+ * The unit of area (squareFeet/squareMetres)
+ */
+ type?: string
+ /**
+ * The minimum area bound
+ */
+ min?: number // double
+ /**
+ * The maximum area bound
+ */
+ max?: number // double
+ }
+ /**
+ * Details of the EPC statistics
+ */
+ epc?: {
+ /**
+ * A flag denoting whether or not this property is exempt from requiring an EPC certificate
+ */
+ exempt?: boolean
+ /**
+ * The current energy efficiency rating
+ */
+ eer?: number // int32
+ /**
+ * The potential energy efficiency rating
+ */
+ eerPotential?: number // int32
+ /**
+ * The current environmental impact rating
+ */
+ eir?: number // int32
+ /**
+ * The potential environmental impact rating
+ */
+ eirPotential?: number // int32
+ }
+ /**
+ * Selling specific details about the property
+ */
+ selling?: {
+ /**
+ * The date that the property was marked as for sale
+ * example:
+ * 2019-08-14
+ */
+ instructed?: string // date
+ /**
+ * The marketing price of the property
+ */
+ price?: number // double
+ /**
+ * The price qualifier (askingPrice/priceOnApplication/guidePrice/offersInRegion/offersOver/offersInExcess/fixedPrice/priceReducedTo)
+ */
+ qualifier?: string
+ /**
+ * The current status of the sale (preAppraisal/valuation/paidValuation/forSale/forSaleUnavailable/underOffer/underOfferUnavailable/reserved/exchanged/completed/soldExternally/withdrawn)
+ */
+ status?: string
+ /**
+ * Details about the tenure of the property
+ */
+ tenure?: {
+ /**
+ * The type of tenure that applies to the property (freehold/leasehold/shareOfFreehold/commonhold/tba)
+ */
+ type?: string
+ /**
+ * The tenure expiration date
+ * example:
+ * 2019-08-14
+ */
+ expiry?: string // date
+ }
+ /**
+ * The unique identifier of the vendor selling the property
+ */
+ vendorId?: string
+ }
+ /**
+ * Letting specific details about the property
+ */
+ letting?: {
+ /**
+ * The date the property was marked as to let
+ * example:
+ * 2019-08-14
+ */
+ instructed?: string // date
+ /**
+ * The date the property is next available from
+ * example:
+ * 2019-08-14
+ */
+ availableFrom?: string // date
+ /**
+ * The date the property is available to
+ * example:
+ * 2019-08-14
+ */
+ availableTo?: string // date
+ /**
+ * The rent being charged for the property
+ */
+ rent?: number // double
+ /**
+ * The frequency at which rent will be collected (weekly/monthly/yearly)
+ */
+ rentFrequency?: string
+ /**
+ * The acceptable letting terms (short/long/any)
+ */
+ term?: string
+ /**
+ * The current status of the let (valuation/toLet/toLetUnavailable/underOffer/underOfferUnavailable/arrangingTenancyUnavailable/arrangingTenancy/tenancyCurrentUnavailable/tenancyCurrent/tenancyFinished/tenancyCancelled/sold/letByOtherAgent/letPrivately/provisional/withdrawn)
+ */
+ status?: string
+ /**
+ * The unique identifier of the landlord letting the property
+ */
+ landlordId?: string
+ }
+ /**
+ * The property type attributes
+ */
+ type?: string[]
+ /**
+ * The property style attributes
+ */
+ style?: string[]
+ /**
+ * The property situation attributes
+ */
+ situation?: string[]
+ /**
+ * The property parking attributes
+ */
+ parking?: string[]
+ /**
+ * The property age attributes
+ */
+ age?: string[]
+ /**
+ * The property locality attributes
+ */
+ locality?: string[]
+ /**
+ * Details of each room in the property
+ */
+ rooms?: {
+ /**
+ * The name of the room
+ */
+ name?: string
+ /**
+ * Details about the dimensions of the room
+ */
+ dimensions?: string
+ /**
+ * Short description of the room
+ */
+ description?: string
+ }[]
+ /**
+ * A collection of unique identifiers of offices attached to the property
+ */
+ officeIds?: string[]
+ /**
+ * App specific metadata that has been set against the property
+ */
+ metadata?: {
+ [name: string]: any
+ }
+ /**
+ * The ETag for the current version of the property. Used for managing update concurrency
+ */
+ readonly _eTag?: string
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+ }[]
+ pageNumber?: number // int32
+ pageSize?: number // int32
+ pageCount?: number // int32
+ totalCount?: number // int32
+ _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+}
+export interface PagedResultSourceModel_ {
+ _embedded?: {
+ /**
+ * The unique identifier of the source
+ */
+ id?: string
+ /**
+ * The date and time when the source was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the source was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The name of the source or advertising publication
+ */
+ name?: string
+ /**
+ * The type of the source (source/advertisement)
+ */
+ type?: string
+ /**
+ * A collection of the unique identifiers of offices that regularly get business from the source
+ */
+ officeIds?: string[]
+ /**
+ * A collection of unique identifiers of departments that regularly get business from the source
+ */
+ departmentIds?: string[]
+ /**
+ * The ETag for the current version of the source. Used for managing update concurrency
+ */
+ readonly _eTag?: string
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+ }[]
+ pageNumber?: number // int32
+ pageSize?: number // int32
+ pageCount?: number // int32
+ totalCount?: number // int32
+ _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+}
+export interface PagedResultTaskModel_ {
+ _embedded?: {
+ /**
+ * The unique identifier of the task
+ */
+ id?: string
+ /**
+ * The date and time when the task was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the task was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The date the task becomes active
+ * example:
+ * 2019-08-14
+ */
+ activates?: string // date
+ /**
+ * The date the task was completed
+ * example:
+ * 2019-08-14
+ */
+ completed?: string // date
+ /**
+ * The unique identifier of the task type
+ */
+ typeId?: string
+ /**
+ * The unique identifer of the negotiator that created the task
+ */
+ senderId?: string
+ /**
+ * The textual contents of the task or message
+ */
+ text?: string
+ /**
+ * The unique identifier of the landlord the task is associated to
+ */
+ landlordId?: string
+ /**
+ * The unique identifier of the property the task is associated to
+ */
+ propertyId?: string
+ /**
+ * The unique identifier of the applicant the task is associated to
+ */
+ applicantId?: string
+ /**
+ * The unique identifier of the tenancy the task is associated to
+ */
+ tenancyId?: string
+ /**
+ * The unique identifier of the contact the task is associated to
+ */
+ contactId?: string
+ /**
+ * The unique identifier of the negotiator or office the task is being sent to
+ */
+ recipientId?: string
+ /**
+ * The type of the recipient (office/negotiator)
+ */
+ recipientType?: string
+ /**
+ * App specific metadata that has been set against the task
+ */
+ metadata?: {
+ [name: string]: any
+ }
+ /**
+ * The ETag for the current version of the task. Used for managing update concurrency
+ */
+ readonly _eTag?: string
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+ }[]
+ pageNumber?: number // int32
+ pageSize?: number // int32
+ pageCount?: number // int32
+ totalCount?: number // int32
+ _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+}
+export interface PagedResultTenancyContactRelationshipModel_ {
+ _embedded?: {
+ /**
+ * The unique identifier of the tenancy relationship
+ */
+ id?: string
+ /**
+ * The date and time when the relationship was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the relationship was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The unique identifier of the tenancy
+ */
+ tenancyId?: string
+ /**
+ * The type of related entity (contact/company)
+ */
+ associatedType?: string
+ /**
+ * The unique identifier of the related contact or company
+ */
+ associatedId?: string
+ /**
+ * A flag denoting whether or not this contact or company should be regarded as the main tenant
+ */
+ isMain?: boolean
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+ }[]
+ pageNumber?: number // int32
+ pageSize?: number // int32
+ pageCount?: number // int32
+ totalCount?: number // int32
+ _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+}
+export interface PagedResultTenancyModel_ {
+ _embedded?: {
+ /**
+ * The unique identifier of the tenancy
+ */
+ id?: string
+ /**
+ * The date and time when the tenancy was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the tenancy was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * example:
+ * 2019-08-14
+ */
+ startDate?: string // date
+ /**
+ * example:
+ * 2019-08-14
+ */
+ endDate?: string // date
+ /**
+ * The current status of the tenancy (offerPending/offerWithdrawn/offerRejected/arranging/current/finished/cancelled)
+ */
+ status?: string
+ /**
+ * The role that the agent is performing for this tenancy (managed/rentCollection/collectFirstPayment/collectRentToDate/lettingOnly/introducingTenant)
+ */
+ agentRole?: string
+ /**
+ * The amount of rent required, returned in relation to the collection frequency
+ */
+ rent?: number // int32
+ /**
+ * The rent collection frequency (weekly/monthly/annually)
+ */
+ rentFrequency?: string
+ /**
+ * A flag determining whether or not this tenancy is confirmed to finish at the end date
+ */
+ endDateConfirmed?: boolean
+ /**
+ * A flag determining whether or not this tenancy has been extended indefinitely
+ */
+ isPeriodic?: boolean
+ /**
+ * The unique identifier of the type of tenancy
+ */
+ typeId?: string
+ /**
+ * The unique identifier of the negotiator who is managing this tenancy
+ */
+ negotiatorId?: string
+ /**
+ * The unique identifier of the property in which this tenancy is for
+ */
+ propertyId?: string
+ /**
+ * The unique identifier of the applicant who has applied to be a tenant
+ */
+ applicantId?: string
+ /**
+ * The source of the tenancy
+ */
+ source?: {
+ /**
+ * The unique identifier of the source for this tenancy
+ */
+ id?: string
+ /**
+ * The source type (office/source)
+ */
+ type?: string
+ }
+ /**
+ * A collection of contact / company tenants associated to this tenancy. The first item in the collection is considered the primary relationship
+ */
+ related?: {
+ /**
+ * The unique identifier of the contact or company
+ */
+ id?: string
+ /**
+ * The name of the contact or company
+ */
+ name?: string
+ /**
+ * The type of the contact (company/contact)
+ */
+ type?: string
+ /**
+ * The home phone number of the contact or company
+ */
+ homePhone?: string
+ /**
+ * The work phone number of the contact or company
+ */
+ workPhone?: string
+ /**
+ * The mobile phone number of the contact or company
+ */
+ mobilePhone?: string
+ /**
+ * The email address of the contact or company
+ */
+ email?: string
+ /**
+ * The primary address of the contact or company
+ */
+ primaryAddress?: {
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides within
+ */
+ countryId?: string
+ }
+ }[]
+ /**
+ * App specific metadata that has been set against the tenancy
+ */
+ metadata?: {
+ [name: string]: any
+ }
+ /**
+ * The ETag for the current version of the tenancy. Used for managing update concurrency
+ */
+ readonly _eTag?: string
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+ }[]
+ pageNumber?: number // int32
+ pageSize?: number // int32
+ pageCount?: number // int32
+ totalCount?: number // int32
+ _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+}
+export interface PagedResultVendorContactRelationshipModel_ {
+ _embedded?: {
+ /**
+ * The unique identifier of the vendor relationship
+ */
+ id?: string
+ /**
+ * The unique identifier of the vendor
+ */
+ vendorId?: string
+ /**
+ * The date and time when the relationship was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the relationship was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The type of related entity (contact/company)
+ */
+ associatedType?: string
+ /**
+ * The unique identifier of the related contact or company
+ */
+ associatedId?: string
+ /**
+ * A flag denoting whether or not this relationship should be regarded as the main relationship for the parent vendor entity
+ */
+ isMain?: boolean
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+ }[]
+ pageNumber?: number // int32
+ pageSize?: number // int32
+ pageCount?: number // int32
+ totalCount?: number // int32
+ _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+}
+export interface PagedResultVendorModel_ {
+ _embedded?: {
+ /**
+ * The unique identifier of the vendor
+ */
+ id?: string
+ /**
+ * The date and time when the vendor was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the vendor was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The date the vendor was last called
+ * example:
+ * 2019-08-14
+ */
+ lastCall?: string // date
+ /**
+ * The date the vendor is next due to be called
+ * example:
+ * 2019-08-14
+ */
+ nextCall?: string // date
+ /**
+ * The unique identifier of the type of vendor
+ */
+ typeId?: string
+ /**
+ * The unique identifier of the reason the vendor is selling
+ */
+ sellingReasonId?: string
+ /**
+ * The unique identifier of the vendor's solicitor
+ */
+ solicitorId?: string
+ /**
+ * The source of the vendor
+ */
+ source?: {
+ /**
+ * The unique identifier of the source of the vendor
+ */
+ id?: string
+ /**
+ * The source type (office/source)
+ */
+ type?: string
+ }
+ /**
+ * A collection of contacts and/or companies associated to the vendor. The first item in the collection is considered the primary relationship
+ */
+ related?: {
+ /**
+ * The unique identifier of the contact or company
+ */
+ id?: string
+ /**
+ * The name of the contact or company
+ */
+ name?: string
+ /**
+ * The type of the contact (company/contact)
+ */
+ type?: string
+ /**
+ * The home phone number of the contact or company
+ */
+ homePhone?: string
+ /**
+ * The work phone number of the contact or company
+ */
+ workPhone?: string
+ /**
+ * The mobile phone number of the contact or company
+ */
+ mobilePhone?: string
+ /**
+ * The email address of the contact or company
+ */
+ email?: string
+ /**
+ * The primary address of the contact or company
+ */
+ primaryAddress?: {
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides within
+ */
+ countryId?: string
+ }
+ }[]
+ /**
+ * The unique identifier of the negotiator attached to the vendor. The first item in the collection is considered the primary negotiator
+ */
+ negotiatorId?: string
+ /**
+ * A collection of unique identifiers of offices attached to the vendor. The first item in the collection is considered the primary office
+ */
+ officeIds?: string[]
+ /**
+ * App specific metadata that has been set against the vendor
+ */
+ metadata?: {
+ [name: string]: any
+ }
+ /**
+ * The ETag for the current version of the vendor. Used for managing update concurrency
+ */
+ readonly _eTag?: string
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+ }[]
+ pageNumber?: number // int32
+ pageSize?: number // int32
+ pageCount?: number // int32
+ totalCount?: number // int32
+ _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+}
+export interface PagedResultWorksOrderItemModel_ {
+ _embedded?: {
+ /**
+ * The unique identifier of the works order item
+ */
+ id?: string
+ /**
+ * The unique identifier of the parent works order
+ */
+ worksOrderId?: string
+ /**
+ * The date and time when the works order item was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the works order item was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The notes attached to the works order item
+ */
+ notes?: string
+ /**
+ * The party to be charged for the work being carried out (landlord/tenant)
+ */
+ chargeTo?: string
+ /**
+ * The estimate of any costs associated with the work being carried out given to the party to be charged for the work
+ */
+ estimate?: number // double
+ /**
+ * The type of estimate supplied (agent/verbal/written)
+ */
+ estimateType?: string
+ /**
+ * The net cost of the work to be carried out
+ */
+ netAmount?: number // double
+ /**
+ * The additional vat cost for the work to be carried out
+ */
+ vatAmount?: number // double
+ /**
+ * The gross cost of the work to be carried out
+ */
+ grossAmount?: number // double
+ /**
+ * The ETag for the current version of the works order item. Used for managing update concurrency
+ */
+ readonly _eTag?: string
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+ }[]
+ pageNumber?: number // int32
+ pageSize?: number // int32
+ pageCount?: number // int32
+ totalCount?: number // int32
+ _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+}
+export interface PagedResultWorksOrderModel_ {
+ _embedded?: {
+ /**
+ * The unique identifier of the works order
+ */
+ id?: string
+ /**
+ * The date and time when the works order was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the works order was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The unique identifier of the company that has been selected to perform the work
+ */
+ companyId?: string
+ /**
+ * The unique identifier of the property where the work is to be carried out
+ */
+ propertyId?: string
+ /**
+ * The unique identifier of the tenancy that the works order originated from
+ */
+ tenancyId?: string
+ /**
+ * The unique identifier of the negotiator that booked the works order
+ */
+ negotiatorId?: string
+ /**
+ * The unique identifier of the type of work that needs to be carried out
+ */
+ typeId?: string
+ /**
+ * The current status of the works order (pendingApproval/pendingQuote/raised/raisedToChase/landlordToComplete/complete/cancelled)
+ */
+ status?: string
+ /**
+ * A free text description of the work required
+ */
+ description?: string
+ /**
+ * The party requesting the work to be carried out (landlord/tenant/other)
+ */
+ reporter?: string
+ /**
+ * The date when the works order was booked
+ * example:
+ * 2019-08-14
+ */
+ booked?: string // date
+ /**
+ * The date when the work is required to be completed by
+ * example:
+ * 2019-08-14
+ */
+ required?: string // date
+ /**
+ * The date when the work was completed
+ * example:
+ * 2019-08-14
+ */
+ completed?: string // date
+ /**
+ * The total net cost for all of the items of work to be carried out
+ */
+ totalNetAmount?: number // double
+ /**
+ * The total additional vat cost for all of the items of work to be carried out
+ */
+ totalVatAmount?: number // double
+ /**
+ * The total gross cost for all of the items of work to be carried out
+ */
+ totalGrossAmount?: number // double
+ /**
+ * A collection of jobs/items of work that the works order should fulfill
+ */
+ items?: {
+ /**
+ * The unique identifier of the works order item
+ */
+ id?: string
+ /**
+ * The unique identifier of the parent works order
+ */
+ worksOrderId?: string
+ /**
+ * The date and time when the works order item was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the works order item was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The notes attached to the works order item
+ */
+ notes?: string
+ /**
+ * The party to be charged for the work being carried out (landlord/tenant)
+ */
+ chargeTo?: string
+ /**
+ * The estimate of any costs associated with the work being carried out given to the party to be charged for the work
+ */
+ estimate?: number // double
+ /**
+ * The type of estimate supplied (agent/verbal/written)
+ */
+ estimateType?: string
+ /**
+ * The net cost of the work to be carried out
+ */
+ netAmount?: number // double
+ /**
+ * The additional vat cost for the work to be carried out
+ */
+ vatAmount?: number // double
+ /**
+ * The gross cost of the work to be carried out
+ */
+ grossAmount?: number // double
+ /**
+ * The ETag for the current version of the works order item. Used for managing update concurrency
+ */
+ readonly _eTag?: string
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+ }[]
+ /**
+ * App specific metadata that has been set against the works order
+ */
+ metadata?: {
+ [name: string]: any
+ }
+ /**
+ * The ETag for the current version of the works order. Used for managing update concurrency
+ */
+ readonly _eTag?: string
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+ }[]
+ pageNumber?: number // int32
+ pageSize?: number // int32
+ pageCount?: number // int32
+ totalCount?: number // int32
+ _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+}
+export interface PagingLinkModel {
+ href?: string
+}
+export interface Properties {
+ PageSize?: number
+ PageNumber?: number
+ SortBy?: string
+ Id?: string[]
+ LandlordId?: string[]
+ Address?: string
+ DepartmentId?: string
+ BedroomsFrom?: number
+ BedroomsTo?: number
+ PriceFrom?: number
+ PriceTo?: number
+ RentFrom?: number
+ RentTo?: number
+ InternetAdvertising?: boolean
+ Embed?: (
+ | 'area'
+ | 'department'
+ | 'documents'
+ | 'images'
+ | 'landlord'
+ | 'negotiator'
+ | 'offers'
+ | 'offices'
+ | 'vendor'
+ )[]
+ Age?: ('period' | 'new' | 'modern')[]
+ LettingStatus?: (
+ | 'valuation'
+ | 'toLet'
+ | 'toLetUnavailable'
+ | 'underOffer '
+ | 'underOfferUnavailable'
+ | 'arrangingTenancyUnavailable '
+ | 'arrangingTenancy'
+ | 'tenancyCurrentUnavailable'
+ | 'tenancyCurrent'
+ | 'tenancyFinished '
+ | 'tenancyCancelled'
+ | 'sold'
+ | 'letByOtherAgent'
+ | 'letPrivately '
+ | 'provisional'
+ | 'withdrawn'
+ )[]
+ Locality?: ('rural' | 'village' | 'townCity')[]
+ Parking?: ('residents' | 'offStreet' | 'secure' | 'underground' | 'garage' | 'doubleGarage' | 'tripleGarage')[]
+ SellingStatus?: (
+ | 'preAppraisal'
+ | 'valuation'
+ | 'paidValuation'
+ | 'forSale '
+ | 'forSaleUnavailable'
+ | 'underOffer'
+ | 'underOfferUnavailable'
+ | 'reserved'
+ | 'exchanged '
+ | 'completed'
+ | 'soldExternally'
+ | 'withdrawn'
+ )[]
+ Situation?: ('garden' | 'land' | 'patio' | 'roofTerrace' | 'conservatory' | 'balcony' | 'communalGardens')[]
+ Style?: (
+ | 'terraced'
+ | 'endTerrace'
+ | 'detached'
+ | 'semiDetached'
+ | 'linkDetached'
+ | 'mews'
+ | 'basement'
+ | 'lowerGroundFloor'
+ | 'groundFloor'
+ | 'firstFloor'
+ | 'upperFloor'
+ | 'upperFloorWithLift'
+ | 'penthouse'
+ )[]
+ Type?: (
+ | 'house'
+ | 'bungalow'
+ | 'flatApartment'
+ | 'maisonette'
+ | 'land'
+ | 'farm'
+ | 'cottage'
+ | 'studio'
+ | 'townhouse'
+ | 'developmentPlot'
+ )[]
+ MarketingMode?: ('selling' | 'letting' | 'sellingAndLetting')[]
+}
+/**
+ * Representation of the physical address of a building or premise
+ */
+export interface PropertyAddressModel {
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides within
+ */
+ countryId?: string
+ /**
+ * The geolocation coordinates associated with the address
+ */
+ geolocation?: {
+ /**
+ * The latitude coordinate of the coordinate pair
+ */
+ latitude?: number // double
+ /**
+ * The longitude coordinate of the coordinate pair
+ */
+ longitude?: number // double
+ }
+}
+/**
+ * Representation of EPC statistics
+ */
+export interface PropertyEpcModel {
+ /**
+ * A flag denoting whether or not this property is exempt from requiring an EPC certificate
+ */
+ exempt?: boolean
+ /**
+ * The current energy efficiency rating
+ */
+ eer?: number // int32
+ /**
+ * The potential energy efficiency rating
+ */
+ eerPotential?: number // int32
+ /**
+ * The current environmental impact rating
+ */
+ eir?: number // int32
+ /**
+ * The potential environmental impact rating
+ */
+ eirPotential?: number // int32
+}
+/**
+ * Representation of the external land area of a property
+ */
+export interface PropertyExternalAreaModel {
+ /**
+ * The unit of area (acres/hectares)
+ */
+ type?: string
+ /**
+ * The minimum area bound
+ */
+ min?: number // double
+ /**
+ * The maximum area bound
+ */
+ max?: number // double
+}
+/**
+ * Representation of the geographical location of an address using coordinates
+ */
+export interface PropertyGeolocationModel {
+ /**
+ * The latitude coordinate of the coordinate pair
+ */
+ latitude?: number // double
+ /**
+ * The longitude coordinate of the coordinate pair
+ */
+ longitude?: number // double
+}
+/**
+ * Representation of a property image
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+export interface PropertyImageModel {
+ /**
+ * The unique identifier of the image, which is also the filename
+ */
+ id?: string
+ /**
+ * The date and time when the image was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the property image was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The unique identifier of the property attached to the image
+ */
+ propertyId?: string
+ /**
+ * The url where the image can be downloaded from
+ */
+ url?: string
+ /**
+ * The image caption
+ */
+ caption?: string
+ /**
+ * The type of image (picture/floorPlan/epc/map)
+ */
+ type?: string
+ /**
+ * The display order index of the image which can be used to correctly order the whole collection
+ */
+ order?: number // int32
+ /**
+ * The ETag for the current version of the image. Used for managing update concurrency
+ */
+ readonly _eTag?: string
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+}
+export interface PropertyImages {
+ PageSize?: number
+ PageNumber?: number
+ SortBy?: string
+ Id?: string[]
+ PropertyId?: string[]
+ Embed?: 'property'[]
+ Type?: ('photograph' | 'map' | 'floorPlan' | 'epc')[]
+}
+/**
+ * Representation of the internal dimensions of a property
+ */
+export interface PropertyInternalAreaModel {
+ /**
+ * The unit of area (squareFeet/squareMetres)
+ */
+ type?: string
+ /**
+ * The minimum area bound
+ */
+ min?: number // double
+ /**
+ * The maximum area bound
+ */
+ max?: number // double
+}
+/**
+ * Representation of property details specific to lettings marketing
+ */
+export interface PropertyLettingModel {
+ /**
+ * The date the property was marked as to let
+ * example:
+ * 2019-08-14
+ */
+ instructed?: string // date
+ /**
+ * The date the property is next available from
+ * example:
+ * 2019-08-14
+ */
+ availableFrom?: string // date
+ /**
+ * The date the property is available to
+ * example:
+ * 2019-08-14
+ */
+ availableTo?: string // date
+ /**
+ * The rent being charged for the property
+ */
+ rent?: number // double
+ /**
+ * The frequency at which rent will be collected (weekly/monthly/yearly)
+ */
+ rentFrequency?: string
+ /**
+ * The acceptable letting terms (short/long/any)
+ */
+ term?: string
+ /**
+ * The current status of the let (valuation/toLet/toLetUnavailable/underOffer/underOfferUnavailable/arrangingTenancyUnavailable/arrangingTenancy/tenancyCurrentUnavailable/tenancyCurrent/tenancyFinished/tenancyCancelled/sold/letByOtherAgent/letPrivately/provisional/withdrawn)
+ */
+ status?: string
+ /**
+ * The unique identifier of the landlord letting the property
+ */
+ landlordId?: string
+}
+/**
+ * Representation of a property
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+export interface PropertyModel {
+ /**
+ * The unique identifier of the property
+ */
+ id?: string
+ /**
+ * The date and time when the property was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the property was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The marketing mode of the property (selling/letting/sellingAndLetting)
+ */
+ marketingMode?: string
+ /**
+ * The currency that applies to monetary amounts exposed in the model
+ */
+ currency?: string
+ /**
+ * The address of the property
+ */
+ address?: {
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides within
+ */
+ countryId?: string
+ /**
+ * The geolocation coordinates associated with the address
+ */
+ geolocation?: {
+ /**
+ * The latitude coordinate of the coordinate pair
+ */
+ latitude?: number // double
+ /**
+ * The longitude coordinate of the coordinate pair
+ */
+ longitude?: number // double
+ }
+ }
+ /**
+ * The unique identifier of the area that the property resides in
+ */
+ areaId?: string
+ /**
+ * The strapline description containing a short summary about the property
+ */
+ strapline?: string
+ /**
+ * The brief description of the property
+ */
+ description?: string
+ /**
+ * The summary of accommodation, typically short phrases or bullet points describing the key features of the property
+ */
+ summary?: string
+ /**
+ * The unique identifier of the department
+ */
+ departmentId?: string
+ /**
+ * The unique identifier of the negotiator managing the property
+ */
+ negotiatorId?: string
+ /**
+ * The total number of bedrooms in the property
+ */
+ bedrooms?: number // int32
+ /**
+ * The total number of reception rooms in the property
+ */
+ receptions?: number // int32
+ /**
+ * The total number of bathrooms in the property
+ */
+ bathrooms?: number // int32
+ /**
+ * The council tax banding of the property (A/B/C/D/E/F/G/H)
+ */
+ councilTax?: string
+ /**
+ * A flag denoting whether or not this property can be advertised on the internet
+ */
+ internetAdvertising?: boolean
+ /**
+ * The arrangements regarding viewing the property
+ */
+ viewingArrangements?: string
+ /**
+ * Details of the external land area associated to this property
+ */
+ externalArea?: {
+ /**
+ * The unit of area (acres/hectares)
+ */
+ type?: string
+ /**
+ * The minimum area bound
+ */
+ min?: number // double
+ /**
+ * The maximum area bound
+ */
+ max?: number // double
+ }
+ /**
+ * Details of the internal dimensions of the property
+ */
+ internalArea?: {
+ /**
+ * The unit of area (squareFeet/squareMetres)
+ */
+ type?: string
+ /**
+ * The minimum area bound
+ */
+ min?: number // double
+ /**
+ * The maximum area bound
+ */
+ max?: number // double
+ }
+ /**
+ * Details of the EPC statistics
+ */
+ epc?: {
+ /**
+ * A flag denoting whether or not this property is exempt from requiring an EPC certificate
+ */
+ exempt?: boolean
+ /**
+ * The current energy efficiency rating
+ */
+ eer?: number // int32
+ /**
+ * The potential energy efficiency rating
+ */
+ eerPotential?: number // int32
+ /**
+ * The current environmental impact rating
+ */
+ eir?: number // int32
+ /**
+ * The potential environmental impact rating
+ */
+ eirPotential?: number // int32
+ }
+ /**
+ * Selling specific details about the property
+ */
+ selling?: {
+ /**
+ * The date that the property was marked as for sale
+ * example:
+ * 2019-08-14
+ */
+ instructed?: string // date
+ /**
+ * The marketing price of the property
+ */
+ price?: number // double
+ /**
+ * The price qualifier (askingPrice/priceOnApplication/guidePrice/offersInRegion/offersOver/offersInExcess/fixedPrice/priceReducedTo)
+ */
+ qualifier?: string
+ /**
+ * The current status of the sale (preAppraisal/valuation/paidValuation/forSale/forSaleUnavailable/underOffer/underOfferUnavailable/reserved/exchanged/completed/soldExternally/withdrawn)
+ */
+ status?: string
+ /**
+ * Details about the tenure of the property
+ */
+ tenure?: {
+ /**
+ * The type of tenure that applies to the property (freehold/leasehold/shareOfFreehold/commonhold/tba)
+ */
+ type?: string
+ /**
+ * The tenure expiration date
+ * example:
+ * 2019-08-14
+ */
+ expiry?: string // date
+ }
+ /**
+ * The unique identifier of the vendor selling the property
+ */
+ vendorId?: string
+ }
+ /**
+ * Letting specific details about the property
+ */
+ letting?: {
+ /**
+ * The date the property was marked as to let
+ * example:
+ * 2019-08-14
+ */
+ instructed?: string // date
+ /**
+ * The date the property is next available from
+ * example:
+ * 2019-08-14
+ */
+ availableFrom?: string // date
+ /**
+ * The date the property is available to
+ * example:
+ * 2019-08-14
+ */
+ availableTo?: string // date
+ /**
+ * The rent being charged for the property
+ */
+ rent?: number // double
+ /**
+ * The frequency at which rent will be collected (weekly/monthly/yearly)
+ */
+ rentFrequency?: string
+ /**
+ * The acceptable letting terms (short/long/any)
+ */
+ term?: string
+ /**
+ * The current status of the let (valuation/toLet/toLetUnavailable/underOffer/underOfferUnavailable/arrangingTenancyUnavailable/arrangingTenancy/tenancyCurrentUnavailable/tenancyCurrent/tenancyFinished/tenancyCancelled/sold/letByOtherAgent/letPrivately/provisional/withdrawn)
+ */
+ status?: string
+ /**
+ * The unique identifier of the landlord letting the property
+ */
+ landlordId?: string
+ }
+ /**
+ * The property type attributes
+ */
+ type?: string[]
+ /**
+ * The property style attributes
+ */
+ style?: string[]
+ /**
+ * The property situation attributes
+ */
+ situation?: string[]
+ /**
+ * The property parking attributes
+ */
+ parking?: string[]
+ /**
+ * The property age attributes
+ */
+ age?: string[]
+ /**
+ * The property locality attributes
+ */
+ locality?: string[]
+ /**
+ * Details of each room in the property
+ */
+ rooms?: {
+ /**
+ * The name of the room
+ */
+ name?: string
+ /**
+ * Details about the dimensions of the room
+ */
+ dimensions?: string
+ /**
+ * Short description of the room
+ */
+ description?: string
+ }[]
+ /**
+ * A collection of unique identifiers of offices attached to the property
+ */
+ officeIds?: string[]
+ /**
+ * App specific metadata that has been set against the property
+ */
+ metadata?: {
+ [name: string]: any
+ }
+ /**
+ * The ETag for the current version of the property. Used for managing update concurrency
+ */
+ readonly _eTag?: string
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+}
+/**
+ * Representation of a single room in a property
+ */
+export interface PropertyRoomModel {
+ /**
+ * The name of the room
+ */
+ name?: string
+ /**
+ * Details about the dimensions of the room
+ */
+ dimensions?: string
+ /**
+ * Short description of the room
+ */
+ description?: string
+}
+/**
+ * Representation of property details specific to sales marketing
+ */
+export interface PropertySellingModel {
+ /**
+ * The date that the property was marked as for sale
+ * example:
+ * 2019-08-14
+ */
+ instructed?: string // date
+ /**
+ * The marketing price of the property
+ */
+ price?: number // double
+ /**
+ * The price qualifier (askingPrice/priceOnApplication/guidePrice/offersInRegion/offersOver/offersInExcess/fixedPrice/priceReducedTo)
+ */
+ qualifier?: string
+ /**
+ * The current status of the sale (preAppraisal/valuation/paidValuation/forSale/forSaleUnavailable/underOffer/underOfferUnavailable/reserved/exchanged/completed/soldExternally/withdrawn)
+ */
+ status?: string
+ /**
+ * Details about the tenure of the property
+ */
+ tenure?: {
+ /**
+ * The type of tenure that applies to the property (freehold/leasehold/shareOfFreehold/commonhold/tba)
+ */
+ type?: string
+ /**
+ * The tenure expiration date
+ * example:
+ * 2019-08-14
+ */
+ expiry?: string // date
+ }
+ /**
+ * The unique identifier of the vendor selling the property
+ */
+ vendorId?: string
+}
+/**
+ * Representation of the tenure of a property
+ */
+export interface PropertyTenureModel {
+ /**
+ * The type of tenure that applies to the property (freehold/leasehold/shareOfFreehold/commonhold/tba)
+ */
+ type?: string
+ /**
+ * The tenure expiration date
+ * example:
+ * 2019-08-14
+ */
+ expiry?: string // date
+}
+/**
+ * Representation of a source of business
+ */
+export interface SourceModel {
+ /**
+ * The unique identifier of the source
+ */
+ id?: string
+ /**
+ * The date and time when the source was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the source was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The name of the source or advertising publication
+ */
+ name?: string
+ /**
+ * The type of the source (source/advertisement)
+ */
+ type?: string
+ /**
+ * A collection of the unique identifiers of offices that regularly get business from the source
+ */
+ officeIds?: string[]
+ /**
+ * A collection of unique identifiers of departments that regularly get business from the source
+ */
+ departmentIds?: string[]
+ /**
+ * The ETag for the current version of the source. Used for managing update concurrency
+ */
+ readonly _eTag?: string
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+}
+export interface Sources {
+ PageSize?: number
+ PageNumber?: number
+ SortBy?: string
+ Id?: string[]
+ OfficeId?: string[]
+ DepartmentId?: string[]
+ Name?: string
+ Type?: string
+ CreatedFrom?: string
+ CreatedTo?: string
+}
+export interface StringSegment {
+ readonly buffer?: string
+ readonly offset?: number // int32
+ readonly length?: number // int32
+ readonly value?: string
+ readonly hasValue?: boolean
+}
+/**
+ * Representation of a task, which can also be an internal message
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+export interface TaskModel {
+ /**
+ * The unique identifier of the task
+ */
+ id?: string
+ /**
+ * The date and time when the task was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the task was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The date the task becomes active
+ * example:
+ * 2019-08-14
+ */
+ activates?: string // date
+ /**
+ * The date the task was completed
+ * example:
+ * 2019-08-14
+ */
+ completed?: string // date
+ /**
+ * The unique identifier of the task type
+ */
+ typeId?: string
+ /**
+ * The unique identifer of the negotiator that created the task
+ */
+ senderId?: string
+ /**
+ * The textual contents of the task or message
+ */
+ text?: string
+ /**
+ * The unique identifier of the landlord the task is associated to
+ */
+ landlordId?: string
+ /**
+ * The unique identifier of the property the task is associated to
+ */
+ propertyId?: string
+ /**
+ * The unique identifier of the applicant the task is associated to
+ */
+ applicantId?: string
+ /**
+ * The unique identifier of the tenancy the task is associated to
+ */
+ tenancyId?: string
+ /**
+ * The unique identifier of the contact the task is associated to
+ */
+ contactId?: string
+ /**
+ * The unique identifier of the negotiator or office the task is being sent to
+ */
+ recipientId?: string
+ /**
+ * The type of the recipient (office/negotiator)
+ */
+ recipientType?: string
+ /**
+ * App specific metadata that has been set against the task
+ */
+ metadata?: {
+ [name: string]: any
+ }
+ /**
+ * The ETag for the current version of the task. Used for managing update concurrency
+ */
+ readonly _eTag?: string
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+}
+export interface Tasks {
+ PageSize?: number
+ PageNumber?: number
+ SortBy?: string
+ Id?: string[]
+ ApplicantId?: string[]
+ ContactId?: string[]
+ LandlordId?: string[]
+ OfficeId?: string[]
+ PropertyId?: string[]
+ RecipientId?: string[]
+ SenderId?: string[]
+ TypeId?: string[]
+ TenancyId?: string[]
+ ActivatesFrom?: string
+ ActivatesTo?: string
+ CreatedFrom?: string
+ CreatedTo?: string
+ Embed?: ('applicant' | 'contact' | 'landlord' | 'property' | 'tenancy' | 'type')[]
+}
+export interface Tenancies {
+ pageSize?: number
+ pageNumber?: number
+ sortBy?: string
+ embed?: ('applicant' | 'documents' | 'negotiator' | 'property' | 'source' | 'tasks' | 'type')[]
+ id?: string[]
+ negotiatorId?: string[]
+ applicantId?: string[]
+ propertyId?: string[]
+ status?: ('offerPending' | 'offerWithdrawn' | 'offerRejected' | 'arranging' | 'current' | 'finished' | 'cancelled')[]
+ createdFrom?: string
+ createdTo?: string
+ modifiedFrom?: string
+ modifiedTo?: string
+}
+/**
+ * Representation of the physical address of a building or premise
+ */
+export interface TenancyContactAddressModel {
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides within
+ */
+ countryId?: string
+}
+/**
+ * A summarised view of the details of a contact or company associated to a tenancy
+ */
+export interface TenancyContactModel {
+ /**
+ * The unique identifier of the contact or company
+ */
+ id?: string
+ /**
+ * The name of the contact or company
+ */
+ name?: string
+ /**
+ * The type of the contact (company/contact)
+ */
+ type?: string
+ /**
+ * The home phone number of the contact or company
+ */
+ homePhone?: string
+ /**
+ * The work phone number of the contact or company
+ */
+ workPhone?: string
+ /**
+ * The mobile phone number of the contact or company
+ */
+ mobilePhone?: string
+ /**
+ * The email address of the contact or company
+ */
+ email?: string
+ /**
+ * The primary address of the contact or company
+ */
+ primaryAddress?: {
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides within
+ */
+ countryId?: string
+ }
+}
+/**
+ * Representation of a relationship between a tenancy and a contact or company
+ */
+export interface TenancyContactRelationshipModel {
+ /**
+ * The unique identifier of the tenancy relationship
+ */
+ id?: string
+ /**
+ * The date and time when the relationship was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the relationship was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The unique identifier of the tenancy
+ */
+ tenancyId?: string
+ /**
+ * The type of related entity (contact/company)
+ */
+ associatedType?: string
+ /**
+ * The unique identifier of the related contact or company
+ */
+ associatedId?: string
+ /**
+ * A flag denoting whether or not this contact or company should be regarded as the main tenant
+ */
+ isMain?: boolean
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+}
+/**
+ * Representation of a tenancy
+ */
+export interface TenancyModel {
+ /**
+ * The unique identifier of the tenancy
+ */
+ id?: string
+ /**
+ * The date and time when the tenancy was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the tenancy was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * example:
+ * 2019-08-14
+ */
+ startDate?: string // date
+ /**
+ * example:
+ * 2019-08-14
+ */
+ endDate?: string // date
+ /**
+ * The current status of the tenancy (offerPending/offerWithdrawn/offerRejected/arranging/current/finished/cancelled)
+ */
+ status?: string
+ /**
+ * The role that the agent is performing for this tenancy (managed/rentCollection/collectFirstPayment/collectRentToDate/lettingOnly/introducingTenant)
+ */
+ agentRole?: string
+ /**
+ * The amount of rent required, returned in relation to the collection frequency
+ */
+ rent?: number // int32
+ /**
+ * The rent collection frequency (weekly/monthly/annually)
+ */
+ rentFrequency?: string
+ /**
+ * A flag determining whether or not this tenancy is confirmed to finish at the end date
+ */
+ endDateConfirmed?: boolean
+ /**
+ * A flag determining whether or not this tenancy has been extended indefinitely
+ */
+ isPeriodic?: boolean
+ /**
+ * The unique identifier of the type of tenancy
+ */
+ typeId?: string
+ /**
+ * The unique identifier of the negotiator who is managing this tenancy
+ */
+ negotiatorId?: string
+ /**
+ * The unique identifier of the property in which this tenancy is for
+ */
+ propertyId?: string
+ /**
+ * The unique identifier of the applicant who has applied to be a tenant
+ */
+ applicantId?: string
+ /**
+ * The source of the tenancy
+ */
+ source?: {
+ /**
+ * The unique identifier of the source for this tenancy
+ */
+ id?: string
+ /**
+ * The source type (office/source)
+ */
+ type?: string
+ }
+ /**
+ * A collection of contact / company tenants associated to this tenancy. The first item in the collection is considered the primary relationship
+ */
+ related?: {
+ /**
+ * The unique identifier of the contact or company
+ */
+ id?: string
+ /**
+ * The name of the contact or company
+ */
+ name?: string
+ /**
+ * The type of the contact (company/contact)
+ */
+ type?: string
+ /**
+ * The home phone number of the contact or company
+ */
+ homePhone?: string
+ /**
+ * The work phone number of the contact or company
+ */
+ workPhone?: string
+ /**
+ * The mobile phone number of the contact or company
+ */
+ mobilePhone?: string
+ /**
+ * The email address of the contact or company
+ */
+ email?: string
+ /**
+ * The primary address of the contact or company
+ */
+ primaryAddress?: {
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides within
+ */
+ countryId?: string
+ }
+ }[]
+ /**
+ * App specific metadata that has been set against the tenancy
+ */
+ metadata?: {
+ [name: string]: any
+ }
+ /**
+ * The ETag for the current version of the tenancy. Used for managing update concurrency
+ */
+ readonly _eTag?: string
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+}
+/**
+ * A tenancy source of enquiry
+ */
+export interface TenancySourceModel {
+ /**
+ * The unique identifier of the source for this tenancy
+ */
+ id?: string
+ /**
+ * The source type (office/source)
+ */
+ type?: string
+}
+/**
+ * The details specific to applicants with a marketingMode of buying
+ */
+export interface UpdateApplicantBuyingModel {
+ /**
+ * The lower bound of the applicant's budget
+ */
+ priceFrom?: number // int32
+ /**
+ * The upper bound of the applicant's budget
+ */
+ priceTo?: number // int32
+}
+/**
+ * The applicant's outdoor space requirements
+ */
+export interface UpdateApplicantExternalAreaModel {
+ /**
+ * The unit of area that each amount corresponds to (acres/hectares)
+ */
+ type?: string
+ /**
+ * The minimum unit value of outside space that the applicant is looking for
+ */
+ amountFrom?: number // double
+ /**
+ * The maximum unit value of outside space that the applicant is looking for
+ */
+ amountTo?: number // double
+}
+/**
+ * The applicant's indoor space requirements
+ */
+export interface UpdateApplicantInternalAreaModel {
+ /**
+ * The unit of area that each amount corresponds to (squareFeet/squareMetres)
+ */
+ type?: string
+ /**
+ * The unit value of inside space that the applicant is looking for
+ */
+ amount?: number // double
+}
+/**
+ * Request body used to update an existing applicant
+ * example:
+ * [object Object]
+ */
+export interface UpdateApplicantModel {
+ /**
+ * Indicates whether the applicant is look to buy or rent a property (buying/renting)
+ */
+ marketingMode?: string
+ /**
+ * A flag determining whether or not the applicant is actively looking for a property
+ */
+ active?: boolean
+ /**
+ * A free text field describing any adhoc buying or renting requirements
+ */
+ notes?: string
+ /**
+ * The date when the applicant was last contacted
+ * example:
+ * 2019-08-14
+ */
+ lastCall?: string // date
+ /**
+ * The date when the applicant is next due to be contacted
+ * example:
+ * 2019-08-14
+ */
+ nextCall?: string // date
+ /**
+ * The unique identifier of the department that the applicant requirements are associated with. The applicant will only match to properties with the same value
+ */
+ departmentId?: string
+ /**
+ * The unique identifier of the solicitor associated to the applicant
+ */
+ solicitorId?: string
+ /**
+ * A list of property type requirements taken from the full listing of the associated department
+ */
+ type?: string[]
+ /**
+ * A list of property style requirements taken from the full listing of the associated department
+ */
+ style?: string[]
+ /**
+ * A list of property situation requirements taken from the full listing of the associated department
+ */
+ situation?: string[]
+ /**
+ * A list of property parking requirements taken from the full listing of the associated department
+ */
+ parking?: string[]
+ /**
+ * A list of property age requirements taken from the full listing of the associated department
+ */
+ age?: string[]
+ /**
+ * A list of property locality requirements taken from the full listing of the associated department
+ */
+ locality?: string[]
+ /**
+ * The minimum number of bedrooms the applicant requires
+ */
+ bedroomsMin?: number // int32
+ /**
+ * The maximum number of bedrooms the applicant requires
+ */
+ bedroomsMax?: number // int32
+ /**
+ * The minimum number of reception rooms the applicant requires
+ */
+ receptionsMin?: number // int32
+ /**
+ * The maximum number of reception rooms the applicant requires
+ */
+ receptionsMax?: number // int32
+ /**
+ * The minimum number of bathrooms the applicant requires
+ */
+ bathroomsMin?: number // int32
+ /**
+ * The maximum number of bathrooms the applicant requires
+ */
+ bathroomsMax?: number // int32
+ /**
+ * The applicant's location type (areas/addresses/none)
+ */
+ locationType?: string
+ /**
+ * The applicant's location options
+ */
+ locationOptions?: string[]
+ /**
+ * The details specific to applicants with a marketingMode of buying
+ */
+ buying?: {
+ /**
+ * The lower bound of the applicant's budget
+ */
+ priceFrom?: number // int32
+ /**
+ * The upper bound of the applicant's budget
+ */
+ priceTo?: number // int32
+ }
+ /**
+ * The details specific to applicants with a marketingMode of renting
+ */
+ renting?: {
+ /**
+ * The date the applicant is looking to move to a new property
+ * example:
+ * 2019-08-14
+ */
+ moveDate?: string // date
+ /**
+ * The applicant's preferred letting term (long/short/any)
+ */
+ term?: string
+ /**
+ * The lower bound of the applicant's budget
+ */
+ rentFrom?: number // double
+ /**
+ * The upper bound of the applicant's budget
+ */
+ rentTo?: number // double
+ /**
+ * The desired rent collection frequency specified by the applicant's budget (weekly/monthly/annually)
+ */
+ rentFrequency?: string
+ /**
+ * A list of property furnishing requirements taken from the full listing of the associated department
+ */
+ furnishing?: string[]
+ }
+ /**
+ * The applicant's outdoor space requirements
+ */
+ externalArea?: {
+ /**
+ * The unit of area that each amount corresponds to (acres/hectares)
+ */
+ type?: string
+ /**
+ * The minimum unit value of outside space that the applicant is looking for
+ */
+ amountFrom?: number // double
+ /**
+ * The maximum unit value of outside space that the applicant is looking for
+ */
+ amountTo?: number // double
+ }
+ /**
+ * The applicant's indoor space requirements
+ */
+ internalArea?: {
+ /**
+ * The unit of area that each amount corresponds to (squareFeet/squareMetres)
+ */
+ type?: string
+ /**
+ * The unit value of inside space that the applicant is looking for
+ */
+ amount?: number // double
+ }
+ /**
+ * The source of the applicant
+ */
+ source?: {
+ /**
+ * The unique identifier of the applicant's source
+ */
+ id?: string
+ /**
+ * The source type (office/source)
+ */
+ type?: string
+ }
+ /**
+ * A collection of unique identifiers of offices attached to the applicant. The first item in the collection is considered the primary office
+ */
+ officeIds?: string[]
+ /**
+ * A collection of unique identifiers of negotiators attached to the applicant. The first item in the collection is considered the primary negotiator
+ */
+ negotiatorIds?: string[]
+ /**
+ * App specific metadata to set against the applicant
+ */
+ metadata?: {
+ [name: string]: any
+ }
+}
+/**
+ * The details specific to applicants with a marketingMode of renting
+ */
+export interface UpdateApplicantRentingModel {
+ /**
+ * The date the applicant is looking to move to a new property
+ * example:
+ * 2019-08-14
+ */
+ moveDate?: string // date
+ /**
+ * The applicant's preferred letting term (long/short/any)
+ */
+ term?: string
+ /**
+ * The lower bound of the applicant's budget
+ */
+ rentFrom?: number // double
+ /**
+ * The upper bound of the applicant's budget
+ */
+ rentTo?: number // double
+ /**
+ * The desired rent collection frequency specified by the applicant's budget (weekly/monthly/annually)
+ */
+ rentFrequency?: string
+ /**
+ * A list of property furnishing requirements taken from the full listing of the associated department
+ */
+ furnishing?: string[]
+}
+/**
+ * An applicant's source of enquiry
+ */
+export interface UpdateApplicantSourceModel {
+ /**
+ * The unique identifier of the applicant's source
+ */
+ id?: string
+ /**
+ * The source type (office/source)
+ */
+ type?: string
+}
+/**
+ * Represents an external attendee on an appointment
+ */
+export interface UpdateAppointmentAttendeeModel {
+ /**
+ * The unique identifier of the attendee
+ */
+ id?: string
+ /**
+ * The type of attendee (applicant/contact/landlord/tenant)
+ */
+ type?: string
+ /**
+ * A flag denoting whether or not the attendee has confirmed their attendance
+ */
+ confirmed?: boolean
+}
+/**
+ * Represents the follow up information on a single appointment
+ */
+export interface UpdateAppointmentFollowUpModel {
+ /**
+ * The unique identifier of a pre-defined follow up response type
+ */
+ responseId?: string
+ /**
+ * The internal follow up notes to be stored against the appointment
+ */
+ notes?: string
+}
+/**
+ * Request body used to update an existing calendar appointment
+ * example:
+ * [object Object]
+ */
+export interface UpdateAppointmentModel {
+ /**
+ * The date and time when the appointment will start
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ start?: string // date-time
+ /**
+ * The date and time when the appointment will end
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ end?: string // date-time
+ /**
+ * The date when the appointment should be followed up
+ * example:
+ * 2019-08-14
+ */
+ followUpOn?: string // date
+ /**
+ * The unique identifier of the appointment type
+ */
+ typeId?: string
+ /**
+ * A free text description about the appointment
+ */
+ description?: string
+ /**
+ * The unique identifier of the property related to the appointment
+ */
+ propertyId?: string
+ /**
+ * The unique identifier of the negotiator that organised the appointment
+ */
+ organiserId?: string
+ /**
+ * A flag denoting whether or not the appointment has been cancelled
+ */
+ cancelled?: boolean
+ /**
+ * A collection of unique identifiers of negotiators attached to the appointment
+ */
+ negotiatorIds?: string[]
+ /**
+ * A collection of unique identifiers of offices attached to the appointment
+ */
+ officeIds?: string[]
+ /**
+ * Details of the external appointment attendee
+ */
+ attendee?: {
+ /**
+ * The unique identifier of the attendee
+ */
+ id?: string
+ /**
+ * The type of attendee (applicant/contact/landlord/tenant)
+ */
+ type?: string
+ /**
+ * A flag denoting whether or not the attendee has confirmed their attendance
+ */
+ confirmed?: boolean
+ }
+ /**
+ * A flag denoting whether or not the appointment will be accompanied by one or more negotiators
+ */
+ accompanied?: boolean
+ /**
+ * A flag denoting whether or not the main negotiator has confirmed their attendance
+ */
+ negotiatorConfirmed?: boolean
+ /**
+ * A flag denoting whether or not the attendee has confirmed their attendance
+ */
+ attendeeConfirmed?: boolean
+ /**
+ * A flag denoting whether or not the property and/or property's vendor has confirmed their attendance
+ */
+ propertyConfirmed?: boolean
+ /**
+ * Details added when the appointment has been followed up
+ */
+ followUp?: {
+ /**
+ * The unique identifier of a pre-defined follow up response type
+ */
+ responseId?: string
+ /**
+ * The internal follow up notes to be stored against the appointment
+ */
+ notes?: string
+ }
+ /**
+ * Details of the recurrence pattern for the appointment
+ */
+ recurrence?: {
+ /**
+ * The type of unit that the `interval` applies to
+ */
+ type?: string
+ /**
+ * The numeric value denoting how often the appointment will recur
+ */
+ interval?: number // int32
+ /**
+ * The date and time when the recurrence will stop
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ until?: string // date-time
+ }
+ /**
+ * App specific metadata to set against the appointment
+ */
+ metadata?: {
+ [name: string]: any
+ }
+}
+/**
+ * Details of an appointment's recurrence pattern
+ */
+export interface UpdateAppointmentRecurrenceModel {
+ /**
+ * The type of unit that the `interval` applies to
+ */
+ type?: string
+ /**
+ * The numeric value denoting how often the appointment will recur
+ */
+ interval?: number // int32
+ /**
+ * The date and time when the recurrence will stop
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ until?: string // date-time
+}
+/**
+ * Request body used to update an existing area
+ * example:
+ * [object Object]
+ */
+export interface UpdateAreaModel {
+ /**
+ * The name of the area
+ */
+ name?: string
+ /**
+ * The location details (comma delimited list of postcodes, group ids or lat/long coordinate groups)
+ */
+ area?: string[]
+ /**
+ * A collection of unique identifiers of departments associated to the area
+ */
+ departmentIds?: string[]
+ /**
+ * A collection of unique identifiers of offices associated to the area
+ */
+ officeIds?: string[]
+}
+/**
+ * Request body to set the address of an existing company
+ */
+export interface UpdateCompanyAddressModel {
+ /**
+ * The type of address (primary/secondary/home/work/forwarding/company/previous)
+ */
+ type?: string
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides within
+ */
+ countryId?: string
+}
+/**
+ * Request body used to update an existing company
+ * example:
+ * [object Object]
+ */
+export interface UpdateCompanyModel {
+ /**
+ * The name of the company
+ */
+ name?: string
+ /**
+ * The branch name of the company
+ */
+ branch?: string
+ /**
+ * A free text field containing notes that describe the company's business or service offering
+ */
+ notes?: string
+ /**
+ * A flag determining whether or not the company is currently active
+ */
+ active?: boolean
+ /**
+ * A flag determining whether or not the company is VAT registered
+ */
+ vatRegistered?: boolean
+ /**
+ * A collection of unique identifiers of company types that categorise the type of business the company operates
+ */
+ typeIds?: string[]
+ /**
+ * The unique identifier of a supplier type, if the company is a supplier
+ */
+ supplierTypeId?: string
+ /**
+ * The work phone number of the company
+ */
+ workPhone?: string
+ /**
+ * The mobile phone number of the company
+ */
+ mobilePhone?: string
+ /**
+ * The email address of the company
+ */
+ email?: string
+ /**
+ * The address of the company
+ */
+ address?: {
+ /**
+ * The type of address (primary/secondary/home/work/forwarding/company/previous)
+ */
+ type?: string
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides within
+ */
+ countryId?: string
+ }
+ /**
+ * App specific metadata to set against the company
+ */
+ metadata?: {
+ [name: string]: any
+ }
+}
+/**
+ * Request body used to update an address on an existing contact
+ */
+export interface UpdateContactAddressModel {
+ /**
+ * The type of address (primary/secondary/home/work/forwarding/company/previous)
+ */
+ type?: string
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the adderess resides in
+ */
+ countryId?: string
+}
+/**
+ * Request body used to update an existing contact
+ * example:
+ * [object Object]
+ */
+export interface UpdateContactModel {
+ /**
+ * The contact's title (eg. Mr, Mrs, Miss, Dr)
+ */
+ title?: string
+ /**
+ * The contact's forename
+ */
+ forename?: string
+ /**
+ * The contact's surname
+ */
+ surname?: string
+ /**
+ * The contact's date of birth
+ * example:
+ * 2019-08-14
+ */
+ dateOfBirth?: string // date
+ /**
+ * A flag determining whether or not the contact is currently active
+ */
+ active?: boolean
+ /**
+ * The marketing consent status of the contact (grant/deny/notAsked)
+ */
+ marketingConsent?: string
+ /**
+ * The source of the contact
+ */
+ source?: {
+ /**
+ * The unique identifier of the source of the contact
+ */
+ id?: string
+ /**
+ * The source type (office/source)
+ */
+ type?: string
+ }
+ /**
+ * The home phone number of the contact
+ */
+ homePhone?: string
+ /**
+ * The work phone number of the contact
+ */
+ workPhone?: string
+ /**
+ * The mobile phone number of the contact
+ */
+ mobilePhone?: string
+ /**
+ * The email address of the contact
+ */
+ email?: string
+ /**
+ * A collection of unique identifiers of offices attached to the contact
+ */
+ officeIds?: string[]
+ /**
+ * A collection of unique identifiers of negotiators attached to the contact
+ */
+ negotiatorIds?: string[]
+ /**
+ * The primary address of the contact
+ */
+ primaryAddress?: {
+ /**
+ * The type of address (primary/secondary/home/work/forwarding/company/previous)
+ */
+ type?: string
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the adderess resides in
+ */
+ countryId?: string
+ }
+ /**
+ * The secondary address of the contact
+ */
+ secondaryAddress?: {
+ /**
+ * The type of address (primary/secondary/home/work/forwarding/company/previous)
+ */
+ type?: string
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the adderess resides in
+ */
+ countryId?: string
+ }
+ /**
+ * The work address of the contact
+ */
+ workAddress?: {
+ /**
+ * The type of address (primary/secondary/home/work/forwarding/company/previous)
+ */
+ type?: string
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the adderess resides in
+ */
+ countryId?: string
+ }
+ /**
+ * App specific metadata to set against the contact
+ */
+ metadata?: {
+ [name: string]: any
+ }
+}
+/**
+ * Request body used to update the source of an existing contact
+ */
+export interface UpdateContactSourceModel {
+ /**
+ * The unique identifier of the source of the contact
+ */
+ id?: string
+ /**
+ * The source type (office/source)
+ */
+ type?: string
+}
+/**
+ * Request body used to update an existing document
+ * example:
+ * [object Object]
+ */
+export interface UpdateDocumentModel {
+ /**
+ * The unique identifier of the type of document
+ */
+ typeId?: string
+ /**
+ * The filename of the document
+ */
+ name?: string
+}
+/**
+ * Request body used to update an exist contact identity check
+ * example:
+ * [object Object]
+ */
+export interface UpdateIdentityCheckModel {
+ /**
+ * The date when the identity check was performed. This may differ to the date when the check was created
+ * example:
+ * 2019-08-14
+ */
+ checkDate?: string // date
+ /**
+ * The current status of the identity check (pass/fail/pending/cancelled/warnings/unchecked)
+ */
+ status?: string
+ /**
+ * The unique identifier of the negotiator that initiated the identity check
+ */
+ negotiatorId?: string
+ /**
+ * The details of the first document that was provided as part of the identity check
+ */
+ identityDocument1?: {
+ /**
+ * The unique identifier of the type of identity document provided
+ */
+ typeId?: string
+ /**
+ * The date when the document expires and becomes invalid
+ * example:
+ * 2019-08-14
+ */
+ expiry?: string // date
+ /**
+ * Details regarding the identity document (eg. passport number)
+ */
+ details?: string
+ /**
+ * The base64 encoded identity document content, prefixed with the content type (eg. data:text/plain;base64,VGVzdCBmaWxl)
+ */
+ fileData?: string
+ /**
+ * The filename to store the document as
+ */
+ name?: string
+ }
+ /**
+ * The details of the second document that was provided as part of the identity check
+ */
+ identityDocument2?: {
+ /**
+ * The unique identifier of the type of identity document provided
+ */
+ typeId?: string
+ /**
+ * The date when the document expires and becomes invalid
+ * example:
+ * 2019-08-14
+ */
+ expiry?: string // date
+ /**
+ * Details regarding the identity document (eg. passport number)
+ */
+ details?: string
+ /**
+ * The base64 encoded identity document content, prefixed with the content type (eg. data:text/plain;base64,VGVzdCBmaWxl)
+ */
+ fileData?: string
+ /**
+ * The filename to store the document as
+ */
+ name?: string
+ }
+ /**
+ * App specific metadata to set against the identity check
+ */
+ metadata?: {
+ [name: string]: any
+ }
+}
+/**
+ * Request body to update an identity document attached to an existing contact identity check
+ */
+export interface UpdateIdentityDocumentModel {
+ /**
+ * The unique identifier of the type of identity document provided
+ */
+ typeId?: string
+ /**
+ * The date when the document expires and becomes invalid
+ * example:
+ * 2019-08-14
+ */
+ expiry?: string // date
+ /**
+ * Details regarding the identity document (eg. passport number)
+ */
+ details?: string
+ /**
+ * The base64 encoded identity document content, prefixed with the content type (eg. data:text/plain;base64,VGVzdCBmaWxl)
+ */
+ fileData?: string
+ /**
+ * The filename to store the document as
+ */
+ name?: string
+}
+/**
+ * Request body used to update an existing landlord
+ * example:
+ * [object Object]
+ */
+export interface UpdateLandlordModel {
+ /**
+ * A flag determining whether or not the landlord is currently active
+ */
+ active?: boolean
+ /**
+ * The unique identifier of the company acting as the landlord's solicitor
+ */
+ solicitorId?: string
+ /**
+ * The unique identifier of the office that is associated to the landlord
+ */
+ officeId?: string
+ /**
+ * The source of the landlord
+ */
+ source?: {
+ /**
+ * The unique identifier of the source of the landlord
+ */
+ id?: string
+ /**
+ * The source type (office/source)
+ */
+ type?: string
+ }
+ /**
+ * App specific metadata that to set against the landlord
+ */
+ metadata?: {
+ [name: string]: any
+ }
+}
+/**
+ * Request body used to update the source of an existing landlord
+ */
+export interface UpdateLandlordSourceModel {
+ /**
+ * The unique identifier of the source of the landlord
+ */
+ id?: string
+ /**
+ * The source type (office/source)
+ */
+ type?: string
+}
+/**
+ * Request body used to update an existing negotiator
+ * example:
+ * [object Object]
+ */
+export interface UpdateNegotiatorModel {
+ /**
+ * The name of the negotiator
+ */
+ name?: string
+ /**
+ * The job title of the negotiator
+ */
+ jobTitle?: string
+ /**
+ * A flag determining whether or not the negotiator is active
+ */
+ active?: boolean
+ /**
+ * The work phone number of the negotiator
+ */
+ workPhone?: string
+ /**
+ * The mobile phone number of the negotiator
+ */
+ mobilePhone?: string
+ /**
+ * The email address of the negotiator
+ */
+ email?: string
+ /**
+ * App specific metadata to set against the negotiator
+ */
+ metadata?: {
+ [name: string]: any
+ }
+}
+/**
+ * Request body used to update an existing offer
+ * example:
+ * [object Object]
+ */
+export interface UpdateOfferModel {
+ /**
+ * The unique identifier of the negotiator associated to the offer
+ */
+ negotiatorId?: string
+ /**
+ * The date when the offer was made
+ * example:
+ * 2019-08-14
+ */
+ date?: string // date
+ /**
+ * The monetary amount of the offer
+ */
+ amount?: number // double
+ /**
+ * The current status of the offer (pending/withdrawn/rejected/accepted/noteOfInterest)
+ */
+ status?: string
+ /**
+ * A free text field describing items that should be included in the sale
+ */
+ inclusions?: string
+ /**
+ * A free text field describing items that are explicitly excluded from the sale
+ */
+ exclusions?: string
+ /**
+ * A free text field describing any other conditions set by either party that relate to the sale
+ */
+ conditions?: string
+ /**
+ * App specific metadata to set against the offer
+ */
+ metadata?: {
+ [name: string]: any
+ }
+}
+/**
+ * Request body used to update the address of an existing office
+ */
+export interface UpdateOfficeAddressModel {
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides within
+ */
+ countryId?: string
+}
+/**
+ * Request body used to update an existing office
+ * example:
+ * [object Object]
+ */
+export interface UpdateOfficeModel {
+ /**
+ * The name of the office
+ */
+ name?: string
+ /**
+ * The name of the office manager
+ */
+ manager?: string
+ /**
+ * The address of the office
+ */
+ address?: {
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides within
+ */
+ countryId?: string
+ }
+ /**
+ * The work phone number of the office
+ */
+ workPhone?: string
+ /**
+ * The email address of the office
+ */
+ email?: string
+ /**
+ * App specific metadata to set against the office
+ */
+ metadata?: {
+ [name: string]: any
+ }
+}
+/**
+ * Request body used to update the address of an existing property
+ */
+export interface UpdatePropertyAddressModel {
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides within
+ */
+ countryId?: string
+ /**
+ * The geolocation coordinates associated with the address
+ */
+ geolocation?: {
+ /**
+ * The latitude coordinate of the coordinate pair
+ */
+ latitude?: number // double
+ /**
+ * The longitude coordinate of the coordinate pair
+ */
+ longitude?: number // double
+ }
+}
+/**
+ * Request body used to update the EPC statistics of an existing property
+ */
+export interface UpdatePropertyEpcModel {
+ /**
+ * A flag denoting whether or not this property is exempt from requiring an EPC certificate
+ */
+ exempt?: boolean
+ /**
+ * The current energy efficiency rating
+ */
+ eer?: number // int32
+ /**
+ * The potential energy efficiency rating
+ */
+ eerPotential?: number // int32
+ /**
+ * The current environmental impact rating
+ */
+ eir?: number // int32
+ /**
+ * The potential environmental impact rating
+ */
+ eirPotential?: number // int32
+}
+/**
+ * Request body to update the external land area of an existing property
+ */
+export interface UpdatePropertyExternalAreaModel {
+ /**
+ * The unit of area (acres/hectares)
+ */
+ type?: string
+ /**
+ * The minimum area bound
+ */
+ min?: number // double
+ /**
+ * The maximum area bound
+ */
+ max?: number // double
+}
+/**
+ * Request body used to update the geolocation coordinates of an existing property's address
+ */
+export interface UpdatePropertyGeolocationModel {
+ /**
+ * The latitude coordinate of the coordinate pair
+ */
+ latitude?: number // double
+ /**
+ * The longitude coordinate of the coordinate pair
+ */
+ longitude?: number // double
+}
+/**
+ * Request body used to update an existing property image
+ * example:
+ * [object Object]
+ */
+export interface UpdatePropertyImageModel {
+ /**
+ * The image caption
+ */
+ caption?: string
+ /**
+ * The type of image (picture/floorPlan/epc/map)
+ */
+ type?: string
+}
+/**
+ * Request body to update the internal dimensions of an existing property
+ */
+export interface UpdatePropertyInternalAreaModel {
+ /**
+ * The unit of area (squareFeet/squareMetres)
+ */
+ type?: string
+ /**
+ * The minimum area bound
+ */
+ min?: number // double
+ /**
+ * The maximum area bound
+ */
+ max?: number // double
+}
+/**
+ * Request body used to update details specific to lettings marketing on an existing property
+ */
+export interface UpdatePropertyLettingModel {
+ /**
+ * The date the property was marked as to let
+ * example:
+ * 2019-08-14
+ */
+ instructed?: string // date
+ /**
+ * The date the property is next available from
+ * example:
+ * 2019-08-14
+ */
+ availableFrom?: string // date
+ /**
+ * The date the property is available to
+ * example:
+ * 2019-08-14
+ */
+ availableTo?: string // date
+ /**
+ * The rent being charged for the property
+ */
+ rent?: number // double
+ /**
+ * The frequency at which rent will be collected (weekly/monthly/yearly)
+ */
+ rentFrequency?: string
+ /**
+ * The acceptable letting terms (short/long/any)
+ */
+ term?: string
+ /**
+ * The current status of the let (valuation/toLet/toLetUnavailable/underOffer/underOfferUnavailable/arrangingTenancyUnavailable/arrangingTenancy/tenancyCurrentUnavailable/tenancyCurrent/tenancyFinished/tenancyCancelled/sold/letByOtherAgent/letPrivately/provisional/withdrawn)
+ */
+ status?: string
+}
+/**
+ * Request body used to update an existing property
+ * example:
+ * [object Object]
+ */
+export interface UpdatePropertyModel {
+ /**
+ * The strapline description containing a short summary about the property
+ */
+ strapline?: string
+ /**
+ * The brief description of the property
+ */
+ description?: string
+ /**
+ * The summary of accommodation, typically short phrases or bullet points describing the key features of the property
+ */
+ summary?: string
+ /**
+ * The address of the property
+ */
+ address?: {
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides within
+ */
+ countryId?: string
+ /**
+ * The geolocation coordinates associated with the address
+ */
+ geolocation?: {
+ /**
+ * The latitude coordinate of the coordinate pair
+ */
+ latitude?: number // double
+ /**
+ * The longitude coordinate of the coordinate pair
+ */
+ longitude?: number // double
+ }
+ }
+ /**
+ * The total number of bedrooms in the property
+ */
+ bedrooms?: number // int32
+ /**
+ * The total number of reception rooms in the property
+ */
+ receptions?: number // int32
+ /**
+ * The total number of bathrooms in the property
+ */
+ bathrooms?: number // int32
+ /**
+ * The council tax banding of the property (A/B/C/D/E/F/G/H)
+ */
+ councilTax?: string
+ /**
+ * A flag denoting whether or not this property can be advertised on the internet
+ */
+ internetAdvertising?: boolean
+ /**
+ * The arrangements regarding viewing the property
+ */
+ viewingArrangements?: string
+ /**
+ * Details of the EPC statistics
+ */
+ epc?: {
+ /**
+ * A flag denoting whether or not this property is exempt from requiring an EPC certificate
+ */
+ exempt?: boolean
+ /**
+ * The current energy efficiency rating
+ */
+ eer?: number // int32
+ /**
+ * The potential energy efficiency rating
+ */
+ eerPotential?: number // int32
+ /**
+ * The current environmental impact rating
+ */
+ eir?: number // int32
+ /**
+ * The potential environmental impact rating
+ */
+ eirPotential?: number // int32
+ }
+ /**
+ * Details of the external land area associated to this property
+ */
+ externalArea?: {
+ /**
+ * The unit of area (acres/hectares)
+ */
+ type?: string
+ /**
+ * The minimum area bound
+ */
+ min?: number // double
+ /**
+ * The maximum area bound
+ */
+ max?: number // double
+ }
+ /**
+ * Details of the internal dimensions of the property
+ */
+ internalArea?: {
+ /**
+ * The unit of area (squareFeet/squareMetres)
+ */
+ type?: string
+ /**
+ * The minimum area bound
+ */
+ min?: number // double
+ /**
+ * The maximum area bound
+ */
+ max?: number // double
+ }
+ /**
+ * Selling specific details about the property
+ */
+ selling?: {
+ /**
+ * The date that the property was marked as for sale
+ * example:
+ * 2019-08-14
+ */
+ instructed?: string // date
+ /**
+ * The marketing price of the property
+ */
+ price?: number // int32
+ /**
+ * The price qualifier (askingPrice/priceOnApplication/guidePrice/offersInRegion/offersOver/offersInExcess/fixedPrice/priceReducedTo)
+ */
+ qualifier?: string
+ /**
+ * The current status of the sale (preAppraisal/valuation/paidValuation/forSale/forSaleUnavailable/underOffer/underOfferUnavailable/reserved/exchanged/completed/soldExternally/withdrawn)
+ */
+ status?: string
+ /**
+ * Details about the tenure of the property
+ */
+ tenure?: {
+ /**
+ * The type of tenure that applies to the property (freehold/leasehold/shareOfFreehold/commonhold/tba)
+ */
+ type?: string
+ /**
+ * The tenure expiration date
+ * example:
+ * 2019-08-14
+ */
+ expiry?: string // date
+ }
+ }
+ /**
+ * Letting specific details about the property
+ */
+ letting?: {
+ /**
+ * The date the property was marked as to let
+ * example:
+ * 2019-08-14
+ */
+ instructed?: string // date
+ /**
+ * The date the property is next available from
+ * example:
+ * 2019-08-14
+ */
+ availableFrom?: string // date
+ /**
+ * The date the property is available to
+ * example:
+ * 2019-08-14
+ */
+ availableTo?: string // date
+ /**
+ * The rent being charged for the property
+ */
+ rent?: number // double
+ /**
+ * The frequency at which rent will be collected (weekly/monthly/yearly)
+ */
+ rentFrequency?: string
+ /**
+ * The acceptable letting terms (short/long/any)
+ */
+ term?: string
+ /**
+ * The current status of the let (valuation/toLet/toLetUnavailable/underOffer/underOfferUnavailable/arrangingTenancyUnavailable/arrangingTenancy/tenancyCurrentUnavailable/tenancyCurrent/tenancyFinished/tenancyCancelled/sold/letByOtherAgent/letPrivately/provisional/withdrawn)
+ */
+ status?: string
+ }
+ /**
+ * The property type attributes
+ */
+ type?: string[]
+ /**
+ * The property style attributes
+ */
+ style?: string[]
+ /**
+ * The property situation attributes
+ */
+ situation?: string[]
+ /**
+ * The property parking attributes
+ */
+ parking?: string[]
+ /**
+ * The property age attributes
+ */
+ age?: string[]
+ /**
+ * The property locality attributes
+ */
+ locality?: string[]
+ /**
+ * The unique identifier of the negotiator managing the property
+ */
+ negotiatorId?: string
+ /**
+ * A collection of unique identifiers of offices attached to the property
+ */
+ officeIds?: string[]
+ /**
+ * The unique identifier of the area that the property resides in
+ */
+ areaId?: string
+ /**
+ * App specific metadata to set against the property
+ */
+ metadata?: {
+ [name: string]: any
+ }
+}
+/**
+ * Request body used to update details specific to sales marketing on an existing property
+ */
+export interface UpdatePropertySellingModel {
+ /**
+ * The date that the property was marked as for sale
+ * example:
+ * 2019-08-14
+ */
+ instructed?: string // date
+ /**
+ * The marketing price of the property
+ */
+ price?: number // int32
+ /**
+ * The price qualifier (askingPrice/priceOnApplication/guidePrice/offersInRegion/offersOver/offersInExcess/fixedPrice/priceReducedTo)
+ */
+ qualifier?: string
+ /**
+ * The current status of the sale (preAppraisal/valuation/paidValuation/forSale/forSaleUnavailable/underOffer/underOfferUnavailable/reserved/exchanged/completed/soldExternally/withdrawn)
+ */
+ status?: string
+ /**
+ * Details about the tenure of the property
+ */
+ tenure?: {
+ /**
+ * The type of tenure that applies to the property (freehold/leasehold/shareOfFreehold/commonhold/tba)
+ */
+ type?: string
+ /**
+ * The tenure expiration date
+ * example:
+ * 2019-08-14
+ */
+ expiry?: string // date
+ }
+}
+/**
+ * Request body used to set the tenure of an existing property
+ */
+export interface UpdatePropertyTenureModel {
+ /**
+ * The type of tenure that applies to the property (freehold/leasehold/shareOfFreehold/commonhold/tba)
+ */
+ type?: string
+ /**
+ * The tenure expiration date
+ * example:
+ * 2019-08-14
+ */
+ expiry?: string // date
+}
+/**
+ * Request body used to update an existing source of business
+ * example:
+ * [object Object]
+ */
+export interface UpdateSourceModel {
+ /**
+ * The name of the source or advertising publication
+ */
+ name?: string
+ /**
+ * The type of the source (source/advertisement)
+ */
+ type?: string
+ /**
+ * A collection of the unique identifiers of offices that regularly get business from the source
+ */
+ officeIds?: string[]
+ /**
+ * A collection of unique identifiers of departments that regularly get business from the source
+ */
+ departmentIds?: string[]
+}
+/**
+ * Request body used to update an existing task, which can also be an internal message
+ * example:
+ * [object Object]
+ */
+export interface UpdateTaskModel {
+ /**
+ * The date the task becomes active
+ * example:
+ * 2019-08-14
+ */
+ activates?: string // date
+ /**
+ * The date the task was completed
+ * example:
+ * 2019-08-14
+ */
+ completed?: string // date
+ /**
+ * The unique identifier of the task type
+ */
+ typeId?: string
+ /**
+ * The unique identifer of the negotiator that created the task
+ */
+ senderId?: string
+ /**
+ * The textual contents of the task or message
+ */
+ text?: string
+ /**
+ * The unique identifier of the landlord the task is associated to
+ */
+ landlordId?: string
+ /**
+ * The unique identifier of the property the task is associated to
+ */
+ propertyId?: string
+ /**
+ * The unique identifier of the applicant the task is associated to
+ */
+ applicantId?: string
+ /**
+ * The unique identifier of the tenancy the task is associated to
+ */
+ tenancyId?: string
+ /**
+ * The unique identifier of the contact the task is associated to
+ */
+ contactId?: string
+ /**
+ * The unique identifier of the negotiator or office the task is being sent to
+ */
+ recipientId?: string
+ /**
+ * The type of the recipient (office/negotiator)
+ */
+ recipientType?: string
+ /**
+ * App specific metadata that has been set against the task
+ */
+ metadata?: {
+ [name: string]: any
+ }
+}
+/**
+ * Request body used to update an existing vendor
+ * example:
+ * [object Object]
+ */
+export interface UpdateVendorModel {
+ /**
+ * The date the vendor was last called
+ * example:
+ * 2019-08-14
+ */
+ lastCall?: string // date
+ /**
+ * The date the vendor is next due to be called
+ * example:
+ * 2019-08-14
+ */
+ nextCall?: string // date
+ /**
+ * The unique identifier of the type of vendor
+ */
+ typeId?: string
+ /**
+ * The unique identifier of the reason the vendor is selling
+ */
+ sellingReasonId?: string
+ /**
+ * The unique identifier of the vendor's solicitor
+ */
+ solicitorId?: string
+ /**
+ * The source of the vendor
+ */
+ source?: {
+ /**
+ * The unique identifier of the source of the vendor
+ */
+ id?: string
+ /**
+ * The source type (office/source)
+ */
+ type?: string
+ }
+ /**
+ * App specific metadata that has been set against the vendor
+ */
+ metadata?: {
+ [name: string]: any
+ }
+}
+/**
+ * Representation of a works order item
+ * example:
+ * [object Object]
+ */
+export interface UpdateWorksOrderItemModel {
+ /**
+ * The notes attached to the works order item
+ */
+ notes?: string
+ /**
+ * The party to be charged for the work being carried out (landlord/tenant)
+ */
+ chargeTo?: string
+ /**
+ * The estimate of any costs associated with the work being carried out given to the party to be charged for the work
+ */
+ estimate?: number // double
+ /**
+ * The type of estimate supplied (agent/verbal/written)
+ */
+ estimateType?: string
+ /**
+ * The net cost of the work to be carried out
+ */
+ netAmount?: number // double
+ /**
+ * The cost of the vat associated with the work
+ */
+ vatAmount?: number // double
+}
+/**
+ * Request body used to update an existing works order
+ * example:
+ * [object Object]
+ */
+export interface UpdateWorksOrderModel {
+ /**
+ * The unique identifier of the company that has been selected to perform the work
+ */
+ companyId?: string
+ /**
+ * The unique identifier of the property where the work is to be carried out
+ */
+ propertyId?: string
+ /**
+ * The unique identifier of the tenancy that the works order originated from
+ */
+ tenancyId?: string
+ /**
+ * The unique identifier of the negotiator that booked the works order
+ */
+ negotiatorId?: string
+ /**
+ * The unique id of the type of work that needs to be carried out
+ */
+ typeId?: string
+ /**
+ * The current status of the works order (pendingApproval/pendingQuote/raised/raisedToChase/landlordToComplete/complete/cancelled)
+ */
+ status?: string
+ /**
+ * A free text description of the work required
+ */
+ description?: string
+ /**
+ * The party requesting the work to be carried out (landlord/tenant/other)
+ */
+ reporter?: string
+ /**
+ * The date when the works order was booked
+ * example:
+ * 2019-08-14
+ */
+ booked?: string // date
+ /**
+ * The date when the work is required to be completed by
+ * example:
+ * 2019-08-14
+ */
+ required?: string // date
+ /**
+ * The date when the work was completed
+ * example:
+ * 2019-08-14
+ */
+ completed?: string // date
+ /**
+ * App specific metadata to set against the works order
+ */
+ metadata?: {
+ [name: string]: any
+ }
+}
+/**
+ * Representation of the physical address of a building or premise
+ */
+export interface VendorContactAddressModel {
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides within
+ */
+ countryId?: string
+}
+/**
+ * A summarised view of the details of a contact or company associated to a vendor
+ */
+export interface VendorContactModel {
+ /**
+ * The unique identifier of the contact or company
+ */
+ id?: string
+ /**
+ * The name of the contact or company
+ */
+ name?: string
+ /**
+ * The type of the contact (company/contact)
+ */
+ type?: string
+ /**
+ * The home phone number of the contact or company
+ */
+ homePhone?: string
+ /**
+ * The work phone number of the contact or company
+ */
+ workPhone?: string
+ /**
+ * The mobile phone number of the contact or company
+ */
+ mobilePhone?: string
+ /**
+ * The email address of the contact or company
+ */
+ email?: string
+ /**
+ * The primary address of the contact or company
+ */
+ primaryAddress?: {
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides within
+ */
+ countryId?: string
+ }
+}
+/**
+ * Representation of a relationship between a vendor and a contact or company
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+export interface VendorContactRelationshipModel {
+ /**
+ * The unique identifier of the vendor relationship
+ */
+ id?: string
+ /**
+ * The unique identifier of the vendor
+ */
+ vendorId?: string
+ /**
+ * The date and time when the relationship was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the relationship was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The type of related entity (contact/company)
+ */
+ associatedType?: string
+ /**
+ * The unique identifier of the related contact or company
+ */
+ associatedId?: string
+ /**
+ * A flag denoting whether or not this relationship should be regarded as the main relationship for the parent vendor entity
+ */
+ isMain?: boolean
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+}
+/**
+ * Representation of a vendor
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+export interface VendorModel {
+ /**
+ * The unique identifier of the vendor
+ */
+ id?: string
+ /**
+ * The date and time when the vendor was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the vendor was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The date the vendor was last called
+ * example:
+ * 2019-08-14
+ */
+ lastCall?: string // date
+ /**
+ * The date the vendor is next due to be called
+ * example:
+ * 2019-08-14
+ */
+ nextCall?: string // date
+ /**
+ * The unique identifier of the type of vendor
+ */
+ typeId?: string
+ /**
+ * The unique identifier of the reason the vendor is selling
+ */
+ sellingReasonId?: string
+ /**
+ * The unique identifier of the vendor's solicitor
+ */
+ solicitorId?: string
+ /**
+ * The source of the vendor
+ */
+ source?: {
+ /**
+ * The unique identifier of the source of the vendor
+ */
+ id?: string
+ /**
+ * The source type (office/source)
+ */
+ type?: string
+ }
+ /**
+ * A collection of contacts and/or companies associated to the vendor. The first item in the collection is considered the primary relationship
+ */
+ related?: {
+ /**
+ * The unique identifier of the contact or company
+ */
+ id?: string
+ /**
+ * The name of the contact or company
+ */
+ name?: string
+ /**
+ * The type of the contact (company/contact)
+ */
+ type?: string
+ /**
+ * The home phone number of the contact or company
+ */
+ homePhone?: string
+ /**
+ * The work phone number of the contact or company
+ */
+ workPhone?: string
+ /**
+ * The mobile phone number of the contact or company
+ */
+ mobilePhone?: string
+ /**
+ * The email address of the contact or company
+ */
+ email?: string
+ /**
+ * The primary address of the contact or company
+ */
+ primaryAddress?: {
+ /**
+ * The building name
+ */
+ buildingName?: string
+ /**
+ * The building number
+ */
+ buildingNumber?: string
+ /**
+ * The first line of the address
+ */
+ line1?: string
+ /**
+ * The second line of the address
+ */
+ line2?: string
+ /**
+ * The third line of the address
+ */
+ line3?: string
+ /**
+ * The fourth line of the address
+ */
+ line4?: string
+ /**
+ * The postcode
+ */
+ postcode?: string
+ /**
+ * The ISO-3166 country code that the address resides within
+ */
+ countryId?: string
+ }
+ }[]
+ /**
+ * The unique identifier of the negotiator attached to the vendor. The first item in the collection is considered the primary negotiator
+ */
+ negotiatorId?: string
+ /**
+ * A collection of unique identifiers of offices attached to the vendor. The first item in the collection is considered the primary office
+ */
+ officeIds?: string[]
+ /**
+ * App specific metadata that has been set against the vendor
+ */
+ metadata?: {
+ [name: string]: any
+ }
+ /**
+ * The ETag for the current version of the vendor. Used for managing update concurrency
+ */
+ readonly _eTag?: string
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+}
+/**
+ * Representation of a vendor's source
+ */
+export interface VendorSourceModel {
+ /**
+ * The unique identifier of the source of the vendor
+ */
+ id?: string
+ /**
+ * The source type (office/source)
+ */
+ type?: string
+}
+/**
+ * Representation of a vendor's source
+ */
+export interface VendorUpdateSourceModel {
+ /**
+ * The unique identifier of the source of the vendor
+ */
+ id?: string
+ /**
+ * The source type (office/source)
+ */
+ type?: string
+}
+export interface Vendors {
+ PageSize?: number
+ PageNumber?: number
+ SortBy?: string
+ Id?: string[]
+ NegotiatorId?: string[]
+ OfficeId?: string[]
+ Address?: string
+ Name?: string
+ CreatedFrom?: string
+ CreatedTo?: string
+ LastCallFrom?: string
+ LastCallTo?: string
+ NextCallFrom?: string
+ NextCallTo?: string
+ Embed?: ('negotiator' | 'offices' | 'sellingReason' | 'solicitor' | 'source' | 'type')[]
+}
+/**
+ * Representation of a works order item
+ */
+export interface WorksOrderItemModel {
+ /**
+ * The unique identifier of the works order item
+ */
+ id?: string
+ /**
+ * The unique identifier of the parent works order
+ */
+ worksOrderId?: string
+ /**
+ * The date and time when the works order item was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the works order item was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The notes attached to the works order item
+ */
+ notes?: string
+ /**
+ * The party to be charged for the work being carried out (landlord/tenant)
+ */
+ chargeTo?: string
+ /**
+ * The estimate of any costs associated with the work being carried out given to the party to be charged for the work
+ */
+ estimate?: number // double
+ /**
+ * The type of estimate supplied (agent/verbal/written)
+ */
+ estimateType?: string
+ /**
+ * The net cost of the work to be carried out
+ */
+ netAmount?: number // double
+ /**
+ * The additional vat cost for the work to be carried out
+ */
+ vatAmount?: number // double
+ /**
+ * The gross cost of the work to be carried out
+ */
+ grossAmount?: number // double
+ /**
+ * The ETag for the current version of the works order item. Used for managing update concurrency
+ */
+ readonly _eTag?: string
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+}
+/**
+ * Representation of a works order
+ */
+export interface WorksOrderModel {
+ /**
+ * The unique identifier of the works order
+ */
+ id?: string
+ /**
+ * The date and time when the works order was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the works order was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The unique identifier of the company that has been selected to perform the work
+ */
+ companyId?: string
+ /**
+ * The unique identifier of the property where the work is to be carried out
+ */
+ propertyId?: string
+ /**
+ * The unique identifier of the tenancy that the works order originated from
+ */
+ tenancyId?: string
+ /**
+ * The unique identifier of the negotiator that booked the works order
+ */
+ negotiatorId?: string
+ /**
+ * The unique identifier of the type of work that needs to be carried out
+ */
+ typeId?: string
+ /**
+ * The current status of the works order (pendingApproval/pendingQuote/raised/raisedToChase/landlordToComplete/complete/cancelled)
+ */
+ status?: string
+ /**
+ * A free text description of the work required
+ */
+ description?: string
+ /**
+ * The party requesting the work to be carried out (landlord/tenant/other)
+ */
+ reporter?: string
+ /**
+ * The date when the works order was booked
+ * example:
+ * 2019-08-14
+ */
+ booked?: string // date
+ /**
+ * The date when the work is required to be completed by
+ * example:
+ * 2019-08-14
+ */
+ required?: string // date
+ /**
+ * The date when the work was completed
+ * example:
+ * 2019-08-14
+ */
+ completed?: string // date
+ /**
+ * The total net cost for all of the items of work to be carried out
+ */
+ totalNetAmount?: number // double
+ /**
+ * The total additional vat cost for all of the items of work to be carried out
+ */
+ totalVatAmount?: number // double
+ /**
+ * The total gross cost for all of the items of work to be carried out
+ */
+ totalGrossAmount?: number // double
+ /**
+ * A collection of jobs/items of work that the works order should fulfill
+ */
+ items?: {
+ /**
+ * The unique identifier of the works order item
+ */
+ id?: string
+ /**
+ * The unique identifier of the parent works order
+ */
+ worksOrderId?: string
+ /**
+ * The date and time when the works order item was created
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ created?: string // date-time
+ /**
+ * The date and time when the works order item was last modified
+ * example:
+ * 2019-08-14T12:30:02.0000000Z
+ */
+ modified?: string // date-time
+ /**
+ * The notes attached to the works order item
+ */
+ notes?: string
+ /**
+ * The party to be charged for the work being carried out (landlord/tenant)
+ */
+ chargeTo?: string
+ /**
+ * The estimate of any costs associated with the work being carried out given to the party to be charged for the work
+ */
+ estimate?: number // double
+ /**
+ * The type of estimate supplied (agent/verbal/written)
+ */
+ estimateType?: string
+ /**
+ * The net cost of the work to be carried out
+ */
+ netAmount?: number // double
+ /**
+ * The additional vat cost for the work to be carried out
+ */
+ vatAmount?: number // double
+ /**
+ * The gross cost of the work to be carried out
+ */
+ grossAmount?: number // double
+ /**
+ * The ETag for the current version of the works order item. Used for managing update concurrency
+ */
+ readonly _eTag?: string
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+ }[]
+ /**
+ * App specific metadata that has been set against the works order
+ */
+ metadata?: {
+ [name: string]: any
+ }
+ /**
+ * The ETag for the current version of the works order. Used for managing update concurrency
+ */
+ readonly _eTag?: string
+ readonly _links?: {
+ [name: string]: {
+ href?: string
+ }
+ }
+ readonly _embedded?: {
+ [name: string]: any
+ }
+}
+export interface WorksOrders {
+ PageSize?: number
+ PageNumber?: number
+ SortBy?: string
+ Id?: string[]
+ CompanyId?: string[]
+ NegotiatorId?: string[]
+ PropertyId?: string[]
+ TenancyId?: string[]
+ TypeId?: string[]
+ CompletedFrom?: string
+ CompletedTo?: string
+ CreatedFrom?: string
+ CreatedTo?: string
+ RequiredFrom?: string
+ RequiredTo?: string
+ Embed?: ('company' | 'documents' | 'negotiator' | 'property' | 'tenancy' | 'type')[]
+ Status?: (
+ | 'pendingApproval'
+ | 'pendingQuote'
+ | 'raised'
+ | 'raisedToChase'
+ | 'landlordToComplete'
+ | 'complete'
+ | 'cancelled'
+ )[]
+}
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/package.json b/packages/react-app-scaffolder/app/templates/redux-internal/package.json
new file mode 100644
index 0000000000..f6a1390da8
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/package.json
@@ -0,0 +1,28 @@
+{
+ "name": "app-name",
+ "version": "0.0.1",
+ "private": true,
+ "description": "Description",
+ "repository": {
+ "type": "git",
+ "url": "git+git@github.com:reapit/app-name.git"
+ },
+ "license": "MIT",
+ "author": "Author",
+ "main": "./src/index.ts",
+ "scripts": {
+ "build:prod": "rimraf public/dist && webpack --config ../../scripts/webpack/webpack.config.prod.js",
+ "fetch-config": "yarn config-manager fetchConfig app-name",
+ "lint": "concurrently \"tsc --noEmit\" \"eslint --cache --ext=ts,tsx src\"",
+ "lint:fix": "eslint --cache --ext=ts,tsx src --fix",
+ "start:dev": "webpack-dev-server --hot --progress --color --mode development --config ../../scripts/webpack/webpack.config.dev.js",
+ "start:prod": "serve public/dist -s -l 8080",
+ "test:ci": "cross-env TZ=UTC jest --ci --colors --coverage --silent --forceExit --detectOpenHandles --runInBand",
+ "test:dev": "cross-env TZ=UTC jest --watch --verbose",
+ "test:update-badges": "yarn test:ci && jest-coverage-badges --input src/tests/coverage/coverage-summary.json --output src/tests/badges"
+ },
+ "dependencies": {
+ "@reapit/foundations-ts-definitions": "2020-02-13"
+ },
+ "devDependencies": {}
+}
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/public/index.html b/packages/react-app-scaffolder/app/templates/redux-internal/public/index.html
new file mode 100644
index 0000000000..e40228b119
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/public/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ Foundations App
+
+
+ You need to enable JavaScript to run this app.
+
+
+
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/public/logo.png b/packages/react-app-scaffolder/app/templates/redux-internal/public/logo.png
new file mode 100644
index 0000000000..eaf5e2e1f3
Binary files /dev/null and b/packages/react-app-scaffolder/app/templates/redux-internal/public/logo.png differ
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/actions/__tests__/auth.ts b/packages/react-app-scaffolder/app/templates/redux-internal/src/actions/__tests__/auth.ts
new file mode 100644
index 0000000000..8ff3b1aa16
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/actions/__tests__/auth.ts
@@ -0,0 +1,20 @@
+import {
+ authLogin,
+ authLoginSuccess,
+ authLoginFailure,
+ authLogout,
+ authLogoutSuccess,
+ authSetRefreshSession,
+} from '../auth'
+import ActionTypes from '../../constants/action-types'
+
+describe('auth actions', () => {
+ it('should create correct actions', () => {
+ expect(authLogin.type).toEqual(ActionTypes.AUTH_LOGIN)
+ expect(authLoginSuccess.type).toEqual(ActionTypes.AUTH_LOGIN_SUCCESS)
+ expect(authLoginFailure.type).toEqual(ActionTypes.AUTH_LOGIN_FAILURE)
+ expect(authLogout.type).toEqual(ActionTypes.AUTH_LOGOUT)
+ expect(authLogoutSuccess.type).toEqual(ActionTypes.AUTH_LOGOUT_SUCCESS)
+ expect(authSetRefreshSession.type).toEqual(ActionTypes.AUTH_SET_REFRESH_SESSION)
+ })
+})
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/actions/__tests__/authenticated.ts b/packages/react-app-scaffolder/app/templates/redux-internal/src/actions/__tests__/authenticated.ts
new file mode 100644
index 0000000000..48bba2c88c
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/actions/__tests__/authenticated.ts
@@ -0,0 +1,18 @@
+import {
+ authenticatedRequestData,
+ authenticatedReceiveData,
+ authenticatedRequestDataFailure,
+ authenticatedLoading,
+ authenticatedClearData,
+} from '../authenticated'
+import ActionTypes from '../../constants/action-types'
+
+describe('authenticated actions', () => {
+ it('should create correct actions', () => {
+ expect(authenticatedRequestData.type).toEqual(ActionTypes.AUTHENTICATED_REQUEST_DATA)
+ expect(authenticatedReceiveData.type).toEqual(ActionTypes.AUTHENTICATED_RECEIVE_DATA)
+ expect(authenticatedRequestDataFailure.type).toEqual(ActionTypes.AUTHENTICATED_REQUEST_FAILURE)
+ expect(authenticatedLoading.type).toEqual(ActionTypes.AUTHENTICATED_LOADING)
+ expect(authenticatedClearData.type).toEqual(ActionTypes.AUTHENTICATED_CLEAR_DATA)
+ })
+})
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/actions/__tests__/error.ts b/packages/react-app-scaffolder/app/templates/redux-internal/src/actions/__tests__/error.ts
new file mode 100644
index 0000000000..13708de63e
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/actions/__tests__/error.ts
@@ -0,0 +1,11 @@
+import { errorClearedComponent, errorClearedServer, errorThrownServer, errorThrownComponent } from '../error'
+import ActionTypes from '../../constants/action-types'
+
+describe('error actions', () => {
+ it('should create correct actions', () => {
+ expect(errorClearedComponent.type).toEqual(ActionTypes.ERROR_CLEARED_COMPONENT)
+ expect(errorClearedServer.type).toEqual(ActionTypes.ERROR_CLEARED_SERVER)
+ expect(errorThrownComponent.type).toEqual(ActionTypes.ERROR_THROWN_COMPONENT)
+ expect(errorThrownServer.type).toEqual(ActionTypes.ERROR_THROWN_SERVER)
+ })
+})
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/actions/auth.ts b/packages/react-app-scaffolder/app/templates/redux-internal/src/actions/auth.ts
new file mode 100644
index 0000000000..84b518fb70
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/actions/auth.ts
@@ -0,0 +1,10 @@
+import ActionTypes from '@/constants/action-types'
+import { actionCreator } from '@/utils/actions'
+import { LoginSession, RefreshParams, LoginParams } from '@reapit/cognito-auth'
+
+export const authLogin = actionCreator(ActionTypes.AUTH_LOGIN)
+export const authLoginSuccess = actionCreator(ActionTypes.AUTH_LOGIN_SUCCESS)
+export const authLoginFailure = actionCreator(ActionTypes.AUTH_LOGIN_FAILURE)
+export const authLogout = actionCreator(ActionTypes.AUTH_LOGOUT)
+export const authLogoutSuccess = actionCreator(ActionTypes.AUTH_LOGOUT_SUCCESS)
+export const authSetRefreshSession = actionCreator(ActionTypes.AUTH_SET_REFRESH_SESSION)
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/actions/authenticated.ts b/packages/react-app-scaffolder/app/templates/redux-internal/src/actions/authenticated.ts
new file mode 100644
index 0000000000..c7a1dea6c7
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/actions/authenticated.ts
@@ -0,0 +1,8 @@
+import { actionCreator } from '../utils/actions'
+import ActionTypes from '../constants/action-types'
+
+export const authenticatedRequestData = actionCreator(ActionTypes.AUTHENTICATED_REQUEST_DATA)
+export const authenticatedReceiveData = actionCreator<{}>(ActionTypes.AUTHENTICATED_RECEIVE_DATA)
+export const authenticatedRequestDataFailure = actionCreator(ActionTypes.AUTHENTICATED_REQUEST_FAILURE)
+export const authenticatedLoading = actionCreator(ActionTypes.AUTHENTICATED_LOADING)
+export const authenticatedClearData = actionCreator(ActionTypes.AUTHENTICATED_CLEAR_DATA)
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/actions/error.ts b/packages/react-app-scaffolder/app/templates/redux-internal/src/actions/error.ts
new file mode 100644
index 0000000000..ab7020c150
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/actions/error.ts
@@ -0,0 +1,8 @@
+import { actionCreator } from '../utils/actions'
+import ActionTypes from '../constants/action-types'
+import { ErrorData } from '../reducers/error'
+
+export const errorClearedComponent = actionCreator(ActionTypes.ERROR_CLEARED_COMPONENT)
+export const errorClearedServer = actionCreator(ActionTypes.ERROR_CLEARED_SERVER)
+export const errorThrownComponent = actionCreator(ActionTypes.ERROR_THROWN_COMPONENT)
+export const errorThrownServer = actionCreator(ActionTypes.ERROR_THROWN_SERVER)
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/assets/images/reapit-connect.png b/packages/react-app-scaffolder/app/templates/redux-internal/src/assets/images/reapit-connect.png
new file mode 100644
index 0000000000..207e7c5599
Binary files /dev/null and b/packages/react-app-scaffolder/app/templates/redux-internal/src/assets/images/reapit-connect.png differ
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/assets/images/reapit-graphic.jpg b/packages/react-app-scaffolder/app/templates/redux-internal/src/assets/images/reapit-graphic.jpg
new file mode 100644
index 0000000000..99137577d8
Binary files /dev/null and b/packages/react-app-scaffolder/app/templates/redux-internal/src/assets/images/reapit-graphic.jpg differ
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/components/hocs/__tests__/error-boundary.tsx b/packages/react-app-scaffolder/app/templates/redux-internal/src/components/hocs/__tests__/error-boundary.tsx
new file mode 100644
index 0000000000..38f391c341
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/components/hocs/__tests__/error-boundary.tsx
@@ -0,0 +1,58 @@
+import * as React from 'react'
+import { shallow, mount } from 'enzyme'
+import toJson from 'enzyme-to-json'
+import { ErrorBoundary, ErrorState } from '../error-boundary'
+import errorMessages from '../../../constants/error-messages'
+import { ErrorData } from '../../../reducers/error'
+
+jest.mock('../../../utils/route-dispatcher')
+
+const Component: React.FC = () => I am a component!
+Component.displayName = 'Component'
+
+const props = {
+ children: Component,
+ errorThrownComponent: jest.fn(),
+ componentError: {
+ type: 'COMPONENT',
+ message: errorMessages.DEFAULT_COMPONENT_ERROR,
+ } as ErrorData,
+}
+
+describe('ErrorBoundary', () => {
+ it('should match a snapshot when no error', () => {
+ expect(toJson(shallow( ))).toMatchSnapshot()
+ })
+
+ it('should match a snapshot when has an error', () => {
+ const component = shallow( )
+ component.setState({
+ hasFailed: true,
+ })
+ expect(toJson(component)).toMatchSnapshot()
+ })
+
+ it('should call the errorThrownComponent and sets the state to hasFailed when it catches', () => {
+ ;(console.error as any) = jest.fn()
+ const DangerousChild = (props: { someProp?: false }) => {
+ if (!props.someProp) {
+ throw new Error('Catch me if you can')
+ }
+ return
+ }
+ const newPops = { ...props, children: }
+
+ const component = mount( )
+ expect(DangerousChild).toThrow()
+ expect(newPops.errorThrownComponent).toHaveBeenCalledTimes(1)
+ expect(newPops.errorThrownComponent).toHaveBeenCalledWith({
+ type: 'COMPONENT',
+ message: errorMessages.DEFAULT_COMPONENT_ERROR,
+ })
+ expect((component.state() as ErrorState).hasFailed).toBe(true)
+ })
+
+ afterEach(() => {
+ jest.restoreAllMocks()
+ })
+})
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/components/hocs/__tests__/route-fetcher.tsx b/packages/react-app-scaffolder/app/templates/redux-internal/src/components/hocs/__tests__/route-fetcher.tsx
new file mode 100644
index 0000000000..1e2a665b22
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/components/hocs/__tests__/route-fetcher.tsx
@@ -0,0 +1,38 @@
+import * as React from 'react'
+import { shallow } from 'enzyme'
+import toJson from 'enzyme-to-json'
+import RouteFetcher from '../route-fetcher'
+import Routes from '../../../constants/routes'
+import { RouteComponentProps, StaticContext } from 'react-router'
+import routeDispatcher from '../../../utils/route-dispatcher'
+
+jest.mock('../../../utils/route-dispatcher')
+
+const Component: React.FC = () => I am a component!
+Component.displayName = 'Component'
+
+const props = {
+ Component,
+ routerProps: {
+ match: {
+ path: Routes.HOME,
+ params: { page: 1 },
+ },
+ } as RouteComponentProps,
+}
+
+describe('RouteFetcher', () => {
+ it('should match a snapshot', () => {
+ expect(toJson(shallow( ))).toMatchSnapshot()
+ })
+
+ it('should call the routeDispatcher with the route path', () => {
+ shallow( )
+ expect(routeDispatcher).toHaveBeenCalledTimes(1)
+ expect(routeDispatcher).toHaveBeenCalledWith(props.routerProps.match.path)
+ })
+
+ afterEach(() => {
+ jest.resetAllMocks()
+ })
+})
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/components/hocs/error-boundary.tsx b/packages/react-app-scaffolder/app/templates/redux-internal/src/components/hocs/error-boundary.tsx
new file mode 100644
index 0000000000..6dd35604d6
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/components/hocs/error-boundary.tsx
@@ -0,0 +1,65 @@
+import * as React from 'react'
+import { connect } from 'react-redux'
+import { errorThrownComponent } from '../../actions/error'
+import { Dispatch } from 'redux'
+import errorMessages from '../../constants/error-messages'
+import { ErrorData } from '../../reducers/error'
+import { ReduxState } from '@/types/core'
+
+interface ErrorMappedActions {
+ errorThrownComponent: (error: ErrorData) => void
+}
+
+interface ErrorMappedProps {
+ componentError: ErrorData | null
+}
+
+export interface ErrorState {
+ hasFailed: boolean
+}
+
+export type ErrorProps = ErrorMappedActions &
+ ErrorMappedProps & {
+ children?: React.ReactNode
+ }
+
+export class ErrorBoundary extends React.Component {
+ static getDerivedStateFromError() {
+ return {
+ hasFailed: true,
+ }
+ }
+
+ constructor(props: ErrorProps) {
+ super(props)
+ this.state = {
+ hasFailed: false,
+ }
+ }
+
+ componentDidCatch(error: Error, info: React.ErrorInfo) {
+ this.props.errorThrownComponent({
+ type: 'COMPONENT',
+ message: errorMessages.DEFAULT_COMPONENT_ERROR,
+ })
+ console.error('ERROR BOUNDARY CAUGHT', error.message, info)
+ }
+
+ render() {
+ if (this.state.hasFailed) {
+ return Something went wrong here, try refreshing your page.
+ }
+
+ return this.props.children
+ }
+}
+
+const mapStateToProps = (state: ReduxState): ErrorMappedProps => ({
+ componentError: state.error.componentError,
+})
+
+const mapDispatchToProps = (dispatch: Dispatch): ErrorMappedActions => ({
+ errorThrownComponent: (error: ErrorData) => dispatch(errorThrownComponent(error)),
+})
+
+export default connect(mapStateToProps, mapDispatchToProps)(ErrorBoundary)
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/components/hocs/route-fetcher.tsx b/packages/react-app-scaffolder/app/templates/redux-internal/src/components/hocs/route-fetcher.tsx
new file mode 100644
index 0000000000..763cdbc52b
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/components/hocs/route-fetcher.tsx
@@ -0,0 +1,17 @@
+import * as React from 'react'
+import { RouteComponentProps } from 'react-router-dom'
+import { StaticContext } from 'react-router'
+import routeDispatcher from '../../utils/route-dispatcher'
+import { RouteValue } from '../../types/core'
+
+interface RouteFetcherProps {
+ routerProps: RouteComponentProps
+ Component: React.FunctionComponent
+}
+
+const RouteFetcher: React.FunctionComponent = ({ routerProps, Component }: RouteFetcherProps) => {
+ routeDispatcher(routerProps.match.path as RouteValue)
+ return
+}
+
+export default RouteFetcher
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/components/pages/__styles__/styles.ts b/packages/react-app-scaffolder/app/templates/redux-internal/src/components/pages/__styles__/styles.ts
new file mode 100644
index 0000000000..f1b00b614a
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/components/pages/__styles__/styles.ts
@@ -0,0 +1,69 @@
+import { css } from 'linaria'
+
+export const container = css`
+ min-width: 100vw;
+ min-height: 100vh;
+ display: flex;
+ justify-content: flex-end;
+ align-items: center;
+ flex-direction: row;
+ background-color: #fff;
+
+ @media screen and (max-width: 900px) {
+ flex-direction: column-reverse;
+ }
+`
+
+export const wrapper = css`
+ background-color: #fff;
+ width: 33.33%;
+ padding: 1rem;
+ pointer-events: auto;
+
+ &.disabled {
+ pointer-events: none;
+ }
+
+ h1,
+ p,
+ img {
+ text-align: center;
+ }
+
+ div > img {
+ margin: 0 auto;
+ max-width: 200px;
+ display: block;
+ }
+
+ button {
+ margin: 0 auto;
+ max-width: 400px;
+ }
+
+ @media screen and (max-width: 900px) {
+ width: 100%;
+ }
+
+ @media screen and (min-width: 1200px) {
+ padding: 0 3rem;
+ }
+`
+
+export const image = css`
+ background-color: #fff;
+ width: 66.66%;
+ height: 100vh;
+ font-size: 0;
+
+ img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ }
+
+ @media screen and (max-width: 900px) {
+ width: 100%;
+ height: 300px;
+ }
+`
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/components/pages/__tests__/authenticated.tsx b/packages/react-app-scaffolder/app/templates/redux-internal/src/components/pages/__tests__/authenticated.tsx
similarity index 73%
rename from packages/react-app-scaffolder/app/templates/apollo/src/components/pages/__tests__/authenticated.tsx
rename to packages/react-app-scaffolder/app/templates/redux-internal/src/components/pages/__tests__/authenticated.tsx
index e28437c868..f0e7df798d 100644
--- a/packages/react-app-scaffolder/app/templates/apollo/src/components/pages/__tests__/authenticated.tsx
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/components/pages/__tests__/authenticated.tsx
@@ -3,7 +3,12 @@ import { shallow } from 'enzyme'
import toJson from 'enzyme-to-json'
import { Authenticated, AuthenticatedProps } from '../authenticated'
-const props: AuthenticatedProps = {}
+const props: AuthenticatedProps = {
+ authenticatedState: {
+ loading: false,
+ authenticatedData: null,
+ },
+}
describe('Authenticated', () => {
it('should match a snapshot', () => {
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/components/pages/__tests__/login.tsx b/packages/react-app-scaffolder/app/templates/redux-internal/src/components/pages/__tests__/login.tsx
new file mode 100644
index 0000000000..29e00706ed
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/components/pages/__tests__/login.tsx
@@ -0,0 +1,72 @@
+import * as React from 'react'
+import { shallow } from 'enzyme'
+import { Login, LoginProps, mapStateToProps } from '@/components/pages/login'
+import { ReduxState } from '@/types/core'
+import { redirectToLogin } from '@reapit/cognito-auth'
+import { Button } from '@reapit/elements'
+
+const props = (hasSession: boolean): LoginProps => ({
+ hasSession,
+ // @ts-ignore: just pick the needed props for the test
+ history: {},
+})
+
+jest.mock('@reapit/cognito-auth', () => ({
+ redirectToLogin: jest.fn(),
+}))
+
+describe('Login', () => {
+ it('should match a snapshot', () => {
+ expect(shallow( )).toMatchSnapshot()
+ })
+
+ it('should match a snapshot when hasSession', () => {
+ expect(shallow( )).toMatchSnapshot()
+ })
+
+ describe('loginHandler', () => {
+ it('should correctly call redirect on click', () => {
+ const props: LoginProps = {
+ hasSession: false,
+ }
+ const wrapper = shallow( )
+
+ wrapper
+ .find(Button)
+ .first()
+ .simulate('click')
+
+ expect(redirectToLogin).toHaveBeenCalledTimes(1)
+ })
+ })
+
+ describe('mapStateToProps', () => {
+ it('should run correctly', () => {
+ // @ts-ignore: only pick necessary props
+ const mockState = {
+ auth: {
+ refreshSession: null,
+ loginSession: null,
+ },
+ } as ReduxState
+ const result = mapStateToProps(mockState)
+ expect(result).toEqual({
+ hasSession: false,
+ })
+ })
+
+ it('should run correctly', () => {
+ // @ts-ignore: only pick necessary props
+ const mockState = {
+ auth: {
+ refreshSession: {},
+ loginSession: null,
+ },
+ } as ReduxState
+ const result = mapStateToProps(mockState)
+ expect(result).toEqual({
+ hasSession: true,
+ })
+ })
+ })
+})
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/components/pages/authenticated.tsx b/packages/react-app-scaffolder/app/templates/redux-internal/src/components/pages/authenticated.tsx
new file mode 100644
index 0000000000..0cbb1e7855
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/components/pages/authenticated.tsx
@@ -0,0 +1,30 @@
+import * as React from 'react'
+import { H3, Section, SubTitleH5 } from '@reapit/elements'
+import { connect } from 'react-redux'
+import { AuthenticatedState } from '@/reducers/authenticated'
+import { ReduxState } from '@/types/core'
+
+export interface AuthenticatedMappedActions {}
+
+export interface AuthenticatedMappedProps {
+ authenticatedState: AuthenticatedState
+}
+
+export type AuthenticatedProps = AuthenticatedMappedActions & AuthenticatedMappedProps
+
+export const Authenticated: React.FunctionComponent = () => {
+ return (
+
+ Welcome To Reapit Foundations
+ You are now authenticated against our sandbox data
+
+ )
+}
+
+export const mapStateToProps = (state: ReduxState): AuthenticatedMappedProps => ({
+ authenticatedState: state.authenticated,
+})
+
+export const mapDispatchToProps = (): AuthenticatedMappedActions => ({})
+
+export default connect(mapStateToProps, mapDispatchToProps)(Authenticated)
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/components/pages/login.tsx b/packages/react-app-scaffolder/app/templates/redux-internal/src/components/pages/login.tsx
new file mode 100644
index 0000000000..50b351a8f5
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/components/pages/login.tsx
@@ -0,0 +1,55 @@
+import * as React from 'react'
+import { connect } from 'react-redux'
+import { Redirect } from 'react-router-dom'
+import { withRouter } from 'react-router'
+import { ReduxState } from '@/types/core'
+import Routes from '@/constants/routes'
+import { Button, Level } from '@reapit/elements'
+import connectImage from '@/assets/images/reapit-connect.png'
+
+import * as loginStyles from './__styles__/styles'
+
+import { redirectToLogin } from '@reapit/cognito-auth'
+
+import logoImage from '@/assets/images/reapit-graphic.jpg'
+
+export interface LoginProps {
+ hasSession: boolean
+}
+
+const loginHandler = () => redirectToLogin(window.reapit.config.cognitoClientId, `${window.location.origin}`)
+
+export const Login: React.FunctionComponent = (props: LoginProps) => {
+ const { wrapper, container, image } = loginStyles
+
+ const { hasSession } = props
+
+ if (hasSession) {
+ return
+ }
+
+ return (
+
+
+
+
+
+
+
+ Login
+
+
+
+
+
+
+
+
+ )
+}
+
+export const mapStateToProps = (state: ReduxState): LoginProps => ({
+ hasSession: !!state.auth.loginSession || !!state.auth.refreshSession,
+})
+
+export default withRouter(connect(mapStateToProps, {})(Login))
diff --git a/packages/react-app-scaffolder/app/templates/apollo/src/components/ui/__tests__/menu.tsx b/packages/react-app-scaffolder/app/templates/redux-internal/src/components/ui/__tests__/menu.tsx
similarity index 67%
rename from packages/react-app-scaffolder/app/templates/apollo/src/components/ui/__tests__/menu.tsx
rename to packages/react-app-scaffolder/app/templates/redux-internal/src/components/ui/__tests__/menu.tsx
index 8b6bd1d770..17c6ade2e7 100644
--- a/packages/react-app-scaffolder/app/templates/apollo/src/components/ui/__tests__/menu.tsx
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/components/ui/__tests__/menu.tsx
@@ -1,6 +1,6 @@
import * as React from 'react'
import { shallow } from 'enzyme'
-import { Menu, MenuProps, generateMenuConfig } from '../menu'
+import { Menu, MenuProps, mapDispatchToProps, generateMenuConfig } from '../menu'
import toJson from 'enzyme-to-json'
const props: MenuProps = {
@@ -16,6 +16,15 @@ describe('Menu', () => {
expect(toJson(shallow( ))).toMatchSnapshot()
})
+ describe('mapDispatchToProps', () => {
+ it('should return loginType', () => {
+ const dispatch = jest.fn()
+ const fn = mapDispatchToProps(dispatch)
+ fn.logout()
+ expect(dispatch).toBeCalled()
+ })
+ })
+
describe('generateMenuConfig', () => {
it('should return config', () => {
const logoutCallback = jest.fn()
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/components/ui/menu.tsx b/packages/react-app-scaffolder/app/templates/redux-internal/src/components/ui/menu.tsx
new file mode 100644
index 0000000000..1e0a3cd10c
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/components/ui/menu.tsx
@@ -0,0 +1,72 @@
+import * as React from 'react'
+import { connect } from 'react-redux'
+import { withRouter, RouteComponentProps } from 'react-router'
+import { Menu as Sidebar, MenuConfig, ReapitLogo } from '@reapit/elements'
+import { authLogout } from '@/actions/auth'
+import { LoginMode } from '@reapit/cognito-auth'
+import { Location } from 'history'
+import { FaSignOutAlt, FaCloud } from 'react-icons/fa'
+import { ReduxState } from '../../types/core'
+
+export const generateMenuConfig = (
+ logoutCallback: () => void,
+ location: Location,
+ mode: LoginMode,
+): MenuConfig => {
+ return {
+ defaultActiveKey: 'LOGO',
+ mode,
+ location,
+ menu: [
+ {
+ key: 'LOGO',
+ icon: ,
+ type: 'LOGO',
+ },
+ {
+ title: 'Apps',
+ key: 'APPS',
+ icon: ,
+ callback: () =>
+ (window.location.href =
+ !window.location.href.includes('dev') || window.location.href.includes('localhost')
+ ? 'https://marketplace.reapit.cloud/client/installed'
+ : 'https://dev.marketplace.reapit.cloud/client/installed'),
+ type: 'PRIMARY',
+ },
+ {
+ title: 'Logout',
+ key: 'LOGOUT',
+ callback: logoutCallback,
+ icon: ,
+ type: 'SECONDARY',
+ },
+ ],
+ }
+}
+
+export interface MenuMappedActions {
+ logout: () => void
+}
+
+export interface MenuMappedState {
+ mode: LoginMode
+}
+
+export type MenuProps = MenuMappedActions & MenuMappedState & RouteComponentProps & {}
+
+export const Menu: React.FunctionComponent = ({ logout, location, mode }) => {
+ const logoutCallback = () => logout()
+ const menuConfigs = generateMenuConfig(logoutCallback, location, mode)
+ return
+}
+
+export const mapDispatchToProps = (dispatch: any): MenuMappedActions => ({
+ logout: () => dispatch(authLogout()),
+})
+
+export const mapStateToProps = (state: ReduxState): MenuMappedState => ({
+ mode: state?.auth?.refreshSession?.mode || 'WEB',
+})
+
+export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Menu))
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/constants/action-types.ts b/packages/react-app-scaffolder/app/templates/redux-internal/src/constants/action-types.ts
new file mode 100644
index 0000000000..290df77999
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/constants/action-types.ts
@@ -0,0 +1,28 @@
+/**
+ * Please follow the <>_<> pattern and group actions by STATE
+ */
+const ActionTypes = {
+ // Auth actions
+ AUTH_LOGIN: 'AUTH_LOGIN',
+ AUTH_LOGIN_SUCCESS: 'AUTH_LOGIN_SUCCESS',
+ AUTH_LOGIN_FAILURE: 'AUTH_LOGIN_FAILURE',
+ AUTH_LOGOUT: 'AUTH_LOGOUT',
+ AUTH_LOGOUT_SUCCESS: 'AUTH_LOGOUT_SUCCESS',
+ AUTH_CHANGE_LOGIN_TYPE: 'AUTH_CHANGE_LOGIN_TYPE',
+ AUTH_SET_DESKTOP_SESSION: 'AUTH_SET_DESKTOP_SESSION',
+ AUTH_SET_REFRESH_SESSION: 'AUTH_SET_REFRESH_SESSION',
+
+ // Error actions
+ ERROR_THROWN_COMPONENT: 'ERROR_THROWN_COMPONENT',
+ ERROR_THROWN_SERVER: 'ERROR_THROWN_SERVER',
+ ERROR_CLEARED_COMPONENT: 'ERROR_CLEARED_COMPONENT',
+ ERROR_CLEARED_SERVER: 'ERROR_CLEARED_SERVER',
+
+ AUTHENTICATED_REQUEST_DATA: 'AUTHENTICATED_REQUEST_DATA',
+ AUTHENTICATED_REQUEST_FAILURE: 'AUTHENTICATED_REQUEST_FAILURE',
+ AUTHENTICATED_LOADING: 'AUTHENTICATED_LOADING',
+ AUTHENTICATED_RECEIVE_DATA: 'AUTHENTICATED_RECEIVE_DATA',
+ AUTHENTICATED_CLEAR_DATA: 'AUTHENTICATED_CLEAR_DATA',
+}
+
+export default ActionTypes
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/constants/api.ts b/packages/react-app-scaffolder/app/templates/redux-internal/src/constants/api.ts
new file mode 100644
index 0000000000..c737c935cb
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/constants/api.ts
@@ -0,0 +1,12 @@
+import { StringMap } from '@/types/core'
+import { COOKIE_SESSION_KEY as COGNITIO_COOKIE_SESSION_KEY } from '@reapit/cognito-auth'
+
+export const CONTACTS_HEADERS = {
+ 'Content-Type': 'application/json',
+} as StringMap
+
+export const API_VERSION = '2020-01-31'
+
+export const COOKIE_SESSION_KEY = COGNITIO_COOKIE_SESSION_KEY
+
+export const URLS = {}
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/constants/auth.ts b/packages/react-app-scaffolder/app/templates/redux-internal/src/constants/auth.ts
new file mode 100644
index 0000000000..1ef168b5f5
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/constants/auth.ts
@@ -0,0 +1,5 @@
+import { StringMap } from '@/types/core'
+
+export const LOGIN_TYPE = {
+ CLIENT: 'CLIENT',
+} as StringMap
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/constants/error-messages.ts b/packages/react-app-scaffolder/app/templates/redux-internal/src/constants/error-messages.ts
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/constants/error-messages.ts
rename to packages/react-app-scaffolder/app/templates/redux-internal/src/constants/error-messages.ts
diff --git a/packages/react-app-scaffolder/app/templates/base/src/constants/routes.ts b/packages/react-app-scaffolder/app/templates/redux-internal/src/constants/routes.ts
similarity index 67%
rename from packages/react-app-scaffolder/app/templates/base/src/constants/routes.ts
rename to packages/react-app-scaffolder/app/templates/redux-internal/src/constants/routes.ts
index e4d9057eab..2403b74c67 100644
--- a/packages/react-app-scaffolder/app/templates/base/src/constants/routes.ts
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/constants/routes.ts
@@ -1,7 +1,6 @@
const Routes = {
HOME: '/',
LOGIN: '/login',
- AUTHENTICATED: '/authenticated',
}
export default Routes
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/core/__mocks__/router.tsx b/packages/react-app-scaffolder/app/templates/redux-internal/src/core/__mocks__/router.tsx
new file mode 100644
index 0000000000..1f5a0334cc
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/core/__mocks__/router.tsx
@@ -0,0 +1,3 @@
+import * as React from 'react'
+
+export default () => I am a router
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/core/__mocks__/store.ts b/packages/react-app-scaffolder/app/templates/redux-internal/src/core/__mocks__/store.ts
new file mode 100644
index 0000000000..29161eef08
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/core/__mocks__/store.ts
@@ -0,0 +1,9 @@
+export default {
+ dispatch: jest.fn(),
+ state: {
+ auth: {
+ loginSession: null,
+ refreshSession: null,
+ },
+ },
+}
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/core/__tests__/app.tsx b/packages/react-app-scaffolder/app/templates/redux-internal/src/core/__tests__/app.tsx
new file mode 100644
index 0000000000..873ca25aae
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/core/__tests__/app.tsx
@@ -0,0 +1,19 @@
+import * as React from 'react'
+import { shallow } from 'enzyme'
+import toJson from 'enzyme-to-json'
+import App from '../app'
+import { render, unmountComponentAtNode } from 'react-dom'
+
+jest.mock('../router')
+
+describe('App', () => {
+ it('should render without crashing', () => {
+ const div = document.createElement('div')
+ render( , div)
+ unmountComponentAtNode(div)
+ })
+
+ it('should match a snapshot', () => {
+ expect(toJson(shallow( ))).toMatchSnapshot()
+ })
+})
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/core/__tests__/private-route-wrapper.tsx b/packages/react-app-scaffolder/app/templates/redux-internal/src/core/__tests__/private-route-wrapper.tsx
new file mode 100644
index 0000000000..7c479e2167
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/core/__tests__/private-route-wrapper.tsx
@@ -0,0 +1,20 @@
+import * as React from 'react'
+import { shallow } from 'enzyme'
+import toJson from 'enzyme-to-json'
+import { PrivateRouteWrapper, PrivateRouteWrapperProps } from '../private-route-wrapper'
+
+const props: PrivateRouteWrapperProps = {
+ path: '/',
+ hasSession: false,
+ setDesktopSession: jest.fn(),
+ // @ts-ignore: ignore to fullfil the definition of RouteComponentProps
+ location: {
+ search: '/client/apps?username=wmcvay@reapit.com&desktopToken=TOKEN',
+ },
+}
+
+describe('PrivateRouter', () => {
+ it('should match a snapshot', () => {
+ expect(toJson(shallow( ))).toMatchSnapshot()
+ })
+})
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/core/__tests__/private-route.tsx b/packages/react-app-scaffolder/app/templates/redux-internal/src/core/__tests__/private-route.tsx
new file mode 100644
index 0000000000..329ebf3ac9
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/core/__tests__/private-route.tsx
@@ -0,0 +1,49 @@
+import * as React from 'react'
+import { shallow, mount } from 'enzyme'
+import toJson from 'enzyme-to-json'
+import { MemoryRouter, Route } from 'react-router'
+import { PrivateRoute } from '../private-route'
+
+describe('PrivateRouter', () => {
+ it('should match a snapshot', () => {
+ expect(toJson(shallow( null} />))).toMatchSnapshot()
+ })
+
+ it('should redirect to /404 page if isLogin is false', () => {
+ const wrapper = mount(
+
+ null} path="/my-path" />
+
} />
+ ,
+ )
+ expect(wrapper.find('.not-found')).toHaveLength(1)
+ })
+
+ it('should return render component if loginType matches allow is true', () => {
+ const wrapper = mount(
+
+
}
+ path="/client"
+ />
+ ,
+ )
+ expect(wrapper.find('.render-class')).toHaveLength(1)
+ })
+
+ it('should return render component if loginType is included in allow array is true', () => {
+ const wrapper = mount(
+
+
}
+ path="/developer/my-apps"
+ />
+ ,
+ )
+ expect(wrapper.find('.render-class')).toHaveLength(1)
+ })
+})
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/core/__tests__/router.tsx b/packages/react-app-scaffolder/app/templates/redux-internal/src/core/__tests__/router.tsx
new file mode 100644
index 0000000000..f9875cafb3
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/core/__tests__/router.tsx
@@ -0,0 +1,25 @@
+import * as React from 'react'
+import { shallow } from 'enzyme'
+import toJson from 'enzyme-to-json'
+import Router, { catchChunkError } from '../router'
+
+describe('Router', () => {
+ it('should match a snapshot', () => {
+ expect(toJson(shallow( ))).toMatchSnapshot()
+ })
+
+ describe('catchChunkError', () => {
+ it('should return promise', done => {
+ const fn = jest.fn().mockResolvedValue(Test
)
+ const promiseFn = catchChunkError(fn)
+ expect(promiseFn).toBeDefined()
+ expect(fn).toBeCalled()
+ expect(
+ promiseFn.then(result => {
+ expect(result).toEqual(Test
)
+ done()
+ }),
+ )
+ })
+ })
+})
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/core/__tests__/store.ts b/packages/react-app-scaffolder/app/templates/redux-internal/src/core/__tests__/store.ts
new file mode 100644
index 0000000000..912f2c4908
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/core/__tests__/store.ts
@@ -0,0 +1,22 @@
+import StoreInstance, { Store } from '../store'
+
+describe('Store', () => {
+ it('should return a singleton instance of Store', () => {
+ expect(StoreInstance instanceof Store).toBe(true)
+ })
+
+ it('should export a store', () => {
+ expect(StoreInstance.reduxStore).toBeDefined()
+ expect(typeof StoreInstance.reduxStore).toBe('object')
+ })
+
+ it('should export a state', () => {
+ expect(StoreInstance.state).toBeDefined()
+ expect(typeof StoreInstance.state).toBe('object')
+ })
+
+ it('should export a dispatch', () => {
+ expect(StoreInstance.dispatch).toBeDefined()
+ expect(typeof StoreInstance.dispatch).toBe('function')
+ })
+})
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/core/app.tsx b/packages/react-app-scaffolder/app/templates/redux-internal/src/core/app.tsx
new file mode 100644
index 0000000000..e2d5d8daa9
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/core/app.tsx
@@ -0,0 +1,20 @@
+import * as React from 'react'
+import Router from './router'
+import ErrorBoundary from '@/components/hocs/error-boundary'
+
+import store from './store'
+import { Provider } from 'react-redux'
+
+import '@/styles/index.css'
+
+const App = () => {
+ return (
+
+
+
+
+
+ )
+}
+
+export default App
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/core/index.tsx b/packages/react-app-scaffolder/app/templates/redux-internal/src/core/index.tsx
new file mode 100644
index 0000000000..afcbec1bbd
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/core/index.tsx
@@ -0,0 +1,65 @@
+import * as Sentry from '@sentry/browser'
+import React from 'react'
+import { render } from 'react-dom'
+import ReactGA from 'react-ga'
+import { Config } from '@/types/global'
+import App from './app'
+import { getMarketplaceGlobalsByKey } from '@reapit/elements'
+
+// Init global config
+window.reapit = {
+ config: {
+ appEnv: 'production',
+ sentryDns: '',
+ cognitoClientId: '',
+ googleAnalyticsKey: '',
+ cognitoOAuthUrl: '',
+ cognitoUserPoolId: '',
+ },
+}
+
+export const renderApp = (Component: React.ComponentType) => {
+ const rootElement = document.querySelector('#root') as Element
+ const isDesktop = getMarketplaceGlobalsByKey()
+ const html = document.querySelector('html')
+ if (isDesktop && html) {
+ html.classList.add('is-desktop')
+ }
+
+ if (rootElement) {
+ render( , rootElement)
+ }
+}
+
+const run = async () => {
+ await fetch('config.json')
+ .then(response => response.json())
+ .then((config: Config) => {
+ window.reapit.config = config
+ const isLocal = config.appEnv === 'local'
+ if (!isLocal && config.sentryDns) {
+ Sentry.init({
+ release: process.env.APP_VERSION,
+ dsn: config.sentryDns,
+ environment: config.appEnv,
+ })
+ }
+ if (!isLocal && config.googleAnalyticsKey) {
+ ReactGA.initialize(config.googleAnalyticsKey)
+ ReactGA.pageview(window.location.pathname + window.location.search)
+ }
+ renderApp(App)
+ })
+ .catch(error => {
+ console.error('Cannot fetch config', error)
+ })
+}
+
+if (module['hot']) {
+ module['hot'].accept('./app', () => {
+ const NextApp = require('./app').default
+ renderApp(NextApp)
+ })
+}
+
+run()
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/core/private-route-wrapper.tsx b/packages/react-app-scaffolder/app/templates/redux-internal/src/core/private-route-wrapper.tsx
new file mode 100644
index 0000000000..9294c0de87
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/core/private-route-wrapper.tsx
@@ -0,0 +1,78 @@
+import * as React from 'react'
+import { RouteComponentProps } from 'react-router-dom'
+import { connect } from 'react-redux'
+import { ReduxState } from 'src/types/core'
+import Menu from '@/components/ui/menu'
+import { Loader, Section, FlexContainerResponsive, AppNavContainer, FlexContainerBasic } from '@reapit/elements'
+import { RefreshParams, getTokenFromQueryString } from '@reapit/cognito-auth'
+import { authSetRefreshSession } from '../actions/auth'
+import { Dispatch } from 'redux'
+import { withRouter } from 'react-router'
+import { redirectToOAuth } from '@reapit/cognito-auth'
+
+const { Suspense } = React
+
+export interface PrivateRouteWrapperConnectActions {
+ setRefreshSession: (refreshParams: RefreshParams) => void
+}
+
+export interface PrivateRouteWrapperConnectState {
+ hasSession: boolean
+ isDesktopMode: boolean
+}
+
+export type PrivateRouteWrapperProps = PrivateRouteWrapperConnectState &
+ PrivateRouteWrapperConnectActions &
+ RouteComponentProps & {
+ path: string
+ }
+
+export const PrivateRouteWrapper: React.FunctionComponent = ({
+ setRefreshSession,
+ children,
+ location,
+ hasSession,
+}) => {
+ const cognitoClientId = window.reapit.config.cognitoClientId
+ const refreshParams = getTokenFromQueryString(location.search, cognitoClientId)
+
+ if (refreshParams && !hasSession) {
+ setRefreshSession(refreshParams)
+ return null
+ }
+
+ if (!hasSession) {
+ redirectToOAuth(cognitoClientId)
+ return null
+ }
+
+ return (
+
+
+
+
+
+
+
+ }
+ >
+ {children}
+
+
+
+
+ )
+}
+
+const mapStateToProps = (state: ReduxState): PrivateRouteWrapperConnectState => ({
+ hasSession: !!state.auth.loginSession || !!state.auth.refreshSession,
+ isDesktopMode: state?.auth?.refreshSession?.mode === 'DESKTOP',
+})
+
+const mapDispatchToProps = (dispatch: Dispatch): PrivateRouteWrapperConnectActions => ({
+ setRefreshSession: refreshParams => dispatch(authSetRefreshSession(refreshParams)),
+})
+
+export default withRouter(connect(mapStateToProps, mapDispatchToProps)(PrivateRouteWrapper))
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/core/private-route.tsx b/packages/react-app-scaffolder/app/templates/redux-internal/src/core/private-route.tsx
new file mode 100644
index 0000000000..3c57f7e292
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/core/private-route.tsx
@@ -0,0 +1,50 @@
+import * as React from 'react'
+import { Route, RouteProps } from 'react-router'
+import { Redirect } from 'react-router-dom'
+import { connect } from 'react-redux'
+import RouteFetcher from '../components/hocs/route-fetcher'
+
+export type LoginType = 'CLIENT' | 'DEVELOPER'
+
+export interface PrivateRouteConnectProps {
+ loginType: LoginType
+}
+
+export interface PrivateRouteProps extends PrivateRouteConnectProps {
+ allow: LoginType | LoginType[]
+ component: React.FunctionComponent
+ exact?: boolean
+ fetcher?: boolean
+}
+
+export const PrivateRoute = ({
+ component,
+ allow,
+ fetcher = false,
+ loginType,
+ ...rest
+}: PrivateRouteProps & RouteProps) => {
+ const allowTypes = Array.isArray(allow) ? allow : [allow]
+ allowTypes.includes(loginType)
+ return (
+ {
+ if (!allowTypes.includes(loginType)) {
+ return
+ }
+ if (fetcher) {
+ return
+ }
+ const Component = component
+
+ return
+ }}
+ />
+ )
+}
+
+const mapStateToProps = (): PrivateRouteConnectProps => ({
+ loginType: 'CLIENT',
+})
+export default connect(mapStateToProps)(PrivateRoute)
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/core/router.tsx b/packages/react-app-scaffolder/app/templates/redux-internal/src/core/router.tsx
new file mode 100644
index 0000000000..1c55587792
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/core/router.tsx
@@ -0,0 +1,51 @@
+import * as React from 'react'
+import { Route, Router as BrowserRouter, Switch, Redirect } from 'react-router-dom'
+import { createBrowserHistory } from 'history'
+import Routes from '../constants/routes'
+import PrivateRoute from './private-route'
+import PrivateRouteWrapper from './private-route-wrapper'
+
+export const history = createBrowserHistory()
+
+export const catchChunkError = (
+ fn: Function,
+ retriesLeft = 3,
+ interval = 500,
+): Promise<{ default: React.ComponentType }> => {
+ return new Promise((resolve, reject) => {
+ fn()
+ .then(resolve)
+ .catch((error: Error) => {
+ // Ignore chunk cache error and retry to fetch, if cannot reload browser
+ console.info(error)
+ setTimeout(() => {
+ if (retriesLeft === 1) {
+ window.location.reload()
+ return
+ }
+ catchChunkError(fn, retriesLeft - 1, interval).then(resolve, reject)
+ }, interval)
+ })
+ })
+}
+
+const LoginPage = React.lazy(() => catchChunkError(() => import('../components/pages/login')))
+const AuthenticatedPage = React.lazy(() => catchChunkError(() => import('../components/pages/authenticated')))
+
+const Router = () => (
+
+
+
+
+
+
+
+
+
+
+
+
+
+)
+
+export default Router
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/core/store.ts b/packages/react-app-scaffolder/app/templates/redux-internal/src/core/store.ts
new file mode 100644
index 0000000000..3980f23ee9
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/core/store.ts
@@ -0,0 +1,85 @@
+import { injectSwitchModeToWindow } from '@reapit/elements'
+import {
+ createStore,
+ applyMiddleware,
+ compose,
+ combineReducers,
+ Store as ReduxStore,
+ Dispatch,
+ Reducer,
+ CombinedState,
+ AnyAction,
+} from 'redux'
+import createSagaMiddleware from 'redux-saga'
+import { all, fork } from '@redux-saga/core/effects'
+import authenticated from '../reducers/authenticated'
+import error from '../reducers/error'
+import auth from '@/reducers/auth'
+import { ReduxState, Action } from '../types/core'
+import authenticatedSagas from '../sagas/authenticated'
+import authSagas from '@/sagas/auth'
+
+export class Store {
+ static _instance: Store
+
+ static get instance() {
+ if (!Store._instance) {
+ Store._instance = new Store()
+ }
+
+ return Store._instance
+ }
+
+ static isProd = process.env.NODE_ENV === 'production'
+
+ static sagaMiddleware = createSagaMiddleware()
+
+ static reducers = combineReducers({
+ error,
+ authenticated,
+ auth,
+ }) as Reducer, Action | AnyAction>
+
+ static sagas = function*() {
+ yield all([fork(authenticatedSagas), fork(authSagas)])
+ }
+
+ static composeEnhancers =
+ !Store.isProd && window && (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
+ ? (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({})
+ : compose
+
+ reduxStore: ReduxStore
+
+ constructor() {
+ injectSwitchModeToWindow()
+ const composed = Store.composeEnhancers(applyMiddleware(Store.sagaMiddleware))
+
+ this.reduxStore = createStore(Store.reducers, composed)
+
+ Store.sagaMiddleware.run(Store.sagas)
+
+ this.hotModuleReloading()
+ }
+
+ hotModuleReloading() {
+ const hotModule = (module as any).hot
+
+ if (hotModule) {
+ // Enable Webpack hot module replacement for reducers
+ hotModule.accept('../reducers', () => {
+ this.reduxStore.replaceReducer(Store.reducers)
+ })
+ }
+ }
+
+ get dispatch(): Dispatch {
+ return this.reduxStore.dispatch
+ }
+
+ get state(): ReduxState {
+ return this.reduxStore.getState()
+ }
+}
+
+export default Store.instance
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/reducers/__tests__/auth.ts b/packages/react-app-scaffolder/app/templates/redux-internal/src/reducers/__tests__/auth.ts
new file mode 100644
index 0000000000..b4551d051f
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/reducers/__tests__/auth.ts
@@ -0,0 +1,80 @@
+import reducer, { defaultState as getDefaultState } from '../auth'
+import { ActionType } from '../../types/core'
+import ActionTypes from '../../constants/action-types'
+
+const defaultState = getDefaultState()
+
+describe('auth reducer', () => {
+ it('should return default state if action not matched', () => {
+ const newState = reducer(undefined, {
+ type: 'UNKNOWN' as ActionType,
+ data: undefined,
+ })
+ expect(newState).toEqual(defaultState)
+ })
+
+ it('authLogin', () => {
+ const newState = reducer(undefined, {
+ type: ActionTypes.AUTH_LOGIN as ActionType,
+ data: null,
+ })
+ const expected = {
+ ...defaultState,
+ error: false,
+ }
+ expect(newState).toEqual(expected)
+ })
+
+ it('authLoginSuccess', () => {
+ const data = { userName: '' }
+ const newState = reducer(undefined, {
+ type: ActionTypes.AUTH_LOGIN_SUCCESS as ActionType,
+ data,
+ })
+ const expected = {
+ ...defaultState,
+ error: false,
+ loginSession: data,
+ }
+ expect(newState).toEqual(expected)
+ })
+
+ it('authLoginFailure', () => {
+ const newState = reducer(undefined, {
+ type: ActionTypes.AUTH_LOGIN_FAILURE as ActionType,
+ data: null,
+ })
+ const expected = {
+ ...defaultState,
+ error: true,
+ }
+ expect(newState).toEqual(expected)
+ })
+
+ it('authLogoutSuccess', () => {
+ const newState = reducer(undefined, {
+ type: ActionTypes.AUTH_LOGOUT_SUCCESS as ActionType,
+ data: null,
+ })
+ const expected = defaultState
+ expect(newState).toEqual(expected)
+ })
+
+ it('authSetRefreshSession', () => {
+ const data = {
+ refreshToken: '',
+ userName: '',
+ loginType: 'CLIENT',
+ mode: 'WEB',
+ }
+ const newState = reducer(undefined, {
+ type: ActionTypes.AUTH_SET_REFRESH_SESSION as ActionType,
+ data,
+ })
+ const expected = {
+ ...defaultState,
+ refreshSession: data,
+ }
+ expect(newState).toEqual(expected)
+ })
+})
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/reducers/__tests__/authenticated.ts b/packages/react-app-scaffolder/app/templates/redux-internal/src/reducers/__tests__/authenticated.ts
new file mode 100644
index 0000000000..c8aa2452b4
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/reducers/__tests__/authenticated.ts
@@ -0,0 +1,46 @@
+import authenticatedReducer, { defaultState } from '../authenticated'
+import { ActionType } from '../../types/core'
+import ActionTypes from '../../constants/action-types'
+
+describe('authenticated reducer', () => {
+ it('should return default state if action not matched', () => {
+ const newState = authenticatedReducer(undefined, { type: 'UNKNOWN' as ActionType, data: undefined })
+ expect(newState).toEqual(defaultState)
+ })
+
+ it('should set loading to true when AUTHENTICATED_LOADING action is called', () => {
+ const newState = authenticatedReducer(undefined, {
+ type: ActionTypes.AUTHENTICATED_LOADING as ActionType,
+ data: true,
+ })
+ const expected = {
+ ...defaultState,
+ loading: true,
+ }
+ expect(newState).toEqual(expected)
+ })
+
+ it('should set approvals list data when AUTHENTICATED_RECEIVE_DATA action is called', () => {
+ const newState = authenticatedReducer(undefined, {
+ type: ActionTypes.AUTHENTICATED_RECEIVE_DATA as ActionType,
+ data: {},
+ })
+ const expected = {
+ ...defaultState,
+ authenticatedData: {},
+ }
+ expect(newState).toEqual(expected)
+ })
+
+ it('should clear approvals list data when AUTHENTICATED_CLEAR_DATA action is called', () => {
+ const newState = authenticatedReducer(undefined, {
+ type: ActionTypes.AUTHENTICATED_CLEAR_DATA as ActionType,
+ data: null,
+ })
+ const expected = {
+ ...defaultState,
+ authenticatedData: null,
+ }
+ expect(newState).toEqual(expected)
+ })
+})
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/reducers/__tests__/error.ts b/packages/react-app-scaffolder/app/templates/redux-internal/src/reducers/__tests__/error.ts
new file mode 100644
index 0000000000..8244e3f611
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/reducers/__tests__/error.ts
@@ -0,0 +1,83 @@
+import errorReducer, { defaultState, ErrorData } from '../error'
+import { ActionType } from '../../types/core'
+import ActionTypes from '../../constants/action-types'
+import errorMessages from '../../constants/error-messages'
+
+describe('error reducer', () => {
+ it('should return default state if action not matched', () => {
+ const newState = errorReducer(undefined, { type: 'UNKNOWN' as ActionType, data: undefined })
+ expect(newState).toEqual(defaultState)
+ })
+
+ it('should set a component error', () => {
+ const errorData = {
+ type: 'COMPONENT',
+ message: errorMessages.DEFAULT_COMPONENT_ERROR,
+ } as ErrorData
+ const newState = errorReducer(undefined, {
+ type: ActionTypes.ERROR_THROWN_COMPONENT as ActionType,
+ data: errorData,
+ })
+ const expected = {
+ ...defaultState,
+ componentError: errorData,
+ }
+ expect(newState).toEqual(expected)
+ })
+
+ it('should clear a component error', () => {
+ const errorData = {
+ type: 'COMPONENT',
+ message: errorMessages.DEFAULT_COMPONENT_ERROR,
+ } as ErrorData
+
+ const newState = errorReducer(
+ { ...defaultState, componentError: errorData },
+ {
+ type: ActionTypes.ERROR_CLEARED_COMPONENT as ActionType,
+ data: null,
+ },
+ )
+ const expected = {
+ ...defaultState,
+ componentError: null,
+ }
+ expect(newState).toEqual(expected)
+ })
+
+ it('should set a server error', () => {
+ const errorData = {
+ type: 'SERVER',
+ message: errorMessages.DEFAULT_SERVER_ERROR,
+ } as ErrorData
+ const newState = errorReducer(undefined, {
+ type: ActionTypes.ERROR_THROWN_SERVER as ActionType,
+ data: errorData,
+ })
+ const expected = {
+ ...defaultState,
+ serverError: errorData,
+ }
+ expect(newState).toEqual(expected)
+ })
+
+ it('should clear a server error', () => {
+ const errorData = {
+ type: 'SERVER',
+ message: errorMessages.DEFAULT_SERVER_ERROR,
+ } as ErrorData
+
+ const newState = errorReducer(
+ { ...defaultState, serverError: errorData },
+ {
+ type: ActionTypes.ERROR_CLEARED_SERVER as ActionType,
+ data: null,
+ },
+ )
+ const expected = {
+ ...defaultState,
+ serverError: null,
+ }
+ expect(newState).toEqual(expected)
+ })
+})
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/reducers/auth.ts b/packages/react-app-scaffolder/app/templates/redux-internal/src/reducers/auth.ts
new file mode 100644
index 0000000000..0da6498c8a
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/reducers/auth.ts
@@ -0,0 +1,62 @@
+import { Action } from '@/types/core'
+import { isType } from '@/utils/actions'
+import { authLogin, authLoginFailure, authLoginSuccess, authLogoutSuccess, authSetRefreshSession } from '@/actions/auth'
+import { RefreshParams, LoginSession, getSessionCookie } from '@reapit/cognito-auth'
+import { COOKIE_SESSION_KEY } from '../constants/api'
+
+export interface AuthState {
+ error: boolean
+ loginSession: LoginSession | null
+ refreshSession: RefreshParams | null
+}
+
+export const defaultState = (): AuthState => {
+ const refreshSession = getSessionCookie(COOKIE_SESSION_KEY)
+ return {
+ error: false,
+ loginSession: null,
+ refreshSession,
+ }
+}
+
+const authReducer = (state: AuthState = defaultState(), action: Action): AuthState => {
+ if (isType(action, authLogin)) {
+ return {
+ ...state,
+ error: false,
+ }
+ }
+
+ if (isType(action, authLoginSuccess)) {
+ return {
+ ...state,
+ error: false,
+ loginSession: action.data,
+ }
+ }
+
+ if (isType(action, authLoginFailure)) {
+ return {
+ ...state,
+ error: true,
+ }
+ }
+
+ if (isType(action, authLogoutSuccess)) {
+ return {
+ ...defaultState(),
+ refreshSession: null,
+ }
+ }
+
+ if (isType(action, authSetRefreshSession)) {
+ return {
+ ...state,
+ refreshSession: action.data,
+ }
+ }
+
+ return state
+}
+
+export default authReducer
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/reducers/authenticated.ts b/packages/react-app-scaffolder/app/templates/redux-internal/src/reducers/authenticated.ts
new file mode 100644
index 0000000000..9e53c751de
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/reducers/authenticated.ts
@@ -0,0 +1,54 @@
+import { Action } from '../types/core'
+import { isType } from '../utils/actions'
+import {
+ authenticatedLoading,
+ authenticatedReceiveData,
+ authenticatedClearData,
+ authenticatedRequestDataFailure,
+} from '../actions/authenticated'
+
+export interface AuthenticatedState {
+ loading: boolean
+ authenticatedData: {} | null
+}
+
+export const defaultState: AuthenticatedState = {
+ loading: false,
+ authenticatedData: null,
+}
+
+const authenticatedReducer = (state: AuthenticatedState = defaultState, action: Action): AuthenticatedState => {
+ if (isType(action, authenticatedLoading)) {
+ return {
+ ...state,
+ loading: action.data,
+ }
+ }
+
+ if (isType(action, authenticatedReceiveData)) {
+ return {
+ ...state,
+ loading: false,
+ authenticatedData: action.data || null,
+ }
+ }
+
+ if (isType(action, authenticatedClearData)) {
+ return {
+ ...state,
+ loading: false,
+ authenticatedData: action.data,
+ }
+ }
+
+ if (isType(action, authenticatedRequestDataFailure)) {
+ return {
+ ...state,
+ loading: false,
+ }
+ }
+
+ return state
+}
+
+export default authenticatedReducer
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/reducers/error.ts b/packages/react-app-scaffolder/app/templates/redux-internal/src/reducers/error.ts
new file mode 100644
index 0000000000..a97165d4b9
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/reducers/error.ts
@@ -0,0 +1,39 @@
+import { Action } from '../types/core'
+import { isType } from '../utils/actions'
+import { errorClearedComponent, errorClearedServer, errorThrownComponent, errorThrownServer } from '../actions/error'
+
+export interface ErrorData {
+ readonly status?: number
+ readonly message?: string
+ readonly type: 'COMPONENT' | 'SERVER'
+}
+
+export interface ErrorState {
+ componentError: ErrorData | null
+ serverError: ErrorData | null
+}
+
+export const defaultState: ErrorState = {
+ componentError: null,
+ serverError: null,
+}
+
+const errorReducer = (state: ErrorState = defaultState, action: Action): ErrorState => {
+ if (isType(action, errorClearedServer) || isType(action, errorThrownServer)) {
+ return {
+ ...state,
+ serverError: action.data,
+ }
+ }
+
+ if (isType(action, errorClearedComponent) || isType(action, errorThrownComponent)) {
+ return {
+ ...state,
+ componentError: action.data,
+ }
+ }
+
+ return state
+}
+
+export default errorReducer
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/sagas/__tests__/auth.ts b/packages/react-app-scaffolder/app/templates/redux-internal/src/sagas/__tests__/auth.ts
new file mode 100644
index 0000000000..5e8614d50f
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/sagas/__tests__/auth.ts
@@ -0,0 +1,90 @@
+import authSagas, { doLogin, doLogout, loginListen, logoutListen } from '../auth'
+import ActionTypes from '../../constants/action-types'
+import { put, all, takeLatest, call } from '@redux-saga/core/effects'
+import { LoginParams, setUserSession, removeSession, redirectToLogout } from '@reapit/cognito-auth'
+import { Action, ActionType } from '@/types/core'
+import { mockLoginSession } from '../../utils/__mocks__/session'
+import { authLoginSuccess, authLoginFailure } from '@/actions/auth'
+import { COOKIE_SESSION_KEY } from '../../constants/api'
+
+jest.mock('../../utils/session')
+jest.mock('../../core/store.ts')
+jest.mock('../../core/router', () => ({
+ history: {
+ push: jest.fn(),
+ },
+}))
+
+jest.mock('@reapit/cognito-auth', () => ({
+ setUserSession: jest.fn(),
+ removeSession: jest.fn(),
+ redirectToLogout: jest.fn(),
+}))
+
+describe('auth sagas', () => {
+ describe('login submit', () => {
+ const loginParams: LoginParams = {
+ loginType: 'CLIENT',
+ userName: 'bob@acme.com',
+ password: 'xxxxxx',
+ mode: 'WEB',
+ cognitoClientId: '123',
+ }
+ const action: Action = {
+ type: ActionTypes.AUTH_LOGIN as ActionType,
+ data: loginParams,
+ }
+
+ test('login success', () => {
+ const gen = doLogin(action)
+ expect(gen.next(mockLoginSession).value).toEqual(call(setUserSession, loginParams))
+ expect(gen.next(mockLoginSession).value).toEqual(put(authLoginSuccess(mockLoginSession)))
+ expect(gen.next().done).toBe(true)
+ })
+
+ test('login fail', () => {
+ const gen = doLogin(action)
+ expect(gen.next(null).value).toEqual(call(setUserSession, loginParams))
+ expect(gen.next(null).value).toEqual(put(authLoginFailure()))
+ expect(gen.next().done).toBe(true)
+ })
+ })
+
+ describe('authLogout', () => {
+ it('should redirect to login page', () => {
+ const gen = doLogout()
+ expect(gen.next().value).toEqual(call(removeSession, COOKIE_SESSION_KEY))
+ expect(gen.next().value).toEqual(
+ call(redirectToLogout, window.reapit.config.cognitoClientId, `${window.location.origin}/login`),
+ )
+ expect(gen.next().done).toBe(true)
+ })
+ })
+
+ describe('authLoginListen', () => {
+ it('should trigger login action', () => {
+ const gen = loginListen()
+
+ expect(gen.next().value).toEqual(takeLatest(ActionTypes.AUTH_LOGIN, doLogin))
+ expect(gen.next().done).toBe(true)
+ })
+ })
+
+ describe('authLogoutListen', () => {
+ it('should trigger logout action', () => {
+ const gen = logoutListen()
+
+ expect(gen.next().value).toEqual(takeLatest(ActionTypes.AUTH_LOGOUT, doLogout))
+ expect(gen.next().done).toBe(true)
+ })
+ })
+
+ describe('itemSagas', () => {
+ it('should wait for login and logout action get called', () => {
+ const gen = authSagas()
+
+ expect(gen.next().value).toEqual(all([loginListen(), logoutListen()]))
+ expect(gen.next().done).toBe(true)
+ })
+ })
+})
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/sagas/__tests__/authenticated.ts b/packages/react-app-scaffolder/app/templates/redux-internal/src/sagas/__tests__/authenticated.ts
new file mode 100644
index 0000000000..da7be73bb4
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/sagas/__tests__/authenticated.ts
@@ -0,0 +1,41 @@
+import authenticatedSagas, { authenticatedDataFetch, authenticatedDataListen } from '../authenticated'
+import ActionTypes from '@/constants/action-types'
+import { put, takeLatest, all, fork } from '@redux-saga/core/effects'
+import { authenticatedLoading, authenticatedReceiveData } from '@/actions/authenticated'
+import { cloneableGenerator } from '@redux-saga/testing-utils'
+import { Action } from '@/types/core'
+
+describe('authenticated fetch data', () => {
+ const gen = cloneableGenerator(authenticatedDataFetch)()
+
+ expect(gen.next().value).toEqual(put(authenticatedLoading(true)))
+ expect(gen.next().value).toEqual(true)
+
+ test('api call success', () => {
+ const clone = gen.clone()
+ expect(clone.next().value).toEqual(put(authenticatedReceiveData({})))
+ expect(clone.next().done).toBe(true)
+ })
+})
+
+describe('authenticated sagas', () => {
+ describe('authenticatedListen', () => {
+ it('should request data when called', () => {
+ const gen = authenticatedDataListen()
+
+ expect(gen.next().value).toEqual(
+ takeLatest>(ActionTypes.AUTHENTICATED_REQUEST_DATA, authenticatedDataFetch),
+ )
+ expect(gen.next().done).toBe(true)
+ })
+ })
+
+ describe('authenticatedSagas', () => {
+ it('should listen data request', () => {
+ const gen = authenticatedSagas()
+
+ expect(gen.next().value).toEqual(all([fork(authenticatedDataListen)]))
+ expect(gen.next().done).toBe(true)
+ })
+ })
+})
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/sagas/auth.ts b/packages/react-app-scaffolder/app/templates/redux-internal/src/sagas/auth.ts
new file mode 100644
index 0000000000..1fe9f1e0ed
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/sagas/auth.ts
@@ -0,0 +1,44 @@
+import { takeLatest, put, call, all } from '@redux-saga/core/effects'
+import { Action } from '@/types/core.ts'
+import ActionTypes from '@/constants/action-types'
+import { authLoginSuccess, authLoginFailure } from '@/actions/auth'
+import { LoginParams, LoginSession, setUserSession, removeSession, redirectToLogout } from '@reapit/cognito-auth'
+import { COOKIE_SESSION_KEY } from '../constants/api'
+
+export const doLogin = function*({ data }: Action) {
+ try {
+ const loginSession: LoginSession | null = yield call(setUserSession, data)
+
+ if (loginSession) {
+ yield put(authLoginSuccess(loginSession))
+ } else {
+ yield put(authLoginFailure())
+ }
+ } catch (err) {
+ console.error(err.message)
+ yield put(authLoginFailure())
+ }
+}
+
+export const doLogout = function*() {
+ try {
+ yield call(removeSession, COOKIE_SESSION_KEY)
+ yield call(redirectToLogout, window.reapit.config.cognitoClientId, `${window.location.origin}/login`)
+ } catch (err) {
+ console.error(err.message)
+ }
+}
+
+export const loginListen = function*() {
+ yield takeLatest(ActionTypes.AUTH_LOGIN, doLogin)
+}
+
+export const logoutListen = function*() {
+ yield takeLatest(ActionTypes.AUTH_LOGOUT, doLogout)
+}
+
+const authSaga = function*() {
+ yield all([loginListen(), logoutListen()])
+}
+
+export default authSaga
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/sagas/authenticated.ts b/packages/react-app-scaffolder/app/templates/redux-internal/src/sagas/authenticated.ts
new file mode 100644
index 0000000000..6fd515eb0d
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/sagas/authenticated.ts
@@ -0,0 +1,39 @@
+import {
+ authenticatedLoading,
+ authenticatedReceiveData,
+ authenticatedRequestDataFailure,
+} from '../actions/authenticated'
+import { put, fork, takeLatest, all } from '@redux-saga/core/effects'
+import ActionTypes from '../constants/action-types'
+import { errorThrownServer } from '../actions/error'
+import errorMessages from '../constants/error-messages'
+import { Action } from '@/types/core'
+
+export const authenticatedDataFetch = function*() {
+ yield put(authenticatedLoading(true))
+
+ try {
+ const response = yield true // Your fetch module here
+
+ yield put(authenticatedReceiveData({ data: response }))
+ } catch (err) {
+ console.error(err.message)
+ yield put(authenticatedRequestDataFailure())
+ yield put(
+ errorThrownServer({
+ type: 'SERVER',
+ message: errorMessages.DEFAULT_SERVER_ERROR,
+ }),
+ )
+ }
+}
+
+export const authenticatedDataListen = function*() {
+ yield takeLatest>(ActionTypes.AUTHENTICATED_REQUEST_DATA, authenticatedDataFetch)
+}
+
+const authenticatedSagas = function*() {
+ yield all([fork(authenticatedDataListen)])
+}
+
+export default authenticatedSagas
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/selectors/auth.ts b/packages/react-app-scaffolder/app/templates/redux-internal/src/selectors/auth.ts
new file mode 100644
index 0000000000..342b9a9bf6
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/selectors/auth.ts
@@ -0,0 +1,17 @@
+import { ReduxState } from '@/types/core'
+
+export const selectUserCode = (state: ReduxState) => {
+ return state?.auth?.loginSession?.loginIdentity?.userCode || ''
+}
+
+export const selectUserLoginStatus = (state: ReduxState) => {
+ return !!state?.auth?.refreshSession || !!state?.auth?.loginSession
+}
+
+export const checkIsDesktopMode = (state: ReduxState) => {
+ return state?.auth?.refreshSession?.mode === 'DESKTOP'
+}
+
+export const checkIsWebMode = (state: ReduxState) => {
+ return state?.auth?.refreshSession?.mode === 'WEB'
+}
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/styles/index.css b/packages/react-app-scaffolder/app/templates/redux-internal/src/styles/index.css
new file mode 100644
index 0000000000..f1323ff4b3
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/styles/index.css
@@ -0,0 +1,6 @@
+@import url('https://fonts.googleapis.com/css?family=Source+Code+Pro&display=swap');
+@import url('https://fonts.googleapis.com/css?family=Roboto&display=swap');
+
+
+
+
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/types/core.ts b/packages/react-app-scaffolder/app/templates/redux-internal/src/types/core.ts
new file mode 100644
index 0000000000..1d4158730c
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/types/core.ts
@@ -0,0 +1,42 @@
+import Routes from '../constants/routes'
+import ActionTypes from '../constants/action-types'
+import { ErrorState } from '../reducers/error'
+import { AuthenticatedState } from '@/reducers/authenticated'
+import { AuthState } from '@/reducers/auth'
+
+export interface Action {
+ readonly type: ActionType
+ readonly data: T
+}
+
+export interface ActionCreator {
+ readonly type: string
+ (data: T): Action
+}
+
+export interface StringMap {
+ [key: string]: string
+}
+
+export type PartialRecord = { [P in K]?: T }
+
+export type RouteValue = keyof typeof Routes
+
+export type ActionType = keyof typeof ActionTypes
+
+export type FormState = 'PENDING' | 'DONE' | 'SUBMITTING' | 'ERROR' | 'SUCCESS'
+
+export interface FetcherParams {
+ method: 'GET' | 'POST' | 'PUT' | 'DELETE'
+ api: string
+ url: string
+ headers: StringMap
+ isPrivate?: boolean
+ body?: T
+}
+
+export interface ReduxState {
+ error: ErrorState
+ authenticated: AuthenticatedState
+ auth: AuthState
+}
diff --git a/packages/react-app-scaffolder/app/templates/redux/src/types/global.d.ts b/packages/react-app-scaffolder/app/templates/redux-internal/src/types/global.d.ts
similarity index 100%
rename from packages/react-app-scaffolder/app/templates/redux/src/types/global.d.ts
rename to packages/react-app-scaffolder/app/templates/redux-internal/src/types/global.d.ts
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/types/index.d.ts b/packages/react-app-scaffolder/app/templates/redux-internal/src/types/index.d.ts
new file mode 100644
index 0000000000..5940037217
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/types/index.d.ts
@@ -0,0 +1,14 @@
+/**
+ * Gobal override types to make the compiler happy
+ */
+
+declare namespace yargs {
+ export type Arguments = any
+}
+
+declare module '*.css'
+declare module '*.scss'
+declare module '*.scss?mod'
+declare module '*.sass'
+declare module '*.jpg'
+declare module '*.png'
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/utils/__mocks__/session.ts b/packages/react-app-scaffolder/app/templates/redux-internal/src/utils/__mocks__/session.ts
new file mode 100644
index 0000000000..7e7050905f
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/utils/__mocks__/session.ts
@@ -0,0 +1,17 @@
+import { LoginSession } from '@reapit/cognito-auth'
+
+export const mockLoginSession = {
+ userName: 'bob@acme.com',
+ accessTokenExpiry: 2,
+ loginType: 'CLIENT',
+ refreshToken: 'MOCK_REFRESH_TOKEN',
+ accessToken: 'MOCK_ACCESS_TOKEN',
+ idToken: 'MOCK_ID_TOKEN',
+ loginIdentity: {
+ developerId: 'SOME_DEV_ID',
+ clientId: 'SOME_CLIENT_ID',
+ adminId: 'SOME_ADMIN_ID',
+ },
+} as LoginSession
+
+export const getAccessToken = jest.fn()
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/utils/__tests__/actions.ts b/packages/react-app-scaffolder/app/templates/redux-internal/src/utils/__tests__/actions.ts
new file mode 100644
index 0000000000..31a48fe095
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/utils/__tests__/actions.ts
@@ -0,0 +1,27 @@
+import { actionCreator, isType } from '../actions'
+import ActionTypes from '../../constants/action-types'
+import { authenticatedLoading } from '../../actions/authenticated'
+import { Action } from '../../types/core'
+
+describe('actions utils', () => {
+ describe('actionCreator', () => {
+ it('should create an action of the correct type', () => {
+ const loadingAction = { data: true, type: 'AUTHENTICATED_LOADING' }
+ expect(actionCreator(ActionTypes.AUTHENTICATED_LOADING)(true)).toEqual(loadingAction)
+ })
+ })
+
+ describe('isType', () => {
+ it('should return true if actions are equal', () => {
+ const loadingAction: Action = { data: true, type: 'AUTHENTICATED_LOADING' }
+
+ expect(isType(loadingAction, authenticatedLoading)).toBe(true)
+ })
+
+ it('should return false if actions are not equal', () => {
+ const anotherAction: Action = { data: true, type: 'AUTHENTICATED_RECEIVE_DATA' }
+
+ expect(isType(anotherAction, authenticatedLoading)).toBe(false)
+ })
+ })
+})
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/utils/__tests__/route-dispatcher.ts b/packages/react-app-scaffolder/app/templates/redux-internal/src/utils/__tests__/route-dispatcher.ts
new file mode 100644
index 0000000000..137372de91
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/utils/__tests__/route-dispatcher.ts
@@ -0,0 +1,16 @@
+import routeDispatcher from '../route-dispatcher'
+import store from '../../core/store'
+import Routes from '../../constants/routes'
+import { RouteValue } from '../../types/core'
+import { authenticatedRequestData } from '../../actions/authenticated'
+
+jest.mock('../../core/store')
+jest.mock('../../sagas/authenticated')
+jest.mock('@/utils/session')
+
+describe('routeDispatcher', () => {
+ it('should dispatch to authenticatedRequestData for the home route', async () => {
+ await routeDispatcher(Routes.HOME as RouteValue)
+ expect(store.dispatch).toHaveBeenCalledWith(authenticatedRequestData())
+ })
+})
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/utils/__tests__/session.ts b/packages/react-app-scaffolder/app/templates/redux-internal/src/utils/__tests__/session.ts
new file mode 100644
index 0000000000..6a86921e3c
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/utils/__tests__/session.ts
@@ -0,0 +1,55 @@
+import { getAccessToken } from '../session'
+import { authLogout, authLoginSuccess } from '@/actions/auth'
+import { getSession, LoginSession, RefreshParams } from '@reapit/cognito-auth'
+import { COOKIE_SESSION_KEY } from '@/constants/api'
+
+import store from '@/core/store'
+
+jest.mock('@/actions/auth')
+jest.mock('@/core/store', () => ({
+ dispatch: jest.fn(),
+ state: {
+ auth: {},
+ },
+}))
+jest.mock('@reapit/cognito-auth', () => ({
+ getSession: jest.fn(),
+}))
+
+describe('session utils', () => {
+ describe('getAccessToken', () => {
+ it('should correctly return null when sessions are not available', async () => {
+ store.state.auth.loginSession = null
+ store.state.auth.refreshSession = null
+ ;(getSession as jest.Mock).mockResolvedValueOnce(null)
+ const returnValue = await getAccessToken()
+ expect(getSession).toHaveBeenCalledWith(
+ store.state.auth.loginSession,
+ store.state.auth.refreshSession,
+ COOKIE_SESSION_KEY,
+ )
+ expect(store.dispatch).toHaveBeenCalledWith(authLogout())
+ expect(returnValue).toBeNull()
+ })
+
+ it('should correctly return value', async () => {
+ store.state.auth.loginSession = {} as LoginSession
+ store.state.auth.refreshSession = {} as RefreshParams
+ const mockGetSessionReturnValue = { accessToken: 'accessToken' } as LoginSession
+ ;(getSession as jest.Mock).mockResolvedValueOnce(mockGetSessionReturnValue)
+ const returnValue = await getAccessToken()
+
+ expect(getSession).toHaveBeenCalledWith(
+ store.state.auth.loginSession,
+ store.state.auth.refreshSession,
+ COOKIE_SESSION_KEY,
+ )
+ expect(store.dispatch).toHaveBeenCalledWith(authLoginSuccess(mockGetSessionReturnValue))
+ expect(returnValue).toEqual(mockGetSessionReturnValue.accessToken)
+ })
+
+ afterEach(() => {
+ jest.resetAllMocks()
+ })
+ })
+})
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/utils/actions.ts b/packages/react-app-scaffolder/app/templates/redux-internal/src/utils/actions.ts
new file mode 100644
index 0000000000..553e24424c
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/utils/actions.ts
@@ -0,0 +1,12 @@
+import { ActionCreator, Action } from '../types/core'
+
+export const actionCreator = (type: string): ActionCreator =>
+ Object.assign((data: T): any => ({ type, data }), { type })
+
+/* This is a type guard used to strongly type reducers see: https://github.com/Microsoft/TypeScript/wiki/What's-new-in-TypeScript#user-defined-type-guard-functions
+ * you will note the value
+ * FYI, does NOT work if reducer is a switch statement - TS not smart enough to infer type of data
+ * hence use of conditionals in reducers
+ */
+export const isType = (action: Action, actionCreator: ActionCreator): action is Action =>
+ action.type === actionCreator.type
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/utils/route-dispatcher.ts b/packages/react-app-scaffolder/app/templates/redux-internal/src/utils/route-dispatcher.ts
new file mode 100644
index 0000000000..f385ce2bd3
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/utils/route-dispatcher.ts
@@ -0,0 +1,19 @@
+import { RouteValue } from '@/types/core'
+import { getAccessToken } from '@/utils/session'
+import store from '@/core/store'
+import Routes from '@/constants/routes'
+import { authenticatedRequestData } from '@/actions/authenticated'
+
+const routeDispatcher = async (route: RouteValue) => {
+ await getAccessToken()
+
+ switch (route) {
+ case Routes.HOME:
+ store.dispatch(authenticatedRequestData())
+ break
+ default:
+ console.error('Route not found, nothing to fetch')
+ }
+}
+
+export default routeDispatcher
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/src/utils/session.ts b/packages/react-app-scaffolder/app/templates/redux-internal/src/utils/session.ts
new file mode 100644
index 0000000000..f770dbff8f
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/src/utils/session.ts
@@ -0,0 +1,18 @@
+import store from '@/core/store'
+import { authLoginSuccess, authLogout } from '@/actions/auth'
+import { getSession } from '@reapit/cognito-auth'
+import { COOKIE_SESSION_KEY } from '../constants/api'
+
+export const getAccessToken = async (): Promise => {
+ const { loginSession, refreshSession } = store.state.auth
+
+ const session = await getSession(loginSession, refreshSession, COOKIE_SESSION_KEY)
+
+ if (session) {
+ store.dispatch(authLoginSuccess(session))
+ return session.accessToken
+ }
+
+ store.dispatch(authLogout())
+ return null
+}
diff --git a/packages/react-app-scaffolder/app/templates/redux-internal/tsconfig.json b/packages/react-app-scaffolder/app/templates/redux-internal/tsconfig.json
new file mode 100644
index 0000000000..1047af33b1
--- /dev/null
+++ b/packages/react-app-scaffolder/app/templates/redux-internal/tsconfig.json
@@ -0,0 +1,30 @@
+{
+ "extends": "../../tsconfig.json",
+ "compilerOptions": {
+ "baseUrl": "./",
+ "paths": {
+ "@/*": [
+ "src/*"
+ ],
+ "@reapit/cognito-auth": [
+ "../cognito-auth/src"
+ ],
+ "@reapit/elements": [
+ "../elements/src"
+ ],
+ "@reapit/elements/*": [
+ "../elements/src/*"
+ ]
+ }
+ },
+ "include": [
+ "src"
+ ],
+ "exclude": [
+ "public",
+ "dist",
+ "./webpack.config.js",
+ "node_modules",
+ "src/tests/coverage"
+ ]
+}
diff --git a/packages/react-app-scaffolder/package.json b/packages/react-app-scaffolder/package.json
index 34ce250676..98d400134e 100644
--- a/packages/react-app-scaffolder/package.json
+++ b/packages/react-app-scaffolder/package.json
@@ -1,6 +1,6 @@
{
"name": "@reapit/generator-react-app-scaffolder",
- "version": "0.0.32",
+ "version": "1.0.0-alpha.1",
"description": "An opinionated gnerator for scaffolding TypeScript React Redux apps",
"keywords": [
"yeoman-generator"
@@ -23,12 +23,8 @@
"scaffold": "yo ./app --force"
},
"dependencies": {
- "yeoman-generator": "^4.0.1",
+ "yeoman-generator": "^4.11.0",
"yo": "^3.1.1",
- "yosay": "^2.0.2",
- "change-case": "^4.1.1"
- },
- "devDependencies": {
- "raw-loader": "^3.1.0"
+ "yosay": "^2.0.2"
}
}
diff --git a/packages/react-app-scaffolder/app/templates/base-is-not-foundation/src/scripts/webpack-prod.js b/scripts/webpack/webpack.pwa.prod.js
similarity index 78%
rename from packages/react-app-scaffolder/app/templates/base-is-not-foundation/src/scripts/webpack-prod.js
rename to scripts/webpack/webpack.pwa.prod.js
index 56701b68b3..48de570e93 100644
--- a/packages/react-app-scaffolder/app/templates/base-is-not-foundation/src/scripts/webpack-prod.js
+++ b/scripts/webpack/webpack.pwa.prod.js
@@ -1,13 +1,16 @@
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const FaviconsWebpackPlugin = require('favicons-webpack-plugin')
+const WorkboxWebpackPlugin = require('workbox-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const ResolveTSPathsToWebpackAlias = require('ts-paths-to-webpack-alias')
const CopyPlugin = require('copy-webpack-plugin')
+const SentryWebpackPlugin = require('@sentry/webpack-plugin')
const HardSourceWebpackPlugin = require('hard-source-webpack-plugin')
-const { SourceMapDevToolPlugin, HashedModuleIdsPlugin } = require('webpack')
+const { EnvironmentPlugin, SourceMapDevToolPlugin, HashedModuleIdsPlugin } = require('webpack')
const { PATHS } = require('./constants')
-const hashFiles = require('./utils')
+const hashFiles = require('../utils/hash-files')
+const { getVersionTag, getRef } = require('../release/utils')
const EXCLUDE_PACKAGES = ['linaria']
@@ -16,6 +19,11 @@ const generateRegexExcludePackages = () => {
return new RegExp(`node_modules/(?!(${listPackagesString})/).*`)
}
+const tagName = getVersionTag()
+const hashOfCommit = getRef()
+const APP_VERSION = `${tagName.packageName}_${tagName.version}`
+const outputFileName = `[name].${hashOfCommit}.js`
+
const babelLoaderOptions = {
presets: [
[
@@ -40,7 +48,7 @@ const webpackConfig = {
entry: ['@babel/polyfill', 'core-js', 'isomorphic-fetch', 'regenerator-runtime/runtime', PATHS.entryWeb],
output: {
path: PATHS.output,
- filename: '[name].[hash].js',
+ filename: outputFileName,
},
optimization: {
nodeEnv: 'production',
@@ -192,7 +200,10 @@ const webpackConfig = {
new SourceMapDevToolPlugin({
filename: '[file].map',
}),
- new CopyPlugin([{ from: 'config.json', to: PATHS.output }]),
+ new CopyPlugin([
+ { from: 'config.json', to: PATHS.output },
+ { from: 'manifest.json', to: PATHS.output },
+ ]),
new HtmlWebpackPlugin({
hash: true,
inject: true,
@@ -233,6 +244,23 @@ const webpackConfig = {
windows: false,
},
}),
+ new EnvironmentPlugin({
+ APP_VERSION: APP_VERSION,
+ }),
+ new WorkboxWebpackPlugin.GenerateSW({
+ clientsClaim: true,
+ exclude: [/\.map$/, /asset-manifest\.json$/],
+ navigateFallback: '/index.html',
+ navigateFallbackDenylist: [
+ // Exclude URLs starting with /_, as they're likely an API call
+ new RegExp('^/_'),
+ // Exclude any URLs whose last part seems to be a file extension
+ // as they're likely a resource and not a SPA route.
+ // URLs containing a "?" character won't be blacklisted as they're likely
+ // a route with query params (e.g. auth callbacks).
+ new RegExp('/[^/?]+\\.[^/]+$'),
+ ],
+ }),
new HashedModuleIdsPlugin(),
new HardSourceWebpackPlugin({
// each package has its own .webpack-cache
@@ -247,4 +275,19 @@ const webpackConfig = {
],
}
+if (process.env.IS_RELEASE) {
+ webpackConfig.plugins.push(
+ new SentryWebpackPlugin({
+ release: APP_VERSION,
+ include: './public/dist/',
+ ignore: ['node_modules', 'webpack.config.js'],
+ configFile: '.sentryclirc',
+ setCommits: {
+ repo: 'reapit/foundations',
+ auto: true,
+ },
+ }),
+ )
+}
+
module.exports = webpackConfig
diff --git a/yarn.lock b/yarn.lock
index 6d950d511c..3bfe4b976a 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1163,7 +1163,7 @@
core-js-pure "^3.0.0"
regenerator-runtime "^0.13.4"
-"@babel/runtime@7.10.2", "@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.1", "@babel/runtime@^7.10.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.1", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2", "@babel/runtime@^7.9.6":
+"@babel/runtime@7.10.2", "@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.1", "@babel/runtime@^7.10.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.1", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2", "@babel/runtime@^7.9.6":
version "7.10.2"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.10.2.tgz#d103f21f2602497d38348a32e008637d506db839"
integrity sha512-6sF3uQw2ivImfVIl62RZ7MXhO2tap69WeWK57vAaimT6AZbE4FbqjdEJIN1UqoD6wI6B+1n9UiagafH1sxjOtg==
@@ -1832,7 +1832,7 @@
"@hapi/cryptiles" "4.x.x"
"@hapi/hoek" "8.x.x"
-"@hapi/joi@15.x.x", "@hapi/joi@^15.0.0":
+"@hapi/joi@15.x.x", "@hapi/joi@^15.1.0":
version "15.1.1"
resolved "https://registry.yarnpkg.com/@hapi/joi/-/joi-15.1.1.tgz#c675b8a71296f02833f8d6d243b34c57b8ce19d7"
integrity sha512-entf8ZMOK8sc+8YfeOlM8pCfg3b5+WZIKBfUaaJT8UsjAAPjartzxIYm3TIbjvA4u+u++KbcXD38k682nVHDAQ==
@@ -5314,6 +5314,14 @@
telejson "^3.2.0"
util-deprecate "^1.0.2"
+"@surma/rollup-plugin-off-main-thread@^1.1.1":
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-1.4.1.tgz#bf1343e5a926e5a1da55e3affd761dda4ce143ef"
+ integrity sha512-ZPBWYQDdO4JZiTmTP3DABsHhIPA7bEJk9Znk7tZsrbPGanoGo8YxMv//WLx5Cvb+lRgS42+6yiOIYYHCKDmkpQ==
+ dependencies:
+ ejs "^2.6.1"
+ magic-string "^0.25.0"
+
"@svgr/babel-plugin-add-jsx-attribute@^4.2.0":
version "4.2.0"
resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-4.2.0.tgz#dadcb6218503532d6884b210e7f3c502caaa44b1"
@@ -9309,15 +9317,6 @@ capability@^0.2.5:
resolved "https://registry.yarnpkg.com/capability/-/capability-0.2.5.tgz#51ad87353f1936ffd77f2f21c74633a4dea88801"
integrity sha1-Ua2HNT8ZNv/Xfy8hx0YzpN6oiAE=
-capital-case@^1.0.3:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/capital-case/-/capital-case-1.0.3.tgz#339bd77e8fab6cf75111d4fca509b3edf7c117c8"
- integrity sha512-OlUSJpUr7SY0uZFOxcwnDOU7/MpHlKTZx2mqnDYQFrDudXLFm0JJ9wr/l4csB+rh2Ug0OPuoSO53PqiZBqno9A==
- dependencies:
- no-case "^3.0.3"
- tslib "^1.10.0"
- upper-case-first "^2.0.1"
-
capture-exit@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4"
@@ -9434,24 +9433,6 @@ chalk@^4.0.0, chalk@^4.1.0:
ansi-styles "^4.1.0"
supports-color "^7.1.0"
-change-case@^4.1.1:
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/change-case/-/change-case-4.1.1.tgz#d5005709275952e7963fed7b91e4f9fdb6180afa"
- integrity sha512-qRlUWn/hXnX1R1LBDF/RelJLiqNjKjUqlmuBVSEIyye8kq49CXqkZWKmi8XeUAdDXWFOcGLUMZ+aHn3Q5lzUXw==
- dependencies:
- camel-case "^4.1.1"
- capital-case "^1.0.3"
- constant-case "^3.0.3"
- dot-case "^3.0.3"
- header-case "^2.0.3"
- no-case "^3.0.3"
- param-case "^3.0.3"
- pascal-case "^3.1.1"
- path-case "^3.0.3"
- sentence-case "^3.0.3"
- snake-case "^3.0.3"
- tslib "^1.10.0"
-
char-regex@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf"
@@ -10316,15 +10297,6 @@ console-control-strings@^1.0.0, console-control-strings@~1.1.0:
resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=
-constant-case@^3.0.3:
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/constant-case/-/constant-case-3.0.3.tgz#ac910a99caf3926ac5112f352e3af599d8c5fc0a"
- integrity sha512-FXtsSnnrFYpzDmvwDGQW+l8XK3GV1coLyBN0eBz16ZUzGaZcT2ANVCJmLeuw2GQgxKHQIe9e0w2dzkSfaRlUmA==
- dependencies:
- no-case "^3.0.3"
- tslib "^1.10.0"
- upper-case "^2.0.1"
-
constantinople@^3.0.1, constantinople@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/constantinople/-/constantinople-3.1.2.tgz#d45ed724f57d3d10500017a7d3a889c1381ae647"
@@ -13441,7 +13413,7 @@ fast-json-patch@~2.1.0:
dependencies:
deep-equal "^1.0.1"
-fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0:
+fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
@@ -14131,7 +14103,7 @@ fs-extra@^0.30.0:
path-is-absolute "^1.0.0"
rimraf "^2.2.8"
-fs-extra@^4.0.2, fs-extra@^4.0.3:
+fs-extra@^4.0.3:
version "4.0.3"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94"
integrity sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==
@@ -15425,14 +15397,6 @@ he@1.2.x, he@^1.1.0, he@^1.2.0:
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
-header-case@^2.0.3:
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/header-case/-/header-case-2.0.3.tgz#8a7407d16edfd5c970f8ebb116e6383f855b5a72"
- integrity sha512-LChe/V32mnUQnTwTxd3aAlNMk8ia9tjCDb/LjYtoMrdAPApxLB+azejUk5ERZIZdIqvinwv6BAUuFXH/tQPdZA==
- dependencies:
- capital-case "^1.0.3"
- tslib "^1.10.0"
-
highlight.js@~9.13.0:
version "9.13.1"
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.13.1.tgz#054586d53a6863311168488a0f58d6c505ce641e"
@@ -18477,13 +18441,6 @@ json-stable-stringify-without-jsonify@^1.0.1:
resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=
-json-stable-stringify@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af"
- integrity sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=
- dependencies:
- jsonify "~0.0.0"
-
json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
@@ -18544,11 +18501,6 @@ jsonfile@^4.0.0:
optionalDependencies:
graceful-fs "^4.1.6"
-jsonify@~0.0.0:
- version "0.0.0"
- resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"
- integrity sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=
-
jsonparse@^1.2.0:
version "1.3.1"
resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280"
@@ -19646,7 +19598,7 @@ macos-release@^2.2.0:
resolved "https://registry.yarnpkg.com/macos-release/-/macos-release-2.3.0.tgz#eb1930b036c0800adebccd5f17bc4c12de8bb71f"
integrity sha512-OHhSbtcviqMPt7yfw5ef5aghS2jzFVKEFyCJndQt2YpSQ9qRVSEv2axSJI1paVThEu+FFGs584h/1YhxjVqajA==
-magic-string@^0.25.2, magic-string@^0.25.5, magic-string@^0.25.7:
+magic-string@^0.25.0, magic-string@^0.25.2, magic-string@^0.25.5, magic-string@^0.25.7:
version "0.25.7"
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051"
integrity sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==
@@ -19902,6 +19854,23 @@ mem-fs-editor@^6.0.0:
through2 "^3.0.1"
vinyl "^2.2.0"
+mem-fs-editor@^7.0.1:
+ version "7.0.1"
+ resolved "https://registry.yarnpkg.com/mem-fs-editor/-/mem-fs-editor-7.0.1.tgz#e0797802b7797acf43ef3c511f3d3ad5ea765783"
+ integrity sha512-eD8r4/d2ayp9HHIgBPHB6Ds0ggA8F9cf9HxcNtbqrwqJXfIDrOSMG5K4fV3+Ib3B+HIdrWqkeDDDvrO7i9EbvQ==
+ dependencies:
+ commondir "^1.0.1"
+ deep-extend "^0.6.0"
+ ejs "^3.0.1"
+ glob "^7.1.4"
+ globby "^9.2.0"
+ isbinaryfile "^4.0.0"
+ mkdirp "^1.0.0"
+ multimatch "^4.0.0"
+ rimraf "^3.0.0"
+ through2 "^3.0.1"
+ vinyl "^2.2.0"
+
mem-fs@^1.1.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/mem-fs/-/mem-fs-1.2.0.tgz#5f29b2d02a5875cd14cd836c388385892d556cde"
@@ -20374,7 +20343,7 @@ mkdirp-promise@^5.0.1:
dependencies:
mkdirp "*"
-mkdirp@*, mkdirp@1.x, mkdirp@^1.0.4, mkdirp@~1.0.3:
+mkdirp@*, mkdirp@1.x, mkdirp@^1.0.0, mkdirp@^1.0.4, mkdirp@~1.0.3:
version "1.0.4"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
@@ -22168,14 +22137,6 @@ path-browserify@0.0.1:
resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a"
integrity sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==
-path-case@^3.0.3:
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/path-case/-/path-case-3.0.3.tgz#d48119aed52c4712e036ca40c6b15984f909554f"
- integrity sha512-UMFU6UETFpCNWbIWNczshPrnK/7JAXBP2NYw80ojElbQ2+JYxdqWDBkvvqM93u4u6oLmuJ/tPOf2tM8KtXv4eg==
- dependencies:
- dot-case "^3.0.3"
- tslib "^1.10.0"
-
path-dirname@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0"
@@ -22668,7 +22629,7 @@ prettier@^2.0.5:
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.0.5.tgz#d6d56282455243f2f92cc1716692c08aa31522d4"
integrity sha512-7PtVymN48hGcO4fGjybyBSIWDsLU4H4XlvOHfq91pz9kkGlonzwTfYkaIEwiRg/dAJF9YlbsduBAgtYLi+8cFg==
-pretty-bytes@5.3.0, pretty-bytes@^5.1.0, pretty-bytes@^5.2.0:
+pretty-bytes@5.3.0, pretty-bytes@^5.2.0, pretty-bytes@^5.3.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.3.0.tgz#f2849e27db79fb4d6cfe24764fc4134f165989f2"
integrity sha512-hjGrh+P926p4R4WbaB6OckyRtO0F0/lQBiT+0gnxjV+5kjPBrfVBFCsCLbMqVQeydvIoouYTCmmEURiH3R1Bdg==
@@ -24884,7 +24845,7 @@ rollup@1.27.13:
"@types/node" "*"
acorn "^7.1.0"
-rollup@^1.27.8, rollup@^1.32.0:
+rollup@^1.27.8, rollup@^1.31.1, rollup@^1.32.0:
version "1.32.1"
resolved "https://registry.yarnpkg.com/rollup/-/rollup-1.32.1.tgz#4480e52d9d9e2ae4b46ba0d9ddeaf3163940f9c4"
integrity sha512-/2HA0Ec70TvQnXdzynFffkjA6XN+1e2pEv/uKS5Ulca40g2L7KuOE3riasHoNVHOsFD5KKZgDsMk1CP3Tw9s+A==
@@ -25235,15 +25196,6 @@ send@0.17.1, send@latest:
range-parser "~1.2.1"
statuses "~1.5.0"
-sentence-case@^3.0.3:
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/sentence-case/-/sentence-case-3.0.3.tgz#47576e4adff7abf42c63c815b0543c9d2f85a930"
- integrity sha512-ZPr4dgTcNkEfcGOMFQyDdJrTU9uQO1nb1cjf+nuzb6FxgMDgKddZOM29qEsB7jvsZSMruLRcL2KfM4ypKpa0LA==
- dependencies:
- no-case "^3.0.3"
- tslib "^1.10.0"
- upper-case-first "^2.0.1"
-
seq-queue@^0.0.5:
version "0.0.5"
resolved "https://registry.yarnpkg.com/seq-queue/-/seq-queue-0.0.5.tgz#d56812e1c017a6e4e7c3e3a37a1da6d78dd3c93e"
@@ -25797,14 +25749,6 @@ smart-buffer@^4.1.0:
resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.1.0.tgz#91605c25d91652f4661ea69ccf45f1b331ca21ba"
integrity sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw==
-snake-case@^3.0.3:
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/snake-case/-/snake-case-3.0.3.tgz#c598b822ab443fcbb145ae8a82c5e43526d5bbee"
- integrity sha512-WM1sIXEO+rsAHBKjGf/6R1HBBcgbncKS08d2Aqec/mrDSpU80SiOU41hO7ny6DToHSyrlwTYzQBIK1FPSx4Y3Q==
- dependencies:
- dot-case "^3.0.3"
- tslib "^1.10.0"
-
snapdragon-node@^2.0.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b"
@@ -27442,6 +27386,15 @@ tempfile@^2.0.0:
temp-dir "^1.0.0"
uuid "^3.0.1"
+tempy@^0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/tempy/-/tempy-0.3.0.tgz#6f6c5b295695a16130996ad5ab01a8bd726e8bf8"
+ integrity sha512-WrH/pui8YCwmeiAoxV+lpRH9HpRtgBhSR2ViBPgpGb/wnYDzp21R4MN45fsCGvLROvY67o3byhJRYRONJyImVQ==
+ dependencies:
+ temp-dir "^1.0.0"
+ type-fest "^0.3.1"
+ unique-string "^1.0.0"
+
term-size@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/term-size/-/term-size-1.2.0.tgz#458b83887f288fc56d6fffbfad262e26638efa69"
@@ -28233,7 +28186,7 @@ type-fest@^0.13.1:
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.13.1.tgz#0172cb5bce80b0bd542ea348db50c7e21834d934"
integrity sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==
-type-fest@^0.3.0:
+type-fest@^0.3.0, type-fest@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.3.1.tgz#63d00d204e059474fe5e1b7c011112bbd1dc29e1"
integrity sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==
@@ -28636,7 +28589,7 @@ unzip-response@^2.0.1:
resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97"
integrity sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=
-upath@^1.1.1, upath@^1.2.0:
+upath@^1.1.1, upath@^1.1.2, upath@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894"
integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==
@@ -28709,25 +28662,11 @@ upper-case-first@^1.1.0:
dependencies:
upper-case "^1.1.1"
-upper-case-first@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/upper-case-first/-/upper-case-first-2.0.1.tgz#32ab436747d891cc20ab1e43d601cb4d0a7fbf4a"
- integrity sha512-105J8XqQ+9RxW3l9gHZtgve5oaiR9TIwvmZAMAIZWRHe00T21cdvewKORTlOJf/zXW6VukuTshM+HXZNWz7N5w==
- dependencies:
- tslib "^1.10.0"
-
upper-case@^1.1.1:
version "1.1.3"
resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598"
integrity sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=
-upper-case@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-2.0.1.tgz#6214d05e235dc817822464ccbae85822b3d8665f"
- integrity sha512-laAsbea9SY5osxrv7S99vH9xAaJKrw5Qpdh4ENRLcaxipjKsiaBwiAsxfa8X5mObKNTQPsupSq0J/VIxsSJe3A==
- dependencies:
- tslib "^1.10.0"
-
uri-js@^4.2.2:
version "4.2.2"
resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0"
@@ -29340,7 +29279,7 @@ webpack-node-externals@^1.7.2:
resolved "https://registry.yarnpkg.com/webpack-node-externals/-/webpack-node-externals-1.7.2.tgz#6e1ee79ac67c070402ba700ef033a9b8d52ac4e3"
integrity sha512-ajerHZ+BJKeCLviLUUmnyd5B4RavLF76uv3cs6KNuO8W+HuQaEs0y0L7o40NQxdPy5w0pcv8Ew7yPUAQG0UdCg==
-webpack-sources@^1.0.1, webpack-sources@^1.1.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack-sources@^1.4.3:
+webpack-sources@^1.0.1, webpack-sources@^1.1.0, webpack-sources@^1.3.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack-sources@^1.4.3:
version "1.4.3"
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933"
integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==
@@ -29599,140 +29538,158 @@ wordwrap@^1.0.0:
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=
-workbox-background-sync@^4.3.1:
- version "4.3.1"
- resolved "https://registry.yarnpkg.com/workbox-background-sync/-/workbox-background-sync-4.3.1.tgz#26821b9bf16e9e37fd1d640289edddc08afd1950"
- integrity sha512-1uFkvU8JXi7L7fCHVBEEnc3asPpiAL33kO495UMcD5+arew9IbKW2rV5lpzhoWcm/qhGB89YfO4PmB/0hQwPRg==
+workbox-background-sync@^5.1.3:
+ version "5.1.3"
+ resolved "https://registry.yarnpkg.com/workbox-background-sync/-/workbox-background-sync-5.1.3.tgz#121c5cf439b627f6320ff490be65fd2bd440c6ea"
+ integrity sha512-V/R95aPxYjbKCaVzUTihrZ9ObGOnzoA5n60r0DQ747p8Pj15/dDTYixonKhhlvavTiNezUrp+wTQBvZvcd/ETA==
dependencies:
- workbox-core "^4.3.1"
+ workbox-core "^5.1.3"
-workbox-broadcast-update@^4.3.1:
- version "4.3.1"
- resolved "https://registry.yarnpkg.com/workbox-broadcast-update/-/workbox-broadcast-update-4.3.1.tgz#e2c0280b149e3a504983b757606ad041f332c35b"
- integrity sha512-MTSfgzIljpKLTBPROo4IpKjESD86pPFlZwlvVG32Kb70hW+aob4Jxpblud8EhNb1/L5m43DUM4q7C+W6eQMMbA==
+workbox-broadcast-update@^5.1.3:
+ version "5.1.3"
+ resolved "https://registry.yarnpkg.com/workbox-broadcast-update/-/workbox-broadcast-update-5.1.3.tgz#312e0f065f06a6fb04a050143c84aa6ba0ed8add"
+ integrity sha512-HJ7FDmgweRcYp8fMiFbkmhaTjMYhMByURe5+TempnCi7cT5NNbyaG4T+rg8NWYxAeumSAB3JQF6XD/z34vRRHA==
dependencies:
- workbox-core "^4.3.1"
+ workbox-core "^5.1.3"
-workbox-build@^4.3.1:
- version "4.3.1"
- resolved "https://registry.yarnpkg.com/workbox-build/-/workbox-build-4.3.1.tgz#414f70fb4d6de47f6538608b80ec52412d233e64"
- integrity sha512-UHdwrN3FrDvicM3AqJS/J07X0KXj67R8Cg0waq1MKEOqzo89ap6zh6LmaLnRAjpB+bDIz+7OlPye9iii9KBnxw==
+workbox-build@^5.1.3:
+ version "5.1.3"
+ resolved "https://registry.yarnpkg.com/workbox-build/-/workbox-build-5.1.3.tgz#ec0dbcb7e260ad792c49407d063f4bcc8a8f08b8"
+ integrity sha512-cssa2cKAi/FNp2P2m2DjF/UsXlVX6b1HgkXOjBTraFkIeyZEKxN1F1DnxOpGkdM/bPPRa7y5OmUvjOpgOd9apA==
dependencies:
- "@babel/runtime" "^7.3.4"
- "@hapi/joi" "^15.0.0"
+ "@babel/core" "^7.8.4"
+ "@babel/preset-env" "^7.8.4"
+ "@babel/runtime" "^7.8.4"
+ "@hapi/joi" "^15.1.0"
+ "@rollup/plugin-node-resolve" "^7.1.1"
+ "@rollup/plugin-replace" "^2.3.1"
+ "@surma/rollup-plugin-off-main-thread" "^1.1.1"
common-tags "^1.8.0"
- fs-extra "^4.0.2"
- glob "^7.1.3"
- lodash.template "^4.4.0"
- pretty-bytes "^5.1.0"
+ fast-json-stable-stringify "^2.1.0"
+ fs-extra "^8.1.0"
+ glob "^7.1.6"
+ lodash.template "^4.5.0"
+ pretty-bytes "^5.3.0"
+ rollup "^1.31.1"
+ rollup-plugin-babel "^4.3.3"
+ rollup-plugin-terser "^5.2.0"
+ source-map "^0.7.3"
+ source-map-url "^0.4.0"
stringify-object "^3.3.0"
strip-comments "^1.0.2"
- workbox-background-sync "^4.3.1"
- workbox-broadcast-update "^4.3.1"
- workbox-cacheable-response "^4.3.1"
- workbox-core "^4.3.1"
- workbox-expiration "^4.3.1"
- workbox-google-analytics "^4.3.1"
- workbox-navigation-preload "^4.3.1"
- workbox-precaching "^4.3.1"
- workbox-range-requests "^4.3.1"
- workbox-routing "^4.3.1"
- workbox-strategies "^4.3.1"
- workbox-streams "^4.3.1"
- workbox-sw "^4.3.1"
- workbox-window "^4.3.1"
-
-workbox-cacheable-response@^4.3.1:
- version "4.3.1"
- resolved "https://registry.yarnpkg.com/workbox-cacheable-response/-/workbox-cacheable-response-4.3.1.tgz#f53e079179c095a3f19e5313b284975c91428c91"
- integrity sha512-Rp5qlzm6z8IOvnQNkCdO9qrDgDpoPNguovs0H8C+wswLuPgSzSp9p2afb5maUt9R1uTIwOXrVQMmPfPypv+npw==
+ tempy "^0.3.0"
+ upath "^1.2.0"
+ workbox-background-sync "^5.1.3"
+ workbox-broadcast-update "^5.1.3"
+ workbox-cacheable-response "^5.1.3"
+ workbox-core "^5.1.3"
+ workbox-expiration "^5.1.3"
+ workbox-google-analytics "^5.1.3"
+ workbox-navigation-preload "^5.1.3"
+ workbox-precaching "^5.1.3"
+ workbox-range-requests "^5.1.3"
+ workbox-routing "^5.1.3"
+ workbox-strategies "^5.1.3"
+ workbox-streams "^5.1.3"
+ workbox-sw "^5.1.3"
+ workbox-window "^5.1.3"
+
+workbox-cacheable-response@^5.1.3:
+ version "5.1.3"
+ resolved "https://registry.yarnpkg.com/workbox-cacheable-response/-/workbox-cacheable-response-5.1.3.tgz#79ec05c9f22796833d653e7cad43774a8f8bf7db"
+ integrity sha512-lOJEwK2T4KWFNdhRFUKxTPBIO5hIYm9E/nYgMq5h/IH3iHPHlBPuFwRMaQy+TTCGWWTA85NomQOjVw1bj65RLw==
dependencies:
- workbox-core "^4.3.1"
+ workbox-core "^5.1.3"
-workbox-core@^4.3.1:
- version "4.3.1"
- resolved "https://registry.yarnpkg.com/workbox-core/-/workbox-core-4.3.1.tgz#005d2c6a06a171437afd6ca2904a5727ecd73be6"
- integrity sha512-I3C9jlLmMKPxAC1t0ExCq+QoAMd0vAAHULEgRZ7kieCdUd919n53WC0AfvokHNwqRhGn+tIIj7vcb5duCjs2Kg==
+workbox-core@^5.1.3:
+ version "5.1.3"
+ resolved "https://registry.yarnpkg.com/workbox-core/-/workbox-core-5.1.3.tgz#0607acd0018c149162777fe4aae08553bd1559f5"
+ integrity sha512-TFSIPxxciX9sFaj0FDiohBeIKpwMcCyNduydi9i3LChItcndDS6TJpErxybv8aBWeCMraXt33TWtF6kKuIObNw==
-workbox-expiration@^4.3.1:
- version "4.3.1"
- resolved "https://registry.yarnpkg.com/workbox-expiration/-/workbox-expiration-4.3.1.tgz#d790433562029e56837f341d7f553c4a78ebe921"
- integrity sha512-vsJLhgQsQouv9m0rpbXubT5jw0jMQdjpkum0uT+d9tTwhXcEZks7qLfQ9dGSaufTD2eimxbUOJfWLbNQpIDMPw==
+workbox-expiration@^5.1.3:
+ version "5.1.3"
+ resolved "https://registry.yarnpkg.com/workbox-expiration/-/workbox-expiration-5.1.3.tgz#c793eef17513de86c9c1b8254eb2c9ba3ed17568"
+ integrity sha512-8YhpmIHqIx+xmtxONADc+di4a3zzCsvVHLiKq6T3vJZUPnqV2jzx+51+UHMUh3T5w5Z5SFC14l0V/jesRbuMKg==
dependencies:
- workbox-core "^4.3.1"
+ workbox-core "^5.1.3"
-workbox-google-analytics@^4.3.1:
- version "4.3.1"
- resolved "https://registry.yarnpkg.com/workbox-google-analytics/-/workbox-google-analytics-4.3.1.tgz#9eda0183b103890b5c256e6f4ea15a1f1548519a"
- integrity sha512-xzCjAoKuOb55CBSwQrbyWBKqp35yg1vw9ohIlU2wTy06ZrYfJ8rKochb1MSGlnoBfXGWss3UPzxR5QL5guIFdg==
+workbox-google-analytics@^5.1.3:
+ version "5.1.3"
+ resolved "https://registry.yarnpkg.com/workbox-google-analytics/-/workbox-google-analytics-5.1.3.tgz#dba0cadcf438d14389f2f2da0fd9c8cb605d35e6"
+ integrity sha512-ouK6xIJa+raFcO29TgwKFU/Hv1ejqSYzCzH9lI2B/4z/Wdnb8maL6mMIojQ8j5SohwKswMZmLDl0Az2PCmX11w==
dependencies:
- workbox-background-sync "^4.3.1"
- workbox-core "^4.3.1"
- workbox-routing "^4.3.1"
- workbox-strategies "^4.3.1"
+ workbox-background-sync "^5.1.3"
+ workbox-core "^5.1.3"
+ workbox-routing "^5.1.3"
+ workbox-strategies "^5.1.3"
-workbox-navigation-preload@^4.3.1:
- version "4.3.1"
- resolved "https://registry.yarnpkg.com/workbox-navigation-preload/-/workbox-navigation-preload-4.3.1.tgz#29c8e4db5843803b34cd96dc155f9ebd9afa453d"
- integrity sha512-K076n3oFHYp16/C+F8CwrRqD25GitA6Rkd6+qAmLmMv1QHPI2jfDwYqrytOfKfYq42bYtW8Pr21ejZX7GvALOw==
+workbox-navigation-preload@^5.1.3:
+ version "5.1.3"
+ resolved "https://registry.yarnpkg.com/workbox-navigation-preload/-/workbox-navigation-preload-5.1.3.tgz#8e49b935aaef16ac614d06db4a0677cbd59f9cae"
+ integrity sha512-29SPQMAccOgbq3BT9Gz7k+ydy0mcKKR0Rmkmd46tnujutiL4ooE57fBhwsA+c6OlLcYdisvilKlV2YWEtKWfgQ==
dependencies:
- workbox-core "^4.3.1"
+ workbox-core "^5.1.3"
-workbox-precaching@^4.3.1:
- version "4.3.1"
- resolved "https://registry.yarnpkg.com/workbox-precaching/-/workbox-precaching-4.3.1.tgz#9fc45ed122d94bbe1f0ea9584ff5940960771cba"
- integrity sha512-piSg/2csPoIi/vPpp48t1q5JLYjMkmg5gsXBQkh/QYapCdVwwmKlU9mHdmy52KsDGIjVaqEUMFvEzn2LRaigqQ==
+workbox-precaching@^5.1.3:
+ version "5.1.3"
+ resolved "https://registry.yarnpkg.com/workbox-precaching/-/workbox-precaching-5.1.3.tgz#08f0b48f4a390872a994c4a6ce8e43d08c6cba57"
+ integrity sha512-9jjBiB00AOI0NnI320ddnhvlL3bjMrDoI3211kEaxcRWh0N2fX25uVn0O8N8u1gWY4tIfwZAn/DgtAU13cFhYA==
dependencies:
- workbox-core "^4.3.1"
+ workbox-core "^5.1.3"
-workbox-range-requests@^4.3.1:
- version "4.3.1"
- resolved "https://registry.yarnpkg.com/workbox-range-requests/-/workbox-range-requests-4.3.1.tgz#f8a470188922145cbf0c09a9a2d5e35645244e74"
- integrity sha512-S+HhL9+iTFypJZ/yQSl/x2Bf5pWnbXdd3j57xnb0V60FW1LVn9LRZkPtneODklzYuFZv7qK6riZ5BNyc0R0jZA==
+workbox-range-requests@^5.1.3:
+ version "5.1.3"
+ resolved "https://registry.yarnpkg.com/workbox-range-requests/-/workbox-range-requests-5.1.3.tgz#f0fc6370ea549d002af1fe902b4ee94bfef6e006"
+ integrity sha512-uUvEoyEUx86LJc7mtmy/6U8xuK0guXU2FnPimt17zDbsC8FSOaPxc92rxtD6xmDSYrI4FqIebypBCjgIe+sfxA==
dependencies:
- workbox-core "^4.3.1"
+ workbox-core "^5.1.3"
-workbox-routing@^4.3.1:
- version "4.3.1"
- resolved "https://registry.yarnpkg.com/workbox-routing/-/workbox-routing-4.3.1.tgz#a675841af623e0bb0c67ce4ed8e724ac0bed0cda"
- integrity sha512-FkbtrODA4Imsi0p7TW9u9MXuQ5P4pVs1sWHK4dJMMChVROsbEltuE79fBoIk/BCztvOJ7yUpErMKa4z3uQLX+g==
+workbox-routing@^5.1.3:
+ version "5.1.3"
+ resolved "https://registry.yarnpkg.com/workbox-routing/-/workbox-routing-5.1.3.tgz#9946da0e9ace45af3db09cc0b4bdc4696723e1f7"
+ integrity sha512-F+sAp9Iy3lVl3BEG+pzXWVq4AftzjiFpHDaZ4Kf4vLoBoKQE0hIHet4zE5DpHqYdyw+Udhp4wrfHamX6PN6z1Q==
dependencies:
- workbox-core "^4.3.1"
+ workbox-core "^5.1.3"
-workbox-strategies@^4.3.1:
- version "4.3.1"
- resolved "https://registry.yarnpkg.com/workbox-strategies/-/workbox-strategies-4.3.1.tgz#d2be03c4ef214c115e1ab29c9c759c9fe3e9e646"
- integrity sha512-F/+E57BmVG8dX6dCCopBlkDvvhg/zj6VDs0PigYwSN23L8hseSRwljrceU2WzTvk/+BSYICsWmRq5qHS2UYzhw==
+workbox-strategies@^5.1.3:
+ version "5.1.3"
+ resolved "https://registry.yarnpkg.com/workbox-strategies/-/workbox-strategies-5.1.3.tgz#220cc9f5519ed76f2452ccb9407a5fd967c37110"
+ integrity sha512-wiXHfmOKnWABeIVW+/ye0e00+2CcS5y7SIj2f9zcdy2ZLEbcOf7B+yOl5OrWpBGlTUwRjIYhV++ZqiKm3Dc+8w==
dependencies:
- workbox-core "^4.3.1"
+ workbox-core "^5.1.3"
+ workbox-routing "^5.1.3"
-workbox-streams@^4.3.1:
- version "4.3.1"
- resolved "https://registry.yarnpkg.com/workbox-streams/-/workbox-streams-4.3.1.tgz#0b57da70e982572de09c8742dd0cb40a6b7c2cc3"
- integrity sha512-4Kisis1f/y0ihf4l3u/+ndMkJkIT4/6UOacU3A4BwZSAC9pQ9vSvJpIi/WFGQRH/uPXvuVjF5c2RfIPQFSS2uA==
+workbox-streams@^5.1.3:
+ version "5.1.3"
+ resolved "https://registry.yarnpkg.com/workbox-streams/-/workbox-streams-5.1.3.tgz#8f381d395ea2e57106b7b6542b9ffcd769a3047b"
+ integrity sha512-8kt70eBd1RXL0qenxEnch3Cd7VyW3O0CkeGBN4Bikt307nIV5Q0JciLA5o0CRteijawYOiTq0/px4GDBv1obgQ==
dependencies:
- workbox-core "^4.3.1"
+ workbox-core "^5.1.3"
+ workbox-routing "^5.1.3"
-workbox-sw@^4.3.1:
- version "4.3.1"
- resolved "https://registry.yarnpkg.com/workbox-sw/-/workbox-sw-4.3.1.tgz#df69e395c479ef4d14499372bcd84c0f5e246164"
- integrity sha512-0jXdusCL2uC5gM3yYFT6QMBzKfBr2XTk0g5TPAV4y8IZDyVNDyj1a8uSXy3/XrvkVTmQvLN4O5k3JawGReXr9w==
+workbox-sw@^5.1.3:
+ version "5.1.3"
+ resolved "https://registry.yarnpkg.com/workbox-sw/-/workbox-sw-5.1.3.tgz#7bffbf034f2f5b58e1734b5b86d240019a5332bb"
+ integrity sha512-Syk6RhYr/8VdFwXrxo5IpVz8Og2xapHTWJhqsZRF+TbxSvlaJs8hrvVPd7edn5ZiiVdPhE9NTeOTOg1+D+FGoA==
-workbox-webpack-plugin@^4.3.1:
- version "4.3.1"
- resolved "https://registry.yarnpkg.com/workbox-webpack-plugin/-/workbox-webpack-plugin-4.3.1.tgz#47ff5ea1cc074b6c40fb5a86108863a24120d4bd"
- integrity sha512-gJ9jd8Mb8wHLbRz9ZvGN57IAmknOipD3W4XNE/Lk/4lqs5Htw4WOQgakQy/o/4CoXQlMCYldaqUg+EJ35l9MEQ==
+workbox-webpack-plugin@^5.1.3:
+ version "5.1.3"
+ resolved "https://registry.yarnpkg.com/workbox-webpack-plugin/-/workbox-webpack-plugin-5.1.3.tgz#a7070e3ea0eedb6f87e11fd916ec5d4430a6e348"
+ integrity sha512-gxSkZ9GFLrMNC/8DGNRjcMhrt8iu+MMXhH/Fpo3wo9rKaSMsI7esGq0klTH/UloP9pNvBizVydysrB52eRhI7w==
dependencies:
- "@babel/runtime" "^7.0.0"
- json-stable-stringify "^1.0.1"
- workbox-build "^4.3.1"
+ "@babel/runtime" "^7.5.5"
+ fast-json-stable-stringify "^2.0.0"
+ source-map-url "^0.4.0"
+ upath "^1.1.2"
+ webpack-sources "^1.3.0"
+ workbox-build "^5.1.3"
-workbox-window@^4.3.1:
- version "4.3.1"
- resolved "https://registry.yarnpkg.com/workbox-window/-/workbox-window-4.3.1.tgz#ee6051bf10f06afa5483c9b8dfa0531994ede0f3"
- integrity sha512-C5gWKh6I58w3GeSc0wp2Ne+rqVw8qwcmZnQGpjiek8A2wpbxSJb1FdCoQVO+jDJs35bFgo/WETgl1fqgsxN0Hg==
+workbox-window@^5.1.3:
+ version "5.1.3"
+ resolved "https://registry.yarnpkg.com/workbox-window/-/workbox-window-5.1.3.tgz#24a2acb2903b0ff2789a4ce32f355621e769eb23"
+ integrity sha512-oYvfVtPLET7FUrhOzbk0R+aATVmpdQBkmDqwyFH4W2dfVqJXTvTXzuGP5Pn9oZ8jMTB3AYW43yhYBlLYM3mYyg==
dependencies:
- workbox-core "^4.3.1"
+ workbox-core "^5.1.3"
worker-farm@^1.7.0:
version "1.7.0"
@@ -30270,7 +30227,41 @@ yeoman-environment@^2.4.0, yeoman-environment@^2.9.5:
untildify "^3.0.3"
yeoman-generator "^4.8.2"
-yeoman-generator@^4.0.1, yeoman-generator@^4.8.2:
+yeoman-generator@^4.11.0:
+ version "4.11.0"
+ resolved "https://registry.yarnpkg.com/yeoman-generator/-/yeoman-generator-4.11.0.tgz#c9e2fab77f17a4d7acff571f31e002bc066ed6a8"
+ integrity sha512-++t6t2Z6HjL5F1/UM7+uNvGknKmQdF8tstJx8WKzsUSEpB+19kLVtapSfQIh9uWqm0L59fLWDzUui//WXoynPw==
+ dependencies:
+ async "^2.6.2"
+ chalk "^2.4.2"
+ cli-table "^0.3.1"
+ cross-spawn "^6.0.5"
+ dargs "^6.1.0"
+ dateformat "^3.0.3"
+ debug "^4.1.1"
+ diff "^4.0.1"
+ error "^7.0.2"
+ find-up "^3.0.0"
+ github-username "^3.0.0"
+ istextorbinary "^2.5.1"
+ lodash "^4.17.11"
+ make-dir "^3.0.0"
+ mem-fs-editor "^7.0.1"
+ minimist "^1.2.5"
+ pretty-bytes "^5.2.0"
+ read-chunk "^3.2.0"
+ read-pkg-up "^5.0.0"
+ rimraf "^2.6.3"
+ run-async "^2.0.0"
+ semver "^7.2.1"
+ shelljs "^0.8.3"
+ text-table "^0.2.0"
+ through2 "^3.0.1"
+ optionalDependencies:
+ grouped-queue "^1.1.0"
+ yeoman-environment "^2.9.5"
+
+yeoman-generator@^4.8.2:
version "4.10.1"
resolved "https://registry.yarnpkg.com/yeoman-generator/-/yeoman-generator-4.10.1.tgz#82853f55856ba14f180ab6c6a70acd89b11c956b"
integrity sha512-QgbtHSaqBAkyJJM0heQUhT63ubCt34NBFMEBydOBUdAuy8RBvGSzeqVBSZOjdh1tSLrwWXlU3Ck6y14awinF6Q==