diff --git a/.gitignore b/.gitignore index cfee706..b1a4580 100644 --- a/.gitignore +++ b/.gitignore @@ -24,4 +24,3 @@ dev-dist *.njsproj *.sln *.sw? -jsconfig.json diff --git a/CHANGELOG.md b/CHANGELOG.md index f29d9f3..efff50a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.4.2] - 2023-10-30 + +### Added + +### Changed +- Converted codebase to Typescript + +### Fixed + + ## [0.4.1] - 2023-10-22 ### Added diff --git a/index.html b/index.html index 2e230e8..b9ed774 100644 --- a/index.html +++ b/index.html @@ -27,6 +27,6 @@
- + \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 0226a61..057421e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "healthrecord", - "version": "0.4.1", + "version": "0.4.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "healthrecord", - "version": "0.4.1", + "version": "0.4.2", "dependencies": { "@headlessui/vue": "^1.7.16", "@heroicons/vue": "^2.0.18", @@ -29,13 +29,18 @@ "yjs": "^13.6.8" }, "devDependencies": { + "@types/file-saver": "^2.0.6", + "@types/number-to-words": "^1.2.2", + "@types/pluralize": "^0.0.32", "@vitejs/plugin-vue": "^4.2.3", "@vue/cli-plugin-router": "~5.0.0", "autoprefixer": "^10.4.15", "postcss": "^8.4.29", "tailwindcss": "^3.3.3", + "typescript": "^5.2.2", "vite": "^4.4.5", - "vite-plugin-pwa": "^0.16.5" + "vite-plugin-pwa": "^0.16.5", + "vue-tsc": "^1.8.20" } }, "node_modules/@achrinza/node-ipc": { @@ -2552,9 +2557,9 @@ } }, "node_modules/@types/estree": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.3.tgz", - "integrity": "sha512-CS2rOaoQ/eAgAfcTfq6amKG7bsN+EMcgGY4FAFQdvSj2y1ixvOZTUA9mOtCai7E1SYu283XNw7urKK30nP3wkQ==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.4.tgz", + "integrity": "sha512-2JwWnHK9H+wUZNorf2Zr6ves96WHoWDJIftkcxPKsS7Djta6Zu519LarhRNljPXkpsZR2ZMwNCPeW7omW07BJw==", "dev": true, "peer": true }, @@ -2584,6 +2589,12 @@ "@types/send": "*" } }, + "node_modules/@types/file-saver": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/file-saver/-/file-saver-2.0.6.tgz", + "integrity": "sha512-Mw671DVqoMHbjw0w4v2iiOro01dlT/WhWp5uwecBa0Wg8c+bcZOjgF1ndBnlaxhtvFCgTRBtsGivSVhrK/vnag==", + "dev": true + }, "node_modules/@types/html-minifier-terser": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", @@ -2630,12 +2641,22 @@ "peer": true }, "node_modules/@types/node": { - "version": "20.8.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.7.tgz", - "integrity": "sha512-21TKHHh3eUHIi2MloeptJWALuCu5H7HQTdTrWIFReA8ad+aggoX+lRes3ex7/FtpC+sVUpFMQ+QTfYr74mruiQ==", + "version": "20.8.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.9.tgz", + "integrity": "sha512-UzykFsT3FhHb1h7yD4CA4YhBHq545JC0YnEz41xkipN88eKQtL6rSgocL5tbAP6Ola9Izm/Aw4Ora8He4x0BHg==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/node-forge": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.8.tgz", + "integrity": "sha512-vGXshY9vim9CJjrpcS5raqSjEfKlJcWy2HNdgUasR66fAnVEYarrf1ULV4nfvpC1nZq/moA9qyqBcu83x+Jlrg==", "dev": true, + "peer": true, "dependencies": { - "undici-types": "~5.25.1" + "@types/node": "*" } }, "node_modules/@types/normalize-package-data": { @@ -2644,6 +2665,12 @@ "integrity": "sha512-ehPtgRgaULsFG8x0NeYJvmyH1hmlfsNLujHe9dQEia/7MAJYdzMSi19JtchUHjmBA6XC/75dK55mzZH+RyieSg==", "dev": true }, + "node_modules/@types/number-to-words": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@types/number-to-words/-/number-to-words-1.2.2.tgz", + "integrity": "sha512-qNG5RJO5+37XRQ/O5VHTnZSNFfOixxsrRteMimQH2E0EmVzNOIvRjkePJjgI48qR7JwBBDPVe0KBF2k/F2Sj2Q==", + "dev": true + }, "node_modules/@types/parse-json": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.1.tgz", @@ -2651,6 +2678,12 @@ "dev": true, "peer": true }, + "node_modules/@types/pluralize": { + "version": "0.0.32", + "resolved": "https://registry.npmjs.org/@types/pluralize/-/pluralize-0.0.32.tgz", + "integrity": "sha512-exDkoRIkWJlbRDRmtYDbI3ZUE28HwBwHe5VKn4mvpvMW7qIRDHO6URItErBsBSX7J8/PrDLSOHCcbUMFXwA6CA==", + "dev": true + }, "node_modules/@types/qs": { "version": "6.9.9", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.9.tgz", @@ -2753,6 +2786,34 @@ "vue": "^3.2.25" } }, + "node_modules/@volar/language-core": { + "version": "1.10.9", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-1.10.9.tgz", + "integrity": "sha512-QXHMX7CeXLqXwvC7nbr6iZ3zrqgKdJ9f6g1B211eZBnvaBki2ds0+Kz8cprUiulVuMQEPJNhDfuh8Vym1gxHRQ==", + "dev": true, + "dependencies": { + "@volar/source-map": "1.10.9" + } + }, + "node_modules/@volar/source-map": { + "version": "1.10.9", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-1.10.9.tgz", + "integrity": "sha512-ul8yGO9nCxy6UedVuo0VsfKMLZzr39N1rgbtnYTGP5C554EDcUix6K/HDurhVdPHEDIw1yhXltLZZQKi3NrTvA==", + "dev": true, + "dependencies": { + "muggle-string": "^0.3.1" + } + }, + "node_modules/@volar/typescript": { + "version": "1.10.9", + "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-1.10.9.tgz", + "integrity": "sha512-5jLB46mCQLJqLII/qDLgfyHSq1cesjwuJQIa2GNWd7LPLSpX5vzo3jfQLWc/gyo3up2fQFrlRJK2kgY5REtwuQ==", + "dev": true, + "dependencies": { + "@volar/language-core": "1.10.9", + "path-browserify": "^1.0.1" + } + }, "node_modules/@vue/cli-overlay": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/@vue/cli-overlay/-/cli-overlay-5.0.8.tgz", @@ -2952,36 +3013,36 @@ "dev": true }, "node_modules/@vue/compiler-core": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.3.6.tgz", - "integrity": "sha512-2JNjemwaNwf+MkkatATVZi7oAH1Hx0B04DdPH3ZoZ8vKC1xZVP7nl4HIsk8XYd3r+/52sqqoz9TWzYc3yE9dqA==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.3.7.tgz", + "integrity": "sha512-pACdY6YnTNVLXsB86YD8OF9ihwpolzhhtdLVHhBL6do/ykr6kKXNYABRtNMGrsQXpEXXyAdwvWWkuTbs4MFtPQ==", "dependencies": { "@babel/parser": "^7.23.0", - "@vue/shared": "3.3.6", + "@vue/shared": "3.3.7", "estree-walker": "^2.0.2", "source-map-js": "^1.0.2" } }, "node_modules/@vue/compiler-dom": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.3.6.tgz", - "integrity": "sha512-1MxXcJYMHiTPexjLAJUkNs/Tw2eDf2tY3a0rL+LfuWyiKN2s6jvSwywH3PWD8bKICjfebX3GWx2Os8jkRDq3Ng==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.3.7.tgz", + "integrity": "sha512-0LwkyJjnUPssXv/d1vNJ0PKfBlDoQs7n81CbO6Q0zdL7H1EzqYRrTVXDqdBVqro0aJjo/FOa1qBAPVI4PGSHBw==", "dependencies": { - "@vue/compiler-core": "3.3.6", - "@vue/shared": "3.3.6" + "@vue/compiler-core": "3.3.7", + "@vue/shared": "3.3.7" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.3.6.tgz", - "integrity": "sha512-/Kms6du2h1VrXFreuZmlvQej8B1zenBqIohP0690IUBkJjsFvJxY0crcvVRJ0UhMgSR9dewB+khdR1DfbpArJA==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.3.7.tgz", + "integrity": "sha512-7pfldWy/J75U/ZyYIXRVqvLRw3vmfxDo2YLMwVtWVNew8Sm8d6wodM+OYFq4ll/UxfqVr0XKiVwti32PCrruAw==", "dependencies": { "@babel/parser": "^7.23.0", - "@vue/compiler-core": "3.3.6", - "@vue/compiler-dom": "3.3.6", - "@vue/compiler-ssr": "3.3.6", - "@vue/reactivity-transform": "3.3.6", - "@vue/shared": "3.3.6", + "@vue/compiler-core": "3.3.7", + "@vue/compiler-dom": "3.3.7", + "@vue/compiler-ssr": "3.3.7", + "@vue/reactivity-transform": "3.3.7", + "@vue/shared": "3.3.7", "estree-walker": "^2.0.2", "magic-string": "^0.30.5", "postcss": "^8.4.31", @@ -2989,12 +3050,12 @@ } }, "node_modules/@vue/compiler-ssr": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.3.6.tgz", - "integrity": "sha512-QTIHAfDCHhjXlYGkUg5KH7YwYtdUM1vcFl/FxFDlD6d0nXAmnjizka3HITp8DGudzHndv2PjKVS44vqqy0vP4w==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.3.7.tgz", + "integrity": "sha512-TxOfNVVeH3zgBc82kcUv+emNHo+vKnlRrkv8YvQU5+Y5LJGJwSNzcmLUoxD/dNzv0bhQ/F0s+InlgV0NrApJZg==", "dependencies": { - "@vue/compiler-dom": "3.3.6", - "@vue/shared": "3.3.6" + "@vue/compiler-dom": "3.3.7", + "@vue/shared": "3.3.7" } }, "node_modules/@vue/component-compiler-utils": { @@ -3072,61 +3133,109 @@ "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.5.1.tgz", "integrity": "sha512-+KpckaAQyfbvshdDW5xQylLni1asvNSGme1JFs8I1+/H5pHEhqUKMEQD/qn3Nx5+/nycBq11qAEi8lk+LXI2dA==" }, + "node_modules/@vue/language-core": { + "version": "1.8.22", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-1.8.22.tgz", + "integrity": "sha512-bsMoJzCrXZqGsxawtUea1cLjUT9dZnDsy5TuZ+l1fxRMzUGQUG9+Ypq4w//CqpWmrx7nIAJpw2JVF/t258miRw==", + "dev": true, + "dependencies": { + "@volar/language-core": "~1.10.5", + "@volar/source-map": "~1.10.5", + "@vue/compiler-dom": "^3.3.0", + "@vue/shared": "^3.3.0", + "computeds": "^0.0.1", + "minimatch": "^9.0.3", + "muggle-string": "^0.3.1", + "vue-template-compiler": "^2.7.14" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@vue/language-core/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@vue/language-core/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@vue/reactivity": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.3.6.tgz", - "integrity": "sha512-gtChAumfQz5lSy5jZXfyXbKrIYPf9XEOrIr6rxwVyeWVjFhJwmwPLtV6Yis+M9onzX++I5AVE9j+iPH60U+B8Q==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.3.7.tgz", + "integrity": "sha512-cZNVjWiw00708WqT0zRpyAgduG79dScKEPYJXq2xj/aMtk3SKvL3FBt2QKUlh6EHBJ1m8RhBY+ikBUzwc7/khg==", "dependencies": { - "@vue/shared": "3.3.6" + "@vue/shared": "3.3.7" } }, "node_modules/@vue/reactivity-transform": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.3.6.tgz", - "integrity": "sha512-RlJl4dHfeO7EuzU1iJOsrlqWyJfHTkJbvYz/IOJWqu8dlCNWtxWX377WI0VsbAgBizjwD+3ZjdnvSyyFW1YVng==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.3.7.tgz", + "integrity": "sha512-APhRmLVbgE1VPGtoLQoWBJEaQk4V8JUsqrQihImVqKT+8U6Qi3t5ATcg4Y9wGAPb3kIhetpufyZ1RhwbZCIdDA==", "dependencies": { "@babel/parser": "^7.23.0", - "@vue/compiler-core": "3.3.6", - "@vue/shared": "3.3.6", + "@vue/compiler-core": "3.3.7", + "@vue/shared": "3.3.7", "estree-walker": "^2.0.2", "magic-string": "^0.30.5" } }, "node_modules/@vue/runtime-core": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.3.6.tgz", - "integrity": "sha512-qp7HTP1iw1UW2ZGJ8L3zpqlngrBKvLsDAcq5lA6JvEXHmpoEmjKju7ahM9W2p/h51h0OT5F2fGlP/gMhHOmbUA==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.3.7.tgz", + "integrity": "sha512-LHq9du3ubLZFdK/BP0Ysy3zhHqRfBn80Uc+T5Hz3maFJBGhci1MafccnL3rpd5/3wVfRHAe6c+PnlO2PAavPTQ==", "dependencies": { - "@vue/reactivity": "3.3.6", - "@vue/shared": "3.3.6" + "@vue/reactivity": "3.3.7", + "@vue/shared": "3.3.7" } }, "node_modules/@vue/runtime-dom": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.3.6.tgz", - "integrity": "sha512-AoX3Cp8NqMXjLbIG9YR6n/pPLWE9TiDdk6wTJHFnl2GpHzDFH1HLBC9wlqqQ7RlnvN3bVLpzPGAAH00SAtOxHg==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.3.7.tgz", + "integrity": "sha512-PFQU1oeJxikdDmrfoNQay5nD4tcPNYixUBruZzVX/l0eyZvFKElZUjW4KctCcs52nnpMGO6UDK+jF5oV4GT5Lw==", "dependencies": { - "@vue/runtime-core": "3.3.6", - "@vue/shared": "3.3.6", + "@vue/runtime-core": "3.3.7", + "@vue/shared": "3.3.7", "csstype": "^3.1.2" } }, "node_modules/@vue/server-renderer": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.3.6.tgz", - "integrity": "sha512-kgLoN43W4ERdZ6dpyy+gnk2ZHtcOaIr5Uc/WUP5DRwutgvluzu2pudsZGoD2b7AEJHByUVMa9k6Sho5lLRCykw==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.3.7.tgz", + "integrity": "sha512-UlpKDInd1hIZiNuVVVvLgxpfnSouxKQOSE2bOfQpBuGwxRV/JqqTCyyjXUWiwtVMyeRaZhOYYqntxElk8FhBhw==", "dependencies": { - "@vue/compiler-ssr": "3.3.6", - "@vue/shared": "3.3.6" + "@vue/compiler-ssr": "3.3.7", + "@vue/shared": "3.3.7" }, "peerDependencies": { - "vue": "3.3.6" + "vue": "3.3.7" } }, "node_modules/@vue/shared": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.6.tgz", - "integrity": "sha512-Xno5pEqg8SVhomD0kTSmfh30ZEmV/+jZtyh39q6QflrjdJCXah5lrnOLi9KB6a5k5aAHXMXjoMnxlzUkCNfWLQ==" + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.7.tgz", + "integrity": "sha512-N/tbkINRUDExgcPTBvxNkvHGu504k8lzlNQRITVnm6YjOjwa4r0nnbd4Jb01sNpur5hAllyRJzSK5PvB9PPwRg==" }, "node_modules/@vue/vue-loader-v15": { "name": "vue-loader", @@ -3362,9 +3471,9 @@ } }, "node_modules/acorn": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", - "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -3384,9 +3493,9 @@ } }, "node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.0.tgz", + "integrity": "sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA==", "dev": true, "peer": true, "engines": { @@ -3696,13 +3805,13 @@ } }, "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.5.tgz", - "integrity": "sha512-Q6CdATeAvbScWPNLB8lzSO7fgUVBkQt6zLgNlfyeCr/EQaEQR+bWiBYYPYAFyE528BMjRhL+1QBMOI4jc/c5TA==", + "version": "0.8.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.6.tgz", + "integrity": "sha512-leDIc4l4tUgU7str5BWLS2h8q2N4Nf6lGZP6UrNDxdtfF2g69eJ5L0H7S8A5Ln/arfFAfHor5InAdZuIOwZdgQ==", "dev": true, "dependencies": { "@babel/helper-define-polyfill-provider": "^0.4.3", - "core-js-compat": "^3.32.2" + "core-js-compat": "^3.33.1" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" @@ -4043,9 +4152,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001553", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001553.tgz", - "integrity": "sha512-N0ttd6TrFfuqKNi+pMgWJTb9qrdJu4JSpgPFLe/lrD19ugC6fZgF0pUewRowDwzdDnb9V41mFcdlYgl/PyKf4A==", + "version": "1.0.30001558", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001558.tgz", + "integrity": "sha512-/Et7DwLqpjS47JPEcz6VnxU9PwcIdVi0ciLXRWBQdj1XFye68pSQYpV0QtPTfUKWuOaEig+/Vez2l74eDc1tPQ==", "dev": true, "funding": [ { @@ -4411,6 +4520,12 @@ "dev": true, "peer": true }, + "node_modules/computeds": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/computeds/-/computeds-0.0.1.tgz", + "integrity": "sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==", + "dev": true + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -4512,9 +4627,9 @@ } }, "node_modules/core-js-compat": { - "version": "3.33.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.33.1.tgz", - "integrity": "sha512-6pYKNOgD/j/bkC5xS5IIg6bncid3rfrI42oBH1SQJbsmYPKF7rhzcFzYCcxYMmNQQ0rCEB8WqpW7QHndOggaeQ==", + "version": "3.33.2", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.33.2.tgz", + "integrity": "sha512-axfo+wxFVxnqf8RvxTzoAlzW4gRoacrHeoFlc9n0x50+7BEyZL/Rt3hicaED1/CEd7I6tPCPVUYcJwCMO5XUYw==", "dev": true, "dependencies": { "browserslist": "^4.22.1" @@ -4911,6 +5026,12 @@ "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==" }, + "node_modules/de-indent": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", + "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==", + "dev": true + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -5336,9 +5457,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.563", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.563.tgz", - "integrity": "sha512-dg5gj5qOgfZNkPNeyKBZQAQitIQ/xwfIDmEQJHCbXaD9ebTZxwJXUsDYcBlAvZGZLi+/354l35J1wkmP6CqYaw==", + "version": "1.4.570", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.570.tgz", + "integrity": "sha512-5GxH0PLSIfXKOUMMHMCT4M0olwj1WwAxsQHzVW5Vh3kbsvGw8b4k7LHQmTLC2aRhsgFzrF57XJomca4XLc/WHA==", "dev": true }, "node_modules/emoji-regex": { @@ -6364,7 +6485,6 @@ "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true, - "peer": true, "bin": { "he": "bin/he" } @@ -6668,14 +6788,6 @@ "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==" }, - "node_modules/immutable": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz", - "integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==", - "dev": true, - "optional": true, - "peer": true - }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -7201,9 +7313,9 @@ } }, "node_modules/jiti": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.20.0.tgz", - "integrity": "sha512-3TV69ZbrvV6U5DfQimop50jE9Dl6J8O1ja1dvBbMba/sZ3YBEQqJ2VZRoQPVnhlzjNtU1vaXRZVrVjU4qtm8yA==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", + "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", "bin": { "jiti": "bin/jiti.js" } @@ -8008,6 +8120,12 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "node_modules/muggle-string": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.3.1.tgz", + "integrity": "sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==", + "dev": true + }, "node_modules/multicast-dns": { "version": "7.2.5", "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", @@ -8520,6 +8638,12 @@ "tslib": "^2.0.3" } }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -9495,9 +9619,9 @@ } }, "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "engines": { "node": ">=6" @@ -9965,25 +10089,6 @@ "dev": true, "peer": true }, - "node_modules/sass": { - "version": "1.69.4", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.69.4.tgz", - "integrity": "sha512-+qEreVhqAy8o++aQfCJwp0sklr2xyEzkm9Pp/Igu9wNPoe7EZEQ8X/MBvvXggI2ql607cxKg/RKOwDj6pp2XDA==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "chokidar": ">=3.0.0 <4.0.0", - "immutable": "^4.0.0", - "source-map-js": ">=0.6.2 <2.0.0" - }, - "bin": { - "sass": "sass.js" - }, - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/schema-utils": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", @@ -10011,12 +10116,13 @@ "peer": true }, "node_modules/selfsigned": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.1.1.tgz", - "integrity": "sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", "dev": true, "peer": true, "dependencies": { + "@types/node-forge": "^1.3.0", "node-forge": "^1" }, "engines": { @@ -10737,19 +10843,19 @@ } }, "node_modules/tailwindcss": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.3.tgz", - "integrity": "sha512-A0KgSkef7eE4Mf+nKJ83i75TMyq8HqY3qmFIJSWy8bNt0v1lG7jUcpGpoTFxAwYcWOphcTBLPPJg+bDfhDf52w==", + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.5.tgz", + "integrity": "sha512-5SEZU4J7pxZgSkv7FP1zY8i2TIAOooNZ1e/OGtxIEv6GltpoiXUqWvLy89+a10qYTB1N5Ifkuw9lqQkN9sscvA==", "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", "chokidar": "^3.5.3", "didyoumean": "^1.2.2", "dlv": "^1.1.3", - "fast-glob": "^3.2.12", + "fast-glob": "^3.3.0", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", - "jiti": "^1.18.2", + "jiti": "^1.19.1", "lilconfig": "^2.1.0", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", @@ -10834,9 +10940,9 @@ } }, "node_modules/terser": { - "version": "5.22.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.22.0.tgz", - "integrity": "sha512-hHZVLgRA2z4NWcN6aS5rQDc+7Dcy58HOf2zbYwmFcQ+ua3h6eEFf5lIDKTzbWwlazPyOZsFQO8V80/IjVNExEw==", + "version": "5.23.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.23.0.tgz", + "integrity": "sha512-Iyy83LN0uX9ZZLCX4Qbu5JiHiWjOCTwrmM9InWOzVeM++KNWEsqV4YgN9U9E8AlohQ6Gs42ztczlWOG/lwDAMA==", "dev": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -11116,6 +11222,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "devOptional": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/unbox-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", @@ -11132,9 +11251,9 @@ } }, "node_modules/undici-types": { - "version": "5.25.3", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.25.3.tgz", - "integrity": "sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA==", + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "dev": true }, "node_modules/unicode-canonical-property-names-ecmascript": { @@ -11365,9 +11484,9 @@ } }, "node_modules/vite-plugin-pwa": { - "version": "0.16.5", - "resolved": "https://registry.npmjs.org/vite-plugin-pwa/-/vite-plugin-pwa-0.16.5.tgz", - "integrity": "sha512-Ahol4dwhMP2UHPQXkllSlXbihOaDFnvBIDPmAxoSZ1EObBUJGP4CMRyCyAVkIHjd6/H+//vH0DM2ON+XxHr81g==", + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/vite-plugin-pwa/-/vite-plugin-pwa-0.16.6.tgz", + "integrity": "sha512-bQPDOWvhPMwydMoWqohXvIzvrq4X8iuCF+q95qEiaM4yC0ybViGKWMnWcpWp0vcnoLk7QvxHDlK65KUZvqB3Sg==", "dev": true, "dependencies": { "debug": "^4.3.4", @@ -11383,21 +11502,21 @@ "url": "https://github.com/sponsors/antfu" }, "peerDependencies": { - "vite": "^3.1.0 || ^4.0.0", + "vite": "^3.1.0 || ^4.0.0 || ^5.0.0-0", "workbox-build": "^7.0.0", "workbox-window": "^7.0.0" } }, "node_modules/vue": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.3.6.tgz", - "integrity": "sha512-jJIDETeWJnoY+gfn4ZtMPMS5KtbP4ax+CT4dcQFhTnWEk8xMupFyQ0JxL28nvT/M4+p4a0ptxaV2WY0LiIxvRg==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.3.7.tgz", + "integrity": "sha512-YEMDia1ZTv1TeBbnu6VybatmSteGOS3A3YgfINOfraCbf85wdKHzscD6HSS/vB4GAtI7sa1XPX7HcQaJ1l24zA==", "dependencies": { - "@vue/compiler-dom": "3.3.6", - "@vue/compiler-sfc": "3.3.6", - "@vue/runtime-dom": "3.3.6", - "@vue/server-renderer": "3.3.6", - "@vue/shared": "3.3.6" + "@vue/compiler-dom": "3.3.7", + "@vue/compiler-sfc": "3.3.7", + "@vue/runtime-dom": "3.3.7", + "@vue/server-renderer": "3.3.7", + "@vue/shared": "3.3.7" }, "peerDependencies": { "typescript": "*" @@ -11496,6 +11615,16 @@ "dev": true, "peer": true }, + "node_modules/vue-template-compiler": { + "version": "2.7.15", + "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.15.tgz", + "integrity": "sha512-yQxjxMptBL7UAog00O8sANud99C6wJF+7kgbcwqkvA38vCGF7HWE66w0ZFnS/kX5gSoJr/PQ4/oS3Ne2pW37Og==", + "dev": true, + "dependencies": { + "de-indent": "^1.0.2", + "he": "^1.2.0" + } + }, "node_modules/vue-template-es2015-compiler": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz", @@ -11503,6 +11632,56 @@ "dev": true, "peer": true }, + "node_modules/vue-tsc": { + "version": "1.8.22", + "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-1.8.22.tgz", + "integrity": "sha512-j9P4kHtW6eEE08aS5McFZE/ivmipXy0JzrnTgbomfABMaVKx37kNBw//irL3+LlE3kOo63XpnRigyPC3w7+z+A==", + "dev": true, + "dependencies": { + "@volar/typescript": "~1.10.5", + "@vue/language-core": "1.8.22", + "semver": "^7.5.4" + }, + "bin": { + "vue-tsc": "bin/vue-tsc.js" + }, + "peerDependencies": { + "typescript": "*" + } + }, + "node_modules/vue-tsc/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/vue-tsc/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/vue-tsc/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "node_modules/watchpack": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", diff --git a/package.json b/package.json index 267e1fd..e8c1766 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "healthrecord", "private": true, - "version": "0.4.1", + "version": "0.4.2", "type": "module", "scripts": { "dev": "vite", @@ -33,16 +33,24 @@ "yjs": "^13.6.8" }, "devDependencies": { + "@types/file-saver": "^2.0.6", + "@types/number-to-words": "^1.2.2", + "@types/pluralize": "^0.0.32", "@vitejs/plugin-vue": "^4.2.3", "@vue/cli-plugin-router": "~5.0.0", "autoprefixer": "^10.4.15", "postcss": "^8.4.29", "tailwindcss": "^3.3.3", + "typescript": "^5.2.2", "vite": "^4.4.5", - "vite-plugin-pwa": "^0.16.5" + "vite-plugin-pwa": "^0.16.5", + "vue-tsc": "^1.8.20" }, "prettier": { "singleQuote": true, - "printWidth": 100 + "printWidth": 100, + "arrowParens": "avoid", + "bracketSameLine": true, + "htmlWhitespaceSensitivity": "ignore" } } diff --git a/src/classes/insight.js b/src/classes/insight.ts similarity index 59% rename from src/classes/insight.js rename to src/classes/insight.ts index 7ea9513..c0c7598 100644 --- a/src/classes/insight.js +++ b/src/classes/insight.ts @@ -1,32 +1,19 @@ -import { record } from "../store/record"; -import pluralize from "pluralize"; +import { record } from '@stores/record'; +import pluralize from 'pluralize'; import n2w from 'number-to-words'; class Insight { - - /** - * The analyzed object - */ - #object; - /** * The analyzed person */ - person; + person: Person; - /** - * @param {import("../typedefs").Vital | import("../typedefs").Measurement} object Object to analyze - * @param {import("../typedefs").Person} person Person to analyze - */ - constructor(object, person) { - this.#object = object - this.person = person + constructor(person: Person) { + this.person = person; } /** * Get the text insight for this object - * - * @returns {string} */ get description() { return ''; @@ -34,49 +21,46 @@ class Insight { } export class VitalInsight extends Insight { - /** * The analyzed vital */ - vital; + vital: Vital; - /** - * @param {import("../typedefs").Vital} object Vital to be analyzed - * @param {import("../typedefs").Person} person Person to analyze - */ - constructor(object, person) { - super(object, person); + constructor(object: Vital, person: Person) { + super(person); this.vital = object; } /** * Get person's measurements for this vital - * - * @returns {import("../typedefs").Measurement[]} */ get #measurements() { + if (!record.value) return []; if (!this.vital.low && !this.vital.high) return []; return record.value.measurements - .filter(measurement => measurement.personId === this.person.id && measurement.vitalId === this.vital.id) + .filter( + measurement => + measurement.personId === this.person.id && measurement.vitalId === this.vital.id + ) .toSorted((a, b) => b.date - a.date); } /** * Measurements whose recent values are below the low value for this vital - * - * @returns {import("../typedefs").Measurement[]} */ get #lowMeasurements() { - return this.#measurements.slice(0, 5).filter(measurement => measurement.value < this.vital.low); + if (!this.vital.low) return []; + const low = this.vital.low; + return this.#measurements.slice(0, 5).filter(measurement => measurement.value < low); } - + /** * Measurements whose recent values are above the high value for this vital - * - * @returns {import("../typedefs").Measurement[]} */ get #highMeasurements() { - return this.#measurements.slice(0, 5).filter(measurement => measurement.value > this.vital.high); + if (!this.vital.high) return []; + const high = this.vital.high; + return this.#measurements.slice(0, 5).filter(measurement => measurement.value > high); } /** @@ -104,11 +88,11 @@ export class VitalInsight extends Insight { /** * Get the text description of this vital's Insight - * + * * @returns {string} */ get description() { - if (!this.level) return null; + if (!this.level) return ''; let text = `Recent ${this.vital.name} measurements`; @@ -124,9 +108,15 @@ export class VitalInsight extends Insight { break; } - if ( (this.level === 'low' && this.trend === 1) || (this.level === 'high' && this.trend === -1) ) { + if ( + (this.level === 'low' && this.trend === 1) || + (this.level === 'high' && this.trend === -1) + ) { text += ', but are'; - } else if ( (this.level === 'low' && this.trend === -1) || (this.level === 'high' && this.trend === 1) ) { + } else if ( + (this.level === 'low' && this.trend === -1) || + (this.level === 'high' && this.trend === 1) + ) { text += ' and are'; } else if (this.trend !== 0) { text += ' and are'; @@ -146,21 +136,23 @@ export class VitalInsight extends Insight { } export class VitalInsightsSummary { + person: Person; - /** - * @param {import("../typedefs").Person} person Person whose vitals are being analyzed - */ - constructor(person) { - this.person = person + constructor(person: Person) { + this.person = person; } get #measurements() { + if (!record.value) return []; return record.value.measurements.filter(measurement => measurement.personId === this.person.id); } get #vitals() { + if (!record.value) return []; + let vitalIds = this.#measurements.map(measurement => measurement.vitalId); vitalIds = [...new Set(vitalIds)]; + return record.value.vitals.filter(vital => vitalIds.includes(vital.id)); } @@ -195,15 +187,30 @@ export class VitalInsightsSummary { const vitalLevelsDescriptions = []; if (this.#normalLevelVitals.length > 0) { - vitalLevelsDescriptions.push(`${n2w.toWords(this.#normalLevelVitals.length)} ${pluralize('vital', this.#normalLevelVitals.length)} ${pluralize('has', this.#normalLevelVitals.length)} normal levels`); + vitalLevelsDescriptions.push( + `${n2w.toWords(this.#normalLevelVitals.length)} ${pluralize( + 'vital', + this.#normalLevelVitals.length + )} ${pluralize('has', this.#normalLevelVitals.length)} normal levels` + ); } if (this.#lowLevelVitals.length > 0) { - vitalLevelsDescriptions.push(`${n2w.toWords(this.#lowLevelVitals.length)} ${pluralize('vital', this.#lowLevelVitals.length)} ${pluralize('has', this.#lowLevelVitals.length)} low levels`); + vitalLevelsDescriptions.push( + `${n2w.toWords(this.#lowLevelVitals.length)} ${pluralize( + 'vital', + this.#lowLevelVitals.length + )} ${pluralize('has', this.#lowLevelVitals.length)} low levels` + ); } if (this.#highLevelVitals.length > 0) { - vitalLevelsDescriptions.push(`${n2w.toWords(this.#highLevelVitals.length)} ${pluralize('vital', this.#highLevelVitals.length)} ${pluralize('has', this.#highLevelVitals.length)} high levels`); + vitalLevelsDescriptions.push( + `${n2w.toWords(this.#highLevelVitals.length)} ${pluralize( + 'vital', + this.#highLevelVitals.length + )} ${pluralize('has', this.#highLevelVitals.length)} high levels` + ); } // Trends @@ -213,11 +220,21 @@ export class VitalInsightsSummary { const vitalTrendsDescriptions = []; if (this.#upwardTrendVitals.length > 0) { - vitalTrendsDescriptions.push(`${n2w.toWords(this.#upwardTrendVitals.length)} ${pluralize('vital', this.#upwardTrendVitals.length)} ${pluralize('is', this.#upwardTrendVitals.length)} trending upward`); + vitalTrendsDescriptions.push( + `${n2w.toWords(this.#upwardTrendVitals.length)} ${pluralize( + 'vital', + this.#upwardTrendVitals.length + )} ${pluralize('is', this.#upwardTrendVitals.length)} trending upward` + ); } if (this.#downwardTrendVitals.length > 0) { - vitalTrendsDescriptions.push(`${n2w.toWords(this.#downwardTrendVitals.length)} ${pluralize('vital', this.#downwardTrendVitals.length)} ${pluralize('is', this.#downwardTrendVitals.length)} trending downward`); + vitalTrendsDescriptions.push( + `${n2w.toWords(this.#downwardTrendVitals.length)} ${pluralize( + 'vital', + this.#downwardTrendVitals.length + )} ${pluralize('is', this.#downwardTrendVitals.length)} trending downward` + ); } const trendsDescription = vitalTrendsDescriptions.join(', '); @@ -230,38 +247,34 @@ export class VitalInsightsSummary { /** * Calculate non-parametric regression - * - * @param {Array} values Values to consider - * @param {Number} bandwidth Bandwidth - * @returns {Number[]} */ -const nonParametricRegression = (values, bandwidth = 0.5) => { +const nonParametricRegression = (values: number[], bandwidth = 0.5) => { // Create a kernel function. - const kernelFunction = (x) => Math.exp(-(Math.pow(x, 2)) / (2 * Math.pow(bandwidth, 2))); + const kernelFunction = (x: number) => Math.exp(-Math.pow(x, 2) / (2 * Math.pow(bandwidth, 2))); // Calculate the weighted average of the data points. - const predictedValues = values.map((yi, i) => { - const weights = values.map((yj, j) => kernelFunction((yi - yj) / bandwidth)); - return values.reduce((acc, yj, j) => acc + weights[j] * yj, 0) / weights.reduce((acc, w) => acc + w, 0); + const predictedValues = values.map(yi => { + const weights = values.map(yj => kernelFunction((yi - yj) / bandwidth)); + return ( + values.reduce((acc, yj, j) => acc + weights[j] * yj, 0) / + weights.reduce((acc, w) => acc + w, 0) + ); }); // Return the predicted values. return predictedValues; -} +}; /** * Calculate trend from values - * - * @param {Array} values Values to consider - * @param {Number} bandwidth Bandwidth - * @returns {1 | 0 | -1} */ -const nonParametricRegressionTrend = (values, bandwidth = 0.5) => { +const nonParametricRegressionTrend = (values: number[], bandwidth = 0.5) => { // Calculate the predicted values using the nonParametricRegression function. const predictedValues = nonParametricRegression(values, bandwidth); // Calculate the slope of the predicted values. - const slope = (predictedValues[predictedValues.length - 1] - predictedValues[0]) / predictedValues.length; + const slope = + (predictedValues[predictedValues.length - 1] - predictedValues[0]) / predictedValues.length; // Return 1 if the trend is up, 0 if the trend is flat, and -1 if the trend is down. if (slope > 0) { @@ -271,4 +284,4 @@ const nonParametricRegressionTrend = (values, bandwidth = 0.5) => { } else { return 0; } -} \ No newline at end of file +}; diff --git a/src/classes/logEntry.js b/src/classes/logEntry.js deleted file mode 100644 index 200c2b7..0000000 --- a/src/classes/logEntry.js +++ /dev/null @@ -1,89 +0,0 @@ -import { people } from "../store/people"; -import { vitals } from "../store/vitals" -import { notes } from "../store/notes"; - -export class LogEntry { - - /** - * - * @param {string} personId - The ID of the {@link Person} associated with this log entry. - */ - constructor(personId) { - this.personId = personId; - this.objectId = this.personId; - } - - /** @type {number} */ - date; - - /** @type {string} */ - objectId; - - get person() { - return people.value.find(person => person.id === this.personId); - } - - get personName() { - return this.person.firstName; - } - - get note() { - return null; - } - - get description() { - return null; - } -} - -export class MeasurementLogEntry extends LogEntry { - - /** - * Create LogEntry from {@link Measurement} - * @param {import("../typedefs").Measurement} measurement - The {@link Measurement} associated with this log entry. - */ - constructor(measurement) { - super(measurement.personId); - this.measurement = measurement; - this.objectId = this.measurement.id; - this.date = this.measurement.created || this.measurement.date; - } - - get vital() { - return vitals.value.find(vital => vital.id === this.measurement.vitalId); - } - - get note() { - if (!this.measurement.noteId) return null; - return notes.value.find(note => note.id === this.measurement.noteId) - } - - get description() { - return `${this.vital.name} measurement`; - } -} - -export class NoteLogEntry extends LogEntry { - - /** @type {import("../typedefs").Note} */ - #note - - /** - * Create LogEntry from {@link Note} - * @param {import("../typedefs").Note} note - The {@link Note} associated with this log entry - */ - constructor(note) { - super(note.personId); - this.#note = note; - this.objectId = note.id; - this.date = note.created; - } - - get description() { - return 'note'; - } - - get note() { - return this.#note - } -} \ No newline at end of file diff --git a/src/classes/logEntry.ts b/src/classes/logEntry.ts new file mode 100644 index 0000000..4906fa9 --- /dev/null +++ b/src/classes/logEntry.ts @@ -0,0 +1,76 @@ +import { people } from '@stores/people'; +import { vitals } from '@stores/vitals'; +import { notes } from '@stores/notes'; + +export class LogEntry { + date: number; + + objectId: string; + + personId: string; + + constructor(personId: string) { + this.personId = personId; + this.objectId = this.personId; + this.date = Date.now(); + } + + get person() { + return people.value.find(person => person.id === this.personId); + } + + get personName() { + return this.person?.firstName; + } + + get note(): Note | undefined { + return undefined; + } + + get description(): string | undefined { + return undefined; + } +} + +export class MeasurementLogEntry extends LogEntry { + measurement: Measurement; + + constructor(measurement: Measurement) { + super(measurement.personId); + this.measurement = measurement; + this.objectId = this.measurement.id; + this.date = this.measurement.date; + } + + get vital() { + return vitals.value.find(vital => vital.id === this.measurement.vitalId); + } + + get note() { + if (!this.measurement.noteId) return undefined; + return notes.value.find(note => note.id === this.measurement.noteId); + } + + get description() { + return `${this.vital?.name} measurement`; + } +} + +export class NoteLogEntry extends LogEntry { + #note: Note; + + constructor(note: Note) { + super(note.personId); + this.#note = note; + this.objectId = note.id; + this.date = note.date; + } + + get description() { + return 'note'; + } + + get note() { + return this.#note; + } +} diff --git a/src/components/Dashboard/Dashboard.vue b/src/components/Dashboard/Dashboard.vue index 20f073c..d78b73e 100644 --- a/src/components/Dashboard/Dashboard.vue +++ b/src/components/Dashboard/Dashboard.vue @@ -1,8 +1,8 @@ - diff --git a/src/components/Interface/LowHighBadge.vue b/src/components/Interface/LowHighBadge.vue new file mode 100644 index 0000000..b64ec95 --- /dev/null +++ b/src/components/Interface/LowHighBadge.vue @@ -0,0 +1,23 @@ + + + diff --git a/src/components/Layout.vue b/src/components/Layout.vue index b9fed82..817d632 100644 --- a/src/components/Layout.vue +++ b/src/components/Layout.vue @@ -1,4 +1,4 @@ - + + diff --git a/src/components/Logbook/LogbookListItem.vue b/src/components/Logbook/LogbookListItem.vue new file mode 100644 index 0000000..0db1bae --- /dev/null +++ b/src/components/Logbook/LogbookListItem.vue @@ -0,0 +1,33 @@ + + + diff --git a/src/components/Logbook/MeasurementLogItem.vue b/src/components/Logbook/MeasurementLogItem.vue new file mode 100644 index 0000000..5ae38f3 --- /dev/null +++ b/src/components/Logbook/MeasurementLogItem.vue @@ -0,0 +1,29 @@ + + + diff --git a/src/components/Person/Logbook/NoteLogItem.vue b/src/components/Logbook/NoteLogItem.vue similarity index 50% rename from src/components/Person/Logbook/NoteLogItem.vue rename to src/components/Logbook/NoteLogItem.vue index dca8501..51c4574 100644 --- a/src/components/Person/Logbook/NoteLogItem.vue +++ b/src/components/Logbook/NoteLogItem.vue @@ -1,17 +1,14 @@ - diff --git a/src/components/Measurements/Create.vue b/src/components/Measurements/Create.vue index d0cbe6f..67e5b69 100644 --- a/src/components/Measurements/Create.vue +++ b/src/components/Measurements/Create.vue @@ -1,47 +1,44 @@ -