diff --git a/.github/workflows/dev.yaml b/.github/workflows/dev.yaml index ce3ac4f..96526d2 100644 --- a/.github/workflows/dev.yaml +++ b/.github/workflows/dev.yaml @@ -24,10 +24,10 @@ jobs: needs: version_check steps: - uses: actions/checkout@v4 - - name: Install Node.js 16.15.1 + - name: Install Node.js 20 uses: actions/setup-node@v4 with: - node-version: 16.15.1 + node-version: 20 - run: | yarn install yarn build diff --git a/.github/workflows/prod.yaml b/.github/workflows/prod.yaml index b060655..31dfa4a 100644 --- a/.github/workflows/prod.yaml +++ b/.github/workflows/prod.yaml @@ -12,19 +12,15 @@ permissions: jobs: build-and-deploy: concurrency: ci-${{ github.ref }} - runs-on: ubuntu-20.04 - strategy: - matrix: - os: [ubuntu-latest] - node-version: [16.15.1] + runs-on: ubuntu-latest steps: - name: Download Code uses: actions/checkout@v4 - - name: Install Node.js ${{ matrix.node-version }} + - name: Install Node.js 20 uses: actions/setup-node@v4 with: - node-version: ${{ matrix.node-version }} + node-version: 20 - name: Install and Build run: | diff --git a/craco.config.js b/craco.config.js index 3ab1dd1..a2c2444 100644 --- a/craco.config.js +++ b/craco.config.js @@ -1,25 +1,39 @@ const path = require('path'); -const { pathsToModuleNameMapper } = require('ts-jest'); -const { compilerOptions } = require('./tsconfig.path.json'); +const fs = require('fs'); const sassResourcesLoader = require('craco-sass-resources-loader'); +const evalSourceMapMiddleware = require('react-dev-utils/evalSourceMapMiddleware'); +const noopServiceWorkerMiddleware = require('react-dev-utils/noopServiceWorkerMiddleware'); +const redirectServedPath = require('react-dev-utils/redirectServedPathMiddleware'); +const paths = require('react-scripts/config/paths'); module.exports = { + devServer: (devServerConfig) => { + delete devServerConfig.onBeforeSetupMiddleware; + delete devServerConfig.onAfterSetupMiddleware; + + devServerConfig.setupMiddlewares = (middlewares, devServer) => { + if (!devServer) { + throw new Error('webpack-dev-server is not defined'); + } + middlewares.push(evalSourceMapMiddleware(devServer)); + if (fs.existsSync(paths.proxySetup)) { + require(paths.proxySetup)(devServer.app); + } + middlewares.push( + redirectServedPath(paths.publicUrlOrPath), + noopServiceWorkerMiddleware(paths.publicUrlOrPath) + ); + return middlewares; + }; + return devServerConfig; + }, plugins: [ - { - plugin: require('craco-less'), - options: { lessLoaderOptions: { lessOptions: { javascriptEnabled: true } } }, - }, { plugin: sassResourcesLoader, options: { resources: ['./src/Assets/scss/base/export.scss'] }, }, ], - style: { - postcss: { plugins: [require('autoprefixer'), require('tailwindcss')] }, - }, - - //* Loading absolute paths webpack: { alias: { '@src': path.resolve(__dirname, 'src'), @@ -29,14 +43,33 @@ module.exports = { '@config': path.resolve(__dirname, 'src/App/Config'), '@components': path.resolve(__dirname, 'src/Components'), }, + configure: (webpackConfig) => { + webpackConfig.module.rules.push({ + test: /\.less$/, + use: [ + 'style-loader', + 'css-loader', + { + loader: 'less-loader', + options: { + lessOptions: { + javascriptEnabled: true, + }, + }, + }, + ], + }); + return webpackConfig; + }, }, - jest: { - configure: { - preset: 'ts-jest', - moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, { - prefix: '/src/', - }), + style: { + sass: { + loaderOptions: { + sassOptions: { + silenceDeprecations: ['legacy-js-api', 'import'], + }, + }, }, }, }; diff --git a/package.json b/package.json index fe9d0b1..657a856 100644 --- a/package.json +++ b/package.json @@ -17,57 +17,27 @@ ], "cracoConfig": "craco.config.js", "dependencies": { - "@craco/craco": "^6.2.0", - "@emotion/react": "^11.7.1", - "@emotion/styled": "^11.6.0", - "@mui/lab": "^5.0.0-alpha.70", - "@reduxjs/toolkit": "^1.6.1", - "@testing-library/jest-dom": "^5.11.4", - "@testing-library/react": "^11.1.0", - "@testing-library/user-event": "^12.1.10", - "@types/jest": "^26.0.15", - "@types/node": "^12.0.0", - "@types/react-router-dom": "^5.1.8", + "@craco/craco": "^7.1.0", + "@reduxjs/toolkit": "^2.2.0", + "@testing-library/jest-dom": "^6.4.0", + "@testing-library/react": "^14.2.0", + "@testing-library/user-event": "^14.5.0", "animate.css": "^4.1.1", - "ansi-html": "^0.0.8", - "axios": "^0.27.2", - "body-parser": "^1.20.3", - "craco-less": "^1.20.0", - "cross-spawn": "^7.0.5", - "decode-uri-component": "^0.2.1", - "ejs": "^3.1.10", - "elliptic": "^6.6.1", - "html-react-parser": "^1.4.5", - "http-proxy-middleware": "^2.0.7", - "ip": "2.0.1", - "json5": "^2.2.2", - "loader-utils": "^2.0.4", - "lodash": "^4.17.21", - "minimatch": "^3.0.5", - "node-forge": "^1.3.0", - "node-sass": "^6.0.1", - "nth-check": "2.0.1", - "path-to-regexp": "^0.1.12", - "react": "^18.2.0", - "react-dom": "^18.2.0", + "react": "^18.3.0", + "react-dom": "^18.3.0", "react-input-mask": "^2.0.4", - "react-redux": "^7.2.4", - "react-router-dom": "^6.14.0", - "react-scripts": "4.0.3", + "react-redux": "^9.1.0", + "react-router-dom": "^6.26.0", + "react-scripts": "5.0.1", "react-syntax-highlighter": "^15.5.0", - "redux": "^4.1.0", "redux-persist": "^6.0.0", - "redux-persist-transform-compress": "^4.2.0", - "redux-state-sync": "^3.1.4", - "rollup": "^2.79.2", - "rsuite": "^5.0.1", - "scss-tokenizer": "^0.4.3", - "semver": "^7.5.2", - "shell-quote": "^1.7.3", - "swiper": "^8.4.5", - "tailwind-animatecss": "^1.0.0", - "typescript": "^4.1.2", - "web-vitals": "^1.0.1" + "redux-persist-transform-compress": "4.2.0", + "rsuite": "^5.70.0", + "sass": "^1.79.0", + "swiper": "^11.1.0", + "tailwind-animatecss": "1.0.0", + "typescript": "^5.5.0", + "web-vitals": "^4.2.0" }, "scripts": { "test": "craco test", @@ -98,42 +68,19 @@ "last 1 safari version" ] }, - "resolutions": { - "react-error-overlay": "6.0.9", - "nth-check": "2.0.1", - "ansi-html": "0.0.8", - "node-forge": "1.3.0", - "scss-tokenizer": "0.4.3", - "minimatch": "3.0.5", - "loader-utils": "2.0.4", - "decode-uri-component": "0.2.1", - "json5": "2.2.2", - "semver": "7.5.2", - "lodash": "4.17.21", - "immer": "9.0.6", - "ip": "2.0.1", - "braces": "3.0.3", - "path-to-regexp": "0.1.12", - "rollup": "2.79.2", - "http-proxy-middleware": "2.0.7", - "cross-spawn": "7.0.5", - "ejs": "3.1.10", - "shell-quote": "^1.7.3", - "elliptic": "6.6.1" - }, "devDependencies": { - "@types/react": "^18.2.14", - "@types/react-dom": "^18.2.6", - "@types/react-input-mask": "^3.0.2", - "@types/react-syntax-highlighter": "^15.5.11", - "@types/redux-persist": "^4.3.1", - "@types/redux-state-sync": "^3.1.3", - "autoprefixer": "9", - "craco-sass-resources-loader": "^1.1.0", - "glob": "^7.2.0", - "postcss": ">=7.0.36", - "tailwindcss": "npm:@tailwindcss/postcss7-compat", - "ts-jest": "^28.0.3", - "xml-js": "^1.6.11" - } + "@types/jest": "^29.5.0", + "@types/node": "^20.14.0", + "@types/react": "^18.3.0", + "@types/react-dom": "^18.3.0", + "@types/react-input-mask": "^3.0.5", + "@types/react-syntax-highlighter": "^15.5.13", + "autoprefixer": "^10.4.0", + "craco-sass-resources-loader": "1.1.0", + "less": "^4.2.0", + "less-loader": "^12.2.0", + "postcss": "^8.4.0", + "tailwindcss": "^3.4.0" + }, + "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e" } diff --git a/src/Assets/scss/base/RSuite.scss b/src/Assets/scss/base/RSuite.scss index 36a851b..91c768b 100644 --- a/src/Assets/scss/base/RSuite.scss +++ b/src/Assets/scss/base/RSuite.scss @@ -37,6 +37,12 @@ .rs-grid-container, .rs-row { @apply w-full m-0 p-0; + display: flex; + flex-wrap: wrap; +} + +.rs-col { + flex-shrink: 0; } .rs-toast-container { @@ -85,17 +91,50 @@ } .rs-modal-wrapper { - @apply flex-center; + position: fixed; + inset: 0; + z-index: 1050; + display: flex; + align-items: center; + justify-content: center; + overflow: auto; +} + +.rs-modal-backdrop { + position: fixed; + inset: 0; + z-index: 1040; + background-color: rgba(0, 0, 0, 0.3); } .rs-modal { - @apply m-0; + position: relative; + z-index: 1050; + margin: auto; + background: white; + border-radius: 6px; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); + + .rs-modal-content { + position: relative; + } + .rs-modal-header { @apply border-b pb-2 border-opacity-30 text-base flex items-center; + position: relative; + padding: 15px 20px; + + .rs-modal-title { + flex: 1; + } + .rs-modal-header-close { - top: 10px; + position: absolute; + right: 15px; + top: 50%; + transform: translateY(-50%); font-size: 12px; - @apply text-black transition-all mr-0; + @apply text-black transition-all; &:hover { @apply text-error; } @@ -105,11 +144,13 @@ .rs-modal-body { max-height: 50vh; @apply py-2 mt-0 overflow-y-auto; + padding: 15px 20px; } .rs-modal-footer { - border-top: 1px solid rgba(0, 0, 0, 0.1) !important; + border-top: 1px solid rgba(0, 0, 0, 0.1); @apply pt-3; + padding: 15px 20px; } .btn-accept { @@ -131,23 +172,17 @@ .rs-modal-no-border { .rs-modal-header, .rs-modal-footer { - border: none !important; + border: none; } } -.rs-notification { - .rs-btn-close { - svg { - color: white !important; - } - } +.rs-notification .rs-btn-close svg { + color: white; } -.rs-picker-toggle, -.rs-btn { - &:focus { - box-shadow: none !important; - } +.rs-picker-toggle:focus, +.rs-btn:focus { + box-shadow: none; } .rs-picker-none { @@ -155,7 +190,7 @@ } .rs-btn-outline { - border-width: 1px !important; + border-width: 1px; @apply border-primary text-primary bg-transparent; &:hover { @apply bg-primary text-white; @@ -165,3 +200,51 @@ .rs-picker-select-menu-items { @apply my-0; } + +.rs-tooltip { + z-index: 9999; +} + +.rs-radio-group-inline { + display: inline-flex; + flex-direction: row; + align-items: center; +} + +.rs-radio-inline { + display: inline-flex; + margin-right: 10px; +} + +.rs-checkbox-group-inline { + display: inline-flex; + flex-direction: row; +} + +.rs-checkbox-inline { + display: inline-flex; +} + +.rs-radio-group.mode-picker { + display: inline-flex; + align-items: center; + + .rs-radio { + margin: 0; + } + + .rs-radio-checker { + padding-left: 0; + + > label { + padding: 8px 12px; + cursor: pointer; + border-bottom: 2px solid transparent; + } + } + + .rs-radio-checked .rs-radio-checker > label { + color: #4b2b79; + border-bottom-color: #4b2b79; + } +} diff --git a/src/Assets/scss/base/media.scss b/src/Assets/scss/base/media.scss index 9c26766..0a00151 100644 --- a/src/Assets/scss/base/media.scss +++ b/src/Assets/scss/base/media.scss @@ -1,3 +1,5 @@ +@use 'sass:map'; + $xs: 0; $sm: 481; $md: 992; @@ -15,8 +17,8 @@ $breakpoints: ( ); @mixin up($breakpoint) { - @if map-has-key($breakpoints, $breakpoint) { - $breakpoint-value: map-get($breakpoints, $breakpoint); + @if map.has-key($breakpoints, $breakpoint) { + $breakpoint-value: map.get($breakpoints, $breakpoint); @media (min-width: $breakpoint-value) { @content; } @@ -24,13 +26,12 @@ $breakpoints: ( @media (min-width: $breakpoint) { @content; } - // @warn 'Invalid breakpoint: #{$breakpoint}.'; } } @mixin down($breakpoint) { - @if map-has-key($breakpoints, $breakpoint) { - $breakpoint-value: map-get($breakpoints, $breakpoint); + @if map.has-key($breakpoints, $breakpoint) { + $breakpoint-value: map.get($breakpoints, $breakpoint); @media (max-width: $breakpoint-value) { @content; } @@ -38,22 +39,21 @@ $breakpoints: ( @media (max-width: $breakpoint) { @content; } - // @warn 'Invalid breakpoint: #{$breakpoint}.'; } } @mixin between($lower, $upper) { - @if map-has-key($breakpoints, $lower) and map-has-key($breakpoints, $upper) { - $lower-breakpoint: map-get($breakpoints, $lower); - $upper-breakpoint: map-get($breakpoints, $upper); + @if map.has-key($breakpoints, $lower) and map.has-key($breakpoints, $upper) { + $lower-breakpoint: map.get($breakpoints, $lower); + $upper-breakpoint: map.get($breakpoints, $upper); @media (min-width: $lower-breakpoint) and (max-width: ($upper-breakpoint - 1)) { @content; } } @else { - @if (map-has-key($breakpoints, $lower) == false) { + @if (map.has-key($breakpoints, $lower) == false) { @warn 'Your lower breakpoint was invalid: #{$lower}.'; } - @if (map-has-key($breakpoints, $upper) == false) { + @if (map.has-key($breakpoints, $upper) == false) { @warn 'Your upper breakpoint was invalid: #{$upper}.'; } } diff --git a/src/Components/EditableInput/EditableInput.tsx b/src/Components/EditableInput/EditableInput.tsx index 96f72c5..d7526e3 100644 --- a/src/Components/EditableInput/EditableInput.tsx +++ b/src/Components/EditableInput/EditableInput.tsx @@ -18,6 +18,7 @@ const EditableInput: FC = inputProps => { editable = true, autoFill = false, innerComponentPosition, + children: _children, ...props } = inputProps; @@ -30,7 +31,8 @@ const EditableInput: FC = inputProps => { if (lines && lines > 1) InputElement =