UNPKG

drf-react-by-schema

Version:

Components and Tools for building a React App having Django Rest Framework (DRF) as server

368 lines (367 loc) 12.7 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.slugify = exports.slugToCamelCase = exports.getPatternFormat = exports.isTmpId = exports.getTmpId = exports.errorProps = exports.buildGenericYupValidationSchema = exports.populateValues = exports.getChoiceByValue = exports.emptyByType = void 0; exports.reducer = reducer; exports.buildDateFormatBySchema = buildDateFormatBySchema; exports.mergeFilterItems = mergeFilterItems; const Yup = __importStar(require("yup")); const emptyByType = (field, forDatabase = false) => { if (field.model_default) { return field.model_default; } switch (field.type) { case 'nested object': // emptyByType must be an empty object for the database, but must be null for the mui-autocomplete component. So I had to make this ugly hack here, when we're preparing to sendo to the database: return forDatabase ? {} : null; case 'field': if (field.child) { return []; } return forDatabase ? undefined : null; case 'string': case 'email': return ''; case 'integer': return 0; case 'array': return []; case 'boolean': return false; default: return null; } }; exports.emptyByType = emptyByType; const getChoiceByValue = (value, choices) => { if (!choices) { return null; } for (const choice of choices) { if (choice.value === value) { return choice.display_name; } } }; exports.getChoiceByValue = getChoiceByValue; const populateValues = ({ data, schema }) => { const values = {}; for (const [key, field] of Object.entries(schema)) { if (key === 'id' && (0, exports.isTmpId)(data[key])) { continue; } if (!data[key]) { values[key] = (0, exports.emptyByType)(field); continue; } if (field.type === 'field' && field.child) { if (Array.isArray(data[key])) { const arValues = []; for (const row of data[key]) { const value = (0, exports.populateValues)({ data: row, schema: field.child.children, }); arValues.push(value); } values[key] = arValues; continue; } values[key] = (0, exports.populateValues)({ data: data[key], schema: field.child.children, }); continue; } if (field.type === 'choice') { values[key] = data[key] ? { value: data[key], display_name: (0, exports.getChoiceByValue)(data[key], field.choices), } : (0, exports.emptyByType)(field); continue; } values[key] = data[key]; } // console.log(values); return values; }; exports.populateValues = populateValues; const getYupValidator = (type) => { let yupFunc; try { switch (type) { case 'slug': yupFunc = Yup.string(); break; case 'email': yupFunc = Yup.string().email('Este campo deve ser um e-mail válido.'); break; case 'integer': yupFunc = Yup.number().integer('Este campo deve ser um número inteiro'); break; case 'choice': yupFunc = Yup.object(); break; case 'field': yupFunc = Yup.mixed(); break; case 'nested object': yupFunc = Yup.object(); break; case 'date': yupFunc = Yup.date(); break; case 'string': yupFunc = Yup.string(); break; case 'number': case 'decimal': yupFunc = Yup.number(); break; case 'boolean': yupFunc = Yup.bool(); break; case 'array': yupFunc = Yup.array(); break; case 'object': yupFunc = Yup.object(); break; default: yupFunc = Yup.string(); break; } // eslint-disable-next-line @typescript-eslint/no-unused-vars } catch (e) { yupFunc = Yup.string(); } return yupFunc.nullable(); }; const buildGenericYupValidationSchema = ({ data, schema, many = false, skipFields = [], extraValidators = {}, }) => { const yupValidator = {}; for (const entry of Object.entries(schema)) { const [key, field] = entry; if (!data || !(key in data) || key === 'id' || skipFields.includes(key)) { continue; } // console.log({ key, field, data: data[key] }); // OneToMany or ManyToMany: if (field.type === 'field' && field.child) { yupValidator[key] = (0, exports.buildGenericYupValidationSchema)({ schema: field.child.children, many: true, data: data[key], extraValidators: key in extraValidators ? extraValidators[key] : {}, }); continue; } // Nested Object: if (field.type === 'nested object' && field.children) { // yupValidator[key] = buildGenericYupValidationSchema({ // schema: field.children, // many: false, // data: data[key], // extraValidators: key in extraValidators ? extraValidators[key] : {} // }); // if (!field.model_required) { // yupValidator[key] = yupValidator[key].nullable(); // } // continue; } yupValidator[key] = key in extraValidators ? extraValidators[key] : getYupValidator(field.type); if (field.model_required) { yupValidator[key] = yupValidator[key].required('Este campo é obrigatório'); } if (field.max_length) { yupValidator[key] = yupValidator[key].max(parseInt(field.max_length), `Este campo só pode ter no máximo ${field.max_length} caracteres`); } if (field.max_digits && field.type === 'decimal') { const maxDigits = field.max_digits; yupValidator[key] = yupValidator[key].test('len', `Este número pode ter no máximo ${maxDigits} dígitos`, (val) => { if (!val) { return true; } return val.toString().length <= maxDigits; }); } if (!field.read_only && field.validators_regex) { for (const validator of field.validators_regex) { yupValidator[key] = yupValidator[key].matches(validator.regex, validator.message); } } } // console.log({ yupValidator }); return many ? Yup.array().of(Yup.object().shape(yupValidator)) : Yup.object().shape(yupValidator); }; exports.buildGenericYupValidationSchema = buildGenericYupValidationSchema; const errorProps = ({ errors, fieldKey, fieldKeyProp, index, }) => { let error; let helperText; if (index) { const hasErrors = errors && errors[fieldKey] && errors[fieldKey][index] && Boolean(errors[fieldKey][index][fieldKeyProp]); error = hasErrors; helperText = hasErrors ? errors[fieldKey][index][fieldKeyProp].message : null; return { error, helperText }; } const hasErrors = errors && errors[fieldKey] && Boolean(errors[fieldKey][fieldKeyProp]); error = hasErrors; helperText = hasErrors ? errors[fieldKey][fieldKeyProp].message : null; return { error, helperText }; }; exports.errorProps = errorProps; const getTmpId = () => { return 'tmp' + Math.floor(Math.random() * 1000000); }; exports.getTmpId = getTmpId; const isTmpId = (id) => { if (!id) { return true; } return id === 'novo' || id.toString().slice(0, 3) === 'tmp'; }; exports.isTmpId = isTmpId; function reducer(state, newState) { if (newState === null) { return null; } if (state === null) { return newState; } return Object.assign(Object.assign({}, state), newState); } const getPatternFormat = (type) => { let format = ''; switch (type) { case 'telefone': case 'fone': case 'phone': case 'contact': case 'contato': format = '(##)#####-####'; break; case 'cpf': format = '###.###.###-##'; break; case 'cnpj': format = '##.###.###/####-##'; break; case 'cep': format = '##.###-###'; break; } return format; }; exports.getPatternFormat = getPatternFormat; function buildDateFormatBySchema(dateViews) { const defaultFormat = 'DD/MM/YYYY'; if (!dateViews) { return defaultFormat; } const hasDay = dateViews.includes('day'); const hasMonth = dateViews.includes('month'); const hasYear = dateViews.includes('year'); if (hasDay && hasMonth && hasYear) { return defaultFormat; } if (!hasDay && hasMonth && hasYear) { return 'MM/YYYY'; } if (!hasDay && !hasMonth && hasYear) { return 'YYYY'; } if (!hasDay && hasMonth && !hasYear) { return 'MM'; } if (hasDay && !hasMonth && !hasYear) { return 'DD'; } return defaultFormat; } const slugToCamelCase = (str, includeFirst = false) => { if (!str) { return ''; } const ret = str.replace(/_([a-z])/g, function (g) { return g[1].toUpperCase(); }); if (includeFirst) { return ret[0].toUpperCase() + ret.slice(1); } return ret; }; exports.slugToCamelCase = slugToCamelCase; const slugify = (text) => { if (!text) { return ''; } return text .toString() .normalize('NFD') .replace(/[\u0300-\u036f]/g, '') .toLowerCase() .trim() .replace(/\s+/g, '-') .replace(/[^\w-]+/g, '') .replace(/--+/g, '-'); }; exports.slugify = slugify; function mergeFilterItems(defaultFilter, filter) { if (!filter && defaultFilter) { return defaultFilter; } if (!defaultFilter && filter) { return filter; } if (filter && defaultFilter) { const items = filter.items; const defaultItems = defaultFilter.items; const mergedItems = defaultItems.map((defaultItem) => { const itemFound = items.find((item) => item.columnField === defaultItem.columnField); if (itemFound) { return itemFound; } return defaultItem; }); const unMergedItems = items.filter((item) => !defaultItems.map((defaultItem) => defaultItem.columnField).includes(item.columnField)); return Object.assign(Object.assign({}, filter), { items: [...mergedItems, ...unMergedItems] }); } return undefined; }