diff --git a/.example.env b/.example.env index 3e71d08fae3..04055c21c5e 100644 --- a/.example.env +++ b/.example.env @@ -47,9 +47,6 @@ REACT_SENTRY_DSN= # Sentry environment (default: staging) REACT_SENTRY_ENVIRONMENT= -# Sample format file paths -REACT_SAMPLE_FORMAT_ASSET_IMPORT=/asset-import-template.xlsx - # Camera feed, still watching idle timeout (in seconds; default: 180) REACT_STILL_WATCHING_IDLE_TIMEOUT= diff --git a/.github/workflows/label-merge-conflict.yml b/.github/workflows/label-merge-conflict.yml index 5c3293e48ce..fd92df00d25 100644 --- a/.github/workflows/label-merge-conflict.yml +++ b/.github/workflows/label-merge-conflict.yml @@ -24,6 +24,6 @@ jobs: wait_ms: 15000 detect_merge_changes: false conflict_comment: | - Conflicts have been detected against the base branch. Please rebase your branch against the base branch. + Conflicts have been detected against the base branch. Please merge the base branch into your branch. cc: @${author} > _See: https://docs.ohc.network/docs/contributing#how-to-resolve-merge-conflicts_ diff --git a/care.config.ts b/care.config.ts index 0bd759fd246..6813a60b331 100644 --- a/care.config.ts +++ b/care.config.ts @@ -64,11 +64,6 @@ const careConfig = { reCaptchaSiteKey: env.REACT_RECAPTCHA_SITE_KEY || "6LdvxuQUAAAAADDWVflgBqyHGfq-xmvNJaToM0pN", - sampleFormats: { - assetImport: - env.REACT_SAMPLE_FORMAT_ASSET_IMPORT || "/asset-import-template.xlsx", - }, - wartimeShifting: boolean("REACT_WARTIME_SHIFTING"), stillWatching: { diff --git a/package-lock.json b/package-lock.json index 50f6ad0bb3b..e8c36ab78e0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,8 +11,6 @@ "license": "MIT", "dependencies": { "@fontsource/figtree": "^5.1.1", - "@googlemaps/react-wrapper": "^1.1.42", - "@googlemaps/typescript-guards": "^2.0.3", "@headlessui/react": "^2.2.0", "@hello-pangea/dnd": "^17.0.0", "@hookform/resolvers": "^3.10.0", @@ -42,7 +40,6 @@ "@tanstack/react-query": "^5.64.1", "@tanstack/react-query-devtools": "^5.64.2", "@vitejs/plugin-react": "^4.3.4", - "@yudiel/react-qr-scanner": "^2.1.0", "bowser": "^2.11.0", "browser-image-compression": "^2.0.2", "browserslist": "^4.24.4", @@ -54,10 +51,6 @@ "cypress": "^14.0.0", "date-fns": "^3.6.0", "dayjs": "^1.11.13", - "echarts": "^5.5.1", - "echarts-for-react": "^3.0.2", - "events": "^3.3.0", - "hi-profiles": "^1.1.0", "html-to-image": "^1.11.11", "i18next": "^24.2.1", "i18next-browser-languagedetector": "^8.0.2", @@ -65,7 +58,6 @@ "i18next-resources-to-backend": "^1.2.1", "input-otp": "^1.4.2", "libphonenumber-js": "^1.11.18", - "lodash-es": "^4.17.21", "lucide-react": "^0.474.0", "markdown-it": "^14.1.0", "next-themes": "^0.4.3", @@ -78,7 +70,6 @@ "react-google-recaptcha": "^3.1.0", "react-hook-form": "^7.53.2", "react-i18next": "^15.2.0", - "react-infinite-scroll-component": "^6.1.0", "react-intersection-observer": "^9.15.1", "react-pdf": "^9.2.1", "react-phone-number-input": "^3.4.11", @@ -88,8 +79,6 @@ "tailwind-merge": "^3.0.0", "tailwindcss-animate": "^1.0.7", "use-keyboard-shortcut": "^1.1.6", - "vaul": "^1.1.1", - "xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz", "zod": "^3.23.8" }, "devDependencies": { @@ -4032,30 +4021,6 @@ "integrity": "sha512-WlauXrKAtHOadYti0l/dA2ez4lK7Yw2iQccv3ulmkMXgfKOdMjngob2AkIVxFyNLcvorVhh/Eq77DiWSGoR2bw==", "license": "OFL-1.1" }, - "node_modules/@googlemaps/js-api-loader": { - "version": "1.16.8", - "resolved": "https://registry.npmjs.org/@googlemaps/js-api-loader/-/js-api-loader-1.16.8.tgz", - "integrity": "sha512-CROqqwfKotdO6EBjZO/gQGVTbeDps5V7Mt9+8+5Q+jTg5CRMi3Ii/L9PmV3USROrt2uWxtGzJHORmByxyo9pSQ==", - "license": "Apache-2.0" - }, - "node_modules/@googlemaps/react-wrapper": { - "version": "1.1.42", - "resolved": "https://registry.npmjs.org/@googlemaps/react-wrapper/-/react-wrapper-1.1.42.tgz", - "integrity": "sha512-rZBqreFTpHmNgB4vYBFkWPjXrjg3HDRmCSQFugCJ7wT45B+Ueh3pzjSvvHHGGIqtSJ3nS5VXRqBhRgpanP0saw==", - "license": "Apache-2.0", - "dependencies": { - "@googlemaps/js-api-loader": "^1.13.2" - }, - "peerDependencies": { - "react": ">=16.8.0" - } - }, - "node_modules/@googlemaps/typescript-guards": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@googlemaps/typescript-guards/-/typescript-guards-2.0.3.tgz", - "integrity": "sha512-3iHuO8H0jPehftsMK0kgyJzPYU/g/oiTRw+wu/yltqSZ7wJPt3vfsJHkPiuRpQjbnnWygX+T3mkRGyK/eyZ/lw==", - "license": "Apache-2.0" - }, "node_modules/@headlessui/react": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-2.2.0.tgz", @@ -6522,12 +6487,6 @@ "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", "license": "MIT" }, - "node_modules/@types/dom-webcodecs": { - "version": "0.1.11", - "resolved": "https://registry.npmjs.org/@types/dom-webcodecs/-/dom-webcodecs-0.1.11.tgz", - "integrity": "sha512-yPEZ3z7EohrmOxbk/QTAa0yonMFkNkjnVXqbGb7D4rMr+F1dGQ8ZUFxXkyLLJuiICPejZ0AZE9Rrk9wUCczx4A==", - "license": "MIT" - }, "node_modules/@types/dompurify": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-3.2.0.tgz", @@ -6539,12 +6498,6 @@ "dompurify": "*" } }, - "node_modules/@types/emscripten": { - "version": "1.39.13", - "resolved": "https://registry.npmjs.org/@types/emscripten/-/emscripten-1.39.13.tgz", - "integrity": "sha512-cFq+fO/isvhvmuP/+Sl4K4jtU6E23DoivtbO4r50e3odaxAiVdbfSYRDdJ4gCdxx+3aRjhphS5ZMwIH4hFy/Cw==", - "license": "MIT" - }, "node_modules/@types/estree": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", @@ -7377,20 +7330,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@yudiel/react-qr-scanner": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@yudiel/react-qr-scanner/-/react-qr-scanner-2.1.0.tgz", - "integrity": "sha512-O3832Qk8YU+vnLO+tsJalfQcXRZ1pOB9l6WrI3OdwpxkQEzukpT48M6Hc2vUUe1rFE6qapQnV3RGRFNM0S7CHw==", - "license": "MIT", - "dependencies": { - "barcode-detector": "^2.3.1", - "webrtc-adapter": "9.0.1" - }, - "peerDependencies": { - "react": "^17 || ^18 || ^19", - "react-dom": "^17 || ^18 || ^19" - } - }, "node_modules/acorn": { "version": "8.14.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", @@ -7926,16 +7865,6 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "license": "MIT" }, - "node_modules/barcode-detector": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/barcode-detector/-/barcode-detector-2.3.1.tgz", - "integrity": "sha512-D9KEtrquS1tmBZduxBZl8qublIKnRrFqD8TAHDYcLCyrHQBo+vitIxmjMJ61LvXjXyAMalOlO7q0Oh/9Rl2PbQ==", - "license": "MIT", - "dependencies": { - "@types/dom-webcodecs": "0.1.11", - "zxing-wasm": "1.3.4" - } - }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -9555,36 +9484,6 @@ "safer-buffer": "^2.1.0" } }, - "node_modules/echarts": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/echarts/-/echarts-5.6.0.tgz", - "integrity": "sha512-oTbVTsXfKuEhxftHqL5xprgLoc0k7uScAwtryCgWF6hPYFLRwOUHiFmHGCBKP5NPFNkDVopOieyUqYGH8Fa3kA==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "2.3.0", - "zrender": "5.6.1" - } - }, - "node_modules/echarts-for-react": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/echarts-for-react/-/echarts-for-react-3.0.2.tgz", - "integrity": "sha512-DRwIiTzx8JfwPOVgGttDytBqdp5VzCSyMRIxubgU/g2n9y3VLUmF2FK7Icmg/sNVkv4+rktmrLN9w22U2yy3fA==", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "size-sensor": "^1.0.1" - }, - "peerDependencies": { - "echarts": "^3.0.0 || ^4.0.0 || ^5.0.0", - "react": "^15.0.0 || >=16.0.0" - } - }, - "node_modules/echarts/node_modules/tslib": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", - "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==", - "license": "0BSD" - }, "node_modules/ejs": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", @@ -10399,15 +10298,6 @@ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", "license": "MIT" }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "license": "MIT", - "engines": { - "node": ">=0.8.x" - } - }, "node_modules/execa": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", @@ -10492,6 +10382,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, "license": "MIT" }, "node_modules/fast-diff": { @@ -11398,16 +11289,6 @@ "node": ">= 0.4" } }, - "node_modules/hi-profiles": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/hi-profiles/-/hi-profiles-1.1.0.tgz", - "integrity": "sha512-xlxkjsjT9dfsent7RnRbBgFpDx++jtErU7Iupnp/GgcDyEFlFbWNiEaxEGepKlZ91Y1XjbhtBzzKRg+7LGQEfg==", - "dependencies": { - "react": "^18.2.0", - "react-dom": "^18.2.0", - "react-icons": "^4.11.0" - } - }, "node_modules/hoist-non-react-statics": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", @@ -13241,12 +13122,6 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "license": "MIT" }, - "node_modules/lodash-es": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", - "license": "MIT" - }, "node_modules/lodash.castarray": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz", @@ -15310,27 +15185,6 @@ } } }, - "node_modules/react-icons": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.12.0.tgz", - "integrity": "sha512-IBaDuHiShdZqmfc/TwHu6+d6k2ltNCf3AszxNmjJc1KUfXdEeRJOKyNvLmAHaarhzGmTSVygNdyu8/opXv2gaw==", - "license": "MIT", - "peerDependencies": { - "react": "*" - } - }, - "node_modules/react-infinite-scroll-component": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/react-infinite-scroll-component/-/react-infinite-scroll-component-6.1.0.tgz", - "integrity": "sha512-SQu5nCqy8DxQWpnUVLx7V7b7LcA37aM7tvoWjTLZp1dk6EJibM5/4EJKzOnl07/BsM1Y40sKLuqjCwwH/xV0TQ==", - "license": "MIT", - "dependencies": { - "throttle-debounce": "^2.1.0" - }, - "peerDependencies": { - "react": ">=16.0.0" - } - }, "node_modules/react-intersection-observer": { "version": "9.15.1", "resolved": "https://registry.npmjs.org/react-intersection-observer/-/react-intersection-observer-9.15.1.tgz", @@ -16212,12 +16066,6 @@ "loose-envify": "^1.1.0" } }, - "node_modules/sdp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/sdp/-/sdp-3.2.0.tgz", - "integrity": "sha512-d7wDPgDV3DDiqulJjKiV2865wKsJ34YI+NDREbm+FySq6WuKOikwyNQcm+doLAZ1O6ltdO0SeKle2xMpN3Brgw==", - "license": "MIT" - }, "node_modules/semver": { "version": "7.6.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", @@ -16503,12 +16351,6 @@ "simple-concat": "^1.0.0" } }, - "node_modules/size-sensor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/size-sensor/-/size-sensor-1.0.2.tgz", - "integrity": "sha512-2NCmWxY7A9pYKGXNBfteo4hy14gWu47rg5692peVMst6lQLPKrVjhY+UTEsPI5ceFRJSl3gVgMYaUi/hKuaiKw==", - "license": "ISC" - }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -17390,15 +17232,6 @@ "node": ">=0.8" } }, - "node_modules/throttle-debounce": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-2.3.0.tgz", - "integrity": "sha512-H7oLPV0P7+jgvrk+6mwwwBDmxTaxnu9HMXmloNLXwnNO0ZxZ31Orah2n8lU1eMPvsaowP2CX+USCgyovXfdOFQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/throttleit": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.1.tgz", @@ -18113,19 +17946,6 @@ "node": ">= 0.10" } }, - "node_modules/vaul": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vaul/-/vaul-1.1.2.tgz", - "integrity": "sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-dialog": "^1.1.1" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc" - } - }, "node_modules/verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", @@ -18971,19 +18791,6 @@ "node": ">=12" } }, - "node_modules/webrtc-adapter": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-9.0.1.tgz", - "integrity": "sha512-1AQO+d4ElfVSXyzNVTOewgGT/tAomwwztX/6e3totvyyzXPvXIIuUUjAmyZGbKBKbZOXauuJooZm3g6IuFuiNQ==", - "license": "BSD-3-Clause", - "dependencies": { - "sdp": "^3.2.0" - }, - "engines": { - "node": ">=6.0.0", - "npm": ">=3.10.0" - } - }, "node_modules/whatwg-encoding": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", @@ -19728,18 +19535,6 @@ } } }, - "node_modules/xlsx": { - "version": "0.20.3", - "resolved": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz", - "integrity": "sha512-oLDq3jw7AcLqKWH2AhCpVTZl8mf6X2YReP+Neh0SJUzV/BdZYjth94tG5toiMB1PPrYtxOCfaoUCkvtuH+3AJA==", - "license": "Apache-2.0", - "bin": { - "xlsx": "bin/xlsx.njs" - }, - "engines": { - "node": ">=0.8" - } - }, "node_modules/xml-name-validator": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", @@ -19817,30 +19612,6 @@ "funding": { "url": "https://github.com/sponsors/colinhacks" } - }, - "node_modules/zrender": { - "version": "5.6.1", - "resolved": "https://registry.npmjs.org/zrender/-/zrender-5.6.1.tgz", - "integrity": "sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag==", - "license": "BSD-3-Clause", - "dependencies": { - "tslib": "2.3.0" - } - }, - "node_modules/zrender/node_modules/tslib": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", - "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==", - "license": "0BSD" - }, - "node_modules/zxing-wasm": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/zxing-wasm/-/zxing-wasm-1.3.4.tgz", - "integrity": "sha512-9l0QymyATF19FmI92QHe7Dayb+BUN7P7zFAt5iDgTnUf0dFWokz6GVA/W9EepjW5q8s3e89fIE/7uxpX27yqEQ==", - "license": "MIT", - "dependencies": { - "@types/emscripten": "^1.39.13" - } } } } diff --git a/package.json b/package.json index f99ce8c1621..df2e0678b34 100644 --- a/package.json +++ b/package.json @@ -49,8 +49,6 @@ }, "dependencies": { "@fontsource/figtree": "^5.1.1", - "@googlemaps/react-wrapper": "^1.1.42", - "@googlemaps/typescript-guards": "^2.0.3", "@headlessui/react": "^2.2.0", "@hello-pangea/dnd": "^17.0.0", "@hookform/resolvers": "^3.10.0", @@ -80,7 +78,6 @@ "@tanstack/react-query": "^5.64.1", "@tanstack/react-query-devtools": "^5.64.2", "@vitejs/plugin-react": "^4.3.4", - "@yudiel/react-qr-scanner": "^2.1.0", "bowser": "^2.11.0", "browser-image-compression": "^2.0.2", "browserslist": "^4.24.4", @@ -92,10 +89,6 @@ "cypress": "^14.0.0", "date-fns": "^3.6.0", "dayjs": "^1.11.13", - "echarts": "^5.5.1", - "echarts-for-react": "^3.0.2", - "events": "^3.3.0", - "hi-profiles": "^1.1.0", "html-to-image": "^1.11.11", "i18next": "^24.2.1", "i18next-browser-languagedetector": "^8.0.2", @@ -103,7 +96,6 @@ "i18next-resources-to-backend": "^1.2.1", "input-otp": "^1.4.2", "libphonenumber-js": "^1.11.18", - "lodash-es": "^4.17.21", "lucide-react": "^0.474.0", "markdown-it": "^14.1.0", "next-themes": "^0.4.3", @@ -116,7 +108,6 @@ "react-google-recaptcha": "^3.1.0", "react-hook-form": "^7.53.2", "react-i18next": "^15.2.0", - "react-infinite-scroll-component": "^6.1.0", "react-intersection-observer": "^9.15.1", "react-pdf": "^9.2.1", "react-phone-number-input": "^3.4.11", @@ -126,8 +117,6 @@ "tailwind-merge": "^3.0.0", "tailwindcss-animate": "^1.0.7", "use-keyboard-shortcut": "^1.1.6", - "vaul": "^1.1.1", - "xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz", "zod": "^3.23.8" }, "devDependencies": { diff --git a/public/asset-import-template.xlsx b/public/asset-import-template.xlsx deleted file mode 100644 index 9d56afe3c3c..00000000000 Binary files a/public/asset-import-template.xlsx and /dev/null differ diff --git a/src/common/schemaParser.ts b/src/common/schemaParser.ts deleted file mode 100644 index d4c2d89e1ee..00000000000 --- a/src/common/schemaParser.ts +++ /dev/null @@ -1,197 +0,0 @@ -export interface SingleKeySchema { - parent?: string; - prop: string; - type: string; - oneOf?: string[]; - required?: boolean; - parse?: (value: any) => any; -} - -export interface SchemaType { - [key: string]: SingleKeySchema; -} - -export interface DataWithError { - [key: string]: { - value: any; - error?: string; - }; -} - -export interface ParsedData { - [key: string]: any; -} - -export interface ErrorData { - index: number; - key: string; - error: string; -} - -interface parseDataProps { - dataWithErrors: DataWithError[]; - parsedData: ParsedData[]; - errors: ErrorData[]; -} - -const validateAndParse = ( - key: string, - value: any, - schema: SingleKeySchema, -): { [key: string]: { value: any; error?: string } } => { - try { - const parsedValue = schema?.parse?.(value) ?? value; - const expectedType = schema?.type; - - if ( - (parsedValue === undefined || parsedValue === null) && - !schema?.required - ) { - return { [key]: { value: parsedValue } }; - } - - if (typeof parsedValue !== expectedType && expectedType !== "any") { - return { - [key]: { - value: parsedValue, - error: `${key} should be of type ${expectedType}`, - }, - }; - } - - if (schema?.oneOf && !schema?.oneOf.includes(parsedValue)) { - return { - [key]: { - value: parsedValue, - error: `${key} should be one of the ${schema?.oneOf}`, - }, - }; - } - - if ( - schema?.required && - (parsedValue === undefined || parsedValue === null) - ) { - return { - [key]: { value: parsedValue, error: `${key} is required` }, - }; - } - - return { [key]: { value: parsedValue } }; - } catch (error: any) { - return { [key]: { value, error: error.message } }; - } -}; - -const parseDataWithSchema = ( - data: any[], - schema: SchemaType, -): parseDataProps => { - const errors: ErrorData[] = []; - const parsedData: ParsedData[] = []; - const dataWithErrors: DataWithError[] = data.map((item, index) => { - return Object.keys(schema).reduce((acc, key) => { - const { - [key]: { value, error }, - } = validateAndParse(key, item[key], schema[key]); - const parsedRow = { [schema[key].prop]: value }; - if (error) { - errors.push({ index, key, error }); - } - const prop = schema[key].prop || key; - - if (schema[key].parent) { - const indexKey = schema[key].parent || key; - acc[indexKey] = acc[indexKey] || {}; - acc[indexKey][prop] = { value, error }; - - if (!parsedData[index]) { - parsedData[index] = {}; - } - - parsedData[index][indexKey] = { - ...(parsedData[index][indexKey] || {}), - [prop]: value, - }; - } else { - acc[prop] = { value, error }; - - if (!parsedData[index]) { - parsedData[index] = {}; - } - - parsedData[index] = { ...parsedData[index], ...parsedRow }; - } - - return acc; - }, {} as ParsedData); - }); - - return { dataWithErrors, parsedData, errors }; -}; -/** - * This function takes in an array of JSON data and a schema and returns the parsed data and the data with errors - * @param dataArray The array of JSON data to be parsed - * @param schema The schema to validate and parse the data against - * @returns An object containing the parsed data, data with errors, and data without errors - * @example - * const data = [ - * { name: "Ram", age: 25 }, - * { name: "Raj", age: "30" }, - * { name: "Sam", age: 35 }, - * ]; - * - * const schema = { - * name: { prop: "name", type: "string", required: true }, - * age: { prop: "age", type: "number", required: true , parse: (value) => { - * if(value < 0 || value > 100) throw new Error("age should be between 0 and 100"); - * return value; - * }, - * }; - * - * const { dataWithErrors, parsedData, ParsedDataWithOutErrors, errors } = schemaParser(data, schema); - * - * dataWithErrors => [ - * { name: { value: "Ram" }, age: { value: 25 } }, - * { name: { value: "Raj" }, age: { value: "30", error: "age should be of type number" } }, - * { name: { value: "Sam" }, age: { value: 35 } }, - * ] - * - * parsedData => [ - * { name: "Ram", age: 25 }, - * { name: "Raj", age: "30" }, - * { name: "Sam", age: 35 }, - * ] - * - * ParsedDataWithOutErrors => [ - * { name: "Ram", age: 25 }, - * { name: "Sam", age: 35 }, - * ] - * - * errors => [ - * { index: 1, key: "age", error: "age should be of type number" } - * ] - * - */ -const schemaParser = ( - dataArray: any[], - schema: SchemaType, -): parseDataProps & { ParsedDataWithOutErrors: ParsedData[] } => { - const { dataWithErrors, parsedData, errors } = parseDataWithSchema( - dataArray, - schema, - ); - - const ParsedDataWithOutErrors = parsedData.filter((item, index) => { - return !Object.values(dataWithErrors[index]).some((item) => item.error); - }); - - return { - dataWithErrors, - parsedData, - ParsedDataWithOutErrors, - errors, - }; -}; - -export default schemaParser; diff --git a/src/common/utils.tsx b/src/common/utils.tsx deleted file mode 100644 index a2f4a681037..00000000000 --- a/src/common/utils.tsx +++ /dev/null @@ -1,15 +0,0 @@ -export const deepEqual = (x: any, y: any): boolean => { - if (x === y) return true; - - if (typeof x == "object" && x != null && typeof y == "object" && y != null) { - if (Object.keys(x).length != Object.keys(y).length) return false; - - Object.keys(x).forEach((key) => { - if (!deepEqual(x[key], y[key])) return false; - }); - - return true; - } - - return false; -}; diff --git a/src/components/Common/AvatarEditable.tsx b/src/components/Common/AvatarEditable.tsx deleted file mode 100644 index bbf3ab6c35f..00000000000 --- a/src/components/Common/AvatarEditable.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import { useTranslation } from "react-i18next"; - -import { cn } from "@/lib/utils"; - -import CareIcon from "@/CAREUI/icons/CareIcon"; - -import { Avatar, AvatarProps } from "@/components/Common/Avatar"; - -interface AvatarEditableProps extends AvatarProps { - id?: string; - editable?: boolean; - onClick?: () => void; -} - -const AvatarEditable: React.FC = ({ - id, - colors: propColors, - name, - imageUrl, - className, - editable = true, - onClick, -}) => { - const { t } = useTranslation(); - return ( -
- - - {editable && ( -
- - {t(imageUrl ? "edit" : "upload")} -
- )} -
- ); -}; - -export default AvatarEditable; diff --git a/src/components/Common/ExcelFIleDragAndDrop.tsx b/src/components/Common/ExcelFIleDragAndDrop.tsx deleted file mode 100644 index 1689d5b3d21..00000000000 --- a/src/components/Common/ExcelFIleDragAndDrop.tsx +++ /dev/null @@ -1,285 +0,0 @@ -import { useEffect, useRef, useState } from "react"; -import { useTranslation } from "react-i18next"; -import { toast } from "sonner"; -import * as XLSX from "xlsx"; - -import CareIcon from "@/CAREUI/icons/CareIcon"; - -import { Button } from "@/components/ui/button"; - -import ExcelViewer from "@/components/Common/ExcelViewer"; - -import useDragAndDrop from "@/hooks/useDragAndDrop"; - -import schemaParser, { - ErrorData, - ParsedData, - SchemaType, -} from "@/common/schemaParser"; - -interface Props { - handleSubmit: (data: any) => void; - loading: boolean; - sampleLink?: string; - schema: SchemaType; - onClose?: () => void; - setIsValid?: (value: boolean) => void; -} - -export default function ExcelFileDragAndDrop({ - handleSubmit, - loading = false, - sampleLink, - schema, - onClose, - setIsValid, -}: Props) { - const [fileData, setFileData] = useState([]); - const [errors, setErrors] = useState([]); - const [preview, setPreview] = useState(false); - const [selectedFile, setSelectedFile] = useState(); - const [validData, setValidData] = useState([]); - const [parsedData, setParsedData] = useState([]); - - const { t } = useTranslation(); - const fileInputRef = useRef(null); - - const closeModal = () => { - setSelectedFile(undefined); - setFileData([]); - onClose?.(); - }; - - const onSelectFile = (file: Blob) => { - setSelectedFile(file); - dragProps.setFileDropError(""); - try { - const reader = new FileReader(); - - reader.onload = (e) => { - const result = (e.target as FileReader).result; - const workbook = XLSX.read(result, { - type: "binary", - cellDates: true, - }); - const worksheetName = workbook.SheetNames[0]; - const worksheet = workbook.Sheets[worksheetName]; - const data = XLSX.utils.sheet_to_json(worksheet, { defval: "" }); - //converts the date to string - data.forEach((row: any) => { - Object.keys(row).forEach((key) => { - if (row[key] instanceof Date) { - row[key] = row[key].toISOString().split("T")[0]; - } - }); - }); - - setFileData(data); - }; - reader.onerror = () => { - throw new Error("Error in reading file"); - }; - - reader.readAsBinaryString(file); - } catch (e: any) { - toast.error(e.message); - } - }; - - useEffect(() => { - if (fileData.length !== 0) { - const { errors, parsedData, ParsedDataWithOutErrors } = schemaParser( - fileData, - schema, - ); - setErrors(errors); - setParsedData(parsedData); - setValidData(ParsedDataWithOutErrors); - if (ParsedDataWithOutErrors.length !== 0) { - setIsValid?.(true); - } - } - }, [fileData]); - - const dragProps = useDragAndDrop(); - const onDrop = (e: React.DragEvent) => { - e.preventDefault(); - dragProps.setDragOver(false); - - const droppedFiles = e?.dataTransfer?.files; - - if (!droppedFiles || droppedFiles.length === 0) { - return dragProps.setFileDropError("Please drop a file to upload!"); - } - - const droppedFile = droppedFiles[0]; - const fileTypes = [ - "vnd.ms-excel", - "text/csv", - "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", - ]; - - if (!fileTypes.includes(droppedFile?.type)) { - dragProps.setFileDropError("Please drop a Excel / CSV file to upload!"); - setSelectedFile(null); - return; - } - onSelectFile(droppedFile); - }; - - return ( -
- {preview && ( - setPreview(false)} - selectedFile={selectedFile} - fileData={fileData} - errors={errors} - handleSubmit={handleSubmit} - parsedData={parsedData} - /> - )} -
!selectedFile && fileInputRef.current?.click()} - className={`mb-8 mt-5 flex flex-1 flex-col items-center justify-center rounded-lg border-[3px] border-dashed px-3 py-6 ${ - dragProps.dragOver ? "border-primary-500" : "border-secondary-500" - } ${dragProps.fileDropError !== "" ? "border-red-500" : ""}`} - > - -

- {dragProps.fileDropError !== "" && dragProps.fileDropError} - {!selectedFile && "Drag & drop xlsx/csv file to upload"} -

- { - const files = e.target.files; - if (files && files.length > 0) { - onSelectFile(files[0]); - } - }} - className="hidden" - ref={fileInputRef} - /> - {selectedFile && ( -
-

- {selectedFile.name} - {(selectedFile.size / 1024).toFixed(2)} KB -

- { - setSelectedFile(undefined); - setFileData([]); - setErrors([]); - setValidData([]); - if (setIsValid) setIsValid(false); - dragProps.setDragOver(false); - dragProps.setFileDropError(""); - }} - > - cancel - -
- )} - {selectedFile ? ( - <> - setPreview(true)} - > - - - ) : ( - e.stopPropagation()} - > - - )} -
-
- -
- - -
-
- ); -} diff --git a/src/components/Common/ExcelViewer.tsx b/src/components/Common/ExcelViewer.tsx deleted file mode 100644 index e77dc0132da..00000000000 --- a/src/components/Common/ExcelViewer.tsx +++ /dev/null @@ -1,287 +0,0 @@ -import { t } from "i18next"; -import { ReactNode, useEffect, useState } from "react"; - -import CareIcon from "@/CAREUI/icons/CareIcon"; - -import { Button } from "@/components/ui/button"; - -import DialogModal from "@/components/Common/Dialog"; -import Pagination from "@/components/Common/Pagination"; - -import { ParsedData } from "@/common/schemaParser"; - -type FilePreviewProps = { - title?: ReactNode; - description?: ReactNode; - show: boolean; - onClose: () => void; - selectedFile: { name: string }; - fileData?: any[]; - downloadURL?: string; - className?: string; - errors?: { index: number; key: string; error: string }[]; - handleSubmit: (data: ParsedData[]) => void; - showCheckbox?: boolean; - parsedData: ParsedData[]; -}; - -const ExcelViewer = ({ - title = "File Preview", - description, - show, - onClose, - className, - selectedFile, - fileData, - downloadURL, - showCheckbox = true, - handleSubmit, - parsedData, - errors = [], -}: FilePreviewProps) => { - const [currentPage, setCurrentPage] = useState(1); - const [rowsPerPage, setRowsPerPage] = useState(10); - const [selectedRowsData, setSelectedRowsData] = useState([]); - - const initialSelectedRows = fileData - ? (fileData - .map((_, i) => i) - .filter((i) => !errors.some((err) => err.index === i)) ?? []) - : []; - - const [selectedRows, setSelectedRows] = - useState(initialSelectedRows); - - const handleClose = () => { - onClose?.(); - }; - - useEffect(() => { - setSelectedRowsData(selectedRows.map((rowIndex) => parsedData[rowIndex])); - }, [selectedRows]); - - return ( - { - handleClose(); - }} - title={title} - description={description} - show={show} - > - <> -
-

- {selectedFile.name} -

-
- {downloadURL && downloadURL.length > 0 && ( - - )} -
-
-
-
- {fileData && fileData[0] ? ( -
- - - - {showCheckbox && ( - - )} - {Object.keys(fileData[0]).map((key) => ( - - ))} - - - - {fileData - .slice( - (currentPage - 1) * rowsPerPage, - (currentPage - 1) * rowsPerPage + rowsPerPage, - ) - .map((row, rowIndex) => { - const currentRowIndex = - rowIndex + (currentPage - 1) * rowsPerPage; - return ( - - {showCheckbox && ( - - )} - {Object.entries(row).map( - ([key, value]: [string, any], colIndex) => { - const error = errors.find( - (err) => - err.index === currentRowIndex && - err.key == key, - ); - - return ( - <> - - - ); - }, - )} - - ); - })} - -
- 0} - onChange={(e) => { - if (e.target.checked) { - setSelectedRows(fileData.map((_, i) => i)); - } else { - setSelectedRows([]); - } - }} - /> - - {key} -
- {errors.some( - (err) => err.index === currentRowIndex, - ) ? ( - err.index === currentRowIndex, - ) - .map((err) => err.key) - .join(", ")} - `} - > - - - ) : ( - err.index === currentRowIndex, - )} - onChange={() => { - if ( - selectedRows.includes(currentRowIndex) - ) { - setSelectedRows( - selectedRows.filter( - (i) => i !== currentRowIndex, - ), - ); - } else { - setSelectedRows([ - ...selectedRows, - currentRowIndex, - ]); - } - }} - className="disabled:bg-danger-500" - /> - )} - - {String(value)} -
-
- ) : ( -
No data found
- )} -
- {fileData && fileData.length > 5 && ( -
-

- Showing {currentPage * rowsPerPage - rowsPerPage + 1} to{" "} - {currentPage * rowsPerPage > fileData.length - ? fileData.length - : currentPage * rowsPerPage}{" "} - of {fileData.length} entries -

- {rowsPerPage < fileData.length && ( - { - setCurrentPage(page); - setRowsPerPage(rowsPerPage); - }} - /> - )} - -
- )} -
- -
- - -
-
- ); -}; - -export default ExcelViewer; diff --git a/src/components/Common/Export.tsx b/src/components/Common/Export.tsx deleted file mode 100644 index 6f9c6bdbb7d..00000000000 --- a/src/components/Common/Export.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import { useTranslation } from "react-i18next"; - -import { cn } from "@/lib/utils"; - -import CareIcon from "@/CAREUI/icons/CareIcon"; - -import { Button } from "@/components/ui/button"; - -import useExport from "@/hooks/useExport"; - -import request from "@/Utils/request/request"; -import { ApiRoute } from "@/Utils/request/types"; - -interface ExportButtonProps { - disabled?: boolean | undefined; - tooltip?: string | undefined; - tooltipClassName?: string; - type?: "csv" | "json"; - action?: Parameters["exportFile"]>[0]; - route?: ApiRoute; - parse?: (data: string) => string; - filenamePrefix: string; - className?: string; - variant?: "primary_gradient" | "secondary"; -} - -export const ExportButton = ({ - tooltipClassName = "tooltip-bottom -translate-x-7", - variant, - type = "csv", - className, - parse, - ...props -}: ExportButtonProps) => { - const { isExporting, exportFile } = useExport(); - const { t } = useTranslation(); - - return ( - <> - - - ); -}; diff --git a/src/components/Medicine/MedicationRequestTable/utils.ts b/src/components/Medicine/MedicationRequestTable/utils.ts deleted file mode 100644 index b32427c3a80..00000000000 --- a/src/components/Medicine/MedicationRequestTable/utils.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { MedicationRequest } from "@/types/emr/medicationRequest"; - -export function isMedicationDiscontinued(medicationRequest: MedicationRequest) { - return ["completed", "ended", "stopped", "cancelled"].includes( - medicationRequest.status!, - ); -} diff --git a/src/components/Patient/allergy/AllergyTable.tsx b/src/components/Patient/allergy/AllergyTable.tsx deleted file mode 100644 index 8aaf982a91c..00000000000 --- a/src/components/Patient/allergy/AllergyTable.tsx +++ /dev/null @@ -1,108 +0,0 @@ -import { - BeakerIcon, - CookingPotIcon, - HeartPulseIcon, - LeafIcon, -} from "lucide-react"; - -import { Badge } from "@/components/ui/badge"; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from "@/components/ui/table"; - -import { Avatar } from "@/components/Common/Avatar"; - -import { AllergyIntolerance } from "@/types/emr/allergyIntolerance/allergyIntolerance"; - -type AllergyCategory = "food" | "medication" | "environment" | "biologic"; - -const CATEGORY_ICONS: Record = { - food: , - medication: , - environment: , - biologic: , -}; - -interface AllergyTableProps { - allergies: AllergyIntolerance[]; - showHeader?: boolean; -} - -export function AllergyTable({ - allergies, - showHeader = true, -}: AllergyTableProps) { - return ( - - {showHeader && ( - - - - Substance - Status - Critical - Verification - Last Occurrence - By - - - )} - - {allergies.map((allergy, index) => ( - - - {allergy.category && - CATEGORY_ICONS[allergy.category as AllergyCategory]} - - - {allergy.code.display} - - - - {allergy.clinical_status} - - - - - {allergy.criticality} - - - - - {allergy.verification_status} - - - - {allergy.last_occurrence - ? new Date(allergy.last_occurrence).toLocaleDateString() - : "-"} - - - - - {allergy.created_by?.first_name} {allergy.created_by?.last_name} - - - {allergy.note && ( - - -
Notes
-
{allergy.note}
-
-
- )} -
- ))} -
-
- ); -} diff --git a/src/components/ui/chart.tsx b/src/components/ui/chart.tsx deleted file mode 100644 index 6ff21377000..00000000000 --- a/src/components/ui/chart.tsx +++ /dev/null @@ -1,363 +0,0 @@ -import * as React from "react"; -import * as RechartsPrimitive from "recharts"; - -import { cn } from "@/lib/utils"; - -// Format: { THEME_NAME: CSS_SELECTOR } -const THEMES = { light: "", dark: ".dark" } as const; - -export type ChartConfig = { - [_ in string]: { - label?: React.ReactNode; - icon?: React.ComponentType; - } & ( - | { color?: string; theme?: never } - | { color?: never; theme: Record } - ); -}; - -type ChartContextProps = { - config: ChartConfig; -}; - -const ChartContext = React.createContext(null); - -function useChart() { - const context = React.useContext(ChartContext); - - if (!context) { - throw new Error("useChart must be used within a "); - } - - return context; -} - -const ChartContainer = React.forwardRef< - HTMLDivElement, - React.ComponentProps<"div"> & { - config: ChartConfig; - children: React.ComponentProps< - typeof RechartsPrimitive.ResponsiveContainer - >["children"]; - } ->(({ id, className, children, config, ...props }, ref) => { - const uniqueId = React.useId(); - const chartId = `chart-${id || uniqueId.replace(/:/g, "")}`; - - return ( - -
- - - {children} - -
-
- ); -}); -ChartContainer.displayName = "Chart"; - -const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => { - const colorConfig = Object.entries(config).filter( - ([, config]) => config.theme || config.color, - ); - - if (!colorConfig.length) { - return null; - } - - return ( -