diff --git a/package-lock.json b/package-lock.json index 50cd2f3..8511eee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@chimera-pe/react-saas", - "version": "0.0.6", + "version": "0.1.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@chimera-pe/react-saas", - "version": "0.0.6", + "version": "0.1.1", "license": "ISC", "dependencies": { "@emotion/react": "^11.11.1", @@ -22,6 +22,7 @@ "jwt-decode": "^3.1.2", "mui-rff": "^6.2.3", "navigator-languages": "^2.0.2", + "node-polyglot": "^2.5.0", "react": ">=18", "react-dom": ">=18", "react-final-form": "^6.5.9", @@ -1815,7 +1816,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/array.prototype.foreach/-/array.prototype.foreach-1.0.4.tgz", "integrity": "sha512-OYqqGR/56CopyheXNwdlJvFtbSvf2Z9RGvL20X6GvAuKePJ76L/D46BqZn3bITd36QA2Ti7Iy0UwVJaD/YwXZA==", - "peer": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -2248,8 +2248,7 @@ "node_modules/es-array-method-boxes-properly": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", - "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", - "peer": true + "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==" }, "node_modules/es-set-tostringtag": { "version": "2.0.1", @@ -3564,7 +3563,6 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/node-polyglot/-/node-polyglot-2.5.0.tgz", "integrity": "sha512-zXVwHNhFsG3mls+LKHxoHF70GQOL3FTDT3jH7ldkb95kG76RdU7F/NbvxV7D2hNIL9VpWXW6y78Fz+3KZkatRg==", - "peer": true, "dependencies": { "array.prototype.foreach": "^1.0.2", "has": "^1.0.3", @@ -4617,7 +4615,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", - "peer": true, "dependencies": { "loose-envify": "^1.0.0" } diff --git a/package.json b/package.json index fa8b8d3..f60eee6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@chimera-pe/react-saas", - "version": "0.0.6", + "version": "0.1.2", "type": "module", "scripts": { "dev": "vite", @@ -22,6 +22,7 @@ "jwt-decode": "^3.1.2", "mui-rff": "^6.2.3", "navigator-languages": "^2.0.2", + "node-polyglot": "^2.5.0", "react": ">=18", "react-dom": ">=18", "react-final-form": "^6.5.9", diff --git a/src/components/Error.jsx b/src/components/Error.jsx index 6f10368..54edb29 100644 --- a/src/components/Error.jsx +++ b/src/components/Error.jsx @@ -2,7 +2,7 @@ import {Box,Alert,AlertTitle} from "@mui/material"; import {useTranslate} from "react-polyglot"; import PropTypes from "prop-types"; -const Error = ({titulo,texto,align = "center",severity = "error"}) => { +const ErrorAlert = ({titulo,texto,align = "center",severity = "error"}) => { const translate = useTranslate(); return ( @@ -28,4 +28,4 @@ Error.propTypes={ severity: PropTypes.string }; -export default Error; \ No newline at end of file +export default ErrorAlert; \ No newline at end of file diff --git a/src/components/Notificacion.jsx b/src/components/Notificacion.jsx index 1318133..3ec3b5a 100644 --- a/src/components/Notificacion.jsx +++ b/src/components/Notificacion.jsx @@ -22,11 +22,11 @@ const Notificacion=() => { return ( - {notificacion && notificacion.mensaje && notificacion.tipo !== "default" && + {notificacion?.mensaje && notificacion.tipo !== "default" && {translate(notificacion.mensaje)} } diff --git a/src/index.js b/src/index.js index 49471b0..df9ad3c 100644 --- a/src/index.js +++ b/src/index.js @@ -1,12 +1,45 @@ -import {SaasApp} from "./components"; +import {SaasApp,Cargando,Error} from "./components"; import {useNotificar} from "./hooks"; -import {Cargando,Error} from "./components"; -import {logout} from "./redux"; +import { + logout, + getInstancia, + getPerfiles, + getToken, + getUsuario +} from "./redux"; +import { + composeValidators, + required, + requiredNotFalse, + number, + minLength, + maxLength, + min, + max, + regex, + email, + remote +} from "./validacion"; export { SaasApp, useNotificar, Cargando, Error, - logout + logout, + getInstancia, + getPerfiles, + getToken, + getUsuario, + composeValidators, + required, + requiredNotFalse, + number, + minLength, + maxLength, + min, + max, + regex, + email, + remote }; diff --git a/src/redux/index.jsx b/src/redux/index.jsx index a8655ee..d76027c 100644 --- a/src/redux/index.jsx +++ b/src/redux/index.jsx @@ -1,6 +1,13 @@ import {store} from "./store"; -import {inicializar} from "./inicializarSlice"; -import {refreshToken,requestToken,logout} from "./loginSlice"; +import {inicializar,getInstancia} from "./inicializarSlice"; +import { + refreshToken, + requestToken, + logout, + getPerfiles, + getToken, + getUsuario +} from "./loginSlice"; import {mostrarNotificacion,ocultarNotificacion} from "./notificacionSlice"; import {cambiarIdioma,cambiarTema} from "./uiSlice"; @@ -13,5 +20,9 @@ export { mostrarNotificacion, ocultarNotificacion, cambiarIdioma, - cambiarTema + cambiarTema, + getInstancia, + getPerfiles, + getToken, + getUsuario }; \ No newline at end of file diff --git a/src/redux/inicializarSlice.jsx b/src/redux/inicializarSlice.jsx index 836a5e8..3c39e18 100644 --- a/src/redux/inicializarSlice.jsx +++ b/src/redux/inicializarSlice.jsx @@ -54,4 +54,6 @@ export const inicializar = createAsyncThunk("inicializar",async (payload) => { return response.data; }); +export const getInstancia=state => state.instancia; + export default inicializarSlice.reducer; \ No newline at end of file diff --git a/src/redux/loginSlice.jsx b/src/redux/loginSlice.jsx index d4416e3..a5855d0 100644 --- a/src/redux/loginSlice.jsx +++ b/src/redux/loginSlice.jsx @@ -91,4 +91,10 @@ export const refreshToken = createAsyncThunk("login/refreshToken",async (devURL, export const {logout} = loginSlice.actions; +export const getToken=state => state.token; + +export const getUsuario=state => state.usuario; + +export const getPerfiles=state => state.perfiles; + export default loginSlice.reducer; \ No newline at end of file diff --git a/src/validacion.js b/src/validacion.js new file mode 100644 index 0000000..3f8e512 --- /dev/null +++ b/src/validacion.js @@ -0,0 +1,77 @@ +import lodashMemoize from "lodash/memoize"; + +const EMAIL_REGEX=/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; + +const isEmpty=(value) => + typeof value === 'undefined' || + value === null || + value === '' || + (Array.isArray(value) && value.length === 0); + +const getMessage=(message,messageArgs,value,values) => ( + typeof message === 'function' + ? message({args: messageArgs,value,values}) + : messageArgs + ? {message,args: messageArgs} + : message +); + +const memoize=(fn) => lodashMemoize(fn,(...args) => JSON.stringify(args)); + +export const composeValidators=(...validators) => (value,values,meta) => { + const allValidators = Array.isArray(validators[0]) ? validators[0] : validators; + return allValidators.reduce( + (error,validator) => + error || + (typeof validator === 'function' && validator(value,values,meta)), + undefined + ); +}; + +export const required=memoize((message="validacion.obligatorio") => ( + Object.assign( + (value,values) => isEmpty(value) ? getMessage(message,undefined,value,values) : undefined, + {isRequired: true} + ) +)); + +export const requiredNotFalse=memoize((message="validacion.obligatorio") => ( + Object.assign( + (value,values) => isEmpty(value) || !value ? getMessage(message,undefined,value,values) : undefined, + {isRequired: true} + ) +)); + +export const number=memoize((message="validacion.numero") => (value,values) => ( + !isEmpty(value) && isNaN(value) ? getMessage(message,undefined,value,values) : undefined +)); + +export const minLength=memoize((min,message="validacion.longitud.minima") => (value,values) => + !isEmpty(value) && value.length < min ? getMessage(message,undefined,value,values) : undefined +); + +export const maxLength=memoize((max,message="validacion.longitud.maxima") => (value,values) => + !isEmpty(value) && value.length > max ? getMessage(message,undefined,value,values) : undefined +); + +export const min=memoize((min,message="validacion.minimo") => (value,values) => + !isEmpty(value) && parseFloat(value) < min ? getMessage(message,undefined,value,values) : undefined +); + +export const max=memoize((max,message="validacion.maximo") => (value,values) => + !isEmpty(value) && parseFloat(value) > max ? getMessage(message,undefined,value,values) : undefined +); + +export const regex=lodashMemoize((pattern,message="validacion.regex") => (value,values) => + !isEmpty(value) && typeof value === "string" && !pattern.test(value) ? getMessage(message,undefined,value,values) : undefined, + (pattern,message) => (pattern.toString() + message) +); + +export const email=memoize((message="validacion.correo") => regex(EMAIL_REGEX,message)); + +export const remote=memoize((call,params,message="validacion.remote") => (value,values,meta) => { + return meta.active && !isEmpty(value) && + call(value,params) + .then(data => data ? getMessage(message,undefined,value,values) : undefined) + .catch(error => getMessage(error.message,undefined,value,values)) +}); diff --git a/vite.config.js b/vite.config.js index 058888b..f122834 100644 --- a/vite.config.js +++ b/vite.config.js @@ -32,6 +32,7 @@ export default defineConfig({ "jwt-decode", "mui-rff", "navigator-languages", + "node-polyglot", "react-polyglot", "react-redux", "react-router-dom", @@ -61,6 +62,7 @@ export default defineConfig({ "jwt-decode": "JWTDecode", "mui-rff": "MUIRFF", "navigator-languages": "NavigatorLanguages", + "node-polyglot": "NodePolyglot", "react-polyglot": "ReactPolyglot", "react-redux": "ReactRedux", "react-router-dom": "ReactRouterDom",