diff --git a/app/package-lock.json b/app/package-lock.json index cb9d4762..a08f6334 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -1054,6 +1054,21 @@ "integrity": "sha512-ui3WwXmjTaY73fOQ3/m3nnajU/Orhi6cEu5rzX+BrAAJxa3eITXZ5ch9suPqtM03OWhAHhPSyBGCN4UKoxO20Q==", "dev": true }, + "@types/jest": { + "version": "24.0.17", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-24.0.17.tgz", + "integrity": "sha512-1cy3xkOAfSYn78dsBWy4M3h/QF/HeWPchNFDjysVtp3GHeTdSmtluNnELfCmfNRRHo0OWEcpf+NsEJQvwQfdqQ==", + "dev": true, + "requires": { + "@types/jest-diff": "20.0.1" + } + }, + "@types/jest-diff": { + "version": "20.0.1", + "resolved": "https://registry.npmjs.org/@types/jest-diff/-/jest-diff-20.0.1.tgz", + "integrity": "sha512-yALhelO3i0hqZwhjtcr6dYyaLoCHbAMshwtj6cGxTvHZAKXHsYGdff6E8EPw3xLKY0ELUTQ69Q1rQiJENnccMA==", + "dev": true + }, "@types/mime": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.1.tgz", diff --git a/app/package.json b/app/package.json index 62cacbf3..f8a1378d 100644 --- a/app/package.json +++ b/app/package.json @@ -38,7 +38,9 @@ "devDependencies": { "@types/express": "^4.17.0", "@types/express-session": "^1.15.13", + "@types/jest": "^24.0.17", "@types/node": "^12.7.1", + "@types/prop-types": "^15.7.1", "@types/react": "^16.9.0", "@types/react-dom": "^16.8.5", "@types/react-router-dom": "^4.3.4", diff --git a/app/src/api/building.js b/app/src/api/building.ts similarity index 99% rename from app/src/api/building.js rename to app/src/api/building.ts index 97b47a93..39bf8d10 100644 --- a/app/src/api/building.js +++ b/app/src/api/building.ts @@ -72,7 +72,7 @@ function queryBuildingsByReference(key, id) { return undefined; }); } - return { error: 'Key must be UPRN or TOID' }; + return Promise.resolve({ error: 'Key must be UPRN or TOID' }); } function getBuildingById(id) { diff --git a/app/src/api/search.js b/app/src/api/search.ts similarity index 100% rename from app/src/api/search.js rename to app/src/api/search.ts diff --git a/app/src/api/user.js b/app/src/api/user.ts similarity index 100% rename from app/src/api/user.js rename to app/src/api/user.ts diff --git a/app/src/client.tsx b/app/src/client.tsx index bfc90364..b2653df5 100644 --- a/app/src/client.tsx +++ b/app/src/client.tsx @@ -8,7 +8,7 @@ import { hydrate } from 'react-dom'; import App from './frontend/app'; -const data = window.__PRELOADED_STATE__; +const data = (window as any).__PRELOADED_STATE__; // TODO: remove any hydrate( diff --git a/app/src/db.js b/app/src/db.ts similarity index 87% rename from app/src/db.js rename to app/src/db.ts index c1b8f8c3..db26e89d 100644 --- a/app/src/db.js +++ b/app/src/db.ts @@ -15,10 +15,10 @@ const pgp = pg(); // database connection (default to env vars) const db = pgp({ 'host': process.env.PGHOST, - 'dbname': process.env.PGDATABASE, + 'database': process.env.PGDATABASE, 'user': process.env.PGUSER, 'password': process.env.PGPASSWORD, - 'port': process.env.PGPORT + 'port': parseInt(process.env.PGPORT) }); export default db; diff --git a/app/src/frontend/app.tsx b/app/src/frontend/app.tsx index f23ffc3f..7c9ee1f0 100644 --- a/app/src/frontend/app.tsx +++ b/app/src/frontend/app.tsx @@ -31,7 +31,13 @@ import { parseCategoryURL } from '../parse'; * map or other pages are rendered, based on the URL. Use a react-router-dom in * child components to navigate without a full page reload. */ -class App extends React.Component { +class App extends React.Component { // TODO: add proper types + static propTypes = { // TODO: generate propTypes from TS + user: PropTypes.object, + building: PropTypes.object, + building_like: PropTypes.bool + } + constructor(props) { super(props); // set building revision id, default 0 @@ -130,7 +136,7 @@ class App extends React.Component { colourBuilding(building) { const cat = parseCategoryURL(window.location.pathname); const q = parse(window.location.search); - const data = (cat === 'like')? {like: true}: JSON.parse(q.data); + const data = (cat === 'like')? {like: true}: JSON.parse(q.data as string); // TODO: verify what happens if data is string[] if (cat === 'like'){ this.likeBuilding(building.building_id) } else { @@ -257,12 +263,6 @@ class App extends React.Component { } } -App.propTypes = { - user: PropTypes.object, - building: PropTypes.object, - building_like: PropTypes.bool -} - /** * Component to fall back on in case of 404 or no other match */ diff --git a/app/src/frontend/building-edit.tsx b/app/src/frontend/building-edit.tsx index 8f61a79e..80da4816 100644 --- a/app/src/frontend/building-edit.tsx +++ b/app/src/frontend/building-edit.tsx @@ -47,17 +47,36 @@ BuildingEdit.propTypes = { building_id: PropTypes.number } -class EditForm extends Component { +class EditForm extends Component { // TODO: add proper types + static propTypes = { // TODO: generate propTypes from TS + title: PropTypes.string, + slug: PropTypes.string, + cat: PropTypes.string, + help: PropTypes.string, + error: PropTypes.object, + like: PropTypes.bool, + building_like: PropTypes.bool, + selectBuilding: PropTypes.func, + building_id: PropTypes.number, + inactive: PropTypes.bool, + fields: PropTypes.array + }; + constructor(props) { super(props); + + // create object and spread into state to avoid TS complaining about modifying readonly state + let fieldsObj = {}; + for (const field of props.fields) { + fieldsObj[field.slug] = props[field.slug]; + } + this.state = { error: this.props.error || undefined, like: this.props.like || undefined, copying: false, - keys_to_copy: {} - } - for (const field of props.fields) { - this.state[field.slug] = props[field.slug] + keys_to_copy: {}, + ...fieldsObj } this.handleChange = this.handleChange.bind(this); @@ -353,20 +372,6 @@ class EditForm extends Component { } } -EditForm.propTypes = { - title: PropTypes.string, - slug: PropTypes.string, - cat: PropTypes.string, - help: PropTypes.string, - error: PropTypes.object, - like: PropTypes.bool, - building_like: PropTypes.bool, - selectBuilding: PropTypes.func, - building_id: PropTypes.number, - inactive: PropTypes.bool, - fields: PropTypes.array -} - const TextInput = (props) => (