From 4f06a670d04a3aafba83c7d496f2e9fe73e245a0 Mon Sep 17 00:00:00 2001 From: rojasadrian012 Date: Tue, 27 May 2025 15:29:53 -0300 Subject: [PATCH 1/6] chore: update package.json to add new dependencies for date handling and type definitions --- package-lock.json | 306 ++++++++++++++++++++++++++++++++++++++++++---- package.json | 3 + 2 files changed, 287 insertions(+), 22 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5519dbd..4fdf2f7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,10 +16,12 @@ "@lemoncode/fonk-formik": "^4.0.1", "@mui/icons-material": "^6.1.7", "@mui/material": "^6.1.7", + "@mui/x-date-pickers": "^8.3.1", "@tanstack/react-query": "^5.63.0", "@tanstack/react-router": "^1.82.1", "@tanstack/react-table": "^8.20.6", "axios": "^1.7.7", + "date-fns": "^4.1.0", "formik": "^2.4.6", "react": "^18.3.1", "react-dom": "^18.3.1" @@ -29,6 +31,7 @@ "@tanstack/react-query-devtools": "^5.63.0", "@tanstack/router-devtools": "^1.82.1", "@tanstack/router-plugin": "^1.81.9", + "@types/express": "^5.0.2", "@types/jest": "^29.5.14", "@types/node": "^22.9.0", "@types/react": "^18.3.12", @@ -316,13 +319,10 @@ } }, "node_modules/@babel/runtime": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz", - "integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.1.tgz", + "integrity": "sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==", "license": "MIT", - "dependencies": { - "regenerator-runtime": "^0.14.0" - }, "engines": { "node": ">=6.9.0" } @@ -1439,10 +1439,13 @@ } }, "node_modules/@mui/types": { - "version": "7.2.19", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.19.tgz", - "integrity": "sha512-6XpZEM/Q3epK9RN8ENoXuygnqUQxE+siN/6rGRi2iwJPgBUR25mphYQ9ZI87plGh58YoZ5pp40bFvKYOCDJ3tA==", + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.4.2.tgz", + "integrity": "sha512-edRc5JcLPsrlNFYyTPxds+d5oUovuUxnnDtpJUbP6WMeV4+6eaX/mqai1ZIWT62lCOe0nlrON0s9HDiv5en5bA==", "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.27.1" + }, "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, @@ -1482,6 +1485,164 @@ } } }, + "node_modules/@mui/x-date-pickers": { + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-8.3.1.tgz", + "integrity": "sha512-QokQvtfrKy802mrs6aH3r351Xhl5r/TYjcIVX97dCp32HRMFD7ygQV9S7+hQYqqpEN8iWEH+L5jJPSIottd/5g==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.27.1", + "@mui/utils": "^7.0.2", + "@mui/x-internals": "8.3.1", + "@types/react-transition-group": "^4.4.12", + "clsx": "^2.1.1", + "prop-types": "^15.8.1", + "react-transition-group": "^4.4.5" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.9.0", + "@emotion/styled": "^11.8.1", + "@mui/material": "^5.15.14 || ^6.0.0 || ^7.0.0", + "@mui/system": "^5.15.14 || ^6.0.0 || ^7.0.0", + "date-fns": "^2.25.0 || ^3.2.0 || ^4.0.0", + "date-fns-jalali": "^2.13.0-0 || ^3.2.0-0 || ^4.0.0-0", + "dayjs": "^1.10.7", + "luxon": "^3.0.2", + "moment": "^2.29.4", + "moment-hijri": "^2.1.2 || ^3.0.0", + "moment-jalaali": "^0.7.4 || ^0.8.0 || ^0.9.0 || ^0.10.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "date-fns": { + "optional": true + }, + "date-fns-jalali": { + "optional": true + }, + "dayjs": { + "optional": true + }, + "luxon": { + "optional": true + }, + "moment": { + "optional": true + }, + "moment-hijri": { + "optional": true + }, + "moment-jalaali": { + "optional": true + } + } + }, + "node_modules/@mui/x-date-pickers/node_modules/@mui/utils": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-7.1.0.tgz", + "integrity": "sha512-/OM3S8kSHHmWNOP+NH9xEtpYSG10upXeQ0wLZnfDgmgadTAk5F4MQfFLyZ5FCRJENB3eRzltMmaNl6UtDnPovw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.27.1", + "@mui/types": "^7.4.2", + "@types/prop-types": "^15.7.14", + "clsx": "^2.1.1", + "prop-types": "^15.8.1", + "react-is": "^19.1.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/x-date-pickers/node_modules/react-is": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.1.0.tgz", + "integrity": "sha512-Oe56aUPnkHyyDxxkvqtd7KkdQP5uIUfHxd5XTb3wE9d/kRnZLmKbDB0GWk919tdQ+mxxPtG6EAs6RMT6i1qtHg==", + "license": "MIT" + }, + "node_modules/@mui/x-internals": { + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/@mui/x-internals/-/x-internals-8.3.1.tgz", + "integrity": "sha512-8kIxT66cea63iEseEIHSWzKju2Wzl7MsWFoAUQEyRvYqOFa2j9Un2Vn/EH2vy9nm/MtMAYpwOE/nt68/KTIA2w==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.27.1", + "@mui/utils": "^7.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@mui/x-internals/node_modules/@mui/utils": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-7.1.0.tgz", + "integrity": "sha512-/OM3S8kSHHmWNOP+NH9xEtpYSG10upXeQ0wLZnfDgmgadTAk5F4MQfFLyZ5FCRJENB3eRzltMmaNl6UtDnPovw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.27.1", + "@mui/types": "^7.4.2", + "@types/prop-types": "^15.7.14", + "clsx": "^2.1.1", + "prop-types": "^15.8.1", + "react-is": "^19.1.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/x-internals/node_modules/react-is": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.1.0.tgz", + "integrity": "sha512-Oe56aUPnkHyyDxxkvqtd7KkdQP5uIUfHxd5XTb3wE9d/kRnZLmKbDB0GWk919tdQ+mxxPtG6EAs6RMT6i1qtHg==", + "license": "MIT" + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -2099,6 +2260,27 @@ "@babel/types": "^7.20.7" } }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/estree": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", @@ -2106,6 +2288,31 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/express": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.2.tgz", + "integrity": "sha512-BtjL3ZwbCQriyb0DGw+Rt12qAXPiBTPs815lsUvtt1Grk0vLRMZNMUZ741d5rjk+UQOxfDiBZ3dxpX00vSkK3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^5.0.0", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.6.tgz", + "integrity": "sha512-3xhRnjJPkULekpSzgtoNYYcTWgEZkp4myc+Saevii5JPnHNvHMRlBSHDbs7Bh1iPPoVTERHEZXyhyLbMEsExsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, "node_modules/@types/hoist-non-react-statics": { "version": "3.3.6", "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.6.tgz", @@ -2115,6 +2322,13 @@ "hoist-non-react-statics": "^3.3.0" } }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", @@ -2156,6 +2370,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/node": { "version": "22.9.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.0.tgz", @@ -2172,9 +2393,23 @@ "license": "MIT" }, "node_modules/@types/prop-types": { - "version": "15.7.13", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz", - "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==", + "version": "15.7.14", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz", + "integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==", + "license": "MIT" + }, + "node_modules/@types/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true, "license": "MIT" }, "node_modules/@types/react": { @@ -2198,14 +2433,37 @@ } }, "node_modules/@types/react-transition-group": { - "version": "4.4.11", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.11.tgz", - "integrity": "sha512-RM05tAniPZ5DZPzzNFP+DmrcOdD0efDUxMy3145oljWSl3x9ZV5vhme98gTxFrj2lhXvmGNnUiuDyJgY9IKkNA==", + "version": "4.4.12", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz", + "integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==", "license": "MIT", - "dependencies": { + "peerDependencies": { "@types/react": "*" } }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, "node_modules/@types/stack-utils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", @@ -3758,6 +4016,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/date-fns": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", + "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, "node_modules/debug": { "version": "4.3.7", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", @@ -7007,12 +7275,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", - "license": "MIT" - }, "node_modules/regexp.prototype.flags": { "version": "1.5.3", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz", diff --git a/package.json b/package.json index d54c8ba..ee08a3d 100644 --- a/package.json +++ b/package.json @@ -34,10 +34,12 @@ "@lemoncode/fonk-formik": "^4.0.1", "@mui/icons-material": "^6.1.7", "@mui/material": "^6.1.7", + "@mui/x-date-pickers": "^8.3.1", "@tanstack/react-query": "^5.63.0", "@tanstack/react-router": "^1.82.1", "@tanstack/react-table": "^8.20.6", "axios": "^1.7.7", + "date-fns": "^4.1.0", "formik": "^2.4.6", "react": "^18.3.1", "react-dom": "^18.3.1" @@ -47,6 +49,7 @@ "@tanstack/react-query-devtools": "^5.63.0", "@tanstack/router-devtools": "^1.82.1", "@tanstack/router-plugin": "^1.81.9", + "@types/express": "^5.0.2", "@types/jest": "^29.5.14", "@types/node": "^22.9.0", "@types/react": "^18.3.12", From 1d9d9160845005137a524459fb75c3a2f3cbcc25 Mon Sep 17 00:00:00 2001 From: rojasadrian012 Date: Tue, 27 May 2025 15:44:52 -0300 Subject: [PATCH 2/6] feat: add components --- .../datos-generales-section.component.tsx | 146 ++++++++++++++++++ .../datos-generales-section.styles.ts | 36 +++++ .../components/form-actions.component.tsx | 18 +++ .../components/form-actions.styles.ts | 13 ++ .../components/index.ts | 3 + .../periodo-ejecucion.component.tsx | 74 +++++++++ .../components/periodo-ejecucion.styles.ts | 39 +++++ 7 files changed, 329 insertions(+) create mode 100644 src/modules/expedientes/editar-datos-generales/components/datos-generales-section.component.tsx create mode 100644 src/modules/expedientes/editar-datos-generales/components/datos-generales-section.styles.ts create mode 100644 src/modules/expedientes/editar-datos-generales/components/form-actions.component.tsx create mode 100644 src/modules/expedientes/editar-datos-generales/components/form-actions.styles.ts create mode 100644 src/modules/expedientes/editar-datos-generales/components/index.ts create mode 100644 src/modules/expedientes/editar-datos-generales/components/periodo-ejecucion.component.tsx create mode 100644 src/modules/expedientes/editar-datos-generales/components/periodo-ejecucion.styles.ts diff --git a/src/modules/expedientes/editar-datos-generales/components/datos-generales-section.component.tsx b/src/modules/expedientes/editar-datos-generales/components/datos-generales-section.component.tsx new file mode 100644 index 0000000..f6d1b57 --- /dev/null +++ b/src/modules/expedientes/editar-datos-generales/components/datos-generales-section.component.tsx @@ -0,0 +1,146 @@ +import React from 'react'; +import { Typography, FormControl, InputLabel, Select, MenuItem, TextField } from '@mui/material'; +import { useWithTheme } from '#core/theme/theme.hooks.ts'; +import { useFormikField } from '../hook'; +import { CLASSES, RESPONSIBLES, STATES, UNITS } from '../constans'; +import * as innerClasses from './datos-generales-section.styles'; + +export const DatosGeneralesSection: React.FC = () => { + const classes = useWithTheme(innerClasses); + const { values, errors, touched, handleChange, handleBlur } = useFormikField(); + + const responsibleOptions = React.useMemo(() => { + const options = [...RESPONSIBLES]; + if (values.responsible && !RESPONSIBLES.includes(values.responsible)) { + options.unshift(values.responsible); + } + return options; + }, [values.responsible]); + + return ( +
+ Datos Generales +
+
+ + Clase + + + + + + {values.title && ( + + {values.title.length}/100 + + )} +
+ +
+
+ + Estado + + + + + + +
+ + + Unidad Proponente + + + + + Responsable + + +
+
+
+ ); +}; diff --git a/src/modules/expedientes/editar-datos-generales/components/datos-generales-section.styles.ts b/src/modules/expedientes/editar-datos-generales/components/datos-generales-section.styles.ts new file mode 100644 index 0000000..7af8de0 --- /dev/null +++ b/src/modules/expedientes/editar-datos-generales/components/datos-generales-section.styles.ts @@ -0,0 +1,36 @@ +import { css } from '@emotion/css'; +import { Theme } from '@mui/material'; + +export const section = () => css` + width: 100%; +`; + +export const stack = (theme: Theme) => css` + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: ${theme.spacing(3)}; + width: 100%; + margin-top: ${theme.spacing(2)}; + + @media (max-width: 768px) { + grid-template-columns: 1fr; + } +`; + +export const stackItem = (theme: Theme) => css` + display: flex; + flex-direction: column; + gap: ${theme.spacing(2)}; +`; + +export const stackItemRow = (theme: Theme) => css` + display: flex; + flex-direction: row; + with: 100%; + gap: ${theme.spacing(2)}; +`; + +export const inputField = () => css` + flex: 1; + min-width: 0; +`; diff --git a/src/modules/expedientes/editar-datos-generales/components/form-actions.component.tsx b/src/modules/expedientes/editar-datos-generales/components/form-actions.component.tsx new file mode 100644 index 0000000..760a102 --- /dev/null +++ b/src/modules/expedientes/editar-datos-generales/components/form-actions.component.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { Button } from '@mui/material'; +import { NavigationButton } from '#common/components/index.ts'; +import { useWithTheme } from '#core/theme/theme.hooks.ts'; +import * as innerClasses from './form-actions.styles'; + +export const FormActions: React.FC = () => { + const classes = useWithTheme(innerClasses); + + return ( +
+ + +
+ ); +}; diff --git a/src/modules/expedientes/editar-datos-generales/components/form-actions.styles.ts b/src/modules/expedientes/editar-datos-generales/components/form-actions.styles.ts new file mode 100644 index 0000000..667238f --- /dev/null +++ b/src/modules/expedientes/editar-datos-generales/components/form-actions.styles.ts @@ -0,0 +1,13 @@ +import { css } from '@emotion/css'; +import { Theme } from '@mui/material'; + +export const buttonContainer = (theme: Theme) => css` + display: flex; + justify-content: flex-end; + gap: ${theme.spacing(4)}; + width: 100%; + + @media (max-width: 768px) { + justify-content: center; + } +`; diff --git a/src/modules/expedientes/editar-datos-generales/components/index.ts b/src/modules/expedientes/editar-datos-generales/components/index.ts new file mode 100644 index 0000000..179e0e2 --- /dev/null +++ b/src/modules/expedientes/editar-datos-generales/components/index.ts @@ -0,0 +1,3 @@ +export * from './periodo-ejecucion.component'; +export * from './datos-generales-section.component'; +export * from './form-actions.component'; diff --git a/src/modules/expedientes/editar-datos-generales/components/periodo-ejecucion.component.tsx b/src/modules/expedientes/editar-datos-generales/components/periodo-ejecucion.component.tsx new file mode 100644 index 0000000..0319a82 --- /dev/null +++ b/src/modules/expedientes/editar-datos-generales/components/periodo-ejecucion.component.tsx @@ -0,0 +1,74 @@ +import React from 'react'; +import { Typography } from '@mui/material'; +import { DatePicker } from '@mui/x-date-pickers/DatePicker'; + +import { calculateEndDate } from '../utils'; +import { useWithTheme } from '#core/theme/theme.hooks.ts'; +import { useFormikField } from '../hook'; +import * as innerClasses from './periodo-ejecucion.styles'; + +export const PeriodoEjecucionSection: React.FC = () => { + const classes = useWithTheme(innerClasses); + const { values, setFieldValue, touched, errors } = useFormikField(); + + const handleStartDateChange = (date: Date | null) => { + if (date) { + setFieldValue('startDate', date); + if (values.executionPeriod) { + const newEndDate = calculateEndDate(date, values.executionPeriod); + setFieldValue('endDate', newEndDate); + } + } + }; + + const handleEndDateChange = (date: Date | null) => { + if (date) { + setFieldValue('endDate', date); + } + }; + + return ( +
+ Período de ejecución +
+
+ {/* Aquí podrías agregar un selector de período si es necesario */} +
+ +
+ +
+ +
+ +
+ +
+
+
+ ); +}; diff --git a/src/modules/expedientes/editar-datos-generales/components/periodo-ejecucion.styles.ts b/src/modules/expedientes/editar-datos-generales/components/periodo-ejecucion.styles.ts new file mode 100644 index 0000000..6d905c7 --- /dev/null +++ b/src/modules/expedientes/editar-datos-generales/components/periodo-ejecucion.styles.ts @@ -0,0 +1,39 @@ +import { css } from '@emotion/css'; +import { Theme } from '@mui/material'; + +export const periodSection = () => css` + width: 100%; +`; + +export const periodContainer = (theme: Theme) => css` + display: flex; + align-items: flex-start; + align-self: stretch; + gap: ${theme.spacing(2)}; + width: 100%; + margin-top: ${theme.spacing(2)}; + justify-content: space-between; + + @media (max-width: 768px) { + grid-template-columns: 1fr; + } +`; + +export const periodSelector = (theme: Theme) => css` + display: flex; + flex-direction: column; + gap: ${theme.spacing(1)}; +`; + +export const divider = () => css` + display: flex; + align-items: center; + justify-content: center; + height: 40px; +`; + +export const selectorNumber = () => css` + text-align: start; + width: 50%; + border: none; +`; From eaf2b0481801f374893198f21824b598e9d45048 Mon Sep 17 00:00:00 2001 From: rojasadrian012 Date: Tue, 27 May 2025 15:46:04 -0300 Subject: [PATCH 3/6] expediente by id --- .../src/dals/expediente/expediente.repository.ts | 7 +++++++ .../src/pods/expediente/expediente.rest-api.ts | 16 +++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/mock-server/src/dals/expediente/expediente.repository.ts b/mock-server/src/dals/expediente/expediente.repository.ts index 4194de7..4030634 100644 --- a/mock-server/src/dals/expediente/expediente.repository.ts +++ b/mock-server/src/dals/expediente/expediente.repository.ts @@ -1,6 +1,7 @@ import { paginateItems } from '#common/helpers/index.js'; import { CollectionQuery } from '#common/models/index.js'; import { db } from '#dals/mock.data.js'; +import { ObjectId } from 'mongodb'; import * as model from './expediente.model.js'; export const expedienteRepository = { @@ -13,4 +14,10 @@ export const expedienteRepository = { totalPages: db.expedientes.length, }, }, + + getExpedienteById: async (id: string): Promise => { + const objectId = new ObjectId(id); + const expediente = db.expedientes.find(e => e.id.equals(objectId)); + return expediente ?? null; + }, }; diff --git a/mock-server/src/pods/expediente/expediente.rest-api.ts b/mock-server/src/pods/expediente/expediente.rest-api.ts index 529158b..c7ca05c 100644 --- a/mock-server/src/pods/expediente/expediente.rest-api.ts +++ b/mock-server/src/pods/expediente/expediente.rest-api.ts @@ -1,9 +1,23 @@ import express from 'express'; import { expedienteRepository } from '#dals/expediente/expediente.repository.js'; -import { mapExpedienteListFromModelToApi } from './expediente.mappers.js'; +import { mapExpedienteFromModelToApi, mapExpedienteListFromModelToApi } from './expediente.mappers.js'; export const expedienteApi = express.Router(); +expedienteApi.get('/:id', async (req, res, next) => { + try { + const { id } = req.params; + const expediente = await expedienteRepository.getExpedienteById(id); + if (!expediente) { + res.status(404).send({ message: 'Expediente no encontrado' }); + return; + } + res.send(mapExpedienteFromModelToApi(expediente)); + } catch (error) { + next(error); + } +}); + expedienteApi.get('/', async (req, res, next) => { try { const page = Number(req.query.page); From 89e799de6a6e2d085518cb708d49b3841d761331 Mon Sep 17 00:00:00 2001 From: rojasadrian012 Date: Tue, 27 May 2025 15:46:33 -0300 Subject: [PATCH 4/6] feat: implement Editar Datos Generales component with API integration and validation --- .../api/expediente-api.ts | 7 ++++ .../editar-datos-generales/api/index.ts | 1 + .../constans/data-selectors.ts | 5 +++ .../editar-datos-generales/constans/index.ts | 1 + .../editar-datos-generales.component.tsx | 37 +++++++++++++++++++ .../editar-datos-generales.mappers.ts | 21 +++++++++++ .../editar-datos-generales.pod.tsx | 17 ++++++++- .../editar-datos-generales.styles.ts | 11 ++++++ .../editar-datos-generales.vm.ts | 33 +++++++++++++++++ .../editar-datos-generales/hook/index.ts | 1 + .../hook/use-formik-field.ts | 7 ++++ .../utils/date-helpers.ts | 7 ++++ .../editar-datos-generales/utils/index.ts | 2 + .../utils/validation-schemas.ts | 24 ++++++++++++ 14 files changed, 173 insertions(+), 1 deletion(-) create mode 100644 src/modules/expedientes/editar-datos-generales/api/expediente-api.ts create mode 100644 src/modules/expedientes/editar-datos-generales/api/index.ts create mode 100644 src/modules/expedientes/editar-datos-generales/constans/data-selectors.ts create mode 100644 src/modules/expedientes/editar-datos-generales/constans/index.ts create mode 100644 src/modules/expedientes/editar-datos-generales/editar-datos-generales.component.tsx create mode 100644 src/modules/expedientes/editar-datos-generales/editar-datos-generales.mappers.ts create mode 100644 src/modules/expedientes/editar-datos-generales/editar-datos-generales.styles.ts create mode 100644 src/modules/expedientes/editar-datos-generales/editar-datos-generales.vm.ts create mode 100644 src/modules/expedientes/editar-datos-generales/hook/index.ts create mode 100644 src/modules/expedientes/editar-datos-generales/hook/use-formik-field.ts create mode 100644 src/modules/expedientes/editar-datos-generales/utils/date-helpers.ts create mode 100644 src/modules/expedientes/editar-datos-generales/utils/index.ts create mode 100644 src/modules/expedientes/editar-datos-generales/utils/validation-schemas.ts diff --git a/src/modules/expedientes/editar-datos-generales/api/expediente-api.ts b/src/modules/expedientes/editar-datos-generales/api/expediente-api.ts new file mode 100644 index 0000000..3569f3f --- /dev/null +++ b/src/modules/expedientes/editar-datos-generales/api/expediente-api.ts @@ -0,0 +1,7 @@ +import axios from 'axios'; +import { Expediente } from '../editar-datos-generales.vm'; + +export const getExpedienteById = async (id: string): Promise => { + const response = await axios.get(`/api/expediente/${id}`); + return response.data; +}; diff --git a/src/modules/expedientes/editar-datos-generales/api/index.ts b/src/modules/expedientes/editar-datos-generales/api/index.ts new file mode 100644 index 0000000..3b1ebcd --- /dev/null +++ b/src/modules/expedientes/editar-datos-generales/api/index.ts @@ -0,0 +1 @@ +export * from './expediente-api'; diff --git a/src/modules/expedientes/editar-datos-generales/constans/data-selectors.ts b/src/modules/expedientes/editar-datos-generales/constans/data-selectors.ts new file mode 100644 index 0000000..b8f7930 --- /dev/null +++ b/src/modules/expedientes/editar-datos-generales/constans/data-selectors.ts @@ -0,0 +1,5 @@ +export const STATES = ['En Proceso', 'Pendiente', 'Finalizado', 'En Revisión']; +export const CLASSES = ['Administrativo', 'Técnico', 'Financiero', 'Legal']; +export const UNITS = ['Subdirección de Formación local', 'Unidad de Recursos Humanos', 'Departamento Técnico']; +export const RESPONSIBLES = ['José García Román', 'María López Sánchez', 'Carlos Martínez Ruiz']; +export const PERIOD_TYPES = ['Meses', 'Años', 'Días']; diff --git a/src/modules/expedientes/editar-datos-generales/constans/index.ts b/src/modules/expedientes/editar-datos-generales/constans/index.ts new file mode 100644 index 0000000..a4d0904 --- /dev/null +++ b/src/modules/expedientes/editar-datos-generales/constans/index.ts @@ -0,0 +1 @@ +export * from './data-selectors'; diff --git a/src/modules/expedientes/editar-datos-generales/editar-datos-generales.component.tsx b/src/modules/expedientes/editar-datos-generales/editar-datos-generales.component.tsx new file mode 100644 index 0000000..328f3a8 --- /dev/null +++ b/src/modules/expedientes/editar-datos-generales/editar-datos-generales.component.tsx @@ -0,0 +1,37 @@ +import React from 'react'; +import { useWithTheme } from '#core/theme/theme.hooks.ts'; +import { Formik, Form } from 'formik'; +import { DatosGeneralesSection, PeriodoEjecucionSection, FormActions } from './components'; +import { GeneralData } from './editar-datos-generales.vm'; +import { validateGeneralData } from './utils'; +import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; +import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns'; +import * as innerClasses from './editar-datos-generales.styles'; + +interface Props { + generalData: GeneralData; + onSubmit?: (values: GeneralData) => void; +} + +export const EditarDatosGenerales: React.FC = ({ generalData, onSubmit }) => { + const classes = useWithTheme(innerClasses); + + const handleSubmit = (values: GeneralData, actions: any) => { + if (onSubmit) { + onSubmit(values); + } + actions.setSubmitting(false); + }; + + return ( + + +
+ + + + +
+
+ ); +}; diff --git a/src/modules/expedientes/editar-datos-generales/editar-datos-generales.mappers.ts b/src/modules/expedientes/editar-datos-generales/editar-datos-generales.mappers.ts new file mode 100644 index 0000000..c4b0fa2 --- /dev/null +++ b/src/modules/expedientes/editar-datos-generales/editar-datos-generales.mappers.ts @@ -0,0 +1,21 @@ +import { GeneralData, Expediente } from './editar-datos-generales.vm'; + +export const mapExpedienteToGeneralData = (expediente: Expediente): GeneralData => { + const executionPeriod = 24; + const startDate = new Date(); + const endDate = new Date(startDate); + endDate.setMonth(endDate.getMonth() + executionPeriod); + + return { + class: expediente.clase, + title: expediente.titulo, + responsible: expediente.adjudicataria, + state: expediente.estado, + numExpediente: '3124 00000312', + numSorolla2: '1034 0000032', + proposingUnit: 'Subdirección de Formación local', + executionPeriod, + startDate, + endDate, + }; +}; diff --git a/src/modules/expedientes/editar-datos-generales/editar-datos-generales.pod.tsx b/src/modules/expedientes/editar-datos-generales/editar-datos-generales.pod.tsx index d36da7c..f442eb0 100644 --- a/src/modules/expedientes/editar-datos-generales/editar-datos-generales.pod.tsx +++ b/src/modules/expedientes/editar-datos-generales/editar-datos-generales.pod.tsx @@ -1,4 +1,8 @@ import React from 'react'; +import { EditarDatosGenerales } from './editar-datos-generales.component'; +import { GeneralData, createEmptyGeneralData } from './editar-datos-generales.vm'; +import { getExpedienteById } from './api'; +import { mapExpedienteToGeneralData } from './editar-datos-generales.mappers'; interface Props { id: string; @@ -6,6 +10,17 @@ interface Props { export const EditarDatosGeneralesPod: React.FC = props => { const { id } = props; + const [generalData, setGeneralData] = React.useState(createEmptyGeneralData()); - return

Datos Generales id: {id}

; + React.useEffect(() => { + getExpedienteById(id).then(expediente => { + setGeneralData(mapExpedienteToGeneralData(expediente)); + }); + }, []); + + const handleSubmit = (values: GeneralData) => { + console.log('Datos enviados:', values); + }; + + return ; }; diff --git a/src/modules/expedientes/editar-datos-generales/editar-datos-generales.styles.ts b/src/modules/expedientes/editar-datos-generales/editar-datos-generales.styles.ts new file mode 100644 index 0000000..1e2d01d --- /dev/null +++ b/src/modules/expedientes/editar-datos-generales/editar-datos-generales.styles.ts @@ -0,0 +1,11 @@ +import { css } from '@emotion/css'; +import { Theme } from '@mui/material'; + +export const formContainer = (theme: Theme) => css` + display: flex; + flex-direction: column; + align-items: flex-start; + gap: ${theme.spacing(4)}; + align-self: stretch; + width: 100%; +`; diff --git a/src/modules/expedientes/editar-datos-generales/editar-datos-generales.vm.ts b/src/modules/expedientes/editar-datos-generales/editar-datos-generales.vm.ts new file mode 100644 index 0000000..94453dd --- /dev/null +++ b/src/modules/expedientes/editar-datos-generales/editar-datos-generales.vm.ts @@ -0,0 +1,33 @@ +export interface GeneralData { + class: string; + state: string; + numExpediente: string; + numSorolla2: string; + title: string; + proposingUnit: string; + responsible: string; + executionPeriod: number; + startDate: Date; + endDate: Date; +} + +export const createEmptyGeneralData = (): GeneralData => ({ + class: '', + state: '', + numExpediente: '', + numSorolla2: '', + title: '', + proposingUnit: '', + responsible: '', + executionPeriod: 0, + startDate: new Date(), + endDate: new Date(), +}); + +export interface Expediente { + id: string; + clase: string; + titulo: string; + adjudicataria: string; + estado: string; +} diff --git a/src/modules/expedientes/editar-datos-generales/hook/index.ts b/src/modules/expedientes/editar-datos-generales/hook/index.ts new file mode 100644 index 0000000..cf72e0d --- /dev/null +++ b/src/modules/expedientes/editar-datos-generales/hook/index.ts @@ -0,0 +1 @@ +export * from './use-formik-field'; diff --git a/src/modules/expedientes/editar-datos-generales/hook/use-formik-field.ts b/src/modules/expedientes/editar-datos-generales/hook/use-formik-field.ts new file mode 100644 index 0000000..7676e1b --- /dev/null +++ b/src/modules/expedientes/editar-datos-generales/hook/use-formik-field.ts @@ -0,0 +1,7 @@ +import { useFormikContext } from 'formik'; +import { GeneralData } from '../editar-datos-generales.vm'; + +export const useFormikField = () => { + const formik = useFormikContext(); + return formik; +}; diff --git a/src/modules/expedientes/editar-datos-generales/utils/date-helpers.ts b/src/modules/expedientes/editar-datos-generales/utils/date-helpers.ts new file mode 100644 index 0000000..e7d8fc6 --- /dev/null +++ b/src/modules/expedientes/editar-datos-generales/utils/date-helpers.ts @@ -0,0 +1,7 @@ +export const calculateEndDate = (startDate: Date, periodValue: number): Date => { + if (!startDate || !periodValue) return new Date(); + + const newEndDate = new Date(startDate); + newEndDate.setMonth(newEndDate.getMonth() + periodValue); + return newEndDate; +}; diff --git a/src/modules/expedientes/editar-datos-generales/utils/index.ts b/src/modules/expedientes/editar-datos-generales/utils/index.ts new file mode 100644 index 0000000..7340776 --- /dev/null +++ b/src/modules/expedientes/editar-datos-generales/utils/index.ts @@ -0,0 +1,2 @@ +export * from './date-helpers'; +export * from './validation-schemas'; diff --git a/src/modules/expedientes/editar-datos-generales/utils/validation-schemas.ts b/src/modules/expedientes/editar-datos-generales/utils/validation-schemas.ts new file mode 100644 index 0000000..46a4321 --- /dev/null +++ b/src/modules/expedientes/editar-datos-generales/utils/validation-schemas.ts @@ -0,0 +1,24 @@ +import { GeneralData } from '../editar-datos-generales.vm'; + +export const validateGeneralData = (values: GeneralData) => { + const errors: Partial> = {}; + + if (!values.class) errors.class = 'La clase es obligatoria'; + if (!values.state) errors.state = 'El estado es obligatorio'; + if (!values.numExpediente) errors.numExpediente = 'El número de expediente es obligatorio'; + if (!values.title) errors.title = 'El título es obligatorio'; + else if (values.title.length > 100) errors.title = 'El título no puede superar los 100 caracteres'; + if (!values.proposingUnit) errors.proposingUnit = 'La unidad proponente es obligatoria'; + if (!values.responsible) errors.responsible = 'El responsable es obligatorio'; + + if (!values.executionPeriod) errors.executionPeriod = 'El período de ejecución es obligatorio'; + else if (values.executionPeriod < 1) errors.executionPeriod = 'Debe ser mayor a 0'; + + if (!values.startDate) errors.startDate = 'La fecha de inicio es obligatoria'; + if (!values.endDate) errors.endDate = 'La fecha de fin es obligatoria'; + else if (values.startDate && values.endDate && values.endDate < values.startDate) { + errors.endDate = 'La fecha de fin debe ser posterior a la fecha de inicio'; + } + + return errors; +}; From 80a47827a393b91cc0521abe34dccf3e40d0a8a2 Mon Sep 17 00:00:00 2001 From: rojasadrian012 Date: Tue, 27 May 2025 18:10:23 -0300 Subject: [PATCH 5/6] feat: enhance PeriodoEjecucionSection with period type selection and styling updates --- .../periodo-ejecucion.component.tsx | 33 ++++++++--- .../components/periodo-ejecucion.styles.ts | 56 ++++++++++++++----- .../editar-datos-generales.mappers.ts | 1 + .../editar-datos-generales.vm.ts | 2 + 4 files changed, 68 insertions(+), 24 deletions(-) diff --git a/src/modules/expedientes/editar-datos-generales/components/periodo-ejecucion.component.tsx b/src/modules/expedientes/editar-datos-generales/components/periodo-ejecucion.component.tsx index 0319a82..a91f45a 100644 --- a/src/modules/expedientes/editar-datos-generales/components/periodo-ejecucion.component.tsx +++ b/src/modules/expedientes/editar-datos-generales/components/periodo-ejecucion.component.tsx @@ -1,11 +1,12 @@ import React from 'react'; -import { Typography } from '@mui/material'; +import { MenuItem, Select, TextField, Typography } from '@mui/material'; import { DatePicker } from '@mui/x-date-pickers/DatePicker'; import { calculateEndDate } from '../utils'; import { useWithTheme } from '#core/theme/theme.hooks.ts'; import { useFormikField } from '../hook'; import * as innerClasses from './periodo-ejecucion.styles'; +import { PERIOD_TYPES } from '../constans'; export const PeriodoEjecucionSection: React.FC = () => { const classes = useWithTheme(innerClasses); @@ -32,7 +33,27 @@ export const PeriodoEjecucionSection: React.FC = () => { Período de ejecución
- {/* Aquí podrías agregar un selector de período si es necesario */} + + +
@@ -44,16 +65,12 @@ export const PeriodoEjecucionSection: React.FC = () => { textField: { fullWidth: true, error: touched.startDate && Boolean(errors.startDate), - // helperText: touched.startDate && errors.startDate, - size: 'small', }, }} /> -
-
+
-
{ textField: { fullWidth: true, error: touched.endDate && Boolean(errors.endDate), - // helperText: touched.endDate && errors.endDate, - size: 'small', }, }} /> diff --git a/src/modules/expedientes/editar-datos-generales/components/periodo-ejecucion.styles.ts b/src/modules/expedientes/editar-datos-generales/components/periodo-ejecucion.styles.ts index 6d905c7..e76ab97 100644 --- a/src/modules/expedientes/editar-datos-generales/components/periodo-ejecucion.styles.ts +++ b/src/modules/expedientes/editar-datos-generales/components/periodo-ejecucion.styles.ts @@ -6,34 +6,60 @@ export const periodSection = () => css` `; export const periodContainer = (theme: Theme) => css` - display: flex; - align-items: flex-start; - align-self: stretch; - gap: ${theme.spacing(2)}; - width: 100%; - margin-top: ${theme.spacing(2)}; - justify-content: space-between; + display: grid; + grid-template-columns: 1fr 1fr; + grid-template-rows: 1fr; + gap: ${theme.spacing(1)}; @media (max-width: 768px) { + display: grid; grid-template-columns: 1fr; + grid-template-rows: 1fr 1fr; + gap: ${theme.spacing(1)}; } `; export const periodSelector = (theme: Theme) => css` - display: flex; - flex-direction: column; gap: ${theme.spacing(1)}; + padding: ${theme.spacing(1)} 0; + display: flex; + + & > div > div > div:nth-child(2) { + width: auto; + } + + & > div > div > div { + width: 100%; + } + + &:nth-child(1) { + grid-area: 1 / 1 / 2 / 2; + } + &:nth-child(2) { + grid-area: 1 / 2 / 2 / 3; + } + + @media (max-width: 768px) { + &:nth-child(1) { + grid-area: 1 / 1 / 2 / 2; + } + &:nth-child(2) { + grid-area: 2 / 1 / 3 / 2; + } + } +`; + +export const timeSelector = css` + flex: 1; `; export const divider = () => css` display: flex; align-items: center; justify-content: center; - height: 40px; -`; + flex: 0; -export const selectorNumber = () => css` - text-align: start; - width: 50%; - border: none; + @media (max-width: 768px) { + display: none; + } `; diff --git a/src/modules/expedientes/editar-datos-generales/editar-datos-generales.mappers.ts b/src/modules/expedientes/editar-datos-generales/editar-datos-generales.mappers.ts index c4b0fa2..45e8e76 100644 --- a/src/modules/expedientes/editar-datos-generales/editar-datos-generales.mappers.ts +++ b/src/modules/expedientes/editar-datos-generales/editar-datos-generales.mappers.ts @@ -17,5 +17,6 @@ export const mapExpedienteToGeneralData = (expediente: Expediente): GeneralData executionPeriod, startDate, endDate, + executionPeriodType: 'Meses', }; }; diff --git a/src/modules/expedientes/editar-datos-generales/editar-datos-generales.vm.ts b/src/modules/expedientes/editar-datos-generales/editar-datos-generales.vm.ts index 94453dd..b478e9a 100644 --- a/src/modules/expedientes/editar-datos-generales/editar-datos-generales.vm.ts +++ b/src/modules/expedientes/editar-datos-generales/editar-datos-generales.vm.ts @@ -9,6 +9,7 @@ export interface GeneralData { executionPeriod: number; startDate: Date; endDate: Date; + executionPeriodType: 'Meses' | 'Años' | 'Días'; } export const createEmptyGeneralData = (): GeneralData => ({ @@ -22,6 +23,7 @@ export const createEmptyGeneralData = (): GeneralData => ({ executionPeriod: 0, startDate: new Date(), endDate: new Date(), + executionPeriodType: 'Meses', }); export interface Expediente { From 6d08350c4dabf30ee58a81e300c23480574edb8a Mon Sep 17 00:00:00 2001 From: rojasadrian012 Date: Wed, 28 May 2025 11:46:18 -0300 Subject: [PATCH 6/6] feat: update PeriodoEjecucionSection to calculate end date based on execution period type and enhance input handling --- .../periodo-ejecucion.component.tsx | 33 ++++++++++++++----- .../utils/date-helpers.ts | 25 ++++++++++++-- 2 files changed, 46 insertions(+), 12 deletions(-) diff --git a/src/modules/expedientes/editar-datos-generales/components/periodo-ejecucion.component.tsx b/src/modules/expedientes/editar-datos-generales/components/periodo-ejecucion.component.tsx index a91f45a..41af16e 100644 --- a/src/modules/expedientes/editar-datos-generales/components/periodo-ejecucion.component.tsx +++ b/src/modules/expedientes/editar-datos-generales/components/periodo-ejecucion.component.tsx @@ -12,22 +12,32 @@ export const PeriodoEjecucionSection: React.FC = () => { const classes = useWithTheme(innerClasses); const { values, setFieldValue, touched, errors } = useFormikField(); + React.useEffect(() => { + if (values.startDate && values.executionPeriod && values.executionPeriodType) { + const numericPeriod = +values.executionPeriod; + const newEndDate = calculateEndDate(values.startDate, numericPeriod, values.executionPeriodType); + setFieldValue('endDate', newEndDate); + } + }, [values.startDate, values.executionPeriod, values.executionPeriodType, setFieldValue]); + const handleStartDateChange = (date: Date | null) => { if (date) { setFieldValue('startDate', date); - if (values.executionPeriod) { - const newEndDate = calculateEndDate(date, values.executionPeriod); - setFieldValue('endDate', newEndDate); - } } }; - const handleEndDateChange = (date: Date | null) => { - if (date) { - setFieldValue('endDate', date); + const handlePeriodChange = (e: React.ChangeEvent) => { + const value = e.target.value; + + if (value === '' || (/^\d+$/.test(value) && parseInt(value) > 0)) { + setFieldValue('executionPeriod', value); } }; + const handlePeriodTypeChange = (e: any) => { + setFieldValue('executionPeriodType', e.target.value); + }; + return (
Período de ejecución @@ -38,7 +48,10 @@ export const PeriodoEjecucionSection: React.FC = () => { id="periodoEjecucion" name="periodoEjecucion" label="Período de ejecución*" + type="number" value={values.executionPeriod} + onChange={handlePeriodChange} + error={touched.executionPeriod && Boolean(errors.executionPeriod)} />