diff --git a/builder-frontend/index.html b/builder-frontend/index.html index ae8453f2..ec4849f2 100644 --- a/builder-frontend/index.html +++ b/builder-frontend/index.html @@ -4,13 +4,7 @@ - - Benefit Decision Toolkit + Benefit Decision Toolkit
diff --git a/builder-frontend/package-lock.json b/builder-frontend/package-lock.json index e78fdaa2..55003df5 100644 --- a/builder-frontend/package-lock.json +++ b/builder-frontend/package-lock.json @@ -16,13 +16,13 @@ "@kogito-tooling/kie-editors-standalone": "^0.16.0", "@solid-primitives/deep": "^0.3.3", "@solid-primitives/resource": "^0.4.2", + "@solidjs/meta": "^0.29.4", "@solidjs/router": "^0.15.3", "dmn-js": "^17.2.1", "fast-xml-parser": "^5.2.5", "firebase": "^11.9.1", "lodash.debounce": "^4.0.8", "lucide-solid": "^1.7.0", - "solid-bootstrap": "^1.0.21", "solid-js": "^1.9.5", "solid-toast": "^0.5.0", "vanilla-jsoneditor": "^3.10.0" @@ -30,6 +30,7 @@ "devDependencies": { "@tailwindcss/forms": "^0.5.10", "@tailwindcss/postcss": "^4.1.8", + "@tailwindcss/vite": "^4.1.18", "@types/json-schema": "^7.0.15", "autoprefixer": "^10.4.21", "postcss": "^8.5.4", @@ -261,14 +262,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/runtime": { - "version": "7.27.4", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.4.tgz", - "integrity": "sha512-t3yaEOuGu9NlIZ+hIeGbBjFtZT7j2cb2tg0fuaJKeGotchRjjLfrBA9Kwf8quhpP1EUuxModQg04q/mBwyg8uA==", - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/template": { "version": "7.27.2", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", @@ -1819,9 +1812,10 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", @@ -2110,15 +2104,6 @@ "resolved": "https://registry.npmjs.org/@patternfly/react-tokens/-/react-tokens-4.94.7.tgz", "integrity": "sha512-h+ducOLDMSxcuec3+YY3x+stM5ZUSnrl/lC/eVmjypil2El08NuE2MNEPMQWdhrod6VRRZFMNqZw/m82iv6U1A==" }, - "node_modules/@popperjs/core": { - "version": "2.11.8", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", - "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/popperjs" - } - }, "node_modules/@protobufjs/aspromise": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", @@ -2527,6 +2512,15 @@ "solid-js": "^1.6.12" } }, + "node_modules/@solidjs/meta": { + "version": "0.29.4", + "resolved": "https://registry.npmjs.org/@solidjs/meta/-/meta-0.29.4.tgz", + "integrity": "sha512-zdIWBGpR9zGx1p1bzIPqF5Gs+Ks/BH8R6fWhmUa/dcK1L2rUC8BAcZJzNRYBQv74kScf1TSOs0EY//Vd/I0V8g==", + "license": "MIT", + "peerDependencies": { + "solid-js": ">=1.8.4" + } + }, "node_modules/@solidjs/router": { "version": "0.15.3", "resolved": "https://registry.npmjs.org/@solidjs/router/-/router-0.15.3.tgz", @@ -2824,6 +2818,525 @@ "tailwindcss": "4.1.8" } }, + "node_modules/@tailwindcss/vite": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.18.tgz", + "integrity": "sha512-jVA+/UpKL1vRLg6Hkao5jldawNmRo7mQYrZtNHMIVpLfLhDml5nMRUo/8MwoX2vNXvnaXNNMedrMfMugAVX1nA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tailwindcss/node": "4.1.18", + "@tailwindcss/oxide": "4.1.18", + "tailwindcss": "4.1.18" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6 || ^7" + } + }, + "node_modules/@tailwindcss/vite/node_modules/@tailwindcss/node": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.18.tgz", + "integrity": "sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.4", + "enhanced-resolve": "^5.18.3", + "jiti": "^2.6.1", + "lightningcss": "1.30.2", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.1.18" + } + }, + "node_modules/@tailwindcss/vite/node_modules/@tailwindcss/oxide": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.18.tgz", + "integrity": "sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.1.18", + "@tailwindcss/oxide-darwin-arm64": "4.1.18", + "@tailwindcss/oxide-darwin-x64": "4.1.18", + "@tailwindcss/oxide-freebsd-x64": "4.1.18", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.18", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.18", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.18", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.18", + "@tailwindcss/oxide-linux-x64-musl": "4.1.18", + "@tailwindcss/oxide-wasm32-wasi": "4.1.18", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.18", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.18" + } + }, + "node_modules/@tailwindcss/vite/node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.18.tgz", + "integrity": "sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/vite/node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.18.tgz", + "integrity": "sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/vite/node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.18.tgz", + "integrity": "sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/vite/node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.18.tgz", + "integrity": "sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/vite/node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.18.tgz", + "integrity": "sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/vite/node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.18.tgz", + "integrity": "sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/vite/node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.18.tgz", + "integrity": "sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/vite/node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.18.tgz", + "integrity": "sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/vite/node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.18.tgz", + "integrity": "sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/vite/node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.18.tgz", + "integrity": "sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1", + "@emnapi/wasi-threads": "^1.1.0", + "@napi-rs/wasm-runtime": "^1.1.0", + "@tybys/wasm-util": "^0.10.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/vite/node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.18.tgz", + "integrity": "sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/vite/node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.18.tgz", + "integrity": "sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/vite/node_modules/lightningcss": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.2.tgz", + "integrity": "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.30.2", + "lightningcss-darwin-arm64": "1.30.2", + "lightningcss-darwin-x64": "1.30.2", + "lightningcss-freebsd-x64": "1.30.2", + "lightningcss-linux-arm-gnueabihf": "1.30.2", + "lightningcss-linux-arm64-gnu": "1.30.2", + "lightningcss-linux-arm64-musl": "1.30.2", + "lightningcss-linux-x64-gnu": "1.30.2", + "lightningcss-linux-x64-musl": "1.30.2", + "lightningcss-win32-arm64-msvc": "1.30.2", + "lightningcss-win32-x64-msvc": "1.30.2" + } + }, + "node_modules/@tailwindcss/vite/node_modules/lightningcss-darwin-arm64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.2.tgz", + "integrity": "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/vite/node_modules/lightningcss-darwin-x64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.2.tgz", + "integrity": "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/vite/node_modules/lightningcss-freebsd-x64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.2.tgz", + "integrity": "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/vite/node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.2.tgz", + "integrity": "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/vite/node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.2.tgz", + "integrity": "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/vite/node_modules/lightningcss-linux-arm64-musl": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.2.tgz", + "integrity": "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/vite/node_modules/lightningcss-linux-x64-gnu": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.2.tgz", + "integrity": "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/vite/node_modules/lightningcss-linux-x64-musl": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.2.tgz", + "integrity": "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/vite/node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.2.tgz", + "integrity": "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/vite/node_modules/lightningcss-win32-x64-msvc": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.2.tgz", + "integrity": "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/vite/node_modules/tailwindcss": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.18.tgz", + "integrity": "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -3528,15 +4041,6 @@ "resolved": "https://registry.npmjs.org/min-dash/-/min-dash-3.8.1.tgz", "integrity": "sha512-evumdlmIlg9mbRVPbC4F5FuRhNmcMS5pvuBUbqb1G9v09Ro0ImPEgz5n3khir83lFok1inKqVDjnKEg3GpDxQg==" }, - "node_modules/dom-helpers": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", - "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", - "dependencies": { - "@babel/runtime": "^7.8.7", - "csstype": "^3.0.2" - } - }, "node_modules/dom-iterator": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/dom-iterator/-/dom-iterator-1.0.2.tgz", @@ -3592,13 +4096,14 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "node_modules/enhanced-resolve": { - "version": "5.18.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz", - "integrity": "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==", + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz", + "integrity": "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==", "dev": true, + "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" + "tapable": "^2.3.0" }, "engines": { "node": ">=10.13.0" @@ -4219,10 +4724,11 @@ } }, "node_modules/jiti": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", - "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", "dev": true, + "license": "MIT", "bin": { "jiti": "lib/jiti-cli.mjs" } @@ -4373,6 +4879,27 @@ "lightningcss-win32-x64-msvc": "1.30.1" } }, + "node_modules/lightningcss-android-arm64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.30.2.tgz", + "integrity": "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/lightningcss-darwin-arm64": { "version": "1.30.1", "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz", @@ -4650,11 +5177,12 @@ } }, "node_modules/magic-string": { - "version": "0.30.17", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", - "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0" + "@jridgewell/sourcemap-codec": "^1.5.5" } }, "node_modules/marked": { @@ -5606,32 +6134,6 @@ "url": "https://opencollective.com/sinon" } }, - "node_modules/solid-bootstrap": { - "version": "1.0.21", - "resolved": "https://registry.npmjs.org/solid-bootstrap/-/solid-bootstrap-1.0.21.tgz", - "integrity": "sha512-B1+1qsdqrdQhl4xgmgrFRafxOM3xrnafxrC1scbOTYYJI2ido1XfoxtYyJ72W1eSHxYjm8eRGXdGTGdBJsGPpg==", - "dependencies": { - "dom-helpers": "^5.2.0", - "solid-bootstrap-core": "^2.0.0", - "solid-react-transition": "^1.0.11" - }, - "peerDependencies": { - "solid-js": ">=1.6.0" - } - }, - "node_modules/solid-bootstrap-core": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/solid-bootstrap-core/-/solid-bootstrap-core-2.0.0.tgz", - "integrity": "sha512-tw1me1iEvI+UzYRL2Gs53MP51WVwx785CU+6KQVGhaLESw3OoayeFLhe1CvUYb7kuskjtNGyAorZMdMwBJQIBA==", - "dependencies": { - "@popperjs/core": "^2.10.1", - "dom-helpers": "^5.2.0", - "solid-react-transition": "^1.0.8" - }, - "peerDependencies": { - "solid-js": ">=1.6.0" - } - }, "node_modules/solid-dismissible": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/solid-dismissible/-/solid-dismissible-0.1.1.tgz", @@ -5690,14 +6192,6 @@ "solid-js": "^1.8" } }, - "node_modules/solid-react-transition": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/solid-react-transition/-/solid-react-transition-1.0.11.tgz", - "integrity": "sha512-YMT7z6sOupCicDtX19156vbVOm3vCIgjVhPTybR9gLKiIPrDB2NDVqnQk4kpNCDZTOwSjLTOyUQw0xJnXgDg2A==", - "peerDependencies": { - "solid-js": ">=1.6.0" - } - }, "node_modules/solid-refresh": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/solid-refresh/-/solid-refresh-0.6.3.tgz", @@ -5890,12 +6384,17 @@ "dev": true }, "node_modules/tapable": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.2.tgz", - "integrity": "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, "node_modules/tar": { diff --git a/builder-frontend/package.json b/builder-frontend/package.json index 0c257b86..0e193f83 100644 --- a/builder-frontend/package.json +++ b/builder-frontend/package.json @@ -17,13 +17,13 @@ "@kogito-tooling/kie-editors-standalone": "^0.16.0", "@solid-primitives/deep": "^0.3.3", "@solid-primitives/resource": "^0.4.2", + "@solidjs/meta": "^0.29.4", "@solidjs/router": "^0.15.3", "dmn-js": "^17.2.1", "fast-xml-parser": "^5.2.5", "firebase": "^11.9.1", "lodash.debounce": "^4.0.8", "lucide-solid": "^1.7.0", - "solid-bootstrap": "^1.0.21", "solid-js": "^1.9.5", "solid-toast": "^0.5.0", "vanilla-jsoneditor": "^3.10.0" @@ -31,6 +31,7 @@ "devDependencies": { "@tailwindcss/forms": "^0.5.10", "@tailwindcss/postcss": "^4.1.8", + "@tailwindcss/vite": "^4.1.18", "@types/json-schema": "^7.0.15", "autoprefixer": "^10.4.21", "postcss": "^8.5.4", diff --git a/builder-frontend/src/assets/logos/bdt-logo-large-mono-dark.svg b/builder-frontend/public/logos/bdt-logo-large-mono-dark.svg similarity index 100% rename from builder-frontend/src/assets/logos/bdt-logo-large-mono-dark.svg rename to builder-frontend/public/logos/bdt-logo-large-mono-dark.svg diff --git a/builder-frontend/src/assets/logos/bdt-logo-large-mono-light.svg b/builder-frontend/public/logos/bdt-logo-large-mono-light.svg similarity index 100% rename from builder-frontend/src/assets/logos/bdt-logo-large-mono-light.svg rename to builder-frontend/public/logos/bdt-logo-large-mono-light.svg diff --git a/builder-frontend/src/assets/logos/bdt-logo-small-mono-light.svg b/builder-frontend/public/logos/bdt-logo-small-mono-light.svg similarity index 100% rename from builder-frontend/src/assets/logos/bdt-logo-small-mono-light.svg rename to builder-frontend/public/logos/bdt-logo-small-mono-light.svg diff --git a/builder-frontend/src/App.tsx b/builder-frontend/src/App.tsx index 0e06f32a..a1d72377 100644 --- a/builder-frontend/src/App.tsx +++ b/builder-frontend/src/App.tsx @@ -1,4 +1,4 @@ -import { Navigate, Route } from "@solidjs/router"; +import { Route, Router } from "@solidjs/router"; import Project from "./components/project/Project"; import AuthForm from "./components/auth/AuthForm"; @@ -7,28 +7,33 @@ import HomeScreen from "./components/homeScreen/HomeScreen"; import EligibilityCheckDetail from "./components/homeScreen/eligibilityCheckList/eligibilityCheckDetail/EligibilityCheckDetail"; import Screener from "./components/screener/Screener"; import Loading from "./components/Loading"; -import { Match, Switch } from "solid-js"; +import { Match, ParentProps, Switch } from "solid-js"; +import { ComponentLibrary } from "@/components/shared/ComponentLibrary"; +import Header from "@/components/Header/Header"; +import ANavBar from "@/components/shared/ANavbar"; +import { ViewLayout } from "@/components/homeScreen/ViewLayout"; +import ProjectsList from "@/components/homeScreen/ProjectsList"; +import EligibilityChecksList from "@/components/homeScreen/eligibilityCheckList/EligibilityChecksList"; - -const ProtectedRoute = (props) => { +const MainLayout = (props: ParentProps) => { const { user, isAuthLoading } = useAuth(); - - const userThing = () => { - console.log(user()) - return user(); - } - // If user is logged in, render the requested component, otherwise redirect to login + const navbarItems = [ + { label: "Projects", href: "/projects" }, + { label: "Eligibility checks", href: "/check" }, + ]; + return ( - - + + - - + +
+ {props.children} ); @@ -36,15 +41,27 @@ const ProtectedRoute = (props) => { function App() { return ( - <> - - - } /> - } /> - } /> - -
404 - Page Not Found
} /> - + + + + + + + + + + + + + + + + +
404 - Page Not Found
} + /> +
); } export default App; diff --git a/builder-frontend/src/components/Header.module.css b/builder-frontend/src/components/Header.module.css new file mode 100644 index 00000000..4d789347 --- /dev/null +++ b/builder-frontend/src/components/Header.module.css @@ -0,0 +1,13 @@ +@import "tailwindcss"; + +.header { + @apply bg-gray-200 min-h-24 h-24 px-4 flex items-center justify-between border-b-2 border-gray-300; +} +.logout-btn, +.back-to-home { + @apply px-4 py-3 font-bold text-gray-700 rounded-md flex items-center cursor-pointer select-none no-underline; +} +.logout-btn:hover, +.back-to-home:hover { + @apply bg-gray-300 text-gray-700; +} diff --git a/builder-frontend/src/components/Header/Header.tsx b/builder-frontend/src/components/Header/Header.tsx index d62efa17..290e80b0 100644 --- a/builder-frontend/src/components/Header/Header.tsx +++ b/builder-frontend/src/components/Header/Header.tsx @@ -1,8 +1,7 @@ import { useAuth } from "../../context/AuthContext"; import { useLocation, useNavigate } from "@solidjs/router"; -import { Component, For, Show } from "solid-js"; +import { Component, createMemo, For, Show } from "solid-js"; -import bdtLogo from "@/assets/logos/bdt-logo-small-mono-light.svg"; import { HamburgerMenu } from "@/components/shared/HamburgerMenu"; import "./Header.css"; @@ -35,7 +34,12 @@ interface MenuProps { } const HeaderMenu: Component = (props) => { + const navigate = useNavigate(); const menuItems: { label: string; onClick: () => void }[] = [ + { + label: "Custom Checks", + onClick: () => navigate("/check"), + }, { label: "User Guide", onClick: () => window.open("https://bdt-docs.web.app/", "_blank"), @@ -71,7 +75,9 @@ export default function Header() { const navigate = useNavigate(); const location = useLocation(); - const isNotRoot = location.pathname !== "/"; + const isNotRoot = createMemo( + () => location.pathname !== "/" && location.pathname !== "/projects", + ); const handleLogout = () => { logout(); @@ -82,14 +88,14 @@ export default function Header() {
BDT logo navigate("/")} />
- + navigate("/")} diff --git a/builder-frontend/src/components/auth/AuthForm.jsx b/builder-frontend/src/components/auth/AuthForm.jsx index 744537ad..0abd1f0c 100644 --- a/builder-frontend/src/components/auth/AuthForm.jsx +++ b/builder-frontend/src/components/auth/AuthForm.jsx @@ -12,10 +12,10 @@ export default function AuthForm() { const location = useLocation(); const toggleMode = () => { - if (location.pathname === "/login") { - navigate("/signup"); + if (location.pathname === "/signup") { + navigate("/"); } else { - navigate("/login"); + navigate("/signup"); } }; @@ -38,10 +38,10 @@ export default function AuthForm() {
Benefits Decision Tookit
- {location.pathname === "/login" ? ( - + {location.pathname === "/signup" ? ( + ) : ( - + )}

diff --git a/builder-frontend/src/components/auth/Login.jsx b/builder-frontend/src/components/auth/Login.jsx index af44fe26..f23b3564 100644 --- a/builder-frontend/src/components/auth/Login.jsx +++ b/builder-frontend/src/components/auth/Login.jsx @@ -50,7 +50,7 @@ export default function Login({ toggleMode }) { Email setIsConfirmationVisible(false)} - className="fixed inset-0 bg-black/10 flex items-center justify-center z-100" - > -
e.stopPropagation()} - className="bg-white px-12 py-8 rounded-xl max-w-100 w-1/2 min-w-80 h-80" - > -
- Are you sure you would like to delete {screenerData.screenerName}? -
-
- Once deleted, all associated data will be deleted and cant be - recovered. -
-
- - -
-
-
- ); -} diff --git a/builder-frontend/src/components/homeScreen/DeleteConfirmation.tsx b/builder-frontend/src/components/homeScreen/DeleteConfirmation.tsx new file mode 100644 index 00000000..2d958230 --- /dev/null +++ b/builder-frontend/src/components/homeScreen/DeleteConfirmation.tsx @@ -0,0 +1,37 @@ +import { Button } from "@/components/shared/Button"; +import TrashIcon from "../icon/TrashIcon"; + +interface Props { + screenerName: string; + onCancel: () => void; + onDelete: () => Promise; +} + +export default function DeleteConfirmation(props: Props) { + return ( +
+
+ Are you sure you would like to delete {props.screenerName}? +
+
+ Once deleted, all associated data will be deleted and cant be recovered. +
+
+ + +
+
+ ); +} diff --git a/builder-frontend/src/components/homeScreen/EditScreenerForm.jsx b/builder-frontend/src/components/homeScreen/EditScreenerForm.jsx deleted file mode 100644 index 0aa18ca5..00000000 --- a/builder-frontend/src/components/homeScreen/EditScreenerForm.jsx +++ /dev/null @@ -1,124 +0,0 @@ -import { createSignal, onCleanup, onMount } from "solid-js"; -import TrashIcon from "../icon/TrashIcon"; -import DeleteConfirmation from "./DeleteConfirmation"; - -export default function EditScreenerForm({ - setIsEditModalVisible, - screenerData, - handleEditScreener, - handleDeleteScreener, -}) { - const [isLoading, setIsLoading] = createSignal(false); - const [isConfirmationVisible, setIsConfirmationVisible] = createSignal(false); - const [screenerName, setScreenerName] = createSignal(); - let isActive = true; - - onMount(() => { - if (screenerData?.screenerName) { - setScreenerName(screenerData.screenerName); - } - }); - - onCleanup(() => { - isActive = false; - }); - - const handleSubmit = async (e) => { - e.preventDefault(); - try { - setIsLoading(true); - const data = { - screenerName: screenerName(), - }; - await handleEditScreener(screenerData.id, data); - if (isActive) setIsLoading(false); - } catch (e) { - if (setIsLoading()) { - setIsLoading(false); - } - } - }; - - const handleDelete = async () => { - try { - setIsLoading(true); - const data = { - id: screenerData.id, - }; - await handleDeleteScreener(data); - if (isActive) setIsLoading(false); - } catch (e) { - if (setIsLoading()) { - setIsLoading(false); - } - } - }; - - const handleDeleteClicked = (e) => { - e.preventDefault(); - setIsConfirmationVisible(true); - }; - - return ( - <> -
setIsEditModalVisible(false)} - className="fixed inset-0 bg-black/10 backdrop-blur-sm flex items-center justify-center z-50" - > -
e.stopPropagation()} - className="bg-white px-12 py-8 rounded-xl max-w-140 w-1/2 min-w-80 h-96" - > -
-
Edit screener
-
setIsEditModalVisible(false)} - className="text-2xl hover:font-bold hover:cursor-pointer" - > - X -
-
- -
-
- - setScreenerName(e.currentTarget.value)} - className="p-1 border-1 border-gray-400 w-90" - > -
- - -
-
-
- - - - {isLoading() &&
Loading ...
} -
-
-
- {isConfirmationVisible() && ( - - )} - - ); -} diff --git a/builder-frontend/src/components/homeScreen/EditScreenerForm.tsx b/builder-frontend/src/components/homeScreen/EditScreenerForm.tsx new file mode 100644 index 00000000..cb9cd056 --- /dev/null +++ b/builder-frontend/src/components/homeScreen/EditScreenerForm.tsx @@ -0,0 +1,98 @@ +import { createSignal, JSX } from "solid-js"; +import TrashIcon from "../icon/TrashIcon"; +import DeleteConfirmation from "./DeleteConfirmation"; +import { Modal } from "@/components/shared/Modal"; +import { Button } from "@/components/shared/Button"; +import Form from "@/components/shared/Form"; + +export interface EditModalData { + screenerId: string; + screenerName: string; +} + +interface Props { + modalData: EditModalData; + handleEditScreener: ( + screenerId: string, + data: { screenerName: string }, + ) => Promise; + handleDeleteScreener: (data: { id: string }) => Promise; +} + +export default function EditScreenerForm(props: Props) { + const [isLoading, setIsLoading] = createSignal(false); + const [isConfirmationVisible, setIsConfirmationVisible] = createSignal(false); + const [error, setError] = createSignal(""); + + const handleSubmit: JSX.EventHandler = async ( + e, + ) => { + e.preventDefault(); + setError(""); + const form = new FormData(e.currentTarget); + const screenerName = form.get("screenerName"); + if (!screenerName) { + setError("Please enter a screener name."); + } else { + try { + setIsLoading(true); + const data = { screenerName: screenerName.toString() }; + await props.handleEditScreener(props.modalData.screenerId, data); + setIsLoading(false); + } catch (e) { + if (isLoading()) { + setIsLoading(false); + } + } + } + }; + + const handleDelete = async () => { + try { + setIsLoading(true); + const data = { id: props.modalData.screenerId }; + await props.handleDeleteScreener(data); + setIsLoading(false); + } catch (e) { + if (isLoading()) { + setIsLoading(false); + } + } + }; + + return ( +
+
+
Edit screener
+ + + + + {error()} + +
+ +
+ + + setIsConfirmationVisible(false)} + > + setIsConfirmationVisible(false)} + onDelete={handleDelete} + /> + +
+ ); +} diff --git a/builder-frontend/src/components/homeScreen/HomeScreen.tsx b/builder-frontend/src/components/homeScreen/HomeScreen.tsx index 86c35384..596e3dac 100644 --- a/builder-frontend/src/components/homeScreen/HomeScreen.tsx +++ b/builder-frontend/src/components/homeScreen/HomeScreen.tsx @@ -1,50 +1,10 @@ -import { Accessor, createSignal, Match, Switch } from "solid-js"; - -import EligibilityChecksList from "./eligibilityCheckList/EligibilityChecksList"; -import ProjectsList from "./ProjectsList"; -import Header from "../Header/Header"; - -import BdtNavbar, { NavbarProps } from "@/components/shared/BdtNavbar"; -0; +import ProjectsList from "@/components/homeScreen/ProjectsList"; +import { Accessor, createSignal } from "solid-js"; const HomeScreen = () => { - const [screenMode, setScreenMode] = createSignal<"screeners" | "checks">( - "screeners", - ); - - const navbarDefs: Accessor = () => { - return { - tabDefs: [ - { - key: "screeners", - label: "Screeners", - onClick: () => setScreenMode("screeners"), - }, - { - key: "checks", - label: "Eligibility checks", - onClick: () => setScreenMode("checks"), - }, - ], - activeTabKey: () => screenMode(), - titleDef: null, - }; - }; - return ( -
-
- -
- - - - - - - - -
+
+
); }; diff --git a/builder-frontend/src/components/homeScreen/NewScreenerForm.jsx b/builder-frontend/src/components/homeScreen/NewScreenerForm.jsx deleted file mode 100644 index 5cce8c79..00000000 --- a/builder-frontend/src/components/homeScreen/NewScreenerForm.jsx +++ /dev/null @@ -1,69 +0,0 @@ -import { createSignal, onCleanup } from "solid-js"; - -export default function NewScreenerForm({ - setIsModalVisible, - handleCreateNewScreener, -}) { - const [isLoading, setIsLoading] = createSignal(false); - let nameInput; - let isActive = true; - - onCleanup(() => { - isActive = false; - }); - - const handleSubmit = async (e) => { - e.preventDefault(); - setIsLoading(true); - const data = { - screenerName: nameInput.value, - }; - await handleCreateNewScreener(data); - if (isActive) setIsLoading(false); - }; - - return ( -
setIsModalVisible(false)} - className="fixed inset-0 bg-black/10 backdrop-blur-sm flex items-center justify-center z-50" - > -
e.stopPropagation()} - className="bg-white px-12 py-8 rounded-xl max-w-140 w-1/2 min-w-80 h-96" - > -
-
Create a screener
-
setIsModalVisible(false)} - className="text-2xl hover:font-bold hover:cursor-pointer" - > - X -
-
-
- What is the name of your screener? -
-
-
- - (nameInput = el)} - class="form-input-custom" - /> -
- - {isLoading() &&
Loading ...
} -
-
-
- ); -} diff --git a/builder-frontend/src/components/homeScreen/NewScreenerForm.tsx b/builder-frontend/src/components/homeScreen/NewScreenerForm.tsx new file mode 100644 index 00000000..15f3794f --- /dev/null +++ b/builder-frontend/src/components/homeScreen/NewScreenerForm.tsx @@ -0,0 +1,54 @@ +import { createNewScreener } from "@/api/screener"; +import { Button } from "@/components/shared/Button"; +import Form from "@/components/shared/Form"; +import { useNavigate } from "@solidjs/router"; +import { createSignal, JSX, onCleanup } from "solid-js"; + +export default function NewScreenerForm({}) { + const navigate = useNavigate(); + const [error, setError] = createSignal(""); + const [isLoading, setIsLoading] = createSignal(false); + + const handleSubmit: JSX.EventHandler = async ( + e, + ) => { + e.preventDefault(); + setIsLoading(true); + setError(""); + const form = new FormData(e.currentTarget); + const screenerName = form.get("screenerName"); + if (screenerName) { + const data = { screenerName: screenerName.toString() }; + try { + const newScreener = await createNewScreener(data); + navigate(`/projects/${newScreener.id}`); + } catch (e) { + console.log("Error creating screener", e); + } + } else { + setError("Please enter a screener name."); + } + }; + + return ( +
+
+ + + + {error()} + +
+
+ ); +} diff --git a/builder-frontend/src/components/homeScreen/ProjectsList.tsx b/builder-frontend/src/components/homeScreen/ProjectsList.tsx index c5e25a7b..7ab13922 100644 --- a/builder-frontend/src/components/homeScreen/ProjectsList.tsx +++ b/builder-frontend/src/components/homeScreen/ProjectsList.tsx @@ -1,7 +1,14 @@ -import { For, Show, createResource, createSignal, onMount } from "solid-js"; +import { + For, + JSX, + Show, + createResource, + createSignal, + onMount, +} from "solid-js"; import { useNavigate } from "@solidjs/router"; -import EditScreenerForm from "./EditScreenerForm"; +import EditScreenerForm, { EditModalData } from "./EditScreenerForm"; import NewScreenerForm from "./NewScreenerForm"; import MenuIcon from "../icon/MenuIcon"; @@ -12,14 +19,18 @@ import { createNewScreener, } from "@/api/screener"; import { useAuth } from "@/context/AuthContext"; +import { Title } from "@solidjs/meta"; +import { Modal } from "@/components/shared/Modal"; export default function ProjectsList() { const [projectList, { refetch: refetchProjectList }] = createResource(fetchProjects); const [isNewScreenerModalVisible, setIsNewScreenerModalVisible] = createSignal(false); - const [isEditModalVisible, setIsEditgModalVisible] = createSignal(false); - const [editModelData, setEditModalData] = createSignal(); + const [isEditModalVisible, setIsEditModalVisible] = createSignal(false); + const [editModelData, setEditModalData] = createSignal( + null, + ); const navigate = useNavigate(); const { user } = useAuth(); @@ -30,7 +41,7 @@ export default function ProjectsList() { }); const navigateToProject = (project) => { - navigate("/project/" + project.id); + navigate("/projects/" + project.id); }; const handleCreateNewScreener = async (screenerData: { @@ -39,17 +50,21 @@ export default function ProjectsList() { }) => { try { const newScreener = await createNewScreener(screenerData); - navigate(`/project/${newScreener.id}`); + navigate(`/projects/${newScreener.id}`); } catch (e) { console.log("Error creating screener", e); } }; - const handleProjectMenuClicked = (e, screenerData) => { - e.stopPropagation(); - setEditModalData(screenerData); - setIsEditgModalVisible(true); - }; + const handleProjectMenuClicked = + ( + screenerData: EditModalData, + ): JSX.EventHandler => + (e) => { + e.stopPropagation(); + setEditModalData(screenerData); + setIsEditModalVisible(true); + }; const handleUpdateScreener = async ( screenerId: string, @@ -58,7 +73,7 @@ export default function ProjectsList() { try { await updateScreener(screenerId, screenerData); refetchProjectList(); - setIsEditgModalVisible(false); + setIsEditModalVisible(false); } catch (e) { console.log("Error editing screener", e); } @@ -68,49 +83,60 @@ export default function ProjectsList() { try { await deleteScreener(screenerData.id); refetchProjectList(); - setIsEditgModalVisible(false); + setIsEditModalVisible(false); } catch (e) { console.log("Error deleting screener", e); } }; return ( - <> -
-
-
- Welcome to Benefit Decision Toolkit! -
-
- Benefit Decision Toolkit is an open-source, civic tech project that - aims to provide an easy and affordable platform for building benefit - eligibility screening tools. -
+
+ BDT - Projects List +
+
+ Welcome to Benefit Decision Toolkit! +
+
+ Benefit Decision Toolkit is an open-source, civic tech project that + aims to provide an easy and affordable platform for building benefit + eligibility screening tools. +
-
- Create a new eligibility screener by adding and configuring - eligibility checks from our library of pre-built eligibility rules. - Or build custom checks that meet your specific needs. -
-
setIsNewScreenerModalVisible(true)} - class=" +
+ Create a new eligibility screener by adding and configuring + eligibility checks from our library of pre-built eligibility rules. Or + build custom checks that meet your specific needs. +
+
setIsNewScreenerModalVisible(true)} + class=" mt-2 px-4 py-2 w-fit cursor-pointer bg-blue-500 rounded-lg shadow-md hover:shadow-lg hover:bg-blue-600 font-bold text-sm text-white" - > - Create new screener -
+ > + Create new screener
- Loading...
}> -
- -
-
Loading screeners...
-
-
- - {(item) => + setIsNewScreenerModalVisible(false)} + > + + +
+ Loading...
}> +
+ +
+
Loading screeners...
+
+
+ + {(item) => { + const screenerData: EditModalData = { + screenerId: item.id, + screenerName: item.screenerName, + }; + return ( item && (
-
handleProjectMenuClicked(e, item)} + onClick={handleProjectMenuClicked(screenerData)} > -
+
navigateToProject(item)} class="h-60 p-4 flex flex-col justify-center items-center" @@ -132,25 +159,25 @@ export default function ProjectsList() {
) - } -
-
- -
- {isNewScreenerModalVisible() && ( - - )} - {isEditModalVisible() && ( - - )} - + ); + }} + + setIsEditModalVisible(false)} + > + + {(modalData) => ( + + )} + + +
+ +
); } diff --git a/builder-frontend/src/components/homeScreen/ViewLayout.tsx b/builder-frontend/src/components/homeScreen/ViewLayout.tsx new file mode 100644 index 00000000..c5ce91a0 --- /dev/null +++ b/builder-frontend/src/components/homeScreen/ViewLayout.tsx @@ -0,0 +1,5 @@ +import { Component, createSignal, JSX, ParentProps } from "solid-js"; + +export const ViewLayout: Component = (props) => { + return
{props.children}
; +}; diff --git a/builder-frontend/src/components/homeScreen/eligibilityCheckList/EligibilityChecksList.tsx b/builder-frontend/src/components/homeScreen/eligibilityCheckList/EligibilityChecksList.tsx index 249b430f..57a31ea6 100644 --- a/builder-frontend/src/components/homeScreen/eligibilityCheckList/EligibilityChecksList.tsx +++ b/builder-frontend/src/components/homeScreen/eligibilityCheckList/EligibilityChecksList.tsx @@ -6,8 +6,11 @@ import CheckModal from "./modals/CheckModal"; import eligibilityCheckResource from "./eligibilityCheckResource"; import type { EligibilityCheck } from "@/types"; -import ConfirmationModal from "@/components/shared/ConfirmationModal"; import Tooltip from "@/components/shared/Tooltip"; +import { Title } from "@solidjs/meta"; +import { Modal } from "@/components/shared/Modal"; +import { ArchiveCheck } from "@/components/homeScreen/eligibilityCheckList/modals/ArchiveCheck"; +import { Button } from "@/components/shared/Button"; const EligibilityChecksList = () => { const { checks, actions, actionInProgress, initialLoadStatus } = @@ -25,7 +28,8 @@ const EligibilityChecksList = () => { }; return ( -
+
+ BDT - Custom Checks @@ -52,12 +56,16 @@ const EligibilityChecksList = () => { class="px-4 py-2 w-fit cursor-pointer bg-blue-500 rounded-lg shadow-md hover:shadow-lg hover:bg-blue-600 font-bold text-sm text-white" - onClick={() => { - setAddingNewCheck(true); - }} + onClick={() => setAddingNewCheck(true)} > Create New Check
+ setAddingNewCheck(false)}> + setAddingNewCheck(false)} + /> +
{(check) => ( @@ -69,20 +77,19 @@ const EligibilityChecksList = () => { )}
- {addingNewCheck() && ( - setAddingNewCheck(false)} - modalAction={actions.addNewCheck} - /> - )} - {checkIdToRemove() && ( - actions.removeCheck(checkIdToRemove()!)} - closeModal={() => setCheckIdToRemove(null)} - /> - )} + setCheckIdToRemove(null)} + > + + {(checkId) => ( + actions.removeCheck(checkId())} + onCancel={() => setCheckIdToRemove(null)} + /> + )} + +
); }; @@ -117,22 +124,22 @@ const CheckCard = ({ id={"benefit-card-actions-" + eligibilityCheck.id} class="p-4 flex justify-end space-x-2" > -
{ navigateToCheck(eligibilityCheck); }} > Edit -
-
+
+
diff --git a/builder-frontend/src/components/homeScreen/eligibilityCheckList/eligibilityCheckDetail/EligibilityCheckDetail.tsx b/builder-frontend/src/components/homeScreen/eligibilityCheckList/eligibilityCheckDetail/EligibilityCheckDetail.tsx index 546929b8..1c30502c 100644 --- a/builder-frontend/src/components/homeScreen/eligibilityCheckList/eligibilityCheckDetail/EligibilityCheckDetail.tsx +++ b/builder-frontend/src/components/homeScreen/eligibilityCheckList/eligibilityCheckDetail/EligibilityCheckDetail.tsx @@ -84,7 +84,6 @@ const EligibilityCheckDetail = () => { -
Promise; + closeModal: () => void; + initialData?: ParamValues; } -const ParameterModal = ( - { actionTitle, modalAction, closeModal, initialData }: - { actionTitle: string, modalAction: (parameter: ParameterDefinition) => Promise; closeModal: () => void, initialData?: ParamValues } -) => { - const [newParam, setNewParam] = createStore(initialData || { key: "", type: "string", label: "", required: undefined }); - // Styling for the Add button based on whether fields are filled - const isAddDisabled = () => { - return ( - newParam.key.trim() === "" || - newParam.label.trim() === "" - ); - } - const addButtonClasses = () => { - return isAddDisabled() ? "opacity-50 cursor-not-allowed" : "hover:bg-sky-700"; - } +/** + * Predicate determining whether a `value` is a valid `ParameterType`. + * Narrows `value`'s type from `string` to `ParameterType` + * for the compiler. Returns a boolean at runtime. + */ +const isParameterType = ( + value: string, +): value is ParameterDefinition["type"] => { + const parameterTypes = [ + "string", + "number", + "boolean", + "date", + "array", + ] as const satisfies readonly ParameterDefinition["type"][]; + return parameterTypes.includes(value as ParameterDefinition["type"]); +}; + +const emptyError: ParamValues = { + key: "", + label: "", + type: "", + required: "", +}; + +const parameterTypeOptions: { + label: string; + value: ParameterDefinition["type"]; +}[] = [ + { label: "String", value: "string" }, + { label: "Number", value: "number" }, + { label: "Boolean", value: "boolean" }, + { label: "Date", value: "date" }, + { label: "String List", value: "array" }, +]; + +const ParameterModal = (props: Props) => { + const [error, setError] = createSignal({ ...emptyError }); + + const handleSubmit: JSX.EventHandler = async ( + e, + ) => { + e.preventDefault(); + setError(() => ({ + key: "", + label: "", + required: "", + type: "", + })); + + const form = new FormData(e.currentTarget); + const parameterKey = form.get("parameterKey"); + const parameterLabel = form.get("parameterLabel"); + const rawParameterType = form.get("parameterType")?.toString(); + const parameterRequired = form.get("parameterRequired"); + + if ( + !parameterKey || + !parameterLabel || + !rawParameterType || + !isParameterType(rawParameterType) || + !parameterRequired + ) { + setError({ + key: !parameterKey ? "Please enter a value." : "", + label: !parameterLabel ? "Please enter a value." : "", + type: !rawParameterType ? "Please enter a value." : "", + required: !parameterRequired ? "Please enter a value." : "", + }); + } else { + const parameter: ParameterDefinition = { + key: parameterKey.toString(), + label: parameterLabel.toString(), + type: rawParameterType, + required: parameterRequired === "true", + }; + await props.modalAction(parameter); + props.closeModal(); + } + }; return (
-
{actionTitle}
-
- - setNewParam("key", e.currentTarget.value)} +
{props.actionTitle}
+
+ -
-
- - setNewParam("label", e.currentTarget.value)} + htmlFor="parameterKey" + > + + + {error().key} + + -
-
- - -
-
- -
-
- setNewParam("required", true)} - class="form-radio" - /> - True -
-
- setNewParam("required", false)} - class="form-radio" - /> - False -
- { - newParam.required === undefined && - Not set - } -
-
-
-
{ closeModal(); }} + + + {error().label} + + - Cancel -
-
{ - if (isAddDisabled()) { - console.log("Please fill in all fields."); - return; - } - const parameter: ParameterDefinition = { - key: newParam.key, - label: newParam.label, - type: newParam.type, - required: newParam.required - }; - await modalAction(parameter); - closeModal(); - }} + + + {error().type} + + - {actionTitle} +
Required
+ True + False +
+ {error().required} + +
+ +
-
+
); -} +}; export default ParameterModal; diff --git a/builder-frontend/src/components/homeScreen/eligibilityCheckList/modals/ArchiveCheck.tsx b/builder-frontend/src/components/homeScreen/eligibilityCheckList/modals/ArchiveCheck.tsx new file mode 100644 index 00000000..a3b533f8 --- /dev/null +++ b/builder-frontend/src/components/homeScreen/eligibilityCheckList/modals/ArchiveCheck.tsx @@ -0,0 +1,32 @@ +import { Button } from "@/components/shared/Button"; + +interface Props { + onCancel: () => void; + onArchive: () => Promise; +} + +export const ArchiveCheck = (props: Props) => { + return ( +
+
Archive Check
+
+ Are you sure you want to archive this Eligibility Check? This action + cannot be undone. +
+
+ + +
+
+ ); +}; diff --git a/builder-frontend/src/components/homeScreen/eligibilityCheckList/modals/CheckModal.tsx b/builder-frontend/src/components/homeScreen/eligibilityCheckList/modals/CheckModal.tsx index 2117c6ef..ba8a448d 100644 --- a/builder-frontend/src/components/homeScreen/eligibilityCheckList/modals/CheckModal.tsx +++ b/builder-frontend/src/components/homeScreen/eligibilityCheckList/modals/CheckModal.tsx @@ -1,103 +1,71 @@ -import { createStore } from "solid-js/store"; - import type { CreateCheckRequest } from "@/types"; +import { createSignal, JSX } from "solid-js"; +import Form from "@/components/shared/Form"; +import { Button } from "@/components/shared/Button"; -type CheckValues = { - name: string; - module: string; - description: string; -}; -const EditCheckModal = ({ - modalAction, - closeModal, -}: { - modalAction: (check: CreateCheckRequest) => Promise; - closeModal: () => void; -}) => { - const [newCheck, setNewCheck] = createStore({ - name: "", +interface Props { + onAddCheck: (check: CreateCheckRequest) => Promise; + onClose: () => void; +} + +const EditCheckModal = (props: Props) => { + const [error, setError] = createSignal({ + checkName: "", module: "", description: "", }); - // Styling for the Add button based on whether fields are filled - const isAddDisabled = () => { - return ( - newCheck.name.trim() === "" || - newCheck.description.trim() === "" || - newCheck.module.trim() === "" - ); - }; - const addButtonClasses = () => { - return isAddDisabled() - ? "opacity-50 cursor-not-allowed" - : "hover:bg-sky-700"; + const handleAddCheck: JSX.EventHandler = async ( + e, + ) => { + e.preventDefault(); + const form = new FormData(e.currentTarget); + const checkName = form.get("checkName"); + const checkModule = form.get("checkModule"); + const checkDescription = form.get("checkDescription"); + + if (!checkName || !checkModule || !checkDescription) { + setError({ + checkName: !checkName ? "Please enter a name." : "", + module: !checkModule ? "Please enter a module." : "", + description: !checkDescription ? "Please enter a description." : "", + }); + } else { + const check: CreateCheckRequest = { + name: checkName.toString(), + module: checkModule.toString(), + description: checkDescription.toString(), + parameterDefinitions: [], + }; + try { + await props.onAddCheck(check); + props.onClose(); + } catch (err) { + console.log(err); + } + } }; return ( -
-
-
Create New Check
-
- - setNewCheck("name", e.currentTarget.value)} - placeholder="Enter check name" - /> -
-
- - setNewCheck("module", e.currentTarget.value)} - placeholder="Enter check module" - /> -
-
- -