diff --git a/package-lock.json b/package-lock.json index bf4dab7db..4dc3a4741 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "@mdi/font": "^7.2.96", "@mdi/js": "^7.1.96", "@react-google-maps/api": "^2.20.3", + "@uiw/react-color": "^2.4.1", "aws-rum-web": "^1.19.0", "chart.js": "^4.4.1", "clean-webpack-plugin": "^4.0.0", @@ -3957,6 +3958,420 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/@uiw/color-convert": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@uiw/color-convert/-/color-convert-2.4.1.tgz", + "integrity": "sha512-MeYpWxogtn5G9KT/xaf4uMUZDFGIsCevSUK++xBe2xrRSGILAC1oSQszopnWMe1HqjVdvyW3qZzy23Y92x6FwA==", + "license": "MIT", + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.19.0" + } + }, + "node_modules/@uiw/react-color": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@uiw/react-color/-/react-color-2.4.1.tgz", + "integrity": "sha512-STgLCHjUYPcOfzzhyt73El/DjC8bmZ2kaSs8lS7SEVpxsIezbC16Z02QLzyI5hdEsVAj9DiSgSsHsaTZ2RmXXg==", + "license": "MIT", + "dependencies": { + "@uiw/color-convert": "2.4.1", + "@uiw/react-color-alpha": "2.4.1", + "@uiw/react-color-block": "2.4.1", + "@uiw/react-color-chrome": "2.4.1", + "@uiw/react-color-circle": "2.4.1", + "@uiw/react-color-colorful": "2.4.1", + "@uiw/react-color-compact": "2.4.1", + "@uiw/react-color-editable-input": "2.4.1", + "@uiw/react-color-editable-input-hsla": "2.4.1", + "@uiw/react-color-editable-input-rgba": "2.4.1", + "@uiw/react-color-github": "2.4.1", + "@uiw/react-color-hue": "2.4.1", + "@uiw/react-color-material": "2.4.1", + "@uiw/react-color-name": "2.4.1", + "@uiw/react-color-saturation": "2.4.1", + "@uiw/react-color-shade-slider": "2.4.1", + "@uiw/react-color-sketch": "2.4.1", + "@uiw/react-color-slider": "2.4.1", + "@uiw/react-color-swatch": "2.4.1", + "@uiw/react-color-wheel": "2.4.1" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.19.0", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@uiw/react-color-alpha": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@uiw/react-color-alpha/-/react-color-alpha-2.4.1.tgz", + "integrity": "sha512-9Yv9TnaYL7Yp2tfzlvdiV4CQixvMOiRZKJLzealrXOa0IpnN3lQzv+H7I4w7RwE54y36B3ZLIZp74voTmTy1UQ==", + "license": "MIT", + "dependencies": { + "@uiw/color-convert": "2.4.1", + "@uiw/react-drag-event-interactive": "2.4.1" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.19.0", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@uiw/react-color-block": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@uiw/react-color-block/-/react-color-block-2.4.1.tgz", + "integrity": "sha512-4ntZPt6j8JTnru0eyDbuvvr7PEQQDWa+nAumrFAPKNDJYLpeyrICVkwylA7nxwg/JOiBEQOZ9VJ5xb0NzysIhQ==", + "license": "MIT", + "dependencies": { + "@uiw/color-convert": "2.4.1", + "@uiw/react-color-editable-input": "2.4.1", + "@uiw/react-color-swatch": "2.4.1" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.19.0", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@uiw/react-color-chrome": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@uiw/react-color-chrome/-/react-color-chrome-2.4.1.tgz", + "integrity": "sha512-PMEPN+1AuPGpNAOAeDpXc/BmxilETrBJmcVvqQUQqshG/G8oWiY6UjkKkJEalEWeG9q9ip9POtKN+tveSv06Qw==", + "license": "MIT", + "dependencies": { + "@uiw/color-convert": "2.4.1", + "@uiw/react-color-alpha": "2.4.1", + "@uiw/react-color-editable-input": "2.4.1", + "@uiw/react-color-editable-input-hsla": "2.4.1", + "@uiw/react-color-editable-input-rgba": "2.4.1", + "@uiw/react-color-github": "2.4.1", + "@uiw/react-color-hue": "2.4.1", + "@uiw/react-color-saturation": "2.4.1" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.19.0", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@uiw/react-color-circle": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@uiw/react-color-circle/-/react-color-circle-2.4.1.tgz", + "integrity": "sha512-QZqb3k8NGZRPw7whKNMMCy6U6ylDhC27XQ+ROeU/l33/Uu8Z7qJ56qWEyKiJISLSDsw3hCTE8lQ51KxhcOfd4A==", + "license": "MIT", + "dependencies": { + "@uiw/color-convert": "2.4.1", + "@uiw/react-color-swatch": "2.4.1" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.19.0", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@uiw/react-color-colorful": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@uiw/react-color-colorful/-/react-color-colorful-2.4.1.tgz", + "integrity": "sha512-Cgw7p0vZ7geEnjbTHEZMfLh3MyoFPW/c5UfipAG294M5w21nzp64KlcvPkf/K4yBp8T9l6VD2bVT5hdnzeGFOg==", + "license": "MIT", + "dependencies": { + "@uiw/color-convert": "2.4.1", + "@uiw/react-color-alpha": "2.4.1", + "@uiw/react-color-hue": "2.4.1", + "@uiw/react-color-saturation": "2.4.1" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.19.0", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@uiw/react-color-compact": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@uiw/react-color-compact/-/react-color-compact-2.4.1.tgz", + "integrity": "sha512-14GPq2OWzwayb/XWz/QgPa4ODvHi5lbfzK+L7FYTgLUEILbdEtA0hO6vu7q8a10rbXAJ548lFiydoBTor7dSmg==", + "license": "MIT", + "dependencies": { + "@uiw/color-convert": "2.4.1", + "@uiw/react-color-editable-input": "2.4.1", + "@uiw/react-color-editable-input-rgba": "2.4.1", + "@uiw/react-color-swatch": "2.4.1" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.19.0", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@uiw/react-color-editable-input": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@uiw/react-color-editable-input/-/react-color-editable-input-2.4.1.tgz", + "integrity": "sha512-VQnOOVaE/y+Nz9uJ821JLNZebYC2qAkQY0PXvo/u7BBSBZsf3GvmwM0ReBJhG1pDZY9f1ptRrrvSEYirAv42zA==", + "license": "MIT", + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.19.0", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@uiw/react-color-editable-input-hsla": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@uiw/react-color-editable-input-hsla/-/react-color-editable-input-hsla-2.4.1.tgz", + "integrity": "sha512-j3ih/TazYYdqBt/uV6TyFdUhY7AMRdtKznevgfMVhpewKKHYQYc6B6BP7dWz1K8NWqedqC8ZWzyzeLhAAuZQlQ==", + "license": "MIT", + "dependencies": { + "@uiw/color-convert": "2.4.1", + "@uiw/react-color-editable-input-rgba": "2.4.1" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.19.0", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@uiw/react-color-editable-input-rgba": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@uiw/react-color-editable-input-rgba/-/react-color-editable-input-rgba-2.4.1.tgz", + "integrity": "sha512-lXW9azOcTc+CFcr3XpjPuT3f54pL2Rff5Q5tTfiEuO7jXNPt9v1jvuAWyIdspP/wE9LKRpNeZSFwuUtjaVEggA==", + "license": "MIT", + "dependencies": { + "@uiw/color-convert": "2.4.1", + "@uiw/react-color-editable-input": "2.4.1" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.19.0", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@uiw/react-color-github": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@uiw/react-color-github/-/react-color-github-2.4.1.tgz", + "integrity": "sha512-hTGvhXMwU59h/gfAbj/3owQAvflI/FTXnj/k1zQvuiGl1RtP1vC0JYAUijpj5Ndp8q8biBBvSP6QivJPre2rsQ==", + "license": "MIT", + "dependencies": { + "@uiw/color-convert": "2.4.1", + "@uiw/react-color-swatch": "2.4.1" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.19.0", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@uiw/react-color-hue": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@uiw/react-color-hue/-/react-color-hue-2.4.1.tgz", + "integrity": "sha512-oWnHnfuW9ScMmNsXetIZO1zXFjHn2FbGz5E1pyP0Nc0lQPI+LZKV1dQAgN9DwIApAtNGrdTBa/VLo4IaxDvUsQ==", + "license": "MIT", + "dependencies": { + "@uiw/color-convert": "2.4.1", + "@uiw/react-color-alpha": "2.4.1" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.19.0", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@uiw/react-color-material": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@uiw/react-color-material/-/react-color-material-2.4.1.tgz", + "integrity": "sha512-btQfauFX5yNpagDjlZrkY/UogThkdBlmTazPupJ2LLOPJnkPDdgdX2CYO0kSwAHvmKFpRuSEO+6xeHLTTUAi+w==", + "license": "MIT", + "dependencies": { + "@uiw/color-convert": "2.4.1", + "@uiw/react-color-editable-input": "2.4.1", + "@uiw/react-color-editable-input-rgba": "2.4.1" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.19.0", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@uiw/react-color-name": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@uiw/react-color-name/-/react-color-name-2.4.1.tgz", + "integrity": "sha512-+iMjH+66mQM7ELUiyn/3d7obgECLWkDicM5FntOyxNq2SLwCE+y2TKeUiWrcn0Fo9w/7zFR/TMcUOmV2QQsHSw==", + "license": "MIT", + "dependencies": { + "colors-named": "^1.0.1", + "colors-named-hex": "^1.0.1" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.19.0" + } + }, + "node_modules/@uiw/react-color-saturation": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@uiw/react-color-saturation/-/react-color-saturation-2.4.1.tgz", + "integrity": "sha512-OdKTRE5lVgiXrx5ituF94tESOE+EmqFvjnDDg3aFVXTARC9tJgmqLE/We+K0PyYq8HNIZLGSMBXWkR89cPqkDQ==", + "license": "MIT", + "dependencies": { + "@uiw/color-convert": "2.4.1", + "@uiw/react-drag-event-interactive": "2.4.1" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.19.0", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@uiw/react-color-shade-slider": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@uiw/react-color-shade-slider/-/react-color-shade-slider-2.4.1.tgz", + "integrity": "sha512-fPzgHd7aoKpLmUlIoTr3nq0hcbiXu9lLQbEIGprDPRu4MYO3eSqPU6q0LNCMVmx8dbo3bFERTe63LJf9j0jcwA==", + "license": "MIT", + "dependencies": { + "@uiw/color-convert": "2.4.1", + "@uiw/react-color-alpha": "2.4.1" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.19.0", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@uiw/react-color-sketch": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@uiw/react-color-sketch/-/react-color-sketch-2.4.1.tgz", + "integrity": "sha512-o6L26p2U0HKxfx8Hm6dr+wTeJ3iF7jxbFgkEWcfpRzAstrXu4cutl8UlP7ZETvEUcaqjFMV+q+R/dfDNqQVJnw==", + "license": "MIT", + "dependencies": { + "@uiw/color-convert": "2.4.1", + "@uiw/react-color-alpha": "2.4.1", + "@uiw/react-color-editable-input": "2.4.1", + "@uiw/react-color-editable-input-rgba": "2.4.1", + "@uiw/react-color-hue": "2.4.1", + "@uiw/react-color-saturation": "2.4.1", + "@uiw/react-color-swatch": "2.4.1" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.19.0", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@uiw/react-color-slider": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@uiw/react-color-slider/-/react-color-slider-2.4.1.tgz", + "integrity": "sha512-dkde0fX0Ye8qNxL3/shpLcix0FmiZD5mMoqlS/hjM2Z5JDqWa6MI9xE2Tq3trVeJcN39LUWFQenLYRwluPMPsg==", + "license": "MIT", + "dependencies": { + "@uiw/color-convert": "2.4.1", + "@uiw/react-color-alpha": "2.4.1" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.19.0", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@uiw/react-color-swatch": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@uiw/react-color-swatch/-/react-color-swatch-2.4.1.tgz", + "integrity": "sha512-TKugNvImoMAHCN4oyh/Xo2TfJ6CR2SYPn8agvDOdnCH/R/P8+RIrXiaNU0wFt53yecozhK++ipJxN3gwQkbM8A==", + "license": "MIT", + "dependencies": { + "@uiw/color-convert": "2.4.1" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.19.0", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@uiw/react-color-wheel": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@uiw/react-color-wheel/-/react-color-wheel-2.4.1.tgz", + "integrity": "sha512-Z0RgyCU0rAt8K7hyjmEhzRM8i6Z1B18/09RKgSVT5NbXsyAHb1zaVCJ5i2x8+zyvSmUATsJDlUrZxtosztDzIA==", + "license": "MIT", + "dependencies": { + "@uiw/color-convert": "2.4.1", + "@uiw/react-drag-event-interactive": "2.4.1" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.19.0", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@uiw/react-drag-event-interactive": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@uiw/react-drag-event-interactive/-/react-drag-event-interactive-2.4.1.tgz", + "integrity": "sha512-BlPmqsq3QsRvJrc2pbT0SAl9D9dTMYXkYr92wap9gknbnFRw/pHXxi3CPIVO2NqPwpe2nPwbfo99+38jymVhiw==", + "license": "MIT", + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.19.0", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, "node_modules/@webassemblyjs/ast": { "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", @@ -5374,6 +5789,30 @@ "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", "dev": true }, + "node_modules/colors-named": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/colors-named/-/colors-named-1.0.2.tgz", + "integrity": "sha512-2ANq2r393PV9njYUD66UdfBcxR1slMqRA3QRTWgCx49JoCJ+kOhyfbQYxKJbPZQIhZUcNjVOs5AlyY1WwXec3w==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + } + }, + "node_modules/colors-named-hex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/colors-named-hex/-/colors-named-hex-1.0.2.tgz", + "integrity": "sha512-k6kq1e1pUCQvSVwIaGFq2l0LrkAPQZWyeuZn1Z8nOiYSEZiKoFj4qx690h2Kd34DFl9Me0gKS6MUwAMBJj8nuA==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + } + }, "node_modules/combine-source-map": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.8.0.tgz", diff --git a/package.json b/package.json index 3433d454c..c4616a635 100644 --- a/package.json +++ b/package.json @@ -87,6 +87,7 @@ "@mdi/font": "^7.2.96", "@mdi/js": "^7.1.96", "@react-google-maps/api": "^2.20.3", + "@uiw/react-color": "^2.4.1", "aws-rum-web": "^1.19.0", "chart.js": "^4.4.1", "clean-webpack-plugin": "^4.0.0", diff --git a/react/assets/forus-platform/resources/_platform-common/assets/img/banner-background-icon.svg b/react/assets/forus-platform/resources/_platform-common/assets/img/banner-background-icon.svg new file mode 100644 index 000000000..2c3e0dc27 --- /dev/null +++ b/react/assets/forus-platform/resources/_platform-common/assets/img/banner-background-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/react/assets/forus-platform/resources/_platform-common/assets/img/icon-fund-form.svg b/react/assets/forus-platform/resources/_platform-common/assets/img/icon-fund-form.svg new file mode 100644 index 000000000..cd9a9e4a8 --- /dev/null +++ b/react/assets/forus-platform/resources/_platform-common/assets/img/icon-fund-form.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/react/assets/forus-platform/scss/_common/blocks/block-banner-editor.scss b/react/assets/forus-platform/scss/_common/blocks/block-banner-editor.scss new file mode 100644 index 000000000..91a26d486 --- /dev/null +++ b/react/assets/forus-platform/scss/_common/blocks/block-banner-editor.scss @@ -0,0 +1,215 @@ +.block.block-banner-editor { + display: flex; + flex-direction: column; + width: 100%; + background-color: #fff; + position: relative; + background-repeat: no-repeat; + background-size: cover; + + .banner-editor-preview { + display: flex; + flex-direction: row; + flex: 1 1 auto; + position: relative; + border-bottom: 1px solid var(--border-color); + padding: 30px 30px; + + .banner-editor-preview-photo { + display: flex; + flex: 0 0 100%; + background-size: cover; + background-position: center; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + border-right: 1px solid var(--border-color); + z-index: 0; + + .banner-editor-photo-pattern { + display: block; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-size: 10px; + } + } + + .banner-editor-preview-content { + display: flex; + flex: 0 0 100%; + background: #fff; + color: #000; + flex-direction: column; + justify-content: center; + gap: 10px; + padding: 30px 30px; + z-index: 1; + border-radius: 4px; + + .banner-editor-title { + font: 500 15px/20px var(--base-font); + } + + .banner-editor-description { + font: 500 12px/18px var(--base-font) !important; + + p { + margin-bottom: 5px; + } + } + + .banner-editor-actions { + } + } + + &.banner-editor-preview-collapse { + padding: 0; + } + } + + .banner-editor-controls { + display: flex; + flex-direction: row; + padding: 0 20px; + gap: 15px; + + .banner-editor-control { + display: flex; + flex-direction: row; + gap: 8px; + padding: 12px 0; + position: relative; + + .banner-editor-control-label { + color: #595959; + font: 500 11px/30px var(--base-font); + } + + .banner-editor-control-value { + color: #134478; + font: 700 11px/30px var(--base-font); + display: flex; + gap: 0; + flex-direction: row; + align-items: center; + cursor: pointer; + position: relative; + + & > .mdi { + font-size: 18px; + color: #646f79; + } + } + + .banner-editor-control-color { + padding: 0 5px; + border: 1px solid var(--border-color); + border-radius: 5px; + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + gap: 5px; + position: relative; + background: #fcfcfc; + cursor: pointer; + + .banner-editor-control-color-preview { + width: 16px; + height: 16px; + border-radius: 4px; + box-shadow: 1px 1px 5px 0 rgba(25, 39, 52, 0.11); + } + + & > .mdi { + font-size: 18px; + color: #646f79; + } + } + + .banner-editor-dropdown { + position: absolute; + top: 100%; + left: 17px; + width: 240px; + display: flex; + flex-direction: column; + align-items: flex-start; + justify-content: center; + z-index: 1; + + .banner-editor-dropdown-close { + position: absolute; + right: 5px; + top: 5px; + display: flex; + height: 20px; + width: 20px; + justify-content: center; + align-items: center; + font-size: 20px; + } + + .banner-editor-dropdown-body { + padding: 12px; + background-color: #fff; + border: 1px solid var(--border-color); + border-radius: var(--border-radius); + display: flex; + flex-direction: column; + gap: 12px; + width: 100%; + position: relative; + box-shadow: 0 13px 36px 0 rgba(0, 0, 0, 0.2); + } + + .banner-editor-dropdown-separator { + height: 1px; + background: var(--border-color); + } + + .banner-editor-dropdown-actions { + display: flex; + flex-direction: row; + gap: 12px; + + & > * { + flex: 1 1 50%; + margin: 0 0; + justify-content: center; + } + } + + .banner-editor-dropdown-triangle { + width: 0; + height: 0; + border-style: solid; + border-width: 0 16px 16px 16px; + border-color: transparent transparent #ffffff transparent; + transform: rotate(0deg); + margin-bottom: -5px; + margin-left: 10px; + z-index: 1; + } + } + } + + .banner-editor-controls-buttons { + flex: 1 1 auto; + display: flex; + flex-direction: row; + align-items: center; + justify-content: flex-end; + gap: 10px; + + & > * { + margin: 0 0; + } + } + } +} diff --git a/react/assets/forus-platform/scss/_common/blocks/block-banner-picker.scss b/react/assets/forus-platform/scss/_common/blocks/block-banner-picker.scss deleted file mode 100644 index 861cde270..000000000 --- a/react/assets/forus-platform/scss/_common/blocks/block-banner-picker.scss +++ /dev/null @@ -1,116 +0,0 @@ -&.block-banner-picker { - width: 100%; - overflow: hidden; - height: 0; - padding-top: 25%; - background-color: #a8c0ce; - position: relative; - background-repeat: no-repeat; - background-size: cover; - - .picker-dark { - position: absolute; - top: 0; - left: 0; - width: 100%; - background-color: rgba($color: #000000, $alpha: 0.5); - padding: 10px 10px; - - .checkbox { - .checkbox-label { - color: #fff; - display: flex; - float: none; - font: 700 13px/18px var(--base-font); - text-shadow: 0 1px 1px rgba($color: #000000, $alpha: 0.2); - } - - .checkbox-box { - border-color: #fff; - box-shadow: 0 1px 1px rgba($color: #000000, $alpha: 0.2); - - .mdi { - color: #fff; - } - } - } - } - - .picker-select { - display: flex; - flex-direction: row; - margin-right: 20px; - - .picker-select-label { - color: #fff; - font: 700 13px/28px var(--base-font); - margin-right: 2.5px; - } - - .picker-select-input { - background: none; - border: none; - color: #fff; - font: 700 13px/18px var(--base-font); - outline: none; - padding: 0; - - option { - color: #000; - font: 700 12px/18px var(--base-font); - } - } - - &:last-child { - margin-right: 0; - } - } - - .picker-overlay { - @include fill_parent(); - background-size: 10px; - background-color: rgba($color: #000000, $alpha: 0.8); - - &.picker-overlay-pattern { - background-color: transparent; - } - } - - .picker-content { - @include fill_parent(); - text-align: center; - display: flex; - flex-direction: column; - justify-content: center; - margin-top: 5%; - - .picker-icon { - color: #fff; - font-size: 96px; - line-height: 80px; - margin: 0 0 15px; - text-shadow: 1px 2px 2px rgba($color: #000000, $alpha: 0.2); - opacity: 0.5; - pointer-events: none; - } - - .picker-description { - color: #fff; - margin: 0 0 15px; - font: 700 16px/24px var(--base-font); - text-shadow: 1px 2px 2px rgba($color: #000000, $alpha: 0.2); - pointer-events: none; - - .mdi { - color: #fff; - text-shadow: 1px 2px 1px rgba($color: #000000, $alpha: 0.4); - font-size: 28px; - height: 25px; - } - - &.picker-description-dark { - color: #353535; - } - } - } -} diff --git a/react/assets/forus-platform/scss/_common/blocks/block-color-picker.scss b/react/assets/forus-platform/scss/_common/blocks/block-color-picker.scss new file mode 100644 index 000000000..588fee270 --- /dev/null +++ b/react/assets/forus-platform/scss/_common/blocks/block-color-picker.scss @@ -0,0 +1,11 @@ +.block.block-color-picker { + display: flex; + flex-direction: column; + width: 100%; + background-color: #fff; + position: relative; + + .color-picker-saturation { + + } +} diff --git a/react/assets/forus-platform/scss/_common/blocks/block-critera-editor.scss b/react/assets/forus-platform/scss/_common/blocks/block-critera-editor.scss index e825684ee..05b46ffcc 100644 --- a/react/assets/forus-platform/scss/_common/blocks/block-critera-editor.scss +++ b/react/assets/forus-platform/scss/_common/blocks/block-critera-editor.scss @@ -1,7 +1,7 @@ &.block-criteria-editor { display: flex; flex-direction: column; - gap: 10px; + gap: 20px; .criterion-list { display: flex; diff --git a/react/assets/forus-platform/scss/_common/blocks/block-fund.scss b/react/assets/forus-platform/scss/_common/blocks/block-fund.scss index fdac58af0..b5a554b48 100644 --- a/react/assets/forus-platform/scss/_common/blocks/block-fund.scss +++ b/react/assets/forus-platform/scss/_common/blocks/block-fund.scss @@ -4,18 +4,17 @@ margin: 0 0; background: #fff; gap: 20px; - display: grid; .fund-overview { border-bottom: 1px solid var(--border-color); - display: grid; + display: flex; flex-direction: row; - grid-template-columns: 190px 1fr; padding-bottom: 25px; gap: 25px; .fund-media { - display: grid; + display: flex; + flex: 0 0 190px; .fund-media-img { display: block; @@ -27,7 +26,7 @@ .fund-details { display: grid; grid-template-rows: max-content; - gap: 15px; + gap: 10px; .fund-header { display: grid; @@ -44,9 +43,11 @@ } .fund-description { - display: block; font: 400 14px/20px var(--base-font); color: #646f79; + display: flex; + gap: 10px; + flex-direction: column; } } } @@ -56,4 +57,15 @@ flex-direction: column; gap: 20px; } + + &.block-fund-compact { + .fund-overview { + padding-bottom: 0; + border-bottom: none; + + .fund-media { + flex: 0 0 150px; + } + } + } } diff --git a/react/assets/forus-platform/scss/_common/components/forms.scss b/react/assets/forus-platform/scss/_common/components/forms.scss index 71a0516e4..dd88430c1 100644 --- a/react/assets/forus-platform/scss/_common/components/forms.scss +++ b/react/assets/forus-platform/scss/_common/components/forms.scss @@ -707,7 +707,7 @@ color: rgba(var(--text-color), 0.75); border-bottom: 1px solid whitesmoke; cursor: pointer; - transition: 0.4s; + transition: background-color .4s, color .4s; height: var(--option-height); @include ellipsis(); @@ -725,6 +725,37 @@ &:last-child { border-bottom: none; } + + &:hover, + &:focus { + background: var(--dropdown-item-hover-background); + color: var(--dropdown-item-hover-color); + outline-offset: -2px !important; + outline-style: auto !important; + } + } + + &.select-control-options-fd { + position: initial; + left: auto; + top: auto; + width: auto; + z-index: 2; + margin: 0 0 0; + border: 1px solid #d4d9dd !important; + border-radius: var(--border-radius); + + &.select-control-options-fd-bottom { + border-top: none !important; + border-top-left-radius: 0 !important; + border-top-right-radius: 0 !important; + } + + &.select-control-options-fd-top { + border-bottom: none !important; + border-bottom-left-radius: 0 !important; + border-bottom-right-radius: 0 !important; + } } } diff --git a/react/assets/forus-platform/scss/_common/components/modals.scss b/react/assets/forus-platform/scss/_common/components/modals.scss index a549c362b..c2cec8692 100644 --- a/react/assets/forus-platform/scss/_common/components/modals.scss +++ b/react/assets/forus-platform/scss/_common/components/modals.scss @@ -68,7 +68,7 @@ .modal-header { background: #fff; padding: 20px 25px; - font: 600 16px/25px 'Source Sans Pro', sans-serif; + font: 600 16px/25px var(--base-font); border-bottom: 1px solid #d4d9dd; position: relative; border-radius: 3px 3px 0 0; @@ -77,6 +77,7 @@ .modal-body { min-height: 20px; overflow: auto; + position: relative; @include webkit_scrollbar(); .signup-layout { @@ -350,7 +351,7 @@ text-align: center; p { - font: 400 14px/22px 'Source Sans Pro', sans-serif; + font: 400 14px/22px var(--base-font); color: #282b39; } @@ -393,6 +394,28 @@ } } + .modal-processing { + display: flex; + background: #f6f9fc; + flex-direction: column; + justify-content: center; + align-items: center; + text-align: center; + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; + z-index: 1; + + .mdi { + font-size: 40px; + display: flex; + opacity: 0.5; + color: var(--color-primary); + } + } + &:last-child { border-bottom: none; border-bottom-left-radius: inherit; @@ -891,6 +914,10 @@ .phone-control { margin-bottom: 10px; } + + .modal-text { + text-align: left; + } } } diff --git a/react/assets/forus-platform/scss/_common/components/tables.scss b/react/assets/forus-platform/scss/_common/components/tables.scss index b7ccef442..18e18b5c1 100644 --- a/react/assets/forus-platform/scss/_common/components/tables.scss +++ b/react/assets/forus-platform/scss/_common/components/tables.scss @@ -414,6 +414,10 @@ &.td-media-round { border-radius: 70px; } + + &.td-media-borderless { + border: none; + } } .td-boolean { diff --git a/react/assets/forus-platform/scss/_common/dashboard.scss b/react/assets/forus-platform/scss/_common/dashboard.scss index d6410b501..17521b17a 100644 --- a/react/assets/forus-platform/scss/_common/dashboard.scss +++ b/react/assets/forus-platform/scss/_common/dashboard.scss @@ -51,7 +51,6 @@ @import 'blocks/block-app_links.scss'; @import 'blocks/block-timeframe.scss'; @import 'blocks/block-financial-dashboard.scss'; - @import 'blocks/block-banner-picker.scss'; @import 'blocks/block-markdownable.scss'; @import 'blocks/block-markdown.scss'; @import 'blocks/block-switch-table.scss'; @@ -87,6 +86,8 @@ @import 'blocks/block-toast.scss'; } +@import 'blocks/block-banner-editor'; +@import 'blocks/block-color-picker'; @import 'blocks/block-info-box.scss'; @import 'blocks/block-fund-amounts.scss'; @import 'blocks/block-info-with-icon.scss'; diff --git a/react/assets/forus-platform/scss/_common/includes/common.scss b/react/assets/forus-platform/scss/_common/includes/common.scss index 62a846c62..9e3dc5738 100644 --- a/react/assets/forus-platform/scss/_common/includes/common.scss +++ b/react/assets/forus-platform/scss/_common/includes/common.scss @@ -1,3 +1,10 @@ +:focus-visible { + outline: var(--focus-outline) !important; + outline-offset: var(--focus-outline-offset) !important; + box-shadow: var(--focus-box-shadow) !important; + z-index: 1; +} + body { background: #f1f4f7; min-height: 100vh; @@ -68,7 +75,7 @@ img { } .text-center { - text-align: center; + text-align: center !important; } .text-left { diff --git a/react/assets/forus-platform/scss/_common/landing.scss b/react/assets/forus-platform/scss/_common/landing.scss index 254feccfe..997ee313a 100644 --- a/react/assets/forus-platform/scss/_common/landing.scss +++ b/react/assets/forus-platform/scss/_common/landing.scss @@ -494,198 +494,6 @@ ui-view { margin: 40px 0 40px; } - &.section-header { - padding: 40px 0 40px; - position: relative; - margin: 0 auto; - width: 100%; - background-size: cover; - background: no-repeat center center; - @include cf(); - - .heade-sprite { - background: no-repeat 100% 0%; - background-size: auto 100%; - @include fill_parent(); - bottom: -50px; - z-index: 2; - } - - .header-body { - position: relative; - @include cf(); - - &.header-body-sprite-fill { - position: initial; - } - } - - .header-content { - position: relative; - z-index: 3; - text-align: center; - padding: 125px 0; - color: #fff; - - .header-title { - font: 700 40px/50px var(--base-font-landing); - margin: 0 0 25px; - } - - .header-description { - font: 400 22px/36px var(--base-font-landing); - margin: 0 0 50px; - } - - .header-download-apps { - margin-right: -60px; - padding-top: 50px; - - .app-item { - width: 100%; - display: block; - margin-bottom: 20px; - padding: 50px 50px 50px 200px; - font: 700 18px/30px var(--base-font-landing); - position: relative; - color: #282b39; - overflow: hidden; - border-radius: 5px; - background: #fff; - text-align: left; - transition: 0.4s; - transform: translate(0, 0); - box-shadow: 5px 15px 30px rgba($color: #000000, $alpha: 0.05); - - .mdi { - top: 50%; - right: 40px; - position: absolute; - transform: translate(0, -50%); - font-size: 18px; - color: #5374d9; - } - - &:before { - content: ''; - position: absolute; - display: block; - width: 225px; - height: 200px; - left: -60px; - top: 50%; - border-radius: 200px; - background-color: #f9fbf0; - background-image: assetUrl('../img/icon-app/app-store-android.svg'); - background-repeat: no-repeat; - background-position: 70% 50%; - transform: translate(0, -50%); - } - - &.app-item-ios { - &:before { - background-color: #f2fafd; - // background-image: assetUrl('../img/icon-app/app-store-ios.svg'); - } - } - - &:hover { - transform: translate(0, -5px); - box-shadow: 5px 20px 40px rgba($color: #000000, $alpha: 0.15); - } - - &:last-child { - margin-bottom: 0; - } - } - } - } - - .header-sprite { - position: absolute; - width: 50%; - height: 100%; - top: 0; - right: 0; - background-position: 100% 100px; - background-repeat: no-repeat; - background-size: 100%; - } - - .lang-selector { - float: left; - padding: 20px 20px; - cursor: pointer; - position: relative; - margin: -20px 0; - - .lang-label { - padding: 4px 0 0; - font: 400 10px/16px var(--base-font-landing); - - .mdi { - display: block; - width: 20px; - color: #064597; - float: left; - font-size: 16px; - margin-left: -20px; - } - } - - .lang-active { - font: 700 13px/20px var(--base-font-landing); - } - - .lang-list { - position: absolute; - border: 1px solid #e8edf1; - text-align: center; - background: #fff; - border-radius: 5px; - margin-top: 10px; - left: 50%; - transform: translate(-50%); - padding: 10px 0; - display: none; - - &:before { - content: ''; - display: block; - width: 20px; - height: 10px; - position: absolute; - bottom: 100%; - left: 50%; - transform: translate(-50%, 0); - background: assetUrl('img/popup-arrow.png'); - } - - .lang-list-item { - padding: 5px 15px; - min-width: 110px; - font: 600 12px/18px var(--base-font-landing); - background: #fff; - transition: background 0.4s; - - &:hover { - background: #d2e6ff; - } - } - } - - &:hover { - .lang-list { - display: block; - } - } - } - - &.section-header-landing { - padding-bottom: 0; - } - } - &.section-faq { position: relative; margin: 0 0 40px; @@ -947,24 +755,6 @@ ui-view { margin: 0 0 20px; font: 700 30px/40px var(--base-font-landing); } - - &.section-header { - .heade-sprite { - bottom: 100px; - } - - .header-content { - .header-title { - font: 700 30px/46px var(--base-font-landing); - margin: 0 0 20px; - } - - .header-description { - font: 400 18px/30px var(--base-font-landing); - margin: 0 0 20px; - } - } - } } @media screen and (max-width: 1000px) { @@ -973,90 +763,6 @@ ui-view { margin: 0 0 20px; } - &.section-header { - padding: 0; - margin: 0 0 30px; - - .heade-sprite { - display: none; - } - - .lang-selector { - margin: -10px 0; - padding: 10px 20px 10px 30px; - - .lang-list { - left: 50%; - margin-left: -20px; - margin-top: 8px; - transform: none; - - &:before { - left: 15px; - } - } - } - - .header-content { - .button { - width: 100%; - } - - @media screen and (min-width: 1024px) { - width: 100%; - text-align: center; - position: relative; - margin: 0 auto; - } - - .header-title { - font: 700 20px/28px var(--base-font-landing); - margin: 0 0 20px; - } - - .header-description { - font: 400 14px/24px var(--base-font-landing); - margin: 0; - color: #fff; - } - - .button { - text-align: center; - font-size: 11px; - padding: 12px 10px; - width: 100%; - } - - .header-download-apps { - padding: 0; - margin: 0 0 0; - - .app-item { - padding: 25px 20px 25px 90px; - font: 700 12px/20px var(--base-font-landing); - @include ellipsis(); - - &:before { - width: 70px; - height: 100%; - border-radius: 0; - left: 0; - background-size: 50px; - background-position: 50%; - } - - .mdi { - display: none; - } - } - } - } - - .header-sprite { - display: none; - } - } - &.section-contact_form { .wrapper { padding: 0; diff --git a/react/assets/forus-platform/scss/_common/select-controls/select-control-organizations.scss b/react/assets/forus-platform/scss/_common/select-controls/select-control-organizations.scss index 10b1623a2..02e646168 100644 --- a/react/assets/forus-platform/scss/_common/select-controls/select-control-organizations.scss +++ b/react/assets/forus-platform/scss/_common/select-controls/select-control-organizations.scss @@ -69,7 +69,8 @@ } .select-control-search-icon { - padding: calc(calc(calc(var(--control-height) - 2px) - var(--control-line-height)) / 2) 6px calc(calc(calc(var(--control-height) - 2px) - var(--control-line-height)) / 2) 10px; + padding: calc(calc(calc(var(--control-height) - 2px) - var(--control-line-height)) / 2) 6px + calc(calc(calc(var(--control-height) - 2px) - var(--control-line-height)) / 2) 10px; width: 40px; .mdi { @@ -116,7 +117,8 @@ input { border: none; font: 500 13px / var(--control-line-height) var(--base-font); - padding: calc(calc(calc(var(--control-height) - 2px) - var(--control-line-height)) / 2) 35px calc(calc(calc(var(--control-height) - 2px) - var(--control-line-height)) / 2) 0; + padding: calc(calc(calc(var(--control-height) - 2px) - var(--control-line-height)) / 2) 35px + calc(calc(calc(var(--control-height) - 2px) - var(--control-line-height)) / 2) 0; color: #151b26; width: 100%; background-color: transparent; @@ -139,8 +141,9 @@ &:focus-visible, &:hover, &:active { - border: none; - outline: none; + border: none !important; + outline: none !important; + box-shadow: none !important; } } } diff --git a/react/assets/forus-platform/scss/general/style-dashboard-general.scss b/react/assets/forus-platform/scss/general/style-dashboard-general.scss index aff28af80..bdfcfb3d0 100644 --- a/react/assets/forus-platform/scss/general/style-dashboard-general.scss +++ b/react/assets/forus-platform/scss/general/style-dashboard-general.scss @@ -9,17 +9,6 @@ height: 100%; @import '../_common/landing'; - .section { - &.section-header { - background-size: contain; - background: url(../img/landing/splash-top-b.png) no-repeat center center; - - .header-content { - color: var(--text-color); - } - } - } - .app.app-container { padding: 0; margin: 0; diff --git a/react/assets/forus-platform/scss/general/vars.scss b/react/assets/forus-platform/scss/general/vars.scss index fb70be845..ea7b0993a 100644 --- a/react/assets/forus-platform/scss/general/vars.scss +++ b/react/assets/forus-platform/scss/general/vars.scss @@ -25,6 +25,11 @@ --box-shadow: 1px 1px 6px 0 rgba(0, 0, 0, 0.1); + // Outline + --focus-outline: 2px solid #315efd; + --focus-outline-offset: 2px; + --focus-box-shadow: 0 0 0 3px white; + // sign up --sign_up_accent_color: #305dfb; --sign_up_accent_color_light: #bdcbff; diff --git a/react/assets/forus-webshop/scss/_common/components/_buttons.scss b/react/assets/forus-webshop/scss/_common/components/_buttons.scss index fc1ea4f1c..1b5ea42d4 100644 --- a/react/assets/forus-webshop/scss/_common/components/_buttons.scss +++ b/react/assets/forus-webshop/scss/_common/components/_buttons.scss @@ -85,6 +85,12 @@ filter: brightness(5); } } + + &.button-light-strict { + color: #303030 !important; + background: #fff !important; + border-color: #fff !important; + } } &.button-primary-outline { diff --git a/react/assets/forus-webshop/scss/_common/components/_form.scss b/react/assets/forus-webshop/scss/_common/components/_form.scss index b3466aa33..c7f98bbbd 100644 --- a/react/assets/forus-webshop/scss/_common/components/_form.scss +++ b/react/assets/forus-webshop/scss/_common/components/_form.scss @@ -336,6 +336,29 @@ border-bottom: none; } } + + &.select-control-options-fd { + position: initial; + left: auto; + top: auto; + width: auto; + z-index: 2; + margin: 0 0 0; + border: 1px solid #d4d9dd !important; + border-radius: var(--border-radius); + + &.select-control-options-fd-bottom { + border-top: none !important; + border-top-left-radius: 0 !important; + border-top-right-radius: 0 !important; + } + + &.select-control-options-fd-top { + border-bottom: none !important; + border-bottom-left-radius: 0 !important; + border-bottom-right-radius: 0 !important; + } + } } &.options { @@ -363,12 +386,15 @@ } .select-control.select-control-country-codes { + z-index: 2; + border: none !important; + .select-control-input { --option-height: 30px; .form-control:not([type='radio']):not([type='checkbox']).select-control-search { font: 600 16px/24px var(--base-font); - border: none; + border: none !important; text-align: left; box-shadow: none; padding-right: 30px; @@ -1107,6 +1133,7 @@ flex-direction: column; justify-content: center; cursor: pointer; + z-index: 1; .mdi { color: #004d93; diff --git a/react/assets/forus-webshop/scss/_common/components/frame-director.scss b/react/assets/forus-webshop/scss/_common/components/frame-director.scss new file mode 100644 index 000000000..35b9aff22 --- /dev/null +++ b/react/assets/forus-webshop/scss/_common/components/frame-director.scss @@ -0,0 +1,15 @@ +.frame-director { + width: 100vw; + height: 100%; + position: absolute; + z-index: 100; + left: 0; + top: 0; + overflow: hidden; + pointer-events: none; + + .fd-content { + position: absolute; + pointer-events: initial; + } +} \ No newline at end of file diff --git a/react/assets/forus-webshop/scss/_common/includes/shame.scss b/react/assets/forus-webshop/scss/_common/includes/shame.scss index d08c9af6a..227f9c651 100644 --- a/react/assets/forus-webshop/scss/_common/includes/shame.scss +++ b/react/assets/forus-webshop/scss/_common/includes/shame.scss @@ -66,8 +66,7 @@ html { } body { - background-color: var(--bg); - background: var(--bg_2); + background: var(--body-background); background-size: cover; display: flex; min-height: 100vh; diff --git a/react/assets/forus-webshop/scss/_common/layout/_grid.scss b/react/assets/forus-webshop/scss/_common/layout/_grid.scss index 3c01bc87c..bf829b927 100644 --- a/react/assets/forus-webshop/scss/_common/layout/_grid.scss +++ b/react/assets/forus-webshop/scss/_common/layout/_grid.scss @@ -1,18 +1,7 @@ .wrapper { width: var(--wrapper-width); - max-width: 100%; margin: 0 auto; display: block; + padding: 0 var(--wrapper-padding); + max-width: 100%; } - -@media screen and (max-width: 1300px) { - .wrapper { - padding: 0 25px; - } -} - -@media screen and (max-width: 1024px) { - .wrapper { - padding: 0 20px; - } -} \ No newline at end of file diff --git a/react/assets/forus-webshop/scss/_common/layout/_header.scss b/react/assets/forus-webshop/scss/_common/layout/_header.scss index 6710d76aa..fdcfdc914 100644 --- a/react/assets/forus-webshop/scss/_common/layout/_header.scss +++ b/react/assets/forus-webshop/scss/_common/layout/_header.scss @@ -12,165 +12,6 @@ color: var(--tc); } - &.section-header { - width: 100%; - position: relative; - z-index: 2; - cursor: default; - background-size: cover; - background-position: center center; - background-repeat: no-repeat; - padding: 50px 0; - margin-bottom: 40px; - @include cf(); - - .header-overlay { - z-index: 1; - opacity: 0; - background-color: rgba($color: #000000, $alpha: 0.8); - @include fill_parent(); - - &.header-overlay-pattern { - background-size: 10px; - background-color: transparent; - } - } - - .header-note { - position: absolute; - bottom: 10px; - right: 15px; - color: #fff; - font: 400 16px/32px var(--base-font); - } - - .wrapper { - position: relative; - z-index: 2; - } - - .header-body { - position: relative; - @include cf(); - } - - .header-content { - padding: var(--header-banner-pane-banner-padding); - max-width: var(--header-banner-pane-banner-max-width); - background: var(--header-banner-pane-banner-background); - border: var(--header-banner-pane-banner-border); - border-radius: var(--header-banner-pane-banner-border-radius); - text-align: left; - color: #fff; - text-shadow: 1px 2px 2px rgba($color: #dfb1b1, $alpha: 0.15); - - .header-read-speaker { - display: inline-flex !important; - margin: 0 0 15px !important; - } - - .header-title { - color: inherit; - font: 700 48px/1.3em var(--hf); - margin: 0 0 20px; - text-shadow: inherit; - } - - .header-description { - color: inherit; - font: 400 21px/1.5em var(--base-font); - text-shadow: inherit; - text-align: inherit; - margin: 0 0 20px; - - p, - ul, - ol, - li, - ol, - .block-markdown { - color: inherit; - font: inherit !important; - margin: 0 0 10px; - text-shadow: inherit; - text-align: inherit; - - &:last-child { - margin-bottom: 0; - } - } - - &:last-child { - margin-bottom: 0; - } - } - - .header-how-it-works { - text-decoration: underline; - cursor: pointer; - margin: 0 0 20px; - font: 400 15px/1.5em var(--base-font); - font-style: italic; - color: inherit; - display: inline-block; - - &:last-child { - margin-bottom: 0; - } - } - } - - &:before, - &:after { - position: relative; - z-index: 2; - } - - &:last-child { - margin-bottom: 0; - } - - &.section-header-dark { - .header-title, - .header-description, - .header-how-it-works { - text-shadow: none; - color: var(--tc); - } - } - - @media screen and (max-width: 1000px) { - padding: 30px 0 0; - background-image: none !important; - margin-bottom: 30px; - - .header-overlay { - display: none; - } - - .header-content { - text-align: center; - max-width: 100%; - padding: 0; - color: var(--tc); - - .header-title { - font: 700 28px/1.5em var(--hf); - margin: 0 0 15px; - } - - .header-description { - font: 300 16px/1.5em var(--base-font); - margin: 0 0 10px; - } - } - - &:last-child { - margin-bottom: 0; - } - } - } - .section-title { @media screen and (max-width: 1000px) { font: 500 1.6em var(--hf); diff --git a/react/assets/forus-webshop/scss/_common/sections/blocks/block-banner.scss b/react/assets/forus-webshop/scss/_common/sections/blocks/block-banner.scss new file mode 100644 index 000000000..8ac8e851b --- /dev/null +++ b/react/assets/forus-webshop/scss/_common/sections/blocks/block-banner.scss @@ -0,0 +1,331 @@ +.block.block-banner { + --wrapper-banner-width: var(--wrapper-width); + --wrapper-banner-padding: var(--wrapper-padding); + + @media screen and (min-width: 1000px) { + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + position: relative; + + .banner-container { + display: flex; + flex-direction: row; + justify-content: center; + align-items: flex-start; + flex: 0 0 var(--wrapper-banner-width); + + .banner-container-wrapper { + display: flex; + flex-direction: row; + justify-content: flex-start; + align-items: center; + flex: 0 1 var(--wrapper-banner-width); + padding: 120px 80px; + + .banner-container-wrapper-pane { + display: flex; + flex-direction: column; + justify-content: center; + align-items: flex-start; + flex: 0 0 60%; + padding: 40px 50px; + gap: 20px; + border-radius: var(--border-radius); + cursor: default; + + .banner-title { + font: 700 48px/64px var(--base-font); + margin: 0 0 0; + } + + .banner-description { + font: 400 20px/30px var(--base-font); + margin: 0 0 0; + + p:last-child { + margin-bottom: 0; + } + } + + .banner-actions { + .banner-actions-button { + &.banner-actions-button-white { + outline-offset: -1px !important; + } + } + } + } + } + } + + .banner-background { + position: absolute; + left: 50%; + top: 0; + bottom: 0; + transform: translate(-50%); + width: var(--wrapper-banner-width); + background-size: cover; + background-position: center; + z-index: -1; + + .banner-background-pattern { + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; + background-size: 10px; + } + } + + &.block-banner-position-center { + .banner-container { + .banner-container-wrapper { + .banner-container-wrapper-pane { + flex: 0 0 100%; + } + } + } + } + + &.block-banner-position-right { + .banner-container { + .banner-container-wrapper { + justify-content: flex-end; + } + } + } + + &.block-banner-collapse { + .banner-container { + .banner-container-wrapper { + padding: 0 0; + + .banner-container-wrapper-pane { + flex: 0 0 50%; + border-radius: 0; + padding: 70px 80px; + } + } + } + + .banner-background { + width: calc(var(--wrapper-banner-width) / 2); + transform: translate(0); + } + + &.block-banner-position-center { + .banner-container { + .banner-container-wrapper { + .banner-container-wrapper-pane { + flex: 0 0 100%; + padding-right: 300px; + } + } + } + + &:not(.block-banner-wide) { + .banner-background { + display: none; + } + } + } + + &.block-banner-position-right { + .banner-background { + transform: translate(-100%); + } + } + } + + &.block-banner-wide { + .banner-container { + flex: 0 0 100%; + + .banner-container-wrapper { + padding: 75px var(--wrapper-banner-padding); + } + } + + .banner-background { + width: 100%; + } + + &.block-banner-collapse { + &.block-banner-position-left { + .banner-container { + .banner-container-wrapper { + .banner-container-wrapper-pane { + padding-left: 0; + + &:before { + content: ''; + left: 0; + right: 50%; + top: 0; + bottom: 0; + background: inherit; + display: block; + position: absolute; + z-index: -1; + } + } + } + } + + .banner-background { + width: 50%; + display: block; + transform: translate(0%); + } + } + + &.block-banner-position-center { + .banner-background { + width: 100%; + display: block; + transform: translate(-50%); + } + } + + &.block-banner-position-right { + .banner-container { + .banner-container-wrapper { + .banner-container-wrapper-pane { + padding-right: 0; + + &:before { + content: ''; + left: 50%; + right: 0; + top: 0; + bottom: 0; + background: inherit; + display: block; + position: absolute; + z-index: -1; + } + } + } + } + + .banner-background { + width: 50%; + display: block; + transform: translate(-100%); + } + } + } + } + + &.block-banner-transparent { + .banner-container { + .banner-container-wrapper { + .banner-container-wrapper-pane { + padding: 0 0; + } + } + } + } + } + + @media screen and (max-width: 999px) { + display: flex; + flex-direction: column; + position: relative; + + .banner-background { + height: 240px; + width: 100%; + background-size: cover; + background-position: center; + position: relative; + + .banner-background-pattern { + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; + background-size: 10px; + } + } + + .banner-container { + .banner-container-wrapper { + .banner-container-wrapper-pane { + padding: 40px 25px 40px; + display: flex; + flex-direction: column; + align-items: center; + gap: 10px; + + .banner-title { + margin: 0 0; + font: 700 30px/40px var(--base-font); + text-align: center; + } + + .banner-description { + margin: 0 0; + font: 400 14px/21px var(--base-font); + + * { + text-align: center !important; + } + } + + .banner-actions { + display: flex; + flex-direction: column; + align-items: center; + } + } + } + } + + &.block-banner-background-empty { + .banner-background { + display: none; + } + } + + &.block-banner-transparent { + .banner-background { + z-index: 0; + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + } + + .banner-container { + z-index: 1; + } + } + + &.block-banner-background-mobile-hide { + .banner-background { + display: none; + } + } + } + + @media screen and (max-width: 420px) { + .banner-container { + .banner-container-wrapper { + .banner-container-wrapper-pane { + .banner-actions { + .banner-actions-button { + width: 100%; + } + } + } + } + } + } +} diff --git a/react/assets/forus-webshop/scss/_common/sections/blocks/block-lang-control.scss b/react/assets/forus-webshop/scss/_common/sections/blocks/block-lang-control.scss index 5782ec536..e2a4764c3 100644 --- a/react/assets/forus-webshop/scss/_common/sections/blocks/block-lang-control.scss +++ b/react/assets/forus-webshop/scss/_common/sections/blocks/block-lang-control.scss @@ -60,6 +60,10 @@ .lang-control-option-name { flex: 1 1 auto; + + &.lang-control-option-name-right { + text-align: right; + } } .lang-control-option-check { diff --git a/react/assets/forus-webshop/scss/_common/sections/blocks/block-navbar-desktop.scss b/react/assets/forus-webshop/scss/_common/sections/blocks/block-navbar-desktop.scss index 0c7d676b6..693eef496 100644 --- a/react/assets/forus-webshop/scss/_common/sections/blocks/block-navbar-desktop.scss +++ b/react/assets/forus-webshop/scss/_common/sections/blocks/block-navbar-desktop.scss @@ -18,7 +18,7 @@ .navbar-desktop-section-wrapper { width: var(--wrapper-width); max-width: 100%; - padding: 0 0; + padding: 0 var(--wrapper-padding); display: flex; flex-direction: row; align-items: center; @@ -357,14 +357,6 @@ } } - @media screen and (max-width: 1300px) { - .navbar-desktop-section { - .navbar-desktop-section-wrapper { - padding: 0 25px; - } - } - } - @media screen and (max-width: 1150px) { .navbar-desktop-menu { gap: 15px; diff --git a/react/assets/forus-webshop/scss/_common/sections/blocks/block-showcase.scss b/react/assets/forus-webshop/scss/_common/sections/blocks/block-showcase.scss index 2d2c446fb..2e6fe92f4 100644 --- a/react/assets/forus-webshop/scss/_common/sections/blocks/block-showcase.scss +++ b/react/assets/forus-webshop/scss/_common/sections/blocks/block-showcase.scss @@ -17,7 +17,8 @@ } .showcase-wrapper { - width: 1280px; + width: var(--wrapper-width); + padding: 0 var(--wrapper-padding); max-width: 100%; margin: 0 auto; display: block; @@ -461,10 +462,6 @@ } @media screen and (max-width: 1300px) { - .showcase-wrapper { - padding: 0 25px; - } - .showcase-layout { .showcase-aside { width: 280px; @@ -506,7 +503,6 @@ } .showcase-wrapper { - padding: 0 20px 10px; position: relative; } diff --git a/react/assets/forus-webshop/scss/berkelland/components/_buttons.scss b/react/assets/forus-webshop/scss/berkelland/components/_buttons.scss index ea2804eba..c0a800fe2 100644 --- a/react/assets/forus-webshop/scss/berkelland/components/_buttons.scss +++ b/react/assets/forus-webshop/scss/berkelland/components/_buttons.scss @@ -12,7 +12,7 @@ &:hover { color: var(--color-default); text-decoration: underline; - background-color: var(--bg); + background-color: #ececec; box-shadow: none; border: 1px solid var(--color-default); } diff --git a/react/assets/forus-webshop/scss/berkelland/layout/_header.scss b/react/assets/forus-webshop/scss/berkelland/layout/_header.scss deleted file mode 100644 index 607e60df7..000000000 --- a/react/assets/forus-webshop/scss/berkelland/layout/_header.scss +++ /dev/null @@ -1,10 +0,0 @@ -.section { - &.section-header { - .header-content { - margin: 0 auto; - max-width: 800px; - text-align: center; - font: 700 40px/1.5em var(--base-font); - } - } -} \ No newline at end of file diff --git a/react/assets/forus-webshop/scss/ede/includes/shame.scss b/react/assets/forus-webshop/scss/ede/includes/shame.scss index a38d90c74..4f45ba661 100644 --- a/react/assets/forus-webshop/scss/ede/includes/shame.scss +++ b/react/assets/forus-webshop/scss/ede/includes/shame.scss @@ -70,28 +70,6 @@ ui-view { } .section { - &.section-header { - padding: 50px 0; - margin: 0 auto; - width: 1280px; - max-width: 100%; - - .header-content { - text-align: center; - padding: 50px 50px; - background-color: #ffffff; - - .header-title { - font: 600 32px/1.3em var(--base-font); - } - - .header-description p { - text-align: center !important; - font: 400 16px/1.5em var(--base-font) !important; - } - } - } - &.section-faq { .faq { width: auto; @@ -104,24 +82,6 @@ ui-view { padding-top: 30px; color: #fff; } - - @media screen and (min-width: 1000px) { - &.section-header { - height: auto; - padding: 30px 0; - - .header-content { - text-align: left; - padding: 30px 50px; - margin-left: 50px; - background-color: #3558A2; - - .header-description p { - text-align: left !important; - } - } - } - } } .block { diff --git a/react/assets/forus-webshop/scss/eemsdelta/includes/shame.scss b/react/assets/forus-webshop/scss/eemsdelta/includes/shame.scss index 77942c35b..7f6e5dc90 100644 --- a/react/assets/forus-webshop/scss/eemsdelta/includes/shame.scss +++ b/react/assets/forus-webshop/scss/eemsdelta/includes/shame.scss @@ -6,15 +6,4 @@ } } } -} - -@media screen and (min-width: 1000px) { - .section { - &.section-header { - .header-content { - padding: 80px 80px; - background-color: #004680; - } - } - } } \ No newline at end of file diff --git a/react/assets/forus-webshop/scss/geertruidenberg/includes/shame.scss b/react/assets/forus-webshop/scss/geertruidenberg/includes/shame.scss index 2f56474d6..1085945bf 100644 --- a/react/assets/forus-webshop/scss/geertruidenberg/includes/shame.scss +++ b/react/assets/forus-webshop/scss/geertruidenberg/includes/shame.scss @@ -1,27 +1,3 @@ -// Header -@media screen and (min-width: 1024px) { - .section { - &.section-header { - display: flex; - flex-direction: column; - justify-content: center; - - &:before { - content: ''; - width: 100%; - height: 80px; - background: #69c url(./assets/img/header-frame-after.svg); - bottom: 0; - position: absolute; - } - - .header-content { - color: var(--tc-var); - padding: 80px 0 160px; - } - } - } -} // Footer .section { diff --git a/react/assets/forus-webshop/scss/goereeoverflakkee/layout/_header.scss b/react/assets/forus-webshop/scss/goereeoverflakkee/layout/_header.scss deleted file mode 100644 index 09405d4db..000000000 --- a/react/assets/forus-webshop/scss/goereeoverflakkee/layout/_header.scss +++ /dev/null @@ -1,44 +0,0 @@ -.section { - &.section-header { - padding: 120px 0; - - .header-content { - background: #fff; - padding: 60px 60px; - border-radius: var(--border-radius); - max-width: 760px; - - .header-title { - font: 400 56px/62px var(--hf); - color: #0B0E12; - } - - .header-description { - font: 400 20px/30px var(--hf); - color: #0B0E12; - } - - .header-how-it-works { - color: #627C18; - } - } - - @media screen and (max-width: 1000px) { - padding: 0 0; - - .header-content { - padding: 30px 0px 0; - - .header-title { - font: 500 28px/38px var(--hf); - color: #0B0E12; - } - - .header-description { - font: 400 14px/22px var(--hf); - color: #0B0E12; - } - } - } - } -} diff --git a/react/assets/forus-webshop/scss/groningen/components/_buttons.scss b/react/assets/forus-webshop/scss/groningen/components/_buttons.scss index c9f4e7cb1..a3c3be772 100644 --- a/react/assets/forus-webshop/scss/groningen/components/_buttons.scss +++ b/react/assets/forus-webshop/scss/groningen/components/_buttons.scss @@ -21,7 +21,7 @@ &:hover { color: var(--color-default); - background-color: var(--bg); + background-color: #fff; box-shadow: none; border: 1px solid var(--color-default); } diff --git a/react/assets/forus-webshop/scss/groningen/layout/_header.scss b/react/assets/forus-webshop/scss/groningen/layout/_header.scss deleted file mode 100644 index 4d29ef7af..000000000 --- a/react/assets/forus-webshop/scss/groningen/layout/_header.scss +++ /dev/null @@ -1,21 +0,0 @@ -.section { - &.section-header { - @media screen and (min-width: 1024px) { - .wrapper { - background-image: url(./assets/img/header-bg-element.svg); - background-repeat: no-repeat; - background-position: right; - } - - .header-content { - .header-title { - font-size: 32px; - } - - .header-description { - font-size: 20px; - } - } - } - } -} diff --git a/react/assets/forus-webshop/scss/kerstpakket/layout/_header.scss b/react/assets/forus-webshop/scss/kerstpakket/layout/_header.scss deleted file mode 100644 index b37a9c46b..000000000 --- a/react/assets/forus-webshop/scss/kerstpakket/layout/_header.scss +++ /dev/null @@ -1,29 +0,0 @@ -.section { - &.section-header { - background: var(--bg-values); - background-size: contain; - background-position: right top; - - .header-content { - display: flex; - flex-direction: column; - justify-self: center; - - .header-title { - font-family: var(--base-font)_2; - } - } - - @media screen and (max-width: 1600px) { - .wrapper { - display: flex; - flex-direction: row; - justify-content: center; - } - - .header-content { - text-align: center; - } - } - } -} diff --git a/react/assets/forus-webshop/scss/noordoostpolder/layout/_header.scss b/react/assets/forus-webshop/scss/noordoostpolder/layout/_header.scss deleted file mode 100644 index 1ee69e107..000000000 --- a/react/assets/forus-webshop/scss/noordoostpolder/layout/_header.scss +++ /dev/null @@ -1,71 +0,0 @@ -.section { - &.section-header { - padding: 80px 0; - - .header-content { - left: 0; - right: 0; - margin: 0 auto; - text-align: center; - z-index: 2; - height: 100%; - max-width: 650px; - - .header-title { - font-size: 40px; - } - - .header-description { - font-size: 18px; - } - - .header-how-it-works { - color: var(--tc-var); - font-style: normal; - - &:hover { - color: #f5ffc4; - } - } - - .button { - &:hover { - background-color: #fff; - color: var(--bc); - } - } - } - - &:before, - &:after { - position: absolute; - display: block; - width: 100%; - top: -2px; - bottom: -2px; - z-index: 1; - content: ' '; - background-size: auto 100%; - background-repeat: no-repeat; - } - - &:before { - left: -2px; - background-image: url('./assets/img/left-leaf.png'); - background-position: top left; - } - - &:after { - right: -2px; - background-image: url('./assets/img/splash-top-b.png'); - background-position: top right; - } - - @media screen and (max-width: 1000px) { - &:before, - &:after { - content: none; - } - } - } -} diff --git a/react/assets/forus-webshop/scss/oostgelre/layout/_header.scss b/react/assets/forus-webshop/scss/oostgelre/layout/_header.scss deleted file mode 100644 index 7e0a3ea81..000000000 --- a/react/assets/forus-webshop/scss/oostgelre/layout/_header.scss +++ /dev/null @@ -1,17 +0,0 @@ -.section { - &.section-header { - .header-content { - max-width: 800px; - margin: 0 auto; - text-align: center; - - .header-title { - font-size: 40px; - } - - .header-description { - font-size: 18px; - } - } - } -} \ No newline at end of file diff --git a/react/assets/forus-webshop/scss/schagen/includes/shame.scss b/react/assets/forus-webshop/scss/schagen/includes/shame.scss index 3445642e1..32a39ac83 100644 --- a/react/assets/forus-webshop/scss/schagen/includes/shame.scss +++ b/react/assets/forus-webshop/scss/schagen/includes/shame.scss @@ -85,21 +85,6 @@ } .section { - &.section-header { - background-position: top center; - padding: 50px 0; - margin: 0 auto; - max-width: 100%; - - .header-content { - text-align: center; - - .header-description p { - text-align: center !important; - } - } - } - &.section-faq { .faq { width: auto; @@ -114,23 +99,6 @@ } @media screen and (min-width: 1000px) { - &.section-header { - height: 500px; - padding: 75px 0; - - .header-content { - text-align: left; - padding: 50px 50px; - margin-left: 50px; - background-color: #ffffff; - text-align: left; - - .header-description p { - text-align: left !important; - } - } - } - &.section-products { width: 100vw; background: #f4f5f7; diff --git a/react/assets/forus-webshop/scss/style-webshop-berg_en_dal-vars.scss b/react/assets/forus-webshop/scss/style-webshop-berg_en_dal-vars.scss index d8e6aee72..70d5e3047 100644 --- a/react/assets/forus-webshop/scss/style-webshop-berg_en_dal-vars.scss +++ b/react/assets/forus-webshop/scss/style-webshop-berg_en_dal-vars.scss @@ -24,7 +24,7 @@ $primaryColorLight: #1B8761; --header-banner-pane-banner-background: #fff; --header-banner-pane-banner-border-radius: var(--border-radius); - --bg_2: #fff; + --body-background: #fff; --border-radius: 0; --box-shadow: 0px 6px 15px 0px rgba(0, 0, 0, 0.04), 0px 12px 12px 0px rgba(0, 0, 0, 0.08); diff --git a/react/assets/forus-webshop/scss/style-webshop-berkelland-vars.scss b/react/assets/forus-webshop/scss/style-webshop-berkelland-vars.scss index e92ffbe84..1cfd513f9 100644 --- a/react/assets/forus-webshop/scss/style-webshop-berkelland-vars.scss +++ b/react/assets/forus-webshop/scss/style-webshop-berkelland-vars.scss @@ -39,9 +39,7 @@ $primaryColorLight: #004d93; --bc: #4990b5; // background color - --bg: #ececec; - - --bg_2: none; + --body-background: none; // footer color --footer_color: #4e4d40; diff --git a/react/assets/forus-webshop/scss/style-webshop-berkelland.scss b/react/assets/forus-webshop/scss/style-webshop-berkelland.scss index 9e40581a6..0bd4c57d5 100644 --- a/react/assets/forus-webshop/scss/style-webshop-berkelland.scss +++ b/react/assets/forus-webshop/scss/style-webshop-berkelland.scss @@ -1,9 +1,6 @@ // SHAME @import "berkelland/includes/shame"; -// LAYOUTS -@import "berkelland/layout/header"; - // COMPONENTS @import "berkelland/components/buttons"; diff --git a/react/assets/forus-webshop/scss/style-webshop-ede-vars.scss b/react/assets/forus-webshop/scss/style-webshop-ede-vars.scss index 3b6cdffa9..49a2fc585 100644 --- a/react/assets/forus-webshop/scss/style-webshop-ede-vars.scss +++ b/react/assets/forus-webshop/scss/style-webshop-ede-vars.scss @@ -45,9 +45,7 @@ $primaryColorLight: #3558a2; --bc: #3558a2; // background color - --bg: #fff; - - --bg_2: none; + --body-background: none; // footer color --footer_background_color: #404040; diff --git a/react/assets/forus-webshop/scss/style-webshop-eemsdelta-vars.scss b/react/assets/forus-webshop/scss/style-webshop-eemsdelta-vars.scss index 0cb3263f2..6fb9bc921 100644 --- a/react/assets/forus-webshop/scss/style-webshop-eemsdelta-vars.scss +++ b/react/assets/forus-webshop/scss/style-webshop-eemsdelta-vars.scss @@ -47,9 +47,7 @@ $primaryColorLight: #0d4379; --bc: #22398e; // background color - --bg: #f5f5f5; - - --bg_2: none; + --body-background: none; // footer color --footer_background_color: #0d4379; diff --git a/react/assets/forus-webshop/scss/style-webshop-geertruidenberg-vars.scss b/react/assets/forus-webshop/scss/style-webshop-geertruidenberg-vars.scss index edbbd1554..d1cb58ba4 100644 --- a/react/assets/forus-webshop/scss/style-webshop-geertruidenberg-vars.scss +++ b/react/assets/forus-webshop/scss/style-webshop-geertruidenberg-vars.scss @@ -38,9 +38,7 @@ $primaryColorLight: #ee8016; --bc: #ee8016; // background color - --bg: #fff; - - --bg_2: none; + --body-background: none; // footer color --footer_background_color: #fff; diff --git a/react/assets/forus-webshop/scss/style-webshop-general-vars.scss b/react/assets/forus-webshop/scss/style-webshop-general-vars.scss index b5018db60..520c8ecfe 100644 --- a/react/assets/forus-webshop/scss/style-webshop-general-vars.scss +++ b/react/assets/forus-webshop/scss/style-webshop-general-vars.scss @@ -47,7 +47,8 @@ $primaryColorLight: #305dfb; --navbar-menu-item-line-position-bottom: auto; // wrapper - --wrapper-width: 1280px; + --wrapper-width: calc(1280px + 50px); + --wrapper-padding: 20px; // Outline --focus-outline: 2px solid #315efd; @@ -95,9 +96,7 @@ $primaryColorLight: #305dfb; --bc: #d13b3b; // background color - --bg: #f3f8fe; - - --bg_2: linear-gradient(to bottom, #f3f8fe 0%, #feffff 100%); + --body-background: #fff; // footer color --footer_background_color: #fff; diff --git a/react/assets/forus-webshop/scss/style-webshop-goereeoverflakkee-vars.scss b/react/assets/forus-webshop/scss/style-webshop-goereeoverflakkee-vars.scss index 84f59419d..524fbf9a3 100644 --- a/react/assets/forus-webshop/scss/style-webshop-goereeoverflakkee-vars.scss +++ b/react/assets/forus-webshop/scss/style-webshop-goereeoverflakkee-vars.scss @@ -39,9 +39,7 @@ $primaryColorLight: #627c18; --bc: #627c18; // background color - --bg: #fff; - - --bg_2: #fff; + --body-background: #fff; // footer color --footer_background_color: #08749b; diff --git a/react/assets/forus-webshop/scss/style-webshop-goereeoverflakkee.scss b/react/assets/forus-webshop/scss/style-webshop-goereeoverflakkee.scss index b94f84cf0..22ae0dde7 100644 --- a/react/assets/forus-webshop/scss/style-webshop-goereeoverflakkee.scss +++ b/react/assets/forus-webshop/scss/style-webshop-goereeoverflakkee.scss @@ -1,6 +1,3 @@ -// LAYOUTS -@import "goereeoverflakkee/layout/header"; - // INCLUDES @import "goereeoverflakkee/includes/buttons"; @import "goereeoverflakkee/includes/form"; diff --git a/react/assets/forus-webshop/scss/style-webshop-groningen-vars.scss b/react/assets/forus-webshop/scss/style-webshop-groningen-vars.scss index 49dcce93d..23fdbf19d 100644 --- a/react/assets/forus-webshop/scss/style-webshop-groningen-vars.scss +++ b/react/assets/forus-webshop/scss/style-webshop-groningen-vars.scss @@ -51,9 +51,7 @@ $primaryColorLight: #e60204; --bc: #e60003; // background color - --bg: #fff; - - --bg_2: none; + --body-background: none; // footer color --footer_background_color: #e60004; diff --git a/react/assets/forus-webshop/scss/style-webshop-groningen.scss b/react/assets/forus-webshop/scss/style-webshop-groningen.scss index 4deb7b94e..7b1f9540b 100644 --- a/react/assets/forus-webshop/scss/style-webshop-groningen.scss +++ b/react/assets/forus-webshop/scss/style-webshop-groningen.scss @@ -1,6 +1,5 @@ // LAYOUTS @import 'groningen/layout/footer'; -@import 'groningen/layout/header'; // COMPONENTS @import 'groningen/components/buttons'; diff --git a/react/assets/forus-webshop/scss/style-webshop-hartvanwestbrabant-vars.scss b/react/assets/forus-webshop/scss/style-webshop-hartvanwestbrabant-vars.scss index 6bd7f172d..23a5cfe2b 100644 --- a/react/assets/forus-webshop/scss/style-webshop-hartvanwestbrabant-vars.scss +++ b/react/assets/forus-webshop/scss/style-webshop-hartvanwestbrabant-vars.scss @@ -38,9 +38,7 @@ $primaryColorLight: #24a1a1; --bc: #24a1a1; // background color - --bg: #fff; - - --bg_2: none; + --body-background: none; // footer color --footer_background_color: #24a1a1; diff --git a/react/assets/forus-webshop/scss/style-webshop-heumen-vars.scss b/react/assets/forus-webshop/scss/style-webshop-heumen-vars.scss index 0845f30bd..17087af14 100644 --- a/react/assets/forus-webshop/scss/style-webshop-heumen-vars.scss +++ b/react/assets/forus-webshop/scss/style-webshop-heumen-vars.scss @@ -38,9 +38,7 @@ $primaryColorLight: #22398e; --bc: #22398e; // background color - --bg: #fff; - - --bg_2: none; + --body-background: none; // footer color --footer_background_color: #22398e; diff --git a/react/assets/forus-webshop/scss/style-webshop-kerstpakket-vars.scss b/react/assets/forus-webshop/scss/style-webshop-kerstpakket-vars.scss index 74d04962a..e6ad04495 100644 --- a/react/assets/forus-webshop/scss/style-webshop-kerstpakket-vars.scss +++ b/react/assets/forus-webshop/scss/style-webshop-kerstpakket-vars.scss @@ -39,9 +39,7 @@ $primaryColorLight: #4c74ff; --bc: #d13b3b; // background color - --bg: #fff; - - --bg_2: none; + --body-background: none; // footer color --footer_background_color: #fff; diff --git a/react/assets/forus-webshop/scss/style-webshop-kerstpakket.scss b/react/assets/forus-webshop/scss/style-webshop-kerstpakket.scss index 6457e49ac..8557493fa 100644 --- a/react/assets/forus-webshop/scss/style-webshop-kerstpakket.scss +++ b/react/assets/forus-webshop/scss/style-webshop-kerstpakket.scss @@ -2,7 +2,6 @@ @import "kerstpakket/components/buttons"; // LAYOUTS -@import "kerstpakket/layout/header"; @import "kerstpakket/layout/footer"; // SECTIONS diff --git a/react/assets/forus-webshop/scss/style-webshop-midden_drenthe-vars.scss b/react/assets/forus-webshop/scss/style-webshop-midden_drenthe-vars.scss index ae6210aaa..dc8131184 100644 --- a/react/assets/forus-webshop/scss/style-webshop-midden_drenthe-vars.scss +++ b/react/assets/forus-webshop/scss/style-webshop-midden_drenthe-vars.scss @@ -24,7 +24,7 @@ $primaryColorLight: #b31869; --header-banner-pane-banner-background: #fff; --header-banner-pane-banner-border-radius: var(--border-radius); - --bg_2: #fff; + --body-background: #fff; // footer color --footer_background_color: #eff2f5; diff --git a/react/assets/forus-webshop/scss/style-webshop-noordoostpolder-vars.scss b/react/assets/forus-webshop/scss/style-webshop-noordoostpolder-vars.scss index c354ee181..7710a6fe8 100644 --- a/react/assets/forus-webshop/scss/style-webshop-noordoostpolder-vars.scss +++ b/react/assets/forus-webshop/scss/style-webshop-noordoostpolder-vars.scss @@ -37,9 +37,7 @@ $primaryColorLight: #fd5392; --bc: #de286b; // background color - --bg: #de286b; - - --bg_2: none; + --body-background: none; // footer color --footer_background_color: #fff; diff --git a/react/assets/forus-webshop/scss/style-webshop-noordoostpolder.scss b/react/assets/forus-webshop/scss/style-webshop-noordoostpolder.scss index d5ee02e52..0f16bd082 100644 --- a/react/assets/forus-webshop/scss/style-webshop-noordoostpolder.scss +++ b/react/assets/forus-webshop/scss/style-webshop-noordoostpolder.scss @@ -1,9 +1,6 @@ // SHAME @import "noordoostpolder/includes/shame"; -// LAYOUTS -@import "noordoostpolder/layout/header"; - // COMPONENTS @import "noordoostpolder/components/label"; diff --git a/react/assets/forus-webshop/scss/style-webshop-oostgelre-vars.scss b/react/assets/forus-webshop/scss/style-webshop-oostgelre-vars.scss index ee45b7eff..f134df30c 100644 --- a/react/assets/forus-webshop/scss/style-webshop-oostgelre-vars.scss +++ b/react/assets/forus-webshop/scss/style-webshop-oostgelre-vars.scss @@ -39,9 +39,7 @@ $primaryColorLight: #660066; --bc: #660066; // background color - --bg: #ececec; - - --bg_2: none; + --body-background: none; // footer color --footer_color: #4e4d40; diff --git a/react/assets/forus-webshop/scss/style-webshop-oostgelre.scss b/react/assets/forus-webshop/scss/style-webshop-oostgelre.scss index 5641906db..797e1a988 100644 --- a/react/assets/forus-webshop/scss/style-webshop-oostgelre.scss +++ b/react/assets/forus-webshop/scss/style-webshop-oostgelre.scss @@ -1,9 +1,6 @@ // SHAME @import "oostgelre/includes/shame"; -// LAYOUTS -@import "oostgelre/layout/header"; - // COMPONENTS @import "oostgelre/components/buttons"; diff --git a/react/assets/forus-webshop/scss/style-webshop-potjeswijzer-vars.scss b/react/assets/forus-webshop/scss/style-webshop-potjeswijzer-vars.scss index 6e4b97d96..c113e707c 100644 --- a/react/assets/forus-webshop/scss/style-webshop-potjeswijzer-vars.scss +++ b/react/assets/forus-webshop/scss/style-webshop-potjeswijzer-vars.scss @@ -37,9 +37,7 @@ $primaryColorLight: #b9cb18; --bc: #000; // background color - --bg: #fff; - - --bg_2: #fff; + --body-background: #fff; // footer color --footer_background_color: #4990b5; diff --git a/react/assets/forus-webshop/scss/style-webshop-schagen-vars.scss b/react/assets/forus-webshop/scss/style-webshop-schagen-vars.scss index 9e7d68b4a..e69ab97f7 100644 --- a/react/assets/forus-webshop/scss/style-webshop-schagen-vars.scss +++ b/react/assets/forus-webshop/scss/style-webshop-schagen-vars.scss @@ -46,9 +46,7 @@ $primaryColorLight: #1c8fd7; --bc: #000; // background color - --bg: #f7f9fc; - - --bg_2: #ffffff; + --body-background: #fff; // footer color --footer_background_color: #306fb3; diff --git a/react/assets/forus-webshop/scss/style-webshop-vergoedingen-vars.scss b/react/assets/forus-webshop/scss/style-webshop-vergoedingen-vars.scss index 8adb15b08..19feffc27 100644 --- a/react/assets/forus-webshop/scss/style-webshop-vergoedingen-vars.scss +++ b/react/assets/forus-webshop/scss/style-webshop-vergoedingen-vars.scss @@ -58,9 +58,7 @@ $primaryColorLight: #2f7f6b; --bc: #000; // background color - --bg: #f7f9fc; - - --bg_2: #ffffff; + --body-background: #fff; // footer color --footer_background_color: #3a3a3a; diff --git a/react/assets/forus-webshop/scss/style-webshop-waalwijk-vars.scss b/react/assets/forus-webshop/scss/style-webshop-waalwijk-vars.scss index c4f8e550e..cd5bd765e 100644 --- a/react/assets/forus-webshop/scss/style-webshop-waalwijk-vars.scss +++ b/react/assets/forus-webshop/scss/style-webshop-waalwijk-vars.scss @@ -41,9 +41,7 @@ $primaryColorLight: #2a2a7f; --bc: #2a2a7f; // background color - --bg: #fff; - - --bg_2: none; + --body-background: none; // footer color --footer_background_color: #2f2d80; diff --git a/react/assets/forus-webshop/scss/style-webshop-wadenheuvel-vars.scss b/react/assets/forus-webshop/scss/style-webshop-wadenheuvel-vars.scss index 7b016605c..6fae45f58 100644 --- a/react/assets/forus-webshop/scss/style-webshop-wadenheuvel-vars.scss +++ b/react/assets/forus-webshop/scss/style-webshop-wadenheuvel-vars.scss @@ -37,9 +37,7 @@ $primaryColorLight: #2a2a7f; --bc: #003b3b; // background color - --bg: #fff; - - --bg_2: none; + --body-background: none; // text formatting --tf: inherit; diff --git a/react/assets/forus-webshop/scss/style-webshop-winterswijk-vars.scss b/react/assets/forus-webshop/scss/style-webshop-winterswijk-vars.scss index b83631379..4879d6ff9 100644 --- a/react/assets/forus-webshop/scss/style-webshop-winterswijk-vars.scss +++ b/react/assets/forus-webshop/scss/style-webshop-winterswijk-vars.scss @@ -37,9 +37,7 @@ $primaryColorLight: #0c6dcb; --bc: #0c6dcb; // background color - --bg: #ececec; - - --bg_2: none; + --body-background: none; // footer color --footer_color: #4e4d40; diff --git a/react/assets/forus-webshop/scss/style-webshop-winterswijk.scss b/react/assets/forus-webshop/scss/style-webshop-winterswijk.scss index 3a23f39fe..6efba5589 100644 --- a/react/assets/forus-webshop/scss/style-webshop-winterswijk.scss +++ b/react/assets/forus-webshop/scss/style-webshop-winterswijk.scss @@ -1,9 +1,6 @@ // SHAME @import "winterswijk/includes/shame"; -// LAYOUTS -@import "winterswijk/layout/header"; - // COMPONENTS @import "winterswijk/components/buttons"; diff --git a/react/assets/forus-webshop/scss/vergoedingen/includes/shame.scss b/react/assets/forus-webshop/scss/vergoedingen/includes/shame.scss index 5856a9ff2..31e7eadf4 100644 --- a/react/assets/forus-webshop/scss/vergoedingen/includes/shame.scss +++ b/react/assets/forus-webshop/scss/vergoedingen/includes/shame.scss @@ -67,32 +67,6 @@ h6 { text-align: left; } - &.section-header { - width: 1280px; - background-position: top center; - padding: 50px 0; - margin: 0 auto; - max-width: 100%; - - .header-content { - text-align: center; - - .header-description p { - text-align: center !important; - } - - .header-how-it-works { - font: 600 20px/20px var(--base-font); - color: #950022; - text-decoration: none; - } - } - - &.section-header-landing { - margin-top: 24px; - } - } - &.section-faq { .faq { width: auto; @@ -124,23 +98,6 @@ h6 { } @media screen and (min-width: 1000px) { - &.section-header { - height: 500px; - padding: 75px 0; - - .header-content { - text-align: left; - padding: 50px 50px; - margin-left: 50px; - background-color: #ffffff; - text-align: left; - - .header-description p { - text-align: left !important; - } - } - } - &.section-products { width: 100vw; background: #f5f5f5; diff --git a/react/assets/forus-webshop/scss/webshop.scss b/react/assets/forus-webshop/scss/webshop.scss index 1c381f133..7047b0870 100644 --- a/react/assets/forus-webshop/scss/webshop.scss +++ b/react/assets/forus-webshop/scss/webshop.scss @@ -34,6 +34,7 @@ @import '_common/components/skiplinks'; @import '_common/components/table'; @import '_common/components/table-pagination'; +@import '_common/components/frame-director'; // SECTIONS @import '_common/sections/faq'; @@ -135,6 +136,7 @@ @import '_common/sections/blocks/block-cookie-banner'; @import '_common/sections/blocks/block-lang-control'; @import '_common/sections/blocks/block-reservation-address'; +@import '_common/sections/blocks/block-banner'; @import '_common/modals/modal-file-preview'; @import '_common/modals/modal-photo-cropper'; diff --git a/react/assets/forus-webshop/scss/winterswijk/layout/_header.scss b/react/assets/forus-webshop/scss/winterswijk/layout/_header.scss deleted file mode 100644 index a8bf1e9d8..000000000 --- a/react/assets/forus-webshop/scss/winterswijk/layout/_header.scss +++ /dev/null @@ -1,30 +0,0 @@ -.section { - &.section-header { - .header-content { - max-width: 800px; - margin: 0 auto; - text-align: center; - font-size: 18px; - - .header-title { - font-size: 40px; - } - - .header-description { - font-size: 18px; - } - } - - @media screen and (max-width: 1000px) { - .header-content { - .header-title { - font-size: 28px; - } - - .header-description { - font-size: 16px; - } - } - } - } -} diff --git a/react/src/backend/Backend.tsx b/react/src/backend/Backend.tsx index 6b63573f1..d19956c90 100644 --- a/react/src/backend/Backend.tsx +++ b/react/src/backend/Backend.tsx @@ -60,7 +60,7 @@ export default function Backend(): React.ReactElement { - + diff --git a/react/src/dashboard/components/elements/fund-criteria-editor/FundCriteriaEditor.tsx b/react/src/dashboard/components/elements/fund-criteria-editor/FundCriteriaEditor.tsx index 2788d484e..c7120cbf6 100644 --- a/react/src/dashboard/components/elements/fund-criteria-editor/FundCriteriaEditor.tsx +++ b/react/src/dashboard/components/elements/fund-criteria-editor/FundCriteriaEditor.tsx @@ -1,4 +1,4 @@ -import React, { createRef, MutableRefObject, useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import React, { createRef, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import Fund from '../../../props/models/Fund'; import Organization from '../../../props/models/Organization'; import RecordType from '../../../props/models/RecordType'; @@ -26,7 +26,6 @@ export default function FundCriteriaEditor({ recordTypes, saveButton, onSaveCriteria, - saveCriteriaRef, className, bodyClassName, footerClassName, @@ -39,7 +38,6 @@ export default function FundCriteriaEditor({ recordTypes: Array; saveButton?: boolean; onSaveCriteria?: (criteria: Array) => void; - saveCriteriaRef?: MutableRefObject<() => Promise> | null>; className?: string; bodyClassName?: string; footerClassName?: string; @@ -153,12 +151,6 @@ export default function FundCriteriaEditor({ }); }, [criteria]); - useEffect(() => { - if (saveCriteriaRef) { - saveCriteriaRef.current = saveCriteria; - } - }, [saveCriteria, saveCriteriaRef]); - return (
diff --git a/react/src/dashboard/components/elements/fund-criteria-editor/FundCriteriaEditorItem.tsx b/react/src/dashboard/components/elements/fund-criteria-editor/FundCriteriaEditorItem.tsx index b9b1be089..1c80be134 100644 --- a/react/src/dashboard/components/elements/fund-criteria-editor/FundCriteriaEditorItem.tsx +++ b/react/src/dashboard/components/elements/fund-criteria-editor/FundCriteriaEditorItem.tsx @@ -2,7 +2,6 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react'; import Organization from '../../../props/models/Organization'; import RecordType from '../../../props/models/RecordType'; import { hasPermission } from '../../../helpers/utils'; -import SelectControlOptions from '../select-control/templates/SelectControlOptions'; import SelectControl from '../select-control/SelectControl'; import FormError from '../forms/errors/FormError'; import { ResponseError } from '../../../props/ApiResponses'; @@ -307,7 +306,6 @@ export default function FundCriteriaEditorItem({ allowSearch={true} onChange={setRecordType} options={recordTypes} - optionsComponent={SelectControlOptions} />
@@ -325,7 +323,6 @@ export default function FundCriteriaEditorItem({ propKey={'key'} value={operators[recordType.key]} options={recordType?.operators} - optionsComponent={SelectControlOptions} onChange={(operator: Operators) => { setOperators({ ...operators, [recordType.key]: operator }); }} @@ -365,7 +362,6 @@ export default function FundCriteriaEditorItem({ propKey={'value'} value={values[recordType.key]} options={recordType.options} - optionsComponent={SelectControlOptions} disabled={disabled} onChange={(value: string) => { values[recordType.key] = value; diff --git a/react/src/dashboard/components/elements/info-box/InfoBox.tsx b/react/src/dashboard/components/elements/info-box/InfoBox.tsx index 73cecc320..6b1625688 100644 --- a/react/src/dashboard/components/elements/info-box/InfoBox.tsx +++ b/react/src/dashboard/components/elements/info-box/InfoBox.tsx @@ -3,13 +3,13 @@ import classNames from 'classnames'; export default function InfoBox({ type = 'default', - dashed = true, + borderType = 'dashed', children, iconColor = 'light', iconPosition = 'center', }: { type?: 'default' | 'primary' | 'warning'; - dashed?: boolean; + borderType?: 'dashed' | 'none'; children: ReactNode; iconColor?: 'light' | 'primary' | 'warning'; iconPosition?: 'top' | 'center'; @@ -21,7 +21,8 @@ export default function InfoBox({ type === 'default' && 'block-info-box-default', type === 'primary' && 'block-info-box-primary', type === 'warning' && 'block-info-box', - dashed && 'block-info-box-dashed', + borderType === 'none' && 'block-info-box-borderless', + borderType === 'dashed' && 'block-info-box-dashed', )}>
- {showInfoBlock && ( - - {infoBlock} - - )} + {showInfoBlock && {infoBlock}} ) : ( {children || } diff --git a/react/src/dashboard/components/elements/photo-selector/PhotoSelector.tsx b/react/src/dashboard/components/elements/photo-selector/PhotoSelector.tsx index cbe0d2321..26d0b2662 100644 --- a/react/src/dashboard/components/elements/photo-selector/PhotoSelector.tsx +++ b/react/src/dashboard/components/elements/photo-selector/PhotoSelector.tsx @@ -1,10 +1,9 @@ -import React, { useCallback, useState, useRef, Fragment, useEffect } from 'react'; +import React, { useCallback, useState, useRef, useEffect, ChangeEvent } from 'react'; import ModalPhotoUploader from '../../modals/ModalPhotoUploader'; import { uniqueId } from 'lodash'; import useOpenModal from '../../../hooks/useOpenModal'; import useAssetUrl from '../../../hooks/useAssetUrl'; import useTranslate from '../../../hooks/useTranslate'; -import PhotoSelectorData from './types/PhotoSelectorData'; export default function PhotoSelector({ id, @@ -15,8 +14,6 @@ export default function PhotoSelector({ thumbnail, defaultThumbnail, template = 'default', - templateData, - updateTemplateData, selectPhoto, resetPhoto, }: { @@ -27,9 +24,7 @@ export default function PhotoSelector({ disabled?: boolean; thumbnail?: string; defaultThumbnail?: string; - template?: 'default' | 'photo-selector-sign_up' | 'photo-selector-notifications' | 'photo-selector-banner'; - templateData?: PhotoSelectorData; - updateTemplateData?: React.Dispatch>; + template?: 'default' | 'photo-selector-sign_up' | 'photo-selector-notifications'; selectPhoto: (file: Blob) => void; resetPhoto?: () => void; }) { @@ -43,7 +38,7 @@ export default function PhotoSelector({ const openModal = useOpenModal(); const onPhotoChange = useCallback( - (e) => { + (e: ChangeEvent) => { const file = e.target.files[0]; e.target.value = null; @@ -175,169 +170,5 @@ export default function PhotoSelector({ ); } - if (template === 'photo-selector-banner') { - return ( -
- {templateData.overlay_enabled && ( -
- )} - -
-
-
-
- { - updateTemplateData({ ...templateData, auto_text_color: e.target.checked }); - }} - /> - -
- -
- { - updateTemplateData({ ...templateData, overlay_enabled: e.target.checked }); - }} - /> - -
-
- - {!templateData.auto_text_color && ( -
- - -
- )} - - {templateData.overlay_enabled && ( - -
- - -
-
- - -
-
- )} -
-
- -
- -
-
-
-
- {templateData.mediaLoading ? ( - -
- - ) : ( - Upload hoofdfoto - )} -
- - - - {templateData.media && ( - - )} -
-
-
-
- ); - } - return null; } diff --git a/react/src/dashboard/components/elements/photo-selector/PhotoSelectorBanner.tsx b/react/src/dashboard/components/elements/photo-selector/PhotoSelectorBanner.tsx new file mode 100644 index 000000000..bdaee6aae --- /dev/null +++ b/react/src/dashboard/components/elements/photo-selector/PhotoSelectorBanner.tsx @@ -0,0 +1,410 @@ +import React, { useCallback, useState, useRef, useEffect, ChangeEvent, useMemo } from 'react'; +import ModalPhotoUploader from '../../modals/ModalPhotoUploader'; +import useOpenModal from '../../../hooks/useOpenModal'; +import useAssetUrl from '../../../hooks/useAssetUrl'; +import PhotoSelectorData from './types/PhotoSelectorData'; +import FormGroup from '../forms/controls/FormGroup'; +import SelectControl from '../select-control/SelectControl'; +import PhotoSelectorBannerControlColorPicker from './elements/PhotoSelectorBannerControlColorPicker'; +import classNames from 'classnames'; +import Markdown from '../../../../webshop/components/elements/markdown/Markdown'; +import PhotoSelectorBannerControl from './elements/PhotoSelectorBannerControl'; +import { hexToHsva } from '@uiw/color-convert'; +import { useMarkdownService } from '../../../services/MarkdownService'; + +export default function PhotoSelectorBanner({ + disabled, + thumbnail, + templateData, + setTemplateData, + selectPhoto, + deletePhoto, + title, + description, + buttonText, +}: { + disabled?: boolean; + thumbnail?: string; + templateData?: PhotoSelectorData; + setTemplateData?: React.Dispatch>; + selectPhoto: (file: Blob) => void; + deletePhoto: () => void; + title?: string; + description?: string; + buttonText?: string; +}) { + const [thumbnailValue, setThumbnailValue] = useState(thumbnail); + const inputRef = useRef(null); + const markdownService = useMarkdownService(); + + const assetUrl = useAssetUrl(); + const openModal = useOpenModal(); + const [activeDropdown, setActiveDropdown] = useState<'style' | 'button' | 'color' | 'background' | 'overlay'>(null); + const [descriptionPreview, setDescriptionPreview] = useState(null); + + const overlayPatternUrl = useMemo(() => { + return assetUrl(`/assets/img/banner-patterns/${templateData.overlay_type}.svg`); + }, [assetUrl, templateData?.overlay_type]); + + const [bannerPatterns] = useState([ + { value: 'color', label: 'Kleur' }, + { value: 'lines', label: 'Lijnen' }, + { value: 'points', label: 'Punten' }, + { value: 'dots', label: 'Stippen' }, + { value: 'circles', label: 'Cirkels' }, + ]); + + const [bannerOpacityOptions] = useState( + [...new Array(10).keys()] + .map((n) => ++n) + .map((option) => ({ + value: (option * 10).toString(), + label: `${(10 - option) * 10}%`, + })), + ); + + const onPhotoChange = useCallback( + (e: ChangeEvent) => { + const file = e.target.files[0]; + e.target.value = null; + + openModal((modal) => ( + { + const thumbnail = presets.find((preset) => preset.key == 'final'); + + selectPhoto(file); + setThumbnailValue(thumbnail?.data); + }} + /> + )); + }, + [openModal, selectPhoto], + ); + + useEffect(() => { + setThumbnailValue(thumbnail); + }, [thumbnail]); + + useEffect(() => { + if (!description) { + return; + } + + markdownService + .toHtml(description) + .then((res) => setDescriptionPreview(res.data.html)) + .catch(console.error); + }, [description, markdownService]); + + return ( +
+ + +
+
+ {templateData.overlay_enabled && ( +
+ )} +
+
+
{title || 'Voorbeeld van de header'}
+ + {descriptionPreview && ( + + )} + +
+
+ {buttonText || 'Voorbeeld'} +
+
+
+
+ +
+ + ( + { + setTemplateData({ ...templateData, banner_position }); + }} + /> + )} + /> + ( + { + setTemplateData({ ...templateData, banner_collapse: banner_collapse === 'yes' }); + }} + /> + )} + /> + ( + { + setTemplateData({ ...templateData, banner_wide: banner_wide === 'yes' }); + }} + /> + )} + /> + ( + { + setTemplateData({ + ...templateData, + banner_background_mobile: banner_background_mobile === 'yes', + }); + }} + /> + )} + /> + + + + ( + { + setTemplateData({ ...templateData, overlay_enabled: overlay_enabled === 'yes' }); + }} + /> + )} + /> + ( + { + setTemplateData({ ...templateData, overlay_type }); + }} + /> + )} + /> + ( + { + setTemplateData({ ...templateData, overlay_opacity }); + }} + /> + )} + /> + + + + ( + { + setTemplateData({ ...templateData, banner_button_type }); + }} + /> + )} + /> + + + + ( + { + setTemplateData({ ...templateData, banner_background: color.hexa }); + }} + alphaFractions={5} + showAlpha={true} + /> + )} + /> + + + + ( + setTemplateData({ ...templateData, banner_color: color.hex })} + /> + )} + /> + + +
+ {templateData.media && ( + + )} + + +
+
+
+ ); +} diff --git a/react/src/dashboard/components/elements/photo-selector/elements/PhotoSelectorBannerControl.tsx b/react/src/dashboard/components/elements/photo-selector/elements/PhotoSelectorBannerControl.tsx new file mode 100644 index 000000000..dfab3fb5d --- /dev/null +++ b/react/src/dashboard/components/elements/photo-selector/elements/PhotoSelectorBannerControl.tsx @@ -0,0 +1,100 @@ +import React, { Fragment, useCallback, useState } from 'react'; +import ClickOutside from '../../click-outside/ClickOutside'; +import classNames from 'classnames'; +import PhotoSelectorData from '../types/PhotoSelectorData'; + +export default function PhotoSelectorBannerControl({ + label, + value, + valueType = 'string', + activeKey, + setActiveKey, + controlKey, + onCancel, + onApply, + children, + templateData, + setTemplateData, +}: { + label: string; + value: string; + valueType?: 'string' | 'color'; + controlKey: 'style' | 'button' | 'color' | 'background' | 'overlay'; + activeKey: 'style' | 'button' | 'color' | 'background' | 'overlay'; + setActiveKey: React.Dispatch>; + onCancel?: () => void; + onApply?: () => void; + children?: React.ReactNode | React.ReactNode[]; + templateData?: PhotoSelectorData; + setTemplateData?: React.Dispatch>; +}) { + const [templateDataBackup, setTemplateDataBackup] = useState(null); + + const cancel = useCallback(() => { + if (templateDataBackup) { + setTemplateData({ ...templateDataBackup }); + } + + onCancel?.(); + setActiveKey?.(null); + }, [onCancel, setActiveKey, setTemplateData, templateDataBackup]); + + return ( +
+
{label}
+
{ + const newKey = activeKey === controlKey ? null : controlKey; + + setActiveKey(newKey); + + if (newKey && newKey !== activeKey) { + setTemplateDataBackup({ ...templateData }); + } + + if (!newKey) { + setTemplateDataBackup(null); + } + }}> + {valueType === 'string' ? ( + {value} + ) : ( +
+ )} + + {activeKey === controlKey && ( + e.stopPropagation() }} + onClickOutside={cancel} + className="banner-editor-dropdown"> +
+
+
+
{children}
+
+
+
+ + Annuleren +
+
{ + onApply?.(); + setActiveKey?.(null); + }}> + + Bevestigen +
+
+
+ + )} +
+
+ ); +} diff --git a/react/src/dashboard/components/elements/photo-selector/elements/PhotoSelectorBannerControlColorPicker.tsx b/react/src/dashboard/components/elements/photo-selector/elements/PhotoSelectorBannerControlColorPicker.tsx new file mode 100644 index 000000000..d4749ae93 --- /dev/null +++ b/react/src/dashboard/components/elements/photo-selector/elements/PhotoSelectorBannerControlColorPicker.tsx @@ -0,0 +1,173 @@ +import React, { CSSProperties, Fragment } from 'react'; +import { + type HsvaColor, + hsvaToRgbaString, + color as handleColor, + validHex, + hexToHsva, + hsvaToHex, + hsvaToHexa, + ColorResult, +} from '@uiw/color-convert'; +import Saturation from '@uiw/react-color-saturation'; +import Hue from '@uiw/react-color-hue'; +import Alpha from '@uiw/react-color-alpha'; +import EditableInput from '@uiw/react-color-editable-input'; +import EditableInputRGBA from '@uiw/react-color-editable-input-rgba'; + +export default function PhotoSelectorBannerControlColorPicker({ + showAlpha = false, + color, + showEditableInput = true, + showColorPreview, + showHue = true, + onChange, + style, + alphaFractions, +}: { + showAlpha?: boolean; + color: string; + style?: CSSProperties | undefined; + showEditableInput?: boolean; + showColorPreview?: boolean; + showHue?: boolean; + alphaFractions?: number; + onChange?: (color: ColorResult) => void; +}) { + const hsva = ( + typeof color === 'string' && validHex(color) ? hexToHsva(color) : color || { h: 0, s: 0, l: 0, a: 0 } + ) as HsvaColor; + + const inputStyle: React.CSSProperties = { + textAlign: 'left', + padding: '4px 10px', + outline: 'none', + font: '500 13px/20px var(--base-font)', + }; + + const handleChange = (hsv: HsvaColor) => { + onChange?.(handleColor({ ...hsv, a: alphaFractions ? roundToNearestFraction(hsv.a, alphaFractions) : hsv.a })); + }; + + const roundToNearestFraction = (num: number, factor: number) => { + // Clamp the input between 0 and 1 + if (num < 0) num = 0; + if (num > 1) num = 1; + + // Multiply by the factor, round to the nearest integer, then divide by the factor + return Math.round(num * factor) / factor; + }; + + const alphaStyle = { + '--chrome-alpha-box-shadow': 'rgb(0 0 0 / 25%) 0px 0px 1px inset', + borderRadius: '50%', + background: hsvaToRgbaString(hsva), + boxShadow: 'var(--chrome-alpha-box-shadow)', + }; + const styleSize = { height: 14, width: 14 }; + + const pointerProps = { + style: { ...styleSize }, + fillProps: { style: styleSize }, + }; + + return ( +
+ { + handleChange({ ...hsva, ...newColor, a: hsva.a }); + }} + /> +
+ {showColorPreview && ( + } + /> + )} +
+ {showHue == true && ( + handleChange({ ...hsva, ...newHue })} + /> + )} + {showAlpha == true && ( + handleChange({ ...hsva, ...newAlpha })} + /> + )} +
+
+ {showEditableInput && ( +
+
+
+
+ HEX +
+ 0 && hsva.a < 1 + ? hsvaToHexa(hsva).toLocaleUpperCase() + : hsvaToHex(hsva).toLocaleUpperCase() + } + onChange={(_, value) => { + if (typeof value === 'string') { + handleChange(hexToHsva(/^#/.test(value) ? value : `#${value}`)); + } + }} + /> +
+
+
+ RGB +
+ handleChange(reColor.hsva)} + /> +
+
+
+ )} +
+ ); +} diff --git a/react/src/dashboard/components/elements/photo-selector/types/PhotoSelectorData.ts b/react/src/dashboard/components/elements/photo-selector/types/PhotoSelectorData.ts index ec241a18e..207583ec1 100644 --- a/react/src/dashboard/components/elements/photo-selector/types/PhotoSelectorData.ts +++ b/react/src/dashboard/components/elements/photo-selector/types/PhotoSelectorData.ts @@ -4,20 +4,13 @@ export default interface PhotoSelectorData { overlay_type: string; overlay_enabled: boolean; overlay_opacity: string; - auto_text_color: boolean; - header_text_color: string; mediaLoading: boolean; - opacityOptions: Array<{ - value: string; - label: string; - }>; - headerTextColors: Array<{ - value: string; - label: string; - }>; - patterns: Array<{ - value: string; - label: string; - }>; media?: Media; + banner_color?: string; + banner_background?: string; + banner_background_mobile?: boolean; + banner_position?: 'left' | 'center' | 'right'; + banner_collapse?: boolean; + banner_wide?: boolean; + banner_button_type?: 'color' | 'white'; } diff --git a/react/src/dashboard/components/elements/resource-states/FundFormStateLabels.tsx b/react/src/dashboard/components/elements/resource-states/FundFormStateLabels.tsx new file mode 100644 index 000000000..e8767d18b --- /dev/null +++ b/react/src/dashboard/components/elements/resource-states/FundFormStateLabels.tsx @@ -0,0 +1,20 @@ +import React, { Fragment, useState } from 'react'; +import TableEmptyValue from '../table-empty-value/TableEmptyValue'; +import FundForm from '../../../props/models/FundForm'; + +export default function FundFormStateLabels({ fundForm }: { fundForm: FundForm }) { + const [stateLabels] = useState({ + active: 'tag-success', + archived: 'tag-default', + }); + + return ( + + {stateLabels[fundForm.state] ? ( + {fundForm.state_locale} + ) : ( + + )} + + ); +} diff --git a/react/src/dashboard/components/elements/select-control/SelectControl.tsx b/react/src/dashboard/components/elements/select-control/SelectControl.tsx index 4a826f943..0025a2cb0 100644 --- a/react/src/dashboard/components/elements/select-control/SelectControl.tsx +++ b/react/src/dashboard/components/elements/select-control/SelectControl.tsx @@ -1,14 +1,15 @@ import React, { FunctionComponent, HTMLInputAutoCompleteAttribute, - UIEvent, + UIEventHandler, useCallback, useEffect, useState, } from 'react'; import './styles/ui-select.scss'; import { uniqueId } from 'lodash'; -import SelectControlOptions from './templates/SelectControlOptions'; +// import SelectControlOptions from './templates/SelectControlOptions'; +import SelectControlOptionsFD from './templates/SelectControlOptionsFD'; type SelectControlProps = { id?: string; @@ -60,7 +61,7 @@ export type SelectControlOptionsProp = { setShowOptions?: React.Dispatch>; searchInputChanged: () => void; searchAutoComplete?: HTMLInputAutoCompleteAttribute; - onOptionsScroll: (e: UIEvent) => void; + onOptionsScroll: UIEventHandler; disabled?: boolean; rawValue?: unknown; propKey?: string | null; @@ -83,7 +84,7 @@ export default function SelectControl({ disabled = false, className = null, scrollSize = 50, - optionsComponent = SelectControlOptions, + optionsComponent = SelectControlOptionsFD, searchAutoComplete = 'off', dusk = null, multiline, @@ -167,25 +168,20 @@ export default function SelectControl({ [allowSearch, autoClear, searchInputChanged], ); - const searchOption = useCallback( - (e: React.MouseEvent) => { - e.stopPropagation(); - - if (disabled || showOptions) { - setShowOptions(false); - return; - } + const searchOption = useCallback(() => { + if (disabled || showOptions) { + setShowOptions(false); + return; + } - setShowOptions(true); + setShowOptions(true); - if (allowSearch && strict && modelValue && modelValue[propValue]) { - setQuery(modelValue[propValue]); - } + if (allowSearch && strict && modelValue && modelValue[propValue]) { + setQuery(modelValue[propValue]); + } - buildSearchedOptions(); - }, - [disabled, showOptions, allowSearch, strict, modelValue, propValue, buildSearchedOptions], - ); + buildSearchedOptions(); + }, [disabled, showOptions, allowSearch, strict, modelValue, propValue, buildSearchedOptions]); const selectOption = useCallback( (option: OptionType) => { @@ -202,11 +198,11 @@ export default function SelectControl({ [onChange, onSearchChange, propKey], ); - const onOptionsScroll = useCallback( + const onOptionsScroll: UIEventHandler = useCallback( (e) => { - const top = e.target.scrollTop + e.target.clientHeight; + const top = e.currentTarget.scrollTop + e.currentTarget.clientHeight; - if (top >= e.target.scrollHeight - scrollEndThreshold) { + if (top >= e.currentTarget.scrollHeight - scrollEndThreshold) { setVisibleCount((visibleCount) => visibleCount + scrollEndThreshold); } }, diff --git a/react/src/dashboard/components/elements/select-control/hooks/useSelectControlKeyEventFDHandlers.tsx b/react/src/dashboard/components/elements/select-control/hooks/useSelectControlKeyEventFDHandlers.tsx new file mode 100644 index 000000000..b3ea112d1 --- /dev/null +++ b/react/src/dashboard/components/elements/select-control/hooks/useSelectControlKeyEventFDHandlers.tsx @@ -0,0 +1,122 @@ +import React, { useCallback, useEffect, useState } from 'react'; + +export default function useSelectControlKeyEventFDHandlers( + selectorRef?: React.MutableRefObject, + optionsRef?: React.MutableRefObject, + placeholderRef?: React.MutableRefObject, + showOptions?: boolean, + setShowOptions?: React.Dispatch>, +) { + const [focusableSelectors] = useState([ + 'a[href]', + 'area[href]', + 'button:not([disabled])', + 'details', + 'iframe', + 'object', + 'input:not([disabled])', + 'select:not([disabled])', + 'textarea:not([disabled])', + '[contentEditable="true"]', + '[tabindex]:not([tabindex^="-"])', + ]); + + const isFocusable = useCallback( + (element?: HTMLElement) => { + if (!element || element.offsetParent === null) { + return false; + } + + return element.matches(focusableSelectors?.join(',')); + }, + [focusableSelectors], + ); + + const getFocusable = useCallback((): Array => { + const focusable = []; + + if (selectorRef.current) { + focusable.push( + ...[...selectorRef.current.querySelectorAll(focusableSelectors.join(','))].filter(isFocusable), + ); + } + + if (optionsRef.current) { + focusable.push( + ...[...optionsRef.current.querySelectorAll(focusableSelectors.join(','))].filter(isFocusable), + ); + } + + return focusable as Array; + }, [selectorRef, optionsRef, focusableSelectors, isFocusable]); + + const onKeyDown = useCallback( + (e: React.KeyboardEvent) => { + const focusable = getFocusable(); + const index = [...focusable].indexOf(document.activeElement as Element & HTMLInputElement); + const hasSelection = index !== -1; + + if ( + selectorRef?.current?.contains(e.currentTarget) && + (['Enter', ' '].includes(e.key) || (!showOptions && e.key === 'ArrowDown')) + ) { + e.preventDefault(); + window.setTimeout(() => selectorRef?.current?.focus(), 0); + return placeholderRef?.current?.click(); + } + + if (e.key == 'Escape') { + e.preventDefault(); + + window.setTimeout(() => selectorRef?.current?.focus(), 0); + return setShowOptions(false); + } + + if (!hasSelection) { + if (['ArrowDown', 'ArrowUp'].includes(e.key)) { + e.preventDefault(); + return window.setTimeout(() => focusable?.[0]?.focus(), 0); + } + } else { + if (e.key === 'ArrowDown' || (e.key === 'Tab' && !e.shiftKey)) { + e.preventDefault(); + (focusable[index + 1] || focusable[0])?.focus(); + } + + if (e.key === 'ArrowUp' || (e.key === 'Tab' && e.shiftKey)) { + e.preventDefault(); + (focusable[index - 1] || focusable[focusable.length - 1]).focus(); + } + } + }, + [getFocusable, showOptions, placeholderRef, setShowOptions, selectorRef], + ); + + const onBlur = useCallback( + (e: React.FocusEvent) => { + if ( + showOptions && + !(selectorRef?.current?.contains(e.relatedTarget) || optionsRef?.current?.contains(e.relatedTarget)) + ) { + if (isFocusable(selectorRef?.current)) { + return selectorRef?.current?.focus(); + } + + const firstFocusable = getFocusable()[0]; + + if (isFocusable(firstFocusable)) { + firstFocusable.focus(); + } + } + }, + [showOptions, selectorRef, optionsRef, isFocusable, getFocusable], + ); + + useEffect(() => { + if (showOptions) { + window.setTimeout(() => getFocusable()[0]?.focus(), 0); + } + }, [getFocusable, showOptions]); + + return { onBlur, onKeyDown }; +} diff --git a/react/src/dashboard/components/elements/select-control/templates/SelectControlOptionsFD.tsx b/react/src/dashboard/components/elements/select-control/templates/SelectControlOptionsFD.tsx new file mode 100644 index 000000000..f55115876 --- /dev/null +++ b/react/src/dashboard/components/elements/select-control/templates/SelectControlOptionsFD.tsx @@ -0,0 +1,165 @@ +import React, { useMemo, useRef, useState } from 'react'; +import { uniqueId } from 'lodash'; +import { SelectControlOptionsProp } from '../SelectControl'; +import classNames from 'classnames'; +import FDTargetClick from '../../../../modules/frame_director/components/targets/FDTargetClick'; +import FDTargetContainerSelect from '../../../../modules/frame_director/components/target-containers/FDTargetContainerSelect'; +import SelectControlOptionItem from './elements/SelectControlOptionItem'; +import useSelectControlKeyEventFDHandlers from '../hooks/useSelectControlKeyEventFDHandlers'; + +export default function SelectControlOptionsFD({ + id, + dusk, + query, + setQuery, + optionsFiltered, + placeholderValue, + placeholder, + selectOption, + allowSearch, + showOptions, + visibleCount, + className, + onInputClick, + searchOption, + setShowOptions, + searchInputChanged, + onOptionsScroll, + disabled, + multiline = { selected: false, options: true }, +}: SelectControlOptionsProp) { + const [controlId] = useState('select_control_' + uniqueId()); + const input = useRef(null); + const selectorRef = useRef(null); + const optionsRef = useRef(null); + const placeholderRef = useRef(null); + + const multilineSelected = useMemo(() => { + return multiline === true || (typeof multiline === 'object' && multiline?.selected === true); + }, [multiline]); + + const multilineOptions = useMemo(() => { + return multiline === true || (typeof multiline === 'object' && multiline?.options === true); + }, [multiline]); + + const { onKeyDown, onBlur } = useSelectControlKeyEventFDHandlers( + selectorRef, + optionsRef, + placeholderRef, + showOptions, + setShowOptions, + ); + + return ( +
(disabled ? null : onKeyDown(e))} + onBlur={onBlur}> + { + if (!showOptions) { + return null; + } + + return ( +
onKeyDown(e)} + onScroll={onOptionsScroll}> + {optionsFiltered.slice(0, visibleCount)?.map((option) => ( + { + selectOption(option); + selectorRef?.current?.focus(); + e.close(); + }} + /> + ))} +
+ ); + }} + align={'start'} + position={'bottom'} + showExternal + show={showOptions} + setShow={setShowOptions}> +
+ {/* Placeholder */} + + + {allowSearch && ( +
+ {showOptions && ( + setQuery(e.target.value)} + className="select-control-search form-control" + /> + )} + + {query && ( +
{ + setQuery(''); + searchInputChanged(); + }} + aria-label="Annuleren"> + +
+ )} +
+ )} +
+
+
+ ); +} diff --git a/react/src/dashboard/components/elements/select-control/templates/SelectControlOptionsLang.tsx b/react/src/dashboard/components/elements/select-control/templates/SelectControlOptionsLang.tsx index 5f55f79af..e27345233 100644 --- a/react/src/dashboard/components/elements/select-control/templates/SelectControlOptionsLang.tsx +++ b/react/src/dashboard/components/elements/select-control/templates/SelectControlOptionsLang.tsx @@ -133,7 +133,12 @@ export default function SelectControlOptionsLang({ {option?.raw?.[propKey]?.toUpperCase() || ''}
-
+
{index != 1 ? {str.value} : {str.value}}
{option.id === modelValue?.id && ( diff --git a/react/src/dashboard/components/elements/tables/elements/TableEntityMain.tsx b/react/src/dashboard/components/elements/tables/elements/TableEntityMain.tsx index be85e865c..fdebd659a 100644 --- a/react/src/dashboard/components/elements/tables/elements/TableEntityMain.tsx +++ b/react/src/dashboard/components/elements/tables/elements/TableEntityMain.tsx @@ -8,6 +8,7 @@ export default function TableEntityMain({ media = false, mediaSize = 'sm', mediaRound = true, + mediaBorder = true, mediaPlaceholder, title, subtitle, @@ -17,7 +18,8 @@ export default function TableEntityMain({ media?: Media | false; mediaSize?: 'sm' | 'md'; mediaRound?: boolean; - mediaPlaceholder?: 'fund' | 'organization' | 'product'; + mediaBorder?: boolean; + mediaPlaceholder?: 'fund' | 'organization' | 'product' | 'form'; title: string; subtitle?: string; collapsed?: boolean; @@ -27,6 +29,7 @@ export default function TableEntityMain({ const thumbnailUrl = useMemo(() => { const thumbnails = { + form: assetUrl('/assets/img/icon-fund-form.svg'), fund: assetUrl('/assets/img/placeholders/fund-thumbnail.png'), product: assetUrl('/assets/img/placeholders/product-thumbnail.png'), organization: assetUrl('/assets/img/placeholders/organization-thumbnail.png'), @@ -51,6 +54,7 @@ export default function TableEntityMain({ mediaSize === 'sm' && 'td-media-sm', mediaSize === 'md' && 'td-media-md', mediaRound && 'td-media-round', + !mediaBorder && 'td-media-borderless', )} src={media?.sizes.thumbnail || thumbnailUrl} alt={''} diff --git a/react/src/dashboard/components/modals/Modal2FADeactivate.tsx b/react/src/dashboard/components/modals/Modal2FADeactivate.tsx index 688df6559..f0755a712 100644 --- a/react/src/dashboard/components/modals/Modal2FADeactivate.tsx +++ b/react/src/dashboard/components/modals/Modal2FADeactivate.tsx @@ -226,7 +226,7 @@ export default function Modal2FADeactivate({
Tweefactorauthenticatie is succesvol uitgeschakeld
-
+
Je tweefactorauthenticatie is succesvol uitgeschakeld
diff --git a/react/src/dashboard/components/modals/Modal2FASetup.tsx b/react/src/dashboard/components/modals/Modal2FASetup.tsx index 01766869a..ab81f52cf 100644 --- a/react/src/dashboard/components/modals/Modal2FASetup.tsx +++ b/react/src/dashboard/components/modals/Modal2FASetup.tsx @@ -5,7 +5,6 @@ import Identity2FA from '../../props/models/Identity2FA'; import usePushSuccess from '../../hooks/usePushSuccess'; import Identity2FAState from '../../props/models/Identity2FAState'; import SelectControl from '../elements/select-control/SelectControl'; -import SelectControlOptions from '../elements/select-control/templates/SelectControlOptions'; import Auth2FAProvider from '../../props/models/Auth2FAProvider'; import QrCode from '../elements/qr-code/QrCode'; import FormError from '../elements/forms/errors/FormError'; @@ -219,6 +218,14 @@ export default function Modal2FASetup({ document.body.removeEventListener('keydown', onKeyDown); }, [onKeyDown]); + useEffect(() => { + bindEvents(); + + return () => { + unbindEvents(); + }; + }, [bindEvents, unbindEvents]); + useEffect(() => { const providers = auth2FAState.providers.filter((provider) => provider.type == type); const active_providers = auth2FAState.active_providers.filter((item) => item.provider_type.type == type); @@ -226,13 +233,7 @@ export default function Modal2FASetup({ setAuth2FA((auth2FA) => (auth2FA ? auth2FA : active_providers.find((auth_2fa) => auth_2fa))); setProvider(providers.find((provider) => provider)); setProviders(providers); - - bindEvents(); - - return () => { - unbindEvents(); - }; - }, [type, bindEvents, unbindEvents, auth2FAState]); + }, [type, auth2FAState]); // should set up useEffect(() => { @@ -295,7 +296,6 @@ export default function Modal2FASetup({ onChange={(provider: Auth2FAProvider) => setProvider(provider)} options={providers} allowSearch={false} - optionsComponent={SelectControlOptions} />
@@ -598,7 +598,7 @@ export default function Modal2FASetup({
Het is gelukt!
-
+
Je bent succesvol ingelogd met tweefactorauthenticatie. Welkom terug!
diff --git a/react/src/dashboard/components/modals/ModalAddPhysicalCard.tsx b/react/src/dashboard/components/modals/ModalAddPhysicalCard.tsx index 02ade7909..886947b20 100644 --- a/react/src/dashboard/components/modals/ModalAddPhysicalCard.tsx +++ b/react/src/dashboard/components/modals/ModalAddPhysicalCard.tsx @@ -2,7 +2,7 @@ import React, { useState } from 'react'; import { ModalState } from '../../modules/modals/context/ModalContext'; import useFormBuilder from '../../hooks/useFormBuilder'; import useSetProgress from '../../hooks/useSetProgress'; -import Voucher from '../../props/models/Voucher'; +import SponsorVoucher from '../../props/models/Sponsor/SponsorVoucher'; import Organization from '../../props/models/Organization'; import PincodeControl from '../elements/forms/controls/PincodeControl'; import FormError from '../elements/forms/errors/FormError'; @@ -21,7 +21,7 @@ export default function ModalAddPhysicalCard({ organization, }: { modal: ModalState; - voucher: Voucher; + voucher: SponsorVoucher; className?: string; onAttached: () => void; organization: Organization; diff --git a/react/src/dashboard/components/modals/ModalApproveFundRequest.tsx b/react/src/dashboard/components/modals/ModalApproveFundRequest.tsx index 351331776..52945048c 100644 --- a/react/src/dashboard/components/modals/ModalApproveFundRequest.tsx +++ b/react/src/dashboard/components/modals/ModalApproveFundRequest.tsx @@ -62,6 +62,8 @@ export default function ModalApproveFundRequest({ fund_amount_preset_id: amountValueOptions[0]?.id, }, ({ type, amount, fund_amount_preset_id, note }) => { + modal.setProcessing(true); + fundRequestService .approve( activeOrganization.id, @@ -74,10 +76,13 @@ export default function ModalApproveFundRequest({ }, ) .then(() => { + modal.setProcessing(false); modal.close(); onDone?.(); }) .catch((err: ResponseError) => { + modal.setProcessing(false); + if (err.data.errors) { form.setErrors(err.data.errors); form.setIsLocked(false); @@ -98,6 +103,12 @@ export default function ModalApproveFundRequest({
Aanvraag keuren en te ontvangen zaken vaststellen
+ {modal?.processing && ( +
+ +
+ )} +
@@ -279,8 +290,13 @@ export default function ModalApproveFundRequest({
- -
diff --git a/react/src/dashboard/components/modals/ModalCreatePrevalidation.tsx b/react/src/dashboard/components/modals/ModalCreatePrevalidation.tsx index 07dc57934..fc0910ad1 100644 --- a/react/src/dashboard/components/modals/ModalCreatePrevalidation.tsx +++ b/react/src/dashboard/components/modals/ModalCreatePrevalidation.tsx @@ -7,7 +7,6 @@ import { usePrevalidationService } from '../../services/PrevalidationService'; import Fund from '../../props/models/Fund'; import DatePickerControl from '../elements/forms/controls/DatePickerControl'; import SelectControl from '../elements/select-control/SelectControl'; -import SelectControlOptions from '../elements/select-control/templates/SelectControlOptions'; import FormError from '../elements/forms/errors/FormError'; import PrevalidationRecord from '../../props/models/PrevalidationRecord'; import { ResponseError } from '../../props/ApiResponses'; @@ -230,7 +229,6 @@ export default function ModalCreatePrevalidation({ placeholder="Waarde" value={form.values[fundRecord]} options={recordTypesByKey[fundRecord].options} - optionsComponent={SelectControlOptions} onChange={(value: string) => { form.update({ [fundRecord]: value }); }} @@ -306,7 +304,6 @@ export default function ModalCreatePrevalidation({ propKey={'key'} value={formNewRecord.values.record_type_key} options={recordTypesAvailable} - optionsComponent={SelectControlOptions} onChange={(record_type_key: string) => { formNewRecord.update({ record_type_key }); }} diff --git a/react/src/dashboard/components/modals/ModalEmployeeEdit.tsx b/react/src/dashboard/components/modals/ModalEmployeeEdit.tsx index fa1e364b0..4e21d00ad 100644 --- a/react/src/dashboard/components/modals/ModalEmployeeEdit.tsx +++ b/react/src/dashboard/components/modals/ModalEmployeeEdit.tsx @@ -11,7 +11,6 @@ import CheckboxControl from '../elements/forms/controls/CheckboxControl'; import Role from '../../props/models/Role'; import { ResponseError } from '../../props/ApiResponses'; import SelectControl from '../elements/select-control/SelectControl'; -import SelectControlOptions from '../elements/select-control/templates/SelectControlOptions'; import useOfficeService from '../../services/OfficeService'; import classNames from 'classnames'; import useIsProviderPanel from '../../hooks/useIsProviderPanel'; @@ -140,7 +139,6 @@ export default function ModalEmployeeEdit({ propValue={'name'} onChange={(office_id: number) => form.update({ office_id })} options={offices} - optionsComponent={SelectControlOptions} />
diff --git a/react/src/dashboard/components/modals/ModalFundInviteProviders.tsx b/react/src/dashboard/components/modals/ModalFundInviteProviders.tsx index 687717a87..4bd9c1c2b 100644 --- a/react/src/dashboard/components/modals/ModalFundInviteProviders.tsx +++ b/react/src/dashboard/components/modals/ModalFundInviteProviders.tsx @@ -4,7 +4,6 @@ import FormError from '../elements/forms/errors/FormError'; import useFormBuilder from '../../hooks/useFormBuilder'; import Fund from '../../props/models/Fund'; import SelectControl from '../elements/select-control/SelectControl'; -import SelectControlOptions from '../elements/select-control/templates/SelectControlOptions'; import useActiveOrganization from '../../hooks/useActiveOrganization'; import { useFundService } from '../../services/FundService'; import useSetProgress from '../../hooks/useSetProgress'; @@ -94,7 +93,6 @@ export default function ModalFundInviteProviders({ propKey={'id'} allowSearch={true} value={form.values?.fund_id} - optionsComponent={SelectControlOptions} onChange={(fund_id: number) => form.update({ fund_id })} />
diff --git a/react/src/dashboard/components/modals/ModalFundRequestAssignValidator.tsx b/react/src/dashboard/components/modals/ModalFundRequestAssignValidator.tsx index 99019def3..23f8b5cf2 100644 --- a/react/src/dashboard/components/modals/ModalFundRequestAssignValidator.tsx +++ b/react/src/dashboard/components/modals/ModalFundRequestAssignValidator.tsx @@ -8,7 +8,6 @@ import FundRequest from '../../props/models/FundRequest'; import { useFundRequestValidatorService } from '../../services/FundRequestValidatorService'; import Organization from '../../props/models/Organization'; import SelectControl from '../elements/select-control/SelectControl'; -import SelectControlOptions from '../elements/select-control/templates/SelectControlOptions'; import Employee from '../../props/models/Employee'; import { strLimit } from '../../helpers/string'; import useTranslate from '../../hooks/useTranslate'; @@ -77,7 +76,6 @@ export default function ModalFundRequestAssignValidator({ options={listEmployees} value={form.values.employee_id} onChange={(employee_id: number) => form.update({ employee_id })} - optionsComponent={SelectControlOptions} />
diff --git a/react/src/dashboard/components/modals/ModalFundRequestRecordEdit.tsx b/react/src/dashboard/components/modals/ModalFundRequestRecordEdit.tsx index 49a3480d1..8b0b4cace 100644 --- a/react/src/dashboard/components/modals/ModalFundRequestRecordEdit.tsx +++ b/react/src/dashboard/components/modals/ModalFundRequestRecordEdit.tsx @@ -9,7 +9,6 @@ import { useFundRequestValidatorService } from '../../services/FundRequestValida import Organization from '../../props/models/Organization'; import FundRequestRecord from '../../props/models/FundRequestRecord'; import FormHint from '../elements/forms/errors/FormHint'; -import SelectControlOptions from '../elements/select-control/templates/SelectControlOptions'; import SelectControl from '../elements/select-control/SelectControl'; import classNames from 'classnames'; @@ -93,7 +92,6 @@ export default function ModalFundRequestRecordEdit({ onChange={(value: string | number) => form.update({ value })} options={criterion.record_type.options} allowSearch={false} - optionsComponent={SelectControlOptions} /> )} diff --git a/react/src/dashboard/components/modals/ModalNotification.tsx b/react/src/dashboard/components/modals/ModalNotification.tsx index d097d9fe0..499b0d493 100644 --- a/react/src/dashboard/components/modals/ModalNotification.tsx +++ b/react/src/dashboard/components/modals/ModalNotification.tsx @@ -36,15 +36,39 @@ export default function ModalNotification({ className={classNames('modal-notification', className)} footer={ - {buttonClose && } - {buttonCancel && } - {buttonSubmit && } + {buttonClose && ( + + )} + + {buttonCancel && ( + + )} + + {buttonSubmit && ( + + )} {buttons?.map((button, index) => ( ))} }> + {modal?.processing && ( +
+ +
+ )} + {icon && (
Icon diff --git a/react/src/dashboard/components/modals/ModalOrderPhysicalCard.tsx b/react/src/dashboard/components/modals/ModalOrderPhysicalCard.tsx index 8cb7278b1..f5f983a92 100644 --- a/react/src/dashboard/components/modals/ModalOrderPhysicalCard.tsx +++ b/react/src/dashboard/components/modals/ModalOrderPhysicalCard.tsx @@ -2,7 +2,7 @@ import React, { FormEvent, useCallback, useState } from 'react'; import { ModalState } from '../../modules/modals/context/ModalContext'; import useFormBuilder from '../../hooks/useFormBuilder'; import useSetProgress from '../../hooks/useSetProgress'; -import Voucher from '../../props/models/Voucher'; +import SponsorVoucher from '../../props/models/Sponsor/SponsorVoucher'; import FormError from '../elements/forms/errors/FormError'; import { usePhysicalCardsRequestService } from '../../services/PhysicalCardsRequestService'; import useTranslate from '../../hooks/useTranslate'; @@ -16,7 +16,7 @@ export default function ModalOrderPhysicalCard({ onRequested, }: { modal: ModalState; - voucher: Voucher; + voucher: SponsorVoucher; className?: string; onRequested: () => void; }) { diff --git a/react/src/dashboard/components/modals/ModalPayoutEdit.tsx b/react/src/dashboard/components/modals/ModalPayoutEdit.tsx index 9dffd7299..99d1d0b39 100644 --- a/react/src/dashboard/components/modals/ModalPayoutEdit.tsx +++ b/react/src/dashboard/components/modals/ModalPayoutEdit.tsx @@ -10,7 +10,6 @@ import useSetProgress from '../../hooks/useSetProgress'; import SelectControlOptionsFund from '../elements/select-control/templates/SelectControlOptionsFund'; import FormGroup from '../elements/forms/controls/FormGroup'; import usePushApiError from '../../hooks/usePushApiError'; -import SelectControlOptions from '../elements/select-control/templates/SelectControlOptions'; import usePayoutTransactionService from '../../services/PayoutTransactionService'; import PayoutTransaction from '../../props/models/PayoutTransaction'; @@ -245,7 +244,6 @@ export default function ModalPayoutEdit({ onChange={setAssignType} options={assignTypes} allowSearch={false} - optionsComponent={SelectControlOptions} /> )} /> diff --git a/react/src/dashboard/components/modals/ModalPhotoUploader.tsx b/react/src/dashboard/components/modals/ModalPhotoUploader.tsx index e1be5861b..07d393bc3 100644 --- a/react/src/dashboard/components/modals/ModalPhotoUploader.tsx +++ b/react/src/dashboard/components/modals/ModalPhotoUploader.tsx @@ -10,12 +10,14 @@ export default function ModalPhotoUploader({ modal, onSubmit, className, + initialCropWidth = 90, }: { type: string; file: File; modal: ModalState; onSubmit: (file: Blob, sizes: Array) => void; className?: string; + initialCropWidth?: number; }) { const appConfigs = useAppConfigs(); @@ -104,6 +106,7 @@ export default function ModalPhotoUploader({ ]} aspect={mediaConfig.aspect_ratio} onChange={(sizes) => setPresets(sizes)} + initialWidth={initialCropWidth} /> )}
diff --git a/react/src/dashboard/components/modals/ModalReimbursementDetailsEdit.tsx b/react/src/dashboard/components/modals/ModalReimbursementDetailsEdit.tsx index 2925d8c0f..d676e42dd 100644 --- a/react/src/dashboard/components/modals/ModalReimbursementDetailsEdit.tsx +++ b/react/src/dashboard/components/modals/ModalReimbursementDetailsEdit.tsx @@ -9,7 +9,6 @@ import { useReimbursementCategoryService } from '../../services/ReimbursementCat import usePushSuccess from '../../hooks/usePushSuccess'; import useSetProgress from '../../hooks/useSetProgress'; import FormError from '../elements/forms/errors/FormError'; -import SelectControlOptions from '../elements/select-control/templates/SelectControlOptions'; import SelectControl from '../elements/select-control/SelectControl'; import ReimbursementCategory from '../../props/models/ReimbursementCategory'; import useOpenModal from '../../hooks/useOpenModal'; @@ -123,7 +122,6 @@ export default function ModalReimbursementDetailsEdit({ formProducts.update({ product_id }) } - optionsComponent={SelectControlOptions} />
diff --git a/react/src/dashboard/components/modals/ModalReservationUpload.tsx b/react/src/dashboard/components/modals/ModalReservationUpload.tsx index e831869e4..1c2d3e494 100644 --- a/react/src/dashboard/components/modals/ModalReservationUpload.tsx +++ b/react/src/dashboard/components/modals/ModalReservationUpload.tsx @@ -45,7 +45,7 @@ export default function ModalReservationUpload({ const [uploadedPartly, setUploadedPartly] = useState(false); const [isValid, setIsValid] = useState(false); const [data, setData] = useState([]); - const [csvFile, setCsvFile] = useState(null); + const [csvFile, setCsvFile] = useState(null); const [hideModal, setHideModal] = useState(false); const fileInput = useRef(null); diff --git a/react/src/dashboard/components/modals/ModalSocialMediaEdit.tsx b/react/src/dashboard/components/modals/ModalSocialMediaEdit.tsx index b684011fe..986fcc302 100644 --- a/react/src/dashboard/components/modals/ModalSocialMediaEdit.tsx +++ b/react/src/dashboard/components/modals/ModalSocialMediaEdit.tsx @@ -6,7 +6,6 @@ import FormError from '../elements/forms/errors/FormError'; import { ModalButton } from './elements/ModalButton'; import { ResponseError } from '../../props/ApiResponses'; import SelectControl from '../elements/select-control/SelectControl'; -import SelectControlOptions from '../elements/select-control/templates/SelectControlOptions'; import ImplementationSocialMedia from '../../props/models/ImplementationSocialMedia'; import Implementation from '../../props/models/Implementation'; import useImplementationSocialMediaService from '../../services/ImplementationSocialMediaService'; @@ -102,7 +101,6 @@ export default function ModalSocialMediaEdit({ propValue={'name'} onChange={(type?: string) => form.update({ type })} options={socialMediaTypes} - optionsComponent={SelectControlOptions} />
diff --git a/react/src/dashboard/components/modals/ModalSwitchBankConnectionAccount.tsx b/react/src/dashboard/components/modals/ModalSwitchBankConnectionAccount.tsx index f2741a947..f44018f78 100644 --- a/react/src/dashboard/components/modals/ModalSwitchBankConnectionAccount.tsx +++ b/react/src/dashboard/components/modals/ModalSwitchBankConnectionAccount.tsx @@ -4,7 +4,6 @@ import useFormBuilder from '../../hooks/useFormBuilder'; import usePushSuccess from '../../hooks/usePushSuccess'; import { useBankConnectionService } from '../../services/BankConnectionService'; import BankConnection from '../../props/models/BankConnection'; -import SelectControlOptions from '../elements/select-control/templates/SelectControlOptions'; import SelectControl from '../elements/select-control/SelectControl'; import FormError from '../elements/forms/errors/FormError'; import { ResponseError } from '../../props/ApiResponses'; @@ -63,7 +62,6 @@ export default function ModalSwitchBankConnectionAccount({ }} options={bankConnection.accounts} allowSearch={false} - optionsComponent={SelectControlOptions} /> diff --git a/react/src/dashboard/components/modals/ModalTransferOrganizationOwnership.tsx b/react/src/dashboard/components/modals/ModalTransferOrganizationOwnership.tsx index a98e730c0..be6485a3f 100644 --- a/react/src/dashboard/components/modals/ModalTransferOrganizationOwnership.tsx +++ b/react/src/dashboard/components/modals/ModalTransferOrganizationOwnership.tsx @@ -7,7 +7,6 @@ import FormError from '../elements/forms/errors/FormError'; import { ModalButton } from './elements/ModalButton'; import { useOrganizationService } from '../../services/OrganizationService'; import SelectControl from '../elements/select-control/SelectControl'; -import SelectControlOptions from '../elements/select-control/templates/SelectControlOptions'; import { ResponseError } from '../../props/ApiResponses'; import useTranslate from '../../hooks/useTranslate'; import classNames from 'classnames'; @@ -83,7 +82,6 @@ export default function ModalTransferOrganizationOwnership({ onChange={(value?: number) => { form.update({ employee_id: value }); }} - optionsComponent={SelectControlOptions} />
diff --git a/react/src/dashboard/components/modals/ModalVoucherActivate.tsx b/react/src/dashboard/components/modals/ModalVoucherActivate.tsx index b861d054f..3a9b73a8a 100644 --- a/react/src/dashboard/components/modals/ModalVoucherActivate.tsx +++ b/react/src/dashboard/components/modals/ModalVoucherActivate.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { ModalState } from '../../modules/modals/context/ModalContext'; import useFormBuilder from '../../hooks/useFormBuilder'; -import Voucher from '../../props/models/Voucher'; +import SponsorVoucher from '../../props/models/Sponsor/SponsorVoucher'; import FormError from '../elements/forms/errors/FormError'; import useTranslate from '../../hooks/useTranslate'; @@ -13,7 +13,7 @@ export default function ModalVoucherActivate({ }: { modal: ModalState; className?: string; - voucher: Voucher; + voucher: SponsorVoucher; onSubmit: (values: object) => void; }) { const translate = useTranslate(); diff --git a/react/src/dashboard/components/modals/ModalVoucherCreate.tsx b/react/src/dashboard/components/modals/ModalVoucherCreate.tsx index 83e250034..0a5406eb8 100644 --- a/react/src/dashboard/components/modals/ModalVoucherCreate.tsx +++ b/react/src/dashboard/components/modals/ModalVoucherCreate.tsx @@ -4,7 +4,6 @@ import useFormBuilder from '../../hooks/useFormBuilder'; import Fund from '../../props/models/Fund'; import FormError from '../elements/forms/errors/FormError'; import SelectControl from '../elements/select-control/SelectControl'; -import SelectControlOptions from '../elements/select-control/templates/SelectControlOptions'; import DatePickerControl from '../elements/forms/controls/DatePickerControl'; import { dateFormat, dateParse } from '../../helpers/dates'; import VoucherRecordsEditor from '../pages/vouchers/elements/VoucherRecordsEditor'; @@ -394,7 +393,6 @@ export default function ModalVoucherCreate({ }} options={creditTypes} allowSearch={false} - optionsComponent={SelectControlOptions} /> @@ -440,7 +438,6 @@ export default function ModalVoucherCreate({ propKey={'id'} options={products} placeholder="Selecteer aanbod..." - optionsComponent={SelectControlOptions} onChange={(product_id: number) => form.update({ product_id })} />
@@ -465,7 +462,6 @@ export default function ModalVoucherCreate({ onChange={setAssignType} options={assignTypes} allowSearch={false} - optionsComponent={SelectControlOptions} /> diff --git a/react/src/dashboard/components/modals/ModalVoucherDeactivation.tsx b/react/src/dashboard/components/modals/ModalVoucherDeactivation.tsx index 5013534ca..7a51f4a4e 100644 --- a/react/src/dashboard/components/modals/ModalVoucherDeactivation.tsx +++ b/react/src/dashboard/components/modals/ModalVoucherDeactivation.tsx @@ -1,7 +1,7 @@ import React, { useState } from 'react'; import { ModalState } from '../../modules/modals/context/ModalContext'; import useFormBuilder from '../../hooks/useFormBuilder'; -import Voucher from '../../props/models/Voucher'; +import SponsorVoucher from '../../props/models/Sponsor/SponsorVoucher'; import FormError from '../elements/forms/errors/FormError'; import CheckboxControl from '../elements/forms/controls/CheckboxControl'; import useOpenModal from '../../hooks/useOpenModal'; @@ -16,7 +16,7 @@ export default function ModalVoucherDeactivation({ className, }: { modal: ModalState; - voucher: Voucher; + voucher: SponsorVoucher; onSubmit: (values: object) => void; className?: string; }) { diff --git a/react/src/dashboard/components/modals/ModalVoucherQRCode.tsx b/react/src/dashboard/components/modals/ModalVoucherQRCode.tsx index 461b035fe..b41116985 100644 --- a/react/src/dashboard/components/modals/ModalVoucherQRCode.tsx +++ b/react/src/dashboard/components/modals/ModalVoucherQRCode.tsx @@ -2,7 +2,7 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { ModalState } from '../../modules/modals/context/ModalContext'; import useFormBuilder from '../../hooks/useFormBuilder'; import FormError from '../elements/forms/errors/FormError'; -import Voucher from '../../props/models/Voucher'; +import SponsorVoucher from '../../props/models/Sponsor/SponsorVoucher'; import useVoucherService from '../../services/VoucherService'; import useActiveOrganization from '../../hooks/useActiveOrganization'; import QrCode from '../elements/qr-code/QrCode'; @@ -28,8 +28,8 @@ export default function ModalVoucherQRCode({ }: { fund: Partial; modal: ModalState; - onSent: (values: Voucher) => void; - voucher: Voucher; + onSent: (values: SponsorVoucher) => void; + voucher: SponsorVoucher; className?: string; onAssigned: (values: object) => void; organization: Organization; @@ -114,7 +114,7 @@ export default function ModalVoucherQRCode({ ); const printQrCode = useCallback( - (voucher: Voucher) => { + (voucher: SponsorVoucher) => { openPrintable((printable) => ( void; className?: string; organization: Organization; @@ -138,7 +137,6 @@ export default function ModalVoucherRecordEdit({ propKey={'key'} options={recordTypes} allowSearch={false} - optionsComponent={SelectControlOptions} disabled={ !!record || (recordTypes.length == 1 && recordTypes[0].key == null) } diff --git a/react/src/dashboard/components/modals/ModalVoucherTransaction/ModalVoucherTransaction.tsx b/react/src/dashboard/components/modals/ModalVoucherTransaction/ModalVoucherTransaction.tsx index ac3a09976..3be082ba5 100644 --- a/react/src/dashboard/components/modals/ModalVoucherTransaction/ModalVoucherTransaction.tsx +++ b/react/src/dashboard/components/modals/ModalVoucherTransaction/ModalVoucherTransaction.tsx @@ -2,7 +2,7 @@ import React, { Fragment, useCallback, useEffect, useMemo, useState } from 'reac import { ModalState } from '../../../modules/modals/context/ModalContext'; import { hasPermission } from '../../../helpers/utils'; import useFormBuilder from '../../../hooks/useFormBuilder'; -import Voucher from '../../../props/models/Voucher'; +import SponsorVoucher from '../../../props/models/Sponsor/SponsorVoucher'; import Organization from '../../../props/models/Organization'; import { useFundService } from '../../../services/FundService'; import Fund from '../../../props/models/Fund'; @@ -10,7 +10,6 @@ import { useOrganizationService } from '../../../services/OrganizationService'; import { useReimbursementsService } from '../../../services/ReimbursementService'; import useVoucherService from '../../../services/VoucherService'; import SelectControl from '../../elements/select-control/SelectControl'; -import SelectControlOptions from '../../elements/select-control/templates/SelectControlOptions'; import FormError from '../../elements/forms/errors/FormError'; import { currencyFormat } from '../../../helpers/string'; import ModalVoucherTransactionPreview from './ModalVoucherTransactionPreview'; @@ -33,7 +32,7 @@ export default function ModalVoucherTransaction({ }: { modal: ModalState; target?: string; - voucher: Voucher; + voucher: SponsorVoucher; onCreated: () => void; className?: string; organization: Organization; @@ -284,7 +283,6 @@ export default function ModalVoucherTransaction({ propKey={'key'} options={targets} allowSearch={false} - optionsComponent={SelectControlOptions} onChange={(target: string) => { form.update({ target }); }} @@ -305,7 +303,6 @@ export default function ModalVoucherTransaction({ propValue={'name'} allowSearch={true} options={providers} - optionsComponent={SelectControlOptions} onChange={(organization_id: number) => form.update({ organization_id })} /> @@ -323,7 +320,6 @@ export default function ModalVoucherTransaction({ propKey={'key'} options={ibanSources} allowSearch={false} - optionsComponent={SelectControlOptions} onChange={(iban_source: 'manual' | 'reimbursement') => { form.update({ iban_source: iban_source }); }} @@ -344,7 +340,6 @@ export default function ModalVoucherTransaction({ value={reimbursement} options={reimbursements} allowSearch={false} - optionsComponent={SelectControlOptions} onChange={setReimbursement} /> diff --git a/react/src/dashboard/components/modals/ModalVoucherTransactionsUpload.tsx b/react/src/dashboard/components/modals/ModalVoucherTransactionsUpload.tsx index ef088c0bc..12e4200bc 100644 --- a/react/src/dashboard/components/modals/ModalVoucherTransactionsUpload.tsx +++ b/react/src/dashboard/components/modals/ModalVoucherTransactionsUpload.tsx @@ -43,7 +43,7 @@ export default function ModalVoucherTransactionsUpload({ const [uploadedPartly, setUploadedPartly] = useState(false); const [isValid, setIsValid] = useState(false); const [data, setData] = useState([]); - const [csvFile, setCsvFile] = useState(null); + const [csvFile, setCsvFile] = useState(null); const [hideModal, setHideModal] = useState(false); const [dataChunkSize] = useState(100); const [maxLinesPerFile] = useState(2500); diff --git a/react/src/dashboard/components/modals/ModalVouchersUpload.tsx b/react/src/dashboard/components/modals/ModalVouchersUpload.tsx index ae51a5b3c..d3d050703 100644 --- a/react/src/dashboard/components/modals/ModalVouchersUpload.tsx +++ b/react/src/dashboard/components/modals/ModalVouchersUpload.tsx @@ -14,7 +14,7 @@ import { ResponseError } from '../../props/ApiResponses'; import { dateFormat } from '../../helpers/dates'; import useAuthIdentity from '../../hooks/useAuthIdentity'; import { useHelperService } from '../../services/HelperService'; -import Voucher from '../../props/models/Voucher'; +import SponsorVoucher from '../../props/models/Sponsor/SponsorVoucher'; import Product from '../../props/models/Product'; import useProductService from '../../services/ProductService'; import ModalDuplicatesPicker from './ModalDuplicatesPicker'; @@ -23,7 +23,6 @@ import CSVProgressBar from '../elements/csv-progress-bar/CSVProgressBar'; import useTranslate from '../../hooks/useTranslate'; import SelectControl from '../elements/select-control/SelectControl'; import SelectControlOptionsFund from '../elements/select-control/templates/SelectControlOptionsFund'; -import SelectControlOptions from '../elements/select-control/templates/SelectControlOptions'; import classNames from 'classnames'; import FormGroupInfo from '../elements/forms/elements/FormGroupInfo'; import usePushInfo from '../../hooks/usePushInfo'; @@ -419,7 +418,7 @@ export default function ModalVouchersUpload({ try { setProgress(0); - const data = await helperService.recursiveLeach(fetchVouchers, 4); + const data = await helperService.recursiveLeach(fetchVouchers, 4); setProgress(100); pushSuccess( @@ -1014,7 +1013,6 @@ export default function ModalVouchersUpload({ onChange={(type: 'fund_voucher' | 'product_voucher') => setType(type)} options={types} allowSearch={false} - optionsComponent={SelectControlOptions} />
diff --git a/react/src/dashboard/components/pages/auth/SignUpProvider.tsx b/react/src/dashboard/components/pages/auth/SignUpProvider.tsx index 989ebf1e2..81dcd3d85 100644 --- a/react/src/dashboard/components/pages/auth/SignUpProvider.tsx +++ b/react/src/dashboard/components/pages/auth/SignUpProvider.tsx @@ -13,7 +13,6 @@ import QrCode from '../../elements/qr-code/QrCode'; import UIControlText from '../../elements/forms/ui-controls/UIControlText'; import UIControlCheckbox from '../../elements/forms/ui-controls/UIControlCheckbox'; import SelectControl from '../../elements/select-control/SelectControl'; -import SelectControlOptions from '../../elements/select-control/templates/SelectControlOptions'; import { useBusinessTypeService } from '../../../services/BusinessTypeService'; import BusinessType from '../../../props/models/BusinessType'; import Tooltip from '../../elements/tooltip/Tooltip'; @@ -1646,7 +1645,6 @@ export default function SignUpProvider() { }} options={businessTypes} placeholder={'Selecteer organisatie type...'} - optionsComponent={SelectControlOptions} /> )}
diff --git a/react/src/dashboard/components/pages/auth/elements/sign-up-steps/SignUpStepOrganizationAdd.tsx b/react/src/dashboard/components/pages/auth/elements/sign-up-steps/SignUpStepOrganizationAdd.tsx index 950dc6500..07a9480e5 100644 --- a/react/src/dashboard/components/pages/auth/elements/sign-up-steps/SignUpStepOrganizationAdd.tsx +++ b/react/src/dashboard/components/pages/auth/elements/sign-up-steps/SignUpStepOrganizationAdd.tsx @@ -5,7 +5,6 @@ import Tooltip from '../../../../elements/tooltip/Tooltip'; import PhotoSelector from '../../../../elements/photo-selector/PhotoSelector'; import UIControlCheckbox from '../../../../elements/forms/ui-controls/UIControlCheckbox'; import SelectControl from '../../../../elements/select-control/SelectControl'; -import SelectControlOptions from '../../../../elements/select-control/templates/SelectControlOptions'; import useFormBuilder from '../../../../../hooks/useFormBuilder'; import { ResponseError } from '../../../../../props/ApiResponses'; import BusinessType from '../../../../../props/models/BusinessType'; @@ -286,7 +285,6 @@ export default function SignUpStepOrganizationAdd({ } options={businessTypes} placeholder={'Selecteer organisatie type...'} - optionsComponent={SelectControlOptions} /> )}
diff --git a/react/src/dashboard/components/pages/bi-connection/BiConnection.tsx b/react/src/dashboard/components/pages/bi-connection/BiConnection.tsx index 388154bb9..84691dd8c 100644 --- a/react/src/dashboard/components/pages/bi-connection/BiConnection.tsx +++ b/react/src/dashboard/components/pages/bi-connection/BiConnection.tsx @@ -3,7 +3,6 @@ import BiConnectionIcon from '../../../../../assets/forus-platform/resources/pla import useFormBuilder from '../../../hooks/useFormBuilder'; import Auth2FARestriction from '../../elements/auth2fa-restriction/Auth2FARestriction'; import SelectControl from '../../elements/select-control/SelectControl'; -import SelectControlOptions from '../../elements/select-control/templates/SelectControlOptions'; import useActiveOrganization from '../../../hooks/useActiveOrganization'; import CheckboxControl from '../../elements/forms/controls/CheckboxControl'; import FormError from '../../elements/forms/errors/FormError'; @@ -513,7 +512,6 @@ export default function BiConnection() { onChange={(expiration_period: number) => { form.update({ expiration_period }); }} - optionsComponent={SelectControlOptions} />
diff --git a/react/src/dashboard/components/pages/csv_validations/elements/PrevalidatedTable.tsx b/react/src/dashboard/components/pages/csv_validations/elements/PrevalidatedTable.tsx index 3c06b82a0..3a3b71d54 100644 --- a/react/src/dashboard/components/pages/csv_validations/elements/PrevalidatedTable.tsx +++ b/react/src/dashboard/components/pages/csv_validations/elements/PrevalidatedTable.tsx @@ -5,7 +5,6 @@ import useFilter from '../../../../hooks/useFilter'; import usePaginatorService from '../../../../modules/paginator/services/usePaginatorService'; import ClickOutside from '../../../elements/click-outside/ClickOutside'; import FilterItemToggle from '../../../elements/tables/elements/FilterItemToggle'; -import SelectControlOptions from '../../../elements/select-control/templates/SelectControlOptions'; import SelectControl from '../../../elements/select-control/SelectControl'; import { dateFormat, dateParse } from '../../../../helpers/dates'; import DatePickerControl from '../../../elements/forms/controls/DatePickerControl'; @@ -265,7 +264,6 @@ export default function PrevalidatedTable({ propKey={'key'} allowSearch={true} options={states} - optionsComponent={SelectControlOptions} onChange={(state: string) => filter.update({ state })} /> @@ -276,7 +274,6 @@ export default function PrevalidatedTable({ propKey={'key'} allowSearch={true} options={statesExported} - optionsComponent={SelectControlOptions} onChange={(exported: number) => filter.update({ exported })} /> diff --git a/react/src/dashboard/components/pages/extra-payments/ExtraPayments.tsx b/react/src/dashboard/components/pages/extra-payments/ExtraPayments.tsx index ac3690a8c..f63ccb167 100644 --- a/react/src/dashboard/components/pages/extra-payments/ExtraPayments.tsx +++ b/react/src/dashboard/components/pages/extra-payments/ExtraPayments.tsx @@ -11,7 +11,6 @@ import StateNavLink from '../../../modules/state_router/StateNavLink'; import Paginator from '../../../modules/paginator/components/Paginator'; import FilterItemToggle from '../../elements/tables/elements/FilterItemToggle'; import SelectControl from '../../elements/select-control/SelectControl'; -import SelectControlOptions from '../../elements/select-control/templates/SelectControlOptions'; import CardHeaderFilter from '../../elements/tables/elements/CardHeaderFilter'; import Fund from '../../../props/models/Fund'; import { useFundService } from '../../../services/FundService'; @@ -158,7 +157,6 @@ export default function ExtraPayments() { options={funds} propKey={'id'} allowSearch={false} - optionsComponent={SelectControlOptions} onChange={(fund_id: string) => filter.update({ fund_id })} /> diff --git a/react/src/dashboard/components/pages/feedback/Feedback.tsx b/react/src/dashboard/components/pages/feedback/Feedback.tsx index 6c17461c2..f87202762 100644 --- a/react/src/dashboard/components/pages/feedback/Feedback.tsx +++ b/react/src/dashboard/components/pages/feedback/Feedback.tsx @@ -3,7 +3,6 @@ import useFormBuilder from '../../../hooks/useFormBuilder'; import useEnvData from '../../../hooks/useEnvData'; import FormError from '../../elements/forms/errors/FormError'; import SelectControl from '../../elements/select-control/SelectControl'; -import SelectControlOptions from '../../elements/select-control/templates/SelectControlOptions'; import useFeedbackService from '../../../services/FeedbackService'; import CheckboxControl from '../../elements/forms/controls/CheckboxControl'; import useAssetUrl from '../../../hooks/useAssetUrl'; @@ -120,7 +119,6 @@ export default function Feedback() { value={form.values?.urgency} onChange={(urgency: string) => form.update({ urgency })} options={urgencyOptions} - optionsComponent={SelectControlOptions} />
diff --git a/react/src/dashboard/components/pages/financial-dashboard-overview/FinancialDashboardOverview.tsx b/react/src/dashboard/components/pages/financial-dashboard-overview/FinancialDashboardOverview.tsx index f397ed874..d6eebb186 100644 --- a/react/src/dashboard/components/pages/financial-dashboard-overview/FinancialDashboardOverview.tsx +++ b/react/src/dashboard/components/pages/financial-dashboard-overview/FinancialDashboardOverview.tsx @@ -1,4 +1,4 @@ -import React, { Fragment, useCallback, useMemo } from 'react'; +import React, { Fragment, useCallback, useMemo, useState } from 'react'; import useActiveOrganization from '../../../hooks/useActiveOrganization'; import FinancialOverviewFundsTable from './elements/FinancialOverviewFundsTable'; import FinancialOverviewFundsBudgetTable from './elements/FinancialOverviewFundsBudgetTable'; @@ -7,6 +7,8 @@ import { useFundService } from '../../../services/FundService'; import Fund from '../../../props/models/Fund'; import { FinancialOverview } from '../financial-dashboard/types/FinancialStatisticTypes'; import usePushApiError from '../../../hooks/usePushApiError'; +import useFilterNext from '../../../modules/filter_next/useFilterNext'; +import { NumberParam } from 'use-query-params'; export default function FinancialDashboardOverview() { const translate = useTranslate(); @@ -15,6 +17,13 @@ export default function FinancialDashboardOverview() { const fundService = useFundService(); const activeOrganization = useActiveOrganization(); + const [overviewLoaded, setOverviewLoaded] = useState(false); + + const [, filterValuesActive, filterUpdate] = useFilterNext<{ year_all: number; year: number }>( + { year_all: new Date().getFullYear(), year: new Date().getFullYear() }, + { queryParams: { year_all: NumberParam, year: NumberParam } }, + ); + const years = useMemo>(() => { const yearsList = []; @@ -58,6 +67,9 @@ export default function FinancialDashboardOverview() { fetchFunds={fetchFunds} fetchFinancialOverview={fetchFinancialOverview} organization={activeOrganization} + year={filterValuesActive.year_all} + setYear={(year) => filterUpdate({ year_all: year })} + setLoaded={() => setOverviewLoaded(true)} /> filterUpdate({ year: year })} /> ); diff --git a/react/src/dashboard/components/pages/financial-dashboard-overview/elements/FinancialOverviewFundsBudgetTable.tsx b/react/src/dashboard/components/pages/financial-dashboard-overview/elements/FinancialOverviewFundsBudgetTable.tsx index d84085d55..cde7fbc08 100644 --- a/react/src/dashboard/components/pages/financial-dashboard-overview/elements/FinancialOverviewFundsBudgetTable.tsx +++ b/react/src/dashboard/components/pages/financial-dashboard-overview/elements/FinancialOverviewFundsBudgetTable.tsx @@ -8,9 +8,6 @@ import Organization from '../../../../props/models/Organization'; import { FinancialOverview } from '../../financial-dashboard/types/FinancialStatisticTypes'; import useTranslate from '../../../../hooks/useTranslate'; import SelectControl from '../../../elements/select-control/SelectControl'; -import SelectControlOptions from '../../../elements/select-control/templates/SelectControlOptions'; -import useFilterNext from '../../../../modules/filter_next/useFilterNext'; -import { NumberParam, StringParam } from 'use-query-params'; import useSetProgress from '../../../../hooks/useSetProgress'; import LoadingCard from '../../../elements/loading-card/LoadingCard'; import { useFundService } from '../../../../services/FundService'; @@ -23,11 +20,17 @@ export default function FinancialOverviewFundsBudgetTable({ fetchFunds, fetchFinancialOverview, organization, + year, + setYear, + loaded, }: { years: Array<{ id: number; name: string }>; fetchFunds: (year: number) => Promise>; fetchFinancialOverview: (year: number) => Promise; organization: Organization; + year: number; + setYear: (year: number) => void; + loaded: boolean; }) { const translate = useTranslate(); const exportFunds = useExportFunds(organization); @@ -45,25 +48,19 @@ export default function FinancialOverviewFundsBudgetTable({ const { headElement, configsElement } = useConfigurableTable(fundService.getColumnsBudget()); - const [filterValues, filterValuesActive, filterUpdate] = useFilterNext<{ q: string; year: number }>( - { q: '', year: new Date().getFullYear() }, - { queryParams: { q: StringParam, year: NumberParam }, throttledValues: ['q'] }, - ); - useEffect(() => { - fetchFunds(filterValuesActive.year).then(setFunds); - }, [fetchFunds, filterValuesActive.year]); + if (!loaded) return; - useEffect(() => { setProgress(0); - fetchFinancialOverview(filterValuesActive.year) - .then(setFinancialOverview) - .finally(() => setProgress(100)); - }, [fetchFinancialOverview, filterValuesActive.year, setProgress]); + Promise.all([ + fetchFinancialOverview(year).then(setFinancialOverview), + fetchFunds(year).then((funds) => setFunds(funds)), + ]).finally(() => setProgress(100)); + }, [fetchFinancialOverview, fetchFunds, year, setProgress, loaded]); if (!budgetFunds?.length || !years.length) { - return null; + return loaded ? : null; } return ( @@ -82,15 +79,12 @@ export default function FinancialOverviewFundsBudgetTable({ options={years} propKey={'id'} allowSearch={false} - value={filterValues.year} - optionsComponent={SelectControlOptions} - onChange={(year?: number) => filterUpdate({ year })} + value={year} + onChange={(year?: number) => setYear(year)} /> - @@ -98,7 +92,7 @@ export default function FinancialOverviewFundsBudgetTable({ - {financialOverview?.year != filterValuesActive.year ? ( + {financialOverview?.year != year ? ( ) : (
diff --git a/react/src/dashboard/components/pages/financial-dashboard-overview/elements/FinancialOverviewFundsTable.tsx b/react/src/dashboard/components/pages/financial-dashboard-overview/elements/FinancialOverviewFundsTable.tsx index 9ca4a6331..96f1c03df 100644 --- a/react/src/dashboard/components/pages/financial-dashboard-overview/elements/FinancialOverviewFundsTable.tsx +++ b/react/src/dashboard/components/pages/financial-dashboard-overview/elements/FinancialOverviewFundsTable.tsx @@ -7,10 +7,7 @@ import { FinancialOverview } from '../../financial-dashboard/types/FinancialStat import useTranslate from '../../../../hooks/useTranslate'; import TableEmptyValue from '../../../elements/table-empty-value/TableEmptyValue'; import SelectControl from '../../../elements/select-control/SelectControl'; -import SelectControlOptions from '../../../elements/select-control/templates/SelectControlOptions'; import LoadingCard from '../../../elements/loading-card/LoadingCard'; -import useFilterNext from '../../../../modules/filter_next/useFilterNext'; -import { NumberParam, StringParam } from 'use-query-params'; import useSetProgress from '../../../../hooks/useSetProgress'; import { useFundService } from '../../../../services/FundService'; import TableTopScroller from '../../../elements/tables/TableTopScroller'; @@ -21,11 +18,17 @@ export default function FinancialOverviewFundsTable({ fetchFunds, fetchFinancialOverview, organization, + year, + setYear, + setLoaded, }: { years: Array<{ id: number; name: string }>; fetchFunds: (year?: number) => Promise>; fetchFinancialOverview: (year?: number) => Promise; organization: Organization; + year: number; + setYear: (year: number) => void; + setLoaded?: () => void; }) { const translate = useTranslate(); const exportFunds = useExportFunds(organization); @@ -39,22 +42,20 @@ export default function FinancialOverviewFundsTable({ const { headElement, configsElement } = useConfigurableTable(fundService.getColumnsBalance()); - const [filterValues, filterValuesActive, filterUpdate] = useFilterNext<{ q: string; year_all: number }>( - { q: '', year_all: new Date().getFullYear() }, - { queryParams: { q: StringParam, year_all: NumberParam }, throttledValues: ['q'] }, - ); - - useEffect(() => { - fetchFunds(filterValuesActive.year_all).then((funds) => setFunds(funds.filter((fund) => fund.budget))); - }, [fetchFunds, filterValuesActive.year_all]); - useEffect(() => { setProgress(0); - fetchFinancialOverview(filterValuesActive.year_all) - .then(setFinancialOverview) - .finally(() => setProgress(100)); - }, [fetchFinancialOverview, filterValuesActive.year_all, setProgress]); + Promise.all([ + fetchFinancialOverview(year).then(setFinancialOverview), + fetchFunds(year).then((funds) => setFunds(funds.filter((fund) => fund.budget))), + ]).finally(() => setProgress(100)); + }, [fetchFinancialOverview, fetchFunds, year, setProgress]); + + useEffect(() => { + if (funds && financialOverview) { + setLoaded(); + } + }, [financialOverview, funds, setLoaded]); if (!funds?.length || !financialOverview || !years.length) { return ; @@ -76,15 +77,12 @@ export default function FinancialOverviewFundsTable({ options={years} propKey={'id'} allowSearch={false} - value={filterValues.year_all} - optionsComponent={SelectControlOptions} - onChange={(year?: number) => filterUpdate({ year_all: year })} + value={year} + onChange={(year?: number) => setYear(year)} />
- @@ -92,7 +90,7 @@ export default function FinancialOverviewFundsTable({ - {financialOverview?.year != filterValuesActive.year_all ? ( + {financialOverview?.year != year ? ( ) : (
diff --git a/react/src/dashboard/components/pages/fund-backoffice-edit/FundBackofficeEdit.tsx b/react/src/dashboard/components/pages/fund-backoffice-edit/FundBackofficeEdit.tsx index c82159d0e..e932bc258 100644 --- a/react/src/dashboard/components/pages/fund-backoffice-edit/FundBackofficeEdit.tsx +++ b/react/src/dashboard/components/pages/fund-backoffice-edit/FundBackofficeEdit.tsx @@ -12,7 +12,6 @@ import { useParams } from 'react-router-dom'; import { useFundService } from '../../../services/FundService'; import Fund from '../../../props/models/Fund'; import Tooltip from '../../elements/tooltip/Tooltip'; -import SelectControlOptions from '../../elements/select-control/templates/SelectControlOptions'; import SelectControl from '../../elements/select-control/SelectControl'; import useTranslate from '../../../hooks/useTranslate'; import usePushApiError from '../../../hooks/usePushApiError'; @@ -374,7 +373,6 @@ export default function FundBackofficeEdit() { propValue={'label'} allowSearch={false} value={form.values?.backoffice_fallback} - optionsComponent={SelectControlOptions} onChange={(value?: boolean) => { form.update({ backoffice_fallback: value }); }} @@ -427,7 +425,6 @@ export default function FundBackofficeEdit() { propValue={'label'} allowSearch={false} value={form.values?.backoffice_ineligible_policy} - optionsComponent={SelectControlOptions} onChange={(value?: string) => { form.update({ backoffice_ineligible_policy: value }); }} diff --git a/react/src/dashboard/components/pages/fund-forms-view/FundFormsView.tsx b/react/src/dashboard/components/pages/fund-forms-view/FundFormsView.tsx new file mode 100644 index 000000000..11f6d8a08 --- /dev/null +++ b/react/src/dashboard/components/pages/fund-forms-view/FundFormsView.tsx @@ -0,0 +1,77 @@ +import React, { Fragment, useCallback, useEffect, useState } from 'react'; +import useActiveOrganization from '../../../hooks/useActiveOrganization'; +import LoadingCard from '../../elements/loading-card/LoadingCard'; +import useSetProgress from '../../../hooks/useSetProgress'; +import { useFundFormService } from '../../../services/FundFormService'; +import FundForm from '../../../props/models/FundForm'; +import { useRecordTypeService } from '../../../services/RecordTypeService'; +import RecordType from '../../../props/models/RecordType'; +import FundFormCriteriaCard from './elements/FundFormCriteriaCard'; +import FundFormConfigsCard from './elements/FundFormConfigsCard'; +import { useParams } from 'react-router-dom'; +import OrganizationFundsShowOverviewCard from '../organizations-funds-show/elements/OrganizationFundsShowOverviewCard'; + +export default function FundFormsView() { + const { id } = useParams(); + const activeOrganization = useActiveOrganization(); + + const setProgress = useSetProgress(); + const fundFormService = useFundFormService(); + const recordTypeService = useRecordTypeService(); + + const [fundForm, setFundForm] = useState(null); + const [recordTypes, setRecordTypes] = useState>(null); + + const fetchRecordTypes = useCallback(() => { + setProgress(0); + + recordTypeService + .list({ criteria: 1 }) + .then((res) => setRecordTypes(res.data)) + .finally(() => setProgress(100)); + }, [recordTypeService, setProgress]); + + const fetchFundForm = useCallback(() => { + setProgress(0); + + fundFormService + .read(activeOrganization.id, parseInt(id)) + .then((res) => setFundForm(res.data.data)) + .finally(() => setProgress(100)); + }, [id, activeOrganization.id, fundFormService, setProgress]); + + useEffect(() => { + fetchFundForm(); + }, [fetchFundForm]); + + useEffect(() => { + fetchRecordTypes(); + }, [fetchRecordTypes]); + + if (!fundForm || !recordTypes) { + return ; + } + + return ( + + + + { + setFundForm({ ...fundForm, fund: { ...fundForm.fund, ...fund } }); + fetchFundForm(); + }} + recordTypes={recordTypes} + /> + + { + setFundForm({ ...fundForm, fund: { ...fundForm.fund, ...fund } }); + fetchFundForm(); + }} + /> + + ); +} diff --git a/react/src/dashboard/components/pages/fund-forms-view/elements/FundFormConfigsCard.tsx b/react/src/dashboard/components/pages/fund-forms-view/elements/FundFormConfigsCard.tsx new file mode 100644 index 000000000..0132dc61a --- /dev/null +++ b/react/src/dashboard/components/pages/fund-forms-view/elements/FundFormConfigsCard.tsx @@ -0,0 +1,344 @@ +import React, { useEffect, useState } from 'react'; +import useSetProgress from '../../../../hooks/useSetProgress'; +import FormError from '../../../elements/forms/errors/FormError'; +import useFormBuilder from '../../../../hooks/useFormBuilder'; +import useTranslate from '../../../../hooks/useTranslate'; +import CheckboxControl from '../../../elements/forms/controls/CheckboxControl'; +import FormGroupInfo from '../../../elements/forms/elements/FormGroupInfo'; +import MarkdownEditor from '../../../elements/forms/markdown-editor/MarkdownEditor'; +import Fund from '../../../../props/models/Fund'; +import { ResponseError } from '../../../../props/ApiResponses'; +import { useFundService } from '../../../../services/FundService'; +import usePushSuccess from '../../../../hooks/usePushSuccess'; +import usePushApiError from '../../../../hooks/usePushApiError'; + +export default function FundFormConfigsCard({ + fund, + setFund, +}: { + fund: Fund; + setFund: React.Dispatch>; +}) { + const translate = useTranslate(); + const pushSuccess = usePushSuccess(); + const setProgress = useSetProgress(); + const pushApiError = usePushApiError(); + + const fundService = useFundService(); + + const [collapsed, setCollapsed] = useState(false); + + const form = useFormBuilder<{ + help_title: string; + help_block_text: string; + help_button_text: string; + help_show_email: boolean; + help_show_phone: boolean; + help_show_website: boolean; + help_show_chat: boolean; + help_email: string; + help_phone: string; + help_website: string; + help_chat: string; + help_description: string; + help_description_html: string; + help_enabled: boolean; + }>( + { + help_title: '', + help_block_text: '', + help_button_text: '', + help_show_email: false, + help_show_phone: false, + help_show_website: false, + help_show_chat: false, + help_email: '', + help_phone: '', + help_website: '', + help_chat: '', + help_description: '', + help_description_html: '', + help_enabled: false, + }, + (values) => { + setProgress(0); + + fundService + .update(fund.organization.id, fund.id, values) + .then(() => { + pushSuccess('Opgeslagen!'); + setFund(fund); + form.setErrors({}); + }) + .catch((err: ResponseError) => { + pushApiError(err); + form.setErrors(err.data.errors); + }) + .finally(() => { + setProgress(100); + form.setIsLocked(false); + }); + }, + ); + + const { update: updateForm } = form; + + useEffect(() => { + if (fund) { + updateForm({ + help_title: fund.help_title, + help_block_text: fund.help_block_text, + help_button_text: fund.help_button_text, + help_show_email: fund.help_show_email, + help_show_phone: fund.help_show_phone, + help_show_website: fund.help_show_website, + help_show_chat: fund.help_show_chat, + help_email: fund.help_email, + help_phone: fund.help_phone, + help_website: fund.help_website, + help_chat: fund.help_chat, + help_description: fund.help_description, + help_description_html: fund.help_description_html, + help_enabled: fund.help_enabled, + }); + } + }, [updateForm, fund]); + + return ( +
+
setCollapsed(!collapsed)}> +
Instellingen aanvraagformulier
+
+ +
+
+
+
+ {translate('fund_request_configurations.titles.main_information')} +
+
+ +
+ form.update({ help_enabled: e.target.checked })} + /> + +
+ +
+
+
+ + + + Banner tekst Een korte tekst onder het aanvraagformulier over de hulp optie + tijdens het invullen van het aanvraagformulier. Deze tekst wordt naast de + hulp knop getoond. +

+ }> + form.update({ help_block_text: e.target.value })} + /> +
+ +
+
+ +
+
+ + + + Knop tekst De tekst van de knop onder het aanvraagformulier. Door te klikken + op deze knop opent er meer informatie (en contactinformatie) over de geboden + ondersteuning. +

+ }> + form.update({ help_button_text: e.target.value })} + /> +
+ + +
+
+
+ +
+ + + form.update({ help_title: e.target.value })} + /> + + +
+ +
+ + form.update({ help_description: description })} + extendedOptions={true} + placeholder={translate('fund_request_configurations.labels.description_placeholder')} + /> +
Max. 1000 tekens
+ +
+ +
+
+ {translate('fund_request_configurations.titles.contact_details')} +
+
+ +
+
+
+ form.update({ help_show_email: e.target.checked })} + /> + + + + form.update({ help_email: e.target.value })} + /> + + + +
+ +
+ form.update({ help_show_website: e.target.checked })} + /> + + + form.update({ help_website: e.target.value })} + /> + + + +
+
+ +
+
+ form.update({ help_show_phone: e.target.checked })} + /> + + + form.update({ help_phone: e.target.value })} + /> + + + +
+ +
+ form.update({ help_show_chat: e.target.checked })} + /> + + + + form.update({ help_chat: e.target.value })} + /> + + + +
+
+
+
+ +
+
+ +
+
+
+ + ); +} diff --git a/react/src/dashboard/components/pages/organizations-funds-show/elements/OrganizationsFundsShowFundRequestCriteriaCard.tsx b/react/src/dashboard/components/pages/fund-forms-view/elements/FundFormCriteriaCard.tsx similarity index 59% rename from react/src/dashboard/components/pages/organizations-funds-show/elements/OrganizationsFundsShowFundRequestCriteriaCard.tsx rename to react/src/dashboard/components/pages/fund-forms-view/elements/FundFormCriteriaCard.tsx index e29b4c564..395e79ca6 100644 --- a/react/src/dashboard/components/pages/organizations-funds-show/elements/OrganizationsFundsShowFundRequestCriteriaCard.tsx +++ b/react/src/dashboard/components/pages/fund-forms-view/elements/FundFormCriteriaCard.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useState } from 'react'; +import React, { useCallback } from 'react'; import useSetProgress from '../../../../hooks/useSetProgress'; import Fund from '../../../../props/models/Fund'; import { useFundService } from '../../../../services/FundService'; @@ -6,10 +6,9 @@ import usePushSuccess from '../../../../hooks/usePushSuccess'; import FundCriteriaEditor from '../../../elements/fund-criteria-editor/FundCriteriaEditor'; import RecordType from '../../../../props/models/RecordType'; import FundCriterion from '../../../../props/models/FundCriterion'; -import classNames from 'classnames'; import usePushApiError from '../../../../hooks/usePushApiError'; -export default function OrganizationsFundsShowFundRequestCriteriaCard({ +export default function FundFormCriteriaCard({ fund, setFund, recordTypes, @@ -24,8 +23,6 @@ export default function OrganizationsFundsShowFundRequestCriteriaCard({ const fundService = useFundService(); - const [collapsed, setCollapsed] = useState(true); - const saveCriteria = useCallback( (criteria: Array) => { setProgress(0); @@ -43,32 +40,12 @@ export default function OrganizationsFundsShowFundRequestCriteriaCard({ ); return ( -
-
setCollapsed(!collapsed)}> - - -
Voorwaarden bewerken
- - {!collapsed ? ( -
setCollapsed(true)}> - - Inklappen -
- ) : ( -
setCollapsed(false)}> - - Uitklappen -
- )} +
+
+
Voorwaarden bewerken
- {!collapsed && ( +
setFund({ ...fund, criteria })} saveButton={true} onSaveCriteria={saveCriteria} - className={'flex-gap-none'} bodyClassName={'collapsable-body'} footerClassName={'collapsable-footer'} /> - )} +
); } diff --git a/react/src/dashboard/components/pages/fund-forms/FundForms.tsx b/react/src/dashboard/components/pages/fund-forms/FundForms.tsx new file mode 100644 index 000000000..7096b457b --- /dev/null +++ b/react/src/dashboard/components/pages/fund-forms/FundForms.tsx @@ -0,0 +1,316 @@ +import React, { useCallback, useEffect, useState } from 'react'; +import { PaginationData } from '../../../props/ApiResponses'; +import useActiveOrganization from '../../../hooks/useActiveOrganization'; +import StateNavLink from '../../../modules/state_router/StateNavLink'; +import usePaginatorService from '../../../modules/paginator/services/usePaginatorService'; +import LoadingCard from '../../elements/loading-card/LoadingCard'; +import useSetProgress from '../../../hooks/useSetProgress'; +import ClickOutside from '../../elements/click-outside/ClickOutside'; +import FilterItemToggle from '../../elements/tables/elements/FilterItemToggle'; +import SelectControl from '../../elements/select-control/SelectControl'; +import SelectControlOptions from '../../elements/select-control/templates/SelectControlOptions'; +import useImplementationService from '../../../services/ImplementationService'; +import Implementation from '../../../props/models/Implementation'; +import { strLimit } from '../../../helpers/string'; +import TableRowActions from '../../elements/tables/TableRowActions'; +import Paginator from '../../../modules/paginator/components/Paginator'; +import EmptyCard from '../../elements/empty-card/EmptyCard'; +import useTranslate from '../../../hooks/useTranslate'; +import TableEmptyValue from '../../elements/table-empty-value/TableEmptyValue'; +import TableTopScroller from '../../elements/tables/TableTopScroller'; +import useConfigurableTable from '../vouchers/hooks/useConfigurableTable'; +import TableEntityMain from '../../elements/tables/elements/TableEntityMain'; +import usePushApiError from '../../../hooks/usePushApiError'; +import BlockLabelTabs from '../../elements/block-label-tabs/BlockLabelTabs'; +import useFilterNext from '../../../modules/filter_next/useFilterNext'; +import { useFundFormService } from '../../../services/FundFormService'; +import FundForm from '../../../props/models/FundForm'; +import FundFormStateLabels from '../../elements/resource-states/FundFormStateLabels'; +import TableDateTime from '../../elements/tables/elements/TableDateTime'; +import { NumberParam, StringParam } from 'use-query-params'; + +export default function FundForms() { + const translate = useTranslate(); + const setProgress = useSetProgress(); + const activeOrganization = useActiveOrganization(); + const pushApiError = usePushApiError(); + + const fundFormService = useFundFormService(); + const paginatorService = usePaginatorService(); + const implementationService = useImplementationService(); + + const [loading, setLoading] = useState(false); + const [paginatorKey] = useState('organization_fund_forms'); + const [implementations, setImplementations] = useState>>(null); + const [fundForms, setFundForms] = useState>(null); + + const [statesOptions] = useState([ + { value: null, label: `Alle` }, + { value: 'active', label: `Actief` }, + { value: 'archived', label: `Archief` }, + ]); + + const { headElement, configsElement } = useConfigurableTable(fundFormService.getColumns()); + + const [filterValues, filterActiveValues, filterUpdate, filter] = useFilterNext<{ + q: string; + state: string; + implementation_id: number; + per_page: number; + page: number; + }>( + { + q: '', + page: 1, + state: null, + implementation_id: null, + per_page: paginatorService.getPerPage(paginatorKey), + }, + { + throttledValues: ['q'], + queryParams: { + q: StringParam, + state: StringParam, + page: NumberParam, + per_page: NumberParam, + implementation_id: NumberParam, + }, + }, + ); + + const fetchFunds = useCallback(() => { + setProgress(0); + setLoading(true); + + fundFormService + .list(activeOrganization.id, filterActiveValues) + .then((res) => setFundForms(res.data)) + .catch(pushApiError) + .finally(() => { + setProgress(100); + setLoading(false); + }); + }, [activeOrganization.id, filterActiveValues, fundFormService, setProgress, pushApiError]); + + const fetchImplementations = useCallback(() => { + setProgress(0); + + implementationService + .list(activeOrganization.id, { per_page: 100 }) + .then((res) => setImplementations([{ id: null, name: 'Alle implementaties' }, ...res.data.data])) + .finally(() => setProgress(100)); + }, [activeOrganization.id, implementationService, setProgress]); + + useEffect(() => { + fetchFunds(); + }, [fetchFunds]); + + useEffect(() => { + fetchImplementations(); + }, [fetchImplementations]); + + if (!fundForms) { + return ; + } + + return ( +
+
+
+ E-formulieren ({fundForms.meta.total}) +
+ +
+
+ filterUpdate({ state: value })} + tabs={statesOptions} + /> + +
+ {filter.show && ( +
+ + Wis filters +
+ )} + + {!filter.show && ( +
+
+ filterUpdate({ q: e.target.value })} + /> +
+
+ )} + + filter.setShow(false)}> +
+ {filter.show && ( +
+
+
+
+ +
+ + filterUpdate({ q: e.target.value })} + placeholder={translate( + 'components.organization_funds_forms.filters.search', + )} + /> + + + + filterUpdate({ state })} + /> + + + + + filterUpdate({ implementation_id }) + } + /> + +
+
+ )} + +
filter.setShow(!filter.show)}> + +
+
+ +
+
+
+
+ + {!loading && fundForms.meta.total > 0 && ( +
+
+ {configsElement} + + + + {headElement} + + + {fundForms.data.map((fundForm) => ( + + + + + + + + + + + + + + ))} + +
+ + + + + + + {fundForm?.steps || } + + + + ( +
+ + Bekijken + +
+ )} + /> +
+
+
+
+ )} + + {!loading && fundForms.meta.total == 0 && } + + {loading && } + + {!loading && fundForms.meta.total > 0 && ( +
+ +
+ )} +
+ ); +} diff --git a/react/src/dashboard/components/pages/fund-requests-view/FundRequestsView.tsx b/react/src/dashboard/components/pages/fund-requests-view/FundRequestsView.tsx index 0142515b5..fea8b504b 100644 --- a/react/src/dashboard/components/pages/fund-requests-view/FundRequestsView.tsx +++ b/react/src/dashboard/components/pages/fund-requests-view/FundRequestsView.tsx @@ -148,7 +148,13 @@ export default function FundRequestsView() { const showInfoModal = useCallback( (title: string, message: string) => { openModal((modal) => ( - + )); }, [openModal], @@ -208,18 +214,24 @@ export default function FundRequestsView() { buttonSubmit={{ onClick: (_e, setDisabled) => { setDisabled(true); - modal.close(); + modal.setProcessing(true); fundRequestService .approve(activeOrganization.id, fundRequestMeta.id) - .then(() => reloadRequest()) + .then(() => { + modal.setProcessing(false); + reloadRequest(); + }) .catch((err: ResponseError) => { + modal.setProcessing(false); setDisabled(false); + showInfoModal( 'Validatie van persoonsgegeven mislukt.', `Reden: ${err.data.message}`, ); - }); + }) + .finally(() => modal.close()); }, }} /> diff --git a/react/src/dashboard/components/pages/fund-requests/FundRequests.tsx b/react/src/dashboard/components/pages/fund-requests/FundRequests.tsx index 3037bbe75..f44f2932c 100644 --- a/react/src/dashboard/components/pages/fund-requests/FundRequests.tsx +++ b/react/src/dashboard/components/pages/fund-requests/FundRequests.tsx @@ -5,7 +5,6 @@ import { getStateRouteUrl } from '../../../modules/state_router/Router'; import FundRequest from '../../../props/models/FundRequest'; import FilterItemToggle from '../../elements/tables/elements/FilterItemToggle'; import SelectControl from '../../elements/select-control/SelectControl'; -import SelectControlOptions from '../../elements/select-control/templates/SelectControlOptions'; import { useEmployeeService } from '../../../services/EmployeeService'; import CardHeaderFilter from '../../elements/tables/elements/CardHeaderFilter'; import { format } from 'date-fns'; @@ -254,7 +253,6 @@ export default function FundRequests() { options={states} propKey={'key'} allowSearch={false} - optionsComponent={SelectControlOptions} onChange={(state: string) => filterUpdate({ state })} /> @@ -264,7 +262,6 @@ export default function FundRequests() { options={assignedOptions} propKey={'key'} allowSearch={false} - optionsComponent={SelectControlOptions} onChange={(assigned: number | null) => filterUpdate({ assigned })} /> @@ -276,7 +273,6 @@ export default function FundRequests() { propKey={'id'} propValue={'email'} allowSearch={false} - optionsComponent={SelectControlOptions} onChange={(employee_id: number | null) => filterUpdate({ employee_id })} /> )} diff --git a/react/src/dashboard/components/pages/identities/Identities.tsx b/react/src/dashboard/components/pages/identities/Identities.tsx index 45062cf64..01635589a 100644 --- a/react/src/dashboard/components/pages/identities/Identities.tsx +++ b/react/src/dashboard/components/pages/identities/Identities.tsx @@ -28,7 +28,6 @@ import TableDateOnly from '../../elements/tables/elements/TableDateOnly'; import useIdentityExportService from '../../../services/exports/useIdentityExportService'; import DatePickerControl from '../../elements/forms/controls/DatePickerControl'; import { dateFormat, dateParse } from '../../../helpers/dates'; -import SelectControlOptions from '../../elements/select-control/templates/SelectControlOptions'; export default function Identities() { const translate = useTranslate(); @@ -307,7 +306,6 @@ export default function Identities() { allowSearch={false} value={filterValues.has_bsn} options={hasBsnOptions} - optionsComponent={SelectControlOptions} onChange={(has_bsn: number) => filterUpdate({ has_bsn })} /> diff --git a/react/src/dashboard/components/pages/identitities-show/cards/IdentityVouchersCard.tsx b/react/src/dashboard/components/pages/identitities-show/cards/IdentityVouchersCard.tsx index 87ffb3226..65f14d36a 100644 --- a/react/src/dashboard/components/pages/identitities-show/cards/IdentityVouchersCard.tsx +++ b/react/src/dashboard/components/pages/identitities-show/cards/IdentityVouchersCard.tsx @@ -1,7 +1,7 @@ import React, { useCallback, useEffect, useState } from 'react'; import Organization from '../../../../props/models/Organization'; import { PaginationData } from '../../../../props/ApiResponses'; -import Voucher from '../../../../props/models/Voucher'; +import SponsorVoucher from '../../../../props/models/Sponsor/SponsorVoucher'; import useVoucherService from '../../../../services/VoucherService'; import SponsorIdentity from '../../../../props/models/Sponsor/SponsorIdentity'; import useSetProgress from '../../../../hooks/useSetProgress'; @@ -13,11 +13,11 @@ import useVoucherTableOptions from '../../vouchers/hooks/useVoucherTableOptions' import usePushApiError from '../../../../hooks/usePushApiError'; export default function IdentityVouchersCard({ - organization, identity, + organization, }: { - organization: Organization; identity: SponsorIdentity; + organization: Organization; }) { const setProgress = useSetProgress(); const pushApiError = usePushApiError(); @@ -25,7 +25,7 @@ export default function IdentityVouchersCard({ const { funds } = useVoucherTableOptions(organization); const [loading, setLoading] = useState(false); - const [vouchers, setVouchers] = useState>(null); + const [vouchers, setVouchers] = useState>(null); const [paginatorKey] = useState('vouchers'); const [filterValues, filterValuesActive, filterUpdate] = useFilterNext({ diff --git a/react/src/dashboard/components/pages/identity-security/Security2FA.tsx b/react/src/dashboard/components/pages/identity-security/Security2FA.tsx index f70a13c5b..dbc9a26fe 100644 --- a/react/src/dashboard/components/pages/identity-security/Security2FA.tsx +++ b/react/src/dashboard/components/pages/identity-security/Security2FA.tsx @@ -4,7 +4,6 @@ import Identity2FAState from '../../../props/models/Identity2FAState'; import useOpenModal from '../../../hooks/useOpenModal'; import SelectControl from '../../elements/select-control/SelectControl'; import useFormBuilder from '../../../hooks/useFormBuilder'; -import SelectControlOptions from '../../elements/select-control/templates/SelectControlOptions'; import LoadingCard from '../../elements/loading-card/LoadingCard'; import usePushSuccess from '../../../hooks/usePushSuccess'; import useSetProgress from '../../../hooks/useSetProgress'; @@ -191,7 +190,6 @@ export default function Security2FA() { onChange={(auth_2fa_remember_ip: 0 | 1) => form.update({ auth_2fa_remember_ip: auth_2fa_remember_ip }) } - optionsComponent={SelectControlOptions} /> ) : (
diff --git a/react/src/dashboard/components/pages/implementations-cms-page/elements/ImplementationsCmsPageForm.tsx b/react/src/dashboard/components/pages/implementations-cms-page/elements/ImplementationsCmsPageForm.tsx index c487f1478..6fb5798e9 100644 --- a/react/src/dashboard/components/pages/implementations-cms-page/elements/ImplementationsCmsPageForm.tsx +++ b/react/src/dashboard/components/pages/implementations-cms-page/elements/ImplementationsCmsPageForm.tsx @@ -11,7 +11,6 @@ import Implementation from '../../../../props/models/Implementation'; import ImplementationPage from '../../../../props/models/ImplementationPage'; import ImplementationPageBlock from '../../../../props/models/ImplementationPageBlock'; import useImplementationPageService from '../../../../services/ImplementationPageService'; -import SelectControlOptions from '../../../elements/select-control/templates/SelectControlOptions'; import SelectControl from '../../../elements/select-control/SelectControl'; import MarkdownEditor from '../../../elements/forms/markdown-editor/MarkdownEditor'; import ImplementationsBlockEditor from './ImplementationsBlockEditor'; @@ -261,7 +260,6 @@ export default function ImplementationsCmsPageForm({ value={form.values?.state} onChange={(state: string) => form.update({ state })} options={states} - optionsComponent={SelectControlOptions} />
@@ -279,7 +277,6 @@ export default function ImplementationsCmsPageForm({ value={form.values?.external} onChange={(external: boolean) => form.update({ external })} options={types} - optionsComponent={SelectControlOptions} />
@@ -359,7 +356,6 @@ export default function ImplementationsCmsPageForm({ form.update({ description_position }); }} options={descriptionPositions} - optionsComponent={SelectControlOptions} />
@@ -433,7 +429,6 @@ export default function ImplementationsCmsPageForm({ value={form.values?.blocks_per_row} onChange={(blocks_per_row: number) => form.update({ blocks_per_row })} options={blocksPerRow} - optionsComponent={SelectControlOptions} />
diff --git a/react/src/dashboard/components/pages/implementations-cms/ImplementationsCms.tsx b/react/src/dashboard/components/pages/implementations-cms/ImplementationsCms.tsx index 4adbaa64c..6bf64328d 100644 --- a/react/src/dashboard/components/pages/implementations-cms/ImplementationsCms.tsx +++ b/react/src/dashboard/components/pages/implementations-cms/ImplementationsCms.tsx @@ -14,9 +14,7 @@ import { useMediaService } from '../../../services/MediaService'; import ImplementationsCmsPages from './elements/ImplementationsCmsPages'; import ModalDangerZone from '../../modals/ModalDangerZone'; import useOpenModal from '../../../hooks/useOpenModal'; -import PhotoSelector from '../../elements/photo-selector/PhotoSelector'; import MarkdownEditor from '../../elements/forms/markdown-editor/MarkdownEditor'; -import SelectControlOptions from '../../elements/select-control/templates/SelectControlOptions'; import SelectControl from '../../elements/select-control/SelectControl'; import DatePickerControl from '../../elements/forms/controls/DatePickerControl'; import { dateFormat, dateParse } from '../../../helpers/dates'; @@ -25,7 +23,11 @@ import PhotoSelectorData from '../../elements/photo-selector/types/PhotoSelector import useTranslate from '../../../hooks/useTranslate'; import FormGroupInfo from '../../elements/forms/elements/FormGroupInfo'; import FormGroup from '../../elements/forms/controls/FormGroup'; +import PhotoSelectorBanner from '../../elements/photo-selector/PhotoSelectorBanner'; +import ToggleControl from '../../elements/forms/controls/ToggleControl'; +import ModalNotification from '../../modals/ModalNotification'; import usePushApiError from '../../../hooks/usePushApiError'; +import InfoBox from '../../elements/info-box/InfoBox'; export default function ImplementationsCms() { const { id } = useParams(); @@ -40,34 +42,11 @@ export default function ImplementationsCms() { const mediaService = useMediaService(); const implementationService = useImplementationService(); - const [resetMedia, setResetMedia] = useState(false); const [bannerMedia, setBannerMedia] = useState(null); const [showInfoBlock, setShowInfoBlock] = useState(false); const [implementation, setImplementation] = useState(null); const [initialCommunicationType, setInitialCommunicationType] = useState(null); - const [bannerPatterns] = useState([ - { value: 'color', label: 'Kleur' }, - { value: 'lines', label: 'Lijnen' }, - { value: 'points', label: 'Punten' }, - { value: 'dots', label: 'Stippen' }, - { value: 'circles', label: 'Cirkels' }, - ]); - - const [headerTextColors] = useState([ - { value: 'dark', label: 'Donker' }, - { value: 'bright', label: 'Licht' }, - ]); - - const [bannerOpacityOptions] = useState( - [...new Array(10).keys()] - .map((n) => ++n) - .map((option) => ({ - value: (option * 10).toString(), - label: `${(10 - option) * 10}%`, - })), - ); - const [communicationTypes] = useState([ { value: true, label: 'Je/jouw' }, { value: false, label: 'U/uw' }, @@ -96,17 +75,18 @@ export default function ImplementationsCms() { { value: true, label: 'Ja' }, ]); - const [bannerMetaDefault] = useState({ + const [bannerMetaDefault] = useState({ media: null, mediaLoading: false, - auto_text_color: true, - patterns: bannerPatterns, - opacityOptions: bannerOpacityOptions, - headerTextColors: headerTextColors, overlay_enabled: false, - overlay_type: bannerPatterns[0].value, - overlay_opacity: bannerOpacityOptions[4].value, - header_text_color: headerTextColors[0].value, + overlay_type: 'color', + overlay_opacity: '40', + banner_color: '#000', + banner_background: '#fff', + banner_background_mobile: true, + banner_wide: true, + banner_collapse: false, + banner_position: 'left', }); const [bannerMeta, setBannerMeta] = useState(bannerMetaDefault); @@ -121,6 +101,11 @@ export default function ImplementationsCms() { informal_communication?: boolean; show_privacy_checkbox?: boolean; show_terms_checkbox?: boolean; + banner_button?: boolean; + banner_button_target?: 'self' | '_blank'; + banner_button_type?: 'color' | 'white'; + banner_button_text?: string; + banner_button_url?: string; announcement?: { type?: string; title?: string; @@ -134,18 +119,22 @@ export default function ImplementationsCms() { }>(null, (values) => { const submit = () => { setProgress(0); + const data = { ...values }; const { overlay_enabled, overlay_type, overlay_opacity } = bannerMeta; - const header_text_color = bannerMeta.auto_text_color ? 'auto' : bannerMeta.header_text_color; + const { banner_collapse, banner_wide, banner_position } = bannerMeta; + const { banner_color, banner_button_type, banner_background, banner_background_mobile } = bannerMeta; - if (resetMedia && values.banner_media_uid) { - mediaService.delete(values.banner_media_uid).catch(pushApiError); + if (data.banner_media_uid === implementation.banner_media_uid) { + delete data.banner_media_uid; } implementationService .updateCMS(activeOrganization.id, implementation.id, { - ...form.values, - ...{ overlay_enabled, overlay_type, overlay_opacity, header_text_color }, + ...data, + ...{ overlay_enabled, overlay_type, overlay_opacity }, + ...{ banner_collapse, banner_wide, banner_position }, + ...{ banner_color, banner_button_type, banner_background, banner_background_mobile }, }) .then((res) => { setImplementation(res.data.data); @@ -200,7 +189,7 @@ export default function ImplementationsCms() { submit(); }); - const { update: formUpdate } = form; + const { update: formUpdate, values: formValues } = form; const selectBanner = useCallback( (mediaFile: File | Blob) => { @@ -211,7 +200,6 @@ export default function ImplementationsCms() { .then((res) => { setBannerMedia(res.data.data); setBannerMeta((meta) => ({ ...meta, media: res.data.data })); - setResetMedia(false); formUpdate({ banner_media_uid: res.data.data.uid }); }) .catch(pushApiError) @@ -220,11 +208,33 @@ export default function ImplementationsCms() { [mediaService, pushApiError, formUpdate], ); - const resetBanner = useCallback(() => { - setResetMedia(true); - setBannerMedia(null); - setBannerMeta(bannerMetaDefault); - }, [bannerMetaDefault]); + const deletePhoto = useCallback(() => { + if (formValues?.banner_media_uid) { + openModal((modal) => ( + { + modal.close(); + mediaService.delete(formValues?.banner_media_uid).catch(pushApiError); + setBannerMedia(null); + formUpdate({ banner_media_uid: null }); + }, + }} + buttonCancel={{ + onClick: () => modal.close(), + }} + /> + )); + } else { + setBannerMedia(null); + formUpdate({ banner_media_uid: null }); + } + }, [openModal, mediaService, formValues?.banner_media_uid, pushApiError, formUpdate]); const fetchImplementation = useCallback(() => { implementationService @@ -246,19 +256,13 @@ export default function ImplementationsCms() { overlay_enabled: implementation.overlay_enabled, overlay_opacity: implementation.overlay_opacity.toString(), - ...(implementation.header_text_color == 'auto' - ? { - auto_text_color: true, - header_text_color: implementation.banner - ? implementation.banner.is_dark - ? 'bright' - : 'dark' - : 'dark', - } - : { - auto_text_color: false, - header_text_color: implementation.header_text_color, - }), + banner_wide: implementation.banner_wide, + banner_collapse: implementation.banner_collapse, + banner_position: implementation.banner_position, + banner_color: implementation.banner_color, + banner_background: implementation.banner_background, + banner_button_type: implementation.banner_button_type, + banner_background_mobile: implementation.banner_background_mobile, }); formUpdate({ @@ -270,6 +274,11 @@ export default function ImplementationsCms() { informal_communication: implementation.informal_communication, show_terms_checkbox: implementation.show_terms_checkbox, show_privacy_checkbox: implementation.show_privacy_checkbox, + banner_button: implementation.banner_button, + banner_button_text: implementation.banner_button_text, + banner_button_url: implementation.banner_button_url, + banner_button_target: implementation.banner_button_target, + banner_media_uid: implementation.banner_media_uid, announcement: { type: announcementTypes[0].value, active: announcementState[0].value, @@ -357,16 +366,28 @@ export default function ImplementationsCms() {
- selectBanner(file)} - template={'photo-selector-banner'} templateData={bannerMeta} - thumbnail={bannerMedia?.sizes?.medium} - resetPhoto={resetBanner} - updateTemplateData={setBannerMeta} + thumbnail={bannerMedia?.sizes?.large} + deletePhoto={deletePhoto} + setTemplateData={setBannerMeta} + title={form.values?.title} + description={form.values?.description} + buttonText={form.values?.banner_button_text} />
+
+ + Zorg ervoor dat tekst voor iedereen leesbaar blijft door een sterk contrast tussen titels en + hun achtergrond te gebruiken. Volgens de verplichte toegankelijksheidsrichtlijnen moet de + contrastverhouding ten minste 4,5:1 zijn voor normale tekst en 3:1 voor grote tekst. Plaats + tekst niet direct op drukke of kleurrijke afbeeldingen en gebruik overlays of effen + achtergronden om de duidelijkheid te verbeteren. Dit zorgt voor toegankelijkheid voor + gebruikers met visuele beperkingen en draagt bij aan de gebruiksvriendelijkheid van de + website. + +
@@ -397,7 +418,9 @@ export default function ImplementationsCms() { extendedOptions={true} allowAlignment={true} value={form.values?.description_html} - onChange={(value) => form.update({ description: value })} + onChange={(value) => { + form.update({ description: value }); + }} />
@@ -432,6 +455,82 @@ export default function ImplementationsCms() {
+
+
+
+ ( + { + form.update({ banner_button: e.target.checked }); + }} + /> + )} + /> + ( + form.update({ banner_button_text: e.target.value })} + /> + )} + /> + ( + form.update({ banner_button_url: e.target.value })} + /> + )} + /> + ( + { + form.update({ banner_button_target }); + }} + /> + )} + /> +
+
+
+
@@ -452,7 +551,6 @@ export default function ImplementationsCms() { onChange={(value?: boolean) => { form.update({ informal_communication: value }); }} - optionsComponent={SelectControlOptions} />
@@ -508,7 +606,6 @@ export default function ImplementationsCms() { announcement: { ...form.values.announcement, active: value }, }); }} - optionsComponent={SelectControlOptions} />
@@ -533,7 +630,6 @@ export default function ImplementationsCms() { announcement: { ...form.values.announcement, type: value }, }); }} - optionsComponent={SelectControlOptions} />
@@ -605,7 +701,6 @@ export default function ImplementationsCms() { }, }); }} - optionsComponent={SelectControlOptions} /> @@ -692,7 +787,6 @@ export default function ImplementationsCms() { onChange={(value?: boolean) => { form.update({ show_privacy_checkbox: value }); }} - optionsComponent={SelectControlOptions} /> )} @@ -729,7 +823,6 @@ export default function ImplementationsCms() { onChange={(value?: boolean) => { form.update({ show_terms_checkbox: value }); }} - optionsComponent={SelectControlOptions} /> )} diff --git a/react/src/dashboard/components/pages/implementations-notifications-edit/elements/SystemNotificationEditor.tsx b/react/src/dashboard/components/pages/implementations-notifications-edit/elements/SystemNotificationEditor.tsx index f52cc83a2..4bd7e0f8e 100644 --- a/react/src/dashboard/components/pages/implementations-notifications-edit/elements/SystemNotificationEditor.tsx +++ b/react/src/dashboard/components/pages/implementations-notifications-edit/elements/SystemNotificationEditor.tsx @@ -7,7 +7,6 @@ import usePushSuccess from '../../../../hooks/usePushSuccess'; import Organization from '../../../../props/models/Organization'; import SystemNotification from '../../../../props/models/SystemNotification'; import SelectControl from '../../../elements/select-control/SelectControl'; -import SelectControlOptions from '../../../elements/select-control/templates/SelectControlOptions'; import SystemNotificationTemplateEditor from './SystemNotificationTemplateEditor'; import Fund from '../../../../props/models/Fund'; import LoadingCard from '../../../elements/loading-card/LoadingCard'; @@ -169,7 +168,6 @@ export default function SystemNotificationEditor({ value={fund} allowSearch={true} onChange={(fund: Partial) => setFund(fund)} - optionsComponent={SelectControlOptions} /> diff --git a/react/src/dashboard/components/pages/implementations-notifications-send/ImplementationsNotificationsSend.tsx b/react/src/dashboard/components/pages/implementations-notifications-send/ImplementationsNotificationsSend.tsx index 1e5f701d1..83c34c967 100644 --- a/react/src/dashboard/components/pages/implementations-notifications-send/ImplementationsNotificationsSend.tsx +++ b/react/src/dashboard/components/pages/implementations-notifications-send/ImplementationsNotificationsSend.tsx @@ -10,7 +10,6 @@ import { useParams } from 'react-router-dom'; import Implementation from '../../../props/models/Implementation'; import { useNavigateState } from '../../../modules/state_router/Router'; import { hasPermission } from '../../../helpers/utils'; -import SelectControlOptions from '../../elements/select-control/templates/SelectControlOptions'; import SelectControl from '../../elements/select-control/SelectControl'; import ThSortable from '../../elements/tables/ThSortable'; import useFilter from '../../../hooks/useFilter'; @@ -448,7 +447,6 @@ export default function ImplementationsNotificationsSend() { value={fund} onChange={(value: Fund) => setFund(value)} options={funds} - optionsComponent={SelectControlOptions} /> @@ -466,7 +464,6 @@ export default function ImplementationsNotificationsSend() { identitiesFilters.update({ target: value }); }} options={identityTargets} - optionsComponent={SelectControlOptions} /> @@ -485,7 +482,6 @@ export default function ImplementationsNotificationsSend() { providersFilters.update({ target: value }); }} options={providerTargets} - optionsComponent={SelectControlOptions} /> diff --git a/react/src/dashboard/components/pages/organizations-edit/elements/OrganizationForm.tsx b/react/src/dashboard/components/pages/organizations-edit/elements/OrganizationForm.tsx index 259865c50..86907d781 100644 --- a/react/src/dashboard/components/pages/organizations-edit/elements/OrganizationForm.tsx +++ b/react/src/dashboard/components/pages/organizations-edit/elements/OrganizationForm.tsx @@ -7,7 +7,6 @@ import Organization from '../../../../props/models/Organization'; import FormError from '../../../elements/forms/errors/FormError'; import CheckboxControl from '../../../elements/forms/controls/CheckboxControl'; import SelectControl from '../../../elements/select-control/SelectControl'; -import SelectControlOptions from '../../../elements/select-control/templates/SelectControlOptions'; import BusinessType from '../../../../props/models/BusinessType'; import { useBusinessTypeService } from '../../../../services/BusinessTypeService'; import { useParams } from 'react-router-dom'; @@ -25,6 +24,7 @@ import StateNavLink from '../../../../modules/state_router/StateNavLink'; import Media from '../../../../props/models/Media'; import useTranslate from '../../../../hooks/useTranslate'; import usePushApiError from '../../../../hooks/usePushApiError'; +import SelectControlOptionsFD from '../../../elements/select-control/templates/SelectControlOptionsFD'; export default function OrganizationForm() { const { organizationId } = useParams(); @@ -339,7 +339,7 @@ export default function OrganizationForm() { propKey={'id'} allowSearch={true} value={form.values?.business_type_id} - optionsComponent={SelectControlOptions} + optionsComponent={SelectControlOptionsFD} onChange={(id?: number) => form.update({ business_type_id: id })} /> diff --git a/react/src/dashboard/components/pages/organizations-funds-edit/OrganizationsFundsEdit.tsx b/react/src/dashboard/components/pages/organizations-funds-edit/OrganizationsFundsEdit.tsx index 5b261a763..66dd0591c 100644 --- a/react/src/dashboard/components/pages/organizations-funds-edit/OrganizationsFundsEdit.tsx +++ b/react/src/dashboard/components/pages/organizations-funds-edit/OrganizationsFundsEdit.tsx @@ -31,7 +31,6 @@ import { parseInt, sortBy, uniqueId } from 'lodash'; import { useRecordTypeService } from '../../../services/RecordTypeService'; import { useEmployeeService } from '../../../services/EmployeeService'; import FundCriterion from '../../../props/models/FundCriterion'; -import FundCriteriaEditor from '../../elements/fund-criteria-editor/FundCriteriaEditor'; import FundConfigContactInfoEditor from './elements/FundConfigContactInfoEditor'; import { useNavigateState } from '../../../modules/state_router/Router'; import MultiSelectControl from '../../elements/forms/controls/MultiSelectControl'; @@ -69,7 +68,7 @@ export default function OrganizationsFundsEdit() { const [faq, setFaq] = useState>([]); const [fund, setFund] = useState(null); const [tags, setTags] = useState>(null); - const [fundPhoto, setFundPhoto] = useState(null); + const [fundPhoto, setFundPhoto] = useState(null); const [validatorEmployees, setValidatorEmployees] = useState>(null); const [showInfoBlock, setShowInfoBlock] = useState(false); @@ -77,7 +76,6 @@ export default function OrganizationsFundsEdit() { const [products, setProducts] = useState>>(null); const [fundStates] = useState(fundService.getStates()); const faqEditorBlock = useRef<() => Promise>(); - const criteriaBlockRef = useRef<() => Promise | null>>(); const [fundTypes] = useState([ { value: 'budget', name: 'Waardebon' }, @@ -153,7 +151,7 @@ export default function OrganizationsFundsEdit() { }, [recordTypes]); const storeMedia = useCallback( - async (mediaFile): Promise => { + async (mediaFile: Blob): Promise => { return await mediaService .store('fund_logo', mediaFile) .then((res) => res.data?.data) @@ -236,20 +234,6 @@ export default function OrganizationsFundsEdit() { form.setErrors(res.data.errors); }; - if (appConfigs.organizations.funds.criteria && !form.values.external_page) { - try { - const criteria = await criteriaBlockRef.current(); - - if (criteria != null) { - data.criteria = criteria; - } else { - return form.setIsLocked(false); - } - } catch { - return form.setIsLocked(false); - } - } - try { await faqEditorBlock.current(); } catch (e) { @@ -1147,29 +1131,6 @@ export default function OrganizationsFundsEdit() { )} - {appConfigs.organizations.funds.criteria && !form.values.external_page && ( - - {(form.values.criteria.length > 0 || hasPermission(activeOrganization, 'manage_funds')) && ( -
-
-
Criteria
-
- form.update({ criteria })} - recordTypes={recordTypes} - saveCriteriaRef={criteriaBlockRef} - /> -
-
-
- )} -
- )} - {!form.values.external_page && (
diff --git a/react/src/dashboard/components/pages/organizations-funds-security/OrganizationsFundsSecurity.tsx b/react/src/dashboard/components/pages/organizations-funds-security/OrganizationsFundsSecurity.tsx index 45ea431fc..c3f49be81 100644 --- a/react/src/dashboard/components/pages/organizations-funds-security/OrganizationsFundsSecurity.tsx +++ b/react/src/dashboard/components/pages/organizations-funds-security/OrganizationsFundsSecurity.tsx @@ -9,7 +9,6 @@ import { useFundService } from '../../../services/FundService'; import { ResponseError } from '../../../props/ApiResponses'; import StateNavLink from '../../../modules/state_router/StateNavLink'; import SelectControl from '../../elements/select-control/SelectControl'; -import SelectControlOptions from '../../elements/select-control/templates/SelectControlOptions'; import OrganizationsFundsSecurityAuth2FAForm from './elements/OrganizationsFundsSecurityAuth2FAForm'; import LoadingCard from '../../elements/loading-card/LoadingCard'; import useTranslate from '../../../hooks/useTranslate'; @@ -125,7 +124,6 @@ export default function OrganizationsFundsSecurity() { allowSearch={false} value={form.values?.auth_2fa_policy} options={auth2FARequiredOptions} - optionsComponent={SelectControlOptions} onChange={( auth_2fa_policy: | 'global' @@ -147,7 +145,6 @@ export default function OrganizationsFundsSecurity() { allowSearch={false} value={fund.organization_funds_2fa.auth_2fa_policy} options={auth2FARequiredOptions} - optionsComponent={SelectControlOptions} disabled={true} onChange={() => null} /> diff --git a/react/src/dashboard/components/pages/organizations-funds-security/elements/OrganizationsFundsSecurityAuth2FAForm.tsx b/react/src/dashboard/components/pages/organizations-funds-security/elements/OrganizationsFundsSecurityAuth2FAForm.tsx index c76b511ca..7b52a5e73 100644 --- a/react/src/dashboard/components/pages/organizations-funds-security/elements/OrganizationsFundsSecurityAuth2FAForm.tsx +++ b/react/src/dashboard/components/pages/organizations-funds-security/elements/OrganizationsFundsSecurityAuth2FAForm.tsx @@ -2,7 +2,6 @@ import React, { Fragment, useState } from 'react'; import CheckboxControl from '../../../elements/forms/controls/CheckboxControl'; import FormError from '../../../elements/forms/errors/FormError'; import SelectControl from '../../../elements/select-control/SelectControl'; -import SelectControlOptions from '../../../elements/select-control/templates/SelectControlOptions'; type Auth2FAValues = { auth_2fa_policy?: 'optional' | 'required' | 'restrict_features' | 'global'; @@ -47,7 +46,6 @@ export default function OrganizationsFundsSecurityAuth2FAForm({ allowSearch={false} value={formValues.auth_2fa_remember_ip} options={auth2FARememberIpOptions} - optionsComponent={SelectControlOptions} disabled={disabled} onChange={(auth_2fa_remember_ip: boolean) => setFormValues({ ...formValues, auth_2fa_remember_ip: auth_2fa_remember_ip }) diff --git a/react/src/dashboard/components/pages/organizations-funds-show/OrganizationsFundsShow.tsx b/react/src/dashboard/components/pages/organizations-funds-show/OrganizationsFundsShow.tsx index 65dbc49af..9b1088dde 100644 --- a/react/src/dashboard/components/pages/organizations-funds-show/OrganizationsFundsShow.tsx +++ b/react/src/dashboard/components/pages/organizations-funds-show/OrganizationsFundsShow.tsx @@ -1,37 +1,27 @@ -import React, { Fragment, useCallback, useEffect, useMemo, useState } from 'react'; +import React, { Fragment, useCallback, useEffect, useState } from 'react'; import StateNavLink from '../../../modules/state_router/StateNavLink'; import useActiveOrganization from '../../../hooks/useActiveOrganization'; import Fund from '../../../props/models/Fund'; import { useFundService } from '../../../services/FundService'; import { useParams } from 'react-router-dom'; import LoadingCard from '../../elements/loading-card/LoadingCard'; -import { hasPermission } from '../../../helpers/utils'; -import ModalNotification from '../../modals/ModalNotification'; -import useOpenModal from '../../../hooks/useOpenModal'; -import { useNavigateState } from '../../../modules/state_router/Router'; import useTranslate from '../../../hooks/useTranslate'; import useSetProgress from '../../../hooks/useSetProgress'; import OrganizationsFundsShowDetailsCard from './elements/OrganizationsFundsShowDetailsCard'; import OrganizationsFundsShowRelationsCard from './elements/OrganizationsFundsShowRelationsCard'; -import FundStateLabels from '../../elements/resource-states/FundStateLabels'; +import OrganizationFundsShowOverviewCard from './elements/OrganizationFundsShowOverviewCard'; export default function OrganizationsFundsShow() { const fundId = useParams().fundId; - const openModal = useOpenModal(); const translate = useTranslate(); const setProgress = useSetProgress(); - const navigateState = useNavigateState(); const activeOrganization = useActiveOrganization(); const fundService = useFundService(); const [fund, setFund] = useState(null); - const canManageFunds = useMemo(() => { - return hasPermission(activeOrganization, 'manage_funds'); - }, [activeOrganization]); - const fetchFund = useCallback(() => { setProgress(0); @@ -41,29 +31,6 @@ export default function OrganizationsFundsShow() { .finally(() => setProgress(100)); }, [setProgress, fundService, activeOrganization.id, fundId]); - const deleteFund = useCallback( - (fund: Fund) => { - openModal((modal) => ( - modal.close() }} - buttonSubmit={{ - onClick: () => { - fundService.destroy(activeOrganization.id, fund.id).then(() => { - modal.close(); - navigateState('organization-funds', { organizationId: activeOrganization.id }); - }); - }, - }} - /> - )); - }, - [activeOrganization.id, fundService, navigateState, openModal, translate], - ); - useEffect(() => { fetchFund(); }, [fetchFund]); @@ -86,61 +53,7 @@ export default function OrganizationsFundsShow() {
{fund.name}
-
-
-
-
-
- {''} -
- -
-
-
{fund.name}
- -
- -
{fund.description_short}
-
-
- -
-
- {canManageFunds && activeOrganization.allow_2fa_restrictions && ( - - - {translate('fund_card_sponsor.buttons.security')} - - )} - - {canManageFunds && fund.state == 'waiting' && ( - - )} - - {hasPermission(fund.organization, ['manage_funds', 'manage_fund_texts']) && ( - - - Bewerken - - )} -
-
-
-
-
+ diff --git a/react/src/dashboard/components/pages/organizations-funds-show/elements/OrganizationFundsShowOverviewCard.tsx b/react/src/dashboard/components/pages/organizations-funds-show/elements/OrganizationFundsShowOverviewCard.tsx new file mode 100644 index 000000000..7fdba4ae3 --- /dev/null +++ b/react/src/dashboard/components/pages/organizations-funds-show/elements/OrganizationFundsShowOverviewCard.tsx @@ -0,0 +1,137 @@ +import FundStateLabels from '../../../elements/resource-states/FundStateLabels'; +import StateNavLink from '../../../../modules/state_router/StateNavLink'; +import { hasPermission } from '../../../../helpers/utils'; +import React, { useCallback, useMemo } from 'react'; +import Fund from '../../../../props/models/Fund'; +import ModalNotification from '../../../modals/ModalNotification'; +import useOpenModal from '../../../../hooks/useOpenModal'; +import { useNavigateState } from '../../../../modules/state_router/Router'; +import useActiveOrganization from '../../../../hooks/useActiveOrganization'; +import useTranslate from '../../../../hooks/useTranslate'; +import { useFundService } from '../../../../services/FundService'; +import classNames from 'classnames'; + +export default function OrganizationFundsShowOverviewCard({ + fund, + compact = false, +}: { + fund: Fund; + compact?: boolean; +}) { + const activeOrganization = useActiveOrganization(); + + const openModal = useOpenModal(); + const translate = useTranslate(); + const navigateState = useNavigateState(); + + const fundService = useFundService(); + + const canManageFunds = useMemo(() => { + return hasPermission(activeOrganization, 'manage_funds'); + }, [activeOrganization]); + + const deleteFund = useCallback( + (fund: Fund) => { + openModal((modal) => ( + modal.close() }} + buttonSubmit={{ + onClick: () => { + fundService.destroy(activeOrganization.id, fund.id).then(() => { + modal.close(); + navigateState('organization-funds', { organizationId: activeOrganization.id }); + }); + }, + }} + /> + )); + }, + [activeOrganization.id, fundService, navigateState, openModal, translate], + ); + + return ( +
+
+
+
+
+ {''} +
+ +
+
+
{fund.name}
+ +
+ +
+ {fund.description_short} + + {compact && ( + + + Open fonds pagina + + )} +
+
+
+ + {!compact && ( +
+
+ {canManageFunds && fund.fund_form_id && ( + + + {translate('fund_card_sponsor.buttons.criteria')} + + )} + + {canManageFunds && activeOrganization.allow_2fa_restrictions && ( + + + {translate('fund_card_sponsor.buttons.security')} + + )} + + {canManageFunds && fund.state == 'waiting' && ( + + )} + + {hasPermission(fund.organization, ['manage_funds', 'manage_fund_texts']) && ( + + + Bewerken + + )} +
+
+ )} +
+
+
+ ); +} diff --git a/react/src/dashboard/components/pages/organizations-funds-show/elements/OrganizationsFundsShowCriteriaCard.tsx b/react/src/dashboard/components/pages/organizations-funds-show/elements/OrganizationsFundsShowCriteriaCard.tsx deleted file mode 100644 index 747c1fb06..000000000 --- a/react/src/dashboard/components/pages/organizations-funds-show/elements/OrganizationsFundsShowCriteriaCard.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import React, { useCallback, useEffect, useState } from 'react'; -import Fund from '../../../../props/models/Fund'; -import LoadingCard from '../../../elements/loading-card/LoadingCard'; -import OrganizationsFundsShowFundRequestConfigCard from './OrganizationsFundsShowFundRequestConfigCard'; -import OrganizationsFundsShowFundRequestCriteriaCard from './OrganizationsFundsShowFundRequestCriteriaCard'; -import RecordType from '../../../../props/models/RecordType'; -import useSetProgress from '../../../../hooks/useSetProgress'; -import { useRecordTypeService } from '../../../../services/RecordTypeService'; - -export default function OrganizationsFundsShowCriteriaCard({ - fund, - setFund, -}: { - fund: Fund; - setFund: React.Dispatch>; -}) { - const setProgress = useSetProgress(); - const recordTypeService = useRecordTypeService(); - - const [recordTypes, setRecordTypes] = useState>(null); - - const fetchRecordTypes = useCallback(() => { - setProgress(0); - - recordTypeService - .list({ criteria: 1 }) - .then((res) => setRecordTypes(res.data)) - .finally(() => setProgress(100)); - }, [recordTypeService, setProgress]); - - useEffect(() => { - fetchRecordTypes(); - }, [fetchRecordTypes]); - - return recordTypes ? ( -
-
- - - -
-
- ) : ( - - ); -} diff --git a/react/src/dashboard/components/pages/organizations-funds-show/elements/OrganizationsFundsShowDetailsCard.tsx b/react/src/dashboard/components/pages/organizations-funds-show/elements/OrganizationsFundsShowDetailsCard.tsx index d724ecb2f..82ae5b484 100644 --- a/react/src/dashboard/components/pages/organizations-funds-show/elements/OrganizationsFundsShowDetailsCard.tsx +++ b/react/src/dashboard/components/pages/organizations-funds-show/elements/OrganizationsFundsShowDetailsCard.tsx @@ -1,7 +1,6 @@ -import OrganizationsFundsShowDescriptionCard from './OrganizationsFundsShowDescriptionCard'; -import OrganizationsFundsShowFormulasCard from './OrganizationsFundsShowFormulasCard'; -import OrganizationsFundsShowCriteriaCard from './OrganizationsFundsShowCriteriaCard'; -import OrganizationsFundsShowStatisticsCard from './OrganizationsFundsShowStatisticsCard'; +import OrganizationsFundsShowDescriptionCard from './tabs-details-card/OrganizationsFundsShowDescriptionCard'; +import OrganizationsFundsShowFormulasCard from './tabs-details-card/OrganizationsFundsShowFormulasCard'; +import OrganizationsFundsShowStatisticsCard from './tabs-details-card/OrganizationsFundsShowStatisticsCard'; import React, { useMemo } from 'react'; import { createEnumParam, useQueryParam, withDefault } from 'use-query-params'; import useTranslate from '../../../../hooks/useTranslate'; @@ -9,7 +8,7 @@ import { hasPermission } from '../../../../helpers/utils'; import Organization from '../../../../props/models/Organization'; import Fund from '../../../../props/models/Fund'; import classNames from 'classnames'; -import OrganizationsFundsShowConfigsCard from './OrganizationsFundsShowConfigsCard'; +import OrganizationsFundsShowConfigsCard from './tabs-details-card/OrganizationsFundsShowConfigsCard'; export default function OrganizationsFundsShowDetailsCard({ fund, @@ -39,7 +38,6 @@ export default function OrganizationsFundsShowDetailsCard({ 'description', canViewFinances ? 'statistics' : null, canManageFunds ? 'formulas' : null, - canManageFunds ? 'criteria' : null, canManagePayouts ? 'configs' : null, ].filter((tab) => tab); }, [canManageFunds, canManagePayouts, canViewFinances]); @@ -77,7 +75,6 @@ export default function OrganizationsFundsShowDetailsCard({ {viewType == 'statistics' && ( )} - {viewType == 'criteria' && } {viewType == 'formulas' && } {viewType == 'configs' && }
diff --git a/react/src/dashboard/components/pages/organizations-funds-show/elements/OrganizationsFundsShowFundRequestConfigCard.tsx b/react/src/dashboard/components/pages/organizations-funds-show/elements/OrganizationsFundsShowFundRequestConfigCard.tsx deleted file mode 100644 index c51c742e8..000000000 --- a/react/src/dashboard/components/pages/organizations-funds-show/elements/OrganizationsFundsShowFundRequestConfigCard.tsx +++ /dev/null @@ -1,386 +0,0 @@ -import React, { Fragment, useEffect, useState } from 'react'; -import useSetProgress from '../../../../hooks/useSetProgress'; -import FormError from '../../../elements/forms/errors/FormError'; -import useFormBuilder from '../../../../hooks/useFormBuilder'; -import useTranslate from '../../../../hooks/useTranslate'; -import CheckboxControl from '../../../elements/forms/controls/CheckboxControl'; -import FormGroupInfo from '../../../elements/forms/elements/FormGroupInfo'; -import MarkdownEditor from '../../../elements/forms/markdown-editor/MarkdownEditor'; -import Fund from '../../../../props/models/Fund'; -import { ResponseError } from '../../../../props/ApiResponses'; -import { useFundService } from '../../../../services/FundService'; -import usePushSuccess from '../../../../hooks/usePushSuccess'; -import classNames from 'classnames'; -import usePushApiError from '../../../../hooks/usePushApiError'; - -export default function OrganizationsFundsShowFundRequestConfigCard({ - fund, - setFund, -}: { - fund: Fund; - setFund: React.Dispatch>; -}) { - const translate = useTranslate(); - const pushSuccess = usePushSuccess(); - const setProgress = useSetProgress(); - const pushApiError = usePushApiError(); - - const fundService = useFundService(); - - const [collapsed, setCollapsed] = useState(true); - - const form = useFormBuilder<{ - help_title: string; - help_block_text: string; - help_button_text: string; - help_show_email: boolean; - help_show_phone: boolean; - help_show_website: boolean; - help_show_chat: boolean; - help_email: string; - help_phone: string; - help_website: string; - help_chat: string; - help_description: string; - help_description_html: string; - help_enabled: boolean; - }>( - { - help_title: '', - help_block_text: '', - help_button_text: '', - help_show_email: false, - help_show_phone: false, - help_show_website: false, - help_show_chat: false, - help_email: '', - help_phone: '', - help_website: '', - help_chat: '', - help_description: '', - help_description_html: '', - help_enabled: false, - }, - (values) => { - setProgress(0); - - fundService - .update(fund.organization.id, fund.id, values) - .then(() => { - pushSuccess('Opgeslagen!'); - setFund(fund); - form.setErrors({}); - }) - .catch((err: ResponseError) => { - pushApiError(err); - form.setErrors(err.data.errors); - }) - .finally(() => { - setProgress(100); - form.setIsLocked(false); - }); - }, - ); - - const { update: updateForm } = form; - - useEffect(() => { - if (fund) { - updateForm({ - help_title: fund.help_title, - help_block_text: fund.help_block_text, - help_button_text: fund.help_button_text, - help_show_email: fund.help_show_email, - help_show_phone: fund.help_show_phone, - help_show_website: fund.help_show_website, - help_show_chat: fund.help_show_chat, - help_email: fund.help_email, - help_phone: fund.help_phone, - help_website: fund.help_website, - help_chat: fund.help_chat, - help_description: fund.help_description, - help_description_html: fund.help_description_html, - help_enabled: fund.help_enabled, - }); - } - }, [updateForm, fund]); - - return ( -
-
setCollapsed(!collapsed)}> - - -
Instellingen aanvraagformulier
- - {!collapsed ? ( - - ) : ( - - )} -
- - {!collapsed && ( - -
-
-
- {translate('fund_request_configurations.titles.main_information')} -
-
- -
- form.update({ help_enabled: e.target.checked })} - /> - -
- -
-
-
- - - - Banner tekst Een korte tekst onder het aanvraagformulier over de hulp - optie tijdens het invullen van het aanvraagformulier. Deze tekst wordt - naast de hulp knop getoond. -

- }> - form.update({ help_block_text: e.target.value })} - /> -
- -
-
- -
-
- - - - Knop tekst De tekst van de knop onder het aanvraagformulier. Door te - klikken op deze knop opent er meer informatie (en contactinformatie) - over de geboden ondersteuning. -

- }> - form.update({ help_button_text: e.target.value })} - /> -
- - -
-
-
- -
- - - form.update({ help_title: e.target.value })} - /> - - -
- -
- - form.update({ help_description: description })} - extendedOptions={true} - placeholder={translate('fund_request_configurations.labels.description_placeholder')} - /> -
Max. 1000 tekens
- -
- -
-
- {translate('fund_request_configurations.titles.contact_details')} -
-
- -
-
-
- form.update({ help_show_email: e.target.checked })} - /> - - - - form.update({ help_email: e.target.value })} - /> - - - -
- -
- form.update({ help_show_website: e.target.checked })} - /> - - - form.update({ help_website: e.target.value })} - /> - - - -
-
- -
-
- form.update({ help_show_phone: e.target.checked })} - /> - - - form.update({ help_phone: e.target.value })} - /> - - - -
- -
- form.update({ help_show_chat: e.target.checked })} - /> - - - - form.update({ help_chat: e.target.value })} - /> - - - -
-
-
-
- -
-
- - - -
-
-
- )} - - ); -} diff --git a/react/src/dashboard/components/pages/organizations-funds-show/elements/OrganizationsFundsShowRelationsCard.tsx b/react/src/dashboard/components/pages/organizations-funds-show/elements/OrganizationsFundsShowRelationsCard.tsx index 38fd3a183..490de32d7 100644 --- a/react/src/dashboard/components/pages/organizations-funds-show/elements/OrganizationsFundsShowRelationsCard.tsx +++ b/react/src/dashboard/components/pages/organizations-funds-show/elements/OrganizationsFundsShowRelationsCard.tsx @@ -3,9 +3,9 @@ import { createEnumParam, useQueryParam, withDefault } from 'use-query-params'; import { hasPermission } from '../../../../helpers/utils'; import Organization from '../../../../props/models/Organization'; import Fund from '../../../../props/models/Fund'; -import OrganizationsFundsShowTopUpsCard from './OrganizationsFundsShowTopUpsCard'; -import OrganizationsFundsShowImplementationsCard from './OrganizationsFundsShowImplementationsCard'; -import OrganizationsFundsShowIdentitiesCard from './OrganizationsFundsShowIdentitiesCard'; +import OrganizationsFundsShowTopUpsCard from './tabs-relations-card/OrganizationsFundsShowTopUpsCard'; +import OrganizationsFundsShowImplementationsCard from './tabs-relations-card/OrganizationsFundsShowImplementationsCard'; +import OrganizationsFundsShowIdentitiesCard from './tabs-relations-card/OrganizationsFundsShowIdentitiesCard'; import { filter } from 'lodash'; type TabType = 'top_ups' | 'identities' | 'implementations'; diff --git a/react/src/dashboard/components/pages/organizations-funds-show/elements/OrganizationsFundsShowConfigsCard.tsx b/react/src/dashboard/components/pages/organizations-funds-show/elements/tabs-details-card/OrganizationsFundsShowConfigsCard.tsx similarity index 95% rename from react/src/dashboard/components/pages/organizations-funds-show/elements/OrganizationsFundsShowConfigsCard.tsx rename to react/src/dashboard/components/pages/organizations-funds-show/elements/tabs-details-card/OrganizationsFundsShowConfigsCard.tsx index 9f54a6bd1..e96ceb000 100644 --- a/react/src/dashboard/components/pages/organizations-funds-show/elements/OrganizationsFundsShowConfigsCard.tsx +++ b/react/src/dashboard/components/pages/organizations-funds-show/elements/tabs-details-card/OrganizationsFundsShowConfigsCard.tsx @@ -1,14 +1,14 @@ import React, { Fragment } from 'react'; -import Fund from '../../../../props/models/Fund'; -import CheckboxControl from '../../../elements/forms/controls/CheckboxControl'; -import useFormBuilder from '../../../../hooks/useFormBuilder'; -import FormGroup from '../../../elements/forms/controls/FormGroup'; -import FormError from '../../../elements/forms/errors/FormError'; -import { useFundService } from '../../../../services/FundService'; -import { ResponseError } from '../../../../props/ApiResponses'; -import usePushSuccess from '../../../../hooks/usePushSuccess'; -import useSetProgress from '../../../../hooks/useSetProgress'; -import usePushApiError from '../../../../hooks/usePushApiError'; +import Fund from '../../../../../props/models/Fund'; +import CheckboxControl from '../../../../elements/forms/controls/CheckboxControl'; +import useFormBuilder from '../../../../../hooks/useFormBuilder'; +import FormGroup from '../../../../elements/forms/controls/FormGroup'; +import FormError from '../../../../elements/forms/errors/FormError'; +import { useFundService } from '../../../../../services/FundService'; +import { ResponseError } from '../../../../../props/ApiResponses'; +import usePushSuccess from '../../../../../hooks/usePushSuccess'; +import useSetProgress from '../../../../../hooks/useSetProgress'; +import usePushApiError from '../../../../../hooks/usePushApiError'; export default function OrganizationsFundsShowConfigsCard({ fund, diff --git a/react/src/dashboard/components/pages/organizations-funds-show/elements/OrganizationsFundsShowDescriptionCard.tsx b/react/src/dashboard/components/pages/organizations-funds-show/elements/tabs-details-card/OrganizationsFundsShowDescriptionCard.tsx similarity index 88% rename from react/src/dashboard/components/pages/organizations-funds-show/elements/OrganizationsFundsShowDescriptionCard.tsx rename to react/src/dashboard/components/pages/organizations-funds-show/elements/tabs-details-card/OrganizationsFundsShowDescriptionCard.tsx index 615c919cb..07e66f802 100644 --- a/react/src/dashboard/components/pages/organizations-funds-show/elements/OrganizationsFundsShowDescriptionCard.tsx +++ b/react/src/dashboard/components/pages/organizations-funds-show/elements/tabs-details-card/OrganizationsFundsShowDescriptionCard.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import Fund from '../../../../props/models/Fund'; -import TranslateHtml from '../../../elements/translate-html/TranslateHtml'; +import Fund from '../../../../../props/models/Fund'; +import TranslateHtml from '../../../../elements/translate-html/TranslateHtml'; export default function OrganizationsFundsShowDescriptionCard({ fund }: { fund: Fund }) { return ( diff --git a/react/src/dashboard/components/pages/organizations-funds-show/elements/OrganizationsFundsShowFormulasCard.tsx b/react/src/dashboard/components/pages/organizations-funds-show/elements/tabs-details-card/OrganizationsFundsShowFormulasCard.tsx similarity index 91% rename from react/src/dashboard/components/pages/organizations-funds-show/elements/OrganizationsFundsShowFormulasCard.tsx rename to react/src/dashboard/components/pages/organizations-funds-show/elements/tabs-details-card/OrganizationsFundsShowFormulasCard.tsx index db3cddb21..0d0ce23dd 100644 --- a/react/src/dashboard/components/pages/organizations-funds-show/elements/OrganizationsFundsShowFormulasCard.tsx +++ b/react/src/dashboard/components/pages/organizations-funds-show/elements/tabs-details-card/OrganizationsFundsShowFormulasCard.tsx @@ -1,7 +1,7 @@ import React from 'react'; -import Fund from '../../../../props/models/Fund'; -import EmptyCard from '../../../elements/empty-card/EmptyCard'; -import TableDateTime from '../../../elements/tables/elements/TableDateTime'; +import Fund from '../../../../../props/models/Fund'; +import EmptyCard from '../../../../elements/empty-card/EmptyCard'; +import TableDateTime from '../../../../elements/tables/elements/TableDateTime'; export default function OrganizationsFundsShowFormulasCard({ fund }: { fund: Fund }) { return ( diff --git a/react/src/dashboard/components/pages/organizations-funds-show/elements/OrganizationsFundsShowStatisticsCard.tsx b/react/src/dashboard/components/pages/organizations-funds-show/elements/tabs-details-card/OrganizationsFundsShowStatisticsCard.tsx similarity index 89% rename from react/src/dashboard/components/pages/organizations-funds-show/elements/OrganizationsFundsShowStatisticsCard.tsx rename to react/src/dashboard/components/pages/organizations-funds-show/elements/tabs-details-card/OrganizationsFundsShowStatisticsCard.tsx index d203eebd2..73de62a85 100644 --- a/react/src/dashboard/components/pages/organizations-funds-show/elements/OrganizationsFundsShowStatisticsCard.tsx +++ b/react/src/dashboard/components/pages/organizations-funds-show/elements/tabs-details-card/OrganizationsFundsShowStatisticsCard.tsx @@ -1,13 +1,13 @@ import React, { Fragment, useCallback, useMemo } from 'react'; -import Fund from '../../../../props/models/Fund'; -import EmptyCard from '../../../elements/empty-card/EmptyCard'; -import { useNavigateState } from '../../../../modules/state_router/Router'; -import ModalFundInviteProviders from '../../../modals/ModalFundInviteProviders'; -import { hasPermission } from '../../../../helpers/utils'; -import Organization from '../../../../props/models/Organization'; -import useTranslate from '../../../../hooks/useTranslate'; -import useOpenModal from '../../../../hooks/useOpenModal'; -import usePushSuccess from '../../../../hooks/usePushSuccess'; +import Fund from '../../../../../props/models/Fund'; +import EmptyCard from '../../../../elements/empty-card/EmptyCard'; +import { useNavigateState } from '../../../../../modules/state_router/Router'; +import ModalFundInviteProviders from '../../../../modals/ModalFundInviteProviders'; +import { hasPermission } from '../../../../../helpers/utils'; +import Organization from '../../../../../props/models/Organization'; +import useTranslate from '../../../../../hooks/useTranslate'; +import useOpenModal from '../../../../../hooks/useOpenModal'; +import usePushSuccess from '../../../../../hooks/usePushSuccess'; export default function OrganizationsFundsShowStatisticsCard({ fund, diff --git a/react/src/dashboard/components/pages/organizations-funds-show/elements/OrganizationsFundsShowIdentitiesCard.tsx b/react/src/dashboard/components/pages/organizations-funds-show/elements/tabs-relations-card/OrganizationsFundsShowIdentitiesCard.tsx similarity index 91% rename from react/src/dashboard/components/pages/organizations-funds-show/elements/OrganizationsFundsShowIdentitiesCard.tsx rename to react/src/dashboard/components/pages/organizations-funds-show/elements/tabs-relations-card/OrganizationsFundsShowIdentitiesCard.tsx index 35c5e3825..d50049f0b 100644 --- a/react/src/dashboard/components/pages/organizations-funds-show/elements/OrganizationsFundsShowIdentitiesCard.tsx +++ b/react/src/dashboard/components/pages/organizations-funds-show/elements/tabs-relations-card/OrganizationsFundsShowIdentitiesCard.tsx @@ -1,23 +1,23 @@ import React, { Fragment, useCallback, useEffect, useState } from 'react'; -import Fund from '../../../../props/models/Fund'; -import ClickOutside from '../../../elements/click-outside/ClickOutside'; -import FilterItemToggle from '../../../elements/tables/elements/FilterItemToggle'; -import EmptyCard from '../../../elements/empty-card/EmptyCard'; -import Paginator from '../../../../modules/paginator/components/Paginator'; -import useTranslate from '../../../../hooks/useTranslate'; -import useActiveOrganization from '../../../../hooks/useActiveOrganization'; -import usePaginatorService from '../../../../modules/paginator/services/usePaginatorService'; -import { PaginationData } from '../../../../props/ApiResponses'; -import useFilter from '../../../../hooks/useFilter'; -import LoadingCard from '../../../elements/loading-card/LoadingCard'; -import StateNavLink from '../../../../modules/state_router/StateNavLink'; -import ThSortable from '../../../elements/tables/ThSortable'; -import SponsorIdentity from '../../../../props/models/Sponsor/SponsorIdentity'; -import useSetProgress from '../../../../hooks/useSetProgress'; -import { useFundService } from '../../../../services/FundService'; -import useFundIdentitiesExportService from '../../../../services/exports/useFundIdentitiesExportService'; -import TableEmptyValue from '../../../elements/table-empty-value/TableEmptyValue'; -import { hasPermission } from '../../../../helpers/utils'; +import Fund from '../../../../../props/models/Fund'; +import ClickOutside from '../../../../elements/click-outside/ClickOutside'; +import FilterItemToggle from '../../../../elements/tables/elements/FilterItemToggle'; +import EmptyCard from '../../../../elements/empty-card/EmptyCard'; +import Paginator from '../../../../../modules/paginator/components/Paginator'; +import useTranslate from '../../../../../hooks/useTranslate'; +import useActiveOrganization from '../../../../../hooks/useActiveOrganization'; +import usePaginatorService from '../../../../../modules/paginator/services/usePaginatorService'; +import { PaginationData } from '../../../../../props/ApiResponses'; +import useFilter from '../../../../../hooks/useFilter'; +import LoadingCard from '../../../../elements/loading-card/LoadingCard'; +import StateNavLink from '../../../../../modules/state_router/StateNavLink'; +import ThSortable from '../../../../elements/tables/ThSortable'; +import SponsorIdentity from '../../../../../props/models/Sponsor/SponsorIdentity'; +import useSetProgress from '../../../../../hooks/useSetProgress'; +import { useFundService } from '../../../../../services/FundService'; +import useFundIdentitiesExportService from '../../../../../services/exports/useFundIdentitiesExportService'; +import TableEmptyValue from '../../../../elements/table-empty-value/TableEmptyValue'; +import { hasPermission } from '../../../../../helpers/utils'; export default function OrganizationsFundsShowIdentitiesCard({ fund, diff --git a/react/src/dashboard/components/pages/organizations-funds-show/elements/OrganizationsFundsShowImplementationsCard.tsx b/react/src/dashboard/components/pages/organizations-funds-show/elements/tabs-relations-card/OrganizationsFundsShowImplementationsCard.tsx similarity index 92% rename from react/src/dashboard/components/pages/organizations-funds-show/elements/OrganizationsFundsShowImplementationsCard.tsx rename to react/src/dashboard/components/pages/organizations-funds-show/elements/tabs-relations-card/OrganizationsFundsShowImplementationsCard.tsx index fb5e91898..ab5ce73ac 100644 --- a/react/src/dashboard/components/pages/organizations-funds-show/elements/OrganizationsFundsShowImplementationsCard.tsx +++ b/react/src/dashboard/components/pages/organizations-funds-show/elements/tabs-relations-card/OrganizationsFundsShowImplementationsCard.tsx @@ -1,20 +1,20 @@ import React, { Fragment, useCallback, useEffect, useState } from 'react'; -import Fund from '../../../../props/models/Fund'; -import ClickOutside from '../../../elements/click-outside/ClickOutside'; -import FilterItemToggle from '../../../elements/tables/elements/FilterItemToggle'; -import EmptyCard from '../../../elements/empty-card/EmptyCard'; -import Paginator from '../../../../modules/paginator/components/Paginator'; -import useTranslate from '../../../../hooks/useTranslate'; -import useActiveOrganization from '../../../../hooks/useActiveOrganization'; -import usePaginatorService from '../../../../modules/paginator/services/usePaginatorService'; -import { PaginationData } from '../../../../props/ApiResponses'; -import useFilter from '../../../../hooks/useFilter'; -import LoadingCard from '../../../elements/loading-card/LoadingCard'; -import TableRowActions from '../../../elements/tables/TableRowActions'; -import { hasPermission } from '../../../../helpers/utils'; -import StateNavLink from '../../../../modules/state_router/StateNavLink'; -import useAssetUrl from '../../../../hooks/useAssetUrl'; -import Implementation from '../../../../props/models/Implementation'; +import Fund from '../../../../../props/models/Fund'; +import ClickOutside from '../../../../elements/click-outside/ClickOutside'; +import FilterItemToggle from '../../../../elements/tables/elements/FilterItemToggle'; +import EmptyCard from '../../../../elements/empty-card/EmptyCard'; +import Paginator from '../../../../../modules/paginator/components/Paginator'; +import useTranslate from '../../../../../hooks/useTranslate'; +import useActiveOrganization from '../../../../../hooks/useActiveOrganization'; +import usePaginatorService from '../../../../../modules/paginator/services/usePaginatorService'; +import { PaginationData } from '../../../../../props/ApiResponses'; +import useFilter from '../../../../../hooks/useFilter'; +import LoadingCard from '../../../../elements/loading-card/LoadingCard'; +import TableRowActions from '../../../../elements/tables/TableRowActions'; +import { hasPermission } from '../../../../../helpers/utils'; +import StateNavLink from '../../../../../modules/state_router/StateNavLink'; +import useAssetUrl from '../../../../../hooks/useAssetUrl'; +import Implementation from '../../../../../props/models/Implementation'; export default function OrganizationsFundsShowImplementationsCard({ fund, diff --git a/react/src/dashboard/components/pages/organizations-funds-show/elements/OrganizationsFundsShowTopUpsCard.tsx b/react/src/dashboard/components/pages/organizations-funds-show/elements/tabs-relations-card/OrganizationsFundsShowTopUpsCard.tsx similarity index 92% rename from react/src/dashboard/components/pages/organizations-funds-show/elements/OrganizationsFundsShowTopUpsCard.tsx rename to react/src/dashboard/components/pages/organizations-funds-show/elements/tabs-relations-card/OrganizationsFundsShowTopUpsCard.tsx index fea77e421..55b656fa5 100644 --- a/react/src/dashboard/components/pages/organizations-funds-show/elements/OrganizationsFundsShowTopUpsCard.tsx +++ b/react/src/dashboard/components/pages/organizations-funds-show/elements/tabs-relations-card/OrganizationsFundsShowTopUpsCard.tsx @@ -1,21 +1,21 @@ import React, { Fragment, useCallback, useEffect, useState } from 'react'; -import Fund from '../../../../props/models/Fund'; -import ClickOutside from '../../../elements/click-outside/ClickOutside'; -import FilterItemToggle from '../../../elements/tables/elements/FilterItemToggle'; -import DatePickerControl from '../../../elements/forms/controls/DatePickerControl'; -import { dateFormat, dateParse } from '../../../../helpers/dates'; -import ThSortable from '../../../elements/tables/ThSortable'; -import FundTopUpTransaction from '../../../../props/models/FundTopUpTransaction'; -import EmptyCard from '../../../elements/empty-card/EmptyCard'; -import Paginator from '../../../../modules/paginator/components/Paginator'; -import useTranslate from '../../../../hooks/useTranslate'; -import useSetProgress from '../../../../hooks/useSetProgress'; -import useActiveOrganization from '../../../../hooks/useActiveOrganization'; -import { useFundService } from '../../../../services/FundService'; -import usePaginatorService from '../../../../modules/paginator/services/usePaginatorService'; -import { PaginationData } from '../../../../props/ApiResponses'; -import useFilter from '../../../../hooks/useFilter'; -import LoadingCard from '../../../elements/loading-card/LoadingCard'; +import Fund from '../../../../../props/models/Fund'; +import ClickOutside from '../../../../elements/click-outside/ClickOutside'; +import FilterItemToggle from '../../../../elements/tables/elements/FilterItemToggle'; +import DatePickerControl from '../../../../elements/forms/controls/DatePickerControl'; +import { dateFormat, dateParse } from '../../../../../helpers/dates'; +import ThSortable from '../../../../elements/tables/ThSortable'; +import FundTopUpTransaction from '../../../../../props/models/FundTopUpTransaction'; +import EmptyCard from '../../../../elements/empty-card/EmptyCard'; +import Paginator from '../../../../../modules/paginator/components/Paginator'; +import useTranslate from '../../../../../hooks/useTranslate'; +import useSetProgress from '../../../../../hooks/useSetProgress'; +import useActiveOrganization from '../../../../../hooks/useActiveOrganization'; +import { useFundService } from '../../../../../services/FundService'; +import usePaginatorService from '../../../../../modules/paginator/services/usePaginatorService'; +import { PaginationData } from '../../../../../props/ApiResponses'; +import useFilter from '../../../../../hooks/useFilter'; +import LoadingCard from '../../../../elements/loading-card/LoadingCard'; export default function OrganizationsFundsShowTopUpsCard({ fund, diff --git a/react/src/dashboard/components/pages/organizations-funds/OrganizationFunds.tsx b/react/src/dashboard/components/pages/organizations-funds/OrganizationFunds.tsx index 887657889..59718fcaf 100644 --- a/react/src/dashboard/components/pages/organizations-funds/OrganizationFunds.tsx +++ b/react/src/dashboard/components/pages/organizations-funds/OrganizationFunds.tsx @@ -12,7 +12,6 @@ import useSetProgress from '../../../hooks/useSetProgress'; import ClickOutside from '../../elements/click-outside/ClickOutside'; import FilterItemToggle from '../../elements/tables/elements/FilterItemToggle'; import SelectControl from '../../elements/select-control/SelectControl'; -import SelectControlOptions from '../../elements/select-control/templates/SelectControlOptions'; import useImplementationService from '../../../services/ImplementationService'; import Implementation from '../../../props/models/Implementation'; import { strLimit } from '../../../helpers/string'; @@ -304,7 +303,6 @@ export default function OrganizationFunds() { allowSearch={false} value={filter.values.state} options={statesOptions} - optionsComponent={SelectControlOptions} onChange={(state: string) => filter.update({ state })} /> @@ -319,7 +317,6 @@ export default function OrganizationFunds() { allowSearch={false} value={filter.values.implementation_id} options={implementations} - optionsComponent={SelectControlOptions} onChange={(implementation_id: string) => filter.update({ implementation_id }) } @@ -387,7 +384,7 @@ export default function OrganizationFunds() { - + {!fund.archived ? ( ( diff --git a/react/src/dashboard/components/pages/organizations-security/OrganizationsSecurity.tsx b/react/src/dashboard/components/pages/organizations-security/OrganizationsSecurity.tsx index 6fb2f340b..35c99251e 100644 --- a/react/src/dashboard/components/pages/organizations-security/OrganizationsSecurity.tsx +++ b/react/src/dashboard/components/pages/organizations-security/OrganizationsSecurity.tsx @@ -2,7 +2,6 @@ import React, { useContext, useState } from 'react'; import useActiveOrganization from '../../../hooks/useActiveOrganization'; import StateNavLink from '../../../modules/state_router/StateNavLink'; import SelectControl from '../../elements/select-control/SelectControl'; -import SelectControlOptions from '../../elements/select-control/templates/SelectControlOptions'; import useFormBuilder from '../../../hooks/useFormBuilder'; import FormError from '../../elements/forms/errors/FormError'; import { useOrganizationService } from '../../../services/OrganizationService'; @@ -138,7 +137,6 @@ export default function OrganizationsSecurity() { allowSearch={false} value={form.values.auth_2fa_policy} options={auth2FARequiredOptions} - optionsComponent={SelectControlOptions} onChange={( auth_2fa_policy: 'optional' | 'required' | 'restrict_features', ) => form.update({ auth_2fa_policy })} @@ -157,7 +155,6 @@ export default function OrganizationsSecurity() { allowSearch={false} value={form.values.auth_2fa_remember_ip} options={auth2FARememberIpOptions} - optionsComponent={SelectControlOptions} onChange={(auth_2fa_remember_ip: 1 | 0) => form.update({ auth_2fa_remember_ip }) } @@ -205,7 +202,6 @@ export default function OrganizationsSecurity() { | 'required' | 'restrict_features', ) => form.update({ auth_2fa_funds_policy })} - optionsComponent={SelectControlOptions} /> @@ -224,7 +220,6 @@ export default function OrganizationsSecurity() { form.update({ auth_2fa_funds_remember_ip }) } options={auth2FARememberIpOptions} - optionsComponent={SelectControlOptions} /> diff --git a/react/src/dashboard/components/pages/payment-methods/elements/MollieConnectionForm.tsx b/react/src/dashboard/components/pages/payment-methods/elements/MollieConnectionForm.tsx index 0362920bc..20ebd0094 100644 --- a/react/src/dashboard/components/pages/payment-methods/elements/MollieConnectionForm.tsx +++ b/react/src/dashboard/components/pages/payment-methods/elements/MollieConnectionForm.tsx @@ -6,7 +6,6 @@ import { ResponseError, ResponseErrorThrottled } from '../../../../props/ApiResp import useMollieConnectionService from '../../../../services/MollieConnectionService'; import useSetProgress from '../../../../hooks/useSetProgress'; import SelectControl from '../../../elements/select-control/SelectControl'; -import SelectControlOptions from '../../../elements/select-control/templates/SelectControlOptions'; import { getCountries } from 'libphonenumber-js'; import countries from 'i18n-iso-countries'; import countriesEn from 'i18n-iso-countries/langs/en.json'; @@ -103,7 +102,6 @@ export default function MollieConnectionForm({ value={form.values.country_code} allowSearch={true} onChange={(country_code: string) => form.update({ country_code })} - optionsComponent={SelectControlOptions} /> diff --git a/react/src/dashboard/components/pages/payment-methods/elements/MollieConnectionProfileSelector.tsx b/react/src/dashboard/components/pages/payment-methods/elements/MollieConnectionProfileSelector.tsx index d255b4cc0..1cf3f0cc0 100644 --- a/react/src/dashboard/components/pages/payment-methods/elements/MollieConnectionProfileSelector.tsx +++ b/react/src/dashboard/components/pages/payment-methods/elements/MollieConnectionProfileSelector.tsx @@ -1,6 +1,5 @@ import React from 'react'; import SelectControl from '../../../elements/select-control/SelectControl'; -import SelectControlOptions from '../../../elements/select-control/templates/SelectControlOptions'; import MollieConnectionProfile from '../../../../props/models/MollieConnectionProfile'; import useTranslate from '../../../../hooks/useTranslate'; @@ -30,7 +29,6 @@ export default function MollieConnectionProfileSelector({ options={profiles} value={currentProfileId} onChange={(currentProfileId: number) => onSelect(currentProfileId)} - optionsComponent={SelectControlOptions} /> diff --git a/react/src/dashboard/components/pages/payouts/Payouts.tsx b/react/src/dashboard/components/pages/payouts/Payouts.tsx index 090ba3e63..cee5c001c 100644 --- a/react/src/dashboard/components/pages/payouts/Payouts.tsx +++ b/react/src/dashboard/components/pages/payouts/Payouts.tsx @@ -8,7 +8,6 @@ import { useFundService } from '../../../services/FundService'; import Fund from '../../../props/models/Fund'; import FilterItemToggle from '../../elements/tables/elements/FilterItemToggle'; import SelectControl from '../../elements/select-control/SelectControl'; -import SelectControlOptions from '../../elements/select-control/templates/SelectControlOptions'; import DatePickerControl from '../../elements/forms/controls/DatePickerControl'; import CardHeaderFilter from '../../elements/tables/elements/CardHeaderFilter'; import { dateFormat, dateParse } from '../../../helpers/dates'; @@ -256,7 +255,6 @@ export default function Payouts() { allowSearch={false} value={filterValues.state} options={states} - optionsComponent={SelectControlOptions} onChange={(state: string) => filterUpdate({ state })} /> diff --git a/react/src/dashboard/components/pages/pre-check/PreCheck.tsx b/react/src/dashboard/components/pages/pre-check/PreCheck.tsx index 691645521..032439e01 100644 --- a/react/src/dashboard/components/pages/pre-check/PreCheck.tsx +++ b/react/src/dashboard/components/pages/pre-check/PreCheck.tsx @@ -3,7 +3,6 @@ import useFormBuilder from '../../../hooks/useFormBuilder'; import LoadingCard from '../../elements/loading-card/LoadingCard'; import Implementation from '../../../props/models/Implementation'; import SelectControl from '../../elements/select-control/SelectControl'; -import SelectControlOptions from '../../elements/select-control/templates/SelectControlOptions'; import Media from '../../../props/models/Media'; import FormError from '../../elements/forms/errors/FormError'; import Fund from '../../../props/models/Fund'; @@ -322,7 +321,6 @@ export default function PreCheck() { onChange={(implementation: Implementation) => { setImplementation(implementation); }} - optionsComponent={SelectControlOptions} /> @@ -339,7 +337,6 @@ export default function PreCheck() { onChange={(pre_check_enabled: boolean) => { preCheckForm.update({ pre_check_enabled }); }} - optionsComponent={SelectControlOptions} /> @@ -486,7 +483,6 @@ export default function PreCheck() { propKey={'value'} allowSearch={false} options={bannerStates} - optionsComponent={SelectControlOptions} value={bannerForm.values.pre_check_banner_state} onChange={(pre_check_banner_state: string) => { bannerForm.update({ pre_check_banner_state }); diff --git a/react/src/dashboard/components/pages/products-edit/elements/ProductCategoriesControl.tsx b/react/src/dashboard/components/pages/products-edit/elements/ProductCategoriesControl.tsx index c6d896e6d..349b311f6 100644 --- a/react/src/dashboard/components/pages/products-edit/elements/ProductCategoriesControl.tsx +++ b/react/src/dashboard/components/pages/products-edit/elements/ProductCategoriesControl.tsx @@ -2,7 +2,6 @@ import React, { useCallback, useEffect, useState } from 'react'; import FormError from '../../../elements/forms/errors/FormError'; import ProductCategory from '../../../../props/models/ProductCategory'; import SelectControl from '../../../elements/select-control/SelectControl'; -import SelectControlOptions from '../../../elements/select-control/templates/SelectControlOptions'; import useProductCategoryService from '../../../../services/ProductCategoryService'; import useTranslate from '../../../../hooks/useTranslate'; @@ -134,7 +133,6 @@ export default function ProductCategoriesControl({ onChange={(value?: number) => changeCategory(index, value)} disabled={disabled} placeholder="Selecteer categorie..." - optionsComponent={SelectControlOptions} /> {index == categoriesHierarchy.length - 1 && } diff --git a/react/src/dashboard/components/pages/products-edit/elements/ProductsForm.tsx b/react/src/dashboard/components/pages/products-edit/elements/ProductsForm.tsx index ebafe2f85..e2a7c4c12 100644 --- a/react/src/dashboard/components/pages/products-edit/elements/ProductsForm.tsx +++ b/react/src/dashboard/components/pages/products-edit/elements/ProductsForm.tsx @@ -15,7 +15,6 @@ import Product from '../../../../props/models/Product'; import useProductService from '../../../../services/ProductService'; import DatePickerControl from '../../../elements/forms/controls/DatePickerControl'; import SelectControl from '../../../elements/select-control/SelectControl'; -import SelectControlOptions from '../../../elements/select-control/templates/SelectControlOptions'; import ProductCategoriesControl from './ProductCategoriesControl'; import FundProvider from '../../../../props/models/FundProvider'; import { useFundService } from '../../../../services/FundService'; @@ -974,7 +973,6 @@ export default function ProductsForm({ form.update({ reservation_policy }); }} options={reservationPolicies} - optionsComponent={SelectControlOptions} />
@@ -1039,7 +1037,6 @@ export default function ProductsForm({ form.update({ reservation_phone }); }} options={reservationPhoneOptions} - optionsComponent={SelectControlOptions} />
@@ -1058,7 +1055,6 @@ export default function ProductsForm({ form.update({ reservation_address }); }} options={reservationAddressOptions} - optionsComponent={SelectControlOptions} /> @@ -1077,7 +1073,6 @@ export default function ProductsForm({ form.update({ reservation_birth_date }); }} options={reservationBirthDateOptions} - optionsComponent={SelectControlOptions} /> @@ -1108,7 +1103,6 @@ export default function ProductsForm({ form.update({ reservation_extra_payments }); }} options={extraPaymentsOptions} - optionsComponent={SelectControlOptions} /> diff --git a/react/src/dashboard/components/pages/provider-funds/elements/ProviderFundsAvailableTable.tsx b/react/src/dashboard/components/pages/provider-funds/elements/ProviderFundsAvailableTable.tsx index 4051f9f09..1acc1f979 100644 --- a/react/src/dashboard/components/pages/provider-funds/elements/ProviderFundsAvailableTable.tsx +++ b/react/src/dashboard/components/pages/provider-funds/elements/ProviderFundsAvailableTable.tsx @@ -14,7 +14,6 @@ import Fund from '../../../../props/models/Fund'; import CardHeaderFilter from '../../../elements/tables/elements/CardHeaderFilter'; import FilterItemToggle from '../../../elements/tables/elements/FilterItemToggle'; import SelectControl from '../../../elements/select-control/SelectControl'; -import SelectControlOptions from '../../../elements/select-control/templates/SelectControlOptions'; import ModalNotification from '../../../modals/ModalNotification'; import useTableToggles from '../../../../hooks/useTableToggles'; import Implementation from '../../../../props/models/Implementation'; @@ -261,7 +260,6 @@ export default function ProviderFundsAvailableTable({ propKey={'id'} propValue={'name'} onChange={(implementation_id?: number) => filter.update({ implementation_id })} - optionsComponent={SelectControlOptions} /> @@ -272,7 +270,6 @@ export default function ProviderFundsAvailableTable({ propKey={'id'} propValue={'name'} onChange={(organization_id?: number) => filter.update({ organization_id })} - optionsComponent={SelectControlOptions} /> @@ -283,7 +280,6 @@ export default function ProviderFundsAvailableTable({ propKey={'key'} propValue={'name'} onChange={(tag?: string) => filter.update({ tag })} - optionsComponent={SelectControlOptions} /> diff --git a/react/src/dashboard/components/pages/reimbursements/Reimbursements.tsx b/react/src/dashboard/components/pages/reimbursements/Reimbursements.tsx index 5f44bf681..6e77e2675 100644 --- a/react/src/dashboard/components/pages/reimbursements/Reimbursements.tsx +++ b/react/src/dashboard/components/pages/reimbursements/Reimbursements.tsx @@ -9,7 +9,6 @@ import usePaginatorService from '../../../modules/paginator/services/usePaginato import { useFundService } from '../../../services/FundService'; import FilterItemToggle from '../../elements/tables/elements/FilterItemToggle'; import SelectControl from '../../elements/select-control/SelectControl'; -import SelectControlOptions from '../../elements/select-control/templates/SelectControlOptions'; import { hasPermission } from '../../../helpers/utils'; import EmptyCard from '../../elements/empty-card/EmptyCard'; import { getStateRouteUrl } from '../../../modules/state_router/Router'; @@ -252,7 +251,6 @@ export default function Reimbursements() { allowSearch={false} value={filterValues.state} options={statesOptions} - optionsComponent={SelectControlOptions} onChange={(state: string) => filterUpdate({ state })} /> @@ -266,7 +264,6 @@ export default function Reimbursements() { allowSearch={false} value={filterValues.expired} options={expiredOptions} - optionsComponent={SelectControlOptions} onChange={(expired: number) => filterUpdate({ expired })} /> @@ -278,7 +275,6 @@ export default function Reimbursements() { allowSearch={false} value={filterValues.deactivated} options={deactivatedOptions} - optionsComponent={SelectControlOptions} onChange={(deactivated: number) => filterUpdate({ deactivated })} /> @@ -346,7 +342,6 @@ export default function Reimbursements() { allowSearch={false} value={filterValues.implementation_id} options={implementations} - optionsComponent={SelectControlOptions} onChange={(implementation_id: string) => filterUpdate({ implementation_id })} /> diff --git a/react/src/dashboard/components/pages/reservations-settings/ReservationsSettings.tsx b/react/src/dashboard/components/pages/reservations-settings/ReservationsSettings.tsx index 972440ab1..5591f1d49 100644 --- a/react/src/dashboard/components/pages/reservations-settings/ReservationsSettings.tsx +++ b/react/src/dashboard/components/pages/reservations-settings/ReservationsSettings.tsx @@ -7,7 +7,6 @@ import usePushSuccess from '../../../hooks/usePushSuccess'; import useUpdateActiveOrganization from '../../../hooks/useUpdateActiveOrganization'; import StateNavLink from '../../../modules/state_router/StateNavLink'; import SelectControl from '../../elements/select-control/SelectControl'; -import SelectControlOptions from '../../elements/select-control/templates/SelectControlOptions'; import FormError from '../../elements/forms/errors/FormError'; import { hasPermission } from '../../../helpers/utils'; import ReservationFieldsEditor from '../reservations/elements/ReservationFieldsEditor'; @@ -122,7 +121,6 @@ export default function ReservationsSettings() { form.update({ reservation_phone: value }) } options={reservationFieldOptions} - optionsComponent={SelectControlOptions} /> @@ -140,7 +138,6 @@ export default function ReservationsSettings() { form.update({ reservation_address: value }) } options={reservationFieldOptions} - optionsComponent={SelectControlOptions} /> @@ -159,7 +156,6 @@ export default function ReservationsSettings() { form.update({ reservation_birth_date: value }) } options={reservationFieldOptions} - optionsComponent={SelectControlOptions} /> @@ -194,7 +190,6 @@ export default function ReservationsSettings() { form.update({ reservation_allow_extra_payments: value }) } options={extraPaymentsOptions} - optionsComponent={SelectControlOptions} /> diff --git a/react/src/dashboard/components/pages/reservations/Reservations.tsx b/react/src/dashboard/components/pages/reservations/Reservations.tsx index 1ee515f7b..d4938d83e 100644 --- a/react/src/dashboard/components/pages/reservations/Reservations.tsx +++ b/react/src/dashboard/components/pages/reservations/Reservations.tsx @@ -20,7 +20,6 @@ import Fund from '../../../props/models/Fund'; import { hasPermission } from '../../../helpers/utils'; import FilterItemToggle from '../../elements/tables/elements/FilterItemToggle'; import SelectControl from '../../elements/select-control/SelectControl'; -import SelectControlOptions from '../../elements/select-control/templates/SelectControlOptions'; import DatePickerControl from '../../elements/forms/controls/DatePickerControl'; import CardHeaderFilter from '../../elements/tables/elements/CardHeaderFilter'; import useAuthIdentity from '../../../hooks/useAuthIdentity'; @@ -444,7 +443,6 @@ export default function Reservations() { propKey={'id'} allowSearch={false} options={funds} - optionsComponent={SelectControlOptions} onChange={(fund_id: number) => filter.update({ fund_id })} /> )} @@ -457,7 +455,6 @@ export default function Reservations() { propKey={'id'} allowSearch={true} options={products} - optionsComponent={SelectControlOptions} onChange={(product_id: number) => filter.update({ product_id })} /> )} @@ -490,7 +487,6 @@ export default function Reservations() { allowSearch={false} value={filter.values.state} options={states} - optionsComponent={SelectControlOptions} onChange={(state: string) => filter.update({ state })} /> diff --git a/react/src/dashboard/components/pages/reservations/elements/ReservationFieldItem.tsx b/react/src/dashboard/components/pages/reservations/elements/ReservationFieldItem.tsx index ce67e504a..a7ece922b 100644 --- a/react/src/dashboard/components/pages/reservations/elements/ReservationFieldItem.tsx +++ b/react/src/dashboard/components/pages/reservations/elements/ReservationFieldItem.tsx @@ -6,7 +6,6 @@ import ModalDangerZone from '../../../modals/ModalDangerZone'; import FormError from '../../../elements/forms/errors/FormError'; import FormGroupInfo from '../../../elements/forms/elements/FormGroupInfo'; import SelectControl from '../../../elements/select-control/SelectControl'; -import SelectControlOptions from '../../../elements/select-control/templates/SelectControlOptions'; import { useSortable } from '@dnd-kit/sortable'; import { CSS } from '@dnd-kit/utilities'; import useTranslate from '../../../../hooks/useTranslate'; @@ -201,7 +200,6 @@ export default function ReservationFieldItem({ onChange([...fields]); }} options={types} - optionsComponent={SelectControlOptions} /> diff --git a/react/src/dashboard/components/pages/sponsor-products/SponsorProducts.tsx b/react/src/dashboard/components/pages/sponsor-products/SponsorProducts.tsx index 625f5929a..4c30529e6 100644 --- a/react/src/dashboard/components/pages/sponsor-products/SponsorProducts.tsx +++ b/react/src/dashboard/components/pages/sponsor-products/SponsorProducts.tsx @@ -13,7 +13,6 @@ import SponsorProductsTable from './elements/SponsorProductsTable'; import SponsorProductsChangesTable from './elements/SponsorProductsChangesTable'; import SponsorProduct from '../../../props/models/Sponsor/SponsorProduct'; import SelectControl from '../../elements/select-control/SelectControl'; -import SelectControlOptions from '../../elements/select-control/templates/SelectControlOptions'; import useFilterNext from '../../../modules/filter_next/useFilterNext'; import { NumberParam, StringParam, createEnumParam, useQueryParam, withDefault } from 'use-query-params'; import DatePickerControl from '../../elements/forms/controls/DatePickerControl'; @@ -239,7 +238,6 @@ export default function SponsorProducts() { allowSearch={false} value={filterValues.fund_id || funds?.[0]?.id} options={funds} - optionsComponent={SelectControlOptions} onChange={(fund_id: number) => filterUpdate({ fund_id })} /> @@ -252,7 +250,6 @@ export default function SponsorProducts() { allowSearch={false} value={filterValues.has_reservations} options={hasReservationOptions} - optionsComponent={SelectControlOptions} onChange={(has_reservations: number) => filterUpdate({ has_reservations }) } diff --git a/react/src/dashboard/components/pages/sponsor-provider-organizations/SponsorProviderOrganizations.tsx b/react/src/dashboard/components/pages/sponsor-provider-organizations/SponsorProviderOrganizations.tsx index ec8e466ba..10baf1cc7 100644 --- a/react/src/dashboard/components/pages/sponsor-provider-organizations/SponsorProviderOrganizations.tsx +++ b/react/src/dashboard/components/pages/sponsor-provider-organizations/SponsorProviderOrganizations.tsx @@ -7,7 +7,6 @@ import useActiveOrganization from '../../../hooks/useActiveOrganization'; import usePaginatorService from '../../../modules/paginator/services/usePaginatorService'; import CardHeaderFilter from '../../elements/tables/elements/CardHeaderFilter'; import FilterItemToggle from '../../elements/tables/elements/FilterItemToggle'; -import SelectControlOptions from '../../elements/select-control/templates/SelectControlOptions'; import SelectControl from '../../elements/select-control/SelectControl'; import useImplementationService from '../../../services/ImplementationService'; import Implementation from '../../../props/models/Implementation'; @@ -278,7 +277,6 @@ export default function SponsorProviderOrganizations() { propKey={'value'} allowSearch={false} value={filterValues.order_by} - optionsComponent={SelectControlOptions} onChange={(order_by: string) => filterUpdate({ order_by })} /> @@ -513,7 +511,6 @@ export default function SponsorProviderOrganizations() { options={implementations} propKey={'id'} allowSearch={false} - optionsComponent={SelectControlOptions} value={filterValues.implementation_id} onChange={(implementation_id: number) => { filterUpdate({ implementation_id }); diff --git a/react/src/dashboard/components/pages/transaction-settings/TransactionSettings.tsx b/react/src/dashboard/components/pages/transaction-settings/TransactionSettings.tsx index 63d4bbe5b..fbc3144a1 100644 --- a/react/src/dashboard/components/pages/transaction-settings/TransactionSettings.tsx +++ b/react/src/dashboard/components/pages/transaction-settings/TransactionSettings.tsx @@ -5,7 +5,6 @@ import StateNavLink from '../../../modules/state_router/StateNavLink'; import CheckboxControl from '../../elements/forms/controls/CheckboxControl'; import useFormBuilder from '../../../hooks/useFormBuilder'; import { useOrganizationService } from '../../../services/OrganizationService'; -import SelectControlOptions from '../../elements/select-control/templates/SelectControlOptions'; import SelectControl from '../../elements/select-control/SelectControl'; import Tooltip from '../../elements/tooltip/Tooltip'; import usePushApiError from '../../../hooks/usePushApiError'; @@ -242,7 +241,6 @@ export default function TransactionSettings() { value={form.values?.bank_separator} onChange={(bank_separator: string) => form.update({ bank_separator })} options={separatorOptions} - optionsComponent={SelectControlOptions} /> diff --git a/react/src/dashboard/components/pages/transactions/Transactions.tsx b/react/src/dashboard/components/pages/transactions/Transactions.tsx index 96e7c6d2f..9250851d8 100644 --- a/react/src/dashboard/components/pages/transactions/Transactions.tsx +++ b/react/src/dashboard/components/pages/transactions/Transactions.tsx @@ -23,7 +23,6 @@ import useProviderFundService from '../../../services/ProviderFundService'; import Fund from '../../../props/models/Fund'; import FilterItemToggle from '../../elements/tables/elements/FilterItemToggle'; import SelectControl from '../../elements/select-control/SelectControl'; -import SelectControlOptions from '../../elements/select-control/templates/SelectControlOptions'; import DatePickerControl from '../../elements/forms/controls/DatePickerControl'; import CardHeaderFilter from '../../elements/tables/elements/CardHeaderFilter'; import StateNavLink from '../../../modules/state_router/StateNavLink'; @@ -501,7 +500,6 @@ export default function Transactions() { allowSearch={false} value={filter.values.state} options={states} - optionsComponent={SelectControlOptions} onChange={(state: string) => filter.update({ state })} /> @@ -513,7 +511,6 @@ export default function Transactions() { propKey={'id'} allowSearch={false} options={funds} - optionsComponent={SelectControlOptions} onChange={(fund_id: number) => filter.update({ fund_id })} /> )} @@ -601,7 +598,6 @@ export default function Transactions() { allowSearch={false} value={filter.values.bulk_state} options={bulkStates} - optionsComponent={SelectControlOptions} onChange={(bulk_state: string) => filter.update({ bulk_state })} /> @@ -615,7 +611,6 @@ export default function Transactions() { allowSearch={false} value={filter.values.fund_state} options={fundStates} - optionsComponent={SelectControlOptions} onChange={(fund_state: string) => filter.update({ fund_state })} /> @@ -708,7 +703,6 @@ export default function Transactions() { allowSearch={false} value={bulkFilter.values.state} options={bulkStates} - optionsComponent={SelectControlOptions} onChange={(state: string) => bulkFilter.update({ state })} /> diff --git a/react/src/dashboard/components/pages/vouchers-view/VouchersViewComponent.tsx b/react/src/dashboard/components/pages/vouchers-view/VouchersViewComponent.tsx index 4d6136464..093bc8ded 100644 --- a/react/src/dashboard/components/pages/vouchers-view/VouchersViewComponent.tsx +++ b/react/src/dashboard/components/pages/vouchers-view/VouchersViewComponent.tsx @@ -2,7 +2,7 @@ import React, { Fragment, useCallback, useEffect, useMemo, useRef, useState } fr import useActiveOrganization from '../../../hooks/useActiveOrganization'; import LoadingCard from '../../elements/loading-card/LoadingCard'; import StateNavLink from '../../../modules/state_router/StateNavLink'; -import Voucher from '../../../props/models/Voucher'; +import SponsorVoucher from '../../../props/models/Sponsor/SponsorVoucher'; import useOpenModal from '../../../hooks/useOpenModal'; import ModalVoucherTransaction from '../../modals/ModalVoucherTransaction/ModalVoucherTransaction'; import Fund from '../../../props/models/Fund'; @@ -50,7 +50,7 @@ export default function VouchersViewComponent() { const reservationTransactionsBlock = useRef<() => void>(); const [fund, setFund] = useState(null); - const [voucher, setVoucher] = useState(null); + const [voucher, setVoucher] = useState(null); const physicalCardsAvailable = useMemo(() => { return ( @@ -99,7 +99,7 @@ export default function VouchersViewComponent() { }, [activeOrganization.id, id, setProgress, voucherService, pushApiError]); const fetchFund = useCallback( - (voucher: Voucher) => { + (voucher: SponsorVoucher) => { setProgress(0); fundService @@ -138,9 +138,12 @@ export default function VouchersViewComponent() { }, [activeOrganization, fetchVoucher, fund, showQrCode, voucher]); const onStateChanged = useCallback( - (promise: Promise>, action: 'deactivation' | 'activation' = 'deactivation') => { + ( + promise: Promise>, + action: 'deactivation' | 'activation' = 'deactivation', + ) => { promise - .then((res: ApiResponseSingle) => { + .then((res: ApiResponseSingle) => { setVoucher(res.data.data); if (action == 'deactivation') { diff --git a/react/src/dashboard/components/pages/vouchers-view/elements/VoucherRecords.tsx b/react/src/dashboard/components/pages/vouchers-view/elements/VoucherRecords.tsx index dd6550db5..1c4650c94 100644 --- a/react/src/dashboard/components/pages/vouchers-view/elements/VoucherRecords.tsx +++ b/react/src/dashboard/components/pages/vouchers-view/elements/VoucherRecords.tsx @@ -1,5 +1,5 @@ import React, { useCallback, useEffect, useState } from 'react'; -import Voucher from '../../../../props/models/Voucher'; +import SponsorVoucher from '../../../../props/models/Sponsor/SponsorVoucher'; import Organization from '../../../../props/models/Organization'; import useOpenModal from '../../../../hooks/useOpenModal'; import Paginator from '../../../../modules/paginator/components/Paginator'; @@ -19,7 +19,13 @@ import useSetProgress from '../../../../hooks/useSetProgress'; import EmptyCard from '../../../elements/empty-card/EmptyCard'; import usePushApiError from '../../../../hooks/usePushApiError'; -export default function VoucherRecords({ voucher, organization }: { voucher: Voucher; organization: Organization }) { +export default function VoucherRecords({ + voucher, + organization, +}: { + voucher: SponsorVoucher; + organization: Organization; +}) { const translate = useTranslate(); const openModal = useOpenModal(); diff --git a/react/src/dashboard/components/pages/vouchers/Vouchers.tsx b/react/src/dashboard/components/pages/vouchers/Vouchers.tsx index 3e73bd138..2a57dffb7 100644 --- a/react/src/dashboard/components/pages/vouchers/Vouchers.tsx +++ b/react/src/dashboard/components/pages/vouchers/Vouchers.tsx @@ -1,7 +1,7 @@ import React, { Fragment, useCallback, useEffect, useState } from 'react'; import LoadingCard from '../../elements/loading-card/LoadingCard'; import { PaginationData } from '../../../props/ApiResponses'; -import Voucher from '../../../props/models/Voucher'; +import SponsorVoucher from '../../../props/models/Sponsor/SponsorVoucher'; import useActiveOrganization from '../../../hooks/useActiveOrganization'; import usePaginatorService from '../../../modules/paginator/services/usePaginatorService'; import useVoucherService from '../../../services/VoucherService'; @@ -34,7 +34,7 @@ export default function Vouchers() { const paginatorService = usePaginatorService(); const [loading, setLoading] = useState(true); - const [vouchers, setVouchers] = useState>(null); + const [vouchers, setVouchers] = useState>(null); const [paginatorKey] = useState('vouchers'); const { funds } = useVoucherTableOptions(activeOrganization); diff --git a/react/src/dashboard/components/pages/vouchers/elements/VouchersTable.tsx b/react/src/dashboard/components/pages/vouchers/elements/VouchersTable.tsx index cc7b552c1..16b5bdd58 100644 --- a/react/src/dashboard/components/pages/vouchers/elements/VouchersTable.tsx +++ b/react/src/dashboard/components/pages/vouchers/elements/VouchersTable.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import Voucher from '../../../../props/models/Voucher'; +import SponsorVoucher from '../../../../props/models/Sponsor/SponsorVoucher'; import Organization from '../../../../props/models/Organization'; import Fund from '../../../../props/models/Fund'; import TableTopScroller from '../../../elements/tables/TableTopScroller'; @@ -24,7 +24,7 @@ export default function VouchersTable({ funds: Array>; loading: boolean; paginatorKey: string; - vouchers: PaginationData; + vouchers: PaginationData; organization: Organization; fetchVouchers: () => void; filterValues: FilterModel; diff --git a/react/src/dashboard/components/pages/vouchers/elements/VouchersTableFilters.tsx b/react/src/dashboard/components/pages/vouchers/elements/VouchersTableFilters.tsx index 8d2056731..af1537bb7 100644 --- a/react/src/dashboard/components/pages/vouchers/elements/VouchersTableFilters.tsx +++ b/react/src/dashboard/components/pages/vouchers/elements/VouchersTableFilters.tsx @@ -12,7 +12,7 @@ import useVoucherService from '../../../../services/VoucherService'; import useVoucherTableOptions from '../hooks/useVoucherTableOptions'; import useVoucherExportService from '../../../../services/exports/useVoucherExportService'; import { PaginationData } from '../../../../props/ApiResponses'; -import Voucher from '../../../../props/models/Voucher'; +import SponsorVoucher from '../../../../props/models/Sponsor/SponsorVoucher'; import Fund from '../../../../props/models/Fund'; import { keyBy } from 'lodash'; @@ -48,7 +48,7 @@ export default function VouchersTableFilters({ funds, }: { organization: Organization; - vouchers: PaginationData; + vouchers: PaginationData; filter: FilterScope; funds: Array>; }) { diff --git a/react/src/dashboard/components/pages/vouchers/elements/VouchersTableRow.tsx b/react/src/dashboard/components/pages/vouchers/elements/VouchersTableRow.tsx index a713e827f..ae2b060c8 100644 --- a/react/src/dashboard/components/pages/vouchers/elements/VouchersTableRow.tsx +++ b/react/src/dashboard/components/pages/vouchers/elements/VouchersTableRow.tsx @@ -1,5 +1,5 @@ import React, { Fragment, useCallback } from 'react'; -import Voucher from '../../../../props/models/Voucher'; +import SponsorVoucher from '../../../../props/models/Sponsor/SponsorVoucher'; import StateNavLink from '../../../../modules/state_router/StateNavLink'; import Organization from '../../../../props/models/Organization'; import { currencyFormat, strLimit } from '../../../../helpers/string'; @@ -19,7 +19,7 @@ export default function VouchersTableRow({ fetchVouchers, }: { funds: Array>; - voucher: Voucher; + voucher: SponsorVoucher; organization: Organization; fetchVouchers: () => void; }) { diff --git a/react/src/dashboard/components/pages/vouchers/elements/VouchersTableRowStatus.tsx b/react/src/dashboard/components/pages/vouchers/elements/VouchersTableRowStatus.tsx index 78d7f5eca..b5a1b0fc3 100644 --- a/react/src/dashboard/components/pages/vouchers/elements/VouchersTableRowStatus.tsx +++ b/react/src/dashboard/components/pages/vouchers/elements/VouchersTableRowStatus.tsx @@ -1,8 +1,8 @@ import React from 'react'; -import Voucher from '../../../../props/models/Voucher'; +import SponsorVoucher from '../../../../props/models/Sponsor/SponsorVoucher'; import { strLimit } from '../../../../helpers/string'; -export default function VouchersTableRowStatus({ voucher }: { voucher: Voucher }) { +export default function VouchersTableRowStatus({ voucher }: { voucher: SponsorVoucher }) { return voucher.expired ? (
diff --git a/react/src/dashboard/components/pages/vouchers/hooks/useShowVoucherQrCode.tsx b/react/src/dashboard/components/pages/vouchers/hooks/useShowVoucherQrCode.tsx index 62ac17f16..d60583590 100644 --- a/react/src/dashboard/components/pages/vouchers/hooks/useShowVoucherQrCode.tsx +++ b/react/src/dashboard/components/pages/vouchers/hooks/useShowVoucherQrCode.tsx @@ -1,5 +1,5 @@ import React, { useCallback } from 'react'; -import Voucher from '../../../../props/models/Voucher'; +import SponsorVoucher from '../../../../props/models/Sponsor/SponsorVoucher'; import ModalVoucherQRCode from '../../../modals/ModalVoucherQRCode'; import Organization from '../../../../props/models/Organization'; import useOpenModal from '../../../../hooks/useOpenModal'; @@ -9,7 +9,7 @@ export default function useShowVoucherQrCode() { const openModal = useOpenModal(); return useCallback( - (organization: Organization, voucher: Voucher, fund: Partial, onChange?: () => void) => { + (organization: Organization, voucher: SponsorVoucher, fund: Partial, onChange?: () => void) => { openModal((modal) => ( { )}
- + diff --git a/react/src/dashboard/layout/elements/aside/LayoutAsideSponsor.tsx b/react/src/dashboard/layout/elements/aside/LayoutAsideSponsor.tsx index 08451b52c..0bf12f9aa 100644 --- a/react/src/dashboard/layout/elements/aside/LayoutAsideSponsor.tsx +++ b/react/src/dashboard/layout/elements/aside/LayoutAsideSponsor.tsx @@ -75,6 +75,15 @@ export default function LayoutAsideSponsor({ organization }: { organization: Org appConfigs?.organizations?.funds?.fund_requests && hasPermission(organization, ['validate_records', 'manage_validators'], false), }, + { + id: 'fund_forms', + name: 'E-formulieren', + state: 'fund-forms', + stateParams: { organizationId: organization?.id }, + show: + appConfigs?.organizations?.funds?.fund_requests && + hasPermission(organization, ['manage_funds'], false), + }, ]} /> diff --git a/react/src/dashboard/modules/frame_director/components/target-containers/FDTargetContainerSelect.tsx b/react/src/dashboard/modules/frame_director/components/target-containers/FDTargetContainerSelect.tsx new file mode 100644 index 000000000..38fac73e4 --- /dev/null +++ b/react/src/dashboard/modules/frame_director/components/target-containers/FDTargetContainerSelect.tsx @@ -0,0 +1,17 @@ +import React from 'react'; +import classNames from 'classnames'; +import useFDOffsetMenu from '../../hooks/useFDOffsetMenu'; +import { FDTargetContainerProps } from '../targets/FDTargetClick'; + +export default function FDTargetContainerSelect(props: FDTargetContainerProps) { + const { item, content } = props; + const { ref } = useFDOffsetMenu(item); + + return ( +
e.stopPropagation()} className={classNames('form')}> +
+ {typeof content === 'function' ? content(props) : content} +
+
+ ); +} diff --git a/react/src/dashboard/modules/frame_director/context/FrameDirectorContext.tsx b/react/src/dashboard/modules/frame_director/context/FrameDirectorContext.tsx index 724acddf0..ad2f9ffda 100644 --- a/react/src/dashboard/modules/frame_director/context/FrameDirectorContext.tsx +++ b/react/src/dashboard/modules/frame_director/context/FrameDirectorContext.tsx @@ -6,7 +6,7 @@ export type FDPosition = 'top' | 'right' | 'bottom' | 'left'; export interface FDItem { key: string; - offset?: FDItemOffset; + offset?: FDItemOffset & FDItemPosition; close?: () => void; element: (e: FDItem) => ReactElement; observedRect?: FDObserverRect; diff --git a/react/src/dashboard/modules/frame_director/hooks/useFDOffsetMenu.ts b/react/src/dashboard/modules/frame_director/hooks/useFDOffsetMenu.ts new file mode 100644 index 000000000..509095cc9 --- /dev/null +++ b/react/src/dashboard/modules/frame_director/hooks/useFDOffsetMenu.ts @@ -0,0 +1,113 @@ +import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import { FDItem, FDItemOffset, FDItemPosition, FDPosition } from '../context/FrameDirectorContext'; +import useFrameDirector from './useFrameDirector'; +import useSortRectByOverlapArea from './helpers/useSortRectByOverlapArea'; +import useIsWithin from './helpers/useIsWithin'; + +export default function useFDOffsetMenu(item: FDItem) { + const ref = useRef(); + const { updateElement } = useFrameDirector(); + + const [elRect, setElRect] = useState(null); + const observedHeight = item.observedRect?.height || 0; + + const isWithin = useIsWithin(); + const sortRectByOverlapArea = useSortRectByOverlapArea(); + + const getOffsets = useCallback( + (position: FDItemPosition) => { + const observerHeight = observedHeight; + + const calcYOffset = () => { + if (position.position === 'top') { + return -elRect?.height; + } + + if (position.position === 'bottom') { + return observerHeight; + } + + return 0; + }; + + return { + x: item?.observedRect?.x, + y: item?.observedRect?.y + calcYOffset(), + position: position.position, + align: position.align, + }; + }, + [observedHeight, elRect?.height, item?.observedRect?.x, item?.observedRect?.y], + ); + + const findOffset = useCallback((): (FDItemOffset & FDItemPosition) | null => { + const rects: Array = ['top', 'bottom'].reduce( + (list, position: FDPosition) => [ + ...list, + { ...getOffsets({ position, align: 'start' }), width: elRect?.width, height: elRect?.height }, + ], + [], + ); + + const sortedRects = sortRectByOverlapArea(document.body.getBoundingClientRect(), rects) as Array< + FDItemOffset & FDItemPosition + >; + + return sortedRects?.[0]; + }, [getOffsets, elRect?.height, elRect?.width, sortRectByOverlapArea]); + + const getAvailableOffset = useCallback((): (FDItemOffset & FDItemPosition) | null => { + const requestedOffset = getOffsets({ + align: item?.requestedPosition?.align, + position: item?.requestedPosition?.position, + }); + + if ( + isWithin(document.body.getBoundingClientRect(), { + ...requestedOffset, + width: elRect?.width, + height: elRect?.height, + }) + ) { + return requestedOffset; + } + + return findOffset(); + }, [ + getOffsets, + item?.requestedPosition?.align, + item?.requestedPosition?.position, + isWithin, + elRect?.width, + elRect?.height, + findOffset, + ]); + + const offset = useMemo(() => { + return getAvailableOffset(); + }, [getAvailableOffset]); + + useEffect(() => { + const observer = new ResizeObserver(() => setElRect(ref?.current?.getBoundingClientRect())); + observer.observe(ref?.current); + + return () => observer.disconnect(); + }, []); + + useEffect(() => { + const observer = new ResizeObserver(() => setElRect(ref?.current?.getBoundingClientRect())); + observer.observe(document.querySelector('body')); + + return () => observer.disconnect(); + }, []); + + useEffect(() => { + if (item?.key) { + updateElement(item.key, { offset }); + } + }, [item.key, offset, updateElement]); + + return useMemo(() => { + return { ref, itemWidth: elRect?.width, itemHeight: elRect?.height, activePosition: offset }; + }, [offset, elRect?.height, elRect?.width]); +} diff --git a/react/src/dashboard/modules/frame_director/hooks/useFrameDirector.ts b/react/src/dashboard/modules/frame_director/hooks/useFrameDirector.ts new file mode 100644 index 000000000..093e0d3b8 --- /dev/null +++ b/react/src/dashboard/modules/frame_director/hooks/useFrameDirector.ts @@ -0,0 +1,6 @@ +import { useContext } from 'react'; +import { frameDirectorContext } from '../context/FrameDirectorContext'; + +export default function useFrameDirector() { + return useContext(frameDirectorContext); +} diff --git a/react/src/dashboard/modules/modals/components/Modals.tsx b/react/src/dashboard/modules/modals/components/Modals.tsx index cfb256722..2b996eb3d 100644 --- a/react/src/dashboard/modules/modals/components/Modals.tsx +++ b/react/src/dashboard/modules/modals/components/Modals.tsx @@ -1,7 +1,7 @@ import React, { useCallback, useContext, useEffect, useMemo, useRef } from 'react'; import { modalsContext } from '../context/ModalContext'; -export default function Modals() { +export default function Modals({ focusExclusions = null }: { focusExclusions?: string }) { const { modals, closeModal } = useContext(modalsContext); const visibleModals = useMemo(() => modals.filter((modal) => !modal.hidden), [modals]); @@ -27,7 +27,16 @@ export default function Modals() { focusModalElement(); const onActiveFocusIn = () => { - if (modalRef.current && !modalRef.current?.contains(document.activeElement)) { + if (!modalRef.current) { + return; + } + + const exclusions = [...(focusExclusions ? document.querySelectorAll(focusExclusions) : [])]; + + const insideModal = modalRef.current?.contains(document.activeElement); + const insideExclusion = exclusions.filter((el) => el.contains(document.activeElement)).length > 0; + + if (!insideModal && !insideExclusion) { focusModalElement(); } }; @@ -35,7 +44,7 @@ export default function Modals() { document.addEventListener('focusin', onActiveFocusIn); return () => document.removeEventListener('focusin', onActiveFocusIn); - }, [visibleModals.length, focusModalElement]); + }, [visibleModals.length, focusModalElement, focusExclusions]); return (
diff --git a/react/src/dashboard/modules/modals/context/ModalContext.tsx b/react/src/dashboard/modules/modals/context/ModalContext.tsx index 61a4b4220..c7238aabc 100644 --- a/react/src/dashboard/modules/modals/context/ModalContext.tsx +++ b/react/src/dashboard/modules/modals/context/ModalContext.tsx @@ -16,12 +16,15 @@ export interface ModalState extends Modal { hidden?: boolean; loading?: boolean; loadingTimer?: number; + processing?: boolean; close?: () => void; setLoading?: (loaded: boolean) => void; setHidden?: (hidden: boolean) => void; + setProcessing?: (loaded: boolean) => void; } -export type ModalOpener = (builder: (modal: ModalState) => React.ReactElement, config?: ModalConfig) => ModalState; +export type ModalBuilder = (modal: ModalState) => React.ReactElement; +export type ModalOpener = (builder: ModalBuilder, config?: ModalConfig) => ModalState; interface ModalsMemo { modals: Array; @@ -41,6 +44,12 @@ const ModalsProvider = ({ children }: { children: React.ReactElement }) => { }); }, []); + const setProcessing = useCallback((id: string, processing: boolean) => { + setModals((modals) => { + return [...modals.map((item) => Object.assign(item, item.id == id ? { processing } : {}))]; + }); + }, []); + const setHidden = useCallback((id: string, hidden: boolean) => { setModals((modals) => { return [...modals.map((item) => Object.assign(item, item.id == id ? { hidden } : {}))]; @@ -49,6 +58,10 @@ const ModalsProvider = ({ children }: { children: React.ReactElement }) => { const closeModal = useCallback( (modal: ModalState) => { + if (modal.processing) { + return; + } + setLoading(modal.id, true); setTimeout(() => { @@ -60,7 +73,7 @@ const ModalsProvider = ({ children }: { children: React.ReactElement }) => { ); const openModal = useCallback( - (builder, config: ModalConfig = {}) => { + (builder: ModalBuilder, config: ModalConfig = {}) => { const id = uniqueId(); const loadingTimer = config.disableAutoLoader ? null : window.setTimeout(() => setLoading(id, false), 200); const modalState: ModalState = { ...config, id, loadingTimer }; @@ -70,12 +83,13 @@ const ModalsProvider = ({ children }: { children: React.ReactElement }) => { modalState.close = () => closeModal(modalState); modalState.setHidden = (loaded: boolean) => setHidden(modalState.id, loaded); modalState.setLoading = (loading: boolean) => setLoading(modalState.id, loading); + modalState.setProcessing = (loading: boolean) => setProcessing(modalState.id, loading); setModals((modals) => [...modals, modalState]); return modalState; }, - [closeModal, setLoading, setHidden], + [closeModal, setLoading, setHidden, setProcessing], ); return ( diff --git a/react/src/dashboard/modules/paginator/components/Paginator.tsx b/react/src/dashboard/modules/paginator/components/Paginator.tsx index ba5e68547..a709750b7 100644 --- a/react/src/dashboard/modules/paginator/components/Paginator.tsx +++ b/react/src/dashboard/modules/paginator/components/Paginator.tsx @@ -4,7 +4,6 @@ import FilterSetter from '../../../types/FilterSetter'; import { ApiPaginationMetaProp } from '../../../props/ApiResponses'; import usePaginatorService from '../services/usePaginatorService'; import SelectControl from '../../../components/elements/select-control/SelectControl'; -import SelectControlOptions from '../../../components/elements/select-control/templates/SelectControlOptions'; import { clickOnKeyEnter } from '../../../helpers/wcag'; import useTranslate from '../../../hooks/useTranslate'; import classNames from 'classnames'; @@ -108,7 +107,6 @@ export default function Paginator({ ; + banner_color?: string; + banner_background?: string; + banner_background_mobile?: boolean; + banner_position?: 'left' | 'center' | 'right'; + banner_wide?: boolean; + banner_collapse?: boolean; + banner_button?: boolean; + banner_button_url?: string; + banner_button_text?: string; + banner_button_target?: 'self' | '_blank'; + banner_button_type?: 'color' | 'white'; } diff --git a/react/src/dashboard/props/models/OrganizationBasic.tsx b/react/src/dashboard/props/models/OrganizationBasic.tsx new file mode 100644 index 000000000..14bf56c8b --- /dev/null +++ b/react/src/dashboard/props/models/OrganizationBasic.tsx @@ -0,0 +1,16 @@ +import Media from './Media'; +import BusinessType from './BusinessType'; + +export default interface OrganizationBasic { + id: number; + name: string; + business_type_id: number; + email_public: boolean; + phone_public: boolean; + website_public: boolean; + email?: string; + phone?: string; + website?: string; + logo?: Media; + business_type: BusinessType; +} diff --git a/react/src/dashboard/props/models/Sponsor/SponsorVoucher.tsx b/react/src/dashboard/props/models/Sponsor/SponsorVoucher.tsx new file mode 100644 index 000000000..2310acdf2 --- /dev/null +++ b/react/src/dashboard/props/models/Sponsor/SponsorVoucher.tsx @@ -0,0 +1,79 @@ +import Fund from '../Fund'; +import Product from '../Product'; +import Reservation from '../Reservation'; +import Office from '../Office'; +import PhysicalCard from '../PhysicalCard'; +import Transaction from '../Transaction'; +import Media from "../Media"; + +export default interface SponsorVoucher { + id: number; + number?: string; + address?: string; + fund_id: number; + expired?: boolean; + fund: Fund; + type?: 'regular' | 'product'; + state?: string; + state_locale?: string; + timestamp?: number; + transactions: Array; + product_vouchers?: Array; + records?: Array<{ + voucher_id: number; + value_locale: string; + record_type_key: string; + record_type_name: string; + }>; + product: Product; + product_reservation: Reservation; + offices?: Array; + allowed_organizations: Array<{ + id: number; + name: string; + logo: Media; + }>; + identity_email?: string; + activation_code?: string; + identity_bsn?: string; + relation_bsn?: string; + client_uid?: string; + physical_card?: PhysicalCard; + source_locale?: string; + amount?: string; + amount_locale?: string; + amount_total?: string; + amount_total_locale?: string; + amount_top_up?: string; + amount_top_up_locale?: string; + amount_available?: string; + amount_available_locale?: string; + amount_spent?: string; + amount_spent_locale?: string; + note?: string; + expire_at_locale?: string; + in_use?: boolean; + first_use_date_locale?: string; + has_payouts?: boolean; + is_granted?: boolean; + is_external: boolean; + limit_multiplier?: number; + identity_address?: string; + history: Array<{ + id: number; + event: string; + event_locale: string; + created_at: string; + created_at_locale: string; + }>; + deactivated?: boolean; + used: boolean; + last_transaction_at?: string; + last_transaction_at_locale?: string; + records_title?: string; + returnable?: boolean; + last_active_day_locale?: string; + created_at?: string; + created_at_locale?: string; + expire_at?: string; +} diff --git a/react/src/dashboard/props/models/Voucher.tsx b/react/src/dashboard/props/models/Voucher.tsx index 4add3b39b..f54995fb3 100644 --- a/react/src/dashboard/props/models/Voucher.tsx +++ b/react/src/dashboard/props/models/Voucher.tsx @@ -1,10 +1,64 @@ import Fund from './Fund'; -import Media from './Media'; -import Product from './Product'; -import Transaction from './Transaction'; import Office from './Office'; import Reservation from './Reservation'; import PhysicalCard from './PhysicalCard'; +import Media from './Media'; +import OrganizationBasic from './OrganizationBasic'; +import Product from './Product'; + +export interface VoucherProduct { + id?: number; + name?: string; + description?: string; + description_html?: string; + product_category_id?: number; + sold_out?: boolean; + reservation_enabled?: boolean; + reservation_policy?: 'accept' | 'review' | 'global'; + alternative_text?: string; + price?: string; + price_locale?: string; + organization_id?: number; + photo?: Media; + organization?: OrganizationBasic; +} + +export interface VoucherTransaction { + id: number; + organization_id: number; + product_id?: number; + address: string; + state: 'success' | 'pending' | 'canceled'; + state_locale: string; + payment_id?: string; + target?: 'provider' | 'iban' | 'top_up' | 'payout'; + amount: string; + amount_locale: string; + amount_extra_cash?: string; + amount_extra_cash_locale?: string; + timestamp: number; + cancelable: boolean; + transfer_in?: number; + organization: { + id: number; + name: string; + logo: Media; + }; + product?: Product; + fund: { + id: number; + name: string; + organization_id: number; + logo?: Media; + organization_name: string; + }; + created_at: string; + created_at_locale: string; + transfer_at?: string; + transfer_at_locale?: string; + updated_at: string; + product_reservation?: Reservation; +} export default interface Voucher { id: number; @@ -17,7 +71,7 @@ export default interface Voucher { state?: string; state_locale?: string; timestamp?: number; - transactions: Array; + transactions: Array; product_vouchers?: Array; records?: Array<{ voucher_id: number; @@ -25,7 +79,7 @@ export default interface Voucher { record_type_key: string; record_type_name: string; }>; - product: Product; + product: VoucherProduct; product_reservation: Reservation; offices?: Array; query_product?: { @@ -35,37 +89,10 @@ export default interface Voucher { reservable_expire_at?: string; reservable_expire_at_locale?: string; }; - allowed_organizations: Array<{ - id: number; - name: string; - logo: Media; - }>; - identity_email?: string; - activation_code?: string; - identity_bsn?: string; - relation_bsn?: string; - client_uid?: string; physical_card?: PhysicalCard; - source_locale?: string; amount?: string; amount_locale?: string; - amount_total?: string; - amount_total_locale?: string; - amount_top_up?: string; - amount_top_up_locale?: string; - amount_available?: string; - amount_available_locale?: string; - amount_spent?: string; - amount_spent_locale?: string; - note?: string; - expire_at_locale?: string; - in_use?: boolean; - first_use_date_locale?: string; - has_payouts?: boolean; - is_granted?: boolean; is_external: boolean; - limit_multiplier?: number; - identity_address?: string; history: Array<{ id: number; event: string; @@ -83,4 +110,5 @@ export default interface Voucher { created_at?: string; created_at_locale?: string; expire_at?: string; + expire_at_locale?: string; } diff --git a/react/src/dashboard/router/routes.tsx b/react/src/dashboard/router/routes.tsx index 9ba3588ef..e68df8e65 100644 --- a/react/src/dashboard/router/routes.tsx +++ b/react/src/dashboard/router/routes.tsx @@ -95,6 +95,8 @@ import SponsorProductView from '../components/pages/sponsor-product/SponsorProdu import Identities from '../components/pages/identities/Identities'; import OrganizationsTranslations from '../components/pages/organizations-translations/OrganizationsTranslations'; import ImplementationsTranslations from '../components/pages/implementations-cookies/ImplementationsTranslations'; +import FundForms from '../components/pages/fund-forms/FundForms'; +import FundFormsView from '../components/pages/fund-forms-view/FundFormsView'; const router = new RouterBuilder(); @@ -568,6 +570,16 @@ router.state('fund-request', , { fallbackState: 'fund-requests', }); +router.state('fund-forms', , { + path: `/organisaties/:organizationId/formulieren`, + altPath: `/organizations/:organizationId/forms`, +}); + +router.state('fund-form', , { + path: `/organisaties/:organizationId/formulieren/:id`, + altPath: `/organizations/:organizationId/forms/:id`, +}); + router.state('employees', , { path: `/organisaties/:organizationId/medewerkers`, altPath: `/organizations/:organizationId/employees`, diff --git a/react/src/dashboard/services/ConfigService.ts b/react/src/dashboard/services/ConfigService.ts index 4d00ff61c..e47392e5c 100644 --- a/react/src/dashboard/services/ConfigService.ts +++ b/react/src/dashboard/services/ConfigService.ts @@ -138,7 +138,18 @@ export type AppConfigProp = { overlay_enabled: boolean; overlay_type: string; overlay_opacity: number; - banner_text_color: string; + banner_wide?: boolean; + banner_color?: string; + banner_background?: string; + banner_background_mobile?: boolean; + banner_collapse?: boolean; + banner_position?: 'left' | 'center' | 'right'; + background_image?: string; + banner_button?: boolean; + banner_button_url?: string; + banner_button_text?: string; + banner_button_type?: 'color' | 'white'; + banner_button_target?: 'self' | '_blank'; }; fronts: { url_webshop: string; diff --git a/react/src/dashboard/services/FundFormService.ts b/react/src/dashboard/services/FundFormService.ts new file mode 100644 index 000000000..1e9ffe935 --- /dev/null +++ b/react/src/dashboard/services/FundFormService.ts @@ -0,0 +1,51 @@ +import ApiResponse, { ApiResponseSingle } from '../props/ApiResponses'; +import { useState } from 'react'; +import ApiRequestService from './ApiRequestService'; +import FundForm from '../props/models/FundForm'; +import { ConfigurableTableColumn } from '../components/pages/vouchers/hooks/useConfigurableTable'; + +export class FundFormService { + /** + * @param apiRequest + */ + public constructor(protected apiRequest: ApiRequestService = new ApiRequestService()) {} + + /** + * Url prefix + * + * @param data + */ + public prefix = '/platform/organizations'; + + /** + * Fetch list + */ + public list( + organization_id: number, + query: object = {}, + ): Promise> { + return this.apiRequest.get(`${this.prefix}/${organization_id}/fund-forms`, query); + } + + public read(organization_id: number, id: number): Promise> { + return this.apiRequest.get(`${this.prefix}/${organization_id}/fund-forms/${id}`); + } + + public getColumns(): Array { + const list = ['name', 'created_at', 'fund', 'steps', 'status'].filter((item) => item); + + return list.map((key) => ({ + key, + label: `components.organization_funds_forms.columns.${key}`, + tooltip: { + key: key, + title: `components.organization_funds_forms.columns.${key}`, + description: `components.organization_funds_forms.tooltips.${key}`, + }, + })); + } +} + +export function useFundFormService(): FundFormService { + return useState(new FundFormService())[0]; +} diff --git a/react/src/dashboard/services/VoucherService.ts b/react/src/dashboard/services/VoucherService.ts index 30b43118c..b1c5efb8c 100644 --- a/react/src/dashboard/services/VoucherService.ts +++ b/react/src/dashboard/services/VoucherService.ts @@ -1,14 +1,14 @@ import ApiResponse, { ApiResponseSingle } from '../props/ApiResponses'; import { useState } from 'react'; import ApiRequestService from './ApiRequestService'; -import Voucher from '../props/models/Voucher'; import Papa from 'papaparse'; import Product from '../props/models/Product'; import { ExportFieldProp } from '../components/modals/ModalExportDataSelect'; import Transaction from '../props/models/Transaction'; import { ConfigurableTableColumn } from '../components/pages/vouchers/hooks/useConfigurableTable'; +import SponsorVoucher from '../props/models/Sponsor/SponsorVoucher'; -export class VoucherService { +export class VoucherService { /** * @param apiRequest */ diff --git a/react/src/webshop/Webshop.tsx b/react/src/webshop/Webshop.tsx index c4cc6c136..0f1be0aa5 100644 --- a/react/src/webshop/Webshop.tsx +++ b/react/src/webshop/Webshop.tsx @@ -1,6 +1,6 @@ import { ModalsProvider } from '../dashboard/modules/modals/context/ModalContext'; import { AuthProvider } from './contexts/AuthContext'; -import React, { Fragment, ReactNode, useContext, useEffect, useState } from 'react'; +import React, { ReactNode, useContext, useEffect, useState } from 'react'; import { Layout } from './layout/Layout'; import { HashRouter, Route, Routes, BrowserRouter } from 'react-router-dom'; import EnvDataProp from '../props/EnvData'; @@ -33,6 +33,7 @@ import i18nUK from './i18n/translated/uk.json'; import CookieBanner from './modules/cookie_banner/CookieBanner'; import ReadSpeakerScript from './modules/read_speaker/ReadSpeakerScript'; import { isValidLocaleString } from '../dashboard/helpers/url'; +import { FrameDirectorProvider } from '../dashboard/modules/frame_director/context/FrameDirectorContext'; const locale = localStorage.getItem('locale'); @@ -116,7 +117,7 @@ export default function Webshop({ envData }: { envData: EnvDataWebshopProp }): R const [allowOptionalCookies, setAllowOptionalCookies] = useState(null); return ( - + - + ); } diff --git a/react/src/webshop/components/elements/block-banner/BlockBanner.tsx b/react/src/webshop/components/elements/block-banner/BlockBanner.tsx new file mode 100644 index 000000000..71d8b8827 --- /dev/null +++ b/react/src/webshop/components/elements/block-banner/BlockBanner.tsx @@ -0,0 +1,266 @@ +import React, { Fragment, useCallback, useEffect, useState } from 'react'; +import useAppConfigs from '../../../hooks/useAppConfigs'; +import Markdown from '../markdown/Markdown'; +import useTranslate from '../../../../dashboard/hooks/useTranslate'; +import useEnvData from '../../../hooks/useEnvData'; +import useAuthIdentity from '../../../hooks/useAuthIdentity'; +import useSetProgress from '../../../../dashboard/hooks/useSetProgress'; +import { useVoucherService } from '../../../services/VoucherService'; +import Voucher from '../../../../dashboard/props/models/Voucher'; +import classNames from 'classnames'; +import { hexToHsva } from '@uiw/color-convert'; +import ReadSpeakerButton from '../../../modules/read_speaker/ReadSpeakerButton'; +import Fund from '../../../props/models/Fund'; + +export default function BlockBanner({ + funds, + config, +}: { + funds?: Fund[]; + config?: { + wide: boolean; + collapse: boolean; + position: 'left' | 'center' | 'right'; + banner_color?: string; + banner_background?: string; + background_image?: string; + }; +}) { + const envData = useEnvData(); + const translate = useTranslate(); + const appConfigs = useAppConfigs(); + const setProgress = useSetProgress(); + const authIdentity = useAuthIdentity(); + + const voucherService = useVoucherService(); + + const [vouchers, setVouchers] = useState>(null); + const [dataConfig, setDataConfig] = useState<{ + wide: boolean; + collapse: boolean; + position: 'left' | 'center' | 'right'; + banner_color?: string; + banner_background?: string; + banner_background_mobile?: boolean; + background_image?: string; + }>(null); + + const fetchVouchers = useCallback(() => { + setProgress(0); + + voucherService + .list() + .then((res) => setVouchers(res.data.data)) + .catch((e) => console.error(e)) + .finally(() => setProgress(100)); + }, [voucherService, setProgress]); + + useEffect(() => { + if (authIdentity) { + fetchVouchers(); + } else { + setVouchers(null); + } + }, [fetchVouchers, authIdentity]); + + useEffect(() => { + if (config) { + setDataConfig(config); + } else { + setDataConfig({ + wide: appConfigs.settings?.banner_wide, + collapse: appConfigs.settings?.banner_collapse, + position: appConfigs.settings?.banner_position, + banner_color: appConfigs.settings?.banner_color, + banner_background: appConfigs.settings?.banner_background, + banner_background_mobile: appConfigs.settings?.banner_background_mobile, + background_image: appConfigs.settings?.background_image, + }); + } + }, [config, appConfigs?.settings]); + + if (!dataConfig) { + return; + } + + return ( +
+
+ {appConfigs.settings.overlay_enabled && ( +
+ )} +
+
+
+
+ +

+ {appConfigs.settings.title + ? appConfigs.settings.title + : translate( + `home.header.${envData.client_key}.title`, + { implementation: appConfigs.implementation?.name }, + 'home.header.title', + )} +

+
+ {appConfigs.settings.description ? ( + + ) : ( + + {!appConfigs.settings.description && !appConfigs.digid && ( + + {funds.length <= 1 && ( +

+ {translate( + `home.header.${envData.client_key}.subtitle`, + { + fund: funds?.[0]?.name, + start_date: funds?.[0]?.start_date_locale, + }, + 'home.header.subtitle', + )} +

+ )} + {funds.length > 1 && ( +

+ {translate( + `home.header.${envData.client_key}.subtitle_multi`, + { org_name: funds?.[0].organization.name }, + 'home.header.subtitle_multi', + )} +

+ )} + {!authIdentity && funds.length <= 1 && ( +

+ {translate( + `home.header.${envData.client_key}.cta`, + { + fund: funds?.[0]?.name, + start_date: funds?.[0]?.start_date_locale, + }, + 'home.header.cta', + )} +

+ )} + + {!authIdentity && funds.length > 1 && ( +

+ {translate( + `home.header.${envData.client_key}.cta`, + { + fund: funds?.[0].name, + start_date: funds?.[0].start_date_locale, + }, + 'home.header.cta_multi', + )} +

+ )} + + {authIdentity && vouchers?.length > 0 && ( +

+ {translate(`home.header.auth_cta`, { + fund: funds?.[0].name, + start_date: funds?.[0].start_date_locale, + })} +

+ )} +
+ )} + + {!appConfigs.settings.description && appConfigs.digid && ( + +

+ {translate( + `home.header.${envData.client_key}.subtitle_av`, + { + fund: funds?.[0]?.name, + start_date: funds?.[0]?.start_date_locale, + }, + 'home.header.subtitle_av', + )} +

+ + {!authIdentity && ( +

+ {translate( + `home.header.${envData.client_key}.cta_av`, + { + fund: funds?.[0]?.name, + start_date: funds?.[0]?.start_date_locale, + }, + 'home.header.cta_av', + )} +

+ )} + + {authIdentity && vouchers?.length > 0 && ( +

+ {translate(`home.header.auth_cta`, { + fund: funds?.[0]?.name, + start_date: funds?.[0]?.start_date_locale, + })} +

+ )} +
+ )} +
+ )} +
+ {appConfigs.settings.banner_button && ( + + )} +
+
+
+
+ ); +} diff --git a/react/src/webshop/components/modals/Modal2FASetup.tsx b/react/src/webshop/components/modals/Modal2FASetup.tsx index 133e770a0..c3642bb53 100644 --- a/react/src/webshop/components/modals/Modal2FASetup.tsx +++ b/react/src/webshop/components/modals/Modal2FASetup.tsx @@ -19,6 +19,7 @@ import Icon2faPhoneConnect from '../../../../assets/forus-webshop/resources/_web import { clickOnKeyEnter } from '../../../dashboard/helpers/wcag'; import classNames from 'classnames'; import useTranslate from '../../../dashboard/hooks/useTranslate'; +import TranslateHtml from '../../../dashboard/components/elements/translate-html/TranslateHtml'; export default function Modal2FASetup({ modal, @@ -250,6 +251,14 @@ export default function Modal2FASetup({ document.body.removeEventListener('keydown', onKeyDown); }, [onKeyDown]); + useEffect(() => { + bindEvents(); + + return () => { + unbindEvents(); + }; + }, [bindEvents, unbindEvents]); + useEffect(() => { const providers = auth2FAState.providers .filter((provider) => provider.type == type) @@ -260,13 +269,7 @@ export default function Modal2FASetup({ setAuth2FA((auth2FA) => (auth2FA ? auth2FA : active_providers.find((auth_2fa) => auth_2fa))); setProvider(providers.find((provider) => provider)); setProviders(providers); - - bindEvents(); - - return () => { - unbindEvents(); - }; - }, [type, bindEvents, unbindEvents, auth2FAState, translate]); + }, [type, auth2FAState, translate]); // should set up useEffect(() => { @@ -341,18 +344,10 @@ export default function Modal2FASetup({
- - {translate('modal_2fa_setup.dont_have_app', { name: provider.name })} - - {translate('modal_2fa_setup.download_from')} - - {translate('modal_2fa_setup.download_from_play_store')} - - {translate('modal_2fa_setup.or')} - - {translate('modal_2fa_setup.download_from_app_store')} - - . +
@@ -388,25 +383,15 @@ export default function Modal2FASetup({
- {translate('modal_2fa_setup.already_have_app')} + {translate('modal_2fa_setup.already_have_app', { name: provider.name })}
- {`1. ${translate('modal_2fa_setup.in_app_select')} - `} - - {translate('modal_2fa_setup.setup_account')} - -
- {`2. ${translate('modal_2fa_setup.choose')} - `} - {translate('modal_2fa_setup.scan_qr')} - {` ${translate('modal_2fa_setup.or')} - `} - - {translate('modal_2fa_setup.enter_key', { secret: auth2FA?.secret })} - +
@@ -528,11 +513,15 @@ export default function Modal2FASetup({
{type == 'phone' && ( -
{translate('modal_2fa_setup.enter_sms_code')}
+
+ {translate('modal_2fa_setup.enter_sms_code')} +
)} {type == 'authenticator' && ( -
{translate('modal_2fa_setup.enter_app_code')}
+
+ {translate('modal_2fa_setup.enter_app_code')} +
)} >(null); - const [vouchers, setVouchers] = useState>(null); const [products, setProducts] = useState>(null); const [subsidies, setSubsidies] = useState>(null); @@ -64,16 +56,6 @@ export default function Home() { .finally(() => setProgress(100)); }, [fundService, setProgress]); - const fetchVouchers = useCallback(() => { - setProgress(0); - - voucherService - .list() - .then((res) => setVouchers(res.data.data)) - .catch((e) => console.error(e)) - .finally(() => setProgress(100)); - }, [voucherService, setProgress]); - const fetchProducts = useCallback(() => { setProgress(0); @@ -101,14 +83,6 @@ export default function Home() { } }, [digidResponse, navigateState]); - useEffect(() => { - if (authIdentity) { - fetchVouchers(); - } else { - setVouchers(null); - } - }, [fetchVouchers, authIdentity]); - useEffect(() => { if (!stateParams?.session_expired) { return; @@ -145,142 +119,7 @@ export default function Home() { return (
-
- {appConfigs.settings.overlay_enabled && ( -
- )} -
- {translate(`home.header.${envData.client_key}.header_note`, null, 'home.header.header_note')} -
-
-
- - {appConfigs.settings.title ? ( -

- {appConfigs.settings.title} -

- ) : ( -

- {translate( - `home.header.${envData.client_key}.title`, - { implementation: appConfigs.implementation?.name }, - 'home.header.title', - )} -

- )} - - {appConfigs.settings.description && ( -
- -
- )} - - {!appConfigs.settings.description && !appConfigs.digid && ( -
- {funds.length <= 1 && ( -

- {translate( - `home.header.${envData.client_key}.subtitle`, - { fund: funds?.[0]?.name, start_date: funds?.[0]?.start_date_locale }, - 'home.header.subtitle', - )} -

- )} - {funds.length > 1 && ( -

- {translate( - `home.header.${envData.client_key}.subtitle_multi`, - { org_name: funds?.[0].organization.name }, - 'home.header.subtitle_multi', - )} -

- )} - {!authIdentity && funds.length <= 1 && ( -

- {translate( - `home.header.${envData.client_key}.cta`, - { fund: funds?.[0]?.name, start_date: funds?.[0]?.start_date_locale }, - 'home.header.cta', - )} -

- )} - - {!authIdentity && funds.length > 1 && ( -

- {translate( - `home.header.${envData.client_key}.cta`, - { fund: funds?.[0].name, start_date: funds?.[0].start_date_locale }, - 'home.header.cta_multi', - )} -

- )} - - {authIdentity && vouchers?.length > 0 && ( -

- {translate(`home.header.auth_cta`, { - fund: funds?.[0].name, - start_date: funds?.[0].start_date_locale, - })} -

- )} -
- )} - - {!appConfigs.settings.description && appConfigs.digid && ( -
-

- {translate( - `home.header.${envData.client_key}.subtitle_av`, - { fund: funds?.[0]?.name, start_date: funds?.[0]?.start_date_locale }, - 'home.header.subtitle_av', - )} -

- - {!authIdentity && ( -

- {translate( - `home.header.${envData.client_key}.cta_av`, - { fund: funds?.[0]?.name, start_date: funds?.[0]?.start_date_locale }, - 'home.header.cta_av', - )} -

- )} - - {authIdentity && vouchers?.length > 0 && ( -

- {translate(`home.header.auth_cta`, { - fund: funds?.[0]?.name, - start_date: funds?.[0]?.start_date_locale, - })} -

- )} -
- )} - - {appConfigs.pages.explanation && ( - - {translate('home.how_it_works')} - - )} -
-
-
+ {envData.client_key === 'vergoedingen' && (
diff --git a/react/src/webshop/components/printable/VoucherQrCodePrintable.tsx b/react/src/webshop/components/printable/VoucherQrCodePrintable.tsx index 7eb40a672..4724d043f 100644 --- a/react/src/webshop/components/printable/VoucherQrCodePrintable.tsx +++ b/react/src/webshop/components/printable/VoucherQrCodePrintable.tsx @@ -1,10 +1,10 @@ import React, { useEffect } from 'react'; import Voucher from '../../../dashboard/props/models/Voucher'; -import Organization from '../../../dashboard/props/models/Organization'; import { PrintableState } from '../../../dashboard/modules/printable/context/PrintableContext'; import useTranslate from '../../../dashboard/hooks/useTranslate'; import QrCode from '../../../dashboard/components/elements/qr-code/QrCode'; import Fund from '../../../dashboard/props/models/Fund'; +import OrganizationBasic from '../../../dashboard/props/models/OrganizationBasic'; export default function VoucherQrCodePrintable({ fund, @@ -20,7 +20,7 @@ export default function VoucherQrCodePrintable({ assetUrl: (uri: string) => string; printable: PrintableState; webshopUrl?: string; - organization: Organization; + organization: OrganizationBasic; showConditions?: boolean; }) { const translate = useTranslate(); diff --git a/react/src/webshop/i18n/nl/modals/modal_2fa_setup.mjs b/react/src/webshop/i18n/nl/modals/modal_2fa_setup.mjs index aaa6fd45a..2aec67007 100644 --- a/react/src/webshop/i18n/nl/modals/modal_2fa_setup.mjs +++ b/react/src/webshop/i18n/nl/modals/modal_2fa_setup.mjs @@ -3,17 +3,11 @@ export default { unknown_error: 'Onbekende fout.', code_resent: 'We hebben de code opnieuw verstuurd.', select_auth_app: 'Selecteer de authenticatie-app die u wilt gebruiken.', - dont_have_app: 'Als je de {name} app niet hebt,', - download_from: 'Kun je deze downloaden vanuit de', - download_from_play_store: 'Play Store', - download_from_app_store: 'App Store', - or: 'of de', - already_have_app: 'Als je al de Google Authenticator-app hebt, volg dan de onderstaande stappen:', - in_app_select: 'In de app, selecteer', - setup_account: 'Account instellen', - choose: 'Kies', - scan_qr: 'Scan een QR-code', - enter_key: 'Voer een installatiesleutel in: {secret}', + dont_have_app: + ' Als je de {{name}} app niet hebt, Kun je deze downloaden vanuit de Play Store of de App Store.', + already_have_app: 'Als je al de {{name}}-app hebt, volg dan de onderstaande stappen:', + already_have_app_steps: + '1. In de app, selecteer Account instellen
2. Kies Scan een QR-code of de Voer een installatiesleutel in: {{secret}}', cancel: 'Annuleer', confirm: 'Bevestigen', link_phone: 'Koppel je telefoonnummer', diff --git a/react/src/webshop/i18n/translated/ar.json b/react/src/webshop/i18n/translated/ar.json index 388d98bb3..fdefe8ed3 100644 --- a/react/src/webshop/i18n/translated/ar.json +++ b/react/src/webshop/i18n/translated/ar.json @@ -2777,18 +2777,13 @@ "modal_2fa_setup": { "2fa": "المصادقة الثنائية", "2fa_success": "تم إعداد المصادقة الثنائية بنجاح", - "already_have_app": "إذا كان لديك تطبيق Google Authenticator بالفعل، فاتبع الخطوات التالية:", "back": "رجوع", "cancel": "إلغاء", - "choose": "اختر", "code_resent": "لقد قمنا بإعادة إرسال الرمز.", "confirm": "تأكيد", - "dont_have_app": "إذا لم يكن لديك تطبيق {الاسم},", - "download_from": "هل يمكنك تنزيله من", "enter_2fa_code": "للمتابعة، أدخل رمز الأمان الخاص بالمصادقة الثنائية.", "enter_app_code": "أدخل الرمز المكون من 6 أرقام من داخل التطبيق", "enter_app_code_6_digits": "للمتابعة، أدخل رمز الأمان المكون من 6 أرقام من {مقدم الخدمة}", - "enter_key": "أدخل مفتاح التثبيت: {السر}", "enter_phone": "للمتابعة، أدخل رقم هاتفك", "enter_sms_code": "أدخل رمز الرسالة النصية القصيرة المكون من 6 أرقام", "enter_sms_code_6_digits": "للمتابعة، يُرجى إدخال رمز الرسالة النصية القصيرة المكون من 6 أرقام المرسلة إلى رقم هاتفك.", @@ -2796,22 +2791,19 @@ "code_sent": "حدث خطأ ما أثناء إرسال الرسالة النصية القصيرة. هل تم إدخال رقم الهاتف الصحيح؟ إذا لم يكن كذلك، حاول مرة أخرى." }, "extra_security": "تم إعداد المصادقة الثنائية بنجاح. أصبح حسابك الآن أكثر أماناً.", - "in_app_select": "في التطبيق، حدد", "link_phone": "ربط رقم هاتفك", - "or": "ما إذا كان", "phone_number": "رقم الهاتف", "resend_code": "إعادة إرسال الرمز", - "scan_qr": "مسح رمز الاستجابة السريعة ضوئياً", "seconds": "{الوقت} ثانية (ثوانٍ)", "select_auth_app": "حدد تطبيق المصادقة الذي تريد استخدامه.", "setup_2fa": "إعداد المصادقة الثنائية", - "setup_account": "إعداد الحساب", "successful_login": "لقد نجح الأمر!", "unknown_error": "خطأ غير معروف.", "verify": "تحقق", "welcome_back": "لقد قمت بتسجيل الدخول بنجاح باستخدام المصادقة الثنائية. مرحباً بعودتك!", - "download_from_app_store": "متجر التطبيقات", - "download_from_play_store": "متجر بلاي ستور" + "already_have_app_steps": "1. في التطبيق، حدد إعداد الحساب
2. اختر مسح رمز الاستجابة السريعة أو مفتاح التثبيت: {{secret}}", + "dont_have_app": " إذا لم يكن لديك تطبيق {{name}} ، يمكنك تنزيله من متجر Play أو متجر التطبيقات.", + "already_have_app": "إذا كان لديك بالفعل تطبيق {{name}} ، فاتبع الخطوات التالية:" }, "modal_fund_help": { "chat": "الدردشة", @@ -3518,6 +3510,9 @@ }, "form": { "optional": "اختياري", - "required": "إلزامي" + "required": "إلزامي", + "placeholders": { + "select_option": "حدد الخيار" + } } } \ No newline at end of file diff --git a/react/src/webshop/i18n/translated/de.json b/react/src/webshop/i18n/translated/de.json index e98350f4b..90acd015e 100644 --- a/react/src/webshop/i18n/translated/de.json +++ b/react/src/webshop/i18n/translated/de.json @@ -1375,18 +1375,13 @@ "modal_2fa_setup": { "2fa": "Zwei-Faktor-Authentifizierung", "2fa_success": "Zwei-Faktor-Authentifizierung erfolgreich eingerichtet", - "already_have_app": "Wenn Sie bereits über die Google Authenticator-App verfügen, führen Sie die folgenden Schritte aus:", "back": "Zurück", "cancel": "Abbrechen", - "choose": "Wählen Sie", "code_resent": "Wir haben den Code erneut gesendet.", "confirm": "Bestätigen Sie", - "dont_have_app": "Wenn Sie die App {Name} nicht haben,", - "download_from": "Können Sie es von der Website", "enter_2fa_code": "Um fortzufahren, geben Sie den Sicherheitscode für die Zwei-Faktor-Authentifizierung ein.", "enter_app_code": "Geben Sie den 6-stelligen Code in der App ein", "enter_app_code_6_digits": "Um fortzufahren, geben Sie den 6-stelligen Sicherheitscode von {Provider} ein.", - "enter_key": "Geben Sie einen Installationsschlüssel ein: {geheim}", "enter_phone": "Um fortzufahren, geben Sie Ihre Rufnummer ein", "enter_sms_code": "Geben Sie den 6-stelligen SMS-Code ein", "enter_sms_code_6_digits": "Um fortzufahren, geben Sie bitte den 6-stelligen SMS-Code ein, der Ihnen an Ihre Telefonnummer geschickt wurde.", @@ -1394,22 +1389,19 @@ "code_sent": "Beim Senden der SMS ist etwas schief gelaufen. Wurde die richtige Telefonnummer eingegeben? Wenn nicht, versuchen Sie es erneut." }, "extra_security": "Ihre Zwei-Faktor-Authentifizierung wurde erfolgreich eingerichtet. Ihr Konto ist jetzt besonders sicher.", - "in_app_select": "Wählen Sie in der App", "link_phone": "Verknüpfen Sie Ihre Rufnummer", - "or": "Ob die", "phone_number": "Rufnummer", "resend_code": "Code erneut senden", - "scan_qr": "Scannen eines QR-Codes", "seconds": "{Zeit} Sekunde(n)", "select_auth_app": "Wählen Sie die Authentifizierungsanwendung, die Sie verwenden möchten.", "setup_2fa": "Einrichten der Zwei-Faktor-Authentifizierung", - "setup_account": "Konto einrichten", "successful_login": "Es hat geklappt!", "unknown_error": "Unbekannter Fehler.", "verify": "Überprüfen Sie", "welcome_back": "Sie haben sich erfolgreich mit der Zwei-Faktor-Authentifizierung angemeldet. Willkommen zurück!", - "download_from_app_store": "App-Store", - "download_from_play_store": "Play Store" + "already_have_app_steps": "1. Wählen Sie in der App Kontoeinrichtung
2. Wählen Sie Scannen eines QR-Codes oder Eingabe eines Installationsschlüssels: {{secret}}", + "dont_have_app": " Wenn Sie die App {{name}} nicht haben, können Sie sie aus dem Play Store oder dem App Store herunterladen.", + "already_have_app": "Wenn Sie bereits über die App {{name}} verfügen, führen Sie die folgenden Schritte aus:" }, "modal_fund_help": { "chat": "Chat", @@ -3518,6 +3510,9 @@ }, "form": { "optional": "Optional", - "required": "Obligatorisch" + "required": "Obligatorisch", + "placeholders": { + "select_option": "Option auswählen" + } } } \ No newline at end of file diff --git a/react/src/webshop/i18n/translated/en-US.json b/react/src/webshop/i18n/translated/en-US.json index ecfb6312b..38d865f05 100644 --- a/react/src/webshop/i18n/translated/en-US.json +++ b/react/src/webshop/i18n/translated/en-US.json @@ -2365,38 +2365,30 @@ }, "2fa": "Two-factor authentication", "2fa_success": "Two-factor authentication successfully set up", - "already_have_app": "If you already have the Google Authenticator app, follow the steps below:", "back": "Back", "cancel": "Cancel", - "choose": "Select", "code_resent": "We have resent the code.", "confirm": "Confirm", - "dont_have_app": "If you don't have the {name} app,", - "download_from": "Can you download it from the", "enter_2fa_code": "To continue, enter the two-factor authentication security code.", "enter_app_code": "Enter the 6-digit code from within the app", "enter_app_code_6_digits": "To continue, enter the 6-digit security code from {provider}", - "enter_key": "Enter an installation key: {secret}", "enter_phone": "To continue, enter your phone number", "enter_sms_code": "Enter the 6-digit SMS code", "enter_sms_code_6_digits": "To proceed, please enter the 6-digit SMS code sent to your phone number.", "extra_security": "Your two-factor authentication has been successfully set up. Your account is now extra secure.", - "in_app_select": "In the app, select", "link_phone": "Link your phone number", - "or": "Whether the", "phone_number": "Phone number", "resend_code": "Resend code", - "scan_qr": "Scan a QR code", "seconds": "{time} second(s)", "select_auth_app": "Select the authentication app you want to use.", "setup_2fa": "Setting up two-factor authentication", - "setup_account": "Account setup", "successful_login": "It worked!", "unknown_error": "Unknown error.", "verify": "Verify", "welcome_back": "You have successfully logged in with two-factor authentication. Welcome back!", - "download_from_app_store": "App Store", - "download_from_play_store": "Play Store" + "already_have_app_steps": "1. In the app, select Account Setup
2. Select Scan a QR code or the Enter an installation key: {{secret}}", + "dont_have_app": " If you do not have the {{name}} app, You can download it from the Play Store or the App Store.", + "already_have_app": "If you already have the {{name}} app, follow the steps below:" }, "modal_product_reserve_cancel": { "description_not_cancelable": "This reservation has already been accepted by the provider. To cancel within 14 days of the date of the reservation, please contact the provider.", @@ -3518,6 +3510,9 @@ }, "form": { "optional": "Optional", - "required": "Mandatory" + "required": "Mandatory", + "placeholders": { + "select_option": "Select option" + } } } \ No newline at end of file diff --git a/react/src/webshop/i18n/translated/fr.json b/react/src/webshop/i18n/translated/fr.json index 124c8a967..ab72893eb 100644 --- a/react/src/webshop/i18n/translated/fr.json +++ b/react/src/webshop/i18n/translated/fr.json @@ -1375,18 +1375,13 @@ "modal_2fa_setup": { "2fa": "Authentification à deux facteurs", "2fa_success": "Authentification à deux facteurs configurée avec succès", - "already_have_app": "Si vous disposez déjà de l'application Google Authenticator, procédez comme suit :", "back": "Retour", "cancel": "Annuler", - "choose": "Sélectionner", "code_resent": "Nous avons renvoyé le code.", "confirm": "Confirmer", - "dont_have_app": "Si vous n'avez pas l'application {nom},", - "download_from": "Pouvez-vous le télécharger à partir du site", "enter_2fa_code": "Pour continuer, saisissez le code de sécurité de l'authentification à deux facteurs.", "enter_app_code": "Saisir le code à 6 chiffres à partir de l'application", "enter_app_code_6_digits": "Pour continuer, entrez le code de sécurité à 6 chiffres de {fournisseur}.", - "enter_key": "Entrez une clé d'installation : {secret}", "enter_phone": "Pour continuer, entrez votre numéro de téléphone", "enter_sms_code": "Saisir le code SMS à 6 chiffres", "enter_sms_code_6_digits": "Pour continuer, veuillez saisir le code SMS à 6 chiffres envoyé à votre numéro de téléphone.", @@ -1394,22 +1389,19 @@ "code_sent": "Un problème s'est produit lors de l'envoi du SMS. Le numéro de téléphone saisi est-il correct ? Si ce n'est pas le cas, réessayez." }, "extra_security": "Votre authentification à deux facteurs a été configurée avec succès. Votre compte est désormais plus sûr.", - "in_app_select": "Dans l'application, sélectionnez", "link_phone": "Liez votre numéro de téléphone", - "or": "La question de savoir si le", "phone_number": "Numéro de téléphone", "resend_code": "Renvoyer le code", - "scan_qr": "Scanner un code QR", "seconds": "{heure} seconde(s)", "select_auth_app": "Sélectionnez l'application d'authentification que vous souhaitez utiliser.", "setup_2fa": "Mise en place de l'authentification à deux facteurs", - "setup_account": "Ouvrir un compte", "successful_login": "Cela a fonctionné !", "unknown_error": "Erreur inconnue.", "verify": "Vérifier", "welcome_back": "Vous vous êtes connecté avec succès à l'aide de l'authentification à deux facteurs. Nous sommes heureux de vous revoir !", - "download_from_app_store": "App Store", - "download_from_play_store": "Play Store" + "already_have_app_steps": "1. Dans l'application, sélectionnez Configuration du compte
2. Sélectionnez Scanner un code QR ou Entrer une clé d'installation: {{secret}}", + "dont_have_app": " Si vous n'avez pas l'application {{name}}, vous pouvez la télécharger sur le Play Store ou l'App Store.", + "already_have_app": "Si vous avez déjà l'application {{name}}, suivez les étapes ci-dessous :" }, "modal_fund_help": { "chat": "Chat", @@ -3518,6 +3510,9 @@ }, "form": { "optional": "En option", - "required": "Obligatoire" + "required": "Obligatoire", + "placeholders": { + "select_option": "Sélectionner une option" + } } } \ No newline at end of file diff --git a/react/src/webshop/i18n/translated/pl.json b/react/src/webshop/i18n/translated/pl.json index 382e9b9f6..c761c2dbf 100644 --- a/react/src/webshop/i18n/translated/pl.json +++ b/react/src/webshop/i18n/translated/pl.json @@ -1375,18 +1375,13 @@ "modal_2fa_setup": { "2fa": "Uwierzytelnianie dwuskładnikowe", "2fa_success": "Uwierzytelnianie dwuskładnikowe zostało pomyślnie skonfigurowane", - "already_have_app": "Jeśli masz już aplikację Google Authenticator, wykonaj poniższe czynności:", "back": "Powrót", "cancel": "Anuluj", - "choose": "Wybierz", "code_resent": "Ponownie wysłaliśmy kod.", "confirm": "Potwierdzenie", - "dont_have_app": "Jeśli nie masz aplikacji {nazwa},", - "download_from": "Czy można go pobrać ze strony", "enter_2fa_code": "Aby kontynuować, wprowadź kod bezpieczeństwa uwierzytelniania dwuskładnikowego.", "enter_app_code": "Wprowadź 6-cyfrowy kod z poziomu aplikacji.", "enter_app_code_6_digits": "Aby kontynuować, wprowadź 6-cyfrowy kod bezpieczeństwa od {dostawcy}.", - "enter_key": "Wprowadź klucz instalacji: {secret}", "enter_phone": "Aby kontynuować, wprowadź swój numer telefonu", "enter_sms_code": "Wprowadź 6-cyfrowy kod SMS", "enter_sms_code_6_digits": "Aby kontynuować, wprowadź 6-cyfrowy kod SMS wysłany na Twój numer telefonu.", @@ -1394,22 +1389,19 @@ "code_sent": "Coś poszło nie tak podczas wysyłania wiadomości SMS. Czy wprowadzono prawidłowy numer telefonu? Jeśli nie, spróbuj ponownie." }, "extra_security": "Uwierzytelnianie dwuskładnikowe zostało pomyślnie skonfigurowane. Twoje konto jest teraz dodatkowo zabezpieczone.", - "in_app_select": "W aplikacji wybierz", "link_phone": "Połącz swój numer telefonu", - "or": "Czy", "phone_number": "Numer telefonu", "resend_code": "Wyślij ponownie kod", - "scan_qr": "Skanowanie kodu QR", "seconds": "{time} second(s)", "select_auth_app": "Wybierz aplikację uwierzytelniającą, której chcesz użyć.", "setup_2fa": "Konfigurowanie uwierzytelniania dwuskładnikowego", - "setup_account": "Konfiguracja konta", "successful_login": "Udało się!", "unknown_error": "Nieznany błąd.", "verify": "Weryfikacja", "welcome_back": "Pomyślnie zalogowano się przy użyciu uwierzytelniania dwuskładnikowego. Witamy ponownie!", - "download_from_app_store": "App Store", - "download_from_play_store": "Sklep Play" + "already_have_app_steps": "1. W aplikacji wybierz opcję Konfiguracja konta
2. Wybierz Skanuj kod QR lub Wprowadź klucz instalacyjny: {{secret}}", + "dont_have_app": " Jeśli nie masz aplikacji {{name}}, możesz ją pobrać ze Sklepu Play lub App Store.", + "already_have_app": "Jeśli masz już aplikację {{name}}, wykonaj poniższe czynności:" }, "modal_fund_help": { "chat": "Czat", @@ -3518,6 +3510,9 @@ }, "form": { "optional": "Opcjonalnie", - "required": "Obowiązkowe" + "required": "Obowiązkowe", + "placeholders": { + "select_option": "Wybierz opcję" + } } } \ No newline at end of file diff --git a/react/src/webshop/i18n/translated/ru.json b/react/src/webshop/i18n/translated/ru.json index aa0174ea1..f717141d9 100644 --- a/react/src/webshop/i18n/translated/ru.json +++ b/react/src/webshop/i18n/translated/ru.json @@ -1375,18 +1375,13 @@ "modal_2fa_setup": { "2fa": "Двухфакторная аутентификация", "2fa_success": "Двухфакторная аутентификация успешно настроена", - "already_have_app": "Если у вас уже есть приложение Google Authenticator, выполните следующие действия:", "back": "Назад", "cancel": "Отмена", - "choose": "Выберите", "code_resent": "Мы повторно отправили код.", "confirm": "Подтвердите", - "dont_have_app": "Если у вас нет приложения {name},", - "download_from": "Вы можете загрузить его с сайта", "enter_2fa_code": "Чтобы продолжить, введите код безопасности двухфакторной аутентификации.", "enter_app_code": "Введите 6-значный код в приложении", "enter_app_code_6_digits": "Чтобы продолжить, введите 6-значный код безопасности от {провайдера}", - "enter_key": "Введите ключ установки: {secret}", "enter_phone": "Чтобы продолжить, введите свой номер телефона", "enter_sms_code": "Введите 6-значный код SMS", "enter_sms_code_6_digits": "Чтобы продолжить, введите 6-значный SMS-код, отправленный на ваш номер телефона.", @@ -1394,22 +1389,19 @@ "code_sent": "Что-то пошло не так при отправке SMS. Введен ли правильный номер телефона? Если нет, попробуйте еще раз." }, "extra_security": "Двухфакторная аутентификация успешно настроена. Теперь ваша учетная запись стала еще более безопасной.", - "in_app_select": "В приложении выберите", "link_phone": "Свяжите свой номер телефона", - "or": "Будет ли", "phone_number": "Номер телефона", "resend_code": "Повторная отправка кода", - "scan_qr": "Сканирование QR-кода", "seconds": "{время} секунда(ы)", "select_auth_app": "Выберите приложение для аутентификации, которое вы хотите использовать.", "setup_2fa": "Настройка двухфакторной аутентификации", - "setup_account": "Создайте учетную запись", "successful_login": "Это сработало!", "unknown_error": "Неизвестная ошибка.", "verify": "Проверьте", "welcome_back": "Вы успешно вошли в систему с помощью двухфакторной аутентификации. С возвращением!", - "download_from_app_store": "App Store", - "download_from_play_store": "Play Store" + "already_have_app_steps": "1. В приложении выберите Настройка учетной записи
2. Выберите Сканировать QR-код или Ввести ключ установки: {{secret}}", + "dont_have_app": " Если у вас нет приложения {{name}}, вы можете загрузить его из Play Store или App Store.", + "already_have_app": "Если у вас уже есть приложение {{name}}, выполните следующие действия:" }, "modal_fund_help": { "chat": "Чат", @@ -3518,6 +3510,9 @@ }, "form": { "optional": "Дополнительно", - "required": "Обязательно" + "required": "Обязательно", + "placeholders": { + "select_option": "Выберите вариант" + } } } \ No newline at end of file diff --git a/react/src/webshop/i18n/translated/tr.json b/react/src/webshop/i18n/translated/tr.json index 53cfe18e7..e9a79e4cb 100644 --- a/react/src/webshop/i18n/translated/tr.json +++ b/react/src/webshop/i18n/translated/tr.json @@ -2777,18 +2777,13 @@ "modal_2fa_setup": { "2fa": "İki faktörlü kimlik doğrulama", "2fa_success": "İki faktörlü kimlik doğrulama başarıyla ayarlandı", - "already_have_app": "Google Authenticator uygulamasına zaten sahipseniz, aşağıdaki adımları izleyin:", "back": "Geri", "cancel": "İptal", - "choose": "Seçiniz", "code_resent": "Kodu yeniden gönderdik.", "confirm": "Onaylayın", - "dont_have_app": "Eğer {name} uygulamasına sahip değilseniz,", - "download_from": "Şu adresten indirebilir misiniz", "enter_2fa_code": "Devam etmek için iki faktörlü kimlik doğrulama güvenlik kodunu girin.", "enter_app_code": "Uygulama içinden 6 haneli kodu girin", "enter_app_code_6_digits": "Devam etmek için {sağlayıcı}'dan 6 haneli güvenlik kodunu girin", - "enter_key": "Bir kurulum anahtarı girin: {secret}", "enter_phone": "Devam etmek için telefon numaranızı girin", "enter_sms_code": "6 haneli SMS kodunu girin", "enter_sms_code_6_digits": "Devam etmek için lütfen telefon numaranıza gönderilen 6 haneli SMS kodunu girin.", @@ -2796,22 +2791,19 @@ "code_sent": "SMS gönderilirken bir şeyler yanlış gitti. Doğru telefon numarası girildi mi? Değilse, tekrar deneyin." }, "extra_security": "İki faktörlü kimlik doğrulamanız başarıyla ayarlandı. Hesabınız artık daha da güvenli.", - "in_app_select": "Uygulamada şunları seçin", "link_phone": "Telefon numaranızı bağlayın", - "or": "Olup olmadığı", "phone_number": "Telefon numarası", "resend_code": "Kodu yeniden gönder", - "scan_qr": "QR kodunu tarayın", "seconds": "{zaman} saniye(ler)", "select_auth_app": "Kullanmak istediğiniz kimlik doğrulama uygulamasını seçin.", "setup_2fa": "İki faktörlü kimlik doğrulamayı ayarlama", - "setup_account": "Hesap oluşturun", "successful_login": "İşe yaradı!", "unknown_error": "Bilinmeyen hata.", "verify": "Doğrulama", "welcome_back": "İki faktörlü kimlik doğrulama ile başarıyla giriş yaptınız. Tekrar hoş geldiniz!", - "download_from_app_store": "App Store", - "download_from_play_store": "Play Store" + "already_have_app_steps": "1. Uygulamada, Hesap kurulumu'nu seçin
2. QR kodu tara veya Yükleme anahtarı girin öğesini seçin: {{secret}}", + "dont_have_app": " {{name}} uygulamasına sahip değilseniz , Play Store veya App Store'dan indirebilirsiniz.", + "already_have_app": "{{name}} uygulamasına zaten sahipseniz, aşağıdaki adımları izleyin:" }, "modal_fund_help": { "chat": "Sohbet", @@ -3518,6 +3510,9 @@ }, "form": { "optional": "Opsiyonel", - "required": "Zorunlu" + "required": "Zorunlu", + "placeholders": { + "select_option": "Seçeneği seçin" + } } } \ No newline at end of file diff --git a/react/src/webshop/i18n/translated/uk.json b/react/src/webshop/i18n/translated/uk.json index 2be84e912..ba183b526 100644 --- a/react/src/webshop/i18n/translated/uk.json +++ b/react/src/webshop/i18n/translated/uk.json @@ -1375,18 +1375,13 @@ "modal_2fa_setup": { "2fa": "Двофакторна автентифікація", "2fa_success": "Двофакторну автентифікацію успішно налаштовано", - "already_have_app": "Якщо у вас вже є додаток Google Authenticator, виконайте наведені нижче дії:", "back": "Назад", "cancel": "Скасувати", - "choose": "Виберіть", "code_resent": "Ми обурені кодом.", "confirm": "Підтвердити", - "dont_have_app": "Якщо у вас немає програми {name},", - "download_from": "Ви можете завантажити його з", "enter_2fa_code": "Щоб продовжити, введіть код безпеки двофакторної автентифікації.", "enter_app_code": "Введіть 6-значний код у додатку", "enter_app_code_6_digits": "Щоб продовжити, введіть 6-значний код безпеки від {провайдера}", - "enter_key": "Введіть ключ встановлення: {secret}", "enter_phone": "Щоб продовжити, введіть свій номер телефону", "enter_sms_code": "Введіть 6-значний SMS-код", "enter_sms_code_6_digits": "Щоб продовжити, введіть 6-значний SMS-код, надісланий на ваш номер телефону.", @@ -1394,22 +1389,19 @@ "code_sent": "Щось пішло не так під час відправлення SMS. Чи правильний номер телефону введено? Якщо ні, спробуйте ще раз." }, "extra_security": "Ваша двофакторна автентифікація була успішно налаштована. Ваш обліковий запис тепер додатково захищений.", - "in_app_select": "У додатку виберіть", "link_phone": "Прив'яжіть свій номер телефону", - "or": "Чи не буде", "phone_number": "Номер телефону", "resend_code": "Код для повторного відправлення", - "scan_qr": "Відскануйте QR-код", "seconds": "{час} секунда(и)", "select_auth_app": "Виберіть програму автентифікації, яку ви хочете використовувати.", "setup_2fa": "Налаштування двофакторної автентифікації", - "setup_account": "Налаштуйте обліковий запис", "successful_login": "Спрацювало!", "unknown_error": "Невідома помилка.", "verify": "Підтвердити", "welcome_back": "Ви успішно увійшли за допомогою двофакторної автентифікації. З поверненням!", - "download_from_app_store": "App Store", - "download_from_play_store": "Play Store" + "already_have_app_steps": "1. У додатку виберіть Налаштування облікового запису
2. Виберіть Відсканувати QR-код або Ввести ключ встановлення: {{secret}}", + "dont_have_app": " Якщо у вас немає програми {{name}} , ви можете завантажити її з Play Store або App Store.", + "already_have_app": "Якщо у вас вже є додаток {{name}}, виконайте наведені нижче дії:" }, "modal_fund_help": { "chat": "Чат", @@ -3518,6 +3510,9 @@ }, "form": { "optional": "Необов'язково", - "required": "Обов'язково" + "required": "Обов'язково", + "placeholders": { + "select_option": "Виберіть варіант" + } } } \ No newline at end of file diff --git a/react/src/webshop/layout/Layout.tsx b/react/src/webshop/layout/Layout.tsx index 0bbc2d012..e1b4a267c 100644 --- a/react/src/webshop/layout/Layout.tsx +++ b/react/src/webshop/layout/Layout.tsx @@ -66,7 +66,7 @@ export const Layout = ({ children }: { children: React.ReactElement }) => { - +
diff --git a/react/src/webshop/services/helpers/useComposeVoucherCardData.ts b/react/src/webshop/services/helpers/useComposeVoucherCardData.ts index d73d44e55..24ea0413e 100644 --- a/react/src/webshop/services/helpers/useComposeVoucherCardData.ts +++ b/react/src/webshop/services/helpers/useComposeVoucherCardData.ts @@ -1,8 +1,7 @@ import { useCallback } from 'react'; -import Voucher from '../../../dashboard/props/models/Voucher'; +import Voucher, { VoucherProduct } from '../../../dashboard/props/models/Voucher'; import useAssetUrl from '../../hooks/useAssetUrl'; import { uniqueId } from 'lodash'; -import Product from '../../props/models/Product'; import Office from '../../../dashboard/props/models/Office'; import Reservation from '../../../dashboard/props/models/Reservation'; import Organization from '../../../dashboard/props/models/Organization'; @@ -13,7 +12,7 @@ type CardTransaction = { timestamp?: number; amount_locale?: string; type?: 'transaction' | 'product_voucher' | string; - product?: Product; + product?: VoucherProduct; target?: 'provider' | 'iban' | 'top_up'; product_reservation?: Reservation; organization?: Organization; @@ -28,7 +27,7 @@ export type VoucherCardType = Voucher & { description?: string; transactionsList?: Array; records_by_key?: { [key: string]: string }; - product?: Product; + product?: VoucherProduct; offices?: Array; }; diff --git a/translations/cache/cache.json b/translations/cache/cache.json index d2b52215b..2f6369bc4 100644 --- a/translations/cache/cache.json +++ b/translations/cache/cache.json @@ -987,6 +987,10 @@ "form.optional", "Optioneel" ], + [ + "form.placeholders.select_option", + "Selecteer optie" + ], [ "form.required", "Verplicht" @@ -3729,7 +3733,11 @@ ], [ "modal_2fa_setup.already_have_app", - "Als je al de Google Authenticator-app hebt, volg dan de onderstaande stappen:" + "Als je al de {{name}}-app hebt, volg dan de onderstaande stappen:" + ], + [ + "modal_2fa_setup.already_have_app_steps", + "1. In de app, selecteer Account instellen
2. Kies Scan een QR-code of de Voer een installatiesleutel in: {{secret}}" ], [ "modal_2fa_setup.back", @@ -3739,10 +3747,6 @@ "modal_2fa_setup.cancel", "Annuleer" ], - [ - "modal_2fa_setup.choose", - "Kies" - ], [ "modal_2fa_setup.code_resent", "We hebben de code opnieuw verstuurd." @@ -3753,19 +3757,7 @@ ], [ "modal_2fa_setup.dont_have_app", - "Als je de {name} app niet hebt," - ], - [ - "modal_2fa_setup.download_from", - "Kun je deze downloaden vanuit de" - ], - [ - "modal_2fa_setup.download_from_app_store", - "App Store" - ], - [ - "modal_2fa_setup.download_from_play_store", - "Play Store" + " Als je de {{name}} app niet hebt, Kun je deze downloaden vanuit de Play Store of de App Store." ], [ "modal_2fa_setup.enter_2fa_code", @@ -3779,10 +3771,6 @@ "modal_2fa_setup.enter_app_code_6_digits", "Om door te gaan, voer de 6-cijferige beveiligingscode in van {provider}" ], - [ - "modal_2fa_setup.enter_key", - "Voer een installatiesleutel in: {secret}" - ], [ "modal_2fa_setup.enter_phone", "Om door te gaan, voer je telefoonnummer in" @@ -3803,18 +3791,10 @@ "modal_2fa_setup.extra_security", "Je tweefactorauthenticatie is succesvol ingesteld. Je account is nu extra beveiligd." ], - [ - "modal_2fa_setup.in_app_select", - "In de app, selecteer" - ], [ "modal_2fa_setup.link_phone", "Koppel je telefoonnummer" ], - [ - "modal_2fa_setup.or", - "of de" - ], [ "modal_2fa_setup.phone_number", "Telefoonnummer" @@ -3823,10 +3803,6 @@ "modal_2fa_setup.resend_code", "Code opnieuw verzenden" ], - [ - "modal_2fa_setup.scan_qr", - "Scan een QR-code" - ], [ "modal_2fa_setup.seconds", "{time} seconde(n)" @@ -3839,10 +3815,6 @@ "modal_2fa_setup.setup_2fa", "Tweefactorauthenticatie instellen" ], - [ - "modal_2fa_setup.setup_account", - "Account instellen" - ], [ "modal_2fa_setup.successful_login", "Het is gelukt!"