From: Roberto Stomeo Date: Tue, 1 Jul 2025 15:04:35 +0000 (+0200) Subject: Initial commit edera-web X-Git-Url: https://git-hsc.dyrecta.com/?a=commitdiff_plain;h=599b693333ec3fcc8738392f9fecde35df597e45;p=pia_hsc.git Initial commit edera-web --- diff --git a/edera-web/.gitignore b/edera-web/.gitignore new file mode 100644 index 0000000..a021272 --- /dev/null +++ b/edera-web/.gitignore @@ -0,0 +1,54 @@ +# These are some examples of commonly ignored file patterns. +# You should customize this list as applicable to your project. +# Learn more about .gitignore: +# https://www.atlassian.com/git/tutorials/saving-changes/gitignore + +# Node artifact files +node_modules/ +dist/ +build/ + +# Compiled Java class files +*.class + +# Compiled Python bytecode +*.py[cod] + +# Log files +*.log + +# Package files +*.jar + +# Maven +target/ +dist/ + +# JetBrains IDE +.idea/ + +# Unit test reports +TEST*.xml + +# Generated by MacOS +.DS_Store + +# Generated by Windows +Thumbs.db + +# Applications +*.app +*.exe +*.war + +# Large media files +*.mp4 +*.tiff +*.avi +*.flv +*.mov +*.wmv + +html/resources/css/ +html/resources/js/ +package-lock.json diff --git a/edera-web/.nvmrc b/edera-web/.nvmrc new file mode 100644 index 0000000..3c03207 --- /dev/null +++ b/edera-web/.nvmrc @@ -0,0 +1 @@ +18 diff --git a/edera-web/.prettierrc b/edera-web/.prettierrc new file mode 100644 index 0000000..d5fba07 --- /dev/null +++ b/edera-web/.prettierrc @@ -0,0 +1,8 @@ +{ + "bracketSpacing": true, + "printWidth": 140, + "singleQuote": true, + "trailingComma": "none", + "tabWidth": 2, + "useTabs": false +} diff --git a/edera-web/.vscode/settings.json b/edera-web/.vscode/settings.json new file mode 100644 index 0000000..7a73a41 --- /dev/null +++ b/edera-web/.vscode/settings.json @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/edera-web/README.md b/edera-web/README.md new file mode 100644 index 0000000..74c7065 --- /dev/null +++ b/edera-web/README.md @@ -0,0 +1,9 @@ +# Come funziona + +Per utilizzare questo archetipo come base per i tuoi progetti segui i seguenti passaggi: + +- crea un fork del progetto +- esegui `nvm use` per impostare la versione di node.js corretta +- esegui `npm install` per installare le dipendenze +- esegui `npm start` per avviare il server di sviluppo +- **divertiti** diff --git a/edera-web/bitbucket-pipelines.yml b/edera-web/bitbucket-pipelines.yml new file mode 100644 index 0000000..4546536 --- /dev/null +++ b/edera-web/bitbucket-pipelines.yml @@ -0,0 +1,57 @@ +image: google/cloud-sdk:412.0.0-slim + +definitions: + steps: + - step: &build + image: node:latest + name: Build + caches: + - node + script: + - source scripts/set-env.sh + - export VERSION="${REVISION}.${BITBUCKET_BUILD_NUMBER}" + - 'echo "{ \"version\": \"${VERSION}\" }" > ./src/build.json' + - npm install + - npm run build + artifacts: + - build/** + - step: &publish + name: Publish + trigger: automatic + services: + - docker + script: + - source scripts/set-env.sh + - export MODULE=web + - export VERSION="${REVISION}.${BITBUCKET_BUILD_NUMBER}" + - export IMAGE_BASE="eu.gcr.io/${PROJECT_ID}/${NAMESPACE}-${MODULE}" + - export IMAGE="${IMAGE_BASE}:${VERSION}" + - cat scripts/service-account.json.base64 | base64 --decode >> build/service-account.json + - gcloud auth activate-service-account --key-file build/service-account.json + - gcloud config set project ${PROJECT_ID} + - gcloud config set compute/zone europe-west1-b + - gcloud auth configure-docker + - docker build -t ${IMAGE} -f ./scripts/docker/Dockerfile . + - docker push ${IMAGE} + - docker tag $IMAGE "${IMAGE_BASE}:latest" + - docker push "${IMAGE_BASE}:latest" + - git tag -a "${VERSION}" -m "version ${VERSION}" + - git push origin "${VERSION}" + artifacts: + - build/** + - step: &deploy + name: Deploy + script: + - source scripts/set-env.sh + - gcloud auth activate-service-account --key-file build/service-account.json + - rm build/service-account.json + - gsutil -m cp -r build/* ${BUCKET} +pipelines: + branches: + develop: + - step: *build + - step: *publish + - step: *deploy + master: + - step: *build + - step: *publish \ No newline at end of file diff --git a/edera-web/config-overrides.js b/edera-web/config-overrides.js new file mode 100644 index 0000000..5c15969 --- /dev/null +++ b/edera-web/config-overrides.js @@ -0,0 +1,31 @@ +const webpack = require('webpack'); +const WorkBoxPlugin = require('workbox-webpack-plugin'); + +module.exports = function override(config) { + config.resolve.fallback = { + process: require.resolve('process/browser'), + // zlib: require.resolve('browserify-zlib'), + stream: require.resolve('stream-browserify'), + crypto: require.resolve('crypto-browserify'), + util: require.resolve('util'), + buffer: require.resolve('buffer') + // asset: require.resolve('assert') + }; + + // https://stackoverflow.com/questions/69135310/workaround-for-cache-size-limit-in-create-react-app-pwa-service-worker + config.plugins.forEach((plugin) => { + if (plugin instanceof WorkBoxPlugin.InjectManifest) { + plugin.config.maximumFileSizeToCacheInBytes = 50 * 1024 * 1024; + } + }); + + config.plugins = [ + ...config.plugins, + new webpack.ProvidePlugin({ + process: 'process/browser.js', + Buffer: ['buffer', 'Buffer'] + }) + ]; + + return config; +}; diff --git a/edera-web/jsconfig.json b/edera-web/jsconfig.json new file mode 100644 index 0000000..35332c7 --- /dev/null +++ b/edera-web/jsconfig.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "target": "esnext", + "module": "commonjs", + "baseUrl": "src" + }, + "include": ["src/**/*"], + "exclude": ["node_modules"] +} diff --git a/edera-web/package-dev.json b/edera-web/package-dev.json new file mode 100644 index 0000000..5584e78 --- /dev/null +++ b/edera-web/package-dev.json @@ -0,0 +1,84 @@ +{ + "name": "edera", + "description": "Manufacturing Execution System - Applica Software Guru", + "version": "1.0.0", + "private": true, + "dependencies": { + "@ant-design/icons": "file:../../modules/react-admin/node_modules/@ant-design/icons", + "@applica-software-guru/crud-client": "^1.1", + "@applica-software-guru/iam-client": "^1.1", + "@applica-software-guru/react-admin": "file:../../modules/react-admin", + "highcharts": "^11.2.0", + "highcharts-react-official": "^3.2.1", + "@mui/icons-material": "file:../../modules/react-admin/node_modules/@mui/icons-material", + "@mui/material": "file:../../modules/react-admin/node_modules/@mui/material", + "@react-pdf/renderer": "^3.1.12", + "dayjs": "^1.11.10", + "react": "file:../../modules/react-admin/node_modules/react", + "react-admin": "file:../../modules/react-admin/node_modules/react-admin", + "react-app-rewired": "^2.2.1", + "react-dom": "file:../../modules/react-admin/node_modules/react-dom", + "react-hook-form": "file:../../modules/react-admin/node_modules/react-hook-form", + "react-router": "file:../../modules/react-admin/node_modules/react-router", + "react-router-dom": "file:../../modules/react-admin/node_modules/react-router-dom", + "react-scripts": "^5.0.1", + "react-sticky-box": "file:../../modules/react-admin/node_modules/react-sticky-box", + "react-query": "file:../../modules/react-admin/node_modules/react-query", + "react-apexcharts": "^1.4.1", + "web-vitals": "^3.0.3", + "apexcharts": "^3.44.0", + "qrcode": "^1.5.3" + }, + "scripts": { + "start": "react-app-rewired start", + "build": "react-app-rewired build", + "test": "react-scripts test", + "eject": "react-scripts eject" + }, + "eslintConfig": { + "extends": [ + "react-app", + "react-app/jest" + ] + }, + "babel": { + "presets": [ + "@babel/preset-react" + ] + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + }, + "resolutions": { + "@svgr/webpack": "6.4.0" + }, + "devDependencies": { + "@babel/core": "^7.19.3", + "@babel/eslint-parser": "^7.19.1", + "@babel/plugin-proposal-private-property-in-object": "^7.21.11", + "buffer": "^6.0.3", + "crypto-browserify": "^3.12.0", + "eslint": "^8.25.0", + "eslint-config-prettier": "^8.5.0", + "eslint-config-react-app": "7.0.1", + "eslint-plugin-flowtype": "^8.0.3", + "eslint-plugin-import": "^2.26.0", + "eslint-plugin-jsx-a11y": "^6.6.1", + "eslint-plugin-prettier": "^4.2.1", + "eslint-plugin-react": "^7.31.10", + "eslint-plugin-react-hooks": "^4.6.0", + "prettier": "^2.7.1", + "process": "^0.11.10", + "react-error-overlay": "6.0.9", + "stream-browserify": "^3.0.0" + } +} diff --git a/edera-web/package.json b/edera-web/package.json new file mode 100644 index 0000000..2e0ba63 --- /dev/null +++ b/edera-web/package.json @@ -0,0 +1,61 @@ +{ + "name": "web", + "description": "Web Template - Applica Software Guru", + "version": "1.0.0", + "private": true, + "dependencies": { + "@applica-software-guru/crud-client": "^1.1", + "@applica-software-guru/iam-client": "^1.1", + "@applica-software-guru/react-admin": "^1.4", + "@react-pdf/renderer": "^3.1.14", + "apexcharts": "^3.44.0", + "highcharts": "^11.2.0", + "highcharts-react-official": "^3.2.1", + "qrcode": "^1.5.3", + "react": "^18.2.0", + "react-apexcharts": "^1.4.1", + "react-app-rewired": "^2.2.1", + "react-dom": "^18.2.0", + "react-scripts": "^5.0.1", + "web-vitals": "^3.0.3" + }, + "scripts": { + "start": "react-app-rewired start", + "build": "react-app-rewired build", + "test": "react-scripts test", + "eject": "react-scripts eject" + }, + "eslintConfig": { + "extends": ["react-app", "react-app/jest"] + }, + "babel": { + "presets": ["@babel/preset-react"] + }, + "browserslist": { + "production": [">0.2%", "not dead", "not op_mini all"], + "development": ["last 1 chrome version", "last 1 firefox version", "last 1 safari version"] + }, + "resolutions": { + "@svgr/webpack": "6.4.0" + }, + "devDependencies": { + "@babel/core": "^7.19.3", + "@babel/eslint-parser": "^7.19.1", + "@babel/plugin-proposal-private-property-in-object": "^7.21.11", + "buffer": "^6.0.3", + "crypto-browserify": "^3.12.0", + "eslint": "^8.25.0", + "eslint-config-prettier": "^8.5.0", + "eslint-config-react-app": "7.0.1", + "eslint-plugin-flowtype": "^8.0.3", + "eslint-plugin-import": "^2.26.0", + "eslint-plugin-jsx-a11y": "^6.6.1", + "eslint-plugin-prettier": "^4.2.1", + "eslint-plugin-react": "^7.31.10", + "eslint-plugin-react-hooks": "^4.6.0", + "prettier": "^2.7.1", + "process": "^0.11.10", + "react-error-overlay": "6.0.9", + "stream-browserify": "^3.0.0" + } +} diff --git a/edera-web/public/favicon-dark.png b/edera-web/public/favicon-dark.png new file mode 100644 index 0000000..85288ca Binary files /dev/null and b/edera-web/public/favicon-dark.png differ diff --git a/edera-web/public/favicon-light.png b/edera-web/public/favicon-light.png new file mode 100644 index 0000000..7fd5d0c Binary files /dev/null and b/edera-web/public/favicon-light.png differ diff --git a/edera-web/public/index.html b/edera-web/public/index.html new file mode 100644 index 0000000..72a97c1 --- /dev/null +++ b/edera-web/public/index.html @@ -0,0 +1,46 @@ + + + + + + + + + + + + + Edera + + + + + + + + + +
+ + + diff --git a/edera-web/scripts/docker/Dockerfile b/edera-web/scripts/docker/Dockerfile new file mode 100644 index 0000000..1334730 --- /dev/null +++ b/edera-web/scripts/docker/Dockerfile @@ -0,0 +1,6 @@ +FROM httpd:2 +ARG PORT=80 + +EXPOSE $PORT + +ADD ./build/ /usr/local/apache2/htdocs/ \ No newline at end of file diff --git a/edera-web/scripts/kube/ingress.yml b/edera-web/scripts/kube/ingress.yml new file mode 100644 index 0000000..a0ce7b5 --- /dev/null +++ b/edera-web/scripts/kube/ingress.yml @@ -0,0 +1,33 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: app-ingress-web + annotations: + cert-manager.io/issuer: letsencrypt + nginx.ingress.kubernetes.io/use-regex: 'true' + nginx.ingress.kubernetes.io/rewrite-target: /edera-web/$1 + nginx.ingress.kubernetes.io/backend-protocol: 'HTTPS' + nginx.ingress.kubernetes.io/upstream-vhost: 'storage.googleapis.com' + kubernetes.io/ingress.class: 'nginx' + kubernetes.io/ingress.allow-http: 'true' + nginx.ingress.kubernetes.io/server-snippet: | + location ~ ^/$ { + rewrite ^.*$ /index.html last; + } +spec: + ingressClassName: nginx + tls: + - hosts: + - edera.applica.guru + secretName: letsencrypt + rules: + - host: edera.applica.guru + http: + paths: + - path: /(?!api)(.*) + pathType: ImplementationSpecific + backend: + service: + name: edera-bucket + port: + number: 443 \ No newline at end of file diff --git a/edera-web/scripts/kube/web.yml b/edera-web/scripts/kube/web.yml new file mode 100644 index 0000000..466cfd7 --- /dev/null +++ b/edera-web/scripts/kube/web.yml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: Service +metadata: + name: edera-bucket +spec: + type: ExternalName + externalName: storage.googleapis.com diff --git a/edera-web/scripts/service-account.json.base64 b/edera-web/scripts/service-account.json.base64 new file mode 100644 index 0000000..6841642 --- /dev/null +++ b/edera-web/scripts/service-account.json.base64 @@ -0,0 +1,42 @@ +ewogICJ0eXBlIjogInNlcnZpY2VfYWNjb3VudCIsCiAgInByb2plY3RfaWQiOiAiYXBwbGljYS1n +ZW5lcmFsIiwKICAicHJpdmF0ZV9rZXlfaWQiOiAiNDk3YzZmNTU5N2Y0NTI3NWY3ZTlmZTQwMzFj +NGI4MjllMjY4NzEyMSIsCiAgInByaXZhdGVfa2V5IjogIi0tLS0tQkVHSU4gUFJJVkFURSBLRVkt +LS0tLVxuTUlJRXZnSUJBREFOQmdrcWhraUc5dzBCQVFFRkFBU0NCS2d3Z2dTa0FnRUFBb0lCQVFD +dDRrY1B3UVJ6bUQ3b1xucHlVQVBlTnBnS01TWGxTM25CYmVtSUFlcmk3dm5GeHJIMFV4RlJndmRN +VTlzRTJ6L0h5WXNTMGNnR1R3Y01Fd1xuQlVVYVF3UWpUMFVxdlBrN3ByY2lOWURSTXVNQXY1MW5Y +WkpRZ0RYeitMSG15VldhaE1VRTlMczM4YzJxeUFpalxuVTBjakhqTmxsMmp3S2J5OWJVNUVUcWlT +eEtxdE1FRVlwSUFzV2kvWG1iekx6NlVtSnladm56ZCtkRFNRQTU3aFxuY0NsOEFTdlBpQTdIeXVz +b1lzVWJ2S2xRS0tmcndtV3NBUllEVjdRc0t6bEpsR0ViWE1sWlozdzB1VCszVkxXOVxuTWMyS1Fo +SGpvaWpoTW9yRjdVdjVWMjJrTWkyL2V4RkI3L3ErbllCejU5K1MxUXZlRmpCd3E5L0gwQTRyTXpU +a1xubWZDYzhjMWZBZ01CQUFFQ2dnRUFOR1dsdlRrUUl0Y2pTYzhvSnJEL2lLaXpPeE5DMnd0Rmx2 +RUVWbnB0ZVZXNFxuUWExc0Y3VEFFM2pRQU4xU0pPVDJGTHI3R1lZVkpLRU5qZTlnbWQvTTdPanpz +a084cEwyQm5PVGJldTZuR2ZBalxudWVTbjlPc1ZsdjEvZWtoOEs3Skxma2xTNnpKSm8rZGdOdnNl +eWhYTkxoVllrVm82WGlpRWQ2L3VPei9aSUpPVVxuTFlHN1hPVHExNWhKcmZaM2trdDBBRldJc2NK +SXVFbFBlUTJOaDVWY3VSeVJwUVQwaFA0NUlRUTZFdElBWXp4OVxuUnRGUWFhd2tpWVFqZ0RkelFO +Qm1tUHN2ZWc4Y2JkQXlWZVlxcitaVkFiNk1pWjJ2N01RR0hyeEFBcnhSeXRMZlxuMmd2VUl0K3pv +dmJBemo3Q3h0YjUvS3JDdHUwMC9aWTcwNzRxTExnR1NRS0JnUUR2NXRkNmxWbUg5cXl3TThTc1xu +NnA5NE5lTVFrbU9vME41SjBUUisxTGFITnBkdjBaY3B0bEJDS0lCTXorVTBBc0p0cG11dlpGTGdH +cmp6U3E2cFxuVFlGUis0Mlc1NjJGMkoxWmlKZmdnWDdubWp3TmhUNzdrdWUwbjVWbE1iTHBUN0Iz +ajB6V3Ftc0hqZ09lZWhDblxueEIwOXpKcXJEYm96MkV3UGVvRkhDVjB5dHdLQmdRQzVqVmpJd21F +d01PU2g5UHF3QzJ5SVBYeS81UkpGTG4yL1xuNWxzUmhRbkkrTkxTZUJjWnRIV1BiOWcyNVF6SFVV +dWRRNGhiYWpHaDM1R2t5SGtIcjJ5MGVjdTFUd2pVTitGMFxubzdhejRzekk4a3kzRk9sRUpvdXM4 +enFNQWsrYnhFR1hrUUNkWmFiL0ltS0svR1dRK21RcXlDV0RtUkFvR3NVcVxuTEJNdUhKOXltUUtC +Z0YrRnJBRGNYT1RkWEk5Z1hZeDRjM3piQUFtR01IWjBqRDRhTmV2V2FNTllBbDU4dHRMZVxuREFE +N3ZYSllTU3czZVJGTjlZekZ4cFlETGVkNXNpZ3BlemVZa1Iwb0xKaWgwcTFtelFxUXBXWTBySHE1 +dG9WWFxuVGpsR1hhY0liZk9tVGw2Y3lYeWtLSysrWlVTQjJBWGsrYnUwcjFVeXh4U0RxRzExV3Vw +ZEdTWHJBb0dCQUo2YVxucm9CMGZvU2wxbGlGd2Q3RzlRK0RsMldqMWJraTQwUXNFRDNxZlJHM2R1 +V0cxeUFXdThKT3RQOC9UR3YzRm00blxuc3ArSkowR1ppN0hSMW5wMlBiSUt4ZENGN1NNUlhQckpr +YnN6cXg0ODFzeEw2SlJqYWxMOFdWZ2lCWkE4OG1BdlxuQnRxRGNIcDNGc3A4c2doNXJ6Tk9mNXA4 +Tkc1RGE3TC9sNmw3dCtOSkFvR0JBT2d6MHM1WGErRzZLTmlVN0IySFxuc0l2MmRNMzZvNlZ3a21P +T3FjdCtkVS8ycG12ZGM4aFpDbFZGYXBQeWZ4djFqVnNjSDUrZG5FaFJIaTEzYXdIU1xuVzc3MnQ5 +WUdBNWpGb2dnakVPRU5QbVR2QUwxd01NL0ExRCtmanVaWVArOEVDaEU0QmFmbVN3WWZGVzJRQmxE +eFxuZlhoOHNmT0FnMjhuMEc1QWNGcXZVSFJNXG4tLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tXG4i +LAogICJjbGllbnRfZW1haWwiOiAiYml0YnVja2V0LXBpcGVsaW5lc0BhcHBsaWNhLWdlbmVyYWwu +aWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLAogICJjbGllbnRfaWQiOiAiMTA4Mzk0ODE1Njc3NDgx +NDI2MjYwIiwKICAiYXV0aF91cmkiOiAiaHR0cHM6Ly9hY2NvdW50cy5nb29nbGUuY29tL28vb2F1 +dGgyL2F1dGgiLAogICJ0b2tlbl91cmkiOiAiaHR0cHM6Ly9vYXV0aDIuZ29vZ2xlYXBpcy5jb20v +dG9rZW4iLAogICJhdXRoX3Byb3ZpZGVyX3g1MDlfY2VydF91cmwiOiAiaHR0cHM6Ly93d3cuZ29v +Z2xlYXBpcy5jb20vb2F1dGgyL3YxL2NlcnRzIiwKICAiY2xpZW50X3g1MDlfY2VydF91cmwiOiAi +aHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vcm9ib3QvdjEvbWV0YWRhdGEveDUwOS9iaXRidWNr +ZXQtcGlwZWxpbmVzJTQwYXBwbGljYS1nZW5lcmFsLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwK +ICAidW5pdmVyc2VfZG9tYWluIjogImdvb2dsZWFwaXMuY29tIgp9Cg== \ No newline at end of file diff --git a/edera-web/scripts/set-env.sh b/edera-web/scripts/set-env.sh new file mode 100644 index 0000000..f3d2c21 --- /dev/null +++ b/edera-web/scripts/set-env.sh @@ -0,0 +1,6 @@ +export PROJECT_ID=applica-general +export PROJECT_NAME=applica-general +export PROFILE=production +export NAMESPACE=edera +export REVISION=1.0 +export BUCKET=gs://edera-web \ No newline at end of file diff --git a/edera-web/src/App.js b/edera-web/src/App.js new file mode 100644 index 0000000..66f158c --- /dev/null +++ b/edera-web/src/App.js @@ -0,0 +1,79 @@ +import '@applica-software-guru/react-admin/style.css'; + +import * as entities from './entities'; + +import { API_URL, APP_NAME, COPY } from './config'; +import { ActivatePage, ApplicaAdmin, HttpError, RecoverPage, RegisterPage, Resource } from '@applica-software-guru/react-admin'; +import { CustomPage, RFIDDeviceTrackPage, RedirectPage } from 'components/pages'; +import { createAttachmentsParser, createDataProvider } from '@applica-software-guru/crud-client'; + +import { CustomRoutes } from 'ra-core'; +import { Route } from 'react-router-dom'; +import build from './build.json'; +import { createAuthProvider } from '@applica-software-guru/iam-client'; +import dayjs from 'dayjs'; +import duration from 'dayjs/plugin/duration'; +import menu from './menu'; +import relativeTime from 'dayjs/plugin/relativeTime'; +import theme from './theme'; + +dayjs.extend(duration); +dayjs.extend(relativeTime); + +const authProvider = createAuthProvider({ apiUrl: API_URL }); +const dataProvider = createDataProvider({ + apiUrl: API_URL, + getHeaders: () => authProvider.getHeaders(), + getToken: () => authProvider.getToken(), + attachmentsParser: createAttachmentsParser(), + HttpErrorClass: HttpError +}); +const App = () => { + return ( + + + + + + + + + + + + + + + + + + + + + } /> + } /> + + + } /> + } /> + } /> + + + + ); +}; + +export default App; diff --git a/edera-web/src/build.json b/edera-web/src/build.json new file mode 100644 index 0000000..40d58d6 --- /dev/null +++ b/edera-web/src/build.json @@ -0,0 +1 @@ +{ "version": "0.0.0" } diff --git a/edera-web/src/components/index.js b/edera-web/src/components/index.js new file mode 100644 index 0000000..37ad9ca --- /dev/null +++ b/edera-web/src/components/index.js @@ -0,0 +1,6 @@ +export * from './ra-lists'; +export * from './ra-inputs'; +export * from './ra-fields'; +export * from './ra-forms'; +export * from './ra-buttons'; +export * from './ra-details'; diff --git a/edera-web/src/components/layout/FixedMainCard.js b/edera-web/src/components/layout/FixedMainCard.js new file mode 100644 index 0000000..6b6f010 --- /dev/null +++ b/edera-web/src/components/layout/FixedMainCard.js @@ -0,0 +1,17 @@ +import { MainCard } from '@applica-software-guru/react-admin'; + +const FixedMainCard = ({ children, ...props }) => ( + + {children} + +); + +export default FixedMainCard; diff --git a/edera-web/src/components/layout/index.js b/edera-web/src/components/layout/index.js new file mode 100644 index 0000000..68e3daf --- /dev/null +++ b/edera-web/src/components/layout/index.js @@ -0,0 +1 @@ +export { default as FixedMainCard } from './FixedMainCard'; diff --git a/edera-web/src/components/pages/CustomPage.jsx b/edera-web/src/components/pages/CustomPage.jsx new file mode 100644 index 0000000..91c077d --- /dev/null +++ b/edera-web/src/components/pages/CustomPage.jsx @@ -0,0 +1,15 @@ +import { Box, Typography } from '@mui/material'; + +import { useTranslate } from '@applica-software-guru/react-admin'; + +const CustomPage = () => { + const translate = useTranslate(); + return ( + + {translate('ra.custom_pages.welcome.title')} + {translate('ra.custom_pages.welcome.subtitle')} + + ); +}; + +export default CustomPage; diff --git a/edera-web/src/components/pages/RFIDDeviceTrackPage.js b/edera-web/src/components/pages/RFIDDeviceTrackPage.js new file mode 100644 index 0000000..f59ad2c --- /dev/null +++ b/edera-web/src/components/pages/RFIDDeviceTrackPage.js @@ -0,0 +1,14 @@ +import { Stack } from '@mui/material'; +import { useThemeConfig } from '@applica-software-guru/react-admin'; +import RFIDDeviceTrackSection from './charts/sections'; + +const RFIDDeviceTrackPage = () => { + const { spacing } = useThemeConfig(); + return ( + + + + ); +}; + +export default RFIDDeviceTrackPage; diff --git a/edera-web/src/components/pages/RedirectPage.jsx b/edera-web/src/components/pages/RedirectPage.jsx new file mode 100644 index 0000000..f35a6da --- /dev/null +++ b/edera-web/src/components/pages/RedirectPage.jsx @@ -0,0 +1,16 @@ +import { Navigate } from 'react-router'; +import { useEffect } from 'react'; +import { useRedirect } from '../../hooks'; +const RedirectPage = () => { + const { get: getRedirect } = useRedirect(); + const redirect = getRedirect(); + useEffect(() => { + if (redirect) { + document.location.href = redirect; + } + }, [redirect]); + + return ; +}; + +export default RedirectPage; diff --git a/edera-web/src/components/pages/charts/BaseChart.jsx b/edera-web/src/components/pages/charts/BaseChart.jsx new file mode 100644 index 0000000..f9f38fc --- /dev/null +++ b/edera-web/src/components/pages/charts/BaseChart.jsx @@ -0,0 +1,67 @@ +import PropTypes from 'prop-types'; +import React from 'react'; +import ReactApexChart from 'react-apexcharts'; +const BaseChart = ({ series, type = 'bar', sparkline = true, height = 150, options }) => { + const chartOptions = options || { + chart: { + sparkline: { + enabled: sparkline + }, + height: 'auto', + type, + toolbar: { + show: false + } + }, + stroke: { + curve: 'straight' + }, + + dataLabels: { + enabled: false + }, + + plotOptions: { + [type]: { + columnWidth: '80%' + } + }, + xaxis: { + labels: { + show: false + } + }, + yaxis: { + labels: { + show: false + } + }, + + tooltip: { + fixed: { + enabled: false + }, + x: { + show: false + }, + marker: { + show: false + } + } + }; + + return ; +}; + +BaseChart.propTypes = { + type: PropTypes.string.isRequired, + sparkline: PropTypes.bool, + series: PropTypes.arrayOf( + PropTypes.shape({ + name: PropTypes.string, + data: PropTypes.any + }) + ) +}; + +export default BaseChart; diff --git a/edera-web/src/components/pages/charts/BaseChartCard.jsx b/edera-web/src/components/pages/charts/BaseChartCard.jsx new file mode 100644 index 0000000..e865627 --- /dev/null +++ b/edera-web/src/components/pages/charts/BaseChartCard.jsx @@ -0,0 +1,45 @@ +import { Chip, Stack, Typography } from '@mui/material'; +import { FallOutlined, RiseOutlined } from '@ant-design/icons'; + +import { MainCard } from '@applica-software-guru/react-admin'; +import React from 'react'; + +const percentageFormatter = new Intl.NumberFormat('it-IT', { + style: 'percent', + maximumFractionDigits: 2 +}); + +const formatPercentage = (v) => percentageFormatter.format(v / 100); + +const BaseChartCard = ({ title, total, trend, children }) => { + return ( + + + {title} + + + {total} + + {trend && ( + 0 ? 'primary' : 'error'} + variant="combined" + icon={ + trend > 0 ? ( + + ) : ( + + ) + } + label={formatPercentage(trend)} + size="small" + /> + )} + + {children} + + + ); +}; + +export default BaseChartCard; diff --git a/edera-web/src/components/pages/charts/DataMainCard.js b/edera-web/src/components/pages/charts/DataMainCard.js new file mode 100644 index 0000000..794b694 --- /dev/null +++ b/edera-web/src/components/pages/charts/DataMainCard.js @@ -0,0 +1,20 @@ +import { LoadingIndicator, MainCard } from '@applica-software-guru/react-admin'; +import { Stack, Typography } from '@mui/material'; + +const DataMainCard = (props) => { + const { isFetching, title, data, unit } = props; + return ( + + + {title} + + + {isFetching ? : `${data} ${unit}`} + + + + + ); +}; + +export default DataMainCard; diff --git a/edera-web/src/components/pages/charts/EmptyAlert.jsx b/edera-web/src/components/pages/charts/EmptyAlert.jsx new file mode 100644 index 0000000..bc9185d --- /dev/null +++ b/edera-web/src/components/pages/charts/EmptyAlert.jsx @@ -0,0 +1,27 @@ +import { useTranslate } from '@applica-software-guru/react-admin'; +import { Box, Typography } from '@mui/material'; +import WarningIcon from '@mui/icons-material/Warning'; + +const WarningIconBig = () => { + return ; +}; + +const EmptyAlert = ({ visible = true }) => { + const translate = useTranslate(); + if (!visible) return null; + return ( + + + {translate('resources.entities/usage.tabs.chart.no-data-description')} + + ); +}; + +export default EmptyAlert; diff --git a/edera-web/src/components/pages/charts/FilterForm.jsx b/edera-web/src/components/pages/charts/FilterForm.jsx new file mode 100644 index 0000000..2971431 --- /dev/null +++ b/edera-web/src/components/pages/charts/FilterForm.jsx @@ -0,0 +1,45 @@ +import { Form, useThemeConfig } from '@applica-software-guru/react-admin'; +import React, { useEffect, useRef } from 'react'; + +import { Grid } from '@mui/material'; +import PropTypes from 'prop-types'; +import { useWatch } from 'react-hook-form'; + +const FilterFormContent = ({ children, onChange }) => { + const { spacing } = useThemeConfig(); + const values = useWatch(); + const didMount = useRef(false); + useEffect(() => { + if (!didMount.current) { + didMount.current = true; + return; + } + onChange(values); + }, [values, onChange]); + + return ( + + {React.Children.map(children, (child) => ( + + {React.cloneElement(child, { fullWidth: true, display: 'legend' })} + + ))} + + ); +}; + +const FilterForm = ({ children, onChange }) => { + const handleSubmit = (values) => console.log(values); + return ( +
+ + + ); +}; + +FilterForm.propTypes = { + children: PropTypes.node, + onChange: PropTypes.func.isRequired +}; + +export default FilterForm; diff --git a/edera-web/src/components/pages/charts/RFIDDeviceTrackChart.jsx b/edera-web/src/components/pages/charts/RFIDDeviceTrackChart.jsx new file mode 100644 index 0000000..9c0b66f --- /dev/null +++ b/edera-web/src/components/pages/charts/RFIDDeviceTrackChart.jsx @@ -0,0 +1,78 @@ +import React, { useMemo } from 'react'; +import BaseChartCard from './BaseChartCard'; +import { useTranslate } from 'react-admin'; +import HighchartsReact from 'highcharts-react-official'; +import Highcharts from 'highcharts'; + +const RFIDDeviceTrackChart = ({ data }) => { + const translate = useTranslate(); + + const { options, loading } = useMemo(() => { + if (!data || !data.tagsAndGatewaysNames || !data.latestTrackedSupplies) { + return { options: {}, loading: true }; + } + + const { tagsAndGatewaysNames, latestTrackedSupplies } = data; + + const gatewaysSorted = tagsAndGatewaysNames.points[0]?.gateways?.sort((a, b) => a.gatewayName[0].localeCompare(b.gatewayName[0])) || []; + const gateways = gatewaysSorted.reduce((acc, gateway) => ({ ...acc, [gateway.gatewayId]: gateway.gatewayName[0] }), {}); + const gatewayIndexes = Object.values(gateways); + + const tagsSorted = tagsAndGatewaysNames.points[0]?.tags?.sort((a, b) => a.tagName[0].localeCompare(b.tagName[0])) || []; + const tags = tagsSorted.reduce((acc, tag) => ({ ...acc, [tag.tagId]: tag.tagName[0] }), {}); + const tagsIndexes = Object.values(tags); + + const seriesData = (latestTrackedSupplies?.points || []).map((track) => ({ + x: tagsIndexes.indexOf(tags[track.latestRfidTrack.tagId]), + y: gatewayIndexes.indexOf(gateways[track.latestRfidTrack.gatewayId]) + })); + + const options = { + chart: { + type: 'scatter', + zoomType: 'xy' + }, + credits: { + enabled: false + }, + title: { + text: '' + }, + xAxis: { + title: { + text: 'Tag' + }, + categories: tagsIndexes, + labels: { + rotation: -45 + } + }, + yAxis: { + title: { + text: 'Gateway' + }, + categories: gatewayIndexes + }, + series: [ + { + name: 'Movimenti RFID', + color: 'rgb(0, 100, 255)', + data: seriesData + } + ] + }; + + return { options }; + }, [data]); + + if (loading) { + return null; + } + return ( + + + + ); +}; + +export default RFIDDeviceTrackChart; diff --git a/edera-web/src/components/pages/charts/UsageChart.jsx b/edera-web/src/components/pages/charts/UsageChart.jsx new file mode 100644 index 0000000..65cae70 --- /dev/null +++ b/edera-web/src/components/pages/charts/UsageChart.jsx @@ -0,0 +1,75 @@ +import React, { useMemo } from 'react'; +import Chart from 'react-apexcharts'; +import dayjs from 'dayjs'; +import { useTranslate } from '@applica-software-guru/react-admin'; +import _ from 'lodash'; +import { BaseChartCard, EmptyAlert } from '.'; + +const formatExponentialToFixed = (number) => { + const num = Number(number); + if (num === 0) return '0.00'; + return num.toFixed(2); +}; + +const UsageChart = ({ data }) => { + const translate = useTranslate(); + const { hasData, options, series } = useMemo(() => { + const points = _.get(data, 'customUsage.points', []); + const hasData = points.length > 0; + const isHourlyData = points.some((point) => point.totalUsageHours != null); + + const series = [ + { + name: translate(isHourlyData ? 'reporting.stats.usageHours' : 'reporting.stats.usageDays'), + data: + points.length > 0 + ? points.map((point) => { + const timestamp = dayjs( + new Date(point.year, isHourlyData ? point.month - 1 : point.month, isHourlyData ? point.day : null) + ).valueOf(); + const usageValue = point?.total; + const formattedValue = usageValue != null ? formatExponentialToFixed(usageValue) : 0; + return { x: timestamp, y: formattedValue }; + }) + : [{ x: dayjs().valueOf(), y: null }] + } + ]; + + const options = { + chart: { + id: 'basic-line', + height: 'auto' + }, + xaxis: { + type: 'datetime', + labels: { + formatter: (val) => dayjs(val).format(isHourlyData ? 'MMM DD' : 'MMM YYYY') + } + }, + yaxis: { + title: { + text: translate(isHourlyData ? 'reporting.stats.usageHours' : 'reporting.stats.usageDays') + } + }, + tooltip: { + x: { + format: 'MMM DD, YYYY' + } + } + }; + + return { options, series, hasData }; + }, [data, translate]); + + if (!hasData) { + return ; + } + + return ( + + + + ); +}; + +export default UsageChart; diff --git a/edera-web/src/components/pages/charts/UsageMLBreakChart.jsx b/edera-web/src/components/pages/charts/UsageMLBreakChart.jsx new file mode 100644 index 0000000..8e27808 --- /dev/null +++ b/edera-web/src/components/pages/charts/UsageMLBreakChart.jsx @@ -0,0 +1,105 @@ +import { useTranslate } from '@applica-software-guru/react-admin'; +import _ from 'lodash'; +import { useMemo } from 'react'; +import dayjs from 'dayjs'; +import { BaseChartCard, EmptyAlert } from '.'; +import Chart from 'react-apexcharts'; +import { useTheme } from '@mui/material/styles'; + +const formatExponentialToFixed = (number) => { + const num = Number(number); + if (num === 0) return '0.00'; + return num.toFixed(2); +}; + +const UsageMLBreakChart = ({ data }) => { + const translate = useTranslate(); + const theme = useTheme(); + + const { hasData, options, series } = useMemo(() => { + const primaryColor = theme.palette.primary.main; + const secondaryColor = theme.palette.secondary.main; + const dangerColor = theme.palette.error.main; + const points = _.get(data, 'predictions.points', []); + const hasData = points.some((p) => p.prediction === 1); + const series = [ + { + name: translate('reporting.stats.predictions.accumulated'), + data: points + ?.filter((p) => !p.broken) + .map((point) => ({ + x: dayjs(new Date(point.year, point.month - 1, point.day)).valueOf(), + y: formatExponentialToFixed(point?.accumulated) + })) + }, + { + name: translate('reporting.stats.predictions.broken'), + data: points + ?.filter((point) => point?.broken) + .map((point) => ({ + x: dayjs(new Date(point.year, point.month - 1, point.day)).valueOf(), + y: formatExponentialToFixed(point?.accumulated) + })) + } + ]; + if (series[0]?.data.length > 0 && series[1]?.data.length > 0) { + series.push({ + data: [series[0]?.data[series[0]?.data.length - 1], series[1]?.data[0]] + }); + } + const breakpointInHours = _.get(data, 'breakpointInHours', 0); + const options = { + chart: { + id: 'basic-line', + height: 'auto' + }, + xaxis: { + type: 'datetime', + labels: { + formatter: (val) => dayjs(val).format('YYYY-MM-DD') + } + }, + tooltip: { + x: { + format: 'MMM DD, YYYY' + } + }, + stroke: { width: 2 }, + markers: { + size: 8 + }, + annotations: { + yaxis: [ + { + y: breakpointInHours, + borderColor: dangerColor, + label: { + borderColor: dangerColor, + style: { + color: '#fff', + background: dangerColor + }, + text: translate('reporting.stats.breakPredictions.line'), + position: 'center' + } + } + ] + }, + colors: [primaryColor, secondaryColor, dangerColor] + }; + + return { hasData, options, series }; + }, [data, translate, theme]); + + if (!hasData) { + return ; + } + + return ( + + + + ); +}; + +export default UsageMLBreakChart; diff --git a/edera-web/src/components/pages/charts/UsageMLHourlyChart.jsx b/edera-web/src/components/pages/charts/UsageMLHourlyChart.jsx new file mode 100644 index 0000000..4da4114 --- /dev/null +++ b/edera-web/src/components/pages/charts/UsageMLHourlyChart.jsx @@ -0,0 +1,82 @@ +import { useTranslate } from '@applica-software-guru/react-admin'; +import _ from 'lodash'; +import { useMemo } from 'react'; +import dayjs from 'dayjs'; +import { BaseChartCard, EmptyAlert } from '.'; +import Chart from 'react-apexcharts'; +import { useTheme } from '@mui/material/styles'; + +const formatExponentialToFixed = (number) => { + const num = Number(number); + if (num === 0) return '0.00'; + return num.toFixed(2); +}; + +const UsageMLHourlyChart = ({ data }) => { + const translate = useTranslate(); + const theme = useTheme(); + + const { hasData, options, series } = useMemo(() => { + const primaryColor = theme.palette.primary.main; + const dangerColor = theme.palette.error.main; + const points = _.get(data, 'predictions.points', []); + const hasData = points.some((p) => p.prediction === 1); + const series = [ + { + name: translate('reporting.stats.predictions.history'), + data: points + ?.filter((point) => point.prediction === 0) + .map((point) => ({ + x: dayjs(new Date(point.year, point.month - 1, point.day)).valueOf(), + y: formatExponentialToFixed(point?.total) + })) + }, + { + name: translate('reporting.stats.predictions.future'), + data: points + ?.filter((point) => point.prediction === 1) + .map((point) => ({ + x: dayjs(new Date(point.year, point.month - 1, point.day)).valueOf(), + y: formatExponentialToFixed(point?.total) + })) + } + ]; + const options = { + chart: { + id: 'basic-bar', + height: 'auto' + }, + xaxis: { + type: 'datetime', + labels: { + formatter: (val) => dayjs(val).format('YYYY-MM-DD') + } + }, + yaxis: { + title: { + text: translate('reporting.stats.predictions.usageHours') + } + }, + tooltip: { + x: { + format: 'MMM DD, YYYY' + } + }, + colors: [primaryColor, dangerColor] + }; + + return { hasData, options, series }; + }, [data, translate, theme]); + + if (!hasData) { + return ; + } + + return ( + + + + ); +}; + +export default UsageMLHourlyChart; diff --git a/edera-web/src/components/pages/charts/index.js b/edera-web/src/components/pages/charts/index.js new file mode 100644 index 0000000..d7786cb --- /dev/null +++ b/edera-web/src/components/pages/charts/index.js @@ -0,0 +1,9 @@ +export { default as UsageChart } from './UsageChart'; +export { default as BaseChartCard } from './BaseChartCard'; +export { default as DataMainCard } from './DataMainCard'; +export { default as FilterForm } from './FilterForm'; +export { default as RFIDDeviceTrackChart } from './RFIDDeviceTrackChart'; +export { default as UsageMLHourlyChart } from './UsageMLHourlyChart'; +export { default as EmptyAlert } from './EmptyAlert'; +export { default as useReportData } from './useReportData'; +export { default as UsageMLBreakChart } from './UsageMLBreakChart'; diff --git a/edera-web/src/components/pages/charts/sections/RFIDDeviceTrackSection.js b/edera-web/src/components/pages/charts/sections/RFIDDeviceTrackSection.js new file mode 100644 index 0000000..c9e5f64 --- /dev/null +++ b/edera-web/src/components/pages/charts/sections/RFIDDeviceTrackSection.js @@ -0,0 +1,100 @@ +import { MainCard, useThemeConfig, useTranslate } from '@applica-software-guru/react-admin'; +import useReportData from '../useReportData'; +import { Grid, Alert, Typography } from '@mui/material'; +import DataMainCard from '../DataMainCard'; +import { Fragment, useCallback, useState } from 'react'; +import { CustomerOfficeAutocompleteInput } from 'components/ra-inputs'; +import { FilterForm, RFIDDeviceTrackChart } from '..'; + +const formatExponentialToFixed = (number) => { + const num = Number(number); + if (isNaN(num) || num === 0) return '0.00'; + return num.toFixed(2); +}; + +const RFIDDeviceTrackSection = () => { + const { spacing } = useThemeConfig(); + const translate = useTranslate(); + const [filters, setFilters] = useState({}); + const handleChange = useCallback((filters) => setFilters(filters), [setFilters]); + const { data, isFetching } = useReportData({ + officeId: filters.officeId, + type: 'supply-tracks' + }); + + const fakeData = { + latestTrackedSupplies: { + points: [], + count: 0 + }, + + tagsAndGatewaysNames: { + points: [ + { + gateways: [], + _id: null, + tags: [] + } + ], + count: 1 + } + }; + + return ( + + + + + + + + + + + + + + + + + + + + + {!data && ( + + + {translate('ra.position.waiting-for-data')} + + + )} + + + + + + + ); +}; + +export default RFIDDeviceTrackSection; diff --git a/edera-web/src/components/pages/charts/sections/index.js b/edera-web/src/components/pages/charts/sections/index.js new file mode 100644 index 0000000..7910d54 --- /dev/null +++ b/edera-web/src/components/pages/charts/sections/index.js @@ -0,0 +1,3 @@ +import RFIDDeviceTrackSection from './RFIDDeviceTrackSection'; + +export default RFIDDeviceTrackSection; diff --git a/edera-web/src/components/pages/charts/useReportData.js b/edera-web/src/components/pages/charts/useReportData.js new file mode 100644 index 0000000..f4fc1f9 --- /dev/null +++ b/edera-web/src/components/pages/charts/useReportData.js @@ -0,0 +1,25 @@ +import dayjs from 'dayjs'; +import { useDataProvider, useNotify } from '@applica-software-guru/react-admin'; +import { useQuery } from 'react-query'; + +const useReportData = ({ supplyId, from, to, trigger, type, officeId }) => { + const dataProvider = useDataProvider(); + const notify = useNotify(); + const fetchData = () => { + if (from && to && dayjs(from).isAfter(dayjs(to))) { + notify('ra.error.invalid-date-range', 'error'); + return Promise.resolve(null); + } + const params = { + from: from || dayjs().startOf('month').add(1, 'hours').toISOString(), + to: dayjs(to).add(1, 'day').toISOString() || dayjs().endOf('month').add(1, 'hours').toISOString(), + supplyId: supplyId, + officeId: officeId + }; + return dataProvider.post(`report/${type}/execute`, params).then(({ data: { data } }) => data); + }; + const shouldFetch = !!supplyId || !!officeId; + return useQuery(['reportData', supplyId, officeId, trigger], fetchData, { enabled: shouldFetch }); +}; + +export default useReportData; diff --git a/edera-web/src/components/pages/index.jsx b/edera-web/src/components/pages/index.jsx new file mode 100644 index 0000000..33f8b4d --- /dev/null +++ b/edera-web/src/components/pages/index.jsx @@ -0,0 +1,4 @@ +import CustomPage from './CustomPage'; +import RedirectPage from './RedirectPage'; +import RFIDDeviceTrackPage from './RFIDDeviceTrackPage'; +export { CustomPage, RedirectPage, RFIDDeviceTrackPage }; diff --git a/edera-web/src/components/pdf/SupplyPdf.js b/edera-web/src/components/pdf/SupplyPdf.js new file mode 100644 index 0000000..8cb73ce --- /dev/null +++ b/edera-web/src/components/pdf/SupplyPdf.js @@ -0,0 +1,23 @@ +import { Document, Page, StyleSheet, View, Image, Text } from '@react-pdf/renderer'; +import React from 'react'; + +const styles = StyleSheet.create({ + page: { + fontFamily: 'Helvetica' + } +}); + +// Approvvigionamento: {supplyName} + +const SupplyPdf = ({ qrCodeDataUrl, serialNumber }) => ( + + + + + SN: {serialNumber} + + + +); + +export default SupplyPdf; diff --git a/edera-web/src/components/pdf/index.js b/edera-web/src/components/pdf/index.js new file mode 100644 index 0000000..941f9c3 --- /dev/null +++ b/edera-web/src/components/pdf/index.js @@ -0,0 +1,2 @@ +import SupplyPdf from './SupplyPdf'; +export { SupplyPdf }; diff --git a/edera-web/src/components/ra-alerts/SupplyLastTrackAlert.js b/edera-web/src/components/ra-alerts/SupplyLastTrackAlert.js new file mode 100644 index 0000000..59fbc99 --- /dev/null +++ b/edera-web/src/components/ra-alerts/SupplyLastTrackAlert.js @@ -0,0 +1,25 @@ +import { useRecordContext, useTranslate } from '@applica-software-guru/react-admin'; +import { Alert, AlertTitle, Typography } from '@mui/material'; +import dayjs from 'dayjs'; +const SupplyLastTrackAlert = () => { + const record = useRecordContext(); + const translate = useTranslate(); + if (!record?.latestRfidTrack) { + return null; + } + return ( + + + + + ); +}; + +export default SupplyLastTrackAlert; diff --git a/edera-web/src/components/ra-alerts/index.js b/edera-web/src/components/ra-alerts/index.js new file mode 100644 index 0000000..76bfdae --- /dev/null +++ b/edera-web/src/components/ra-alerts/index.js @@ -0,0 +1 @@ +export { default as SupplyLastTrackAlert } from './SupplyLastTrackAlert'; diff --git a/edera-web/src/components/ra-buttons/EntityBackButton.js b/edera-web/src/components/ra-buttons/EntityBackButton.js new file mode 100644 index 0000000..7cd6efd --- /dev/null +++ b/edera-web/src/components/ra-buttons/EntityBackButton.js @@ -0,0 +1,15 @@ +import { Button } from '@mui/material'; +import KeyboardReturnIcon from '@mui/icons-material/KeyboardReturn'; +import { Link } from 'react-router-dom'; +import { useTranslate } from '@applica-software-guru/react-admin'; + +const EntityBackButton = ({ type, id, label }) => { + const translate = useTranslate(); + return ( + + ); +}; + +export default EntityBackButton; diff --git a/edera-web/src/components/ra-buttons/EquipmentBackButton.js b/edera-web/src/components/ra-buttons/EquipmentBackButton.js new file mode 100644 index 0000000..a565575 --- /dev/null +++ b/edera-web/src/components/ra-buttons/EquipmentBackButton.js @@ -0,0 +1,18 @@ +import { Button } from '@applica-software-guru/react-admin'; +import KeyboardReturnIcon from '@mui/icons-material/KeyboardReturn'; +import { Link } from 'react-router-dom'; + +const EquipmentBackButton = ({ equipmentId }) => { + return ( + + + + + {options.map((option) => ( + + {option.name} + + ))} + + + + ); +}; + +PrintDocxButton.propTypes = { + type: PropTypes.string.isRequired +}; + +export default PrintDocxButton; diff --git a/edera-web/src/components/ra-buttons/RegisterMaintenanceButton.js b/edera-web/src/components/ra-buttons/RegisterMaintenanceButton.js new file mode 100644 index 0000000..621df4f --- /dev/null +++ b/edera-web/src/components/ra-buttons/RegisterMaintenanceButton.js @@ -0,0 +1,26 @@ +import { Button } from '@mui/material'; +import { useNavigate } from 'react-router-dom'; +import { useTranslate } from '@applica-software-guru/react-admin'; + +const RegisterMaintenanceButton = (props) => { + const navigate = useNavigate(); + const translate = useTranslate(); + const { record } = props; + const handleClick = () => { + navigate('/entities/maintenance/create', { + state: { + record: { + supplyId: record?.id + } + } + }); + }; + + return ( + + ); +}; + +export default RegisterMaintenanceButton; diff --git a/edera-web/src/components/ra-buttons/RequestAssistanceButton.js b/edera-web/src/components/ra-buttons/RequestAssistanceButton.js new file mode 100644 index 0000000..bc23069 --- /dev/null +++ b/edera-web/src/components/ra-buttons/RequestAssistanceButton.js @@ -0,0 +1,34 @@ +import { useTranslate } from '@applica-software-guru/react-admin'; +import { Button } from '@mui/material'; +import { useNavigate } from 'react-router-dom'; + +const RequestAssistanceButton = (props) => { + const navigate = useNavigate(); + const translate = useTranslate(); + const { record } = props; + const handleClick = () => { + navigate('/entities/activity/create', { + state: { + record: { + supplierId: record?.supplier?.id, + customerId: record?.customer?.id, + supplyId: record?.id, + supply: { + supplierId: record?.supplier?.id + }, + customer: { + id: record?.customer?.id + } + } + } + }); + }; + + return ( + + ); +}; + +export default RequestAssistanceButton; diff --git a/edera-web/src/components/ra-buttons/StartAndStopUsageButton.js b/edera-web/src/components/ra-buttons/StartAndStopUsageButton.js new file mode 100644 index 0000000..70e057a --- /dev/null +++ b/edera-web/src/components/ra-buttons/StartAndStopUsageButton.js @@ -0,0 +1,50 @@ +import React, { useState } from 'react'; +import { useDataProvider, useNotify, useTranslate } from '@applica-software-guru/react-admin'; +import PlayCircleFilledIcon from '@mui/icons-material/PlayCircleFilled'; +import StopCircleIcon from '@mui/icons-material/StopCircle'; +import { Button } from '@mui/material'; +import { get } from 'lodash'; + +const StartAndStopUsageButton = ({ record, setStatus, setColor }) => { + const dataProvider = useDataProvider(); + const translate = useTranslate(); + const notify = useNotify(); + const [status, setUsageStatus] = useState(get(record, 'usageStatus', 'STOPPED') || 'STOPPED'); + + const handleStart = () => { + dataProvider + .get(`supply/supply-start/${record?.id}`) + .then(() => { + setUsageStatus('RUNNING'); + setColor('green'); + setStatus('RUNNING'); + notify('resources.entities.supply.notifications.started', { type: 'info' }); + }) + .catch(() => { + notify('ra.notification.http_error', { type: 'error' }); + }); + }; + + const handleStop = async () => { + dataProvider + .get(`supply/supply-stop/${record?.id}`) + .then(() => { + setUsageStatus('STOPPED'); + setColor('red'); + setStatus('STOPPED'); + notify('resources.entities.supply.notifications.stopped', { type: 'info' }); + }) + .catch(() => notify('ra.notification.http_error', { type: 'error' })); + }; + return status === 'STOPPED' || status === null ? ( + + ) : ( + + ); +}; + +export default StartAndStopUsageButton; diff --git a/edera-web/src/components/ra-buttons/SupplierBackButton.js b/edera-web/src/components/ra-buttons/SupplierBackButton.js new file mode 100644 index 0000000..e62211d --- /dev/null +++ b/edera-web/src/components/ra-buttons/SupplierBackButton.js @@ -0,0 +1,18 @@ +import { Button } from '@applica-software-guru/react-admin'; +import KeyboardReturnIcon from '@mui/icons-material/KeyboardReturn'; +import { Link } from 'react-router-dom'; + +const SupplierBackButton = ({ supplierId, tab }) => { + return ( + + + + + {translate('reporting.stats.loading')} + + + {!isFetching && ( + + + + )} + + + {!isFetching && ( + + + + + + + + + + + + + + + + + )} + + ); +}; + +export default UsageStatisticsTab; diff --git a/edera-web/src/components/ra-details/supply/index.js b/edera-web/src/components/ra-details/supply/index.js new file mode 100644 index 0000000..970bb1d --- /dev/null +++ b/edera-web/src/components/ra-details/supply/index.js @@ -0,0 +1,10 @@ +import UsageStatisticsTab from './UsageStatisticsTab'; +import DetailsTab from './DetailsTab'; +import SupplyTab from './SupplyTab'; +import ProtocolTab from './ProtocolTab'; +import EquipmentAttachmentTab from './EquipmentAttachmentTab'; +import ActivityTab from './ActivityTab'; +import UsageRecordTab from './UsageRecordTab'; +import RFIDDeviceTab from './RFIDDeviceTab'; + +export { UsageStatisticsTab, DetailsTab, SupplyTab, ProtocolTab, EquipmentAttachmentTab, ActivityTab, UsageRecordTab, RFIDDeviceTab }; diff --git a/edera-web/src/components/ra-fields/ActivityStatusField.js b/edera-web/src/components/ra-fields/ActivityStatusField.js new file mode 100644 index 0000000..8e44388 --- /dev/null +++ b/edera-web/src/components/ra-fields/ActivityStatusField.js @@ -0,0 +1,18 @@ +import { useRecordContext, useTranslate } from '@applica-software-guru/react-admin'; + +import { Chip } from '@mui/material'; +import { get } from 'lodash'; + +const STATUS_COLOR = { + OPEN: 'info', + CLOSED: 'error' +}; +const ActivityStatusField = () => { + const translate = useTranslate(); + const record = useRecordContext(); + const status = get(record, 'status', 'new') || 'new'; + const color = get(STATUS_COLOR, status, 'info'); + return ; +}; + +export default ActivityStatusField; diff --git a/edera-web/src/components/ra-fields/AuditLogMessageField.js b/edera-web/src/components/ra-fields/AuditLogMessageField.js new file mode 100644 index 0000000..507b46c --- /dev/null +++ b/edera-web/src/components/ra-fields/AuditLogMessageField.js @@ -0,0 +1,38 @@ +import { useRecordContext, useTranslate } from '@applica-software-guru/react-admin'; + +import PropTypes from 'prop-types'; +import { Typography } from '@mui/material'; +import { get } from 'lodash'; + +const TRANSATABLE_FIELDS = ['entity']; +const AuditLogMessageField = ({ source }) => { + const translate = useTranslate(); + const record = useRecordContext(); + const args = get(record, `${source}.args`); + const message = get(record, `${source}.message`) || 'ra.audit_log.default_message'; + const messageArgs = + args && args !== null + ? Object.keys(args).reduce( + (acc, key) => ({ + ...acc, + [key]: TRANSATABLE_FIELDS.indexOf(key) !== -1 ? translate(get(args, key, ''), { smart_count: 1 }) : get(args, key, '') + }), + {} + ) + : { + ...record, + method: record?.method || 'unknown' + }; + + return ( + + {translate(message, messageArgs)} + + ); +}; + +AuditLogMessageField.propTypes = { + source: PropTypes.string.isRequired +}; + +export default AuditLogMessageField; diff --git a/edera-web/src/components/ra-fields/CityField.js b/edera-web/src/components/ra-fields/CityField.js new file mode 100644 index 0000000..deb6209 --- /dev/null +++ b/edera-web/src/components/ra-fields/CityField.js @@ -0,0 +1,9 @@ +import { ReferenceField, TextField } from '@applica-software-guru/react-admin'; + +const CityField = (props) => ( + + + +); + +export default CityField; diff --git a/edera-web/src/components/ra-fields/DirtyFormPrintAlertField.js b/edera-web/src/components/ra-fields/DirtyFormPrintAlertField.js new file mode 100644 index 0000000..38a3ad9 --- /dev/null +++ b/edera-web/src/components/ra-fields/DirtyFormPrintAlertField.js @@ -0,0 +1,20 @@ +import { useFormState } from 'react-hook-form'; +import { Collapse, Alert, AlertTitle } from '@mui/material'; +import { useTranslate } from '@applica-software-guru/react-admin'; + +const DirtyFormPrintAlertField = () => { + const { dirtyFields } = useFormState(); + const isDirty = Object.keys(dirtyFields).length > 0; + const translate = useTranslate(); + + return ( + + + {translate('ra.form.docx_print.dirty')} + {translate('ra.form.docx_print.dirty_message')} + + + ); +}; + +export default DirtyFormPrintAlertField; diff --git a/edera-web/src/components/ra-fields/MoneyField.js b/edera-web/src/components/ra-fields/MoneyField.js new file mode 100644 index 0000000..07e61e5 --- /dev/null +++ b/edera-web/src/components/ra-fields/MoneyField.js @@ -0,0 +1,15 @@ +import { FunctionField } from '@applica-software-guru/react-admin'; +import { get } from 'lodash'; +const formatMoney = (record, source) => { + const value = get(record, source); + if (typeof value === 'number') { + return `€ ${value.toFixed(2).replace('.', ',')}`; + } + return ''; +}; + +const MoneyField = (props) => { + return formatMoney(record, props.source)} />; +}; + +export default MoneyField; diff --git a/edera-web/src/components/ra-fields/RFIDDeviceTrackManyField.js b/edera-web/src/components/ra-fields/RFIDDeviceTrackManyField.js new file mode 100644 index 0000000..c3deaed --- /dev/null +++ b/edera-web/src/components/ra-fields/RFIDDeviceTrackManyField.js @@ -0,0 +1,27 @@ +import { Datagrid, DateField, ReferenceField, ReferenceManyInput, TextField } from '@applica-software-guru/react-admin'; +import { CustomerAreaAutocompleteInput, RFIDDeviceAutocomplete } from 'components/ra-inputs'; + +const RFIDDeviceTrackManyField = () => { + return ( + , + + ]} + sort={{ field: 'ts', order: 'DESC' }} + > + + + + + + + + + + ); +}; + +export default RFIDDeviceTrackManyField; diff --git a/edera-web/src/components/ra-fields/SupplyStatusField.js b/edera-web/src/components/ra-fields/SupplyStatusField.js new file mode 100644 index 0000000..6f40028 --- /dev/null +++ b/edera-web/src/components/ra-fields/SupplyStatusField.js @@ -0,0 +1,18 @@ +import { useRecordContext, useTranslate } from '@applica-software-guru/react-admin'; + +import { Chip } from '@mui/material'; +import { get } from 'lodash'; + +const STATUS_COLOR = { + RUNNING: 'success', + STOPPED: 'secondary' +}; +const SupplyStatusField = () => { + const record = useRecordContext(); + const translate = useTranslate(); + const status = get(record, 'usageStatus', 'STOPPED') || 'STOPPED'; + const color = get(STATUS_COLOR, status, 'secondary'); + return ; +}; + +export default SupplyStatusField; diff --git a/edera-web/src/components/ra-fields/UserPictureField.js b/edera-web/src/components/ra-fields/UserPictureField.js new file mode 100644 index 0000000..c8008b7 --- /dev/null +++ b/edera-web/src/components/ra-fields/UserPictureField.js @@ -0,0 +1,20 @@ +import { CoverField, useRecordContext } from '@applica-software-guru/react-admin'; + +import PropTypes from 'prop-types'; +import React from 'react'; +import { get } from 'lodash'; + +const UserPictureField = ({ source, ...props }) => { + const record = useRecordContext(); + const image = get(record, source); + if (!image) { + return null; + } + return ; +}; + +UserPictureField.propTypes = { + source: PropTypes.string.isRequired +}; + +export default UserPictureField; diff --git a/edera-web/src/components/ra-fields/index.js b/edera-web/src/components/ra-fields/index.js new file mode 100644 index 0000000..9ed1a72 --- /dev/null +++ b/edera-web/src/components/ra-fields/index.js @@ -0,0 +1,8 @@ +export { default as AuditLogMessageField } from './AuditLogMessageField'; +export { default as UserPictureField } from './UserPictureField'; +export { default as CityField } from './CityField'; +export { default as MoneyField } from './MoneyField'; +export { default as ActivityStatusField } from './ActivityStatusField'; +export { default as SupplyStatusField } from './SupplyStatusField'; +export { default as RFIDDeviceTrackManyField } from './RFIDDeviceTrackManyField'; +export { default as DirtyFormPrintAlertField } from './DirtyFormPrintAlertField'; diff --git a/edera-web/src/components/ra-forms/ActivityForm.js b/edera-web/src/components/ra-forms/ActivityForm.js new file mode 100644 index 0000000..caad150 --- /dev/null +++ b/edera-web/src/components/ra-forms/ActivityForm.js @@ -0,0 +1,163 @@ +import { + ActionsMenu, + CardForm, + DateInput, + DeleteWithConfirmButton, + ReadonlyField, + SaveButton, + SelectInput, + SmartTextInput, + TextInput, + Toolbar, + required, + useDataProvider, + useNotify, + usePermissions, + useRecordContext, + useResourceTitle, + useThemeConfig +} from '@applica-software-guru/react-admin'; +import { + ActivityTypeAutocompleteInput, + CustomerAutocompleteInput, + MaintenanceManyInput, + SupplierAutocompleteInput, + SupplyActivityAutocompleteInput +} from 'components/ra-inputs'; +import { useLocation } from 'react-router-dom'; +import { Grid } from '@mui/material'; +import { EntityBackButton, PrintDocxButton } from 'components/ra-buttons'; +import queryString from 'query-string'; +import { useEffect, useState } from 'react'; + +const ActivityForm = ({ activityStatus }) => { + const { spacing } = useThemeConfig(); + const record = useRecordContext(); + const dataProvider = useDataProvider(); + const notify = useNotify(); + const currentDate = new Date().toISOString().slice(0, 10); + const title = useResourceTitle(); + const { permissions, isLoading } = usePermissions(); + const canEdit = !isLoading && permissions.includes('activity:new'); + const canDelete = !isLoading && permissions.includes('activity:delete'); + const location = useLocation(); + const queryParams = queryString.parse(location.search); + const activityId = queryParams['activity-id']; + const activityTypeIdUrl = queryParams['activity-type-id']; + const [activity, setActivity] = useState(null); + + useEffect(() => { + if (!activityId) return; + + const fetchDetails = async () => { + try { + const { data } = await dataProvider.getOne('entities/activity', { id: activityId }); + setActivity(data); + } catch (error) { + notify('ra.notification.http_error', 'error', {}); + } + }; + + fetchDetails(); + }, [activityId, dataProvider, notify]); + + return ( + + + + + ) + } + > + + {record?.id && ( + + + + )} + {!isLoading && permissions.includes('supplier:list') && ( + + + + )} + {!isLoading && permissions.includes('customer:list') && ( + + + + )} + {!isLoading && permissions.includes('supply:list') && ( + + + + )} + {!isLoading && permissions.includes('activity-type:list') && ( + + + + )} + + + + + + + + + + + + + + + {canEdit && } + + {record?.id && } + + + {record?.id && ( + + + + )} + + ); +}; + +export default ActivityForm; diff --git a/edera-web/src/components/ra-forms/ActivityTypeForm.js b/edera-web/src/components/ra-forms/ActivityTypeForm.js new file mode 100644 index 0000000..dee955d --- /dev/null +++ b/edera-web/src/components/ra-forms/ActivityTypeForm.js @@ -0,0 +1,21 @@ +import { AttachmentInput, SimpleForm, TextInput, required, useThemeConfig } from '@applica-software-guru/react-admin'; + +import { Grid } from '@mui/material'; + +const ActivityTypeForm = () => { + const { spacing } = useThemeConfig(); + return ( + + + + + + + + + + + ); +}; + +export default ActivityTypeForm; diff --git a/edera-web/src/components/ra-forms/CustomerAreaForm.js b/edera-web/src/components/ra-forms/CustomerAreaForm.js new file mode 100644 index 0000000..6106e68 --- /dev/null +++ b/edera-web/src/components/ra-forms/CustomerAreaForm.js @@ -0,0 +1,29 @@ +import { SimpleForm, SmartTextInput, TextInput, required, useRecordContext, useThemeConfig } from '@applica-software-guru/react-admin'; + +import { CustomerOfficeAutocompleteInput, RFIDDeviceAutocomplete } from '../ra-inputs'; +import { Grid } from '@mui/material'; + +const CustomerAreaForm = () => { + const { spacing } = useThemeConfig(); + const record = useRecordContext(); + return ( + + + + + + + + + + + + + + + + + ); +}; + +export default CustomerAreaForm; diff --git a/edera-web/src/components/ra-forms/CustomerCreateForm.js b/edera-web/src/components/ra-forms/CustomerCreateForm.js new file mode 100644 index 0000000..bf72951 --- /dev/null +++ b/edera-web/src/components/ra-forms/CustomerCreateForm.js @@ -0,0 +1,25 @@ +import { BooleanInput, SimpleForm, TextInput, useThemeConfig } from '@applica-software-guru/react-admin'; + +import { Grid } from '@mui/material'; + +const CustomerCreateForm = (props) => { + const { spacing } = useThemeConfig(); + + return ( + + + + + + + + + + + + + + ); +}; + +export default CustomerCreateForm; diff --git a/edera-web/src/components/ra-forms/CustomerEditForm.js b/edera-web/src/components/ra-forms/CustomerEditForm.js new file mode 100644 index 0000000..688182a --- /dev/null +++ b/edera-web/src/components/ra-forms/CustomerEditForm.js @@ -0,0 +1,82 @@ +import { + ActionsMenu, + BooleanInput, + DeleteWithConfirmButton, + LongForm, + MainCard, + SaveButton, + TextInput, + Toolbar, + required, + useRecordContext, + useResourceTitle, + useThemeConfig, + useTranslate +} from '@applica-software-guru/react-admin'; +import { CustomerAreaManyInput, CustomerOfficeManyInput, CustomerReferentManyInput } from '../ra-inputs'; +import { HomeOutlined, InfoCircleOutlined, ShareAltOutlined, UserAddOutlined } from '@ant-design/icons'; + +import { FixedMainCard } from '../layout'; +import { Grid } from '@mui/material'; + +const CustomerEditForm = () => { + const { spacing } = useThemeConfig(); + const translate = useTranslate(); + const record = useRecordContext(); + const title = useResourceTitle(); + return ( + + } + label="resources.entities/customer.tabs.details" + title={title} + secondary={ + + + + } + > + + + + + + + + + + + + + + + + + + {record?.id && ( + } label="resources.entities/customer.tabs.offices"> + + + + + )} + {record?.id && ( + } label="resources.entities/customer.tabs.areas"> + + + + + )} + {record?.id && ( + } label="resources.entities/customer.tabs.referents"> + + + + + )} + + ); +}; + +export default CustomerEditForm; diff --git a/edera-web/src/components/ra-forms/CustomerOfficeForm.js b/edera-web/src/components/ra-forms/CustomerOfficeForm.js new file mode 100644 index 0000000..5722c51 --- /dev/null +++ b/edera-web/src/components/ra-forms/CustomerOfficeForm.js @@ -0,0 +1,46 @@ +import { BooleanInput, SimpleForm, TextInput, email, required, useThemeConfig } from '@applica-software-guru/react-admin'; +import { CityAutocompleteInput, NationAutocompleteInput, ProvinceAutocompleteInput, RegionAutocompleteInput } from '../ra-inputs'; + +import { Grid } from '@mui/material'; +import PropTypes from 'prop-types'; + +const CustomerOfficeForm = ({ modal, ...props }) => { + const { spacing } = useThemeConfig(); + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +CustomerOfficeForm.propTypes = { + modal: PropTypes.bool +}; + +CustomerOfficeForm.defaultProps = { + modal: true +}; + +export default CustomerOfficeForm; diff --git a/edera-web/src/components/ra-forms/CustomerReferentForm.js b/edera-web/src/components/ra-forms/CustomerReferentForm.js new file mode 100644 index 0000000..5b474ef --- /dev/null +++ b/edera-web/src/components/ra-forms/CustomerReferentForm.js @@ -0,0 +1,44 @@ +import { SimpleForm, TextInput, email, required, useRecordContext, useThemeConfig } from '@applica-software-guru/react-admin'; + +import { CustomerOfficeAutocompleteInput } from '../ra-inputs'; +import { Grid } from '@mui/material'; +import PropTypes from 'prop-types'; + +const CustomerReferentForm = ({ modal, ...props }) => { + const { spacing } = useThemeConfig(); + const record = useRecordContext(); + return ( + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +CustomerReferentForm.propTypes = { + modal: PropTypes.bool +}; + +CustomerReferentForm.defaultProps = { + modal: true +}; + +export default CustomerReferentForm; diff --git a/edera-web/src/components/ra-forms/DeviceForm.js b/edera-web/src/components/ra-forms/DeviceForm.js new file mode 100644 index 0000000..0488479 --- /dev/null +++ b/edera-web/src/components/ra-forms/DeviceForm.js @@ -0,0 +1,29 @@ +import { ReadonlyField, SimpleForm, TextInput, required, useRecordContext, useThemeConfig } from '@applica-software-guru/react-admin'; + +import { Grid } from '@mui/material'; + +const DeviceForm = () => { + const { spacing } = useThemeConfig(); + const record = useRecordContext(); + return ( + + + {record?.id && ( + + + + )} + + + + {record?.id && ( + + + + )} + + + ); +}; + +export default DeviceForm; diff --git a/edera-web/src/components/ra-forms/DocxTemplateForm.js b/edera-web/src/components/ra-forms/DocxTemplateForm.js new file mode 100644 index 0000000..eac8d20 --- /dev/null +++ b/edera-web/src/components/ra-forms/DocxTemplateForm.js @@ -0,0 +1,47 @@ +import { AttachmentInput, SimpleForm, TextInput, required, useThemeConfig, useTranslate } from '@applica-software-guru/react-admin'; +import { useWatch } from 'react-hook-form'; +import { Grid, Typography, Collapse } from '@mui/material'; +import { DocxTemplateTypeSelectInput } from '../ra-inputs'; +import { API_URL } from '../../config'; + +const TypeHelperLink = () => { + const type = useWatch({ name: 'type' }); + const translate = useTranslate(); + + return ( + + + + ); +}; + +const DocxTemplateForm = () => { + const { spacing } = useThemeConfig(); + return ( + + + + + + + + + + + + + + + ); +}; + +export default DocxTemplateForm; diff --git a/edera-web/src/components/ra-forms/EquipmentAttachmentForm.js b/edera-web/src/components/ra-forms/EquipmentAttachmentForm.js new file mode 100644 index 0000000..3d42474 --- /dev/null +++ b/edera-web/src/components/ra-forms/EquipmentAttachmentForm.js @@ -0,0 +1,21 @@ +import { AttachmentInput, SimpleForm, TextInput, required, useThemeConfig } from '@applica-software-guru/react-admin'; + +import { Grid } from '@mui/material'; + +const EquipmentAttachmentForm = (props) => { + const { spacing } = useThemeConfig(); + return ( + + + + + + + + + + + ); +}; + +export default EquipmentAttachmentForm; diff --git a/edera-web/src/components/ra-forms/EquipmentCreateForm.js b/edera-web/src/components/ra-forms/EquipmentCreateForm.js new file mode 100644 index 0000000..eeff47b --- /dev/null +++ b/edera-web/src/components/ra-forms/EquipmentCreateForm.js @@ -0,0 +1,19 @@ +import { SimpleForm, required, useThemeConfig } from '@applica-software-guru/react-admin'; + +import { EquipmentTypeAutocompleteInput } from 'components/ra-inputs'; +import { Grid } from '@mui/material'; + +const EquipmentCreateForm = (props) => { + const { spacing } = useThemeConfig(); + return ( + + + + + + + + ); +}; + +export default EquipmentCreateForm; diff --git a/edera-web/src/components/ra-forms/EquipmentCreateInDialogForm.js b/edera-web/src/components/ra-forms/EquipmentCreateInDialogForm.js new file mode 100644 index 0000000..b23e9de --- /dev/null +++ b/edera-web/src/components/ra-forms/EquipmentCreateInDialogForm.js @@ -0,0 +1,22 @@ +import { SimpleForm, required, useThemeConfig } from '@applica-software-guru/react-admin'; + +import { EquipmentTypeAutocompleteInput, SupplierAutocompleteInput } from 'components/ra-inputs'; +import { Grid } from '@mui/material'; + +const EquipmentCreateInDialogForm = (props) => { + const { spacing } = useThemeConfig(); + return ( + + + + + + + + + + + ); +}; + +export default EquipmentCreateInDialogForm; diff --git a/edera-web/src/components/ra-forms/EquipmentEditForm.js b/edera-web/src/components/ra-forms/EquipmentEditForm.js new file mode 100644 index 0000000..3b8992c --- /dev/null +++ b/edera-web/src/components/ra-forms/EquipmentEditForm.js @@ -0,0 +1,65 @@ +import { + ActionsMenu, + CardForm, + DeleteWithConfirmButton, + ReadonlyField, + Toolbar, + usePermissions, + useRecordContext, + useResourceTitle, + useThemeConfig +} from '@applica-software-guru/react-admin'; + +import { Grid } from '@mui/material'; +import { SupplierBackButton } from 'components/ra-buttons'; +import { EquipmentAttachmentManyInput, SupplyManyInput } from 'components/ra-inputs'; + +const EquipmentEditForm = () => { + const { spacing } = useThemeConfig(); + const record = useRecordContext(); + const title = useResourceTitle(); + const { permissions, isLoading } = usePermissions(); + const canEdit = !isLoading && permissions ? permissions['equipment:edit'] : false; + return ( + + + + + ) : ( + <> + ) + } + > + + + + + + {!isLoading && permissions.includes('supplier:edit') && ( + + + + )} + + + + + + + {!isLoading && permissions.includes('supply:new') && ( + + + + + + )} + + ); +}; + +export default EquipmentEditForm; diff --git a/edera-web/src/components/ra-forms/EquipmentTypeAttachmentForm.js b/edera-web/src/components/ra-forms/EquipmentTypeAttachmentForm.js new file mode 100644 index 0000000..db1f139 --- /dev/null +++ b/edera-web/src/components/ra-forms/EquipmentTypeAttachmentForm.js @@ -0,0 +1,21 @@ +import { AttachmentInput, SimpleForm, TextInput, required, useThemeConfig } from '@applica-software-guru/react-admin'; + +import { Grid } from '@mui/material'; + +const EquipmentTypeAttachmentForm = (props) => { + const { spacing } = useThemeConfig(); + return ( + + + + + + + + + + + ); +}; + +export default EquipmentTypeAttachmentForm; diff --git a/edera-web/src/components/ra-forms/EquipmentTypeCreateForm.js b/edera-web/src/components/ra-forms/EquipmentTypeCreateForm.js new file mode 100644 index 0000000..c06c0e2 --- /dev/null +++ b/edera-web/src/components/ra-forms/EquipmentTypeCreateForm.js @@ -0,0 +1,23 @@ +import { BooleanInput, SimpleForm, TextInput, required, useResourceTitle, useThemeConfig } from '@applica-software-guru/react-admin'; + +import { Grid } from '@mui/material'; + +const EquipmentTypeCreateForm = (props) => { + const { spacing } = useThemeConfig(); + const title = useResourceTitle(); + + return ( + + + + + + + + + + + ); +}; + +export default EquipmentTypeCreateForm; diff --git a/edera-web/src/components/ra-forms/EquipmentTypeEditForm.js b/edera-web/src/components/ra-forms/EquipmentTypeEditForm.js new file mode 100644 index 0000000..c0d7a1b --- /dev/null +++ b/edera-web/src/components/ra-forms/EquipmentTypeEditForm.js @@ -0,0 +1,99 @@ +import { + ActionsMenu, + BooleanInput, + CardForm, + DeleteWithConfirmButton, + MainCard, + NumberInput, + SaveButton, + TextInput, + Toolbar, + required, + useRecordContext, + useResourceTitle, + useThemeConfig, + useTranslate +} from '@applica-software-guru/react-admin'; + +import NavigateNextIcon from '@mui/icons-material/NavigateNext'; +import { Link } from 'react-router-dom'; +import { Typography } from '@mui/material'; +import Breadcrumbs from '@mui/material/Breadcrumbs'; +import { Grid } from '@mui/material'; +import { EntityBackButton } from 'components/ra-buttons'; +import { EquipmentTypeAttachmentManyInput, EquipmentTypeManyInput } from 'components/ra-inputs'; + +const EquipmentTypeBreadcrumbs = ({ record }) => { + const parents = record?.parents; + if (!Array.isArray(parents)) { + return null; + } + + const reversedParents = [...parents].reverse(); + + return ( + }> + {reversedParents.map(({ id, name }, index) => ( + + {name} + + ))} + {record?.name} + + ); +}; + +const EquipmentTypeEditForm = () => { + const { spacing } = useThemeConfig(); + const record = useRecordContext(); + const title = useResourceTitle(); + const translate = useTranslate(); + + return ( + + } + secondary={ + + + + } + > + + + + + + + + + + + + + + + {record?.parentId && } + + + + + + + + + + + + + + ); +}; + +export default EquipmentTypeEditForm; diff --git a/edera-web/src/components/ra-forms/I18nMessageForm.js b/edera-web/src/components/ra-forms/I18nMessageForm.js new file mode 100644 index 0000000..691e4c6 --- /dev/null +++ b/edera-web/src/components/ra-forms/I18nMessageForm.js @@ -0,0 +1,24 @@ +import { SimpleForm, SmartTextInput, TextInput, useThemeConfig } from '@applica-software-guru/react-admin'; + +import { Grid } from '@mui/material'; +import { LangSelectInput } from '../ra-inputs'; + +const I18nMessageForm = () => { + const { spacing } = useThemeConfig(); + return ( + + + + + + + + + + + + + + ); +}; +export default I18nMessageForm; diff --git a/edera-web/src/components/ra-forms/MaintenanceCreateForm.js b/edera-web/src/components/ra-forms/MaintenanceCreateForm.js new file mode 100644 index 0000000..0620142 --- /dev/null +++ b/edera-web/src/components/ra-forms/MaintenanceCreateForm.js @@ -0,0 +1,43 @@ +import { + AttachmentInput, + DateInput, + SimpleForm, + SmartTextInput, + TextInput, + required, + useThemeConfig +} from '@applica-software-guru/react-admin'; + +import { Grid } from '@mui/material'; +import { ActivitySelectInput, InterventionArrayInput } from 'components/ra-inputs'; + +const MaintenanceCreateForm = () => { + const { spacing } = useThemeConfig(); + return ( + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default MaintenanceCreateForm; diff --git a/edera-web/src/components/ra-forms/MaintenanceEditForm.js b/edera-web/src/components/ra-forms/MaintenanceEditForm.js new file mode 100644 index 0000000..561e82d --- /dev/null +++ b/edera-web/src/components/ra-forms/MaintenanceEditForm.js @@ -0,0 +1,85 @@ +import { ActivitySelectInput, InterventionArrayInput } from 'components/ra-inputs'; +import { + ActionsMenu, + AttachmentInput, + CardForm, + DateInput, + DeleteWithConfirmButton, + ReadonlyField, + SaveButton, + SmartTextInput, + TextInput, + Toolbar, + required, + usePermissions, + useRecordContext, + useResourceTitle, + useThemeConfig +} from '@applica-software-guru/react-admin'; + +import { Grid } from '@mui/material'; +import { EntityBackButton, PrintDocxButton } from 'components/ra-buttons'; +import { DirtyFormPrintAlertField } from '../ra-fields'; + +const MaintenanceEditForm = () => { + const { spacing } = useThemeConfig(); + const { permissions, isLoading } = usePermissions(); + const canDelete = !isLoading && permissions.includes('maintenance:delete'); + const record = useRecordContext(); + const title = useResourceTitle(); + return ( + + + + + ) + } + > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default MaintenanceEditForm; diff --git a/edera-web/src/components/ra-forms/PriceListForm.js b/edera-web/src/components/ra-forms/PriceListForm.js new file mode 100644 index 0000000..0f4c856 --- /dev/null +++ b/edera-web/src/components/ra-forms/PriceListForm.js @@ -0,0 +1,65 @@ +import { + ActionsMenu, + CardForm, + DateInput, + DeleteWithConfirmButton, + SaveButton, + TextInput, + Toolbar, + required, + useRecordContext, + useResourceTitle, + useThemeConfig +} from '@applica-software-guru/react-admin'; + +import { Grid } from '@mui/material'; +import { PriceListBackButton } from 'components/ra-buttons'; +import { PriceListItemManyInput } from 'components/ra-inputs'; + +const PriceListForm = ({ toolbar }) => { + const { spacing } = useThemeConfig(); + const record = useRecordContext(); + const title = useResourceTitle(); + + return ( + + + + + ) + } + > + + + + + + + + + + + + {!toolbar && ( + + + {record?.id && } + + )} + + + {record?.id && ( + + + + )} + + ); +}; + +export default PriceListForm; diff --git a/edera-web/src/components/ra-forms/PriceListItemEditForm.js b/edera-web/src/components/ra-forms/PriceListItemEditForm.js new file mode 100644 index 0000000..00f2080 --- /dev/null +++ b/edera-web/src/components/ra-forms/PriceListItemEditForm.js @@ -0,0 +1,22 @@ +import { SimpleForm, TextInput, required, useThemeConfig } from '@applica-software-guru/react-admin'; + +import { Grid } from '@mui/material'; +import { EquipmentSelectInput } from 'components/ra-inputs'; + +const PriceListItemEditForm = () => { + const { spacing } = useThemeConfig(); + return ( + + + + + + + + + + + ); +}; + +export default PriceListItemEditForm; diff --git a/edera-web/src/components/ra-forms/PriceListItemForm.js b/edera-web/src/components/ra-forms/PriceListItemForm.js new file mode 100644 index 0000000..776ea28 --- /dev/null +++ b/edera-web/src/components/ra-forms/PriceListItemForm.js @@ -0,0 +1,22 @@ +import { EquipmentAutocompleteInput, MoneyInput } from 'components/ra-inputs'; +import { SimpleForm, required, useThemeConfig } from '@applica-software-guru/react-admin'; + +import { Grid } from '@mui/material'; + +const PriceListItemForm = () => { + const { spacing } = useThemeConfig(); + return ( + + + + + + + + + + + ); +}; + +export default PriceListItemForm; diff --git a/edera-web/src/components/ra-forms/ProtocolAttachmentForm.js b/edera-web/src/components/ra-forms/ProtocolAttachmentForm.js new file mode 100644 index 0000000..d0731bb --- /dev/null +++ b/edera-web/src/components/ra-forms/ProtocolAttachmentForm.js @@ -0,0 +1,21 @@ +import { AttachmentInput, SimpleForm, TextInput, required, useThemeConfig } from '@applica-software-guru/react-admin'; + +import { Grid } from '@mui/material'; + +const ProtocolAttachmentForm = (props) => { + const { spacing } = useThemeConfig(); + return ( + + + + + + + + + + + ); +}; + +export default ProtocolAttachmentForm; diff --git a/edera-web/src/components/ra-forms/ProtocolDialogForm.js b/edera-web/src/components/ra-forms/ProtocolDialogForm.js new file mode 100644 index 0000000..27bb910 --- /dev/null +++ b/edera-web/src/components/ra-forms/ProtocolDialogForm.js @@ -0,0 +1,44 @@ +import { + DateInput, + SimpleForm, + SmartTextInput, + TextInput, + required, + usePermissions, + useResourceTitle, + useThemeConfig +} from '@applica-software-guru/react-admin'; +import { CustomerAutocompleteInput } from 'components/ra-inputs'; +import { Grid } from '@mui/material'; + +const ProtocolDialogForm = () => { + const { spacing } = useThemeConfig(); + const title = useResourceTitle(); + const { permissions, isLoading } = usePermissions(); + const isEditable = !isLoading && permissions.includes('protocol:new'); + return ( + + + {!isLoading && permissions.includes('customer:list') && ( + + + + )} + + + + + + + + + + + + + + + ); +}; + +export default ProtocolDialogForm; diff --git a/edera-web/src/components/ra-forms/ProtocolForm.js b/edera-web/src/components/ra-forms/ProtocolForm.js new file mode 100644 index 0000000..5bc24df --- /dev/null +++ b/edera-web/src/components/ra-forms/ProtocolForm.js @@ -0,0 +1,90 @@ +import { + ActionsMenu, + DateInput, + DeleteWithConfirmButton, + LongForm, + MainCard, + SaveButton, + SmartTextInput, + TextInput, + Toolbar, + required, + usePermissions, + useResourceTitle, + useThemeConfig, + useTranslate +} from '@applica-software-guru/react-admin'; +import { ProtocolServiceArrayInput, CustomerAutocompleteInput, ProtocolAttachmentManyInput } from 'components/ra-inputs'; +import { InfoCircleOutlined, FileOutlined, AppstoreAddOutlined } from '@ant-design/icons'; +import { Grid } from '@mui/material'; + +const ProtocolForm = () => { + const { spacing } = useThemeConfig(); + const title = useResourceTitle(); + const translate = useTranslate(); + const { permissions, isLoading } = usePermissions(); + const isEditable = !isLoading && permissions.includes('protocol:new'); + return ( + + } + title={title} + label="resources.entities/protocol.tabs.details" + secondary={ + + + + } + > + + + + } + > + + {!isLoading && permissions.includes('customer:list') && ( + + + + )} + + + + + + + + + + + + + + + + + + + } id="attachment" label="resources.entities/protocol-attachment.title"> + + + } id="service" label="resources.entities/protocol-service.title"> + + + + + + + + + + + ); +}; + +export default ProtocolForm; diff --git a/edera-web/src/components/ra-forms/RFIDDeviceForm.js b/edera-web/src/components/ra-forms/RFIDDeviceForm.js new file mode 100644 index 0000000..1c11be0 --- /dev/null +++ b/edera-web/src/components/ra-forms/RFIDDeviceForm.js @@ -0,0 +1,25 @@ +import { SimpleForm, TextInput, required, useThemeConfig } from '@applica-software-guru/react-admin'; + +import { Grid } from '@mui/material'; +import { RFIDDeviceTypeSelectInput } from 'components/ra-inputs'; + +const RFIDDeviceForm = () => { + const { spacing } = useThemeConfig(); + return ( + + + + + + + + + + + + + + ); +}; + +export default RFIDDeviceForm; diff --git a/edera-web/src/components/ra-forms/SupplierCreateForm.js b/edera-web/src/components/ra-forms/SupplierCreateForm.js new file mode 100644 index 0000000..beec95a --- /dev/null +++ b/edera-web/src/components/ra-forms/SupplierCreateForm.js @@ -0,0 +1,33 @@ +import { SimpleForm, TextInput, required, useThemeConfig } from '@applica-software-guru/react-admin'; +import { CityAutocompleteInput } from 'components/ra-inputs'; + +import { Grid } from '@mui/material'; + +const SupplierCreateForm = (props) => { + const { spacing } = useThemeConfig(); + return ( + + + + + + + + + + + + + + + + + ); +}; + +export default SupplierCreateForm; diff --git a/edera-web/src/components/ra-forms/SupplierForm.js b/edera-web/src/components/ra-forms/SupplierForm.js new file mode 100644 index 0000000..2311209 --- /dev/null +++ b/edera-web/src/components/ra-forms/SupplierForm.js @@ -0,0 +1,95 @@ +import { + ActionsMenu, + DeleteWithConfirmButton, + LongForm, + MainCard, + SaveButton, + TextInput, + Toolbar, + required, + useRecordContext, + useResourceTitle, + useThemeConfig, + useTranslate +} from '@applica-software-guru/react-admin'; +import { CityAutocompleteInput, EquipmentManyInput, PriceListManyInput, SupplierReferentManyInput } from 'components/ra-inputs'; +import { ContainerOutlined, InfoCircleOutlined, ToolOutlined } from '@ant-design/icons'; + +import { FixedMainCard } from '../layout'; +import { Grid } from '@mui/material'; + +const SupplierForm = () => { + const { spacing } = useThemeConfig(); + const translate = useTranslate(); + const record = useRecordContext(); + const title = useResourceTitle(); + return ( + + } + title={title} + label="resources.entities/customer.tabs.details" + secondary={ + + + + } + > + + + + } + > + + + + + + + + + + + + + + + + + + + {record?.id && ( + + + + )} + + {record?.id && ( + } label="resources.entities/supplier.tabs.equipment"> + + + + + )} + {record?.id && ( + } label="resources.entities/supplier.tabs.price-list"> + + + + + )} + + ); +}; + +export default SupplierForm; diff --git a/edera-web/src/components/ra-forms/SupplierReferentForm.js b/edera-web/src/components/ra-forms/SupplierReferentForm.js new file mode 100644 index 0000000..360154f --- /dev/null +++ b/edera-web/src/components/ra-forms/SupplierReferentForm.js @@ -0,0 +1,30 @@ +import { SimpleForm, TextInput, email, required, useThemeConfig } from '@applica-software-guru/react-admin'; + +import { Grid } from '@mui/material'; + +const SupplierReferent = (props) => { + const { spacing } = useThemeConfig(); + return ( + + + + + + + + + + + + + + + + + + + + ); +}; + +export default SupplierReferent; diff --git a/edera-web/src/components/ra-forms/SupplyDialogForm.js b/edera-web/src/components/ra-forms/SupplyDialogForm.js new file mode 100644 index 0000000..e3bf499 --- /dev/null +++ b/edera-web/src/components/ra-forms/SupplyDialogForm.js @@ -0,0 +1,73 @@ +import { + ActionsMenu, + CardForm, + DateInput, + DeleteWithConfirmButton, + NumberInput, + TextInput, + required, + useResourceTitle, + useThemeConfig, + SaveButton, + Toolbar +} from '@applica-software-guru/react-admin'; + +import { Grid } from '@mui/material'; +import { CustomerOfficeAutocompleteInput, CustomerReadOnlyInput, ProtocolAutoComplete, RFIDDeviceAutocomplete } from 'components/ra-inputs'; +import CustomerAreaAutocompleteInput from 'components/ra-inputs/CustomerAreaAutocompleteInput'; + +const SupplyDialogForm = () => { + const { spacing } = useThemeConfig(); + const title = useResourceTitle(); + return ( + + + + + } + > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default SupplyDialogForm; diff --git a/edera-web/src/components/ra-forms/SupplyForm.js b/edera-web/src/components/ra-forms/SupplyForm.js new file mode 100644 index 0000000..84bd1fa --- /dev/null +++ b/edera-web/src/components/ra-forms/SupplyForm.js @@ -0,0 +1,127 @@ +import { + ActionsMenu, + CardForm, + DateInput, + DeleteWithConfirmButton, + NumberInput, + TextInput, + required, + useResourceTitle, + useThemeConfig, + SaveButton, + Toolbar, + usePermissions, + useRecordContext, + useTranslate +} from '@applica-software-guru/react-admin'; + +import { Grid } from '@mui/material'; +import { GenerateQRCodePdfButton } from 'components/ra-buttons'; +import { RFIDDeviceTrackManyField, SupplyStatusField } from 'components/ra-fields'; +import { + CustomerOfficeAutocompleteInput, + EquipmentAutocompleteInput, + ProtocolAutoComplete, + RFIDDeviceAutocomplete, + SupplierAutocompleteInput +} from 'components/ra-inputs'; +import { CustomerReadOnlyInput } from 'components/ra-inputs'; +import CustomerAreaAutocompleteInput from 'components/ra-inputs/CustomerAreaAutocompleteInput'; +import { Fragment } from 'react'; +import { SupplyLastTrackAlert } from '../ra-alerts'; + +const SupplyForm = () => { + const { spacing } = useThemeConfig(); + const title = useResourceTitle(); + const { permissions, isLoading } = usePermissions(); + const isEditable = !isLoading && permissions.includes('supply:new'); + const translate = useTranslate(); + const record = useRecordContext(); + return ( + + + {title} {record?.id && } + + } + secondary={ + isEditable && ( + + + + ) + } + > + + {!isLoading && permissions.includes('supplier:list') && ( + + + + )} + + + + + + + {!isLoading && permissions.includes('customer:list') && ( + + + + )} + + + + + + + + + + + + + + + + {!isLoading && permissions.includes('rfid-device:new') && ( + + + + )} + {!isLoading && permissions.includes('customer:new') && ( + + + + + + + + + )} + + + + + {!isLoading && permissions.includes('rfid-device:list') && } + + + {isEditable && } + + + {record?.id && record?.rfidDeviceId && ( + + + + )} + + ); +}; + +export default SupplyForm; diff --git a/edera-web/src/components/ra-forms/UserForm.js b/edera-web/src/components/ra-forms/UserForm.js new file mode 100644 index 0000000..064545a --- /dev/null +++ b/edera-web/src/components/ra-forms/UserForm.js @@ -0,0 +1,59 @@ +import { ImageInput, SelectArrayInput, SimpleForm, TextInput, required, useThemeConfig } from '@applica-software-guru/react-admin'; +import { useFormContext, useWatch } from 'react-hook-form'; + +import { CustomerAutocompleteInput } from 'components/ra-inputs'; +import { Grid } from '@mui/material'; +import PropTypes from 'prop-types'; +import { useEffect } from 'react'; + +const UserFormContext = ({ configuredRoles }) => { + const { spacing } = useThemeConfig(); + const { setValue } = useFormContext(); + const customerId = useWatch({ + name: 'customerId' + }); + const roles = useWatch({ + name: 'roles' + }); + + useEffect(() => setValue('roles', customerId == null ? [] : ['ROLE_CUSTOMER']), [customerId, setValue]); + + return ( + + + + + + + + + + + + + + {!customerId && ( + + + + )} + + + + + ); +}; + +const UserForm = ({ configuredRoles }) => { + return ( + + + + ); +}; + +UserForm.propTypes = { + configuredRoles: PropTypes.arrayOf(PropTypes.shape({ id: PropTypes.string, name: PropTypes.string })).isRequired +}; + +export default UserForm; diff --git a/edera-web/src/components/ra-forms/index.js b/edera-web/src/components/ra-forms/index.js new file mode 100644 index 0000000..69bb700 --- /dev/null +++ b/edera-web/src/components/ra-forms/index.js @@ -0,0 +1,31 @@ +export { default as CustomerAreaForm } from './CustomerAreaForm'; +export { default as CustomerCreateForm } from './CustomerCreateForm'; +export { default as CustomerEditForm } from './CustomerEditForm'; +export { default as CustomerOfficeForm } from './CustomerOfficeForm'; +export { default as CustomerReferentForm } from './CustomerReferentForm'; +export { default as DeviceForm } from './DeviceForm'; +export { default as I18nMessageForm } from './I18nMessageForm'; +export { default as ActivityTypeForm } from './ActivityTypeForm'; +export { default as RFIDDeviceForm } from './RFIDDeviceForm'; +export { default as SupplierForm } from './SupplierForm'; +export { default as SupplierReferentForm } from './SupplierReferentForm'; +export { default as UserForm } from './UserForm'; +export { default as EquipmentTypeEditForm } from './EquipmentTypeEditForm'; +export { default as EquipmentTypeAttachmentForm } from './EquipmentTypeAttachmentForm'; +export { default as EquipmentTypeCreateForm } from './EquipmentTypeCreateForm'; +export { default as PriceListForm } from './PriceListForm'; +export { default as EquipmentCreateForm } from './EquipmentCreateForm'; +export { default as ProtocolForm } from './ProtocolForm'; +export { default as ProtocolAttachmentForm } from './ProtocolAttachmentForm'; +export { default as EquipmentEditForm } from './EquipmentEditForm'; +export { default as SupplyDialogForm } from './SupplyDialogForm'; +export { default as PriceListItemForm } from './PriceListItemForm'; +export { default as SupplyForm } from './SupplyForm'; +export { default as ActivityForm } from './ActivityForm'; +export { default as MaintenanceCreateForm } from './MaintenanceCreateForm'; +export { default as MaintenanceEditForm } from './MaintenanceEditForm'; +export { default as EquipmentAttachmentForm } from './EquipmentAttachmentForm'; +export { default as EquipmentCreateInDialogForm } from './EquipmentCreateInDialogForm'; +export { default as SupplierCreateForm } from './SupplierCreateForm'; +export { default as ProtocolDialogForm } from './ProtocolDialogForm'; +export { default as DocxTemplateForm } from './DocxTemplateForm'; diff --git a/edera-web/src/components/ra-inputs/ActivitySelectInput.js b/edera-web/src/components/ra-inputs/ActivitySelectInput.js new file mode 100644 index 0000000..70ec6e0 --- /dev/null +++ b/edera-web/src/components/ra-inputs/ActivitySelectInput.js @@ -0,0 +1,82 @@ +import { Alert, AlertTitle, Typography } from '@mui/material'; +import { ReferenceInput, SelectInput, useDataProvider, useNotify, useTranslate } from '@applica-software-guru/react-admin'; +import { Fragment, useEffect, useState } from 'react'; + +import { useWatch } from 'react-hook-form'; + +const AlertBox = () => { + const [activityDetails, setActivityDetails] = useState(null); + const dataProvider = useDataProvider(); + const notify = useNotify(); + const translate = useTranslate(); + const activityId = useWatch({ + name: 'activityId' + }); + + useEffect(() => { + if (!activityId) return; + + const fetchDetails = async () => { + try { + const { data } = await dataProvider.get('maintenance/activity-info/' + activityId); + setActivityDetails(data.activityDetailsDTO); + } catch (error) { + notify('ra.notification.http_error', 'error', {}); + } + }; + + fetchDetails(); + }, [activityId, dataProvider, notify]); + + if (!activityDetails) return null; + + return ( + + {translate('resources.entities/activity.title')} + + + ); +}; + +const renderOption = (option) => { + return ( + + {option.title} + + ); +}; + +const ActivitySelectInput = ({ validate, ...props }) => { + const supplyId = useWatch({ + name: 'supplyId' + }); + + return ( + + ({ keyword: searchText })} + filter={{ supplyId: supplyId || [] }} + perPage={100} + sort={{ + field: 'name', + order: 'ASC' + }} + > + + + + + ); +}; + +export default ActivitySelectInput; diff --git a/edera-web/src/components/ra-inputs/ActivityTypeAutocompleteInput.js b/edera-web/src/components/ra-inputs/ActivityTypeAutocompleteInput.js new file mode 100644 index 0000000..44e86dc --- /dev/null +++ b/edera-web/src/components/ra-inputs/ActivityTypeAutocompleteInput.js @@ -0,0 +1,18 @@ +import { AutocompleteInput, ReferenceInput } from '@applica-software-guru/react-admin'; + +const ActivityTypeAutocompleteInput = ({ validate, ...props }) => ( + ({ keyword: searchText })} + perPage={100} + sort={{ + field: 'name', + order: 'ASC' + }} + > + + +); + +export default ActivityTypeAutocompleteInput; diff --git a/edera-web/src/components/ra-inputs/CityAutocompleteInput.js b/edera-web/src/components/ra-inputs/CityAutocompleteInput.js new file mode 100644 index 0000000..24a2803 --- /dev/null +++ b/edera-web/src/components/ra-inputs/CityAutocompleteInput.js @@ -0,0 +1,27 @@ +import { AutocompleteInput, ReferenceInput } from '@applica-software-guru/react-admin'; + +import { useWatch } from 'react-hook-form'; + +const CityAutocompleteInput = ({ filterByProvince, validate, ...props }) => { + const provinceId = useWatch({ + name: 'provinceId' + }); + return ( + ({ keyword: searchText })} + perPage={100} + sort={{ + field: 'name', + order: 'ASC' + }} + > + + + ); +}; + +export default CityAutocompleteInput; diff --git a/edera-web/src/components/ra-inputs/CustomerAreaAutocompleteInput.js b/edera-web/src/components/ra-inputs/CustomerAreaAutocompleteInput.js new file mode 100644 index 0000000..13129d0 --- /dev/null +++ b/edera-web/src/components/ra-inputs/CustomerAreaAutocompleteInput.js @@ -0,0 +1,42 @@ +import { AutocompleteInput, ReferenceInput } from '@applica-software-guru/react-admin'; +import { useEffect, useState } from 'react'; +import { useWatch, useFormContext } from 'react-hook-form'; +import _ from 'lodash'; + +const CustomerAreaAutocompleteInput = ({ validate, ...props }) => { + const officeId = useWatch({ + name: 'area.officeId' + }); + const { isAreaPresent, ...rest } = props; + const [isDisabled, setIsDisabled] = useState(false); + const { setValue } = useFormContext(); + + useEffect(() => { + if (isAreaPresent) { + if (_.isEmpty(officeId)) { + setValue('areaId', null); + setIsDisabled(true); + } else { + setIsDisabled(false); + } + } + }, [isAreaPresent, officeId, setValue]); + + return ( + ({ keyword: searchText })} + perPage={100} + sort={{ + field: 'name', + order: 'ASC' + }} + > + + + ); +}; + +export default CustomerAreaAutocompleteInput; diff --git a/edera-web/src/components/ra-inputs/CustomerAreaManyInput.js b/edera-web/src/components/ra-inputs/CustomerAreaManyInput.js new file mode 100644 index 0000000..7d83f1d --- /dev/null +++ b/edera-web/src/components/ra-inputs/CustomerAreaManyInput.js @@ -0,0 +1,72 @@ +import { + ActionsMenu, + CreateInDialogButton, + Datagrid, + DateField, + DeleteWithConfirmButton, + EditInDialogButton, + ReferenceField, + ReferenceManyInput, + SearchInput, + TextField, + TopToolbar, + useRecordContext +} from '@applica-software-guru/react-admin'; + +import { CustomerAreaForm } from '../ra-forms'; +import CustomerOfficeAutocompleteInput from './CustomerOfficeAutocompleteInput'; + +const CustomerAreaManyInput = ({ ...props }) => { + const record = useRecordContext(); + + return ( + , + + ]} + actions={ + + + + + + } + > + + + + + + + `/entities/rfid-device-track?gateway-id=${data?.id}`} + sortable={false} + > + + + + + + + + + + + + ); +}; + +export default CustomerAreaManyInput; diff --git a/edera-web/src/components/ra-inputs/CustomerAutocompleteInput.js b/edera-web/src/components/ra-inputs/CustomerAutocompleteInput.js new file mode 100644 index 0000000..a0c78c2 --- /dev/null +++ b/edera-web/src/components/ra-inputs/CustomerAutocompleteInput.js @@ -0,0 +1,20 @@ +import { AutocompleteInput, ReferenceInput } from '@applica-software-guru/react-admin'; + +const CustomerAutocompleteInput = ({ validate, ...props }) => { + return ( + ({ keyword: searchText })} + perPage={100} + sort={{ + field: 'name', + order: 'ASC' + }} + > + + + ); +}; + +export default CustomerAutocompleteInput; diff --git a/edera-web/src/components/ra-inputs/CustomerOfficeAutocompleteInput.js b/edera-web/src/components/ra-inputs/CustomerOfficeAutocompleteInput.js new file mode 100644 index 0000000..5351f7d --- /dev/null +++ b/edera-web/src/components/ra-inputs/CustomerOfficeAutocompleteInput.js @@ -0,0 +1,42 @@ +import { AutocompleteInput, ReferenceInput } from '@applica-software-guru/react-admin'; +import { useEffect, useState } from 'react'; +import { useWatch, useFormContext } from 'react-hook-form'; +import _ from 'lodash'; + +const renderText = (record) => `${record.city.name} - ${record.address}`; +const CustomerOfficeAutocompleteInput = ({ validate, ...props }) => { + const { isAreaPresent, ...rest } = props; + const [isDisabled, setIsDisabled] = useState(false); + const rfidDeviceId = useWatch({ name: 'rfidDeviceId' }); + const customerId = useWatch({ name: 'customerId' }); + const protocolId = useWatch({ name: 'protocolId' }); + const { setValue } = useFormContext(); + + useEffect(() => { + if (isAreaPresent) { + if (!_.isEmpty(rfidDeviceId) || _.isEmpty(protocolId) || customerId === '') { + setValue('area.officeId', null); + setIsDisabled(true); + } else { + setIsDisabled(false); + } + } + }, [isAreaPresent, rfidDeviceId, customerId, protocolId, setValue]); + + return ( + ({ keyword: searchText })} + filter={{ customerId: customerId ? customerId : undefined }} + sort={{ + field: 'address', + order: 'ASC' + }} + > + + + ); +}; + +export default CustomerOfficeAutocompleteInput; diff --git a/edera-web/src/components/ra-inputs/CustomerOfficeManyInput.js b/edera-web/src/components/ra-inputs/CustomerOfficeManyInput.js new file mode 100644 index 0000000..09a5a43 --- /dev/null +++ b/edera-web/src/components/ra-inputs/CustomerOfficeManyInput.js @@ -0,0 +1,65 @@ +import { + ActionsMenu, + BooleanField, + CreateInDialogButton, + Datagrid, + DateField, + DeleteWithConfirmButton, + EditInDialogButton, + ReferenceManyInput, + SearchInput, + TextField, + TopToolbar, + useRecordContext +} from '@applica-software-guru/react-admin'; + +import CityAutocompleteInput from './CityAutocompleteInput'; +import { CustomerOfficeForm } from '../ra-forms'; + +const CustomerOfficeManyInput = ({ ...props }) => { + const record = useRecordContext(); + + return ( + , + + ]} + actions={ + + + + + + } + > + + + + + + + + + + + + + + + + + ); +}; + +export default CustomerOfficeManyInput; diff --git a/edera-web/src/components/ra-inputs/CustomerReadOnlyInput.js b/edera-web/src/components/ra-inputs/CustomerReadOnlyInput.js new file mode 100644 index 0000000..ace20aa --- /dev/null +++ b/edera-web/src/components/ra-inputs/CustomerReadOnlyInput.js @@ -0,0 +1,41 @@ +import { TextInput, useDataProvider, useNotify } from '@applica-software-guru/react-admin'; +import { useEffect, useState } from 'react'; +import { useWatch, useFormContext } from 'react-hook-form'; +import _ from 'lodash'; + +const CustomerReadOnlyInput = (props) => { + const dataProvider = useDataProvider(); + const protocolId = useWatch({ name: 'protocolId' }); + const { setValue } = useFormContext(); + const [isInitialized, setIsInitialized] = useState(false); + const notify = useNotify(); + + useEffect(() => { + if (isInitialized || !_.isEmpty(protocolId)) { + if (!_.isEmpty(protocolId)) { + dataProvider + .getOne('entities/protocol', { id: protocolId }) + .then(({ data }) => { + if (data && data.customer) { + setValue('customerName', data.customer.name); + setValue('customerId', data.customer.id); + } + }) + .catch((error) => { + notify('ra.error.fetch', error); + }); + } else { + setValue('customerName', ''); + setValue('customerId', ''); + } + } + }, [dataProvider, protocolId, setValue, isInitialized, notify]); + + useEffect(() => { + setIsInitialized(true); + }, [protocolId]); + + return ; +}; + +export default CustomerReadOnlyInput; diff --git a/edera-web/src/components/ra-inputs/CustomerReferentManyInput.js b/edera-web/src/components/ra-inputs/CustomerReferentManyInput.js new file mode 100644 index 0000000..c6b65ae --- /dev/null +++ b/edera-web/src/components/ra-inputs/CustomerReferentManyInput.js @@ -0,0 +1,63 @@ +import { + ActionsMenu, + CreateInDialogButton, + Datagrid, + DateField, + DeleteWithConfirmButton, + EditInDialogButton, + ReferenceField, + ReferenceManyInput, + SearchInput, + TextField, + TopToolbar, + useRecordContext +} from '@applica-software-guru/react-admin'; + +import { CustomerReferentForm } from '../ra-forms'; + +const CustomerReferentManyInput = ({ ...props }) => { + const record = useRecordContext(); + + return ( + ]} + actions={ + + + + + + } + > + + + + + + + + + + + + + + + + + + + ); +}; + +export default CustomerReferentManyInput; diff --git a/edera-web/src/components/ra-inputs/DocxTemplateTypeSelectInput.js b/edera-web/src/components/ra-inputs/DocxTemplateTypeSelectInput.js new file mode 100644 index 0000000..e397dda --- /dev/null +++ b/edera-web/src/components/ra-inputs/DocxTemplateTypeSelectInput.js @@ -0,0 +1,18 @@ +import { SelectInput, useDataProvider } from '@applica-software-guru/react-admin'; +import { useEffect, useState } from 'react'; + +const DocxTemplateTypeSelectInput = (props) => { + const dataProvider = useDataProvider(); + const [choices, setChoices] = useState([]); + useEffect(() => { + dataProvider + .get('values/docx-types') + .then(({ data: { value: data } }) => + setChoices(data.map(({ label, value }) => ({ id: value, name: `docx-template.type.${label}` }))) + ); + }, [dataProvider]); + + return ; +}; + +export default DocxTemplateTypeSelectInput; diff --git a/edera-web/src/components/ra-inputs/EquipmentAttachmentManyInput.js b/edera-web/src/components/ra-inputs/EquipmentAttachmentManyInput.js new file mode 100644 index 0000000..9cd7a05 --- /dev/null +++ b/edera-web/src/components/ra-inputs/EquipmentAttachmentManyInput.js @@ -0,0 +1,67 @@ +import { + ActionsMenu, + AttachmentField, + BulkDeleteWithConfirmButton, + CreateInDialogButton, + Datagrid, + DateField, + DeleteWithConfirmButton, + EditInDialogButton, + ReferenceManyInput, + SearchInput, + TextField, + TopToolbar, + usePermissions, + useRecordContext, + useThemeConfig +} from '@applica-software-guru/react-admin'; + +import { EquipmentAttachmentForm } from 'components/ra-forms'; +import { Grid } from '@mui/material'; + +const EquipmentAttachmentManyInput = () => { + const record = useRecordContext(); + const { spacing } = useThemeConfig(); + const { permissions, isLoading } = usePermissions(); + const canEdit = !isLoading && permissions.includes('equipment-attachment:edit'); + const canCreate = !isLoading && permissions.includes('equipment-attachment:new'); + + return ( + + + ]} + sort={{ field: 'created', order: 'ASC' }} + actions={ + + {canCreate && ( + + + + )} + + } + > + }> + + + + {canEdit && ( + + + + + + + + )} + + + + + ); +}; + +export default EquipmentAttachmentManyInput; diff --git a/edera-web/src/components/ra-inputs/EquipmentAutocompleteInput.js b/edera-web/src/components/ra-inputs/EquipmentAutocompleteInput.js new file mode 100644 index 0000000..5db7083 --- /dev/null +++ b/edera-web/src/components/ra-inputs/EquipmentAutocompleteInput.js @@ -0,0 +1,43 @@ +import { AutocompleteInput, ReferenceInput } from '@applica-software-guru/react-admin'; +import { useEffect } from 'react'; +import { useFormContext, useWatch } from 'react-hook-form'; + +const EquipmentAutocompleteInput = ({ validate, ...props }) => { + const { setValue } = useFormContext(); + const supplierId = useWatch({ + name: 'supplierId' + }); + + const priceListId = useWatch({ + name: 'priceListId' + }); + + useEffect(() => { + setValue('equipmentId', null); + }, [supplierId, setValue]); + + const filter = {}; + if (supplierId) { + filter.supplierId = supplierId; + } + if (priceListId) { + filter.priceListId = priceListId; + } + + return ( + + + + ); +}; + +export default EquipmentAutocompleteInput; diff --git a/edera-web/src/components/ra-inputs/EquipmentListAutocompleteInput.js b/edera-web/src/components/ra-inputs/EquipmentListAutocompleteInput.js new file mode 100644 index 0000000..61f338f --- /dev/null +++ b/edera-web/src/components/ra-inputs/EquipmentListAutocompleteInput.js @@ -0,0 +1,18 @@ +import { AutocompleteInput, ReferenceInput } from '@applica-software-guru/react-admin'; +const renderText = (record) => `${record.equipmentType.name} (${record?.supplier?.businessName})`; +const EquipmentListAutocompleteInput = ({ validate, ...props }) => ( + ({ keyword: searchText })} + perPage={100} + sort={{ + field: 'name', + order: 'ASC' + }} + > + + +); + +export default EquipmentListAutocompleteInput; diff --git a/edera-web/src/components/ra-inputs/EquipmentManyInput.js b/edera-web/src/components/ra-inputs/EquipmentManyInput.js new file mode 100644 index 0000000..be50884 --- /dev/null +++ b/edera-web/src/components/ra-inputs/EquipmentManyInput.js @@ -0,0 +1,48 @@ +import { + ActionsMenu, + CreateInDialogButton, + Datagrid, + DateField, + DeleteWithConfirmButton, + EditButton, + ReferenceManyInput, + SearchInput, + TextField, + TopToolbar, + useRecordContext +} from '@applica-software-guru/react-admin'; +import { EquipmentCreateForm, EquipmentEditForm } from 'components/ra-forms'; + +const EquipmentManyInput = ({ ...props }) => { + const record = useRecordContext(); + + return ( + ]} + actions={ + + + + + + } + > + + + + + + + + + + + + ); +}; + +export default EquipmentManyInput; diff --git a/edera-web/src/components/ra-inputs/EquipmentTypeAttachmentManyInput.js b/edera-web/src/components/ra-inputs/EquipmentTypeAttachmentManyInput.js new file mode 100644 index 0000000..d433b05 --- /dev/null +++ b/edera-web/src/components/ra-inputs/EquipmentTypeAttachmentManyInput.js @@ -0,0 +1,56 @@ +import { + ActionsMenu, + AttachmentField, + CreateInDialogButton, + Datagrid, + DateField, + DeleteWithConfirmButton, + EditInDialogButton, + ReferenceManyInput, + SearchInput, + TextField, + TopToolbar, + useRecordContext, + useThemeConfig +} from '@applica-software-guru/react-admin'; + +import { EquipmentTypeAttachmentForm } from 'components/ra-forms'; +import { Grid } from '@mui/material'; + +const EquipmentTypeAttachmentManyInput = () => { + const record = useRecordContext(); + const { spacing } = useThemeConfig(); + return ( + + + ]} + sort={{ field: 'created', order: 'ASC' }} + actions={ + + + + + + } + > + + + + + + + + + + + + + + + ); +}; + +export default EquipmentTypeAttachmentManyInput; diff --git a/edera-web/src/components/ra-inputs/EquipmentTypeAutocompleteInput.js b/edera-web/src/components/ra-inputs/EquipmentTypeAutocompleteInput.js new file mode 100644 index 0000000..3169e81 --- /dev/null +++ b/edera-web/src/components/ra-inputs/EquipmentTypeAutocompleteInput.js @@ -0,0 +1,22 @@ +import { AutocompleteInput, ReferenceInput } from '@applica-software-guru/react-admin'; +import { useWatch } from 'react-hook-form'; + +const EquipmentTypeAutocompleteInput = ({ label, validate, ...props }) => { + const supplierId = useWatch({ name: 'supplierId' }); + return ( + + + + ); +}; + +export default EquipmentTypeAutocompleteInput; diff --git a/edera-web/src/components/ra-inputs/EquipmentTypeManyInput.js b/edera-web/src/components/ra-inputs/EquipmentTypeManyInput.js new file mode 100644 index 0000000..feb3f1b --- /dev/null +++ b/edera-web/src/components/ra-inputs/EquipmentTypeManyInput.js @@ -0,0 +1,48 @@ +import { + BooleanField, + CreateInDialogButton, + Datagrid, + EditButton, + ReferenceManyInput, + SearchInput, + TextField, + TopToolbar, + useRecordContext, + useThemeConfig +} from '@applica-software-guru/react-admin'; +import { Grid } from '@mui/material'; +import { EquipmentTypeEditForm, EquipmentTypeCreateForm } from 'components/ra-forms'; + +const EquipmentTypeManyInput = () => { + const record = useRecordContext(); + const { spacing } = useThemeConfig(); + return ( + + + ]} + sort={{ field: 'created', order: 'ASC' }} + actions={ + + + + + + } + > + + + + + + + + + + + ); +}; + +export default EquipmentTypeManyInput; diff --git a/edera-web/src/components/ra-inputs/InterventionArrayInput.js b/edera-web/src/components/ra-inputs/InterventionArrayInput.js new file mode 100644 index 0000000..1710372 --- /dev/null +++ b/edera-web/src/components/ra-inputs/InterventionArrayInput.js @@ -0,0 +1,38 @@ +import { + ArrayInput, + SimpleFormIterator, + TableFormIterator, + TextInput, + required, + useTranslateLabel +} from '@applica-software-guru/react-admin'; +import { useMediaQuery, Grid } from '@mui/material'; +import EquipmentTypeAutocompleteInput from './EquipmentTypeAutocompleteInput'; +import YesOrNoSelectInput from './YesOrNoSelectInput'; + +const InterventionArrayInput = (props) => { + const translateLabel = useTranslateLabel(); + const isXsScreen = useMediaQuery((theme) => theme.breakpoints.down('sm')); + return ( + + + {!isXsScreen ? ( + + + + + + + ) : ( + + + + + + + )} + + + ); +}; +export default InterventionArrayInput; diff --git a/edera-web/src/components/ra-inputs/LangSelectInput.js b/edera-web/src/components/ra-inputs/LangSelectInput.js new file mode 100644 index 0000000..69967a9 --- /dev/null +++ b/edera-web/src/components/ra-inputs/LangSelectInput.js @@ -0,0 +1,4 @@ +import { SelectInput } from '@applica-software-guru/react-admin'; +const LangSelectInput = (props) => ; + +export default LangSelectInput; diff --git a/edera-web/src/components/ra-inputs/MaintenanceManyInput.js b/edera-web/src/components/ra-inputs/MaintenanceManyInput.js new file mode 100644 index 0000000..8547ec4 --- /dev/null +++ b/edera-web/src/components/ra-inputs/MaintenanceManyInput.js @@ -0,0 +1,57 @@ +import { + BulkDeleteWithConfirmButton, + CreateButton, + Datagrid, + DateField, + EditButton, + ReferenceManyInput, + SearchInput, + TextField, + TopToolbar, + usePermissions, + useRecordContext, + useThemeConfig +} from '@applica-software-guru/react-admin'; +import { MaintenanceCreateForm, MaintenanceEditForm } from 'components/ra-forms'; + +import { Grid } from '@mui/material'; + +const MaintenanceManyInput = () => { + const record = useRecordContext(); + const { spacing } = useThemeConfig(); + const { permissions, isLoading } = usePermissions(); + const canDelete = !isLoading && permissions.includes('maintenance:delete'); + + return ( + + + ]} + sort={{ field: 'created', order: 'ASC' }} + actions={ + + + + + + } + > + }> + + + + + + + + + + + + + ); +}; + +export default MaintenanceManyInput; diff --git a/edera-web/src/components/ra-inputs/MoneyInput.js b/edera-web/src/components/ra-inputs/MoneyInput.js new file mode 100644 index 0000000..8023b82 --- /dev/null +++ b/edera-web/src/components/ra-inputs/MoneyInput.js @@ -0,0 +1,33 @@ +import { TextInput } from '@applica-software-guru/react-admin'; + +const parseMoney = (value) => { + const convertedValue = value?.replace(',', '.'); + + const decimalMatch = /\.(\d{2,})$/.exec(convertedValue); + + if (decimalMatch) { + const decimalPart = decimalMatch[1]; + + const twoDecimals = decimalPart.slice(0, 2); + + const integerPart = convertedValue.split('.')[0]; + return `${integerPart}.${twoDecimals}`; + } + return convertedValue; +}; +const MoneyInput = (props) => { + return ( + + ); +}; + +export default MoneyInput; diff --git a/edera-web/src/components/ra-inputs/NationAutocompleteInput.js b/edera-web/src/components/ra-inputs/NationAutocompleteInput.js new file mode 100644 index 0000000..156a53b --- /dev/null +++ b/edera-web/src/components/ra-inputs/NationAutocompleteInput.js @@ -0,0 +1,18 @@ +import { AutocompleteInput, ReferenceInput } from '@applica-software-guru/react-admin'; + +const NationAutocompleteInput = ({ validate, ...props }) => ( + ({ keyword: searchText })} + perPage={100} + sort={{ + field: 'name', + order: 'ASC' + }} + > + + +); + +export default NationAutocompleteInput; diff --git a/edera-web/src/components/ra-inputs/PriceListItemManyInput.js b/edera-web/src/components/ra-inputs/PriceListItemManyInput.js new file mode 100644 index 0000000..bb0eae0 --- /dev/null +++ b/edera-web/src/components/ra-inputs/PriceListItemManyInput.js @@ -0,0 +1,55 @@ +import { + ActionsMenu, + CreateInDialogButton, + Datagrid, + DeleteWithConfirmButton, + EditInDialogButton, + ReferenceManyInput, + SearchInput, + TextField, + TopToolbar, + useRecordContext, + useThemeConfig, + DateField +} from '@applica-software-guru/react-admin'; +import { Grid } from '@mui/material'; +import { MoneyField } from 'components/ra-fields'; +import { PriceListItemForm } from 'components/ra-forms'; + +const PriceListItemManyInput = () => { + const record = useRecordContext(); + const { spacing } = useThemeConfig(); + return ( + + + ]} + sort={{ field: 'created', order: 'ASC' }} + actions={ + + + + + + } + > + + + + + + + + + + + + + + + ); +}; + +export default PriceListItemManyInput; diff --git a/edera-web/src/components/ra-inputs/PriceListManyInput.js b/edera-web/src/components/ra-inputs/PriceListManyInput.js new file mode 100644 index 0000000..b97e6c1 --- /dev/null +++ b/edera-web/src/components/ra-inputs/PriceListManyInput.js @@ -0,0 +1,58 @@ +import { + ActionsMenu, + CreateInDialogButton, + Datagrid, + DateField, + DeleteWithConfirmButton, + EditButton, + ReferenceManyInput, + SearchInput, + TextField, + TopToolbar, + useRecordContext +} from '@applica-software-guru/react-admin'; + +import { PriceListForm } from 'components/ra-forms'; + +const PriceListManyInput = ({ ...props }) => { + const record = useRecordContext(); + + return ( + ]} + actions={ + + + + + + } + > + + + + + + + + + + + + + + ); +}; + +export default PriceListManyInput; diff --git a/edera-web/src/components/ra-inputs/ProtocolAttachmentManyInput.js b/edera-web/src/components/ra-inputs/ProtocolAttachmentManyInput.js new file mode 100644 index 0000000..766bd45 --- /dev/null +++ b/edera-web/src/components/ra-inputs/ProtocolAttachmentManyInput.js @@ -0,0 +1,78 @@ +import { + ActionsMenu, + AttachmentField, + BulkDeleteWithConfirmButton, + CreateInDialogButton, + Datagrid, + DateField, + DeleteWithConfirmButton, + EditInDialogButton, + ReferenceManyInput, + SearchInput, + TextField, + TopToolbar, + usePermissions, + useRecordContext, + useThemeConfig, + useTranslate +} from '@applica-software-guru/react-admin'; + +import { Grid } from '@mui/material'; +import { FixedMainCard } from 'components/layout'; +import { ProtocolAttachmentForm } from 'components/ra-forms'; + +const ProtocolAttachmentManyInput = () => { + const record = useRecordContext(); + const translate = useTranslate(); + const { spacing } = useThemeConfig(); + const { isLoading, permissions } = usePermissions(); + const canCreate = !isLoading && permissions.includes('protocol-attachment:new'); + const canEdit = !isLoading && permissions.includes('protocol-attachment:edit'); + const canDelete = !isLoading && permissions.includes('protocol-attachment:delete'); + return ( + + + + ]} + sort={{ field: 'created', order: 'ASC' }} + actions={ + + {canCreate && ( + + + + )} + + } + > + }> + + + + {canEdit && ( + + + + + + + + )} + + + + + + ); +}; + +export default ProtocolAttachmentManyInput; diff --git a/edera-web/src/components/ra-inputs/ProtocolAutoComplete.js b/edera-web/src/components/ra-inputs/ProtocolAutoComplete.js new file mode 100644 index 0000000..e23b174 --- /dev/null +++ b/edera-web/src/components/ra-inputs/ProtocolAutoComplete.js @@ -0,0 +1,18 @@ +import { AutocompleteInput, ReferenceInput } from '@applica-software-guru/react-admin'; + +const ProtocolAutoComplete = ({ validate, ...props }) => ( + ({ keyword: searchText })} + perPage={100} + sort={{ + field: 'name', + order: 'ASC' + }} + > + + +); + +export default ProtocolAutoComplete; diff --git a/edera-web/src/components/ra-inputs/ProtocolServiceArrayInput.js b/edera-web/src/components/ra-inputs/ProtocolServiceArrayInput.js new file mode 100644 index 0000000..4eded4a --- /dev/null +++ b/edera-web/src/components/ra-inputs/ProtocolServiceArrayInput.js @@ -0,0 +1,43 @@ +import { + ArrayInput, + TableFormIterator, + SimpleFormIterator, + TextInput, + DateInput, + required, + useTranslate +} from '@applica-software-guru/react-admin'; +import { useMediaQuery } from '@mui/material'; +import { ActivityTypeAutocompleteInput } from '.'; +import { useMemo } from 'react'; +const ProtocolServiceArrayInput = (props) => { + const isMobile = useMediaQuery((theme) => theme.breakpoints.down('sm')); + const translate = useTranslate(); + const Component = useMemo(() => (isMobile ? SimpleFormIterator : TableFormIterator), [isMobile]); + + return ( + + + + + + + + + ); +}; + +export default ProtocolServiceArrayInput; diff --git a/edera-web/src/components/ra-inputs/ProvinceAutocompleteInput.js b/edera-web/src/components/ra-inputs/ProvinceAutocompleteInput.js new file mode 100644 index 0000000..6acb9a6 --- /dev/null +++ b/edera-web/src/components/ra-inputs/ProvinceAutocompleteInput.js @@ -0,0 +1,35 @@ +import { AutocompleteInput, ReferenceInput } from '@applica-software-guru/react-admin'; +import { useFormContext, useWatch } from 'react-hook-form'; + +import { useEffect } from 'react'; + +const ProvinceAutocompleteInput = ({ validate, ...props }) => { + const { setValue } = useFormContext(); + const regionId = useWatch({ + name: 'regionId' + }); + + useEffect(() => { + setValue('provinceId', null); + }, [regionId, setValue]); + + return ( + ({ keyword: searchText })} + perPage={100} + sort={{ + field: 'name', + order: 'ASC' + }} + > + + + ); +}; + +export default ProvinceAutocompleteInput; diff --git a/edera-web/src/components/ra-inputs/RFIDDeviceAutocomplete.js b/edera-web/src/components/ra-inputs/RFIDDeviceAutocomplete.js new file mode 100644 index 0000000..22e08fa --- /dev/null +++ b/edera-web/src/components/ra-inputs/RFIDDeviceAutocomplete.js @@ -0,0 +1,41 @@ +import { AutocompleteInput, ReferenceInput } from '@applica-software-guru/react-admin'; +import { useEffect, useState } from 'react'; +import { useWatch, useFormContext } from 'react-hook-form'; +import _ from 'lodash'; + +const RFIDDeviceAutocomplete = ({ validate, ...props }) => { + const { isAreaPresent, type, ...rest } = props; + const [isDisabled, setIsDisabled] = useState(false); + const officeId = useWatch({ name: 'area.officeId' }); + const { setValue } = useFormContext(); + + useEffect(() => { + if (isAreaPresent) { + if (!_.isEmpty(officeId)) { + setValue('rfidDeviceId', null); + setIsDisabled(true); + } else { + setIsDisabled(false); + } + } + }, [isAreaPresent, officeId, setValue]); + + return ( + ({ keyword: searchText })} + filter={{ type: type }} + perPage={100} + sort={{ + field: 'name', + order: 'ASC' + }} + disabled={isDisabled} + > + + + ); +}; + +export default RFIDDeviceAutocomplete; diff --git a/edera-web/src/components/ra-inputs/RFIDDeviceTypeSelectInput.js b/edera-web/src/components/ra-inputs/RFIDDeviceTypeSelectInput.js new file mode 100644 index 0000000..8b63e47 --- /dev/null +++ b/edera-web/src/components/ra-inputs/RFIDDeviceTypeSelectInput.js @@ -0,0 +1,24 @@ +import React, { useState, useEffect } from 'react'; +import { SelectInput, useDataProvider } from '@applica-software-guru/react-admin'; + +const RFIDDeviceTypeSelect = (props) => { + const [options, setOptions] = useState([]); + const dataProvider = useDataProvider(); + + useEffect(() => { + dataProvider + .get('values/rfid-device-types', { + pagination: { page: 1, perPage: 100 }, + sort: { field: 'name', order: 'ASC' } + }) + .then((response) => { + const { data } = response; + + setOptions(data.value.map((item) => ({ id: item.label, name: item.value }))); + }); + }, [dataProvider]); + + return ; +}; + +export default RFIDDeviceTypeSelect; diff --git a/edera-web/src/components/ra-inputs/RegionAutocompleteInput.js b/edera-web/src/components/ra-inputs/RegionAutocompleteInput.js new file mode 100644 index 0000000..0af88c2 --- /dev/null +++ b/edera-web/src/components/ra-inputs/RegionAutocompleteInput.js @@ -0,0 +1,35 @@ +import { AutocompleteInput, ReferenceInput } from '@applica-software-guru/react-admin'; +import { useFormContext, useWatch } from 'react-hook-form'; + +import { useEffect } from 'react'; + +const RegionAutocompleteInput = ({ validate, ...props }) => { + const { setValue } = useFormContext(); + const nationId = useWatch({ + name: 'nationId' + }); + + useEffect(() => { + setValue('regionId', null); + }, [nationId, setValue]); + + return ( + ({ keyword: searchText })} + perPage={100} + sort={{ + field: 'name', + order: 'ASC' + }} + > + + + ); +}; + +export default RegionAutocompleteInput; diff --git a/edera-web/src/components/ra-inputs/SupplierAutocompleteInput.js b/edera-web/src/components/ra-inputs/SupplierAutocompleteInput.js new file mode 100644 index 0000000..7eb783c --- /dev/null +++ b/edera-web/src/components/ra-inputs/SupplierAutocompleteInput.js @@ -0,0 +1,21 @@ +import { AutocompleteInput, ReferenceInput } from '@applica-software-guru/react-admin'; + +const SupplierAutocompleteInput = ({ validate, ...props }) => { + return ( + ({ keyword: searchText })} + key={(searchText) => ({ keyword: searchText })} + perPage={100} + sort={{ + field: 'businessName', + order: 'ASC' + }} + > + + + ); +}; + +export default SupplierAutocompleteInput; diff --git a/edera-web/src/components/ra-inputs/SupplierReferentManyInput.js b/edera-web/src/components/ra-inputs/SupplierReferentManyInput.js new file mode 100644 index 0000000..fccc9d0 --- /dev/null +++ b/edera-web/src/components/ra-inputs/SupplierReferentManyInput.js @@ -0,0 +1,49 @@ +import { + ActionsMenu, + CreateInDialogButton, + Datagrid, + DeleteWithConfirmButton, + EditInDialogButton, + ReferenceManyInput, + SearchInput, + TextField, + TopToolbar, + useRecordContext +} from '@applica-software-guru/react-admin'; + +import { SupplierReferentForm } from 'components/ra-forms'; + +const SupplierReferentManyInput = () => { + const record = useRecordContext(); + return ( + ]} + sort={{ field: 'created', order: 'ASC' }} + actions={ + + + + + + } + > + + + + + + + + + + + + + + + ); +}; + +export default SupplierReferentManyInput; diff --git a/edera-web/src/components/ra-inputs/SupplyActivityAutocompleteInput.js b/edera-web/src/components/ra-inputs/SupplyActivityAutocompleteInput.js new file mode 100644 index 0000000..f144b7c --- /dev/null +++ b/edera-web/src/components/ra-inputs/SupplyActivityAutocompleteInput.js @@ -0,0 +1,93 @@ +import { AutocompleteInput, ReferenceInput, useTranslate, useDataProvider, useNotify } from '@applica-software-guru/react-admin'; +import { useEffect, useState } from 'react'; +import { useFormContext, useWatch } from 'react-hook-form'; +import { usePermissions } from 'react-admin'; +import _ from 'lodash'; +import { Alert, AlertTitle, Typography } from '@mui/material'; +import { Box } from '@mui/material'; + +const AlertBox = () => { + const [supplyDetails, setSupplyDetails] = useState(null); + const dataProvider = useDataProvider(); + const notify = useNotify(); + const translate = useTranslate(); + const supplyId = useWatch({ + name: 'supplyId' + }); + + useEffect(() => { + if (!supplyId) return; + + const fetchDetails = async () => { + try { + const { data } = await dataProvider.get(`maintenance/supply-info/${supplyId}`); + setSupplyDetails(data.supplyDetailsDTO); + } catch (error) { + notify('ra.notification.http_error', 'error', {}); + } + }; + + fetchDetails(); + }, [supplyId, dataProvider, notify]); + + if (!supplyDetails) return null; + + return ( + + {translate('resources.entities/supply.title')}: + + + ); +}; + +const renderText = (record) => + `${record.supplier.businessName} - ${record.equipmentType.name} - ${record.protocol.title} N° ${record.protocol.protocolNumber} - ${record.ddtNumber}`; + +const SupplyActivityAutocompleteInput = ({ validate, ...props }) => { + const { setValue } = useFormContext(); + const customerId = useWatch({ + name: 'customer.id' + }); + const supplierId = useWatch({ + name: 'supply.supplierId' + }); + const { permissions, isLoading } = usePermissions(); + + useEffect(() => { + if (_.isEmpty(customerId) || _.isEmpty(supplierId)) { + setValue('supplyId', null); + } + }, [customerId, supplierId, setValue]); + + const filter = + !isLoading && permissions.includes('customer:list') ? { customerId: customerId || 'none', supplierId: supplierId || 'none' } : {}; + + return ( + + ({ keyword: searchText })} + filter={filter} + perPage={100} + sort={{ + field: 'name', + order: 'ASC' + }} + > + + + + + ); +}; + +export default SupplyActivityAutocompleteInput; diff --git a/edera-web/src/components/ra-inputs/SupplyAutocompleteInput.js b/edera-web/src/components/ra-inputs/SupplyAutocompleteInput.js new file mode 100644 index 0000000..d008f99 --- /dev/null +++ b/edera-web/src/components/ra-inputs/SupplyAutocompleteInput.js @@ -0,0 +1,25 @@ +import { AutocompleteInput, ReferenceInput } from '@applica-software-guru/react-admin'; +import { useWatch } from 'react-hook-form'; + +const renderText = (record) => + `${record.supplier.businessName} - ${record.equipmentType.name} - ${record.protocol.title} N° ${record.protocol.protocolNumber} - ${record.ddtNumber}`; + +const SupplyAutocompleteInput = ({ label, validate, ...props }) => { + const supplierId = useWatch({ name: 'supplierId' }); + return ( + + + + ); +}; + +export default SupplyAutocompleteInput; diff --git a/edera-web/src/components/ra-inputs/SupplyManyInput.js b/edera-web/src/components/ra-inputs/SupplyManyInput.js new file mode 100644 index 0000000..8069e0c --- /dev/null +++ b/edera-web/src/components/ra-inputs/SupplyManyInput.js @@ -0,0 +1,72 @@ +import { + ActionsMenu, + BulkDeleteWithConfirmButton, + CreateInDialogButton, + Datagrid, + DateField, + DeleteWithConfirmButton, + EditInDialogButton, + ReferenceManyInput, + TextField, + TopToolbar, + usePermissions, + useRecordContext, + useThemeConfig +} from '@applica-software-guru/react-admin'; + +import { Grid } from '@mui/material'; +import ProtocolAutoComplete from './ProtocolAutoComplete'; +import { SupplyDialogForm } from 'components/ra-forms'; + +const SupplyManyInput = () => { + const record = useRecordContext(); + const { spacing } = useThemeConfig(); + const { permissions, isLoading } = usePermissions(); + const canEdit = !isLoading && permissions.includes('equipment-attachment:edit'); + const canCreate = !isLoading && permissions.includes('equipment-attachment:new'); + + return ( + + + ]} + sort={{ field: 'created', order: 'ASC' }} + actions={ + + {canCreate && ( + + + + )} + + } + > + }> + + + + + + {canEdit && ( + + + + + + + )} + + + + + ); +}; + +export default SupplyManyInput; diff --git a/edera-web/src/components/ra-inputs/UserAutocompleteInput.js b/edera-web/src/components/ra-inputs/UserAutocompleteInput.js new file mode 100644 index 0000000..60b1037 --- /dev/null +++ b/edera-web/src/components/ra-inputs/UserAutocompleteInput.js @@ -0,0 +1,9 @@ +import { AutocompleteInput, ReferenceInput } from '@applica-software-guru/react-admin'; + +const UserAutocompleteInput = ({ validate, ...props }) => ( + ({ name: searchText })}> + + +); + +export default UserAutocompleteInput; diff --git a/edera-web/src/components/ra-inputs/YesOrNoSelectInput.js b/edera-web/src/components/ra-inputs/YesOrNoSelectInput.js new file mode 100644 index 0000000..0426106 --- /dev/null +++ b/edera-web/src/components/ra-inputs/YesOrNoSelectInput.js @@ -0,0 +1,13 @@ +import { SelectInput } from '@applica-software-guru/react-admin'; +const YesOrNoSelectInput = (props) => ( + +); + +export default YesOrNoSelectInput; diff --git a/edera-web/src/components/ra-inputs/index.js b/edera-web/src/components/ra-inputs/index.js new file mode 100644 index 0000000..4e3ce71 --- /dev/null +++ b/edera-web/src/components/ra-inputs/index.js @@ -0,0 +1,39 @@ +export { default as ActivitySelectInput } from './ActivitySelectInput'; +export { default as ActivityTypeAutocompleteInput } from './ActivityTypeAutocompleteInput'; +export { default as CityAutocompleteInput } from './CityAutocompleteInput'; +export { default as CustomerAreaManyInput } from './CustomerAreaManyInput'; +export { default as CustomerAutocompleteInput } from './CustomerAutocompleteInput'; +export { default as CustomerOfficeAutocompleteInput } from './CustomerOfficeAutocompleteInput'; +export { default as CustomerOfficeManyInput } from './CustomerOfficeManyInput'; +export { default as CustomerReferentManyInput } from './CustomerReferentManyInput'; +export { default as EquipmentAttachmentManyInput } from './EquipmentAttachmentManyInput'; +export { default as EquipmentAutocompleteInput } from './EquipmentAutocompleteInput'; +export { default as EquipmentListAutocompleteInput } from './EquipmentListAutocompleteInput'; +export { default as EquipmentManyInput } from './EquipmentManyInput'; +export { default as EquipmentTypeAttachmentManyInput } from './EquipmentTypeAttachmentManyInput'; +export { default as EquipmentTypeAutocompleteInput } from './EquipmentTypeAutocompleteInput'; +export { default as EquipmentTypeManyInput } from './EquipmentTypeManyInput'; +export { default as InterventionArrayInput } from './InterventionArrayInput'; +export { default as LangSelectInput } from './LangSelectInput'; +export { default as MaintenanceManyInput } from './MaintenanceManyInput'; +export { default as MoneyInput } from './MoneyInput'; +export { default as NationAutocompleteInput } from './NationAutocompleteInput'; +export { default as PriceListItemManyInput } from './PriceListItemManyInput'; +export { default as PriceListManyInput } from './PriceListManyInput'; +export { default as ProtocolAttachmentManyInput } from './ProtocolAttachmentManyInput'; +export { default as ProtocolAutoComplete } from './ProtocolAutoComplete'; +export { default as ProvinceAutocompleteInput } from './ProvinceAutocompleteInput'; +export { default as RFIDDeviceAutocomplete } from './RFIDDeviceAutocomplete'; +export { default as RFIDDeviceTypeSelectInput } from './RFIDDeviceTypeSelectInput'; +export { default as RegionAutocompleteInput } from './RegionAutocompleteInput'; +export { default as SupplierAutocompleteInput } from './SupplierAutocompleteInput'; +export { default as SupplierReferentManyInput } from './SupplierReferentManyInput'; +export { default as SupplyActivityAutocompleteInput } from './SupplyActivityAutocompleteInput'; +export { default as SupplyManyInput } from './SupplyManyInput'; +export { default as UserAutocompleteInput } from './UserAutocompleteInput'; +export { default as YesOrNoSelectInput } from './YesOrNoSelectInput'; +export { default as CustomerReadOnlyInput } from './CustomerReadOnlyInput'; +export { default as CustomerAreaAutocompleteInput } from './CustomerAreaAutocompleteInput'; +export { default as SupplyAutocompleteInput } from './SupplyAutocompleteInput'; +export { default as DocxTemplateTypeSelectInput } from './DocxTemplateTypeSelectInput'; +export { default as ProtocolServiceArrayInput } from './ProtocolServiceArrayInput'; diff --git a/edera-web/src/components/ra-lists/ActivityList.js b/edera-web/src/components/ra-lists/ActivityList.js new file mode 100644 index 0000000..d3149da --- /dev/null +++ b/edera-web/src/components/ra-lists/ActivityList.js @@ -0,0 +1,57 @@ +import { ActivityTypeAutocompleteInput, CustomerAutocompleteInput, SupplyActivityAutocompleteInput } from 'components/ra-inputs'; +import { + BulkDeleteWithConfirmButton, + Datagrid, + DateField, + List, + ReferenceField, + SearchInput, + SelectInput, + TextField, + usePermissions +} from '@applica-software-guru/react-admin'; + +import { ActivityStatusField } from 'components/ra-fields'; + +const ActivityList = ({ activityStatus }) => { + const { permissions, isLoading } = usePermissions(); + const canDelete = !isLoading && permissions.includes('activity:delete'); + const canCreate = !isLoading && permissions.includes('activity:new'); + + const filtersList = [ + , + , + , + + ]; + + if (!isLoading && permissions.includes('customer:list')) { + filtersList.push(); + } + + return ( + + }> + {!isLoading && permissions.includes('supplier:list') && ( + + + + )} + {!isLoading && permissions.includes('customer:list') && } + {!isLoading && permissions.includes('equipment:list') && ( + + + + )} + + + + + + + + + ); +}; + +export default ActivityList; diff --git a/edera-web/src/components/ra-lists/ActivityTypeList.js b/edera-web/src/components/ra-lists/ActivityTypeList.js new file mode 100644 index 0000000..4d00ac2 --- /dev/null +++ b/edera-web/src/components/ra-lists/ActivityTypeList.js @@ -0,0 +1,13 @@ +import { AttachmentField, Datagrid, DateField, List, SearchInput, TextField } from '@applica-software-guru/react-admin'; + +const ActivityTypeList = () => ( + ]}> + + + + + + +); + +export default ActivityTypeList; diff --git a/edera-web/src/components/ra-lists/AuditLogList.js b/edera-web/src/components/ra-lists/AuditLogList.js new file mode 100644 index 0000000..4d788f6 --- /dev/null +++ b/edera-web/src/components/ra-lists/AuditLogList.js @@ -0,0 +1,49 @@ +import { Datagrid, DateField, DateTimeInput, List, ReferenceField, SearchInput, TextField } from '@applica-software-guru/react-admin'; + +import { AuditLogMessageField } from '../ra-fields'; +import { UserAutocompleteInput } from 'components/ra-inputs'; + +const parse = (date) => date; + +const AuditLogList = () => { + return ( + , + , + , + + ]} + > + + + + + + + + + ); +}; + +export default AuditLogList; diff --git a/edera-web/src/components/ra-lists/CustomerList.js b/edera-web/src/components/ra-lists/CustomerList.js new file mode 100644 index 0000000..2e2c673 --- /dev/null +++ b/edera-web/src/components/ra-lists/CustomerList.js @@ -0,0 +1,45 @@ +import { + BooleanField, + CreateInDialogButton, + Datagrid, + DateField, + Empty, + List, + SearchInput, + TextField +} from '@applica-software-guru/react-admin'; + +import { CustomerCreateForm } from '../ra-forms'; + +const Actions = () => ( + + + +); + +const CustomerList = () => ( + ]} + empty={} />} + actions={} + > + + + + + + + +); + +export default CustomerList; diff --git a/edera-web/src/components/ra-lists/DeviceList.js b/edera-web/src/components/ra-lists/DeviceList.js new file mode 100644 index 0000000..a04aa85 --- /dev/null +++ b/edera-web/src/components/ra-lists/DeviceList.js @@ -0,0 +1,25 @@ +import { Datagrid, DateField, List, SearchInput, TextField, useThemeConfig, useTranslate } from '@applica-software-guru/react-admin'; + +import { Alert } from '@mui/material'; + +const AlertBox = () => { + const { spacing } = useThemeConfig(); + const translate = useTranslate(); + return ( + + {translate('resources.entities/device.alert')} + + ); +}; +const DeviceList = () => ( + ]}> + + + + + + + +); + +export default DeviceList; diff --git a/edera-web/src/components/ra-lists/DocxTemplateList.js b/edera-web/src/components/ra-lists/DocxTemplateList.js new file mode 100644 index 0000000..790376d --- /dev/null +++ b/edera-web/src/components/ra-lists/DocxTemplateList.js @@ -0,0 +1,13 @@ +import { AttachmentField, Datagrid, DateField, List, SearchInput, TextField } from '@applica-software-guru/react-admin'; + +const DocxTemplateList = () => ( + ]}> + + + + + + +); + +export default DocxTemplateList; diff --git a/edera-web/src/components/ra-lists/EquipmentList.js b/edera-web/src/components/ra-lists/EquipmentList.js new file mode 100644 index 0000000..f2cf3d0 --- /dev/null +++ b/edera-web/src/components/ra-lists/EquipmentList.js @@ -0,0 +1,56 @@ +import { + BulkDeleteWithConfirmButton, + CreateInDialogButton, + Datagrid, + DateField, + Empty, + List, + SearchInput, + TextField, + usePermissions +} from '@applica-software-guru/react-admin'; + +import { EquipmentCreateInDialogForm } from 'components/ra-forms'; + +const Actions = () => { + const { permissions, isLoading } = usePermissions(); + return ( + !isLoading && + permissions.includes('equipment:new') && ( + + + + ) + ); +}; + +const EquipmentList = () => { + const { permissions, isLoading } = usePermissions(); + const canDelete = !isLoading && permissions.includes('equipment:delete'); + return ( + ]} + exporter={false} + actions={} + empty={} />} + > + }> + {!isLoading && permissions.includes('supplier:list') && } + + + + + ); +}; + +export default EquipmentList; diff --git a/edera-web/src/components/ra-lists/EquipmentTypeList.js b/edera-web/src/components/ra-lists/EquipmentTypeList.js new file mode 100644 index 0000000..61e37c6 --- /dev/null +++ b/edera-web/src/components/ra-lists/EquipmentTypeList.js @@ -0,0 +1,30 @@ +import { BooleanField, Datagrid, DateField, List, SearchInput, TextField, CreateInDialogButton } from '@applica-software-guru/react-admin'; +import { EquipmentTypeCreateForm } from 'components/ra-forms'; + +const Actions = () => ( + + + +); + +const EquipmentTypeList = () => ( + ]} exporter={false} actions={}> + + + + + + + +); + +export default EquipmentTypeList; diff --git a/edera-web/src/components/ra-lists/I18nMessageList.js b/edera-web/src/components/ra-lists/I18nMessageList.js new file mode 100644 index 0000000..9c0d684 --- /dev/null +++ b/edera-web/src/components/ra-lists/I18nMessageList.js @@ -0,0 +1,14 @@ +import { ActionsField, Datagrid, List, RecordInput, SearchInput, TextField } from '@applica-software-guru/react-admin'; + +const I18nMessageList = () => ( + ]}> + + + + + + + +); + +export default I18nMessageList; diff --git a/edera-web/src/components/ra-lists/MaintenanceList.js b/edera-web/src/components/ra-lists/MaintenanceList.js new file mode 100644 index 0000000..708d676 --- /dev/null +++ b/edera-web/src/components/ra-lists/MaintenanceList.js @@ -0,0 +1,35 @@ +import { ActivitySelectInput, UserAutocompleteInput } from 'components/ra-inputs'; +import { + BulkDeleteWithConfirmButton, + Datagrid, + DateField, + List, + SearchInput, + TextField, + usePermissions +} from '@applica-software-guru/react-admin'; + +const MaintenanceList = () => { + const { isLoading, permissions } = usePermissions(); + const canDelete = !isLoading && permissions.includes('maintenance:delete'); + return ( + , + , + + ]} + > + }> + + + + + + + + ); +}; + +export default MaintenanceList; diff --git a/edera-web/src/components/ra-lists/ProtocolList.js b/edera-web/src/components/ra-lists/ProtocolList.js new file mode 100644 index 0000000..ebd8815 --- /dev/null +++ b/edera-web/src/components/ra-lists/ProtocolList.js @@ -0,0 +1,55 @@ +import { + BulkDeleteWithConfirmButton, + CreateInDialogButton, + Datagrid, + DateField, + Empty, + List, + SearchInput, + TextField, + usePermissions +} from '@applica-software-guru/react-admin'; +import { ProtocolDialogForm } from 'components/ra-forms'; + +import { CustomerAutocompleteInput } from 'components/ra-inputs'; + +const Actions = () => ( + + + +); + +const ProtocolList = () => { + const { permissions, isLoading } = usePermissions(); + const canCreate = !isLoading && permissions.includes('protocol:new'); + const canDelete = !isLoading && permissions.includes('protocol:delete'); + + const filtersList = []; + + if (!isLoading && permissions.includes('customer:list')) { + filtersList.push(); + } + + return ( + } />} actions={}> + }> + {!isLoading && permissions.includes('customer:list') && } + + + + + + + ); +}; + +export default ProtocolList; diff --git a/edera-web/src/components/ra-lists/RFIDDeviceList.js b/edera-web/src/components/ra-lists/RFIDDeviceList.js new file mode 100644 index 0000000..06d2838 --- /dev/null +++ b/edera-web/src/components/ra-lists/RFIDDeviceList.js @@ -0,0 +1,14 @@ +import { Datagrid, DateField, List, SearchInput, TextField } from '@applica-software-guru/react-admin'; + +const RFIDeviceList = () => ( + ]}> + + + + + + + +); + +export default RFIDeviceList; diff --git a/edera-web/src/components/ra-lists/RFIDDeviceTrackList.js b/edera-web/src/components/ra-lists/RFIDDeviceTrackList.js new file mode 100644 index 0000000..bc21ae1 --- /dev/null +++ b/edera-web/src/components/ra-lists/RFIDDeviceTrackList.js @@ -0,0 +1,123 @@ +import { + Datagrid, + DateField, + DateTimeInput, + List, + MainCard, + ReferenceField, + TextField, + useListContext, + useThemeConfig, + useTranslate +} from '@applica-software-guru/react-admin'; +import { Grid, List as MuiList, ListItem, ListItemText, Typography } from '@mui/material'; +import { RFIDDeviceAutocomplete, SupplyAutocompleteInput, CustomerAreaAutocompleteInput } from 'components/ra-inputs'; +import queryString from 'query-string'; +import { useLocation } from 'react-router-dom'; +import { Fragment, useEffect } from 'react'; + +const FilterSetter = () => { + const location = useLocation(); + const queryParams = queryString.parse(location.search); + const gatewayId = queryParams['gateway-id']; + const { setFilters } = useListContext(); + + useEffect(() => { + if (gatewayId) { + setFilters({ gatewayId: gatewayId }); + } + }, [gatewayId, setFilters]); + + return null; +}; + +const RFIDDeviceTrackList = () => { + const translate = useTranslate(); + const { spacing } = useThemeConfig(); + const location = useLocation(); + const queryParams = queryString.parse(location.search); + const gatewayId = queryParams['gateway-id']; + const currentUrl = `http://${window.location.hostname}${window.location.port ? `:8080` : ''}/api/track?`; + + return ( + + + + + + {`${currentUrl}`}} /> + + + + + Includere tag (ID del tag RFID), timestamp e gate (ID del gateway RFID). Il campo{' '} + timestamp, se non specificato, sarà impostato al momento della chiamata automaticamente. +
+
+ + Attenzione: ricorda che tag e gateway devono essere preventivamente registrati nel sistema all'interno della + sezione RFID. + + + } + /> +
+ + GET {`${currentUrl}tag=1234&gate=gate01`}} /> + + + + È possibile aggiungere ulteriori parametri che saranno accodati alla chiamata. + + } + /> + +
+
+
+ + , + , + , + , + , + + ]} + sort={{ field: 'ts', order: 'DESC' }} + > + + + + + + + + `/entities/customer/${data?.customerId}/areas`} + > + + + + + + + +
+ ); +}; + +export default RFIDDeviceTrackList; diff --git a/edera-web/src/components/ra-lists/SupplierList.js b/edera-web/src/components/ra-lists/SupplierList.js new file mode 100644 index 0000000..ba0367b --- /dev/null +++ b/edera-web/src/components/ra-lists/SupplierList.js @@ -0,0 +1,36 @@ +import { CreateInDialogButton, Datagrid, DateField, Empty, List, SearchInput, TextField } from '@applica-software-guru/react-admin'; +import { SupplierCreateForm } from 'components/ra-forms'; + +const Actions = () => ( + + + +); + +const SupplierList = () => ( + ]} + exporter={false} + empty={} />} + actions={} + > + + + + + + + +); + +export default SupplierList; diff --git a/edera-web/src/components/ra-lists/SupplyList.js b/edera-web/src/components/ra-lists/SupplyList.js new file mode 100644 index 0000000..89918bd --- /dev/null +++ b/edera-web/src/components/ra-lists/SupplyList.js @@ -0,0 +1,35 @@ +import { BulkDeleteWithConfirmButton, Datagrid, DateField, List, TextField, usePermissions } from '@applica-software-guru/react-admin'; +import { SupplyStatusField } from 'components/ra-fields'; +import { EquipmentListAutocompleteInput, ProtocolAutoComplete, SupplierAutocompleteInput } from 'components/ra-inputs'; + +const SupplyList = () => { + const { isLoading, permissions } = usePermissions(); + const canCreate = !isLoading && permissions.includes('supply:new'); + const canDelete = !isLoading && permissions.includes('supply:delete'); + + const filtersList = [ + , + + ]; + + if (!isLoading && permissions.includes('supplier:list')) { + filtersList.push(); + } + + return ( + + }> + {!isLoading && permissions.includes('supplier:list') && } + {!isLoading && permissions.includes('equipment:list') && } + + + + + + + + + ); +}; + +export default SupplyList; diff --git a/edera-web/src/components/ra-lists/UserList.js b/edera-web/src/components/ra-lists/UserList.js new file mode 100644 index 0000000..06a7d1a --- /dev/null +++ b/edera-web/src/components/ra-lists/UserList.js @@ -0,0 +1,95 @@ +import { + BooleanField, + BooleanInput, + CoverField, + Datagrid, + DateField, + EmailField, + FunctionField, + ImpersonateUserButton, + List, + ReferenceField, + SearchInput, + SelectInput, + SimpleList, + TextField, + useTranslate +} from '@applica-software-guru/react-admin'; +import { Chip, useMediaQuery } from '@mui/material'; + +import { CustomerAutocompleteInput } from 'components/ra-inputs'; +import PropTypes from 'prop-types'; + +const sortRoles = (roles, configuredRoles) => { + return roles + ?.filter((r) => configuredRoles.find((cr) => cr.id === r)) + .sort((a, b) => { + const aIndex = configuredRoles.findIndex((r) => r.id === a); + const bIndex = configuredRoles.findIndex((r) => r.id === b); + + return aIndex - bIndex; + }); +}; +const UserList = ({ configuredRoles }) => { + const isSmall = useMediaQuery((theme) => theme.breakpoints.down('sm')); + const translate = useTranslate(); + return ( + , + , + + , + + ]} + > + {isSmall ? ( + } + primaryText={(record) => record.name} + secondaryText={(record) => record.email} + /> + ) : ( + + + + + + + + + + + sortRoles(record?.roles, configuredRoles)?.map((role) => ( + r.id === role)?.name)} + key={role} + sx={{ mr: 1, mt: 1 }} + color="secondary" + /> + )) + } + /> + + + )} + + ); +}; + +UserList.propTypes = { + configuredRoles: PropTypes.arrayOf(PropTypes.shape({ id: PropTypes.string, name: PropTypes.string })).isRequired +}; + +export default UserList; diff --git a/edera-web/src/components/ra-lists/index.js b/edera-web/src/components/ra-lists/index.js new file mode 100644 index 0000000..4457fea --- /dev/null +++ b/edera-web/src/components/ra-lists/index.js @@ -0,0 +1,16 @@ +export { default as AuditLogList } from './AuditLogList'; +export { default as CustomerList } from './CustomerList'; +export { default as DeviceList } from './DeviceList'; +export { default as I18nMessageList } from './I18nMessageList'; +export { default as RFIDeviceList } from './RFIDDeviceList'; +export { default as SupplierList } from './SupplierList'; +export { default as UserList } from './UserList'; +export { default as EquipmentTypeList } from './EquipmentTypeList'; +export { default as ProtocolList } from './ProtocolList'; +export { default as SupplyList } from './SupplyList'; +export { default as ActivityList } from './ActivityList'; +export { default as ActivityTypeList } from './ActivityTypeList'; +export { default as MaintenanceList } from './MaintenanceList'; +export { default as EquipmentList } from './EquipmentList'; +export { default as RFIDDeviceTrackList } from './RFIDDeviceTrackList'; +export { default as DocxTemplateList } from './DocxTemplateList'; diff --git a/edera-web/src/config.js b/edera-web/src/config.js new file mode 100644 index 0000000..28b41c7 --- /dev/null +++ b/edera-web/src/config.js @@ -0,0 +1,27 @@ +let environment = 'PRODUCTION'; +let appUrl = `//${document.location.host}/`; +if (appUrl.endsWith(':3000/')) { + appUrl = 'http://localhost:8080/'; + environment = 'DEVELOPER'; +} else if (appUrl.endsWith(':3001/')) { + appUrl = 'http://localhost:8001/'; + environment = 'DEVELOPER'; +} +export const APP_URL = appUrl; +export const API_URL = `${APP_URL}api`; +export const ENVIRONMENT = environment; +export const APP_NAME = 'Edera'; +export const COPY = '© Dyrecta for '; + +export const CONFIGURED_ROLES = [ + { id: 'ROLE_ADMIN', name: 'ra.roles.admin' }, + { id: 'ROLE_OPERATOR', name: 'ra.roles.operator' }, + { id: 'ROLE_USER', name: 'ra.roles.user' }, + { id: 'ROLE_MAINTAINER', name: 'ra.roles.maintainer' }, + { id: 'ROLE_CUSTOMER', name: 'ra.roles.customer' } +]; + +export const ACTIVITY_STATUS = [ + { id: 'OPEN', name: 'ra.status.open' }, + { id: 'CLOSED', name: 'ra.status.closed' } +]; diff --git a/edera-web/src/contexts/index.js b/edera-web/src/contexts/index.js new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/edera-web/src/contexts/index.js @@ -0,0 +1 @@ +export {}; diff --git a/edera-web/src/entities/activity-type.js b/edera-web/src/entities/activity-type.js new file mode 100644 index 0000000..eb77f85 --- /dev/null +++ b/edera-web/src/entities/activity-type.js @@ -0,0 +1,23 @@ +import { ActivityTypeForm, ActivityTypeList } from 'components'; +import { Create, Edit } from '@applica-software-guru/react-admin'; +const ActivityTypeCreate = () => ( + + + +); +const ActivityTypeEdit = () => ( + + + +); + +const config = { + list: ActivityTypeList, + edit: ActivityTypeEdit, + create: ActivityTypeCreate, + options: { + group: 'maintenance' + } +}; + +export default config; diff --git a/edera-web/src/entities/activity.js b/edera-web/src/entities/activity.js new file mode 100644 index 0000000..4fb135e --- /dev/null +++ b/edera-web/src/entities/activity.js @@ -0,0 +1,27 @@ +import { ActivityForm, ActivityList } from 'components'; +import { Create, Edit } from '@applica-software-guru/react-admin'; + +import { ACTIVITY_STATUS } from 'config'; +const ActivityCreate = () => ( + + + +); +const ActivityEdit = () => ( + + + +); + +const CustomActivityList = () => ; + +const config = { + list: CustomActivityList, + edit: ActivityEdit, + create: ActivityCreate, + options: { + group: 'maintenance' + } +}; + +export default config; diff --git a/edera-web/src/entities/audit-log.js b/edera-web/src/entities/audit-log.js new file mode 100644 index 0000000..4b6da55 --- /dev/null +++ b/edera-web/src/entities/audit-log.js @@ -0,0 +1,10 @@ +import { AuditLogList } from 'components'; + +const config = { + list: AuditLogList, + options: { + group: 'security' + } +}; + +export default config; diff --git a/edera-web/src/entities/customer.js b/edera-web/src/entities/customer.js new file mode 100644 index 0000000..ea61471 --- /dev/null +++ b/edera-web/src/entities/customer.js @@ -0,0 +1,25 @@ +import { Create, Edit } from '@applica-software-guru/react-admin'; +import { CustomerEditForm, CustomerList } from 'components'; + +const CustomerCreate = () => ( + + + +); + +const CustomerEdit = () => ( + + + +); + +const config = { + list: CustomerList, + edit: CustomerEdit, + create: CustomerCreate, + options: { + group: 'control-panel' + } +}; + +export default config; diff --git a/edera-web/src/entities/device.js b/edera-web/src/entities/device.js new file mode 100644 index 0000000..224cf4d --- /dev/null +++ b/edera-web/src/entities/device.js @@ -0,0 +1,23 @@ +import { Create, Edit } from '@applica-software-guru/react-admin'; +import { DeviceForm, DeviceList } from 'components'; +const DeviceCreate = () => ( + + + +); +const DeviceEdit = () => ( + + + +); + +const config = { + list: DeviceList, + edit: DeviceEdit, + create: DeviceCreate, + options: { + group: 'security' + } +}; + +export default config; diff --git a/edera-web/src/entities/docx-template.js b/edera-web/src/entities/docx-template.js new file mode 100644 index 0000000..ff2b69c --- /dev/null +++ b/edera-web/src/entities/docx-template.js @@ -0,0 +1,23 @@ +import { DocxTemplateForm, DocxTemplateList } from 'components'; +import { Create, Edit } from '@applica-software-guru/react-admin'; +const DocxTemplateCreate = () => ( + + + +); +const DocxTemplateEdit = () => ( + + + +); + +const config = { + list: DocxTemplateList, + edit: DocxTemplateEdit, + create: DocxTemplateCreate, + options: { + group: 'control-panel' + } +}; + +export default config; diff --git a/edera-web/src/entities/equipment-type.js b/edera-web/src/entities/equipment-type.js new file mode 100644 index 0000000..768060d --- /dev/null +++ b/edera-web/src/entities/equipment-type.js @@ -0,0 +1,24 @@ +import { Create, Edit } from '@applica-software-guru/react-admin'; +import { EquipmentTypeList, EquipmentTypeEditForm, EquipmentTypeCreateForm } from 'components'; + +const EquipmentTypeCreate = () => ( + + + +); +const EquipmentTypeEdit = () => ( + + + +); + +const config = { + list: EquipmentTypeList, + edit: EquipmentTypeEdit, + create: EquipmentTypeCreate, + options: { + group: 'control-panel' + } +}; + +export default config; diff --git a/edera-web/src/entities/equipment.js b/edera-web/src/entities/equipment.js new file mode 100644 index 0000000..b7eaf9f --- /dev/null +++ b/edera-web/src/entities/equipment.js @@ -0,0 +1,24 @@ +import { Create, Edit } from '@applica-software-guru/react-admin'; +import { EquipmentCreateForm, EquipmentEditForm, EquipmentList } from 'components'; + +const EquipmentCreate = () => ( + + + +); +const EquipmentEdit = () => ( + + + +); + +const config = { + edit: EquipmentEdit, + create: EquipmentCreate, + list: EquipmentList, + options: { + group: 'control-panel' + } +}; + +export default config; diff --git a/edera-web/src/entities/i18n-message.js b/edera-web/src/entities/i18n-message.js new file mode 100644 index 0000000..7ea7363 --- /dev/null +++ b/edera-web/src/entities/i18n-message.js @@ -0,0 +1,25 @@ +import { Create, Edit } from '@applica-software-guru/react-admin'; +import { I18nMessageForm, I18nMessageList } from 'components'; + +const MessageCreate = () => ( + + + +); + +const MessageEdit = () => ( + + + +); + +const config = { + list: I18nMessageList, + edit: MessageEdit, + create: MessageCreate, + options: { + group: 'control-panel' + } +}; + +export default config; diff --git a/edera-web/src/entities/index.js b/edera-web/src/entities/index.js new file mode 100644 index 0000000..0660353 --- /dev/null +++ b/edera-web/src/entities/index.js @@ -0,0 +1,18 @@ +export { default as user } from './user'; +export { default as notification } from './notification'; +export { default as i18nMessage } from './i18n-message'; +export { default as device } from './device'; +export { default as auditLog } from './audit-log'; +export { default as rfidDevice } from './rfid-device'; +export { default as customer } from './customer'; +export { default as supplier } from './supplier'; +export { default as equipmentType } from './equipment-type'; +export { default as priceList } from './price-list'; +export { default as protocol } from './protocol'; +export { default as equipment } from './equipment'; +export { default as supply } from './supply'; +export { default as activity } from './activity'; +export { default as activityType } from './activity-type'; +export { default as maintenance } from './maintenance'; +export { default as rfidDeviceTrack } from './rfid-device-track'; +export { default as docxTemplate } from './docx-template'; diff --git a/edera-web/src/entities/maintenance.js b/edera-web/src/entities/maintenance.js new file mode 100644 index 0000000..d0e6b04 --- /dev/null +++ b/edera-web/src/entities/maintenance.js @@ -0,0 +1,23 @@ +import { Create, Edit } from '@applica-software-guru/react-admin'; +import { MaintenanceCreateForm, MaintenanceEditForm, MaintenanceList } from 'components'; +const MaintenanceCreate = () => ( + + + +); +const MaintenanceEdit = () => ( + + + +); + +const config = { + list: MaintenanceList, + edit: MaintenanceEdit, + create: MaintenanceCreate, + options: { + group: 'maintenance' + } +}; + +export default config; diff --git a/edera-web/src/entities/notification.js b/edera-web/src/entities/notification.js new file mode 100644 index 0000000..ebd46e2 --- /dev/null +++ b/edera-web/src/entities/notification.js @@ -0,0 +1,16 @@ +import { NotificationList as BaseNotificationList, List } from '@applica-software-guru/react-admin'; + +import React from 'react'; + +const NotificationList = () => ( + + + +); +const config = { + list: NotificationList, + options: { + group: 'dashboard' + } +}; +export default config; diff --git a/edera-web/src/entities/price-list.js b/edera-web/src/entities/price-list.js new file mode 100644 index 0000000..c33c6f4 --- /dev/null +++ b/edera-web/src/entities/price-list.js @@ -0,0 +1,25 @@ +import { Create, Edit } from '@applica-software-guru/react-admin'; + +import { PriceListForm } from 'components'; + +const PriceListCreate = () => ( + + + +); + +const PriceListEdit = () => ( + + + +); + +const config = { + edit: PriceListEdit, + create: PriceListCreate, + options: { + group: 'control-panel' + } +}; + +export default config; diff --git a/edera-web/src/entities/protocol.js b/edera-web/src/entities/protocol.js new file mode 100644 index 0000000..55158e6 --- /dev/null +++ b/edera-web/src/entities/protocol.js @@ -0,0 +1,24 @@ +import { Create, Edit } from '@applica-software-guru/react-admin'; +import { ProtocolList, ProtocolForm, ProtocolDialogForm } from 'components'; + +const ProtocolCreate = () => ( + + + +); +const ProtocolEdit = () => ( + + + +); + +const config = { + list: ProtocolList, + edit: ProtocolEdit, + create: ProtocolCreate, + options: { + group: 'control-panel' + } +}; + +export default config; diff --git a/edera-web/src/entities/rfid-device-track.js b/edera-web/src/entities/rfid-device-track.js new file mode 100644 index 0000000..6ce5a5d --- /dev/null +++ b/edera-web/src/entities/rfid-device-track.js @@ -0,0 +1,10 @@ +import { RFIDDeviceTrackList } from 'components'; + +const config = { + list: RFIDDeviceTrackList, + options: { + group: 'control-panel' + } +}; + +export default config; diff --git a/edera-web/src/entities/rfid-device.js b/edera-web/src/entities/rfid-device.js new file mode 100644 index 0000000..5abc2e7 --- /dev/null +++ b/edera-web/src/entities/rfid-device.js @@ -0,0 +1,23 @@ +import { Create, Edit } from '@applica-software-guru/react-admin'; +import { RFIDeviceList, RFIDDeviceForm } from 'components'; +const RFIDDeviceCreate = () => ( + + + +); +const RFIDDeviceEdit = () => ( + + + +); + +const config = { + list: RFIDeviceList, + edit: RFIDDeviceEdit, + create: RFIDDeviceCreate, + options: { + group: 'control-panel' + } +}; + +export default config; diff --git a/edera-web/src/entities/supplier.js b/edera-web/src/entities/supplier.js new file mode 100644 index 0000000..c827bd8 --- /dev/null +++ b/edera-web/src/entities/supplier.js @@ -0,0 +1,24 @@ +import { Create, Edit } from '@applica-software-guru/react-admin'; +import { SupplierList, SupplierForm } from 'components'; + +const SupplierCreate = () => ( + + + +); +const SupplierEdit = () => ( + + + +); + +const config = { + list: SupplierList, + edit: SupplierEdit, + create: SupplierCreate, + options: { + group: 'control-panel' + } +}; + +export default config; diff --git a/edera-web/src/entities/supply.js b/edera-web/src/entities/supply.js new file mode 100644 index 0000000..542de0f --- /dev/null +++ b/edera-web/src/entities/supply.js @@ -0,0 +1,25 @@ +import { Create, Edit } from '@applica-software-guru/react-admin'; +import { SupplyForm, SupplyList, SupplyShow } from 'components'; + +const SupplyCreate = () => ( + + + +); +const SupplyEdit = () => ( + + + +); + +const config = { + list: SupplyList, + edit: SupplyEdit, + create: SupplyCreate, + show: SupplyShow, + options: { + group: 'control-panel' + } +}; + +export default config; diff --git a/edera-web/src/entities/user.js b/edera-web/src/entities/user.js new file mode 100644 index 0000000..c800e2f --- /dev/null +++ b/edera-web/src/entities/user.js @@ -0,0 +1,26 @@ +import { Create, Edit } from '@applica-software-guru/react-admin'; +import { UserForm, UserList } from 'components'; + +import { CONFIGURED_ROLES } from 'config'; + +const UserCreate = () => ( + + + +); +const UserEdit = () => ( + + + +); + +const config = { + list: , + edit: UserEdit, + create: UserCreate, + options: { + group: 'security' + } +}; + +export default config; diff --git a/edera-web/src/hooks/index.js b/edera-web/src/hooks/index.js new file mode 100644 index 0000000..fddf830 --- /dev/null +++ b/edera-web/src/hooks/index.js @@ -0,0 +1 @@ +export { default as useRedirect } from './useRedirect'; diff --git a/edera-web/src/hooks/useRedirect.js b/edera-web/src/hooks/useRedirect.js new file mode 100644 index 0000000..46aad5f --- /dev/null +++ b/edera-web/src/hooks/useRedirect.js @@ -0,0 +1,11 @@ +const set = (path) => localStorage.setItem('redirect', path); +const get = (remove = true) => { + var redirect = localStorage.getItem('redirect'); + if (remove) { + localStorage.removeItem('redirect'); + } + return redirect; +}; +const useRedirect = () => ({ set, get }); + +export default useRedirect; diff --git a/edera-web/src/index.js b/edera-web/src/index.js new file mode 100644 index 0000000..64cc5af --- /dev/null +++ b/edera-web/src/index.js @@ -0,0 +1,10 @@ +import App from './App'; +import { createRoot } from 'react-dom/client'; +import reportWebVitals from './reportWebVitals'; + +const container = document.getElementById('root'); +const root = createRoot(container); + +root.render(); + +reportWebVitals(); diff --git a/edera-web/src/menu.js b/edera-web/src/menu.js new file mode 100644 index 0000000..26a614e --- /dev/null +++ b/edera-web/src/menu.js @@ -0,0 +1,204 @@ +import { + DashboardOutlined, + EyeOutlined, + FlagOutlined, + InboxOutlined, + NotificationOutlined, + ScheduleOutlined, + SolutionOutlined, + TableOutlined, + ToolOutlined, + UserOutlined, + UsergroupAddOutlined, + WifiOutlined, + GlobalOutlined +} from '@ant-design/icons'; +import RadarIcon from '@mui/icons-material/Radar'; +import EngineeringOutlinedIcon from '@mui/icons-material/EngineeringOutlined'; +const config = [ + { + id: 'dashboard', + title: 'Dashboard', + type: 'group', + icon: DashboardOutlined, + children: [ + { + id: 'entities/notification', + title: 'ra.menu.item.notification', + type: 'item', + url: '/entities/notification', + icon: NotificationOutlined + }, + { + id: 'position', + title: 'ra.menu.item.position', + type: 'item', + url: '/position', + icon: RadarIcon, + roles: ['ROLE_ADMIN', 'ROLE_OPERATOR'], + resource: false + } + ] + }, + { + id: 'maintenance', + title: 'ra.menu.maintenance', + icon: TableOutlined, + type: 'group', + children: [ + { + id: 'entities/activity-type', + title: 'ra.menu.item.entities/activity-type', + type: 'item', + url: '/entities/activity-type', + icon: TableOutlined, + resource: true, + roles: ['ROLE_ADMIN', 'ROLE_OPERATOR'] + }, + { + id: 'entities/activity', + title: 'ra.menu.item.entities/activity', + type: 'item', + url: '/entities/activity', + icon: ScheduleOutlined, + resource: true + }, + { + id: 'entities/maintenance', + title: 'ra.menu.item.entities/maintenance', + type: 'item', + url: '/entities/maintenance', + icon: EngineeringOutlinedIcon, + resource: true + } + ] + }, + { + id: 'control-panel', + title: 'ra.menu.control-panel', + icon: TableOutlined, + type: 'group', + children: [ + { + id: 'entities/customer', + title: 'ra.menu.item.entities/customer', + type: 'item', + url: '/entities/customer', + icon: UsergroupAddOutlined, + roles: ['ROLE_ADMIN', 'ROLE_OPERATOR'] + }, + { + id: 'entities/protocol', + title: 'ra.menu.item.entities/protocol', + type: 'item', + url: '/entities/protocol', + icon: SolutionOutlined, + resource: true + }, + { + id: 'entities/supplier', + title: 'ra.menu.item.supplier', + type: 'item', + url: '/entities/supplier', + icon: UserOutlined, + resource: true, + roles: ['ROLE_ADMIN', 'ROLE_OPERATOR'] + }, + { + id: 'entities/supply', + title: 'ra.menu.item.entities/supply', + type: 'item', + url: '/entities/supply', + icon: InboxOutlined, + resource: true, + roles: ['ROLE_ADMIN', 'ROLE_OPERATOR', 'ROLE_CUSTOMER', 'ROLE_MAINTAINER'] + }, + { + id: 'entities/equipment', + title: 'ra.menu.item.entities/equipment', + type: 'item', + url: '/entities/equipment', + icon: ToolOutlined, + resource: true + }, + { + id: 'entities/equipment-type', + title: 'ra.menu.item.entities/equipment-type', + type: 'item', + url: '/entities/equipment-type', + icon: TableOutlined, + resource: true, + roles: ['ROLE_ADMIN', 'ROLE_OPERATOR'] + }, + { + id: 'entities/rfid-device', + title: 'ra.menu.item.entities/rfid-device', + type: 'item', + url: '/entities/rfid-device', + icon: WifiOutlined, + resource: true, + roles: ['ROLE_ADMIN'] + }, + { + id: 'entities/docx-template', + title: 'ra.menu.item.entities/docx-template', + type: 'item', + url: '/entities/docx-template', + icon: TableOutlined, + resource: true, + roles: ['ROLE_ADMIN'] + }, + { + id: 'entities/rfid-device-track', + title: 'ra.menu.item.entities/rfid-device-track', + type: 'item', + url: '/entities/rfid-device-track', + icon: GlobalOutlined, + resource: true, + roles: ['ROLE_ADMIN'] + }, + { + id: 'entities/i18n-message', + title: 'ra.menu.item.entities/i18n-message', + type: 'item', + url: '/entities/i18n-message', + icon: FlagOutlined, + roles: ['ROLE_ADMIN'] + } + ] + }, + { + id: 'security', + title: 'ra.menu.security', + icon: TableOutlined, + type: 'group', + children: [ + { + id: 'entities/audit-log', + title: 'ra.menu.item.entities/audit-log', + type: 'item', + url: '/entities/audit-log', + icon: EyeOutlined, + roles: ['ROLE_ADMIN'] + }, + { + id: 'entities/user', + title: 'ra.menu.item.entities/user', + type: 'item', + url: '/entities/user', + icon: UserOutlined, + roles: ['ROLE_ADMIN'] + }, + { + id: 'entities/device', + title: 'ra.menu.item.entities/device', + type: 'item', + url: '/entities/device', + icon: TableOutlined, + roles: ['ROLE_ADMIN'] + } + ] + } +]; + +export default config; diff --git a/edera-web/src/react-app-env.d.js b/edera-web/src/react-app-env.d.js new file mode 100644 index 0000000..6431bc5 --- /dev/null +++ b/edera-web/src/react-app-env.d.js @@ -0,0 +1 @@ +/// diff --git a/edera-web/src/reportWebVitals.js b/edera-web/src/reportWebVitals.js new file mode 100644 index 0000000..532f29b --- /dev/null +++ b/edera-web/src/reportWebVitals.js @@ -0,0 +1,13 @@ +const reportWebVitals = (onPerfEntry) => { + if (onPerfEntry && onPerfEntry instanceof Function) { + import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { + getCLS(onPerfEntry); + getFID(onPerfEntry); + getFCP(onPerfEntry); + getLCP(onPerfEntry); + getTTFB(onPerfEntry); + }); + } +}; + +export default reportWebVitals; diff --git a/edera-web/src/theme.js b/edera-web/src/theme.js new file mode 100644 index 0000000..6cb3e15 --- /dev/null +++ b/edera-web/src/theme.js @@ -0,0 +1,3 @@ +const theme = () => ({}); + +export default theme;