diff --git a/.eslintrc.js b/.eslintrc.js
index dc33748..817b049 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -1,12 +1,27 @@
+// eslint-disable-next-line @typescript-eslint/no-var-requires
const { config } = require('@dhis2/cli-style')
module.exports = {
- extends: [config.eslintReact],
+ extends: [
+ config.eslintReact,
+ 'plugin:@typescript-eslint/recommended',
+ 'plugin:import/typescript',
+ ],
+ settings: {
+ 'import/resolver': {
+ node: {
+ extensions: ['.js', '.jsx', '.ts', '.tsx'],
+ },
+ },
+ },
globals: {
cy: 'readonly',
Cypress: 'readonly',
},
rules: {
+ 'react/prop-types': 'off',
'react/display-name': 'off',
+ 'import/extensions': 'off',
+ '@typescript-eslint/no-explicit-any': 'off',
},
}
diff --git a/README.md b/README.md
index 17833f7..5f18604 100644
--- a/README.md
+++ b/README.md
@@ -47,3 +47,53 @@ You can learn more about the platform in the [DHIS2 Application Platform Documen
You can learn more about the runtime in the [DHIS2 Application Runtime Documentation](https://runtime.dhis2.nu/).
To learn React, check out the [React documentation](https://reactjs.org/).
+
+
+## Migrating to TS
+
+- the simplest `tsconfig.json`
+
+```json
+{
+ "compilerOptions": {
+ "allowJs": true,
+ "target": "es5"
+ },
+ "include": ["./src/**/*"]
+}
+```
+from: https://www.typescriptlang.org/docs/handbook/migrating-from-javascript.html#writing-a-configuration-file
+
+- install `typescript`
+
+```bash
+yarn add --dev typescript
+```
+
+(optionally) add an alias to make testing easier in `package.json`, to run `yarn tsc --noEmit` for example.
+
+:::note[TypeScript is a typed "superset" of JavaScript]
+
+TypeScript is a language that is a superset of JavaScript: JS syntax is therefore legal TS.
+:::
+
+- Rename all files from `.js` to `.ts` (or `.jsx` to `.tsx`). You could use a script:
+
+```bash
+find ./src -depth -name "*.js" -exec sh -c 'mv "$1" "${1%.js}.tsx"' _ {} \;
+```
+
+- Remove all references to modules `.js` - get rid of extensions (if you want to keep extensions, you'd need to set `allowImportingTsExtensions` - not worth the hassle)
+
+(this will cause eslint errors)
+
+- Fix eslint config
+
+install `yarn add @typescript-eslint/eslint-plugin @typescript-eslint/parser`
+
+extend eslint config
+
+- inferred types
+- settings cast
+- generics (DRY)
+-
\ No newline at end of file
diff --git a/d2.config.js b/d2.config.js
index 40860ee..9bc5a4f 100644
--- a/d2.config.js
+++ b/d2.config.js
@@ -6,7 +6,7 @@ const config = {
minDHIS2Version: '2.39',
coreApp: false,
entryPoints: {
- app: './src/index.js',
+ app: './src/index.tsx',
},
}
diff --git a/package.json b/package.json
index 494c249..92e7e2c 100644
--- a/package.json
+++ b/package.json
@@ -18,18 +18,22 @@
"cypress:open:live": "start-server-and-test 'yarn cypress:start' http://localhost:3000 'yarn cypress open --env networkMode=live'",
"cypress:run:live": "start-server-and-test 'yarn cypress:start' http://localhost:3000 'yarn cypress run --env networkMode=live'",
"cypress:run:capture": "start-server-and-test 'yarn cypress:start' http://localhost:3000 'yarn cypress run --env networkMode=capture'",
- "cypress:run:stub": "start-server-and-test 'yarn cypress:start' http://localhost:3000 'yarn cypress run --env networkMode=stub'"
+ "cypress:run:stub": "start-server-and-test 'yarn cypress:start' http://localhost:3000 'yarn cypress run --env networkMode=stub'",
+ "tsc": "tsc"
},
"devDependencies": {
"@dhis2/cli-app-scripts": "^10.4.1",
"@dhis2/cli-style": "^10.4.1",
"@dhis2/cypress-commands": "^9.0.2",
"@dhis2/cypress-plugins": "^9.0.2",
+ "@typescript-eslint/eslint-plugin": "^7.11.0",
+ "@typescript-eslint/parser": "^7.11.0",
"cypress": "^9.7.0",
"cypress-cucumber-preprocessor": "^4.3.1",
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.6",
- "start-server-and-test": "^1.14.0"
+ "start-server-and-test": "^1.14.0",
+ "typescript": "^5.4.5"
},
"dependencies": {
"@dhis2/analytics": "999.9.9-outlier-table.alpha.1",
diff --git a/src/app.js b/src/app.tsx
similarity index 95%
rename from src/app.js
rename to src/app.tsx
index 6a45dcc..5a3ba3e 100644
--- a/src/app.js
+++ b/src/app.tsx
@@ -4,8 +4,8 @@ import React from 'react'
import { HashRouter, Route, Routes } from 'react-router-dom'
import { QueryParamProvider } from 'use-query-params'
import { ReactRouter6Adapter } from 'use-query-params/adapters/react-router-6'
-import { AppProvider, UserProvider } from './context/index.js'
-import { DataPage, EditPage, EditItem, AddItem } from './pages/index.js'
+import { AppProvider, UserProvider } from './context/index'
+import { DataPage, EditPage, EditItem, AddItem } from './pages/index'
const App = ({ router: Router }) => (
<>
diff --git a/src/components/common/button-with-tooltip/button-with-tooltip.js b/src/components/common/button-with-tooltip/button-with-tooltip.tsx
similarity index 100%
rename from src/components/common/button-with-tooltip/button-with-tooltip.js
rename to src/components/common/button-with-tooltip/button-with-tooltip.tsx
diff --git a/src/components/common/button-with-tooltip/index.js b/src/components/common/button-with-tooltip/index.js
deleted file mode 100644
index 0eab838..0000000
--- a/src/components/common/button-with-tooltip/index.js
+++ /dev/null
@@ -1 +0,0 @@
-export { ButtonWithTooltip } from './button-with-tooltip.js'
diff --git a/src/components/common/button-with-tooltip/index.tsx b/src/components/common/button-with-tooltip/index.tsx
new file mode 100644
index 0000000..fce121c
--- /dev/null
+++ b/src/components/common/button-with-tooltip/index.tsx
@@ -0,0 +1 @@
+export { ButtonWithTooltip } from './button-with-tooltip'
diff --git a/src/components/common/index.js b/src/components/common/index.js
deleted file mode 100644
index 40bc2f5..0000000
--- a/src/components/common/index.js
+++ /dev/null
@@ -1,2 +0,0 @@
-export * from './loader/index.js'
-export * from './warning/index.js'
diff --git a/src/components/common/index.tsx b/src/components/common/index.tsx
new file mode 100644
index 0000000..77a571f
--- /dev/null
+++ b/src/components/common/index.tsx
@@ -0,0 +1,2 @@
+export * from './loader/index'
+export * from './warning/index'
diff --git a/src/components/common/loader/index.js b/src/components/common/loader/index.js
deleted file mode 100644
index f56b222..0000000
--- a/src/components/common/loader/index.js
+++ /dev/null
@@ -1 +0,0 @@
-export { Loader } from './loader.js'
diff --git a/src/components/common/loader/index.tsx b/src/components/common/loader/index.tsx
new file mode 100644
index 0000000..1213eb7
--- /dev/null
+++ b/src/components/common/loader/index.tsx
@@ -0,0 +1 @@
+export { Loader } from './loader'
diff --git a/src/components/common/loader/loader.js b/src/components/common/loader/loader.js
deleted file mode 100644
index b460392..0000000
--- a/src/components/common/loader/loader.js
+++ /dev/null
@@ -1,10 +0,0 @@
-import { CenteredContent, CircularLoader } from '@dhis2/ui'
-import React from 'react'
-
-const Loader = () => (
-
{i18n.t('No requests')}
diff --git a/src/components/edit/exchange-update/useFetchExchange.js b/src/components/edit/exchange-update/useFetchExchange.tsx
similarity index 91%
rename from src/components/edit/exchange-update/useFetchExchange.js
rename to src/components/edit/exchange-update/useFetchExchange.tsx
index 80a4238..a76c22c 100644
--- a/src/components/edit/exchange-update/useFetchExchange.js
+++ b/src/components/edit/exchange-update/useFetchExchange.tsx
@@ -1,15 +1,17 @@
import { useDataEngine } from '@dhis2/app-runtime'
import { useCallback, useState } from 'react'
import {
- SCHEME_TYPES,
- OU_GROUP_PREFIX,
- OU_LEVEL_PREFIX,
-} from '../shared/index.js'
+ AggregateDataExchange,
+ ModelCollectionResponse,
+ OrganisationUnit,
+ Visualization,
+} from '../../../types/generated'
+import { SCHEME_TYPES, OU_GROUP_PREFIX, OU_LEVEL_PREFIX } from '../shared/index'
import {
getMetadataWithCode,
getFilterCodeMap,
getOuLevelMap,
-} from './codeDetailsHelpers.js'
+} from './codeDetailsHelpers'
const EXCHANGE_QUERY = {
exchange: {
@@ -76,9 +78,9 @@ export const useFetchExchange = () => {
// set to loading
setLoading(true)
try {
- const { exchange } = await engine.query(EXCHANGE_QUERY, {
+ const { exchange } = (await engine.query(EXCHANGE_QUERY, {
variables: { id },
- })
+ })) as { exchange: AggregateDataExchange }
// get metadata information for dx, pe
const metadataRequests = exchange.source.requests.map(
@@ -136,9 +138,14 @@ export const useFetchExchange = () => {
)
const { organisationUnits: orgUnitDetails } =
- await engine.query(ORG_UNITS_QUERY, {
+ (await engine.query(ORG_UNITS_QUERY, {
variables: { ids: [...ousToLookUp] },
- })
+ })) as {
+ organisationUnits: ModelCollectionResponse<
+ OrganisationUnit,
+ 'organisationUnits'
+ >
+ }
const ouMap = orgUnitDetails.organisationUnits.reduce(
(orgUnitsMap, orgUnit) => {
@@ -155,9 +162,14 @@ export const useFetchExchange = () => {
)
)
const { visualizations: visualizationsDetails } =
- await engine.query(VISUALIZATIONS_QUERY, {
+ (await engine.query(VISUALIZATIONS_QUERY, {
variables: { ids: [...visualizationsToLookUp] },
- })
+ })) as {
+ visualizations: ModelCollectionResponse<
+ Visualization,
+ 'visualizations'
+ >
+ }
const visualizationsMap =
visualizationsDetails.visualizations.reduce(
(visMap, visualization) => {
diff --git a/src/components/edit/exchange-update/useRequests.js b/src/components/edit/exchange-update/useRequests.tsx
similarity index 95%
rename from src/components/edit/exchange-update/useRequests.js
rename to src/components/edit/exchange-update/useRequests.tsx
index 4e3a14d..ccb5ec3 100644
--- a/src/components/edit/exchange-update/useRequests.js
+++ b/src/components/edit/exchange-update/useRequests.tsx
@@ -1,5 +1,5 @@
import { useCallback, useReducer, useState } from 'react'
-import { requestsReducer } from '../request-update/index.js'
+import { requestsReducer } from '../request-update/index'
export const useRequests = ({ exchangeInfo }) => {
const [requestEditInfo, setRequestEditInfo] = useState({
diff --git a/src/components/edit/exchange-update/useUpdateExchange.js b/src/components/edit/exchange-update/useUpdateExchange.tsx
similarity index 82%
rename from src/components/edit/exchange-update/useUpdateExchange.js
rename to src/components/edit/exchange-update/useUpdateExchange.tsx
index 7bdb39d..af2f733 100644
--- a/src/components/edit/exchange-update/useUpdateExchange.js
+++ b/src/components/edit/exchange-update/useUpdateExchange.tsx
@@ -1,6 +1,7 @@
import { useDataEngine } from '@dhis2/app-runtime'
import { useCallback, useState } from 'react'
-import { getExchangeValuesFromForm } from './getExchangeValues.js'
+import { Error } from '../../../types/generated'
+import { getExchangeValuesFromForm } from './getExchangeValues'
const getChange = ({ field, value }) => ({
op: 'add',
@@ -48,13 +49,33 @@ const getJsonPatch = ({ formattedValues, form, requestsTouched }) => {
return changes
}
-export const useUpdateExchange = ({ onComplete }) => {
+type RefetchExchangeFunc = ({
+ id,
+ form,
+ values,
+ requests,
+ requestsTouched,
+ newExchange,
+}: any) => Promise